m8-mcp-server 1.0.3 → 1.0.5
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/README.md +184 -14
- package/dist/generator/index.d.ts +5 -1
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +435 -150
- package/dist/generator/index.js.map +1 -1
- package/dist/generator/vue-template.d.ts +51 -3
- package/dist/generator/vue-template.d.ts.map +1 -1
- package/dist/generator/vue-template.js +928 -85
- package/dist/generator/vue-template.js.map +1 -1
- package/dist/tools/generate-code.d.ts +1 -1
- package/dist/tools/generate-code.d.ts.map +1 -1
- package/dist/tools/generate-code.js +72 -16
- package/dist/tools/generate-code.js.map +1 -1
- package/dist/types/index.d.ts +9 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/resources/components/actionsheet.json +199 -0
- package/resources/components/amap.json +66 -0
- package/resources/components/area.json +158 -0
- package/resources/components/badge.json +93 -0
- package/resources/components/button.json +260 -74
- package/resources/components/calendar.json +225 -0
- package/resources/components/cascader.json +115 -0
- package/resources/components/cell.json +85 -69
- package/resources/components/chart.json +55 -0
- package/resources/components/checkbox.json +158 -0
- package/resources/components/circle.json +138 -0
- package/resources/components/collapse.json +88 -0
- package/resources/components/countdown.json +105 -0
- package/resources/components/datepicker.json +216 -0
- package/resources/components/dialog.json +250 -0
- package/resources/components/divider.json +82 -0
- package/resources/components/dragsort.json +67 -0
- package/resources/components/dropdownmenu.json +129 -0
- package/resources/components/easycalendar.json +84 -0
- package/resources/components/empty.json +90 -0
- package/resources/components/field.json +423 -88
- package/resources/components/form.json +156 -0
- package/resources/components/grid.json +131 -0
- package/resources/components/header.json +147 -0
- package/resources/components/icon.json +104 -0
- package/resources/components/image.json +169 -0
- package/resources/components/imagepreview.json +150 -0
- package/resources/components/imagescale.json +245 -0
- package/resources/components/indexbar.json +83 -0
- package/resources/components/layout.json +74 -0
- package/resources/components/lazyload.json +46 -0
- package/resources/components/loading.json +103 -0
- package/resources/components/minirefresh.json +341 -0
- package/resources/components/noticebar.json +148 -0
- package/resources/components/notify.json +60 -0
- package/resources/components/numberkeyboard.json +216 -0
- package/resources/components/overlay.json +78 -0
- package/resources/components/pagination.json +137 -0
- package/resources/components/panel.json +87 -0
- package/resources/components/passwordinput.json +103 -0
- package/resources/components/picker.json +195 -0
- package/resources/components/popover.json +161 -0
- package/resources/components/popup.json +229 -0
- package/resources/components/progress.json +111 -0
- package/resources/components/qrcode.json +128 -0
- package/resources/components/radio.json +139 -0
- package/resources/components/rate.json +157 -0
- package/resources/components/rtc.json +35 -0
- package/resources/components/search.json +234 -0
- package/resources/components/selectperson.json +175 -0
- package/resources/components/sidebar.json +74 -0
- package/resources/components/skeleton.json +110 -0
- package/resources/components/slider.json +159 -0
- package/resources/components/stepper.json +241 -0
- package/resources/components/steps.json +108 -0
- package/resources/components/sticky.json +72 -0
- package/resources/components/swipe.json +146 -0
- package/resources/components/swipecell.json +118 -0
- package/resources/components/switch.json +123 -0
- package/resources/components/switchcell.json +123 -0
- package/resources/components/tab.json +257 -0
- package/resources/components/tabbar.json +137 -0
- package/resources/components/table.json +149 -0
- package/resources/components/tag.json +149 -0
- package/resources/components/toast.json +70 -0
- package/resources/components/treeselect.json +106 -0
- package/resources/components/uploader.json +283 -0
- package/resources/components/verifycode.json +94 -0
package/dist/generator/index.js
CHANGED
|
@@ -2,76 +2,122 @@
|
|
|
2
2
|
* 代码生成器主入口
|
|
3
3
|
* @作者 M8 Team
|
|
4
4
|
* @创建时间 2024-12-29
|
|
5
|
-
* @描述 根据需求生成符合 M8
|
|
5
|
+
* @描述 根据需求生成符合 M8 规范的代码,包括 Vue、SCSS、Router、Mock 等
|
|
6
6
|
*/
|
|
7
7
|
import { generateFileHeader, generateScssFileHeader } from './header.js';
|
|
8
|
-
import { generateVueTemplate } from './vue-template.js';
|
|
8
|
+
import { generateVueTemplate, filterValidComponents, suggestComponents } from './vue-template.js';
|
|
9
|
+
/**
|
|
10
|
+
* 从需求描述中提取模块名称
|
|
11
|
+
* @param requirement 需求描述
|
|
12
|
+
* @returns 模块名称 (kebab-case)
|
|
13
|
+
*/
|
|
14
|
+
function extractModuleName(requirement) {
|
|
15
|
+
// 尝试从需求中提取有意义的名称
|
|
16
|
+
const patterns = [
|
|
17
|
+
/创建(.+?)组件/,
|
|
18
|
+
/生成(.+?)页面/,
|
|
19
|
+
/实现(.+?)功能/,
|
|
20
|
+
/(.+?)页面/,
|
|
21
|
+
/(.+?)列表/,
|
|
22
|
+
/(.+?)表单/,
|
|
23
|
+
/(.+?)详情/
|
|
24
|
+
];
|
|
25
|
+
for (const pattern of patterns) {
|
|
26
|
+
const match = requirement.match(pattern);
|
|
27
|
+
if (match && match[1]) {
|
|
28
|
+
// 转换为 kebab-case
|
|
29
|
+
return match[1]
|
|
30
|
+
.trim()
|
|
31
|
+
.replace(/[\s_]+/g, '-')
|
|
32
|
+
.toLowerCase();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// 默认名称
|
|
36
|
+
return 'my-page';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 从需求描述中提取页面标题
|
|
40
|
+
* @param requirement 需求描述
|
|
41
|
+
* @returns 页面标题
|
|
42
|
+
*/
|
|
43
|
+
function extractPageTitle(requirement) {
|
|
44
|
+
const patterns = [
|
|
45
|
+
/创建(.+?)组件/,
|
|
46
|
+
/生成(.+?)页面/,
|
|
47
|
+
/实现(.+?)功能/,
|
|
48
|
+
/(.+?)页面/,
|
|
49
|
+
];
|
|
50
|
+
for (const pattern of patterns) {
|
|
51
|
+
const match = requirement.match(pattern);
|
|
52
|
+
if (match && match[1]) {
|
|
53
|
+
return match[1].trim();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return '页面标题';
|
|
57
|
+
}
|
|
9
58
|
/**
|
|
10
59
|
* 生成 API 调用代码
|
|
11
60
|
* @param requirement 需求描述
|
|
61
|
+
* @param moduleName 模块名称
|
|
62
|
+
* @param useMock 是否使用 Mock
|
|
12
63
|
* @returns 生成的代码
|
|
13
64
|
*/
|
|
14
|
-
function generateApiCallCode(requirement) {
|
|
65
|
+
function generateApiCallCode(requirement, moduleName, useMock = true) {
|
|
15
66
|
const header = generateFileHeader({
|
|
16
67
|
description: requirement
|
|
17
68
|
});
|
|
18
|
-
|
|
69
|
+
const apiPath = useMock ? `/rest/mock/${moduleName}` : `/api/${moduleName}`;
|
|
19
70
|
const code = `${header}
|
|
20
71
|
|
|
21
72
|
/**
|
|
22
|
-
* ${requirement}
|
|
73
|
+
* ${requirement} - API 接口
|
|
23
74
|
* 使用 Util.ajax 发送请求,遵循 M8 规范
|
|
24
75
|
*/
|
|
25
76
|
|
|
26
|
-
// 引入配置
|
|
27
|
-
import Config from '@/config';
|
|
28
|
-
|
|
29
77
|
/**
|
|
30
|
-
*
|
|
78
|
+
* 获取列表数据
|
|
31
79
|
* @param {Object} params - 请求参数
|
|
32
80
|
* @returns {Promise} 请求结果
|
|
33
81
|
*/
|
|
34
|
-
export function
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
resolve(res.data);
|
|
43
|
-
} else {
|
|
44
|
-
reject(new Error(res.message || '请求失败'));
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
error: (err) => {
|
|
48
|
-
reject(err);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
82
|
+
export function getList(params = {}) {
|
|
83
|
+
return Util.ajax({
|
|
84
|
+
url: Config.serverUrl + '${apiPath}/list',
|
|
85
|
+
type: 'POST',
|
|
86
|
+
data: {
|
|
87
|
+
params: JSON.stringify(params)
|
|
88
|
+
},
|
|
89
|
+
dataPath: 'data'
|
|
51
90
|
});
|
|
52
91
|
}
|
|
53
92
|
|
|
54
93
|
/**
|
|
55
|
-
*
|
|
94
|
+
* 获取详情数据
|
|
56
95
|
* @param {string} id - 数据 ID
|
|
57
96
|
* @returns {Promise} 请求结果
|
|
58
97
|
*/
|
|
59
|
-
export function
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
98
|
+
export function getDetail(id) {
|
|
99
|
+
return Util.ajax({
|
|
100
|
+
url: Config.serverUrl + '${apiPath}/detail',
|
|
101
|
+
type: 'POST',
|
|
102
|
+
data: {
|
|
103
|
+
params: JSON.stringify({ id })
|
|
104
|
+
},
|
|
105
|
+
dataPath: 'data'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 提交数据
|
|
111
|
+
* @param {Object} data - 提交的数据
|
|
112
|
+
* @returns {Promise} 请求结果
|
|
113
|
+
*/
|
|
114
|
+
export function submitData(data) {
|
|
115
|
+
return Util.ajax({
|
|
116
|
+
url: Config.serverUrl + '${apiPath}/submit',
|
|
117
|
+
type: 'POST',
|
|
118
|
+
data: {
|
|
119
|
+
params: JSON.stringify(data)
|
|
120
|
+
}
|
|
75
121
|
});
|
|
76
122
|
}
|
|
77
123
|
`;
|
|
@@ -81,8 +127,8 @@ export function getDataById(id) {
|
|
|
81
127
|
explanation: `生成了符合 M8 规范的 API 调用代码:
|
|
82
128
|
- 使用 Util.ajax 而非 fetch 或 axios
|
|
83
129
|
- 使用 Config.serverUrl 作为 API 基础 URL
|
|
84
|
-
-
|
|
85
|
-
-
|
|
130
|
+
- ${useMock ? '使用 Mock 接口路径 /rest/mock/' : '使用正式接口路径 /api/'}
|
|
131
|
+
- 包含完整的错误处理`
|
|
86
132
|
};
|
|
87
133
|
}
|
|
88
134
|
/**
|
|
@@ -100,8 +146,6 @@ function generateJavaScriptCode(requirement) {
|
|
|
100
146
|
* ${requirement}
|
|
101
147
|
*/
|
|
102
148
|
|
|
103
|
-
// TODO: 根据需求实现具体逻辑
|
|
104
|
-
|
|
105
149
|
/**
|
|
106
150
|
* 示例函数
|
|
107
151
|
* @param {Object} options - 配置选项
|
|
@@ -124,131 +168,325 @@ export function processData(options = {}) {
|
|
|
124
168
|
/**
|
|
125
169
|
* 生成 SCSS 代码
|
|
126
170
|
* @param requirement 需求描述
|
|
171
|
+
* @param moduleName 模块名称
|
|
127
172
|
* @returns 生成的代码
|
|
128
173
|
*/
|
|
129
|
-
function generateScssCode(requirement) {
|
|
174
|
+
function generateScssCode(requirement, moduleName) {
|
|
130
175
|
const header = generateScssFileHeader({
|
|
131
176
|
description: requirement
|
|
132
177
|
});
|
|
133
|
-
|
|
178
|
+
// 生成 CSS 类名 (使用下划线风格)
|
|
179
|
+
const cssClassName = moduleName.replace(/-/g, '_');
|
|
180
|
+
const req = requirement.toLowerCase();
|
|
181
|
+
// 判断页面类型生成对应样式
|
|
182
|
+
const isLoginPage = req.includes('登录') || req.includes('login');
|
|
183
|
+
const isFormPage = req.includes('表单') || req.includes('form') || isLoginPage;
|
|
184
|
+
const isListPage = req.includes('列表') || req.includes('list');
|
|
185
|
+
let styleContent = '';
|
|
186
|
+
if (isLoginPage) {
|
|
187
|
+
styleContent = `
|
|
188
|
+
// 登录页面样式
|
|
189
|
+
.${cssClassName} {
|
|
190
|
+
min-height: 100vh;
|
|
191
|
+
padding: 40px 24px;
|
|
192
|
+
background: #f5f7fa;
|
|
134
193
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
$text-color: #323233;
|
|
142
|
-
$border-color: #ebedf0;
|
|
143
|
-
$background-color: #f7f8fa;
|
|
144
|
-
|
|
145
|
-
// 混入定义
|
|
146
|
-
@mixin flex-center {
|
|
147
|
-
display: flex;
|
|
148
|
-
align-items: center;
|
|
149
|
-
justify-content: center;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@mixin ellipsis {
|
|
153
|
-
overflow: hidden;
|
|
154
|
-
text-overflow: ellipsis;
|
|
155
|
-
white-space: nowrap;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 组件样式
|
|
159
|
-
.component {
|
|
160
|
-
padding: 12px;
|
|
161
|
-
background-color: $background-color;
|
|
194
|
+
&__form {
|
|
195
|
+
padding: 24px;
|
|
196
|
+
background: #fff;
|
|
197
|
+
border-radius: 8px;
|
|
198
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
199
|
+
}
|
|
162
200
|
|
|
163
|
-
&
|
|
164
|
-
|
|
165
|
-
padding:
|
|
166
|
-
border-bottom: 1px solid $border-color;
|
|
201
|
+
&__actions {
|
|
202
|
+
margin-top: 24px;
|
|
203
|
+
padding: 0 16px;
|
|
167
204
|
}
|
|
205
|
+
}`;
|
|
206
|
+
}
|
|
207
|
+
else if (isFormPage) {
|
|
208
|
+
styleContent = `
|
|
209
|
+
// 表单页面样式
|
|
210
|
+
.${cssClassName} {
|
|
211
|
+
min-height: 100vh;
|
|
212
|
+
padding: 12px;
|
|
213
|
+
background: #f5f7fa;
|
|
168
214
|
|
|
169
|
-
&
|
|
170
|
-
|
|
215
|
+
&__actions {
|
|
216
|
+
margin-top: 24px;
|
|
217
|
+
padding: 0 16px;
|
|
171
218
|
}
|
|
219
|
+
}`;
|
|
220
|
+
}
|
|
221
|
+
else if (isListPage) {
|
|
222
|
+
styleContent = `
|
|
223
|
+
// 列表页面样式
|
|
224
|
+
.${cssClassName} {
|
|
225
|
+
min-height: 100vh;
|
|
226
|
+
background: #f5f7fa;
|
|
172
227
|
|
|
173
|
-
&
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
color: $text-color;
|
|
228
|
+
&__item {
|
|
229
|
+
margin-bottom: 8px;
|
|
230
|
+
background: #fff;
|
|
177
231
|
}
|
|
232
|
+
}`;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
styleContent = `
|
|
236
|
+
// 页面样式
|
|
237
|
+
.${cssClassName} {
|
|
238
|
+
min-height: 100vh;
|
|
239
|
+
padding: 12px;
|
|
240
|
+
background: #f5f7fa;
|
|
178
241
|
|
|
179
|
-
&
|
|
180
|
-
padding:
|
|
181
|
-
|
|
242
|
+
&__content {
|
|
243
|
+
padding: 16px;
|
|
244
|
+
background: #fff;
|
|
245
|
+
border-radius: 8px;
|
|
182
246
|
}
|
|
183
|
-
}
|
|
247
|
+
}`;
|
|
248
|
+
}
|
|
249
|
+
const code = `${header}
|
|
250
|
+
/**
|
|
251
|
+
* ${requirement}
|
|
252
|
+
* 样式文件遵循 BEM 命名规范
|
|
253
|
+
*/
|
|
254
|
+
${styleContent}
|
|
184
255
|
`;
|
|
185
256
|
return {
|
|
186
257
|
code,
|
|
187
258
|
language: 'scss',
|
|
188
259
|
explanation: `生成了符合 M8 规范的 SCSS 代码:
|
|
189
260
|
- 使用 BEM 命名规范
|
|
190
|
-
-
|
|
191
|
-
- 包含常用混入
|
|
261
|
+
- 使用下划线风格的类名
|
|
192
262
|
- 规范的文件头注释`
|
|
193
263
|
};
|
|
194
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* 生成路由配置代码
|
|
267
|
+
* @param moduleName 模块名称
|
|
268
|
+
* @param pageTitle 页面标题
|
|
269
|
+
* @returns 生成的代码
|
|
270
|
+
*/
|
|
271
|
+
function generateRouterCode(moduleName, pageTitle) {
|
|
272
|
+
const header = generateFileHeader({
|
|
273
|
+
description: `${pageTitle} - 路由配置`
|
|
274
|
+
});
|
|
275
|
+
const code = `${header}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* ${pageTitle} 路由配置
|
|
279
|
+
* router.js 无需 import 组件,path 路径需与 vue 组件名称保持匹配
|
|
280
|
+
* 构建时会自动将模块下的路由配置合并到 pages.json 内
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
// 定义路由规则
|
|
284
|
+
const routes = [
|
|
285
|
+
{
|
|
286
|
+
path: 'pages/${moduleName}/index',
|
|
287
|
+
style: {
|
|
288
|
+
navigationBarTitleText: '${pageTitle}',
|
|
289
|
+
navigationStyle: 'custom'
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
];
|
|
293
|
+
|
|
294
|
+
// 路由选项
|
|
295
|
+
const options = {
|
|
296
|
+
autoSubPackages: true,
|
|
297
|
+
isFirstModule: false
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// 导出路由配置
|
|
301
|
+
export default { routes, options };
|
|
302
|
+
`;
|
|
303
|
+
return {
|
|
304
|
+
code,
|
|
305
|
+
language: 'javascript',
|
|
306
|
+
explanation: `生成了符合 M8 规范的路由配置:
|
|
307
|
+
- 路径与 Vue 组件名称匹配
|
|
308
|
+
- 包含导航栏标题配置
|
|
309
|
+
- 使用 custom 导航样式`
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* 生成 Mock 数据代码
|
|
314
|
+
* @param moduleName 模块名称
|
|
315
|
+
* @param requirement 需求描述
|
|
316
|
+
* @returns 生成的代码
|
|
317
|
+
*/
|
|
318
|
+
function generateMockCode(moduleName, requirement) {
|
|
319
|
+
const header = generateFileHeader({
|
|
320
|
+
description: `${requirement} - Mock 数据`
|
|
321
|
+
});
|
|
322
|
+
const req = requirement.toLowerCase();
|
|
323
|
+
const isLoginPage = req.includes('登录') || req.includes('login');
|
|
324
|
+
const isListPage = req.includes('列表') || req.includes('list');
|
|
325
|
+
let mockContent = '';
|
|
326
|
+
if (isLoginPage) {
|
|
327
|
+
mockContent = `
|
|
328
|
+
{
|
|
329
|
+
// 登录接口
|
|
330
|
+
methodUrl: '/rest/mock/${moduleName}/submit',
|
|
331
|
+
input: {},
|
|
332
|
+
output: Mock.mock({
|
|
333
|
+
status: {
|
|
334
|
+
code: 1,
|
|
335
|
+
text: '登录成功'
|
|
336
|
+
},
|
|
337
|
+
data: {
|
|
338
|
+
token: '@guid',
|
|
339
|
+
userId: '@id',
|
|
340
|
+
username: '@cname'
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
}`;
|
|
344
|
+
}
|
|
345
|
+
else if (isListPage) {
|
|
346
|
+
mockContent = `
|
|
347
|
+
{
|
|
348
|
+
// 列表接口
|
|
349
|
+
methodUrl: '/rest/mock/${moduleName}/list',
|
|
350
|
+
input: {},
|
|
351
|
+
output: Mock.mock({
|
|
352
|
+
status: {
|
|
353
|
+
code: 1,
|
|
354
|
+
text: '成功'
|
|
355
|
+
},
|
|
356
|
+
data: {
|
|
357
|
+
'list|10-20': [
|
|
358
|
+
{
|
|
359
|
+
'id|+1': 1,
|
|
360
|
+
title: '@ctitle(5, 15)',
|
|
361
|
+
date: '@date("yyyy-MM-dd")',
|
|
362
|
+
content: '@cparagraph(1, 2)'
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
total: '@integer(50, 200)'
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
// 详情接口
|
|
371
|
+
methodUrl: '/rest/mock/${moduleName}/detail',
|
|
372
|
+
input: {},
|
|
373
|
+
output: Mock.mock({
|
|
374
|
+
status: {
|
|
375
|
+
code: 1,
|
|
376
|
+
text: '成功'
|
|
377
|
+
},
|
|
378
|
+
data: {
|
|
379
|
+
id: '@id',
|
|
380
|
+
title: '@ctitle(10, 20)',
|
|
381
|
+
content: '@cparagraph(5, 10)',
|
|
382
|
+
createTime: '@datetime("yyyy-MM-dd HH:mm:ss")',
|
|
383
|
+
author: '@cname'
|
|
384
|
+
}
|
|
385
|
+
})
|
|
386
|
+
}`;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
mockContent = `
|
|
390
|
+
{
|
|
391
|
+
// 获取数据接口
|
|
392
|
+
methodUrl: '/rest/mock/${moduleName}',
|
|
393
|
+
input: {},
|
|
394
|
+
output: Mock.mock({
|
|
395
|
+
status: {
|
|
396
|
+
code: 1,
|
|
397
|
+
text: '成功'
|
|
398
|
+
},
|
|
399
|
+
data: {
|
|
400
|
+
id: '@id',
|
|
401
|
+
name: '@cname',
|
|
402
|
+
createTime: '@datetime("yyyy-MM-dd HH:mm:ss")'
|
|
403
|
+
}
|
|
404
|
+
})
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
// 提交数据接口
|
|
408
|
+
methodUrl: '/rest/mock/${moduleName}/submit',
|
|
409
|
+
input: {},
|
|
410
|
+
output: Mock.mock({
|
|
411
|
+
status: {
|
|
412
|
+
code: 1,
|
|
413
|
+
text: '提交成功'
|
|
414
|
+
},
|
|
415
|
+
data: {
|
|
416
|
+
id: '@id'
|
|
417
|
+
}
|
|
418
|
+
})
|
|
419
|
+
}`;
|
|
420
|
+
}
|
|
421
|
+
const code = `${header}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* ${requirement} - Mock 数据配置
|
|
425
|
+
* Mock 文件定义请求本地接口时响应的模拟数据
|
|
426
|
+
*/
|
|
427
|
+
import Mock from '@mock';
|
|
428
|
+
|
|
429
|
+
const mockData = [${mockContent}
|
|
430
|
+
];
|
|
431
|
+
|
|
432
|
+
export default mockData;
|
|
433
|
+
`;
|
|
434
|
+
return {
|
|
435
|
+
code,
|
|
436
|
+
language: 'javascript',
|
|
437
|
+
explanation: `生成了符合 M8 规范的 Mock 数据配置:
|
|
438
|
+
- 使用 @mock 导入 Mock 库
|
|
439
|
+
- 定义了 methodUrl 匹配的接口
|
|
440
|
+
- 使用 Mock.mock 生成随机数据`
|
|
441
|
+
};
|
|
442
|
+
}
|
|
195
443
|
/**
|
|
196
444
|
* 生成 Vue 组件代码
|
|
197
445
|
* @param requirement 需求描述
|
|
198
446
|
* @param vueVersion Vue 版本
|
|
199
447
|
* @param components 使用的组件列表
|
|
448
|
+
* @param useMock 是否使用 Mock
|
|
200
449
|
* @returns 生成的代码
|
|
201
450
|
*/
|
|
202
|
-
function generateVueComponentCode(requirement, vueVersion = 2, components = []) {
|
|
451
|
+
function generateVueComponentCode(requirement, vueVersion = 2, components = [], useMock = true) {
|
|
203
452
|
// 从需求中提取组件名称
|
|
204
|
-
const componentName =
|
|
453
|
+
const componentName = extractModuleName(requirement);
|
|
454
|
+
const pageTitle = extractPageTitle(requirement);
|
|
455
|
+
// 验证组件
|
|
456
|
+
const { valid: validComponents, warnings } = filterValidComponents(components);
|
|
457
|
+
// 如果没有指定组件,根据需求智能推荐
|
|
458
|
+
const finalComponents = validComponents.length > 0
|
|
459
|
+
? validComponents
|
|
460
|
+
: suggestComponents(requirement);
|
|
205
461
|
const options = {
|
|
206
462
|
name: componentName,
|
|
207
463
|
vueVersion,
|
|
208
464
|
description: requirement,
|
|
209
|
-
components,
|
|
210
|
-
includeStyle: true
|
|
465
|
+
components: finalComponents,
|
|
466
|
+
includeStyle: true,
|
|
467
|
+
useMock,
|
|
468
|
+
pageTitle
|
|
211
469
|
};
|
|
212
470
|
const code = generateVueTemplate(options);
|
|
213
471
|
const apiStyle = vueVersion === 3 ? 'Composition API (script setup)' : 'Options API';
|
|
472
|
+
let explanation = `生成了 Vue${vueVersion} 组件代码:
|
|
473
|
+
- 使用 ${apiStyle} 语法
|
|
474
|
+
- 包含规范的文件头注释
|
|
475
|
+
- 样式通过 @import 引入外部 SCSS 文件
|
|
476
|
+
- 使用 ejs.ui.toast/showWaiting 等原生 API
|
|
477
|
+
- 使用 Util.ajax + Config.serverUrl 发送请求`;
|
|
478
|
+
if (finalComponents.length > 0) {
|
|
479
|
+
explanation += `\n- 使用了 ${finalComponents.join(', ')} 组件`;
|
|
480
|
+
}
|
|
481
|
+
if (warnings.length > 0) {
|
|
482
|
+
explanation += `\n\n⚠️ 警告:\n${warnings.map(w => `- ${w}`).join('\n')}`;
|
|
483
|
+
}
|
|
214
484
|
return {
|
|
215
485
|
code,
|
|
216
486
|
language: 'vue',
|
|
217
|
-
explanation
|
|
218
|
-
- 使用 ${apiStyle} 语法
|
|
219
|
-
- 包含规范的文件头注释
|
|
220
|
-
- 使用 BEM 命名的 SCSS 样式
|
|
221
|
-
- ${components.length > 0 ? `集成了 ${components.join(', ')} 组件` : '基础组件结构'}`
|
|
487
|
+
explanation
|
|
222
488
|
};
|
|
223
489
|
}
|
|
224
|
-
/**
|
|
225
|
-
* 从需求描述中提取组件名称
|
|
226
|
-
* @param requirement 需求描述
|
|
227
|
-
* @returns 组件名称
|
|
228
|
-
*/
|
|
229
|
-
function extractComponentName(requirement) {
|
|
230
|
-
// 尝试从需求中提取有意义的名称
|
|
231
|
-
const patterns = [
|
|
232
|
-
/创建(.+?)组件/,
|
|
233
|
-
/生成(.+?)页面/,
|
|
234
|
-
/实现(.+?)功能/,
|
|
235
|
-
/(.+?)列表/,
|
|
236
|
-
/(.+?)表单/,
|
|
237
|
-
/(.+?)详情/
|
|
238
|
-
];
|
|
239
|
-
for (const pattern of patterns) {
|
|
240
|
-
const match = requirement.match(pattern);
|
|
241
|
-
if (match && match[1]) {
|
|
242
|
-
// 转换为 kebab-case
|
|
243
|
-
return match[1]
|
|
244
|
-
.trim()
|
|
245
|
-
.replace(/[\s_]+/g, '-')
|
|
246
|
-
.toLowerCase();
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// 默认名称
|
|
250
|
-
return 'my-component';
|
|
251
|
-
}
|
|
252
490
|
/**
|
|
253
491
|
* 代码生成器类
|
|
254
492
|
*/
|
|
@@ -259,14 +497,15 @@ export class CodeGenerator {
|
|
|
259
497
|
* @returns 生成的代码
|
|
260
498
|
*/
|
|
261
499
|
generateCode(options) {
|
|
262
|
-
const { type, requirement, vueVersion = 2, components = [] } = options;
|
|
500
|
+
const { type, requirement, vueVersion = 2, components = [], useMock = true } = options;
|
|
263
501
|
// 如果 type 是数组,使用 generateMultipleCode
|
|
264
502
|
if (Array.isArray(type)) {
|
|
265
503
|
const result = this.generateMultipleCode({
|
|
266
504
|
types: type,
|
|
267
505
|
requirement,
|
|
268
506
|
vueVersion,
|
|
269
|
-
components
|
|
507
|
+
components,
|
|
508
|
+
useMock
|
|
270
509
|
});
|
|
271
510
|
// 返回第一个文件作为兼容
|
|
272
511
|
return {
|
|
@@ -275,25 +514,27 @@ export class CodeGenerator {
|
|
|
275
514
|
explanation: result.explanation
|
|
276
515
|
};
|
|
277
516
|
}
|
|
517
|
+
const moduleName = extractModuleName(requirement);
|
|
278
518
|
switch (type) {
|
|
279
519
|
case 'vue-component':
|
|
280
|
-
return generateVueComponentCode(requirement, vueVersion, components);
|
|
520
|
+
return generateVueComponentCode(requirement, vueVersion, components, useMock);
|
|
281
521
|
case 'javascript':
|
|
282
522
|
return generateJavaScriptCode(requirement);
|
|
283
523
|
case 'scss':
|
|
284
|
-
return generateScssCode(requirement);
|
|
524
|
+
return generateScssCode(requirement, moduleName);
|
|
285
525
|
case 'api-call':
|
|
286
|
-
return generateApiCallCode(requirement);
|
|
526
|
+
return generateApiCallCode(requirement, moduleName, useMock);
|
|
287
527
|
case 'full-page':
|
|
288
|
-
// full-page
|
|
528
|
+
// full-page 转换为完整页面生成(Vue + SCSS + Router + Mock)
|
|
289
529
|
const result = this.generateMultipleCode({
|
|
290
|
-
types: ['vue-component', 'scss'],
|
|
530
|
+
types: ['vue-component', 'scss', 'router', 'mock'],
|
|
291
531
|
requirement,
|
|
292
532
|
vueVersion,
|
|
293
|
-
components
|
|
533
|
+
components,
|
|
534
|
+
useMock
|
|
294
535
|
});
|
|
295
536
|
return {
|
|
296
|
-
code: result.files.map(f => `// === ${f.filename} ===\n${f.code}`).join('\n\n'),
|
|
537
|
+
code: result.files.map(f => `// === ${f.relativePath || f.filename} ===\n${f.code}`).join('\n\n'),
|
|
297
538
|
language: 'text',
|
|
298
539
|
explanation: result.explanation
|
|
299
540
|
};
|
|
@@ -311,29 +552,47 @@ export class CodeGenerator {
|
|
|
311
552
|
* @returns 多文件生成结果
|
|
312
553
|
*/
|
|
313
554
|
generateMultipleCode(options) {
|
|
314
|
-
const { types, requirement, vueVersion = 2, components = [] } = options;
|
|
315
|
-
const
|
|
555
|
+
const { types, requirement, vueVersion = 2, components = [], useMock = true } = options;
|
|
556
|
+
const moduleName = extractModuleName(requirement);
|
|
557
|
+
const pageTitle = extractPageTitle(requirement);
|
|
558
|
+
// 默认模块路径在 src/pages 下
|
|
559
|
+
const modulePath = options.modulePath || `src/pages/${moduleName}`;
|
|
316
560
|
const files = [];
|
|
317
561
|
const explanations = [];
|
|
318
562
|
for (const type of types) {
|
|
319
563
|
let result;
|
|
320
564
|
let filename;
|
|
565
|
+
let relativePath;
|
|
321
566
|
switch (type) {
|
|
322
567
|
case 'vue-component':
|
|
323
|
-
result = generateVueComponentCode(requirement, vueVersion, components);
|
|
324
|
-
filename =
|
|
568
|
+
result = generateVueComponentCode(requirement, vueVersion, components, useMock);
|
|
569
|
+
filename = 'index.vue';
|
|
570
|
+
relativePath = `${modulePath}/index.vue`;
|
|
325
571
|
break;
|
|
326
572
|
case 'javascript':
|
|
327
573
|
result = generateJavaScriptCode(requirement);
|
|
328
|
-
filename = `${
|
|
574
|
+
filename = `${moduleName}.js`;
|
|
575
|
+
relativePath = `${modulePath}/${moduleName}.js`;
|
|
329
576
|
break;
|
|
330
577
|
case 'scss':
|
|
331
|
-
result = generateScssCode(requirement);
|
|
332
|
-
filename = `${
|
|
578
|
+
result = generateScssCode(requirement, moduleName);
|
|
579
|
+
filename = `${moduleName}.scss`;
|
|
580
|
+
relativePath = `${modulePath}/css/${moduleName}.scss`;
|
|
333
581
|
break;
|
|
334
582
|
case 'api-call':
|
|
335
|
-
result = generateApiCallCode(requirement);
|
|
336
|
-
filename =
|
|
583
|
+
result = generateApiCallCode(requirement, moduleName, useMock);
|
|
584
|
+
filename = 'api.js';
|
|
585
|
+
relativePath = `${modulePath}/api.js`;
|
|
586
|
+
break;
|
|
587
|
+
case 'router':
|
|
588
|
+
result = generateRouterCode(moduleName, pageTitle);
|
|
589
|
+
filename = 'router.js';
|
|
590
|
+
relativePath = `${modulePath}/router.js`;
|
|
591
|
+
break;
|
|
592
|
+
case 'mock':
|
|
593
|
+
result = generateMockCode(moduleName, requirement);
|
|
594
|
+
filename = 'mock.js';
|
|
595
|
+
relativePath = `${modulePath}/mock.js`;
|
|
337
596
|
break;
|
|
338
597
|
default:
|
|
339
598
|
continue;
|
|
@@ -342,13 +601,39 @@ export class CodeGenerator {
|
|
|
342
601
|
type,
|
|
343
602
|
code: result.code,
|
|
344
603
|
language: result.language,
|
|
345
|
-
filename
|
|
604
|
+
filename,
|
|
605
|
+
relativePath
|
|
346
606
|
});
|
|
347
|
-
explanations.push(`**${
|
|
607
|
+
explanations.push(`**${relativePath}**: ${result.explanation.split('\n')[0]}`);
|
|
348
608
|
}
|
|
609
|
+
// 生成目录结构说明
|
|
610
|
+
const structureExplanation = `
|
|
611
|
+
## 生成的文件结构
|
|
612
|
+
|
|
613
|
+
\`\`\`
|
|
614
|
+
${modulePath}/
|
|
615
|
+
├── index.vue # Vue 页面组件
|
|
616
|
+
├── router.js # 路由配置
|
|
617
|
+
├── mock.js # Mock 数据
|
|
618
|
+
└── css/
|
|
619
|
+
└── ${moduleName}.scss # 样式文件
|
|
620
|
+
\`\`\`
|
|
621
|
+
|
|
622
|
+
## 文件说明
|
|
623
|
+
|
|
624
|
+
${explanations.join('\n\n')}
|
|
625
|
+
|
|
626
|
+
## 使用说明
|
|
627
|
+
|
|
628
|
+
1. 将生成的文件放置到对应目录
|
|
629
|
+
2. Mock 数据会自动被框架加载
|
|
630
|
+
3. 路由配置会自动合并到 pages.json
|
|
631
|
+
4. 样式文件通过 @import 在 Vue 组件中引入
|
|
632
|
+
`;
|
|
349
633
|
return {
|
|
350
634
|
files,
|
|
351
|
-
explanation:
|
|
635
|
+
explanation: structureExplanation,
|
|
636
|
+
modulePath
|
|
352
637
|
};
|
|
353
638
|
}
|
|
354
639
|
/**
|