@agile-team/wl-skills-kit 2.9.3 → 2.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.9.4] - 2026-05-18
4
+
5
+ ### Fixed
6
+
7
+ - **规范条数 13→14 全面对齐**:`standards/index.md` 已升级至 14 条(新增 `14-layout-containers.md`),同步修复以下 7 个文件中残留的"13 条"引用:
8
+ - `copilot-instructions.md`、`convention-audit/SKILL.md`、`_best-practices.md`、`guides/usage.md`、`page-codegen/USAGE.md`
9
+ - **`copilot-instructions.md` 任务类型映射去重**:移除与 `standards/index.md` 重复且过期的映射副本,改为唯一指针引用
10
+ - **`copilot-instructions.md` 导入路径纠正**:代码示例中 `@jhlc/common-core/src/...` 深路径改为 `@/types/page` 桶文件导入,与 `page-codegen` 模板及 `standards/09` 规范一致
11
+ - **`prototype-scan` 交互模式枚举对齐**:`FORM_TAB` → `DETAIL_TABS`,补齐 `FORM_ROUTE / CHANGE_HISTORY / RECORD_FORM / OPERATION_STATION / TEMPLATE_DRIVEN` 5 种模式,与 `page-codegen` 模板完全一致
12
+ - **`page-codegen` Pre-flight 补齐 `standards/14`**:任务类型 A 必读规范已含 14,Pre-flight 声明同步补齐
13
+ - **`convention-audit` 审计维度表补齐 14 行**:审计维度表和覆盖矩阵模板各补一行 `14 布局容器`
14
+
3
15
  ## [2.9.3] - 2026-05-17
4
16
 
5
17
  ### Fixed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @agile-team/wl-skills-kit
2
2
 
3
- **AI Skill 模板包 v2.9.3 ** — 一键将 13 条规范、10 个 AI Skill、17 个 MCP Tool、编辑器 MCP 配置、文档导入 Vue 3 项目。
3
+ **AI Skill 模板包 v2.9.4** — 一键将 14 条规范、10 个 AI Skill、17 个 MCP Tool、编辑器 MCP 配置、文档导入 Vue 3 项目。
4
4
 
5
5
  让 AI 编辑器(Copilot / Cursor / Windsurf / Claude Code / Cline / Kiro / Trae / Qoder / 通用 Agents)**真正理解项目规范**,从原型/详设到完整页面代码全流程自动化。
6
6
 
package/bin/wl-skills.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * wl-skills-kit CLI v2.9.3
4
+ * wl-skills-kit CLI v2.9.4
5
5
  *
6
6
  * 命令:
7
7
  * init 全量安装(默认,向后兼容)
@@ -52,11 +52,13 @@ mock/
52
52
  > 基类内置 `getAction`/`postAction`/`putAction`/`deleteAction`/`actionBatch` 等 HTTP 方法(详见 `docs/request.md`),标准 CRUD 无需独立 API 文件。
53
53
 
