{
  "name": "apizt feishu 离线审核教学（n8n 2.42.3）",
  "active": false,
  "nodes": [
    {
      "parameters": {},
      "id": "feishu-trigger",
      "name": "手动开始",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const bundles = [{\"source\": {\"record_id\": \"DEMO-RECORD-A\", \"fields\": {\"原文\": [{\"type\": \"text\", \"text\": \"青禾台灯底座松动，\"}, {\"type\": \"text\", \"text\": \"请售后联系确认。\"}], \"输入版本\": 1}}, \"current\": {\"record_id\": \"DEMO-RECORD-A\", \"fields\": {\"原文\": \"青禾台灯底座松动，请售后联系确认。\", \"输入版本\": 1, \"处理状态\": \"待处理\"}}, \"model_output\": {\"summary\": \"青禾台灯底座松动，需要售后联系确认。\"}}, {\"source\": {\"record_id\": \"DEMO-RECORD-B\", \"fields\": {\"原文\": \"退款到账时间需要核对。\", \"输入版本\": 1}}, \"current\": {\"record_id\": \"DEMO-RECORD-B\", \"fields\": {\"原文\": \"退款已经到账。\", \"输入版本\": 2, \"处理状态\": \"待处理\"}}, \"model_output\": {\"summary\": \"需要核对退款到账时间。\"}}, {\"source\": {\"record_id\": \"DEMO-RECORD-C\", \"fields\": {\"原文\": \"申请修改收货地址。\", \"输入版本\": 1}}, \"current\": {\"record_id\": \"DEMO-RECORD-C\", \"fields\": {\"原文\": \"申请修改收货地址。\", \"输入版本\": 1, \"处理状态\": \"完成\", \"处理版本\": 1}}, \"model_output\": {\"summary\": \"申请修改收货地址。\"}}];\nreturn bundles.map((bundle) => ({json: bundle}));"
      },
      "id": "feishu-fixture",
      "name": "离线教学资料",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "function plainText(value) {\n  if (typeof value === \"string\") return value;\n  if (!Array.isArray(value) || value.some((part) => !part || part.type !== \"text\" || typeof part.text !== \"string\")) throw new Error(\"Expected a text field; attachment, person and link fields need their own mapping\");\n  return value.map((part) => part.text).join(\"\");\n}\n\nfunction prepareFeishuReview(bundles) {\n  if (!Array.isArray(bundles) || bundles.length > 100) throw new Error(\"Expected at most 100 record bundles\");\n  const seen = new Set();\n  return bundles.map(({ source, current, model_output }) => {\n    if (!source || typeof source.record_id !== \"string\" || !source.record_id.trim() || seen.has(source.record_id)) throw new Error(\"Missing or duplicate record_id\");\n    seen.add(source.record_id);\n    const text = plainText(source.fields?.[\"原文\"]);\n    const revision = source.fields?.[\"输入版本\"];\n    if (!Number.isSafeInteger(revision) || revision < 1 || !text.trim() || text.length > 4000) throw new Error(\"Invalid text or revision\");\n    const identity = { record_id: source.record_id, input_revision: revision };\n    if (!current || current.record_id !== source.record_id || current.fields?.[\"输入版本\"] !== revision || plainText(current.fields?.[\"原文\"]) !== text) return { ...identity, decision: \"stale\", write_allowed: false };\n    if (current.fields?.[\"处理状态\"] === \"完成\" && current.fields?.[\"处理版本\"] === revision) return { ...identity, decision: \"already_done\", write_allowed: false };\n    const result = typeof model_output === \"string\" ? JSON.parse(model_output) : model_output;\n    if (!result || Object.keys(result).sort().join(\",\") !== \"summary\" || typeof result.summary !== \"string\" || !result.summary.trim() || Array.from(result.summary).length > 100 || /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]/.test(result.summary)) throw new Error(\"Expected exactly one bounded summary\");\n    return { ...identity, fields: { \"AI摘要\": result.summary, \"处理状态\": \"待审核\", \"处理版本\": revision }, decision: \"awaiting_human\", write_allowed: false };\n  });\n}\n\nreturn prepareFeishuReview($input.all().map((item) => item.json)).map((json, index) => ({json, pairedItem: {item: index}}));"
      },
      "id": "feishu-guard",
      "name": "生成审核计划",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        560,
        0
      ]
    }
  ],
  "connections": {
    "手动开始": {
      "main": [
        [
          {
            "node": "离线教学资料",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "离线教学资料": {
      "main": [
        [
          {
            "node": "生成审核计划",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
