nsgm-cli 2.1.12 → 2.1.14
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 +369 -163
- package/client/components/Button.tsx +3 -5
- package/client/components/__tests__/Button.test.tsx +10 -10
- package/client/layout/index.tsx +149 -137
- package/client/redux/reducers.ts +1 -1
- package/client/redux/store.ts +2 -1
- package/client/redux/template/manage/actions.ts +77 -88
- package/client/redux/template/manage/reducers.ts +25 -37
- package/client/redux/template/manage/types.ts +1 -1
- package/client/service/template/manage.ts +20 -21
- package/client/styled/common.ts +12 -13
- package/client/styled/layout/index.ts +19 -19
- package/client/styled/template/manage.ts +14 -13
- package/client/utils/common.ts +23 -21
- package/client/utils/cookie.ts +18 -19
- package/client/utils/fetch.ts +64 -100
- package/client/utils/menu.tsx +16 -3
- package/client/utils/sso.ts +74 -84
- package/eslint.config.js +38 -1
- package/generation/README.md +25 -18
- package/generation/__tests__/example.test.js +41 -0
- package/generation/client/utils/menu.tsx +9 -2
- package/generation/env.example +3 -0
- package/generation/eslint.config.js +112 -0
- package/generation/gitignore +6 -1
- package/generation/jest.config.js +40 -0
- package/generation/package.json +25 -4
- package/jest.config.js +23 -6
- package/lib/args.js +9 -1
- package/lib/cli/app.d.ts +28 -0
- package/lib/cli/app.js +99 -0
- package/lib/cli/commands/build.d.ts +2 -0
- package/lib/cli/commands/build.js +29 -0
- package/lib/cli/commands/create.d.ts +2 -0
- package/lib/cli/commands/create.js +113 -0
- package/lib/cli/commands/delete.d.ts +3 -0
- package/lib/cli/commands/delete.js +151 -0
- package/lib/cli/commands/export.d.ts +2 -0
- package/lib/cli/commands/export.js +42 -0
- package/lib/cli/commands/help.d.ts +2 -0
- package/lib/cli/commands/help.js +42 -0
- package/lib/cli/commands/init.d.ts +2 -0
- package/lib/cli/commands/init.js +115 -0
- package/lib/cli/commands/server.d.ts +3 -0
- package/lib/cli/commands/server.js +26 -0
- package/lib/cli/commands/upgrade.d.ts +2 -0
- package/lib/cli/commands/upgrade.js +38 -0
- package/lib/cli/commands/version.d.ts +2 -0
- package/lib/cli/commands/version.js +24 -0
- package/lib/cli/index.d.ts +16 -0
- package/lib/cli/index.js +33 -0
- package/lib/cli/parser.d.ts +22 -0
- package/lib/cli/parser.js +115 -0
- package/lib/cli/registry.d.ts +33 -0
- package/lib/cli/registry.js +81 -0
- package/lib/cli/types/project.d.ts +10 -0
- package/lib/cli/types/project.js +2 -0
- package/lib/cli/types.d.ts +31 -0
- package/lib/cli/types.js +20 -0
- package/lib/cli/utils/console.d.ts +62 -0
- package/lib/cli/utils/console.js +148 -0
- package/lib/cli/utils/index.d.ts +2 -0
- package/lib/cli/utils/index.js +7 -0
- package/lib/cli/utils/prompt.d.ts +83 -0
- package/lib/cli/utils/prompt.js +368 -0
- package/lib/constants.d.ts +58 -0
- package/lib/constants.js +162 -0
- package/lib/generate.d.ts +25 -3
- package/lib/generate.js +97 -621
- package/lib/generate_create.d.ts +9 -0
- package/lib/generate_create.js +326 -0
- package/lib/generate_delete.d.ts +8 -0
- package/lib/generate_delete.js +156 -0
- package/lib/generate_init.d.ts +50 -0
- package/lib/generate_init.js +492 -0
- package/lib/generators/base-generator.d.ts +47 -0
- package/lib/generators/base-generator.js +92 -0
- package/lib/generators/generator-factory.d.ts +20 -0
- package/lib/generators/generator-factory.js +25 -0
- package/lib/generators/page-generator.d.ts +41 -0
- package/lib/generators/page-generator.js +552 -0
- package/lib/generators/resolver-generator.d.ts +12 -0
- package/lib/generators/resolver-generator.js +303 -0
- package/lib/generators/schema-generator.d.ts +7 -0
- package/lib/generators/schema-generator.js +57 -0
- package/lib/generators/service-generator.d.ts +7 -0
- package/lib/generators/service-generator.js +119 -0
- package/lib/generators/sql-generator.d.ts +8 -0
- package/lib/generators/sql-generator.js +52 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +14 -193
- package/lib/server/csrf.js +9 -16
- package/lib/server/db.js +6 -7
- package/lib/server/graphql.js +5 -6
- package/lib/server/plugins/date.js +1 -1
- package/lib/server/utils/graphql-cache.js +3 -3
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils/project-config.d.ts +5 -0
- package/lib/utils/project-config.js +145 -0
- package/lib/utils.js +1 -1
- package/next.config.js +12 -8
- package/package.json +10 -7
- package/pages/_app.tsx +23 -28
- package/pages/_document.tsx +39 -19
- package/pages/index.tsx +84 -39
- package/pages/login.tsx +21 -21
- package/pages/template/manage.tsx +114 -89
- package/public/fonts/font-awesome.min.css +4 -0
- package/public/fonts/fontawesome-webfont.woff +0 -0
- package/public/fonts/fontawesome-webfont.woff2 +0 -0
- package/public/slbhealthcheck.html +1 -1
- package/server/apis/template.js +0 -2
- package/generation/eslintrc.js +0 -16
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Console = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
/**
|
|
9
|
+
* 控制台输出工具类
|
|
10
|
+
*/
|
|
11
|
+
class Console {
|
|
12
|
+
/**
|
|
13
|
+
* 成功消息
|
|
14
|
+
*/
|
|
15
|
+
static success(message) {
|
|
16
|
+
console.log(chalk_1.default.green('✅ ') + chalk_1.default.white(message));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 错误消息
|
|
20
|
+
*/
|
|
21
|
+
static error(message) {
|
|
22
|
+
console.log(chalk_1.default.red('❌ ') + chalk_1.default.white(message));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 警告消息
|
|
26
|
+
*/
|
|
27
|
+
static warning(message) {
|
|
28
|
+
console.log(chalk_1.default.yellow('⚠️ ') + chalk_1.default.white(message));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 信息消息
|
|
32
|
+
*/
|
|
33
|
+
static info(message) {
|
|
34
|
+
console.log(chalk_1.default.blue('ℹ️ ') + chalk_1.default.white(message));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 调试消息
|
|
38
|
+
*/
|
|
39
|
+
static debug(message) {
|
|
40
|
+
console.log(chalk_1.default.gray('🐛 ') + chalk_1.default.gray(message));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 标题
|
|
44
|
+
*/
|
|
45
|
+
static title(message) {
|
|
46
|
+
console.log(chalk_1.default.bold.blue(message));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 副标题
|
|
50
|
+
*/
|
|
51
|
+
static subtitle(message) {
|
|
52
|
+
console.log(chalk_1.default.cyan(message));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 突出显示
|
|
56
|
+
*/
|
|
57
|
+
static highlight(message) {
|
|
58
|
+
console.log(chalk_1.default.bold.yellow(message));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 分隔线
|
|
62
|
+
*/
|
|
63
|
+
static separator() {
|
|
64
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 空行
|
|
68
|
+
*/
|
|
69
|
+
static newLine(count = 1) {
|
|
70
|
+
console.log('\n'.repeat(count - 1));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 简单的加载动画
|
|
74
|
+
*/
|
|
75
|
+
static spinner(text, color = 'cyan') {
|
|
76
|
+
let spinnerInterval = null;
|
|
77
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
78
|
+
let currentFrame = 0;
|
|
79
|
+
return {
|
|
80
|
+
start() {
|
|
81
|
+
process.stdout.write(chalk_1.default[color](`${frames[0]} ${text}`));
|
|
82
|
+
spinnerInterval = setInterval(() => {
|
|
83
|
+
currentFrame = (currentFrame + 1) % frames.length;
|
|
84
|
+
process.stdout.write(`\r${chalk_1.default[color](`${frames[currentFrame]} ${text}`)}`);
|
|
85
|
+
}, 100);
|
|
86
|
+
},
|
|
87
|
+
stop() {
|
|
88
|
+
if (spinnerInterval) {
|
|
89
|
+
clearInterval(spinnerInterval);
|
|
90
|
+
spinnerInterval = null;
|
|
91
|
+
process.stdout.write(`\r${' '.repeat(text.length + 2)}\r`);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
succeed(message) {
|
|
95
|
+
this.stop();
|
|
96
|
+
Console.success(message || text);
|
|
97
|
+
},
|
|
98
|
+
fail(message) {
|
|
99
|
+
this.stop();
|
|
100
|
+
Console.error(message || text);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 带边框的消息
|
|
106
|
+
*/
|
|
107
|
+
static box(message, type = 'info') {
|
|
108
|
+
const colors = {
|
|
109
|
+
success: chalk_1.default.green,
|
|
110
|
+
error: chalk_1.default.red,
|
|
111
|
+
warning: chalk_1.default.yellow,
|
|
112
|
+
info: chalk_1.default.blue,
|
|
113
|
+
};
|
|
114
|
+
const icons = {
|
|
115
|
+
success: '✅',
|
|
116
|
+
error: '❌',
|
|
117
|
+
warning: '⚠️',
|
|
118
|
+
info: 'ℹ️',
|
|
119
|
+
};
|
|
120
|
+
const color = colors[type];
|
|
121
|
+
const icon = icons[type];
|
|
122
|
+
const lines = message.split('\n');
|
|
123
|
+
const maxLength = Math.max(...lines.map((line) => line.length));
|
|
124
|
+
const border = '─'.repeat(maxLength + 4);
|
|
125
|
+
console.log(color(`┌${border}┐`));
|
|
126
|
+
console.log(color(`│ ${icon} ${' '.repeat(maxLength - 1)} │`));
|
|
127
|
+
lines.forEach((line) => {
|
|
128
|
+
const padding = ' '.repeat(maxLength - line.length);
|
|
129
|
+
console.log(color(`│ ${line}${padding} │`));
|
|
130
|
+
});
|
|
131
|
+
console.log(color(`└${border}┘`));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 进度条(简单版本)
|
|
135
|
+
*/
|
|
136
|
+
static progress(current, total, description = '') {
|
|
137
|
+
const percentage = Math.round((current / total) * 100);
|
|
138
|
+
const completed = Math.round((current / total) * 20);
|
|
139
|
+
const remaining = 20 - completed;
|
|
140
|
+
const progressBar = chalk_1.default.green('█'.repeat(completed)) + chalk_1.default.gray('░'.repeat(remaining));
|
|
141
|
+
const text = description ? ` ${description}` : '';
|
|
142
|
+
process.stdout.write(`\r[${progressBar}] ${percentage}%${text}`);
|
|
143
|
+
if (current === total) {
|
|
144
|
+
console.log(); // 换行
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.Console = Console;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Prompt = exports.Console = void 0;
|
|
4
|
+
var console_1 = require("./console");
|
|
5
|
+
Object.defineProperty(exports, "Console", { enumerable: true, get: function () { return console_1.Console; } });
|
|
6
|
+
var prompt_1 = require("./prompt");
|
|
7
|
+
Object.defineProperty(exports, "Prompt", { enumerable: true, get: function () { return prompt_1.Prompt; } });
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export interface FieldDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
type: 'varchar' | 'text' | 'integer' | 'decimal' | 'boolean' | 'date' | 'datetime' | 'timestamp';
|
|
4
|
+
length?: string | number;
|
|
5
|
+
required?: boolean;
|
|
6
|
+
comment?: string;
|
|
7
|
+
isPrimaryKey?: boolean;
|
|
8
|
+
isAutoIncrement?: boolean;
|
|
9
|
+
isSystemField?: boolean;
|
|
10
|
+
showInList?: boolean;
|
|
11
|
+
showInForm?: boolean;
|
|
12
|
+
searchable?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 交互式提示工具类
|
|
16
|
+
*/
|
|
17
|
+
export declare class Prompt {
|
|
18
|
+
/**
|
|
19
|
+
* 确认提示
|
|
20
|
+
*/
|
|
21
|
+
static confirm(message: string, defaultValue?: boolean): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* 输入提示
|
|
24
|
+
*/
|
|
25
|
+
static input(message: string, defaultValue?: string, validate?: (input: string) => boolean | string): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* 密码输入
|
|
28
|
+
*/
|
|
29
|
+
static password(message: string, validate?: (input: string) => boolean | string): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* 单选提示
|
|
32
|
+
*/
|
|
33
|
+
static select(message: string, choices: string[] | Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
value: any;
|
|
36
|
+
}>): Promise<any>;
|
|
37
|
+
/**
|
|
38
|
+
* 多选提示
|
|
39
|
+
*/
|
|
40
|
+
static multiSelect(message: string, choices: string[] | Array<{
|
|
41
|
+
name: string;
|
|
42
|
+
value: any;
|
|
43
|
+
checked?: boolean;
|
|
44
|
+
}>): Promise<any[]>;
|
|
45
|
+
/**
|
|
46
|
+
* 自定义提示
|
|
47
|
+
*/
|
|
48
|
+
static custom(questions: any): Promise<any>;
|
|
49
|
+
/**
|
|
50
|
+
* 项目初始化向导
|
|
51
|
+
*/
|
|
52
|
+
static initWizard(): Promise<{
|
|
53
|
+
projectName: string;
|
|
54
|
+
description: string;
|
|
55
|
+
author: string;
|
|
56
|
+
database: boolean;
|
|
57
|
+
features: string[];
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* 控制器创建向导
|
|
61
|
+
*/
|
|
62
|
+
static createControllerWizard(): Promise<{
|
|
63
|
+
controller: string;
|
|
64
|
+
action: string;
|
|
65
|
+
description: string;
|
|
66
|
+
dictionary: string;
|
|
67
|
+
includeDatabase: boolean;
|
|
68
|
+
fields: FieldDefinition[];
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* 收集字段定义
|
|
72
|
+
*/
|
|
73
|
+
static collectFieldDefinitions(): Promise<FieldDefinition[]>;
|
|
74
|
+
/**
|
|
75
|
+
* 控制器删除向导
|
|
76
|
+
*/
|
|
77
|
+
static deleteControllerWizard(): Promise<{
|
|
78
|
+
controller: string;
|
|
79
|
+
action: string;
|
|
80
|
+
dictionary: string;
|
|
81
|
+
deleteDatabase: boolean;
|
|
82
|
+
}>;
|
|
83
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Prompt = void 0;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const console_1 = require("./console");
|
|
9
|
+
/**
|
|
10
|
+
* 交互式提示工具类
|
|
11
|
+
*/
|
|
12
|
+
class Prompt {
|
|
13
|
+
/**
|
|
14
|
+
* 确认提示
|
|
15
|
+
*/
|
|
16
|
+
static async confirm(message, defaultValue = false) {
|
|
17
|
+
const { confirmed } = await inquirer_1.default.prompt({
|
|
18
|
+
type: 'confirm',
|
|
19
|
+
name: 'confirmed',
|
|
20
|
+
message,
|
|
21
|
+
default: defaultValue,
|
|
22
|
+
});
|
|
23
|
+
return confirmed;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 输入提示
|
|
27
|
+
*/
|
|
28
|
+
static async input(message, defaultValue, validate) {
|
|
29
|
+
const config = {
|
|
30
|
+
type: 'input',
|
|
31
|
+
name: 'value',
|
|
32
|
+
message,
|
|
33
|
+
validate: validate || (() => true),
|
|
34
|
+
};
|
|
35
|
+
if (defaultValue !== undefined) {
|
|
36
|
+
config.default = defaultValue;
|
|
37
|
+
}
|
|
38
|
+
const { value } = await inquirer_1.default.prompt(config);
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 密码输入
|
|
43
|
+
*/
|
|
44
|
+
static async password(message, validate) {
|
|
45
|
+
const { value } = await inquirer_1.default.prompt({
|
|
46
|
+
type: 'password',
|
|
47
|
+
name: 'value',
|
|
48
|
+
message,
|
|
49
|
+
validate: validate || (() => true),
|
|
50
|
+
});
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 单选提示
|
|
55
|
+
*/
|
|
56
|
+
static async select(message, choices) {
|
|
57
|
+
const { selected } = await inquirer_1.default.prompt({
|
|
58
|
+
type: 'list',
|
|
59
|
+
name: 'selected',
|
|
60
|
+
message,
|
|
61
|
+
choices,
|
|
62
|
+
});
|
|
63
|
+
return selected;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 多选提示
|
|
67
|
+
*/
|
|
68
|
+
static async multiSelect(message, choices) {
|
|
69
|
+
const { selected } = await inquirer_1.default.prompt({
|
|
70
|
+
type: 'checkbox',
|
|
71
|
+
name: 'selected',
|
|
72
|
+
message,
|
|
73
|
+
choices,
|
|
74
|
+
});
|
|
75
|
+
return selected;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 自定义提示
|
|
79
|
+
*/
|
|
80
|
+
static async custom(questions) {
|
|
81
|
+
return await inquirer_1.default.prompt(questions);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 项目初始化向导
|
|
85
|
+
*/
|
|
86
|
+
static async initWizard() {
|
|
87
|
+
console_1.Console.title('🚀 NSGM 项目初始化向导');
|
|
88
|
+
console_1.Console.newLine();
|
|
89
|
+
const answers = await inquirer_1.default.prompt([
|
|
90
|
+
{
|
|
91
|
+
type: 'input',
|
|
92
|
+
name: 'projectName',
|
|
93
|
+
message: '项目名称:',
|
|
94
|
+
default: 'my-nsgm-project',
|
|
95
|
+
validate: (input) => {
|
|
96
|
+
if (!input.trim())
|
|
97
|
+
return '项目名称不能为空';
|
|
98
|
+
// 允许路径格式,包括相对路径和绝对路径
|
|
99
|
+
if (!/^[a-zA-Z0-9\-_./\\]+$/.test(input))
|
|
100
|
+
return '项目名称只能包含字母、数字、横线、下划线和路径分隔符';
|
|
101
|
+
return true;
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
type: 'input',
|
|
106
|
+
name: 'description',
|
|
107
|
+
message: '项目描述:',
|
|
108
|
+
default: 'A NSGM fullstack project',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: 'input',
|
|
112
|
+
name: 'author',
|
|
113
|
+
message: '作者:',
|
|
114
|
+
default: 'Your Name',
|
|
115
|
+
},
|
|
116
|
+
]);
|
|
117
|
+
// 设置默认配置
|
|
118
|
+
const result = {
|
|
119
|
+
...answers,
|
|
120
|
+
database: true,
|
|
121
|
+
features: ['nextjs', 'styled-components', 'graphql', 'mysql', 'typescript', 'eslint'],
|
|
122
|
+
};
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 控制器创建向导
|
|
127
|
+
*/
|
|
128
|
+
static async createControllerWizard() {
|
|
129
|
+
console_1.Console.title('📝 创建控制器向导 (包含完整CRUD + 导入导出 + 批量删除功能)');
|
|
130
|
+
console_1.Console.newLine();
|
|
131
|
+
const answers = await inquirer_1.default.prompt([
|
|
132
|
+
{
|
|
133
|
+
type: 'input',
|
|
134
|
+
name: 'controller',
|
|
135
|
+
message: '控制器名称:',
|
|
136
|
+
validate: (input) => {
|
|
137
|
+
if (!input.trim())
|
|
138
|
+
return '控制器名称不能为空';
|
|
139
|
+
if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(input))
|
|
140
|
+
return '控制器名称必须以字母开头,只能包含字母和数字';
|
|
141
|
+
return true;
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'input',
|
|
146
|
+
name: 'description',
|
|
147
|
+
message: '控制器描述:',
|
|
148
|
+
default: (answers) => `${answers.controller} 控制器`,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
type: 'input',
|
|
152
|
+
name: 'dictionary',
|
|
153
|
+
message: '项目目录:',
|
|
154
|
+
default: '.',
|
|
155
|
+
validate: (input) => {
|
|
156
|
+
if (!input.trim())
|
|
157
|
+
return '项目目录不能为空';
|
|
158
|
+
return true;
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: 'confirm',
|
|
163
|
+
name: 'useCustomFields',
|
|
164
|
+
message: '是否自定义字段配置?(默认字段: id, name, create_date, update_date)',
|
|
165
|
+
default: false,
|
|
166
|
+
},
|
|
167
|
+
]);
|
|
168
|
+
// 设置默认action为manage(包含完整的CRUD + 导入 + 导出 + 批量删除功能)
|
|
169
|
+
answers.action = 'manage';
|
|
170
|
+
answers.includeDatabase = true;
|
|
171
|
+
if (answers.useCustomFields) {
|
|
172
|
+
// 如果用户选择自定义字段,收集字段定义
|
|
173
|
+
answers.fields = await this.collectFieldDefinitions();
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// 使用默认字段配置
|
|
177
|
+
answers.fields = [
|
|
178
|
+
{ name: 'id', type: 'integer', required: true, comment: '主键', isPrimaryKey: true, isAutoIncrement: true },
|
|
179
|
+
{
|
|
180
|
+
name: 'name',
|
|
181
|
+
type: 'varchar',
|
|
182
|
+
length: 100,
|
|
183
|
+
required: true,
|
|
184
|
+
comment: '名称',
|
|
185
|
+
showInList: true,
|
|
186
|
+
showInForm: true,
|
|
187
|
+
searchable: true,
|
|
188
|
+
},
|
|
189
|
+
{ name: 'create_date', type: 'timestamp', required: true, comment: '创建时间', isSystemField: true },
|
|
190
|
+
{ name: 'update_date', type: 'timestamp', required: true, comment: '更新时间', isSystemField: true },
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
return answers;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 收集字段定义
|
|
197
|
+
*/
|
|
198
|
+
static async collectFieldDefinitions() {
|
|
199
|
+
const fields = [];
|
|
200
|
+
let addMore = true;
|
|
201
|
+
// 默认添加ID字段
|
|
202
|
+
fields.push({
|
|
203
|
+
name: 'id',
|
|
204
|
+
type: 'integer',
|
|
205
|
+
required: true,
|
|
206
|
+
comment: '主键',
|
|
207
|
+
isPrimaryKey: true,
|
|
208
|
+
isAutoIncrement: true,
|
|
209
|
+
});
|
|
210
|
+
console_1.Console.info('💡 提示:系统会自动添加 create_date 和 update_date 字段');
|
|
211
|
+
while (addMore) {
|
|
212
|
+
const fieldAnswers = await inquirer_1.default.prompt([
|
|
213
|
+
{
|
|
214
|
+
type: 'input',
|
|
215
|
+
name: 'name',
|
|
216
|
+
message: '字段名称:',
|
|
217
|
+
validate: (input) => {
|
|
218
|
+
if (!input.trim())
|
|
219
|
+
return '字段名称不能为空';
|
|
220
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input))
|
|
221
|
+
return '字段名称只能包含字母、数字和下划线,且以字母或下划线开头';
|
|
222
|
+
if (fields.some((f) => f.name === input.trim()))
|
|
223
|
+
return '字段名称已存在';
|
|
224
|
+
if (['create_date', 'update_date'].includes(input.trim()))
|
|
225
|
+
return '系统字段将自动添加';
|
|
226
|
+
return true;
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
type: 'list',
|
|
231
|
+
name: 'type',
|
|
232
|
+
message: '字段类型:',
|
|
233
|
+
choices: [
|
|
234
|
+
{ name: 'varchar - 字符串', value: 'varchar' },
|
|
235
|
+
{ name: 'text - 长文本', value: 'text' },
|
|
236
|
+
{ name: 'integer - 整数', value: 'integer' },
|
|
237
|
+
{ name: 'decimal - 小数', value: 'decimal' },
|
|
238
|
+
{ name: 'boolean - 布尔值', value: 'boolean' },
|
|
239
|
+
{ name: 'date - 日期', value: 'date' },
|
|
240
|
+
{ name: 'datetime - 日期时间', value: 'datetime' },
|
|
241
|
+
{ name: 'timestamp - 时间戳', value: 'timestamp' },
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: 'input',
|
|
246
|
+
name: 'length',
|
|
247
|
+
message: '字段长度 (可选,数字类型可指定精度):',
|
|
248
|
+
when: (answers) => ['varchar', 'decimal'].includes(answers.type),
|
|
249
|
+
default: (answers) => (answers.type === 'varchar' ? '255' : '10,2'),
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
type: 'confirm',
|
|
253
|
+
name: 'required',
|
|
254
|
+
message: '是否必填:',
|
|
255
|
+
default: false,
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
type: 'input',
|
|
259
|
+
name: 'comment',
|
|
260
|
+
message: '字段注释:',
|
|
261
|
+
default: (answers) => answers.name,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
type: 'confirm',
|
|
265
|
+
name: 'showInList',
|
|
266
|
+
message: '是否在列表页显示:',
|
|
267
|
+
default: true,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
type: 'confirm',
|
|
271
|
+
name: 'showInForm',
|
|
272
|
+
message: '是否在表单中显示:',
|
|
273
|
+
default: true,
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
type: 'confirm',
|
|
277
|
+
name: 'searchable',
|
|
278
|
+
message: '是否可搜索:',
|
|
279
|
+
default: (answers) => answers.type === 'varchar',
|
|
280
|
+
},
|
|
281
|
+
]);
|
|
282
|
+
fields.push({
|
|
283
|
+
name: fieldAnswers.name.trim(),
|
|
284
|
+
type: fieldAnswers.type,
|
|
285
|
+
length: fieldAnswers.length ? fieldAnswers.length.trim() : undefined,
|
|
286
|
+
required: fieldAnswers.required,
|
|
287
|
+
comment: fieldAnswers.comment.trim(),
|
|
288
|
+
showInList: fieldAnswers.showInList,
|
|
289
|
+
showInForm: fieldAnswers.showInForm,
|
|
290
|
+
searchable: fieldAnswers.searchable,
|
|
291
|
+
});
|
|
292
|
+
const continueAnswer = await inquirer_1.default.prompt([
|
|
293
|
+
{
|
|
294
|
+
type: 'confirm',
|
|
295
|
+
name: 'addMore',
|
|
296
|
+
message: '是否继续添加字段:',
|
|
297
|
+
default: false,
|
|
298
|
+
},
|
|
299
|
+
]);
|
|
300
|
+
addMore = continueAnswer.addMore;
|
|
301
|
+
}
|
|
302
|
+
// 自动添加系统字段
|
|
303
|
+
fields.push({
|
|
304
|
+
name: 'create_date',
|
|
305
|
+
type: 'timestamp',
|
|
306
|
+
required: true,
|
|
307
|
+
comment: '创建时间',
|
|
308
|
+
isSystemField: true,
|
|
309
|
+
}, {
|
|
310
|
+
name: 'update_date',
|
|
311
|
+
type: 'timestamp',
|
|
312
|
+
required: true,
|
|
313
|
+
comment: '更新时间',
|
|
314
|
+
isSystemField: true,
|
|
315
|
+
});
|
|
316
|
+
return fields;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* 控制器删除向导
|
|
320
|
+
*/
|
|
321
|
+
static async deleteControllerWizard() {
|
|
322
|
+
console_1.Console.title('🗑️ 删除控制器向导');
|
|
323
|
+
console_1.Console.newLine();
|
|
324
|
+
const answers = await inquirer_1.default.prompt([
|
|
325
|
+
{
|
|
326
|
+
type: 'input',
|
|
327
|
+
name: 'controller',
|
|
328
|
+
message: '控制器名称:',
|
|
329
|
+
validate: (input) => {
|
|
330
|
+
if (!input.trim())
|
|
331
|
+
return '控制器名称不能为空';
|
|
332
|
+
if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(input))
|
|
333
|
+
return '控制器名称必须以字母开头,只能包含字母和数字';
|
|
334
|
+
return true;
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
type: 'list',
|
|
339
|
+
name: 'action',
|
|
340
|
+
message: '删除范围:',
|
|
341
|
+
choices: [
|
|
342
|
+
{ name: '删除所有相关文件', value: 'all' },
|
|
343
|
+
{ name: '仅删除指定操作', value: 'manage' },
|
|
344
|
+
],
|
|
345
|
+
default: 'all',
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
type: 'input',
|
|
349
|
+
name: 'dictionary',
|
|
350
|
+
message: '项目目录:',
|
|
351
|
+
default: '.',
|
|
352
|
+
validate: (input) => {
|
|
353
|
+
if (!input.trim())
|
|
354
|
+
return '项目目录不能为空';
|
|
355
|
+
return true;
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
type: 'confirm',
|
|
360
|
+
name: 'deleteDatabase',
|
|
361
|
+
message: '是否同时删除数据库表?',
|
|
362
|
+
default: false,
|
|
363
|
+
},
|
|
364
|
+
]);
|
|
365
|
+
return answers;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
exports.Prompt = Prompt;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
declare const sourceFolder: string;
|
|
2
|
+
declare const destFolder: string;
|
|
3
|
+
declare const isLocal: boolean;
|
|
4
|
+
declare const mysqlUser: any, mysqlPassword: any, mysqlHost: any, mysqlPort: any, mysqlDatabase: any;
|
|
5
|
+
declare const generationPath = "../generation";
|
|
6
|
+
declare const clientPathSource = "../client";
|
|
7
|
+
declare const clientPath = "./client";
|
|
8
|
+
declare const serverPathSource = "../server";
|
|
9
|
+
declare const serverPath = "./server";
|
|
10
|
+
declare const pagesPathSource = "../pages";
|
|
11
|
+
declare const pagesPath = "./pages";
|
|
12
|
+
declare const publicPathSource = "../public";
|
|
13
|
+
declare const publicPath = "./public";
|
|
14
|
+
declare const scriptsPathSource = "../scripts";
|
|
15
|
+
declare const scriptsPath = "./scripts";
|
|
16
|
+
declare const reduxPath = "/redux";
|
|
17
|
+
declare const servicePath = "/service";
|
|
18
|
+
declare const styledPath = "/styled";
|
|
19
|
+
declare const styledLayoutPath = "/layout";
|
|
20
|
+
declare const utilsPath = "/utils";
|
|
21
|
+
declare const layoutPath = "/layout";
|
|
22
|
+
declare const modulesPath = "/modules";
|
|
23
|
+
declare const apisPath = "/apis";
|
|
24
|
+
declare const sqlPath = "/sql";
|
|
25
|
+
declare const utilsMenuPath = "/menu.tsx";
|
|
26
|
+
declare const reduxReducersPath = "/reducers.ts";
|
|
27
|
+
declare const slbHealthCheckPath = "/slbhealthcheck.html";
|
|
28
|
+
declare const packagePath = "/package.json";
|
|
29
|
+
declare const restPath = "/rest.js";
|
|
30
|
+
declare const sourceGenerationPath: string;
|
|
31
|
+
declare const sourceClientPath: string;
|
|
32
|
+
declare const sourceClientPathGeneration: string;
|
|
33
|
+
declare const sourceServerPath: string;
|
|
34
|
+
declare const sourceServerPathGeneration: string;
|
|
35
|
+
declare const sourcePagesPath: string;
|
|
36
|
+
declare const sourcePublicPath: string;
|
|
37
|
+
declare const sourceScriptsPath: string;
|
|
38
|
+
declare const destClientPath: string;
|
|
39
|
+
declare const destClientReduxPath: string;
|
|
40
|
+
declare const destClientServicePath: string;
|
|
41
|
+
declare const destClientStyledPath: string;
|
|
42
|
+
declare const destClientStyledLayoutPath: string;
|
|
43
|
+
declare const destClientUtilsPath: string;
|
|
44
|
+
declare const destClientLayoutPath: string;
|
|
45
|
+
declare const destServerPath: string;
|
|
46
|
+
declare const destServerModulesPath: string;
|
|
47
|
+
declare const destServerApisPath: string;
|
|
48
|
+
declare const destServerSqlPath: string;
|
|
49
|
+
declare const destServerUtilsPath: string;
|
|
50
|
+
declare const destPagesPath: string;
|
|
51
|
+
declare const destPublicPath: string;
|
|
52
|
+
declare const destScriptsPath: string;
|
|
53
|
+
declare const destClientUtilsMenuPath: string;
|
|
54
|
+
declare const destClientReduxReducersAllPath: string;
|
|
55
|
+
declare const destPublicHealthCheckPath: string;
|
|
56
|
+
declare const destPackagePath: string;
|
|
57
|
+
declare const destServerRestPath: string;
|
|
58
|
+
export { sourceFolder, destFolder, isLocal, generationPath, clientPathSource, clientPath, serverPathSource, serverPath, pagesPathSource, pagesPath, publicPathSource, publicPath, scriptsPathSource, scriptsPath, reduxPath, servicePath, styledPath, styledLayoutPath, utilsPath, layoutPath, modulesPath, apisPath, sqlPath, utilsMenuPath, reduxReducersPath, slbHealthCheckPath, packagePath, restPath, sourceGenerationPath, sourceClientPath, sourceClientPathGeneration, sourceServerPath, sourceServerPathGeneration, sourcePagesPath, sourcePublicPath, sourceScriptsPath, destClientPath, destClientReduxPath, destClientServicePath, destClientStyledPath, destClientStyledLayoutPath, destClientUtilsPath, destClientLayoutPath, destServerPath, destServerModulesPath, destServerApisPath, destServerSqlPath, destServerUtilsPath, destPagesPath, destPublicPath, destScriptsPath, destClientUtilsMenuPath, destClientReduxReducersAllPath, destPublicHealthCheckPath, destPackagePath, destServerRestPath, mysqlUser, mysqlPassword, mysqlHost, mysqlPort, mysqlDatabase, };
|