@agile-team/wl-skills-kit 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -22
- package/README.md +11 -103
- package/bin/wl-skills.js +2 -42
- package/files/.github/guides/README.md +13 -13
- package/files/.github/guides/architecture.md +555 -555
- package/files/.github/guides/usage.md +176 -173
- 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 +124 -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/env.local.json +2 -1
- 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/mcp/api/client.js +76 -0
- package/mcp/api/dictApi.js +40 -0
- package/mcp/api/menuApi.js +32 -0
- package/mcp/config.js +47 -0
- package/mcp/server.js +210 -0
- package/mcp/tools/dictSync.js +173 -0
- package/mcp/tools/menuSync.js +96 -0
- package/package.json +6 -9
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { queryDictModules, saveDictModule, saveDictItem } = require('../api/dictApi')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 从字典树查询响应中提取模块列表
|
|
7
|
+
* 响应结构: { dictionary: { children: DictModule[] } }
|
|
8
|
+
*
|
|
9
|
+
* @param {any} data - queryDictModules 返回的 result.data
|
|
10
|
+
* @returns {object[]}
|
|
11
|
+
*/
|
|
12
|
+
function extractModules(data) {
|
|
13
|
+
if (!data) return []
|
|
14
|
+
if (data.dictionary && Array.isArray(data.dictionary.children)) {
|
|
15
|
+
return data.dictionary.children
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(data)) return data
|
|
18
|
+
return []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* wls_dict_query 工具处理器
|
|
23
|
+
* 查询当前应用的所有字典模块及字典项
|
|
24
|
+
*
|
|
25
|
+
* @param {object} config
|
|
26
|
+
* @returns {Promise<string>}
|
|
27
|
+
*/
|
|
28
|
+
async function handleDictQuery(config) {
|
|
29
|
+
const result = await queryDictModules(config)
|
|
30
|
+
|
|
31
|
+
if (!result.ok) {
|
|
32
|
+
return `❌ 查询字典失败: ${result.error} (code: ${result.code})`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const modules = extractModules(result.data)
|
|
36
|
+
|
|
37
|
+
if (modules.length === 0) {
|
|
38
|
+
return '✅ 字典查询成功,当前应用暂无字典数据'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return `✅ 字典查询成功,共 ${modules.length} 个模块\n\n${JSON.stringify(modules, null, 2)}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* wls_dict_upsert 工具处理器
|
|
46
|
+
* 新增或更新字典模块及字典项(完整幂等流程)
|
|
47
|
+
*
|
|
48
|
+
* 流程:
|
|
49
|
+
* ① 查询现有模块,检查 strSn 是否已存在
|
|
50
|
+
* ② 若不存在:创建模块(data=null)→ 重新查询 → 用 strSn 定位拿 id
|
|
51
|
+
* ③ 若已存在:跳过模块创建,直接取已有 id
|
|
52
|
+
* ④ 遍历 items,跳过 strSn 已存在的,其余逐条创建
|
|
53
|
+
*
|
|
54
|
+
* @param {{ module: object, items?: object[] }} args
|
|
55
|
+
* @param {object} config
|
|
56
|
+
* @returns {Promise<string>}
|
|
57
|
+
*/
|
|
58
|
+
async function handleDictUpsert(args, config) {
|
|
59
|
+
const { module: moduleBody, items = [] } = args
|
|
60
|
+
|
|
61
|
+
if (!moduleBody || !moduleBody.strSn) {
|
|
62
|
+
return '❌ 参数错误:module.strSn 必填'
|
|
63
|
+
}
|
|
64
|
+
if (!moduleBody.strName) {
|
|
65
|
+
return '❌ 参数错误:module.strName 必填'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ① 查询现有模块
|
|
69
|
+
const queryResult = await queryDictModules(config)
|
|
70
|
+
if (!queryResult.ok) {
|
|
71
|
+
return `❌ 查询字典失败: ${queryResult.error}`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const existingModules = extractModules(queryResult.data)
|
|
75
|
+
let targetModule = existingModules.find((m) => m.strSn === moduleBody.strSn)
|
|
76
|
+
let moduleAction
|
|
77
|
+
|
|
78
|
+
// ② 模块不存在时创建
|
|
79
|
+
if (!targetModule) {
|
|
80
|
+
const saveBody = {
|
|
81
|
+
strSn: moduleBody.strSn,
|
|
82
|
+
strName: moduleBody.strName,
|
|
83
|
+
sortPriority: moduleBody.sortPriority != null ? String(moduleBody.sortPriority) : '1',
|
|
84
|
+
strLevel: 2,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const createResult = await saveDictModule(saveBody, config)
|
|
88
|
+
if (!createResult.ok) {
|
|
89
|
+
return `❌ 创建字典模块失败: ${createResult.error}`
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ③ 重新查询(data=null,只能靠 re-query 拿 id)
|
|
93
|
+
const reQueryResult = await queryDictModules(config)
|
|
94
|
+
if (!reQueryResult.ok) {
|
|
95
|
+
return `❌ 重新查询字典失败: ${reQueryResult.error}`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const freshModules = extractModules(reQueryResult.data)
|
|
99
|
+
targetModule = freshModules.find((m) => m.strSn === moduleBody.strSn)
|
|
100
|
+
|
|
101
|
+
if (!targetModule) {
|
|
102
|
+
return `❌ 字典模块创建后未能找到(strSn="${moduleBody.strSn}"),请在字典管理后台确认`
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
moduleAction = '✅ 已创建'
|
|
106
|
+
} else {
|
|
107
|
+
moduleAction = '⏭ 已存在(跳过创建)'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const moduleId = targetModule.id
|
|
111
|
+
|
|
112
|
+
// ④ 处理字典项
|
|
113
|
+
const existingItems = Array.isArray(targetModule.dictionaries)
|
|
114
|
+
? targetModule.dictionaries
|
|
115
|
+
: []
|
|
116
|
+
const existingSns = new Set(existingItems.map((i) => i.strSn))
|
|
117
|
+
|
|
118
|
+
const itemResults = []
|
|
119
|
+
|
|
120
|
+
for (const item of items) {
|
|
121
|
+
if (existingSns.has(item.strSn)) {
|
|
122
|
+
itemResults.push({
|
|
123
|
+
strSn: item.strSn,
|
|
124
|
+
strName: item.strName || '',
|
|
125
|
+
status: '⏭ 已存在(跳过)',
|
|
126
|
+
})
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const itemBody = {
|
|
131
|
+
moduleId,
|
|
132
|
+
strSn: item.strSn,
|
|
133
|
+
strName: item.strName,
|
|
134
|
+
strLevel: 2,
|
|
135
|
+
dtlValue: item.dtlValue != null ? item.dtlValue : '',
|
|
136
|
+
dtlValueRequired: item.dtlValueRequired || false,
|
|
137
|
+
dtlValue2Required: item.dtlValue2Required || false,
|
|
138
|
+
dtlValue3Required: item.dtlValue3Required || false,
|
|
139
|
+
dtlValue4Required: item.dtlValue4Required || false,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const createResult = await saveDictItem(itemBody, config)
|
|
143
|
+
if (createResult.ok) {
|
|
144
|
+
itemResults.push({ strSn: item.strSn, strName: item.strName || '', status: '✅ 已创建' })
|
|
145
|
+
} else {
|
|
146
|
+
itemResults.push({
|
|
147
|
+
strSn: item.strSn,
|
|
148
|
+
strName: item.strName || '',
|
|
149
|
+
status: `❌ 失败: ${createResult.error}`,
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const createdCount = itemResults.filter((r) => r.status.startsWith('✅')).length
|
|
155
|
+
const skippedCount = itemResults.filter((r) => r.status.startsWith('⏭')).length
|
|
156
|
+
const failedCount = itemResults.filter((r) => r.status.startsWith('❌')).length
|
|
157
|
+
|
|
158
|
+
let output = `字典模块 "${moduleBody.strSn}" (${moduleBody.strName}):${moduleAction}\n`
|
|
159
|
+
output += `模块 ID:${moduleId}\n`
|
|
160
|
+
|
|
161
|
+
if (items.length > 0) {
|
|
162
|
+
output += `字典项:创建 ${createdCount},跳过 ${skippedCount},失败 ${failedCount}\n\n`
|
|
163
|
+
output += '| strSn | strName | 状态 |\n'
|
|
164
|
+
output += '|---|---|---|\n'
|
|
165
|
+
for (const r of itemResults) {
|
|
166
|
+
output += `| ${r.strSn} | ${r.strName} | ${r.status} |\n`
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return output
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = { handleDictQuery, handleDictUpsert }
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { queryMenuTree, saveMenu } = require('../api/menuApi')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* wls_menu_query 工具处理器
|
|
7
|
+
* 自动从 config.menu.domainId 读取应用域 ID,查询完整菜单树
|
|
8
|
+
*
|
|
9
|
+
* @param {{ menu: { domainId?: string } }} config
|
|
10
|
+
* @returns {Promise<string>} 返回给 AI 的文本内容
|
|
11
|
+
*/
|
|
12
|
+
async function handleMenuQuery(config) {
|
|
13
|
+
const domainId = config.menu && config.menu.domainId
|
|
14
|
+
|
|
15
|
+
if (!domainId || domainId.toString().includes('domainId')) {
|
|
16
|
+
return [
|
|
17
|
+
'❌ 请在 env.local.json 的 menu.domainId 字段填写真实的应用域 ID',
|
|
18
|
+
'',
|
|
19
|
+
'获取方式:打开菜单管理后台,在 Network 面板找到类似',
|
|
20
|
+
' getMenuTreeByDomainId?domainId=1777597797627056130',
|
|
21
|
+
'中的数字即为 domainId,填入 env.local.json:',
|
|
22
|
+
' "menu": { "domainId": "1777597797627056130", ... }',
|
|
23
|
+
].join('\n')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const result = await queryMenuTree(domainId, config)
|
|
27
|
+
|
|
28
|
+
if (!result.ok) {
|
|
29
|
+
return `❌ 查询菜单树失败: ${result.error} (code: ${result.code})`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const tree = result.data
|
|
33
|
+
const isEmpty = !tree || (Array.isArray(tree) && tree.length === 0)
|
|
34
|
+
if (isEmpty) {
|
|
35
|
+
return `✅ 菜单树查询成功,当前应用域(domainId=${domainId})暂无菜单数据`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return `✅ 菜单树查询成功(domainId=${domainId})\n\n${JSON.stringify(tree, null, 2)}`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* wls_menu_upsert 工具处理器
|
|
43
|
+
* 批量新增(无 id)或更新(有 id)菜单项
|
|
44
|
+
* 新增时从响应 data 取服务端生成的 id,可用于链式创建子菜单
|
|
45
|
+
*
|
|
46
|
+
* @param {{ items: object[] }} args
|
|
47
|
+
* @param {object} config
|
|
48
|
+
* @returns {Promise<string>}
|
|
49
|
+
*/
|
|
50
|
+
async function handleMenuUpsert(args, config) {
|
|
51
|
+
const { items } = args
|
|
52
|
+
|
|
53
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
54
|
+
return '❌ 参数错误:items 必须是非空数组'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const results = []
|
|
58
|
+
|
|
59
|
+
for (const item of items) {
|
|
60
|
+
const isUpdate = Boolean(item.id)
|
|
61
|
+
const action = isUpdate ? '更新' : '新增'
|
|
62
|
+
|
|
63
|
+
const result = await saveMenu(item, config)
|
|
64
|
+
|
|
65
|
+
if (result.ok) {
|
|
66
|
+
const saved = result.data
|
|
67
|
+
results.push({
|
|
68
|
+
action,
|
|
69
|
+
menuName: item.menuName || '(未命名)',
|
|
70
|
+
id: saved ? saved.id : item.id,
|
|
71
|
+
status: '✅ 成功',
|
|
72
|
+
})
|
|
73
|
+
} else {
|
|
74
|
+
results.push({
|
|
75
|
+
action,
|
|
76
|
+
menuName: item.menuName || '(未命名)',
|
|
77
|
+
id: item.id || '(新增)',
|
|
78
|
+
status: `❌ 失败: ${result.error}`,
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const successCount = results.filter((r) => r.status.startsWith('✅')).length
|
|
84
|
+
const failCount = results.length - successCount
|
|
85
|
+
|
|
86
|
+
let output = `菜单操作完成:成功 ${successCount} 条,失败 ${failCount} 条\n\n`
|
|
87
|
+
output += '| 操作 | 菜单名 | ID | 状态 |\n'
|
|
88
|
+
output += '|---|---|---|---|\n'
|
|
89
|
+
for (const r of results) {
|
|
90
|
+
output += `| ${r.action} | ${r.menuName} | ${r.id} | ${r.status} |\n`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return output
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = { handleMenuQuery, handleMenuUpsert }
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agile-team/wl-skills-kit",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "AI Skill 模板包
|
|
3
|
+
"version": "2.3.1",
|
|
4
|
+
"description": "AI Skill 模板包 — 一键导入 AI 指令 + 组件文档 + 通用组件 + 领域样例,覆盖 Copilot/Cursor/Windsurf/Kiro 等主流 AI 编辑器",
|
|
5
5
|
"main": "./bin/wl-skills.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"wl-skills": "bin/wl-skills.js"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
11
|
"files/",
|
|
12
|
+
"mcp/",
|
|
12
13
|
"README.md",
|
|
13
14
|
"CHANGELOG.md"
|
|
14
15
|
],
|
|
@@ -26,7 +27,6 @@
|
|
|
26
27
|
],
|
|
27
28
|
"author": "JHLC Frontend Team",
|
|
28
29
|
"license": "UNLICENSED",
|
|
29
|
-
"homepage": "https://github.com/ChenyCHENYU/wl-skills-kit#readme",
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
32
|
"url": "git+https://github.com/ChenyCHENYU/wl-skills-kit.git"
|
|
@@ -34,10 +34,7 @@
|
|
|
34
34
|
"engines": {
|
|
35
35
|
"node": ">=16.0.0"
|
|
36
36
|
},
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"version": "node scripts/sync-version.js && git add README.md files/.github/guides/architecture.md bin/wl-skills.js"
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"xlsx": "^0.18.5"
|
|
42
39
|
}
|
|
43
|
-
}
|
|
40
|
+
}
|