{"skill":{"slug":"forces-reanalyze-smart","displayName":"Forces Reanalyze Smart","summary":"完成智慧门店工单复盘全流程。触发词：工单复盘、复盘工单、拉取工单数据、创建复盘文档、工单分析、创建复盘。完整覆盖三个阶段：(1)拉取Furcas工单数据并导入多维表格 (2)创建/更新工单复盘总文档 (3)创建开发复盘文档并填充TOP5统计。当用户要求进行工单复盘时使用。","description":"---\nname: forces-reanalyze-smart\nversion: 1.0.2\ndescription: '完成智慧门店工单复盘全流程。触发词：工单复盘、复盘工单、拉取工单数据、创建复盘文档、工单分析、创建复盘。完整覆盖三个阶段：(1)拉取Furcas工单数据并导入多维表格 (2)创建/更新工单复盘总文档 (3)创建开发复盘文档并填充TOP5统计。当用户要求进行工单复盘时使用。'\n---\n\n# 智慧门店工单复盘全流程\n\n## 流程概览\n\n一次完整的工单复盘涉及 **3个文档**，按顺序执行：\n\n```\nStep 0：复盘跟踪表（前置检查）\n  检查/创建 目标月份记录 → 落数据基线\n\n阶段一：工单数据表（飞书多维表格）\n  Step 1 → Step 2 → Step 3 → Step 4 → Step 5 → Step 5b\n  解析月份 → 获取Cookie → 拉取Furcas数据 → 创建/复用月份bitable（模板：J4tawf06GijvEmkBTSCcdyNsnyd）→ 导入CSV → 更新mention-doc链接\n\n阶段二：工单复盘总文档（知识库文档）\n  Step 6 → Step 7\n  创建文档（模板：GEqawooPYiDXLWkRKZHcJnLcnFc）→ 填充变量\n\n阶段三：开发复盘文档（知识库文档）\n  Step 8\n  创建文档（模板：Secqwa7deiaRwTkUsG6cJ7xpnzj）→ 填充TOP5统计\n```\n\n## 关键链接\n\n| 类型 | 链接/Token |\n|------|-----------|\n| 工单数据Bitable模板 | `J4tawf06GijvEmkBTSCcdyNsnyd` (table: `tblXtjn9QHTcB5oa`, view: `vew8A2EB9c`) |\n| 复盘总文档模板 | `GEqawooPYiDXLWkRKZHcJnLcnFc` |\n| 开发复盘文档模板 | `Secqwa7deiaRwTkUsG6cJ7xpnzj` |\n| 复盘跟踪表（前置数据源） | `YMQjwQeWCipABCkl8y7ckZlunQe` (table: `tblpygt9n8dqZcsw`，参见 Step 0) |\n| Bot App ID | `cli_a97b6a0ffc399cc0` |\n\n---\n\n# ⚙️ 环境要求与配置\n\n## 运行时依赖\n\n使用此 skill 需要以下运行时环境（OpenClaw 标准环境已预装 Node.js）：\n\n| 依赖 | 用途 | 安装命令 |\n|------|------|---------|\n| Python 3 | 运行 fetch_furcas.py & generate_batches.py | 通常已预装 |\n| requests (Python) | Furcas API 调用 | `pip3 install requests` |\n| Node.js 18+ | 运行 import_to_bitable.mjs & fill_review_cells.cjs | 通常已预装 |\n\n## 环境变量说明\n\n> **这是此 skill 被其他人使用时最容易出错的部分。** 以下是所有脚本读取的环境变量：\n\n### 必须设置的环境变量\n\n| 环境变量 | 脚本 | 说明 |\n|---------|------|------|\n| `FURCAS_COOKIE` | `fetch_furcas.py` | Furcas 登录 Cookie。从 https://furcas.shouqianba.com 登录后 F12 → Network → 复制完整 Cookie 请求头 |\n| `SENDER_OPEN_ID` | `fill_review_cells.cjs` | 当前用户的飞书 open_id（每人不同）。格式 `ou_xxxxxxxx`。可从飞书开发者后台获取 |\n\n### 可选设置的环境变量\n\n| 环境变量 | 脚本 | 默认值 | 说明 |\n|---------|------|-------|------|\n| `FEISHU_UAT_DIR` | `import_to_bitable.mjs`, `fill_review_cells.cjs` | `$XDG_DATA_HOME/openclaw-feishu-uat` | OAuth 加密令牌存储目录。标准部署无需修改，特殊部署需指定 |\n| `APP_TOKEN` | `import_to_bitable.mjs` | （必填） | 工单数据多维表格的 app_token |\n| `TABLE_ID` | `import_to_bitable.mjs` | （必填） | 工单数据表的 table_id |\n| `CSV_PATH` | `import_to_bitable.mjs` | `/workspace/furcas.csv` | CSV 文件路径 |\n| `BATCH_SIZE` | `import_to_bitable.mjs` | `15` | 每批导入条数 |\n| `TABLE_NAME` | `import_to_bitable.mjs` | `工单数据` | 目标表名（用于校验） |\n| `APP_ID` | `fill_review_cells.cjs` | `cli_a97b6a0ffc399cc0` | Bot App ID（团队共用，通常无需修改） |\n| `DOC_ID` | `fill_review_cells.cjs` | （必填） | 要填充的复盘总文档 ID |\n| `MONTH` | `fill_review_cells.cjs` | （必填） | 目标月份标签，如 `2026-05` |\n\n## 首次使用前的准备\n\n1. **安装 Python 依赖**：运行一次 `pip3 install requests`\n2. **完成飞书 OAuth 授权**：执行 `clawhub install forces-reanalyze-smart` 后，按提示完成飞书授权\n3. **获取 Furcas Cookie**：登录 Furcas 后拷贝 Cookie\n4. **确认自己的 open_id**：在飞书开放平台获取或咨询管理员\n\n---\n\n# 前置步骤：复盘跟踪表\n\n## Step 0: 检查/创建跟踪表记录\n\n在创建任何文档之前，先检查复盘跟踪表是否已有目标月份的记录。\n\n### 跟踪表链接\n\n`https://sqb.feishu.cn/wiki/YMQjwQeWCipABCkl8y7ckZlunQe?table=tblpygt9n8dqZcsw&view=vewme7V2C9`\n\n- Bitable App Token: `YMQjwQeWCipABCkl8y7ckZlunQe`\n- Table ID: `tblpygt9n8dqZcsw`\n\n### ⚠️ 核心规则：必须先查存在，绝不复件\n\n> **这条规则是全局最高优先级。任何创建操作前必须先查，查到已存在则直接复用，绝不允许创建第二条同名记录。**\n\n### 操作步骤\n\n1. **查询已有记录（必须执行，不可跳过）**：\n\n```\n操作：feishu_bitable_app_table_record list\n参数：\n  app_token: \"YMQjwQeWCipABCkl8y7ckZlunQe\"\n  table_id: \"tblpygt9n8dqZcsw\"\n  filter: {\n    conjunction: \"and\",\n    conditions: [\n      {field_name: \"复盘范围\", operator: \"is\", value: [\"2026-05\"]}\n    ]\n  }\n```\n\n> **注意 field_name 必须用中文名「复盘范围」（是文本类型的主字段），不要用 field_id。**\n\n2. **判断是否已有目标月份**：\n   - ✅ **找到记录** → **立即停止创建流程**，直接使用已有记录的 `record_id` 及其包含的所有数据（工单总数、复盘工单数、各分类统计等），进入阶段一\n   - ❌ **没找到** → 执行第 3 步创建新记录\n\n   > **绝对禁止**：查到已有记录后，再创建第二条同名或同周期的记录。\n\n3. **新建记录**（仅在确认不存在时执行）：\n\n```\n操作：feishu_bitable_app_table_record create\n参数：\n  app_token: \"YMQjwQeWCipABCkl8y7ckZlunQe\"\n  table_id: \"tblpygt9n8dqZcsw\"\n  fields:\n    复盘范围: \"{月份标签}\"     // 整月如 \"2026-05\"（不要加 \"-整\" 后缀）\n    开始时间: {毫秒时间戳}     // 范围起始日期 00:00:00 UTC+8\n    结束时间: {毫秒时间戳}     // 范围结束日期 23:59:59 UTC+8\n    日期: {毫秒时间戳}         // 当前操作日期（执行复盘的当天）\n```\n\n### 字段说明\n\n| 字段 | 类型 | 填写规则 |\n|------|------|---------|\n| `复盘范围` | 文本 (主字段) | 整月：`2026-05`（**不要写** `2026-05-整`）；上半月：`2026-05-上`；下半月：`2026-05-下` |\n| `开始时间` | 日期（毫秒时间戳） | 范围起始日 `00:00:00 UTC+8`，如2026年5月整月 → `1777593600000`（对应 `2026-05-01T00:00:00+08:00`） |\n| `结束时间` | 日期（毫秒时间戳） | 范围结束日 `23:59:59 UTC+8`，如2026年5月整月 → `1780271999000`（对应 `2026-05-31T23:59:59+08:00`） |\n| `日期` | 日期（毫秒时间戳） | 当前操作日期，即执行复盘的当天，如2026年5月6日 → `1777910400000`（`2026-05-06T00:00:00+08:00`） |\n\n> ⏰ **时间戳必须二次确认**：创建记录后立即读取该记录，检查时间戳对应的年份是否与目标年份一致（2026年）。一个常见的错误是毫秒时间戳算成了2025年的日期。如果时间戳不对，删除该记录，重新计算并创建。\n\n> **注意**：其余字段（工单总数、复盘工单、超时工单数、各解决类别统计等）均为 Lookup/Formula 自动计算字段，无需手动填写，数据导入后会自行更新。\n\n### 创建后操作\n\n- ✅ 确认记录已成功创建\n- ✅ **读取刚创建的记录，验证时间戳是否对应正确的日期（2026年不是2025年）**\n- 记录下 `record_id`，后续阶段二填充文档第三节表格时需要\n- 进入阶段一，开始拉取工单数据\n\n---\n\n# 阶段一：工单数据表\n\n## Step 1: 解析用户意图\n\n用户说\"做X月工单复盘\"或\"复盘X月\"时：\n- 提取目标月份（如 `2026-04`）\n- 计算开始/结束日期：`2026-04-01` ~ `2026-04-30`\n- 记录月份标签：`2026-04`\n\n如果用户提到\"拉取X到X的工单数据\"，直接使用指定的起止日期。\n\n## Step 2: 获取 Cookie\n\n本阶段需要有效的 Furcas Cookie。\n\n1. 如果已有可用的 `FURCAS_COOKIE` 环境变量，直接使用\n2. 如果没有，引导用户：\n   - 登录 `https://furcas.shouqianba.com`\n   - F12 开发者工具 → Network → 复制完整的 Cookie 请求头\n   - 设置环境变量：`export FURCAS_COOKIE=\"完整Cookie值\"`\n\n> ⚠️ **不要**将 Cookie 硬编码写入脚本文件。这是个人凭据，每个使用者必须用自己的 Cookie。\n> 环境变量方式可在 session 级别临时设置，不会污染源代码，也便于他人使用。\n\n## Step 3: 拉取工单数据\n\n```bash\npython scripts/fetch_furcas.py -s \"2026-04-01\" -n \"2026-04-30\" -o /workspace/furcas.csv\n```\n\n输出字段：问题描述、问题链接、工单状态\\|修复情况、问题原因、责任人、解决类别、解决模块、超时时间、超时备注\n\n## Step 4: 创建/复用月份工单数据 Bitable\n\n⚠️ **必须检查**：先确认目标月份目录下是否已有同名 bitable。用 `feishu_wiki_space_node list` 列出目录内容，看是否已有工单数据表。如有则直接复用，跳过创建。\n\n### 正确创建方式（仅需一步）\n\n使用 `feishu_wiki_space_node copy` 将模板节点直接复制到目标月份目录：\n\n```\n操作：feishu_wiki_space_node copy\n参数：\n  node_token: \"J4tawf06GijvEmkBTSCcdyNynsd\"  // 工单数据表模板\n  space_id: \"7510046829784662017\"\n  target_parent_token: \"{目标月份目录节点token}\"\n  target_space_id: \"7510046829784662017\"\n```\n\n**为什么必须用 wiki node copy？**\n- ❌ `feishu_bitable_app copy` → 创建独立 bitable（不在 wiki 目录中）\n- ❌ `feishu_wiki_space_node create` → 创建空白 bitable（表名 \"Table\"，字段全英文）\n- ✅ `feishu_wiki_space_node copy` → 直接在 wiki 内创建模板副本，字段/视图全部正确\n\n### 复制后的处理\n\n1. **重命名**：bitable 名称 → `智慧门店-2026-5月工单数据`\n2. **删除模板空记录**：模板自带 5 条空记录（`fields: {}`），用 `batch_delete` 清空\n3. **验证字段结构**：应包含以下 9 个字段：\n   - `文本`（Text, primary）、`问题链接`（Url）、`工单状态|修复情况`（Text）、`问题原因`（Text）\n   - `责任人`（Text）、`解决类别`（SingleSelect）、`解决模块`（SingleSelect）\n   - `超时时间`（Text）、`超时备注`（Text）\n\n**关键约束**：\n- `工单状态|修复情况` 含竖线 `|`（CSV中为 `/`，脚本会自动映射）\n- `问题链接` 是 URL 类型，导入时用 `{\"link\": \"URL\", \"text\": \"查看工单\"}`\n- `责任人` 是文本类型（type=1），不是人员类型\n\n## Step 5: 导入数据到多维表格\n\n**推荐：使用导入脚本**\n\n```bash\nAPP_TOKEN={月份bitable的app_token} \\\nTABLE_ID={月份bitable的table_id} \\\nCSV_PATH=/workspace/furcas.csv \\\nBATCH_SIZE=15 \\\nnode scripts/import_to_bitable.mjs --name \"数据表\"\n```\n\n> ⚠️ **`--name` 参数必须传**：模板复制出来的表名叫 `数据表`，但脚本默认校验名为 `工单数据`。必须用 `--name \"数据表\"` 或 `TABLE_NAME=\"数据表\"` 让校验通过。不传的话校验会警告但不阻止导入。\n\n脚本自动：校验表名 → 清空旧数据 → 分批创建记录 → 创建看板视图 → 验证条目数 → **校验超时备注** → **去重检查**。\n\n> ⚠️ **`batch_delete` 参数名是 `record_ids`（不是 `records`）**：这是飞书 API 的规范。如果写错，清空静默失败，新数据追加到旧数据上，导致重复。\n\n> ⚠️ **去重检查是最后一道防线**：即使清空步骤因意外失败（如网络超时、API 限流），去重步骤也会自动删除重复工单，保证每个工单 ID 唯一。\n\n> ⚠️ **表名校验**：脚本在导入前会调用 API 读取目标表的实际名称，与 `TABLE_NAME` 环境变量比对。如果名称不匹配会给出警告，防止数据写入错误的表。\n\n**手动替代方案**：使用 `feishu_bitable_app_table_record` 工具 `action=batch_create`，records 参数用 `string=\"false\"`。\n\n---\n\n# 阶段二：工单复盘总文档\n\n## Step 5b: 更新文档 Mention-Doc 链接\n\n导入数据后，立即更新复盘总文档中的 mention-doc 链接，确保指向当前月份的正确表格和开发复盘文档。\n\n**为什么必须做：** 复盘总文档从模板复制后，mention-doc 链接指向的是模板的占位对象（如旧月份的表格或模板文档）。不更新的话，点击链接会看到错误的数据。\n\n### 更新步骤\n\n1. **获取复盘总文档的文档 ID**（从 step 6/7 创建或之前创建的文档获取）\n2. **找到 mention-doc 所在的 block**：\n   - 遍历文档根级 children，找到包含「月具体工单请查看飞书表格」文本的 block\n   - 该 block 是 type=2（text），其 elements[] 中包含 mention_doc 类型的 element\n3. **PATCH 更新该 block 的 elements**：\n   - `工单数据表 mention-doc`：token → 当前月份的 bitable token，obj_type → 8（bitable）\n   - `开发复盘文档 mention-doc`：token → 当前月份的 wiki 节点 token，obj_type → 16（wiki）\n   - **不写 text_run 的 content**（显示文本由文档标题决定）\n   - **obj_type 必须传整数**（8=bitable, 16=wiki），传字符串会报 `99992402`\n\n### 脚本参考\n\n```javascript\n// PATCH /docx/v1/documents/{docId}/blocks/{blockId}\n// Body: { update_text_elements: { elements: [originalElements] } }\n// 只改 mention_doc.token/obj_type/url，保持 text_run 不变\n```\n\n### 第 34 个经验（2026-05-07）：Mention-doc 更新后 token 被自动解析\n\n发送 wiki 节点 token 后，飞书 API 会自动解析为实际文档的 obj_token，类型也会从 wiki(16) 变为具体类型（如 docx=22, bitable=8）。修改后 fetch-doc 验证即可。\n\n## Step 6: 创建工单复盘总文档\n\n### 前置检查\n\n**在创建之前，先检查目标月度目录下是否已存在同名的文档。**\n\n使用 `feishu_wiki_space_node list` 列出月度目录下的所有节点。如果已有同名文档，直接进入 Step 7 更新即可，**不要重复创建**。\n\n### 创建步骤\n\n1. **复制模板**：从模板 `GEqawooPYiDXLWkRKZHcJnLcnFc` 复制创建新文档\n2. **重命名**：按月份命名，如 `智慧门店-2026-05月-工单复盘`\n3. **放入对应目录**：确认文档在正确的年度/月度知识库目录下\n\n复制文档的两种方式：\n- 使用 `feishu_wiki_space_node` 的 `copy` 操作（如果模板是 wiki 节点），传入 `space_id` 和 `target_parent_token`\n- 或用 `feishu_create_doc` 从模板创建（传入 wiki 节点 token）\n- 或用 `feishu_drive_file` 的 `copy` 操作\n\n## Step 7: 填充复盘总文档变量\n\n模板中有大量 `x` 占位符（橙色高亮），需要按以下规则替换为实际数据。\n\n### 模板结构要点（非常重要）\n\n**不要破坏模板原有的换行和段落结构。** 模板中每个变量的位置和间距都有意义。以下从实际模板 `GEqawooPYiDXLWkRKZHcJnLcnFc` 获取的精确结构：\n\n```\n# 一、会议信息\n会议主题：智慧门店-<text color=\"orange\">2026-</text><text color=\"orange\">10</text>月工单复盘\n会议时间：<text color=\"orange\">2026.05.07（周四） 16:00 - 16:30</text>\n\n# 二、会议议程\n**复盘时间：**<text color=\"orange\">**2026.05.07**</text>\n**复盘范围：**<text color=\"orange\">**2026.04.01 00:00:00-2026.04.30 23:59:59**</text>\n**参与人员：**\n- **开发：朱栋泉、**<text color=\"orange\">**李文茂(28)、付雷(12)、王佳明(10)、赵杭琪(9)**</text>\n- **产品：**\n- **测试：**\n- **技术支持：崔文思**\n- **运营：蒋达周**\n\n# 三、工单总计<text color=\"orange\">XX</text>个(按工单数统计)\n\n[Table: 10行×11列，3个月数据（2026-02/03/04），每33格一组=110格]\n⚠️ 2026-04 组（最近一个月）使用整体橙色格式，与 02/03 组的逐字橙色不同\n\n<text color=\"orange\">2026-04</text>月具体工单请查看飞书表格：<mention-doc token=\"J4tawf06GijvEmkBTSCcdyNynsd\" type=\"wiki\">2026-xx月-智慧门店工单数据</mention-doc>\n开发复盘文档：<mention-doc token=\"Secqwa7deiaRwTkUsG6cJ7xpnzj\" type=\"wiki\">开发复盘文档模板</mention-doc>\n\n# 四、工单总结\n## 工单数量分析\n- <text color=\"orange\">2026-04</text>月共产生工单<text color=\"orange\">646</text>个，本次复盘筛选出<text color=\"orange\">154</text>个工单。同比<text color=\"orange\">2026-03</text>月<text color=\"orange\">增加25.19%</text>\n- 从**解决类别**看，工单主要集中在：<text color=\"orange\">外部原因-无需技术排查(208)、设计如此-无需优化(160)、外部原因-需技术排查(81)</text>\n- 从**解决模块**看：工单主要集中在：<text color=\"orange\">收银系统-餐饮(197)、打印机(150)、扫码点单(117)</text>\n\n## 工单时效分析\n<text color=\"orange\">90</text>个超时工单（其中产研介入<text color=\"orange\">59</text>个），时效内解决占比<text color=\"orange\">84.67</text>%，较3月<text color=\"orange\">82%</text>有所提高。\n主要超时原因：\n\n## 问题总结\n立即更改内容跟进：\n同步客服&技术支持：\n\n# 五、历史跟进事项\n<text color=\"orange\">**2026-03**</text>**月跟进事项**：\n...\n<text color=\"orange\">**2026-02**</text>**月跟进事项**：\n...\n```\n\n#### 📌 模板关键位置标注\n| 位置 | 说明 |\n|------|------|\n| Section 3 标题 | `# 三、工单总计<text color=\"orange\">XX</text>个(按工单数统计)`，**无 callout 块** |\n| Section 3 末尾 | **Mention-doc**（工单数据表 bitable + 开发复盘文档 wiki） |\n| Section 4: 工单数量分析 | 含同比上月数据行 `<text color=\"orange\">同比...增加xx%</text>` |\n| Section 4: 工单时效分析 | `主要超时原因：`后为填空区域 |\n| Section 5 | 月份为「目标月-1」和「目标月-2」，如05月复盘则显示04和03月 |\n| 表格最后一组（最近月） | 使用整体橙色 `<text color=\"orange\">已解决x（产研介x）</text>` 格式，与前面两组不同 |\n\n#### 📌 Section 5 月份命名规则\n- 表头显示「目标月-1」和「目标月-2」的跟进事项\n- 例如：05月复盘 → 显示 `**2026-04**月跟进事项` 和 `**2026-03**月跟进事项`\n- 月份部分用橙色标签包裹：`<text color=\"orange\">**2026-03**</text>**月跟进事项**：`\n\n---\n\n### 🏷️ 命名规范（必须遵守）\n\n创建文档时**禁止直接使用模板的名称**。每次创建必须按以下规范重命名：\n\n| 文档类型 | 模板节点 | 创建后命名规范 | 示例（2026-05月） |\n|---------|---------|--------------|------------------|\n| 工单数据跟踪表（多维表格） | `J4tawf06GijvEmkBTSCcdyNynsd` | `智慧门店-2026-xx月-工单数据` | `智慧门店-2026-05月-工单数据` |\n| 工单复盘文档（知识库文档） | `GEqawooPYiDXLWkRKZHcJnLcnFc` | `智慧门店-2026-xx月-工单复盘` | `智慧门店-2026-05月-工单复盘` |\n| 开发复盘文档（知识库文档） | `Secqwa7deiaRwTkUsG6cJ7xpnzj` | `智慧门店-2026-xx月-开发复盘文档` | `智慧门店-2026-05月-开发复盘文档` |\n\n**重命名方式**（API 不支持，必须手工）：\n1. 复制模板创建文档后，在飞书页面打开\n2. 右键左侧目录树中的节点 → 选择「重命名」\n3. 按上表命名规范输入新名称\n4. 标题改完后，mention-doc 的显示文字会自动更新（因为 mention 显示的是文档实际标题）\n\n> ⚠️ Section 3 的表格是 `<lark-table>` 格式（带 rowspan/colspan 的复杂表格），**不能用 markdown 表格替代**。\n> 使用 `overwrite` 模式重写文档时，表格结构会丢失。因此 Section 3 必须保留原始 `<lark-table>` 代码。\n\n### ⚠️ ⚠️ ⚠️ 三大数据来源规则（必须遵守，不要再出错） ⚠️ ⚠️ ⚠️\n\n> **以下3条规则已经被用户多次重复强调。每次出错都会导致文档数据混乱。阅读此文件时请逐条仔细核对！**\n\n#### 规则1：参与人员 → 取开发复盘文档 TOP5\n\n**复盘总文档**中 `# 二、会议议程` → `参与人员：` → `开发：` 后面的橙色部分，必须填入**开发复盘文档 Section 2 中前5名责任人** 的姓名和工单数量。\n\n- 不要使用模板中的旧数据（如 `李文茂(28)、付雷(12)、王佳明(10)、赵杭琪(9)`）\n- 不要自行编造\n- 准确取本月的开发复盘文档中 Section 2 的5位开发人员及其工单数量\n- 格式：`李文茂(5)、蒋达周(3)、赵杭琪(2)、金海轩(2)、王金楠(2)`\n\n#### 规则2：工单总计 XX + 第三节表格 → 全部来自复盘跟踪表\n\n**模板中所有带 `x` 的数字占位符**（包括 Section 3 标题 `XX`、表格中所有 `x`）的填充值，必须全部从 **复盘跟踪表** Bitable 获取：\n\n```\n复盘跟踪表: https://sqb.feishu.cn/wiki/YMQjwQeWCipABCkl8y7ckZlunQe?table=tblpygt9n8dqZcsw\n```\n\n- **Section 3 标题** `三、工单总计XX个` → X 填复盘跟踪表中当月记录的 `工单总数` 字段\n- **表格数据** → 全部填复盘跟踪表中各月份的字段值\n- **表格顺序**：必须按时间从上到下排列，**新数据在下方**。例如做 5 月复盘时：\n  - 第一行（最上方）：2026-03（最旧）\n  - 第二行（中间）：2026-04\n  - 第三行（最下方）：2026-05（最新）\n  - **不要**把最新行放在最上面\n\n#### 规则3：Section 4 工单数量分析 + 工单时效分析 → 全部来自复盘跟踪表\n\n`# 四、工单总结` 下所有带数字的橙色文本，数据来源均为**复盘跟踪表**（不是工单数据表）：\n\n- `X月共产生工单X个` → 跟踪表 `工单总数`\n- `本次复盘筛选出X个工单` → 跟踪表 `复盘工单`\n- `同比上月增加/减少XX%` → 对比跟踪表中上月的 `工单总数`\n- `解决类别TOP3` → 跟踪表中各解决类别字段（`外部原因-无需技术排查`、`无需优化`、`外部原因-需技术排查` 等）\n- `解决模块TOP3` → 跟踪表中各模块字段（`收银系统-餐饮`、`扫码点单`、`打印机` 等）\n- **超时工单数/产研介入** → 跟踪表 `超时工单数`、`超时工单数-产研介入`\n- **时效内解决占比** → `1 - 超时工单数/工单总数 × 100%`\n\n---\n\n### 数据来源一览\n\n| 数据 | 来源 |\n|------|------|\n| 会议信息、议程 | 用户提供或从上月文档沿用 |\n| **参与人员（开发TOP5）** | **开发复盘文档 Section 2 的前5名责任人** |\n| **第三节标题 XX** | **复盘跟踪表 `工单总数`** |\n| **第三节表格（所有数字）** | **复盘跟踪表（全部字段）** |\n| **工单数量分析（所有数字）** | **复盘跟踪表** |\n| **工单时效分析（所有数字）** | **复盘跟踪表** |\n| 历史跟进事项 | 从上月复盘文档复制 |\n\n### 7.1 填充第三节表格\n\n使用 `scripts/fill_review_cells.cjs` 填充嵌套表格单元格。详细操作见 `references/data_mapping.md`。\n\n配置脚本顶部：\n```javascript\nconst DOC_ID = '...';  // 新创建的复盘总文档 ID\nconst MONTH = '2026-04';  // 目标月份\nconst CELL_DATA = {\n  total:    '644',\n  noOpt:    '160（产研介入94）',\n  prodOpt:  '42（20）',\n  techWork: '0',\n  techCheck:'79（48）',\n  noTech:   '208（28）',\n  internal: '138（产研介入87）',\n  solved:   '已解决54（27）',\n  deferred: '延期处理66（46）',\n  noRepro:  '无法重现：18（14）',\n  timeout:  '88（58）',\n};\n```\n\n执行：`node scripts/fill_review_cells.cjs`\n\n### 7.2 第三节表格：最近3个月数据\n\n模板中 `# 三、工单总计XX个(按工单数统计)` 下方自带一个 `<lark-table>` 格式的嵌套表格。此表格**必须保留**，不能删除或替换为文本。\n\n#### 表格内容规则\n\n表格内应填充**最近3次工单复盘的数据**（包含目标月份+前2个月）。例如做 2026-05 月复盘时，表格应包含：\n\n| 行 | 内容 |\n|----|------|\n| 第一行（表头） | 复盘范围、时间、工单总数等列名 |\n| 第一数据行（最旧） | 2026-03 数据（跟踪表记录） |\n| 第二数据行（中间） | 2026-04 数据（跟踪表记录） |\n| 第三数据行（最新，在最下方） | 2026-05 数据（跟踪表记录） |\n\n**⚠️ 顺序规则**：\n- 模板默认把最近月放在第一行（上方），但**正确顺序是旧数据在上、新数据在下**\n- 因此需要把模板的行标签和数据都修改过来。例如模板中的 `2026-02` 行应改为 `2026-03` 数据，`2026-03` 行改为 `2026-04` 数据，`2026-04` 行改为 `2026-05` 数据\n- 是的，需要把所有行的标签和数据都改一遍，不能偷懒只改一行\n\n#### 数据获取\n\n1. 从复盘跟踪表 `list` 全部记录\n2. 找到最近3个月的记录（按月份排序 `2026-05` / `2026-04` / `2026-03`）\n3. 提取各字段值：工单总数、复盘工单、超时工单数、无需优化、待产品优化、内部原因等\n\n#### 填充方式\n\n使用 `scripts/fill_review_cells.cjs` 逐个填充表格单元格。详细操作见 `references/data_mapping.md`。\n\n配置脚本顶部：\n```javascript\nconst DOC_ID = '...';  // 新创建的复盘总文档 ID\nconst MONTH = '2026-05';  // 目标月份（用于查找表格中的对应单元格）\nconst CELL_DATA = {\n  // 以下数据来自复盘跟踪表，key 见 data_mapping.md\n  total:    '21',\n  noOpt:    '11（产研介入7）',\n  prodOpt:  '0',\n  techWork: '0',\n  techCheck: '0',\n  noTech:   '0',\n  internal: '10（产研介入3）',\n  solved:   '已解决4（1）',\n  deferred: '延期处理6（2）',\n  noRepro:  '无法重现：0',\n  timeout:  '11（3）',\n};\n```\n\n如果目标月份在跟踪表中尚无数据（月未结束），表格中该行留空或填 \"-\"，用附注说明。\n\n#### 重要：表格数据来自复盘跟踪表\n\n复盘总文档第三节表格的数据**不直接来自工单数据表**，而是来自复盘跟踪表。跟踪表中各字段是 Lookup 公式，会自动根据 Step 0 创建的记录中的时间范围和已导入的工单数据计算汇总值。\n\n因此复盘的正常顺序是：\n1. **Step 0** → 创建跟踪表记录\n2. **阶段一** → 导入工单数据\n3. **之后** 跟踪表各 Lookup 字段会自动计算\n4. **Step 7** → 从跟踪表读取计算结果，填入第三节表格\n\n### 7.3 填充工单总结\n\n**⚠️ 所有数字均来自复盘跟踪表，不是工单数据表**\n\n模板中 Section 4 的每一条文本都有橙色标记的数字占位符。所有数值必须从**复盘跟踪表**获取，不能从刚导入的工单数据表（24条）统计。\n\n**工单数量分析**需要以下统计数据（全部来自复盘跟踪表 filter `复盘范围`=当月）：\n\n| 变量 | 跟踪表字段 | 取值方式 |\n|------|-----------|---------|\n| 当月工单总数 | `工单总数` | 直接取值 |\n| 复盘工单数 | `复盘工单` | 直接取值 |\n| 同比上月增减% | 对比上月 `工单总数` | `(本月-上月)/上月 × 100%` |\n| 解决类别TOP3 | `外部原因-无需技术排查`、`无需优化`、`待产品优化`、`外部原因-需技术排查` 等 | 按字段值排序取TOP3 |\n| 解决模块TOP3 | `收银系统-餐饮`、`扫码点单`、`打印机`、`收银系统-零售` 等 | 按字段值排序取TOP3 |\n\n**工单时效分析**需要（全部来自跟踪表）：\n| 变量 | 跟踪表字段 | 取值方式 |\n|------|-----------|---------|\n| 超时工单数 | `超时工单数` | 直接取值 |\n| 超时产研介入 | `超时工单数-产研介入` | 直接取值 |\n| 时效内解决占比% | `工单总数` + `超时工单数` | `(1 - 超时工单数/工单总数 × 100%)`，保留两位小数 |\n\n**获取方式**：`feishu_bitable_app_table_record list` 查询 `复盘范围` = 当月，然后从返回的 fields 中提取所需字段。\n\n**注意**：Section 4 的文本包含大量橙色标记（`<text color=\"orange\">`），无法通过简单的 `replace_range` 或 `selection_with_ellipsis` 更新（因为标记打断了文本连续性）。\n- 超时文本块（如 `25个超时工单`）可以通过 block PATCH 更新（type 2 块）\n- 列表项（type 12）和标题块（type 3）无法通过 block API 更新\n- 必须通过 `feishu_update_doc replace_all`（但会破坏 callout）或手动编辑\n\n**问题总结**和**历史跟进事项**从上月文档复制，或由用户填写。\n\n---\n\n# 阶段三：开发复盘文档\n\n## Step 8: 创建开发复盘文档\n\n### 前置检查\n\n**同样先检查目标月度目录下是否已有同名文档。** 使用 `feishu_wiki_space_node list` 确认后再操作。\n\n### 创建步骤\n\n1. **复制模板**：从 `Secqwa7deiaRwTkUsG6cJ7xpnzj` 复制创建\n2. **重命名**：按月份命名，如 `智慧门店-2026-05月-开发复盘文档`\n3. **放入对应目录**\n\n### ⚠️ 开发复盘文档需要修改/填充的内容（共3项，缺一不可！）\n\n**不要破坏模板原有的换行和段落结构。** 完整模板结构如下：\n\n```\n# 一、开发复盘文档\n- 工单复盘文档：<mention-doc token=\"...\" type=\"wiki\">智慧门店工单复盘模版</mention-doc>   ← 需修改 ①\n- 复盘表格内容：<mention-doc token=\"...\" type=\"wiki\">2026-xx月-智慧门店工单数据</mention-doc>   ← 需修改 ②\n\n# 二、主要人员总结材料\n<text color=\"orange\">开发A(</text>工单总数<text color=\"orange\">x</text>个)(超时工单<text color=\"orange\">x</text>个)   ← 需修改 ③\n[callout] ← 保持模板原样！不要改动！\n```\n\n---\n\n#### 修改① 替换「工单复盘文档」mention-doc\n\n**目标**：指向本次创建的复盘总文档 wiki 节点\n```\n{ mention_doc: { token: \"{复盘总文档的wiki节点token}\", obj_type: 16, // wiki\n  title: \"智慧门店-2026-05月-工单复盘\",\n  url: \"https://sqb.feishu.cn/wiki/{wiki节点token}\" } }\n```\n\n#### 修改② 替换「复盘表格内容」mention-doc\n\n**目标**：指向当前月份的工单数据 bitable\n```\n{ mention_doc: { token: \"{月份bitable的app_token}\", obj_type: 8, // bitable\n  title: \"智慧门店-2026-5月工单数据\",\n  url: \"https://sqb.feishu.cn/base/{app_token}?table={table_id}&view={view_id}\" } }\n```\n\n#### 修改③ 替换橙色高亮区的占位符（开发A~E 和 x）\n\n**这是最容易出错的地方！严格按照以下步骤：**\n\n1. 找到文档根 children 中的 **type 2 块**（5个，对应开发A~E）\n2. 对每个块的 elements，执行 3 个替换：\n\n| 位置 | 原来 | 改为 | 示例（李文茂） |\n|------|------|------|------|\n| 第一个 text_run | `开发A(` | `责任人姓名+（` | `李文茂(` |\n| 中间 text_run（内容为`x`） | `x` | 该人**工单总数** | `5` |\n| 末尾 text_run（内容为`x`） | `x` | 该人**超时工单数** | `4` |\n\n**元素结构参考**（以开发A为例，其余开发B~E结构相同但元素数可能不同）：\n```javascript\n// 开发A 的 elements（8个元素）：\n[ {text_run: \"开发A(\"},      // 改为人名\n  {text_run: \"工单总\"},        // 不动\n  {text_run: \"数\"},           // 不动\n  {text_run: \"x\"},           // 改为工单总数\n  {text_run: \"个\"},           // 不动\n  {text_run: \")(超时工单\"},    // 不动\n  {text_run: \"x\"},           // 改为超时工单数\n  {text_run: \"个)\"}           // 不动\n]\n\n// 开发B~E 的 elements（6个元素）：\n[ {text_run: \"开发X(\"},       // 改为人名\n  {text_run: \"工单总数\"},       // 不动\n  {text_run: \"x\"},            // 改为工单总数\n  {text_run: \"个)(超时工单\"},   // 不动\n  {text_run: \"x\"},            // 改为超时工单数\n  {text_run: \"个)\"}            // 不动\n]\n\n// 替换后效果：\n[ {text_run: \"李文茂(\"},\n  {text_run: \"工单总\"},\n  {text_run: \"数\"},\n  {text_run: \"5\"},           // 原来是 x\n  {text_run: \"个\"},\n  {text_run: \")(超时工单\"},\n  {text_run: \"4\"},           // 原来是 x\n  {text_run: \"个)\"}\n]\n```\n\n**✅ 最终橙色高亮区的效果**（模板 → 正确）：\n```\n<text color=\"orange\">开发A(</text>工单总数<text color=\"orange\">x</text>个)(超时工单<text color=\"orange\">x</text>个)\n   ↓ 替换为\n<text color=\"orange\">李文茂(</text>工单总数<text color=\"orange\">5</text>个)(超时工单<text color=\"orange\">4</text>个)\n```\n\n---\n\n### ❗ 绝对不要做的事（踩坑记录）\n\n| ❌ 错误 | 后果 |\n|---------|------|\n| 只替换数字 `x`，不把`开发A`改成责任人姓名 | 橙色区显示 \"开发A(工单总数5个)\" 而非 \"李文茂(工单总数5个)\" |\n| 把分析总结填入 callout 内容 | callout 应该保持模板占位符状态，留给用户手动填写 |\n| 写入多行文本到 callout 块（如 `工单原因分析：\\n1. xxx`） | 后续无法一次性清空，需要逐元素删除残留行 |\n| 用 `feishu_update_doc replace_all` 更新文档内容 | 会破坏 `<callout>` 块结构 |\n\n---\n\n### 责任人的选取规则\n- 从工单数据表（阶段一导入的）统计 TOP5 责任人\n- **排除** `崔文思` 和 `蒋达周`\n- 统计每个责任人：\n  - 工单总数：该责任人名下的工单数量\n  - 超时工单数：该责任人名下 `超时时间` 不为空的工单数\n\n**数据获取方式**：\n1. 从工单数据表 `list` 全部记录\n2. 按 `责任人` 字段分组计数\n3. 排除崔文思、蒋达周\n4. 取工单数最多的前5名\n5. 对每个负责人统计超时工单数\n\n**填充方式**：\n- 使用 UAT 调飞书 Docx PATCH API 逐元素更新，不要用 `feishu_update_doc`（会破坏 `<callout>` 块）\n- 通过 PATCH `update_text_elements` 替换橙色占位符的 `x`，保留 `<text color=\"orange\">` 样式\n- 模板已有5个开发者槽位（开发A-E），直接 PATCH 全部5个槽位的占位符，无需 POST 追加\n\n### 分析总结占位符\n\n每个责任人段落的 callout 区域包含需要用户填写的分析总结（无法自动生成）：\n```\n分析总结：\n超时工单分析：\n工单原因分析：\n需更改需跟进事项：\n需同步产品：\n需同步开发：\n需同步测试：\n需同步客服：\n需同步技术支持：\n其他：\n```\n\n在填充数据后告知用户这些区域需要手动填写。\n\n---\n\n# 脚本说明\n\n## `scripts/fetch_furcas.py`\n从 Furcas API 拉取数据。参数：`-s` 开始日期、`-n` 结束日期、`-o` 输出路径。\n\n## `scripts/import_to_bitable.mjs`\nCSV → 多维表格导入一体化脚本。环境变量：`APP_TOKEN`, `TABLE_ID`, `CSV_PATH`, `BATCH_SIZE`, `TABLE_NAME`。\n\n## `scripts/generate_batches.py`\nCSV → JSON 批处理文件。参数：`--csv`, `--output-dir`, `--batch-size`。\n\n## `scripts/fill_review_cells.cjs`\n填充复盘总文档第三节嵌套表格单元格。直接调飞书 Docx PATCH API，用用户 OAuth UAT。顶部配置区设置月份和数据。\n\n---\n\n# 注意事项\n\n## 通用\n\n1. **Cookie 时效性**：Furcas Cookie 可能过期，过期后需用户重新拷贝\n2. **导入长度限制**：batch_create 每批 ≤ 15 条\n3. **看板视图分组**：创建后需显式设置 `kanban_field_id`\n4. **表格嵌套单元格**：不能用 markdown flat table 替代，必须用 `fill_review_cells.cjs` 逐个填充\n5. **替换 `x` 变量**：开发复盘文档的 `<text color=\"orange\">x</text>` 占位符必须用 UAT PATCH API 逐元素更新（保留橙色样式），**禁止用 `feishu_update_doc replace_all`**（会破坏 `<callout>` 块）。复盘总文档的 `x` 同样用 PATCH API 更新。\n6. **责任人排除**：开发复盘 TOP5 统计需排除崔文思、蒋达周\n7. **文档排版**：从模板复制后，确认文档结构完整。当前模板（2026-05起）已无 callout 提示块，无需手动删除\n\n### 模板结构守则\n\n8. **永远不要合并或删除模板中的换行**。模板的每个段落、列表都是精心设计的结构。特别是：\n   - 会议信息的 `会议主题` / `会议时间` 各占一行\n   - 会议议程的 `**复盘时间：**` / `**复盘范围：**` / `**参与人员：**` 各自独立成段\n   - 参与人员列表用 `-` 无序列表格式\n   - 开发复盘文档的 callout 中每个冒号标题独占一行，`>` 前缀必须保留\n   - ⚠️ 复盘总文档模板（2026-05 版本）**已无 callout 块**，Section 3 标题后直接是 `<lark-table>`\n\n9. **`feishu_update_doc` 禁止用于含表格的文档**：复盘总文档的 Section 3 包含 `<lark-table>`，**任何模式（overwrite/replace_all/append/insert_after/replace_range/delete_range）都会摧毁表格属性**（rowspan、colspan 丢失，cols 数变化）。\n   - ❌ `feishu_update_doc` 会先序列化文档为 markdown 再反序列化，过程中 lark-table 的 HTML 属性丢失\n   - ✅ **所有更新必须使用 UAT Token 直接调飞书 PATCH blocks API，逐元素更新**\n   - ✅ 表格单元格：`PATCH /blocks/{cell_child_text_id}` 用 `update_text_elements`\n   - ✅ 文本段落：`PATCH /blocks/{block_id}` 用 `update_text_elements`\n\n10. **`feishu_update_doc` 禁止用于含 callout 块的文档**：开发复盘文档不含 lark-table，但含有 `<callout>` 块（type=19），feishu_update_doc 的 markdown 序列化/反序列化会：\n    - ❌ `<callout>` → `>` blockquote（结构被破坏，callout 框消失）\n    - ❌ `<text color=\"orange\">` → 普通文本（颜色标记丢失）\n    - ❌ 可能引入额外段落（如 `# 三、总结`）\n    - ✅ **正确做法：所有更新必须使用 UAT Token 直接调飞书 PATCH blocks API，逐元素更新**\n\n## 开发复盘文档填充经验\n\n11. **替换开发 A/B/C/D/E 标记**（模板现含5个槽位）：\n    - 模板使用 `<text color=\"orange\">开发A(</text>工单总数<text color=\"orange\">x</text>个)(超时工单<text color=\"orange\">x</text>个)`（B/C/D/E同理）\n    - 替换时搜索整个带标记的字符串，替换为 `**张姝（工单总数12个）（超时工单5个）**`\n    - 橙色标记在替换时自动去除，改用加粗（** **）\n\n12. **模板已有 5 个开发者槽位（开发A-E）**：最新模板 `Secqwa7deiaRwTkUsG6cJ7xpnzj` 已直接包含 5 组（开发A/B/C/D/E），每组含 `<text color=\"orange\">开发X(工单总数x个)(超时工单x个)</text>` + `<callout>` 块。\n    - 直接 PATCH 填满全部 5 个槽位即可（无需 POST 追加）\n    - TOP5 开发者按工单数从多到少填入开发A→E\n    - ❌ 模板只有3个槽位时（旧版），才需要 POST `/children` 追加开发D和E\n\n## 含表格文档的 PATCH API 更新（关键）\n\n### ⚠️ 核心规则：feishu_update_doc 不可用于含复杂表格的文档\n\n复盘总文档的 Section 3 包含 `<lark-table>`（带 rowspan/colspan），**feishu_update_doc 的任何模式（replace_all、insert_after、delete_range、replace_range、overwrite）都会摧毁表格属性**。\n\n原因：这些模式先将文档序列化为 markdown 再反序列化，反序列化时 lark-table 的 HTML 属性丢失。\n\n后果示例：\n- `cols=\"11\"` → `cols=\"10\"`（colspan=2 的合列丢失）\n- `rowspan=\"3\"` → 消失（每月 3 行不再合并）\n- 表格从 10 行 11 列 → 7 行 10 列\n\n### ✅ 正确做法：直接调飞书 Docx PATCH API\n\n```\nPATCH /open-apis/docx/v1/documents/{document_id}/blocks/{block_id}\nAuthorization: Bearer {user_access_token}\nBody: {\n  \"update_text_elements\": {\n    \"elements\": [{\n      \"text_run\": {\n        \"content\": \"新文本内容\",\n        \"text_element_style\": {}\n      }\n    }]\n  }\n}\n```\n\n⚠️ `update_text_elements` 会**丢失格式**（bold/orange）：新的 text_run 使用空的 `text_element_style: {}`，所以加粗、橙色标记等格式会丢失。如需保留格式，需在 `text_element_style` 中显式设置 `bold: {}` 或 `inline_code: {color: 25, background_color: 2}`（橙色）。\n\n### 更新顺序不可逆\n\n```\n模板拷贝 → 填表（fill_review_cells.cjs）→ 更新文本（PATCH API）\n                 ↑                 ↑\n           必须先做             后做\n```\n\n填表（表格单元格级别的 block 操作）必须在任何文本替换之前完成。如果先做文本替换再填表，feishu_update_doc 已经破坏了表格结构。\n\n### Block-type-specific 文本属性\n\n通过 PATCH API 读取/更新文本时，不同 block type 的文本存在不同属性中，不是都在 `block.text` 下：\n\n| Block Type | 描述 | 文本所在属性 |\n|-----------|------|------------|\n| 2 | 文本段落 | `block.text.elements` |\n| 3 | 标题1（#） | `block.heading1.elements` |\n| 4 | 标题2（##） | `block.heading2.elements` |\n| 5 | 标题3（###） | `block.heading3.elements` |\n| 12 | 无序列表项（-） | `block.bullet.elements` |\n| 14 | 有序列表项（1.） | `block.ordered.elements` |\n\n**PATCH API 写入统一使用 `update_text_elements`**，不分类型。\n\n### Heading 块可以有子节点\n\n飞书文档中，标题块（block_type=3/4/5）**可以有** 子 children（如 Section 4 的 `## 工单数量分析` 就包含 bullet 子节点）。Section 4 的文本不是根级节点，而是 heading 的 children：\n\n```javascript\n// Section 4 的数据需要遍历 heading 的 children 获取：\nconst rootBlocks = getChildren(document_block_id);\nfor (const b of rootBlocks) {\n  // b.block_type === 4 （heading2）\n  // b.txt === '工单数量分析'\n  const sectionKids = getChildren(b.block_id);  // ← ✅ 能拿到子节点\n  // sectionKids[0].block_type === 12 （bullet）\n  // sectionKids[0].txt === '2026-05月共产生工单81个...'\n}\n```\n\n**但是**：表格（type=31）和 callout（type=19）**不是**任何块的 children，它们始终是文档根层的同级节点。即使它们在视觉上位于某个 heading 下方，API 读取时它们和 heading 是平级关系。\n\n### 权限与加密\n\nPATCH API 需要 User Access Token（UAT），用 OAuth 方式获取。UAT 加密存储，解密方式：\n\n```javascript\nconst d = path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'), 'openclaw-feishu-uat');\nconst enc = fs.readFileSync(path.join(d, '{appId}_{userOpenId}.enc'));\nconst masterKey = fs.readFileSync(path.join(d, 'master.key'));\n// AES-256-GCM: IV 12 bytes + tag 16 bytes + ciphertext\nconst iv = enc.subarray(0, 12), tag = enc.subarray(12, 28), cipher = enc.subarray(28);\nconst decipher = crypto.createDecipheriv('aes-256-gcm', masterKey, iv);\ndecipher.setAuthTag(tag);\nconst uat = JSON.parse(Buffer.concat([decipher.update(cipher), decipher.final()]).toString('utf8')).accessToken;\n```\n\n### fill_review_cells.cjs 的使用\n\n位置：`scripts/fill_review_cells.cjs`\n\n配置方式（通过环境变量传入，不需要修改脚本）：\n```bash\n# 设置必要的环境变量\nexport DOC_ID=\"新文档的obj_token\"\nexport SENDER_OPEN_ID=\"ou_你的飞书open_id\"\nexport MONTH=\"2026-05\"\nexport APP_ID=\"cli_a97b6a0ffc399cc0\"  # 团队共用，通常已设为默认值\n\n# 运行脚本\nnode scripts/fill_review_cells.cjs\n```\n\n脚本中的 `CELL_DATA` 由 AI 根据复盘跟踪表数据自动生成并作为环境变量传入，请勿手动修改。\n\n脚本会自动填充**最近 3 个月**（本月 + 前 2 个月）的数据到表格中的对应位置。填写规则见 `references/data_mapping.md`。\n\n### 文本更新脚本参考\n\n```javascript\n// readText 必须检查所有 block-type 属性\nfunction readText(block) {\n  const src = block?.text || block?.heading1 || block?.heading2 || \n              block?.heading3 || block?.bullet || block?.ordered || block?.todo;\n  return src?.elements?.map(e => e.text_run?.content || '').join('') || '';\n}\n\n// 写入统一用 update_text_elements\nasync function patchBlock(uat, blockId, newText) {\n  const body = {\n    update_text_elements: {\n      elements: [{ text_run: { content: newText, text_element_style: {} } }]\n    }\n  };\n  const url = `${DOCX_BASE}/${DOC_ID}/blocks/${blockId}`;\n  return apiRetry('PATCH', url, { Authorization: `Bearer ${uat}` }, JSON.stringify(body));\n}\n```\n\n## UAT 与 API 调用\n\n13. **UAT 解密方式**：\n    - 加密目录路径（动态解析）：`$FEISHU_UAT_DIR` → `$XDG_DATA_HOME/openclaw-feishu-uat` → `~/.local/share/openclaw-feishu-uat`\n    - 加密文件：`{uatDir}/{appId}_{userOpenId}.enc`\n    - Master key：`{uatDir}/master.key`（**32 字节原始密钥，不需要 SHA256 哈希**）\n    - 解密算法：AES-256-GCM，IV 12 字节 + tag 16 字节 + ciphertext\n    - 解密后的 JSON 字段：`accessToken`（驼峰，不是 `access_token`）\n    - `import_to_bitable.mjs` 和 `fill_review_cells.cjs` 均已正确实现动态路径解析\n\n14. **mention-doc 的 token 解析**：\n    - 当用 `<mention-doc token=\"wiki节点token\" type=\"wiki\">` 时，飞书 API 会自动解析为实际文档的 obj_token\n    - type 也会自动更新（如 wiki → docx 或 bitable）\n    - 因此如果后续的 replace_all 索引用的原始 wiki token 找不到内容，很可能已被 API 自动替换\n    - 应在每次更新后重新 fetch-doc 确认实际内容\n\n## Import 脚本已知 bug\n\n15. **`import_to_bitable.mjs` 看板创建 bug**：\n    - `createKanbanView(\"按责任人分组\")` 创建的看板视图没有返回正确的 view_id（返回 undefined）\n    - 后续设置 `kanban_field_id` 时会因 `view_id=undefined` 而失败\n    - 变通方案：脚本跑完后，手动创建看板视图或用 UAT 调飞书 API PATCH `/views/{viewId}` 设置 `kanban_field_id`\n    - 正确字段 ID：`责任人` 的 field_id（可通过 list_fields 获取）\n\n16. **FIELD_MAP 硬编码**：CSV 列名 \"工单状态/修复情况\" → bitable 字段名 \"工单状态|修复情况\"（竖线）。如果 bitable 字段名用了斜杠，需要修改 FIELD_MAP 或重命名字段。\n\n17. **超时备注字段可能导入后为空（2026-05-15 发现）**：\n    - FIELD_MAP 包含 `\"超时备注\": \"超时备注\"` 映射\n    - `batch_create` 传入纯字符串 `\"崔文思->某人: 05-15 10:00；\"` 可以正确写入（已验证）\n    - `PUT` 传入纯字符串也可以正确写入（已用此方法补了19条）\n    - **但某些情况下数据会丢失**：猜测与 Cookie 切换后 CSV 列顺序或旧数据残留有关\n    - **修复**：已加 [5b/6] 校验步骤，导入后自动对比 CSV 与 Bitable 中超时备注数据量，发现不一致则警告\n\n## 2026-05-06 完整复盘经验总结\n\n以下为 2026-05 月工单复盘全流程中遇到并解决的问题汇总，下次工单复盘前请先通读，避免重复踩坑。\n\n---\n\n### 一、Furcas 数据拉取\n\n#### ❗ Cookie 过期处理\nFurcas API 登录态不可持久化。每次执行 `fetch_furcas.py` 前：\n1. 打开浏览器 → F12 → Network → 随便请求 Furcas 页面\n2. 从请求头复制 cookie 请求头完整值（含 `acw_tc` 和 `furcas` 字段）\n3. 更新脚本中的 `HEADERS[\"Cookie\"]` 变量\n4. 不要只更新部分字段，`acw_tc` 每次都会变\n\n#### ❗ 解决类别 ID 映射\n拉取数据后 `fetch_furcas.py` 会按解决类别分类写入 CSV，ID 映射如下：\n| ID | 类别 |\n|----|------|\n| 1 | 设计如此-无需优化 |\n| 2 | 外部原因-无需优化 |\n| 3 | 内部原因-已解决 |\n| 4 | 内部原因-延期处理 |\n| 5 | 内部原因-无法重现 |\n\n---\n\n### 二、复盘跟踪表（bitable 操作）\n\n#### ❗ 跟踪表记录创建规范\n创建复盘跟踪表记录时：\n- `app_token = YMQjwQeWCipABCkl8y7ckZlunQe`\n- `table_id = tblpygt9n8dqZcsw`\n- 年份字段填 2026（单选）\n- 月份字段填 05（单选）\n- `工单总数` = 该月 Furcas 所有工单的总数（从查询结果 count 获取）\n- `复盘工单` = 筛选后需要复盘的工单数（排除设计如此、外部原因-无需优化后）\n- 创建后等待 1-2 秒再 PATCH 其他字段\n\n#### ❗ 字段 ID 映射（跟蹤表）\n| 字段名 | field_id |\n|--------|----------|\n| 工单总数 | fldg7k4Zb |\n| 复盘工单 | fldBxBSm3x |\n| 无需优化 | fld2Fi7oVD |\n| 待产品优化 | fldQ45Kqj8 |\n| 外部原因-技术派工 | fldW8sKSSx |\n| 外部原因-需技术排查 | fldRerqDIp |\n| 外部原因-无需技术排查 | fldVefvMG2 |\n| 内部原因 | fldIor3W9R |\n| 已解决 | flde2eaOu |\n| 延期处理 | fldZqWk3G |\n| 无法复现 | fldYplayCE |\n| 超时工单数 | fldTQkMXsW |\n\n#### ✅ 工单总数来源\n`工单总数` 字段值来自 **Furcas API 返回的总数**，不是从导入 bitable 的记录数获取，不是从 CSV 行数获取。导入脚本只导入需要复盘的工单（筛选后的子集），不能当作总数。\n\n---\n\n### 三、复盘总文档操作（含表格的文档）\n\n#### ❗ 含 lark-table 的文档禁止用 feishu_update_doc 的任何模式\n`feishu_update_doc` 的 `overwrite`、`replace_all`、`append` 模式**都会损坏 lark-table**（返回 3000/4000515 等错误）。\n- ✅ 正确做法：使用 UAT Token 直接调用 PATCH blocks API，逐格更新单元格文本\n- ✅ 使用 PATCH 更新文本块（heading、text、bullet 等）\n- ❌ 禁止 `feishu_update_doc` 的任何模式\n\n#### ❗ 表格单元格偏移（110格布局）\n每个复盘表格有 110 个单元格：\n- 前 11 格 = 表头行\n- 之后每 33 格 = 一个月的数据\n- Group 0（03月）= cells[11..43]\n- Group 1（04月）= cells[44..76]\n- Group 2（05月）= cells[77..109]\n\n**每个月份组 33 格，单元格偏移**：\n| 偏移（组内） | 字段 | 行 |\n|-------------|------|----|\n| 0 | 月份标签 | row1 |\n| 1 | 工单总数 | row1 |\n| 2-3 | 无需优化（colspan=2） | row1 |\n| 4 | 待产品优化 | row1 |\n| 5 | 外部原因-技术派工 | row1 |\n| 6 | 外部原因-需技术排查 | row1 |\n| 7 | 外部原因-无需技术排查 | row1 |\n| 8 | 内部原因 | row1 |\n| 9 | 已解决 | row1 |\n| 10 | 超时（rowspan=3） | row1 |\n| 20 | 延期处理 | row2 |\n| 31 | 无法复现 | row3 |\n\n**数据数组顺序必须匹配 offset 顺序**：\n```javascript\n// 正确顺序：total(1), noOpt(2), prodOpt(4), techWork(5), techCheck(6), noTech(7), internal(8), solved(9), timeout(10), deferred(20), noRepro(31)\nconst data = ['516', '147（产研介入55）', '48（产研介入17）', '3（产研介入3）', '72（产研介入53）', '147（产研介入25）', '96（产研介入56）', '已解决38（产研介入16）', '49（产研介入28）', '延期处理47（产研介入31）', '无法复现：11（产研介入9）'];\n```\n\n#### ❗ 月份标签重命名级联 bug（关键！）\n**不能按顺序逐个改多个月份标签**！\n- ❌ 错误做法：依次执行 02→03, 03→04, 04→05\n  - 改名 02→03 后，原 03 组的标签仍然是 03\n  - 第二次操作 03→04 会匹配到 **刚改好的那组**，而不是原 03 组\n  - 导致一个月份被跳过\n- ✅ 正确方案 A：从后往前改（04→05, 03→04, 02→03）\n- ✅ **推荐方案 B**：一次性全部覆盖写入，无视当前值\n  - 用已知正确数据直接覆盖所有三组，每次重新写全部数据\n  - 这是最安全的做法\n\n#### ❗ 表头标题行丢前缀\n更新 heading1 的 `工单总计XX个(按工单数统计)` 后，前缀 `三、` 会丢失。\n- **原因**：`update_text_elements` 完全替换了所有元素，前缀在另一个 element 中\n- **修复**：更新时要保留完整标题，用 `# 三、工单总计x个(按工单数统计)`\n\n#### ❗ heading 块用 update_text_elements\n- ❌ `update_heading1` / `update_heading2` / `update_heading3` → 返回 `1770001 invalid param`\n- ✅ `update_text_elements` → 对 heading1/2/3/text/bullet/ordered 都有效\n- **通用原则**：所有文本元素的更新一律用 `update_text_elements: { elements: [...] }`\n\n#### ❗ Section 4 子块遍历\nSection 4（工单数量分析等）的 bullet 文本是 **heading 的 children**，不是根级块。\n需要：\n1. 遍历根级块找到 heading（type=4, txt='工单数量分析'）\n2. 获取该 heading 的 children（`gC(docId, heading.block_id)`）\n3. 逐个更新这些 bullet 块的文本\n\n#### ✅ 文本更新用 element-level 操作\n当 template 有 `<text color=\"orange\">x</text>` 样式时，不能简单替换整个文本字符串——会丢失颜色样式。\n- ✅ 遍历 `elements[]`，只改 content 不变 style\n- ✅ 如在会议主题中改 `10`→`05`，保留其余所有 element 的 style 属性\n\n---\n\n### 四、Callout 块处理\n\n#### ❗ Callout 块不可通过 API 删除\n- Feishu Docx API 的 DELETE 端点对 type=19（callout/quote）块返回 404\n- ❌ `DELETE /blocks/{block_id}` 对 callout 无效\n- ✅ 变通方案：只清空子节点的文本内容（将其 text element content 设为空字符串）\n- ⚠️ Callout 框本身只能**手动在飞书页面删除**（选中后按 Delete/Backspace）\n\n---\n\n### 五、mention-doc 处理\n\n#### ❗ mention-doc 是内联元素\n- mention-doc **不是**独立的 type=33 块（那是独立 mention doc block）\n- 在文本段落中，mention-doc 是 `elements[]` 数组中的一个 element\n- 同一 element 可能同时有 `text_run` 和 `mention_doc` 两个属性\n\n#### ❗ 更新 mention-doc token 的正确方式\nPATCH 时需传入完整 element，**必须带的字段**：\n```json\n{\n  \"text_run\": { \"content\": \"显示文字\", \"text_element_style\": {} },\n  \"mention_doc\": {\n    \"obj_type\": 16,  // 整數！不能传字符串 \"wiki\"\n    \"text_element_style\": {},\n    \"token\": \"UJdQwNdkPidcvKkXZzbcL1tDnaf\",  // wiki 节点 token\n    \"title\": \"显示标题\",\n    \"url\": \"https://sqb.feishu.cn/wiki/UJdQwNdk...\"\n  }\n}\n```\n- `obj_type` 是**整数**（16=wiki节点），传字符串会报 `99992402 field validation failed`\n\n#### ❗ token 会被自动解析\n发送 wiki 节点 token 后，飞书 API 会自动解析为实际文档的 obj_token：\n- ⚡ token: `UJdQwNdk...` (wiki) → `UtJCdfO5Iotw...` (docx obj_token)\n- ⚡ type: 16 (wiki) → 22 (docx)\n- ⚡ url 保持不变（wiki URL）\n- ⚡ title 会自动从**文档实际标题**获取，发送的 title 字段被忽略\n\n#### ❗ 显示文本无法通过 API 修改\nmention 在文档中显示的文字由**文档标题**决定，不是由你写入的 text_run.content 或 title 字段决定。\n- ✅ 要改显示文字，必须**改文档标题**（手工右键重命名）\n- ❌ 通过 PATCH 修改 element 中的 text_run.content 或 mention_doc.title 均无效\n\n---\n\n### 六、开发复盘文档操作\n\n#### ❗ 旧版模板只有3个开发槽位（已更新为5个）\n模板 `Secqwa7deiaRwTkUsG6cJ7xpnzj` 已在 2026-05-07 更新，直接包含开发A-E 五个槽位。旧版只有3个时：\n1. 先 PATCH 填满 3 个槽位\n2. 再通过 `POST /blocks/{root_doc_id}/children` 添加第 4、5 个\n1. 用 UAT PATCH API 更新 3 个槽位的开发者名称和数量（逐元素更新，保留橙色样式）\n2. 再通过 `POST /blocks/{root_doc_id}/children` 添加第 4、5 个\n\n#### ❗ insert_after 的正确方式（插入兄弟块）\n要插入兄弟块**不是** POST 到目标块，而是 POST 到**父块**（根文档 block_id = doc_id）：\n```javascript\n// ✅ 正确：POST 到父块（文档本身），指定 index\nPOST /documents/{docId}/blocks/{docId}/children\n{ index: 金海轩的索引+1, children: [{ block_type: 2, text: { elements: [...] } }] }\n\n// ❌ 错误：POST 到目标块自己（会把新内容作为金海轩的子块）\nPOST /documents/{docId}/blocks/{金海轩的block_id}/children\n```\n\n#### ❗ x 是单字母不是 xxx\n模板中的占位符是 `x`（如 `工单总数x个`），不是 `xxx`。替换时注意匹配模式。\n\n#### ❗ 排除特定人员\n开发复盘 TOP5 必须排除崔文思（技术支持）和蒋达周（运营）。统计开发者时：\n- 先统计每个开发者的工单数\n- 去掉崔文思和蒋达周\n- 取前 5 个填入\n\n---\n\n### 七、文档创建与复制\n\n#### ❗ 模板复制后需验证 obj_token\n`wiki_space_node action=copy` 返回的 `obj_token` 可能字符错位（如 `UtJCdfO5Iotw` 与 `UtJCdfO5Iotw` 中的 `5` 和 `O` 互换）。复制后：\n1. ✅ 立即用 `wiki_space_node action=get` 验证新节点的实际 `obj_token`\n2. ✅ 或用 `feishu_fetch_doc` 直接读节点 token 验证文档是否可访问\n\n#### ❗ 文档创建后有一定延迟\n复制创建的文档不会立即就绪。如果立即调用 PATCH 操作，可能返回 `4000515 resource not found`。\n✅ 建议做法：创建后等待 2-3 秒再操作。\n\n#### ❗ 标题改不了（API 限制）\n- ❌ `PATCH /docx/v1/documents/{docId}` → `1770001 invalid param`（不支持改标题）\n- ❌ `PATCH /wiki/v2/spaces/{spaceId}/nodes/{nodeToken}` → 404（没有 rename 端点）\n- ✅ **必须手工操作**：在飞书页面右键节点 → 重命名\n\n---\n\n### 八、UAT 工具链\n\n#### ❗ 标准 UAT 文件路径\n```javascript\nconst LINUX_UAT_DIR = path.join(\n  process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'),\n  'openclaw-feishu-uat'\n);\nconst encFile = path.join(LINUX_UAT_DIR, `${APP_ID}_${OPEN_ID}.enc`);\nconst masterKey = fs.readFileSync(path.join(LINUX_UAT_DIR, 'master.key'));\nconst uatToken = JSON.parse(\n  decrypt(fs.readFileSync(encFile), masterKey)\n).accessToken;  // 驼峰！不是 access_token\n```\n- 不要硬编码 `/root/.local/share/`，用 `XDG_DATA_HOME` 环境变量\n- 加密文件命名规则：`{appId}_{userOpenId}.enc`（冒号替换为下划线）\n- `accessToken` 是驼峰，不是下划线格式\n- 解密算法：AES-256-GCM，IV=12字节 + tag=16字节 + ciphertext\n- Master key 是 32 字节原始密钥，**不需要 SHA256 哈希**\n\n---\n\n### 九、复盘范围规范\n\n#### ✅ 复盘范围时间格式\n| 复盘类型 | 时间范围 |\n|---------|---------|\n| 整月复盘 | 当月1日 00:00:00 - 当月最后一日 23:59:59 |\n| 上半月复盘 | — 当月15日 23:59:59 |\n| 下半月复盘 | 当月16日 00:00:00 — |\n\n文档中 color=\"orange\" 的复盘范围文本要保持橙底样式，仅改日期文字。\n\n---\n\n### ⚠️ 文档命名规范（严格执行，否则重做）\n\n#### 三个文档必须从模板创建，命名必须为：\n\n| 文档类型 | 模板 | 命名规范（5月示例） |\n|---------|------|------------------|\n| 工单数据跟踪表（Bitable） | `J4tawf06GijvEmkBTSCcdyNynsd` | `智慧门店-2026-05月-工单数据` |\n| 工单复盘总文档 | GEqawooPYiDXLWkRKZHcJnLcnFc (wiki节点) | `智慧门店-2026-05月-工单复盘` |\n| 开发复盘文档 | Secqwa7deiaRwTkUsG6cJ7xpnzj (wiki节点) | `智慧门店-2026-05月-开发复盘文档` |\n\n#### 顺序：先建数据表 → 拉数据 → 建复盘文档\n\n#### 常见错误：命名带\"模版\"后缀、用\"05-整\"格式、忘记创建在对应月份目录下\n\n### 十一、文档填充规则\n\n#### 表格更新（重要）\n- lark-table文档禁止feishu_update_doc（破坏结构）\n- 使用docx PATCH API更新text block的`update_text_elements`\n- 结构：table_cell(31) → 110个type32子节点 → 每个含type2 text block\n\n#### 文本更新\n- Feishu文本可能拆成多个text_run元素（每个有独立样式）\n- 判断用`elements.map(e=>e.text_run?.content).join('')`（完整文本），修改用单个element的content\n- `update_text_elements`对所有block_type通用\n- type 12是bullet块，元素在`.bullet.elements`中\n- mention_doc不可通过API修改\n- **`feishu_update_doc` 禁止用于含 callout(type=19) 的文档**（序列化会破坏callout结构）\n- callout块的内容需通过PATCH其子block的`update_text_elements`更新，不要替换整个文档\n\n#### 文档标题/命名\n- 创建时在copy request的`title`参数设置\n- 不能通过API修改已有wiki节点标题\n- 需重命名时：copy新文档+删除旧节点\n\n### 十二、关键常量表\n\n| 项目 | 值 |\n|------|-----|\n| 工单数据(含Furcas) app_token | `YMQjwQeWCipABCkl8y7ckZlunQe` |\n| 工单汇总表 table_id | `tblpygt9n8dqZcsw` |\n| Furcas工单表 table_id | `tbln4MvksjBRkGGn` |\n| 工单数据跟踪表模板(Bitable) | `J4tawf06GijvEmkBTSCcdyNynsd` |\n| 2026目录节点（space 7510046829784662017 下） | `MDK5w5CcGi8RK6kRFMKcuBKLnNg` |\n| 复盘总文档模板 | wiki 节点 `GEqawooPYiDXLWkRKZHcJnLcnFc` |\n| 开发复盘文档模板 | wiki 节点 `Secqwa7deiaRwTkUsG6cJ7xpnzj` |\n| 用户 open_id（需替换为自己的） | `ou_xxx...` |\n| App ID | `cli_a97b6a0ffc399cc0` |\n| Space ID | `7510046829784662017` |\n| 05月目录节点 | `KAXEwRivKinTfTkshDucvSiGn4g` |\n\n---\n\n### 十三、2026-05-07 追加经验\n\n以下为 2026-05-07 修复 4 月工单数据时发现并解决的问题。\n\n#### ❗ `import_to_bitable.mjs` 清空步骤有静默失败 bug（致命！）\n\n**bug 描述**：清空旧数据的 `batch_delete` API 参数名写错，用的 `records` 但正确参数是 `record_ids`。且 try-catch 吞掉了错误，导致清空失败时不停机：\n```javascript\n// ❌ 错误（旧代码）\nawait api(\"POST\", `.../records/batch_delete`, { records: ids });\n// 清空失败，错误被 catch 吃掉\n// 旧数据继续留在表中，新数据追加写入\n// → 每条工单出现 2 遍（304条 = 152 × 2）\n```\n\n**修复**：\n1. 参数名改为 `record_ids` ✅\n2. 去掉 try-catch，让清空失败直接报错停机 ✅\n3. 导入完成后新增去重步骤（最后一道防线）✅\n4. 去重逻辑：按工单 ID 分组，每个工单只保留 1 条记录 ✅\n\n#### ❗ 多条同名空表被创建（`智慧门店-2026-05月-工单数据` × 4）\n\n**原因**：首次创建 bitable 时没有检查知识库目录下是否已有同名表格。\n\n**修复方式**：后续复盘时，在创建新 bitable 前必须：\n1. 先搜索「工单数据表」目录下是否有同月名称的表格\n2. 如果有，直接复用，不创建新的\n3. 搜索方式：`feishu_wiki_space_node list` 列出目录下所有节点，检查名称是否包含目标月份\n\n#### ❗ Mention-doc 指向错误的表格\n\n**原因**：从模板复制复盘总文档后，文档内的 mention-doc 指向的是模板的占位对象（4月表或模板），不是当前月份的表。\n\n**修复方式**（已添加 Step 5b 到流程中）：\n1. 导入数据后立即更新 mention-doc 链接\n2. 将指向前月份的 bitable mention-doc 改为当前月份的\n3. 将指向模板的 wiki mention-doc 改为实际开发复盘文档节点\n\n#### ❗ UAT 没有 bitable 读取权限\n\nRaw API 调用 `/bitable/v1/apps/{token}/tables/{table_id}/records` 返回 `99991679 Unauthorized`：\n- UAT 用户授权不包含 `bitable:app:readonly` 或 `base:record:read`\n- ✅ **feishu_bitable_app_table_record 工具可以正常读取**（使用 bot 身份或不同授权路径）\n- ✅ 如果脚本需要用 UAT 读 bitable，需要先 check 权限，否则使用 `feishu_bitable_app_table_record` 工具\n\n#### ❗ 单个 DELETE 大量记录会超时\n\n去重脚本一次删 152 条记录（逐条 DELETE）因超时被 SIGTERM：\n- 超时阈值约 2 分钟\n- ✅ 分批删除 20 条为一个 checkpoint，每次加 `await new Promise(r => setTimeout(r, 50))` 限速\n- ✅ 如果超时，再次运行脚本即可继续删剩余的\n\n#### ❗ feishu_update_doc replace_all 破坏 callout 块（生成 \"三、总结\"）\n\n**现象**：使用 `feishu_update_doc replace_all` 更新开发复盘文档后：\n- `<callout>` 块 → `>` markdown blockquote（callout 框消失）\n- `<text color=\"orange\">` → 普通文本（橙色丢失）\n- 多出 `# 三、总结` 等异常段落\n\n**根因**：`feishu_update_doc` 先将文档序列化为 markdown，再反序列化回飞书文档格式。反序列化时：\n- `<callout>` 被当作 `>` blockquote 处理\n- 如果 markdown 末尾包含 `# 三、总结` 等标题，会被当作新段落加入\n- **SKILL.md 第10条之前错误地允许了在含 callout 的文档中使用 feishu_update_doc**\n\n**修复**：\n1. 从模板重新创建文档 ✅（必须用 copy，不能用 feishu_create_doc 写 markdown）\n2. 所有更新用 UAT PATCH API 逐元素操作，不用 feishu_update_doc ✅\n3. SKILL.md 第10条已更正，明确禁止 feishu_update_doc 用于含 callout 的文档 ✅\n\n#### ❗ 开发复盘文档模板更新为5个开发者槽位（2026-05-07）\n\n模板 `Secqwa7deiaRwTkUsG6cJ7xpnzj` 在 2026-05-07 更新，\"主要人员总结材料\"下从3个槽位（开发A/B/C）扩展到5个（开发A/B/C/D/E）。\n\n**影响**：\n- ✅ 复盘流程不再需要 POST `/children` 追加开发D/E\n- ✅ 直接 PATCH 填充5个槽位即可\n- ⚠️ 旧版3槽位模板已废弃，但SKILL.md保留了旧方法作为参考\n- SKILL.md 第11条已改为\"替换开发 A/B/C/D/E 标记\"\n- SKILL.md 第12条已更新\n\n#### ❗ 开发复盘文档 Section 1 的 mention-doc 链接需替换（2026-05-07）\n\n复制模板后，开发复盘文档的 Section 1 包含两个指向模板/占位对象的 mention-doc：\n\n```\n# 一、开发复盘文档\n- 工单复盘文档：<mention-doc token=\"GEqawooPYiDXLWkRKZHcJnLcnFc\" type=\"wiki\">智慧门店工单复盘模版</mention-doc>\n- 复盘表格内容：<mention-doc token=\"J4tawf06GijvEmkBTSCcdyNynsd\" type=\"wiki\">2026-xx月-智慧门店工单数据</mention-doc>\n```\n\n**必须替换为：**\n1. `工单复盘文档` mention-doc: token → 本次创建的 **复盘总文档** wiki 节点 token\n2. `复盘表格内容` mention-doc: token → 当前月份工单数据 **bitable** token（含 table_id 和 view_id）\n\n**变更方式**：PATCH 对应 block 的 `update_text_elements`，修改 mention_doc 的 `token`、`obj_type`、`url`。\n\n#### ❗ 创建月份工单数据 bitable 的正确方式（2026-05-07）\n\n**错误做法**（之前踩过的坑）：\n1. ❌ `feishu_bitable_app copy` 从模板复制 → 创建独立 bitable（不在 wiki 目录中）\n2. ❌ `feishu_wiki_space_node create` 传 obj_token → 又新建一个**空白 bitable**（表名 \"Table\"，字段全英文）\n→ 导致 wiki 链接指向空表，数据在独立表里\n\n**正确做法**（仅需一步）：\n1. ✅ `feishu_wiki_space_node copy` 直接将模板节点复制到目标月份目录\n   - `node_token: \"J4tawf06GijvEmkBTSCcdyNynsd\"`（工单数据表模板）\n   - `target_parent_token: \"{目标月份目录节点token}\"`\n   - `space_id: \"7510046829784662017\"`\n   → 直接在 wiki 内创建副本，bitable 结构、字段、视图全部正确\n\n**复制后的处理**：\n1. 重命名 bitable（如 \"智慧门店-2026-5月工单数据\"）\n2. 删除模板自带的 5 条空记录（`batch_delete` 空记录的 `record_ids`）\n3. 导入 CSV 数据\n\n**导入脚本注意事项**：\n- 表名默认校验为 \"工单数据\"，但模板复制出来的表名是 \"数据表\"\n  → 用 `--name \"数据表\"` 参数\n- 看板视图创建后的 `view_id` 可能返回 undefined（脚本返回值解析 bug）\n  → 视图实际已创建，可通过 `feishu_bitable_app_table_view list` 获取 `view_id`\n  → 手工设置 `property: { kanban_field_id: \"责任人字段ID\" }`\n\n**开发复盘文档人名占位符规则（2026-05-07）**：\n- 模板中 `开发A(` `开发B(` 等是**人名占位符**，不是固定标签\n- 必须替换为责任人实际姓名（如 `李文茂(`），不是仅替换数字\n- 替换后第一个元素内容从 \"开发A(\" → \"李文茂(\"，保持橙色样式不变\n\n**开发复盘文档 callout 内容规则（2026-05-07）**：\n- callout 内（分析总结：、超时工单分析：等10个字段）**不要填充任何内容**\n- callout 应保持模板的占位符状态，留给用户手动填写\n- 如果误填了多行文本，清理时需要：1) 把多余元素全删除 2) 只剩单元素 \"分析总结：\"\n\n---\n\n### 2026-05-15 新增经验\n\n#### ❗ 超时备注导入后校验\nFIELD_MAP 已有映射，但首次导入后超时备注字段为空。已在脚本 [5/6] 验证后追加 [5b/6] 校验步骤，自动检测 CSV 中超时备注数据是否成功写入 bitable。\n\n**补救方法**（当超时备注导入失败时）：\n```bash\n# 从 CSV 读取超时备注数据，逐条写入 bitable（通过 UAT PUT API）\n# 脚本逻辑：遍历 bitable 记录 → 按问题链接匹配 CSV → 对有超时时间的记录填写超时备注\n```\nUAT API 的 `batch_create` 和 `PUT` 操作均正常，传入纯字符串即可。\n\n#### ❗ 视图可能隐藏关键字段\n4月数据表的视图 `vewadQIK4f` 的 `hidden_fields` 中包含了 `解决类别`、`解决模块`、`责任人` 三个字段，导致用户看不到数据。\n\n**排查方法**：用 `feishu_bitable_app_table_view action=get` 获取视图配置，检查 `property.hidden_fields` 列表\n\n**修复方法**：调用 UAT API PATCH 视图，设置 `property: { }`（空对象或省略 hidden_fields 即可清除）\n\n---\n","topics":["开发","文档"],"tags":{"latest":"1.0.2"},"stats":{"comments":0,"downloads":403,"installsAllTime":15,"installsCurrent":0,"stars":0,"versions":3},"createdAt":1778146009843,"updatedAt":1779346231400},"latestVersion":{"version":"1.0.2","createdAt":1779346231400,"changelog":"forces-reanalyze-smart 1.0.2\n\n- 文档更新：SKILL.md 文件内容细节修订，无功能或逻辑改动。\n- 保持原有流程与用法，涉及文档表述优化及补充说明。","license":"MIT-0"},"metadata":null,"owner":{"handle":"runkecheng","userId":"s177cbem7examhbe7rq6035fad840jdh","displayName":"runkecheng","image":"https://avatars.githubusercontent.com/u/68526782?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1779975873342}}