@agile-team/wl-skills-kit 2.3.0 → 2.3.2
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 +42 -57
- package/README.md +23 -148
- package/bin/wl-skills.js +2 -100
- package/files/.github/guides/README.md +13 -13
- package/files/.github/guides/architecture.md +555 -576
- package/files/.github/guides/usage.md +176 -176
- package/files/.github/reports/README.md +65 -65
- package/files/.github/reports/SYS_DICT_INFO.md +50 -50
- package/files/.github/reports/SYS_MENU_INFO.md +247 -247
- package/files/.github/reports/SYS_PERMISSION_INFO.md +20 -20
- package/files/.github/reports//347/273/204/344/273/266/346/217/220/345/217/226/345/273/272/350/256/256.md +33 -33
- package/files/.github/reports//350/247/204/350/214/203/345/256/241/346/237/245/346/212/245/345/221/212.md +44 -44
- package/files/.github/skills/_compat/README.md +108 -108
- package/files/.github/skills/_compat/headers/agents.txt +8 -8
- package/files/.github/skills/_compat/headers/claude-code.txt +7 -7
- package/files/.github/skills/_compat/headers/cline.txt +7 -7
- package/files/.github/skills/_compat/headers/cursor-mdc.txt +16 -16
- package/files/.github/skills/_compat/headers/cursor-rules.txt +7 -7
- package/files/.github/skills/_compat/headers/github-copilot.txt +1 -1
- package/files/.github/skills/_compat/headers/kiro.txt +10 -10
- package/files/.github/skills/_compat/headers/trae.txt +11 -11
- package/files/.github/skills/_compat/headers/windsurf.txt +7 -7
- package/files/.github/skills/_registry.md +81 -81
- package/files/.github/skills/core/api-contract/SKILL.md +344 -344
- package/files/.github/skills/core/api-contract/USAGE.md +110 -110
- package/files/.github/skills/core/convention-audit/SKILL.md +189 -189
- package/files/.github/skills/core/convention-audit/USAGE.md +99 -99
- package/files/.github/skills/core/page-codegen/SKILL.md +973 -973
- package/files/.github/skills/core/page-codegen/USAGE.md +102 -102
- package/files/.github/skills/core/page-codegen/templates/_index.md +46 -46
- package/files/.github/skills/core/page-codegen/templates/domains/_CONTRIBUTING.md +107 -107
- package/files/.github/skills/core/page-codegen/templates/domains/produce/TPL-OPERATION-STATION.md +442 -442
- package/files/.github/skills/core/page-codegen/templates/domains/sale/README.md +26 -26
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-CHANGE-HISTORY.md +276 -276
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-DETAIL-TABS.md +1145 -1145
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-DRIVEN.md +309 -124
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-FORM-ROUTE.md +436 -436
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-LIST.md +191 -191
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-MASTER-DETAIL.md +148 -148
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-RECORD-FORM.md +376 -376
- package/files/.github/skills/core/page-codegen/templates/universal/TPL-TREE-LIST.md +186 -186
- package/files/.github/skills/core/prototype-scan/SKILL.md +498 -498
- package/files/.github/skills/core/prototype-scan/USAGE.md +95 -95
- package/files/.github/skills/core/template-extract/SKILL.md +139 -139
- package/files/.github/skills/core/template-extract/USAGE.md +93 -93
- package/files/.github/skills/domain/README.md +51 -51
- package/files/.github/skills/sync/menu-sync/SKILL.md +263 -263
- package/files/.github/skills/sync/menu-sync/USAGE.md +104 -104
- package/files/.github/skills/sync/menu-sync/env/env.local.json +7 -7
- package/files/.github/skills/sync/menu-sync/env/guide.md +99 -99
- package/files/.github/skills/sync/permission-sync/SKILL.draft.md +91 -91
- package/files/.github/standards/01-toolchain.md +57 -57
- package/files/.github/standards/02-code-structure.md +111 -111
- package/files/.github/standards/03-comments.md +53 -53
- package/files/.github/standards/04-coding-basics.md +33 -33
- package/files/.github/standards/05-logging.md +38 -38
- package/files/.github/standards/06-security.md +44 -44
- package/files/.github/standards/07-config.md +52 -52
- package/files/.github/standards/08-git.md +60 -60
- package/files/.github/standards/09-typescript.md +71 -71
- package/files/.github/standards/10-pinia.md +57 -57
- package/files/.github/standards/11-form-validation.md +81 -81
- package/files/.github/standards/12-base-table.md +153 -153
- package/files/.github/standards/13-platform-components.md +123 -123
- package/files/.github/standards/index.md +89 -89
- package/files/demo/produce/aiflow/mmwr-customer-apply-add/api.md +1 -1
- package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/data.ts +196 -196
- package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.scss +150 -150
- package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.vue +79 -79
- package/files/docs/jh-date-range.md +257 -257
- package/files/docs/jh-date.md +222 -222
- package/files/docs/jh-dept-picker.md +190 -190
- package/files/docs/jh-drag-row.md +590 -590
- package/files/docs/jh-file-upload.md +216 -216
- package/files/docs/jh-picker.md +218 -218
- package/files/docs/jh-select.md +148 -148
- package/files/docs/jh-text.md +248 -248
- package/files/docs/jh-user-picker.md +197 -197
- package/files/docs/request.md +24 -9
- package/files/src/components/global/C_RightToolbar/data.ts +228 -0
- package/files/src/components/global/C_RightToolbar/index.scss +44 -0
- package/files/src/components/global/C_RightToolbar/index.vue +34 -336
- package/files/src/components/global/C_Splitter/index.scss +61 -0
- package/files/src/components/global/C_Splitter/index.vue +2 -64
- package/files/src/components/global/C_SvgIcon/index.scss +15 -0
- package/files/src/components/global/C_SvgIcon/index.vue +20 -50
- package/files/src/components/global/C_TagStatus/index.scss +20 -0
- package/files/src/components/global/C_TagStatus/index.vue +1 -22
- package/files/src/components/global/C_Tree/data.ts +61 -0
- package/files/src/components/global/C_Tree/index.vue +12 -53
- package/files/src/components/local/c_listModal/index.scss +4 -0
- package/files/src/components/local/c_listModal/index.vue +1 -1
- package/package.json +5 -9
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
# domain/ — 领域专属 Skill 占位目录
|
|
2
|
-
|
|
3
|
-
> **当前状态**:空目录,等待领域 Skill 沉淀。
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 用途
|
|
8
|
-
|
|
9
|
-
`domain/` 用于存放**强业务域相关的 Skill**——这类 Skill 在其他域几乎无复用价值,但在特定业务域内高频使用。
|
|
10
|
-
|
|
11
|
-
与 `core/`(全业务通用)和 `sync/`(后端联动通用)不同,`domain/` 的 Skill 允许直接依赖领域特有的术语、流程和数据结构。
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 目录结构预期
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
domain/
|
|
19
|
-
├── README.md ← 本文件
|
|
20
|
-
├── produce/ 生产域(如高炉计划、轧钢批次、工序流转等专属流程)
|
|
21
|
-
│ └── ...
|
|
22
|
-
├── sale/ 销售域(如合同审批流、信用额度等专属流程)
|
|
23
|
-
│ └── ...
|
|
24
|
-
└── {其他域}/ 按需创建
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 何时在此创建新 Skill
|
|
30
|
-
|
|
31
|
-
满足以下条件时,在对应域子目录下创建新 Skill:
|
|
32
|
-
|
|
33
|
-
1. 该流程与业务域**强绑定**(换了域就完全不适用)
|
|
34
|
-
2. 在本域内**高频触发**(≥3 个不同功能模块会用到)
|
|
35
|
-
3. `core/` 里已有的 Skill **无法覆盖**(不是简单参数调整能解决的)
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## 贡献流程
|
|
40
|
-
|
|
41
|
-
1. 在对应域子目录下创建 `{skill-name}/SKILL.md`
|
|
42
|
-
2. 更新 `skills/_registry.md` 启用路由表
|
|
43
|
-
3. 同步在 `skills/_registry.md` 的目录分级图里添加条目
|
|
44
|
-
4. 可选:创建 `USAGE.md` 供域内团队成员阅读
|
|
45
|
-
5. 参考 `kit-internal/CONTRIBUTING.md` 第三节"添加新 Skill"
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## 扩展策略
|
|
50
|
-
|
|
51
|
-
> 当 `domain/` 下某个域的 Skill 数量超过 **5 个**,或产生跨团队复用需求时,考虑将其拆为独立 npm 包(如 `@agile-team/wl-skills-produce`),本包仅保留 `core/sync/ops`。
|
|
1
|
+
# domain/ — 领域专属 Skill 占位目录
|
|
2
|
+
|
|
3
|
+
> **当前状态**:空目录,等待领域 Skill 沉淀。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 用途
|
|
8
|
+
|
|
9
|
+
`domain/` 用于存放**强业务域相关的 Skill**——这类 Skill 在其他域几乎无复用价值,但在特定业务域内高频使用。
|
|
10
|
+
|
|
11
|
+
与 `core/`(全业务通用)和 `sync/`(后端联动通用)不同,`domain/` 的 Skill 允许直接依赖领域特有的术语、流程和数据结构。
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 目录结构预期
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
domain/
|
|
19
|
+
├── README.md ← 本文件
|
|
20
|
+
├── produce/ 生产域(如高炉计划、轧钢批次、工序流转等专属流程)
|
|
21
|
+
│ └── ...
|
|
22
|
+
├── sale/ 销售域(如合同审批流、信用额度等专属流程)
|
|
23
|
+
│ └── ...
|
|
24
|
+
└── {其他域}/ 按需创建
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 何时在此创建新 Skill
|
|
30
|
+
|
|
31
|
+
满足以下条件时,在对应域子目录下创建新 Skill:
|
|
32
|
+
|
|
33
|
+
1. 该流程与业务域**强绑定**(换了域就完全不适用)
|
|
34
|
+
2. 在本域内**高频触发**(≥3 个不同功能模块会用到)
|
|
35
|
+
3. `core/` 里已有的 Skill **无法覆盖**(不是简单参数调整能解决的)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 贡献流程
|
|
40
|
+
|
|
41
|
+
1. 在对应域子目录下创建 `{skill-name}/SKILL.md`
|
|
42
|
+
2. 更新 `skills/_registry.md` 启用路由表
|
|
43
|
+
3. 同步在 `skills/_registry.md` 的目录分级图里添加条目
|
|
44
|
+
4. 可选:创建 `USAGE.md` 供域内团队成员阅读
|
|
45
|
+
5. 参考 `kit-internal/CONTRIBUTING.md` 第三节"添加新 Skill"
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 扩展策略
|
|
50
|
+
|
|
51
|
+
> 当 `domain/` 下某个域的 Skill 数量超过 **5 个**,或产生跨团队复用需求时,考虑将其拆为独立 npm 包(如 `@agile-team/wl-skills-produce`),本包仅保留 `core/sync/ops`。
|
|
@@ -1,263 +1,263 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: menu-sync
|
|
3
|
-
description: "Use when: creating system menus for newly generated pages, batch registering menus, or syncing pages.ts entries to the backend menu table. Triggers on: 创建菜单, 注册菜单, 同步菜单, 补菜单, menu sync, create menu, register menu."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: 菜单同步(menu-sync)
|
|
7
|
-
|
|
8
|
-
将 pages.ts 中注册的页面同步到后端菜单表,使系统能够路由到新页面。
|
|
9
|
-
|
|
10
|
-
> **背景**:本项目是 Module Federation 子应用,页面在 `pages.ts` 注册后,
|
|
11
|
-
> 还需要在后端菜单表中创建对应记录,系统才能路由到该页面。
|
|
12
|
-
> 设计文档:`.github/guides/architecture.md`
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## 配置与使用方式(一次配置,无需反复填写)
|
|
17
|
-
|
|
18
|
-
### 数据来源分工
|
|
19
|
-
|
|
20
|
-
| 数据 | 来源 | 说明 |
|
|
21
|
-
| ------------------------------------------------ | -------------------------- | --------------------------------------- |
|
|
22
|
-
| 菜单名称、路径、组件、权限、隐藏、排序、应用编码 | `reports/SYS_MENU_INFO.md` | 由 page-codegen 追加写入,AI 直接读取 |
|
|
23
|
-
| `parentMenuNameCode` | API 自动查询 | AI 调 children 接口获取,无需手填 |
|
|
24
|
-
| **gatewayPath、parentMenuId、sysAppNo、token** | `env.local.json` | 每套环境不同,唯一需要手动维护的 4 个值 |
|
|
25
|
-
|
|
26
|
-
### 配置文件(统一维护,菜单/字典/权限共用)
|
|
27
|
-
|
|
28
|
-
优先读取 `.github/skills/sync/env.local.json`(v2.1.5+ 统一配置):
|
|
29
|
-
|
|
30
|
-
```json
|
|
31
|
-
{
|
|
32
|
-
"gatewayPath": "http://网关地址:端口",
|
|
33
|
-
"sysAppNo": "应用编码(从已有菜单的sysAppNo字段获取,非明文)",
|
|
34
|
-
"token": "Bearer Token(不含bearer前缀)",
|
|
35
|
-
"menu": {
|
|
36
|
-
"parentMenuId": "父级菜单ID"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
> 向下兼容:如上述文件不存在,回落读取 `menu-sync/env/env.local.json`(旧版路径)。
|
|
42
|
-
> 字段说明及获取方式见 `env/guide.md`
|
|
43
|
-
|
|
44
|
-
menu-sync 读取规则:`parentMenuId` 优先从 `menu.parentMenuId` 读取,回落到根级 `parentMenuId`。
|
|
45
|
-
|
|
46
|
-
### 使用步骤
|
|
47
|
-
|
|
48
|
-
1. **首次**:按 `env/guide.md` 填写 `skills/sync/env.local.json` 的字段
|
|
49
|
-
2. **之后**:直接对 AI 说「帮我创建菜单」/「同步菜单」/「补菜单」
|
|
50
|
-
3. AI 自动执行:读 `reports/SYS_MENU_INFO.md` → 读 `env.local.json` → 查父级已有子节点 → 逐条对比去重 → 调 `/system/menu/save` → 输出 created/skipped 结果表
|
|
51
|
-
4. **全程无需手动执行任何命令**
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## 方案演进路线
|
|
56
|
-
|
|
57
|
-
| 阶段 | 方案 | 状态 | 说明 |
|
|
58
|
-
| ----------- | --------------------------------- | ------------- | ---------------------------------------------------- |
|
|
59
|
-
| **Phase 1** | AI 调用现有 API 逐条创建 | ✅ 当前可用 | 利用 `/system/menu/save` 接口,AI 充当自动化脚本 |
|
|
60
|
-
| **Phase 2** | 前端推送脚本 `pnpm run menu:push` | ⏳ 待后端接口 | 需后端提供 `POST /system/menu/batchPush` upsert 接口 |
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Phase 1:AI 调用 API 创建菜单(当前方案)
|
|
65
|
-
|
|
66
|
-
> 此方案参考平台伙伴的 jh4j-cloud skill,适配 cx-ui-produce 项目。
|
|
67
|
-
> 本质是 **menu-sync-design.md 的方案 C(只增不删)**,由 AI 自动执行。
|
|
68
|
-
|
|
69
|
-
### 前置条件
|
|
70
|
-
|
|
71
|
-
1. 用户提供后端系统管理地址(如 `http://localhost:9000` 或实际网关地址)
|
|
72
|
-
2. 用户提供有效的 Bearer Token(从浏览器开发者工具 Network 面板复制)
|
|
73
|
-
3. 用户提供父级菜单 ID(`menuId`),可通过查询接口获取
|
|
74
|
-
|
|
75
|
-
### 输入
|
|
76
|
-
|
|
77
|
-
用户提供以下信息(或 AI 从 pages.ts 自动提取):
|
|
78
|
-
|
|
79
|
-
- **父级菜单 ID**:`menuId`(后端菜单树中的上级目录 ID)
|
|
80
|
-
- **应用编码**:`sysAppNo`(如 `produce`、`sale`、`system`)
|
|
81
|
-
- **菜单数据**:可以是 pages.ts 中的条目,或用户手动指定
|
|
82
|
-
|
|
83
|
-
菜单类型:
|
|
84
|
-
|
|
85
|
-
| type | 含义 | 必填字段 |
|
|
86
|
-
| ---- | ------------ | --------------------------------------------- |
|
|
87
|
-
| `M` | 目录 | `menuName`, `path` |
|
|
88
|
-
| `C` | 菜单(页面) | `menuName`, `path`, `permission`, `component` |
|
|
89
|
-
| `A` | 动作按钮 | `menuName`, `path` |
|
|
90
|
-
|
|
91
|
-
### 执行流程
|
|
92
|
-
|
|
93
|
-
#### Step 1: 查询父级下已有菜单(防重复)
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
GET {gatewayPath}/system/menu/children?current=1&size=100&menuId={parentMenuId}
|
|
97
|
-
Headers:
|
|
98
|
-
authorization: bearer {token}
|
|
99
|
-
Sysappno: {sysAppNo}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
#### Step 2: 逐条创建菜单
|
|
103
|
-
|
|
104
|
-
对于每条待创建的菜单,先检查是否与已有菜单重名(`menuName` 或 `path` 相同),重复则跳过。
|
|
105
|
-
|
|
106
|
-
> **响应码说明**:后端成功响应为 `code: 2000`(非标准 HTTP 200),判断成功应检查 `response.body.code === 2000` 或 `message` 包含"成功"。
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
POST {gatewayPath}/system/menu/save
|
|
110
|
-
Headers:
|
|
111
|
-
authorization: bearer {token}
|
|
112
|
-
Sysappno: {sysAppNo}
|
|
113
|
-
Content-Type: application/json
|
|
114
|
-
|
|
115
|
-
Body:
|
|
116
|
-
{
|
|
117
|
-
"useCache": 1,
|
|
118
|
-
"icon": "list",
|
|
119
|
-
"common": 2,
|
|
120
|
-
"hidden": false,
|
|
121
|
-
"type": "C",
|
|
122
|
-
"parentId": "{parentMenuId}",
|
|
123
|
-
"sysAppNo": "{sysAppNo}",
|
|
124
|
-
"orderNum": {nextOrder},
|
|
125
|
-
"menuName": "客户档案",
|
|
126
|
-
"menuNameCode": "{parentMenuNameCode}:{pinyinName}",
|
|
127
|
-
"path": "mmwrCustomerArchive",
|
|
128
|
-
"permission": "mmwrCustomerArchive",
|
|
129
|
-
"component": "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue"
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
#### Step 3: 记录结果
|
|
134
|
-
|
|
135
|
-
创建完成后输出结果表格:
|
|
136
|
-
|
|
137
|
-
| 菜单名 | path | type | 状态 | id |
|
|
138
|
-
| -------- | ------------------- | ---- | ------------------- | ------ |
|
|
139
|
-
| 客户档案 | mmwrCustomerArchive | C | ✅ created | 123456 |
|
|
140
|
-
| 客户详情 | mmwrCustomerDetail | C | ⏭️ skipped (已存在) | - |
|
|
141
|
-
|
|
142
|
-
### 字段生成规则
|
|
143
|
-
|
|
144
|
-
| 字段 | 规则 |
|
|
145
|
-
| -------------- | -------------------------------------------------------------------------------------------- |
|
|
146
|
-
| `menuName` | 取 pages.ts 的 `label` |
|
|
147
|
-
| `path` | 页面目录名转 camelCase(如 `mmwr-customer-archive` → `mmwrCustomerArchive`) |
|
|
148
|
-
| `component` | 取 pages.ts 的 `name`(如 `produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue`) |
|
|
149
|
-
| `permission` | `{域}:{path}:list`(如 `produce:mmwrCustomerArchive:list`) |
|
|
150
|
-
| `menuNameCode` | `{父级menuNameCode}:{菜单名拼音}`(小写连续拼接) |
|
|
151
|
-
| `hidden` | 表单页/详情页等隐藏路由设为 `true`,菜单可见页面设为 `false` |
|
|
152
|
-
| `orderNum` | 从父级已有菜单最大 orderNum + 1 开始递增 |
|
|
153
|
-
| `icon` | 目录级 `"list"`,菜单级 `"list"` |
|
|
154
|
-
|
|
155
|
-
### pages.ts → 菜单数据映射示例
|
|
156
|
-
|
|
157
|
-
以 `aiflow` 子模块为例:
|
|
158
|
-
|
|
159
|
-
```
|
|
160
|
-
pages.ts 条目:
|
|
161
|
-
["mmwr-customer-archive", "客户档案"]
|
|
162
|
-
|
|
163
|
-
→ 菜单数据:
|
|
164
|
-
{
|
|
165
|
-
type: "C",
|
|
166
|
-
menuName: "客户档案",
|
|
167
|
-
path: "mmwrCustomerArchive",
|
|
168
|
-
component: "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue",
|
|
169
|
-
permission: "produce:mmwrCustomerArchive:list",
|
|
170
|
-
hidden: false
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
隐藏页面示例:
|
|
174
|
-
["mmwr-customer-apply-add-form", "客户申请新增表单"]
|
|
175
|
-
|
|
176
|
-
→ 菜单数据:
|
|
177
|
-
{
|
|
178
|
-
type: "C",
|
|
179
|
-
menuName: "客户申请新增表单",
|
|
180
|
-
path: "mmwrCustomerApplyAddForm",
|
|
181
|
-
component: "produce/production-mmwr/aiflow/mmwr-customer-apply-add-form/index.vue",
|
|
182
|
-
permission: "produce:mmwrCustomerApplyAddForm:list",
|
|
183
|
-
hidden: true // ← 表单页隐藏
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### 隐藏页面判断规则
|
|
188
|
-
|
|
189
|
-
以下页面类型应设置 `hidden: true`:
|
|
190
|
-
|
|
191
|
-
- 目录名含 `-form`(独立路由表单页)
|
|
192
|
-
- 目录名含 `-detail`(详情页)
|
|
193
|
-
- 目录名含 `-history`(历史查询页)
|
|
194
|
-
- reports/SYS_MENU_INFO.md 中标注为"隐藏菜单"的页面
|
|
195
|
-
|
|
196
|
-
### 跳过规则
|
|
197
|
-
|
|
198
|
-
- 当前父级下已有同名 `menuName` → 跳过
|
|
199
|
-
- 当前父级下已有相同 `path` → 跳过
|
|
200
|
-
- 跳过时不做更新、不做覆盖,只记录"已跳过"
|
|
201
|
-
|
|
202
|
-
### 树形菜单处理
|
|
203
|
-
|
|
204
|
-
如果需要先创建目录再创建子菜单:
|
|
205
|
-
|
|
206
|
-
1. 先以 `type: "M"` 创建目录
|
|
207
|
-
2. 保存成功后取返回的 `data.id`
|
|
208
|
-
3. 以新 `id` 作为 `parentId` 继续创建子菜单
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
## Phase 2:推送脚本方案(待后端接口就绪后启用)
|
|
213
|
-
|
|
214
|
-
> 对应 menu-sync-design.md 的 **方案 D(推送覆盖)**,是最终目标方案。
|
|
215
|
-
|
|
216
|
-
### 与 Phase 1 的差异
|
|
217
|
-
|
|
218
|
-
| 维度 | Phase 1 (AI 调 API) | Phase 2 (推送脚本) |
|
|
219
|
-
| -------- | ------------------- | ---------------------------- |
|
|
220
|
-
| 执行者 | AI | `pnpm run menu:push` 脚本 |
|
|
221
|
-
| 更新能力 | 只增不删(方案 C) | upsert 覆盖(方案 D) |
|
|
222
|
-
| 改名支持 | ❌ 会产生重复 | ✅ 按 componentPath 匹配更新 |
|
|
223
|
-
| 权限影响 | 无 | 无(只写结构字段) |
|
|
224
|
-
| 依赖 | Token + 网关地址 | 后端 `batchPush` 接口 |
|
|
225
|
-
|
|
226
|
-
### 所需后端接口
|
|
227
|
-
|
|
228
|
-
```
|
|
229
|
-
POST /system/menu/batchPush
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
- 按 `componentPath` 做 upsert(存在则更新结构字段,不存在则新增)
|
|
233
|
-
- **不删除**后端多余的菜单
|
|
234
|
-
- **不碰**权限/角色绑定字段
|
|
235
|
-
- 详见 `.github/guides/architecture.md`
|
|
236
|
-
|
|
237
|
-
### pages.ts 扩展
|
|
238
|
-
|
|
239
|
-
在 `SharedPageItem` 中增加 `menuMeta` 字段:
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
export interface SharedPageItem {
|
|
243
|
-
name: string;
|
|
244
|
-
label: string;
|
|
245
|
-
menuMeta?: {
|
|
246
|
-
parentName: string;
|
|
247
|
-
menuPath: string;
|
|
248
|
-
sortOrder: number;
|
|
249
|
-
appCode: string;
|
|
250
|
-
hidden?: boolean;
|
|
251
|
-
icon?: string;
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### 切换步骤
|
|
257
|
-
|
|
258
|
-
1. 后端提供 `batchPush` 接口
|
|
259
|
-
2. 在 pages.ts 的页面条目中补充 `menuMeta`
|
|
260
|
-
3. 创建 `scripts/menu-push.ts`(vite-node 执行)
|
|
261
|
-
4. 注册 `pnpm run menu:push` 命令
|
|
262
|
-
5. page-codegen Skill 生成页面时自动填充 `menuMeta`
|
|
263
|
-
6. 废弃 Phase 1 的 AI 手动调 API 流程
|
|
1
|
+
---
|
|
2
|
+
name: menu-sync
|
|
3
|
+
description: "Use when: creating system menus for newly generated pages, batch registering menus, or syncing pages.ts entries to the backend menu table. Triggers on: 创建菜单, 注册菜单, 同步菜单, 补菜单, menu sync, create menu, register menu."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: 菜单同步(menu-sync)
|
|
7
|
+
|
|
8
|
+
将 pages.ts 中注册的页面同步到后端菜单表,使系统能够路由到新页面。
|
|
9
|
+
|
|
10
|
+
> **背景**:本项目是 Module Federation 子应用,页面在 `pages.ts` 注册后,
|
|
11
|
+
> 还需要在后端菜单表中创建对应记录,系统才能路由到该页面。
|
|
12
|
+
> 设计文档:`.github/guides/architecture.md`
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 配置与使用方式(一次配置,无需反复填写)
|
|
17
|
+
|
|
18
|
+
### 数据来源分工
|
|
19
|
+
|
|
20
|
+
| 数据 | 来源 | 说明 |
|
|
21
|
+
| ------------------------------------------------ | -------------------------- | --------------------------------------- |
|
|
22
|
+
| 菜单名称、路径、组件、权限、隐藏、排序、应用编码 | `reports/SYS_MENU_INFO.md` | 由 page-codegen 追加写入,AI 直接读取 |
|
|
23
|
+
| `parentMenuNameCode` | API 自动查询 | AI 调 children 接口获取,无需手填 |
|
|
24
|
+
| **gatewayPath、parentMenuId、sysAppNo、token** | `env.local.json` | 每套环境不同,唯一需要手动维护的 4 个值 |
|
|
25
|
+
|
|
26
|
+
### 配置文件(统一维护,菜单/字典/权限共用)
|
|
27
|
+
|
|
28
|
+
优先读取 `.github/skills/sync/env.local.json`(v2.1.5+ 统一配置):
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"gatewayPath": "http://网关地址:端口",
|
|
33
|
+
"sysAppNo": "应用编码(从已有菜单的sysAppNo字段获取,非明文)",
|
|
34
|
+
"token": "Bearer Token(不含bearer前缀)",
|
|
35
|
+
"menu": {
|
|
36
|
+
"parentMenuId": "父级菜单ID"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> 向下兼容:如上述文件不存在,回落读取 `menu-sync/env/env.local.json`(旧版路径)。
|
|
42
|
+
> 字段说明及获取方式见 `env/guide.md`
|
|
43
|
+
|
|
44
|
+
menu-sync 读取规则:`parentMenuId` 优先从 `menu.parentMenuId` 读取,回落到根级 `parentMenuId`。
|
|
45
|
+
|
|
46
|
+
### 使用步骤
|
|
47
|
+
|
|
48
|
+
1. **首次**:按 `env/guide.md` 填写 `skills/sync/env.local.json` 的字段
|
|
49
|
+
2. **之后**:直接对 AI 说「帮我创建菜单」/「同步菜单」/「补菜单」
|
|
50
|
+
3. AI 自动执行:读 `reports/SYS_MENU_INFO.md` → 读 `env.local.json` → 查父级已有子节点 → 逐条对比去重 → 调 `/system/menu/save` → 输出 created/skipped 结果表
|
|
51
|
+
4. **全程无需手动执行任何命令**
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 方案演进路线
|
|
56
|
+
|
|
57
|
+
| 阶段 | 方案 | 状态 | 说明 |
|
|
58
|
+
| ----------- | --------------------------------- | ------------- | ---------------------------------------------------- |
|
|
59
|
+
| **Phase 1** | AI 调用现有 API 逐条创建 | ✅ 当前可用 | 利用 `/system/menu/save` 接口,AI 充当自动化脚本 |
|
|
60
|
+
| **Phase 2** | 前端推送脚本 `pnpm run menu:push` | ⏳ 待后端接口 | 需后端提供 `POST /system/menu/batchPush` upsert 接口 |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Phase 1:AI 调用 API 创建菜单(当前方案)
|
|
65
|
+
|
|
66
|
+
> 此方案参考平台伙伴的 jh4j-cloud skill,适配 cx-ui-produce 项目。
|
|
67
|
+
> 本质是 **menu-sync-design.md 的方案 C(只增不删)**,由 AI 自动执行。
|
|
68
|
+
|
|
69
|
+
### 前置条件
|
|
70
|
+
|
|
71
|
+
1. 用户提供后端系统管理地址(如 `http://localhost:9000` 或实际网关地址)
|
|
72
|
+
2. 用户提供有效的 Bearer Token(从浏览器开发者工具 Network 面板复制)
|
|
73
|
+
3. 用户提供父级菜单 ID(`menuId`),可通过查询接口获取
|
|
74
|
+
|
|
75
|
+
### 输入
|
|
76
|
+
|
|
77
|
+
用户提供以下信息(或 AI 从 pages.ts 自动提取):
|
|
78
|
+
|
|
79
|
+
- **父级菜单 ID**:`menuId`(后端菜单树中的上级目录 ID)
|
|
80
|
+
- **应用编码**:`sysAppNo`(如 `produce`、`sale`、`system`)
|
|
81
|
+
- **菜单数据**:可以是 pages.ts 中的条目,或用户手动指定
|
|
82
|
+
|
|
83
|
+
菜单类型:
|
|
84
|
+
|
|
85
|
+
| type | 含义 | 必填字段 |
|
|
86
|
+
| ---- | ------------ | --------------------------------------------- |
|
|
87
|
+
| `M` | 目录 | `menuName`, `path` |
|
|
88
|
+
| `C` | 菜单(页面) | `menuName`, `path`, `permission`, `component` |
|
|
89
|
+
| `A` | 动作按钮 | `menuName`, `path` |
|
|
90
|
+
|
|
91
|
+
### 执行流程
|
|
92
|
+
|
|
93
|
+
#### Step 1: 查询父级下已有菜单(防重复)
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
GET {gatewayPath}/system/menu/children?current=1&size=100&menuId={parentMenuId}
|
|
97
|
+
Headers:
|
|
98
|
+
authorization: bearer {token}
|
|
99
|
+
Sysappno: {sysAppNo}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Step 2: 逐条创建菜单
|
|
103
|
+
|
|
104
|
+
对于每条待创建的菜单,先检查是否与已有菜单重名(`menuName` 或 `path` 相同),重复则跳过。
|
|
105
|
+
|
|
106
|
+
> **响应码说明**:后端成功响应为 `code: 2000`(非标准 HTTP 200),判断成功应检查 `response.body.code === 2000` 或 `message` 包含"成功"。
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
POST {gatewayPath}/system/menu/save
|
|
110
|
+
Headers:
|
|
111
|
+
authorization: bearer {token}
|
|
112
|
+
Sysappno: {sysAppNo}
|
|
113
|
+
Content-Type: application/json
|
|
114
|
+
|
|
115
|
+
Body:
|
|
116
|
+
{
|
|
117
|
+
"useCache": 1,
|
|
118
|
+
"icon": "list",
|
|
119
|
+
"common": 2,
|
|
120
|
+
"hidden": false,
|
|
121
|
+
"type": "C",
|
|
122
|
+
"parentId": "{parentMenuId}",
|
|
123
|
+
"sysAppNo": "{sysAppNo}",
|
|
124
|
+
"orderNum": {nextOrder},
|
|
125
|
+
"menuName": "客户档案",
|
|
126
|
+
"menuNameCode": "{parentMenuNameCode}:{pinyinName}",
|
|
127
|
+
"path": "mmwrCustomerArchive",
|
|
128
|
+
"permission": "mmwrCustomerArchive",
|
|
129
|
+
"component": "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### Step 3: 记录结果
|
|
134
|
+
|
|
135
|
+
创建完成后输出结果表格:
|
|
136
|
+
|
|
137
|
+
| 菜单名 | path | type | 状态 | id |
|
|
138
|
+
| -------- | ------------------- | ---- | ------------------- | ------ |
|
|
139
|
+
| 客户档案 | mmwrCustomerArchive | C | ✅ created | 123456 |
|
|
140
|
+
| 客户详情 | mmwrCustomerDetail | C | ⏭️ skipped (已存在) | - |
|
|
141
|
+
|
|
142
|
+
### 字段生成规则
|
|
143
|
+
|
|
144
|
+
| 字段 | 规则 |
|
|
145
|
+
| -------------- | -------------------------------------------------------------------------------------------- |
|
|
146
|
+
| `menuName` | 取 pages.ts 的 `label` |
|
|
147
|
+
| `path` | 页面目录名转 camelCase(如 `mmwr-customer-archive` → `mmwrCustomerArchive`) |
|
|
148
|
+
| `component` | 取 pages.ts 的 `name`(如 `produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue`) |
|
|
149
|
+
| `permission` | `{域}:{path}:list`(如 `produce:mmwrCustomerArchive:list`) |
|
|
150
|
+
| `menuNameCode` | `{父级menuNameCode}:{菜单名拼音}`(小写连续拼接) |
|
|
151
|
+
| `hidden` | 表单页/详情页等隐藏路由设为 `true`,菜单可见页面设为 `false` |
|
|
152
|
+
| `orderNum` | 从父级已有菜单最大 orderNum + 1 开始递增 |
|
|
153
|
+
| `icon` | 目录级 `"list"`,菜单级 `"list"` |
|
|
154
|
+
|
|
155
|
+
### pages.ts → 菜单数据映射示例
|
|
156
|
+
|
|
157
|
+
以 `aiflow` 子模块为例:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
pages.ts 条目:
|
|
161
|
+
["mmwr-customer-archive", "客户档案"]
|
|
162
|
+
|
|
163
|
+
→ 菜单数据:
|
|
164
|
+
{
|
|
165
|
+
type: "C",
|
|
166
|
+
menuName: "客户档案",
|
|
167
|
+
path: "mmwrCustomerArchive",
|
|
168
|
+
component: "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue",
|
|
169
|
+
permission: "produce:mmwrCustomerArchive:list",
|
|
170
|
+
hidden: false
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
隐藏页面示例:
|
|
174
|
+
["mmwr-customer-apply-add-form", "客户申请新增表单"]
|
|
175
|
+
|
|
176
|
+
→ 菜单数据:
|
|
177
|
+
{
|
|
178
|
+
type: "C",
|
|
179
|
+
menuName: "客户申请新增表单",
|
|
180
|
+
path: "mmwrCustomerApplyAddForm",
|
|
181
|
+
component: "produce/production-mmwr/aiflow/mmwr-customer-apply-add-form/index.vue",
|
|
182
|
+
permission: "produce:mmwrCustomerApplyAddForm:list",
|
|
183
|
+
hidden: true // ← 表单页隐藏
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 隐藏页面判断规则
|
|
188
|
+
|
|
189
|
+
以下页面类型应设置 `hidden: true`:
|
|
190
|
+
|
|
191
|
+
- 目录名含 `-form`(独立路由表单页)
|
|
192
|
+
- 目录名含 `-detail`(详情页)
|
|
193
|
+
- 目录名含 `-history`(历史查询页)
|
|
194
|
+
- reports/SYS_MENU_INFO.md 中标注为"隐藏菜单"的页面
|
|
195
|
+
|
|
196
|
+
### 跳过规则
|
|
197
|
+
|
|
198
|
+
- 当前父级下已有同名 `menuName` → 跳过
|
|
199
|
+
- 当前父级下已有相同 `path` → 跳过
|
|
200
|
+
- 跳过时不做更新、不做覆盖,只记录"已跳过"
|
|
201
|
+
|
|
202
|
+
### 树形菜单处理
|
|
203
|
+
|
|
204
|
+
如果需要先创建目录再创建子菜单:
|
|
205
|
+
|
|
206
|
+
1. 先以 `type: "M"` 创建目录
|
|
207
|
+
2. 保存成功后取返回的 `data.id`
|
|
208
|
+
3. 以新 `id` 作为 `parentId` 继续创建子菜单
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Phase 2:推送脚本方案(待后端接口就绪后启用)
|
|
213
|
+
|
|
214
|
+
> 对应 menu-sync-design.md 的 **方案 D(推送覆盖)**,是最终目标方案。
|
|
215
|
+
|
|
216
|
+
### 与 Phase 1 的差异
|
|
217
|
+
|
|
218
|
+
| 维度 | Phase 1 (AI 调 API) | Phase 2 (推送脚本) |
|
|
219
|
+
| -------- | ------------------- | ---------------------------- |
|
|
220
|
+
| 执行者 | AI | `pnpm run menu:push` 脚本 |
|
|
221
|
+
| 更新能力 | 只增不删(方案 C) | upsert 覆盖(方案 D) |
|
|
222
|
+
| 改名支持 | ❌ 会产生重复 | ✅ 按 componentPath 匹配更新 |
|
|
223
|
+
| 权限影响 | 无 | 无(只写结构字段) |
|
|
224
|
+
| 依赖 | Token + 网关地址 | 后端 `batchPush` 接口 |
|
|
225
|
+
|
|
226
|
+
### 所需后端接口
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
POST /system/menu/batchPush
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- 按 `componentPath` 做 upsert(存在则更新结构字段,不存在则新增)
|
|
233
|
+
- **不删除**后端多余的菜单
|
|
234
|
+
- **不碰**权限/角色绑定字段
|
|
235
|
+
- 详见 `.github/guides/architecture.md`
|
|
236
|
+
|
|
237
|
+
### pages.ts 扩展
|
|
238
|
+
|
|
239
|
+
在 `SharedPageItem` 中增加 `menuMeta` 字段:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
export interface SharedPageItem {
|
|
243
|
+
name: string;
|
|
244
|
+
label: string;
|
|
245
|
+
menuMeta?: {
|
|
246
|
+
parentName: string;
|
|
247
|
+
menuPath: string;
|
|
248
|
+
sortOrder: number;
|
|
249
|
+
appCode: string;
|
|
250
|
+
hidden?: boolean;
|
|
251
|
+
icon?: string;
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 切换步骤
|
|
257
|
+
|
|
258
|
+
1. 后端提供 `batchPush` 接口
|
|
259
|
+
2. 在 pages.ts 的页面条目中补充 `menuMeta`
|
|
260
|
+
3. 创建 `scripts/menu-push.ts`(vite-node 执行)
|
|
261
|
+
4. 注册 `pnpm run menu:push` 命令
|
|
262
|
+
5. page-codegen Skill 生成页面时自动填充 `menuMeta`
|
|
263
|
+
6. 废弃 Phase 1 的 AI 手动调 API 流程
|