← Back to Skills Marketplace
runkecheng

Forces Reanalyze Smart

by runkecheng · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
35
Downloads
0
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install forces-reanalyze-smart
Description
完成智慧门店工单复盘全流程。触发词:工单复盘、复盘工单、拉取工单数据、创建复盘文档、工单分析、创建复盘。完整覆盖三个阶段:(1)拉取Furcas工单数据并导入多维表格 (2)创建/更新工单复盘总文档 (3)创建开发复盘文档并填充TOP5统计。当用户要求进行工单复盘时使用。
README (SKILL.md)

智慧门店工单复盘全流程

流程概览

一次完整的工单复盘涉及 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 ID cli_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 获取的精确结构:

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

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

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

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

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

# 四、工单总结
## 工单数量分析
- \x3Ctext color="orange">2026-04\x3C/text>月共产生工单\x3Ctext color="orange">646\x3C/text>个,本次复盘筛选出\x3Ctext color="orange">154\x3C/text>个工单。同比\x3Ctext color="orange">2026-03\x3C/text>月\x3Ctext color="orange">增加25.19%\x3C/text>
- 从**解决类别**看,工单主要集中在:\x3Ctext color="orange">外部原因-无需技术排查(208)、设计如此-无需优化(160)、外部原因-需技术排查(81)\x3C/text>
- 从**解决模块**看:工单主要集中在:\x3Ctext color="orange">收银系统-餐饮(197)、打印机(150)、扫码点单(117)\x3C/text>

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

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

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

📌 模板关键位置标注

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

📌 Section 5 月份命名规则

  • 表头显示「目标月-1」和「目标月-2」的跟进事项
  • 例如:05月复盘 → 显示 **2026-04**月跟进事项**2026-03**月跟进事项
  • 月份部分用橙色标签包裹:\x3Ctext color="orange">**2026-03**\x3C/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 的表格是 \x3Clark-table> 格式(带 rowspan/colspan 的复杂表格),不能用 markdown 表格替代。 使用 overwrite 模式重写文档时,表格结构会丢失。因此 Section 3 必须保留原始 \x3Clark-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个(按工单数统计) 下方自带一个 \x3Clark-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 的文本包含大量橙色标记(\x3Ctext 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项,缺一不可!)

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

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

# 二、主要人员总结材料
\x3Ctext color="orange">开发A(\x3C/text>工单总数\x3Ctext color="orange">x\x3C/text>个)(超时工单\x3Ctext color="orange">x\x3C/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(内容为x x 该人工单总数 5
末尾 text_run(内容为x x 该人超时工单数 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: "个)"}
]

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

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

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

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

责任人的选取规则

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

数据获取方式

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

填充方式

  • 使用 UAT 调飞书 Docx PATCH API 逐元素更新,不要用 feishu_update_doc(会破坏 \x3Ccallout> 块)
  • 通过 PATCH update_text_elements 替换橙色占位符的 x,保留 \x3Ctext 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 变量:开发复盘文档的 \x3Ctext color="orange">x\x3C/text> 占位符必须用 UAT PATCH API 逐元素更新(保留橙色样式),禁止用 feishu_update_doc replace_all(会破坏 \x3Ccallout> 块)。复盘总文档的 x 同样用 PATCH API 更新。
  6. 责任人排除:开发复盘 TOP5 统计需排除崔文思、蒋达周
  7. 文档排版:从模板复制后,确认文档结构完整。当前模板(2026-05起)已无 callout 提示块,无需手动删除

模板结构守则

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

    • 会议信息的 会议主题 / 会议时间 各占一行
    • 会议议程的 **复盘时间:** / **复盘范围:** / **参与人员:** 各自独立成段
    • 参与人员列表用 - 无序列表格式
    • 开发复盘文档的 callout 中每个冒号标题独占一行,> 前缀必须保留
    • ⚠️ 复盘总文档模板(2026-05 版本)已无 callout 块,Section 3 标题后直接是 \x3Clark-table>
  2. feishu_update_doc 禁止用于含表格的文档:复盘总文档的 Section 3 包含 \x3Clark-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,但含有 \x3Ccallout> 块(type=19),feishu_update_doc 的 markdown 序列化/反序列化会:

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

开发复盘文档填充经验

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

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

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

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

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

复盘总文档的 Section 3 包含 \x3Clark-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 解析

    • 当用 \x3Cmention-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 有 \x3Ctext color="orange">x\x3C/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_token YMQjwQeWCipABCkl8y7ckZlunQe
工单汇总表 table_id tblpygt9n8dqZcsw
Furcas工单表 table_id tbln4MvksjBRkGGn
工单数据跟踪表模板(Bitable) J4tawf06GijvEmkBTSCcdyNynsd
2026目录节点(space 7510046829784662017 下) MDK5w5CcGi8RK6kRFMKcuBKLnNg
复盘总文档模板 wiki 节点 GEqawooPYiDXLWkRKZHcJnLcnFc
开发复盘文档模板 wiki 节点 Secqwa7deiaRwTkUsG6cJ7xpnzj
用户 open_id ou_229ec432e6d99a781896afb23e386ee1
App ID cli_a97b6a0ffc399cc0
Space ID 7510046829784662017
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 更新开发复盘文档后:

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

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

  • \x3Ccallout> 被当作 > 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:

# 一、开发复盘文档
- 工单复盘文档:\x3Cmention-doc token="GEqawooPYiDXLWkRKZHcJnLcnFc" type="wiki">智慧门店工单复盘模版\x3C/mention-doc>
- 复盘表格内容:\x3Cmention-doc token="J4tawf06GijvEmkBTSCcdyNynsd" type="wiki">2026-xx月-智慧门店工单数据\x3C/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) 只剩单元素 "分析总结:"

