Install
openclaw skills install @chenzhe223-tech/quotationalyasize多项目(同批供应商、同一询价口径)报价对比看板生成器,输出「中英双语可切换的自包含 HTML 看板 + 结构一致的 Excel」。适用于一次询价覆盖 2 个及以上子项目,需同时呈现回标状态、逐项目明细、工期门槛判定、条款对比、待澄清清单、分项目价格排序与「满足工期前提下价格最低优先」的定标建议,且明确不做跨项目合计的场景。数据层与渲染层严格分离,HTML 与 Excel 共用同一份数据层,口径永不发叉。
openclaw skills install @chenzhe223-tech/quotationalyasize把「一批同口径询价的多家回标」变成「一份可决策的双语看板 + 一张可存档的 Excel」。
本技能不含任何真实门店/供应商名称,全部由数据层驱动;换项目、换供应商数量、换货币、换工期门槛都不需要改渲染代码。模板自带可跑的脱敏示例(2 个项目 × 3 家供应商),python gen_board.py 即可出图。
| 场景 | 用本技能 | 改用 |
|---|---|---|
| 同一批供应商、多个子项目横向比价(报价 + 工期 + 条款 + 定标建议) | ✅ | |
| 单项目、多供应商、需要「分部分项 + 单方造价 + 异常核查 + 历史门店对比」 | ➖ | bid-quote-cockpit |
| 只要一份轻量「双方案/多方案价格对比」可视化(成本构成堆叠条 / 周期时间轴 / tradeoff 结论卡) | ➖ | bilingual-price-compare |
| 某家澄清/修订后报价回灌既有对比表 | ➖ | bid-quote-clarification-sync |
| 两家 Excel/BOQ 逐行机械比对 | ➖ | excel-quote-compare |
与 bid-quote-cockpit 的关键区别(选型要点):
| 维度 | multi-project-quote-board(本技能) | bid-quote-cockpit |
|---|---|---|
| 项目数 | 多项目并置(本项目核心) | 单项目为主 |
| 跨项目合计 | 明令禁止,分项目独立定标 | 不涉及 |
| 定标逻辑 | 内置工期门槛 + 最低价判定(7.1–7.5) | 侧重总价排名/异常核查,定标为可选模块 |
| 配置方式 | 直接改 Python 数据层(dict) | 填 config.json / quotes.json |
| 交付物 | HTML + 结构对齐的 Excel(6 sheet) | HTML(+ 可选) |
| 依赖 | 纯标准库出 HTML;Excel 需 openpyxl | 需内联 echarts |
共用红线:只用报价原文数字,禁止补全/估算/同口径估算;勾稽
生产 + 运输 + 安装 == Total必须全通过。
SK=~/.workbuddy/skills/multi-project-quote-board
# 1. 复制模板到工作目录
cp $SK/scripts/gen_board.py ./gen_board.py
cp $SK/scripts/gen_excel.py ./gen_excel.py
# 2. 改 gen_board.py 顶部 DATA LAYER(只改这一处!)—— 项目/供应商/报价/工期/条款/待澄清
# 然后出 HTML 看板
python gen_board.py # → board.html(自带中英切换)
# 3. 用同一数据层出 Excel(务必用带 Pillow 的解释器,若含图片)
python gen_excel.py # → board.xlsx(6 个 sheet)
运行成功标志(务必核对):
=== RECON (Unit+Transport+Install==Total): ALL OK ===
WROTE board.html bytes=...
WROTE board.xlsx bytes=...
RECON不是ALL OK→ 先修数字,不要交付。每一条prod+trans+inst != total的明细都会打印RECON FAIL: <key> <pid> {...}。
gen_board.py
├── ① DATA LAYER (上半部,标 "DATA LAYER —— 唯一手工维护区")
│ BOARD_TITLE / PROJECTS / SUPPLIERS / QUOTES / LEAD_* / TERMS / CLAR / TRANS_NOTE
│ ⋮
│ # ============================ DATA LAYER END ============================
└── ② RENDER LAYER (下半部,读数据层出 HTML,一般不动)
gen_excel.py
读 gen_board.py → split("DATA LAYER END")[0] → exec 复用同一数据层 → 出 6 sheet
为什么这样设计: HTML 与 Excel 是两份交付物,若各自硬编码数字,迟早「HTML 改了 Excel 没改」。把数据层做成唯一的真源、Excel 生成器 exec 复用,口径在物理上不可能发叉。改一个报价只需改 QUOTES 一处。
DATA LAYER END 这行标记是契约:gen_excel.py 靠它切分。删掉或改写这行,Excel 生成器会直接 SystemExit。
| 变量 | 作用 | 修改要点 |
|---|---|---|
BOARD_TITLE | (中文标题, English title) 二元组 | H1 与 Excel 标题、<title> 同步 |
TENDER_DATE / INVITED_COUNT | 发标日 / 邀请家数 | 只用于总览副标题,不参与计算 |
PROJECTS | [{id,name,area,qty}] 子项目列表 | id 是 QUOTES 的键,一旦定下不要改 |
SUPPLIERS | [{key,name,color,status,date}] | status: received / pending(顺序即条款表列序,见 §6 坑 1) |
QUOTES | {key:{pid:{prod,trans,inst,total}}} | 四值须满足 prod+trans+inst==total;只有原文数字 |
TRANS_NOTE | {(key,pid):"已含在运输费用中"} | 驱动明细表数字格的三态文案(见 §7) |
LEAD_START | 统一起算日(下单日) | 定标工期门槛的基准 |
LEAD_DEADLINE | 安装完成截止日 | 完成日 <= 此日 → 满足工期 |
LEAD_SPAN | {key:{pid:天数}} 自起算至完成总天数 | 严格取自报价原文 |
LEAD_ABS_END | {key:{pid:date}} 绝对日期排期者 | 绝对日期者不顺延(见 §8) |
LEAD_BASIS / LEAD_BASIS_PID | 工期依据原文(中英) | 进「7.1 工期满足性判定表」的依据列 |
TERMS | [(中,英, 各供应商取值…)] | 每条取值个数 == SUPPLIERS 个数,顺序对齐 |
CLAR | [(级别,中,英)],级别 P0/P1/P2 | 自动按 P0→P1→P2 排序 |
SUPPLIERS 加 dict + QUOTES 补该项目条目 + TERMS 每行补一列 + TRANS_NOTE/LEAD_SPAN/LEAD_BASIS 补键。渲染层无需动。status 保持 "pending",看板自动渲染「待回标」占位行,不影响任何计算(RECV_KEYS 只含 received)。QUOTES 数值 → 最低标高亮、差额、排序、定标结论全部自动重算。| # | 板块 | 内容 |
|---|---|---|
| 一 | 回标状态与总览 | KPI 卡(已回标家数 / 各项目「满足工期+报价最低」)+ 供应商状态表 |
| 二 | 逐项目明细对比 | 生产 / 运输 / 安装 / Total / vs 最低;数字格三态(见 §7) |
| 三 | 工期(Lead Time)对比 | 各家所报工期 + 起算推算完成日 + 是否满足 |
| 四 | 条款对比 | 材质工艺 / 运输口径 / VAT / 付款条件… |
| 五 | 待澄清清单 | 按 P0 > P1 > P2 排序 |
| 六 | 各项目价格排序 | 纯价格排序,每项目独立一行,绝不做跨项目合计 |
| 七 | 定标建议 | 工期判定 + 满足者按价排序 + 推荐结论 + 需澄清 + 前置条件 |
| 八 | 扩容说明 | 数据层改动指引(写进看板,便于团队自查) |
本节(及全板)禁止把两个项目的总价加总。理由(已写入看板第六节说明):不同项目的工程量与交付条件不同,合并总价无决策意义。若要表达「打包」,只能单列 what-if,且必须明确标注为情景假设、不进排名。
对应地:KPI 按项目拆成独立卡片、第六节删掉「两项目合计」行、7.3 结论按项目独立定标。Excel 侧同样(01 回标状态 无合计列、06 定标建议 无合计行)。
TERMS 取值顺序必须 == SUPPLIERS 顺序TERMS 每行是 (中, 英, v1, v2, v3…),v1…vn 按 SUPPLIERS 顺序一一对应。若顺序错一位,整列条款错位且不报错(静默错误,最危险)。
% 格式化大段 HTML 会炸渲染层把整页 HTML 拼成一个字符串。若正文里出现 width:100%、%s 等,与 Python 的 % 格式化冲突 → TypeError: not enough arguments for format string,且产物静默为空。
模板的解法:标题用 token 占位 @@TITLE@@ + .replace("@@TITLE@@", …),不用 % 拼标题。你新增含 % 的文案时,沿用局部拼接或 .replace(),别整段 %。
运输/安装列取值只有三种合法形态:数字 / 已包含在运输费用中 / 未报价待澄清。由 cell_state() 依据 QUOTES 值 + TRANS_NOTE 自动派生,不要在数据格里手写中文(会把数字列变成文本列,Excel 求和/排序失效)。
判定三原则(看板第七节顶部固定文案):
LEAD_START(下单日)起算。LEAD_DEADLINE 前完成安装 → 满足;不能 → 列入「需请对方澄清」(⚠️ 不是直接淘汰)。实现函数(渲染层,Excel 侧同样实现一份):
def lead_result(k, pid):
# 绝对日期排期者不顺延;其余 = 起算日 + 总天数
est = LEAD_ABS_END[k][pid] if (k in LEAD_ABS_END and pid in LEAD_ABS_END[k]) \
else LEAD_START + dt.timedelta(days=LEAD_SPAN[k][pid])
return {"days": …, "est": est, "ok": est <= LEAD_DEADLINE, …}
def sched_lowest(pid):
cand = sorted([k for k in RECV_KEYS if satisfied(k, pid)],
key=lambda k: QUOTES[k][pid]["total"])
if not cand: # 无人满足 → 回退纯最低(并须在看板提示)
cand = sorted(RECV_KEYS, key=lambda k: QUOTES[k][pid]["total"])
return cand[0], QUOTES[cand[0]][pid]["total"], cand
第七节固定结构(老板认可的清晰版式,勿改顺序):
7.0 判定规则三条(灰底 info 卡)
7.1 工期满足性判定表(项目 × 供应商:所报工期 / 依据原文 / 完成日 / 是否满足)
7.2 满足工期的候选 —— 按报价排序(首位绿底 rec-row)
7.3 定标推荐结论(逐项目卡片:推荐 + 报价 + 备选)
7.4 需请对方澄清(工期不满足)—— 列出超出天数
7.5 定标前置条件(P0 未闭环不按当前价定标;起算日需各家认可)
KPI / chip 口径必须与定标口径一致:项目卡右上角「✓ 当前报价最低(工期满足+报价最低)」、KPI 卡取值都走 sched_lowest,不能显示纯最低价那家(否则会出现「KPI 说 A 最低,第七节却推 B」的自相矛盾)。
绝对日期特例(LEAD_ABS_END):某些供应商给的是绝对排期(如「X 月 X 日完成」),不随统一起算日顺延。这类必须放进 LEAD_ABS_END,否则会被错误地按「起算日 + 天数」平移。
<span class="zh">中文</span><span class="en">English</span>(模板封装为 Z() / E() / BI(zh,en))。#lzh / #len + body:has(#lzh:checked) .en{display:none} 等 CSS 规则实现切换。自检:zh span 数应等于 en span 数(模板示例 134 = 134)。不等 → 有段落漏了英文或漏了中文。
| 用途 | 要求 |
|---|---|
| 出 HTML | 任意 Python 3(纯标准库:os / datetime / html,无第三方依赖) |
| 出 Excel | openpyxl |
| Excel 嵌图(可选) | 必须用带 Pillow 的解释器,否则图片静默跳过(产物 media=0) |
本机固定用 venv 解释器(Pillow 10.4.0 + openpyxl 3.1.5):
C:/Users/admin/.workbuddy/binaries/python/envs/default/Scripts/python.exe gen_excel.py
托管的基础解释器 3.13.12 无 PIL:
openpyxl.drawing.image.Image会全部静默跳过,xlsx 体积明显偏小(如 18KB)且无图片。出图必须走上面这个 venv 解释器。
=== RECON … ALL OK ===(每条明细勾稽通过)board.html 已生成,浏览器打开:中/英切换正常,两语字数相等LEAD_START / LEAD_DEADLINE 全文一致,无残留旧日期board.xlsx 6 个 sheet 齐全,条款表列顺序 == 供应商顺序scripts/gen_board.py —— 数据层 + 渲染层模板(可直接改,含脱敏示例)scripts/gen_excel.py —— 复用数据层出 6 sheet Excelreferences/pitfalls.md —— 踩坑与修复记录(% 格式化、条款错位、图片静默跳过、双语不等长等)关联技能:bid-quote-cockpit(单项目重看板)、bilingual-price-compare(轻量双方案对比)、bid-quote-clarification-sync(澄清回灌)、excel-quote-compare(机械比对)、bid-price-analysis(商务标分析表)。