ol-base-components 2.7.10 → 2.8.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/package.json CHANGED
@@ -1,19 +1,22 @@
1
1
  {
2
2
  "name": "ol-base-components",
3
- "version": "2.7.10",
3
+ "version": "2.8.1",
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();
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const os = require("os");
5
+
6
+ // 检测 VSCode 扩展目录
7
+ function getVSCodeExtensionsPath() {
8
+ const platform = os.platform();
9
+ const homeDir = os.homedir();
10
+
11
+ switch (platform) {
12
+ case "win32":
13
+ return path.join(homeDir, ".vscode", "extensions");
14
+ case "darwin":
15
+ return path.join(homeDir, ".vscode", "extensions");
16
+ case "linux":
17
+ return path.join(homeDir, ".vscode", "extensions");
18
+ default:
19
+ throw new Error("Unsupported platform");
20
+ }
21
+ }
22
+
23
+ // 安装 VSCode 扩展
24
+ function installVSCodeExtension() {
25
+ try {
26
+ const extensionsPath = getVSCodeExtensionsPath();
27
+ const extensionName = "vue-page-generator";
28
+ const extensionDir = path.join(extensionsPath, extensionName);
29
+
30
+ // 创建扩展目录
31
+ if (!fs.existsSync(extensionDir)) {
32
+ fs.mkdirSync(extensionDir, { recursive: true });
33
+ }
34
+
35
+ // 复制扩展文件
36
+ const srcDir = path.join(__dirname, "../src/vscode");
37
+ const files = ["extension.js"];
38
+
39
+ files.forEach(file => {
40
+ const srcFile = path.join(srcDir, file);
41
+ const destFile = path.join(extensionDir, file);
42
+
43
+ if (fs.existsSync(srcFile)) {
44
+ fs.copyFileSync(srcFile, destFile);
45
+ console.log(`✅ 复制文件: ${file}`);
46
+ }
47
+ });
48
+
49
+ // 复制 webview 目录
50
+ const webviewSrcDir = path.join(srcDir, "webview");
51
+ const webviewDestDir = path.join(extensionDir, "webview");
52
+
53
+ if (fs.existsSync(webviewSrcDir)) {
54
+ if (!fs.existsSync(webviewDestDir)) {
55
+ fs.mkdirSync(webviewDestDir, { recursive: true });
56
+ }
57
+
58
+ const panelFile = path.join(webviewSrcDir, "panel.js");
59
+ const panelDestFile = path.join(webviewDestDir, "panel.js");
60
+
61
+ if (fs.existsSync(panelFile)) {
62
+ fs.copyFileSync(panelFile, panelDestFile);
63
+ console.log("✅ 复制文件: webview/panel.js");
64
+ }
65
+ }
66
+
67
+ // 创建 package.json
68
+ const packageJson = {
69
+ name: extensionName,
70
+ displayName: "Vue Page Generator",
71
+ description: "Generate Vue CRUD pages from Swagger API",
72
+ version: "0.0.1",
73
+ engines: {
74
+ vscode: "^1.60.0",
75
+ },
76
+ activationEvents: ["onCommand:vue-generator.createPage"],
77
+ main: "./extension.js",
78
+ contributes: {
79
+ commands: [
80
+ {
81
+ command: "vue-generator.createPage",
82
+ title: "Generate Vue Page",
83
+ category: "Vue Generator",
84
+ },
85
+ ],
86
+ menus: {
87
+ "explorer/context": [
88
+ {
89
+ command: "vue-generator.createPage",
90
+ group: "navigation",
91
+ when: "resourceExtname == .vue || resourceExtname == .js",
92
+ },
93
+ ],
94
+ },
95
+ },
96
+ };
97
+
98
+ const packageJsonPath = path.join(extensionDir, "package.json");
99
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
100
+ console.log("✅ 创建文件: package.json");
101
+
102
+ console.log("\n�� VSCode 扩展安装成功!");
103
+ console.log("请重启 VSCode 以激活扩展。");
104
+ console.log("安装位置:", extensionDir);
105
+ } catch (error) {
106
+ console.error("❌ 安装失败:", error.message);
107
+ process.exit(1);
108
+ }
109
+ }
110
+
111
+ // 如果直接运行此脚本
112
+ if (require.main === module) {
113
+ installVSCodeExtension();
114
+ }
115
+
116
+ module.exports = {
117
+ installVSCodeExtension,
118
+ };
@@ -319,8 +319,7 @@ export default {
319
319
  handleindexChange(val) {
320
320
  this.paginations.page = val;
321
321
  this.init();
322
- },
323
- ${generateMethods()}
322
+ },${generateMethods()}
324
323
  }
325
324
  }
326
325
  </script>
@@ -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
+ };