فهرست منبع

[Mod 0000] 提交合并文件

hongrunxia 1 هفته پیش
والد
کامیت
c51fc5f9f8
2فایلهای تغییر یافته به همراه100 افزوده شده و 47 حذف شده
  1. 0 47
      改动说明-fix-subapp-loading.md
  2. 100 0
      改动说明-perf-base-v1.md

+ 0 - 47
改动说明-fix-subapp-loading.md

@@ -1,47 +0,0 @@
-# 改动说明:fix-subapp-loading(基座微应用挂载健壮性修复)
-
-> 日期:2026-09-10 | 分支:`fix-subapp-loading`(基于 master `b5a6721d`)| 范围:**仅 mky-vent-base**
-> 依据:docs/17 §8 实测("风量监测"新开标签页永久加载)、docs/16 基座审核 #6、docs/15。
-> 原则:小步修改,不改业务逻辑与子应用通信协议;每处带 `[fix-subapp-loading]` 注释;可单项 revert。
-
-## 背景一句话
-
-用户典型路径(首页点"风量监测"→新开标签页)出现**永久"正在加载"**:基座的两层加载遮罩(启动屏 + ventModal 挂载遮罩)的收起条件完全依赖"三维子应用就绪",而生产所部署的子应用构建存在绘制链停摆缺陷 → 遮罩永挂、整页不可用。本分支让基座在该场景下**超时放行**,并修复子应用卸载竞态。
-
-## 改动明细(6 文件,2 组提交)
-
-### 第 1 组:挂载遮罩超时兜底 + 就绪等待防中断
-
-| 文件 | 改动 |
-|---|---|
-| `src/utils/domUtils.ts` | `resetMicroContentWH(domId, callBack, maxWaitMs = 60000)`:新增 `maxWaitMs` 参数(默认 60s,向后兼容)。原实现每秒无限轮询等待 `#容器` 出现首个子节点——微应用挂载失败时容器永远为空,遮罩永久转圈。现超时后强制执行 `callBack()`(隐藏遮罩、放行页面)并停止轮询(原实现还有轮询本身永不停止的小泄漏)。超时时输出 `console.error` 便于定位。 |
-| `src/components/vent/micro/ventModal.vue`(3D 容器) | `onMounted` 中 `mountMicroApp(...)` 包 `try`,`resetMicroContentWH(...)` 移入 `finally`——若 mount 同步抛错,就绪等待仍然启动,遮罩不会因"抛错跳过收起逻辑"而永久卡死。 |
-| `ventModal2D.vue` / `needAir.vue` / `ventDoc.vue` | 同款 try/finally(分别对应 2D / 需风量 / 内业三个子应用容器)。 |
-
-**为什么是 60 秒**:正常暖缓存挂载 ≤10s(实测 8.6~10.6s),冷缓存 40~60s;60s 仍未见容器内容基本可判定子应用挂载失败。超时放行后的表现:页面可见、三维区可能空白(用户可刷新重试),远好于无限转圈。参数可按现场调整(调大调小只改默认值)。
-
-### 第 2 组:`src/qiankun/index.ts` 卸载竞态修复
-
-`unmountMicroApps` 原实现两个 bug:
-1. `multipleApp.filter(async (name) => { await …unmount() })` —— `filter` 的 async 回调使 `await` 不被任何方等待,**卸载是"发射后不管"**;调用方 `onBeforeUnmount(async () => { await unmountMicroApps(...) })` 以为在等,实际拿到的是 filter 的新数组(立即返回)。旧实例的卸载与新实例的挂载并发竞争容器。
-2. 判断条件 `multipleApp.some` 是**函数引用**(恒真),属笔误;且卸载后不清理 `activeApps` 注册表。
-
-修复:改为 `for…of Object.keys(activeApps)` 顺序 `await` 卸载,`try/catch` 单个失败不阻断其余,卸载成功后 `delete activeApps[key]`;入参空数组直接返回。匹配语义保持原样(`name.includes(key)`)。
-
-## 预期效果
-
-| 场景 | 改前 | 改后 |
-|---|---|---|
-| 子应用挂载失败/停摆 | 整页"正在加载"永久转圈 | 最多 60s 后放行页面(附 console.error 定位信息) |
-| 门户在两个子应用宿主路由间切换 | 旧实例卸载与新挂载竞态,实例泄漏/争抢 | 卸载完成后再挂载,注册表干净 |
-| 子应用正常挂载 | 正常 | 正常(无行为变化) |
-
-## 风险与回退
-
-- 本分支未改子应用通信协议、路由结构、任何业务页面;最坏情况是"超时放行后三维区空白"(与改前"永久转圈"相比是改善)。
-- 回退:`git revert` 对应 commit 即可,两组改动相互独立。
-- **未做构建验证**:本机无该仓库 node_modules(pnpm 工程,依赖未安装)。改动均为小范围 TS/Vue 模板级修改,已逐行自查;请审核者本地 `pnpm install && pnpm build` 验证后再合并。
-
-## 与 VentModelWeb 修复分支的关系
-
-VentModelWeb 侧的修复分支 `perf-load-v5`(Gogs 同服务 msx/VentModelWeb)解决三维子应用自身的切页重建/泄漏/绘制停摆;**本分支不替代它,二者建议都合**——本分支是基座侧的防御性兜底:即使未来子应用再出挂载问题,门户也不会整页永久卡死。