54
54
  ```typescript
55
- import { AbstractPageQueryHook } from "@jhlc/common-core/src/page-hooks/page-query-hook.ts";
56
- import { BaseQueryItemDesc } from "@jhlc/common-core/src/components/form/base-query/type.ts";
57
- import { ActionButtonDesc } from "@jhlc/common-core/src/components/toolbar/type.ts";
58
- import { TableColumnDesc } from "@jhlc/common-core/src/components/table/base-table/type.ts";
59
- import { BusLogicDataType } from "@jhlc/types/src/logical-data";
55
+ import {
56
+ AbstractPageQueryHook,
57
+ BaseQueryItemDesc,
58
+ ActionButtonDesc,
59
+ TableColumnDesc,
60
+ BusLogicDataType
61
+ } from "@/types/page";
60
62
  import { getAction, postAction } from "@jhlc/common-core/src/api/action";
61
63
 
62
64
  export const API_CONFIG = {
@@ -230,16 +232,9 @@ onMounted(() => select());
230
232
 
231
233
  > ⚠️ 本节为**强制约定**,所有 AI 编辑器/模型都必须遵守。
232
234
 
233
- 完整 13 条编码规范拆分在 `.github/standards/01 ~ 13.md`,由 `standards/index.md` 提供任务类型 → 规范子集映射,**按需加载,不全量读取**。
235
+ 完整 14 条编码规范拆分在 `.github/standards/01 ~ 14.md`,由 `standards/index.md` 提供任务类型 → 规范子集映射,**按需加载,不全量读取**。
234
236
 
235
- | 任务类型 | 必读规范 |
236
- | --------------------- | ------------------------------------------------- |
237
- | A. 生成新页面 | 01, 02, 03, 04, 05, 06, 07, 09, 10, 11, 12, 13 |
238
- | B. 修改/重构现有代码 | 02, 04, 05, 06, 09, 10, 12, 13 |
239
- | C. 规范审计 | 全部 01 ~ 13 |
240
- | D. 模板提取 | 02, 03, 09, 12, 13 |
241
- | E. 数据同步(菜单等) | 04, 05, 07 |
242
- | F. Git/分支/提交 | 08 |
237
+ > 任务类型 → 必读规范映射以 `standards/index.md` 为**唯一数据源**,此处不再重复列表。执行前先 `read_file` 加载 `standards/index.md` 确认当前映射。
243
238
 
244
239
  **执行任何代码生成或改动前**:
245
240
  1. 先 `read_file` 加载 `standards/index.md` 确认任务类型
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **读者**:团队技术负责人 / wl-skills-kit 维护者 / 对体系设计感兴趣的团队成员
4
4
  > **更新方式**:重大架构变更后追加对应章节,旧章节原文保留(历史可溯)
5
- > **当前版本**:v2.9.3(2026-05-17
5
+ > **当前版本**:v2.9.4(2026-05-18
6
6
 
7
7
  ---
8
8
 
@@ -62,7 +62,7 @@ AI 会自动识别意图,触发对应的 Skill。
62
62
  | `page-codegen` | 生成页面 / 帮我生成 | 生成页面骨架 + 菜单注册 |
63
63
  | `menu-sync` | 创建菜单 / 同步菜单 | 菜单数据同步到后端(MCP 自动 / prompt 手动两种模式) |
64
64
  | `dict-sync` | 同步字典 / 创建字典 / 字典审计 | 字典基线同步到后端(MCP 自动 / prompt 手动两种模式) |
65
- | `convention-audit` | 规范审计 / 代码审计 | 13 条规范扫描 + 偏差报告 |
65
+ | `convention-audit` | 规范审计 / 代码审计 | 14 条规范扫描 + 偏差报告 |
66
66
  | `business-doc-extract` | 语义级智能触发(无关键词列表) | 原型/详设/字段/字典/现有页面 → docs/business 业务文档 |
67
67
  | `template-extract` | 提取模板 / 抄取模板 | 从现有页面沉淀领域专属模板 |
68
68
  | `permission-sync` | 创建角色 / 角色授权 / 同步权限 | 角色+授权+动作权限同步(MCP) |
@@ -130,7 +130,7 @@ wls_menu_sync_from_report ← MCP 工具,自动读报告 + 查菜单树 + 一
130
130
 
131
131
  ```
132
132
  wls_code_scan ← 概览:页面目录、API_CONFIG、文件完整性
133
- → convention-audit ← 13 条规范全量扫描,产出 AUDIT_*.md
133
+ → convention-audit ← 14 条规范全量扫描,产出 AUDIT_*.md
134
134
  → code-fix(可选) ← 自动修复可整改项
135
135
  ```
136
136
 
@@ -188,7 +188,7 @@ mock/
188
188
  | business-doc-extract | 模块级资料 → 业务文档沉淀 |
189
189
  | api-contract | 生成 `api.md` 接口约定 |
190
190
  | page-codegen | 生成 Vue 页面三件套 + api.md + SYS_MENU_INFO.md |
191
- | convention-audit | 13 条规范审计 |
191
+ | convention-audit | 14 条规范审计 |
192
192
  | code-fix | 按审计报告自动修复 |
193
193
  | menu-sync | 后端菜单同步(MCP)|
194
194
  | dict-sync | 后端字典同步(MCP)|
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: convention-audit
3
- description: "Use when: auditing project source code against the 13 modular standards in .github/standards/. Outputs deviation report and component-extraction suggestions to reports/. Triggers on: 规范审计, 规范检查, 代码审计, 对齐规范, 规范偏差, 接手新项目, 存量代码分析, 项目体检, audit code, check conventions, onboard project."
3
+ description: "Use when: auditing project source code against the 14 modular standards in .github/standards/. Outputs deviation report and component-extraction suggestions to reports/. Triggers on: 规范审计, 规范检查, 代码审计, 对齐规范, 规范偏差, 接手新项目, 存量代码分析, 项目体检, audit code, check conventions, onboard project."
4
4
  ---
5
5
 
6
6
  # Skill: 规范审计(convention-audit)v2
7
7
 
8
- 以 `.github/standards/` 13 条规范为唯一基线,扫描项目源码,输出**偏差报告**和**组件提取建议**到 `reports/` 目录。
8
+ 以 `.github/standards/` 14 条规范为唯一基线,扫描项目源码,输出**偏差报告**和**组件提取建议**到 `reports/` 目录。
9
9
 
10
10
  > **核心理念**:审查全覆盖、结果强量化、规则场景化、新增严格 + 存量渐进。
11
11
  > 本 Skill 只负责发现偏差并给出整改建议,**不自动修复**(修复由 code-fix Skill 完成)。
@@ -23,7 +23,7 @@ description: "Use when: auditing project source code against the 13 modular stan
23
23
  ```
