欠料跟踪工作台 · 周更
祥哥(PMC)每周会更新《周交货计划跟踪表-2026》里的出货计划 sheet 和库存 sheet,本技能负责把新数据变成更新后的在线工作台。
固定资产(不要每次重新找)
| 项 | 值 |
|---|---|
| 资料库源文件节点 | FG4QtNXkkxoz8lNZHaXBuL(周交货计划跟踪表-2026.xlsx,约 28MB,160 个 sheet) |
| 备选数据源节点 | YeZmQNBUkouYtqyO7gXAqA(订单交货信息查询6.1-9.13.xlsx);dO0Cz5TCYQyRCmtXmyO8UV(库存26.9.2.xlsx) |
| 已发布页面 nodeId | VkGfwpZZMCGP1otxe1VFny(2026-09-02 重建;原 kVvaIgYKWZ9VfAYbCEUNU2 已被删除) |
| 在线链接 | https://workbuddy.link/p/VkGfwpZZMCGP1otxe1VFny |
| 本地工作目录 | 任意,建议新建 data/ 存中间文件 |
> 若以后源文件被替换/改名,先用 space.searcher.search-nodes --query "周交货计划跟踪表" 重新定位并更新本表。
源数据结构(重要)
同一个 xlsx 里混装三类 sheet,命名随年份重复出现,靠文件名选 sheet 会选错:
- 周计划 sheet:
8.24-9.6、8-19-8.28、12.30-1.15形式(起月.起日-止月.止日)。同一日期区间在文件里可能出现多次(不同年份)。 - 库存 sheet:
26.8.18库存、库存数260511、库存26.6.1形式(名称含"库存")。 - 其它:
工单欠料跟踪、盛美物料跟踪、项目催料、图样工序库、包装装配周出货计划等,不参与计算。
周计划表头(第 2 行):序号 / 客户名 / 下单日期 / 订单编号 / 物料长代码 / 物料名称 / 图号 / 规格型号 / 未交数量 / 单位 / 交货日期 / 追料记录 / 工序 / 图样 / 系统库存 / 出货缺数 / 备注
库存表头:No. / 仓库名称 / 物料代码 / 物料名称 / 图号 / 图号版次 / 基本单位 / 存放位置 / 基本单位数量 / … / 库存状态 / 材质 / 库存天数 / 最后出入库时间
执行流程
数据源①:固美特云FMS(每日 7:30 自动跑,2026-09-02 起)
最省 token 的方式:浏览器自动化跑通后直接 Node.js 脚本,AI 不参与浏览器交互。
前置依赖(一台机器装一次即可):
- 已装 playwright-core + xlsx(SheetJS)于 C:/Users/Administrator/.workbuddy/binaries/node/workspace/node_modules
- 本机 Edge 浏览器:C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe(用系统自带 Edge,不下载 Chromium,最省)
- 注:曾尝试 agent-browser(Rust CLI)但其内置 Chromium 下载在沙箱内反复超时;playwright-core + Edge 是更稳更省的方案
ERP 信息(写死脚本里,不要每次重新找):
- URL: http://<ERP服务器IP>:808/#/login?redirect=%2FMainList
- 账号 <ERP账号>,密码 <ERP密码>,账套「<账套名>」
- 菜单①:业务 → 4.订单交货信息查询
- 查询条件:下单日期+产品交期都清空 = 全窗口(2026-09-02 修正,此前只清产品交期、下单日期默认 08-03~09-02 会漏更早下单的未完成订单;其他不动:订单状态=未结案、订单单行状态=未完成、交付状态=未完成)
- ⚠️ 清空日期必须用 Vue 组件实例:改 input.value / 点清除图标 / 键盘输入 / 面板操作全部无效(组件内部 value 没变,请求参数 OrderDate 仍是旧值)。正确姿势:el.__vue__.value=''; el.__vue__.$emit('input','')(沿 DOM 向上找 6 层 __vue__ 且有 value 属性的节点)。已写死在 daily_export.js 的 clearRange()
- 后台 API 名 ShowSaleOrderFinishQuery(GET /app/apifuncs,参数 index 0-based、pagenation=100 → UI 翻页)
- ⚠️ 订单 API 图号字段名是 CustNo,不是 PartDraw(2026-09-02 踩坑:daily_export.js FIELD_MAP 曾写成 PartDraw: '图号' → API 无此字段 → 每行取 undefined → xlsx「图号」列整列 3689 行全空 → 工作台清单名称下无图号。页面表头「图号」列、库存 API 的图号均同为此 CustNo)。修法:FIELD_MAP 用 CustNo: '图号';build_from_order.py 另加兜底——订单图号为空时回填 --stock 库存文件同物料代码图号(双保险)。验证:图号 100% 补齐、与库存同物料比对 834 条全部一致
- 导出:「导出数据」→ 弹窗「确定」(注意按钮文本是「确 定」字间有空格,按钮严格匹配需去空白后再比)
- 菜单②(库存):仓库 → 5.仓库查询 → 1.库存查询(URL #/MiStockQuery,无 iframe,直接操作主文档)
- 仓库下拉 = 查询面板第 2 个 .el-select(第 1 个是空的、第 3 个物料类别、第 4 个材质)→ 选 CP_成品仓
- 查询按钮文本「查询」;后台 API 名 StockQuery(参数 index 0-based、pagenation 恒 100/页 → UI 翻页)
- 表格关键列(API 字段):PartNo物料代码 PartName物料名称 CustNo图号 Unit基本单位 StockPlace存放位置=库位 StockQty基本单位数量 StockCode仓库编码 StockName仓库名称 StockStateName库存状态 Mat材质 PartSpec规格 MainKind物料类别 inStockDays库存天数 LastOpDate最后出入库时间
- ⚠️ 不要点「导出数据」按钮:与订单页同因,单次导出有 100 行上限("所有行"勾选仍截断)→ 一律走 API 拦截 + UI 翻页拿全量
- ⚠️ 页面底部还有「操作/出入库记录」明细表,也带分页器 → 翻页循环按分页器文本「共 N 条」算好需翻页数,翻够即停,避免点到多余分页器空耗时间(2026-09-02 实测第一次未限次数空翻 61 次耗时 139s,限次数后 17 次 59s)
# 一键完成(推荐,每日自动化同款):库存导出 + 订单导出 + 构建 app_data.js(约 3.5 分钟)
cd "C:/Users/Administrator/WorkBuddy/2026-09-01-14-30-54"
set NODE_PATH=C:/Users/Administrator/.workbuddy/binaries/node/workspace/node_modules
# ① CP_成品仓库存(含库位,1 分钟)
"C:/Users/Administrator/.workbuddy/binaries/node/versions/22.22.2-2/node.exe" "C:/Users/Administrator/.workbuddy/skills/pmc-shortage-workbench/scripts/inventory_export.js"
# ② 订单全窗口导出 + 构建(自动探测最新 库存-CP成品仓-*.xlsx 传给 build,明细带库位;约 2.5 分钟)
"C:/Users/Administrator/.workbuddy/binaries/node/versions/22.22.2-2/node.exe" "C:/Users/Administrator/.workbuddy/skills/pmc-shortage-workbench/scripts/daily_export.js"
# 输出含 [done] app_data.js 已就绪
# 库存行数校验:CP_成品仓 ≈1600(<500 或混入非 CP 编码=仓库筛选没生效,停止报告)
# 订单行数校验:明细 ≥ 3000(全窗口口径;< 1000 说明查询条件没清干净,停止并向祥哥报告)
# 也可用 run_daily.ps1 一步跑完①②(powershell -ExecutionPolicy Bypass -File scripts/run_daily.ps1)
部署(链接不变,需要 open platform token,由 agent 取):
"C:/Users/Administrator/.workbuddy/binaries/python/versions/3.13.12/python.exe" \
"C:/Users/Administrator/.workbuddy/skills/pmc-shortage-workbench/scripts/deploy.py" \
--data "C:/Users/Administrator/WorkBuddy/2026-09-01-14-30-54/data/app_data.js" \
--out "C:/Users/Administrator/WorkBuddy/2026-09-01-14-30-54/欠料跟踪工作台.html" \
--node-id VkGfwpZZMCGP1otxe1VFny --token "$T"
自动化(id 31609bac-de93-4e57-b500-79682f117de8,rrule FREQ=DAILY;BYHOUR=7;BYMINUTE=30)每天 7:30 跑:① inventory_export.js(CP_成品仓库存)→ ② daily_export.js(订单全窗口 + 构建,自动带最新库存)→ agent 取 token → ③ deploy.py → 报告结果(含行数校验:库存<500 / 明细<1000 即停)。
已知约束(v2 已突破 100 行限制):ERP 单次导出上限 100 行(弹窗里「所有行」已默认勾选但仍限制)。daily_export.js v2 通过拦截 /app/apifuncs API 响应 + UI 翻页拿全量(pagenation=100、index 是 0-based 页码不是行偏移;signature 与请求参数绑定,手动改参重发会报「未定义的功能」,必须靠 UI 翻页生成新签名)。行数校验:全窗口口径下明细应 ≥ 3000 行;若 < 1000 行说明查询条件未清空(OrderDate 仍带默认窗口),停止并报告。
2026-09-02 全窗口实测(下单日期+产品交期都清空,风险口径已统一为「交期优先」):3732 行 / 翻页 38 次 / 未交合计 101802 / 下单日期覆盖 2024-06-14 ~ 2026-09-02 / 明细 3732 行 / 物料 1585 项 / 订单 665 单 / 逾期 344 / 3天内 62 / 本周 87 / 待核 452 / 1周后 93 / 齐套 547 / 缺口合计 42210(app_data.js 1256 KB)。已部署线上。Python cnt 与页面「全部」状态 KPI 已一致(playwright 验证:344/62/35%/452 全命中)。
2026-09-02 v11 起(图号补齐修复):根因 = daily_export.js FIELD_MAP 把订单 API 图号字段错写成 PartDraw(实际是 CustNo),导致写出的订单 xlsx「图号」列整列全空(3689/3689),工作台清单「名称 / 图号」列只剩物料名称。修复:①daily_export.js 改 CustNo: '图号';②build_from_order.py 订单图号为空时回填库存同物料代码图号。实测:订单 xlsx 图号非空 3689/3689(100%)、app_data.js 物料 1560/1560 + 明细 3689/3689 全带图号、与库存同物料比对 834 条 0 差异(version=11,线上已校验 200)。教训:写 API 字段映射前先 dump 一次真实响应字段名,别按页面中文列名猜英文名(PartDraw 猜错 vs CustNo 实际)。
2026-09-02 v10 起(库存数据源切到每日 ERP 的 CP_成品仓导出,含库位):库存 1612 条 / 翻页 17 次(59s)/ 库存命中物料 846(原内联列仅 518,覆盖面更大)/ 逾期 351 / 3天内 65 / 本周 99 / 待核 452 / 1周后 93 / 齐套 525 / 缺口合计 42336(app_data.js 1408 KB,version=10,线上已校验 200)。明细/物料行/订单展开/详情弹窗/CSV 均带库位(格式 X424×674);库存 tab 显示全部 1612 条 CP 仓记录并支持按库位搜索。
数据源②:订单交货信息查询文件(手动/资料库下载)
前置:客户端模式下先 ToolSearch{tool_names:["connect_open_platform"]} → DeferExecuteTool 取 token(约 30 分钟有效)。下面把 token 记为 $T。
SK="C:/Users/Administrator/.workbuddy/skills/pmc-shortage-workbench/scripts"
PY="C:/Users/Administrator/.workbuddy/binaries/python/versions/3.13.12/python.exe"
# 1 从资料库下载新源文件(nodeId 见固定资产表;文件名带日期,每次可能不同)
# 用 space_api.py search-nodes 定位最新「订单交货信息查询」文件,get_download_link.py 取链接后
# 用 python urllib 下载(curl 长 URL 会截断导致签名失效,务必用 Python 下载)
# 2 生成数据(脚本内置列映射,直接跑;可加 --stock 指定 CP 仓库存文件,缺省回退订单内联库存列)
"$PY" "$SK/build_from_order.py" --src "data/订单交货信息查询6.1-9.13.xlsx" --out data/app_data.js
# 完整口径(带库位):--stock "data/库存-CP成品仓-2026-09-02.xlsx"
# 若文件改名/换列:改脚本顶部 SRC / 列 idx 映射
# 3 部署(链接不变)
"$PY" "$SK/deploy.py" --data data/app_data.js --out 欠料跟踪工作台.html \
--node-id VkGfwpZZMCGP1otxe1VFny --token "$T"
数据源③:周交货计划跟踪表(原流程)
前置:客户端模式下先 ToolSearch{tool_names:["connect_open_platform"]} → DeferExecuteTool 取 token(约 30 分钟有效)。下面把 token 记为 $T。
SK="C:/Users/Administrator/.workbuddy/skills/pmc-shortage-workbench/scripts"
PY="C:/Users/Administrator/.workbuddy/binaries/python/versions/3.13.12/python.exe"
# 1 下载源表
"$PY" "$SK/fetch_plan.py" --token "$T" --out data/delivery.xlsx
# 2 先核对自动识别的 sheet 是否正确(必须看这一眼)
"$PY" "$SK/build_data.py" --xlsx data/delivery.xlsx --list
# 3 生成数据(确认 sheet 无误后)
"$PY" "$SK/build_data.py" --xlsx data/delivery.xlsx --out data/app_data.js
# 识别错了就手工指定:--plan "8.31-9.13" --stock "26.9.01库存"(plan 只传本周最新那一张)
# 非当天跑数加 --date YYYY-MM-DD
# 4 生成 HTML + 更新已发布页面(链接不变)
"$PY" "$SK/deploy.py" --data data/app_data.js --out 欠料跟踪工作台.html \
--node-id VkGfwpZZMCGP1otxe1VFny --token "$T"
只更新本地文件不给 token 也行:deploy.py --data … --out …(跳过上传)。
首次发布(页面被删了要重建):去掉 --node-id,脚本会新建并返回新 nodeId —— 记得回来更新本文件的「固定资产」表。
部署后端到端校验(避免误判"页面已被删除")
deploy.py 在 publish 成功后会自动跑两段验证(可加 --no-verify 关闭):
1. 短链 https://workbuddy.link/p/{nodeId} GET 应返回 HTTP 200,且 HTML 含 __PUBLISH_BOOTSTRAP__
2. 从 bootstrap 解析静态资源 base URL,GET janus.data.json 与 index.html 均应 HTTP 200
⚠️ 看截图报"页面已被删除或不存在"时的排查清单(2026-09-02 立)
这不是页面真被删了,是 workbuddy.link 套壳 SPA 的鉴权抖动。只要下列任一项成立,工作台就是好的:
| 检查 | 命令 | 期望 |
|---|---|---|
| 短链 HTTP 状态 | curl -sL -o /dev/null -w '%{http_code}' <短链> |
200 |
| 静态 janus 资源 | 从 bootstrap 解析 url 后 curl <base>/janus.data.json |
200 |
| 静态 index 资源 | 同上 curl <base>/index.html |
200 |
| 工作台 DOM 树非空 | wc -c janus.data.json |
> 100 KB |
| Playwright 截图 iframe 1280×900 | playwright + 本机 Edge 全屏截图 | 能看到 KPI/筛选/明细 |
真实根因:workbuddy.link 的 React SPA 启动时调 /space/api/page/share/userinfo,未登录返回 code 11607 "not login";SPA 某些渲染分支(特别是用户浏览器缓存了旧 bootstrap 或 CDN 一次性抖动)会显示"该资源已被删除或不存在"占位 UI(对应 publish.api.error.resourceNotFound 文案),但 iframe 内的工作台其实正常加载。
解决办法:浏览器强刷(Ctrl+F5),或点 SPA 套壳右上角"回 WorkBuddy 继续聊"按钮离开再回来。如果对照表格短链/静态资源都 200,不用动 SKILL 或重新发布。
自动识别规则(改脚本前先读这段)
- 周计划候选 = 含「物料长代码」表头的 sheet;用表内「下单日期/交货日期」的年份众数推断年份,只保留与基准日期同年的。
- 当前周 = 起始日期 ≤ 基准日期中最大的那张;只取这一张(祥哥 2026-09-01 确认:周计划只取本周最新计划,不叠加上周)。
- 库存 = 名称含「库存」且解析日期最大的一张(支持
yy.m.d/yymmdd/m.d)。 - 若最新周计划的结束日已过期,脚本会打印
[警告] …报表可能尚未更新到本周—— 看到就提醒祥哥确认是否还没更新。
数据源②结构(订单交货信息查询)
SheetJS 单 sheet,表头第 1 行(部分列头导出为 0,实际含义由数据反推已验证):
| idx | 含义 | idx | 含义 |
|---|---|---|---|
| 1 | 客户名称 | 10 | 产品交期(YYYY-MM-DD) |
| 3 | 客户订单号 | 12 | 库存数量(已核实 = 库存26.9.2) |
| 5 | 物料名称 | 13 | 物料代码 |
| 6 | 图号 | 38 | 规格 |
| 8 | 未交数量(=订单数量-已交数量,即需求) | 41 | 交货完成否 |
> 下单日期(列名直接取,2026-09-02 起加入供时间筛选;不再依赖列位序)
口径(方案A,2026-09-02 祥哥选定):取全窗口未完成订单(未交数量>0),交期已过的自动进「逾期」红色警示。库存默认 = 每日 ERP 库存查询 CP_成品仓导出(inventory_export.js → build --stock,含库位);仅当没有该文件时才回退订单文件内联库存列。2026-09-02 起每日 ERP 自动化下单日期+产品交期都清空 = 真全窗口(覆盖 2024-06-14 起所有未完成订单,3732 行 / 未交合计 101802;此前默认下单日期窗口 08-03~09-02 只有 1520 行,会漏更早下单的未完成订单——已修正)。手动上传的《订单交货信息查询6.1-9.13.xlsx》为 1737 行,仅覆盖 6.1~9.13 下单的订单,窗口比每日自动化小。
计算口径(改动需先跟祥哥确认)
- 需求 = 本周最新周计划 sheet「未交数量」按物料汇总(只取一张 sheet):
- 同一 sheet 内「交期+数量」完全相同的行 = 重复录入,只留一条
- 同订单+同物料但交期不同 = 分批交期,累加
- 库存 = 每日 ERP「仓库→1.库存查询」CP_成品仓导出(inventory_export.js 产物,1612 条含库位)按「物料代码」精确匹配多库位求和;item/明细/订单展开带
loc(库位串,格式A12-2-2×90、X424×674,同库位自动合并) - 命中率约 53%(846/1585,2026-09-02 实测;比旧内联列 518 覆盖面更大),未匹配的多是零件/外协件,成品仓里本来就没有,属正常现象(页面标「未匹配」可手工填库存覆盖)
- 无 --stock 时回退订单文件内联库存列(旧口径,无库位)
- 图号带
-DRW-xxx后缀的不要做去尾段模糊匹配,实测不提命中率 - 缺口 = 需求 − 库存,> 0 即欠料
- 风险分级(2026-09-02 统一口径,Python build_from_order.py 与模板 riskOf 完全一致):交期优先,库存「未匹配」不降级——逾期/3天内/本周是客观事实(未交>0 且交期临近/已过),与库存表是否命中无关;未匹配另有「未匹配」标签列提示。
- 判定顺序:缺口 ≤ 0 → ok;交期 < today → over 已逾期;交期 ≤ today+3 → urgent 3天内;交期 ≤ today+7 → soon 本周;其余(交期 >7天 或 空交期)→ 库存命中(live) → later >1周,未匹配(none) → chk 库存待核
- 注意:模板 riskOf 的 gap 用
stockOf()(考虑页面手工覆盖 S.ovr),Python 用原始 k——手工覆盖后页面数字实时变化属预期,不属口径差异
页面说明
assets/template.html 是页面骨架,数据占位符为 /*__DATA__*/,deploy.py 负责注入。改页面样式/功能直接改模板,下次部署自动生效。
四个模块:今天要处理(置顶)· 欠料清单(物料维度)· 订单齐套分析 · 实时库存查询。
源数据是静态快照内嵌;用户填的处理状态/手工库存/追料记录存在浏览器 localStorage,有导出备份/导入恢复/导出 CSV。
日期筛选(2026-09-02 上线 · 9 月 2 日 13 时增加手动输入)
工作台有「日期筛选」条(位于 tabs 下方),上方快捷按钮:全部 / 近1月(30天) / 近3月(90天) / 近6月(180天) / 近1年(365天) / 近2年(730天)。下方手动输入行(输入即生效 + 「应用」/「清空」按钮):
下单日期 [起] ~ [止] · 客户交期 [起] ~ [止]
- 作用范围:物料/订单/KPI/今天要处理/图表/欠料清单/订单齐套 全联动(库存 tab 自动隐藏筛选条,库存快照与日期无关)。
- 快捷按钮与手动输入二选一:点击快捷按钮会自动清空手动框;手动输入框变化(change 事件)会自动应用。
odRange实时显示当前生效条件,如「下单 2026-07-01 ~ 2026-09-02 · 交期 ≥ 2026-09-01」。 - 交期 = 产品交期(det.d 字段),UI 标签写「客户交期」与 ERP 查询条件一致。
- 实现要点(前端重聚合,不要只用 IT.filter()):按明细行
det.od与det.d过滤后重新聚合物料/订单,保证物料级缺口 = 范围内订单缺口合计,与展开明细一致。直接对 IT/OD 过滤会因 k(库存)重复计数导致缺口虚高。 - 数据字段(Python build_from_order.py 已带上):
det.od每行下单日期、det.d每行产品交期(ISO 字符串)items.od该物料最近一次下单日期orders.od该订单最早下单日期meta.odMin / odMax全数据下单日期范围- 输入解析:
<input type="date">原生日历 + 手输;parseD()兼容 2026/9/1、20260901、2026-09-01 等格式,校验失败返回''等同于不限。 - 避坑:
- click 委托里
closest()选择器必须包含[data-od],否则按钮点不响应(2026-09-02 v1 漏选,已修复)。 - 手动框设置了交期筛选时,空交期行不计入(交期未定的订单不属于任何交期区间),其它情况下空值视为不限。
- 起止日期校验:开始 > 结束时 toast 拒绝并保留原筛选状态。
已知待优化
- ~~ERP 单次导出上限 100 行~~ → 已解决(2026-09-02):daily_export.js v2 用 API 拦截 + UI 翻页拿全量;v2.1 下单日期也清空 → 全窗口 3732 行(未交合计 101802)
- ~~库存快照只有一个成品仓且缺库位~~ → 已解决(2026-09-02):每日 ERP 自动导出 CP_成品仓全量(1612 条·含库位),明细可显示库位;仍只覆盖成品仓,原材料/半成品/外协仓未接入,导致「未匹配」仍占约一半。若祥哥要并入其它仓,把 inventory_export.js 的仓库下拉从 CP_成品仓 改为全仓/多仓即可(StockCode 校验段需同步放宽)
- 页面未接资料库数据表,追料状态无法多设备同步;需要时再升级
- 下单日期筛选档位只覆盖到 2 年,更老的订单只能在"全部"里看(实际意义不大,2024 年起的订单数稳定)