param 表更新工作流(xlsx → md)
适用场景
- "把这个 xlsx 转成 md,更新 param_xxx.md"
- "对比一下 param 表和 workstation-review,看有没有不一致"
- "我在 xlsx 里用删除线标了要删的记录,帮我处理"
- "把这次改动记录到 param_change_history.md"
定位
处理结构化设备参数表(机器人/容器/货架/充电桩/工作站等)从 Excel 到 Markdown 数据文件的同步,典型用于 HPS3/HPC 等产品线选型算法的数据源维护(如 business-flow-config-design.md 类文档 §4 会直接引用这些 param 表)。不负责 PRD 正文撰写,那是 write-a-prd / lark-workflow-prd-sync 的职责——如果 param 更新最终要反映到 PRD 正文,本 skill 只把结论准备好,落到哪份规格文档由用户决定。
前置
- Python3 +
openpyxl(读取带样式的 xlsx,用于识别删除线)+pandas(转 Markdown 表格,to_markdown依赖tabulate) - 目标
.md文件已存在且是「## sheet名」分节结构(按 sheet 名对齐替换整个分节,不做逐行 diff 合并) - lark-cli(Step 4 同步飞书
param_change_history文档时需要;参考../lark-shared/SKILL.md做认证) - 项目里需要知道
param_change_history对应的飞书文档 token/URL(通常记在本地param_change_history.md的 frontmatter,或直接问用户要)
固定四步流程
Step 1: xlsx → md(清除删除线记录)
│
▼
Step 2: 与规格文档(workstation-review 等)逐条比对差异
│
▼
Step 3: 整理更新清单 → 用户审批 ──[驳回/修改]──┐
│ │
[批准] │
│◄─────────────────────────────────────────┘
▼
写入 param_hps3.md / param_hps5.md(或对应 HPC 文件)
│
▼
Step 4: 变更记录写入本地 param_change_history.md + 同步 append 到飞书对应文档
关键约束:Step 1/2 只做只读分析,不修改任何 param_*.md。只有 Step 3 用户明确批准后,才允许写入。 这是与 v1.0 版本最大的区别——旧版本在生成差异后即直接写入,新版本强制过一道人工审批闸门再落盘。
Step 1 — xlsx → md:清除所有带删除线的记录
不能只用 pandas.read_excel(会丢失删除线等格式信息)。用 openpyxl.load_workbook(path, data_only=True) 逐 sheet、逐 cell 读值,同时读 cell.font.strike:
import openpyxl
wb = openpyxl.load_workbook(xlsx_path, data_only=True)
for name in wb.sheetnames:
ws = wb[name]
header = [c.value for c in ws[1]]
rows = []
for row in ws.iter_rows(min_row=2):
values = [c.value for c in row]
strikes = [bool(c.font and c.font.strike) for c in row]
rows.append((values, strikes))
处理规则:只要一行里存在带删除线的非空单元格,这一行就整体从转换结果里删除(不再区分"整行删除线"与"单元格级删除线"两种情况——这是本版本相对 v1.0 的简化:v1.0 曾对单元格级删除线做"保留整行仅备注废弃"的特殊处理,但实践中容易和用户的真实意图产生分歧,v2.0 统一按用户可见的删除线视觉信号执行删除,删除范围以什么记录为准由 Step 2/3 的清单向用户说明并接受审批)。
判断为空需要小心:一行里如果所有非空单元格都没有删除线,正常保留;只要出现至少一个非空单元格带删除线,整行标记为待删除,不写入转换结果。
转 Markdown 时的格式坑:
- xlsx 整数被 pandas 读成
float64会在 md 里多出.0(如600.0)——转换前对照目标 md 文件已有格式,必要时对列显式转型(如.astype('Int64'))。 - JSON/富文本字段(如
chargerRatio里的 JSON 数组字符串)不要被自动转义或截断,原样保留。 - 每个 sheet 对应目标 md 文件里的「## sheet_name」二级标题分节,替换时只换表格内容,保留标题。
Step 1 产出(暂存,不写入正式文件):转换后的候选 md 内容 + 一份"本次删除了哪些记录"清单(sheet 名、productNumber/productName、简要说明),供 Step 3 呈现给用户。
Step 2 — 与规格文档逐条比对差异
如果项目里有一份「人可读」的规格梳理文档(如本项目的 prd/2026/7/workstation-review.md),把 Step 1 的候选 md 内容与之逐字段核对:
- 数值型字段(切箱时间、效率区间、部署距离等):直接比大小,标出具体不一致的数字
- 覆盖范围:param 表有的记录,规格文档是否体现了对应档位/场景(反之亦然)
- 先排除「假差异」:若按单一 key 去重后比对,同一 key(如
productNumber)对应多行(国内版/CE 版各一条)会被误判成新增或差异。比对前先确认 key 是否唯一,不唯一就按完整字段集比对。 - 警惕来源版本落后的情况:如果新 xlsx 是基于比当前 md 更早的版本整理的(比如仍带着上一轮已清理掉的冗余记录),不要整表覆盖——只提取真正变化的字段/记录,避免把之前已确认的清理/归类工作撤销。判断方法:对比新旧行数与已知的历史清理记录,如果候选转换结果的行数明显多于当前 md 且多出来的行正是历史记录里标注过要删除的,就要提醒用户"这份 xlsx 疑似基于旧版本整理"。
Step 3 — 整理更新清单,交用户审批
把 Step 1(删除了什么)+ Step 2(比对出的差异/待更新字段)合并成一份结构化清单,格式建议:
删除的记录(N 处):
| Sheet | productNumber/productName | 说明 |
新增/变更的字段(M 处):
| Sheet | productNumber | 字段名 | 旧值 | 新值 |
未变化部分:xxx
呈现清单后停下来,明确请求用户批准("以上改动是否批准写入 param 表?"),不要自行决定写入。任何字面表述可能有歧义的地方(比如用户说"删除工作站"但删除线其实也覆盖了货架/充电桩记录)都要在清单里单独标注出来问清楚,不要自己判断按哪种理解处理。
用户批准后(可能是全部批准,也可能是部分调整后批准):
- 按最终确认的内容写入目标
param_hps3.md/param_hps5.md(或项目里对应的其他 HPC/HPS param 文件) - 只替换涉及改动的「## sheet」分节,其余分节保持原样不动
Step 4 — 变更记录:本地 + 飞书双写
4.1 本地
在项目的变更历史文档(如 .raw/param_change_history.md;不存在则先创建)里追加新版本块(版本号在已有文件基础上递增),固定包含:来源、删除记录表(如有)、新增/变更字段表(如有)、归类/结构调整说明(如有)、未变化部分。如规格文档(workstation-review 等)也因本轮变更同步修改,在它自己的变更记录章节里另加一条,两处变更记录不要合并成一份。
4.2 飞书
param_change_history.md 若已有对应的飞书文档(token/URL 记在 frontmatter 或由用户提供),把本轮新增的版本块同步过去:
# 用 markdown 格式 append 到文档末尾,避免 overwrite 抹掉之前的历史记录
lark-cli docs +update --api-version v2 \
--doc "DOC_TOKEN" \
--command append \
--doc-format markdown \
--content @_v{N}_content.md \
--as user
必须用 append,不能用 overwrite——overwrite 会清空之前版本的记录、评论等内容。写入内容前留意 Markdown 转义规则(-、#、|、~ 等符号在特定位置需要转义,尤其 productNumber 里常见的 -;具体规则见 lark-cli 内置的 skills read lark-doc references/lark-doc-md.md)。
--content @file 只接受当前工作目录下的相对路径,写临时文件时放在 cwd 下(如 ./_v{N}_content.md),append 成功后删除。
若项目里还没有 param_change_history 对应的飞书文档,先问用户是否需要新建(可用飞书文档导入类工具把本地 md 首次导入生成飞书文档,并把返回的 token 记录到本地 md 的 frontmatter 里,供以后 append 使用)。
Step 5(可选)— 输出总结
给用户一份简短总结:"本轮删除了 N 条记录、更新了 M 个字段、已写入 param 表、变更记录已同步本地与飞书",附关键差异表格。
参考实现
本 skill 总结自 pst/layout 项目 2026-07-28/29/30 的多轮实际迭代(该项目 .raw/param_change_history.md 记录了完整过程:v1 新增字段 → v2 规格核对修正 → v3 双循环归类清理 → v4 单字段精确更新),可作为字段命名、判断阈值等细节的参照案例。