24
24
  🚀 已触发技能 convention-audit/SKILL.md → 规范审计:扫描源码 + 偏差报告 + 提取建议
25
25
  ✅ 已读取 standards/index.md → 规范门控
26
- ✅ 已读取 standards/01 ~ 13 → 完整 13 条规范基线(审计场景需全量加载)
26
+ ✅ 已读取 standards/01 ~ 14 → 完整 14 条规范基线(审计场景需全量加载)
27
27
  ✅ 已读取 reports/规范审查报告.md → 现有报告(用于追加,不覆盖)
28
28
  ✅ 审计范围:{用户指定的目录或单文件}
29
29
  ✅ 工具链检测:ESLint {状态} / tsc {状态} / Husky {状态}
@@ -45,7 +45,7 @@ description: "Use when: auditing project source code against the 13 modular stan
45
45
 
46
46
  ---
47
47
 
48
- ## 审计范围(13 条规范全覆盖)
48
+ ## 审计范围(14 条规范全覆盖)
49
49
 
50
50
  ### 审计方式分层
51
51
 
@@ -55,7 +55,7 @@ description: "Use when: auditing project source code against the 13 modular stan
55
55
  | **工具链委托** | ESLint / tsc --noEmit / Git 命令(高可信度,不浪费 AI 算力) |
56
56
  | **AI 场景判断** | 页面类型识别、豁免判定(中可信度,需人工确认) |
57
57
 
58
- ### 13 条规范审计维度
58
+ ### 14 条规范审计维度
59
59
 
60
60
  | 编号 | 审计维度 | 审计方式 | 严重度判定 |
61
61
  | ---- | -------- | -------- | ---------- |
@@ -72,6 +72,7 @@ description: "Use when: auditing project source code against the 13 modular stan
72
72
  | 11 | 表单校验 | AI 场景判断 | FORM_ROUTE 缺 validate / resetFields → 🔴 |
73
73
  | 12 | BaseTable + cid | 静态 + 场景判断 | 主列表用 el-table → 🔴;cid 缺失/重复 → 🔴;弹窗小表格见豁免规则 |
74
74
  | 13 | 平台组件合规 | 静态扫描 | 业务页面用 el-form/el-table/el-date-picker 替代封装 → 🔴;封装组件内部 → ⚠️ 待确认;3+ 复用 → 提取建议 |
75
+ | 14 | 布局容器 | 静态扫描 | 业务代码用 `C_Splitter` → 🔴(必须替换为 `jh-drag-row`/`jh-drag-col`) |
75
76
 
76
77
  ---
77
78
 
@@ -159,7 +160,7 @@ description: "Use when: auditing project source code against the 13 modular stan
159
160
  | 当前分支 | {分支名} — {符合规范 / 不符合规范} |
160
161
  | 最近提交规范性 | {N}/{总数} 条符合 type(scope): 格式 |
161
162
 
162
- ### 3. 13 条规范覆盖矩阵
163
+ ### 3. 14 条规范覆盖矩阵
163
164
 
164
165
  | 规范 | 审查方式 | 结果 | 🔴 | 🟡 | 🟢 |
165
166
  |---|---|---|---:|---:|---:|
@@ -176,6 +177,7 @@ description: "Use when: auditing project source code against the 13 modular stan
176
177
  | 11 表单校验 | 场景扫描 | {结果} | {N} | {N} | {N} |
177
178
  | 12 BaseTable | 静态+场景 | {结果} | {N} | {N} | {N} |
178
179
  | 13 平台组件 | 静态扫描 | {结果} | {N} | {N} | {N} |
180
+ | 14 布局容器 | 静态扫描 | {结果} | {N} | {N} | {N} |
179
181
 
180
182
  ### 4. 🔴 严重偏差(必须整改)
181
183
 
