8
n8n 中文网amn8n.com

通过Gmail将设备请求路由至采购部门并需经理批准

高级

这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 55 个节点。主要使用 If, Set, Form, Gmail, Merge 等节点。 通过Gmail将设备请求路由至采购部门,需经理批准

前置要求
  • Google 账号和 Gmail API 凭证
  • MySQL 数据库连接信息
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "rtK6UJNlclMQboZu",
  "meta": {
    "instanceId": "46f10f8f90bd424d08d7ec9e92bdd735f336873f2ca9f21d76cc7ac132eeaabd",
    "templateCredsSetupCompleted": true
  },
  "name": "通过 Gmail 将设备请求路由至采购部门并需经理批准",
  "tags": [],
  "nodes": [
    {
      "id": "37da6182-7899-43ea-8266-f63209c78a45",
      "name": "问题表单",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -416,
        -144
      ],
      "webhookId": "65a85fa9-64a9-4bfb-b2b0-ee43675117b4",
      "parameters": {
        "options": {
          "customCss": "/* ===== Base layout ===== */\nhtml, body {\n  height: 100%;\n  font-family: var(--font-family);\n  font-weight: var(--font-weight-normal);\n  font-size: var(--font-size-body);\n  background:\n    radial-gradient(1200px 800px at 10% -10%, #f0f2ff 0%, transparent 60%),\n    radial-gradient(1000px 700px at 110% 0%, #fef3f0 0%, transparent 55%),\n    var(--color-background);\n  color: var(--color-html-text);\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.container, .form-wrapper, .n8n-form {\n  max-width: var(--container-width);\n  margin: 32px auto;\n  padding: 0 12px;\n}\n\n/* ===== Test banner (top) ===== */\n.test-notice {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  margin: 0 auto 12px;\n  max-width: var(--container-width);\n  background: var(--color-test-notice-bg);\n  border: 1px solid var(--color-test-notice-border);\n  color: var(--color-test-notice-text);\n  padding: var(--padding-test-notice-vertical) var(--padding-test-notice-horizontal);\n  border-radius: var(--border-radius-input);\n  font-size: var(--font-size-test-notice);\n}\n\n/* ===== Card ===== */\n.form-card {\n  background: var(--color-card-bg);\n  border: 1px solid var(--color-card-border);\n  border-radius: var(--border-radius-card);\n  box-shadow: var(--box-shadow-card);\n  padding: var(--padding-card);\n  margin-bottom: var(--margin-bottom-card);\n}\n\n/* ===== Headings & subtitle ===== */\n.form-card h1,\nh1.form-title {\n  font-size: var(--font-size-header);\n  color: var(--color-header);\n  margin: 4px 0 6px;\n  font-weight: var(--font-weight-bold);\n  letter-spacing: -0.2px;\n}\n\n.form-subtitle {\n  font-size: var(--font-size-paragraph);\n  color: var(--color-header-subtext);\n  margin: 0 0 16px;\n  line-height: 1.5;\n}\n\n/* ===== Form fields ===== */\n.form-field {\n  display: grid;\n  gap: 6px;\n  margin-bottom: 14px;\n}\n\n.form-field label {\n  font-size: var(--font-size-label);\n  color: var(--color-label);\n  font-weight: 600;\n}\n\n.form-field label .required {\n  color: var(--color-required);\n  margin-left: 2px;\n}\n\n/* Inputs / selects / textareas */\ninput[type=\"text\"],\ninput[type=\"email\"],\ninput[type=\"number\"],\ninput[type=\"search\"],\ntextarea,\nselect {\n  width: 100%;\n  appearance: none;\n  border: 1px solid var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  font-size: var(--font-size-input);\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n  opacity: var(--opacity-placeholder);\n}\n\n/* Hover / focus */\ninput:hover,\ntextarea:hover,\nselect:hover {\n  border-color: #cfd5e2;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n  outline: none;\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* Invalid */\n.is-invalid,\ninput[aria-invalid=\"true\"],\ntextarea[aria-invalid=\"true\"],\nselect[aria-invalid=\"true\"] {\n  border-color: var(--color-error);\n  box-shadow: 0 0 0 4px rgba(234, 31, 48, .12);\n}\n\n/* Help / error text */\n.help-text {\n  font-size: 12px;\n  color: var(--color-link);\n}\n\n.error-text {\n  font-size: var(--font-size-error);\n  color: var(--color-error);\n  margin-top: 4px;\n}\n\n/* ===== File input (custom) ===== */\n.input-file {\n  position: relative;\n}\n\n.input-file input[type=\"file\"] {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  cursor: pointer;\n}\n\n.input-file .file-ui {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 10px;\n  border: 1px dashed var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease;\n}\n\n.input-file .file-ui:hover {\n  border-color: #cfd5e2;\n}\n\n.input-file .file-ui:has(+ input[type=\"file\"]:focus) {\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* ===== Checkboxes / radios (accessible but nicer) ===== */\ninput[type=\"checkbox\"], input[type=\"radio\"] {\n  accent-color: var(--color-focus-border);\n  width: var(--checkbox-size);\n  height: var(--checkbox-size);\n}\n\n/* ===== Buttons ===== */\n.actions,\n.form-actions {\n  margin-top: 8px;\n}\n\nbutton[type=\"submit\"],\n.button-submit {\n  width: 100%;\n  height: var(--submit-btn-height);\n  background: var(--color-submit-btn-bg);\n  color: var(--color-submit-btn-text);\n  border: 1px solid transparent;\n  border-radius: var(--border-radius-input);\n  font-size: 15px;\n  font-weight: 700;\n  letter-spacing: .2px;\n  cursor: pointer;\n  transition: transform .05s ease, filter .15s ease, box-shadow .15s ease;\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .25);\n}\n\nbutton[type=\"submit\"]:hover {\n  filter: brightness(0.98);\n  transform: translateY(-1px);\n  box-shadow: 0 8px 24px rgba(255, 109, 90, .28);\n}\n\nbutton[type=\"submit\"]:active {\n  transform: translateY(0);\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .22);\n}\n\nbutton[disabled] {\n  opacity: .6;\n  cursor: not-allowed;\n}\n\n/* Secondary link under button (e.g., “Clear form”) */\n.clear-link {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  margin-top: 10px;\n  font-size: var(--font-size-link);\n  color: var(--color-link);\n  text-decoration: none;\n}\n.clear-link:hover { text-decoration: underline; }\n\n/* ===== Footer / “Automated with n8n” ===== */\n.form-footer {\n  margin: 10px auto 24px;\n  max-width: var(--container-width);\n  text-align: center;\n  color: var(--color-link);\n  font-size: var(--font-size-link);\n}\n\n/* ===== Responsive ===== */\n@media (max-width: 520px) {\n  .container, .form-wrapper, .n8n-form {\n    margin: 20px auto;\n    padding: 0 10px;\n  }\n  .form-card { padding: 20px; }\n  .form-card h1, h1.form-title { font-size: 18px; }\n  .form-subtitle { font-size: 13px; }\n}\n\n/* ===== Optional: Dark mode (auto) ===== */\n@media (prefers-color-scheme: dark) {\n  body {\n    background:\n      radial-gradient(1200px 800px at 10% -10%, #272a33 0%, transparent 60%),\n      radial-gradient(1000px 700px at 110% 0%, #2c2433 0%, transparent 55%),\n      #16181d;\n    color: #d8dbe3;\n  }\n\n  .test-notice {\n    background: #2a2115;\n    border-color: #3a2b18;\n    color: #ffce74;\n  }\n\n  .form-card {\n    background: #1c1f27;\n    border-color: #2a2f3a;\n    box-shadow: 0 8px 24px rgba(0,0,0,.35);\n  }\n\n  .form-card h1, h1.form-title { color: #e9ebf3; }\n  .form-subtitle { color: #a6adbb; }\n\n  input, textarea, select {\n    background: #11151c;\n    border-color: #2a2f3a;\n    color: #d8dbe3;\n  }\n  input:hover, textarea:hover, select:hover { border-color: #3a4250; }\n  input:focus, textarea:focus, select:focus {\n    border-color: #b7a8ff;\n    box-shadow: 0 0 0 4px rgba(183,168,255,.18);\n  }\n\n  .help-text { color: #9aa3b2; }\n\n  button[type=\"submit\"],\n  .button-submit {\n    box-shadow: 0 10px 26px rgba(255,109,90,.34);\n  }\n\n  .form-footer { color: #9aa3b2; }\n}\n",
          "buttonLabel": "Send question"
        },
        "formTitle": "Equipment Request Form",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Your employee enrollment",
              "requiredField": true
            }
          ]
        },
        "responseMode": "lastNode",
        "formDescription": "Please fill in your employee ID so we can validate your information and identify your manager"
      },
      "typeVersion": 2.3
    },
    {
      "id": "4e3062f4-9644-4830-9410-1bdf4802a49d",
      "name": "如果",
      "type": "n8n-nodes-base.if",
      "position": [
        400,
        -144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d0fdfd93-0d28-43cf-8db7-1a4b22d57a15",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isEmpty() }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b6487e94-9186-4ec6-b0a6-cbe4fb04401c",
      "name": "返回未找到员工",
      "type": "n8n-nodes-base.form",
      "position": [
        720,
        -352
      ],
      "webhookId": "df14c48b-886d-4b8b-9c25-c0476114b939",
      "parameters": {
        "options": {},
        "operation": "completion",
        "completionTitle": "Employee not found",
        "completionMessage": "It was not possible to find your registration based on your enrollment number."
      },
      "typeVersion": 2.3
    },
    {
      "id": "1f8c6236-784a-49e9-9da6-4ad8b53d7de5",
      "name": "获取请求信息",
      "type": "n8n-nodes-base.form",
      "position": [
        -416,
        464
      ],
      "webhookId": "6abb8175-8e68-480c-a179-7798db9c266d",
      "parameters": {
        "options": {
          "customCss": "/* ===== Base layout ===== */\nhtml, body {\n  height: 100%;\n  font-family: var(--font-family);\n  font-weight: var(--font-weight-normal);\n  font-size: var(--font-size-body);\n  background:\n    radial-gradient(1200px 800px at 10% -10%, #f0f2ff 0%, transparent 60%),\n    radial-gradient(1000px 700px at 110% 0%, #fef3f0 0%, transparent 55%),\n    var(--color-background);\n  color: var(--color-html-text);\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.container, .form-wrapper, .n8n-form {\n  max-width: var(--container-width);\n  margin: 32px auto;\n  padding: 0 12px;\n}\n\n/* ===== Test banner (top) ===== */\n.test-notice {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  margin: 0 auto 12px;\n  max-width: var(--container-width);\n  background: var(--color-test-notice-bg);\n  border: 1px solid var(--color-test-notice-border);\n  color: var(--color-test-notice-text);\n  padding: var(--padding-test-notice-vertical) var(--padding-test-notice-horizontal);\n  border-radius: var(--border-radius-input);\n  font-size: var(--font-size-test-notice);\n}\n\n/* ===== Card ===== */\n.form-card {\n  background: var(--color-card-bg);\n  border: 1px solid var(--color-card-border);\n  border-radius: var(--border-radius-card);\n  box-shadow: var(--box-shadow-card);\n  padding: var(--padding-card);\n  margin-bottom: var(--margin-bottom-card);\n}\n\n/* ===== Headings & subtitle ===== */\n.form-card h1,\nh1.form-title {\n  font-size: var(--font-size-header);\n  color: var(--color-header);\n  margin: 4px 0 6px;\n  font-weight: var(--font-weight-bold);\n  letter-spacing: -0.2px;\n}\n\n.form-subtitle {\n  font-size: var(--font-size-paragraph);\n  color: var(--color-header-subtext);\n  margin: 0 0 16px;\n  line-height: 1.5;\n}\n\n/* ===== Form fields ===== */\n.form-field {\n  display: grid;\n  gap: 6px;\n  margin-bottom: 14px;\n}\n\n.form-field label {\n  font-size: var(--font-size-label);\n  color: var(--color-label);\n  font-weight: 600;\n}\n\n.form-field label .required {\n  color: var(--color-required);\n  margin-left: 2px;\n}\n\n/* Inputs / selects / textareas */\ninput[type=\"text\"],\ninput[type=\"email\"],\ninput[type=\"number\"],\ninput[type=\"search\"],\ntextarea,\nselect {\n  width: 100%;\n  appearance: none;\n  border: 1px solid var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  font-size: var(--font-size-input);\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n  opacity: var(--opacity-placeholder);\n}\n\n/* Hover / focus */\ninput:hover,\ntextarea:hover,\nselect:hover {\n  border-color: #cfd5e2;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n  outline: none;\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* Invalid */\n.is-invalid,\ninput[aria-invalid=\"true\"],\ntextarea[aria-invalid=\"true\"],\nselect[aria-invalid=\"true\"] {\n  border-color: var(--color-error);\n  box-shadow: 0 0 0 4px rgba(234, 31, 48, .12);\n}\n\n/* Help / error text */\n.help-text {\n  font-size: 12px;\n  color: var(--color-link);\n}\n\n.error-text {\n  font-size: var(--font-size-error);\n  color: var(--color-error);\n  margin-top: 4px;\n}\n\n/* ===== File input (custom) ===== */\n.input-file {\n  position: relative;\n}\n\n.input-file input[type=\"file\"] {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  cursor: pointer;\n}\n\n.input-file .file-ui {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 10px;\n  border: 1px dashed var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease;\n}\n\n.input-file .file-ui:hover {\n  border-color: #cfd5e2;\n}\n\n.input-file .file-ui:has(+ input[type=\"file\"]:focus) {\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* ===== Checkboxes / radios (accessible but nicer) ===== */\ninput[type=\"checkbox\"], input[type=\"radio\"] {\n  accent-color: var(--color-focus-border);\n  width: var(--checkbox-size);\n  height: var(--checkbox-size);\n}\n\n/* ===== Buttons ===== */\n.actions,\n.form-actions {\n  margin-top: 8px;\n}\n\nbutton[type=\"submit\"],\n.button-submit {\n  width: 100%;\n  height: var(--submit-btn-height);\n  background: var(--color-submit-btn-bg);\n  color: var(--color-submit-btn-text);\n  border: 1px solid transparent;\n  border-radius: var(--border-radius-input);\n  font-size: 15px;\n  font-weight: 700;\n  letter-spacing: .2px;\n  cursor: pointer;\n  transition: transform .05s ease, filter .15s ease, box-shadow .15s ease;\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .25);\n}\n\nbutton[type=\"submit\"]:hover {\n  filter: brightness(0.98);\n  transform: translateY(-1px);\n  box-shadow: 0 8px 24px rgba(255, 109, 90, .28);\n}\n\nbutton[type=\"submit\"]:active {\n  transform: translateY(0);\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .22);\n}\n\nbutton[disabled] {\n  opacity: .6;\n  cursor: not-allowed;\n}\n\n/* Secondary link under button (e.g., “Clear form”) */\n.clear-link {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  margin-top: 10px;\n  font-size: var(--font-size-link);\n  color: var(--color-link);\n  text-decoration: none;\n}\n.clear-link:hover { text-decoration: underline; }\n\n/* ===== Footer / “Automated with n8n” ===== */\n.form-footer {\n  margin: 10px auto 24px;\n  max-width: var(--container-width);\n  text-align: center;\n  color: var(--color-link);\n  font-size: var(--font-size-link);\n}\n\n/* ===== Responsive ===== */\n@media (max-width: 520px) {\n  .container, .form-wrapper, .n8n-form {\n    margin: 20px auto;\n    padding: 0 10px;\n  }\n  .form-card { padding: 20px; }\n  .form-card h1, h1.form-title { font-size: 18px; }\n  .form-subtitle { font-size: 13px; }\n}\n\n/* ===== Optional: Dark mode (auto) ===== */\n@media (prefers-color-scheme: dark) {\n  body {\n    background:\n      radial-gradient(1200px 800px at 10% -10%, #272a33 0%, transparent 60%),\n      radial-gradient(1000px 700px at 110% 0%, #2c2433 0%, transparent 55%),\n      #16181d;\n    color: #d8dbe3;\n  }\n\n  .test-notice {\n    background: #2a2115;\n    border-color: #3a2b18;\n    color: #ffce74;\n  }\n\n  .form-card {\n    background: #1c1f27;\n    border-color: #2a2f3a;\n    box-shadow: 0 8px 24px rgba(0,0,0,.35);\n  }\n\n  .form-card h1, h1.form-title { color: #e9ebf3; }\n  .form-subtitle { color: #a6adbb; }\n\n  input, textarea, select {\n    background: #11151c;\n    border-color: #2a2f3a;\n    color: #d8dbe3;\n  }\n  input:hover, textarea:hover, select:hover { border-color: #3a4250; }\n  input:focus, textarea:focus, select:focus {\n    border-color: #b7a8ff;\n    box-shadow: 0 0 0 4px rgba(183,168,255,.18);\n  }\n\n  .help-text { color: #9aa3b2; }\n\n  button[type=\"submit\"],\n  .button-submit {\n    box-shadow: 0 10px 26px rgba(255,109,90,.34);\n  }\n\n  .form-footer { color: #9aa3b2; }\n}\n"
        },
        "formFields": {
          "values": [
            {
              "fieldType": "textarea",
              "fieldLabel": "What would you like to request?",
              "requiredField": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "393cdcc8-af4d-42bb-b8c1-5891d1b089de",
      "name": "OpenAI 聊天模型",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2304,
        400
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-nano",
          "cachedResultName": "gpt-4.1-nano"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "zwivGqRORUgpjepY",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "fae1ff57-f79b-46e6-a9c1-97abab368585",
      "name": "获取员工",
      "type": "n8n-nodes-base.mySql",
      "position": [
        16,
        -144
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "employees",
          "cachedResultName": "employees"
        },
        "where": {
          "values": [
            {
              "value": "={{ $json['Your employee enrollment'] }}",
              "column": "enrollment_number"
            }
          ]
        },
        "options": {},
        "operation": "select",
        "returnAll": true
      },
      "credentials": {
        "mySql": {
          "id": "sQeUBEQkBvNWbM2y",
          "name": "MySQL - Estudos"
        }
      },
      "typeVersion": 2.5,
      "alwaysOutputData": true
    },
    {
      "id": "c5d3a970-c61e-4a87-910e-18809d9f7cee",
      "name": "员工数据",
      "type": "n8n-nodes-base.set",
      "position": [
        720,
        96
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3f65a01e-465e-412e-b9f5-31b366724dc7",
              "name": "employee.enrollment_number",
              "type": "string",
              "value": "={{ $json.enrollment_number }}"
            },
            {
              "id": "e2f24a33-b96b-4106-a7cc-bdad369407b4",
              "name": "employee.name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "c7fe12b0-389d-477b-ab73-62da0fcafd3a",
              "name": "employee.email",
              "type": "string",
              "value": "={{ $json.email }}"
            },
            {
              "id": "8ceb93de-c37a-4c9e-af13-54a582a2e7bd",
              "name": "employee.manager",
              "type": "number",
              "value": "={{ $json.manager }}"
            },
            {
              "id": "971f3df4-3b51-44a0-b824-9c0d43f86f92",
              "name": "employee.requires_approval",
              "type": "boolean",
              "value": "={{ $json.manager ? true : false }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "1858f338-3622-4d98-8d07-051069436f39",
      "name": "是否需要批准?",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "16796776-0e35-4704-86fa-d65e91d9c20f",
              "operator": {
                "type": "number",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.employee.manager }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c3e7dc19-8840-4108-8049-ad34aa0ef9f9",
      "name": "获取经理",
      "type": "n8n-nodes-base.mySql",
      "position": [
        1360,
        32
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "employees",
          "cachedResultName": "employees"
        },
        "where": {
          "values": [
            {
              "value": "={{ $json.employee.manager }}",
              "column": "id"
            }
          ]
        },
        "options": {},
        "operation": "select",
        "returnAll": true
      },
      "credentials": {
        "mySql": {
          "id": "sQeUBEQkBvNWbM2y",
          "name": "MySQL - Estudos"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "d5df5874-e4e4-47c7-a224-120f2f69f0cc",
      "name": "员工和经理",
      "type": "n8n-nodes-base.merge",
      "position": [
        2016,
        16
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "da2d6915-dcb3-4a11-a36c-a7e39ae5212b",
      "name": "设置经理字段",
      "type": "n8n-nodes-base.set",
      "position": [
        1680,
        32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7b2ad1ea-22a6-4e66-b17b-12e6c8273a75",
              "name": "manager",
              "type": "object",
              "value": "={{ $json }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f85e302e-2285-43d8-a29d-8b11267cb442",
      "name": "合并员工数据和请求",
      "type": "n8n-nodes-base.merge",
      "position": [
        1360,
        448
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "abb1fb4d-f473-41e8-aef2-9679dd56356c",
      "name": "批准请求消息",
      "type": "n8n-nodes-base.if",
      "position": [
        1696,
        448
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "586bed7e-b297-47ef-bdd0-d0e17de39ef7",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.employee.requires_approval }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "ba028c9d-b723-4bac-9713-7ab9fb98d32a",
      "name": "创建批准消息",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2352,
        256
      ],
      "parameters": {
        "text": "=Employee request:\n\n{{ $json['What would you like to request?'] }}\n",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=You are a writing assistant.  \nYou will receive an equipment/item request.  \nYour tasks are:  \n1. Sanitize the request (fix grammar, remove unnecessary words, strange characters, or informal language).  \n2. Rewrite it into a clear, professional, and polite approval request message to a manager.  \n3. Output the result as a valid JSON object containing both the improved request and the full e-mail text.  \n\nKeep the tone formal, concise, and business-appropriate.  \nDo not invent information; only improve grammar, clarity, and tone.  \n\nFormat strictly as JSON, like this:\n\n{\n  \"sanitized_request\": \"[sanitized and improved version of the request]\",\n  \"email_text\": \"Dear {{ $json.manager.name }},\\n\\nPlease approve the procurement of [sanitized_request] for employee {{ $json.employee.name }} (Enrollment: {{ $json.employee.enrollment_number }}).\\n\\nThank you for your attention to this request.\\n\\nBest regards,\\nEquipment request AI\"\n}\n\nEmployee data:\nEnrollment: {{ $json.employee.enrollment_number }}\nName: {{ $json.employee.name }}\nEmail: {{ $json.employee.email }}\n\nManager data:\nName: {{ $json.manager.name }}\nEmail: {{ $json.manager.email }}\n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "8cffcddb-27f7-4f16-8e10-95302097c363",
      "name": "数据和消息",
      "type": "n8n-nodes-base.merge",
      "position": [
        2816,
        272
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "836480a0-a663-4bcb-9357-034b889e2170",
      "name": "结束员工请求",
      "type": "n8n-nodes-base.form",
      "position": [
        3248,
        272
      ],
      "webhookId": "912c0497-44a9-4c79-9824-a3c7d4611177",
      "parameters": {
        "options": {
          "customCss": "/* ===== Base layout ===== */\nhtml, body {\n  height: 100%;\n  font-family: var(--font-family);\n  font-weight: var(--font-weight-normal);\n  font-size: var(--font-size-body);\n  background:\n    radial-gradient(1200px 800px at 10% -10%, #f0f2ff 0%, transparent 60%),\n    radial-gradient(1000px 700px at 110% 0%, #fef3f0 0%, transparent 55%),\n    var(--color-background);\n  color: var(--color-html-text);\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.container, .form-wrapper, .n8n-form {\n  max-width: var(--container-width);\n  margin: 32px auto;\n  padding: 0 12px;\n}\n\n/* ===== Test banner (top) ===== */\n.test-notice {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  margin: 0 auto 12px;\n  max-width: var(--container-width);\n  background: var(--color-test-notice-bg);\n  border: 1px solid var(--color-test-notice-border);\n  color: var(--color-test-notice-text);\n  padding: var(--padding-test-notice-vertical) var(--padding-test-notice-horizontal);\n  border-radius: var(--border-radius-input);\n  font-size: var(--font-size-test-notice);\n}\n\n/* ===== Card ===== */\n.form-card {\n  background: var(--color-card-bg);\n  border: 1px solid var(--color-card-border);\n  border-radius: var(--border-radius-card);\n  box-shadow: var(--box-shadow-card);\n  padding: var(--padding-card);\n  margin-bottom: var(--margin-bottom-card);\n}\n\n/* ===== Headings & subtitle ===== */\n.form-card h1,\nh1.form-title {\n  font-size: var(--font-size-header);\n  color: var(--color-header);\n  margin: 4px 0 6px;\n  font-weight: var(--font-weight-bold);\n  letter-spacing: -0.2px;\n}\n\n.form-subtitle {\n  font-size: var(--font-size-paragraph);\n  color: var(--color-header-subtext);\n  margin: 0 0 16px;\n  line-height: 1.5;\n}\n\n/* ===== Form fields ===== */\n.form-field {\n  display: grid;\n  gap: 6px;\n  margin-bottom: 14px;\n}\n\n.form-field label {\n  font-size: var(--font-size-label);\n  color: var(--color-label);\n  font-weight: 600;\n}\n\n.form-field label .required {\n  color: var(--color-required);\n  margin-left: 2px;\n}\n\n/* Inputs / selects / textareas */\ninput[type=\"text\"],\ninput[type=\"email\"],\ninput[type=\"number\"],\ninput[type=\"search\"],\ntextarea,\nselect {\n  width: 100%;\n  appearance: none;\n  border: 1px solid var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  font-size: var(--font-size-input);\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n  opacity: var(--opacity-placeholder);\n}\n\n/* Hover / focus */\ninput:hover,\ntextarea:hover,\nselect:hover {\n  border-color: #cfd5e2;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n  outline: none;\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* Invalid */\n.is-invalid,\ninput[aria-invalid=\"true\"],\ntextarea[aria-invalid=\"true\"],\nselect[aria-invalid=\"true\"] {\n  border-color: var(--color-error);\n  box-shadow: 0 0 0 4px rgba(234, 31, 48, .12);\n}\n\n/* Help / error text */\n.help-text {\n  font-size: 12px;\n  color: var(--color-link);\n}\n\n.error-text {\n  font-size: var(--font-size-error);\n  color: var(--color-error);\n  margin-top: 4px;\n}\n\n/* ===== File input (custom) ===== */\n.input-file {\n  position: relative;\n}\n\n.input-file input[type=\"file\"] {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  cursor: pointer;\n}\n\n.input-file .file-ui {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 10px;\n  border: 1px dashed var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease;\n}\n\n.input-file .file-ui:hover {\n  border-color: #cfd5e2;\n}\n\n.input-file .file-ui:has(+ input[type=\"file\"]:focus) {\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* ===== Checkboxes / radios (accessible but nicer) ===== */\ninput[type=\"checkbox\"], input[type=\"radio\"] {\n  accent-color: var(--color-focus-border);\n  width: var(--checkbox-size);\n  height: var(--checkbox-size);\n}\n\n/* ===== Buttons ===== */\n.actions,\n.form-actions {\n  margin-top: 8px;\n}\n\nbutton[type=\"submit\"],\n.button-submit {\n  width: 100%;\n  height: var(--submit-btn-height);\n  background: var(--color-submit-btn-bg);\n  color: var(--color-submit-btn-text);\n  border: 1px solid transparent;\n  border-radius: var(--border-radius-input);\n  font-size: 15px;\n  font-weight: 700;\n  letter-spacing: .2px;\n  cursor: pointer;\n  transition: transform .05s ease, filter .15s ease, box-shadow .15s ease;\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .25);\n}\n\nbutton[type=\"submit\"]:hover {\n  filter: brightness(0.98);\n  transform: translateY(-1px);\n  box-shadow: 0 8px 24px rgba(255, 109, 90, .28);\n}\n\nbutton[type=\"submit\"]:active {\n  transform: translateY(0);\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .22);\n}\n\nbutton[disabled] {\n  opacity: .6;\n  cursor: not-allowed;\n}\n\n/* Secondary link under button (e.g., “Clear form”) */\n.clear-link {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  margin-top: 10px;\n  font-size: var(--font-size-link);\n  color: var(--color-link);\n  text-decoration: none;\n}\n.clear-link:hover { text-decoration: underline; }\n\n/* ===== Footer / “Automated with n8n” ===== */\n.form-footer {\n  margin: 10px auto 24px;\n  max-width: var(--container-width);\n  text-align: center;\n  color: var(--color-link);\n  font-size: var(--font-size-link);\n}\n\n/* ===== Responsive ===== */\n@media (max-width: 520px) {\n  .container, .form-wrapper, .n8n-form {\n    margin: 20px auto;\n    padding: 0 10px;\n  }\n  .form-card { padding: 20px; }\n  .form-card h1, h1.form-title { font-size: 18px; }\n  .form-subtitle { font-size: 13px; }\n}\n\n/* ===== Optional: Dark mode (auto) ===== */\n@media (prefers-color-scheme: dark) {\n  body {\n    background:\n      radial-gradient(1200px 800px at 10% -10%, #272a33 0%, transparent 60%),\n      radial-gradient(1000px 700px at 110% 0%, #2c2433 0%, transparent 55%),\n      #16181d;\n    color: #d8dbe3;\n  }\n\n  .test-notice {\n    background: #2a2115;\n    border-color: #3a2b18;\n    color: #ffce74;\n  }\n\n  .form-card {\n    background: #1c1f27;\n    border-color: #2a2f3a;\n    box-shadow: 0 8px 24px rgba(0,0,0,.35);\n  }\n\n  .form-card h1, h1.form-title { color: #e9ebf3; }\n  .form-subtitle { color: #a6adbb; }\n\n  input, textarea, select {\n    background: #11151c;\n    border-color: #2a2f3a;\n    color: #d8dbe3;\n  }\n  input:hover, textarea:hover, select:hover { border-color: #3a4250; }\n  input:focus, textarea:focus, select:focus {\n    border-color: #b7a8ff;\n    box-shadow: 0 0 0 4px rgba(183,168,255,.18);\n  }\n\n  .help-text { color: #9aa3b2; }\n\n  button[type=\"submit\"],\n  .button-submit {\n    box-shadow: 0 10px 26px rgba(255,109,90,.34);\n  }\n\n  .form-footer { color: #9aa3b2; }\n}"
        },
        "operation": "completion",
        "completionTitle": "Request sent for your manager’s approval",
        "completionMessage": "Soon you will receive a response on whether your request has been approved."
      },
      "typeVersion": 2.3
    },
    {
      "id": "cbb41697-dee5-40d1-9ae9-1618e0da91c2",
      "name": "多表:您可以连接多个表以实现有组织的数据结构",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        2544,
        400
      ],
      "parameters": {
        "jsonSchemaExample": "{\n\t\"email_text\": \"California\",\n\t\"sanitized_request\": \"request\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "eec5a816-c41b-4d53-80b5-0d73ffe7c92f",
      "name": "通知已批准请求",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4480,
        80
      ],
      "webhookId": "1dcd89a1-1c9d-4fa2-a91d-a18dc99ea559",
      "parameters": {
        "sendTo": "={{ $('Data and message').item.json.employee.email }}",
        "message": "=Dear {{ $('Data and message').item.json.employee.name }},\n\nYour request for the following item(s) has been approved and forwarded to the Procurement Department:\n\n{{ $('Data and message').item.json.output.sanitized_request }}\n\nThe purchasing team will proceed with the necessary steps and contact you if additional details are required.\n\nBest regards,  \nEquipment request AI\n",
        "options": {},
        "subject": "Equipment Request Approved",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "cyXtSoIVe4Tw1W50",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "1b39aac6-8136-4f70-b59b-df0dd81bbcd9",
      "name": "通知已拒绝请求",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4480,
        416
      ],
      "webhookId": "1dcd89a1-1c9d-4fa2-a91d-a18dc99ea559",
      "parameters": {
        "sendTo": "={{ $('Data and message').item.json.employee.email }}",
        "message": "=Dear {{ $('Data and message').item.json.employee.name }},\n\nYour request for the following item(s) has been approved and forwarded to the Procurement Department:\n\n{{ $('Data and message').item.json.output.sanitized_request }}\n\nThe purchasing team will proceed with the necessary steps and contact you if additional details are required.\n\nBest regards,  \nEquipment request AI\n",
        "options": {},
        "subject": "Equipment Request Approved",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "cyXtSoIVe4Tw1W50",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "ff97d6fb-ede9-4cfb-bf37-080fba03ead8",
      "name": "OpenAI 聊天模型1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2304,
        880
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-nano",
          "cachedResultName": "gpt-4.1-nano"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "zwivGqRORUgpjepY",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d8260916-6491-4b73-94cc-7bf1e8e0e42c",
      "name": "结构化输出解析器1",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        2528,
        880
      ],
      "parameters": {
        "jsonSchemaExample": "{\n\t\"email_text\": \"California\",\n\t\"sanitized_request\": \"request\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "f5d570f0-16f8-4610-8484-5d8338a95cae",
      "name": "创建请求消息",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2336,
        736
      ],
      "parameters": {
        "text": "=Employee request:\n\n{{ $json['What would you like to request?'] }}\n",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=You are a writing assistant.  \nYou will receive an equipment/item request.  \nYour tasks are:  \n1. Sanitize the request (fix grammar, remove unnecessary words, strange characters, or informal language).  \n2. Rewrite it into a clear, professional, and polite approval request message to a manager.  \n3. Output the result as a valid JSON object containing both the improved request and the full e-mail text.  \n\nKeep the tone formal, concise, and business-appropriate.  \nDo not invent information; only improve grammar, clarity, and tone.  \n\nFormat strictly as JSON, like this:\n\n{\n  \"sanitized_request\": \"[sanitized and improved version of the request]\",\n  \"email_text\": \"Dear {{ $json.manager.name }},\\n\\nPlease approve the procurement of [sanitized_request] for employee {{ $json.employee.name }} (Enrollment: {{ $json.employee.enrollment_number }}).\\n\\nThank you for your attention to this request.\\n\\nBest regards,\\nEquipment request AI\"\n}\n\nEmployee data:\nEnrollment: {{ $json.employee.enrollment_number }}\nName: {{ $json.employee.name }}\nEmail: {{ $json.employee.email }}\n\nManager data:\nName: {{ $json.manager.name }}\nEmail: {{ $json.manager.email }}\n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "7c273ebb-019b-4eed-ba76-254437904b2f",
      "name": "OpenAI 聊天模型2",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        4832,
        416
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-nano",
          "cachedResultName": "gpt-4.1-nano"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "zwivGqRORUgpjepY",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d7f6d4ff-5c14-46bd-8f88-57fbe9999058",
      "name": "结构化输出解析器2",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        5088,
        416
      ],
      "parameters": {
        "jsonSchemaExample": "{\n\t\"email_text\": \"California\",\n\t\"sanitized_request\": \"request\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "bd8d035b-b0da-46c6-9c8b-1712095f6df0",
      "name": "创建已批准请求消息",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        4880,
        256
      ],
      "parameters": {
        "text": "=Employee request:\n\n{{ $('Data and message').item.json['What would you like to request?'] }}\n",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=You are a writing assistant.  \nYou will receive an equipment/item request that has already been approved by the employee’s manager.  \nYour tasks are:  \n1. Sanitize the request (fix grammar, remove unnecessary words, strange characters, or informal language).  \n2. Rewrite it into a clear, professional, and polite procurement request e-mail addressed to the Purchasing Department.  \n3. Explicitly state in the message that the request was approved by the employee’s manager.  \n4. Output the result as a valid JSON object containing both the improved request and the full e-mail text.  \n\nKeep the tone formal, concise, and business-appropriate.  \nDo not invent information; only improve grammar, clarity, and tone.  \n\nFormat strictly as JSON, like this:\n\n{\n  \"sanitized_request\": \"[sanitized and improved version of the request]\",\n  \"email_text\": \"Dear Purchasing Department,\\n\\nPlease proceed with the procurement of [sanitized_request] for employee {{ $('Data and message').item.json.employee.name }} (Enrollment: {{ $('Data and message').item.json.employee.enrollment_number }}). This request has been reviewed and approved by the manager {{ $('Data and message').item.json.manager.name }}.\\n\\nThank you for your attention to this request.\\n\\nBest regards,\\nEquipment request AI\"\n}\n\nEmployee data:  \nEnrollment: {{ $('Data and message').item.json.employee.enrollment_number }}  \nName: {{ $('Data and message').item.json.employee.name }}  \nEmail: {{ $('Data and message').item.json.employee.email }}  \n\nManager data:  \nName: {{ $('Data and message').item.json.manager.name }}  \nEmail: {{ $('Data and message').item.json.manager.email }}  \n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "c4896c62-35a5-4c34-b97f-0c28a9aa5225",
      "name": "发送已批准请求至采购部门",
      "type": "n8n-nodes-base.noOp",
      "position": [
        5440,
        256
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "7374c685-d578-4b89-a730-21f12c1e3168",
      "name": "发送请求至采购部门",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2880,
        736
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9f0e9bdd-d1ee-480c-8808-624dfbb661bf",
      "name": "结束经理请求",
      "type": "n8n-nodes-base.form",
      "position": [
        3360,
        736
      ],
      "webhookId": "912c0497-44a9-4c79-9824-a3c7d4611177",
      "parameters": {
        "options": {
          "customCss": "/* ===== Base layout ===== */\nhtml, body {\n  height: 100%;\n  font-family: var(--font-family);\n  font-weight: var(--font-weight-normal);\n  font-size: var(--font-size-body);\n  background:\n    radial-gradient(1200px 800px at 10% -10%, #f0f2ff 0%, transparent 60%),\n    radial-gradient(1000px 700px at 110% 0%, #fef3f0 0%, transparent 55%),\n    var(--color-background);\n  color: var(--color-html-text);\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.container, .form-wrapper, .n8n-form {\n  max-width: var(--container-width);\n  margin: 32px auto;\n  padding: 0 12px;\n}\n\n/* ===== Test banner (top) ===== */\n.test-notice {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  margin: 0 auto 12px;\n  max-width: var(--container-width);\n  background: var(--color-test-notice-bg);\n  border: 1px solid var(--color-test-notice-border);\n  color: var(--color-test-notice-text);\n  padding: var(--padding-test-notice-vertical) var(--padding-test-notice-horizontal);\n  border-radius: var(--border-radius-input);\n  font-size: var(--font-size-test-notice);\n}\n\n/* ===== Card ===== */\n.form-card {\n  background: var(--color-card-bg);\n  border: 1px solid var(--color-card-border);\n  border-radius: var(--border-radius-card);\n  box-shadow: var(--box-shadow-card);\n  padding: var(--padding-card);\n  margin-bottom: var(--margin-bottom-card);\n}\n\n/* ===== Headings & subtitle ===== */\n.form-card h1,\nh1.form-title {\n  font-size: var(--font-size-header);\n  color: var(--color-header);\n  margin: 4px 0 6px;\n  font-weight: var(--font-weight-bold);\n  letter-spacing: -0.2px;\n}\n\n.form-subtitle {\n  font-size: var(--font-size-paragraph);\n  color: var(--color-header-subtext);\n  margin: 0 0 16px;\n  line-height: 1.5;\n}\n\n/* ===== Form fields ===== */\n.form-field {\n  display: grid;\n  gap: 6px;\n  margin-bottom: 14px;\n}\n\n.form-field label {\n  font-size: var(--font-size-label);\n  color: var(--color-label);\n  font-weight: 600;\n}\n\n.form-field label .required {\n  color: var(--color-required);\n  margin-left: 2px;\n}\n\n/* Inputs / selects / textareas */\ninput[type=\"text\"],\ninput[type=\"email\"],\ninput[type=\"number\"],\ninput[type=\"search\"],\ntextarea,\nselect {\n  width: 100%;\n  appearance: none;\n  border: 1px solid var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  font-size: var(--font-size-input);\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n  opacity: var(--opacity-placeholder);\n}\n\n/* Hover / focus */\ninput:hover,\ntextarea:hover,\nselect:hover {\n  border-color: #cfd5e2;\n}\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n  outline: none;\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* Invalid */\n.is-invalid,\ninput[aria-invalid=\"true\"],\ntextarea[aria-invalid=\"true\"],\nselect[aria-invalid=\"true\"] {\n  border-color: var(--color-error);\n  box-shadow: 0 0 0 4px rgba(234, 31, 48, .12);\n}\n\n/* Help / error text */\n.help-text {\n  font-size: 12px;\n  color: var(--color-link);\n}\n\n.error-text {\n  font-size: var(--font-size-error);\n  color: var(--color-error);\n  margin-top: 4px;\n}\n\n/* ===== File input (custom) ===== */\n.input-file {\n  position: relative;\n}\n\n.input-file input[type=\"file\"] {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  cursor: pointer;\n}\n\n.input-file .file-ui {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 10px;\n  border: 1px dashed var(--color-input-border);\n  border-radius: var(--border-radius-input);\n  padding: 12px 14px;\n  color: var(--color-input-text);\n  background: #fff;\n  transition: border-color .15s ease, box-shadow .15s ease;\n}\n\n.input-file .file-ui:hover {\n  border-color: #cfd5e2;\n}\n\n.input-file .file-ui:has(+ input[type=\"file\"]:focus) {\n  border-color: var(--color-focus-border);\n  box-shadow: 0 0 0 4px rgba(90, 76, 194, .12);\n}\n\n/* ===== Checkboxes / radios (accessible but nicer) ===== */\ninput[type=\"checkbox\"], input[type=\"radio\"] {\n  accent-color: var(--color-focus-border);\n  width: var(--checkbox-size);\n  height: var(--checkbox-size);\n}\n\n/* ===== Buttons ===== */\n.actions,\n.form-actions {\n  margin-top: 8px;\n}\n\nbutton[type=\"submit\"],\n.button-submit {\n  width: 100%;\n  height: var(--submit-btn-height);\n  background: var(--color-submit-btn-bg);\n  color: var(--color-submit-btn-text);\n  border: 1px solid transparent;\n  border-radius: var(--border-radius-input);\n  font-size: 15px;\n  font-weight: 700;\n  letter-spacing: .2px;\n  cursor: pointer;\n  transition: transform .05s ease, filter .15s ease, box-shadow .15s ease;\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .25);\n}\n\nbutton[type=\"submit\"]:hover {\n  filter: brightness(0.98);\n  transform: translateY(-1px);\n  box-shadow: 0 8px 24px rgba(255, 109, 90, .28);\n}\n\nbutton[type=\"submit\"]:active {\n  transform: translateY(0);\n  box-shadow: 0 6px 18px rgba(255, 109, 90, .22);\n}\n\nbutton[disabled] {\n  opacity: .6;\n  cursor: not-allowed;\n}\n\n/* Secondary link under button (e.g., “Clear form”) */\n.clear-link {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  margin-top: 10px;\n  font-size: var(--font-size-link);\n  color: var(--color-link);\n  text-decoration: none;\n}\n.clear-link:hover { text-decoration: underline; }\n\n/* ===== Footer / “Automated with n8n” ===== */\n.form-footer {\n  margin: 10px auto 24px;\n  max-width: var(--container-width);\n  text-align: center;\n  color: var(--color-link);\n  font-size: var(--font-size-link);\n}\n\n/* ===== Responsive ===== */\n@media (max-width: 520px) {\n  .container, .form-wrapper, .n8n-form {\n    margin: 20px auto;\n    padding: 0 10px;\n  }\n  .form-card { padding: 20px; }\n  .form-card h1, h1.form-title { font-size: 18px; }\n  .form-subtitle { font-size: 13px; }\n}\n\n/* ===== Optional: Dark mode (auto) ===== */\n@media (prefers-color-scheme: dark) {\n  body {\n    background:\n      radial-gradient(1200px 800px at 10% -10%, #272a33 0%, transparent 60%),\n      radial-gradient(1000px 700px at 110% 0%, #2c2433 0%, transparent 55%),\n      #16181d;\n    color: #d8dbe3;\n  }\n\n  .test-notice {\n    background: #2a2115;\n    border-color: #3a2b18;\n    color: #ffce74;\n  }\n\n  .form-card {\n    background: #1c1f27;\n    border-color: #2a2f3a;\n    box-shadow: 0 8px 24px rgba(0,0,0,.35);\n  }\n\n  .form-card h1, h1.form-title { color: #e9ebf3; }\n  .form-subtitle { color: #a6adbb; }\n\n  input, textarea, select {\n    background: #11151c;\n    border-color: #2a2f3a;\n    color: #d8dbe3;\n  }\n  input:hover, textarea:hover, select:hover { border-color: #3a4250; }\n  input:focus, textarea:focus, select:focus {\n    border-color: #b7a8ff;\n    box-shadow: 0 0 0 4px rgba(183,168,255,.18);\n  }\n\n  .help-text { color: #9aa3b2; }\n\n  button[type=\"submit\"],\n  .button-submit {\n    box-shadow: 0 10px 26px rgba(255,109,90,.34);\n  }\n\n  .form-footer { color: #9aa3b2; }\n}\n"
        },
        "operation": "completion",
        "completionTitle": "Request sent to the purchasing department",
        "completionMessage": "Your request has already been forwarded to the purchasing department."
      },
      "typeVersion": 2.3
    },
    {
      "id": "2411f09c-2392-48d2-83a4-3ce0d087b8ea",
      "name": "发送待批准请求",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3696,
        272
      ],
      "webhookId": "dde2b15d-a1d9-462b-ae23-f0eb024319c2",
      "parameters": {
        "sendTo": "={{ $('Data and message').item.json.manager.email }}",
        "message": "={{ $('Data and message').item.json.output.email_text }}",
        "options": {},
        "subject": "=Equipment Request Approval – {{ $('Data and message').item.json.employee.name }} (Enrollment:{{ $('Data and message').item.json.employee.enrollment_number }})",
        "operation": "sendAndWait",
        "approvalOptions": {
          "values": {
            "approvalType": "double"
          }
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "cyXtSoIVe4Tw1W50",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "4f63e8a7-04d8-491d-acea-1a46108182dc",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -1056
      ],
      "parameters": {
        "width": 1072,
        "height": 544,
        "content": "## 设备请求 — 批准与采购流程"
      },
      "typeVersion": 1
    },
    {
      "id": "13f364a2-b86e-4283-8fce-fa11e3e3d5f7",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -336
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 400,
        "content": "收集员工工号。"
      },
      "typeVersion": 1
    },
    {
      "id": "d35815c9-44fb-465e-b2a0-19badd10711c",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -128,
        -336
      ],
      "parameters": {
        "color": 5,
        "width": 416,
        "height": 400,
        "content": "在 `employees` 中按 enrollment_number 查找员工。"
      },
      "typeVersion": 1
    },
    {
      "id": "8a81d631-b8dd-4772-8bde-24d698b73074",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        304,
        -336
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 400,
        "content": "检查数据库查找是否返回空。"
      },
      "typeVersion": 1
    },
    {
      "id": "bb7851a9-a5cc-414f-bd1b-bae07fb2af89",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        624,
        -528
      ],
      "parameters": {
        "color": 5,
        "width": 304,
        "height": 368,
        "content": "当无法匹配工号时的用户面向消息。"
      },
      "typeVersion": 1
    },
    {
      "id": "1b55d378-cdd2-44a3-a71a-7b5421bd4cb6",
      "name": "便签5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        624,
        -144
      ],
      "parameters": {
        "color": 5,
        "width": 304,
        "height": 400,
        "content": "规范化员工对象供后续节点使用:"
      },
      "typeVersion": 1
    },
    {
      "id": "f28a39e9-3817-410c-bf68-949bebc16b3f",
      "name": "便签6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        -144
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 368,
        "content": "分支:"
      },
      "typeVersion": 1
    },
    {
      "id": "1d511e50-b193-432f-8115-d8171790948f",
      "name": "便签7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        -144
      ],
      "parameters": {
        "color": 5,
        "width": 304,
        "height": 368,
        "content": "通过 `id = employee.manager` 从 `employees` 获取经理记录。"
      },
      "typeVersion": 1
    },
    {
      "id": "b00441ed-2399-485f-a129-1fb0e60cba0f",
      "name": "便签8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        -144
      ],
      "parameters": {
        "color": 5,
        "width": 304,
        "height": 368,
        "content": "将经理行包装为单个 `manager` 对象以便访问。"
      },
      "typeVersion": 1
    },
    {
      "id": "66ac3153-bab7-4ad1-a878-9105a390b060",
      "name": "便签9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        -144
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 368,
        "content": "在数据库查找后合并员工和经理流。"
      },
      "typeVersion": 1
    },
    {
      "id": "50a8c7f3-a77e-4daa-942e-a98af2ff699a",
      "name": "便签 10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        304
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 400,
        "content": "询问员工想要请求什么(自由文本)。"
      },
      "typeVersion": 1
    },
    {
      "id": "6f027668-fc90-4824-9858-09b48e3ceade",
      "name": "便签 11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        320
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 368,
        "content": "将员工上下文和自由文本请求合并为一个有效载荷。"
      },
      "typeVersion": 1
    },
    {
      "id": "7ff2a7ab-94b6-48ca-82d5-0c09ed386233",
      "name": "便签12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        320
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 368,
        "content": "简单门控:"
      },
      "typeVersion": 1
    },
    {
      "id": "d15fafb7-c9a3-4cc2-aa85-be88371d809f",
      "name": "便签13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2224,
        48
      ],
      "parameters": {
        "color": 5,
        "width": 464,
        "height": 480,
        "content": "提示 LLM:"
      },
      "typeVersion": 1
    },
    {
      "id": "15864539-f1ae-45ed-ae6f-a7fa57bc6507",
      "name": "便签14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2704,
        48
      ],
      "parameters": {
        "color": 5,
        "width": 336,
        "height": 480,
        "content": "将清理后的输出与员工/经理上下文合并供邮件节点使用。"
      },
      "typeVersion": 1
    },
    {
      "id": "23d85284-cddc-4070-9d55-ff137832fcad",
      "name": "便签15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3056,
        48
      ],
      "parameters": {
        "color": 3,
        "width": 464,
        "height": 448,
        "content": "在\"需要批准\"路径中提交后请求者的最终屏幕。"
      },
      "typeVersion": 1
    },
    {
      "id": "2a5c9acd-e1b9-4682-afac-6b326a417a11",
      "name": "便签16",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3536,
        48
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 448,
        "content": "向经理发送带有 `email_text` 的邮件并等待批准/拒绝(双重批准)。"
      },
      "typeVersion": 1
    },
    {
      "id": "2d6051aa-aa42-47c4-9204-170113ee1765",
      "name": "请求批准了吗?",
      "type": "n8n-nodes-base.if",
      "position": [
        4080,
        272
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "bc6a5fcf-a316-48b6-88cf-d6e24b9a37f0",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "176cba48-2ecf-4b7d-b511-a6a8ad28dd5b",
      "name": "便签17",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3968,
        48
      ],
      "parameters": {
        "color": 6,
        "width": 352,
        "height": 448,
        "content": "根据经理的决定路由:"
      },
      "typeVersion": 1
    },
    {
      "id": "0c768e9a-d02d-4cfe-bb67-133b990d5e9c",
      "name": "便签18",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4336,
        -96
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 336,
        "content": "Sends a confirmation to the employee that the request was approved\nand forwarded to Procurement.\n\nCustomize copy for your internal SLA.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "6b4f3045-856b-4727-8fd5-e631bcf64852",
      "name": "便签19",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4336,
        256
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 336,
        "content": "Informs the employee that the manager denied the request.\nConsider including a short re-submission instruction.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5ee6d466-de66-4cc8-ac37-3e5ccc10618f",
      "name": "便签20",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4768,
        64
      ],
      "parameters": {
        "color": 5,
        "width": 464,
        "height": 480,
        "content": "Generates the Procurement email for an APPROVED request.\nExplicitly states the manager’s approval in the text.\n\nReturns JSON: { sanitized_request, email_text }.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c1da8b91-d925-496e-82b7-625c7483988c",
      "name": "便签21",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5248,
        64
      ],
      "parameters": {
        "color": 5,
        "width": 464,
        "height": 480,
        "content": "Replace this with your actual Procurement notifier:\n- Gmail node (to procurement@…),\n- Helpdesk ticket (Jira/Zendesk),\n- Slack/Teams message,\n- ERP API call.\n\nUse `email_text` from the approved message node.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5b155d25-a94e-4986-bd3d-626d1a4e8508",
      "name": "Sticky Note22",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2224,
        544
      ],
      "parameters": {
        "color": 5,
        "width": 464,
        "height": 480,
        "content": "For employees who are managers (no approval required):\n- Sanitizes the request,\n- Generates Procurement email (no approval mention).\n\nReturns JSON: { sanitized_request, email_text }.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "7c6efdbe-749e-4930-9a1a-d69765a0be0c",
      "name": "Sticky Note23",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2704,
        544
      ],
      "parameters": {
        "color": 5,
        "width": 464,
        "height": 480,
        "content": "Replace this with your actual Procurement notifier:\n- Gmail node (to procurement@…),\n- Helpdesk ticket (Jira/Zendesk),\n- Slack/Teams message,\n- ERP API call.\n\nUse `email_text` from the approved message node.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5ba873c7-8cc4-4b82-858e-720a5e899e2d",
      "name": "便签24",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3184,
        544
      ],
      "parameters": {
        "color": 3,
        "width": 464,
        "height": 448,
        "content": "Final screen when the requester is a manager:\n- Confirms it was directly forwarded to Procurement.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {
    "Question form": [
      {
        "json": {
          "formMode": "production",
          "submittedAt": "2025-09-18T11:10:33.897-03:00",
          "Your employee enrollment": "000001"
        }
      }
    ],
    "Get request information": [
      {
        "json": {
          "formMode": "production",
          "submittedAt": "2025-09-18T11:10:51.899-03:00",
          "What would you like to request?": "One mouse and keyboard"
        }
      }
    ],
    "Send request to approve": [
      {
        "json": {
          "data": {
            "approved": true
          }
        }
      }
    ]
  },
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "82bcb16a-4cec-4a22-b683-02337402ad3e",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Return Employee not found",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Employee data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Manager": {
      "main": [
        [
          {
            "node": "Set Manager field",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Employee": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Employee data": {
      "main": [
        [
          {
            "node": "Get request information",
            "type": "main",
            "index": 0
          },
          {
            "node": "Is approval required?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Question form": {
      "main": [
        [
          {
            "node": "Get Employee",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data and message": {
      "main": [
        [
          {
            "node": "End employee request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Create approval message",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Request approved?": {
      "main": [
        [
          {
            "node": "Notify approved request",
            "type": "main",
            "index": 0
          },
          {
            "node": "Create request approved message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify denied request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Manager field": {
      "main": [
        [
          {
            "node": "Employee and Manager",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Create request message",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "Create request approved message",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Employee and Manager": {
      "main": [
        [
          {
            "node": "Merge Employee data and request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "End employee request": {
      "main": [
        [
          {
            "node": "Send request to approve",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is approval required?": {
      "main": [
        [
          {
            "node": "Get Manager",
            "type": "main",
            "index": 0
          },
          {
            "node": "Employee and Manager",
            "type": "main",
            "index": 1
          }
        ],
        [
          {
            "node": "Merge Employee data and request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create request message": {
      "main": [
        [
          {
            "node": "Send request to the purchasing department",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create approval message": {
      "main": [
        [
          {
            "node": "Data and message",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Get request information": {
      "main": [
        [
          {
            "node": "Merge Employee data and request",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Send request to approve": {
      "main": [
        [
          {
            "node": "Request approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval request message": {
      "main": [
        [
          {
            "node": "Create approval message",
            "type": "main",
            "index": 0
          },
          {
            "node": "Data and message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create request message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Create approval message",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser1": {
      "ai_outputParser": [
        [
          {
            "node": "Create request message",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser2": {
      "ai_outputParser": [
        [
          {
            "node": "Create request approved message",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Create request approved message": {
      "main": [
        [
          {
            "node": "Send request approved to the purchasing department",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Employee data and request": {
      "main": [
        [
          {
            "node": "Approval request message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send request to the purchasing department": {
      "main": [
        [
          {
            "node": "End manager request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 内容创作, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量55
分类2
节点类型12
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Gabriel Santos

Gabriel Santos

@gabrielhmsantos

Enthusiastic developer passionate about automation and system integration. I work mainly with Python, RPA, and N8N, building workflows and custom solutions to optimize processes and connect platforms. Always learning, sharing, and exploring new ways to automate smarter.

外部链接
在 n8n.io 查看

分享此工作流