@agile-team/wl-skills-kit 2.3.4 → 2.3.6

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 (96) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +16 -10
  3. package/files/.cursor/mcp.json +8 -8
  4. package/files/.github/guides/README.md +13 -13
  5. package/files/.github/guides/architecture.md +555 -555
  6. package/files/.github/guides/mcp-setup.md +109 -109
  7. package/files/.github/guides/usage.md +184 -184
  8. package/files/.github/reports/README.md +65 -65
  9. package/files/.github/reports/SYS_DICT_INFO.md +50 -50
  10. package/files/.github/reports/SYS_MENU_INFO.md +247 -247
  11. package/files/.github/reports/SYS_PERMISSION_INFO.md +20 -20
  12. 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
  13. 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
  14. package/files/.github/skills/_compat/README.md +108 -108
  15. package/files/.github/skills/_compat/headers/agents.txt +8 -8
  16. package/files/.github/skills/_compat/headers/claude-code.txt +7 -7
  17. package/files/.github/skills/_compat/headers/cline.txt +7 -7
  18. package/files/.github/skills/_compat/headers/cursor-mdc.txt +16 -16
  19. package/files/.github/skills/_compat/headers/cursor-rules.txt +7 -7
  20. package/files/.github/skills/_compat/headers/github-copilot.txt +1 -1
  21. package/files/.github/skills/_compat/headers/kiro.txt +10 -10
  22. package/files/.github/skills/_compat/headers/qoder.txt +8 -8
  23. package/files/.github/skills/_compat/headers/trae.txt +11 -11
  24. package/files/.github/skills/_compat/headers/windsurf.txt +7 -7
  25. package/files/.github/skills/_registry.md +81 -81
  26. package/files/.github/skills/core/api-contract/SKILL.md +344 -344
  27. package/files/.github/skills/core/api-contract/USAGE.md +110 -110
  28. package/files/.github/skills/core/convention-audit/SKILL.md +189 -189
  29. package/files/.github/skills/core/convention-audit/USAGE.md +99 -99
  30. package/files/.github/skills/core/page-codegen/SKILL.md +973 -973
  31. package/files/.github/skills/core/page-codegen/USAGE.md +102 -102
  32. package/files/.github/skills/core/page-codegen/templates/_index.md +46 -46
  33. package/files/.github/skills/core/page-codegen/templates/domains/_CONTRIBUTING.md +107 -107
  34. package/files/.github/skills/core/page-codegen/templates/domains/produce/TPL-OPERATION-STATION.md +442 -442
  35. package/files/.github/skills/core/page-codegen/templates/domains/sale/README.md +26 -26
  36. package/files/.github/skills/core/page-codegen/templates/universal/TPL-CHANGE-HISTORY.md +276 -276
  37. package/files/.github/skills/core/page-codegen/templates/universal/TPL-DETAIL-TABS.md +1145 -1145
  38. package/files/.github/skills/core/page-codegen/templates/universal/TPL-DRIVEN.md +309 -309
  39. package/files/.github/skills/core/page-codegen/templates/universal/TPL-FORM-ROUTE.md +436 -436
  40. package/files/.github/skills/core/page-codegen/templates/universal/TPL-LIST.md +191 -191
  41. package/files/.github/skills/core/page-codegen/templates/universal/TPL-MASTER-DETAIL.md +148 -148
  42. package/files/.github/skills/core/page-codegen/templates/universal/TPL-RECORD-FORM.md +376 -376
  43. package/files/.github/skills/core/page-codegen/templates/universal/TPL-TREE-LIST.md +186 -186
  44. package/files/.github/skills/core/prototype-scan/SKILL.md +498 -498
  45. package/files/.github/skills/core/prototype-scan/USAGE.md +95 -95
  46. package/files/.github/skills/core/template-extract/SKILL.md +139 -139
  47. package/files/.github/skills/core/template-extract/USAGE.md +93 -93
  48. package/files/.github/skills/domain/README.md +51 -51
  49. package/files/.github/skills/sync/env.local.json +0 -5
  50. package/files/.github/skills/sync/menu-sync/SKILL.md +263 -263
  51. package/files/.github/skills/sync/menu-sync/USAGE.md +104 -104
  52. package/files/.github/skills/sync/menu-sync/env/env.local.json +7 -7
  53. package/files/.github/skills/sync/menu-sync/env/guide.md +99 -99
  54. package/files/.github/skills/sync/permission-sync/SKILL.md +239 -0
  55. package/files/.github/skills/sync/permission-sync/USAGE.md +93 -0
  56. package/files/.github/standards/01-toolchain.md +57 -57
  57. package/files/.github/standards/02-code-structure.md +111 -111
  58. package/files/.github/standards/03-comments.md +53 -53
  59. package/files/.github/standards/04-coding-basics.md +33 -33
  60. package/files/.github/standards/05-logging.md +38 -38
  61. package/files/.github/standards/06-security.md +44 -44
  62. package/files/.github/standards/07-config.md +52 -52
  63. package/files/.github/standards/08-git.md +60 -60
  64. package/files/.github/standards/09-typescript.md +71 -71
  65. package/files/.github/standards/10-pinia.md +57 -57
  66. package/files/.github/standards/11-form-validation.md +81 -81
  67. package/files/.github/standards/12-base-table.md +153 -153
  68. package/files/.github/standards/13-platform-components.md +123 -123
  69. package/files/.github/standards/index.md +89 -89
  70. package/files/.kiro/settings/mcp.json +8 -8
  71. package/files/.mcp.json +8 -8
  72. package/files/.vscode/mcp.json +9 -9
  73. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/data.ts +196 -196
  74. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.scss +150 -150
  75. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.vue +79 -79
  76. package/files/docs/jh-date-range.md +257 -257
  77. package/files/docs/jh-date.md +222 -222
  78. package/files/docs/jh-dept-picker.md +190 -190
  79. package/files/docs/jh-drag-row.md +590 -590
  80. package/files/docs/jh-file-upload.md +216 -216
  81. package/files/docs/jh-picker.md +218 -218
  82. package/files/docs/jh-select.md +148 -148
  83. package/files/docs/jh-text.md +248 -248
  84. package/files/docs/jh-user-picker.md +197 -197
  85. package/files/src/components/global/C_RightToolbar/data.ts +228 -228
  86. package/files/src/components/global/C_RightToolbar/index.scss +44 -44
  87. package/files/src/components/global/C_Splitter/index.scss +61 -61
  88. package/files/src/components/global/C_SvgIcon/index.scss +15 -15
  89. package/files/src/components/global/C_TagStatus/index.scss +20 -20
  90. package/files/src/components/global/C_Tree/data.ts +61 -61
  91. package/files/src/components/local/c_listModal/index.scss +4 -4
  92. package/mcp/api/roleApi.js +60 -0
  93. package/mcp/server.js +125 -5
  94. package/mcp/tools/permissionSync.js +321 -0
  95. package/package.json +1 -1
  96. package/files/.github/skills/sync/permission-sync/SKILL.draft.md +0 -91
