@meadmin/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/commanders/crud.d.ts +2 -0
  2. package/dist/commanders/crud.js +543 -0
  3. package/dist/commanders/index.d.ts +2 -0
  4. package/dist/commanders/index.js +12 -0
  5. package/dist/commanders/sync.d.ts +2 -0
  6. package/dist/commanders/sync.js +32 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +12 -0
  9. package/dist/utils/app.d.ts +5 -0
  10. package/dist/utils/app.js +12 -0
  11. package/dist/utils/db.d.ts +1 -0
  12. package/dist/utils/db.js +8 -0
  13. package/dist/utils/env.d.ts +1 -0
  14. package/dist/utils/env.js +20 -0
  15. package/dist/utils/file.d.ts +13 -0
  16. package/dist/utils/file.js +24 -0
  17. package/dist/utils/formatting.d.ts +68 -0
  18. package/dist/utils/formatting.js +103 -0
  19. package/dist/utils/log.d.ts +12 -0
  20. package/dist/utils/log.js +59 -0
  21. package/package.json +55 -0
  22. package/template/crud/server/controller/controller.ts.art +124 -0
  23. package/template/crud/server/dto/create.dto.ts.art +11 -0
  24. package/template/crud/server/dto/query.dto.ts.art +19 -0
  25. package/template/crud/server/dto/update.dto.ts.art +11 -0
  26. package/template/crud/server/service/service.ts.art +220 -0
  27. package/template/crud/view/api/api.ts.art +120 -0
  28. package/template/crud/view/api/class.ts.art +2 -0
  29. package/template/crud/view/api/searchTypes.ts.art +4 -0
  30. package/template/crud/view/api/type.ts.art +2 -0
  31. package/template/crud/view/api/valueDefault.ts.art +1 -0
  32. package/template/crud/view/api/valueType.ts.art +3 -0
  33. package/template/crud/view/views/components/addOrUp.vue.art +96 -0
  34. package/template/crud/view/views/components/addOrUpItem.vue.art +26 -0
  35. package/template/crud/view/views/components/info.vue.art +63 -0
  36. package/template/crud/view/views/components/rules.ts.art +5 -0
  37. package/template/crud/view/views/components/rulesList.ts.art +2 -0
  38. package/template/crud/view/views/dict.ts.art +11 -0
  39. package/template/crud/view/views/index.vue.art +83 -0
  40. package/template/crud/view/views/lang/en.json.art +4 -0
  41. package/template/crud/view/views/searchItem.vue.art +17 -0
  42. package/template/crud/view/views/tableColum.vue.art +19 -0
