Excel to HTML — 过程工程计算 HTML 工作流
> 本 Skill 固化了我(灵犀)在将 Excel 工程计算表转化为单文件 HTML 过程中积累的所有经验。
核心概念
将过程工程计算(Excel / VBA / 手工公式)转化为单文件 HTML 应用,具备专业工业 UI、双主题、SVG 可视化图标、实时计算和导出功能。
输入来源
- Excel (.xlsm):含 VBA 计算逻辑
- 工程标准公式文档(HG/T、GB、API 等)
- 现有计算表格/电子表格
输出文件
- 单文件 HTML:内嵌 CSS + JavaScript,零外部资源(禁 CDN、禁外链字体/图片/图标;确需第三方库时把源码内联进文件并保留其许可证声明)——⚠️ 硬约束,见 Step 6
- "可离线使用"以此为准,不得以"CDN 除外"放宽
- 双主题支持:
- 亮色模式:绿松石 #2aa889 + 琥珀 #e7a642(清爽专业风,默认)
- 暗色模式:科技深邃风(霓虹青 #00E5FF + 紫蓝 #7B61FF)
源文件校验原则(必须先执行,第 0 步)
> ⚠️ 核心原则:发现源文件逻辑错误时,先暂停任务,提醒用户修正原始 Excel,绝不直接在 HTML 中将错就错。
执行流程
- 提取公式后、开始转换前,必须对所有关键公式做合理性校验
- 发现可疑点时(数值异常大/小、单位换算可疑、与标准公式不符),立即暂停
- 暂停动作:
- 向用户明确列出可疑公式的位置(单元格坐标)
- 说明可疑原因("数值大了 1000 倍" / "单位换算方向可能反了")
- 提醒用户先去修正 Excel 源文件
- 等用户确认 Excel 已修正后,再重新提取公式、继续转换 - 禁止行为:
- ❌ 不在 HTML 中"悄悄修正" Excel 的错误公式
- ❌ 不假设"可能是用户故意这样写的"而直接照抄
- ❌ 不在未告知用户的情况下,用"我认为正确"的数值覆盖源文件逻辑
- ❌ 不虚构工作簿中不存在的数值(输入默认值必须来自源文件或用户确认)
- ❌ 不修改/覆盖原始 Excel 文件(只读转换)
典型可疑信号(遇到立即暂停)
| 信号 | 示例 | 行动 |
|---|---|---|
| 计算结果数量级异常 | 孔板数量 = 528 块(正常应为 1~3 块) | 暂停,提示用户检查公式 |
| 单位换算常数可疑 | /10^6 但上下文是 kPa→MPa(应为 /10^3) |
暂停,列出原始公式让用户确认 |
| 与标准公式明显不符 | HG/T 公式应为 √(2ΔP/ρ),实际写的是 ΔP/2ρ |
暂停,给出标准公式对比 |
| 常数值无来源 | 公式里出现 16484 但标准里是 128.45 |
从 XML 提取原始公式,让用户确认 |
提示用户的话术模板
⚠️ 发现源文件公式可疑,已暂停转换:
[单元格坐标]:[原始公式]
可疑原因:[具体说明]
正确应为:[标准公式或合理值]
请先修正 Excel 源文件中的公式,保存后告诉我,我再重新提取并继续。
工作流步骤
Step 1: 读取 Excel 理解计算逻辑
Step 0.5 前置结构勘查(多 sheet 场景必做):
1. 先列全部工作表名 + 各 sheet 角色:数据表 vs 计算书(信号:计算书行少、标签多、含合并单元格;数据表行多、结构规整)
2. 识别命名区域(named ranges)与 VBA 模块清单
3. >3 个 sheet 时问用户转哪些,除非有明确名为"计算书/计算/Calc"的 sheet(默认它并说明假设)
4. 输出勘查清单后再进入提取,防多 sheet 场景漏转
主体步骤:
1. 用 Python zipfile 读取 .xlsm 内部结构
2. 提取 VBA 代码 (xl/vbaProject.bin)
3. 识别关键计算函数及其参数含义
Step 2: 提取计算函数并转换为 JavaScript
将 VBA 函数逻辑改写为 JavaScript,注意:
- VBA 数组索引从 1 开始 → JS 从 0 开始
- Application.WorksheetFunction → 原生 JS Math API
- 保持与 Excel 一致的计算精度
关键函数对照:
| VBA / Excel | JavaScript | 功能 |
|---|---|---|
Application.Pi() |
Math.PI |
π 常数 |
Sqr() |
Math.sqrt() |
平方根 |
Atn() |
Math.atan() |
反正切 |
WorksheetFunction.Acos() |
Math.acos() |
反余弦 |
Int() / Fix() |
Math.floor() / Math.ceil() |
取整 |
Step 3: 创建 HTML 基础结构
参考 assets/html-template.html 模板,包含:
- Head: 零外部资源——图表用内联 SVG/Canvas;确需第三方库(图表、导出)时把库源码内联进 HTML,并在文件内保留其许可证声明
- CSS Variables: Design Tokens 配色方案
- Body: 布局 + 输入卡片 + 结果展示 + 图表区域
- JavaScript: 计算函数 + 事件监听 + 图表渲染 + 导出功能
Step 4: 应用配色方案与 UI 组件
选择配色方案(见 references/color-schemes.md),并根据需要添加:
- SVG 工业图标可视化面板
- 合并式输入组件
- 响应式布局
- 实时计算模块
溯源 Footer(必做):页面页脚标注 源文件: {原始文件名} · 转换日期: {YYYY-MM-DD} · 计算基准: {标准号如 HG/T 20570.5-95}(小字号、低调配色)——工程计算书的版本追溯刚需,交接/审计时可查数据来源。
⚠️ 阶段升级/重建必须同步更新 Footer 的阶段名与点位数(v2.4.0,G7)——Footer 是写死文本,从早期阶段继承后会静默失真:CHEF 实证 P1~P4 四个产物 Footer 全停在「P1 · 25 842 点位」,而 P4 实为 90 728。判据:Footer 阶段名 == 文件名阶段 且 点位数 == 该阶段对拍合计。
Step 5: 验证计算精度(三态验证门——未过门不得标交付)
- 对比 HTML 输出与 Excel 原数据(openpyxl
data_only=True实测值),逐单元格出对比表 - 确保误差 < 0.001;测试边界条件(零值/极值/负值)
源头验证层(v2.2.0 新增,先于三态门):HTML vs Excel 验证只证明"实现一致",补关键公式 ↔ 规范原文对照(如 HG/T 20570/GB 相应条款)核实 Excel 公式形式与系数是否抄对——Excel 本身可能有笔误/改版残留,规范原文才是权威;仅凭 Excel 公式与 HTML 一致不能排除"两个都错"(同源错误)。用户无规范原文时,结论标注置信度。
基准可信性 + 归因三条(v2.5.0 补,先于"设阈值对拍"):
- 先体检基准自身——上面那条的前提是"规范原文拿得到"。拿不到而想拿存量当基准时,先证基准可信:实测某存量化工表的液体密度系数算得 144 kg/m³(真值 ~1460,差 10 倍)。基准自身有错时,据此设的验收阈值必然导出错误结论。
- 双源互证定责——用两个独立来源交叉核对同一量:两者一致而与基准不符 ⇒ 基准错;两者互斥 ⇒ 该项降级或剔除,不硬判。一个新物质能否入库,看的是"两个独立源是否互证",不是"能否复现存量"。
- "换参数无效"判据(划分"实现问题"与"源差异")——把可疑差异在多个参数下重跑(实测:8 个候选温区逐一拟合)。若量级/结论不变(实测中位误差恒在 1.59–1.75%),则差异来自数据源沿革而非本实现,不应返工实现;若随参数显著变化,才回查实现。
> 📌 配套:数据提取环节的静默损坏见 references/pitfalls.md 坑点 9;往存量表追加新行时的去重与合规尺见坑点 10。
三种结论,只能标一种:
| 状态 | 判定 | 交付动作 |
|---|---|---|
| ✅ 交付 | 全部关键单元格误差 < 0.001,边界测试通过 | 正常交付 HTML |
| ⚠️ 带缺口交付 | 个别单元格无法验证(如源文件未保存缓存值) | 交付但明确列出未验证项 |
| ⛔ 不交付 | 任一关键单元格误差超限且定位不到原因 | 不交付,附对比表 + 排查方向,回 Step 1 重建映射 |
数值显示规范(JS 浮点经典丑角):显示层必须格式化——0.1+0.2=0.30000000000000004 直接上屏 = 不专业。用 toFixed(n) 或有效数字 + 单位(工程数值一般 3-4 位有效数字);比对验证用容差(Math.abs(a-b)<0.001),绝不用 === 比浮点。
Step 5.5: 交付前五道门(v2.3.0 新增四门;v2.6.0 补 E 门)
> 把"产物对不对"拆成互不蕴含的五道门,各报各的(来源:外部对比)。配方细节 → references/verification-toolkit.md
| 门 | 查什么 | 手段 |
|---|---|---|
| A 确定性 | 数值/结构正确、字节确定 | Step 5 三态门 |
| B 离线自包含 | 外部子资源集合为空 | Step 6 |
| C 运行时行为 | 页面真能跑、交互真成立 | Step 7 |
| D 人工感知 | 版式、可读性、视觉可用 | 人(或读图模型)真看渲染结果;无读图能力 → D0 机器代偿 |
| E 视口机检 | 各视口无溢出、逐变体均可辨 | references E 节(probe_template.js) |
铁律:A 通过不蕴含 C(数据全对但页面白屏,CHEF 实证);A+C 不蕴含 D;D 不蕴含 E(视觉可读 ≠ 各视口都装得下、各变体都看得出区别)。绝不在未真正查看产物时报 D 通过;无读图能力不得直接报 skipped——按 references D0 走机器代偿(凡可量化的视觉事实必须代偿)。未执行的门必须显式报 skipped——省略状态词本身就会让读者以为五门都过了(CHEF 4.5 承接复核轮实证)。
> ⚠️ E 门是 v2.6.0 补进来的:此前"四道门"没有一道管视口与变体,而实测教训表明同一页面不同风格变体的可辨性可以差到有的过有的不过——只跑默认态会全绿放行(双控文化墙任务,2026-09-18)。
> 📌 门字母以本节为唯一规范(A 确定性/B 离线自包含/C 运行时行为/D 人工感知/E 视口机检);references/verification-toolkit.md 按此对齐——v2.4.0 前其回执模板 B/C 错位、漏整道 B 门,其 D 节又用 D 指「COM 对拍台」= 同一字母两处三义(G1)。
> ⚠️ D 门截图必须配 DOM 探针(G3):headless 截图不捕获 JS 生成的面板——CHEF 实测 30 s 预算 + 3600 px 视口正文仍全空白,而 jsdom 探针显示默认 Tab 已渲染 223 行;只看截图会把捕获 artifact 误判成白屏。配方见 references D 节。
状态词:passed(真实执行且通过)/partial(仅 D 门机器代偿用,见 references D0,不许在 A/B/C/E 门使用)/failed(真实执行且发现缺陷)/skipped(仅当环境不具备,须写明缺什么)。
⚠️ 禁止把"运行失败/采集中断"归一化成 skipped —— 失败就是 failed。
证据绑定:报告必须记录被验证文件的 SHA-256 + 字节数(Get-FileHash -Algorithm SHA256)——对中间产物验证却交付了另一个文件,"验的不是交付的那份",哈希是唯一能证伪的手段。
⚠️ 并且必须写进「交付件/交接件本身」(HANDOFF、README-P*.md、交付说明)——只写在会话报告里,下一轮承接方与审计方拿不到,风险照旧(G2)。CHEF 4.5 实证:交接件只记字节数 1 259 593 B、无哈希,承接方无法证伪"验的是交付的那份",补算 85AAF86A…53E3 回填后才闭合。ray-handoff 铁律 3 与本条配套。
修正轮次上限 2 轮:两轮聚焦修正后仍不过 → 停下汇报(防无限返工掩盖真实设计问题)。回执含 artifact_sha256 / artifact_bytes / correction_rounds 等字段,模板见 references A 节。
Step 6: 离线自包含断言(交付前必做)
判据:外部子资源集合必须为空 —— <link rel=stylesheet/preload/…>、@import、url(//…)、src/srcset/poster/data、SVG <image|use|feImage href> 全算,<iframe srcdoc> 递归查。
三条易错(别凭印象写):⚠️ 必须解析(parse5/DOMParser)而非正则扫全文——注释与脚本串里的 URL 会误报、srcdoc 会漏检;⚠️ 远程判定须覆盖协议相对 //host/path(/^(?:https?:)?\/\//,最常见漏网形态);⚠️ 失败处理是把资源内联(字体 base64/库源码贴入/图标改内联 SVG),不是删断言或放宽判据。
脚本:node assets/check_offline.mjs <产物.html>(零依赖,附 4 项工程化护栏)。拒绝清单见 references B 节。
> ⚠️ 本节修掉一处自相矛盾:description 承诺"可离线使用",此前 Step 3 却要求引 CDN,且从无测试证明。
Step 7: 运行时行为冒烟测试(交付前必做)
> 数据/公式全对,页面仍可能整体不可用。 CHEF 4.5 实证两个真 bug 在数据层验证下结构性不可见:localStorage 未包 try → file:// 下主题初始化中断、整页脚本连崩白屏;navigator.clipboard 未探测 → 非安全上下文抛未捕获 TypeError。
做法:jsdom 在真 DOM 加载产物 + 跑交互断言(npm i -D jsdom,仅开发期)。
必测 6 项:无未捕获异常/容器渲染出预期数量子元素/搜索筛选与数据口径一致/结果与 Step 5 基准一致/API 缺失时走降级不抛错/主题与 Tab 切换生效。
断言纪律(防"假 PASS"):失败必须返回 false,禁止返回描述串冒充通过;不写"命中数 > 0"式无脑门槛,要写"与数据口径一致";剔除环境噪声(如 jsdom 未实现 scrollTo)须显式列出被剔除项;⚠️ JSDOM 必须传 url——不传退化成 opaque origin 致 localStorage 抛异常,失败的是环境不是产物。
无 node 环境 → 报 skipped (node/jsdom unavailable),不得报 passed。骨架见 references/verification-toolkit.md C 节。
Excel 转 HTML 公式映射与验证规范(V1.2 泵系统项目经验)
> 本章节固化从 HG/T 20570.5-95 泵系统计算书 Excel → HTML 过程中积累的公式对齐经验。
> 适用场景:任何涉及多工况(正常/设计)、多模块、复杂单元格引用的工程计算表转换。
核心原则:逐个单元格映射,逆向推导工况属性
必须建立 Excel → HTML 的逐单元格映射表,不能仅凭变量名"感觉"对应。Excel 中经常出现跨工况混搭引用,必须逆向推导每个单元格实际使用的工况。
映射表模板
| Excel 单元格 | Excel 公式 | 实际工况 | HTML 变量名 | 说明 |
|---|---|---|---|---|
| F29 | =dP2_d+dPe2 |
正常工况 | dP2_design_excel + dPe2_design_excel |
设计可变压降(仅管道,不含恒定压力) |
| F30 | =F27+F29 |
设计工况 | discharge_constP + F29 |
设计管路总压降 = 恒定压力 + 可变压降 |
| F31 | =F32-F30 |
设计工况 | dP_cv_n = F32 - F30 |
控制阀压降 = 设计泵排出压力 - 设计管路总压降 |
| P22 | =10*Va*(γ/F31)^0.5 |
正常工况 | 10*Va*Math.pow(gamma/dP_cv_n, 0.5) |
Cvc 计算 |
| P23 | =P22/CV |
正常/设计混合 | Cvc_normal / CV |
Cvc/CV 比值(分子正常,分母设计) |
| P24 | =F31/F29 |
设计/正常混合 | dP_cv_n / F29 |
S 比值(分子设计,分母正常) |
工况标注规则
- 正常工况:下标通常省略或使用
n(如dP2_d= 正常流量下的排出管道压降) - 设计工况:下标通常用
d或design(如dP2_design= 设计流量下的排出管道压降) - 混合工况:分子分母可能来自不同工况,必须分别标注
验证方法:Python openpyxl 双模式提取
import openpyxl
# 模式 A:提取公式(data_only=False)
wb_formula = openpyxl.load_workbook('泵系统计算书.xlsx', data_only=False)
ws = wb_formula.active
print(f"F29 公式: {ws['F29'].value}")
print(f"F30 公式: {ws['F30'].value}")
# 模式 B:提取计算值(data_only=True,需要 Excel 先打开保存过)
wb_value = openpyxl.load_workbook('泵系统计算书.xlsx', data_only=True)
ws_val = wb_value.active
print(f"F29 值: {ws_val['F29'].value}")
print(f"F30 值: {ws_val['F30'].value}")
验证流程:
1. 先用 data_only=False 提取所有公式,建立映射表
2. 手动在 Excel 中执行计算(确保公式被求值)
3. 用 data_only=True 提取实际数值
4. 对比 HTML 输出与 Excel 实际值,逐单元格验证
对拍台升级:Excel COM 实算(v2.3.0 新增)
缓存值通常只有一个工况,随机 + 边界工况对拍才能证明引擎正确(每模块 ≥20 组:正常/边界/极值/零值,全中间列比对——只在终点比,差异定位不了)。
四条硬性注意:⚠️ 用 app.Calculate(),绝不用 CalculateFull()(后者在含外部链接的工作簿上实测卡死 10 分钟,换掉后 13 秒完成);⚠️ 只清理本次新建的 COM 进程 PID(Stop-Process -Name EXCEL 全杀会误杀用户的 Excel 会话,已实际发生);⚠️ 开副本须 AskToUpdateLinks=False + Open(UpdateLinks=0, ReadOnly=True) + AutomationSecurity=3;⚠️ 只操作副本,源文件全程只读,收尾 Close(SaveChanges=False)。
骨架与坑表见 references/verification-toolkit.md 「COM 对拍台」节(v2.4.0 前该节编号为 D,与 Step 5.5 的 D 门(人工感知)撞字母,已去编号)。
> ⚠️ 四类高频坑(跨工况混搭引用 / 单位标注与实际量纲不符 / 阈值系数凭印象 / 宽屏 auto-fill 左侧空白)的「现象-根因-修复」全文见 references/pitfalls.md「泵系统公式对齐坑点」——数值或版式异常时先读它。
参考资料
- 计算公式与推导:
references/formulas.md - 配色方案详细定义:
references/color-schemes.md - HTML/CSS/JS 模板库(按需加载):
references/templates.md——UI 可视化设计规范(SVG 图标/Valve Grid 面板)、管道压力降设计规范(HG/T 20570.7-95)、实时计算模块、通用 UI 规范(字体/主题切换/标题/徽章)、导出功能(Excel/PDF + 中文乱码方案) - 验证工具箱(按需加载):
references/verification-toolkit.md——交付回执模板与五态状态词(A)/离线自包含拒绝清单(B)/运行时冒烟骨架与断言纪律(C)/人工感知评审配方与假信号(D)+ 无读图能力的 D0 机器代偿路径/视口机检判据(E:逐变体 E1 + 纵向放行条件 E2)/COM 对拍台配方与坑表(无编号) - 变更记录(按需加载):
references/changelog.md——v2.0.0 起逐版变更(含门字母统一 G1、哈希持久化 G2 等口径沿革) - 坑点与经验(按需加载):
references/pitfalls.md——坑点 1-4(JS null/缺 try-catch/oninput 绑定/DOM ID 重复)、坑点 5(Edge tip 表格列丢失)、坑点 6(工程标准关系图处理)、坑点 7(检查器自身的缺陷三类)、坑点 8(验证的三类假信号)、坑点 9(数据提取层的静默损坏——提取代码改坏数据)、坑点 10(扩充存量表——身份键去重 + 拿存量惯例当合规尺);另有「泵系统公式对齐坑点」与「COM 对拍台」
模板文件与脚本
- 基础 HTML 模板:
assets/html-template.html - 离线自包含断言脚本:
assets/check_offline.mjs(Step 6 用;node assets/check_offline.mjs <产物.html>) - D0/E 门的现成实现(外置,避免本 skill 重复造轮子):
ray-doc-toolbox的assets/probe_template.js(无头 Edge 渲染量测:多视口溢出 / 像素采样含两道落点守卫 / 文本断言 / 逐变体 click 采样 / 控件遍历回退 / 高清截图,配置驱动 +--selftest)+assets/struct_check_html.py(结构体检,零依赖);工序与采样纪律见该 skill 的references/html-visual-sop.md。⚠️ 用前先--selftest证检查器可信。
中英双语界面规范
所有按钮和状态文字均采用 英文(风格化)+ 中文 的双语格式:
| 状态 | 英文(风格化) | 中文 | 完整显示 |
|---|---|---|---|
| 计算按钮(正常) | EXECUTE CALCULATION |
执行计算 | EXECUTE CALCULATION · 执行计算 |
| 计算按钮(实时中) | REAL TIME CALCULATING |
自动计算中... | REAL TIME CALCULATING 自动计算中... |
| Toast 成功 | — | — | ✅ 计算完成 |
| Toast 错误 | — | — | ⚠️ 计算出错: xxx |
原则:英文部分保留风格化(全大写、紧凑字母间距),中文部分紧随其后,用 · 或空格分隔。
快速命令
# 查看 XLSM 内部结构
python -c "import zipfile; z=zipfile.ZipFile('file.xlsm'); print(z.namelist())"
维护记录
> 历次版本变更详见 references/changelog.md(v2.0.0 起)。