nsgm-cli 2.1.19 → 2.1.21
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/client/components/Button.tsx +3 -3
- package/client/components/ClientProviders.tsx +12 -12
- package/client/components/LanguageSwitcher.tsx +26 -26
- package/client/components/SSRSafeAntdProvider.tsx +7 -7
- package/client/components/SuppressHydrationWarnings.tsx +30 -30
- package/client/components/__tests__/Button.test.tsx +12 -12
- package/client/layout/index.tsx +124 -124
- package/client/redux/reducers.ts +2 -2
- package/client/redux/store.ts +24 -24
- package/client/redux/template/manage/actions.ts +40 -40
- package/client/redux/template/manage/reducers.ts +32 -32
- package/client/redux/template/manage/types.ts +19 -19
- package/client/service/template/manage.ts +29 -29
- package/client/styled/common.ts +6 -6
- package/client/styled/layout/index.ts +17 -17
- package/client/styled/template/manage.ts +19 -19
- package/client/utils/common.ts +54 -54
- package/client/utils/cookie.ts +30 -30
- package/client/utils/fetch.ts +111 -111
- package/client/utils/i18n.ts +41 -41
- package/client/utils/menu.tsx +12 -12
- package/client/utils/navigation.ts +22 -22
- package/client/utils/sso.ts +124 -124
- package/client/utils/suppressWarnings.ts +17 -17
- package/generation/prettierrc +6 -0
- package/lib/args.js +19 -19
- package/lib/cli/app.d.ts +1 -1
- package/lib/cli/app.js +2 -2
- package/lib/cli/commands/build.d.ts +1 -1
- package/lib/cli/commands/build.js +9 -9
- package/lib/cli/commands/create.d.ts +1 -1
- package/lib/cli/commands/create.js +36 -36
- package/lib/cli/commands/delete.d.ts +1 -1
- package/lib/cli/commands/delete.js +55 -55
- package/lib/cli/commands/export.d.ts +1 -1
- package/lib/cli/commands/export.js +12 -12
- package/lib/cli/commands/help.d.ts +1 -1
- package/lib/cli/commands/help.js +29 -29
- package/lib/cli/commands/init.d.ts +1 -1
- package/lib/cli/commands/init.js +31 -31
- package/lib/cli/commands/server.d.ts +1 -1
- package/lib/cli/commands/server.js +12 -12
- package/lib/cli/commands/upgrade.d.ts +1 -1
- package/lib/cli/commands/upgrade.js +13 -13
- package/lib/cli/commands/version.d.ts +1 -1
- package/lib/cli/commands/version.js +7 -7
- package/lib/cli/index.d.ts +13 -13
- package/lib/cli/parser.d.ts +1 -1
- package/lib/cli/parser.js +12 -12
- package/lib/cli/registry.d.ts +1 -1
- package/lib/cli/types.d.ts +2 -2
- package/lib/cli/utils/console.d.ts +2 -2
- package/lib/cli/utils/console.js +22 -22
- package/lib/cli/utils/index.d.ts +2 -2
- package/lib/cli/utils/prompt.d.ts +1 -1
- package/lib/cli/utils/prompt.js +98 -98
- package/lib/constants.js +28 -28
- package/lib/generate.d.ts +2 -2
- package/lib/generate.js +19 -19
- package/lib/generate_create.d.ts +1 -1
- package/lib/generate_create.js +38 -38
- package/lib/generate_delete.js +63 -63
- package/lib/generate_init.js +94 -94
- package/lib/generators/base-generator.d.ts +1 -1
- package/lib/generators/base-generator.js +23 -23
- package/lib/generators/file-generator.js +15 -15
- package/lib/generators/generator-factory.d.ts +5 -5
- package/lib/generators/i18n-generator.d.ts +1 -1
- package/lib/generators/i18n-generator.js +127 -127
- package/lib/generators/page-generator.d.ts +1 -1
- package/lib/generators/page-generator.js +25 -25
- package/lib/generators/resolver-generator.d.ts +1 -1
- package/lib/generators/resolver-generator.js +27 -27
- package/lib/generators/schema-generator.d.ts +1 -1
- package/lib/generators/schema-generator.js +4 -4
- package/lib/generators/service-generator.d.ts +1 -1
- package/lib/generators/service-generator.js +29 -29
- package/lib/generators/sql-generator.d.ts +1 -1
- package/lib/generators/sql-generator.js +10 -10
- package/lib/index.js +23 -23
- package/lib/server/csrf.d.ts +3 -3
- package/lib/server/csrf.js +20 -20
- package/lib/server/db.d.ts +1 -1
- package/lib/server/db.js +21 -21
- package/lib/server/graphql.js +26 -26
- package/lib/server/plugins/date.d.ts +1 -1
- package/lib/server/plugins/date.js +6 -6
- package/lib/server/utils/graphql-cache.js +5 -5
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils/project-config.d.ts +1 -1
- package/lib/utils/project-config.js +20 -20
- package/lib/utils.js +3 -3
- package/package.json +1 -1
- package/pages/_app.tsx +62 -62
- package/pages/_document.tsx +15 -15
- package/pages/_error.tsx +26 -26
- package/pages/index.tsx +48 -48
- package/pages/login.tsx +64 -64
- package/pages/template/manage.tsx +175 -175
|
@@ -7,21 +7,21 @@ const base_generator_1 = require("./base-generator");
|
|
|
7
7
|
*/
|
|
8
8
|
class ResolverGenerator extends base_generator_1.BaseGenerator {
|
|
9
9
|
generate() {
|
|
10
|
-
const selectFields = this.fields.map((f) => f.name).join(
|
|
10
|
+
const selectFields = this.fields.map((f) => f.name).join(", ");
|
|
11
11
|
const insertFields = this.getFormFields();
|
|
12
12
|
const searchableFields = this.getSearchableFields();
|
|
13
|
-
const insertFieldNames = insertFields.map((f) => f.name).join(
|
|
14
|
-
const insertPlaceholders = insertFields.map(() =>
|
|
13
|
+
const insertFieldNames = insertFields.map((f) => f.name).join(", ");
|
|
14
|
+
const insertPlaceholders = insertFields.map(() => "?").join(", ");
|
|
15
15
|
const insertValues = insertFields
|
|
16
16
|
.map((f) => {
|
|
17
|
-
if (f.type ===
|
|
17
|
+
if (f.type === "integer") {
|
|
18
18
|
return `valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)}`;
|
|
19
19
|
}
|
|
20
20
|
return `data.${f.name}`;
|
|
21
21
|
})
|
|
22
|
-
.join(
|
|
22
|
+
.join(", ");
|
|
23
23
|
const searchConditions = this.generateSearchConditions(searchableFields);
|
|
24
|
-
const updateFields = insertFields.map((f) => `${f.name} = ?`).join(
|
|
24
|
+
const updateFields = insertFields.map((f) => `${f.name} = ?`).join(", ");
|
|
25
25
|
return `const { executeQuery, executePaginatedQuery } = require('../../utils/common')
|
|
26
26
|
const { validateInteger, validatePagination, validateId } = require('../../utils/validation')
|
|
27
27
|
|
|
@@ -230,9 +230,9 @@ ${this.generateUpdateValidation(insertFields)}
|
|
|
230
230
|
}
|
|
231
231
|
generateSearchConditions(searchableFields) {
|
|
232
232
|
if (searchableFields.length === 0)
|
|
233
|
-
return
|
|
233
|
+
return "";
|
|
234
234
|
const conditions = searchableFields.map((field) => {
|
|
235
|
-
if (field.type ===
|
|
235
|
+
if (field.type === "varchar" || field.type === "text") {
|
|
236
236
|
return ` if (data.${field.name} && data.${field.name}.trim() !== '') {
|
|
237
237
|
whereSql += ' AND ${field.name} LIKE ?';
|
|
238
238
|
const ${field.name}Pattern = \`%\${data.${field.name}.trim()}%\`;
|
|
@@ -240,7 +240,7 @@ ${this.generateUpdateValidation(insertFields)}
|
|
|
240
240
|
countValues.push(${field.name}Pattern);
|
|
241
241
|
}`;
|
|
242
242
|
}
|
|
243
|
-
else if (field.type ===
|
|
243
|
+
else if (field.type === "integer") {
|
|
244
244
|
return ` if (data.${field.name} !== undefined && data.${field.name} !== null && data.${field.name} !== '') {
|
|
245
245
|
// 使用通用验证工具验证 ${field.name}
|
|
246
246
|
const valid${field.name.charAt(0).toUpperCase() + field.name.slice(1)} = validateInteger(data.${field.name}, '${field.name}', { min: 0, max: 150 });
|
|
@@ -259,13 +259,13 @@ ${this.generateUpdateValidation(insertFields)}
|
|
|
259
259
|
}`;
|
|
260
260
|
}
|
|
261
261
|
});
|
|
262
|
-
return conditions.join(
|
|
262
|
+
return conditions.join("\n\n");
|
|
263
263
|
}
|
|
264
264
|
generateNewValidationCalls(insertFields) {
|
|
265
265
|
return insertFields
|
|
266
266
|
.map((f) => {
|
|
267
|
-
if (f.type ===
|
|
268
|
-
const validationOptions = f.name ===
|
|
267
|
+
if (f.type === "integer") {
|
|
268
|
+
const validationOptions = f.name === "age" ? "{ min: 0, max: 150, required: true }" : "{ required: true }";
|
|
269
269
|
return ` const valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = validateInteger(data.${f.name}, '${f.name}', ${validationOptions});`;
|
|
270
270
|
}
|
|
271
271
|
else if (f.required) {
|
|
@@ -273,16 +273,16 @@ ${this.generateUpdateValidation(insertFields)}
|
|
|
273
273
|
throw new Error('${f.comment || f.name}是必填字段');
|
|
274
274
|
}`;
|
|
275
275
|
}
|
|
276
|
-
return
|
|
276
|
+
return "";
|
|
277
277
|
})
|
|
278
278
|
.filter((call) => call.length > 0)
|
|
279
|
-
.join(
|
|
279
|
+
.join("\n");
|
|
280
280
|
}
|
|
281
281
|
generateBatchValidation(insertFields) {
|
|
282
282
|
return insertFields
|
|
283
283
|
.map((f) => {
|
|
284
|
-
if (f.type ===
|
|
285
|
-
const validationOptions = f.name ===
|
|
284
|
+
if (f.type === "integer") {
|
|
285
|
+
const validationOptions = f.name === "age" ? "{ min: 0, max: 150, required: true }" : "{ required: true }";
|
|
286
286
|
return ` const valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = validateInteger(data.${f.name}, \`第\${index + 1}条数据的${f.name}\`, ${validationOptions});`;
|
|
287
287
|
}
|
|
288
288
|
else if (f.required) {
|
|
@@ -290,16 +290,16 @@ ${this.generateUpdateValidation(insertFields)}
|
|
|
290
290
|
throw new Error('${f.comment || f.name}是必填字段');
|
|
291
291
|
}`;
|
|
292
292
|
}
|
|
293
|
-
return
|
|
293
|
+
return "";
|
|
294
294
|
})
|
|
295
295
|
.filter((call) => call.length > 0)
|
|
296
|
-
.join(
|
|
296
|
+
.join("\n");
|
|
297
297
|
}
|
|
298
298
|
generateUpdateValidation(insertFields) {
|
|
299
299
|
return insertFields
|
|
300
300
|
.map((f) => {
|
|
301
|
-
if (f.type ===
|
|
302
|
-
const validationOptions = f.name ===
|
|
301
|
+
if (f.type === "integer") {
|
|
302
|
+
const validationOptions = f.name === "age" ? "{ min: 0, max: 150, required: true }" : "{ required: true }";
|
|
303
303
|
return ` let valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = data.${f.name};
|
|
304
304
|
if (data.${f.name} !== undefined) {
|
|
305
305
|
valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = validateInteger(data.${f.name}, '${f.name}', ${validationOptions});
|
|
@@ -310,33 +310,33 @@ ${this.generateUpdateValidation(insertFields)}
|
|
|
310
310
|
throw new Error('${f.comment || f.name}是必填字段');
|
|
311
311
|
}`;
|
|
312
312
|
}
|
|
313
|
-
return
|
|
313
|
+
return "";
|
|
314
314
|
})
|
|
315
315
|
.filter((call) => call.length > 0)
|
|
316
|
-
.join(
|
|
316
|
+
.join("\n");
|
|
317
317
|
}
|
|
318
318
|
generateUpdateValues(insertFields) {
|
|
319
319
|
return insertFields
|
|
320
320
|
.map((f) => {
|
|
321
|
-
if (f.type ===
|
|
321
|
+
if (f.type === "integer") {
|
|
322
322
|
return `valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)}`;
|
|
323
323
|
}
|
|
324
324
|
return `data.${f.name}`;
|
|
325
325
|
})
|
|
326
|
-
.join(
|
|
326
|
+
.join(", ");
|
|
327
327
|
}
|
|
328
328
|
generateBatchReturnObject(insertFields) {
|
|
329
329
|
return insertFields
|
|
330
330
|
.map((f) => {
|
|
331
|
-
if (f.type ===
|
|
331
|
+
if (f.type === "integer") {
|
|
332
332
|
return `${f.name}: valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)}`;
|
|
333
333
|
}
|
|
334
334
|
return `${f.name}: data.${f.name}`;
|
|
335
335
|
})
|
|
336
|
-
.join(
|
|
336
|
+
.join(", ");
|
|
337
337
|
}
|
|
338
338
|
generateBatchInsertValues(insertFields) {
|
|
339
|
-
return insertFields.map((f) => `data.${f.name}`).join(
|
|
339
|
+
return insertFields.map((f) => `data.${f.name}`).join(", ");
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
exports.ResolverGenerator = ResolverGenerator;
|
|
@@ -11,14 +11,14 @@ class SchemaGenerator extends base_generator_1.BaseGenerator {
|
|
|
11
11
|
const pluralTypeName = `${capitalizedTypeName}s`;
|
|
12
12
|
const typeFields = this.getNonSystemFields()
|
|
13
13
|
.map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`)
|
|
14
|
-
.join(
|
|
14
|
+
.join("\n");
|
|
15
15
|
const inputFields = this.getFormFields()
|
|
16
16
|
.map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`)
|
|
17
|
-
.join(
|
|
17
|
+
.join("\n");
|
|
18
18
|
const searchableFields = this.getSearchableFields();
|
|
19
19
|
const searchFields = searchableFields.length > 0
|
|
20
|
-
? searchableFields.map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`).join(
|
|
21
|
-
:
|
|
20
|
+
? searchableFields.map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`).join("\n")
|
|
21
|
+
: " name: String";
|
|
22
22
|
return `module.exports = {
|
|
23
23
|
query: \`
|
|
24
24
|
${this.controller}(page: Int, pageSize: Int): ${pluralTypeName}
|
|
@@ -10,14 +10,14 @@ class ServiceGenerator extends base_generator_1.BaseGenerator {
|
|
|
10
10
|
const capitalizedTypeName = this.getCapitalizedController();
|
|
11
11
|
// 排除系统字段 create_date 和 update_date
|
|
12
12
|
const selectFields = this.fields
|
|
13
|
-
.filter((f) => ![
|
|
13
|
+
.filter((f) => !["create_date", "update_date"].includes(f.name))
|
|
14
14
|
.map((f) => f.name)
|
|
15
|
-
.join(
|
|
15
|
+
.join(" ");
|
|
16
16
|
const inputFields = this.getFormFields();
|
|
17
17
|
const searchFields = this.getSearchableFields();
|
|
18
18
|
// 检查是否有integer类型字段需要验证
|
|
19
|
-
const hasIntegerFields = inputFields.some((field) => field.type ===
|
|
20
|
-
const validationFunctions = hasIntegerFields ? this.generateValidationFunctions(inputFields) :
|
|
19
|
+
const hasIntegerFields = inputFields.some((field) => field.type === "integer");
|
|
20
|
+
const validationFunctions = hasIntegerFields ? this.generateValidationFunctions(inputFields) : "";
|
|
21
21
|
return `import { getLocalGraphql } from '@/utils/fetch'
|
|
22
22
|
import _ from 'lodash'
|
|
23
23
|
|
|
@@ -49,9 +49,9 @@ export const search${capitalizedTypeName}ByIdService = (id: number) => {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export const search${capitalizedTypeName}Service = (page = 0, pageSize = 10, data: any) => {
|
|
52
|
-
const { ${searchFields.map((f) => f.name).join(
|
|
52
|
+
const { ${searchFields.map((f) => f.name).join(", ")} } = data
|
|
53
53
|
|
|
54
|
-
${this.generateValidationCallsForService(searchFields,
|
|
54
|
+
${this.generateValidationCallsForService(searchFields, " ", false)}
|
|
55
55
|
|
|
56
56
|
const search${capitalizedTypeName}Query = \`query ($page: Int, $pageSize: Int, $data: ${capitalizedTypeName}SearchInput) {
|
|
57
57
|
${this.controller}Search(page: $page, pageSize: $pageSize, data: $data) {
|
|
@@ -71,9 +71,9 @@ ${this.generateDataObjectWithValidation(searchFields)}
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
export const add${capitalizedTypeName}Service = (data: any) => {
|
|
74
|
-
const { ${inputFields.map((f) => f.name).join(
|
|
74
|
+
const { ${inputFields.map((f) => f.name).join(", ")} } = data
|
|
75
75
|
|
|
76
|
-
${this.generateValidationCallsForService(inputFields,
|
|
76
|
+
${this.generateValidationCallsForService(inputFields, " ", true)}
|
|
77
77
|
|
|
78
78
|
const add${capitalizedTypeName}Query = \`mutation ($data: ${capitalizedTypeName}AddInput) { ${this.controller}Add(data: $data) }\`
|
|
79
79
|
|
|
@@ -85,9 +85,9 @@ ${this.generateDataObjectWithValidation(inputFields)}
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
export const update${capitalizedTypeName}Service = (id: number, data: any) => {
|
|
88
|
-
const { ${inputFields.map((f) => f.name).join(
|
|
88
|
+
const { ${inputFields.map((f) => f.name).join(", ")} } = data
|
|
89
89
|
|
|
90
|
-
${this.generateValidationCallsForService(inputFields,
|
|
90
|
+
${this.generateValidationCallsForService(inputFields, " ", true)}
|
|
91
91
|
|
|
92
92
|
const update${capitalizedTypeName}Query = \`mutation ($id: Int, $data: ${capitalizedTypeName}AddInput) { ${this.controller}Update(id: $id, data: $data) }\`
|
|
93
93
|
|
|
@@ -108,7 +108,7 @@ export const delete${capitalizedTypeName}Service = (id: number) => {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
export const batchAdd${capitalizedTypeName}Service = (datas: any) => {
|
|
111
|
-
${this.generateBatchValidationCalls(inputFields,
|
|
111
|
+
${this.generateBatchValidationCalls(inputFields, " ")}
|
|
112
112
|
|
|
113
113
|
const batchAdd${capitalizedTypeName}Query = \`mutation ($datas: [${capitalizedTypeName}AddInput]) { ${this.controller}BatchAdd(datas: $datas) }\`
|
|
114
114
|
|
|
@@ -127,9 +127,9 @@ export const batchDelete${capitalizedTypeName}Service = (ids: any) => {
|
|
|
127
127
|
`;
|
|
128
128
|
}
|
|
129
129
|
generateValidationFunctions(inputFields) {
|
|
130
|
-
const integerFields = inputFields.filter((field) => field.type ===
|
|
130
|
+
const integerFields = inputFields.filter((field) => field.type === "integer");
|
|
131
131
|
if (integerFields.length === 0) {
|
|
132
|
-
return
|
|
132
|
+
return "";
|
|
133
133
|
}
|
|
134
134
|
const validationFunctions = integerFields.map((field) => {
|
|
135
135
|
const fieldName = field.name;
|
|
@@ -156,18 +156,18 @@ const validate${capitalizedName} = (${fieldName}: any, required = false) => {
|
|
|
156
156
|
return { valid: true, value: parsed${capitalizedName} }
|
|
157
157
|
}`;
|
|
158
158
|
});
|
|
159
|
-
return `${validationFunctions.join(
|
|
159
|
+
return `${validationFunctions.join("\n\n")}\n\n`;
|
|
160
160
|
}
|
|
161
161
|
generateValidationCallsForService(inputFields, indent, required) {
|
|
162
|
-
const integerFields = inputFields.filter((field) => field.type ===
|
|
162
|
+
const integerFields = inputFields.filter((field) => field.type === "integer");
|
|
163
163
|
if (integerFields.length === 0) {
|
|
164
|
-
return
|
|
164
|
+
return "";
|
|
165
165
|
}
|
|
166
166
|
const validationCalls = integerFields.map((field) => {
|
|
167
167
|
const fieldName = field.name;
|
|
168
168
|
const capitalizedName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
|
|
169
|
-
const requiredStr = required ?
|
|
170
|
-
return `${indent}// 验证${required ?
|
|
169
|
+
const requiredStr = required ? "true" : "false";
|
|
170
|
+
return `${indent}// 验证${required ? "必填" : ""}${fieldName}
|
|
171
171
|
${indent}const ${fieldName}Validation = validate${capitalizedName}(${fieldName}, ${requiredStr})
|
|
172
172
|
${indent}if (!${fieldName}Validation.valid) {
|
|
173
173
|
${indent} return Promise.reject({
|
|
@@ -177,37 +177,37 @@ ${indent} code: ${fieldName}Validation.code
|
|
|
177
177
|
${indent} })
|
|
178
178
|
${indent}}`;
|
|
179
179
|
});
|
|
180
|
-
return validationCalls.join(
|
|
180
|
+
return validationCalls.join("\n\n") + (validationCalls.length > 0 ? "\n\n" : "");
|
|
181
181
|
}
|
|
182
182
|
generateDataObjectWithValidation(inputFields) {
|
|
183
183
|
return inputFields
|
|
184
184
|
.map((field) => {
|
|
185
|
-
if (field.type ===
|
|
185
|
+
if (field.type === "integer") {
|
|
186
186
|
return ` ${field.name}: ${field.name}Validation.value`;
|
|
187
187
|
}
|
|
188
188
|
return ` ${field.name}`;
|
|
189
189
|
})
|
|
190
|
-
.join(
|
|
190
|
+
.join(",\n");
|
|
191
191
|
}
|
|
192
192
|
generateBatchValidationCalls(inputFields, indent) {
|
|
193
|
-
const integerFields = inputFields.filter((field) => field.type ===
|
|
193
|
+
const integerFields = inputFields.filter((field) => field.type === "integer");
|
|
194
194
|
if (integerFields.length === 0) {
|
|
195
195
|
return `${indent}// 验证批量数据
|
|
196
|
-
${indent}const validatedDatas: Array<{ ${inputFields.map((f) => `${f.name}: any`).join(
|
|
196
|
+
${indent}const validatedDatas: Array<{ ${inputFields.map((f) => `${f.name}: any`).join("; ")} }> = []
|
|
197
197
|
|
|
198
198
|
${indent}for (let i = 0; i < datas.length; i++) {
|
|
199
|
-
${indent} const { ${inputFields.map((f) => f.name).join(
|
|
199
|
+
${indent} const { ${inputFields.map((f) => f.name).join(", ")} } = datas[i]
|
|
200
200
|
|
|
201
201
|
${indent} validatedDatas.push({
|
|
202
|
-
${indent} ${inputFields.map((f) => f.name).join(
|
|
202
|
+
${indent} ${inputFields.map((f) => f.name).join(",\n ")}
|
|
203
203
|
${indent} })
|
|
204
204
|
${indent}}`;
|
|
205
205
|
}
|
|
206
206
|
return `${indent}// 验证批量数据
|
|
207
|
-
${indent}const validatedDatas: Array<{ ${inputFields.map((f) => `${f.name}: ${f.type ===
|
|
207
|
+
${indent}const validatedDatas: Array<{ ${inputFields.map((f) => `${f.name}: ${f.type === "integer" ? "number" : "any"}`).join("; ")} }> = []
|
|
208
208
|
|
|
209
209
|
${indent}for (let i = 0; i < datas.length; i++) {
|
|
210
|
-
${indent} const { ${inputFields.map((f) => f.name).join(
|
|
210
|
+
${indent} const { ${inputFields.map((f) => f.name).join(", ")} } = datas[i]
|
|
211
211
|
|
|
212
212
|
${integerFields
|
|
213
213
|
.map((field) => {
|
|
@@ -222,10 +222,10 @@ ${indent} code: ${fieldName}Validation.code
|
|
|
222
222
|
${indent} })
|
|
223
223
|
${indent} }`;
|
|
224
224
|
})
|
|
225
|
-
.join(
|
|
225
|
+
.join("\n\n")}
|
|
226
226
|
|
|
227
227
|
${indent} validatedDatas.push({
|
|
228
|
-
${indent} ${inputFields.map((field) => (field.type ===
|
|
228
|
+
${indent} ${inputFields.map((field) => (field.type === "integer" ? `${field.name}: ${field.name}Validation.value!` : field.name)).join(",\n ")}
|
|
229
229
|
${indent} })
|
|
230
230
|
${indent}}`;
|
|
231
231
|
}
|
|
@@ -14,23 +14,23 @@ class SQLGenerator extends base_generator_1.BaseGenerator {
|
|
|
14
14
|
sql += ` ${this.getSQLType(field)}`;
|
|
15
15
|
// 是否必填
|
|
16
16
|
if (field.required && !field.isAutoIncrement) {
|
|
17
|
-
sql +=
|
|
17
|
+
sql += " NOT NULL";
|
|
18
18
|
}
|
|
19
19
|
else if (!field.required) {
|
|
20
|
-
sql +=
|
|
20
|
+
sql += " DEFAULT NULL";
|
|
21
21
|
}
|
|
22
22
|
// 自增
|
|
23
23
|
if (field.isAutoIncrement) {
|
|
24
|
-
sql +=
|
|
24
|
+
sql += " AUTO_INCREMENT";
|
|
25
25
|
}
|
|
26
26
|
// 默认值
|
|
27
|
-
if (field.type ===
|
|
28
|
-
sql +=
|
|
27
|
+
if (field.type === "timestamp" && field.name === "create_date") {
|
|
28
|
+
sql += " DEFAULT CURRENT_TIMESTAMP(3)";
|
|
29
29
|
}
|
|
30
|
-
else if (field.type ===
|
|
31
|
-
sql +=
|
|
30
|
+
else if (field.type === "timestamp" && field.name === "update_date") {
|
|
31
|
+
sql += " DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)";
|
|
32
32
|
}
|
|
33
|
-
else if (field.type ===
|
|
33
|
+
else if (field.type === "varchar" && field.name !== "id" && !field.required) {
|
|
34
34
|
sql += " DEFAULT ''";
|
|
35
35
|
}
|
|
36
36
|
// 注释
|
|
@@ -40,11 +40,11 @@ class SQLGenerator extends base_generator_1.BaseGenerator {
|
|
|
40
40
|
return sql;
|
|
41
41
|
});
|
|
42
42
|
const primaryKeyField = this.fields.find((f) => f.isPrimaryKey);
|
|
43
|
-
const primaryKey = primaryKeyField ? ` PRIMARY KEY (\`${primaryKeyField.name}\`)` :
|
|
43
|
+
const primaryKey = primaryKeyField ? ` PRIMARY KEY (\`${primaryKeyField.name}\`)` : "";
|
|
44
44
|
return `use crm_demo;
|
|
45
45
|
|
|
46
46
|
CREATE TABLE \`${this.controller}\` (
|
|
47
|
-
${fieldDefinitions.join(
|
|
47
|
+
${fieldDefinitions.join(",\n")},
|
|
48
48
|
${primaryKey}
|
|
49
49
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;`;
|
|
50
50
|
}
|
package/lib/index.js
CHANGED
|
@@ -6,10 +6,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.startExpress = void 0;
|
|
8
8
|
// 加载环境变量
|
|
9
|
-
require(
|
|
9
|
+
require("dotenv").config({ quiet: true });
|
|
10
10
|
// 仅在开发环境中禁用TLS证书验证
|
|
11
|
-
if (process.env.NODE_ENV ===
|
|
12
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED =
|
|
11
|
+
if (process.env.NODE_ENV === "development") {
|
|
12
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
13
13
|
}
|
|
14
14
|
const next_1 = __importDefault(require("next"));
|
|
15
15
|
const express_1 = __importDefault(require("express"));
|
|
@@ -38,15 +38,15 @@ const handleServer = (server, prefix, _command) => {
|
|
|
38
38
|
// 只看单个文件,不看目录
|
|
39
39
|
if (isFile) {
|
|
40
40
|
let filename = item;
|
|
41
|
-
if (item.indexOf(
|
|
42
|
-
filename = item.split(
|
|
41
|
+
if (item.indexOf(".") !== -1) {
|
|
42
|
+
filename = item.split(".")[0];
|
|
43
43
|
}
|
|
44
|
-
if (server && filename !== undefined && filename !==
|
|
44
|
+
if (server && filename !== undefined && filename !== "") {
|
|
45
45
|
try {
|
|
46
46
|
const routeModule = require(resolverPath);
|
|
47
47
|
// 检查导入的模块是否是有效的Express中间件
|
|
48
|
-
if (typeof routeModule ===
|
|
49
|
-
(routeModule && typeof routeModule ===
|
|
48
|
+
if (typeof routeModule === "function" ||
|
|
49
|
+
(routeModule && typeof routeModule === "object" && routeModule.router)) {
|
|
50
50
|
server.use(`/${filename}`, routeModule);
|
|
51
51
|
server.use(`${prefix}/${filename}`, routeModule);
|
|
52
52
|
}
|
|
@@ -63,7 +63,7 @@ const handleServer = (server, prefix, _command) => {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
|
-
const startExpress = (options, callback, command =
|
|
66
|
+
const startExpress = (options, callback, command = "dev") => {
|
|
67
67
|
// console.info('startExpress', curFolder)
|
|
68
68
|
const app = (0, next_1.default)(options);
|
|
69
69
|
const handle = app.getRequestHandler();
|
|
@@ -78,25 +78,25 @@ const startExpress = (options, callback, command = 'dev') => {
|
|
|
78
78
|
try {
|
|
79
79
|
const dbPoolManager = require(resolve(`${curFolder}/server/utils/db-pool-manager`));
|
|
80
80
|
await dbPoolManager.initialize();
|
|
81
|
-
console.log(
|
|
81
|
+
console.log("数据库连接池初始化完成");
|
|
82
82
|
}
|
|
83
83
|
catch (error) {
|
|
84
84
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
85
|
-
console.error(
|
|
85
|
+
console.error("数据库连接池初始化失败:", errorMessage);
|
|
86
86
|
// 不要因为数据库连接失败就退出,允许应用继续运行
|
|
87
87
|
}
|
|
88
88
|
const server = (0, express_1.default)();
|
|
89
89
|
// 配置 session(CSRF 保护需要)
|
|
90
90
|
server.use((0, express_session_1.default)({
|
|
91
|
-
secret: process.env.SESSION_SECRET ||
|
|
91
|
+
secret: process.env.SESSION_SECRET || "nsgm-default-secret-key-change-in-production",
|
|
92
92
|
resave: false,
|
|
93
93
|
saveUninitialized: true, // 改为 true,确保 session 被创建
|
|
94
|
-
name:
|
|
94
|
+
name: "sessionId", // 明确指定 session cookie 名称
|
|
95
95
|
cookie: {
|
|
96
96
|
secure: false, // 开发环境总是使用 false,生产环境再考虑 HTTPS
|
|
97
97
|
httpOnly: true,
|
|
98
98
|
maxAge: 24 * 60 * 60 * 1000, // 24小时
|
|
99
|
-
sameSite:
|
|
99
|
+
sameSite: "lax", // 设置 SameSite 策略
|
|
100
100
|
domain: undefined, // 不设置 domain,使用默认
|
|
101
101
|
},
|
|
102
102
|
}));
|
|
@@ -108,31 +108,31 @@ const startExpress = (options, callback, command = 'dev') => {
|
|
|
108
108
|
// 支持跨域,nsgm export 之后前后分离
|
|
109
109
|
server.use((0, cors_1.default)({
|
|
110
110
|
credentials: true, // 允许发送 cookies
|
|
111
|
-
origin: process.env.ALLOWED_ORIGINS?.split(
|
|
111
|
+
origin: process.env.ALLOWED_ORIGINS?.split(",") || ["http://localhost:3000"],
|
|
112
112
|
}));
|
|
113
113
|
server.use(body_parser_1.default.json());
|
|
114
114
|
// 添加基本安全中间件
|
|
115
115
|
server.use(csrf_1.securityMiddleware.basicHeaders);
|
|
116
|
-
if (process.env.NODE_ENV ===
|
|
116
|
+
if (process.env.NODE_ENV === "production") {
|
|
117
117
|
server.use((0, csrf_1.createCSPMiddleware)()); // 内容安全策略
|
|
118
118
|
}
|
|
119
119
|
// 添加 CSRF 保护中间件(在解析 body 之后)
|
|
120
120
|
server.use(csrf_1.csrfProtection);
|
|
121
121
|
server.use((0, express_fileupload_1.default)());
|
|
122
|
-
server.use(
|
|
123
|
-
server.use(
|
|
122
|
+
server.use("/static", express_1.default.static(path_1.default.join(__dirname, "public")));
|
|
123
|
+
server.use("/graphql", (0, graphql_1.default)(command));
|
|
124
124
|
const nextConfig = (0, config_1.default)();
|
|
125
125
|
const { publicRuntimeConfig } = nextConfig;
|
|
126
126
|
const { host, port, prefix } = publicRuntimeConfig;
|
|
127
127
|
// 提供 CSRF token 的端点
|
|
128
|
-
server.get(
|
|
129
|
-
if (prefix !==
|
|
128
|
+
server.get("/csrf-token", csrf_1.getCSRFToken);
|
|
129
|
+
if (prefix !== "") {
|
|
130
130
|
server.get(`${prefix}/csrf-token`, csrf_1.getCSRFToken);
|
|
131
|
-
server.use(`${prefix}/static`, express_1.default.static(path_1.default.join(__dirname,
|
|
131
|
+
server.use(`${prefix}/static`, express_1.default.static(path_1.default.join(__dirname, "public")));
|
|
132
132
|
server.use(`${prefix}/graphql`, (0, graphql_1.default)(command));
|
|
133
133
|
}
|
|
134
134
|
handleServer(server, prefix, command);
|
|
135
|
-
server.get(
|
|
135
|
+
server.get("*", (req, res) => {
|
|
136
136
|
const { url } = req;
|
|
137
137
|
const parsedUrl = (0, url_1.parse)(url, true);
|
|
138
138
|
return handle(req, res, parsedUrl);
|
|
@@ -149,6 +149,6 @@ const startExpress = (options, callback, command = 'dev') => {
|
|
|
149
149
|
exports.startExpress = startExpress;
|
|
150
150
|
// 使用新的 CLI 架构
|
|
151
151
|
(0, cli_1.runCli)().catch((error) => {
|
|
152
|
-
console.error(
|
|
152
|
+
console.error("CLI 执行失败:", error);
|
|
153
153
|
process.exit(1);
|
|
154
154
|
});
|
package/lib/server/csrf.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from
|
|
2
|
-
declare module
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
declare module "express-session" {
|
|
3
3
|
interface SessionData {
|
|
4
4
|
_csrf?: string;
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
-
declare module
|
|
7
|
+
declare module "express-serve-static-core" {
|
|
8
8
|
interface Request {
|
|
9
9
|
csrfToken?: () => string;
|
|
10
10
|
}
|
package/lib/server/csrf.js
CHANGED
|
@@ -9,36 +9,36 @@ const lusca_1 = __importDefault(require("lusca"));
|
|
|
9
9
|
const luscaConfig = {
|
|
10
10
|
// CSRF 保护 - 修正配置格式
|
|
11
11
|
csrf: {
|
|
12
|
-
header:
|
|
13
|
-
cookie:
|
|
14
|
-
key:
|
|
15
|
-
secret: process.env.CSRF_SECRET ||
|
|
12
|
+
header: "x-csrf-token", // 从 header 中读取 token
|
|
13
|
+
cookie: "_csrf", // cookie 名称
|
|
14
|
+
key: "csrf", // session key
|
|
15
|
+
secret: process.env.CSRF_SECRET || "your-csrf-secret-change-in-production",
|
|
16
16
|
},
|
|
17
17
|
// 内容安全策略
|
|
18
18
|
csp: {
|
|
19
19
|
policy: {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
"default-src": "'self'",
|
|
21
|
+
"script-src": "'self' 'unsafe-inline'",
|
|
22
|
+
"style-src": "'self' 'unsafe-inline'",
|
|
23
|
+
"img-src": "'self' data: https:",
|
|
24
|
+
"font-src": "'self' https:",
|
|
25
|
+
"connect-src": "'self'",
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
28
|
// 其他安全设置
|
|
29
|
-
xframe:
|
|
29
|
+
xframe: "SAMEORIGIN",
|
|
30
30
|
nosniff: true,
|
|
31
31
|
xssProtection: true,
|
|
32
|
-
referrerPolicy:
|
|
32
|
+
referrerPolicy: "same-origin",
|
|
33
33
|
};
|
|
34
34
|
// 条件性 CSRF 保护中间件
|
|
35
35
|
const csrfProtection = (req, res, next) => {
|
|
36
36
|
// 跳过 GET 请求和某些不需要 CSRF 保护的路径
|
|
37
|
-
if (req.method ===
|
|
38
|
-
req.path.startsWith(
|
|
39
|
-
req.path ===
|
|
40
|
-
req.path.startsWith(
|
|
41
|
-
req.path.startsWith(
|
|
37
|
+
if (req.method === "GET" ||
|
|
38
|
+
req.path.startsWith("/static") ||
|
|
39
|
+
req.path === "/csrf-token" ||
|
|
40
|
+
req.path.startsWith("/_next") || // Next.js 内部资源
|
|
41
|
+
req.path.startsWith("/__next") // Next.js 开发模式内部端点
|
|
42
42
|
) {
|
|
43
43
|
return next();
|
|
44
44
|
}
|
|
@@ -67,10 +67,10 @@ const getCSRFToken = (req, res) => {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
catch (error) {
|
|
70
|
-
console.error(
|
|
70
|
+
console.error("获取 CSRF token 错误:", error);
|
|
71
71
|
res.status(500).json({
|
|
72
|
-
error:
|
|
73
|
-
message:
|
|
72
|
+
error: "Failed to generate CSRF token",
|
|
73
|
+
message: "生成 CSRF 令牌失败",
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
};
|
package/lib/server/db.d.ts
CHANGED