@agile-team/wl-skills-kit 1.2.0 → 2.1.0

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.
Files changed (86) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +169 -366
  3. package/bin/wl-skills.js +149 -43
  4. package/files/.github/copilot-instructions.md +105 -42
  5. package/files/.github/guides/README.md +13 -0
  6. package/files/.github/guides/architecture.md +555 -0
  7. package/files/.github/guides/usage.md +166 -0
  8. package/files/.github/reports/README.md +65 -0
  9. package/files/.github/reports/SYS_DICT_INFO.md +19 -0
  10. package/files/.github/reports/SYS_PERMISSION_INFO.md +20 -0
  11. package/files/.github/reports//347/273/204/344/273/266/346/217/220/345/217/226/345/273/272/350/256/256.md +33 -0
  12. package/files/.github/reports//350/247/204/350/214/203/345/256/241/346/237/245/346/212/245/345/221/212.md +44 -0
  13. package/files/.github/skills/_compat/README.md +108 -0
  14. package/files/.github/skills/_compat/editors.json +61 -0
  15. package/files/.github/skills/_compat/headers/agents.txt +8 -0
  16. package/files/.github/skills/_compat/headers/claude-code.txt +7 -0
  17. package/files/.github/skills/_compat/headers/cline.txt +7 -0
  18. package/files/.github/skills/_compat/headers/cursor-mdc.txt +16 -0
  19. package/files/.github/skills/_compat/headers/cursor-rules.txt +7 -0
  20. package/files/.github/skills/_compat/headers/github-copilot.txt +1 -0
  21. package/files/.github/skills/_compat/headers/kiro.txt +10 -0
  22. package/files/.github/skills/_compat/headers/trae.txt +11 -0
  23. package/files/.github/skills/_compat/headers/windsurf.txt +7 -0
  24. package/files/.github/skills/_registry.md +81 -0
  25. package/files/.github/skills/{api-contract → core/api-contract}/SKILL.md +126 -29
  26. package/files/.github/skills/core/api-contract/USAGE.md +110 -0
  27. package/files/.github/skills/core/convention-audit/SKILL.md +189 -0
  28. package/files/.github/skills/core/convention-audit/USAGE.md +99 -0
  29. package/files/.github/skills/{page-codegen → core/page-codegen}/SKILL.md +67 -22
  30. package/files/.github/skills/core/page-codegen/USAGE.md +102 -0
  31. package/files/.github/skills/core/page-codegen/templates/_index.md +46 -0
  32. package/files/.github/skills/core/page-codegen/templates/domains/_CONTRIBUTING.md +107 -0
  33. package/files/.github/skills/{page-codegen → core/page-codegen/templates/domains/produce}/TPL-OPERATION-STATION.md +442 -442
  34. package/files/.github/skills/core/page-codegen/templates/domains/sale/README.md +26 -0
  35. package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-DETAIL-TABS.md +94 -39
  36. package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-DRIVEN.md +124 -124
  37. package/files/.github/skills/{prototype-scan → core/prototype-scan}/SKILL.md +87 -3
  38. package/files/.github/skills/core/prototype-scan/USAGE.md +95 -0
  39. package/files/.github/skills/core/template-extract/SKILL.md +139 -0
  40. package/files/.github/skills/core/template-extract/USAGE.md +93 -0
  41. package/files/.github/skills/domain/README.md +51 -0
  42. package/files/.github/skills/ops/code-fix/SKILL.draft.md +108 -0
  43. package/files/.github/skills/sync/dict-sync/SKILL.draft.md +100 -0
  44. package/files/.github/skills/{menu-sync → sync/menu-sync}/SKILL.md +258 -258
  45. package/files/.github/skills/sync/menu-sync/USAGE.md +104 -0
  46. package/files/.github/skills/{menu-sync → sync/menu-sync}/env/guide.md +83 -83
  47. package/files/.github/skills/sync/permission-sync/SKILL.draft.md +91 -0
  48. package/files/.github/standards/01-toolchain.md +57 -0
  49. package/files/.github/standards/02-code-structure.md +111 -0
  50. package/files/.github/standards/03-comments.md +53 -0
  51. package/files/.github/standards/04-coding-basics.md +33 -0
  52. package/files/.github/standards/05-logging.md +38 -0
  53. package/files/.github/standards/06-security.md +44 -0
  54. package/files/.github/standards/07-config.md +52 -0
  55. package/files/.github/standards/08-git.md +60 -0
  56. package/files/.github/standards/09-typescript.md +71 -0
  57. package/files/.github/standards/10-pinia.md +57 -0
  58. package/files/.github/standards/11-form-validation.md +81 -0
  59. package/files/.github/standards/12-base-table.md +116 -0
  60. package/files/.github/standards/13-platform-components.md +123 -0
  61. package/files/.github/standards/index.md +89 -0
  62. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/data.ts +196 -196
  63. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.scss +150 -150
  64. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.vue +79 -79
  65. package/files/docs/jh-date-range.md +257 -257
  66. package/files/docs/jh-date.md +222 -222
  67. package/files/docs/jh-dept-picker.md +190 -190
  68. package/files/docs/jh-drag-row.md +590 -590
  69. package/files/docs/jh-file-upload.md +216 -216
  70. package/files/docs/jh-picker.md +218 -218
  71. package/files/docs/jh-select.md +148 -148
  72. package/files/docs/jh-text.md +248 -248
  73. package/files/docs/jh-user-picker.md +197 -197
  74. package/package.json +4 -1
  75. package/files/.github/docs/menu-sync-design.md +0 -264
  76. package/files/.github/docs/use-skill.md +0 -382
  77. package/files/.github/docs/wl-skills-kit.md +0 -266
  78. package/files/.github/skills/convention-extract/SKILL.md +0 -236
  79. /package/files/.github/{docs → reports}/SYS_MENU_INFO.md +0 -0
  80. /package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-CHANGE-HISTORY.md +0 -0
  81. /package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-FORM-ROUTE.md +0 -0
  82. /package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-LIST.md +0 -0
  83. /package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-MASTER-DETAIL.md +0 -0
  84. /package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-RECORD-FORM.md +0 -0
  85. /package/files/.github/skills/{page-codegen → core/page-codegen/templates/universal}/TPL-TREE-LIST.md +0 -0
  86. /package/files/.github/skills/{menu-sync → sync/menu-sync}/env/env.local.json +0 -0
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: dict-sync
3
+ description: "[PLANNED — DRAFT, not yet active] 字典同步 Skill 设计草稿。机制类同 menu-sync:基于 reports/SYS_DICT_INFO.md 基线 ↔ 线上字典对比,自动补齐。"
4
+ status: planned
5
+ ---
6
+
7
+ # Skill: 字典同步(dict-sync)— 草稿
8
+
9
+ > ⚠️ **本文件为设计草稿(SKILL.draft.md),未启用,不参与 AI 调度。**
10
+ > 待相关后端接口稳定后,转正为 `SKILL.md`。
11
+
12
+ ---
13
+
14
+ ## 1. 设计目标
15
+
16
+ 页面 `data.ts` 中常使用 `logicType: BusLogicDataType.dict` 引用数据字典(如 `customer_state`、`mmwr_apply_status`)。新增页面/字段时,需要:
17
+
18
+ 1. 在系统字典表中**添加新字典码**(dictCode + 描述)
19
+ 2. 在字典表中**添加各项条目**(value + label + sortNo)
20
+ 3. 团队基线中保存当前线上字典(review/diff 用)
21
+
22
+ `dict-sync` 自动化以上 3 步。
23
+
24
+ ---
25
+
26
+ ## 2. 数据流
27
+
28
+ ```
29
+ 本地基线 后端接口 Skill 触发
30
+ ───────────────────────────────────── ───────────────────────────────── ────────────────
31
+ reports/SYS_DICT_INFO.md ──fetch───→ GET /sys/dict/listAll
32
+ ←──compare─── POST /sys/dict/save
33
+ ──upload───→ POST /sys/dictItem/batchSave ─→ "同步字典"
34
+ ```
35
+
36
+ ---
37
+
38
+ ## 3. 三种工作模式
39
+
40
+ | 模式 | 触发 | 动作 |
41
+ | ----------------- | --------------------- | ----------------------------------------- |
42
+ | `pull`(刷基线) | "刷新字典基线" | 从线上拉全量字典 → 写入 SYS_DICT_INFO.md |
43
+ | `push`(推新增) | "同步字典 / 创建字典" | 对比 data.ts 引用的字典 vs 基线,补齐线上 |
44
+ | `audit`(仅检查) | "字典审计" | 输出报告,不调接口 |
45
+
46
+ ---
47
+
48
+ ## 4. 配置文件
49
+
50
+ `.github/skills/sync/dict-sync/env/env.local.json`(不入 git):
51
+
52
+ ```json
53
+ {
54
+ "gatewayPath": "https://uat-api.example.com",
55
+ "token": "Bearer xxx",
56
+ "tenantId": "10001",
57
+ "_inherit": "复用 skills/sync/menu-sync/env/env.local.json 的 token、gatewayPath 等基础配置"
58
+ }
59
+ ```
60
+
61
+ > 实现时支持 `_inherit`:本目录无 env.local.json 时回落到 menu-sync 的同名文件。
62
+
63
+ ---
64
+
65
+ ## 5. 冲突处理策略
66
+
67
+ | 场景 | 策略 |
68
+ | -------------------------------- | -------------------------------------------- |
69
+ | 本地新增字典,线上不存在 | 调用 /sys/dict/save 创建 |
70
+ | 本地有的字典项,线上字典已禁用 | 询问:跳过 / 重新启用 / 视为新建 |
71
+ | 本地与线上 value 相同 label 不同 | 询问:以本地为准 / 以线上为准 / 跳过 |
72
+ | 线上有的字典/项,本地没有 | 仅记录日志,**不主动删除**(防误删生产数据) |
73
+
74
+ ---
75
+
76
+ ## 6. 与其他 Skill 联动
77
+
78
+ - **page-codegen**:生成页面时如发现 data.ts 用到未在基线中的字典码,自动在生成报告中提示"运行 dict-sync 补齐"
79
+ - **convention-audit**:审计 standards/data-ts.md 时,对比基线检测"字典码未定义"
80
+ - **prototype-scan**:扫描原型阶段如识别出状态/枚举字段,提出字典码建议
81
+
82
+ ---
83
+
84
+ ## 7. 转正前的开发任务
85
+
86
+ - [ ] 确认后端字典批量保存接口(save / batchSave / 字段名 / 响应外壳是否 `{code:2000,data}`)
87
+ - [ ] 设计 SYS_DICT_INFO.md 自动序列化/反序列化(防 markdown 渲染破坏数据)
88
+ - [ ] 实现 `_inherit` 配置回落机制
89
+ - [ ] 决定字典审计严格度(必须有 enabled / sortNo / remark 等字段)
90
+ - [ ] 提供 `dict-collect` Skill 或集成到 prototype-scan:从代码自动汇总字典依赖
91
+ - [ ] 处理多语言字典(i18n label)
92
+ - [ ] PROD 环境保护机制(推送前必须二次确认)
93
+
94
+ ---
95
+
96
+ ## 8. 风险与边界
97
+
98
+ - **不删除**:永远不主动删除线上字典/字典项
99
+ - **租户隔离**:env.local.json 的 tenantId 严格隔离
100
+ - **审计日志**:每次 push 输出 `reports/DICT_SYNC_<YYYYMMDD>.md`,含调用接口列表 + 入参 + 响应 + 回滚 SQL
@@ -1,258 +1,258 @@
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/docs/menu-sync-design.md`
13
-
14
- ---
15
-
16
- ## 配置与使用方式(一次配置,无需反复填写)
17
-
18
- ### 数据来源分工
19
-
20
- | 数据 | 来源 | 说明 |
21
- | ------------------------------------------------ | ------------------ | --------------------------------------- |
22
- | 菜单名称、路径、组件、权限、隐藏、排序、应用编码 | `SYS_MENU_INFO.md` | 原型/详设阶段自动生成,AI 直接读取 |
23
- | `parentMenuNameCode` | API 自动查询 | AI 调 children 接口获取,无需手填 |
24
- | **gatewayPath、parentMenuId、sysAppNo、token** | `env.local.json` | 每套环境不同,唯一需要手动维护的 4 个值 |
25
-
26
- ### 配置文件(只需填 4 个字段)
27
-
28
- `.github/skills/menu-sync/env/env.local.json`(已加入 `.gitignore`,本地维护,不提交)
29
-
30
- ```json
31
- {
32
- "gatewayPath": "http://网关地址:端口",
33
- "parentMenuId": "父级菜单ID",
34
- "sysAppNo": "应用编码(从已有菜单的sysAppNo字段获取,非明文)",
35
- "token": "Bearer Token(不含bearer前缀)"
36
- }
37
- ```
38
-
39
- > 字段说明及获取方式见 `env/guide.md`
40
-
41
- ### 使用步骤
42
-
43
- 1. **首次**:按 `env/guide.md` 填写 `env.local.json` 的 4 个字段
44
- 2. **之后**:直接对 AI 说「帮我创建菜单」/「同步菜单」/「补菜单」
45
- 3. AI 自动执行:读 `SYS_MENU_INFO.md` → 读 `env.local.json` → 查父级已有子节点 → 逐条对比去重 → 调 `/system/menu/save` → 输出 created/skipped 结果表
46
- 4. **全程无需手动执行任何命令**
47
-
48
- ---
49
-
50
- ## 方案演进路线
51
-
52
- | 阶段 | 方案 | 状态 | 说明 |
53
- | ----------- | --------------------------------- | ------------- | ---------------------------------------------------- |
54
- | **Phase 1** | AI 调用现有 API 逐条创建 | ✅ 当前可用 | 利用 `/system/menu/save` 接口,AI 充当自动化脚本 |
55
- | **Phase 2** | 前端推送脚本 `pnpm run menu:push` | ⏳ 待后端接口 | 需后端提供 `POST /system/menu/batchPush` upsert 接口 |
56
-
57
- ---
58
-
59
- ## Phase 1:AI 调用 API 创建菜单(当前方案)
60
-
61
- > 此方案参考平台伙伴的 jh4j-cloud skill,适配 cx-ui-produce 项目。
62
- > 本质是 **menu-sync-design.md 的方案 C(只增不删)**,由 AI 自动执行。
63
-
64
- ### 前置条件
65
-
66
- 1. 用户提供后端系统管理地址(如 `http://localhost:9000` 或实际网关地址)
67
- 2. 用户提供有效的 Bearer Token(从浏览器开发者工具 Network 面板复制)
68
- 3. 用户提供父级菜单 ID(`menuId`),可通过查询接口获取
69
-
70
- ### 输入
71
-
72
- 用户提供以下信息(或 AI 从 pages.ts 自动提取):
73
-
74
- - **父级菜单 ID**:`menuId`(后端菜单树中的上级目录 ID)
75
- - **应用编码**:`sysAppNo`(如 `produce`、`sale`、`system`)
76
- - **菜单数据**:可以是 pages.ts 中的条目,或用户手动指定
77
-
78
- 菜单类型:
79
-
80
- | type | 含义 | 必填字段 |
81
- | ---- | ------------ | --------------------------------------------- |
82
- | `M` | 目录 | `menuName`, `path` |
83
- | `C` | 菜单(页面) | `menuName`, `path`, `permission`, `component` |
84
- | `A` | 动作按钮 | `menuName`, `path` |
85
-
86
- ### 执行流程
87
-
88
- #### Step 1: 查询父级下已有菜单(防重复)
89
-
90
- ```
91
- GET {gatewayPath}/system/menu/children?current=1&size=100&menuId={parentMenuId}
92
- Headers:
93
- authorization: bearer {token}
94
- Sysappno: {sysAppNo}
95
- ```
96
-
97
- #### Step 2: 逐条创建菜单
98
-
99
- 对于每条待创建的菜单,先检查是否与已有菜单重名(`menuName` 或 `path` 相同),重复则跳过。
100
-
101
- > **响应码说明**:后端成功响应为 `code: 2000`(非标准 HTTP 200),判断成功应检查 `response.body.code === 2000` 或 `message` 包含"成功"。
102
-
103
- ```
104
- POST {gatewayPath}/system/menu/save
105
- Headers:
106
- authorization: bearer {token}
107
- Sysappno: {sysAppNo}
108
- Content-Type: application/json
109
-
110
- Body:
111
- {
112
- "useCache": 1,
113
- "icon": "list",
114
- "common": 2,
115
- "hidden": false,
116
- "type": "C",
117
- "parentId": "{parentMenuId}",
118
- "sysAppNo": "{sysAppNo}",
119
- "orderNum": {nextOrder},
120
- "menuName": "客户档案",
121
- "menuNameCode": "{parentMenuNameCode}:{pinyinName}",
122
- "path": "mmwrCustomerArchive",
123
- "permission": "mmwrCustomerArchive",
124
- "component": "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue"
125
- }
126
- ```
127
-
128
- #### Step 3: 记录结果
129
-
130
- 创建完成后输出结果表格:
131
-
132
- | 菜单名 | path | type | 状态 | id |
133
- | -------- | ------------------- | ---- | ------------------- | ------ |
134
- | 客户档案 | mmwrCustomerArchive | C | ✅ created | 123456 |
135
- | 客户详情 | mmwrCustomerDetail | C | ⏭️ skipped (已存在) | - |
136
-
137
- ### 字段生成规则
138
-
139
- | 字段 | 规则 |
140
- | -------------- | -------------------------------------------------------------------------------------------- |
141
- | `menuName` | 取 pages.ts 的 `label` |
142
- | `path` | 页面目录名转 camelCase(如 `mmwr-customer-archive` → `mmwrCustomerArchive`) |
143
- | `component` | 取 pages.ts 的 `name`(如 `produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue`) |
144
- | `permission` | `{域}:{path}:list`(如 `produce:mmwrCustomerArchive:list`) |
145
- | `menuNameCode` | `{父级menuNameCode}:{菜单名拼音}`(小写连续拼接) |
146
- | `hidden` | 表单页/详情页等隐藏路由设为 `true`,菜单可见页面设为 `false` |
147
- | `orderNum` | 从父级已有菜单最大 orderNum + 1 开始递增 |
148
- | `icon` | 目录级 `"list"`,菜单级 `"list"` |
149
-
150
- ### pages.ts → 菜单数据映射示例
151
-
152
- 以 `aiflow` 子模块为例:
153
-
154
- ```
155
- pages.ts 条目:
156
- ["mmwr-customer-archive", "客户档案"]
157
-
158
- → 菜单数据:
159
- {
160
- type: "C",
161
- menuName: "客户档案",
162
- path: "mmwrCustomerArchive",
163
- component: "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue",
164
- permission: "produce:mmwrCustomerArchive:list",
165
- hidden: false
166
- }
167
-
168
- 隐藏页面示例:
169
- ["mmwr-customer-apply-add-form", "客户申请新增表单"]
170
-
171
- → 菜单数据:
172
- {
173
- type: "C",
174
- menuName: "客户申请新增表单",
175
- path: "mmwrCustomerApplyAddForm",
176
- component: "produce/production-mmwr/aiflow/mmwr-customer-apply-add-form/index.vue",
177
- permission: "produce:mmwrCustomerApplyAddForm:list",
178
- hidden: true // ← 表单页隐藏
179
- }
180
- ```
181
-
182
- ### 隐藏页面判断规则
183
-
184
- 以下页面类型应设置 `hidden: true`:
185
-
186
- - 目录名含 `-form`(独立路由表单页)
187
- - 目录名含 `-detail`(详情页)
188
- - 目录名含 `-history`(历史查询页)
189
- - SYS_MENU_INFO.md 中标注为"隐藏菜单"的页面
190
-
191
- ### 跳过规则
192
-
193
- - 当前父级下已有同名 `menuName` → 跳过
194
- - 当前父级下已有相同 `path` → 跳过
195
- - 跳过时不做更新、不做覆盖,只记录"已跳过"
196
-
197
- ### 树形菜单处理
198
-
199
- 如果需要先创建目录再创建子菜单:
200
-
201
- 1. 先以 `type: "M"` 创建目录
202
- 2. 保存成功后取返回的 `data.id`
203
- 3. 以新 `id` 作为 `parentId` 继续创建子菜单
204
-
205
- ---
206
-
207
- ## Phase 2:推送脚本方案(待后端接口就绪后启用)
208
-
209
- > 对应 menu-sync-design.md 的 **方案 D(推送覆盖)**,是最终目标方案。
210
-
211
- ### 与 Phase 1 的差异
212
-
213
- | 维度 | Phase 1 (AI 调 API) | Phase 2 (推送脚本) |
214
- | -------- | ------------------- | ---------------------------- |
215
- | 执行者 | AI | `pnpm run menu:push` 脚本 |
216
- | 更新能力 | 只增不删(方案 C) | upsert 覆盖(方案 D) |
217
- | 改名支持 | ❌ 会产生重复 | ✅ 按 componentPath 匹配更新 |
218
- | 权限影响 | 无 | 无(只写结构字段) |
219
- | 依赖 | Token + 网关地址 | 后端 `batchPush` 接口 |
220
-
221
- ### 所需后端接口
222
-
223
- ```
224
- POST /system/menu/batchPush
225
- ```
226
-
227
- - 按 `componentPath` 做 upsert(存在则更新结构字段,不存在则新增)
228
- - **不删除**后端多余的菜单
229
- - **不碰**权限/角色绑定字段
230
- - 详见 `.github/docs/menu-sync-design.md`
231
-
232
- ### pages.ts 扩展
233
-
234
- 在 `SharedPageItem` 中增加 `menuMeta` 字段:
235
-
236
- ```typescript
237
- export interface SharedPageItem {
238
- name: string;
239
- label: string;
240
- menuMeta?: {
241
- parentName: string;
242
- menuPath: string;
243
- sortOrder: number;
244
- appCode: string;
245
- hidden?: boolean;
246
- icon?: string;
247
- };
248
- }
249
- ```
250
-
251
- ### 切换步骤
252
-
253
- 1. 后端提供 `batchPush` 接口
254
- 2. 在 pages.ts 的页面条目中补充 `menuMeta`
255
- 3. 创建 `scripts/menu-push.ts`(vite-node 执行)
256
- 4. 注册 `pnpm run menu:push` 命令
257
- 5. page-codegen Skill 生成页面时自动填充 `menuMeta`
258
- 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
+ ### 配置文件(只需填 4 个字段)
27
+
28
+ `.github/skills/sync/menu-sync/env/env.local.json`(已加入 `.gitignore`,本地维护,不提交)
29
+
30
+ ```json
31
+ {
32
+ "gatewayPath": "http://网关地址:端口",
33
+ "parentMenuId": "父级菜单ID",
34
+ "sysAppNo": "应用编码(从已有菜单的sysAppNo字段获取,非明文)",
35
+ "token": "Bearer Token(不含bearer前缀)"
36
+ }
37
+ ```
38
+
39
+ > 字段说明及获取方式见 `env/guide.md`
40
+
41
+ ### 使用步骤
42
+
43
+ 1. **首次**:按 `env/guide.md` 填写 `env.local.json` 的 4 个字段
44
+ 2. **之后**:直接对 AI 说「帮我创建菜单」/「同步菜单」/「补菜单」
45
+ 3. AI 自动执行:读 `reports/SYS_MENU_INFO.md` → 读 `env.local.json` → 查父级已有子节点 → 逐条对比去重 → 调 `/system/menu/save` → 输出 created/skipped 结果表
46
+ 4. **全程无需手动执行任何命令**
47
+
48
+ ---
49
+
50
+ ## 方案演进路线
51
+
52
+ | 阶段 | 方案 | 状态 | 说明 |
53
+ | ----------- | --------------------------------- | ------------- | ---------------------------------------------------- |
54
+ | **Phase 1** | AI 调用现有 API 逐条创建 | ✅ 当前可用 | 利用 `/system/menu/save` 接口,AI 充当自动化脚本 |
55
+ | **Phase 2** | 前端推送脚本 `pnpm run menu:push` | ⏳ 待后端接口 | 需后端提供 `POST /system/menu/batchPush` upsert 接口 |
56
+
57
+ ---
58
+
59
+ ## Phase 1:AI 调用 API 创建菜单(当前方案)
60
+
61
+ > 此方案参考平台伙伴的 jh4j-cloud skill,适配 cx-ui-produce 项目。
62
+ > 本质是 **menu-sync-design.md 的方案 C(只增不删)**,由 AI 自动执行。
63
+
64
+ ### 前置条件
65
+
66
+ 1. 用户提供后端系统管理地址(如 `http://localhost:9000` 或实际网关地址)
67
+ 2. 用户提供有效的 Bearer Token(从浏览器开发者工具 Network 面板复制)
68
+ 3. 用户提供父级菜单 ID(`menuId`),可通过查询接口获取
69
+
70
+ ### 输入
71
+
72
+ 用户提供以下信息(或 AI 从 pages.ts 自动提取):
73
+
74
+ - **父级菜单 ID**:`menuId`(后端菜单树中的上级目录 ID)
75
+ - **应用编码**:`sysAppNo`(如 `produce`、`sale`、`system`)
76
+ - **菜单数据**:可以是 pages.ts 中的条目,或用户手动指定
77
+
78
+ 菜单类型:
79
+
80
+ | type | 含义 | 必填字段 |
81
+ | ---- | ------------ | --------------------------------------------- |
82
+ | `M` | 目录 | `menuName`, `path` |
83
+ | `C` | 菜单(页面) | `menuName`, `path`, `permission`, `component` |
84
+ | `A` | 动作按钮 | `menuName`, `path` |
85
+
86
+ ### 执行流程
87
+
88
+ #### Step 1: 查询父级下已有菜单(防重复)
89
+
90
+ ```
91
+ GET {gatewayPath}/system/menu/children?current=1&size=100&menuId={parentMenuId}
92
+ Headers:
93
+ authorization: bearer {token}
94
+ Sysappno: {sysAppNo}
95
+ ```
96
+
97
+ #### Step 2: 逐条创建菜单
98
+
99
+ 对于每条待创建的菜单,先检查是否与已有菜单重名(`menuName` 或 `path` 相同),重复则跳过。
100
+
101
+ > **响应码说明**:后端成功响应为 `code: 2000`(非标准 HTTP 200),判断成功应检查 `response.body.code === 2000` 或 `message` 包含"成功"。
102
+
103
+ ```
104
+ POST {gatewayPath}/system/menu/save
105
+ Headers:
106
+ authorization: bearer {token}
107
+ Sysappno: {sysAppNo}
108
+ Content-Type: application/json
109
+
110
+ Body:
111
+ {
112
+ "useCache": 1,
113
+ "icon": "list",
114
+ "common": 2,
115
+ "hidden": false,
116
+ "type": "C",
117
+ "parentId": "{parentMenuId}",
118
+ "sysAppNo": "{sysAppNo}",
119
+ "orderNum": {nextOrder},
120
+ "menuName": "客户档案",
121
+ "menuNameCode": "{parentMenuNameCode}:{pinyinName}",
122
+ "path": "mmwrCustomerArchive",
123
+ "permission": "mmwrCustomerArchive",
124
+ "component": "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue"
125
+ }
126
+ ```
127
+
128
+ #### Step 3: 记录结果
129
+
130
+ 创建完成后输出结果表格:
131
+
132
+ | 菜单名 | path | type | 状态 | id |
133
+ | -------- | ------------------- | ---- | ------------------- | ------ |
134
+ | 客户档案 | mmwrCustomerArchive | C | ✅ created | 123456 |
135
+ | 客户详情 | mmwrCustomerDetail | C | ⏭️ skipped (已存在) | - |
136
+
137
+ ### 字段生成规则
138
+
139
+ | 字段 | 规则 |
140
+ | -------------- | -------------------------------------------------------------------------------------------- |
141
+ | `menuName` | 取 pages.ts 的 `label` |
142
+ | `path` | 页面目录名转 camelCase(如 `mmwr-customer-archive` → `mmwrCustomerArchive`) |
143
+ | `component` | 取 pages.ts 的 `name`(如 `produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue`) |
144
+ | `permission` | `{域}:{path}:list`(如 `produce:mmwrCustomerArchive:list`) |
145
+ | `menuNameCode` | `{父级menuNameCode}:{菜单名拼音}`(小写连续拼接) |
146
+ | `hidden` | 表单页/详情页等隐藏路由设为 `true`,菜单可见页面设为 `false` |
147
+ | `orderNum` | 从父级已有菜单最大 orderNum + 1 开始递增 |
148
+ | `icon` | 目录级 `"list"`,菜单级 `"list"` |
149
+
150
+ ### pages.ts → 菜单数据映射示例
151
+
152
+ 以 `aiflow` 子模块为例:
153
+
154
+ ```
155
+ pages.ts 条目:
156
+ ["mmwr-customer-archive", "客户档案"]
157
+
158
+ → 菜单数据:
159
+ {
160
+ type: "C",
161
+ menuName: "客户档案",
162
+ path: "mmwrCustomerArchive",
163
+ component: "produce/production-mmwr/aiflow/mmwr-customer-archive/index.vue",
164
+ permission: "produce:mmwrCustomerArchive:list",
165
+ hidden: false
166
+ }
167
+
168
+ 隐藏页面示例:
169
+ ["mmwr-customer-apply-add-form", "客户申请新增表单"]
170
+
171
+ → 菜单数据:
172
+ {
173
+ type: "C",
174
+ menuName: "客户申请新增表单",
175
+ path: "mmwrCustomerApplyAddForm",
176
+ component: "produce/production-mmwr/aiflow/mmwr-customer-apply-add-form/index.vue",
177
+ permission: "produce:mmwrCustomerApplyAddForm:list",
178
+ hidden: true // ← 表单页隐藏
179
+ }
180
+ ```
181
+
182
+ ### 隐藏页面判断规则
183
+
184
+ 以下页面类型应设置 `hidden: true`:
185
+
186
+ - 目录名含 `-form`(独立路由表单页)
187
+ - 目录名含 `-detail`(详情页)
188
+ - 目录名含 `-history`(历史查询页)
189
+ - reports/SYS_MENU_INFO.md 中标注为"隐藏菜单"的页面
190
+
191
+ ### 跳过规则
192
+
193
+ - 当前父级下已有同名 `menuName` → 跳过
194
+ - 当前父级下已有相同 `path` → 跳过
195
+ - 跳过时不做更新、不做覆盖,只记录"已跳过"
196
+
197
+ ### 树形菜单处理
198
+
199
+ 如果需要先创建目录再创建子菜单:
200
+
201
+ 1. 先以 `type: "M"` 创建目录
202
+ 2. 保存成功后取返回的 `data.id`
203
+ 3. 以新 `id` 作为 `parentId` 继续创建子菜单
204
+
205
+ ---
206
+
207
+ ## Phase 2:推送脚本方案(待后端接口就绪后启用)
208
+
209
+ > 对应 menu-sync-design.md 的 **方案 D(推送覆盖)**,是最终目标方案。
210
+
211
+ ### 与 Phase 1 的差异
212
+
213
+ | 维度 | Phase 1 (AI 调 API) | Phase 2 (推送脚本) |
214
+ | -------- | ------------------- | ---------------------------- |
215
+ | 执行者 | AI | `pnpm run menu:push` 脚本 |
216
+ | 更新能力 | 只增不删(方案 C) | upsert 覆盖(方案 D) |
217
+ | 改名支持 | ❌ 会产生重复 | ✅ 按 componentPath 匹配更新 |
218
+ | 权限影响 | 无 | 无(只写结构字段) |
219
+ | 依赖 | Token + 网关地址 | 后端 `batchPush` 接口 |
220
+
221
+ ### 所需后端接口
222
+
223
+ ```
224
+ POST /system/menu/batchPush
225
+ ```
226
+
227
+ - 按 `componentPath` 做 upsert(存在则更新结构字段,不存在则新增)
228
+ - **不删除**后端多余的菜单
229
+ - **不碰**权限/角色绑定字段
230
+ - 详见 `.github/guides/architecture.md`
231
+
232
+ ### pages.ts 扩展
233
+
234
+ 在 `SharedPageItem` 中增加 `menuMeta` 字段:
235
+
236
+ ```typescript
237
+ export interface SharedPageItem {
238
+ name: string;
239
+ label: string;
240
+ menuMeta?: {
241
+ parentName: string;
242
+ menuPath: string;
243
+ sortOrder: number;
244
+ appCode: string;
245
+ hidden?: boolean;
246
+ icon?: string;
247
+ };
248
+ }
249
+ ```
250
+
251
+ ### 切换步骤
252
+
253
+ 1. 后端提供 `batchPush` 接口
254
+ 2. 在 pages.ts 的页面条目中补充 `menuMeta`
255
+ 3. 创建 `scripts/menu-push.ts`(vite-node 执行)
256
+ 4. 注册 `pnpm run menu:push` 命令
257
+ 5. page-codegen Skill 生成页面时自动填充 `menuMeta`
258
+ 6. 废弃 Phase 1 的 AI 手动调 API 流程