Skill flagged — review recommended

ClawHub Security found sensitive or high-impact capabilities. Review the scan results before using.

Forces Reanalyze Smart

完成智慧门店工单复盘全流程。触发词:工单复盘、复盘工单、拉取工单数据、创建复盘文档、工单分析、创建复盘。完整覆盖三个阶段:(1)拉取Furcas工单数据并导入多维表格 (2)创建/更新工单复盘总文档 (3)创建开发复盘文档并填充TOP5统计。当用户要求进行工单复盘时使用。

Audits

Suspicious

Install

openclaw skills install forces-reanalyze-smart

智慧门店工单复盘全流程

流程概览

一次完整的工单复盘涉及 3个文档,按顺序执行:

Step 0:复盘跟踪表(前置检查)
  检查/创建 目标月份记录 → 落数据基线

阶段一:工单数据表(飞书多维表格)
  Step 1 → Step 2 → Step 3 → Step 4 → Step 5 → Step 5b
  解析月份 → 获取Cookie → 拉取Furcas数据 → 创建/复用月份bitable(模板:J4tawf06GijvEmkBTSCcdyNsnyd)→ 导入CSV → 更新mention-doc链接

阶段二:工单复盘总文档(知识库文档)
  Step 6 → Step 7
  创建文档(模板:GEqawooPYiDXLWkRKZHcJnLcnFc)→ 填充变量

阶段三:开发复盘文档(知识库文档)
  Step 8
  创建文档(模板:Secqwa7deiaRwTkUsG6cJ7xpnzj)→ 填充TOP5统计

关键链接

类型链接/Token
工单数据Bitable模板J4tawf06GijvEmkBTSCcdyNsnyd (table: tblXtjn9QHTcB5oa, view: vew8A2EB9c)
复盘总文档模板GEqawooPYiDXLWkRKZHcJnLcnFc
开发复盘文档模板Secqwa7deiaRwTkUsG6cJ7xpnzj
复盘跟踪表(前置数据源)YMQjwQeWCipABCkl8y7ckZlunQe (table: tblpygt9n8dqZcsw,参见 Step 0)
Bot App IDcli_a97b6a0ffc399cc0

前置步骤:复盘跟踪表

Step 0: 检查/创建跟踪表记录

在创建任何文档之前,先检查复盘跟踪表是否已有目标月份的记录。

跟踪表链接

https://sqb.feishu.cn/wiki/YMQjwQeWCipABCkl8y7ckZlunQe?table=tblpygt9n8dqZcsw&view=vewme7V2C9

  • Bitable App Token: YMQjwQeWCipABCkl8y7ckZlunQe
  • Table ID: tblpygt9n8dqZcsw

⚠️ 核心规则:必须先查存在,绝不复件

这条规则是全局最高优先级。任何创建操作前必须先查,查到已存在则直接复用,绝不允许创建第二条同名记录。

操作步骤

  1. 查询已有记录(必须执行,不可跳过)
操作:feishu_bitable_app_table_record list
参数:
  app_token: "YMQjwQeWCipABCkl8y7ckZlunQe"
  table_id: "tblpygt9n8dqZcsw"
  filter: {
    conjunction: "and",
    conditions: [
      {field_name: "复盘范围", operator: "is", value: ["2026-05"]}
    ]
  }

注意 field_name 必须用中文名「复盘范围」(是文本类型的主字段),不要用 field_id。

  1. 判断是否已有目标月份

    • 找到记录立即停止创建流程,直接使用已有记录的 record_id 及其包含的所有数据(工单总数、复盘工单数、各分类统计等),进入阶段一
    • 没找到 → 执行第 3 步创建新记录

    绝对禁止:查到已有记录后,再创建第二条同名或同周期的记录。

  2. 新建记录(仅在确认不存在时执行):

操作:feishu_bitable_app_table_record create
参数:
  app_token: "YMQjwQeWCipABCkl8y7ckZlunQe"
  table_id: "tblpygt9n8dqZcsw"
  fields:
    复盘范围: "{月份标签}"     // 整月如 "2026-05"(不要加 "-整" 后缀)
    开始时间: {毫秒时间戳}     // 范围起始日期 00:00:00 UTC+8
    结束时间: {毫秒时间戳}     // 范围结束日期 23:59:59 UTC+8
    日期: {毫秒时间戳}         // 当前操作日期(执行复盘的当天)

字段说明

