nsgm-cli 2.1.13 → 2.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +394 -156
  2. package/client/components/Button.tsx +3 -5
  3. package/client/components/ClientProviders.tsx +29 -0
  4. package/client/components/LanguageSwitcher.tsx +59 -0
  5. package/client/components/SSRSafeAntdProvider.tsx +24 -0
  6. package/client/components/SuppressHydrationWarnings.tsx +55 -0
  7. package/client/components/__tests__/Button.test.tsx +10 -10
  8. package/client/layout/index.tsx +153 -185
  9. package/client/redux/reducers.ts +1 -1
  10. package/client/redux/store.ts +2 -1
  11. package/client/redux/template/manage/actions.ts +77 -88
  12. package/client/redux/template/manage/reducers.ts +25 -37
  13. package/client/redux/template/manage/types.ts +1 -1
  14. package/client/service/template/manage.ts +20 -21
  15. package/client/styled/common.ts +12 -14
  16. package/client/styled/layout/index.ts +234 -120
  17. package/client/styled/template/manage.ts +102 -14
  18. package/client/utils/common.ts +23 -21
  19. package/client/utils/cookie.ts +18 -19
  20. package/client/utils/fetch.ts +64 -100
  21. package/client/utils/i18n.ts +68 -0
  22. package/client/utils/menu.tsx +42 -23
  23. package/client/utils/navigation.ts +58 -0
  24. package/client/utils/sso.ts +74 -84
  25. package/client/utils/suppressWarnings.ts +32 -0
  26. package/eslint.config.js +53 -19
  27. package/generation/README.md +25 -6
  28. package/generation/__tests__/example.test.js +41 -0
  29. package/generation/client/redux/reducers.ts +1 -1
  30. package/generation/client/utils/menu.tsx +36 -23
  31. package/generation/env +3 -0
  32. package/generation/env.example +3 -0
  33. package/generation/eslint.config.js +112 -0
  34. package/generation/gitignore +6 -1
  35. package/generation/jest.config.js +40 -0
  36. package/generation/next.config.js +7 -3
  37. package/generation/package.json +28 -4
  38. package/generation/tsconfig.json +6 -19
  39. package/jest.config.js +23 -6
  40. package/lib/args.js +9 -1
  41. package/lib/cli/app.d.ts +28 -0
  42. package/lib/cli/app.js +99 -0
  43. package/lib/cli/commands/build.d.ts +2 -0
  44. package/lib/cli/commands/build.js +29 -0
  45. package/lib/cli/commands/create.d.ts +2 -0
  46. package/lib/cli/commands/create.js +113 -0
  47. package/lib/cli/commands/delete.d.ts +3 -0
  48. package/lib/cli/commands/delete.js +151 -0
  49. package/lib/cli/commands/export.d.ts +2 -0
  50. package/lib/cli/commands/export.js +42 -0
  51. package/lib/cli/commands/help.d.ts +2 -0
  52. package/lib/cli/commands/help.js +42 -0
  53. package/lib/cli/commands/init.d.ts +2 -0
  54. package/lib/cli/commands/init.js +115 -0
  55. package/lib/cli/commands/server.d.ts +3 -0
  56. package/lib/cli/commands/server.js +26 -0
  57. package/lib/cli/commands/upgrade.d.ts +2 -0
  58. package/lib/cli/commands/upgrade.js +38 -0
  59. package/lib/cli/commands/version.d.ts +2 -0
  60. package/lib/cli/commands/version.js +24 -0
  61. package/lib/cli/index.d.ts +16 -0
  62. package/lib/cli/index.js +33 -0
  63. package/lib/cli/parser.d.ts +22 -0
  64. package/lib/cli/parser.js +115 -0
  65. package/lib/cli/registry.d.ts +33 -0
  66. package/lib/cli/registry.js +81 -0
  67. package/lib/cli/types/project.d.ts +10 -0
  68. package/lib/cli/types/project.js +2 -0
  69. package/lib/cli/types.d.ts +31 -0
  70. package/lib/cli/types.js +20 -0
  71. package/lib/cli/utils/console.d.ts +62 -0
  72. package/lib/cli/utils/console.js +148 -0
  73. package/lib/cli/utils/index.d.ts +2 -0
  74. package/lib/cli/utils/index.js +7 -0
  75. package/lib/cli/utils/prompt.d.ts +83 -0
  76. package/lib/cli/utils/prompt.js +327 -0
  77. package/lib/constants.d.ts +65 -0
  78. package/lib/constants.js +177 -0
  79. package/lib/generate.d.ts +25 -3
  80. package/lib/generate.js +98 -621
  81. package/lib/generate_create.d.ts +9 -0
  82. package/lib/generate_create.js +329 -0
  83. package/lib/generate_delete.d.ts +8 -0
  84. package/lib/generate_delete.js +233 -0
  85. package/lib/generate_init.d.ts +56 -0
  86. package/lib/generate_init.js +612 -0
  87. package/lib/generators/base-generator.d.ts +47 -0
  88. package/lib/generators/base-generator.js +92 -0
  89. package/lib/generators/file-generator.d.ts +48 -0
  90. package/lib/generators/file-generator.js +455 -0
  91. package/lib/generators/generator-factory.d.ts +20 -0
  92. package/lib/generators/generator-factory.js +25 -0
  93. package/lib/generators/i18n-generator.d.ts +51 -0
  94. package/lib/generators/i18n-generator.js +320 -0
  95. package/lib/generators/page-generator.d.ts +45 -0
  96. package/lib/generators/page-generator.js +578 -0
  97. package/lib/generators/resolver-generator.d.ts +14 -0
  98. package/lib/generators/resolver-generator.js +342 -0
  99. package/lib/generators/schema-generator.d.ts +7 -0
  100. package/lib/generators/schema-generator.js +57 -0
  101. package/lib/generators/service-generator.d.ts +11 -0
  102. package/lib/generators/service-generator.js +233 -0
  103. package/lib/generators/sql-generator.d.ts +8 -0
  104. package/lib/generators/sql-generator.js +52 -0
  105. package/lib/index.d.ts +1 -1
  106. package/lib/index.js +14 -173
  107. package/lib/server/csrf.js +9 -16
  108. package/lib/server/db.js +6 -7
  109. package/lib/server/graphql.js +5 -6
  110. package/lib/server/plugins/date.js +1 -1
  111. package/lib/server/utils/graphql-cache.js +3 -3
  112. package/lib/tsconfig.build.tsbuildinfo +1 -1
  113. package/lib/utils/project-config.d.ts +5 -0
  114. package/lib/utils/project-config.js +145 -0
  115. package/lib/utils.js +1 -1
  116. package/next-i18next.config.js +18 -0
  117. package/next.config.js +61 -18
  118. package/package.json +16 -8
  119. package/pages/_app.tsx +77 -33
  120. package/pages/_document.tsx +78 -21
  121. package/pages/_error.tsx +66 -0
  122. package/pages/index.tsx +109 -47
  123. package/pages/login.tsx +66 -41
  124. package/pages/template/manage.tsx +162 -151
  125. package/public/fonts/font-awesome.min.css +4 -0
  126. package/public/fonts/fontawesome-webfont.woff +0 -0
  127. package/public/fonts/fontawesome-webfont.woff2 +0 -0
  128. package/public/locales/en-US/common.json +48 -0
  129. package/public/locales/en-US/home.json +57 -0
  130. package/public/locales/en-US/layout.json +22 -0
  131. package/public/locales/en-US/login.json +13 -0
  132. package/public/locales/en-US/template.json +42 -0
  133. package/public/locales/ja-JP/common.json +48 -0
  134. package/public/locales/ja-JP/home.json +57 -0
  135. package/public/locales/ja-JP/layout.json +22 -0
  136. package/public/locales/ja-JP/login.json +13 -0
  137. package/public/locales/ja-JP/template.json +42 -0
  138. package/public/locales/zh-CN/common.json +48 -0
  139. package/public/locales/zh-CN/home.json +57 -0
  140. package/public/locales/zh-CN/layout.json +22 -0
  141. package/public/locales/zh-CN/login.json +13 -0
  142. package/public/locales/zh-CN/template.json +42 -0
  143. package/public/slbhealthcheck.html +1 -1
  144. package/server/apis/template.js +0 -2
  145. package/server/utils/validation.js +163 -0
  146. package/types/i18next.d.ts +10 -0
  147. package/generation/eslintrc.js +0 -16
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResolverGenerator = void 0;
4
+ const base_generator_1 = require("./base-generator");
5
+ /**
6
+ * Resolver生成器
7
+ */
8
+ class ResolverGenerator extends base_generator_1.BaseGenerator {
9
+ generate() {
10
+ const selectFields = this.fields.map((f) => f.name).join(', ');
11
+ const insertFields = this.getFormFields();
12
+ const searchableFields = this.getSearchableFields();
13
+ const insertFieldNames = insertFields.map((f) => f.name).join(', ');
14
+ const insertPlaceholders = insertFields.map(() => '?').join(', ');
15
+ const insertValues = insertFields
16
+ .map((f) => {
17
+ if (f.type === 'integer') {
18
+ return `valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)}`;
19
+ }
20
+ return `data.${f.name}`;
21
+ })
22
+ .join(', ');
23
+ const searchConditions = this.generateSearchConditions(searchableFields);
24
+ const updateFields = insertFields.map((f) => `${f.name} = ?`).join(', ');
25
+ return `const { executeQuery, executePaginatedQuery } = require('../../utils/common')
26
+ const { validateInteger, validatePagination, validateId } = require('../../utils/validation')
27
+
28
+ module.exports = {
29
+ // 获取${this.controller}列表(分页)
30
+ ${this.controller}: async ({ page = 0, pageSize = 10 }) => {
31
+ try {
32
+ const { page: validPage, pageSize: validPageSize } = validatePagination(page, pageSize);
33
+
34
+ const sql = 'SELECT ${selectFields} FROM ${this.controller} LIMIT ? OFFSET ?';
35
+ const countSql = 'SELECT COUNT(*) as counts FROM ${this.controller}';
36
+ const values = [validPageSize, validPage * validPageSize];
37
+
38
+ console.log('执行分页查询:', { sql, values, countSql });
39
+
40
+ return await executePaginatedQuery(sql, countSql, values);
41
+ } catch (error) {
42
+ console.error('获取${this.controller}列表失败:', error.message);
43
+ throw error;
44
+ }
45
+ },
46
+
47
+ // 根据ID获取${this.controller}
48
+ ${this.controller}Get: async ({ id }) => {
49
+ try {
50
+ const validId = validateId(id);
51
+
52
+ const sql = 'SELECT ${selectFields} FROM ${this.controller} WHERE id = ?';
53
+ const values = [validId];
54
+
55
+ console.log('根据ID查询${this.controller}:', { sql, values });
56
+
57
+ const results = await executeQuery(sql, values);
58
+
59
+ if (results.length === 0) {
60
+ throw new Error(\`ID为 \${validId} 的${this.controller}不存在\`);
61
+ }
62
+
63
+ return results[0];
64
+ } catch (error) {
65
+ console.error('获取${this.controller}失败:', error.message);
66
+ throw error;
67
+ }
68
+ },
69
+
70
+ // 搜索${this.controller}(分页)
71
+ ${this.controller}Search: async ({ page = 0, pageSize = 10, data = {} }) => {
72
+ try {
73
+ const { page: validPage, pageSize: validPageSize } = validatePagination(page, pageSize);
74
+
75
+ const values = [];
76
+ const countValues = [];
77
+
78
+ let whereSql = '';
79
+ ${searchConditions}
80
+
81
+ const sql = \`SELECT ${selectFields} FROM ${this.controller} WHERE 1=1\${whereSql} LIMIT ? OFFSET ?\`;
82
+ const countSql = \`SELECT COUNT(*) as counts FROM ${this.controller} WHERE 1=1\${whereSql}\`;
83
+
84
+ values.push(validPageSize, validPage * validPageSize);
85
+
86
+ console.log('搜索${this.controller}:', { sql, values, countSql, countValues });
87
+
88
+ return await executePaginatedQuery(sql, countSql, values, countValues);
89
+ } catch (error) {
90
+ console.error('搜索${this.controller}失败:', error.message);
91
+ throw error;
92
+ }
93
+ },
94
+
95
+ // 添加${this.controller}
96
+ ${this.controller}Add: async ({ data }) => {
97
+ try {
98
+ ${this.generateNewValidationCalls(insertFields)}
99
+
100
+ const sql = 'INSERT INTO ${this.controller} (${insertFieldNames}) VALUES (${insertPlaceholders})';
101
+ const values = [${insertValues}];
102
+
103
+ console.log('添加${this.controller}:', { sql, values });
104
+
105
+ const results = await executeQuery(sql, values);
106
+ return results.insertId;
107
+ } catch (error) {
108
+ console.error('添加${this.controller}失败:', error.message);
109
+ throw error;
110
+ }
111
+ },
112
+
113
+ // 批量添加${this.controller}
114
+ ${this.controller}BatchAdd: async ({ datas }) => {
115
+ try {
116
+ if (!Array.isArray(datas) || datas.length === 0) {
117
+ throw new Error('批量添加数据不能为空');
118
+ }
119
+
120
+ // 验证所有数据并转换
121
+ const validatedDatas = datas.map((data, index) => {
122
+ try {
123
+ ${this.generateBatchValidation(insertFields)}
124
+ return { ${this.generateBatchReturnObject(insertFields)} };
125
+ } catch (error) {
126
+ throw new Error(\`第 \${index + 1} 条数据验证失败: \${error.message}\`);
127
+ }
128
+ });
129
+
130
+ const placeholders = validatedDatas.map(() => '(${insertPlaceholders})').join(',');
131
+ const sql = \`INSERT INTO ${this.controller} (${insertFieldNames}) VALUES \${placeholders}\`;
132
+ const values = validatedDatas.flatMap(data => [${this.generateBatchInsertValues(insertFields)}]);
133
+
134
+ console.log('批量添加${this.controller}:', { sql, values });
135
+
136
+ const results = await executeQuery(sql, values);
137
+ return results.insertId;
138
+ } catch (error) {
139
+ console.error('批量添加${this.controller}失败:', error.message);
140
+ throw error;
141
+ }
142
+ },
143
+
144
+ // 更新${this.controller}
145
+ ${this.controller}Update: async ({ id, data }) => {
146
+ try {
147
+ const validId = validateId(id);
148
+
149
+ if (!data) {
150
+ throw new Error('更新数据不能为空');
151
+ }
152
+
153
+ ${this.generateUpdateValidation(insertFields)}
154
+
155
+ const sql = 'UPDATE ${this.controller} SET ${updateFields} WHERE id = ?';
156
+ const values = [${this.generateUpdateValues(insertFields)}, validId];
157
+
158
+ console.log('更新${this.controller}:', { sql, values });
159
+
160
+ const results = await executeQuery(sql, values);
161
+
162
+ if (results.affectedRows === 0) {
163
+ throw new Error(\`ID为 \${validId} 的${this.controller}不存在\`);
164
+ }
165
+
166
+ return true;
167
+ } catch (error) {
168
+ console.error('更新${this.controller}失败:', error.message);
169
+ throw error;
170
+ }
171
+ },
172
+
173
+ // 删除${this.controller}
174
+ ${this.controller}Delete: async ({ id }) => {
175
+ try {
176
+ const validId = validateId(id);
177
+
178
+ const sql = 'DELETE FROM ${this.controller} WHERE id = ?';
179
+ const values = [validId];
180
+
181
+ console.log('删除${this.controller}:', { sql, values });
182
+
183
+ const results = await executeQuery(sql, values);
184
+
185
+ if (results.affectedRows === 0) {
186
+ throw new Error(\`ID为 \${validId} 的${this.controller}不存在\`);
187
+ }
188
+
189
+ return true;
190
+ } catch (error) {
191
+ console.error('删除${this.controller}失败:', error.message);
192
+ throw error;
193
+ }
194
+ },
195
+
196
+ // 批量删除${this.controller}
197
+ ${this.controller}BatchDelete: async ({ ids }) => {
198
+ try {
199
+ if (!Array.isArray(ids) || ids.length === 0) {
200
+ throw new Error('批量删除的ID列表不能为空');
201
+ }
202
+
203
+ // 验证所有ID
204
+ const validIds = ids.map((id, index) => {
205
+ try {
206
+ return validateId(id, \`第\${index + 1}个ID\`);
207
+ } catch (error) {
208
+ throw new Error(\`第 \${index + 1} 个ID验证失败: \${error.message}\`);
209
+ }
210
+ });
211
+
212
+ const placeholders = validIds.map(() => '?').join(',');
213
+ const sql = \`DELETE FROM ${this.controller} WHERE id IN (\${placeholders})\`;
214
+
215
+ console.log('批量删除${this.controller}:', { sql, values: validIds });
216
+
217
+ const results = await executeQuery(sql, validIds);
218
+
219
+ if (results.affectedRows === 0) {
220
+ throw new Error('没有找到要删除的${this.controller}');
221
+ }
222
+
223
+ return true;
224
+ } catch (error) {
225
+ console.error('批量删除${this.controller}失败:', error.message);
226
+ throw error;
227
+ }
228
+ }
229
+ }`;
230
+ }
231
+ generateSearchConditions(searchableFields) {
232
+ if (searchableFields.length === 0)
233
+ return '';
234
+ const conditions = searchableFields.map((field) => {
235
+ if (field.type === 'varchar' || field.type === 'text') {
236
+ return ` if (data.${field.name} && data.${field.name}.trim() !== '') {
237
+ whereSql += ' AND ${field.name} LIKE ?';
238
+ const ${field.name}Pattern = \`%\${data.${field.name}.trim()}%\`;
239
+ values.push(${field.name}Pattern);
240
+ countValues.push(${field.name}Pattern);
241
+ }`;
242
+ }
243
+ else if (field.type === 'integer') {
244
+ return ` if (data.${field.name} !== undefined && data.${field.name} !== null && data.${field.name} !== '') {
245
+ // 使用通用验证工具验证 ${field.name}
246
+ const valid${field.name.charAt(0).toUpperCase() + field.name.slice(1)} = validateInteger(data.${field.name}, '${field.name}', { min: 0, max: 150 });
247
+ if (valid${field.name.charAt(0).toUpperCase() + field.name.slice(1)} !== undefined) {
248
+ whereSql += ' AND ${field.name} = ?';
249
+ values.push(valid${field.name.charAt(0).toUpperCase() + field.name.slice(1)});
250
+ countValues.push(valid${field.name.charAt(0).toUpperCase() + field.name.slice(1)});
251
+ }
252
+ }`;
253
+ }
254
+ else {
255
+ return ` if (data.${field.name} !== undefined && data.${field.name} !== null) {
256
+ whereSql += ' AND ${field.name} = ?';
257
+ values.push(data.${field.name});
258
+ countValues.push(data.${field.name});
259
+ }`;
260
+ }
261
+ });
262
+ return conditions.join('\n\n');
263
+ }
264
+ generateNewValidationCalls(insertFields) {
265
+ return insertFields
266
+ .map((f) => {
267
+ if (f.type === 'integer') {
268
+ const validationOptions = f.name === 'age' ? '{ min: 0, max: 150, required: true }' : '{ required: true }';
269
+ return ` const valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = validateInteger(data.${f.name}, '${f.name}', ${validationOptions});`;
270
+ }
271
+ else if (f.required) {
272
+ return ` if (!data.${f.name}) {
273
+ throw new Error('${f.comment || f.name}是必填字段');
274
+ }`;
275
+ }
276
+ return '';
277
+ })
278
+ .filter((call) => call.length > 0)
279
+ .join('\n');
280
+ }
281
+ generateBatchValidation(insertFields) {
282
+ return insertFields
283
+ .map((f) => {
284
+ if (f.type === 'integer') {
285
+ const validationOptions = f.name === 'age' ? '{ min: 0, max: 150, required: true }' : '{ required: true }';
286
+ return ` const valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = validateInteger(data.${f.name}, \`第\${index + 1}条数据的${f.name}\`, ${validationOptions});`;
287
+ }
288
+ else if (f.required) {
289
+ return ` if (!data.${f.name}) {
290
+ throw new Error('${f.comment || f.name}是必填字段');
291
+ }`;
292
+ }
293
+ return '';
294
+ })
295
+ .filter((call) => call.length > 0)
296
+ .join('\n');
297
+ }
298
+ generateUpdateValidation(insertFields) {
299
+ return insertFields
300
+ .map((f) => {
301
+ if (f.type === 'integer') {
302
+ const validationOptions = f.name === 'age' ? '{ min: 0, max: 150, required: true }' : '{ required: true }';
303
+ return ` let valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = data.${f.name};
304
+ if (data.${f.name} !== undefined) {
305
+ valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)} = validateInteger(data.${f.name}, '${f.name}', ${validationOptions});
306
+ }`;
307
+ }
308
+ else if (f.required) {
309
+ return ` if (data.${f.name} !== undefined && !data.${f.name}) {
310
+ throw new Error('${f.comment || f.name}是必填字段');
311
+ }`;
312
+ }
313
+ return '';
314
+ })
315
+ .filter((call) => call.length > 0)
316
+ .join('\n');
317
+ }
318
+ generateUpdateValues(insertFields) {
319
+ return insertFields
320
+ .map((f) => {
321
+ if (f.type === 'integer') {
322
+ return `valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)}`;
323
+ }
324
+ return `data.${f.name}`;
325
+ })
326
+ .join(', ');
327
+ }
328
+ generateBatchReturnObject(insertFields) {
329
+ return insertFields
330
+ .map((f) => {
331
+ if (f.type === 'integer') {
332
+ return `${f.name}: valid${f.name.charAt(0).toUpperCase() + f.name.slice(1)}`;
333
+ }
334
+ return `${f.name}: data.${f.name}`;
335
+ })
336
+ .join(', ');
337
+ }
338
+ generateBatchInsertValues(insertFields) {
339
+ return insertFields.map((f) => `data.${f.name}`).join(', ');
340
+ }
341
+ }
342
+ exports.ResolverGenerator = ResolverGenerator;
@@ -0,0 +1,7 @@
1
+ import { BaseGenerator } from './base-generator';
2
+ /**
3
+ * GraphQL Schema生成器
4
+ */
5
+ export declare class SchemaGenerator extends BaseGenerator {
6
+ generate(): string;
7
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaGenerator = void 0;
4
+ const base_generator_1 = require("./base-generator");
5
+ /**
6
+ * GraphQL Schema生成器
7
+ */
8
+ class SchemaGenerator extends base_generator_1.BaseGenerator {
9
+ generate() {
10
+ const capitalizedTypeName = this.getCapitalizedController();
11
+ const pluralTypeName = `${capitalizedTypeName}s`;
12
+ const typeFields = this.getNonSystemFields()
13
+ .map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`)
14
+ .join('\n');
15
+ const inputFields = this.getFormFields()
16
+ .map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`)
17
+ .join('\n');
18
+ const searchableFields = this.getSearchableFields();
19
+ const searchFields = searchableFields.length > 0
20
+ ? searchableFields.map((field) => ` ${field.name}: ${this.getGraphQLType(field.type)}`).join('\n')
21
+ : ' name: String';
22
+ return `module.exports = {
23
+ query: \`
24
+ ${this.controller}(page: Int, pageSize: Int): ${pluralTypeName}
25
+ ${this.controller}Get(id: Int): ${capitalizedTypeName}
26
+ ${this.controller}Search(page: Int, pageSize: Int, data: ${capitalizedTypeName}SearchInput): ${pluralTypeName}
27
+ \`,
28
+ mutation: \`
29
+ ${this.controller}Add(data: ${capitalizedTypeName}AddInput): Int
30
+ ${this.controller}BatchAdd(datas: [${capitalizedTypeName}AddInput]): Int
31
+ ${this.controller}Update(id: Int, data: ${capitalizedTypeName}AddInput): Boolean
32
+ ${this.controller}Delete(id: Int): Boolean
33
+ ${this.controller}BatchDelete(ids: [Int]): Boolean
34
+ \`,
35
+ subscription: \`\`,
36
+ type: \`
37
+ type ${capitalizedTypeName} {
38
+ ${typeFields}
39
+ }
40
+
41
+ type ${pluralTypeName} {
42
+ totalCounts: Int
43
+ items: [${capitalizedTypeName}]
44
+ }
45
+
46
+ input ${capitalizedTypeName}AddInput {
47
+ ${inputFields}
48
+ }
49
+
50
+ input ${capitalizedTypeName}SearchInput {
51
+ ${searchFields}
52
+ }
53
+ \`
54
+ }`;
55
+ }
56
+ }
57
+ exports.SchemaGenerator = SchemaGenerator;
@@ -0,0 +1,11 @@
1
+ import { BaseGenerator } from './base-generator';
2
+ /**
3
+ * 客户端服务生成器
4
+ */
5
+ export declare class ServiceGenerator extends BaseGenerator {
6
+ generate(): string;
7
+ private generateValidationFunctions;
8
+ private generateValidationCallsForService;
9
+ private generateDataObjectWithValidation;
10
+ private generateBatchValidationCalls;
11
+ }
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceGenerator = void 0;
4
+ const base_generator_1 = require("./base-generator");
5
+ /**
6
+ * 客户端服务生成器
7
+ */
8
+ class ServiceGenerator extends base_generator_1.BaseGenerator {
9
+ generate() {
10
+ const capitalizedTypeName = this.getCapitalizedController();
11
+ // 排除系统字段 create_date 和 update_date
12
+ const selectFields = this.fields
13
+ .filter((f) => !['create_date', 'update_date'].includes(f.name))
14
+ .map((f) => f.name)
15
+ .join(' ');
16
+ const inputFields = this.getFormFields();
17
+ const searchFields = this.getSearchableFields();
18
+ // 检查是否有integer类型字段需要验证
19
+ const hasIntegerFields = inputFields.some((field) => field.type === 'integer');
20
+ const validationFunctions = hasIntegerFields ? this.generateValidationFunctions(inputFields) : '';
21
+ return `import { getLocalGraphql } from '@/utils/fetch'
22
+ import _ from 'lodash'
23
+
24
+ ${validationFunctions}
25
+
26
+ export const get${capitalizedTypeName}Service = (page = 0, pageSize = 10) => {
27
+ const get${capitalizedTypeName}Query = \`query ($page: Int, $pageSize: Int) { ${this.controller}(page: $page, pageSize: $pageSize) {
28
+ totalCounts items {
29
+ ${selectFields}
30
+ }
31
+ }
32
+ }\`
33
+
34
+ return getLocalGraphql(get${capitalizedTypeName}Query, {
35
+ page,
36
+ pageSize
37
+ })
38
+ }
39
+
40
+ export const search${capitalizedTypeName}ByIdService = (id: number) => {
41
+ const search${capitalizedTypeName}ByIdQuery = \`query ($id: Int) { ${this.controller}Get(id: $id){
42
+ ${selectFields}
43
+ }
44
+ }\`
45
+
46
+ return getLocalGraphql(search${capitalizedTypeName}ByIdQuery, {
47
+ id
48
+ })
49
+ }
50
+
51
+ export const search${capitalizedTypeName}Service = (page = 0, pageSize = 10, data: any) => {
52
+ const { ${searchFields.map((f) => f.name).join(', ')} } = data
53
+
54
+ ${this.generateValidationCallsForService(searchFields, ' ', false)}
55
+
56
+ const search${capitalizedTypeName}Query = \`query ($page: Int, $pageSize: Int, $data: ${capitalizedTypeName}SearchInput) {
57
+ ${this.controller}Search(page: $page, pageSize: $pageSize, data: $data) {
58
+ totalCounts items {
59
+ ${selectFields}
60
+ }
61
+ }
62
+ }\`
63
+
64
+ return getLocalGraphql(search${capitalizedTypeName}Query, {
65
+ page,
66
+ pageSize,
67
+ data: {
68
+ ${this.generateDataObjectWithValidation(searchFields)}
69
+ }
70
+ })
71
+ }
72
+
73
+ export const add${capitalizedTypeName}Service = (data: any) => {
74
+ const { ${inputFields.map((f) => f.name).join(', ')} } = data
75
+
76
+ ${this.generateValidationCallsForService(inputFields, ' ', true)}
77
+
78
+ const add${capitalizedTypeName}Query = \`mutation ($data: ${capitalizedTypeName}AddInput) { ${this.controller}Add(data: $data) }\`
79
+
80
+ return getLocalGraphql(add${capitalizedTypeName}Query, {
81
+ data: {
82
+ ${this.generateDataObjectWithValidation(inputFields)}
83
+ }
84
+ })
85
+ }
86
+
87
+ export const update${capitalizedTypeName}Service = (id: number, data: any) => {
88
+ const { ${inputFields.map((f) => f.name).join(', ')} } = data
89
+
90
+ ${this.generateValidationCallsForService(inputFields, ' ', true)}
91
+
92
+ const update${capitalizedTypeName}Query = \`mutation ($id: Int, $data: ${capitalizedTypeName}AddInput) { ${this.controller}Update(id: $id, data: $data) }\`
93
+
94
+ return getLocalGraphql(update${capitalizedTypeName}Query, {
95
+ id,
96
+ data: {
97
+ ${this.generateDataObjectWithValidation(inputFields)}
98
+ }
99
+ })
100
+ }
101
+
102
+ export const delete${capitalizedTypeName}Service = (id: number) => {
103
+ const delete${capitalizedTypeName}Query = \`mutation ($id: Int) { ${this.controller}Delete(id: $id) }\`
104
+
105
+ return getLocalGraphql(delete${capitalizedTypeName}Query, {
106
+ id
107
+ })
108
+ }
109
+
110
+ export const batchAdd${capitalizedTypeName}Service = (datas: any) => {
111
+ ${this.generateBatchValidationCalls(inputFields, ' ')}
112
+
113
+ const batchAdd${capitalizedTypeName}Query = \`mutation ($datas: [${capitalizedTypeName}AddInput]) { ${this.controller}BatchAdd(datas: $datas) }\`
114
+
115
+ return getLocalGraphql(batchAdd${capitalizedTypeName}Query, {
116
+ datas: validatedDatas
117
+ })
118
+ }
119
+
120
+ export const batchDelete${capitalizedTypeName}Service = (ids: any) => {
121
+ const batchDelete${capitalizedTypeName}Query = \`mutation ($ids: [Int]) { ${this.controller}BatchDelete(ids: $ids) }\`
122
+
123
+ return getLocalGraphql(batchDelete${capitalizedTypeName}Query, {
124
+ ids
125
+ })
126
+ }
127
+ `;
128
+ }
129
+ generateValidationFunctions(inputFields) {
130
+ const integerFields = inputFields.filter((field) => field.type === 'integer');
131
+ if (integerFields.length === 0) {
132
+ return '';
133
+ }
134
+ const validationFunctions = integerFields.map((field) => {
135
+ const fieldName = field.name;
136
+ const capitalizedName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
137
+ const upperFieldName = fieldName.toUpperCase();
138
+ return `// 简化的${fieldName}验证函数
139
+ const validate${capitalizedName} = (${fieldName}: any, required = false) => {
140
+ if (${fieldName} === undefined || ${fieldName} === null || ${fieldName} === '') {
141
+ if (required) {
142
+ return { valid: false, error: '${fieldName}是必填字段', code: 'REQUIRED_${upperFieldName}_MISSING' }
143
+ }
144
+ return { valid: true, value: undefined }
145
+ }
146
+
147
+ const parsed${capitalizedName} = parseInt(${fieldName}, 10)
148
+ if (isNaN(parsed${capitalizedName})) {
149
+ return {
150
+ valid: false,
151
+ error: \`${fieldName}必须是数字,收到的值: "\${${fieldName}}"\`,
152
+ code: 'INVALID_${upperFieldName}_FORMAT'
153
+ }
154
+ }
155
+
156
+ return { valid: true, value: parsed${capitalizedName} }
157
+ }`;
158
+ });
159
+ return `${validationFunctions.join('\n\n')}\n\n`;
160
+ }
161
+ generateValidationCallsForService(inputFields, indent, required) {
162
+ const integerFields = inputFields.filter((field) => field.type === 'integer');
163
+ if (integerFields.length === 0) {
164
+ return '';
165
+ }
166
+ const validationCalls = integerFields.map((field) => {
167
+ const fieldName = field.name;
168
+ const capitalizedName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
169
+ const requiredStr = required ? 'true' : 'false';
170
+ return `${indent}// 验证${required ? '必填' : ''}${fieldName}
171
+ ${indent}const ${fieldName}Validation = validate${capitalizedName}(${fieldName}, ${requiredStr})
172
+ ${indent}if (!${fieldName}Validation.valid) {
173
+ ${indent} return Promise.reject({
174
+ ${indent} error: true,
175
+ ${indent} message: ${fieldName}Validation.error,
176
+ ${indent} code: ${fieldName}Validation.code
177
+ ${indent} })
178
+ ${indent}}`;
179
+ });
180
+ return validationCalls.join('\n\n') + (validationCalls.length > 0 ? '\n\n' : '');
181
+ }
182
+ generateDataObjectWithValidation(inputFields) {
183
+ return inputFields
184
+ .map((field) => {
185
+ if (field.type === 'integer') {
186
+ return ` ${field.name}: ${field.name}Validation.value`;
187
+ }
188
+ return ` ${field.name}`;
189
+ })
190
+ .join(',\n');
191
+ }
192
+ generateBatchValidationCalls(inputFields, indent) {
193
+ const integerFields = inputFields.filter((field) => field.type === 'integer');
194
+ if (integerFields.length === 0) {
195
+ return `${indent}// 验证批量数据
196
+ ${indent}const validatedDatas: Array<{ ${inputFields.map((f) => `${f.name}: any`).join('; ')} }> = []
197
+
198
+ ${indent}for (let i = 0; i < datas.length; i++) {
199
+ ${indent} const { ${inputFields.map((f) => f.name).join(', ')} } = datas[i]
200
+
201
+ ${indent} validatedDatas.push({
202
+ ${indent} ${inputFields.map((f) => f.name).join(',\n ')}
203
+ ${indent} })
204
+ ${indent}}`;
205
+ }
206
+ return `${indent}// 验证批量数据
207
+ ${indent}const validatedDatas: Array<{ ${inputFields.map((f) => `${f.name}: ${f.type === 'integer' ? 'number' : 'any'}`).join('; ')} }> = []
208
+
209
+ ${indent}for (let i = 0; i < datas.length; i++) {
210
+ ${indent} const { ${inputFields.map((f) => f.name).join(', ')} } = datas[i]
211
+
212
+ ${integerFields
213
+ .map((field) => {
214
+ const fieldName = field.name;
215
+ const capitalizedName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
216
+ return `${indent} const ${fieldName}Validation = validate${capitalizedName}(${fieldName}, true)
217
+ ${indent} if (!${fieldName}Validation.valid) {
218
+ ${indent} return Promise.reject({
219
+ ${indent} error: true,
220
+ ${indent} message: \`第 \${i + 1} 条数据: \${${fieldName}Validation.error}\`,
221
+ ${indent} code: ${fieldName}Validation.code
222
+ ${indent} })
223
+ ${indent} }`;
224
+ })
225
+ .join('\n\n')}
226
+
227
+ ${indent} validatedDatas.push({
228
+ ${indent} ${inputFields.map((field) => (field.type === 'integer' ? `${field.name}: ${field.name}Validation.value!` : field.name)).join(',\n ')}
229
+ ${indent} })
230
+ ${indent}}`;
231
+ }
232
+ }
233
+ exports.ServiceGenerator = ServiceGenerator;
@@ -0,0 +1,8 @@
1
+ import { BaseGenerator } from './base-generator';
2
+ /**
3
+ * SQL生成器
4
+ * 专门负责生成数据库表结构
5
+ */
6
+ export declare class SQLGenerator extends BaseGenerator {
7
+ generate(): string;
8
+ }