ol-base-components 2.7.9 → 2.8.0

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/package.json CHANGED
@@ -1,19 +1,22 @@
1
1
  {
2
2
  "name": "ol-base-components",
3
- "version": "2.7.9",
3
+ "version": "2.8.0",
4
4
  "private": false,
5
5
  "main": "src/package/index.js",
6
6
  "bin": {
7
7
  "init": "src/api/init.js",
8
8
  "run": "src/api/run.js",
9
9
  "api": "src/api/api.js",
10
- "add": "src/bin/add.js"
10
+ "add": "src/bin/add.js",
11
+ "install-vscode": "scripts/install-vscode.js"
11
12
  },
12
13
  "scripts": {
13
14
  "serve": "vue-cli-service serve --no-verify",
14
15
  "build": "vue-cli-service build",
15
16
  "lint": "vue-cli-service lint",
16
- "add": "node src/bin/add.js"
17
+ "add": "node src/bin/add.js",
18
+ "vscode:build": "node scripts/build-vscode.js",
19
+ "vscode:install": "node scripts/install-vscode.js"
17
20
  },
18
21
  "dependencies": {
19
22
  "commander": "^14.0.0",
@@ -36,7 +39,41 @@
36
39
  "prettier": "^2.8.8",
37
40
  "sass": "^1.89.2",
38
41
  "sass-loader": "^16.0.5",
39
- "vue-template-compiler": "^2.6.14"
42
+ "vue-template-compiler": "^2.6.14",
43
+ "@types/vscode": "^1.60.0"
44
+ },
45
+ "vscode": {
46
+ "extension": {
47
+ "name": "vue-page-generator",
48
+ "displayName": "Vue Page Generator",
49
+ "description": "Generate Vue CRUD pages from Swagger API",
50
+ "version": "0.0.1",
51
+ "engines": {
52
+ "vscode": "^1.60.0"
53
+ },
54
+ "activationEvents": [
55
+ "onCommand:vue-generator.createPage"
56
+ ],
57
+ "main": "./src/vscode/extension.js",
58
+ "contributes": {
59
+ "commands": [
60
+ {
61
+ "command": "vue-generator.createPage",
62
+ "title": "Generate Vue Page",
63
+ "category": "Vue Generator"
64
+ }
65
+ ],
66
+ "menus": {
67
+ "explorer/context": [
68
+ {
69
+ "command": "vue-generator.createPage",
70
+ "group": "navigation",
71
+ "when": "resourceExtname == .vue || resourceExtname == .js"
72
+ }
73
+ ]
74
+ }
75
+ }
76
+ }
40
77
  },
41
78
  "eslintConfig": {
42
79
  "root": true,
@@ -55,7 +92,7 @@
55
92
  "keywords": [
56
93
  "ol-base-components"
57
94
  ],
58
- "description": "二次封装的通用组件库。table,form。核心解决前后端字段联调问题。",
95
+ "description": "交互式命令行方式自动生成联调好的CRUD页面",
59
96
  "browserslist": [
60
97
  "> 1%",
61
98
  "last 2 versions",
@@ -0,0 +1,30 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ // 复制扩展文件到输出目录
5
+ function buildVSCodeExtension() {
6
+ const srcDir = path.join(__dirname, "../src/vscode");
7
+ const outDir = path.join(__dirname, "../dist/vscode-extension");
8
+
9
+ // 创建输出目录
10
+ if (!fs.existsSync(outDir)) {
11
+ fs.mkdirSync(outDir, { recursive: true });
12
+ }
13
+
14
+ // 复制文件
15
+ fs.copyFileSync(path.join(srcDir, "extension.js"), path.join(outDir, "extension.js"));
16
+
17
+ // 复制 webview 目录
18
+ const webviewSrcDir = path.join(srcDir, "webview");
19
+ const webviewOutDir = path.join(outDir, "webview");
20
+
21
+ if (!fs.existsSync(webviewOutDir)) {
22
+ fs.mkdirSync(webviewOutDir, { recursive: true });
23
+ }
24
+
25
+ fs.copyFileSync(path.join(webviewSrcDir, "panel.js"), path.join(webviewOutDir, "panel.js"));
26
+
27
+ console.log("VSCode extension built successfully!");
28
+ }
29
+
30
+ buildVSCodeExtension();
@@ -70,7 +70,7 @@ const vue2Template = (moduleName, config = {}) => {
70
70
  if (config.hasAdd || config.hasEdit || config.hasDetail) {
71
71
  methods.push(`
72
72
  onCancel() {
73
- this.dialogVisible = false;
73
+ this.formConfig.dialogVisible = false;
74
74
  }`);
75
75
  }
76
76
 
@@ -98,8 +98,10 @@ const vue2Template = (moduleName, config = {}) => {
98
98
  if (config.hasAdd) {
99
99
  methods.push(`
100
100
  addBtnHandler() {
101
- this.type = 1;
102
- this.dialogVisible = true;
101
+ this.formConfig.title = "新增";
102
+ this.formConfig.type = 1;
103
+ this.formConfig.formData = {};
104
+ this.formConfig.dialogVisible = true;
103
105
  }`);
104
106
  }
105
107
 
@@ -112,11 +114,12 @@ const vue2Template = (moduleName, config = {}) => {
112
114
  ${
113
115
  config.hasDetail
114
116
  ? `const { result = {} } = await ${detailUrlKey}(row.${config.rowId});
115
- this.formData = result || {};`
116
- : `this.formData = { ...row };`
117
+ this.formConfig.formData = result || {};`
118
+ : `this.formConfig.formData = { ...row };`
117
119
  }
118
- this.type = 2;
119
- this.dialogVisible = true;
120
+ this.formConfig.title = "编辑";
121
+ this.formConfig.type = 2;
122
+ this.formConfig.dialogVisible = true;
120
123
  }`);
121
124
  }
122
125
 
@@ -128,9 +131,10 @@ const vue2Template = (moduleName, config = {}) => {
128
131
  if(data.length !== 1) return this.$message.info("请选择一条数据");
129
132
  const row = data[0];
130
133
  const { result = {} } = await ${detailUrlKey}(row.${config.rowId});
131
- this.formData = result || {};
132
- this.type = 0;
133
- this.dialogVisible = true;
134
+ this.formConfig.formData = result || {};
135
+ this.formConfig.title = "详情";
136
+ this.formConfig.type = 0;
137
+ this.formConfig.dialogVisible = true;
134
138
  }`);
135
139
  }
136
140
 
@@ -204,10 +208,11 @@ const vue2Template = (moduleName, config = {}) => {
204
208
  />
205
209
  ${
206
210
  config.hasDialog
207
- ? `<el-dialog :title="this.form.title" :visible.sync="dialogVisible" width="80%">
211
+ ? `<el-dialog :title="formConfig.title" :visible.sync="formConfig.dialogVisible" width="80%">
208
212
  <FormModule
209
- v-if="dialogVisible"
210
- :formData="formData"
213
+ v-if="formConfig.dialogVisible"
214
+ :formData="formConfig.formData"
215
+ :type="formConfig.type"
211
216
  @onCancel="onCancel"
212
217
  @onSubmit="onSubmit"
213
218
  />
@@ -265,9 +270,12 @@ export default {
265
270
  },
266
271
  ${
267
272
  config.hasDialog
268
- ? `type: 1,
269
- formData: {},
270
- dialogVisible: false`
273
+ ? `formConfig: {
274
+ type: 1,
275
+ formData: {},
276
+ title:"",
277
+ dialogVisible: false
278
+ }`
271
279
  : ""
272
280
  }
273
281
  }
@@ -311,8 +319,7 @@ export default {
311
319
  handleindexChange(val) {
312
320
  this.paginations.page = val;
313
321
  this.init();
314
- },
315
- ${generateMethods()}
322
+ },${generateMethods()}
316
323
  }
317
324
  }
318
325
  </script>
@@ -387,7 +394,7 @@ export default {
387
394
  }
388
395
  },
389
396
  created(){
390
- this.form.value = { ...this.formData };
397
+ if(this.type !== 1) this.form.value = { ...this.formData };
391
398
  },
392
399
  methods: {
393
400
  onCancel() {
@@ -0,0 +1,20 @@
1
+ const vscode = require("vscode");
2
+ const { GeneratorPanel } = require("./webview/panel");
3
+
4
+ function activate(context) {
5
+ console.log("Vue Page Generator is now active!");
6
+
7
+ // 注册右键菜单命令
8
+ const disposable = vscode.commands.registerCommand("vue-generator.createPage", uri => {
9
+ GeneratorPanel.createOrShow(context.extensionUri, uri);
10
+ });
11
+
12
+ context.subscriptions.push(disposable);
13
+ }
14
+
15
+ function deactivate() {}
16
+
17
+ module.exports = {
18
+ activate,
19
+ deactivate,
20
+ };
@@ -0,0 +1,734 @@
1
+ const vscode = require("vscode");
2
+ const path = require("path");
3
+ const fs = require("fs");
4
+
5
+ // 复用现有的模板生成逻辑
6
+ function generateKeyName(url, method) {
7
+ const cleanedUrl = url.replace(/\/api\/app/, "");
8
+ const arr = cleanedUrl.split("/");
9
+
10
+ const processedArr = arr.map(item =>
11
+ item
12
+ .replace(/{(.*?)}/, (_, param) => `By${param.charAt(0).toUpperCase() + param.slice(1)}`)
13
+ .replace(/[-_]/g, "")
14
+ );
15
+
16
+ if (processedArr[0] === "") {
17
+ processedArr.shift();
18
+ }
19
+
20
+ const resultArr = [];
21
+ for (let i = 0; i < processedArr.length; i++) {
22
+ if (i === 0 || processedArr[i] !== processedArr[i - 1]) {
23
+ const capitalizedItem = processedArr[i].charAt(0).toUpperCase() + processedArr[i].slice(1);
24
+ resultArr.push(capitalizedItem);
25
+ }
26
+ }
27
+ const key = resultArr.join("");
28
+ return `${method.toLowerCase()}${key}`;
29
+ }
30
+
31
+ // 复用现有的 vue2Template 函数
32
+ function vue2Template(moduleName, config) {
33
+ let pageUrlKey = "",
34
+ exportUrlKey = "",
35
+ addUrlKey = "",
36
+ editUrlKey = "",
37
+ deleteUrlKey = "",
38
+ detailUrlKey = "",
39
+ baseUrlKey = "";
40
+
41
+ if (config.pageUrl) pageUrlKey = generateKeyName(config.pageUrl, "get");
42
+ if (config.exportUrl) exportUrlKey = generateKeyName(config.exportUrl, "post");
43
+ if (config.detailUrl) {
44
+ detailUrlKey = generateKeyName(config.detailUrl, "get");
45
+ baseUrlKey = `${detailUrlKey}CompleteUrl`;
46
+ }
47
+ if (config.editUrl) {
48
+ editUrlKey = generateKeyName(config.editUrl, "put");
49
+ baseUrlKey = `${editUrlKey}CompleteUrl`;
50
+ }
51
+ if (config.addUrl) baseUrlKey = addUrlKey = generateKeyName(config.addUrl, "post");
52
+ if (config.deleteUrl) deleteUrlKey = generateKeyName(config.deleteUrl, "delete");
53
+
54
+ const generateImports = () => {
55
+ const imports = [];
56
+ if (config.pageUrl) imports.push(`${pageUrlKey}`);
57
+ if (config.addUrl) imports.push(`${addUrlKey}`);
58
+ if (config.editUrl) imports.push(`${editUrlKey}`);
59
+ if (config.detailUrl) imports.push(`${detailUrlKey}`);
60
+ if (config.deleteUrl) imports.push(`${deleteUrlKey}`);
61
+ return imports.join(", ");
62
+ };
63
+
64
+ const generateMethods = () => {
65
+ const methods = [];
66
+ if (config.hasAdd) {
67
+ methods.push(`
68
+ addBtnHandler() {
69
+ this.type = 1;
70
+ this.dialogVisible = true;
71
+ }`);
72
+ }
73
+
74
+ if (config.hasEdit) {
75
+ methods.push(`
76
+ ${config.hasDetail ? `async ` : ``}editBtnHandler() {
77
+ const data = this.multipleSelection;
78
+ if(data.length !== 1) return this.$message.info("请选择一条数据");
79
+ const row = data[0];
80
+ ${
81
+ config.hasDetail
82
+ ? `const { result = {} } = await ${detailUrlKey}(row.${config.rowId});
83
+ this.formData = result || {};`
84
+ : `this.formData = { ...row };`
85
+ }
86
+ this.type = 2;
87
+ this.dialogVisible = true;
88
+ }`);
89
+ }
90
+
91
+ if (config.hasDetail) {
92
+ methods.push(`async detailBtnHandler() {
93
+ const data = this.multipleSelection;
94
+ if(data.length !== 1) return this.$message.info("请选择一条数据");
95
+ const row = data[0];
96
+ const { result = {} } = await ${detailUrlKey}(row.${config.rowId});
97
+ this.formData = result || {};
98
+ this.type = 0;
99
+ this.dialogVisible = true;
100
+ }`);
101
+ }
102
+
103
+ if (config.hasDelete) {
104
+ methods.push(`
105
+ deleteBtnHandler() {
106
+ const data = this.multipleSelection;
107
+ if(data.length !== 1) return this.$message.info("请选择一条数据");
108
+ const row = data[0];
109
+ this.$confirm('确认删除当前数据吗?', '提示', {
110
+ confirmButtonText: '确定',
111
+ cancelButtonText: '取消',
112
+ type: 'warning'
113
+ }).then(() => {
114
+ ${deleteUrlKey}(row.${config.rowId}).then(() => {
115
+ this.$message.success('删除成功');
116
+ this.init();
117
+ }).catch(() => {
118
+ this.$message.error('删除失败');
119
+ });
120
+ }).catch(() => {});
121
+ }`);
122
+ }
123
+
124
+ if (config.hasAdd || config.hasEdit || config.hasDetail) {
125
+ methods.push(`
126
+ onCancel() {
127
+ this.dialogVisible = false;
128
+ }`);
129
+ }
130
+
131
+ if (config.hasAdd || config.hasEdit) {
132
+ methods.push(`
133
+ async onSubmit({ form, data }) {
134
+ if(form.type === 1){
135
+ const res = await ${addUrlKey}(data);
136
+ if(res.code !== 200) return;
137
+ this.$message("新建成功");
138
+ }else if (form.type === 2) {
139
+ const res = await ${editUrlKey}(data['${config.rowId}'], data);
140
+ if(res.code !== 200) return;
141
+ this.$message("编辑成功");
142
+ this.init();
143
+ };
144
+ this.init();
145
+ this.onCancel()
146
+ }`);
147
+ }
148
+
149
+ return methods.join(",");
150
+ };
151
+
152
+ return `<!--
153
+ Filename: ${moduleName}.vue
154
+ name: ${moduleName}
155
+ Created Date: ${new Date().toLocaleString()}
156
+ Author:
157
+ -->
158
+ <template>
159
+ <div>
160
+ <ol-search
161
+ :url="swaggerUrl.${pageUrlKey}"
162
+ :form-search-data="formSearchData"
163
+ @handleSearch="handleSearch"
164
+ @handleReset="handleReset"
165
+ />
166
+ <ol-table
167
+ :url="swaggerUrl.${pageUrlKey}"
168
+ :paginations="paginations"
169
+ :btnlist="this.hasBtn(this)"
170
+ :empty-img="tableData.emptyImg"
171
+ :table-data="tableData"
172
+ :multiple-selection="multipleSelection"
173
+ @SelectionChange="SelectionChange"
174
+ @handleSizeChange="handleSizeChange"
175
+ @handleindexChange="handleindexChange"
176
+ />
177
+ ${
178
+ config.hasDialog
179
+ ? `<el-dialog :title="this.form.title" :visible.sync="dialogVisible" width="80%">
180
+ <FormModule
181
+ v-if="dialogVisible"
182
+ :formData="formData"
183
+ @onCancel="onCancel"
184
+ @onSubmit="onSubmit"
185
+ />
186
+ </el-dialog>`
187
+ : ""
188
+ }
189
+ </div>
190
+ </template>
191
+ <script>
192
+ import { ${generateImports()} } from "@/api/modules";
193
+ import { ${config.swaggerModule} } from '@/api/swagger';
194
+ ${config.hasDialog ? `import FormModule from "./components/formModule.vue"` : ""}
195
+ export default {
196
+ name: "${moduleName}",
197
+ ${
198
+ config.hasDialog
199
+ ? `components: {
200
+ FormModule
201
+ },`
202
+ : ""
203
+ }
204
+ data() {
205
+ return {
206
+ swaggerUrl: ${config.swaggerModule},
207
+ multipleSelection: [],
208
+ formSearchData: {
209
+ reset: true,
210
+ expendShow: true,
211
+ value: {},
212
+ tableSearch: []
213
+ },
214
+ tableData: {
215
+ loading: false,
216
+ emptyImg: true,
217
+ options: {
218
+ selection: true,
219
+ index: null,
220
+ headTool: true,
221
+ refreshBtn: true,
222
+ downloadBtn: true
223
+ },
224
+ rows: [],
225
+ columns: [],
226
+ operatesAttrs: {},
227
+ operates: [],
228
+ tableHeightDiff: 330
229
+ },
230
+ paginations: {
231
+ page: 1,
232
+ total: 10,
233
+ limit: 30,
234
+ pagetionShow: true
235
+ },
236
+ ${
237
+ config.hasDialog
238
+ ? `type: 1,
239
+ formData: {},
240
+ dialogVisible: false`
241
+ : ""
242
+ }
243
+ }
244
+ },
245
+ created() {
246
+ this.init()
247
+ },
248
+ methods: {
249
+ async init() {
250
+ const params = {
251
+ ...this.formSearchData.value,
252
+ Page: this.paginations.page,
253
+ MaxResultCount: this.paginations.limit
254
+ };
255
+ const { result: { items = [], totalCount = 0 } = {} } = await ${pageUrlKey}(params, {
256
+ isLoading: true
257
+ });
258
+ this.tableData.rows = items;
259
+ this.paginations.total = totalCount;
260
+ this.tableData.emptyImg = true;
261
+ },
262
+ handleSearch(from) {
263
+ this.formSearchData.value = { ...from };
264
+ this.paginations.page = 1;
265
+ this.init();
266
+ },
267
+ handleReset() {
268
+ for (let key in this.formSearchData.value) {
269
+ this.formSearchData.value[key] = null;
270
+ }
271
+ this.paginations.page = 1;
272
+ },
273
+ SelectionChange(row) {
274
+ this.multipleSelection = row;
275
+ },
276
+ handleSizeChange(val) {
277
+ this.paginations.page = 1;
278
+ this.paginations.limit = val;
279
+ this.init();
280
+ },
281
+ handleindexChange(val) {
282
+ this.paginations.page = val;
283
+ this.init();
284
+ },
285
+ ${
286
+ config.hasExport
287
+ ? `export() {
288
+ const timer = this.formSearchData.value.createdTime;
289
+ this.formSearchData.value.BeginTime = timer ? timer[0] : "";
290
+ this.formSearchData.value.EndTime = timer ? timer[1] : "";
291
+ this.post({
292
+ url: ${config.swaggerModule}.${exportUrlKey},
293
+ isLoading: true,
294
+ responseType: "blob",
295
+ data: Object.assign(this.formSearchData.value, {
296
+ Page: this.paginations.page,
297
+ MaxResultCount: this.paginations.limit
298
+ })
299
+ }).then(res => {
300
+ this.fnexsl(res);
301
+ });
302
+ },`
303
+ : ""
304
+ }${generateMethods()}
305
+ }
306
+ }
307
+ </script>
308
+ `;
309
+ }
310
+
311
+ // 复用现有的 vue2Form 函数
312
+ function vue2Form(moduleName, config) {
313
+ let editUrlKey = "",
314
+ detailUrlKey = "",
315
+ baseUrlKey = "";
316
+
317
+ if (config.detailUrl) {
318
+ detailUrlKey = generateKeyName(config.detailUrl, "get");
319
+ baseUrlKey = `${detailUrlKey}CompleteUrl`;
320
+ }
321
+
322
+ if (config.editUrl) {
323
+ editUrlKey = generateKeyName(config.editUrl, "put");
324
+ baseUrlKey = `${editUrlKey}CompleteUrl`;
325
+ }
326
+
327
+ if (config.addUrl) baseUrlKey = generateKeyName(config.addUrl, "post");
328
+
329
+ return `<!--
330
+ Filename: ${moduleName}.vue
331
+ name: ${moduleName}
332
+ Created Date: ${new Date().toLocaleString()}
333
+ Author:
334
+ -->
335
+ <template>
336
+ <ol-form
337
+ v-if="dialogVisible"
338
+ :url="swaggerUrl.${baseUrlKey}"
339
+ :form="form"
340
+ @onCancel="onCancel"
341
+ @onSubmit="onSubmit"
342
+ />
343
+ </template>
344
+ <script>
345
+ import { ${config.swaggerModule} } from '@/api/swagger';
346
+ export default {
347
+ name: "${moduleName}Form",
348
+ props: {
349
+ formData: {
350
+ type: Object,
351
+ default: () => ({})
352
+ },
353
+ type: {
354
+ type: Number,
355
+ default: 1
356
+ }
357
+ },
358
+ data() {
359
+ return {
360
+ swaggerUrl: ${config.swaggerModule},
361
+ form: {
362
+ type: this.type,
363
+ title: "",
364
+ defaultValue: {},
365
+ value: {},
366
+ model: [],
367
+ rules: {},
368
+ attrs: {},
369
+ }
370
+ }
371
+ },
372
+ watch: {
373
+ type: {
374
+ handler(val){
375
+ this.form.type = val;
376
+ },
377
+ immediate: true
378
+ }
379
+ },
380
+ created(){
381
+ this.form.value = { ...this.formData };
382
+ },
383
+ methods: {
384
+ onCancel() {
385
+ this.$emit("onCancel");
386
+ },
387
+ onSubmit({form, data}) {
388
+ this.$emit("onSubmit", { form, data });
389
+ }
390
+ }
391
+ }
392
+ </script>
393
+ `;
394
+ }
395
+
396
+ class GeneratorPanel {
397
+ static currentPanel = undefined;
398
+
399
+ static createOrShow(extensionUri, targetUri) {
400
+ const column = vscode.window.activeTextEditor
401
+ ? vscode.window.activeTextEditor.viewColumn
402
+ : undefined;
403
+
404
+ if (GeneratorPanel.currentPanel) {
405
+ GeneratorPanel.currentPanel._panel.reveal(column);
406
+ return;
407
+ }
408
+
409
+ const panel = vscode.window.createWebviewPanel(
410
+ "vueGenerator",
411
+ "Vue 页面生成器",
412
+ column || vscode.ViewColumn.One,
413
+ {
414
+ enableScripts: true,
415
+ localResourceRoots: [extensionUri],
416
+ }
417
+ );
418
+
419
+ GeneratorPanel.currentPanel = new GeneratorPanel(panel, extensionUri, targetUri);
420
+ }
421
+
422
+ constructor(panel, extensionUri, targetUri) {
423
+ this._panel = panel;
424
+ this._extensionUri = extensionUri;
425
+ this._targetUri = targetUri;
426
+ this._disposables = [];
427
+
428
+ this._setWebviewMessageListener();
429
+ this._update();
430
+ }
431
+
432
+ _setWebviewMessageListener() {
433
+ this._panel.webview.onDidReceiveMessage(
434
+ message => {
435
+ switch (message.command) {
436
+ case "generate":
437
+ this._generateFiles(message.config);
438
+ return;
439
+ }
440
+ },
441
+ undefined,
442
+ this._disposables
443
+ );
444
+ }
445
+
446
+ async _generateFiles(config) {
447
+ try {
448
+ const moduleName = config.moduleName;
449
+ const targetPath = path.dirname(this._targetUri.fsPath);
450
+ const outputDir = path.join(targetPath, moduleName);
451
+
452
+ // 检查目录是否存在
453
+ if (fs.existsSync(outputDir)) {
454
+ vscode.window.showErrorMessage(`❌ 创建失败,文件夹 ${outputDir} 已存在`);
455
+ return;
456
+ }
457
+
458
+ // 创建目录
459
+ fs.mkdirSync(outputDir, { recursive: true });
460
+
461
+ // 生成主页面
462
+ const mainContent = vue2Template(moduleName, config);
463
+ const mainPath = path.join(outputDir, "index.vue");
464
+ fs.writeFileSync(mainPath, mainContent);
465
+
466
+ // 如果有弹窗功能,生成表单组件
467
+ if (config.hasDialog) {
468
+ const componentsDir = path.join(outputDir, "components");
469
+ fs.mkdirSync(componentsDir, { recursive: true });
470
+
471
+ const formContent = vue2Form(moduleName, config);
472
+ const formPath = path.join(componentsDir, "formModule.vue");
473
+ fs.writeFileSync(formPath, formContent);
474
+ }
475
+
476
+ vscode.window.showInformationMessage(`✅ 模板已生成并保存到 ${outputDir}`);
477
+
478
+ // 打开生成的文件
479
+ const document = await vscode.workspace.openTextDocument(mainPath);
480
+ vscode.window.showTextDocument(document);
481
+ } catch (error) {
482
+ vscode.window.showErrorMessage(`❌ 发生错误:${error.message}`);
483
+ }
484
+ }
485
+
486
+ _update() {
487
+ const webview = this._panel.webview;
488
+ this._panel.title = "Vue 页面生成器";
489
+ this._panel.webview.html = this._getHtmlForWebview(webview);
490
+ }
491
+
492
+ _getHtmlForWebview(webview) {
493
+ return `<!DOCTYPE html>
494
+ <html lang="zh-CN">
495
+ <head>
496
+ <meta charset="UTF-8">
497
+ <title>Vue 页面生成器</title>
498
+ <style>
499
+ body {
500
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
501
+ padding: 20px;
502
+ background-color: var(--vscode-editor-background);
503
+ color: var(--vscode-editor-foreground);
504
+ }
505
+ .container {
506
+ max-width: 600px;
507
+ margin: 0 auto;
508
+ }
509
+ .form-group {
510
+ margin-bottom: 20px;
511
+ }
512
+ label {
513
+ display: block;
514
+ margin-bottom: 5px;
515
+ font-weight: 500;
516
+ }
517
+ input[type="text"], input[type="url"] {
518
+ width: 100%;
519
+ padding: 8px 12px;
520
+ border: 1px solid var(--vscode-input-border);
521
+ border-radius: 4px;
522
+ background-color: var(--vscode-input-background);
523
+ color: var(--vscode-input-foreground);
524
+ box-sizing: border-box;
525
+ }
526
+ .checkbox-group {
527
+ display: flex;
528
+ flex-wrap: wrap;
529
+ gap: 15px;
530
+ }
531
+ .checkbox-group label {
532
+ display: flex;
533
+ align-items: center;
534
+ margin-bottom: 0;
535
+ cursor: pointer;
536
+ }
537
+ .checkbox-group input[type="checkbox"] {
538
+ margin-right: 5px;
539
+ }
540
+ .btn {
541
+ background-color: var(--vscode-button-background);
542
+ color: var(--vscode-button-foreground);
543
+ border: none;
544
+ padding: 10px 20px;
545
+ border-radius: 4px;
546
+ cursor: pointer;
547
+ font-size: 14px;
548
+ }
549
+ .btn:hover {
550
+ background-color: var(--vscode-button-hoverBackground);
551
+ }
552
+ .section {
553
+ background-color: var(--vscode-editor-inactiveSelectionBackground);
554
+ padding: 15px;
555
+ border-radius: 6px;
556
+ margin-bottom: 20px;
557
+ }
558
+ .section h3 {
559
+ margin-top: 0;
560
+ margin-bottom: 15px;
561
+ color: var(--vscode-editor-foreground);
562
+ }
563
+ </style>
564
+ </head>
565
+ <body>
566
+ <div class="container">
567
+ <h2>🎉 Vue 页面生成器</h2>
568
+
569
+ <div class="section">
570
+ <h3>基础配置</h3>
571
+ <div class="form-group">
572
+ <label for="moduleName">页面名称:</label>
573
+ <input type="text" id="moduleName" placeholder="请输入页面名称" required>
574
+ </div>
575
+ </div>
576
+
577
+ <div class="section">
578
+ <h3>API 配置</h3>
579
+ <div class="form-group">
580
+ <label for="pageUrl">分页接口地址:</label>
581
+ <input type="url" id="pageUrl" placeholder="/api/app/xxx/paged-result" required>
582
+ </div>
583
+
584
+ <div class="form-group">
585
+ <label>
586
+ <input type="checkbox" id="hasExport"> 是否有导出接口
587
+ </label>
588
+ </div>
589
+
590
+ <div class="form-group" id="exportUrlGroup" style="display:none;">
591
+ <label for="exportUrl">导出接口地址:</label>
592
+ <input type="url" id="exportUrl" placeholder="/api/app/xxx/export">
593
+ </div>
594
+ </div>
595
+
596
+ <div class="section">
597
+ <h3>功能选择</h3>
598
+ <div class="form-group">
599
+ <div class="checkbox-group">
600
+ <label><input type="checkbox" id="hasAdd"> 新增功能</label>
601
+ <label><input type="checkbox" id="hasEdit"> 编辑功能</label>
602
+ <label><input type="checkbox" id="hasDelete"> 删除功能</label>
603
+ <label><input type="checkbox" id="hasDetail"> 详情功能</label>
604
+ </div>
605
+ </div>
606
+ </div>
607
+
608
+ <div class="section" id="operationConfig" style="display:none;">
609
+ <h3>操作接口配置</h3>
610
+ <div class="form-group">
611
+ <label for="baseUrl">操作接口基础路径:</label>
612
+ <input type="url" id="baseUrl" placeholder="/api/app/xxx">
613
+ </div>
614
+
615
+ <div class="form-group">
616
+ <label for="idField">URL后缀ID字段名:</label>
617
+ <input type="text" id="idField" placeholder="admissionInfoId">
618
+ </div>
619
+
620
+ <div class="form-group">
621
+ <label for="rowId">行数据中ID字段键名:</label>
622
+ <input type="text" id="rowId" placeholder="id">
623
+ </div>
624
+ </div>
625
+
626
+ <div class="section">
627
+ <h3>模块配置</h3>
628
+ <div class="form-group">
629
+ <label for="swaggerModule">接口模块名:</label>
630
+ <input type="text" id="swaggerModule" placeholder="AdmissionInfo">
631
+ </div>
632
+ </div>
633
+
634
+ <button class="btn" id="generateBtn">🚀 生成页面</button>
635
+ </div>
636
+
637
+ <script>
638
+ const vscode = acquireVsCodeApi();
639
+
640
+ // 获取DOM元素
641
+ const moduleNameInput = document.getElementById('moduleName');
642
+ const pageUrlInput = document.getElementById('pageUrl');
643
+ const hasExportCheckbox = document.getElementById('hasExport');
644
+ const exportUrlGroup = document.getElementById('exportUrlGroup');
645
+ const exportUrlInput = document.getElementById('exportUrl');
646
+ const hasAddCheckbox = document.getElementById('hasAdd');
647
+ const hasEditCheckbox = document.getElementById('hasEdit');
648
+ const hasDeleteCheckbox = document.getElementById('hasDelete');
649
+ const hasDetailCheckbox = document.getElementById('hasDetail');
650
+ const operationConfig = document.getElementById('operationConfig');
651
+ const baseUrlInput = document.getElementById('baseUrl');
652
+ const idFieldInput = document.getElementById('idField');
653
+ const rowIdInput = document.getElementById('rowId');
654
+ const swaggerModuleInput = document.getElementById('swaggerModule');
655
+ const generateBtn = document.getElementById('generateBtn');
656
+
657
+ // 监听导出功能选择
658
+ hasExportCheckbox.addEventListener('change', () => {
659
+ exportUrlGroup.style.display = hasExportCheckbox.checked ? 'block' : 'none';
660
+ });
661
+
662
+ // 监听功能选择
663
+ function updateOperationConfig() {
664
+ const hasOperations = hasAddCheckbox.checked || hasEditCheckbox.checked ||
665
+ hasDeleteCheckbox.checked || hasDetailCheckbox.checked;
666
+ operationConfig.style.display = hasOperations ? 'block' : 'none';
667
+ }
668
+
669
+ hasAddCheckbox.addEventListener('change', updateOperationConfig);
670
+ hasEditCheckbox.addEventListener('change', updateOperationConfig);
671
+ hasDeleteCheckbox.addEventListener('change', updateOperationConfig);
672
+ hasDetailCheckbox.addEventListener('change', updateOperationConfig);
673
+
674
+ // 生成按钮点击事件
675
+ generateBtn.addEventListener('click', () => {
676
+ // 验证必填字段
677
+ if (!moduleNameInput.value.trim()) {
678
+ alert('请输入页面名称');
679
+ return;
680
+ }
681
+ if (!pageUrlInput.value.trim()) {
682
+ alert('请输入分页接口地址');
683
+ return;
684
+ }
685
+
686
+ const config = {
687
+ moduleName: moduleNameInput.value.trim(),
688
+ pageUrl: pageUrlInput.value.trim(),
689
+ hasExport: hasExportCheckbox.checked,
690
+ exportUrl: exportUrlInput.value.trim(),
691
+ hasAdd: hasAddCheckbox.checked,
692
+ hasEdit: hasEditCheckbox.checked,
693
+ hasDelete: hasDeleteCheckbox.checked,
694
+ hasDetail: hasDetailCheckbox.checked,
695
+ baseUrl: baseUrlInput.value.trim(),
696
+ idField: idFieldInput.value.trim() || 'id',
697
+ rowId: rowIdInput.value.trim() || 'id',
698
+ swaggerModule: swaggerModuleInput.value.trim() || 'Module',
699
+ hasDialog: hasAddCheckbox.checked || hasEditCheckbox.checked || hasDetailCheckbox.checked
700
+ };
701
+
702
+ // 发送消息给扩展
703
+ vscode.postMessage({
704
+ command: 'generate',
705
+ config: config
706
+ });
707
+ });
708
+
709
+ // 设置默认值
710
+ pageUrlInput.value = '/api/app/admission-info/paged-result';
711
+ baseUrlInput.value = '/api/app/admission-info/admission-info';
712
+ idFieldInput.value = 'admissionInfoId';
713
+ rowIdInput.value = 'id';
714
+ swaggerModuleInput.value = 'AdmissionInfo';
715
+ </script>
716
+ </body>
717
+ </html>`;
718
+ }
719
+
720
+ dispose() {
721
+ GeneratorPanel.currentPanel = undefined;
722
+ this._panel.dispose();
723
+ while (this._disposables.length) {
724
+ const x = this._disposables.pop();
725
+ if (x) {
726
+ x.dispose();
727
+ }
728
+ }
729
+ }
730
+ }
731
+
732
+ module.exports = {
733
+ GeneratorPanel,
734
+ };