@@ -0,0 +1,321 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ queryRoleList,
5
+ saveRole,
6
+ queryAssignableMenus,
7
+ saveRoleMenus,
8
+ queryMenuChildren,
9
+ } = require('../api/roleApi')
10
+ const { saveMenu } = require('../api/menuApi')
11
+
12
+ /* ──────────────────────────────────────────────────────────────────────
13
+ * 角色管理
14
+ * ──────────────────────────────────────────────────────────────────── */
15
+
16
+ /**
17
+ * wls_role_query 工具处理器
18
+ * 查询角色列表(仅返回字段精简后的角色摘要)
19
+ */
20
+ async function handleRoleQuery(args, config) {
21
+ const result = await queryRoleList(args || {}, config)
22
+
23
+ if (!result.ok) {
24
+ return `❌ 查询角色失败: ${result.error} (code: ${result.code})`
25
+ }
26
+
27
+ const page = result.data && result.data.page
28
+ const records = (page && page.records) || []
29
+
30
+ if (records.length === 0) {
31
+ return '✅ 角色查询成功,当前应用暂无角色数据'
32
+ }
33
+
34
+ // 仅保留关键字段,减少 token 浪费
35
+ const slim = records.map((r) => ({
36
+ id: r.id,
37
+ roleName: r.roleName,
38
+ code: r.code,
39
+ sysAppNo: r.sysAppNo,
40
+ roleDesc: r.roleDesc,
41
+ }))
42
+
43
+ return [
44
+ `✅ 角色查询成功,当前页 ${records.length} 条 / 共 ${page.total} 条(current=${page.current}, pages=${page.pages})`,
45
+ '',
46
+ JSON.stringify(slim, null, 2),
47
+ ].join('\n')
48
+ }
49
+
50
+ /**
51
+ * wls_role_upsert 工具处理器
52
+ * 批量新增角色(仅新增,不更新;以 code 字段去重)
53
+ *
54
+ * @param {{ items: Array<{ roleName: string, code: string, configDesc?: string }> }} args
55
+ */
56
+ async function handleRoleUpsert(args, config) {
57
+ const { items } = args || {}
58
+
59
+ if (!Array.isArray(items) || items.length === 0) {
60
+ return '❌ 参数错误:items 必须是非空数组'
61
+ }
62
+
63
+ // 先查全量角色,按 code 去重
64
+ const queryResult = await queryRoleList({ size: 999 }, config)
65
+ if (!queryResult.ok) {
66
+ return `❌ 查询现有角色失败: ${queryResult.error}`
67
+ }
68
+ const existingCodes = new Set(
69
+ ((queryResult.data && queryResult.data.page && queryResult.data.page.records) || [])
70
+ .map((r) => r.code)
71
+ )
72
+
73
+ const results = []
74
+
75
+ for (const item of items) {
76
+ if (!item.roleName || !item.code) {
77
+ results.push({
78
+ roleName: item.roleName || '(未命名)',
79
+ code: item.code || '(无)',
80
+ status: '❌ roleName 与 code 必填',
81
+ })
82
+ continue
83
+ }
84
+
85
+ if (existingCodes.has(item.code)) {
86
+ results.push({
87
+ roleName: item.roleName,
88
+ code: item.code,
89
+ status: '⏭ 已存在(跳过)',
90
+ })
91
+ continue
92
+ }
93
+
94
+ const body = {
95
+ roleName: item.roleName,
96
+ code: item.code,
97
+ configDesc: item.configDesc || '',
98
+ }
99
+
100
+ const r = await saveRole(body, config)
101
+ results.push({
102
+ roleName: item.roleName,
103
+ code: item.code,
104
+ status: r.ok ? '✅ 创建成功' : `❌ 失败: ${r.error}`,
105
+ })
106
+ }
107
+
108
+ return formatTable(
109
+ results,
110
+ ['roleName', 'code', 'status'],
111
+ ['角色名', 'code', '状态']
112
+ )
113
+ }
114
+
115
+ /* ──────────────────────────────────────────────────────────────────────
116
+ * 角色授权(给角色挂菜单)
117
+ * ──────────────────────────────────────────────────────────────────── */
118
+
119
+ /**
120
+ * wls_role_assign_menus 工具处理器
121
+ * 给指定角色批量分配菜单权限
122
+ *
123
+ * @param {{ roleId: string, menuIds: string[] }} args - menuIds 用数组传入,内部拼成逗号字符串
124
+ */
125
+ async function handleRoleAssignMenus(args, config) {
126
+ const { roleId, menuIds } = args || {}
127
+
128
+ if (!roleId) {
129
+ return '❌ 参数错误:roleId 必填'
130
+ }
131
+ if (!Array.isArray(menuIds) || menuIds.length === 0) {
132
+ return '❌ 参数错误:menuIds 必须是非空字符串数组'
133
+ }
134
+
135
+ const body = {
136
+ roleId,
137
+ menuIds: menuIds.join(','),
138
+ }
139
+
140
+ const r = await saveRoleMenus(body, config)
141
+ if (!r.ok) {
142
+ return `❌ 角色授权失败: ${r.error} (code: ${r.code})`
143
+ }
144
+
145
+ return `✅ 角色授权成功(roleId=${roleId},已分配 ${menuIds.length} 个菜单/动作)`
146
+ }
147
+
148
+ /**
149
+ * wls_assignable_menus_query 工具处理器
150
+ * 查询全量可授权菜单(扁平/树形由后端决定)
151
+ */
152
+ async function handleAssignableMenusQuery(_args, config) {
153
+ const r = await queryAssignableMenus(config)
154
+ if (!r.ok) {
155
+ return `❌ 查询可授权菜单失败: ${r.error} (code: ${r.code})`
156
+ }
157
+ // data 可能是 { records: [...] } 或数组
158
+ const records = (r.data && r.data.records) || (Array.isArray(r.data) ? r.data : [])
159
+ if (records.length === 0) {
160
+ return '✅ 查询成功,当前无可授权菜单'
161
+ }
162
+ return [
163
+ `✅ 可授权菜单查询成功,共 ${records.length} 条`,
164
+ '',
165
+ JSON.stringify(records, null, 2),
166
+ ].join('\n')
167
+ }
168
+
169
+ /* ──────────────────────────────────────────────────────────────────────
170
+ * 挂动作(给页面菜单加 type=A 的动作按钮)
171
+ * ──────────────────────────────────────────────────────────────────── */
172
+
173
+ /**
174
+ * wls_action_query 工具处理器
175
+ * 查询指定页面菜单下的动作子项(type=A)
176
+ *
177
+ * @param {{ menuId: string }} args
178
+ */
179
+ async function handleActionQuery(args, config) {
180
+ const { menuId } = args || {}
181
+ if (!menuId) {
182
+ return '❌ 参数错误:menuId 必填(页面菜单 id)'
183
+ }
184
+
185
+ const r = await queryMenuChildren(menuId, config)
186
+ if (!r.ok) {
187
+ return `❌ 查询子菜单失败: ${r.error} (code: ${r.code})`
188
+ }
189
+
190
+ const records = (r.data && r.data.records) || []
191
+ // 仅保留 type=A(动作)
192
+ const actions = records.filter((m) => m.type === 'A')
193
+
194
+ if (actions.length === 0) {
195
+ return `✅ 查询成功,菜单 ${menuId} 下暂无动作(type=A)`
196
+ }
197
+
198
+ const slim = actions.map((a) => ({
199
+ id: a.id,
200
+ menuName: a.menuName,
201
+ permission: a.permission,
202
+ orderNum: a.orderNum,
203
+ icon: a.icon,
204
+ }))
205
+
206
+ return [
207
+ `✅ 动作查询成功,共 ${actions.length} 条`,
208
+ '',
209
+ JSON.stringify(slim, null, 2),
210
+ ].join('\n')
211
+ }
212
+
213
+ /**
214
+ * wls_action_upsert 工具处理器
215
+ * 在指定页面菜单下批量新增动作(type=A),按 permission 去重
216
+ *
217
+ * @param {{ parentId: string, items: Array<object> }} args
218
+ * items 元素:{ menuName, permission, icon?, orderNum?, useCache? }
219
+ */
220
+ async function handleActionUpsert(args, config) {
221
+ const { parentId, items } = args || {}
222
+
223
+ if (!parentId) {
224
+ return '❌ 参数错误:parentId 必填(页面菜单 id)'
225
+ }
226
+ if (!Array.isArray(items) || items.length === 0) {
227
+ return '❌ 参数错误:items 必须是非空数组'
228
+ }
229
+
230
+ // 先查父菜单下已有动作,按 permission 去重
231
+ const queryResult = await queryMenuChildren(parentId, config)
232
+ if (!queryResult.ok) {
233
+ return `❌ 查询现有动作失败: ${queryResult.error}`
234
+ }
235
+ const existing = ((queryResult.data && queryResult.data.records) || [])
236
+ .filter((m) => m.type === 'A')
237
+ const existingPerms = new Set(existing.map((m) => m.permission))
238
+
239
+ const results = []
240
+
241
+ for (const item of items) {
242
+ if (!item.menuName || !item.permission) {
243
+ results.push({
244
+ menuName: item.menuName || '(未命名)',
245
+ permission: item.permission || '(无)',
246
+ status: '❌ menuName 与 permission 必填',
247
+ })
248
+ continue
249
+ }
250
+
251
+ if (existingPerms.has(item.permission)) {
252
+ results.push({
253
+ menuName: item.menuName,
254
+ permission: item.permission,
255
+ status: '⏭ 已存在(跳过)',
256
+ })
257
+ continue
258
+ }
259
+
260
+ const body = {
261
+ parentId,
262
+ type: 'A',
263
+ menuName: item.menuName,
264
+ permission: item.permission,
265
+ icon: item.icon || 'list',
266
+ orderNum: item.orderNum != null ? item.orderNum : 1,
267
+ useCache: item.useCache != null ? item.useCache : 1,
268
+ sysAppNo: config.sysAppNo,
269
+ intIsActive: 1,
270
+ }
271
+
272
+ const r = await saveMenu(body, config)
273
+ if (r.ok) {
274
+ const saved = r.data
275
+ results.push({
276
+ menuName: item.menuName,
277
+ permission: item.permission,
278
+ status: `✅ 创建成功 (id=${saved ? saved.id : '?'})`,
279
+ })
280
+ } else {
281
+ results.push({
282
+ menuName: item.menuName,
283
+ permission: item.permission,
284
+ status: `❌ 失败: ${r.error}`,
285
+ })
286
+ }
287
+ }
288
+
289
+ return formatTable(
290
+ results,
291
+ ['menuName', 'permission', 'status'],
292
+ ['动作名', '权限码', '状态']
293
+ )
294
+ }
295
+
296
+ /* ──────────────────────────────────────────────────────────────────────
297
+ * 工具函数
298
+ * ──────────────────────────────────────────────────────────────────── */
299
+
300
+ function formatTable(rows, keys, headers) {
301
+ const successCount = rows.filter((r) => r.status.startsWith('✅')).length
302
+ const skipCount = rows.filter((r) => r.status.startsWith('⏭')).length
303
+ const failCount = rows.length - successCount - skipCount
304
+
305
+ let out = `操作完成:成功 ${successCount} 条,跳过 ${skipCount} 条,失败 ${failCount} 条\n\n`
306
+ out += '| ' + headers.join(' | ') + ' |\n'
307
+ out += '|' + headers.map(() => '---').join('|') + '|\n'
308
+ for (const r of rows) {
309
+ out += '| ' + keys.map((k) => r[k]).join(' | ') + ' |\n'
310
+ }
311
+ return out
312
+ }
313
+
314
+ module.exports = {
315
+ handleRoleQuery,
316
+ handleRoleUpsert,
317
+ handleRoleAssignMenus,
318
+ handleAssignableMenusQuery,
319
+ handleActionQuery,
320
+ handleActionUpsert,
321
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agile-team/wl-skills-kit",
3
- "version": "2.3.4",
3
+ "version": "2.3.6",
4
4
  "description": "AI Skill 模板包 — 一键导入 AI 指令 + 组件文档 + 通用组件 + 领域样例,覆盖 Copilot/Cursor/Windsurf/Kiro 等主流 AI 编辑器",
5
5
  "main": "./bin/wl-skills.js",
6
6
  "bin": {
@@ -1,91 +0,0 @@
1
- ---
2
- name: permission-sync
3
- description: "[PLANNED — DRAFT, not yet active] 权限同步 Skill 设计草稿。基于 reports/SYS_PERMISSION_INFO.md 基线,将页面级/按钮级权限码注册到系统权限表,并按角色分配。"
4
- status: planned
5
- ---
6
-
7
- # Skill: 权限同步(permission-sync)— 草稿
8
-
9
- > ⚠️ **本文件为设计草稿(SKILL.draft.md),未启用,不参与 AI 调度。**
10
-
11
- ---
12
-
13
- ## 1. 设计目标
14
-
15
- 新增页面后,除菜单外还需注册:
16
-
17
- - **页面访问权限**(`mmwr:customer:list`)
18
- - **按钮级权限**(`mmwr:customer:add` / `:edit` / `:remove` / `:approve` / `:export` ...)
19
- - **数据权限**(可选:客户经理只看自己的客户等)
20
- - **角色绑定**(哪些角色获得这些权限)
21
-
22
- ---
23
-
24
- ## 2. 数据流
25
-
26
- ```
27
- 本地基线 后端接口 Skill 触发
28
- ──────────────────────────────────────── ────────────────────────────────── ────────────────
29
- reports/SYS_PERMISSION_INFO.md ─fetch─→ GET /sys/permission/listAll
30
- ←compare── POST /sys/permission/batchSave
31
- ─upload─→ POST /sys/role/assignPermissions ─→ "同步权限"
32
- ```
33
-
34
- ---
35
-
36
- ## 3. 权限码命名规范
37
-
38
- ```
39
- {服务缩写}:{资源camelCase}:{操作}
40
- ```
41
-
42
- | 操作 | 含义 | 示例 |
43
- | -------- | -------------- | ------------------------------- |
44
- | list | 查看列表 | `mmwr:customer:list` |
45
- | detail | 查看详情 | `mmwr:customer:detail` |
46
- | add | 新增 | `mmwr:customer:add` |
47
- | edit | 编辑 | `mmwr:customer:edit` |
48
- | remove | 删除 | `mmwr:customer:remove` |
49
- | export | 导出 | `mmwr:customer:export` |
50
- | import | 导入 | `mmwr:customer:import` |
51
- | submit | 提交审批 | `mmwr:customer:submit` |
52
- | approve | 审批通过 | `mmwr:customer:approve` |
53
- | reject | 审批驳回 | `mmwr:customer:reject` |
54
- | {custom} | 自定义业务操作 | `mmwr:customer:convertToFormal` |
55
-
56
- ---
57
-
58
- ## 4. 三种工作模式
59
-
60
- | 模式 | 触发 | 动作 |
61
- | ---------- | ----------------------- | ------------------------------------------------------ |
62
- | `scan` | "扫描权限码" | 从 src/views/ 扫 v-permission / hasPerm 调用,输出清单 |
63
- | `register` | "注册权限码 / 同步权限" | 对比基线 → 创建缺失 + 更新描述 |
64
- | `assign` | "给 XX 角色分配权限" | 选定角色 + 选定权限码 → 调 /sys/role/assignPermissions |
65
-
66
- ---
67
-
68
- ## 5. 安全约束
69
-
70
- - **生产环境拒绝直接 push**:检测 gatewayPath 含 prod/.com 时强制走"导出 SQL"模式
71
- - **角色分配二次确认**:每次 assign 必须在 Pre-flight 中列出"角色 → 新增/移除的权限",得到用户 yes 才执行
72
- - **不删除权限**:永远只新增/更新,删除走人工 SQL(防误删导致大面积失权)
73
- - **审计**:每次 register/assign 输出 `reports/PERMISSION_SYNC_<YYYYMMDD>.md`,含完整调用日志和回滚 SQL
74
-
75
- ---
76
-
77
- ## 6. 与其他 Skill 联动
78
-
79
- - **page-codegen**:生成 toolbar 时根据 api.md 操作集自动加 `v-permission` 指令
80
- - **menu-sync**:菜单注册后提示"是否同步注册访问权限"
81
- - **convention-audit**:审计按钮是否都有 v-permission
82
-
83
- ---
84
-
85
- ## 7. 转正前的开发任务
86
-
87
- - [ ] 确认后端权限模型(RBAC / ABAC?是否分页面权限和按钮权限?)
88
- - [ ] 数据权限是否纳入本 Skill(建议:暂不,单独 data-permission-sync)
89
- - [ ] 设计 v-permission 指令的项目内实现(如 @jhlc/common-core 提供则复用)
90
- - [ ] 多租户场景下的权限继承策略
91
- - [ ] 与 SSO(嘉为蓝鲸)权限同步策略