Usage Guidance
Review carefully before installing. Only use this skill in the intended Furcas and Feishu workspace, rotate/remove the bundled Furcas cookie, verify which Feishu OAuth account will be used, confirm APP_TOKEN/TABLE_ID/DOC_ID/month values before running scripts, and back up Feishu tables before any clear/delete/import step.
Capability Analysis
Type: OpenClaw Skill Name: forces-reanalyze-smart Version: 1.0.0 The skill bundle is classified as suspicious due to the presence of a hardcoded session cookie in `scripts/fetch_furcas.py`, which constitutes a credential leak vulnerability. While the bundle's logic—including data fetching from Furcas and automated document/Bitable updates in Feishu via `scripts/import_to_bitable.mjs` and `scripts/fill_review_cells.cjs`—is consistent with the stated goal of work order review, the inclusion of sensitive credentials in plain text is a high-risk practice. The `SKILL.md` provides detailed operational instructions and technical constraints to ensure the AI agent performs the multi-step workflow correctly, but it does not contain evidence of malicious prompt injection or unauthorized data exfiltration.
Capability Tags
cryptorequires-oauth-tokenrequires-sensitive-credentials
Capability Assessment
Purpose & Capability
The overall Furcas data pull and Feishu review-document workflow is coherent, but bundled scripts contain a non-empty Furcas session cookie and hard-coded Feishu document/month/data, so the capability is not safely limited to the installing user's requested review.
Instruction Scope
The workflow authorizes creating, updating, clearing, and deleting Feishu Bitable records and document content. Some safeguards exist, but one script continues even after detecting a table-name mismatch.
Install Mechanism
The registry says there is no install spec and no required credentials or env vars, while the skill includes Python/Node scripts that require Furcas cookies, Feishu OAuth token storage, and APP_TOKEN/TABLE_ID-style configuration.
Credentials
The scripts read sensitive local Feishu OAuth token files and use a bundled Furcas cookie to access internal ticket data; this is high-impact access that is not adequately declared or scoped.
Persistence & Privilege
The skill modifies persistent Feishu tables and documents, including deletion/replacement of records, and reads persistent local token stores without clear account selection or containment.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install forces-reanalyze-smart
  3. After installation, invoke the skill by name or use /forces-reanalyze-smart
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
forces-reanalyze-smart v1.0.0 - Initial release: fully automates the end-to-end process for "智慧门店工单复盘" (smart store work order review). - Covers three major stages: (1) Fetch and import Furcas work order data to Feishu multi-dimensional tables, (2) Create/update overall review documentation, (3) Create technical review docs with TOP5 statistics. - Strict record de-duplication and validation enforced at every step, especially for tracking and data documents. - Thorough instructions and field requirements to prevent common input, time, and duplication errors. - Scripted data import, mention-doc updating, and template handling to ensure correct references and formatting.
Metadata
Slug forces-reanalyze-smart
Version 1.0.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

What is Forces Reanalyze Smart?

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

How do I install Forces Reanalyze Smart?

Run "/install forces-reanalyze-smart" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Forces Reanalyze Smart free?

Yes, Forces Reanalyze Smart is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Forces Reanalyze Smart support?

Forces Reanalyze Smart is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Forces Reanalyze Smart?

It is built and maintained by runkecheng (@runkecheng); the current version is v1.0.0.

💬 Comments