字段类型填写规则
复盘范围文本 (主字段)整月:2026-05不要写 2026-05-整);上半月:2026-05-上;下半月:2026-05-下
开始时间日期(毫秒时间戳)范围起始日 00:00:00 UTC+8,如2026年5月整月 → 1777593600000(对应 2026-05-01T00:00:00+08:00
结束时间日期(毫秒时间戳)范围结束日 23:59:59 UTC+8,如2026年5月整月 → 1780271999000(对应 2026-05-31T23:59:59+08:00
日期日期(毫秒时间戳)当前操作日期,即执行复盘的当天,如2026年5月6日 → 17779104000002026-05-06T00:00:00+08:00

时间戳必须二次确认:创建记录后立即读取该记录,检查时间戳对应的年份是否与目标年份一致(2026年)。一个常见的错误是毫秒时间戳算成了2025年的日期。如果时间戳不对,删除该记录,重新计算并创建。

注意:其余字段(工单总数、复盘工单、超时工单数、各解决类别统计等)均为 Lookup/Formula 自动计算字段,无需手动填写,数据导入后会自行更新。

创建后操作

  • ✅ 确认记录已成功创建
  • 读取刚创建的记录,验证时间戳是否对应正确的日期(2026年不是2025年)
  • 记录下 record_id,后续阶段二填充文档第三节表格时需要
  • 进入阶段一,开始拉取工单数据

阶段一:工单数据表

Step 1: 解析用户意图

用户说"做X月工单复盘"或"复盘X月"时:

  • 提取目标月份(如 2026-04
  • 计算开始/结束日期:2026-04-01 ~ 2026-04-30
  • 记录月份标签:2026-04

如果用户提到"拉取X到X的工单数据",直接使用指定的起止日期。

Step 2: 获取 Cookie

本阶段需要有效的 Furcas Cookie。

  1. 如果已有可用 cookie,直接使用
  2. 如果没有,引导用户:
    • 登录 https://furcas.shouqianba.com
    • F12 开发者工具 → Network → 复制 Cookie 请求头
    • 粘贴到 scripts/fetch_furcas.pycookie = "" 变量中

Step 3: 拉取工单数据

python scripts/fetch_furcas.py -s "2026-04-01" -n "2026-04-30" -o /workspace/furcas.csv

输出字段:问题描述、问题链接、工单状态|修复情况、问题原因、责任人、解决类别、解决模块、超时时间、超时备注

Step 4: 创建/复用月份工单数据 Bitable

⚠️ 必须检查:先确认目标月份目录下是否已有同名 bitable。用 feishu_wiki_space_node list 列出目录内容,看是否已有工单数据表。如有则直接复用,跳过创建。

正确创建方式(仅需一步)

使用 feishu_wiki_space_node copy 将模板节点直接复制到目标月份目录:

操作:feishu_wiki_space_node copy
参数:
  node_token: "J4tawf06GijvEmkBTSCcdyNynsd"  // 工单数据表模板
  space_id: "7510046829784662017"
  target_parent_token: "{目标月份目录节点token}"
  target_space_id: "7510046829784662017"

为什么必须用 wiki node copy?

  • feishu_bitable_app copy → 创建独立 bitable(不在 wiki 目录中)
  • feishu_wiki_space_node create → 创建空白 bitable(表名 "Table",字段全英文)
  • feishu_wiki_space_node copy → 直接在 wiki 内创建模板副本,字段/视图全部正确

复制后的处理

  1. 重命名:bitable 名称 → 智慧门店-2026-5月工单数据
  2. 删除模板空记录:模板自带 5 条空记录(fields: {}),用 batch_delete 清空
  3. 验证字段结构:应包含以下 9 个字段:
    • 文本(Text, primary)、问题链接(Url)、工单状态|修复情况(Text)、问题原因(Text)
    • 责任人(Text)、解决类别(SingleSelect)、解决模块(SingleSelect)
    • 超时时间(Text)、超时备注(Text)

关键约束

  • 工单状态|修复情况 含竖线 |(CSV中为 /,脚本会自动映射)
  • 问题链接 是 URL 类型,导入时用 {"link": "URL", "text": "查看工单"}
  • 责任人 是文本类型(type=1),不是人员类型

Step 5: 导入数据到多维表格

推荐:使用导入脚本

APP_TOKEN={月份bitable的app_token} \
TABLE_ID={月份bitable的table_id} \
CSV_PATH=/workspace/furcas.csv \
BATCH_SIZE=15 \
node scripts/import_to_bitable.mjs --name "数据表"

⚠️ --name 参数必须传:模板复制出来的表名叫 数据表,但脚本默认校验名为 工单数据。必须用 --name "数据表"TABLE_NAME="数据表" 让校验通过。不传的话校验会警告但不阻止导入。

脚本自动:校验表名 → 清空旧数据 → 分批创建记录 → 创建看板视图 → 验证 → 去重检查

⚠️ batch_delete 参数名是 record_ids(不是 records:这是飞书 API 的规范。如果写错,清空静默失败,新数据追加到旧数据上,导致重复。

⚠️ 去重检查是最后一道防线:即使清空步骤因意外失败(如网络超时、API 限流),去重步骤也会自动删除重复工单,保证每个工单 ID 唯一。

⚠️ 表名校验:脚本在导入前会调用 API 读取目标表的实际名称,与 TABLE_NAME 环境变量比对。如果名称不匹配会给出警告,防止数据写入错误的表。

手动替代方案:使用 feishu_bitable_app_table_record 工具 action=batch_create,records 参数用 string="false"


阶段二:工单复盘总文档

Step 5b: 更新文档 Mention-Doc 链接

导入数据后,立即更新复盘总文档中的 mention-doc 链接,确保指向当前月份的正确表格和开发复盘文档。

为什么必须做: 复盘总文档从模板复制后,mention-doc 链接指向的是模板的占位对象(如旧月份的表格或模板文档)。不更新的话,点击链接会看到错误的数据。

更新步骤

  1. 获取复盘总文档的文档 ID(从 step 6/7 创建或之前创建的文档获取)
  2. 找到 mention-doc 所在的 block
    • 遍历文档根级 children,找到包含「月具体工单请查看飞书表格」文本的 block
    • 该 block 是 type=2(text),其 elements[] 中包含 mention_doc 类型的 element
  3. PATCH 更新该 block 的 elements
    • 工单数据表 mention-doc:token → 当前月份的 bitable token,obj_type → 8(bitable)
    • 开发复盘文档 mention-doc:token → 当前月份的 wiki 节点 token,obj_type → 16(wiki)
    • 不写 text_run 的 content(显示文本由文档标题决定)
    • obj_type 必须传整数(8=bitable, 16=wiki),传字符串会报 99992402

脚本参考

// PATCH /docx/v1/documents/{docId}/blocks/{blockId}
// Body: { update_text_elements: { elements: [originalElements] } }
// 只改 mention_doc.token/obj_type/url,保持 text_run 不变

第 34 个经验(2026-05-07):Mention-doc 更新后 token 被自动解析

发送 wiki 节点 token 后,飞书 API 会自动解析为实际文档的 obj_token,类型也会从 wiki(16) 变为具体类型(如 docx=22, bitable=8)。修改后 fetch-doc 验证即可。

Step 6: 创建工单复盘总文档

前置检查

在创建之前,先检查目标月度目录下是否已存在同名的文档。

使用 feishu_wiki_space_node list 列出月度目录下的所有节点。如果已有同名文档,直接进入 Step 7 更新即可,不要重复创建

创建步骤

  1. 复制模板:从模板 GEqawooPYiDXLWkRKZHcJnLcnFc 复制创建新文档
  2. 重命名:按月份命名,如 智慧门店-2026-05月-工单复盘
  3. 放入对应目录:确认文档在正确的年度/月度知识库目录下

复制文档的两种方式:

  • 使用 feishu_wiki_space_nodecopy 操作(如果模板是 wiki 节点),传入 space_idtarget_parent_token
  • 或用 feishu_create_doc 从模板创建(传入 wiki 节点 token)
  • 或用 feishu_drive_filecopy 操作

Step 7: 填充复盘总文档变量

模板中有大量 x 占位符(橙色高亮),需要按以下规则替换为实际数据。

模板结构要点(非常重要)

不要破坏模板原有的换行和段落结构。 模板中每个变量的位置和间距都有意义。以下从实际模板 GEqawooPYiDXLWkRKZHcJnLcnFc 获取的精确结构:

# 一、会议信息
会议主题:智慧门店-<text color="orange">2026-</text><text color="orange">10</text>月工单复盘
会议时间:<text color="orange">2026.05.07(周四) 16:00 - 16:30</text>

# 二、会议议程
**复盘时间:**<text color="orange">**2026.05.07**</text>
**复盘范围:**<text color="orange">**2026.04.01 00:00:00-2026.04.30 23:59:59**</text>
**参与人员:**
- **开发:朱栋泉、**<text color="orange">**李文茂(28)、付雷(12)、王佳明(10)、赵杭琪(9)**</text>
- **产品:**
- **测试:**
- **技术支持:崔文思**
- **运营:蒋达周**

# 三、工单总计<text color="orange">XX</text>个(按工单数统计)

[Table: 10行×11列,3个月数据(2026-02/03/04),每33格一组=110格]
⚠️ 2026-04 组(最近一个月)使用整体橙色格式,与 02/03 组的逐字橙色不同

<text color="orange">2026-04</text>月具体工单请查看飞书表格:<mention-doc token="J4tawf06GijvEmkBTSCcdyNynsd" type="wiki">2026-xx月-智慧门店工单数据</mention-doc>
开发复盘文档:<mention-doc token="Secqwa7deiaRwTkUsG6cJ7xpnzj" type="wiki">开发复盘文档模板</mention-doc>

# 四、工单总结
## 工单数量分析
- <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>
- 从**解决类别**看,工单主要集中在:<text color="orange">外部原因-无需技术排查(208)、设计如此-无需优化(160)、外部原因-需技术排查(81)</text>
- 从**解决模块**看:工单主要集中在:<text color="orange">收银系统-餐饮(197)、打印机(150)、扫码点单(117)</text>

## 工单时效分析
<text color="orange">90</text>个超时工单(其中产研介入<text color="orange">59</text>个),时效内解决占比<text color="orange">84.67</text>%,较3月<text color="orange">82%</text>有所提高。
主要超时原因:

## 问题总结
立即更改内容跟进:
同步客服&技术支持:

# 五、历史跟进事项
<text color="orange">**2026-03**</text>**月跟进事项**:
...
<text color="orange">**2026-02**</text>**月跟进事项**:
...

📌 模板关键位置标注

位置说明
Section 3 标题# 三、工单总计<text color="orange">XX</text>个(按工单数统计)无 callout 块
Section 3 末尾Mention-doc(工单数据表 bitable + 开发复盘文档 wiki)
Section 4: 工单数量分析含同比上月数据行 <text color="orange">同比...增加xx%</text>
Section 4: 工单时效分析主要超时原因:后为填空区域
Section 5月份为「目标月-1」和「目标月-2」,如05月复盘则显示04和03月
表格最后一组(最近月)使用整体橙色 <text color="orange">已解决x(产研介x)</text> 格式,与前面两组不同

📌 Section 5 月份命名规则

  • 表头显示「目标月-1」和「目标月-2」的跟进事项
  • 例如:05月复盘 → 显示 **2026-04**月跟进事项**2026-03**月跟进事项
  • 月份部分用橙色标签包裹:<text color="orange">**2026-03**</text>**月跟进事项**:

🏷️ 命名规范(必须遵守)

创建文档时禁止直接使用模板的名称。每次创建必须按以下规范重命名:

文档类型模板节点创建后命名规范示例(2026-05月)
工单数据跟踪表(多维表格)J4tawf06GijvEmkBTSCcdyNynsd智慧门店-2026-xx月-工单数据智慧门店-2026-05月-工单数据
工单复盘文档(知识库文档)GEqawooPYiDXLWkRKZHcJnLcnFc智慧门店-2026-xx月-工单复盘智慧门店-2026-05月-工单复盘
开发复盘文档(知识库文档)Secqwa7deiaRwTkUsG6cJ7xpnzj智慧门店-2026-xx月-开发复盘文档智慧门店-2026-05月-开发复盘文档

重命名方式(API 不支持,必须手工):

  1. 复制模板创建文档后,在飞书页面打开
  2. 右键左侧目录树中的节点 → 选择「重命名」
  3. 按上表命名规范输入新名称
  4. 标题改完后,mention-doc 的显示文字会自动更新(因为 mention 显示的是文档实际标题)

⚠️ Section 3 的表格是 <lark-table> 格式(带 rowspan/colspan 的复杂表格),不能用 markdown 表格替代。 使用 overwrite 模式重写文档时,表格结构会丢失。因此 Section 3 必须保留原始 <lark-table> 代码。

⚠️ ⚠️ ⚠️ 三大数据来源规则(必须遵守,不要再出错) ⚠️ ⚠️ ⚠️

以下3条规则已经被用户多次重复强调。每次出错都会导致文档数据混乱。阅读此文件时请逐条仔细核对!

规则1:参与人员 → 取开发复盘文档 TOP5

复盘总文档# 二、会议议程参与人员:开发: 后面的橙色部分,必须填入开发复盘文档 Section 2 中前5名责任人 的姓名和工单数量。

  • 不要使用模板中的旧数据(如 李文茂(28)、付雷(12)、王佳明(10)、赵杭琪(9)
  • 不要自行编造
  • 准确取本月的开发复盘文档中 Section 2 的5位开发人员及其工单数量
  • 格式:李文茂(5)、蒋达周(3)、赵杭琪(2)、金海轩(2)、王金楠(2)

规则2:工单总计 XX + 第三节表格 → 全部来自复盘跟踪表

模板中所有带 x 的数字占位符(包括 Section 3 标题 XX、表格中所有 x)的填充值,必须全部从 复盘跟踪表 Bitable 获取:

复盘跟踪表: https://sqb.feishu.cn/wiki/YMQjwQeWCipABCkl8y7ckZlunQe?table=tblpygt9n8dqZcsw
  • Section 3 标题 三、工单总计XX个 → X 填复盘跟踪表中当月记录的 工单总数 字段
  • 表格数据 → 全部填复盘跟踪表中各月份的字段值
  • 表格顺序:必须按时间从上到下排列,新数据在下方。例如做 5 月复盘时:
    • 第一行(最上方):2026-03(最旧)
    • 第二行(中间):2026-04
    • 第三行(最下方):2026-05(最新)
    • 不要把最新行放在最上面

规则3:Section 4 工单数量分析 + 工单时效分析 → 全部来自复盘跟踪表

# 四、工单总结 下所有带数字的橙色文本,数据来源均为复盘跟踪表(不是工单数据表):

  • X月共产生工单X个 → 跟踪表 工单总数
  • 本次复盘筛选出X个工单 → 跟踪表 复盘工单
  • 同比上月增加/减少XX% → 对比跟踪表中上月的 工单总数
  • 解决类别TOP3 → 跟踪表中各解决类别字段(外部原因-无需技术排查无需优化外部原因-需技术排查 等)
  • 解决模块TOP3 → 跟踪表中各模块字段(收银系统-餐饮扫码点单打印机 等)
  • 超时工单数/产研介入 → 跟踪表 超时工单数超时工单数-产研介入
  • 时效内解决占比1 - 超时工单数/工单总数 × 100%

数据来源一览

数据来源
会议信息、议程用户提供或从上月文档沿用
参与人员(开发TOP5)开发复盘文档 Section 2 的前5名责任人
第三节标题 XX复盘跟踪表 工单总数
第三节表格(所有数字)复盘跟踪表(全部字段)
工单数量分析(所有数字)复盘跟踪表
工单时效分析(所有数字)复盘跟踪表
历史跟进事项从上月复盘文档复制

7.1 填充第三节表格

使用 scripts/fill_review_cells.cjs 填充嵌套表格单元格。详细操作见 references/data_mapping.md

配置脚本顶部:

const DOC_ID = '...';  // 新创建的复盘总文档 ID
const MONTH = '2026-04';  // 目标月份
const CELL_DATA = {
  total:    '644',
  noOpt:    '160(产研介入94)',
  prodOpt:  '42(20)',
  techWork: '0',
  techCheck:'79(48)',
  noTech:   '208(28)',
  internal: '138(产研介入87)',
  solved:   '已解决54(27)',
  deferred: '延期处理66(46)',
  noRepro:  '无法重现:18(14)',
  timeout:  '88(58)',
};

执行:node scripts/fill_review_cells.cjs

7.2 第三节表格:最近3个月数据

模板中 # 三、工单总计XX个(按工单数统计) 下方自带一个 <lark-table> 格式的嵌套表格。此表格必须保留,不能删除或替换为文本。

表格内容规则

表格内应填充最近3次工单复盘的数据(包含目标月份+前2个月)。例如做 2026-05 月复盘时,表格应包含:

内容
第一行(表头)复盘范围、时间、工单总数等列名
第一数据行(最旧)2026-03 数据(跟踪表记录)
第二数据行(中间)2026-04 数据(跟踪表记录)
第三数据行(最新,在最下方)2026-05 数据(跟踪表记录)

⚠️ 顺序规则

  • 模板默认把最近月放在第一行(上方),但正确顺序是旧数据在上、新数据在下
  • 因此需要把模板的行标签和数据都修改过来。例如模板中的 2026-02 行应改为 2026-03 数据,2026-03 行改为 2026-04 数据,2026-04 行改为 2026-05 数据
  • 是的,需要把所有行的标签和数据都改一遍,不能偷懒只改一行

数据获取

  1. 从复盘跟踪表 list 全部记录
  2. 找到最近3个月的记录(按月份排序 2026-05 / 2026-04 / 2026-03
  3. 提取各字段值:工单总数、复盘工单、超时工单数、无需优化、待产品优化、内部原因等

填充方式

使用 scripts/fill_review_cells.cjs 逐个填充表格单元格。详细操作见 references/data_mapping.md

配置脚本顶部:

const DOC_ID = '...';  // 新创建的复盘总文档 ID
const MONTH = '2026-05';  // 目标月份(用于查找表格中的对应单元格)
const CELL_DATA = {
  // 以下数据来自复盘跟踪表,key 见 data_mapping.md
  total:    '21',
  noOpt:    '11(产研介入7)',
  prodOpt:  '0',
  techWork: '0',
  techCheck: '0',
  noTech:   '0',
  internal: '10(产研介入3)',
  solved:   '已解决4(1)',
  deferred: '延期处理6(2)',
  noRepro:  '无法重现:0',
  timeout:  '11(3)',
};

如果目标月份在跟踪表中尚无数据(月未结束),表格中该行留空或填 "-",用附注说明。

重要:表格数据来自复盘跟踪表

复盘总文档第三节表格的数据不直接来自工单数据表,而是来自复盘跟踪表。跟踪表中各字段是 Lookup 公式,会自动根据 Step 0 创建的记录中的时间范围和已导入的工单数据计算汇总值。

因此复盘的正常顺序是:

  1. Step 0 → 创建跟踪表记录
  2. 阶段一 → 导入工单数据
  3. 之后 跟踪表各 Lookup 字段会自动计算
  4. Step 7 → 从跟踪表读取计算结果,填入第三节表格

7.3 填充工单总结

⚠️ 所有数字均来自复盘跟踪表,不是工单数据表

模板中 Section 4 的每一条文本都有橙色标记的数字占位符。所有数值必须从复盘跟踪表获取,不能从刚导入的工单数据表(24条)统计。

工单数量分析需要以下统计数据(全部来自复盘跟踪表 filter 复盘范围=当月):

变量跟踪表字段取值方式
当月工单总数工单总数直接取值
复盘工单数复盘工单直接取值
同比上月增减%对比上月 工单总数(本月-上月)/上月 × 100%
解决类别TOP3外部原因-无需技术排查无需优化待产品优化外部原因-需技术排查按字段值排序取TOP3
解决模块TOP3收银系统-餐饮扫码点单打印机收银系统-零售按字段值排序取TOP3

工单时效分析需要(全部来自跟踪表):

变量跟踪表字段取值方式
超时工单数超时工单数直接取值
超时产研介入超时工单数-产研介入直接取值
时效内解决占比%工单总数 + 超时工单数(1 - 超时工单数/工单总数 × 100%),保留两位小数

获取方式feishu_bitable_app_table_record list 查询 复盘范围 = 当月,然后从返回的 fields 中提取所需字段。

注意:Section 4 的文本包含大量橙色标记(<text color="orange">),无法通过简单的 replace_rangeselection_with_ellipsis 更新(因为标记打断了文本连续性)。

  • 超时文本块(如 25个超时工单)可以通过 block PATCH 更新(type 2 块)
  • 列表项(type 12)和标题块(type 3)无法通过 block API 更新
  • 必须通过 feishu_update_doc replace_all(但会破坏 callout)或手动编辑

问题总结历史跟进事项从上月文档复制,或由用户填写。


阶段三:开发复盘文档

Step 8: 创建开发复盘文档

前置检查

同样先检查目标月度目录下是否已有同名文档。 使用 feishu_wiki_space_node list 确认后再操作。

创建步骤

  1. 复制模板:从 Secqwa7deiaRwTkUsG6cJ7xpnzj 复制创建
  2. 重命名:按月份命名,如 智慧门店-2026-05月-开发复盘文档
  3. 放入对应目录

⚠️ 开发复盘文档需要修改/填充的内容(共3项,缺一不可!)

不要破坏模板原有的换行和段落结构。 完整模板结构如下:

# 一、开发复盘文档
- 工单复盘文档:<mention-doc token="..." type="wiki">智慧门店工单复盘模版</mention-doc>   ← 需修改 ①
- 复盘表格内容:<mention-doc token="..." type="wiki">2026-xx月-智慧门店工单数据</mention-doc>   ← 需修改 ②

# 二、主要人员总结材料
<text color="orange">开发A(</text>工单总数<text color="orange">x</text>个)(超时工单<text color="orange">x</text>个)   ← 需修改 ③
[callout] ← 保持模板原样!不要改动!

修改① 替换「工单复盘文档」mention-doc

目标:指向本次创建的复盘总文档 wiki 节点

{ mention_doc: { token: "{复盘总文档的wiki节点token}", obj_type: 16, // wiki
  title: "智慧门店-2026-05月-工单复盘",
  url: "https://sqb.feishu.cn/wiki/{wiki节点token}" } }

修改② 替换「复盘表格内容」mention-doc

目标:指向当前月份的工单数据 bitable

{ mention_doc: { token: "{月份bitable的app_token}", obj_type: 8, // bitable
  title: "智慧门店-2026-5月工单数据",
  url: "https://sqb.feishu.cn/base/{app_token}?table={table_id}&view={view_id}" } }

修改③ 替换橙色高亮区的占位符(开发A~E 和 x)

这是最容易出错的地方!严格按照以下步骤:

  1. 找到文档根 children 中的 type 2 块(5个,对应开发A~E)
  2. 对每个块的 elements,执行 3 个替换:
位置原来改为示例(李文茂)
第一个 text_run开发A(责任人姓名+(李文茂(
中间 text_run(内容为xx该人工单总数5
末尾 text_run(内容为xx该人超时工单数4

元素结构参考(以开发A为例,其余开发B~E结构相同但元素数可能不同):

// 开发A 的 elements(8个元素):
[ {text_run: "开发A("},      // 改为人名
  {text_run: "工单总"},        // 不动
  {text_run: "数"},           // 不动
  {text_run: "x"},           // 改为工单总数
  {text_run: "个"},           // 不动
  {text_run: ")(超时工单"},    // 不动
  {text_run: "x"},           // 改为超时工单数
  {text_run: "个)"}           // 不动
]

// 开发B~E 的 elements(6个元素):
[ {text_run: "开发X("},       // 改为人名
  {text_run: "工单总数"},       // 不动
  {text_run: "x"},            // 改为工单总数
  {text_run: "个)(超时工单"},   // 不动
  {text_run: "x"},            // 改为超时工单数
  {text_run: "个)"}            // 不动
]

// 替换后效果:
[ {text_run: "李文茂("},
  {text_run: "工单总"},
  {text_run: "数"},
  {text_run: "5"},           // 原来是 x
  {text_run: "个"},
  {text_run: ")(超时工单"},
  {text_run: "4"},           // 原来是 x
  {text_run: "个)"}
]

✅ 最终橙色高亮区的效果(模板 → 正确):

<text color="orange">开发A(</text>工单总数<text color="orange">x</text>个)(超时工单<text color="orange">x</text>个)
   ↓ 替换为
<text color="orange">李文茂(</text>工单总数<text color="orange">5</text>个)(超时工单<text color="orange">4</text>个)

❗ 绝对不要做的事(踩坑记录)

❌ 错误后果
只替换数字 x,不把开发A改成责任人姓名橙色区显示 "开发A(工单总数5个)" 而非 "李文茂(工单总数5个)"
把分析总结填入 callout 内容callout 应该保持模板占位符状态,留给用户手动填写
写入多行文本到 callout 块(如 工单原因分析:\n1. xxx后续无法一次性清空,需要逐元素删除残留行
feishu_update_doc replace_all 更新文档内容会破坏 <callout> 块结构

责任人的选取规则

  • 从工单数据表(阶段一导入的)统计 TOP5 责任人
  • 排除 崔文思蒋达周
  • 统计每个责任人:
    • 工单总数:该责任人名下的工单数量
    • 超时工单数:该责任人名下 超时时间 不为空的工单数

数据获取方式

  1. 从工单数据表 list 全部记录
  2. 责任人 字段分组计数
  3. 排除崔文思、蒋达周
  4. 取工单数最多的前5名
  5. 对每个负责人统计超时工单数

填充方式

  • 使用 UAT 调飞书 Docx PATCH API 逐元素更新,不要用 feishu_update_doc(会破坏 <callout> 块)
  • 通过 PATCH update_text_elements 替换橙色占位符的 x,保留 <text color="orange"> 样式
  • 模板已有5个开发者槽位(开发A-E),直接 PATCH 全部5个槽位的占位符,无需 POST 追加

分析总结占位符

每个责任人段落的 callout 区域包含需要用户填写的分析总结(无法自动生成):

分析总结:
超时工单分析:
工单原因分析:
需更改需跟进事项:
需同步产品:
需同步开发:
需同步测试:
需同步客服:
需同步技术支持:
其他:

在填充数据后告知用户这些区域需要手动填写。


脚本说明

scripts/fetch_furcas.py

从 Furcas API 拉取数据。参数:-s 开始日期、-n 结束日期、-o 输出路径。

scripts/import_to_bitable.mjs

CSV → 多维表格导入一体化脚本。环境变量:APP_TOKEN, TABLE_ID, CSV_PATH, BATCH_SIZE, TABLE_NAME

scripts/generate_batches.py

CSV → JSON 批处理文件。参数:--csv, --output-dir, --batch-size

scripts/fill_review_cells.cjs

填充复盘总文档第三节嵌套表格单元格。直接调飞书 Docx PATCH API,用用户 OAuth UAT。顶部配置区设置月份和数据。


注意事项

通用

  1. Cookie 时效性:Furcas Cookie 可能过期,过期后需用户重新拷贝
  2. 导入长度限制:batch_create 每批 ≤ 15 条
  3. 看板视图分组:创建后需显式设置 kanban_field_id
  4. 表格嵌套单元格:不能用 markdown flat table 替代,必须用 fill_review_cells.cjs 逐个填充
  5. 替换 x 变量:开发复盘文档的 <text color="orange">x</text> 占位符必须用 UAT PATCH API 逐元素更新(保留橙色样式),禁止用 feishu_update_doc replace_all(会破坏 <callout> 块)。复盘总文档的 x 同样用 PATCH API 更新。
  6. 责任人排除:开发复盘 TOP5 统计需排除崔文思、蒋达周
  7. 文档排版:从模板复制后,确认文档结构完整。当前模板(2026-05起)已无 callout 提示块,无需手动删除

模板结构守则

  1. 永远不要合并或删除模板中的换行。模板的每个段落、列表都是精心设计的结构。特别是:

    • 会议信息的 会议主题 / 会议时间 各占一行
    • 会议议程的 **复盘时间:** / **复盘范围:** / **参与人员:** 各自独立成段
    • 参与人员列表用 - 无序列表格式
    • 开发复盘文档的 callout 中每个冒号标题独占一行,> 前缀必须保留
    • ⚠️ 复盘总文档模板(2026-05 版本)已无 callout 块,Section 3 标题后直接是 <lark-table>
  2. feishu_update_doc 禁止用于含表格的文档:复盘总文档的 Section 3 包含 <lark-table>任何模式(overwrite/replace_all/append/insert_after/replace_range/delete_range)都会摧毁表格属性(rowspan、colspan 丢失,cols 数变化)。

    • feishu_update_doc 会先序列化文档为 markdown 再反序列化,过程中 lark-table 的 HTML 属性丢失
    • 所有更新必须使用 UAT Token 直接调飞书 PATCH blocks API,逐元素更新
    • ✅ 表格单元格:PATCH /blocks/{cell_child_text_id}update_text_elements
    • ✅ 文本段落:PATCH /blocks/{block_id}update_text_elements
  3. feishu_update_doc 禁止用于含 callout 块的文档:开发复盘文档不含 lark-table,但含有 <callout> 块(type=19),feishu_update_doc 的 markdown 序列化/反序列化会:

    • <callout>> blockquote(结构被破坏,callout 框消失)
    • <text color="orange"> → 普通文本(颜色标记丢失)
    • ❌ 可能引入额外段落(如 # 三、总结
    • 正确做法:所有更新必须使用 UAT Token 直接调飞书 PATCH blocks API,逐元素更新

开发复盘文档填充经验

  1. 替换开发 A/B/C/D/E 标记(模板现含5个槽位):

    • 模板使用 <text color="orange">开发A(</text>工单总数<text color="orange">x</text>个)(超时工单<text color="orange">x</text>个)(B/C/D/E同理)
    • 替换时搜索整个带标记的字符串,替换为 **张姝(工单总数12个)(超时工单5个)**
    • 橙色标记在替换时自动去除,改用加粗(** **)
  2. 模板已有 5 个开发者槽位(开发A-E):最新模板 Secqwa7deiaRwTkUsG6cJ7xpnzj 已直接包含 5 组(开发A/B/C/D/E),每组含 <text color="orange">开发X(工单总数x个)(超时工单x个)</text> + <callout> 块。

    • 直接 PATCH 填满全部 5 个槽位即可(无需 POST 追加)
    • TOP5 开发者按工单数从多到少填入开发A→E
    • ❌ 模板只有3个槽位时(旧版),才需要 POST /children 追加开发D和E

含表格文档的 PATCH API 更新(关键)

⚠️ 核心规则:feishu_update_doc 不可用于含复杂表格的文档

复盘总文档的 Section 3 包含 <lark-table>(带 rowspan/colspan),feishu_update_doc 的任何模式(replace_all、insert_after、delete_range、replace_range、overwrite)都会摧毁表格属性

原因:这些模式先将文档序列化为 markdown 再反序列化,反序列化时 lark-table 的 HTML 属性丢失。

后果示例:

  • cols="11"cols="10"(colspan=2 的合列丢失)
  • rowspan="3" → 消失(每月 3 行不再合并)
  • 表格从 10 行 11 列 → 7 行 10 列

✅ 正确做法:直接调飞书 Docx PATCH API

PATCH /open-apis/docx/v1/documents/{document_id}/blocks/{block_id}
Authorization: Bearer {user_access_token}
Body: {
  "update_text_elements": {
    "elements": [{
      "text_run": {
        "content": "新文本内容",
        "text_element_style": {}
      }
    }]
  }
}

⚠️ update_text_elements丢失格式(bold/orange):新的 text_run 使用空的 text_element_style: {},所以加粗、橙色标记等格式会丢失。如需保留格式,需在 text_element_style 中显式设置 bold: {}inline_code: {color: 25, background_color: 2}(橙色)。

更新顺序不可逆

模板拷贝 → 填表(fill_review_cells.cjs)→ 更新文本(PATCH API)
                 ↑                 ↑
           必须先做             后做

填表(表格单元格级别的 block 操作)必须在任何文本替换之前完成。如果先做文本替换再填表,feishu_update_doc 已经破坏了表格结构。

Block-type-specific 文本属性

通过 PATCH API 读取/更新文本时,不同 block type 的文本存在不同属性中,不是都在 block.text 下:

Block Type描述文本所在属性
2文本段落block.text.elements
3标题1(#)block.heading1.elements
4标题2(##)block.heading2.elements
5标题3(###)block.heading3.elements
12无序列表项(-)block.bullet.elements
14有序列表项(1.)block.ordered.elements

PATCH API 写入统一使用 update_text_elements,不分类型。

Heading 块可以有子节点

飞书文档中,标题块(block_type=3/4/5)可以有 子 children(如 Section 4 的 ## 工单数量分析 就包含 bullet 子节点)。Section 4 的文本不是根级节点,而是 heading 的 children:

// Section 4 的数据需要遍历 heading 的 children 获取:
const rootBlocks = getChildren(document_block_id);
for (const b of rootBlocks) {
  // b.block_type === 4 (heading2)
  // b.txt === '工单数量分析'
  const sectionKids = getChildren(b.block_id);  // ← ✅ 能拿到子节点
  // sectionKids[0].block_type === 12 (bullet)
  // sectionKids[0].txt === '2026-05月共产生工单81个...'
}

但是:表格(type=31)和 callout(type=19)不是任何块的 children,它们始终是文档根层的同级节点。即使它们在视觉上位于某个 heading 下方,API 读取时它们和 heading 是平级关系。

权限与加密

PATCH API 需要 User Access Token(UAT),用 OAuth 方式获取。UAT 加密存储,解密方式:

const d = path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'), 'openclaw-feishu-uat');
const enc = fs.readFileSync(path.join(d, '{appId}_{userOpenId}.enc'));
const masterKey = fs.readFileSync(path.join(d, 'master.key'));
// AES-256-GCM: IV 12 bytes + tag 16 bytes + ciphertext
const iv = enc.subarray(0, 12), tag = enc.subarray(12, 28), cipher = enc.subarray(28);
const decipher = crypto.createDecipheriv('aes-256-gcm', masterKey, iv);
decipher.setAuthTag(tag);
const uat = JSON.parse(Buffer.concat([decipher.update(cipher), decipher.final()]).toString('utf8')).accessToken;

fill_review_cells.cjs 的使用

位置:scripts/fill_review_cells.cjs

配置顶部变量:

const DOC_ID = '新文档 obj_token';
const APP_ID = 'cli_a97b6a0ffc399cc0';
const SENDER_OPEN_ID = 'ou_229ec432e6d99a781896afb23e386ee1';
const CELL_DATA = {
  total: '21',
  noOpt: '11(产研介入7)',
  prodOpt: '0',
  techWork: '0',
  techCheck: '0',
  noTech: '0',
  internal: '10(产研介入3)',
  solved: '已解决4(1)',
  deferred: '延期处理6(2)',
  noRepro: '无法重现:0',
  timeout: '11(3)',
};

脚本会自动填充最近 3 个月(本月 + 前 2 个月)的数据到表格中的对应位置。填写规则见 references/data_mapping.md

文本更新脚本参考

// readText 必须检查所有 block-type 属性
function readText(block) {
  const src = block?.text || block?.heading1 || block?.heading2 || 
              block?.heading3 || block?.bullet || block?.ordered || block?.todo;
  return src?.elements?.map(e => e.text_run?.content || '').join('') || '';
}

// 写入统一用 update_text_elements
async function patchBlock(uat, blockId, newText) {
  const body = {
    update_text_elements: {
      elements: [{ text_run: { content: newText, text_element_style: {} } }]
    }
  };
  const url = `${DOCX_BASE}/${DOC_ID}/blocks/${blockId}`;
  return apiRetry('PATCH', url, { Authorization: `Bearer ${uat}` }, JSON.stringify(body));
}

UAT 与 API 调用

  1. UAT 解密方式

    • 加密文件路径:/state/share/openclaw-feishu-uat/{appId}_{userOpenId}.enc
    • Master key:/state/share/openclaw-feishu-uat/master.key32 字节原始密钥,不需要 SHA256 哈希
    • 解密算法:AES-256-GCM,IV 12 字节 + tag 16 字节 + ciphertext
    • 解密后的 JSON 字段:accessToken(驼峰,不是 access_token
    • fill_review_cells.cjs 已正确实现(fs.readFileSync 直接读 Buffer)
  2. mention-doc 的 token 解析

    • 当用 <mention-doc token="wiki节点token" type="wiki"> 时,飞书 API 会自动解析为实际文档的 obj_token
    • type 也会自动更新(如 wiki → docx 或 bitable)
    • 因此如果后续的 replace_all 索引用的原始 wiki token 找不到内容,很可能已被 API 自动替换
    • 应在每次更新后重新 fetch-doc 确认实际内容

Import 脚本已知 bug

  1. import_to_bitable.mjs 看板创建 bug

    • createKanbanView("按责任人分组") 创建的看板视图没有返回正确的 view_id(返回 undefined)
    • 后续设置 kanban_field_id 时会因 view_id=undefined 而失败
    • 变通方案:脚本跑完后,手动创建看板视图或用 UAT 调飞书 API PATCH /views/{viewId} 设置 kanban_field_id
    • 正确字段 ID:责任人 的 field_id(可通过 list_fields 获取)
  2. FIELD_MAP 硬编码:CSV 列名 "工单状态/修复情况" → bitable 字段名 "工单状态|修复情况"(竖线)。如果 bitable 字段名用了斜杠,需要修改 FIELD_MAP 或重命名字段。

2026-05-06 完整复盘经验总结

以下为 2026-05 月工单复盘全流程中遇到并解决的问题汇总,下次工单复盘前请先通读,避免重复踩坑。


一、Furcas 数据拉取

❗ Cookie 过期处理

Furcas API 登录态不可持久化。每次执行 fetch_furcas.py 前:

  1. 打开浏览器 → F12 → Network → 随便请求 Furcas 页面
  2. 从请求头复制 cookie 请求头完整值(含 acw_tcfurcas 字段)
  3. 更新脚本中的 HEADERS["Cookie"] 变量
  4. 不要只更新部分字段,acw_tc 每次都会变

❗ 解决类别 ID 映射

拉取数据后 fetch_furcas.py 会按解决类别分类写入 CSV,ID 映射如下:

ID类别
1设计如此-无需优化
2外部原因-无需优化
3内部原因-已解决
4内部原因-延期处理
5内部原因-无法重现

二、复盘跟踪表(bitable 操作)

❗ 跟踪表记录创建规范

创建复盘跟踪表记录时:

  • app_token = YMQjwQeWCipABCkl8y7ckZlunQe
  • table_id = tblpygt9n8dqZcsw
  • 年份字段填 2026(单选)
  • 月份字段填 05(单选)
  • 工单总数 = 该月 Furcas 所有工单的总数(从查询结果 count 获取)
  • 复盘工单 = 筛选后需要复盘的工单数(排除设计如此、外部原因-无需优化后)
  • 创建后等待 1-2 秒再 PATCH 其他字段

❗ 字段 ID 映射(跟蹤表)

字段名field_id
工单总数fldg7k4Zb
复盘工单fldBxBSm3x
无需优化fld2Fi7oVD
待产品优化fldQ45Kqj8
外部原因-技术派工fldW8sKSSx
外部原因-需技术排查fldRerqDIp
外部原因-无需技术排查fldVefvMG2
内部原因fldIor3W9R
已解决flde2eaOu
延期处理fldZqWk3G
无法复现fldYplayCE
超时工单数fldTQkMXsW

✅ 工单总数来源

工单总数 字段值来自 Furcas API 返回的总数,不是从导入 bitable 的记录数获取,不是从 CSV 行数获取。导入脚本只导入需要复盘的工单(筛选后的子集),不能当作总数。


三、复盘总文档操作(含表格的文档)

❗ 含 lark-table 的文档禁止用 feishu_update_doc 的任何模式

feishu_update_docoverwritereplace_allappend 模式都会损坏 lark-table(返回 3000/4000515 等错误)。

  • ✅ 正确做法:使用 UAT Token 直接调用 PATCH blocks API,逐格更新单元格文本
  • ✅ 使用 PATCH 更新文本块(heading、text、bullet 等)
  • ❌ 禁止 feishu_update_doc 的任何模式

❗ 表格单元格偏移(110格布局)

每个复盘表格有 110 个单元格:

  • 前 11 格 = 表头行
  • 之后每 33 格 = 一个月的数据
  • Group 0(03月)= cells[11..43]
  • Group 1(04月)= cells[44..76]
  • Group 2(05月)= cells[77..109]

每个月份组 33 格,单元格偏移

偏移(组内)字段
0月份标签row1
1工单总数row1
2-3无需优化(colspan=2)row1
4待产品优化row1
5外部原因-技术派工row1
6外部原因-需技术排查row1
7外部原因-无需技术排查row1
8内部原因row1
9已解决row1
10超时(rowspan=3)row1
20延期处理row2
31无法复现row3

数据数组顺序必须匹配 offset 顺序

// 正确顺序:total(1), noOpt(2), prodOpt(4), techWork(5), techCheck(6), noTech(7), internal(8), solved(9), timeout(10), deferred(20), noRepro(31)
const data = ['516', '147(产研介入55)', '48(产研介入17)', '3(产研介入3)', '72(产研介入53)', '147(产研介入25)', '96(产研介入56)', '已解决38(产研介入16)', '49(产研介入28)', '延期处理47(产研介入31)', '无法复现:11(产研介入9)'];

❗ 月份标签重命名级联 bug(关键!)

不能按顺序逐个改多个月份标签

  • ❌ 错误做法:依次执行 02→03, 03→04, 04→05
    • 改名 02→03 后,原 03 组的标签仍然是 03
    • 第二次操作 03→04 会匹配到 刚改好的那组,而不是原 03 组
    • 导致一个月份被跳过
  • ✅ 正确方案 A:从后往前改(04→05, 03→04, 02→03)
  • 推荐方案 B:一次性全部覆盖写入,无视当前值
    • 用已知正确数据直接覆盖所有三组,每次重新写全部数据
    • 这是最安全的做法

❗ 表头标题行丢前缀

更新 heading1 的 工单总计XX个(按工单数统计) 后,前缀 三、 会丢失。

  • 原因update_text_elements 完全替换了所有元素,前缀在另一个 element 中
  • 修复:更新时要保留完整标题,用 # 三、工单总计x个(按工单数统计)

❗ heading 块用 update_text_elements

  • update_heading1 / update_heading2 / update_heading3 → 返回 1770001 invalid param
  • update_text_elements → 对 heading1/2/3/text/bullet/ordered 都有效
  • 通用原则:所有文本元素的更新一律用 update_text_elements: { elements: [...] }

❗ Section 4 子块遍历

Section 4(工单数量分析等)的 bullet 文本是 heading 的 children,不是根级块。 需要:

  1. 遍历根级块找到 heading(type=4, txt='工单数量分析')
  2. 获取该 heading 的 children(gC(docId, heading.block_id)
  3. 逐个更新这些 bullet 块的文本

✅ 文本更新用 element-level 操作

当 template 有 <text color="orange">x</text> 样式时,不能简单替换整个文本字符串——会丢失颜色样式。

  • ✅ 遍历 elements[],只改 content 不变 style
  • ✅ 如在会议主题中改 1005,保留其余所有 element 的 style 属性

四、Callout 块处理

❗ Callout 块不可通过 API 删除

  • Feishu Docx API 的 DELETE 端点对 type=19(callout/quote)块返回 404
  • DELETE /blocks/{block_id} 对 callout 无效
  • ✅ 变通方案:只清空子节点的文本内容(将其 text element content 设为空字符串)
  • ⚠️ Callout 框本身只能手动在飞书页面删除(选中后按 Delete/Backspace)

五、mention-doc 处理

❗ mention-doc 是内联元素

  • mention-doc 不是独立的 type=33 块(那是独立 mention doc block)
  • 在文本段落中,mention-doc 是 elements[] 数组中的一个 element
  • 同一 element 可能同时有 text_runmention_doc 两个属性

❗ 更新 mention-doc token 的正确方式

PATCH 时需传入完整 element,必须带的字段

{
  "text_run": { "content": "显示文字", "text_element_style": {} },
  "mention_doc": {
    "obj_type": 16,  // 整數!不能传字符串 "wiki"
    "text_element_style": {},
    "token": "UJdQwNdkPidcvKkXZzbcL1tDnaf",  // wiki 节点 token
    "title": "显示标题",
    "url": "https://sqb.feishu.cn/wiki/UJdQwNdk..."
  }
}
  • obj_type整数(16=wiki节点),传字符串会报 99992402 field validation failed

❗ token 会被自动解析

发送 wiki 节点 token 后,飞书 API 会自动解析为实际文档的 obj_token:

  • ⚡ token: UJdQwNdk... (wiki) → UtJCdfO5Iotw... (docx obj_token)
  • ⚡ type: 16 (wiki) → 22 (docx)
  • ⚡ url 保持不变(wiki URL)
  • ⚡ title 会自动从文档实际标题获取,发送的 title 字段被忽略

❗ 显示文本无法通过 API 修改

mention 在文档中显示的文字由文档标题决定,不是由你写入的 text_run.content 或 title 字段决定。

  • ✅ 要改显示文字,必须改文档标题(手工右键重命名)
  • ❌ 通过 PATCH 修改 element 中的 text_run.content 或 mention_doc.title 均无效

六、开发复盘文档操作

❗ 旧版模板只有3个开发槽位(已更新为5个)

模板 Secqwa7deiaRwTkUsG6cJ7xpnzj 已在 2026-05-07 更新,直接包含开发A-E 五个槽位。旧版只有3个时:

  1. 先 PATCH 填满 3 个槽位
  2. 再通过 POST /blocks/{root_doc_id}/children 添加第 4、5 个
  3. 用 UAT PATCH API 更新 3 个槽位的开发者名称和数量(逐元素更新,保留橙色样式)
  4. 再通过 POST /blocks/{root_doc_id}/children 添加第 4、5 个

❗ insert_after 的正确方式(插入兄弟块)

要插入兄弟块不是 POST 到目标块,而是 POST 到父块(根文档 block_id = doc_id):

// ✅ 正确:POST 到父块(文档本身),指定 index
POST /documents/{docId}/blocks/{docId}/children
{ index: 金海轩的索引+1, children: [{ block_type: 2, text: { elements: [...] } }] }

// ❌ 错误:POST 到目标块自己(会把新内容作为金海轩的子块)
POST /documents/{docId}/blocks/{金海轩的block_id}/children

❗ x 是单字母不是 xxx

模板中的占位符是 x(如 工单总数x个),不是 xxx。替换时注意匹配模式。

❗ 排除特定人员

开发复盘 TOP5 必须排除崔文思(技术支持)和蒋达周(运营)。统计开发者时:

  • 先统计每个开发者的工单数
  • 去掉崔文思和蒋达周
  • 取前 5 个填入

七、文档创建与复制

❗ 模板复制后需验证 obj_token

wiki_space_node action=copy 返回的 obj_token 可能字符错位(如 UtJCdfO5IotwUtJCdfO5Iotw 中的 5O 互换)。复制后:

  1. ✅ 立即用 wiki_space_node action=get 验证新节点的实际 obj_token
  2. ✅ 或用 feishu_fetch_doc 直接读节点 token 验证文档是否可访问

❗ 文档创建后有一定延迟

复制创建的文档不会立即就绪。如果立即调用 PATCH 操作,可能返回 4000515 resource not found。 ✅ 建议做法:创建后等待 2-3 秒再操作。

❗ 标题改不了(API 限制)

  • PATCH /docx/v1/documents/{docId}1770001 invalid param(不支持改标题)
  • PATCH /wiki/v2/spaces/{spaceId}/nodes/{nodeToken} → 404(没有 rename 端点)
  • 必须手工操作:在飞书页面右键节点 → 重命名

八、UAT 工具链

❗ 标准 UAT 文件路径

const LINUX_UAT_DIR = path.join(
  process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'),
  'openclaw-feishu-uat'
);
const encFile = path.join(LINUX_UAT_DIR, `${APP_ID}_${OPEN_ID}.enc`);
const masterKey = fs.readFileSync(path.join(LINUX_UAT_DIR, 'master.key'));
const uatToken = JSON.parse(
  decrypt(fs.readFileSync(encFile), masterKey)
).accessToken;  // 驼峰!不是 access_token
  • 不要硬编码 /root/.local/share/,用 XDG_DATA_HOME 环境变量
  • 加密文件命名规则:{appId}_{userOpenId}.enc(冒号替换为下划线)
  • accessToken 是驼峰,不是下划线格式
  • 解密算法:AES-256-GCM,IV=12字节 + tag=16字节 + ciphertext
  • Master key 是 32 字节原始密钥,不需要 SHA256 哈希

九、复盘范围规范

✅ 复盘范围时间格式

复盘类型时间范围
整月复盘当月1日 00:00:00 - 当月最后一日 23:59:59
上半月复盘— 当月15日 23:59:59
下半月复盘当月16日 00:00:00 —

文档中 color="orange" 的复盘范围文本要保持橙底样式,仅改日期文字。


⚠️ 文档命名规范(严格执行,否则重做)

三个文档必须从模板创建,命名必须为:

文档类型模板命名规范(5月示例)
工单数据跟踪表(Bitable)J4tawf06GijvEmkBTSCcdyNynsd智慧门店-2026-05月-工单数据
工单复盘总文档GEqawooPYiDXLWkRKZHcJnLcnFc (wiki节点)智慧门店-2026-05月-工单复盘
开发复盘文档Secqwa7deiaRwTkUsG6cJ7xpnzj (wiki节点)智慧门店-2026-05月-开发复盘文档

顺序:先建数据表 → 拉数据 → 建复盘文档

常见错误:命名带"模版"后缀、用"05-整"格式、忘记创建在对应月份目录下

十一、文档填充规则

表格更新(重要)

  • lark-table文档禁止feishu_update_doc(破坏结构)
  • 使用docx PATCH API更新text block的update_text_elements
  • 结构:table_cell(31) → 110个type32子节点 → 每个含type2 text block

文本更新

  • Feishu文本可能拆成多个text_run元素(每个有独立样式)
  • 判断用elements.map(e=>e.text_run?.content).join('')(完整文本),修改用单个element的content
  • update_text_elements对所有block_type通用
  • type 12是bullet块,元素在.bullet.elements
  • mention_doc不可通过API修改
  • feishu_update_doc 禁止用于含 callout(type=19) 的文档(序列化会破坏callout结构)
  • callout块的内容需通过PATCH其子block的update_text_elements更新,不要替换整个文档

文档标题/命名

  • 创建时在copy request的title参数设置
  • 不能通过API修改已有wiki节点标题
  • 需重命名时:copy新文档+删除旧节点

十二、关键常量表

项目
工单数据(含Furcas) app_tokenYMQjwQeWCipABCkl8y7ckZlunQe
工单汇总表 table_idtblpygt9n8dqZcsw
Furcas工单表 table_idtbln4MvksjBRkGGn
工单数据跟踪表模板(Bitable)J4tawf06GijvEmkBTSCcdyNynsd
2026目录节点(space 7510046829784662017 下)MDK5w5CcGi8RK6kRFMKcuBKLnNg
复盘总文档模板wiki 节点 GEqawooPYiDXLWkRKZHcJnLcnFc
开发复盘文档模板wiki 节点 Secqwa7deiaRwTkUsG6cJ7xpnzj
用户 open_idou_229ec432e6d99a781896afb23e386ee1
App IDcli_a97b6a0ffc399cc0
Space ID7510046829784662017
05月目录节点KAXEwRivKinTfTkshDucvSiGn4g

十三、2026-05-07 追加经验

以下为 2026-05-07 修复 4 月工单数据时发现并解决的问题。

import_to_bitable.mjs 清空步骤有静默失败 bug(致命!)

bug 描述:清空旧数据的 batch_delete API 参数名写错,用的 records 但正确参数是 record_ids。且 try-catch 吞掉了错误,导致清空失败时不停机:

// ❌ 错误(旧代码)
await api("POST", `.../records/batch_delete`, { records: ids });
// 清空失败,错误被 catch 吃掉
// 旧数据继续留在表中,新数据追加写入
// → 每条工单出现 2 遍(304条 = 152 × 2)

修复

  1. 参数名改为 record_ids
  2. 去掉 try-catch,让清空失败直接报错停机 ✅
  3. 导入完成后新增去重步骤(最后一道防线)✅
  4. 去重逻辑:按工单 ID 分组,每个工单只保留 1 条记录 ✅

❗ 多条同名空表被创建(智慧门店-2026-05月-工单数据 × 4)

原因:首次创建 bitable 时没有检查知识库目录下是否已有同名表格。

修复方式:后续复盘时,在创建新 bitable 前必须:

  1. 先搜索「工单数据表」目录下是否有同月名称的表格
  2. 如果有,直接复用,不创建新的
  3. 搜索方式:feishu_wiki_space_node list 列出目录下所有节点,检查名称是否包含目标月份

❗ Mention-doc 指向错误的表格

原因:从模板复制复盘总文档后,文档内的 mention-doc 指向的是模板的占位对象(4月表或模板),不是当前月份的表。

修复方式(已添加 Step 5b 到流程中):

  1. 导入数据后立即更新 mention-doc 链接
  2. 将指向前月份的 bitable mention-doc 改为当前月份的
  3. 将指向模板的 wiki mention-doc 改为实际开发复盘文档节点

❗ UAT 没有 bitable 读取权限

Raw API 调用 /bitable/v1/apps/{token}/tables/{table_id}/records 返回 99991679 Unauthorized

  • UAT 用户授权不包含 bitable:app:readonlybase:record:read
  • feishu_bitable_app_table_record 工具可以正常读取(使用 bot 身份或不同授权路径)
  • ✅ 如果脚本需要用 UAT 读 bitable,需要先 check 权限,否则使用 feishu_bitable_app_table_record 工具

❗ 单个 DELETE 大量记录会超时

去重脚本一次删 152 条记录(逐条 DELETE)因超时被 SIGTERM:

  • 超时阈值约 2 分钟
  • ✅ 分批删除 20 条为一个 checkpoint,每次加 await new Promise(r => setTimeout(r, 50)) 限速
  • ✅ 如果超时,再次运行脚本即可继续删剩余的

❗ feishu_update_doc replace_all 破坏 callout 块(生成 "三、总结")

现象:使用 feishu_update_doc replace_all 更新开发复盘文档后:

  • <callout> 块 → > markdown blockquote(callout 框消失)
  • <text color="orange"> → 普通文本(橙色丢失)
  • 多出 # 三、总结 等异常段落

根因feishu_update_doc 先将文档序列化为 markdown,再反序列化回飞书文档格式。反序列化时:

  • <callout> 被当作 > blockquote 处理
  • 如果 markdown 末尾包含 # 三、总结 等标题,会被当作新段落加入
  • SKILL.md 第10条之前错误地允许了在含 callout 的文档中使用 feishu_update_doc

修复

  1. 从模板重新创建文档 ✅(必须用 copy,不能用 feishu_create_doc 写 markdown)
  2. 所有更新用 UAT PATCH API 逐元素操作,不用 feishu_update_doc ✅
  3. SKILL.md 第10条已更正,明确禁止 feishu_update_doc 用于含 callout 的文档 ✅

❗ 开发复盘文档模板更新为5个开发者槽位(2026-05-07)

模板 Secqwa7deiaRwTkUsG6cJ7xpnzj 在 2026-05-07 更新,"主要人员总结材料"下从3个槽位(开发A/B/C)扩展到5个(开发A/B/C/D/E)。

影响

  • ✅ 复盘流程不再需要 POST /children 追加开发D/E
  • ✅ 直接 PATCH 填充5个槽位即可
  • ⚠️ 旧版3槽位模板已废弃,但SKILL.md保留了旧方法作为参考
  • SKILL.md 第11条已改为"替换开发 A/B/C/D/E 标记"
  • SKILL.md 第12条已更新

❗ 开发复盘文档 Section 1 的 mention-doc 链接需替换(2026-05-07)

复制模板后,开发复盘文档的 Section 1 包含两个指向模板/占位对象的 mention-doc:

# 一、开发复盘文档
- 工单复盘文档:<mention-doc token="GEqawooPYiDXLWkRKZHcJnLcnFc" type="wiki">智慧门店工单复盘模版</mention-doc>
- 复盘表格内容:<mention-doc token="J4tawf06GijvEmkBTSCcdyNynsd" type="wiki">2026-xx月-智慧门店工单数据</mention-doc>

必须替换为:

  1. 工单复盘文档 mention-doc: token → 本次创建的 复盘总文档 wiki 节点 token
  2. 复盘表格内容 mention-doc: token → 当前月份工单数据 bitable token(含 table_id 和 view_id)

变更方式:PATCH 对应 block 的 update_text_elements,修改 mention_doc 的 tokenobj_typeurl

❗ 创建月份工单数据 bitable 的正确方式(2026-05-07)

错误做法(之前踩过的坑):

  1. feishu_bitable_app copy 从模板复制 → 创建独立 bitable(不在 wiki 目录中)
  2. feishu_wiki_space_node create 传 obj_token → 又新建一个空白 bitable(表名 "Table",字段全英文) → 导致 wiki 链接指向空表,数据在独立表里

正确做法(仅需一步):

  1. feishu_wiki_space_node copy 直接将模板节点复制到目标月份目录
    • node_token: "J4tawf06GijvEmkBTSCcdyNynsd"(工单数据表模板)
    • target_parent_token: "{目标月份目录节点token}"
    • space_id: "7510046829784662017" → 直接在 wiki 内创建副本,bitable 结构、字段、视图全部正确

复制后的处理

  1. 重命名 bitable(如 "智慧门店-2026-5月工单数据")
  2. 删除模板自带的 5 条空记录(batch_delete 空记录的 record_ids
  3. 导入 CSV 数据

导入脚本注意事项

  • 表名默认校验为 "工单数据",但模板复制出来的表名是 "数据表" → 用 --name "数据表" 参数
  • 看板视图创建后的 view_id 可能返回 undefined(脚本返回值解析 bug) → 视图实际已创建,可通过 feishu_bitable_app_table_view list 获取 view_id → 手工设置 property: { kanban_field_id: "责任人字段ID" }

开发复盘文档人名占位符规则(2026-05-07)

  • 模板中 开发A( 开发B( 等是人名占位符,不是固定标签
  • 必须替换为责任人实际姓名(如 李文茂(),不是仅替换数字
  • 替换后第一个元素内容从 "开发A(" → "李文茂(",保持橙色样式不变

开发复盘文档 callout 内容规则(2026-05-07)

  • callout 内(分析总结:、超时工单分析:等10个字段)不要填充任何内容
  • callout 应保持模板的占位符状态,留给用户手动填写
  • 如果误填了多行文本,清理时需要:1) 把多余元素全删除 2) 只剩单元素 "分析总结:"