@@ -0,0 +1,220 @@
1
+ import { BadRequestError } from '@midwayjs/core/dist/error/http.js';
2
+ import { InjectRepository } from '@/decorators/index.js';
3
+ import { Provide, Inject } from '@midwayjs/core';
4
+ import { {{@ replaceNames.CreateDto}} } from '{{@ paths.createDtoPath}}';
5
+ import { {{@ replaceNames.QueryDto}} } from '{{@ paths.queryDtoPath}}';
6
+ import { {{@ replaceNames.UpdateDto}} } from '{{@ paths.updateDtoPath}}';
7
+ import { {{@ replaceNames.Name}} } from '{{@ paths.entityPath}}';
8
+ import { MidwayI18nService } from '@midwayjs/i18n';
9
+ import { Transaction } from '@/decorators/index.js';
10
+ import { Op } from '@sequelize/core';{{each $imports.objectKeys(entity.belongsToEntity)}}<% const valueEntity = entity.belongsToEntity[$value]; %>{{if ['File'].includes(valueEntity.entityName)}}<% return; %>{{/if}}
11
+ import { {{@ valueEntity.entityName}} } from '{{@ paths.entityPath.replace(replaceNames.name,valueEntity.entityFileName)}}';{{/each}}{{each $imports.objectKeys(entity.belongsToManyEntity)}}<% const valueEntity = entity.belongsToManyEntity[$value]; %>{{if ['File'].includes(valueEntity.entityName)}}<% return; %>{{/if}}
12
+ import { {{@ valueEntity.entityName}} } from '{{@ paths.entityPath.replace(replaceNames.name,valueEntity.entityFileName)}}';{{/each}}
13
+
14
+ {{if entity.pk.length > 1}}type PK = {
15
+ {{each entity.pk}}
16
+ {{@ $value}}: {{@ entitySchema.properties[$value].type}},
17
+ {{/each}}
18
+ }{{/if}}
19
+ //{{@ entity.tableComment}}
20
+ @Provide()
21
+ export class {{@ replaceNames.Service}} {
22
+ @InjectRepository({{@ replaceNames.Name}})
23
+ {{@ replaceNames.name}}Repository: typeof {{@ replaceNames.Name}}
24
+
25
+ @Inject()
26
+ i18nService: MidwayI18nService;
27
+ <% const hasStatement = ['File']; %>
28
+ {{each $imports.objectKeys(entity.belongsToEntity).filter(v=>v!='File')}}<% const valueEntity = entity.belongsToEntity[$value]; %>{{if hasStatement.includes(valueEntity.entityName)}}<% return; %>{{else}}<% hasStatement.push(valueEntity.entityName);%>{{/if}}
29
+ //查询belongsTo关联模型{{@ $value}}{{@ valueEntity.tableComment}}
30
+ @InjectRepository({{@ valueEntity.entityName}})
31
+ {{@ valueEntity.entityFileName}}Repository: typeof {{@ valueEntity.entityName}}
32
+
33
+ /**
34
+ * 获取{{@ valueEntity.tableComment}}信息
35
+ * @param queryDto
36
+ * @returns
37
+ */
38
+ @Transaction()
39
+ async get{{@ valueEntity.entityName}}(page:number,pageSize:number,{{@ valueEntity.pk[0]}}:{{@ swaggerSchemas[valueEntity.entityName]?.properties?.[entity.pk[0]]?.type || 'string'}}{{if valueEntity.nameKeys.length}},{{@ valueEntity.nameKeys[0]}}: string = '', {{/if}}) {
40
+ const where = {};
41
+ if({{@ valueEntity.pk[0]}}){
42
+ where['{{@ valueEntity.pk[0]}}'] = {{@ valueEntity.pk[0]}};
43
+ }
44
+ {{if valueEntity.nameKeys.length}}if({{@ valueEntity.nameKeys[0]}}){
45
+ where['{{@ valueEntity.nameKeys[0]}}'] = { [Op.like]: '%'+{{@ valueEntity.nameKeys[0]}}+'%' };
46
+ }{{/if}}
47
+ const { count, rows } = await this.{{@ valueEntity.entityFileName}}Repository.findAndCountAll({
48
+ where,
49
+ offset: (page - 1) * pageSize,
50
+ limit: pageSize,
51
+ });
52
+ return {
53
+ list: rows,
54
+ total: count,
55
+ page: page,
56
+ pageSize: pageSize,
57
+ };
58
+ }{{/each}}
59
+
60
+ {{each $imports.objectKeys(entity.belongsToManyEntity).filter(v=>v!='File')}}<% const valueEntity = entity.belongsToManyEntity[$value]; %>{{if hasStatement.includes(valueEntity.entityName)}}<% return; %>{{else}}<% hasStatement.push(valueEntity.entityName);%>{{/if}}
61
+ //查询belongsToMany关联模型{{@ $value}}{{@ valueEntity.tableComment}}
62
+ @InjectRepository({{@ valueEntity.entityName}})
63
+ {{@ valueEntity.entityFileName}}Repository: typeof {{@ valueEntity.entityName}}
64
+
65
+ /**
66
+ * 获取{{@ valueEntity.tableComment}}信息
67
+ * @param queryDto
68
+ * @returns
69
+ */
70
+ @Transaction()
71
+ async get{{@ valueEntity.entityName}}(page:number,pageSize:number,{{@ valueEntity.pk[0]}}:{{@ swaggerSchemas[valueEntity.entityName]?.properties?.[entity.pk[0]]?.type || 'string'}}{{if valueEntity.nameKeys.length}},{{@ valueEntity.nameKeys[0]}}: string = '', {{/if}}) {
72
+ const where = {};
73
+ if({{@ valueEntity.pk[0]}}){
74
+ where['{{@ valueEntity.pk[0]}}'] = {{@ valueEntity.pk[0]}};
75
+ }
76
+ {{if valueEntity.nameKeys.length}}if({{@ valueEntity.nameKeys[0]}}){
77
+ where['{{@ valueEntity.nameKeys[0]}}'] = { [Op.like]: '%'+{{@ valueEntity.nameKeys[0]}}+'%' };
78
+ }{{/if}}
79
+ const { count, rows } = await this.{{@ valueEntity.entityFileName}}Repository.findAndCountAll({
80
+ where,
81
+ offset: (page - 1) * pageSize,
82
+ limit: pageSize,
83
+ });
84
+ return {
85
+ list: rows,
86
+ total: count,
87
+ page: page,
88
+ pageSize: pageSize,
89
+ };
90
+ }{{/each}}
91
+
92
+ /**
93
+ * 创建数据
94
+ * @param createDto
95
+ * @returns
96
+ */
97
+ @Transaction()
98
+ async create(createDto: {{@ replaceNames.CreateDto}}) {
99
+ const entity = await this.{{@ replaceNames.name}}Repository.create(createDto);
100
+ {{each entity.belongsTo}}
101
+ if(createDto.{{@ $value}}){//关联模型用主键进行设置,用对象设置时必须确保对象为模型model的实例
102
+ await entity.set{{@ $imports.upFirstCase($value)}}(createDto.{{@ $value}}.{{@ entity.belongsToEntity[$value].pk[0]}});
103
+ }
104
+ {{/each}}
105
+ {{each entity.belongsToMany}}
106
+ if(createDto.{{@ $value}}){//关联模型用主键进行设置,用对象设置时必须确保对象为模型model的实例
107
+ await entity.set{{@ $imports.upFirstCase($value)}}(createDto.{{@ $value}}.map(v=>v.{{@ entity.belongsToManyEntity[$value].pk[0]}}));
108
+ }
109
+ {{/each}}
110
+ return entity;
111
+ }
112
+
113
+ /**
114
+ * 列表分页查询
115
+ * @param queryDto 查询条件
116
+ * @returns
117
+ */
118
+ @Transaction()
119
+ async list(queryDto: {{@ replaceNames.QueryDto}}) {
120
+ const where = {};
121
+ Object.keys(queryDto).forEach((key) => {
122
+ if(['page', 'pageSize'].includes(key)){
123
+ return;
124
+ }
125
+ if([null, undefined, ''].includes(queryDto[key])){
126
+ return;
127
+ }{{each entitySchema.properties}}{{if $index.endsWith('At')}}
128
+ if (key === 'start{{@ $imports.upFirstCase($index)}}') {
129
+ where['{{@ $index}}'] = where['{{@ $index}}'] ?? {};
130
+ where['{{@ $index}}'][Op.gte] = queryDto[key];
131
+ return;
132
+ }
133
+ if (key === 'end{{@ $imports.upFirstCase($index)}}') {
134
+ where['{{@ $index}}'] = where['{{@ $index}}'] ?? {};
135
+ where['{{@ $index}}'][Op.lte] = queryDto[key];
136
+ return;
137
+ }{{/if}}{{/each}}
138
+ where[key] = queryDto[key];
139
+ });
140
+ const { count, rows } = await this.{{@ replaceNames.name}}Repository.findAndCountAll({
141
+ where,
142
+ offset: (queryDto.page - 1) * queryDto.pageSize,
143
+ limit: queryDto.pageSize,
144
+ {{if entity.belongs.length }}include:[
145
+ {{each entity.belongs}}<% const valueEntity = entity.belongsToManyEntity[$value] || entity.belongsToEntity[$value]; %>{{if valueEntity?.entityName === 'File'}}{
146
+ association: '{{@ $value}}',
147
+ attributes: { exclude: [] }, //必须设置attributes,否则file的附件属性 url属性返回给前端时没有,已提交[BUG反馈](https://github.com/sequelize/sequelize/issues/18059)
148
+ },
149
+ {{else}}'{{@ $value}}',{{/if}}{{/each}}
150
+ ],{{/if}}
151
+ {{if $imports.objectKeys(entitySchema.properties).includes('createdAt')}}order: [['createdAt', 'DESC']],{{/if}}
152
+ });
153
+ return {
154
+ list: rows,
155
+ total: count,
156
+ page: queryDto.page,
157
+ pageSize: queryDto.pageSize,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * 根据主键获取一条信息
163
+ * @param {{if entity.pk.length > 1}}pk{{else}}{{@ entity.pk[0]}}{{/if}} 主键
164
+ * @returns
165
+ */
166
+ @Transaction()
167
+ async findOne({{if entity.pk.length > 1}}pk:PK{{else}}{{@ entity.pk[0]}}: {{@ entitySchema.properties[entity.pk[0]].type}}{{/if}}) {
168
+ const entity = await this.{{@ replaceNames.name}}Repository.findByPk({{if entity.pk.length > 1}}pk{{else}}{{@ entity.pk[0]}}{{/if}} {{if entity.belongs.length }},{include:[
169
+ {{each entity.belongs}}<% const valueEntity = entity.belongsToManyEntity[$value] || entity.belongsToEntity[$value]; %>{{if valueEntity?.entityName === 'File'}}{
170
+ association: '{{@ $value}}',
171
+ attributes: { exclude: [] }, //必须设置attributes,否则file的附件属性 url属性返回给前端时没有,已提交[BUG反馈](https://github.com/sequelize/sequelize/issues/18059)
172
+ },
173
+ {{else}}'{{@ $value}}',{{/if}}{{/each}}
174
+ ]}{{/if}});
175
+ if (!entity) {
176
+ throw new BadRequestError(this.i18nService.translate('没有对应的信息'));
177
+ }
178
+ return entity;
179
+ }
180
+
181
+ /**
182
+ * 更新数据
183
+ * @param {{if entity.pk.length > 1}}pk{{else}}{{@ entity.pk[0]}}{{/if}} 主键
184
+ * @param updateDto 数据对象
185
+ * @returns
186
+ */
187
+ @Transaction()
188
+ async update({{if entity.pk.length > 1}}pk:PK{{else}}{{@ entity.pk[0]}}: {{@ entitySchema.properties[entity.pk[0]].type}}{{/if}}, updateDto: {{@ replaceNames.UpdateDto}}) {
189
+ const entity = await this.{{@ replaceNames.name}}Repository.findByPk({{if entity.pk.length > 1}}pk{{else}}{{@ entity.pk[0]}}{{/if}});
190
+ if (!entity) {
191
+ throw new BadRequestError(this.i18nService.translate('没有对应的信息'));
192
+ }
193
+ Object.assign(entity, updateDto);
194
+ {{each entity.belongsTo}}
195
+ if(updateDto.{{@ $value}} !== undefined){//关联模型用主键进行设置,用对象设置时必须确保对象为模型model的实例
196
+ await entity.set{{@ $imports.upFirstCase($value)}}(updateDto.{{@ $value}}?.{{@ entity.belongsToEntity[$value].pk[0]}} ?? null);
197
+ }
198
+ {{/each}}
199
+ {{each entity.belongsToMany}}
200
+ if(updateDto.{{@ $value}}){//关联模型用主键进行设置,用对象设置时必须确保对象为模型model的实例
201
+ await entity.set{{@ $imports.upFirstCase($value)}}(updateDto.{{@ $value}}.map(v=>v.{{@ entity.belongsToManyEntity[$value].pk[0]}}));
202
+ }
203
+ {{/each}}
204
+ return await entity.save();
205
+ }
206
+
207
+ /**
208
+ * 删除数据
209
+ * @param {{if entity.pk.length > 1}}pk{{else}}{{@ entity.pk[0]}}{{/if}} 主键
210
+ * @returns
211
+ */
212
+ @Transaction()
213
+ async remove({{if entity.pk.length > 1}}pk:PK{{else}}{{@ entity.pk[0]}}: {{@ entitySchema.properties[entity.pk[0]].type}}{{/if}}) {
214
+ const entity = await this.{{@ replaceNames.name}}Repository.findByPk({{if entity.pk.length > 1}}pk{{else}}{{@ entity.pk[0]}}{{/if}});
215
+ if (!entity) {
216
+ throw new BadRequestError(this.i18nService.translate('没有对应的信息'));
217
+ }
218
+ await entity.destroy();
219
+ }
220
+ }
@@ -0,0 +1,120 @@
1
+ import request, { RequestOptions } from '@/utils/request.js';
2
+ import { PageParam, PageResult } from '@/api/api.model.js';
3
+ import { FileInfo } from '@/api/file.js';
4
+ import { SystemAdminInfo } from '@/api/system/admin.js';
5
+
6
+ {{each swaggerSchemas}}
7
+ {{if $index === replaceNames.Name}}
8
+ //{{@ entity.tableComment}}
9
+ export class {{@ $index}} {
10
+ <% include('./class.ts.art', {...$value, entity:entity}) %>
11
+ {{else}}<% const scgemaEntity = $imports.tableInfo($index); %>{{if scgemaEntity.tableComment}}//{{@ scgemaEntity.tableComment}}{{/if}}
12
+ export type {{@ $index}} = {
13
+ <% include('./type.ts.art', {...$value, entity:scgemaEntity}) %>
14
+ {{/if}}
15
+ }
16
+ {{/each}}
17
+
18
+ <% const hasStatement = ['File']; %>
19
+ {{each $imports.objectKeys(entity.belongsToEntity)}}<% const valueEnitty = entity.belongsToEntity[$value]; %>{{if hasStatement.includes(valueEnitty.entityName)}}<% return; %>{{else}}<% hasStatement.push(valueEnitty.entityName);%>{{/if}}
20
+ //获取{{@ valueEnitty.tableComment}}信息
21
+ export function get{{@ valueEnitty.entityName}}Api() {
22
+ return request<PageResult<{{@ valueEnitty.entityName}}>, [{
23
+ {{@ valueEnitty.pk[0]}}?: {{@ swaggerSchemas[valueEnitty.entityName]?.properties?.[entity.pk[0]]?.type || 'string'}},{{if valueEnitty.nameKeys.length}}
24
+ {{@ valueEnitty.nameKeys[0]}}?: string,{{/if}}
25
+ page:number,
26
+ pageSize:number,
27
+ }]>(
28
+ (data) => ({
29
+ url: '{{@ replaceNames.controllerPath}}/get{{@ valueEnitty.entityName}}',
30
+ method: 'post',
31
+ data: data,
32
+ }),
33
+ { noLoading: true },
34
+ );
35
+ }{{/each}}
36
+
37
+ {{each $imports.objectKeys(entity.belongsToManyEntity)}}<% const valueEnitty = entity.belongsToManyEntity[$value]; %>{{if hasStatement.includes(valueEnitty.entityName)}}<% return; %>{{else}}<% hasStatement.push(valueEnitty.entityName);%>{{/if}}
38
+ //获取{{@ valueEnitty.tableComment}}信息
39
+ export function get{{@ valueEnitty.entityName}}Api() {
40
+ return request<PageResult<{{@ valueEnitty.entityName}}>, [{
41
+ {{@ valueEnitty.pk[0]}}?: {{@ swaggerSchemas[valueEnitty.entityName]?.properties?.[entity.pk[0]]?.type || 'string'}},{{if valueEnitty.nameKeys.length}}
42
+ {{@ valueEnitty.nameKeys[0]}}?: string,{{/if}}
43
+ page:number,
44
+ pageSize:number,
45
+ }]>(
46
+ (data) => ({
47
+ url: '{{@ replaceNames.controllerPath}}/get{{@ valueEnitty.entityName}}',
48
+ method: 'post',
49
+ data: data,
50
+ }),
51
+ { noLoading: true },
52
+ );
53
+ }{{/each}}
54
+
55
+ export type {{@ replaceNames.Name}}Info = {{@ replaceNames.Name}} & {
56
+ {{each entity.autoAttributes}}{{if swaggerSchemas[replaceNames.Name].properties[$value]}}
57
+ {{@ $value}}: <% include('./valueType.ts.art', {...swaggerSchemas[replaceNames.Name].properties[$value],key:$value,entity:entity}) %>, {{if swaggerSchemas[replaceNames.Name].properties[$value]?.description}}//{{@ swaggerSchemas[replaceNames.Name].properties[$value]?.description}}{{/if}}{{/if}}{{/each}}
58
+ };
59
+ //添加{{@ entity.tableComment}}信息
60
+ export function add{{@ replaceNames.Name}}Api() {
61
+ return request<{{@ replaceNames.Name}}Info, [{{@ replaceNames.Name}}]>(
62
+ (data) => ({
63
+ url: '{{@ replaceNames.controllerPath}}/add',
64
+ method: 'post',
65
+ data: data,
66
+ }),
67
+ { success: true },
68
+ );
69
+ }
70
+
71
+ export type {{@ replaceNames.Name}}ListResult = PageResult<{{@ replaceNames.Name}}Info>;
72
+ export class {{@ replaceNames.Name}}ListParam extends PageParam {
73
+ <% include('./searchTypes.ts.art', {...entitySchema, entity:entity}) %>
74
+ }
75
+ //获取{{@ entity.tableComment}}列表
76
+ export function {{@ replaceNames.name}}ListApi(options?: RequestOptions<{{@ replaceNames.Name}}ListResult, [{{replaceNames.Name}}ListParam]>) {
77
+ return request<{{@ replaceNames.Name}}ListResult, [{{@ replaceNames.Name}}ListParam]>(
78
+ (data) => ({
79
+ url: '{{@ replaceNames.controllerPath}}/',
80
+ method: 'post',
81
+ data: data,
82
+ }),
83
+ Object.assign({ noLoading: true, clearEmpty: ['', undefined, null] }, options),
84
+ );
85
+ }
86
+
87
+ //根据{{@ entity.pk.join('/:')}}获取{{@ entity.tableComment}}详情
88
+ export function {{@ replaceNames.name}}InfoApi(options?: RequestOptions<{{@ replaceNames.Name}}Info, [{{@ entity.pk.map(v=>entitySchema.properties[v].type).join(', ')}}]>) {
89
+ return request<{{@ replaceNames.Name}}Info, [{{entity.pk.map(v=>entitySchema.properties[v].type).join(', ')}}]>(
90
+ ({{@ entity.pk.join(', ')}}) => ({
91
+ url: `{{@ replaceNames.controllerPath}}/info/${<%- entity.pk.join('/${') %>}`,
92
+ method: 'get',
93
+ }),
94
+ Object.assign({ noLoading: true }, options),
95
+ );
96
+ }
97
+
98
+ export type Update{{replaceNames.Name}}InfoParam = Omit<Partial<{{@ replaceNames.Name}}Info>,'{{@ entity.autoAttributes.filter(v=>swaggerSchemas[replaceNames.Name].properties[v]).join("'|'")}}'>;
99
+ //修改{{@ entity.tableComment}}信息
100
+ export function update{{@ replaceNames.Name}}Api(options?: RequestOptions<{{@ replaceNames.Name}}Info, [{{each entity.pk}}{{entitySchema.properties[$value].type}}, {{/each}}Update{{replaceNames.Name}}InfoParam]>) {
101
+ return request<{{@ replaceNames.Name}}Info, [{{each entity.pk}}{{entitySchema.properties[$value].type}}, {{/each}}Update{{replaceNames.Name}}InfoParam]>(
102
+ ({{@ entity.pk.join(', ')}}, data) => ({
103
+ url: `{{@ replaceNames.controllerPath}}/up/${<%- entity.pk.join('/${') %>}`,
104
+ method: 'post',
105
+ data: data,
106
+ }),
107
+ Object.assign({ success: true, noLoading: true }, options),
108
+ );
109
+ }
110
+
111
+ //删除{{@ entity.tableComment}}
112
+ export function del{{@ replaceNames.Name}}Api(options?: RequestOptions<null, [{{@ entity.pk.map(v=>entitySchema.properties[v].type).join(', ')}}]>) {
113
+ return request<null, [{{entity.pk.map(v=>entitySchema.properties[v].type).join(', ')}}]>(
114
+ ({{@ entity.pk.join(', ')}}) => ({
115
+ url: `{{@ replaceNames.controllerPath}}/del/${<%- entity.pk.join('/${') %>}`,
116
+ method: 'post',
117
+ }),
118
+ Object.assign({ noLoading: true }, options),
119
+ );
120
+ }
@@ -0,0 +1,2 @@
1
+ {{each properties}}{{if !entity?.autoAttributes?.includes($index)}}{{@ $index}} = <% include('./valueDefault.ts.art', {...$value, key:$index ,entity:entity, needAs:true}) %>; {{if $value.description}}//{{@ $value.description}}{{/if}}
2
+ {{/if}}{{/each}}
@@ -0,0 +1,4 @@
1
+ {{each properties}}{{if $index.endsWith('At')}}
2
+ start{{@ $imports.upFirstCase($index)}}?: <% include('./valueType.ts.art', {...$value,key:$index,entity:entity}) %>; //{{@ $value.description}}(起)
3
+ end{{@ $imports.upFirstCase($index)}}?: <% include('./valueType.ts.art', {...$value,key:$index,entity:entity}) %>; //{{@ $value.description}}(止){{else}}
4
+ {{@ $index}}?: <% include('./valueType.ts.art', {...$value,key:$index,entity:entity}) %>; //{{@ $value.description}}{{/if}}{{/each}}
@@ -0,0 +1,2 @@
1
+ {{each properties}}{{@ $index}}: <% include('./valueType.ts.art', {...$value,key:$index,entity:entity}) %>; {{if $value.description}}//{{@ $value.description}}{{/if}}
2
+ {{/each}}
@@ -0,0 +1 @@
1
+ {{if $data.default}}{{if typeof $data.default === 'string'}}'{{@ $data.default}}'{{else}}{{@ $data.default}}{{/if}}{{if needAs}} as <% include('./valueType.ts.art', data) %>{{/if}}{{else if type==='string'}}''{{if needAs&&!$data.enum}} as <% include('./valueType.ts.art', $data) %>{{/if}}{{else if type==='object'}}{}{{if needAs}} as <% include('./valueType.ts.art', $data) %>{{/if}}{{else if type ==='array'}}[]{{if needAs}} as <% include('./valueType.ts.art', $data) %>{{/if}}{{else}}undefined{{if needAs}} as <% include('./valueType.ts.art', $data) %>| undefined{{/if}}{{/if}}
@@ -0,0 +1,3 @@
1
+ {{if $ref}}{{@ $ref.replace('#/components/schemas/','')}}{{else if ['object','Object'].includes(type)}}{
2
+ <% include('./type.ts.art', {properties:properties,entity:{}}) %>
3
+ }{{else if ['array','Array'].includes(type)}}Array<<% include('./valueType.ts.art', {...items, key:$data.key, entity:{}, notNull:true}) %>>{{else if $data.enum}}{{if type==='string'}}'{{@ $data.enum.map(v=>''+v).join("' | '")}}'{{else}}{{@ $data.enum.map(v=>''+v).join(' | ')}}{{/if}}{{else}}{{if type ==='integer'}}number{{else}}{{@ type}}{{/if}}{{/if}}{{if !notNull && !entity?.pk?.includes(key) && entity?.attributes?.get(key)?.allowNull !==false && !['array','Array'].includes(type) }} | null{{/if}}
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <me-dialog v-model="show" :title="t({{@ entity.pk[0]}} ? '编辑' : '新增')" :close-on-click-modal="false"
3
+ @closed="emit('closed')">
4
+ <el-form v-loading="loading" ref="formEl" :model="info" :rules="rules" class="add" label-width="auto">
5
+ <% include('./addOrUpItem.vue.art', {...entitySchema, entity:entity, belongsToEntity:entity.belongsToEntity, belongsToManyEntity:entity.belongsToManyEntity}) %>
6
+ </el-form>
7
+ <template #footer>
8
+ <me-button @click="() => show = false">{{@ $imports.leftTag()}} t('取消') {{@ $imports.rightTag()}}</me-button>
9
+ <me-button type="primary" @click="submit">{{@ $imports.leftTag()}} t('提交') {{@ $imports.rightTag()}}</me-button>
10
+ </template>
11
+ </me-dialog>
12
+ </template>
13
+
14
+ <script setup lang="ts" name="AddOrUp{{@ replaceNames.Name}}">
15
+ import { {{@ replaceNames.Name}}, {{@ replaceNames.Name}}Info, add{{@ replaceNames.Name}}Api, update{{@ replaceNames.Name}}Api, {{@ replaceNames.name}}InfoApi } from '@/api/{{@ replaceNames.namePath}}';
16
+ import { useLocalesI18n } from '@/locales/i18n';
17
+ import { resetObj<% if($imports.objectValues(entitySchema.properties).some(v=>v.enum || v.description.includes(':'))){%>, formatterStr<%}%> } from '@/utils/helper';
18
+ import { FormInstance, FormRules } from 'element-plus';
19
+ {{if $imports.objectValues(entitySchema.properties).some(value=>value.rule?._rules.some(v=>v.name==='mobile'))}}import { isMobile } from '@/utils/validate.js';{{/if}}
20
+ //接口需要现在setup顶层初始化(如果是异步setup需要在异步调用之前初始化),否则会有unMounted,非法调用警告,因为vueRequest使用了unMounted
21
+ const { runAsync:updateRunAsync } = update{{@ replaceNames.Name}}Api();
22
+ const { runAsync:addRunAsync } = add{{@ replaceNames.Name}}Api();
23
+ const { runAsync:infoRunAsync } = {{@ replaceNames.name}}InfoApi();
24
+ <% const hasStatement = ['File']; %>
25
+ {{each $imports.objectKeys(entity.belongsToEntity)}}<% const valueEntity = entity.belongsToEntity[$value]; %>{{if hasStatement.includes(valueEntity.entityName)}}<% return; %>{{else}}<% hasStatement.push(valueEntity.entityName);%>{{/if}}
26
+ import {get{{@ valueEntity.entityName}}Api} from '@/api/{{@ replaceNames.namePath}}';
27
+ const { runAsync:get{{@ valueEntity.entityName}}RunAsync } = get{{@ valueEntity.entityName}}Api();
28
+ const serach{{@ valueEntity.entityName}} = async (query:string,page:number,pageSize:number)=>{
29
+ return await get{{@ valueEntity.entityName}}RunAsync({
30
+ {{@ valueEntity.nameKeys?.[0] || valueEntity.pk[0]}}:query,
31
+ page:page,
32
+ pageSize:pageSize
33
+ })
34
+ }
35
+ {{/each}}
36
+ {{each $imports.objectKeys(entity.belongsToManyEntity)}}<% const valueEntity = entity.belongsToManyEntity[$value]; %>{{if hasStatement.includes(valueEntity.entityName)}}<% return; %>{{else}}<% hasStatement.push(valueEntity.entityName);%>{{/if}}
37
+ import {get{{@ valueEntity.entityName}}Api} from '@/api/{{@ replaceNames.namePath}}';
38
+ const { runAsync:get{{@ valueEntity.entityName}}RunAsync } = get{{@ valueEntity.entityName}}Api();
39
+ const serach{{@ valueEntity.entityName}} = async (query:string,page:number,pageSize:number)=>{
40
+ return await get{{@ valueEntity.entityName}}RunAsync({
41
+ {{@ valueEntity.nameKeys?.[0] || valueEntity.pk[0]}}:query,
42
+ page:page,
43
+ pageSize:pageSize
44
+ })
45
+ }
46
+ {{/each}}
47
+
48
+ let { t, loadRes } = useLocalesI18n({}, [(locale: string) => import(`../lang/${locale}.json`), '{{@ replaceNames.name}}']);
49
+ await loadRes;
50
+ <% if( $imports.objectKeys(entitySchema.properties).some( k=>entitySchema.properties[k].enum || entitySchema.properties[k].description.includes(':') ) ){ %>import { getDict } from '../dict.js';
51
+ const dict = getDict(t);<%}%>
52
+ const show = defineModel<boolean>();
53
+ const props = defineProps<{
54
+ {{each entity.pk}}
55
+ {{@ $value}}?: {{@ entitySchema.properties[$value].type}};
56
+ {{/each}}
57
+ }>();
58
+ const emit = defineEmits<{
59
+ (e: 'success'): void;
60
+ (e: 'closed'): void;
61
+ }>();
62
+
63
+
64
+
65
+ const info = reactive(new {{@ replaceNames.Name}}());
66
+ const loading = ref(false);
67
+ watch(
68
+ () => {{if entity.pk.length===1}}props.{{@ entity.pk[0]}}{{else}}[props.{{@ entity.pk.join(', props.')}}]{{/if}},
69
+ async ({{@ entity.pk.map(v=>`${v}?:${entitySchema.properties[v].type}`).join(', ')}}) => {
70
+ if ({{@ entity.pk[0]}}) {
71
+ loading.value = true;
72
+ resetObj(info, await infoRunAsync({{@ entity.pk.join(', ')}}));
73
+ loading.value = false;
74
+ }
75
+ },
76
+ { immediate: true },
77
+ );
78
+ const rules: FormRules = {
79
+ <% include('./rules.ts.art', {...entitySchema, entity:entity}) %>
80
+ };
81
+ const formEl = ref<FormInstance>();
82
+ const submit = async () => {
83
+ try {
84
+ await formEl.value!.validate();
85
+ } catch (invalidFields) {
86
+ return formEl.value!.scrollToField(Object.keys(invalidFields!)[0]);
87
+ }
88
+ if (props.{{@ entity.pk[0]}}) {
89
+ await updateRunAsync(props.{{@ entity.pk.join(', props.')}}, info);
90
+ } else {
91
+ await addRunAsync(info);
92
+ }
93
+ show.value = false;
94
+ emit('success');
95
+ }
96
+ </script>
@@ -0,0 +1,26 @@
1
+ {{each properties}}<% const keyInfo = $imports.getKeyInfo($value.description); %>{{if !entity.autoAttributes.includes($index)}}{{if ['number','string','integer'].includes($value.type)}}
2
+ <el-form-item :label="t('{{@ keyInfo.name}}')" prop="{{@ $index}}">
3
+ {{if $value.enum || keyInfo.dict}}<el-select v-model="info.{{@ $index}}" {{if !required.includes($index)}}:value-on-clear="null" clearable {{/if}}>
4
+ <el-option v-for="val in dict.{{@ $index}}" :key="val.value" :value="val.value" :label="val.label" />
5
+ </el-select>
6
+ {{else if ['number','integer'].includes($value.type)}}
7
+ <el-input-number v-model="info.{{@ $index}}" {{if !required.includes($index)}}:value-on-clear="null"{{/if}}></el-input-number>
8
+ {{else if $value.type === 'string'}}
9
+ <el-input v-model="info.{{@ $index}}" ></el-input>
10
+ {{/if}}
11
+ </el-form-item>{{else if $value.type==='boolean'}}
12
+ <el-form-item :label="t('{{@ keyInfo.name}}')" prop="{{@ $index}}">
13
+ <el-switch v-model="info.{{@ $index}}" />
14
+ </el-form-item>{{else if $value.type === 'array'}}{{if $value?.items.$ref === '#/components/schemas/FileInfo'}}
15
+ <el-form-item :label="t('{{@ keyInfo.name}}')" prop="{{@ $index}}">
16
+ <me-upload v-model="info.{{@ $index}}" ></me-upload>
17
+ </el-form-item>{{else if $value?.items.$ref}}<% const entityName = $value.items.$ref.replace('#/components/schemas/',''); %><% const valueEntity = belongsToManyEntity[$index] || belongsToEntity[$index]; %>{{if !valueEntity}}<% return;%>{{/if}}
18
+ <el-form-item :label="t('{{@ keyInfo.name}}')" prop="{{@ $index}}">
19
+ <me-select-list v-model="info.{{@ $index}}" :props="{label:'{{@ valueEntity.nameKeys?.[0] || valueEntity.pk[0]}}',value:'{{@ valueEntity.pk[0] }}'}" value-key="{{@ valueEntity.pk[0] }}" @search="serach{{@ valueEntity.entityName}}" :multiple="true"></me-select-list>
20
+ </el-form-item>{{/if}}{{else if $value.$ref === '#/components/schemas/FileInfo'}}
21
+ <el-form-item :label="t('{{@ keyInfo.name}}')" prop="{{@ $index}}">
22
+ <me-upload :limit="1" :model-value="info.{{@ $index}}?[info.{{@ $index}}]:[]" @update:modelValue="(files)=>info.{{@ $index}} =files.length? files[0]:null" ></me-upload>
23
+ </el-form-item>{{else if $value.$ref}}<% const entityName = $value.$ref.replace('#/components/schemas/',''); %><% const valueEntity = belongsToManyEntity[$index] || belongsToEntity[$index]; %>{{if !valueEntity}}<% return;%>{{/if}}
24
+ <el-form-item :label="t('{{@ keyInfo.name}}')" prop="{{@ $index}}">
25
+ <me-select-list v-model="info.{{@ $index}}" :props="{label:'{{@ valueEntity.nameKeys?.[0] || valueEntity.pk[0]}}',value:'{{@ valueEntity.pk[0] }}'}" value-key="{{@ valueEntity.pk[0] }}" @search="serach{{@ valueEntity.entityName}}" clearable></me-select-list>
26
+ </el-form-item>{{/if}}{{/if}}{{/each}}
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <me-dialog v-model="show" :title="t('详情')" :close-on-click-modal="false" @closed="emit('closed')">
3
+ <el-descriptions class="info" :border="true" v-loading="loading">
4
+ {{each entitySchema.properties}} {{if ['createdAdmin','updatedAdmin'].includes($index)}} <% return; %>{{/if}} <% const keyInfo = $imports.getKeyInfo($value.description); %>
5
+ <el-descriptions-item :label="t('{{@ keyInfo.name}}')">{{if $value.$ref === '#/components/schemas/FileInfo'}}
6
+ <me-files-view :files="data?.{{$index}}?[data.{{$index}}]:[]"></me-files-view>
7
+ {{else if $value.type==='array' && $value.items?.$ref === '#/components/schemas/FileInfo'}}
8
+ <me-files-view :files="data?.{{$index}}??[]"></me-files-view>
9
+ {{else}} {{@ $imports.leftTag()}}
10
+ <% if ($value.enum || $value.description.includes(':')){%>
11
+ formatterDictExec(dict,'{{@ $index}}',
12
+ {{else if $index.endsWith('At')}}
13
+ formatterAtExec(
14
+ {{else if $value.type === 'array'}}
15
+ {{if $value.items?.$ref }}<% const entityName = $value.items.$ref.replace('#/components/schemas/',''); %><% const valueEntity = entity.belongsToManyEntity[$index] || entity.belongsToEntity[$index]; %>
16
+ {{if valueEntity}}formatterArrExecFn('{{@ valueEntity.nameKeys?.[0] || valueEntity.pk[0]}}')({{else}}formatterArrExecFn()({{/if}}
17
+ {{else}}formatterArrExecFn()({{/if}}
18
+ {{else if $value.$ref}}<% const entityName = $value.$ref.replace('#/components/schemas/',''); %><% const valueEntity = entity.belongsToManyEntity[$index] || entity.belongsToEntity[$index]; %>
19
+ {{if valueEntity}}formatterObjectExecFn('{{@ valueEntity.nameKeys?.[0] || valueEntity.pk[0]}}')({{else}}formatterStrExec({{/if}}
20
+ {{else}}formatterStrExec(<%}%>data?.{{@ $index}}) {{@ $imports.rightTag()}}{{/if}} </el-descriptions-item>{{/each}}{{if entitySchema.properties.createdAdmin}}
21
+ <el-descriptions-item :label="t('{{@ entitySchema.properties.createdAdmin.description}}')"> {{@ $imports.leftTag()}} formatterObjectExecFn(obj=>`${obj.nickname}(${obj.username})`)(data?.createdAdmin) {{@ $imports.rightTag()}} </el-descriptions-item>
22
+ {{/if}}{{if entitySchema.properties.updatedAdmin}}<el-descriptions-item :label="t('{{@ entitySchema.properties.updatedAdmin.description}}')"> {{@ $imports.leftTag()}} formatterObjectExecFn(obj=>`${obj.nickname}(${obj.username})`)(data?.updatedAdmin) {{@ $imports.rightTag()}} </el-descriptions-item>{{/if}}
23
+ </el-descriptions>
24
+ <template #footer>
25
+ <me-button @click="() => (show = false)">{{@ $imports.leftTag()}} t('关闭') {{@ $imports.rightTag()}}</me-button>
26
+ </template>
27
+ </me-dialog>
28
+ </template>
29
+
30
+ <script setup lang="ts" name="Info">
31
+ import { {{@ replaceNames.name}}InfoApi } from '@/api/{{@ replaceNames.namePath}}';
32
+ import { useLocalesI18n } from '@/locales/hooks.js';
33
+ import { formatterAtExec, formatterStrExec,formatterObjectExecFn,formatterArrExecFn } from '@/utils/helper.js';
34
+ let { t, loadRes } = useLocalesI18n({}, [(locale: string) => import(`../lang/${locale}.json`), '{{@ replaceNames.name}}']);
35
+ await loadRes;
36
+ <% if( $imports.objectKeys(entitySchema.properties).some( k=>entitySchema.properties[k].enum || entitySchema.properties[k].description.includes(':') ) ){ %>import { getDict } from '../dict.js';
37
+ import {formatterDictExec} from '@/utils/helper.js';
38
+ const dict = getDict(t);<%}%>
39
+ const show = defineModel<boolean>();
40
+ const props = defineProps<{
41
+ {{each entity.pk}}
42
+ {{@ $value}}?: {{@ entitySchema.properties[$value].type}};
43
+ {{/each}}
44
+ }>();
45
+ const emit = defineEmits<{
46
+ (e: 'closed'): void;
47
+ }>();
48
+ const { data, loading, runAsync } = {{@ replaceNames.name}}InfoApi();
49
+ watch(
50
+ () => {{if entity.pk.length===1}}props.{{@ entity.pk[0]}}{{else}}[props.{{@ entity.pk.join(', props.')}}]{{/if}},
51
+ async ({{@ entity.pk.map(v=>`${v}?:${entitySchema.properties[v].type}`).join(', ')}}) => {
52
+ if ({{@ entity.pk[0]}}) {
53
+ runAsync({{@ entity.pk.join(', ')}});
54
+ }
55
+ },
56
+ { immediate: true },
57
+ );
58
+ </script>
59
+ <style lang="scss" scoped>
60
+ .info {
61
+
62
+ }
63
+ </style>
@@ -0,0 +1,5 @@
1
+ {{each properties}}{{if ['number','string','integer'].includes($value.type) && !entity.autoAttributes.includes($index)}}{{if required.includes($index)||$value.rule?._rules.length}}<% const keyInfo = $imports.getKeyInfo($value.description); %>
2
+ {{@ $index}}: [{{if required.includes($index)}}
3
+ { required: true, message: t('{label} 必须填写', {label:t('{{@ keyInfo.name}}')}), trigger: 'blur' },{{/if}}{{if $value.rule._rules.some(v=>v.name === 'max') && $value.rule._rules.some(v=>v.name==='min')}}
4
+ <% const minMax={min:$value.rule._rules.find(v=>v.name === 'min').args.limit, max:$value.rule._rules.find(v=>v.name === 'max').args.limit} %>{type:'{{@ $value.type}}', min:{{@ minMax.min}}, max:{{@ minMax.max}}, message:t('{label} {{if $value.type==='string'}}长度{{/if}}必须在 {min} 及 {max} 之间',{ label:t('{{@ keyInfo.name}}'), min:{{@ minMax.min}}, max:{{@ minMax.max}} }), trigger: 'blur' },{{else}}{{each $value.rule._rules $val $key}} {{if $val.name ==='max'}}{type:'{{@ $value.type}}', max:{{@ $val.args.limit}}, message: t('{label} {{if $value.type==='string'}}长度{{/if}}必须小于等于 {max}', { label:t('{{@ keyInfo.name}}'), max:{{@ $val.args.limit}} }), trigger: 'blur' },{{/if}}{{if $val.name ==='min'}}{type:'{{@ $value.type}}', min:{{@ $val.args.limit}}, message: t('{label}{{if $value.type==='string'}}长度{{/if}}必须大于等于 {min}', { label:t('{{@ keyInfo.name}}'), max:{{@ $val.args.limit}} }), trigger: 'blur' },{{/if}}{{/each}}{{/if}}<% include('./rulesList.ts.art', {$value:$value, keyInfo:keyInfo}) %>
5
+ ],{{/if}}{{/if}}{{/each}}
@@ -0,0 +1,2 @@
1
+ {{each $value.rule._rules $val $key}}{{if $val.name === 'email'}}{ type: 'email', message:t('{label} 必须是正确的邮箱格式', {label: t('{{@ keyInfo.name}}')}), trigger: 'blur' },{{/if}}{{if $val.name === 'mobile'}}{validator:(rule, value:string|number)=>isMobile(value), message: t('{label} 必须是正确的手机号', {label: t('{{@ keyInfo.name}}')}), trigger: 'blur'},{{/if}}{{if $val.name === 'url'}}{ type: 'url', message: t('{label} 必须是正确的链接格式', {label: t('{{@ keyInfo.name}}')}), trigger: 'blur' },{{/if}}{{if $val.name === 'length'}}{ type: '{{@ $value.type}}',len:{{@ $val.args.limit}}, message: t('{label} 长度必须为 {len}',{ label: t('{{@ keyInfo.name}}'), len:{{@ $val.args.limit}} }), trigger: 'blur' },
2
+ {{/if}}{{/each}}
@@ -0,0 +1,11 @@
1
+ <% if($imports.objectKeys(entitySchema.properties).some(k=>entitySchema.properties[k].enum || entitySchema.properties[k].description.includes(':'))){%>export const getDict = (t = (str:string)=>str)=>reactive({
2
+ {{each entitySchema.properties}}<% const keyInfo = $imports.getKeyInfo($value.description);%>{{if keyInfo.dict}}
3
+ {{@ $index}}:[
4
+ {{each keyInfo.dictArr $val $key}}{value:{{if $value.type==='string'}}'{{/if}}{{$val.value}}{{if $value.type==='string'}}'{{/if}}, label:t('{{@ $val.label}}')},{{/each}}
5
+ ],{{else if $value.enum}}
6
+ {{@ $index}}:[
7
+ {{each $value.enum $val $key}}{value:{{if $value.type==='string'}}'{{/if}}{{$val+''}}{{if $value.type==='string'}}'{{/if}}, label:t('{{@ $val+''}}')},{{/each}}
8
+ ],
9
+ {{/if}}{{/each}}
10
+ });
11
+ <%}%>