@agile-team/wl-skills-kit 2.7.0 → 2.7.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 +48 -0
- package/README.md +16 -1
- package/bin/wl-skills.js +1 -1
- package/files/.github/copilot-instructions.md +12 -0
- package/files/.github/guides/architecture.md +1 -1
- package/files/.github/skills/_best-practices.md +220 -0
- package/files/.github/skills/_registry.md +23 -19
- package/files/.github/skills/sync/_mcp-guardrail.md +109 -0
- package/files/.github/skills/sync/dict-sync/SKILL.md +86 -329
- package/files/.github/skills/sync/menu-sync/SKILL.md +34 -27
- package/files/.github/skills/sync/menu-sync/USAGE.md +17 -11
- package/files/.github/skills/sync/permission-sync/SKILL.md +19 -2
- package/files/docs/jh-date-range.md +40 -8
- package/files/docs/jh-date.md +45 -18
- package/files/docs/jh-dept-picker.md +17 -0
- package/files/docs/jh-drag-row.md +44 -21
- package/files/docs/jh-file-upload.md +43 -0
- package/files/docs/jh-select.md +51 -14
- package/files/docs/jh-text.md +29 -11
- package/files/docs/jh-textarea.md +159 -0
- package/files/docs/jh-user-picker.md +17 -0
- package/files/docs/page-query-hook-best-practices.md +431 -362
- package/mcp/api/client.js +8 -1
- package/mcp/server.js +21 -0
- package/package.json +5 -4
|
@@ -7,14 +7,21 @@ description: "Use when: syncing data dictionary entries to the backend, pulling
|
|
|
7
7
|
|
|
8
8
|
将 `data.ts` 中引用的数据字典(`logicType: BusLogicDataType.dict, logicValue: "DICT_CODE"`)同步到后端字典表,保持本地基线与线上一致。
|
|
9
9
|
|
|
10
|
-
> **与 menu-sync
|
|
11
|
-
> 配置直接复用 `skills/sync/env.local.json` 统一配置文件,无需重复填写。
|
|
10
|
+
> **与 menu-sync / permission-sync 对称**:同样读取本地基线 → 与线上对比 → 补齐差异。配置共用 `skills/sync/env.local.json`。
|
|
12
11
|
|
|
13
12
|
---
|
|
14
13
|
|
|
15
|
-
##
|
|
14
|
+
## 📖 必读公共护栏
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
本 Skill 遵守 `../_mcp-guardrail.md`(MCP 调用纪律与自愈闭环)。AI 首次执行 sync 类任务时先 `read_file` 加载它。
|
|
17
|
+
|
|
18
|
+
本 Skill 使用的 MCP 工具:`wls_dict_query` / `wls_dict_upsert`。调用失败时按 guardrail §2 剧本引导用户完善 `env.local.json` 后重试,**不得用 curl/手拼 HTTP 绕开 MCP**。
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 配置(统一配置文件)
|
|
23
|
+
|
|
24
|
+
读取 `.github/skills/sync/env.local.json`(已在 `.gitignore`,不入 git):
|
|
18
25
|
|
|
19
26
|
```json
|
|
20
27
|
{
|
|
@@ -27,9 +34,14 @@ description: "Use when: syncing data dictionary entries to the backend, pulling
|
|
|
27
34
|
}
|
|
28
35
|
```
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
| 字段 | 说明 |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `gatewayPath` | 后端网关,末尾不加斜杠 |
|
|
40
|
+
| `sysAppNo` | 应用编码(非明文) |
|
|
41
|
+
| `token` | 纯 JWT,**不含 `bearer ` 前缀**(MCP 内部自动拼接) |
|
|
42
|
+
| `dict.moduleId` | 字典所属模块 ID(字典管理后台 Network 抓取) |
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
> 字段获取方式见同目录 `../menu-sync/env/guide.md`。
|
|
33
45
|
|
|
34
46
|
---
|
|
35
47
|
|
|
@@ -37,26 +49,14 @@ description: "Use when: syncing data dictionary entries to the backend, pulling
|
|
|
37
49
|
|
|
38
50
|
```
|
|
39
51
|
🚀 已触发技能 dict-sync/SKILL.md → 字典同步
|
|
40
|
-
✅
|
|
41
|
-
✅ 已读取
|
|
52
|
+
✅ MCP 工具检查:wls_dict_query / wls_dict_upsert 均可用
|
|
53
|
+
✅ 已读取 .github/skills/sync/env.local.json → 网关 + token + sysAppNo + dict.moduleId
|
|
54
|
+
✅ 已读取 .github/reports/SYS_DICT_INFO.md → 本地字典基线
|
|
42
55
|
✅ 操作模式:{pull / push / audit}
|
|
43
|
-
✅ 目标字典码:{用户指定 /
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## API 调用规范
|
|
49
|
-
|
|
50
|
-
所有接口使用以下 Headers:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
Authorization: Bearer {token}
|
|
54
|
-
Sysappno: {sysAppNo}
|
|
55
|
-
Content-Type: application/json
|
|
56
|
+
✅ 目标字典码:{用户指定 / data.ts 扫描结果}
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
**Token 失效**:`code === 401` 或 `code` 不在 `[200, 2000]` 且 message 含 "token" → 停止执行,提示用户更新 token。
|
|
59
|
+
> Pre-flight 任一项失败(特别是 MCP 工具检查),立即停止并向用户报告,**不得**降级为手动调接口。
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
@@ -66,40 +66,13 @@ Content-Type: application/json
|
|
|
66
66
|
|
|
67
67
|
**触发词**:`刷新字典基线` / `拉字典`
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
调用
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**接口**:
|
|
77
|
-
```
|
|
78
|
-
GET {gatewayPath}/system/business/dict/getDictionaryTreeData
|
|
79
|
-
Headers:
|
|
80
|
-
Authorization: Bearer {token}
|
|
81
|
-
Sysappno: {sysAppNo}
|
|
82
|
-
```
|
|
69
|
+
**执行**:
|
|
70
|
+
1. 调用 MCP 工具 `wls_dict_query`(无参)
|
|
71
|
+
2. 工具返回当前应用域全部字典模块 + 字典项树
|
|
72
|
+
3. AI 解析返回结果,整理为 SYS_DICT_INFO.md 格式覆盖写入
|
|
73
|
+
4. 输出:"共拉取 N 个字典码,M 个字典项"
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
```json
|
|
86
|
-
{
|
|
87
|
-
"code": 2000,
|
|
88
|
-
"data": {
|
|
89
|
-
"dictionary": {
|
|
90
|
-
"children": [
|
|
91
|
-
{
|
|
92
|
-
"id": "节点ID",
|
|
93
|
-
"strSn": "字典编码或模块编码",
|
|
94
|
-
"strName": "字典名称",
|
|
95
|
-
"children": [...]
|
|
96
|
-
}
|
|
97
|
-
]
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
叶节点(无 `children`)= 实际字典,取其 `id`(用于后续创建字典项)和 `strSn`。
|
|
75
|
+
> MCP 内部对应 `GET /system/business/dict/getDictionaryTreeData`,AI **无需关心**。
|
|
103
76
|
|
|
104
77
|
---
|
|
105
78
|
|
|
@@ -110,93 +83,82 @@ Headers:
|
|
|
110
83
|
#### Step 1:扫描 data.ts 中的字典引用
|
|
111
84
|
|
|
112
85
|
从用户指定范围扫描所有:
|
|
86
|
+
|
|
113
87
|
```typescript
|
|
114
88
|
logicType: BusLogicDataType.dict, logicValue: "DICT_CODE"
|
|
115
89
|
```
|
|
116
|
-
|
|
90
|
+
|
|
91
|
+
去重得到「当前用到的字典码集合」。
|
|
117
92
|
|
|
118
93
|
#### Step 2:与本地基线 + 线上对比(去重双保险)
|
|
119
94
|
|
|
120
95
|
```
|
|
121
|
-
① 读取 reports/SYS_DICT_INFO.md →
|
|
122
|
-
② 调用
|
|
96
|
+
① 读取 reports/SYS_DICT_INFO.md → 本地已知字典码
|
|
97
|
+
② 调用 wls_dict_query → 线上当前字典码(strSn 列表)
|
|
123
98
|
③ 待创建 = 用到的字典码 - 线上已有字典码
|
|
124
99
|
```
|
|
125
100
|
|
|
126
|
-
>
|
|
127
|
-
> 去重通过 Step ② 线上实时查询保证:A 创建了,B 运行时线上已有,自动跳过,**不会重复创建**。
|
|
128
|
-
> 即使极端并发(两人同一秒执行),后端 `strSn` 字段有唯一约束,第二次创建会返回"已存在",Skill 将其视为成功跳过。
|
|
101
|
+
> **多人协同**:每人 env.local.json 不入 git。去重通过 ② 线上实时查询保证;后端 `strSn` 字段有唯一约束,并发场景下第二次创建会被服务端跳过,Skill 视为成功。
|
|
129
102
|
|
|
130
|
-
#### Step 3:Pre-flight
|
|
103
|
+
#### Step 3:Pre-flight 输出待新建清单,等待确认
|
|
131
104
|
|
|
132
105
|
```
|
|
133
106
|
📋 待同步字典清单:
|
|
134
107
|
新建:ORDER_STATUS(订单状态)— 含 4 项
|
|
135
108
|
新建:SALES_COMPANY(销售公司)— 含 3 项
|
|
136
109
|
跳过(线上已有):PRODUCT_SEGMENT
|
|
137
|
-
|
|
138
110
|
确认执行?(yes/no)
|
|
139
111
|
```
|
|
140
112
|
|
|
141
|
-
#### Step 4
|
|
113
|
+
#### Step 4:批量创建字典码 + 字典项
|
|
142
114
|
|
|
143
|
-
|
|
144
|
-
POST {gatewayPath}/system/business/dict/save
|
|
145
|
-
Headers: Authorization / Sysappno / Content-Type
|
|
115
|
+
调用 MCP 工具 `wls_dict_upsert`(**逐个字典模块**调一次):
|
|
146
116
|
|
|
147
|
-
|
|
117
|
+
```jsonc
|
|
118
|
+
// MCP 工具入参
|
|
148
119
|
{
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
120
|
+
"module": {
|
|
121
|
+
"strSn": "ORDER_STATUS",
|
|
122
|
+
"strName": "订单状态",
|
|
123
|
+
"sortPriority": "1",
|
|
124
|
+
"strLevel": 2
|
|
125
|
+
},
|
|
126
|
+
"items": [
|
|
127
|
+
{ "strSn": "0", "strName": "草稿", "strLevel": 2 },
|
|
128
|
+
{ "strSn": "1", "strName": "待审核", "strLevel": 2 },
|
|
129
|
+
{ "strSn": "2", "strName": "已通过", "strLevel": 2 },
|
|
130
|
+
{ "strSn": "3", "strName": "已驳回", "strLevel": 2 }
|
|
131
|
+
]
|
|
154
132
|
}
|
|
155
133
|
```
|
|
156
134
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
#### Step 5:创建字典项
|
|
160
|
-
|
|
161
|
-
**逐条**调用(服务端会跳过重复的 strKey):
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
POST {gatewayPath}/system/dictDtl/save
|
|
165
|
-
Headers: Authorization / Sysappno / Content-Type
|
|
166
|
-
|
|
167
|
-
Body:
|
|
168
|
-
{
|
|
169
|
-
"strKey": "1",
|
|
170
|
-
"strValue": "待审核",
|
|
171
|
-
"strSn": "ORDER_STATUS",
|
|
172
|
-
"dictId": "{上一步获取的字典 id}"
|
|
173
|
-
}
|
|
174
|
-
```
|
|
135
|
+
> 工具内部:模块不存在则创建并自动 re-query 取 id;字典项按 strSn 自动跳过已存在项。AI 无需手动管理 id。
|
|
175
136
|
|
|
176
|
-
#### Step
|
|
137
|
+
#### Step 5:输出结果表 + 更新基线
|
|
177
138
|
|
|
178
139
|
| 字典码 | 字典名称 | 字典项数 | 状态 |
|
|
179
|
-
|
|
140
|
+
|---|---|---|---|
|
|
180
141
|
| ORDER_STATUS | 订单状态 | 4 | ✅ created |
|
|
181
142
|
| SALES_COMPANY | 销售公司 | 3 | ✅ created |
|
|
182
143
|
| PRODUCT_SEGMENT | 产品板块 | - | ⏭️ skipped(线上已有) |
|
|
183
144
|
|
|
184
|
-
执行完成后,将新建字典追加写入
|
|
145
|
+
执行完成后,将新建字典追加写入 `.github/reports/SYS_DICT_INFO.md`。
|
|
185
146
|
|
|
186
147
|
---
|
|
187
148
|
|
|
188
|
-
### audit —
|
|
149
|
+
### audit — 仅检查,不调写接口
|
|
189
150
|
|
|
190
151
|
**触发词**:`字典审计` / `检查字典`
|
|
191
152
|
|
|
192
153
|
```
|
|
193
154
|
1. 扫描指定范围的 data.ts,收集所有 logicValue 字典码
|
|
194
|
-
2.
|
|
195
|
-
3.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
155
|
+
2. 调用 wls_dict_query 获取线上现状
|
|
156
|
+
3. 对比 SYS_DICT_INFO.md 本地基线
|
|
157
|
+
4. 输出三类清单:
|
|
158
|
+
✅ 已在基线 + 线上(健康)
|
|
159
|
+
⚠️ data.ts 用到但缺失(建议执行 push)
|
|
160
|
+
💤 在基线但未被任何 data.ts 引用(可能已废弃)
|
|
161
|
+
5. 不调用任何写接口
|
|
200
162
|
```
|
|
201
163
|
|
|
202
164
|
---
|
|
@@ -208,244 +170,39 @@ Body:
|
|
|
208
170
|
```markdown
|
|
209
171
|
## ORDER_STATUS(订单状态)
|
|
210
172
|
|
|
211
|
-
| 值(
|
|
212
|
-
|
|
|
213
|
-
| 0
|
|
214
|
-
| 1
|
|
215
|
-
| 2
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
**字典码命名规范**:全大写 + 下划线,如 `ORDER_STATUS` / `SALES_COMPANY`(来自项目实际 data.ts 用法)。
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## 与其他 Skill 联动
|
|
223
|
-
|
|
224
|
-
| Skill | 联动方式 |
|
|
225
|
-
|-------|---------|
|
|
226
|
-
| **page-codegen** | 生成 data.ts 时,如 `logicValue` 不在基线中,报告末尾提示"建议运行 dict-sync 补齐" |
|
|
227
|
-
| **convention-audit** | 可调用 audit 模式,"字典码未在基线"列为 🟡 偏差 |
|
|
228
|
-
| **menu-sync** | 共享 `skills/sync/env.local.json`,gatewayPath / token / sysAppNo 同一份配置 |
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
# Skill: 字典同步(dict-sync)
|
|
232
|
-
|
|
233
|
-
将 `data.ts` 中引用的数据字典(`logicType: BusLogicDataType.dict`)同步到后端字典表,保持本地基线与线上一致。
|
|
234
|
-
|
|
235
|
-
> **与 menu-sync 的关系**:机制完全对称——同样读取本地基线报告 → 与线上对比 → 补齐差异。
|
|
236
|
-
> 配置直接复用 `menu-sync/env/env.local.json`,无需重复填写。
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
## ⚠️ 激活前请确认 3 个 API 端点
|
|
241
|
-
|
|
242
|
-
在开始使用本 Skill 前,请与后端团队核实以下 3 个接口路径,并将正确路径填入本文件对应位置(搜索 `TODO_CONFIRM`):
|
|
243
|
-
|
|
244
|
-
| # | 用途 | 草稿路径(待确认) | 确认方式 |
|
|
245
|
-
|---|------|--------------------|---------|
|
|
246
|
-
| 1 | 查询全量字典列表(去重用) | `GET /system/dict/list` | DevTools → 进入"数据字典"列表页 → 查看 Network |
|
|
247
|
-
| 2 | 创建/更新单个字典码 | `POST /system/dict/save` | DevTools → 新增一条字典 → 查看 Request URL + Body |
|
|
248
|
-
| 3 | 批量保存字典项(value/label) | `POST /system/dictItem/save` | DevTools → 为字典添加项 → 查看 Request URL + Body |
|
|
249
|
-
|
|
250
|
-
确认完成后,删除此区块即可正式使用。
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
## 配置(复用 menu-sync,无需重复填写)
|
|
255
|
-
|
|
256
|
-
本 Skill 读取顺序:
|
|
257
|
-
|
|
258
|
-
1. 优先读取 `skills/sync/dict-sync/env/env.local.json`(如存在)
|
|
259
|
-
2. 回落到 `skills/sync/menu-sync/env/env.local.json`(_inherit 机制)
|
|
260
|
-
|
|
261
|
-
**绝大多数情况下无需单独创建字典配置**——menu-sync 配置的 `gatewayPath`、`token`、`sysAppNo` 完全共用。
|
|
262
|
-
|
|
263
|
-
仅当字典接口需要独立 token 或不同网关时,才在 `dict-sync/env/env.local.json` 单独配置:
|
|
264
|
-
|
|
265
|
-
```json
|
|
266
|
-
{
|
|
267
|
-
"gatewayPath": "http://网关地址:端口",
|
|
268
|
-
"sysAppNo": "应用编码",
|
|
269
|
-
"token": "Bearer Token(不含 bearer 前缀)"
|
|
270
|
-
}
|
|
173
|
+
| 值(strSn) | 显示名称(strName) | 备注 |
|
|
174
|
+
| ---------- | ------------------ | ---- |
|
|
175
|
+
| 0 | 草稿 | |
|
|
176
|
+
| 1 | 待审核 | |
|
|
177
|
+
| 2 | 已通过 | |
|
|
178
|
+
| 3 | 已驳回 | |
|
|
271
179
|
```
|
|
272
180
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
## Pre-flight 声明(执行前必须输出)
|
|
276
|
-
|
|
277
|
-
```
|
|
278
|
-
🚀 已触发技能 dict-sync/SKILL.md → 字典同步
|
|
279
|
-
✅ 已读取 menu-sync/env/env.local.json → 网关地址、token、sysAppNo
|
|
280
|
-
✅ 已读取 reports/SYS_DICT_INFO.md → 本地字典基线
|
|
281
|
-
✅ 操作模式:{pull / push / audit}
|
|
282
|
-
✅ 目标字典码:{用户指定 / 从 data.ts 扫描到的字典码列表}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
---
|
|
286
|
-
|
|
287
|
-
## SYS_DICT_INFO.md — 本地基线格式
|
|
288
|
-
|
|
289
|
-
路径:`.github/reports/SYS_DICT_INFO.md`
|
|
290
|
-
|
|
291
|
-
写入规范(每次 pull 后覆盖更新,push 后追加):
|
|
292
|
-
|
|
293
|
-
```markdown
|
|
294
|
-
## {DICT_CODE}({字典中文名})
|
|
295
|
-
|
|
296
|
-
| 值(value) | 显示名称(label) | 排序 | 备注 |
|
|
297
|
-
| ---------- | ---------------- | ---- | ---- |
|
|
298
|
-
| 0 | 草稿 | 1 | |
|
|
299
|
-
| 1 | 待审核 | 2 | |
|
|
300
|
-
| 2 | 审核通过 | 3 | |
|
|
301
|
-
| 3 | 已驳回 | 4 | |
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
**字典码命名规范**(来自项目 data.ts 分析):
|
|
305
|
-
|
|
306
|
-
| 风格 | 正确 ✅ | 错误 ❌ |
|
|
307
|
-
|------|---------|---------|
|
|
308
|
-
| 全大写+下划线 | `ORDER_STATUS` / `SALES_COMPANY` | `orderStatus` / `salesCompany` |
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
## 三种工作模式
|
|
313
|
-
|
|
314
|
-
### pull — 刷新本地基线
|
|
315
|
-
|
|
316
|
-
**触发词**:`刷新字典基线` / `拉字典`
|
|
317
|
-
|
|
318
|
-
```
|
|
319
|
-
1. 调用 GET {TODO_CONFIRM: /system/dict/list?size=500} → 获取全量字典
|
|
320
|
-
2. 整理为 SYS_DICT_INFO.md 格式
|
|
321
|
-
3. 覆盖写入 reports/SYS_DICT_INFO.md
|
|
322
|
-
4. 输出:共拉取 N 个字典码,M 个字典项
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
**接口调用**:
|
|
326
|
-
```
|
|
327
|
-
GET {gatewayPath}/system/dict/list?current=1&size=500 ← TODO_CONFIRM 路径
|
|
328
|
-
Headers:
|
|
329
|
-
authorization: bearer {token}
|
|
330
|
-
Sysappno: {sysAppNo}
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
**响应处理**:取 `data.records`(或 `data.list`,以实际为准),`code === 2000` 为成功。
|
|
334
|
-
|
|
335
|
-
---
|
|
336
|
-
|
|
337
|
-
### push — 推送新增字典(核心模式)
|
|
338
|
-
|
|
339
|
-
**触发词**:`同步字典` / `创建字典` / `补字典`
|
|
340
|
-
|
|
341
|
-
#### Step 1:扫描当前 data.ts 中的字典引用
|
|
342
|
-
|
|
343
|
-
从用户指定范围(单文件 / 整个 src/views/)扫描所有:
|
|
344
|
-
```typescript
|
|
345
|
-
logicType: BusLogicDataType.dict, logicValue: "DICT_CODE"
|
|
346
|
-
```
|
|
347
|
-
收集所有 `logicValue` 值,去重后得到「当前用到的字典码集合」。
|
|
348
|
-
|
|
349
|
-
#### Step 2:与本地基线对比
|
|
350
|
-
|
|
351
|
-
读取 `reports/SYS_DICT_INFO.md`,找出「未在基线中的字典码」(即需要新建的字典)。
|
|
352
|
-
|
|
353
|
-
> 若本地基线为空或过期,提示用户先执行 `pull` 模式拉取基线。
|
|
354
|
-
|
|
355
|
-
#### Step 3:Pre-flight 输出待新建清单
|
|
356
|
-
|
|
357
|
-
在执行任何 API 调用前,输出:
|
|
358
|
-
|
|
359
|
-
```
|
|
360
|
-
📋 待同步字典清单:
|
|
361
|
-
新建字典码:ORDER_STATUS(订单状态)— 含 4 个字典项
|
|
362
|
-
新建字典码:SALES_COMPANY(销售公司)— 含 3 个字典项
|
|
363
|
-
跳过(已在基线中):PRODUCT_SEGMENT
|
|
364
|
-
|
|
365
|
-
确认执行?(yes/no)
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
等待用户确认后再执行。
|
|
369
|
-
|
|
370
|
-
#### Step 4:逐条创建字典码
|
|
371
|
-
|
|
372
|
-
```
|
|
373
|
-
POST {gatewayPath}/system/dict/save ← TODO_CONFIRM 路径
|
|
374
|
-
Headers:
|
|
375
|
-
authorization: bearer {token}
|
|
376
|
-
Sysappno: {sysAppNo}
|
|
377
|
-
Content-Type: application/json
|
|
378
|
-
|
|
379
|
-
Body(待确认字段名):
|
|
380
|
-
{
|
|
381
|
-
"dictCode": "ORDER_STATUS",
|
|
382
|
-
"dictName": "订单状态",
|
|
383
|
-
"remark": ""
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
#### Step 5:批量写入字典项
|
|
388
|
-
|
|
389
|
-
```
|
|
390
|
-
POST {gatewayPath}/system/dictItem/save ← TODO_CONFIRM 路径
|
|
391
|
-
Headers:
|
|
392
|
-
authorization: bearer {token}
|
|
393
|
-
Sysappno: {sysAppNo}
|
|
394
|
-
Content-Type: application/json
|
|
395
|
-
|
|
396
|
-
Body(待确认字段名,按实际接口响应调整):
|
|
397
|
-
{
|
|
398
|
-
"dictCode": "ORDER_STATUS",
|
|
399
|
-
"items": [
|
|
400
|
-
{ "dictItemValue": "0", "dictItemLabel": "草稿", "sortNo": 1 },
|
|
401
|
-
{ "dictItemValue": "1", "dictItemLabel": "待审核", "sortNo": 2 }
|
|
402
|
-
]
|
|
403
|
-
}
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
#### Step 6:输出结果表
|
|
407
|
-
|
|
408
|
-
| 字典码 | 字典名称 | 字典项数 | 状态 |
|
|
409
|
-
|--------|---------|---------|------|
|
|
410
|
-
| ORDER_STATUS | 订单状态 | 4 | ✅ created |
|
|
411
|
-
| SALES_COMPANY | 销售公司 | 3 | ✅ created |
|
|
412
|
-
| PRODUCT_SEGMENT | 产品板块 | 5 | ⏭️ skipped(已存在) |
|
|
413
|
-
|
|
414
|
-
执行完成后,将新建字典追加写入 `reports/SYS_DICT_INFO.md`。
|
|
415
|
-
|
|
416
|
-
---
|
|
417
|
-
|
|
418
|
-
### audit — 仅检查,不调接口
|
|
419
|
-
|
|
420
|
-
**触发词**:`字典审计` / `检查字典`
|
|
421
|
-
|
|
422
|
-
```
|
|
423
|
-
1. 扫描指定范围的 data.ts,收集所有 logicValue 字典码
|
|
424
|
-
2. 与 SYS_DICT_INFO.md 基线对比
|
|
425
|
-
3. 输出三个清单:
|
|
426
|
-
✅ 已在基线中(无需操作)
|
|
427
|
-
⚠️ 在 data.ts 中使用但不在基线中(建议执行 push)
|
|
428
|
-
💤 在基线中但未被任何 data.ts 使用(可能已废弃)
|
|
429
|
-
4. 不调用任何接口
|
|
430
|
-
```
|
|
181
|
+
**字典码命名规范**:全大写 + 下划线,如 `ORDER_STATUS` / `SALES_COMPANY`。
|
|
431
182
|
|
|
432
183
|
---
|
|
433
184
|
|
|
434
185
|
## 冲突处理原则
|
|
435
186
|
|
|
436
187
|
| 场景 | 策略 |
|
|
437
|
-
|
|
438
|
-
|
|
|
439
|
-
|
|
|
440
|
-
| 字典项
|
|
441
|
-
|
|
|
188
|
+
|---|---|
|
|
189
|
+
| 本地新增、线上不存在 | 调 `wls_dict_upsert` 创建 |
|
|
190
|
+
| 字典码已存在、字典名不同 | 询问用户:以本地为准 / 保留线上 / 跳过 |
|
|
191
|
+
| 字典项 strSn 相同、strName 不同 | 询问用户决定(Skill 默认跳过,不覆盖) |
|
|
192
|
+
| 线上存在、本地无记录 | 仅在 audit 中报告,**绝不主动删除** |
|
|
442
193
|
|
|
443
194
|
---
|
|
444
195
|
|
|
445
196
|
## 与其他 Skill 联动
|
|
446
197
|
|
|
447
198
|
| Skill | 联动方式 |
|
|
448
|
-
|
|
449
|
-
| **page-codegen** | 生成 data.ts
|
|
450
|
-
| **convention-audit** |
|
|
451
|
-
| **menu-sync** | 共享 env.local.json
|
|
199
|
+
|---|---|
|
|
200
|
+
| **page-codegen** | 生成 data.ts 时如 `logicValue` 不在基线中,报告末尾提示"建议运行 dict-sync 补齐" |
|
|
201
|
+
| **convention-audit** | 调用 audit 模式,"字典码未在基线"列为 🟡 偏差 |
|
|
202
|
+
| **menu-sync / permission-sync** | 共享 `skills/sync/env.local.json`,gatewayPath / token / sysAppNo 同一份 |
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## MCP 不可用或调用失败时怎么办
|
|
207
|
+
|
|
208
|
+
见 `../_mcp-guardrail.md` §2 自愈闭环剧本。**原则**:先帮用户完善 `env.local.json` 里的 token / dict.moduleId,重试 MCP 工具。**绝不允许** AI 用 curl/PowerShell/fetch 绕开 MCP 手拼 HTTP。
|
|
@@ -69,16 +69,19 @@ SYS_MENU_INFO.md 是 menu-sync Skill 的输入数据源:
|
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
|
72
|
-
## Phase 1:
|
|
72
|
+
## Phase 1:MCP 驱动创建菜单(当前方案)
|
|
73
73
|
|
|
74
|
-
>
|
|
75
|
-
|
|
74
|
+
> 本质是 **menu-sync-design.md 的方案 C(只增不删)**,由 AI 调 MCP 工具自动执行。
|
|
75
|
+
|
|
76
|
+
> 📖 **必读公共护栏**:`../_mcp-guardrail.md`
|
|
77
|
+
> 该文件定义了 MCP 调用纪律、错误分层判定、自愈闭环剧本。AI 首次执行 sync 类任务时必须先 `read_file` 加载它。
|
|
78
|
+
>
|
|
79
|
+
> 本 Skill 使用的 MCP 工具:`wls_menu_sync_from_report` / `wls_menu_query` / `wls_menu_upsert`。工具不可用或调用失败时,按 guardrail §2 剧本引导用户完善 `env.local.json` 后重试,**不得用 curl/手拼 HTTP 绕开 MCP**。
|
|
76
80
|
|
|
77
81
|
### 前置条件
|
|
78
82
|
|
|
79
|
-
1.
|
|
80
|
-
2.
|
|
81
|
-
3. 用户提供父级菜单 ID(`menuId`),可通过查询接口获取
|
|
83
|
+
1. MCP 已连接(工具列表中可见 `wls_menu_sync_from_report`)
|
|
84
|
+
2. `.github/skills/sync/env.local.json` 已填写 `token`(纯 JWT,不含 `bearer ` 前缀)、`gatewayPath`、`sysAppNo`、`menu.parentMenuId`、`menu.domainId`
|
|
82
85
|
|
|
83
86
|
### 输入
|
|
84
87
|
|
|
@@ -96,45 +99,47 @@ SYS_MENU_INFO.md 是 menu-sync Skill 的输入数据源:
|
|
|
96
99
|
| `C` | 菜单(页面) | `menuName`, `path`, `permission`, `component` |
|
|
97
100
|
| `A` | 动作按钮 | `menuName`, `path` |
|
|
98
101
|
|
|
99
|
-
###
|
|
102
|
+
### 执行流程(首选:一步到位)
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
**默认走 `wls_menu_sync_from_report`**——它内部完成「读报告 → 查菜单树 → 一级目录 upsert → 二级菜单 upsert」全流程:
|
|
102
105
|
|
|
103
106
|
```
|
|
104
|
-
工具:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
工具:wls_menu_sync_from_report
|
|
108
|
+
入参:{ dryRun?: boolean, reportPath?: string } // 不传 reportPath 自动用最新 SYS_MENU_INFO*.md
|
|
109
|
+
第一次执行:先传 dryRun: true 预览,确认无误后再正式执行(去掉 dryRun)
|
|
107
110
|
```
|
|
108
111
|
|
|
109
|
-
|
|
112
|
+
### 手动拆分流程(仅当一步式不满足时)
|
|
110
113
|
|
|
111
|
-
#### Step
|
|
112
|
-
|
|
113
|
-
对于 `SYS_MENU_INFO` 中的一级目录,按 `menuName/path` 在父级 `parentMenuId` 下去重;不存在则创建,存在则复用 id。
|
|
114
|
+
#### Step 1: 查询当前 domain 菜单树(防重复 + 取父级信息)
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
```
|
|
117
|
+
工具:wls_menu_query (无参,自动读 env.local.json → menu.domainId)
|
|
118
|
+
返回:当前应用域完整菜单树
|
|
119
|
+
```
|
|
116
120
|
|
|
117
|
-
|
|
121
|
+
#### Step 2: 先创建一级目录(type=M),再创建二级页面菜单(type=C)
|
|
118
122
|
|
|
119
|
-
|
|
123
|
+
- 一级目录按 `menuName/path` 在父级 `parentMenuId` 下去重;不存在则创建,存在则复用 id
|
|
124
|
+
- 二级页面菜单的 `parentId` 必须是上一步对应目录的 id,**禁止**全部挂到根 `parentMenuId`
|
|
120
125
|
|
|
121
126
|
```
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
Sysappno: {sysAppNo}
|
|
126
|
-
Content-Type: application/json
|
|
127
|
+
工具:wls_menu_upsert
|
|
128
|
+
入参:{ items: [<下面的对象>...] }
|
|
129
|
+
```
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
**`items[]` 单条对象模板(仅作为 MCP 入参参考,禁止 AI 自行 fetch)**:
|
|
132
|
+
|
|
133
|
+
```jsonc
|
|
129
134
|
{
|
|
130
135
|
"useCache": 1,
|
|
131
136
|
"icon": "list",
|
|
132
137
|
"common": 2,
|
|
133
138
|
"hidden": false,
|
|
134
|
-
"type": "C",
|
|
135
|
-
"parentId": "{
|
|
139
|
+
"type": "C", // "M"=目录, "C"=菜单, "A"=动作
|
|
140
|
+
"parentId": "{父级目录的 id}",
|
|
136
141
|
"sysAppNo": "{sysAppNo}",
|
|
137
|
-
"orderNum":
|
|
142
|
+
"orderNum": 1,
|
|
138
143
|
"menuName": "客户档案",
|
|
139
144
|
"menuNameCode": "{parentMenuNameCode}:{pinyinName}",
|
|
140
145
|
"path": "mmwrCustomerArchive",
|
|
@@ -143,6 +148,8 @@ Body:
|
|
|
143
148
|
}
|
|
144
149
|
```
|
|
145
150
|
|
|
151
|
+
> **MCP 内部说明**(AI 不可据此自行调接口):底层走 `POST /system/menu/save`,成功码 `code: 2000`。
|
|
152
|
+
|
|
146
153
|
#### Step 3: 记录结果
|
|
147
154
|
|
|
148
155
|
创建完成后输出结果表格:
|
|
@@ -31,18 +31,22 @@
|
|
|
31
31
|
|
|
32
32
|
## 前置条件
|
|
33
33
|
|
|
34
|
-
`.github/skills/sync/
|
|
34
|
+
`.github/skills/sync/env.local.json`(首次使用先填写,已加入 `.gitignore`):
|
|
35
35
|
|
|
36
36
|
```json
|
|
37
37
|
{
|
|
38
|
-
"gatewayPath": "
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
38
|
+
"gatewayPath": "http://192.168.10.50:9000",
|
|
39
|
+
"sysAppNo": "应用编码(非明文,从已有菜单接口响应获取)",
|
|
40
|
+
"token": "eyJhbGci...(纯 JWT,不含 bearer 前缀)",
|
|
41
|
+
"menu": {
|
|
42
|
+
"parentMenuId": "父级菜单 ID(菜单管理后台获取)",
|
|
43
|
+
"domainId": "应用域 ID(Network 面板 getMenuTreeByDomainId?domainId=xxx 获取)"
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
> **`env.local.json` 不入 git
|
|
48
|
+
> **`env.local.json` 不入 git**。每个开发者本地填自己的 token(更新 token 时只换 token 字段,其他不动)。
|
|
49
|
+
> 字段获取详见 `env/guide.md`。
|
|
46
50
|
|
|
47
51
|
---
|
|
48
52
|
|
|
@@ -54,11 +58,11 @@ AI:[Pre-flight]
|
|
|
54
58
|
步骤 1:读取线上菜单基线 reports/SYS_MENU_INFO.md(最新更新:2025-04-20)
|
|
55
59
|
步骤 2:扫描 src/views/produce/aiflow/ 共 7 个页面
|
|
56
60
|
步骤 3:对比缺失:5 项缺失,2 项已存在
|
|
57
|
-
步骤 4:将调用
|
|
61
|
+
步骤 4:将调用 wls_menu_sync_from_report 创建 5 项
|
|
58
62
|
[需你确认]:
|
|
59
|
-
- 父菜单:精整作业 → 客户管理(
|
|
60
|
-
- 排序:
|
|
61
|
-
- 权限标识:
|
|
63
|
+
- 父菜单:精整作业 → 客户管理(menu.parentMenuId: xxx)
|
|
64
|
+
- 排序:orderNum 自动递增
|
|
65
|
+
- 权限标识:mmwrCustomerArchive 等
|
|
62
66
|
确认 yes/no?
|
|
63
67
|
```
|
|
64
68
|
|
|
@@ -78,8 +82,10 @@ AI:[Pre-flight]
|
|
|
78
82
|
| -------------------- | ---------------------------- | ---------------------------------------------- |
|
|
79
83
|
| 同步成功但 UI 看不到 | 用户角色没分配新菜单 | 跑 permission-sync(PLANNED)或后台手工分配 |
|
|
80
84
|
| 401/403 报错 | env.local.json 的 token 过期 | 重新登录系统,从 Network 抓 Authorization 替换 |
|
|
85
|
+
| AI 用 curl/Invoke-RestMethod 调接口,返回 4004 | AI 没走 MCP,自行拼接了错误的接口路径 | 确认 MCP 已连接(Cursor/Kiro 设置里可见 wls_menu_sync_from_report),然后重新说「帮我同步菜单」|
|
|
86
|
+
| token 填了 `Bearer eyJ...` 整串,接口 401 | Authorization Header 变成 `Bearer Bearer eyJ...` | token 字段只填 `eyJ...` 纯 JWT 部分,去掉 `bearer ` 前缀 |
|
|
81
87
|
| 同名菜单重复创建 | 没读 SYS_MENU_INFO.md 基线 | 先跑一遍"刷新基线"再 sync |
|
|
82
|
-
| 父菜单 ID 不对 |
|
|
88
|
+
| 父菜单 ID 不对 | menu.parentMenuId 配错 | 从菜单后台编辑页复制菜单 ID,填入 env.local.json |
|
|
83
89
|
|
|
84
90
|
---
|
|
85
91
|
|