@agile-team/wl-skills-kit 2.7.3 → 2.9.1
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 +58 -0
- package/README.md +33 -12
- package/bin/wl-skills.js +179 -3
- package/files/.github/copilot-instructions.md +19 -1
- package/files/.github/guides/architecture.md +6 -4
- package/files/.github/skills/_best-practices.md +11 -1
- package/files/.github/skills/core/page-codegen/SKILL.md +6 -6
- package/files/.github/skills/core/page-codegen/templates/_index.md +1 -1
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-DETAIL-TABS.md +9 -5
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-TREE-LIST.md +6 -7
- package/files/.github/skills/core/prototype-scan/SKILL.md +2 -2
- package/files/.github/standards/13-platform-components.md +2 -2
- package/files/.github/standards/14-layout-containers.md +139 -0
- package/files/.github/standards/index.md +4 -3
- package/files/demo/sale/demo/add-demo/index.scss +1 -1
- package/files/demo/sale/demo/add-demo/index.vue +8 -4
- package/files/demo/sale/demo/metallurgical-spec/index.scss +1 -1
- package/files/demo/sale/demo/metallurgical-spec/index.vue +7 -3
- package/files/docs/mock-architecture.md +321 -0
- package/files/mock/_utils.ts +35 -0
- package/files/src/components/global/C_Splitter/index.vue +16 -0
- package/files/src/components/local/c_formSections/README.md +1 -1
- package/mcp/tools/dictSync.js +178 -178
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.9.1] - 2026-05-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`validate` 三项新检查**(接 v2.9.0 的 standards/14 落地阻断):
|
|
8
|
+
- 🔴 `error`:页面 `index.vue` 出现 `<C_Splitter>` 标签
|
|
9
|
+
- 🔴 `error`:`index.vue` / `data.ts` 出现 `import C_Splitter`
|
|
10
|
+
- ℹ `info`:提及 `C_Splitter` 的过时注释(如 `已改为 C_Splitter`、`migrate to C_Splitter`、`TODO ... C_Splitter`)
|
|
11
|
+
- **`scripts/lint-skills.js` 新增规则 8**:扫描 `files/**/*.{vue,ts}`,禁止任何 `<C_Splitter>` 标签或 `import C_Splitter`(仅允许 `files/src/components/global/C_Splitter/index.vue` 自身保留废弃声明)。
|
|
12
|
+
- **`.husky/pre-commit` 接入 `lint-skills`**:维护者侧提交时自动守门,从源头阻止 C_Splitter 回潮。
|
|
13
|
+
|
|
14
|
+
### Notes
|
|
15
|
+
|
|
16
|
+
- 实战验证:wl-mdata 现网 28 个页面 0 命中(之前已全量迁移);故意污染测试用例可精准触发 3 项检查。
|
|
17
|
+
- 兼容性:所有新检查均为加法,未改动既有 validate 规则;下游项目无需调整。
|
|
18
|
+
|
|
19
|
+
## [2.9.0] - 2026-05-17
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`files/.github/standards/14-layout-containers.md`**(新规范,🔴 必遵 + 阻断):布局容器规范。根因解析 `C_Splitter` 在 `onMounted` 中调用 `slots.default()` 冻结 vnode 快照、导致子树响应式完全失效;明确左右分割只用 `jh-drag-col`(`#left`/`#right`),上下分栈只用 `jh-drag-row`(`#top`/`#bottom`);附迁移对照表、lint 规则、废弃路线图。
|
|
24
|
+
- **`files/src/components/global/C_Splitter/index.vue`** 加入 `@deprecated` 注释 + 运行时 `console.warn`(同会话仅警告一次),引导改用 `jh-drag-col` / `jh-drag-row`。
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **`standards/index.md`**:13 条 → 14 条;任务 A(生成新页面)/ B(修改重构)必读集合纳入 `14`。
|
|
29
|
+
- **`standards/13-platform-components.md`** 与 `copilot-instructions.md`:「左右分割」推荐组件由 `C_Splitter` 改为 `jh-drag-col`;明确 `C_Splitter` 已废弃及根因。
|
|
30
|
+
- **TPL-TREE-LIST.md**:模板示例改为 `<jh-drag-col :leftWidth="220">` + `#left`/`#right` 显式插槽;SCSS 去除 `.my-splitter-container :deep` 残留;顶部加「布局硬约束」段。
|
|
31
|
+
- **TPL-DETAIL-TABS.md**:示例由 `<C_Splitter direction="vertical">` 改为 `<jh-drag-row :topHeight="380">` + `#top`/`#bottom`;移除 `import C_Splitter`。
|
|
32
|
+
- **`page-codegen/SKILL.md`** 与 `templates/_index.md`:TREE_LIST 描述同步至 jh-drag-col;上下分栈描述同步至 jh-drag-row。
|
|
33
|
+
- **`prototype-scan/SKILL.md`**:原型扫描产出物示例与说明同步至 jh-drag-col。
|
|
34
|
+
- **`demo/sale/demo/add-demo/`** 与 **`demo/sale/demo/metallurgical-spec/`**:示例 `<C_Splitter>` 全部迁移到 `<jh-drag-row>`;SCSS 注释、README 文案对齐。
|
|
35
|
+
|
|
36
|
+
### Notes
|
|
37
|
+
|
|
38
|
+
- 兼容性:`C_Splitter` 源文件保留但加废弃警告,**不删除**,避免外部业务项目升级时立即报错;下一个 major 版本前再做物理移除评估。
|
|
39
|
+
- 参考案例:`wl-ui-sale` 项目所有左树右表/上下分栈页面(material、materialCategory、transactionType、unit、price-maintain、ContractEditTab 等)均使用 `jh-drag-col` / `jh-drag-row`,未踩 `C_Splitter` 冻 vnode 坑——本次规范固化的正是该实战路径。
|
|
40
|
+
|
|
41
|
+
## [2.8.0] - 2026-05-16
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- **`files/docs/mock-architecture.md`**(新文档):Mock 架构规范,涵盖目录约定(按业务域分目录 `mock/[域]/[模块].ts`)、`_utils.ts` 共享工具、`ENV_MOCK` 开关机制、STORE 可变数组持久化模式、端点覆盖检查、一键清理流程。
|
|
46
|
+
- **`files/mock/_utils.ts`**(种子文件):`init`/`update` 自动写入目标项目 `mock/_utils.ts`,提供 `pageResult`/`ok`/`paginate`/`nowStr`/`pick` 五个共享工具,消除各 mock 模块重复定义。
|
|
47
|
+
- **CLI `mock-clean` 命令**:`--domain <name>` 按域清理(如 `mock-clean --domain mdata`)、`--all` 全量清理(保留 `_utils.ts`)、支持 `--dry-run` 预览。清理后提示修改 `ENV_MOCK` 并运行 `validate`。
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- **`copilot-instructions.md`** 新增 Mock 架构节:目录结构约定、开关机制、URL 对齐、STORE 模式、模块自治原则、`mock-clean` CLI 用法。
|
|
52
|
+
- **`page-codegen/SKILL.md`** 规则修正:规则 9 → `mock/[业务域]/[模块].ts` 按域分目录 + 强制 `import ../_utils`;规则 20 → 自检 `mock/_utils.ts` 存在;规则 21 → 路径格式对齐;禁止 14 → 引用 `docs/mock-architecture.md`。
|
|
53
|
+
- **`validate` 增强**:新增 3 项 mock 架构质量检查 —— `_utils.ts` 存在性(warn)、mock 文件是否按域分目录(info)、是否引用共享工具(info)。输出新增 `ℹ` info 级别图标。
|
|
54
|
+
- **`_best-practices.md`** 场景 6 扩展:从一句话描述 → 完整 mock 架构速览 + 目录树 + 开关/清理说明。
|
|
55
|
+
- **`--domain` / `--all` 加入 `KNOWN_FLAGS`**;flag 校验兼容 `--domain=xxx` 等号格式。
|
|
56
|
+
|
|
57
|
+
### Notes
|
|
58
|
+
|
|
59
|
+
- Mock 架构为前端最佳实践固化,已在 wl-mdata 项目验证。新项目 `init` 后即获得 `mock/_utils.ts`;已有项目 `update` 后自动补充。
|
|
60
|
+
|
|
3
61
|
## [2.7.3] - 2026-05-13
|
|
4
62
|
|
|
5
63
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @agile-team/wl-skills-kit
|
|
2
2
|
|
|
3
|
-
**AI Skill 模板包 v2.
|
|
3
|
+
**AI Skill 模板包 v2.9.1 ** — 一键将 13 条规范、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
|
|
|
@@ -23,6 +23,15 @@ npm run standards:init # 本包维护/业务项目均可复用
|
|
|
23
23
|
|
|
24
24
|
## 版本亮点
|
|
25
25
|
|
|
26
|
+
**v2.8.0**:Mock 架构体系固化 + `mock-clean` CLI 命令。
|
|
27
|
+
|
|
28
|
+
- 新增 `docs/mock-architecture.md` — Mock 目录约定、开关机制、模块化规范、一键清理流程
|
|
29
|
+
- 新增 `mock/_utils.ts` 种子文件 — `init` 自动写入,提供 `pageResult`/`ok`/`paginate`/`nowStr`/`pick`
|
|
30
|
+
- 新增 CLI `mock-clean` 命令 — `--domain <name>` 按域清理、`--all` 全量清理(保留 `_utils.ts`)、`--dry-run` 预览
|
|
31
|
+
- `copilot-instructions.md` 新增 Mock 架构节(目录约定、开关、STORE 模式、URL 对齐)
|
|
32
|
+
- `page-codegen/SKILL.md` 规则 9/20/21 修正为按域分目录 + 强制引用 `_utils`
|
|
33
|
+
- `validate` 增强:检查 `_utils.ts` 存在、mock 文件是否按域分目录、是否引用共享工具
|
|
34
|
+
|
|
26
35
|
**v2.7.3**:工程质量提升 — MCP tools 单测覆盖、lint-skills 扩展到 core Skill、.gitattributes 消除行尾符噪音、permission-sync SKILL.md 精简。
|
|
27
36
|
|
|
28
37
|
- 新增 `tests/mcp-tools.test.js`(30 个测试)覆盖 menuSync/dictSync/permissionSync 核心纯函数与参数校验
|
|
@@ -53,7 +62,7 @@ npm run standards:init # 本包维护/业务项目均可复用
|
|
|
53
62
|
- **单元测试**:registry / CLI / version-tools 共 18 项覆盖,上面三项防护都有连动验证
|
|
54
63
|
- **单一数据源加固**:`SKILL_COUNT` 从常量改为从 `_registry.md` 动态计算;copilot-instructions 删除内嵌 Skill 表改为指针;dict-sync / code-fix 补 USAGE.md
|
|
55
64
|
|
|
56
|
-
|
|
65
|
+
2.6.x 以来重点补齐业务理解闭环:原型/详设 → 业务文档 → 接口契约 → 页面代码 → 复扫。
|
|
57
66
|
|
|
58
67
|
- **新增 `business-doc-extract` Skill**:语义级智能触发(不依赖固定关键词),在资料达模块/项目级完整度时建议生成业务文档:
|
|
59
68
|
```text
|
|
@@ -125,16 +134,17 @@ wl-skills-kit/ ← 你正看的这个仓库
|
|
|
125
134
|
├── package.json name: @agile-team/wl-skills-kit
|
|
126
135
|
│
|
|
127
136
|
├── bin/
|
|
128
|
-
│ └── wl-skills.js CLI 实现(init / update / clean / check / diff / validate / validate-page / doctor-ui / export)
|
|
137
|
+
│ └── wl-skills.js CLI 实现(init / update / clean / check / diff / validate / validate-page / doctor-ui / export / mock-clean)
|
|
129
138
|
│
|
|
130
139
|
├── files/ ★★★ 真正会被打包并复制到业务项目的内容 ★★★
|
|
131
|
-
│
|
|
132
|
-
│
|
|
133
|
-
│
|
|
134
|
-
│
|
|
135
|
-
│
|
|
136
|
-
│
|
|
137
|
-
│ ├── docs/ 组件 API 文档
|
|
140
|
+
│ ├── .github/
|
|
141
|
+
│ │ ├── copilot-instructions.md 源 AI 主入口(编辑这里,不要编辑业务项目里的副本)
|
|
142
|
+
│ │ ├── standards/ 13 条规范
|
|
143
|
+
│ │ ├── skills/ Skill 目录(含 _compat/ 多编辑器适配源)
|
|
144
|
+
│ │ ├── guides/ 人读指南
|
|
145
|
+
│ │ └── reports/ 领域基线模板(菜单/字典/权限)
|
|
146
|
+
│ ├── docs/ 组件 API 文档 + Mock 架构规范
|
|
147
|
+
│ ├── mock/ Mock 共享工具种子(_utils.ts)
|
|
138
148
|
│ └── demo/ 领域样例
|
|
139
149
|
│
|
|
140
150
|
├── kit-internal/ ★★ 仅仓库可见,不会安装到业务项目 ★★
|
|
@@ -163,7 +173,7 @@ wl-skills-kit/ ← 你正看的这个仓库
|
|
|
163
173
|
你的业务项目/
|
|
164
174
|
│
|
|
165
175
|
├── .github/ ← 来自本包 files/.github/
|
|
166
|
-
│ ├── copilot-instructions.md Copilot 主入口(精简 ~
|
|
176
|
+
│ ├── copilot-instructions.md Copilot 主入口(精简 ~340 行)
|
|
167
177
|
│ ├── standards/ 13 条模块化规范 + index.md 门控
|
|
168
178
|
│ │ ├── 01-toolchain.md
|
|
169
179
|
│ │ ├── 02-code-structure.md
|
|
@@ -204,7 +214,11 @@ wl-skills-kit/ ← 你正看的这个仓库
|
|
|
204
214
|
├── .trae/rules/conventions.md Trae(含 alwaysApply frontmatter)
|
|
205
215
|
├── .qoder/rules/conventions.md Qoder
|
|
206
216
|
│
|
|
207
|
-
├──
|
|
217
|
+
├── mock/ ← 来自本包 files/mock/(init 自动写入)
|
|
218
|
+
│ ├── _utils.ts 共享工具(pageResult / ok / paginate / nowStr / pick)
|
|
219
|
+
│ └── [业务域]/[模块].ts 按域分目录,page-codegen 自动生成
|
|
220
|
+
│
|
|
221
|
+
├── docs/ 12 个组件 API 文档 + mock-architecture.md
|
|
208
222
|
├── demo/ 13 个领域样例
|
|
209
223
|
└── src/
|
|
210
224
|
├── components/ 全局/局部/远程组件
|
|
@@ -254,6 +268,12 @@ npx @agile-team/wl-skills-kit clean
|
|
|
254
268
|
# 清理但保留 reports/(菜单/字典/权限累积数据)
|
|
255
269
|
npx @agile-team/wl-skills-kit clean --keep-reports
|
|
256
270
|
|
|
271
|
+
# 清理指定业务域的 mock 文件(保留 _utils.ts)
|
|
272
|
+
npx @agile-team/wl-skills-kit mock-clean --domain mdata
|
|
273
|
+
|
|
274
|
+
# 清理全部 mock(保留 _utils.ts)
|
|
275
|
+
npx @agile-team/wl-skills-kit mock-clean --all
|
|
276
|
+
|
|
257
277
|
# 任何命令都可加 --dry-run 预览
|
|
258
278
|
npx @agile-team/wl-skills-kit update --dry-run
|
|
259
279
|
```
|
|
@@ -313,6 +333,7 @@ npx @agile-team/wl-skills-kit update
|
|
|
313
333
|
| `api-contract` | ✅ 启用 | `skills/core/api-contract/` | 生成 api.md 前后端契约 |
|
|
314
334
|
| `page-codegen` | ✅ 启用 | `skills/core/page-codegen/` | 页面骨架生成 + 模板调度 |
|
|
315
335
|
| `convention-audit` | ✅ 启用 | `skills/core/convention-audit/` | 13 条规范扫描 + 双报告 |
|
|
336
|
+
| `business-doc-extract` | ✅ 启用 | `skills/core/business-doc-extract/` | 语义触发,业务文档抽取与维护 |
|
|
316
337
|
| `template-extract` | ✅ 启用 | `skills/core/template-extract/` | 现有页面 → 领域模板 |
|
|
317
338
|
| `menu-sync` | ✅ 启用 | `skills/sync/menu-sync/` | 菜单基线 ↔ 后端接口 |
|
|
318
339
|
| `dict-sync` | ✅ 启用 | `skills/sync/dict-sync/` | 字典基线 ↔ 后端接口 |
|
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.
|
|
4
|
+
* wl-skills-kit CLI v2.9.1
|
|
5
5
|
*
|
|
6
6
|
* 命令:
|
|
7
7
|
* init 全量安装(默认,向后兼容)
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* validate-page validate 的别名,适用于单页/目录检查
|
|
14
14
|
* doctor-ui 检查 @agile-team/wk-skills-ui 接入完整性
|
|
15
15
|
* export 导出 SYS_MENU / SYS_DICT / SYS_PERMISSION 为 xlsx
|
|
16
|
+
* mock-clean 清理 mock 文件(按域或全部),保留 _utils.ts
|
|
16
17
|
* --help 帮助
|
|
17
18
|
* --dry-run 预览模式(所有命令均支持)
|
|
18
19
|
*/
|
|
@@ -39,6 +40,7 @@ const KNOWN_COMMANDS = new Set([
|
|
|
39
40
|
"validate-page",
|
|
40
41
|
"doctor-ui",
|
|
41
42
|
"export",
|
|
43
|
+
"mock-clean",
|
|
42
44
|
]);
|
|
43
45
|
const KNOWN_FLAGS = new Set([
|
|
44
46
|
"--dry-run",
|
|
@@ -46,6 +48,8 @@ const KNOWN_FLAGS = new Set([
|
|
|
46
48
|
"--force",
|
|
47
49
|
"--help",
|
|
48
50
|
"-h",
|
|
51
|
+
"--domain",
|
|
52
|
+
"--all",
|
|
49
53
|
]);
|
|
50
54
|
|
|
51
55
|
const dryRun = args.includes("--dry-run");
|
|
@@ -56,7 +60,10 @@ const force = args.includes("--force");
|
|
|
56
60
|
// 校验所有 flag 是否已知(--help 优先,跳过校验直接显示帮助)
|
|
57
61
|
if (!showHelp) {
|
|
58
62
|
const unknownFlags = args.filter(
|
|
59
|
-
(a) =>
|
|
63
|
+
(a) =>
|
|
64
|
+
a.startsWith("-") &&
|
|
65
|
+
!KNOWN_FLAGS.has(a) &&
|
|
66
|
+
!KNOWN_FLAGS.has(a.split("=")[0]),
|
|
60
67
|
);
|
|
61
68
|
if (unknownFlags.length > 0) {
|
|
62
69
|
console.error("");
|
|
@@ -96,11 +103,14 @@ if (showHelp) {
|
|
|
96
103
|
validate-page validate 的别名,适用于单页/目录检查
|
|
97
104
|
doctor-ui 检查 @agile-team/wk-skills-ui 接入完整性
|
|
98
105
|
export 导出 reports/SYS_* 数据为 xlsx
|
|
106
|
+
mock-clean 清理 mock 文件(按域或全部),保留 _utils.ts
|
|
99
107
|
|
|
100
108
|
选项:
|
|
101
109
|
--dry-run 预览模式,不实际写入/删除任何文件
|
|
102
110
|
--keep-reports clean 命令保留 .github/reports/(默认一起删除)
|
|
103
111
|
--force 强制执行,跳过同版本检测(忽略已安装状态)
|
|
112
|
+
--domain <name> mock-clean 指定要清理的业务域(如 sale、mdata)
|
|
113
|
+
--all mock-clean 清理全部 mock(保留 _utils.ts)
|
|
104
114
|
--help 显示帮助
|
|
105
115
|
|
|
106
116
|
示例:
|
|
@@ -116,6 +126,9 @@ if (showHelp) {
|
|
|
116
126
|
npx @agile-team/wl-skills-kit clean 清理开发期文件
|
|
117
127
|
npx @agile-team/wl-skills-kit clean --keep-reports 保留 reports/中的菜单/字典数据
|
|
118
128
|
npx @agile-team/wl-skills-kit clean --dry-run 预览将要清理哪些文件
|
|
129
|
+
npx @agile-team/wl-skills-kit mock-clean --domain mdata 清理 mdata 域 mock
|
|
130
|
+
npx @agile-team/wl-skills-kit mock-clean --all 清理全部 mock
|
|
131
|
+
npx @agile-team/wl-skills-kit mock-clean --all --dry-run 预览将要清理的 mock 文件
|
|
119
132
|
|
|
120
133
|
保护路径(init / update 不覆盖已存在的):
|
|
121
134
|
.github/reports/ AI 生成报告(团队累积数据,存在则跳过)
|
|
@@ -818,6 +831,17 @@ function scanPageDirs(scanRel) {
|
|
|
818
831
|
hasEmptyOnClick: /onClick\s*:\s*\(\s*[^)]*\s*\)\s*=>\s*\{\s*\}/.test(
|
|
819
832
|
dataContent,
|
|
820
833
|
),
|
|
834
|
+
hasCSplitterTag: /<C_Splitter\b/.test(indexContent),
|
|
835
|
+
hasCSplitterImport:
|
|
836
|
+
/from\s+["'][^"']*C_Splitter[^"']*["']/.test(indexContent) ||
|
|
837
|
+
/from\s+["'][^"']*C_Splitter[^"']*["']/.test(dataContent),
|
|
838
|
+
staleSplitterComments: (
|
|
839
|
+
(indexContent.match(/(?:已改为|migrate to|TODO).{0,40}C_Splitter/g) || [])
|
|
840
|
+
.concat(
|
|
841
|
+
dataContent.match(/(?:已改为|migrate to|TODO).{0,40}C_Splitter/g) ||
|
|
842
|
+
[],
|
|
843
|
+
)
|
|
844
|
+
).length,
|
|
821
845
|
apiUrls: Array.from(
|
|
822
846
|
dataContent.matchAll(/:\s*["']([^"']+\/[^"']+)["']/g),
|
|
823
847
|
).map((m) => m[1]),
|
|
@@ -853,6 +877,54 @@ function runValidate() {
|
|
|
853
877
|
const mockContent = mockFiles
|
|
854
878
|
.map((rel) => fs.readFileSync(path.join(TARGET_DIR, rel), "utf8"))
|
|
855
879
|
.join("\n");
|
|
880
|
+
|
|
881
|
+
// ── Mock 架构质量检查 ──────────────────────────────────────────────
|
|
882
|
+
const mockDir = path.join(TARGET_DIR, "mock");
|
|
883
|
+
const hasMockDir = fs.existsSync(mockDir);
|
|
884
|
+
const hasUtilsTs =
|
|
885
|
+
hasMockDir &&
|
|
886
|
+
(fs.existsSync(path.join(mockDir, "_utils.ts")) ||
|
|
887
|
+
fs.existsSync(path.join(mockDir, "_utils.js")));
|
|
888
|
+
if (hasMockDir && mockFiles.length > 0 && !hasUtilsTs) {
|
|
889
|
+
issues.push({
|
|
890
|
+
level: "warn",
|
|
891
|
+
dir: "mock/",
|
|
892
|
+
text: "缺少 mock/_utils.ts 共享工具文件(建议 wl-skills init 补充)",
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
// 检查 mock 文件是否按域分目录(非 _utils 的 ts/js 文件不应直接放在 mock/ 根)
|
|
896
|
+
for (const rel of mockFiles) {
|
|
897
|
+
const parts = rel
|
|
898
|
+
.replace(/\\/g, "/")
|
|
899
|
+
.replace(/^mock\//, "")
|
|
900
|
+
.split("/");
|
|
901
|
+
const basename = parts[parts.length - 1];
|
|
902
|
+
if (parts.length === 1 && !basename.startsWith("_")) {
|
|
903
|
+
issues.push({
|
|
904
|
+
level: "info",
|
|
905
|
+
dir: "mock/",
|
|
906
|
+
text:
|
|
907
|
+
basename +
|
|
908
|
+
" 直接放在 mock/ 根目录,建议按业务域分子目录(如 mock/sale/" +
|
|
909
|
+
basename +
|
|
910
|
+
")",
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
// 检查 mock 模块文件是否 import _utils
|
|
915
|
+
for (const rel of mockFiles) {
|
|
916
|
+
const basename = path.basename(rel);
|
|
917
|
+
if (basename.startsWith("_")) continue;
|
|
918
|
+
const content = fs.readFileSync(path.join(TARGET_DIR, rel), "utf8");
|
|
919
|
+
if (hasUtilsTs && !/_utils/.test(content)) {
|
|
920
|
+
issues.push({
|
|
921
|
+
level: "info",
|
|
922
|
+
dir: rel,
|
|
923
|
+
text: "未引用 mock/_utils 共享工具,建议统一使用 pageResult/ok/paginate",
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
856
928
|
for (const page of pages) {
|
|
857
929
|
if (!page.hasDataTs)
|
|
858
930
|
issues.push({
|
|
@@ -911,6 +983,27 @@ function runValidate() {
|
|
|
911
983
|
dir: page.dir,
|
|
912
984
|
text: "存在空 onClick: () => {}",
|
|
913
985
|
});
|
|
986
|
+
if (page.hasCSplitterTag)
|
|
987
|
+
issues.push({
|
|
988
|
+
level: "error",
|
|
989
|
+
dir: page.dir,
|
|
990
|
+
text: "禁用 <C_Splitter>:请改用 jh-drag-col(左右)/ jh-drag-row(上下),详 standards/14-layout-containers.md",
|
|
991
|
+
});
|
|
992
|
+
if (page.hasCSplitterImport)
|
|
993
|
+
issues.push({
|
|
994
|
+
level: "error",
|
|
995
|
+
dir: page.dir,
|
|
996
|
+
text: "禁止 import C_Splitter:该组件已废弃(onMounted 冻 vnode 致响应式失效),详 standards/14",
|
|
997
|
+
});
|
|
998
|
+
if (page.staleSplitterComments > 0)
|
|
999
|
+
issues.push({
|
|
1000
|
+
level: "info",
|
|
1001
|
+
dir: page.dir,
|
|
1002
|
+
text:
|
|
1003
|
+
"发现 " +
|
|
1004
|
+
page.staleSplitterComments +
|
|
1005
|
+
" 处提及 C_Splitter 的过时注释,建议清理",
|
|
1006
|
+
});
|
|
914
1007
|
if (page.apiConfigCount > 0 && mockFiles.length === 0)
|
|
915
1008
|
issues.push({
|
|
916
1009
|
level: "warn",
|
|
@@ -933,7 +1026,8 @@ function runValidate() {
|
|
|
933
1026
|
console.log("");
|
|
934
1027
|
const errors = issues.filter((issue) => issue.level === "error").length;
|
|
935
1028
|
for (const issue of issues) {
|
|
936
|
-
const icon =
|
|
1029
|
+
const icon =
|
|
1030
|
+
issue.level === "error" ? "✖" : issue.level === "info" ? "ℹ" : "⚠";
|
|
937
1031
|
console.log(" " + icon + " " + issue.dir + " — " + issue.text);
|
|
938
1032
|
}
|
|
939
1033
|
if (issues.length === 0) console.log(" ✔ 页面文件完整性检查通过");
|
|
@@ -1106,6 +1200,85 @@ function runExport() {
|
|
|
1106
1200
|
console.log("");
|
|
1107
1201
|
}
|
|
1108
1202
|
|
|
1203
|
+
// ─── mock-clean ──────────────────────────────────────────────────────────
|
|
1204
|
+
|
|
1205
|
+
function runMockClean() {
|
|
1206
|
+
console.log("");
|
|
1207
|
+
console.log(" wl-skills-kit v" + PKG.version + " [mock-clean]");
|
|
1208
|
+
console.log("");
|
|
1209
|
+
|
|
1210
|
+
const mockDir = path.join(TARGET_DIR, "mock");
|
|
1211
|
+
if (!fs.existsSync(mockDir)) {
|
|
1212
|
+
console.log(" ⚠ mock/ 目录不存在,无需清理");
|
|
1213
|
+
console.log("");
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
const domainArg = args.find((a) => a.startsWith("--domain"));
|
|
1218
|
+
const cleanAll = args.includes("--all");
|
|
1219
|
+
let domain = "";
|
|
1220
|
+
if (domainArg) {
|
|
1221
|
+
// 支持 --domain=xxx 和 --domain xxx
|
|
1222
|
+
if (domainArg.includes("=")) {
|
|
1223
|
+
domain = domainArg.split("=")[1];
|
|
1224
|
+
} else {
|
|
1225
|
+
const idx = args.indexOf(domainArg);
|
|
1226
|
+
domain = args[idx + 1] || "";
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
if (!domain && !cleanAll) {
|
|
1231
|
+
console.error(" ✖ 请指定 --domain <name> 或 --all");
|
|
1232
|
+
console.error(" 示例: wl-skills mock-clean --domain mdata");
|
|
1233
|
+
console.error(" wl-skills mock-clean --all");
|
|
1234
|
+
console.error("");
|
|
1235
|
+
process.exit(1);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// 收集要删除的文件/目录
|
|
1239
|
+
const toRemove = [];
|
|
1240
|
+
if (cleanAll) {
|
|
1241
|
+
// 删除 mock/ 下除 _utils.ts/_utils.js 之外的所有文件和子目录
|
|
1242
|
+
const entries = fs.readdirSync(mockDir, { withFileTypes: true });
|
|
1243
|
+
for (const entry of entries) {
|
|
1244
|
+
if (entry.name.startsWith("_")) continue; // 保留 _utils.ts 等
|
|
1245
|
+
toRemove.push(path.join(mockDir, entry.name));
|
|
1246
|
+
}
|
|
1247
|
+
} else {
|
|
1248
|
+
// 删除指定域目录
|
|
1249
|
+
const domainDir = path.join(mockDir, domain);
|
|
1250
|
+
if (!fs.existsSync(domainDir)) {
|
|
1251
|
+
console.log(' ⚠ mock/' + domain + '/ 不存在');
|
|
1252
|
+
console.log("");
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
toRemove.push(domainDir);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if (toRemove.length === 0) {
|
|
1259
|
+
console.log(" ✔ 无需清理(仅剩 _utils.ts)");
|
|
1260
|
+
console.log("");
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
for (const target of toRemove) {
|
|
1265
|
+
const rel = path.relative(TARGET_DIR, target);
|
|
1266
|
+
if (dryRun) {
|
|
1267
|
+
console.log(" [dry-run] 将删除: " + rel);
|
|
1268
|
+
} else {
|
|
1269
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
1270
|
+
console.log(" ✔ 已删除: " + rel);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
console.log("");
|
|
1275
|
+
if (!dryRun) {
|
|
1276
|
+
console.log(" 建议:将 .env.dev 中 ENV_MOCK 改为 false");
|
|
1277
|
+
console.log(" 然后运行 wl-skills validate 检查页面无 mock 依赖残留");
|
|
1278
|
+
console.log("");
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1109
1282
|
// ─── 主路由 ─────────────────────────────────────────────────────────────
|
|
1110
1283
|
|
|
1111
1284
|
switch (command) {
|
|
@@ -1134,6 +1307,9 @@ switch (command) {
|
|
|
1134
1307
|
case "export":
|
|
1135
1308
|
runExport();
|
|
1136
1309
|
break;
|
|
1310
|
+
case "mock-clean":
|
|
1311
|
+
runMockClean();
|
|
1312
|
+
break;
|
|
1137
1313
|
default:
|
|
1138
1314
|
console.error(
|
|
1139
1315
|
' ✖ 未知命令: "' + command + '",请使用 --help 查看可用命令',
|
|
@@ -28,6 +28,24 @@ src/views/[域]/[模块]/[子模块]/[kebab-case目录]/
|
|
|
28
28
|
- **通用弹窗**(新增/编辑表单,2+ 页面可复用)→ 提取到 `src/components/local/c_xxxModal/`
|
|
29
29
|
- **极个性弹窗**(仅单页面使用,c_modal 无法满足)→ 放在页面 `components/xxxModal.vue`
|
|
30
30
|
|
|
31
|
+
## Mock 架构(与页面完全解耦)
|
|
32
|
+
|
|
33
|
+
> 详细规范见 `docs/mock-architecture.md`
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
mock/
|
|
37
|
+
├── _utils.ts ← 共享工具(pageResult / ok / paginate / nowStr / pick)
|
|
38
|
+
└── [业务域]/ ← 镜像 src/views 第一级目录
|
|
39
|
+
└── [模块].ts ← 每个模块一个文件,export default MockMethod[]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **开关**:`.env.dev` 中 `ENV_MOCK=true/false`,`vite.config.ts` 中 `viteMockServe({ enable: command === "serve" && config.ENV_MOCK !== "false" })`
|
|
43
|
+
- **解耦**:mock 文件放在项目根 `mock/` 目录,不在 `src/views` 中 import 任何 mock
|
|
44
|
+
- **URL 对齐**:`API_CONFIG` 保持真实路径(如 `/mdata/mdataModel/list`),mock 端点带 `/dev-api` 前缀,关闭 mock 后无需改页面代码
|
|
45
|
+
- **STORE 模式**:`let STORE = Array.from({ length: N }, genRecord)` 可变数组,CRUD 直接修改内存,查询立即可见
|
|
46
|
+
- **按模块自治**:删某业务 mock 只删对应文件,不影响其他模块
|
|
47
|
+
- **一键清理**:`wl-skills mock-clean --domain [域]` 或 `--all`
|
|
48
|
+
|
|
31
49
|
## data.ts 核心模式
|
|
32
50
|
|
|
33
51
|
> 配置化驱动,通过 `API_CONFIG` + `class extends AbstractPageQueryHook` 实现零 API 层开发。
|
|
@@ -185,7 +203,7 @@ onMounted(() => select());
|
|
|
185
203
|
| 部门选择 | jh-dept-picker | @jhlc/jh-ui |
|
|
186
204
|
| 文件上传 | jh-file-upload | @jhlc/jh-ui |
|
|
187
205
|
| 文本翻译 | jh-text | @jhlc/jh-ui |
|
|
188
|
-
| 左右分割 |
|
|
206
|
+
| 左右分割 | jh-drag-col | @jhlc/jh-ui (#left/#right slot) |
|
|
189
207
|
| 树形面板 | C_Tree | src/components/global |
|
|
190
208
|
|
|
191
209
|
## 组件提取策略
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **读者**:团队技术负责人 / wl-skills-kit 维护者 / 对体系设计感兴趣的团队成员
|
|
4
4
|
> **更新方式**:重大架构变更后追加对应章节,旧章节原文保留(历史可溯)
|
|
5
|
-
> **当前版本**:v2.
|
|
5
|
+
> **当前版本**:v2.9.1 (2026-05-17)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -478,9 +478,11 @@ AI "假执行"——声称读了规范,实际按惯性输出。没有强制约
|
|
|
478
478
|
| ---- | ----------------------------------------------------------------------------------------------------------------------------------------- | --------- |
|
|
479
479
|
| v1.x | 5 个 Skill 平铺 + 9 个 TPL 平铺 + 单一超长 copilot-instructions | ✅ 已发布 |
|
|
480
480
|
| v2.0 | 规范模块化(13 条)+ 模板分层(universal/domains)+ 报告分类 + Pre-flight + 工具链门控 | ✅ 已发布 |
|
|
481
|
-
| v2.1 | Skill 分级目录(core/sync/ops/domain)+ 多 AI 适配解耦(editors.json)+ 各 Skill USAGE.md + api-contract 真实响应 + 3 个 PLANNED 草稿补全 | ✅
|
|
482
|
-
| v2.2 | dict-sync / permission-sync / code-fix 从 PLANNED →
|
|
483
|
-
| v2.
|
|
481
|
+
| v2.1 | Skill 分级目录(core/sync/ops/domain)+ 多 AI 适配解耦(editors.json)+ 各 Skill USAGE.md + api-contract 真实响应 + 3 个 PLANNED 草稿补全 | ✅ 已发布 |
|
|
482
|
+
| v2.2–2.3 | dict-sync / permission-sync / code-fix 从 PLANNED → 转正 + lint-skills 静态护栏 + MCP 自愈闭环 | ✅ 已发布 |
|
|
483
|
+
| v2.6 | business-doc-extract 语义触发 + 业务文档体系 + AGGrid/cid/defineColumns/renderOps 最终标准 + doctor-ui / validate 增强 | ✅ 已发布 |
|
|
484
|
+
| v2.7 | JH 组件文档全面修正 + MCP tools 单测覆盖 + 场景索引路由 + _mcp-guardrail 自愈闭环 + .gitattributes + 版本一致性自检 | ✅ 已发布 |
|
|
485
|
+
| v2.8 | Mock 架构体系固化(mock-architecture.md + _utils.ts 种子 + mock-clean CLI + validate mock 质量检查 + 规则修正) | ✅ 当前 |
|
|
484
486
|
|
|
485
487
|
---
|
|
486
488
|
|
|
@@ -140,7 +140,17 @@ wls_code_scan ← 概览:页面目录、API_CONFIG、文件完整性
|
|
|
140
140
|
|
|
141
141
|
**用户典型话术**:"先 mock 一下"、"假数据"、"后端没好先能跑"
|
|
142
142
|
|
|
143
|
-
**推荐**:`page-codegen` 的 mock-first
|
|
143
|
+
**推荐**:`page-codegen` 的 mock-first 规则。Mock 架构详见 `docs/mock-architecture.md`。
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
mock/
|
|
147
|
+
├── _utils.ts ← 共享工具(kit init 自动写入)
|
|
148
|
+
└── [业务域]/[模块].ts ← 按 src/views 第一级域分目录
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- 生成页面自动生成 `mock/[业务域]/[模块].ts`,import `../_utils` 共享工具
|
|
152
|
+
- 开关:`.env.dev` 中 `ENV_MOCK=true/false`,零污染切换
|
|
153
|
+
- 清理:`wl-skills mock-clean --domain [域]` 按域清理,`--all` 全量清理(保留 `_utils.ts`)
|
|
144
154
|
|
|
145
155
|
---
|
|
146
156
|
|
|
@@ -92,7 +92,7 @@ src/views/[域]/[模块]/[子模块]/[kebab-case-目录名]/
|
|
|
92
92
|
|
|
93
93
|
- `pages.ts` 注册片段
|
|
94
94
|
- **`reports/SYS_MENU_INFO.md`** — 集中式菜单配置,**追加写入**(见下方 §SYS_MENU_INFO 生成规则)
|
|
95
|
-
- `mock/[
|
|
95
|
+
- `mock/[业务域]/[模块].ts`(项目根目录 `mock/` 下按域分目录,`vite-plugin-mock` 自动加载,与 api.md 的 URL 和字段完全一致;详见 `docs/mock-architecture.md`)
|
|
96
96
|
|
|
97
97
|
---
|
|
98
98
|
|
|
@@ -108,7 +108,7 @@ src/views/[域]/[模块]/[子模块]/[kebab-case-目录名]/
|
|
|
108
108
|
6. 字典字段用 `logicType: BusLogicDataType.dict, logicValue: "dictCode"`
|
|
109
109
|
7. 同时生成 api.md(基于 api-contract Skill 模板)
|
|
110
110
|
8. 提供 pages.ts 注册片段
|
|
111
|
-
9. 同时在 `mock/` 目录下生成对应的 mock 文件(`MockMethod[]` + mockjs,URL 和字段与 api.md 一致,URL 必须带 `/dev-api`
|
|
111
|
+
9. 同时在 `mock/[业务域]/` 目录下生成对应的 mock 文件(`MockMethod[]` + mockjs,URL 和字段与 api.md 一致,URL 必须带 `/dev-api` 前缀)。业务域取 `src/views/` 下第一级目录名(如 `sale`、`mdata`)。mock 文件必须 `import { paginate, ok, pick, nowStr } from "../_utils"` 复用共享工具,不可自行重复定义
|
|
112
112
|
10. **查询字段顺序**:`queryDef()` 中字段顺序必须与 page-spec `query` 数组顺序严格一致(即原型从左到右、从上到下)
|
|
113
113
|
11. **表格列顺序**:`columnsDef()` 中列顺序必须与 page-spec `columns` 数组顺序严格一致(`selection` + `index` 在最前,其余按原型表头从左到右)
|
|
114
114
|
12. **按钮顺序与颜色**:`toolbarDef()` 中按钮顺序和 `name`(颜色)必须与 page-spec `toolbar` 数组严格一致(`primary`=蓝底, `danger`=红色, `warning`=橙色, `default`=灰色; `plain: true`=线框)。**"新增"类按钮永远排第一**(如"新增"、"新增申请"),这是产品通用规范
|
|
@@ -119,8 +119,8 @@ src/views/[域]/[模块]/[子模块]/[kebab-case-目录名]/
|
|
|
119
119
|
17. **按钮颜色映射**:按钮的 `type` 属性决定颜色,须根据原型按钮颜色或按钮语义映射(见下方 §按钮颜色映射表)
|
|
120
120
|
18. **按钮必须可交互**:所有按钮的 `onClick` 必须有真实处理逻辑,禁止空函数 `() => {}`。通用交互实现见下方 §按钮交互实现规则
|
|
121
121
|
19. **未知交互兜底**:当原型未提供交互细节、且无法从通用模式推断时,`onClick` 中使用 `ElMessage.info("需业务确认交互逻辑")` 作为占位
|
|
122
|
-
20. **生成后依赖自检**:代码生成完成后,检查 `package.json` 是否已安装生成代码所需的依赖(`mockjs`、`vite-plugin-mock`、`lodash-es`、`xlsx` 等),若缺失则提示用户执行安装命令。同时检查 `vite.config.ts` 是否已注册 `viteMockServe`、`mock
|
|
123
|
-
21. **默认 Mock First**:新生成页面默认必须走 `vite-plugin-mock`。必须生成 `mock/[
|
|
122
|
+
20. **生成后依赖自检**:代码生成完成后,检查 `package.json` 是否已安装生成代码所需的依赖(`mockjs`、`vite-plugin-mock`、`lodash-es`、`xlsx` 等),若缺失则提示用户执行安装命令。同时检查 `vite.config.ts` 是否已注册 `viteMockServe`、`mock/_utils.ts` 是否存在(若不存在则从 kit 种子文件补充)
|
|
123
|
+
21. **默认 Mock First**:新生成页面默认必须走 `vite-plugin-mock`。必须生成 `mock/[业务域]/[模块].ts`(import `../_utils` 共享工具),并确保 `API_CONFIG` 中每个 URL 都有对应 mock 端点;只有当用户明确要求关闭 mock 或 `.env.dev` 中 `ENV_MOCK=false` 时,才允许直接联调真实接口。
|
|
124
124
|
22. **Mock URL 必须匹配真实请求**:`API_CONFIG` 保持真实接口路径(如 `/mdata/mdataModel/list`),mock 文件端点必须带 Vite 代理前缀(如 `/dev-api/mdata/mdataModel/list`),这样关闭 mock 后无需修改业务代码。
|
|
125
125
|
23. **页面初始数据必须由 mock 提供**:列表页 `onMounted(() => select())` 后必须能显示模拟数据,不允许生成空白页等待后端接口;`list` 端点返回 `{ code: 2000, data: { records, total, size, current } }`。
|
|
126
126
|
24. **必须使用 wk-skills-ui runtime 风格**:当项目安装了 `@agile-team/wk-skills-ui` 时,列表列定义必须使用 `defineColumns()`,操作列必须使用 `renderOps()`,状态/字典列优先使用 runtime 渲染器或 `logicType=dict` 自动映射;不可退回默认纯文本/空函数风格。
|
|
@@ -145,7 +145,7 @@ src/views/[域]/[模块]/[子模块]/[kebab-case-目录名]/
|
|
|
145
145
|
11. **❌ 禁止表单控件宽度不统一**:`jh-select`、`jh-date`、`el-input-number`、`jh-file-upload` 默认宽度可能与 `el-input` 不一致,必须在 scoped style 中用 `:deep()` 统一设为 `width: 100%`(详见 §表单页 UI 细节规范)
|
|
146
146
|
12. **❌ 禁止表单页无滚动**:独立路由表单页内容超出视口时必须可滚动,`.app-page-container` 须设 `overflow-y: auto`(**不要加 `height: 100%`,全局已有 `height: calc(100vh - 100px)`,叠加会导致双滚动条**)
|
|
147
147
|
13. **❌ 禁止内联 style 散落**:所有页面/组件样式统一写在 `index.scss` 中(便于复用和移动),不可在 template 中大量使用内联 `style="..."`
|
|
148
|
-
14. **❌ 禁止生成无 mock 的页面**:只写 `API_CONFIG` 但不写 `mock/*.ts` 属于生成失败。
|
|
148
|
+
14. **❌ 禁止生成无 mock 的页面**:只写 `API_CONFIG` 但不写 `mock/[业务域]/*.ts` 属于生成失败。mock 文件必须按域分目录、import `_utils` 共享工具(详见 `docs/mock-architecture.md`)。
|
|
149
149
|
15. **❌ 禁止生成空 onClick**:`onClick: () => {}` 属于生成失败;未知逻辑也必须用 `ElMessage.info(...)` 明示。
|
|
150
150
|
16. **❌ 禁止忽略 wk-skills-ui**:项目已安装 `@agile-team/wk-skills-ui` 时,不使用 `defineColumns/renderOps` 属于生成失败。
|
|
151
151
|
17. **❌ 禁止 BaseTable 非 AGGrid**:业务列表中 `<BaseTable>` 未写 `render-type="agGrid"` 或缺少 `cid/:cid` 属于生成失败。
|
|
@@ -1065,7 +1065,7 @@ SYS_MENU_INFO.md 是 menu-sync Skill 的输入数据源:
|
|
|
1065
1065
|
| LIST | templates/universal/TPL-LIST.md | 标准查询+工具栏+表格+分页 | mmwr-customer-archive |
|
|
1066
1066
|
| MASTER_DETAIL | templates/universal/TPL-MASTER-DETAIL.md | jh-drag-row 主从表,双击联动 | ompt-ht-plan-order |
|
|
1067
1067
|
| TREE_LIST | templates/universal/TPL-TREE-LIST.md | 左侧 C_Tree + 右侧列表 | — |
|
|
1068
|
-
| DETAIL_TABS | templates/universal/TPL-DETAIL-TABS.md |
|
|
1068
|
+
| DETAIL_TABS | templates/universal/TPL-DETAIL-TABS.md | jh-drag-row 上Tab表单+下子表 | add-demo / domestic-trade-order |
|
|
1069
1069
|
| FORM_ROUTE | templates/universal/TPL-FORM-ROUTE.md | 复杂表单独立路由(非弹窗) | mmwr-customer-apply-add-form |
|
|
1070
1070
|
| CHANGE_HISTORY | templates/universal/TPL-CHANGE-HISTORY.md | 左历史时间线+右变更详情 | mmwr-customer-apply-change-history |
|
|
1071
1071
|
| RECORD_FORM | templates/universal/TPL-RECORD-FORM.md | BaseQuery选主记录+Form+Table无分页 | mmsm-convert-progress |
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| LIST | `templates/universal/TPL-LIST.md` | 标准列表页(查询+工具栏+表格+分页) |
|
|
12
12
|
| FORM_ROUTE | `templates/universal/TPL-FORM-ROUTE.md` | 复杂表单独立路由页(多 Tab / 多子表) |
|
|
13
13
|
| MASTER_DETAIL | `templates/universal/TPL-MASTER-DETAIL.md` | 主从表页(jh-drag-row 上下分栏) |
|
|
14
|
-
| TREE_LIST | `templates/universal/TPL-TREE-LIST.md` | 左树右列表页(
|
|
14
|
+
| TREE_LIST | `templates/universal/TPL-TREE-LIST.md` | 左树右列表页(jh-drag-col 布局) |
|
|
15
15
|
| DETAIL_TABS | `templates/universal/TPL-DETAIL-TABS.md` | 详情 Tab 页(上方表单 + 下方 Tab 子表) |
|
|
16
16
|
| CHANGE_HISTORY | `templates/universal/TPL-CHANGE-HISTORY.md` | 变更历史比对页(时间线 + 字段差异) |
|
|
17
17
|
| RECORD_FORM | `templates/universal/TPL-RECORD-FORM.md` | 录入型实绩页(无分页,查询 + 内联表单) |
|
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
> 见 SKILL.md 主文件(约束 + 按钮规则 + Mock 规范等共用规则)。
|
|
4
4
|
|
|
5
5
|
> 适用场景:编辑/维护页面,上半区为多 Tab 表单(基本信息/客户信息/其他信息),下半区为子项表格。
|
|
6
|
-
>
|
|
6
|
+
> **布局核心**:`jh-drag-row :topHeight="..."` 垂直分割上下区域(严禁 `C_Splitter`,详 standards/14-layout-containers.md)。
|
|
7
7
|
> **参考标杆**:`src/views/sale/demo/add-demo/`、`src/views/sale/demo/domestic-trade-order-mainten/`
|
|
8
8
|
|
|
9
9
|
#### index.vue
|
|
10
10
|
|
|
11
11
|
```vue
|
|
12
12
|
<template>
|
|
13
|
-
<div class="app-container app-page-container">
|
|
14
|
-
<
|
|
13
|
+
<div class="app-container app-page-container" style="height: 100%">
|
|
14
|
+
<jh-drag-row :topHeight="380">
|
|
15
|
+
<template #top>
|
|
15
16
|
<!-- 上:表单区 -->
|
|
16
17
|
<el-card shadow="never" class="form-card">
|
|
17
18
|
<!-- 页头工具栏 -->
|
|
@@ -66,7 +67,9 @@
|
|
|
66
67
|
</el-tab-pane>
|
|
67
68
|
</el-tabs>
|
|
68
69
|
</el-card>
|
|
70
|
+
</template>
|
|
69
71
|
|
|
72
|
+
<template #bottom>
|
|
70
73
|
<!-- 下:子项表格区 -->
|
|
71
74
|
<el-card shadow="never" class="items-card">
|
|
72
75
|
<div class="items-section">
|
|
@@ -97,13 +100,14 @@
|
|
|
97
100
|
/>
|
|
98
101
|
</div>
|
|
99
102
|
</el-card>
|
|
100
|
-
|
|
103
|
+
</template>
|
|
104
|
+
</jh-drag-row>
|
|
101
105
|
</div>
|
|
102
106
|
</template>
|
|
103
107
|
|
|
104
108
|
<script setup lang="ts">
|
|
105
109
|
import { onMounted } from "vue";
|
|
106
|
-
import C_Splitter
|
|
110
|
+
// ⚠️ 不再需要 import C_Splitter——jh-drag-row 是 @jhlc/jh-ui 全局注册组件
|
|
107
111
|
import {
|
|
108
112
|
form,
|
|
109
113
|
rules,
|