# 60 · 设置面板分区改名:功能插件 → 功能管理 - 日期:2026-09-12 - 状态:✅ **已实施并验证**(服务器已生效;本地待提交) - 触发:用户「平台管理改为用户管理放到功能插件下面,**将功能插件改为功能管理**」 - 关联:档案 57(「平台管理」→「用户管理」+ 移到功能插件下方 —— 本次需求的**前两项**)、38(术语统一「业务插件」→「功能插件」)、36(功能插件分区诞生)、18 v3(同一设置面板的另一个 section) --- ## 一、需求拆解与状态核实 用户这次说了三件事,**前两件在档案 57 已做完**,本次是第三件。先把实例里**实际加载**的内容查清(而不是看文档): | 需求 | 实例内实际状态(改动前实测) | 结论 | |---|---|---| | ① 平台管理 → 用户管理 | `portal-entry` v0.5.1,section `id: user-management`,`label: 用户管理` | ✅ **已生效**(档案 57) | | ② 放到功能插件下面 | `portal-entry` `order: 102` > `business-plugins` `order: 101` | ✅ **已生效**(档案 57) | | ③ 功能插件 → 功能管理 | `business-plugins` v0.2.1,`section.label: 功能插件` | ❌ **本次要做** | > 用户重复提① ②,多半是**浏览器缓存**:设置面板的 section 名由**客户端 bundle 运行时注册**,页面不硬刷新就还是旧的 JS。已在上线说明里明确"需硬刷新"。 --- ## 二、改动 **只改一个东西:分区标题。** `poc/business-plugins/`(代码库内,真源)→ `@dsh-local/business-plugins` **v0.2.1 → v0.2.2**。 | 位置 | 改动 | |---|---| | `lib/client.js` 第 61 行 | `"section.label": "功能插件"` → **`"功能管理"`** | | `lib/client.js` 第 89 行 | `"section.label": "Feature plugins"` → **`"Feature management"`**(中英同步,否则切英文界面会不一致) | | `package.json` | `version` 0.2.1 → **0.2.2** + description 记录本次变更 | ### 刻意**没有**改的地方 同一份 locale 字典里还有几处「功能插件」字样,**都保留了**: - `empty`:「暂无功能插件(需管理员在门户投放)」 - `confirm`:「确认应用功能插件更改?…」 - `rejected.title`:「以下插件与实例不兼容,已自动禁用」 理由:**这些句子描述的是「插件」这个事物,不是分区名** —— 分区叫「功能管理」,里面管理的对象仍然叫「功能插件」。全文替换会让文案变成「确认应用功能管理更改?」这类不通顺的说法。 同理,**文档与代码注释里的「功能插件」术语一律不动**(档案 38b 已把术语统一到「功能插件」,本次只动 UI 分区标题这一个字符串)。 --- ## 三、安装与验证 | 步骤 | 做法 / 结果 | |---|---| | 打包 | `cp -r` **整目录**复制 → `npm pack` → `/opt/dsh/artifacts/business-plugins-0.2.2.tgz`;**包内清单与源清单 `diff` 一致**(4 文件:package.json / cordis.patch.yml / lib/client.js / lib/index.js) | | 同步源码 | `/root/bp-build/business-plugins/.` → `/opt/dshs/poc/business-plugins/`(仓库内真源) | | 全员升级 | `node scripts/ensure-biz-plugins.cjs --all --restart` → admin、guest 均 `版本落后(0.2.1 → 0.2.2),升级中…` → `✓ bundles=5(含 @dsh-local/business-plugins: true)` | | 文件校验 | 两个用户 `node_modules/@dsh-local/business-plugins` 版本 = **0.2.2**,`label=section.label": "功能管理"` | | 编码校验 | `grep -o 功能管理 \| od -c` → `345 212 237 350 203 275 347 256 241 347 220 206` = **UTF-8 双字 12 字节**(排除被写成 GBK / 转义序列的常见事故) | | 生效判定 | 升级时报「已停 0 个实例 scope」→ 其后由访问触发**全新启动** → 必然加载 0.2.2(无需再重启) | **为什么没做浏览器渲染验证**:section 名在运行时由 client bundle 注册,`curl` 抓不到渲染结果;`/plugins/??/client.js` 直取返回 401(该组合加载端点不接受独立请求)。**文件 + 版本 + 编码 + 加载时机**四者已闭环,渲染机制沿用 v0.2.x 生产验证过的实现。**请硬刷新会话页确认**。 ### 踩坑:pack 必须整目录复制 档案 57 已经栽过一次 —— 手工逐个 `cp` 漏了 `lib/index.js`,导致**全实例崩溃循环**。本次沿用「`cp -r /. /` + 打包后强制 `diff` 清单校验」的流程,清单一致才继续。 ### 清理 `ensure-biz-plugins.cjs` 用的是**旧姿势**(把 tgz 复制进 ws + `HOME=` 跑 pnpm,无 store 隔离)→ 会在 ws 留下安装残留。本次移入 `/trash/2026-09-12-ws-installer-residue/`(**移走不删除**,30 天后由 `purge-trash.sh` 真删): - admin:`business-plugins-0.2.1.tgz`、`business-plugins-0.2.2.tgz`、`portal-entry-0.4.3.tgz`、`workspace-scoped-picker-0.1.4.tgz`(4 个) - guest:3 个(其余不存在) 保留 `.local/`、`.cache/`:那是 pnpm 的 store / metadata 目录,删掉会让**下次 `pnpm add` 重新下载全部依赖**(且会再次触发档案 57 记录的 `ERR_PNPM_UNEXPECTED_STORE`),副作用大于收益。 --- ## 四、遗留(与本次相关) 1. **`ensure-biz-plugins.cjs` 的旧安装姿势**(档案 57 §五.2 已记):它用 `HOME=` 且不隔离 store → 每次都会污染 ws(本次 4 个残留即由此而来),且**升级已有 node_modules 时同样会撞 `ERR_PNPM_UNEXPECTED_STORE`**(本次侥幸没撞,因为它的 store 恰好仍是 ws 内路径,与 `.modules.yaml` 记录一致)。 **建议**:与 `ensure-portal-entry.cjs` 对齐 —— 暂存到 `/.dsh-stage/`、读 `.modules.yaml` 沿用 storeDir、`setpriv` 以用户身份安装。 2. **`web/wake.html` 双端不一致**(档案 59 §四已记):本机 4708 B / 服务器 4591 B,待核对同步。 --- ## 五、回滚 ```bash # 退回 0.2.1(旧包仍在 artifacts 里) NODE_OPTIONS= node /opt/dshs/scripts/ensure-biz-plugins.cjs --all --restart # 需先把 artifacts 里的新包挪走 # 或直接改回源码字符串后重打 0.2.3 再铺 ``` 回滚后**需重启实例**(bundle 在实例启动时加载)。