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.
Files changed (84) hide show
  1. package/README.md +184 -14
  2. package/dist/generator/index.d.ts +5 -1
  3. package/dist/generator/index.d.ts.map +1 -1
  4. package/dist/generator/index.js +435 -150
  5. package/dist/generator/index.js.map +1 -1
  6. package/dist/generator/vue-template.d.ts +51 -3
  7. package/dist/generator/vue-template.d.ts.map +1 -1
  8. package/dist/generator/vue-template.js +928 -85
  9. package/dist/generator/vue-template.js.map +1 -1
  10. package/dist/tools/generate-code.d.ts +1 -1
  11. package/dist/tools/generate-code.d.ts.map +1 -1
  12. package/dist/tools/generate-code.js +72 -16
  13. package/dist/tools/generate-code.js.map +1 -1
  14. package/dist/types/index.d.ts +9 -1
  15. package/dist/types/index.d.ts.map +1 -1
  16. package/package.json +2 -1
  17. package/resources/components/actionsheet.json +199 -0
  18. package/resources/components/amap.json +66 -0
  19. package/resources/components/area.json +158 -0
  20. package/resources/components/badge.json +93 -0
  21. package/resources/components/button.json +260 -74
  22. package/resources/components/calendar.json +225 -0
  23. package/resources/components/cascader.json +115 -0
  24. package/resources/components/cell.json +85 -69
  25. package/resources/components/chart.json +55 -0
  26. package/resources/components/checkbox.json +158 -0
  27. package/resources/components/circle.json +138 -0
  28. package/resources/components/collapse.json +88 -0
  29. package/resources/components/countdown.json +105 -0
  30. package/resources/components/datepicker.json +216 -0
  31. package/resources/components/dialog.json +250 -0
  32. package/resources/components/divider.json +82 -0
  33. package/resources/components/dragsort.json +67 -0
  34. package/resources/components/dropdownmenu.json +129 -0
  35. package/resources/components/easycalendar.json +84 -0
  36. package/resources/components/empty.json +90 -0
  37. package/resources/components/field.json +423 -88
  38. package/resources/components/form.json +156 -0
  39. package/resources/components/grid.json +131 -0
  40. package/resources/components/header.json +147 -0
  41. package/resources/components/icon.json +104 -0
  42. package/resources/components/image.json +169 -0
  43. package/resources/components/imagepreview.json +150 -0
  44. package/resources/components/imagescale.json +245 -0
  45. package/resources/components/indexbar.json +83 -0
  46. package/resources/components/layout.json +74 -0
  47. package/resources/components/lazyload.json +46 -0
  48. package/resources/components/loading.json +103 -0
  49. package/resources/components/minirefresh.json +341 -0
  50. package/resources/components/noticebar.json +148 -0
  51. package/resources/components/notify.json +60 -0
  52. package/resources/components/numberkeyboard.json +216 -0
  53. package/resources/components/overlay.json +78 -0
  54. package/resources/components/pagination.json +137 -0
  55. package/resources/components/panel.json +87 -0
  56. package/resources/components/passwordinput.json +103 -0
  57. package/resources/components/picker.json +195 -0
  58. package/resources/components/popover.json +161 -0
  59. package/resources/components/popup.json +229 -0
  60. package/resources/components/progress.json +111 -0
  61. package/resources/components/qrcode.json +128 -0
  62. package/resources/components/radio.json +139 -0
  63. package/resources/components/rate.json +157 -0
  64. package/resources/components/rtc.json +35 -0
  65. package/resources/components/search.json +234 -0
  66. package/resources/components/selectperson.json +175 -0
  67. package/resources/components/sidebar.json +74 -0
  68. package/resources/components/skeleton.json +110 -0
  69. package/resources/components/slider.json +159 -0
  70. package/resources/components/stepper.json +241 -0
  71. package/resources/components/steps.json +108 -0
  72. package/resources/components/sticky.json +72 -0
  73. package/resources/components/swipe.json +146 -0
  74. package/resources/components/swipecell.json +118 -0
  75. package/resources/components/switch.json +123 -0
  76. package/resources/components/switchcell.json +123 -0
  77. package/resources/components/tab.json +257 -0
  78. package/resources/components/tabbar.json +137 -0
  79. package/resources/components/table.json +149 -0
  80. package/resources/components/tag.json +149 -0
  81. package/resources/components/toast.json +70 -0
  82. package/resources/components/treeselect.json +106 -0
  83. package/resources/components/uploader.json +283 -0
  84. package/resources/components/verifycode.json +94 -0
@@ -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
- // 分析需求,生成对应的 API 调用代码
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
- * 发送 API 请求
78
+ * 获取列表数据
31
79
  * @param {Object} params - 请求参数
32
80
  * @returns {Promise} 请求结果
33
81
  */
34
- export function fetchData(params = {}) {
35
- return new Promise((resolve, reject) => {
36
- Util.ajax({
37
- url: Config.serverUrl + '/api/endpoint',
38
- type: 'POST',
39
- data: params,
40
- success: (res) => {
41
- if (res.success) {
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
- * GET 请求示例
94
+ * 获取详情数据
56
95
  * @param {string} id - 数据 ID
57
96
  * @returns {Promise} 请求结果
58
97
  */
59
- export function getDataById(id) {
60
- return new Promise((resolve, reject) => {
61
- Util.ajax({
62
- url: Config.serverUrl + '/api/data/' + id,
63
- type: 'GET',
64
- success: (res) => {
65
- if (res.success) {
66
- resolve(res.data);
67
- } else {
68
- reject(new Error(res.message || '请求失败'));
69
- }
70
- },
71
- error: (err) => {
72
- reject(err);
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
- const code = `${header}
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
- * ${requirement}
137
- */
138
-
139
- // 变量定义
140
- $primary-color: #1989fa;
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
- &__header {
164
- @include flex-center;
165
- padding: 8px 0;
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
- &__content {
170
- padding: 16px 0;
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
- &__title {
174
- @include ellipsis;
175
- font-size: 16px;
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
- &__footer {
180
- padding: 8px 0;
181
- text-align: center;
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 = extractComponentName(requirement);
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: `生成了 Vue${vueVersion} 组件代码:
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 componentName = extractComponentName(requirement);
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 = `${toPascalCase(componentName)}.vue`;
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 = `${componentName}.js`;
574
+ filename = `${moduleName}.js`;
575
+ relativePath = `${modulePath}/${moduleName}.js`;
329
576
  break;
330
577
  case 'scss':
331
- result = generateScssCode(requirement);
332
- filename = `${componentName}.scss`;
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 = `${componentName}-api.js`;
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(`**${filename}**: ${result.explanation}`);
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: explanations.join('\n\n')
635
+ explanation: structureExplanation,
636
+ modulePath
352
637
  };
353
638
  }
354
639
  /**