@@ -370,7 +372,7 @@ description: "Use when: auditing project source code against the 13 modular stan
370
372
 
371
373
  ## 注意事项
372
374
 
373
- 1. **规范基线唯一**:以 `standards/index.md` 加载的 13 条文件为准,**不接受**"旧代码一直这么写"的辩解
375
+ 1. **规范基线唯一**:以 `standards/index.md` 加载的 14 条文件为准,**不接受**"旧代码一直这么写"的辩解
374
376
  2. **追加不覆盖**:每次审计追加新章节到报告,**不删除历史**,便于追溯整改进度
375
377
  3. **菜单位置解析**:依赖 koroFileHeader 文件头注释,缺失文件头时标记 `菜单位置:未知`
376
378
  4. **AI 自我审计**:page-codegen 生成代码后,建议立即跑一次单页审计验证合规
@@ -19,6 +19,7 @@ description: "Use when: generating complete Vue 3 page code (index.vue + data.ts
19
19
  ✅ 已读取 standards/02-code-structure.md → 三文件分离+接口契约 + 三段式 + script 9段顺序
20
20
  ✅ 已读取 standards/12-base-table.md → AGGrid必用 + cid命名规范
21
21
  ✅ 已读取 standards/13-platform-components.md → 平台组件对照表 + docs前置读取清单
22
+ ✅ 已读取 standards/14-layout-containers.md → 布局容器(禁用 C_Splitter,必须用 jh-drag-row/jh-drag-col)
22
23
  ✅ 已读取 docs/{涉及的jh-*文档} → 当前页涉及组件的使用规范
23
24
  ✅ 工具链检测:.prettierrc.js ✓ eslint.config.ts ✓ .husky/ ✓ [全部就绪]
24
25
  ✅ cid 已生成:{value}({首字母缩写说明})
@@ -114,7 +114,7 @@ wl-skills doctor-ui
114
114
  ## FAQ
115
115
 
116
116
  **Q:生成完了但 build 报错?**
117
- A:跑一下 `convention-audit` Skill,会扫出 13 条规范偏差并给出修复建议。
117
+ A:跑一下 `convention-audit` Skill,会扫出 14 条规范偏差并给出修复建议。
118
118
 
119
119
  **Q:能否只生成 data.ts 不生成 index.vue?**
120
120
  A:可以,告诉 AI"只生成 data.ts"。但通常一起生成,因为它们字段必须对齐。
@@ -233,7 +233,7 @@ AI 根据提取的信息,内部构建 page-spec JSON(**不输出给用户**
233
233
  // ===== 页面基本信息 =====
234
234
  "pageName": "客户档案", // 中文名
235
235
  "kebabName": "customer-archive", // kebab-case 目录名
236
- "pattern": "LIST", // LIST | MASTER_DETAIL | TREE_LIST | FORM_TAB | COMPOSITE
236
+ "pattern": "LIST", // LIST | MASTER_DETAIL | TREE_LIST | DETAIL_TABS | FORM_ROUTE | CHANGE_HISTORY | RECORD_FORM | OPERATION_STATION | TEMPLATE_DRIVEN
237
237
  "path": "views/sale/demo/khda/customer-archive/",
238
238
  "pagesTs": ["customer-archive", "客户档案"], // pages.ts 注册项
239
239
  "platformComponents": ["BaseQuery", "BaseTable", "jh-pagination"],
@@ -285,7 +285,7 @@ AI 根据提取的信息,内部构建 page-spec JSON(**不输出给用户**
285
285
  }
286
286
  ],
287
287
 
