@agile-team/wl-skills-kit 2.9.2 → 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 +23 -0
- package/README.md +1 -1
- package/bin/wl-skills.js +19 -11
- package/files/.github/copilot-instructions.md +9 -14
- package/files/.github/guides/architecture.md +1 -1
- package/files/.github/guides/usage.md +1 -1
- package/files/.github/skills/_best-practices.md +2 -2
- package/files/.github/skills/core/convention-audit/SKILL.md +9 -7
- package/files/.github/skills/core/page-codegen/SKILL.md +1 -0
- package/files/.github/skills/core/page-codegen/USAGE.md +1 -1
- package/files/.github/skills/core/prototype-scan/SKILL.md +3 -3
- package/files/.github/standards/14-layout-containers.md +159 -159
- package/files/demo/sale/demo/add-demo/index.scss +207 -207
- package/files/demo/sale/demo/add-demo/index.vue +171 -171
- package/files/demo/sale/demo/metallurgical-spec/index.scss +264 -264
- package/files/demo/sale/demo/metallurgical-spec/index.vue +313 -313
- package/files/src/components/global/C_Splitter/index.vue +149 -149
- package/files/src/components/local/c_formSections/README.md +496 -496
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
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
|
+
|
|
15
|
+
## [2.9.3] - 2026-05-17
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **`doctor-ui` C_Splitter 残留扫描噪音过大**:
|
|
20
|
+
- 豁免词扩展为 `已废弃 / DEPRECATED / 严禁 / 禁用 / 禁止 / 废弃 / 不再需要 / 已迁移 / deprecated`
|
|
21
|
+
- `standards/14-*` 文件路径整体豁免(文档本身就是讲 C_Splitter 的)
|
|
22
|
+
- `*.d.ts` 和 `components.d.ts` 整体豁免(unplugin-vue-components 自动生成产物)
|
|
23
|
+
- 文档/规则残留改为**纯警告**,不再参与 exitCode 判定(业务代码命中才阻断)
|
|
24
|
+
- 实战验证:wl-mdata 仓库二次扫描从 1 处业务残留 + 18 处误报 → **0 命中**
|
|
25
|
+
|
|
3
26
|
## [2.9.2] - 2026-05-17
|
|
4
27
|
|
|
5
28
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @agile-team/wl-skills-kit
|
|
2
2
|
|
|
3
|
-
**AI Skill 模板包 v2.9.
|
|
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.
|
|
4
|
+
* wl-skills-kit CLI v2.9.4
|
|
5
5
|
*
|
|
6
6
|
* 命令:
|
|
7
7
|
* init 全量安装(默认,向后兼容)
|
|
@@ -1109,7 +1109,7 @@ function runDoctorUi() {
|
|
|
1109
1109
|
// —— C_Splitter 残留扫描(standards/14 一致性)——
|
|
1110
1110
|
// 业务代码(.vue / .scss / .ts)禁止任何 C_Splitter;文档/规则(.md / .mdc)只允许"废弃说明"句式
|
|
1111
1111
|
const EXEMPT_KEYWORDS =
|
|
1112
|
-
/已废弃|DEPRECATED
|
|
1112
|
+
/已废弃|DEPRECATED|严禁|禁用|禁止|废弃|不再需要|已迁移|deprecated/i;
|
|
1113
1113
|
const splitterFiles = files.filter(
|
|
1114
1114
|
(rel) =>
|
|
1115
1115
|
/\.(ts|vue|scss|js|tsx|md|mdc)$/.test(rel) &&
|
|
@@ -1123,9 +1123,13 @@ function runDoctorUi() {
|
|
|
1123
1123
|
if (
|
|
1124
1124
|
rel.includes("/C_Splitter/") ||
|
|
1125
1125
|
rel.endsWith("/C_Splitter/index.vue") ||
|
|
1126
|
-
rel.endsWith("/C_Splitter/index.scss")
|
|
1126
|
+
rel.endsWith("/C_Splitter/index.scss") ||
|
|
1127
|
+
/standards\/14[-_]/.test(rel) ||
|
|
1128
|
+
/\.d\.ts$/.test(rel) ||
|
|
1129
|
+
rel === "components.d.ts" ||
|
|
1130
|
+
rel.endsWith("/components.d.ts")
|
|
1127
1131
|
)
|
|
1128
|
-
continue; //
|
|
1132
|
+
continue; // 组件自身 + standards/14 + 自动生成产物豁免
|
|
1129
1133
|
const full = path.join(TARGET_DIR, rel);
|
|
1130
1134
|
let content;
|
|
1131
1135
|
try {
|
|
@@ -1152,17 +1156,21 @@ function runDoctorUi() {
|
|
|
1152
1156
|
? "无"
|
|
1153
1157
|
: codeHits.length + " 处(详见下方明细,需改 jh-drag-col/-row)",
|
|
1154
1158
|
);
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
+
// 文档/规则残留只 warn,不参与 exitCode
|
|
1160
|
+
const docOk = docHits.length === 0;
|
|
1161
|
+
checks.push({
|
|
1162
|
+
name: "C_Splitter 文档/规则残留",
|
|
1163
|
+
ok: true,
|
|
1164
|
+
warn: !docOk,
|
|
1165
|
+
detail: docOk
|
|
1159
1166
|
? "无"
|
|
1160
|
-
: docHits.length + "
|
|
1161
|
-
);
|
|
1167
|
+
: docHits.length + " 处(详见下方明细,仅警告)",
|
|
1168
|
+
});
|
|
1162
1169
|
|
|
1163
1170
|
for (const item of checks) {
|
|
1171
|
+
const icon = item.warn ? "⚠" : statusIcon(item.ok);
|
|
1164
1172
|
console.log(
|
|
1165
|
-
" " +
|
|
1173
|
+
" " + icon + " " + item.name + " — " + item.detail,
|
|
1166
1174
|
);
|
|
1167
1175
|
}
|
|
1168
1176
|
if (codeHits.length || docHits.length) {
|
|
@@ -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 {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
完整
|
|
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` 确认任务类型
|
|
@@ -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` | 规范审计 / 代码审计 |
|
|
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 ←
|
|
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 |
|
|
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
|
|
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/`
|
|
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 ~
|
|
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
|
-
## 审计范围(
|
|
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
|
-
###
|
|
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.
|
|
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` 加载的
|
|
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,会扫出
|
|
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 |
|
|
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
|
-
// ===== 表单字段(
|
|
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 /
|
|
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)
|