{
  "name": "XXX-\u8a62\u50f9\u4e3b\u6d41\u7a0b (LINE\u2192Dify\u2192\u8a08\u50f9\u2192\u5be9\u6838)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "bagking-line-webhook",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "node-webhook",
      "name": "LINE Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        120,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "OK",
        "options": {}
      },
      "id": "node-webhook-200",
      "name": "\u56de\u8986 LINE 200",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        340,
        480
      ]
    },
    {
      "parameters": {
        "jsCode": "// \u5f9e LINE webhook \u53d6\u51fa\u7b2c\u4e00\u5247\u6587\u5b57\u8a0a\u606f\u4e8b\u4ef6\nconst body = $input.first().json.body || $input.first().json;\nconst events = body.events || [];\nconst out = [];\nfor (const ev of events) {\n  if (ev.type === 'message' && ev.message && ev.message.type === 'text') {\n    out.push({\n      json: {\n        replyToken: ev.replyToken,\n        userId: ev.source && ev.source.userId,\n        rawInput: ev.message.text,\n      },\n    });\n  }\n}\nreturn out;"
      },
      "id": "node-extract",
      "name": "\u89e3\u6790 LINE \u8a0a\u606f",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        340,
        220
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.DIFY_API_URL }}/workflows/run",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.DIFY_API_KEY }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"inputs\": { \"raw_input\": \"{{ $json.rawInput }}\", \"customer_name\": \"\" },\n  \"response_mode\": \"blocking\",\n  \"user\": \"{{ $json.userId }}\"\n}",
        "options": {}
      },
      "id": "node-dify",
      "name": "\u547c\u53eb Dify \u89e3\u6790+\u8a08\u50f9",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        560,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "// \u53d6\u51fa Dify \u5de5\u4f5c\u6d41\u8f38\u51fa\uff08parsed + quote\uff09\uff0c\u7522\u751f\u55ae\u865f\uff0c\u4e26\u628a\u6574\u7b46\u5831\u50f9\u6301\u4e45\u5316\u5230 workflow staticData\nconst prev = $('\u89e3\u6790 LINE \u8a0a\u606f').first().json;\nconst data = $input.first().json;\nconst outputs = (data.data && data.data.outputs) || data.outputs || {};\nconst parsed = outputs.parsed || {};\nconst quote = outputs.quote || {};\n\n// \u7522\u751f\u8a62\u50f9\u55ae\u865f BK-YYYYMMDD-HHMMSS\nconst d = new Date();\nconst pad = (n) => String(n).padStart(2, '0');\nconst quoteNo = `BK-${d.getFullYear()}${pad(d.getMonth()+1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;\n\n// === \u6301\u4e45\u5316\uff1a\u5b58\u5230 workflow staticData\uff0c\u4f9b\u5be9\u6838\u56de\u547c\u6d41\u7a0b\u4f9d quoteNo \u67e5\u56de ===\n// \u8a3b\uff1astaticData \u70ba MVP \u66ab\u5b58\u65b9\u6848\uff1b\u6b63\u5f0f\u74b0\u5883\u5efa\u8b70\u6539\u7528\u8cc7\u6599\u5eab\u6216\u76f4\u63a5\u547c\u53eb Web \u7cfb\u7d71 API\uff08\u898b bagking_inquiry_via_webapi.json\uff09\u3002\nconst staticData = $getWorkflowStaticData('global');\nif (!staticData.quotes) staticData.quotes = {};\nstaticData.quotes[quoteNo] = {\n  quoteNo,\n  customerUserId: prev.userId,   // \u6700\u521d\u8a62\u50f9\u5ba2\u6236\uff0c\u6838\u51c6\u6642\u56de\u50b3\u7d66\u4ed6\n  rawInput: prev.rawInput,\n  parsed,\n  quote,\n  status: 'pending',\n  createdAt: d.toISOString(),\n};\n\nconst summary = quote.ok\n  ? `\u3010\u65b0\u8a62\u50f9\u5f85\u5be9\u6838\u3011\\n\u55ae\u865f\uff1a${quoteNo}\\n\u54c1\u9805\uff1a${quote.item}${quote.material ? '\uff08'+quote.material+'\uff09' : ''}\\n\u6578\u91cf\uff1a${quote.quantity}\\n\u542b\u7a05\u55ae\u50f9\uff1a$${quote.unitPriceInclTax}\\n\u542b\u7a05\u7e3d\u8a08\uff1a$${quote.totalInclTax}\\n\u6298\u6263\uff1a${quote.discountLabel}${quote.below_moq ? '\\n\u26a0 \u4f4e\u65bc\u8d77\u8a02\u91cf '+quote.moq : ''}\\n\u539f\u59cb\u9700\u6c42\uff1a${prev.rawInput}`\n  : `\u3010\u8a62\u50f9\u9700\u4eba\u5de5\u78ba\u8a8d\u3011\\n\u55ae\u865f\uff1a${quoteNo}\\n\u539f\u56e0\uff1a${quote.reason || '\u89e3\u6790\u5931\u6557'}\\n\u539f\u59cb\u9700\u6c42\uff1a${prev.rawInput}`;\n\nreturn [{ json: { quoteNo, replyToken: prev.replyToken, userId: prev.userId, rawInput: prev.rawInput, parsed, quote, adminSummary: summary } }];"
      },
      "id": "node-build",
      "name": "\u7d44\u88dd\u5831\u50f9\u6458\u8981+\u6301\u4e45\u5316",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        780,
        220
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.line.me/v2/bot/message/reply",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.LINE_CHANNEL_ACCESS_TOKEN }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"replyToken\": \"{{ $json.replyToken }}\",\n  \"messages\": [\n    { \"type\": \"text\", \"text\": \"\u5df2\u6536\u5230\u60a8\u7684\u8a62\u50f9\uff01\\n\u55ae\u865f\uff1a{{ $json.quoteNo }}\\n\u6211\u5011\u7684 AI \u5df2\u5b8c\u6210\u521d\u6b65\u8a66\u7b97\uff0c\u5c07\u7531\u5c08\u4eba\u5be9\u6838\u5f8c\u56de\u8986\u6b63\u5f0f\u5831\u50f9\uff0c\u8acb\u7a0d\u5019 \ud83d\ude4f\" }\n  ]\n}",
        "options": {}
      },
      "id": "node-reply-customer",
      "name": "\u56de\u8986\u5ba2\u6236(\u6536\u5230\u901a\u77e5)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1000,
        320
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.line.me/v2/bot/message/push",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.LINE_CHANNEL_ACCESS_TOKEN }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"to\": \"{{ $env.ADMIN_LINE_USER_ID }}\",\n  \"messages\": [\n    {\n      \"type\": \"text\",\n      \"text\": {{ JSON.stringify($json.adminSummary) }}\n    },\n    {\n      \"type\": \"template\",\n      \"altText\": \"\u5831\u50f9\u5be9\u6838\uff1a{{ $json.quoteNo }}\",\n      \"template\": {\n        \"type\": \"confirm\",\n        \"text\": \"\u662f\u5426\u6838\u51c6\u5831\u50f9 {{ $json.quoteNo }}\uff1f\",\n        \"actions\": [\n          { \"type\": \"postback\", \"label\": \"Approve \u540c\u610f\", \"data\": \"action=approve&quoteNo={{ $json.quoteNo }}\", \"displayText\": \"\u6838\u51c6 {{ $json.quoteNo }}\" },\n          { \"type\": \"postback\", \"label\": \"Reject \u62d2\u7d55\", \"data\": \"action=reject&quoteNo={{ $json.quoteNo }}\", \"displayText\": \"\u62d2\u7d55 {{ $json.quoteNo }}\" }\n        ]\n      }\n    }\n  ]\n}",
        "options": {}
      },
      "id": "node-push-admin",
      "name": "\u63a8\u64ad\u7ba1\u7406\u54e1(\u542b\u5be9\u6838\u6309\u9215)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1000,
        180
      ]
    }
  ],
  "connections": {
    "LINE Webhook": {
      "main": [
        [
          {
            "node": "\u89e3\u6790 LINE \u8a0a\u606f",
            "type": "main",
            "index": 0
          },
          {
            "node": "\u56de\u8986 LINE 200",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u89e3\u6790 LINE \u8a0a\u606f": {
      "main": [
        [
          {
            "node": "\u547c\u53eb Dify \u89e3\u6790+\u8a08\u50f9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u547c\u53eb Dify \u89e3\u6790+\u8a08\u50f9": {
      "main": [
        [
          {
            "node": "\u7d44\u88dd\u5831\u50f9\u6458\u8981+\u6301\u4e45\u5316",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u7d44\u88dd\u5831\u50f9\u6458\u8981+\u6301\u4e45\u5316": {
      "main": [
        [
          {
            "node": "\u63a8\u64ad\u7ba1\u7406\u54e1(\u542b\u5be9\u6838\u6309\u9215)",
            "type": "main",
            "index": 0
          },
          {
            "node": "\u56de\u8986\u5ba2\u6236(\u6536\u5230\u901a\u77e5)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": [
    {
      "name": "XXX"
    },
    {
      "name": "\u5831\u50f9\u7cfb\u7d71"
    }
  ]
}