288
- // ===== 表单字段(FORM_TAB / 弹窗 页面使用) =====
288
+ // ===== 表单字段(DETAIL_TABS / FORM_ROUTE / 弹窗 页面使用) =====
289
289
  "formSections": [
290
290
  {
291
291
  "name": "basicInfo",
@@ -428,7 +428,7 @@ const [模块名]Module = gProd("[base-path]", {
428
428
  ## [页面名称]
429
429
 
430
430
  **基本信息**
431
- - 交互模式:LIST / MASTER_DETAIL / TREE_LIST / FORM_TAB
431
+ - 交互模式:LIST / MASTER_DETAIL / TREE_LIST / DETAIL_TABS / FORM_ROUTE / CHANGE_HISTORY / RECORD_FORM / OPERATION_STATION / TEMPLATE_DRIVEN
432
432
  - 目录名:kebab-case(如 customer-archive)
433
433
  - 服务缩写:sale(如 pm / mmwr / sale / hrms / base)
434
434
  - 是否隐藏菜单:否
@@ -1,159 +1,159 @@
1
- # 14 — 布局容器规范(C_Splitter 禁用 + jh-drag-col/row 唯一推荐)
2
-
3
- > **强制度**:🔴 必遵 + 阻断式(lint 命中即报错)。
4
- > **背景**:2024 年 12 月一次真实事故,左树右表页面右侧面板永不刷新,最终定位为 `C_Splitter` 在 `onMounted` 中调用 `slots.default()` 冻结 vnode 快照,导致子树所有响应式绑定与父组件 ref 脱钩。
5
- > **结论**:项目中**禁止再使用 `C_Splitter`**,所有左右/上下分栏一律用 `jh-drag-col` / `jh-drag-row`。
6
-
7
- ---
8
-
9
- ## 1. 强制对照
10
-
11
- | 场景 | ✅ 必用 | ❌ 禁用 |
12
- | ---------- | -------------------------------------- | ------------------- |
13
- | 左右分栏 | `<jh-drag-col :leftWidth="240">` + `#left` / `#right` slot | `C_Splitter`、`el-aside`+`el-main` 手写 flex |
14
- | 上下分栏 | `<jh-drag-row :topHeight="240">` + `#top` / `#bottom` slot | `C_Splitter direction="vertical"`、手写 flex |
15
- | 嵌套分栏 | 多层 `jh-drag-col` / `jh-drag-row` 直接嵌套 | C_Splitter 嵌套(双倍 vnode 冻结) |
16
-
17
- > `@jhlc/jh-ui` 的 `jh-drag-col` / `jh-drag-row` 使用 Vue 原生 `<slot />` 直接渲染,**不缓存 vnode**,子组件响应式与父组件 ref 完全连通。
18
-
19
- ---
20
-
21
- ## 2. C_Splitter 为什么必须废弃(根因)
22
-
23
- `src/components/global/C_Splitter/index.vue` 内部实现:
24
-
25
- ```js
26
- onMounted(() => {
27
- const defaultSlots = slots.default ? slots.default() : [];
28
- // ...
29
- vnodes.value = children; // 冻结 vnode 列表
30
- });
31
- // 模板里
32
- // <component :is="item" />
33
- ```
34
-
35
- **反应链**:
36
-
37
- 1. `slots.default()` 只在 `onMounted` 执行一次 → 拿到的是**当时**的 vnode 快照
38
- 2. 模板用 `<component :is="item" />` 渲染快照 → 子组件的所有 props/slot props/ref 绑定**永远定格在 mount 那一刻**
39
- 3. 父组件后续修改 ref(`activeModelId.value = "xxx"`)→ 子组件 v-if/v-show/插值**全部失效**
40
- 4. 表现:点击树节点,右侧表格**永远显示初始数据**或空白;vue-devtools 看 ref 已变但 UI 不动
41
-
42
- > 这是 Vue 3 slot 渲染模型的本质:`slots.default()` 是一次性的 render function 调用,**不能用 ref 缓存其结果当模板用**。任何"缓存 vnode 数组再 component is 渲染"的写法都有同样的 bug。
43
-
44
- ---
45
-
46
- ## 3. 标准用法
47
-
48
- ### 3.1 左树右表(最常见)
49
-
50
- ```vue
51
- <template>
52
- <div class="app-container app-page-container" style="height: 100%">
53
- <jh-drag-col :leftWidth="240">
54
- <template #left>
55
- <C_Tree :data="treeData" @node-click="onNodeClick" />
56
- </template>
57
- <template #right>
58
- <BaseQuery ... />
59
- <BaseToolbar ... />
60
- <BaseTable v-if="activeModelId" ... />
61
- </template>
62
- </jh-drag-col>
63
- </div>
64
- </template>
65
- ```
66
-
67
- ✅ `v-if`、`ref` 赋值、所有响应式都能正常驱动右侧重渲染。
68
-
69
- ### 3.2 上表下详情(master-detail)
70
-
71
- ```vue
72
- <jh-drag-row :topHeight="320">
73
- <template #top>
74
- <BaseTable ... @row-click="onRowClick" />
75
- </template>
76
- <template #bottom>
77
- <DetailPanel v-if="currentRow" :data="currentRow" />
78
- </template>
79
- </jh-drag-row>
80
- ```
81
-
82
- ### 3.3 上 Tab 表单 + 下子表
83
-
84
- ```vue
85
- <jh-drag-row :topHeight="280">
86
- <template #top>
87
- <el-tabs v-model="activeTab"> ... </el-tabs>
88
- </template>
89
- <template #bottom>
90
- <BaseTable ... />
91
- </template>
92
- </jh-drag-row>
93
- ```
94
-
95
- ---
96
-
97
- ## 4. 兼容期处理
98
-
99
- 若现存项目仍引用 `C_Splitter`:
100
-
101
- 1. **当前版本**:保留组件文件,在 `onMounted` 顶部加 `console.warn("[C_Splitter 已废弃] ...")` 提示
102
- 2. **下一版本**:删除 `src/components/global/C_Splitter/`,全量替换为 `jh-drag-col/row`
103
- 3. **lint 规则**:`wl-skills validate` / `wl-skills doctor-ui` 命中 `import C_Splitter` 或 `<C_Splitter` 时报 ERROR
104
-
105
- ---
106
-
107
- ## 5. 自动迁移建议
108
-
109
- ```bash
110
- # 项目根目录执行
111
- grep -rln "C_Splitter" src/views | while read f; do
112
- echo "需要人工改造:$f"
113
- done
114
- ```
115
-
116
- 迁移要点:
117
-
118
- | 旧写法 | 新写法 |
119
- | ------ | ------ |
120
- | `<C_Splitter :left-width="220">` | `<jh-drag-col :leftWidth="220">` |
121
- | `<C_Splitter direction="vertical">` | `<jh-drag-row :topHeight="...">` |
122
- | 默认 slot 顺序:第一项 / 第二项 | 显式 `#left` `#right` / `#top` `#bottom` |
123
- | 拖动配置:`min-left-width="200"` | `jh-drag-col` 内置阈值 |
124
-
125
- ---
126
-
127
- ## 6. lint / codegen 强制项
128
-
129
- - `prototype-scan` / `page-codegen` 生成的模板**禁止**包含 `C_Splitter`
130
- - TPL-TREE-LIST、TPL-DETAIL-TABS 等模板必须使用 `jh-drag-col` / `jh-drag-row`
131
- - `wl-skills validate-page` 扫到 `C_Splitter` 直接 fail
132
- - `wl-skills validate src/views`:业务页面扫描 `<C_Splitter` / `import C_Splitter` / 过时注释(error / info 三级)
133
- - `wl-skills doctor-ui`:全仓扫描 `.vue/.ts/.scss/.md/.mdc`,区分**业务代码残留(error)**与**文档/规则残留(warn)**;含 `已废弃|DEPRECATED|严禁|不再需要|已迁移` 关键词的上下文自动豁免;`C_Splitter/` 组件目录自身豁免
134
-
135
- > 推荐在 CI 非阻断阶段挂 `wl-skills doctor-ui`,残留明细一目了然;提交前 pre-commit 由 `lint-skills` 兜底,禁止任何新增引用流入仓库。
136
-
137
- ---
138
-
139
- ## 7. FAQ
140
-
141
- **Q1:旧页面跑得好好的,为什么也要改?**
142
- 现状只是"还没踩到 ref 变更的场景"。一旦页面后续接入树节点切换 / 全屏刷新 / 编辑回填,就会出现 ref 改了 UI 不动的灵异 bug,排查成本远大于一次性迁移。
143
-
144
- **Q2:`jh-drag-col` 没有 `min-left-width` 怎么办?**
145
- 内部默认 200~600 阈值已可用;如需自定义,传 `:minLeftWidth` / `:maxLeftWidth`(数值,单位 px)。
146
-
147
- **Q3:嵌套两层分栏会有性能问题吗?**
148
- 不会。`jh-drag-col` / `jh-drag-row` 都是直接 `<slot />`,没有 vnode 缓存或额外 watcher,嵌套层数与原生 div 等价。
149
-
150
- **Q4:必须保留 `C_Splitter` 组件文件吗?**
151
- 保留一段过渡期(带 deprecation warning)即可。等仓库扫描 0 命中后,下一个大版本直接删除 `src/components/global/C_Splitter/`。
152
-
153
- ---
154
-
155
- ## 关联
156
-
157
- - `12-base-table.md` — BaseTable 内部高度撑满依赖父容器有明确高度,jh-drag-col/row 已正确给子区设 `height: 100%`
158
- - `13-platform-components.md` — 平台组件对照表已同步移除 C_Splitter
159
- - 真实场景案例:`demo/produce/aiflow/mmwr-customer-detail/`(master-detail 使用 jh-drag-row)
1
+ # 14 — 布局容器规范(C_Splitter 禁用 + jh-drag-col/row 唯一推荐)
2
+
3
+ > **强制度**:🔴 必遵 + 阻断式(lint 命中即报错)。
4
+ > **背景**:2024 年 12 月一次真实事故,左树右表页面右侧面板永不刷新,最终定位为 `C_Splitter` 在 `onMounted` 中调用 `slots.default()` 冻结 vnode 快照,导致子树所有响应式绑定与父组件 ref 脱钩。
5
+ > **结论**:项目中**禁止再使用 `C_Splitter`**,所有左右/上下分栏一律用 `jh-drag-col` / `jh-drag-row`。
6
+
7
+ ---
8
+
9
+ ## 1. 强制对照
10
+
11
+ | 场景 | ✅ 必用 | ❌ 禁用 |
12
+ | ---------- | -------------------------------------- | ------------------- |
13
+ | 左右分栏 | `<jh-drag-col :leftWidth="240">` + `#left` / `#right` slot | `C_Splitter`、`el-aside`+`el-main` 手写 flex |
14
+ | 上下分栏 | `<jh-drag-row :topHeight="240">` + `#top` / `#bottom` slot | `C_Splitter direction="vertical"`、手写 flex |
15
+ | 嵌套分栏 | 多层 `jh-drag-col` / `jh-drag-row` 直接嵌套 | C_Splitter 嵌套(双倍 vnode 冻结) |
16
+
17
+ > `@jhlc/jh-ui` 的 `jh-drag-col` / `jh-drag-row` 使用 Vue 原生 `<slot />` 直接渲染,**不缓存 vnode**,子组件响应式与父组件 ref 完全连通。
18
+
19
+ ---
20
+
21
+ ## 2. C_Splitter 为什么必须废弃(根因)
22
+
23
+ `src/components/global/C_Splitter/index.vue` 内部实现:
24
+
25
+ ```js
26
+ onMounted(() => {
27
+ const defaultSlots = slots.default ? slots.default() : [];
28
+ // ...
29
+ vnodes.value = children; // 冻结 vnode 列表
30
+ });
31
+ // 模板里
32
+ // <component :is="item" />
33
+ ```
34
+
35
+ **反应链**:
36
+
37
+ 1. `slots.default()` 只在 `onMounted` 执行一次 → 拿到的是**当时**的 vnode 快照
38
+ 2. 模板用 `<component :is="item" />` 渲染快照 → 子组件的所有 props/slot props/ref 绑定**永远定格在 mount 那一刻**
39
+ 3. 父组件后续修改 ref(`activeModelId.value = "xxx"`)→ 子组件 v-if/v-show/插值**全部失效**
40
+ 4. 表现:点击树节点,右侧表格**永远显示初始数据**或空白;vue-devtools 看 ref 已变但 UI 不动
41
+
42
+ > 这是 Vue 3 slot 渲染模型的本质:`slots.default()` 是一次性的 render function 调用,**不能用 ref 缓存其结果当模板用**。任何"缓存 vnode 数组再 component is 渲染"的写法都有同样的 bug。
43
+
44
+ ---
45
+
46
+ ## 3. 标准用法
47
+
48
+ ### 3.1 左树右表(最常见)
49
+
50
+ ```vue
51
+ <template>
52
+ <div class="app-container app-page-container" style="height: 100%">
53
+ <jh-drag-col :leftWidth="240">
54
+ <template #left>
55
+ <C_Tree :data="treeData" @node-click="onNodeClick" />
56
+ </template>
57
+ <template #right>
58
+ <BaseQuery ... />
59
+ <BaseToolbar ... />
60
+ <BaseTable v-if="activeModelId" ... />
61
+ </template>
62
+ </jh-drag-col>
63
+ </div>
64
+ </template>
65
+ ```
66
+
67
+ ✅ `v-if`、`ref` 赋值、所有响应式都能正常驱动右侧重渲染。
68
+
69
+ ### 3.2 上表下详情(master-detail)
70
+
71
+ ```vue
72
+ <jh-drag-row :topHeight="320">
73
+ <template #top>
74
+ <BaseTable ... @row-click="onRowClick" />
75
+ </template>
76
+ <template #bottom>
77
+ <DetailPanel v-if="currentRow" :data="currentRow" />
78
+ </template>
79
+ </jh-drag-row>
80
+ ```
81
+
82
+ ### 3.3 上 Tab 表单 + 下子表
83
+
84
+ ```vue
85
+ <jh-drag-row :topHeight="280">
86
+ <template #top>
87
+ <el-tabs v-model="activeTab"> ... </el-tabs>
88
+ </template>
89
+ <template #bottom>
90
+ <BaseTable ... />
91
+ </template>
92
+ </jh-drag-row>
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 4. 兼容期处理
98
+
99
+ 若现存项目仍引用 `C_Splitter`:
100
+
101
+ 1. **当前版本**:保留组件文件,在 `onMounted` 顶部加 `console.warn("[C_Splitter 已废弃] ...")` 提示
102
+ 2. **下一版本**:删除 `src/components/global/C_Splitter/`,全量替换为 `jh-drag-col/row`
103
+ 3. **lint 规则**:`wl-skills validate` / `wl-skills doctor-ui` 命中 `import C_Splitter` 或 `<C_Splitter` 时报 ERROR
104
+
105
+ ---
106
+
107
+ ## 5. 自动迁移建议
108
+
109
+ ```bash
110
+ # 项目根目录执行
111
+ grep -rln "C_Splitter" src/views | while read f; do
112
+ echo "需要人工改造:$f"
113
+ done
114
+ ```
115
+
116
+ 迁移要点:
117
+
118
+ | 旧写法 | 新写法 |
119
+ | ------ | ------ |
120
+ | `<C_Splitter :left-width="220">` | `<jh-drag-col :leftWidth="220">` |
121
+ | `<C_Splitter direction="vertical">` | `<jh-drag-row :topHeight="...">` |
122
+ | 默认 slot 顺序:第一项 / 第二项 | 显式 `#left` `#right` / `#top` `#bottom` |
123
+ | 拖动配置:`min-left-width="200"` | `jh-drag-col` 内置阈值 |
124
+
125
+ ---
126
+
127
+ ## 6. lint / codegen 强制项
128
+
129
+ - `prototype-scan` / `page-codegen` 生成的模板**禁止**包含 `C_Splitter`
130
+ - TPL-TREE-LIST、TPL-DETAIL-TABS 等模板必须使用 `jh-drag-col` / `jh-drag-row`
131
+ - `wl-skills validate-page` 扫到 `C_Splitter` 直接 fail
132
+ - `wl-skills validate src/views`:业务页面扫描 `<C_Splitter` / `import C_Splitter` / 过时注释(error / info 三级)
133
+ - `wl-skills doctor-ui`:全仓扫描 `.vue/.ts/.scss/.md/.mdc`,区分**业务代码残留(error)**与**文档/规则残留(warn)**;含 `已废弃|DEPRECATED|严禁|不再需要|已迁移` 关键词的上下文自动豁免;`C_Splitter/` 组件目录自身豁免
134
+
135
+ > 推荐在 CI 非阻断阶段挂 `wl-skills doctor-ui`,残留明细一目了然;提交前 pre-commit 由 `lint-skills` 兜底,禁止任何新增引用流入仓库。
136
+
137
+ ---
138
+
139
+ ## 7. FAQ
140
+
141
+ **Q1:旧页面跑得好好的,为什么也要改?**
142
+ 现状只是"还没踩到 ref 变更的场景"。一旦页面后续接入树节点切换 / 全屏刷新 / 编辑回填,就会出现 ref 改了 UI 不动的灵异 bug,排查成本远大于一次性迁移。
143
+
144
+ **Q2:`jh-drag-col` 没有 `min-left-width` 怎么办?**
145
+ 内部默认 200~600 阈值已可用;如需自定义,传 `:minLeftWidth` / `:maxLeftWidth`(数值,单位 px)。
146
+
147
+ **Q3:嵌套两层分栏会有性能问题吗?**
148
+ 不会。`jh-drag-col` / `jh-drag-row` 都是直接 `<slot />`,没有 vnode 缓存或额外 watcher,嵌套层数与原生 div 等价。
149
+
150
+ **Q4:必须保留 `C_Splitter` 组件文件吗?**
151
+ 保留一段过渡期(带 deprecation warning)即可。等仓库扫描 0 命中后,下一个大版本直接删除 `src/components/global/C_Splitter/`。
152
+
153
+ ---
154
+
155
+ ## 关联
156
+
157
+ - `12-base-table.md` — BaseTable 内部高度撑满依赖父容器有明确高度,jh-drag-col/row 已正确给子区设 `height: 100%`
158
+ - `13-platform-components.md` — 平台组件对照表已同步移除 C_Splitter
159
+ - 真实场景案例:`demo/produce/aiflow/mmwr-customer-detail/`(master-detail 使用 jh-drag-row)