+ 100 - 0
改动说明-perf-base-v1.md

@@ -0,0 +1,100 @@
+# 改动说明:perf-base-v1(基座稳定性与性能优化轮)
+
+> 日期:2026-09-11 | 分支:`perf-base-v1` | 范围:**仅 mky-vent-base**(基座门户)
+> 基线:origin/fix-subapp-loading(含 fix-subapp-loading 三项修复)+ origin/master `497477be`(测风拓扑/ventAI 弹框等新功能)合并,起点 `cb285f47`
+> 依据:docs/19《基座深度审查与稳定性提速方案》(三代理分域深审:30+ 稳定性缺陷/速度新根因/8 张改进设计卡)
+> 原则:小步修改、不改业务逻辑与子应用通信协议、逐项独立 commit 可单独 revert、修改处带 `[perf-base-v1]` 注释标记
+> 提交总量:31 个(15 批次1 + 10 批次2 + D1/D2 修复 + 文档 + 合并),**未推送前已经 QA 全量验证**,QA 后补交 D1/D2 修复与本文档
+
+---
+
+## 背景一句话
+
+docs/19 深审确认基座存在成体系的"挂而不摘"缺陷(20 处定时器泄漏、WS 三断点、3D 越切越卡根因、首屏新根因等),本分支按审定批次 1+2 落地修复,目标是:**首屏 <5s、页面切换 <1s、内存平稳**。
+
+---
+
+## 改动明细
+
+### 第一组:批次 1 稳定性速赢(15 提交)
+
+| 编号 | commit | 文件 | 改动 | 为什么 |
+|---|---|---|---|---|
+| base-S-T1/L1 | `266d8bfc` | configurable/ 下 20 个分版页面 | `setInterval` 返回值补赋值到 `interval`/`timer` | 原代码裸调用 + `clearInterval(undefined)` 无效——每进一次页面永久新增一条 60s 轮询器("门户挂一天后请求风暴"的主因,20 处同款复制粘贴 bug) |
+| base-S-T2 | `09baba85` | monitorManager/nitrogenMonitor/index.vue | 同上补赋值 + onUnmounted 清理 | 裸 60s 轮询永久泄漏 |
+| base-S-T3 | `2d402cd2` | vent/home/colliery/index.vue | 1s 时钟补 `clockTimer` + 卸载清理 | 每秒 dayjs 格式化永久运行 |
+| base-S-T6 | `1b4ea726` | vent/dataCenter/deviceCenter/index.vue | 设备列表 3s 与行展开 1s 两个轮询拆分为 listTimer/expandTimer | 原共用一个变量:展开行清掉列表轮询且不恢复,设备列表静默停止刷新 |
+| base-L2 | `16180b1b` | index.html | liveplayer-lib.min.js(844KB)加 `defer` | 同步阻塞脚本拖慢首屏 |
+| base-L4 | `cd695880` | .env.production | VITE_USE_MOCK=true→false | 生产构建注入 mock 服务器有正确性风险 |
+| base-L5 | `fcf6636f` | src/qiankun/apps.ts | prefetchApps 只保留 3D 子应用 | 4 个子应用全量预取 ≈10-30MB 后台下载,挤占首屏窗口 |
+| base-L8 | `c94267e5` | package.json | 删除 plyr(全仓 0 引用) | 依赖卫生 |
+| base-L9 | `0d8116b9` | src/api/sys/vent.ts | 删除 return 之后 3.88 万行不可达内联 mock | 构建/解析负担与误导性代码 |
+| base-L10 | `e4914c17` | components/Container/src/Adaptive.vue | resize 监听改为单次注册 | 原每次 resize 新增一条永久 window 监听 |
+| base-L11 | `d2601c76` | App.vue、design/default.less | @font-face 加 font-display:swap | 5MB 字体下载期间文字不可见(FOIT) |
+| base-L14 | `abfa00d3` | index.html、public/vent/ | 启动屏背景图落 public 并修正 url | 原 `./src/...` 引用生产 404,启动屏背景缺失 |
+| base-S-L1 | `d2ce667f` | utils/threejs/useThree.ts、hooks/vent/useThree.ts(删除) | resize 注册/移除统一用 `_boundResize` 同一引用 | 原 `.bind()` 注册 vs 原引用移除静默失败,20+ 处 3D 页每进一次泄漏一条监听;死文件 hooks/vent/useThree.ts(0 引用)一并删除 |
+| base-S-3D2 | `a3244d5c` | utils/threejs/useThree.ts | destroy() 不再调用全局 `$renderer.dispose()` | 全仓 3D 页共享该渲染器,页面销毁时清空 GPU 缓存会导致下一个 3D 页全量重编译 shader——"3D 页越切越卡"的直接根因 |
+| base-S-D1 | `dad68da1` | store/modules/errorLog.ts | 错误日志 `.slice(0, 100)` | 只进不出,长会话线性增长 |
+
+### 第二组:批次 2 安全与性能主线(8 提交)
+
+| 编号 | commit | 文件 | 改动 | 为什么 |
+|---|---|---|---|---|
+| base-卡3 | `6292f7aa` | vite.config.ts | build.modulePreload.resolveDependencies:html 入口剔除 office-preview/markdown-vendor/tinymce-vendor/html2canvas/codemirror/cron-parser 预载 | 这些重型 chunk 对多数页面是纯预载浪费;保留 echarts-vendor(首页图表在用)不误杀 |
+| base-卡2a | `1e683e3c` | rightPositionBar.vue、content-New.vue、blue/content.vue、blue/content-New.vue、blue/content-FireNew.vue、green/content-green.vue | MiniChat 静态 import 改 defineAsyncComponent | 布局头部静态链把 4.46MB office-preview + markdown/echarts vendor 拖进登录后首帧 |
+| base-卡2b | `308b8226` | components/AIChat/MiniChat.vue | vue-office 三组件改 defineAsyncComponent(isShowDoc 时才加载);echarts 改 initChart 内 await import | 文件预览/图表非必现路径,按需加载 |
+| base-卡2c | `0d2113bf` | ventAI/.../FilePreviewPanel.vue | VueOfficeDocx 与 XLSX 改按需 import | 同上 |
+| base-卡6a | `934b59b3` | 新增 src/utils/markdownSafe.ts;ventAI chatModal/utils.ts 改转调 | 公共消毒管线(marked+DOMPurify,白名单 ADD_TAGS:['img'])收敛为单一实现 | 原两处实现漂移:ventAI 版有消毒、MiniChat 版裸渲染 |
+| base-卡6b | `8cc07e7c` | MiniChat.vue、AIChat/index.vue、DataPickerModal.vue、MarkdownViewer.vue | 4 处高危 v-html 数据源接入 DOMPurify 消毒 | LLM 输出 + 用户输入双通道裸渲染 = 同源 XSS(可窃 token);顺带删除 0 引用死文件 Aichat copy.vue |
+| base-卡1 | `0e54a39e` | index.html、public/js/config.js、新增 utils/onlyOffice.ts、3 个 DocEditor 弹窗 | 移除首屏 9050 注入;onlyOfficeUrl 配置化;loadDocsApi 单例按需加载,弹窗 await + 失败提示 | 原每次进门户无条件请求 `http://<host>:9050`(死链必现错误;HTTPS 下被混合内容拦截) |
+| base-卡7 | `94bd9674` | public/js/config.js、新增 utils/aiChatApi.ts、AIChat.ts(6 处)、MiniChat.vue(9 处)、.env.development、types/global.d.ts | AI 接口地址配置化(aiChatUrl/difyUrl),删除全部硬编码 IP;difyApiKey 改 config 可配 | HTTPS 部署下明文 IP fetch 全量失效;换网段部署需改码重构建 |
+| base-S-W | `d0120534` | hooks/web/useWebSocket.ts、useVentWebSocket.ts、balancePress 两页 | WS 三断点修复:①不再覆写 vueuse open/close(原致连接无法关闭/断线永久死亡);②connectWebSocket 按 url 幂等(原每次调用新建连接覆盖全局变量,同一条告警被 N 个连接重复分发);③balancePress 匿名回调改命名 + 卸载 offWebSocket + warnModal destroy(原离开页面后告警弹窗照样弹且成倍增加);useVentWebSocket 真 close + autoReconnect + watchEffect 防叠加 | 告警通道可靠性 |
+| base-L14b | `fdf7839d` | index.html | 删除 deepblue 主题指向不存在图片的 background-image 行 | 与 L14 同款 404 隐患 |
+
+### 第三组:QA 缺陷修复(1 提交)
+
+| 编号 | commit | 文件 | 改动 | 为什么 |
+|---|---|---|---|---|
+| base-D1 | `7617a39e`(并入) | pnpm-lock.yaml | 重新生成本地 lockfile(plyr 清零) | 删 plyr 后 lockfile 未同步,CI frozen-lockfile 场景会失败(QA 实测发现并提供再生 diff) |
+| base-D2 | `7617a39e`(并入) | configurable/index.vue:90 | 60s 轮询补 `interval =` 赋值 | S-T1 同款模式的最后一处遗漏(QA A3 复核发现) |
+
+---
+
+## 验证记录
+
+| 项 | 结果 |
+|---|---|
+| QA 静态核验矩阵 | **9/9 PASS**(24 个治理点逐一到位,证据 docs/audit/验证-基座perf-base-v1-20260911.md) |
+| 语法校验 | 14 个 .ts + 42 个 .vue 全量校验 0 真实错误 |
+| `pnpm build` 生产构建 | **成功**(dist 343MB;office-preview/tinymce 等为独立异步 chunk) |
+| dist 产物 | modulepreload 收敛为 5 个 vendor;6005/8000 硬编码 IP 不再进入运行时代码;`:9050` 仅剩代理表字符串;应用自有 console 清除 |
+| 消毒链路 | 4 处高危 v-html 全部经 DOMPurify 白名单管线 |
+| WS 消费方兼容 | 7 个 useWebSocket 消费方 API 兼容(导出签名未变) |
+
+### E2E GUI 冒烟(本地 nginx:新基座 dist + 修复版子应用 dist + 生产后端反代)
+
+| 场景 | 结果 |
+|---|---|
+| 登录 → 首页三维场景 | 渲染完整(Cesium 地形/巷道/设备/实时数据),**console 0 错误、9050 请求 0 次** |
+| 首页 → 设备监测页(tunMonitor&windrect&tabtype=monitor,生产上**永久加载**的变体) | **遮罩 19s 正常收起**,页面完整渲染(36 条实时数据),零报错——生产上该页 15 分钟永不完成 |
+| 内存 | 加载期峰值 ~1.2GB(含在途 GLB),稳定后正常 |
+
+---
+
+## 风险与回退
+
+1. **构建未在本机全量复跑**:本机 node_modules 曾被 pnpm 12 失败重装破坏(cross-env 丢失)。QA 在损坏前已完成 `pnpm build` 验证(构建成功 + 产物核验),其后仅 D2 一行改动未随 dist 验证——**合并后请重跑 `pnpm build`**(先 `pnpm install` 修复 node_modules)。
+2. **行为变化点**(审核关注):① `connectWebSocket` 异 url 互斥(当前部署各 url 殊途同归 :9999 同频道,风险低→观察项 O1);② `useVentWebSocket` 开启 autoReconnect(原一次心跳超时即永久断流);③ 生产 mock 关闭(若某接口依赖 mock 需核实);④ 工作区路由 glob 内的 `blue/ventNew copy.vue` 未删除(有路由风险,仅修了其中的定时器赋值)。
+3. **回退**:每组改动独立 commit,`git revert <commit>` 单项回退;整组回退 `git revert <A> <B>`(第一组/第二组各自连续)。
+
+## 遗留清单(本轮不做,已登记 docs/19)
+
+- MiniChat.vue:388 第二枚硬编码 dify key(深度思考开关覆写 APIKEY)→ 建议增加 difyApiKeyR1 配置项;
+- ventNew copy.vue 死文件删除(落在路由 glob 内,需先确认 DB 菜单无引用);
+- 全仓 echarts dispose 补齐(46 处 init 仅 3 处 dispose)、巨型内联 SVG 静态化、3D 子应用保活、批次 3/4(9050 反代落地、mp4 懒加载、three 按需化)——按 docs/19 §8 排期。
+
+## 与其他分支/文档的关系
+
+- `perf-base-v1` 已包含 `fix-subapp-loading` 全部修复(挂载遮罩 60s 兜底 + 卸载竞态修复);
+- 子应用侧配套分支:msx/VentModelWeb `perf-load-v5`(切页 keep-alive 复用 + 生命周期治理,QA Go)——**建议两分支配套合并部署**;
+- 审查依据与完整缺陷清单:docs/19;仓库更新后新增代码审计:docs/18。