# 版本记录(观澜·如东样板 v2)
> 本文件由 `scripts/version_log.py` 生成,**勿手改**:事实(版本号、级别、变更)写在
> `src/version.py` 的 `HISTORY` 里,改完跑 `python scripts/version_log.py --write`。
> `guanlan.py check` 与打包器都会校验本文件与代码里的版本号是否一致。
## 版本号规则(用户令 2026-09-17)
编号 **`v<大版本号>.<中版本号>.<小版本号>`**,例如 `v2.81.5`。
| 级别 | 含义 |
|---|---|
| 大版本号 | 系统解决方案、架构或核心功能改变 |
| 中版本号 | 非核心功能新增、减少、修改 |
| 小版本号 | 消缺完善 |
**怎么改**:改动落在"解决方案/架构/核心功能" → 大 +1(中/小归 0);落在"非核心功能的新增/减少/修改" → 中 +1(小归 0);只是"消缺完善" → 小 +1;一次发布混了几类,取最高那一级
**打包文件名** = `app_guanlang_v2.81.5.zip`(规则:`app_guanlang_v<版本号>.zip`)。
版本号只写在 `src/version.py` 一行(`VERSION = '2.81.5'`);打包器、安装脚本、安装记录 `install-info.json`、自检都读它,不另设真源。
| 版本 | 日期 | 级别 | 主要变更 | 说明 |
|---|---|---|---|---|
| `v2.81.5` | 2026-10-05 | 小 | 修「系统维护」等页签内容未加载:App 改为按页签按需取数 | 用户反馈:工作台「系统维护」里除「数据重算」外的其他内容未加载。**实逮根因**:App 的 `load()` **只取 `/api/fleet`**,而各视图要的数据走 `props.apis[...]`:`System.vue` 要 `/api/maint_survey`、`Decision/Report` 要 `/api/ask_models`、`Generation` 要 `/api/curves` ⇒ 这些接口在真实页面上**从未被请求过** ⇒ 页签内容为空(旧页是**按页签按需取**的)。**为何判据曾是绿的**:一致性/对拍脚本会把接口数据**喂**给 Vue 侧,掩盖了"应用自己不取数"这一层。**处置**:`App.vue` 增 `TAB_APIS` 映射与 `ensureTabApis(id)`(取过即缓存,失败也记 error 不阻塞),`watch(tab)` 在进入工作台时按需取数,并把 `apis` / `curves` 传给 `Workbench`(此前未传)。**验证**:真应用选中「系统维护」时实际请求 `["/api/maint_survey","/api/fleet"]` ✓(`MAINT_CALLED true`);用**远端真实** `/api/maint_survey` 夹具渲染,巡检表与文字(覆盖/末次更新/责任…)出现 ✓。 |
| `v2.81.4` | 2026-10-05 | 小 | 修「数据重算」看不到清除产物/重算按钮:网关去掉 X-Frame-Options 默认 DENY | 用户反馈:并入「系统维护」的「数据重算」里**没有"清除产物""重算按钮"**。**根因(实逮)**:那两个按钮位于内嵌的 **`/ops` 运维控制台**里(该页按钮:`b_start`/`b_stop`/`b_restart`/`b_off`=清除产物(直接删除,不留备份)✓,`/ops` 本身 200·9,889 B 完全可用),但 `/ops` 的响应头带 **`X-Frame-Options: DENY`** ⇒ **浏览器拒绝把它放进 iframe** ⇒ 页面上只剩 hero 与 chip、看不到控制台内容。该头来自**网关侧 Spring Security 的默认 frameOptions=DENY**(`GatewaySecurityConfig` 未覆写)。**处置**:在网关安全链里 `http.headers().frameOptions().disable();`(内网单机工具,去掉该头以支持**同源**嵌入;WebFlux 的 `FrameOptionsSpec` 没有 Servlet 的 `sameOrigin()`,故用 disable)。本地离线编译通过(class 4,310 B)→ 上传 `target/classes/.../GatewaySecurityConfig.class` → 重启服务。**复验(远端响应头)**:`/ops` ⇒ 200 · 9,889 B · **响应头 {}(已无 DENY)** ✓;`/` 200·413 B ✓;`/detail/v2` 200·413 B ✓;`/algorithm/healthz` 200 ✓。(`/api/fleet` 仍带 DENY —— 那是它自己另设的头,与 iframe 嵌入无关。)注:`backend-gateway/build_offline.py` 在"组装依赖"一步因离线取不到 maven 插件而返回非 0(`target/lib` 已存在,不影响编译产物),故本次按"编译是否产出新 class"判定后单独上传。 |
| `v2.81.3` | 2026-10-04 | 小 | 「系统维护」内的「数据重算」改为同源 iframe + 门户 CSS(渲染与 v2.9.2 一致) | 用户反馈「数据重算嵌入系统维护后与 v2.9.2 的系统维护 + 数据重算有差异」。**实逮差异点**:该节的 hero/chip 是**门户 CSS** 渲染的(深色 hero、圆角 chip),而我只是把 HTML 用 `v-html` 塞进工作台,门户 CSS 并未作用于该块 ⇒ 计算样式实测 `hero bg=透明/padding=0`、`chip 无背景`(门户里不是这样)。**处置**:照门户四节的既有手法,把这一节装进**同源 iframe(srcdoc = 门户 CSS + `#recalc` 节原文)**,`width:100% · height:1420px · border:0`,`` 保证链接打到顶层;该 iframe 仍标 `data-added="recalc"`,继续被一致性判据排除(`system` 页签仍 220 元素一致 ✓)。另外核实用户第 1 项:「振动 CMS」的按窗实时值**代码已在远端产物中**(`窗口内报警工单`/`CMS 采集窗`/`CMS 裁决`/`当前时间窗` 均在 bundle 内 ✓)⇒ 若界面未见,属浏览器缓存,需 Ctrl+F5。 |
| `v2.81.2` | 2026-10-04 | 小 | 「系统维护」内的「数据重算」改为 v2.9.2 原样(hero + 3 chip + /ops 控制台 iframe) | 用户反馈:并入「系统维护」的「数据重算」与 v2.9.2 有差别。**实逮**:我在该处放的是**自写的**状态面板(`Recalc.vue`:运行状态 + 开始重算按钮 + 日志 pre),而 v2.9.2 门户的「数据重算」节是「运维 · 数据重算与产物」hero + 3 个 chip(● 重算期间按钮全灰 / ● 后端拒绝 = 真生效(HTTP 409)/ ● 重算产物即时进页面)+ **内嵌 `/ops` 控制台 iframe**(宽 100%、高 1150px、`loading=lazy`)+ 「直接打开:/ops 控制台」回退链接。已按原文替换:抽出 `lib/portalRecalc.ts`(864 字符,取自门户 shell 的 `#recalc`),`System.vue` 用 `v-html` 渲染该块;iframe 在门户里由 JS 赋 `src`,此处直接写 **`/ops`**(同源相对路径,原 `` 也改为 `/ops`)。该块是**用户指定并入**的新增内容,已在判据工具中按 `data-added` 子树排除(`struct_diff.mjs`),故 `system` 页签仍为 **220 个元素一致** ✓。核验:块存在 ✓ · kicker「运维 · 数据重算与产物」✓ · iframe `src=/ops` + `title=数据重算与产物` ✓ · 回退链接 `/ops` ✓。 |
| `v2.81.1` | 2026-10-04 | 小 | 「振动 CMS」页数值全部按窗/CMS 实时(并修 portal_cms 未触发取数) | 用户令:「振动 CMS」页要**按窗实时值**。① 窗口侧实时:当前时间窗(`d.win`)、需关注/未见异常(`d.fus.kpi` 候选观察/全场,随 `/api/fleet?win=` 变)、**窗口内报警工单条数**(`d.fus.事件.主轴.工单.总条数`);② CMS 侧实时(`/api/vibcms`):采集窗 + 时间范围(`窗`/`时间范围`)、裁决分布(`grades` 统计优秀/良好/报警)、行动项条数(`action`)、数据时点(`date`);③ 移除门户里**写死的**「TCM 六采集窗 · 320 万记录 · 160 万谱」——该记录/谱计数**接口并不提供**,故改为用接口可得的实时项替代(不编造)。④ **实逮并修**:按需取数只对 `cms` 触发,`portal_cms` 未触发 ⇒ CMS 侧 chip 全为 0;已改为两者都触发。双窗验证:窗口`2026年` ⇒「当前时间窗 · 2026年」「需关注 35 台」「窗口内报警工单 · 11 条」「CMS 采集窗 w0316 · 2026-03-16 → 2026-04-21」「CMS 裁决 · 优秀 32 / 良好 3 / 报警 3」「行动项 … 条 · 数据时点 2026-09-29」;切到`全程` ⇒ 时间窗与需关注/未见异常随之变化 ✓。 |
| `v2.81.0` | 2026-10-04 | 中 | 门户「振动·CMS」迁入「振动融合分析」为并列子选项卡「振动 CMS」(受时间窗影响) | 用户令:把门户的「振动·CMS」迁到「振动融合分析」里,成为与"融合矩阵/端到端闭环/逐台情况/报警工单/振动分析"**并列的第 6 个子选项卡「振动 CMS」**,且**受时间窗影响**。实现:① 从 v2.9.2 门户 shell 抽出 `#cms` 节(1.6 KB:hero + 状态 chip + 入口)为 `src/lib/portalCms.ts`;② `lib/vib.ts` 的 `FUS_SUBS` 增 `portal_cms`(6 项),新增 `portalCmsHtml(d)`:把门户里的**静态数字**替换为**按当前时间窗实时算**的值 —— 「需关注 N 台」「未见异常 M 台」取自 `d.fus.kpi`(候选观察/全场,二者随 `/api/fleet?win=` 变化)、「证据窗末」取 `d.fus.证据窗末`,并**追加一个「当前时间窗 · 」chip**(直接体现窗口);③ i18n 增 `fus.sub.portal_cms`(zh:振动 CMS / en:Vibration CMS);④ `Vibration.vue` 接 `portal_cms` 分支。**实测(真应用 jsdom 点击 + 两个窗口对比)**:子选项卡为 ["融合矩阵","端到端闭环","逐台情况","报警工单","振动分析","振动 CMS"](6 个);点「振动 CMS」出门户内容(HAS_HERO true:振动与 SCADA 联合分析 / 六层模型…);**随窗变化**:窗口`2026年` ⇒ chips ["当前时间窗 · 2026年","需关注 35 台","未见异常 3 台",…];窗口`全程` ⇒ ["当前时间窗 · 全程","需关注 9 台","未见异常 29 台",…] ✓。远端已部署 36 件。 |
| `v2.80.2` | 2026-10-04 | 小 | 修「振动融合分析」点击子选项卡页面不变(弃用 v-unwrap) | 用户反馈:「振动融合分析」里点「端到端闭环 / 逐台情况 / 报警工单」页面没有变化。**根因(实逮)**:这些子视图的 HTML 挂在 `v-html` + **`v-unwrap`** 上,而 `v-unwrap` 只在 `mounted` **解包一次**(把宿主替换为子节点后把宿主移出文档)⇒ 之后 Vue 每次 `v-html` 更新都写进**已脱离文档的宿主** ⇒ 页面上永远是最初那一屏(表现为"点了没反应")。中途我曾把指令改成"注释锚点 + updated 同步",但在**数据异步到达 / 重复渲染**下锚点与节点归属会错位(实测元素数出现堆积与错位:matrix 10、units 4150 等),机制本身过于脆弱。**最终处置**:**弃用 `v-unwrap`**(`Assistant.vue` / `Decision.vue` / `Vibration.vue` 三处),改为保留宿主 `div.unwrap-host` —— 先核实**没有任何 CSS 依赖 `#root` 的直接子结构**(扫描 0 条命中),故该层 div 无样式副作用;对拍工具本就把它按"透明"处理,**10/10 页签结构一致性不受影响**。**修复后真应用点击实测**(点 5 个子选项卡各一次,数 `#root` 元素数):matrix **1126**(基线 1126)· loop **13**(基线 13)· units 4151(基线 3398)· events **626**(基线 626)· cms 558(基线 543)—— 前三+events 与基线**逐字相同**,units/cms 因"真应用按真实数据/真实交互路径渲染"与SSR 对拍口径不同而略有出入(非堆积,多次点击不再增长)。 |
| `v2.80.1` | 2026-10-04 | 小 | 振动融合分析(含 5 个子页面)与 v2.9.2 差异核定;修 cms 子页面未取 /api/vibcms | 用户令:核定「振动融合分析」中所有页面(含子页面)与 v2.9.2 的差异并修改。① **判据补强**:`tools/struct_diff.mjs` 增加**子视图支持**(`tab:sub`:基线点 `#root [data-fsub=]` 停稳后比骨架,Vue 侧把 `sub` 传给 `renderTab`),于是 5 个子页面都进了结构对拍。② **结构**:vibration `matrix/loop/units/events/cms` = **5/5 一致**(1126 / 13 / 3398 / 626 / 543 个元素)。③ **内容**:同 5 项文本/表格/图数字 = **5/5 一致**(561 / 9 / 1126 / 492 / 158 项文本;表 1/0/2/9/2 张;含 1 条已登记例外:后端"页面按窗缓存 vs 实时 /api/fleet"的措辞差异,非前端)。④ **实逮到一处真实差异(工具此前掩盖)**:旧页在选中 cms 子视图时会**按需异步取 `/api/vibcms`**(`app.js:980`),而 Vue 应用**从不取该接口**(只在契约里声明路径、靠父组件传 `cms` 而无人传)⇒ **真实打开「振动分析」时无数据**;我的对拍脚本会替它喂数据,所以此前判据是"绿的"却与实际不符。已修:`Vibration.vue` 选中 cms 时按需 `fetch('/api/vibcms')`(prop 优先,保持对拍同源口径 + `cmsErr` 兜底)。**真行为验证**(真应用 + 远端真实 `/api/vibcms` 6,297 B 夹具):点击「振动分析」⇒ 实际发出 `["/api/fleet","/api/vibcms"]`、`VIB_CMS_CALLED true`、渲染出表格 **39 行** ✓。 |
| `v2.80.0` | 2026-10-04 | 中 | 页签精简(去「架构与资料/门户」、数据重算并入系统维护)+ 删除页头模式按钮(修布局乱) | 用户两项:① **页签精简** —— 工作台页签由 14 减为 **11**:去掉「架构与资料」(其首个子选项卡即"系统架构")与「门户」;「数据重算」不再单列页签,改为并入 **系统维护** 页签内的一个区块(`System.vue` 内渲染 ``)。现页签为:总览 · 电量算账 · 部件问题 · 振动融合分析 · 发电性能 · 故障统计 · 检修决策 · 检修助手 · 汇报定制 · 系统维护 · 交付文档。② **修布局乱** —— **实逮**根因:页头里还残留一组"模式按钮"(工作台 / 契约自检 / 关于本前端),它们用的容器也是 `