Commit 40d2882890f596d6e2b68ba5ca4c0db24622049f
1 parent
7d89ce5a
🎈 perf(codegen): 优化代码生成器 Excel 导入:新增 import-enable 开关,Vue3 / Vben5 Schema 抽独立 Im…
…portForm 组件对齐 user 模块,补齐 Vben5 4 套 frontType 单测与 importEnable=true 断言 基于 #1082 #1083 的二开
Showing
34 changed files
with
1123 additions
and
336 deletions
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenProperties.java
| @@ -55,4 +55,10 @@ public class CodegenProperties { | @@ -55,4 +55,10 @@ public class CodegenProperties { | ||
| 55 | @NotNull(message = "是否生成单元测试不能为空") | 55 | @NotNull(message = "是否生成单元测试不能为空") |
| 56 | private Boolean unitTestEnable; | 56 | private Boolean unitTestEnable; |
| 57 | 57 | ||
| 58 | + /** | ||
| 59 | + * 是否生成 Excel 导入接口 | ||
| 60 | + */ | ||
| 61 | + @NotNull(message = "是否生成 Excel 导入接口不能为空") | ||
| 62 | + private Boolean importEnable; | ||
| 63 | + | ||
| 58 | } | 64 | } |
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
| @@ -128,6 +128,8 @@ public class CodegenEngine { | @@ -128,6 +128,8 @@ public class CodegenEngine { | ||
| 128 | vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) | 128 | vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) |
| 129 | .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/form.vue"), | 129 | .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/form.vue"), |
| 130 | vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) | 130 | vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) |
| 131 | + .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/import.vue"), | ||
| 132 | + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}ImportForm.vue")) | ||
| 131 | .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑 | 133 | .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑 |
| 132 | vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) | 134 | vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) |
| 133 | .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑 | 135 | .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑 |
| @@ -166,6 +168,8 @@ public class CodegenEngine { | @@ -166,6 +168,8 @@ public class CodegenEngine { | ||
| 166 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) | 168 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) |
| 167 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/form.vue"), | 169 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/form.vue"), |
| 168 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) | 170 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) |
| 171 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/import.vue"), | ||
| 172 | + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue")) | ||
| 169 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("api/api.ts"), | 173 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("api/api.ts"), |
| 170 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) | 174 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) |
| 171 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 | 175 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 |
| @@ -183,6 +187,8 @@ public class CodegenEngine { | @@ -183,6 +187,8 @@ public class CodegenEngine { | ||
| 183 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) | 187 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) |
| 184 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/form.vue"), | 188 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/form.vue"), |
| 185 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) | 189 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) |
| 190 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/import.vue"), | ||
| 191 | + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue")) | ||
| 186 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("api/api.ts"), | 192 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("api/api.ts"), |
| 187 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) | 193 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) |
| 188 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 | 194 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 |
| @@ -202,6 +208,8 @@ public class CodegenEngine { | @@ -202,6 +208,8 @@ public class CodegenEngine { | ||
| 202 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) | 208 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) |
| 203 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("views/form.vue"), | 209 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("views/form.vue"), |
| 204 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) | 210 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) |
| 211 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("views/import.vue"), | ||
| 212 | + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue")) | ||
| 205 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("api/api.ts"), | 213 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("api/api.ts"), |
| 206 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) | 214 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) |
| 207 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 | 215 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(), vue3Vben5EpSchemaTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 |
| @@ -219,6 +227,8 @@ public class CodegenEngine { | @@ -219,6 +227,8 @@ public class CodegenEngine { | ||
| 219 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) | 227 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) |
| 220 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/form.vue"), | 228 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/form.vue"), |
| 221 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) | 229 | vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) |
| 230 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/import.vue"), | ||
| 231 | + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue")) | ||
| 222 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("api/api.ts"), | 232 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("api/api.ts"), |
| 223 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) | 233 | vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) |
| 224 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 | 234 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 |
| @@ -286,6 +296,7 @@ public class CodegenEngine { | @@ -286,6 +296,7 @@ public class CodegenEngine { | ||
| 286 | globalBindingMap.put("jakartaPackage", jakartaEnable ? "jakarta" : "javax"); | 296 | globalBindingMap.put("jakartaPackage", jakartaEnable ? "jakarta" : "javax"); |
| 287 | globalBindingMap.put("voType", codegenProperties.getVoType()); | 297 | globalBindingMap.put("voType", codegenProperties.getVoType()); |
| 288 | globalBindingMap.put("deleteBatchEnable", codegenProperties.getDeleteBatchEnable()); | 298 | globalBindingMap.put("deleteBatchEnable", codegenProperties.getDeleteBatchEnable()); |
| 299 | + globalBindingMap.put("importEnable", codegenProperties.getImportEnable()); | ||
| 289 | // 全局 Java Bean | 300 | // 全局 Java Bean |
| 290 | globalBindingMap.put("CommonResultClassName", CommonResult.class.getName()); | 301 | globalBindingMap.put("CommonResultClassName", CommonResult.class.getName()); |
| 291 | globalBindingMap.put("PageResultClassName", PageResult.class.getName()); | 302 | globalBindingMap.put("PageResultClassName", PageResult.class.getName()); |
| @@ -345,6 +356,11 @@ public class CodegenEngine { | @@ -345,6 +356,11 @@ public class CodegenEngine { | ||
| 345 | if (!CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { | 356 | if (!CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { |
| 346 | return; | 357 | return; |
| 347 | } | 358 | } |
| 359 | + } else if (isImportTemplate(vmPath)) { | ||
| 360 | + // 关闭 import 时,跳过 ImportExcelVO / ImportRespVO 的生成 | ||
| 361 | + if (!Boolean.TRUE.equals(codegenProperties.getImportEnable())) { | ||
| 362 | + return; | ||
| 363 | + } | ||
| 348 | } | 364 | } |
| 349 | // 2.3 默认生成 | 365 | // 2.3 默认生成 |
| 350 | generateCode(result, vmPath, filePath, bindingMap); | 366 | generateCode(result, vmPath, filePath, bindingMap); |
| @@ -678,4 +694,9 @@ public class CodegenEngine { | @@ -678,4 +694,9 @@ public class CodegenEngine { | ||
| 678 | return path.contains("listReqVO"); | 694 | return path.contains("listReqVO"); |
| 679 | } | 695 | } |
| 680 | 696 | ||
| 697 | + private static boolean isImportTemplate(String path) { | ||
| 698 | + return path.contains("importExcelVO") || path.contains("importRespVO") | ||
| 699 | + || path.contains("views/import.vue"); | ||
| 700 | + } | ||
| 701 | + | ||
| 681 | } | 702 | } |
yudao-module-infra/src/main/resources/codegen/java/controller/controller.vm
| 1 | package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; | 1 | package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; |
| 2 | 2 | ||
| 3 | import org.springframework.web.bind.annotation.*; | 3 | import org.springframework.web.bind.annotation.*; |
| 4 | +#if ($importEnable) | ||
| 4 | import org.springframework.web.multipart.MultipartFile; | 5 | import org.springframework.web.multipart.MultipartFile; |
| 6 | +#end | ||
| 5 | import ${jakartaPackage}.annotation.Resource; | 7 | import ${jakartaPackage}.annotation.Resource; |
| 6 | import org.springframework.validation.annotation.Validated; | 8 | import org.springframework.validation.annotation.Validated; |
| 7 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end | 9 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end |
| @@ -160,13 +162,14 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | @@ -160,13 +162,14 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | ||
| 160 | BeanUtils.toBean(list, ${table.className}RespVO.class)); | 162 | BeanUtils.toBean(list, ${table.className}RespVO.class)); |
| 161 | } | 163 | } |
| 162 | #end | 164 | #end |
| 165 | +#if ($importEnable) | ||
| 163 | 166 | ||
| 164 | @GetMapping("/get-import-template") | 167 | @GetMapping("/get-import-template") |
| 165 | @Operation(summary = "获得导入${table.classComment}模板") | 168 | @Operation(summary = "获得导入${table.classComment}模板") |
| 166 | #if ($sceneEnum.scene == 1) | 169 | #if ($sceneEnum.scene == 1) |
| 167 | @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") | 170 | @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") |
| 168 | #end | 171 | #end |
| 169 | - public void import${simpleClassName}Template(HttpServletResponse response) throws IOException { | 172 | + public void importTemplate(HttpServletResponse response) throws IOException { |
| 170 | ExcelUtils.write(response, "${table.classComment}导入模板.xls", "数据", | 173 | ExcelUtils.write(response, "${table.classComment}导入模板.xls", "数据", |
| 171 | ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class, Collections.emptyList()); | 174 | ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class, Collections.emptyList()); |
| 172 | } | 175 | } |
| @@ -177,11 +180,11 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | @@ -177,11 +180,11 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | ||
| 177 | #if ($sceneEnum.scene == 1) | 180 | #if ($sceneEnum.scene == 1) |
| 178 | @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") | 181 | @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") |
| 179 | #end | 182 | #end |
| 180 | - @ApiAccessLog(operateType = IMPORT) | ||
| 181 | - public CommonResult<${sceneEnum.prefixClass}${table.className}ImportRespVO> import${simpleClassName}(@RequestParam("file") MultipartFile file) throws Exception { | 183 | + public CommonResult<${sceneEnum.prefixClass}${table.className}ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception { |
| 182 | List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> list = ExcelUtils.read(file, ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class); | 184 | List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> list = ExcelUtils.read(file, ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class); |
| 183 | return success(${classNameVar}Service.import${simpleClassName}List(list)); | 185 | return success(${classNameVar}Service.import${simpleClassName}List(list)); |
| 184 | } | 186 | } |
| 187 | +#end | ||
| 185 | 188 | ||
| 186 | ## 特殊:主子表专属逻辑 | 189 | ## 特殊:主子表专属逻辑 |
| 187 | #foreach ($subTable in $subTables) | 190 | #foreach ($subTable in $subTables) |
yudao-module-infra/src/main/resources/codegen/java/service/service.vm
| @@ -25,6 +25,7 @@ public interface ${table.className}Service { | @@ -25,6 +25,7 @@ public interface ${table.className}Service { | ||
| 25 | * @return 编号 | 25 | * @return 编号 |
| 26 | */ | 26 | */ |
| 27 | ${primaryColumn.javaType} create${simpleClassName}(@Valid ${saveReqVOClass} ${saveReqVOVar}); | 27 | ${primaryColumn.javaType} create${simpleClassName}(@Valid ${saveReqVOClass} ${saveReqVOVar}); |
| 28 | +#if ($importEnable) | ||
| 28 | 29 | ||
| 29 | /** | 30 | /** |
| 30 | * 导入${table.classComment} | 31 | * 导入${table.classComment} |
| @@ -33,6 +34,7 @@ public interface ${table.className}Service { | @@ -33,6 +34,7 @@ public interface ${table.className}Service { | ||
| 33 | * @return 导入结果 | 34 | * @return 导入结果 |
| 34 | */ | 35 | */ |
| 35 | ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList); | 36 | ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList); |
| 37 | +#end | ||
| 36 | 38 | ||
| 37 | /** | 39 | /** |
| 38 | * 更新${table.classComment} | 40 | * 更新${table.classComment} |
yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm
| @@ -7,7 +7,9 @@ import org.springframework.validation.annotation.Validated; | @@ -7,7 +7,9 @@ import org.springframework.validation.annotation.Validated; | ||
| 7 | import org.springframework.transaction.annotation.Transactional; | 7 | import org.springframework.transaction.annotation.Transactional; |
| 8 | 8 | ||
| 9 | import java.util.*; | 9 | import java.util.*; |
| 10 | +#if ($importEnable) | ||
| 10 | import java.util.concurrent.atomic.AtomicInteger; | 11 | import java.util.concurrent.atomic.AtomicInteger; |
| 12 | +#end | ||
| 11 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; | 13 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; |
| 12 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; | 14 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; |
| 13 | ## 特殊:主子表专属逻辑 | 15 | ## 特殊:主子表专属逻辑 |
| @@ -92,46 +94,32 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | @@ -92,46 +94,32 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | ||
| 92 | // 返回 | 94 | // 返回 |
| 93 | return ${classNameVar}.getId(); | 95 | return ${classNameVar}.getId(); |
| 94 | } | 96 | } |
| 97 | +#if ($importEnable) | ||
| 95 | 98 | ||
| 96 | @Override | 99 | @Override |
| 97 | - @Transactional(rollbackFor = Exception.class) | 100 | + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 |
| 98 | public ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList) { | 101 | public ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList) { |
| 99 | if (CollUtil.isEmpty(importList)) { | 102 | if (CollUtil.isEmpty(importList)) { |
| 100 | return ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() | 103 | return ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() |
| 101 | - .successCount(0) | ||
| 102 | - .failureCount(0) | ||
| 103 | - .failureRows(new LinkedHashMap<>()) | ||
| 104 | - .build(); | 104 | + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build(); |
| 105 | } | 105 | } |
| 106 | - AtomicInteger successCount = new AtomicInteger(); | ||
| 107 | - Map<Integer, String> failureRows = new LinkedHashMap<>(); | 106 | + // 遍历,逐个创建 |
| 107 | + ${sceneEnum.prefixClass}${table.className}ImportRespVO respVO = ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() | ||
| 108 | + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build(); | ||
| 108 | AtomicInteger index = new AtomicInteger(1); | 109 | AtomicInteger index = new AtomicInteger(1); |
| 109 | importList.forEach(importItem -> { | 110 | importList.forEach(importItem -> { |
| 110 | int currentIndex = index.getAndIncrement(); | 111 | int currentIndex = index.getAndIncrement(); |
| 111 | try { | 112 | try { |
| 112 | create${simpleClassName}(BeanUtils.toBean(importItem, ${saveReqVOClass}.class)); | 113 | create${simpleClassName}(BeanUtils.toBean(importItem, ${saveReqVOClass}.class)); |
| 113 | - successCount.incrementAndGet(); | 114 | + respVO.setSuccessCount(respVO.getSuccessCount() + 1); |
| 114 | } catch (Exception ex) { | 115 | } catch (Exception ex) { |
| 115 | - failureRows.put(currentIndex, resolveImportFailureMessage(ex)); | 116 | + respVO.getFailureRows().put(currentIndex, ex.getMessage()); |
| 116 | } | 117 | } |
| 117 | }); | 118 | }); |
| 118 | - return ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() | ||
| 119 | - .successCount(successCount.get()) | ||
| 120 | - .failureCount(failureRows.size()) | ||
| 121 | - .failureRows(failureRows) | ||
| 122 | - .build(); | ||
| 123 | - } | ||
| 124 | - | ||
| 125 | - /** | ||
| 126 | - * 仅返回根因异常信息,避免把 MyBatis 长堆栈直接暴露给前端。 | ||
| 127 | - */ | ||
| 128 | - private String resolveImportFailureMessage(Exception ex) { | ||
| 129 | - Throwable root = ex; | ||
| 130 | - while (root.getCause() != null && root.getCause() != root) { | ||
| 131 | - root = root.getCause(); | ||
| 132 | - } | ||
| 133 | - return root.getMessage() != null ? root.getMessage() : ex.getMessage(); | 119 | + respVO.setFailureCount(respVO.getFailureRows().size()); |
| 120 | + return respVO; | ||
| 134 | } | 121 | } |
| 122 | +#end | ||
| 135 | 123 | ||
| 136 | @Override | 124 | @Override |
| 137 | ## 特殊:主子表专属逻辑(非 ERP 模式) | 125 | ## 特殊:主子表专属逻辑(非 ERP 模式) |
yudao-module-infra/src/main/resources/codegen/sql/sql.vm
| 1 | ## 通用变量定义 | 1 | ## 通用变量定义 |
| 2 | +#if ($importEnable) | ||
| 2 | #set ($functionNames = ['查询', '创建', '更新', '删除', '导出', '导入']) | 3 | #set ($functionNames = ['查询', '创建', '更新', '删除', '导出', '导入']) |
| 3 | #set ($functionOps = ['query', 'create', 'update', 'delete', 'export', 'import']) | 4 | #set ($functionOps = ['query', 'create', 'update', 'delete', 'export', 'import']) |
| 5 | +#else | ||
| 6 | +#set ($functionNames = ['查询', '创建', '更新', '删除', '导出']) | ||
| 7 | +#set ($functionOps = ['query', 'create', 'update', 'delete', 'export']) | ||
| 8 | +#end | ||
| 4 | ## | 9 | ## |
| 5 | ## 宏定义:生成按钮 SQL(通用部分) | 10 | ## 宏定义:生成按钮 SQL(通用部分) |
| 6 | #macro(insertButtonSql $parentIdVar) | 11 | #macro(insertButtonSql $parentIdVar) |
yudao-module-infra/src/main/resources/codegen/vue/api/api.js.vm
| @@ -73,6 +73,7 @@ export function export${simpleClassName}Excel(params) { | @@ -73,6 +73,7 @@ export function export${simpleClassName}Excel(params) { | ||
| 73 | responseType: 'blob' | 73 | responseType: 'blob' |
| 74 | }) | 74 | }) |
| 75 | } | 75 | } |
| 76 | +#if ($importEnable) | ||
| 76 | 77 | ||
| 77 | // 下载${table.classComment}导入模板 | 78 | // 下载${table.classComment}导入模板 |
| 78 | export function import${simpleClassName}Template() { | 79 | export function import${simpleClassName}Template() { |
| @@ -91,6 +92,7 @@ export function import${simpleClassName}(data) { | @@ -91,6 +92,7 @@ export function import${simpleClassName}(data) { | ||
| 91 | data | 92 | data |
| 92 | }) | 93 | }) |
| 93 | } | 94 | } |
| 95 | +#end | ||
| 94 | ## 特殊:主子表专属逻辑 | 96 | ## 特殊:主子表专属逻辑 |
| 95 | #foreach ($subTable in $subTables) | 97 | #foreach ($subTable in $subTables) |
| 96 | #set ($index = $foreach.count - 1) | 98 | #set ($index = $foreach.count - 1) |
yudao-module-infra/src/main/resources/codegen/vue/views/index.vue.vm
| @@ -49,6 +49,7 @@ | @@ -49,6 +49,7 @@ | ||
| 49 | <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openForm(undefined)" | 49 | <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openForm(undefined)" |
| 50 | v-hasPermi="['${permissionPrefix}:create']">新增</el-button> | 50 | v-hasPermi="['${permissionPrefix}:create']">新增</el-button> |
| 51 | </el-col> | 51 | </el-col> |
| 52 | +#if ($importEnable) | ||
| 52 | <el-col :span="1.5"> | 53 | <el-col :span="1.5"> |
| 53 | <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" | 54 | <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" |
| 54 | :loading="importLoading" v-hasPermi="['${permissionPrefix}:import']">导入</el-button> | 55 | :loading="importLoading" v-hasPermi="['${permissionPrefix}:import']">导入</el-button> |
| @@ -57,6 +58,7 @@ | @@ -57,6 +58,7 @@ | ||
| 57 | <el-button type="info" plain icon="el-icon-document" size="mini" @click="handleImportTemplate" | 58 | <el-button type="info" plain icon="el-icon-document" size="mini" @click="handleImportTemplate" |
| 58 | v-hasPermi="['${permissionPrefix}:import']">导入模板</el-button> | 59 | v-hasPermi="['${permissionPrefix}:import']">导入模板</el-button> |
| 59 | </el-col> | 60 | </el-col> |
| 61 | +#end | ||
| 60 | <el-col :span="1.5"> | 62 | <el-col :span="1.5"> |
| 61 | <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading" | 63 | <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading" |
| 62 | v-hasPermi="['${permissionPrefix}:export']">导出</el-button> | 64 | v-hasPermi="['${permissionPrefix}:export']">导出</el-button> |
| @@ -86,7 +88,9 @@ | @@ -86,7 +88,9 @@ | ||
| 86 | #end | 88 | #end |
| 87 | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | 89 | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
| 88 | </el-row> | 90 | </el-row> |
| 91 | +#if ($importEnable) | ||
| 89 | <input ref="importFileRef" type="file" style="display: none" accept=".xls,.xlsx" @change="handleImportFileChange" /> | 92 | <input ref="importFileRef" type="file" style="display: none" accept=".xls,.xlsx" @change="handleImportFileChange" /> |
| 93 | +#end | ||
| 90 | 94 | ||
| 91 | ## 特殊:主子表专属逻辑 | 95 | ## 特殊:主子表专属逻辑 |
| 92 | #if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 ) | 96 | #if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 ) |
| @@ -253,8 +257,10 @@ export default { | @@ -253,8 +257,10 @@ export default { | ||
| 253 | loading: true, | 257 | loading: true, |
| 254 | // 导出遮罩层 | 258 | // 导出遮罩层 |
| 255 | exportLoading: false, | 259 | exportLoading: false, |
| 260 | +#if ($importEnable) | ||
| 256 | // 导入遮罩层 | 261 | // 导入遮罩层 |
| 257 | importLoading: false, | 262 | importLoading: false, |
| 263 | +#end | ||
| 258 | // 显示搜索条件 | 264 | // 显示搜索条件 |
| 259 | showSearch: true, | 265 | showSearch: true, |
| 260 | ## 特殊:树表专属逻辑(树不需要分页接口) | 266 | ## 特殊:树表专属逻辑(树不需要分页接口) |
| @@ -333,6 +339,7 @@ export default { | @@ -333,6 +339,7 @@ export default { | ||
| 333 | openForm(id) { | 339 | openForm(id) { |
| 334 | this.#[[$]]#refs["formRef"].open(id); | 340 | this.#[[$]]#refs["formRef"].open(id); |
| 335 | }, | 341 | }, |
| 342 | +#if ($importEnable) | ||
| 336 | /** 导入按钮操作 */ | 343 | /** 导入按钮操作 */ |
| 337 | handleImport() { | 344 | handleImport() { |
| 338 | this.$refs.importFileRef && this.$refs.importFileRef.click(); | 345 | this.$refs.importFileRef && this.$refs.importFileRef.click(); |
| @@ -369,6 +376,7 @@ export default { | @@ -369,6 +376,7 @@ export default { | ||
| 369 | this.importLoading = false; | 376 | this.importLoading = false; |
| 370 | } | 377 | } |
| 371 | }, | 378 | }, |
| 379 | +#end | ||
| 372 | /** 删除按钮操作 */ | 380 | /** 删除按钮操作 */ |
| 373 | async handleDelete(row) { | 381 | async handleDelete(row) { |
| 374 | const ${primaryColumn.javaField} = row.${primaryColumn.javaField}; | 382 | const ${primaryColumn.javaField} = row.${primaryColumn.javaField}; |
yudao-module-infra/src/main/resources/codegen/vue3/api/api.ts.vm
| @@ -98,6 +98,7 @@ export const ${simpleClassName}Api = { | @@ -98,6 +98,7 @@ export const ${simpleClassName}Api = { | ||
| 98 | export${simpleClassName}: async (params) => { | 98 | export${simpleClassName}: async (params) => { |
| 99 | return await request.download({ url: `${baseURL}/export-excel`, params }) | 99 | return await request.download({ url: `${baseURL}/export-excel`, params }) |
| 100 | }, | 100 | }, |
| 101 | +#if ($importEnable) | ||
| 101 | 102 | ||
| 102 | // 下载${table.classComment}导入模板 | 103 | // 下载${table.classComment}导入模板 |
| 103 | import${simpleClassName}Template: async () => { | 104 | import${simpleClassName}Template: async () => { |
| @@ -108,6 +109,7 @@ export const ${simpleClassName}Api = { | @@ -108,6 +109,7 @@ export const ${simpleClassName}Api = { | ||
| 108 | import${simpleClassName}: async (data: FormData) => { | 109 | import${simpleClassName}: async (data: FormData) => { |
| 109 | return await request.upload({ url: `${baseURL}/import`, data }) | 110 | return await request.upload({ url: `${baseURL}/import`, data }) |
| 110 | }, | 111 | }, |
| 112 | +#end | ||
| 111 | ## 特殊:主子表专属逻辑 | 113 | ## 特殊:主子表专属逻辑 |
| 112 | #foreach ($subTable in $subTables) | 114 | #foreach ($subTable in $subTables) |
| 113 | #set ($index = $foreach.count - 1) | 115 | #set ($index = $foreach.count - 1) |
yudao-module-infra/src/main/resources/codegen/vue3/views/import.vue.vm
0 → 100644
| 1 | +<template> | ||
| 2 | + <Dialog v-model="dialogVisible" title="${table.classComment}导入" width="400"> | ||
| 3 | + <el-upload | ||
| 4 | + ref="uploadRef" | ||
| 5 | + v-model:file-list="fileList" | ||
| 6 | + :auto-upload="false" | ||
| 7 | + :disabled="formLoading" | ||
| 8 | + :limit="1" | ||
| 9 | + :on-exceed="handleExceed" | ||
| 10 | + accept=".xlsx, .xls" | ||
| 11 | + action="none" | ||
| 12 | + drag | ||
| 13 | + > | ||
| 14 | + <Icon icon="ep:upload" /> | ||
| 15 | + <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> | ||
| 16 | + <template #tip> | ||
| 17 | + <div class="el-upload__tip text-center"> | ||
| 18 | + <span>仅允许导入 xls、xlsx 格式文件。</span> | ||
| 19 | + <el-link | ||
| 20 | + :underline="false" | ||
| 21 | + style="font-size: 12px; vertical-align: baseline" | ||
| 22 | + type="primary" | ||
| 23 | + @click="handleDownloadTemplate" | ||
| 24 | + > | ||
| 25 | + 下载模板 | ||
| 26 | + </el-link> | ||
| 27 | + </div> | ||
| 28 | + </template> | ||
| 29 | + </el-upload> | ||
| 30 | + <template #footer> | ||
| 31 | + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> | ||
| 32 | + <el-button @click="dialogVisible = false">取 消</el-button> | ||
| 33 | + </template> | ||
| 34 | + </Dialog> | ||
| 35 | +</template> | ||
| 36 | +<script setup lang="ts"> | ||
| 37 | +import type { UploadUserFile } from 'element-plus' | ||
| 38 | +import download from '@/utils/download' | ||
| 39 | +import { ${simpleClassName}Api } from '@/api/${table.moduleName}/${table.businessName}' | ||
| 40 | + | ||
| 41 | +/** ${table.classComment} 导入 */ | ||
| 42 | +defineOptions({ name: '${simpleClassName}ImportForm' }) | ||
| 43 | + | ||
| 44 | +const message = useMessage() // 消息弹窗 | ||
| 45 | + | ||
| 46 | +const dialogVisible = ref(false) // 弹窗的是否展示 | ||
| 47 | +const formLoading = ref(false) // 表单的加载中:上传、下载模板 | ||
| 48 | +const uploadRef = ref() | ||
| 49 | +const fileList = ref<UploadUserFile[]>([]) | ||
| 50 | + | ||
| 51 | +/** 打开弹窗 */ | ||
| 52 | +const open = async () => { | ||
| 53 | + dialogVisible.value = true | ||
| 54 | + await resetForm() | ||
| 55 | +} | ||
| 56 | +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||
| 57 | + | ||
| 58 | +/** 提交导入 */ | ||
| 59 | +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||
| 60 | +const submitForm = async () => { | ||
| 61 | + if (fileList.value.length === 0) { | ||
| 62 | + message.error('请上传文件') | ||
| 63 | + return | ||
| 64 | + } | ||
| 65 | + formLoading.value = true | ||
| 66 | + try { | ||
| 67 | + const formData = new FormData() | ||
| 68 | + formData.append('file', fileList.value[0].raw as Blob) | ||
| 69 | + const res = await ${simpleClassName}Api.import${simpleClassName}(formData) | ||
| 70 | + const data = res.data | ||
| 71 | + let text = '导入成功数量:' + data.successCount + ';导入失败数量:' + data.failureCount + ';' | ||
| 72 | + if (data.failureCount > 0) { | ||
| 73 | + for (const rowNo in data.failureRows) { | ||
| 74 | + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >' | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + message.alert(text) | ||
| 78 | + dialogVisible.value = false | ||
| 79 | + emit('success') | ||
| 80 | + } finally { | ||
| 81 | + formLoading.value = false | ||
| 82 | + await resetForm() | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +/** 下载导入模板 */ | ||
| 87 | +const handleDownloadTemplate = async () => { | ||
| 88 | + const data = await ${simpleClassName}Api.import${simpleClassName}Template() | ||
| 89 | + download.excel(data, '${table.classComment}导入模板.xls') | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +/** 文件超限 */ | ||
| 93 | +const handleExceed = (): void => { | ||
| 94 | + message.error('最多只能上传一个文件!') | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +/** 重置表单 */ | ||
| 98 | +const resetForm = async () => { | ||
| 99 | + fileList.value = [] | ||
| 100 | + await nextTick() | ||
| 101 | + uploadRef.value?.clearFiles() | ||
| 102 | +} | ||
| 103 | +</script> |
yudao-module-infra/src/main/resources/codegen/vue3/views/index.vue.vm
| @@ -92,6 +92,7 @@ | @@ -92,6 +92,7 @@ | ||
| 92 | > | 92 | > |
| 93 | <Icon icon="ep:plus" class="mr-5px" /> 新增 | 93 | <Icon icon="ep:plus" class="mr-5px" /> 新增 |
| 94 | </el-button> | 94 | </el-button> |
| 95 | +#if ($importEnable) | ||
| 95 | <el-button | 96 | <el-button |
| 96 | type="warning" | 97 | type="warning" |
| 97 | plain | 98 | plain |
| @@ -100,6 +101,7 @@ | @@ -100,6 +101,7 @@ | ||
| 100 | > | 101 | > |
| 101 | <Icon icon="ep:upload" class="mr-5px" /> 导入 | 102 | <Icon icon="ep:upload" class="mr-5px" /> 导入 |
| 102 | </el-button> | 103 | </el-button> |
| 104 | +#end | ||
| 103 | <el-button | 105 | <el-button |
| 104 | type="success" | 106 | type="success" |
| 105 | plain | 107 | plain |
| @@ -245,43 +247,11 @@ | @@ -245,43 +247,11 @@ | ||
| 245 | @pagination="getList" | 247 | @pagination="getList" |
| 246 | /> | 248 | /> |
| 247 | </ContentWrap> | 249 | </ContentWrap> |
| 250 | +#if ($importEnable) | ||
| 248 | 251 | ||
| 249 | <!-- 导入弹窗 --> | 252 | <!-- 导入弹窗 --> |
| 250 | - <Dialog v-model="importDialogVisible" title="${table.classComment}导入" width="400"> | ||
| 251 | - <el-upload | ||
| 252 | - ref="uploadRef" | ||
| 253 | - v-model:file-list="fileList" | ||
| 254 | - :auto-upload="false" | ||
| 255 | - :disabled="importFormLoading" | ||
| 256 | - :limit="1" | ||
| 257 | - :on-exceed="handleImportExceed" | ||
| 258 | - accept=".xlsx, .xls" | ||
| 259 | - action="none" | ||
| 260 | - drag | ||
| 261 | - > | ||
| 262 | - <Icon icon="ep:upload" /> | ||
| 263 | - <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> | ||
| 264 | - <template #tip> | ||
| 265 | - <div class="el-upload__tip text-center"> | ||
| 266 | - <span>仅允许导入 xls、xlsx 格式文件。</span> | ||
| 267 | - <el-link | ||
| 268 | - :underline="false" | ||
| 269 | - style="font-size: 12px; vertical-align: baseline" | ||
| 270 | - type="primary" | ||
| 271 | - @click="handleImportTemplate" | ||
| 272 | - > | ||
| 273 | - 下载模板 | ||
| 274 | - </el-link> | ||
| 275 | - </div> | ||
| 276 | - </template> | ||
| 277 | - </el-upload> | ||
| 278 | - <template #footer> | ||
| 279 | - <el-button :disabled="importFormLoading" type="primary" @click="submitImportForm"> | ||
| 280 | - 确 定 | ||
| 281 | - </el-button> | ||
| 282 | - <el-button @click="importDialogVisible = false">取 消</el-button> | ||
| 283 | - </template> | ||
| 284 | - </Dialog> | 253 | + <${simpleClassName}ImportForm ref="importRef" @success="getList" /> |
| 254 | +#end | ||
| 285 | 255 | ||
| 286 | <!-- 表单弹窗:添加/修改 --> | 256 | <!-- 表单弹窗:添加/修改 --> |
| 287 | <${simpleClassName}Form ref="formRef" @success="getList" /> | 257 | <${simpleClassName}Form ref="formRef" @success="getList" /> |
| @@ -308,7 +278,9 @@ | @@ -308,7 +278,9 @@ | ||
| 308 | import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' | 278 | import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' |
| 309 | import { isEmpty } from '@/utils/is' | 279 | import { isEmpty } from '@/utils/is' |
| 310 | import { dateFormatter } from '@/utils/formatTime' | 280 | import { dateFormatter } from '@/utils/formatTime' |
| 311 | -import type { UploadUserFile } from 'element-plus' | 281 | +#if ($importEnable) |
| 282 | +import ${simpleClassName}ImportForm from './${simpleClassName}ImportForm.vue' | ||
| 283 | +#end | ||
| 312 | ## 特殊:树表专属逻辑 | 284 | ## 特殊:树表专属逻辑 |
| 313 | #if ( $table.templateType == 2 ) | 285 | #if ( $table.templateType == 2 ) |
| 314 | import { handleTree } from '@/utils/tree' | 286 | import { handleTree } from '@/utils/tree' |
| @@ -354,10 +326,9 @@ const queryParams = reactive({ | @@ -354,10 +326,9 @@ const queryParams = reactive({ | ||
| 354 | }) | 326 | }) |
| 355 | const queryFormRef = ref() // 搜索的表单 | 327 | const queryFormRef = ref() // 搜索的表单 |
| 356 | const exportLoading = ref(false) // 导出的加载中 | 328 | const exportLoading = ref(false) // 导出的加载中 |
| 357 | -const importDialogVisible = ref(false) // 导入弹窗 | ||
| 358 | -const importFormLoading = ref(false) // 导入的加载中 | ||
| 359 | -const uploadRef = ref() | ||
| 360 | -const fileList = ref<UploadUserFile[]>([]) | 329 | +#if ($importEnable) |
| 330 | +const importRef = ref() // ${table.classComment} 导入组件的 Ref | ||
| 331 | +#end | ||
| 361 | 332 | ||
| 362 | /** 查询列表 */ | 333 | /** 查询列表 */ |
| 363 | const getList = async () => { | 334 | const getList = async () => { |
| @@ -394,58 +365,13 @@ const formRef = ref() | @@ -394,58 +365,13 @@ const formRef = ref() | ||
| 394 | const openForm = (type: string, id?: number) => { | 365 | const openForm = (type: string, id?: number) => { |
| 395 | formRef.value.open(type, id) | 366 | formRef.value.open(type, id) |
| 396 | } | 367 | } |
| 368 | +#if ($importEnable) | ||
| 397 | 369 | ||
| 398 | /** 导入按钮操作 */ | 370 | /** 导入按钮操作 */ |
| 399 | -const handleImport = async () => { | ||
| 400 | - importDialogVisible.value = true | ||
| 401 | - await resetImportForm() | ||
| 402 | -} | ||
| 403 | - | ||
| 404 | -/** 提交导入 */ | ||
| 405 | -const submitImportForm = async () => { | ||
| 406 | - if (fileList.value.length === 0) { | ||
| 407 | - message.error('请上传文件') | ||
| 408 | - return | ||
| 409 | - } | ||
| 410 | - importFormLoading.value = true | ||
| 411 | - try { | ||
| 412 | - const formData = new FormData() | ||
| 413 | - formData.append('file', fileList.value[0].raw as Blob) | ||
| 414 | - const res = await ${simpleClassName}Api.import${simpleClassName}(formData) | ||
| 415 | - const data = res.data | ||
| 416 | - let text = '导入成功数量:' + data.successCount + ';导入失败数量:' + data.failureCount + ';' | ||
| 417 | - if (data.failureCount > 0) { | ||
| 418 | - for (const rowNo in data.failureRows) { | ||
| 419 | - text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >' | ||
| 420 | - } | ||
| 421 | - } | ||
| 422 | - message.alert(text) | ||
| 423 | - importDialogVisible.value = false | ||
| 424 | - await getList() | ||
| 425 | - } catch { | ||
| 426 | - } finally { | ||
| 427 | - importFormLoading.value = false | ||
| 428 | - await resetImportForm() | ||
| 429 | - } | ||
| 430 | -} | ||
| 431 | - | ||
| 432 | -/** 下载导入模板 */ | ||
| 433 | -const handleImportTemplate = async () => { | ||
| 434 | - const data = await ${simpleClassName}Api.import${simpleClassName}Template() | ||
| 435 | - download.excel(data, '${table.classComment}导入模板.xls') | ||
| 436 | -} | ||
| 437 | - | ||
| 438 | -/** 导入文件超限 */ | ||
| 439 | -const handleImportExceed = (): void => { | ||
| 440 | - message.error('最多只能上传一个文件!') | ||
| 441 | -} | ||
| 442 | - | ||
| 443 | -/** 重置导入表单 */ | ||
| 444 | -const resetImportForm = async () => { | ||
| 445 | - fileList.value = [] | ||
| 446 | - await nextTick() | ||
| 447 | - uploadRef.value?.clearFiles() | 371 | +const handleImport = () => { |
| 372 | + importRef.value.open() | ||
| 448 | } | 373 | } |
| 374 | +#end | ||
| 449 | 375 | ||
| 450 | /** 删除按钮操作 */ | 376 | /** 删除按钮操作 */ |
| 451 | const handleDelete = async (id: number) => { | 377 | const handleDelete = async (id: number) => { |
yudao-module-infra/src/main/resources/codegen/vue3_vben/api/api.ts.vm
| @@ -30,6 +30,7 @@ export function delete${simpleClassName}(id: number) { | @@ -30,6 +30,7 @@ export function delete${simpleClassName}(id: number) { | ||
| 30 | export function export${simpleClassName}(params) { | 30 | export function export${simpleClassName}(params) { |
| 31 | return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls') | 31 | return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls') |
| 32 | } | 32 | } |
| 33 | +#if ($importEnable) | ||
| 33 | 34 | ||
| 34 | // 下载${table.classComment}导入模板 | 35 | // 下载${table.classComment}导入模板 |
| 35 | export function import${simpleClassName}Template() { | 36 | export function import${simpleClassName}Template() { |
| @@ -40,3 +41,4 @@ export function import${simpleClassName}Template() { | @@ -40,3 +41,4 @@ export function import${simpleClassName}Template() { | ||
| 40 | export function import${simpleClassName}(data: FormData) { | 41 | export function import${simpleClassName}(data: FormData) { |
| 41 | return defHttp.post({ url: '${baseURL}/import', data }) | 42 | return defHttp.post({ url: '${baseURL}/import', data }) |
| 42 | } | 43 | } |
| 44 | +#end |
yudao-module-infra/src/main/resources/codegen/vue3_vben/views/index.vue.vm
| @@ -11,8 +11,10 @@ import { | @@ -11,8 +11,10 @@ import { | ||
| 11 | delete${simpleClassName}, | 11 | delete${simpleClassName}, |
| 12 | export${simpleClassName}, | 12 | export${simpleClassName}, |
| 13 | get${simpleClassName}Page, | 13 | get${simpleClassName}Page, |
| 14 | +#if ($importEnable) | ||
| 14 | import${simpleClassName}, | 15 | import${simpleClassName}, |
| 15 | import${simpleClassName}Template, | 16 | import${simpleClassName}Template, |
| 17 | +#end | ||
| 16 | } from '@/api/${table.moduleName}/${table.businessName}' | 18 | } from '@/api/${table.moduleName}/${table.businessName}' |
| 17 | 19 | ||
| 18 | defineOptions({ name: '${table.className}' }) | 20 | defineOptions({ name: '${table.className}' }) |
| @@ -20,8 +22,10 @@ defineOptions({ name: '${table.className}' }) | @@ -20,8 +22,10 @@ defineOptions({ name: '${table.className}' }) | ||
| 20 | const { t } = useI18n() | 22 | const { t } = useI18n() |
| 21 | const { createConfirm, createMessage } = useMessage() | 23 | const { createConfirm, createMessage } = useMessage() |
| 22 | const [registerModal, { openModal }] = useModal() | 24 | const [registerModal, { openModal }] = useModal() |
| 25 | +#if ($importEnable) | ||
| 23 | const importFileRef = ref<HTMLInputElement>() | 26 | const importFileRef = ref<HTMLInputElement>() |
| 24 | const importLoading = ref(false) | 27 | const importLoading = ref(false) |
| 28 | +#end | ||
| 25 | 29 | ||
| 26 | const [registerTable, { getForm, reload }] = useTable({ | 30 | const [registerTable, { getForm, reload }] = useTable({ |
| 27 | title: '${table.classComment}列表', | 31 | title: '${table.classComment}列表', |
| @@ -57,6 +61,7 @@ async function handleExport() { | @@ -57,6 +61,7 @@ async function handleExport() { | ||
| 57 | }, | 61 | }, |
| 58 | }) | 62 | }) |
| 59 | } | 63 | } |
| 64 | +#if ($importEnable) | ||
| 60 | 65 | ||
| 61 | function handleImport() { | 66 | function handleImport() { |
| 62 | importFileRef.value?.click() | 67 | importFileRef.value?.click() |
| @@ -93,6 +98,7 @@ async function handleImportFileChange(event: Event) { | @@ -93,6 +98,7 @@ async function handleImportFileChange(event: Event) { | ||
| 93 | importLoading.value = false | 98 | importLoading.value = false |
| 94 | } | 99 | } |
| 95 | } | 100 | } |
| 101 | +#end | ||
| 96 | 102 | ||
| 97 | async function handleDelete(record: Recordable) { | 103 | async function handleDelete(record: Recordable) { |
| 98 | await delete${simpleClassName}(record.id) | 104 | await delete${simpleClassName}(record.id) |
| @@ -107,12 +113,14 @@ async function handleDelete(record: Recordable) { | @@ -107,12 +113,14 @@ async function handleDelete(record: Recordable) { | ||
| 107 | <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate"> | 113 | <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate"> |
| 108 | {{ t('action.create') }} | 114 | {{ t('action.create') }} |
| 109 | </a-button> | 115 | </a-button> |
| 116 | +#if ($importEnable) | ||
| 110 | <a-button v-auth="['${permissionPrefix}:import']" :loading="importLoading" @click="handleImport"> | 117 | <a-button v-auth="['${permissionPrefix}:import']" :loading="importLoading" @click="handleImport"> |
| 111 | 导入 | 118 | 导入 |
| 112 | </a-button> | 119 | </a-button> |
| 113 | <a-button v-auth="['${permissionPrefix}:import']" @click="handleImportTemplateDownload"> | 120 | <a-button v-auth="['${permissionPrefix}:import']" @click="handleImportTemplateDownload"> |
| 114 | 导入模板 | 121 | 导入模板 |
| 115 | </a-button> | 122 | </a-button> |
| 123 | +#end | ||
| 116 | <a-button v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport"> | 124 | <a-button v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport"> |
| 117 | {{ t('action.export') }} | 125 | {{ t('action.export') }} |
| 118 | </a-button> | 126 | </a-button> |
| @@ -138,7 +146,9 @@ async function handleDelete(record: Recordable) { | @@ -138,7 +146,9 @@ async function handleDelete(record: Recordable) { | ||
| 138 | </template> | 146 | </template> |
| 139 | </template> | 147 | </template> |
| 140 | </BasicTable> | 148 | </BasicTable> |
| 149 | +#if ($importEnable) | ||
| 141 | <input ref="importFileRef" type="file" accept=".xls,.xlsx" class="hidden" @change="handleImportFileChange" /> | 150 | <input ref="importFileRef" type="file" accept=".xls,.xlsx" class="hidden" @change="handleImportFileChange" /> |
| 151 | +#end | ||
| 142 | <${simpleClassName}Modal @register="registerModal" @success="reload()" /> | 152 | <${simpleClassName}Modal @register="registerModal" @success="reload()" /> |
| 143 | </div> | 153 | </div> |
| 144 | </template> | 154 | </template> |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/api/api.ts.vm
| @@ -100,6 +100,7 @@ export function delete${simpleClassName}List(ids: number[]) { | @@ -100,6 +100,7 @@ export function delete${simpleClassName}List(ids: number[]) { | ||
| 100 | export function export${simpleClassName}(params: any) { | 100 | export function export${simpleClassName}(params: any) { |
| 101 | return requestClient.download('${baseURL}/export-excel', { params }); | 101 | return requestClient.download('${baseURL}/export-excel', { params }); |
| 102 | } | 102 | } |
| 103 | +#if ($importEnable) | ||
| 103 | 104 | ||
| 104 | /** 下载${table.classComment}导入模板 */ | 105 | /** 下载${table.classComment}导入模板 */ |
| 105 | export function import${simpleClassName}Template() { | 106 | export function import${simpleClassName}Template() { |
| @@ -110,6 +111,7 @@ export function import${simpleClassName}Template() { | @@ -110,6 +111,7 @@ export function import${simpleClassName}Template() { | ||
| 110 | export function import${simpleClassName}(data: FormData) { | 111 | export function import${simpleClassName}(data: FormData) { |
| 111 | return requestClient.post('${baseURL}/import', data); | 112 | return requestClient.post('${baseURL}/import', data); |
| 112 | } | 113 | } |
| 114 | +#end | ||
| 113 | 115 | ||
| 114 | ## 特殊:主子表专属逻辑 | 116 | ## 特殊:主子表专属逻辑 |
| 115 | #foreach ($subTable in $subTables) | 117 | #foreach ($subTable in $subTables) |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/views/import.vue.vm
0 → 100644
| 1 | +<script lang="ts" setup> | ||
| 2 | +import type { FileType } from 'ant-design-vue/es/upload/interface'; | ||
| 3 | + | ||
| 4 | +import { ref } from 'vue'; | ||
| 5 | + | ||
| 6 | +import { useVbenModal } from '@vben/common-ui'; | ||
| 7 | +import { downloadFileFromBlobPart } from '@vben/utils'; | ||
| 8 | + | ||
| 9 | +import { Button, message, Upload } from 'ant-design-vue'; | ||
| 10 | + | ||
| 11 | +import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}'; | ||
| 12 | + | ||
| 13 | +defineOptions({ name: '${simpleClassName}Import' }); | ||
| 14 | + | ||
| 15 | +const emit = defineEmits(['success']); | ||
| 16 | +const fileRef = ref<File | null>(null); | ||
| 17 | + | ||
| 18 | +const [Modal, modalApi] = useVbenModal({ | ||
| 19 | + async onConfirm() { | ||
| 20 | + if (!fileRef.value) { | ||
| 21 | + message.error('请上传文件'); | ||
| 22 | + return; | ||
| 23 | + } | ||
| 24 | + modalApi.lock(); | ||
| 25 | + try { | ||
| 26 | + const formData = new FormData(); | ||
| 27 | + formData.append('file', fileRef.value); | ||
| 28 | + const response: any = await import${simpleClassName}(formData); | ||
| 29 | + const data = response?.data ?? response ?? {}; | ||
| 30 | + let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';'; | ||
| 31 | + if (data.failureRows) { | ||
| 32 | + Object.keys(data.failureRows).forEach((rowNo) => { | ||
| 33 | + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >'; | ||
| 34 | + }); | ||
| 35 | + } | ||
| 36 | + message.info(text); | ||
| 37 | + await modalApi.close(); | ||
| 38 | + emit('success'); | ||
| 39 | + } finally { | ||
| 40 | + modalApi.unlock(); | ||
| 41 | + } | ||
| 42 | + }, | ||
| 43 | +}); | ||
| 44 | + | ||
| 45 | +/** 上传前:拦截 antd Upload 的自动上传,文件存到 ref */ | ||
| 46 | +function beforeUpload(file: FileType) { | ||
| 47 | + fileRef.value = file as unknown as File; | ||
| 48 | + return false; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +/** 下载导入模板 */ | ||
| 52 | +async function handleDownload() { | ||
| 53 | + const data = await import${simpleClassName}Template(); | ||
| 54 | + downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 55 | +} | ||
| 56 | +</script> | ||
| 57 | + | ||
| 58 | +<template> | ||
| 59 | + <Modal title="导入${table.classComment}" class="w-1/3"> | ||
| 60 | + <div class="mx-4"> | ||
| 61 | + <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload"> | ||
| 62 | + <Button type="primary"> 选择 Excel 文件 </Button> | ||
| 63 | + </Upload> | ||
| 64 | + </div> | ||
| 65 | + <template #prepend-footer> | ||
| 66 | + <div class="flex flex-auto items-center"> | ||
| 67 | + <Button @click="handleDownload"> 下载导入模板 </Button> | ||
| 68 | + </div> | ||
| 69 | + </template> | ||
| 70 | + </Modal> | ||
| 71 | +</template> |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/views/index.vue.vm
| @@ -27,9 +27,12 @@ import { getRangePickerDefaultProps } from '#/utils/rangePickerProps'; | @@ -27,9 +27,12 @@ import { getRangePickerDefaultProps } from '#/utils/rangePickerProps'; | ||
| 27 | import { $t } from '#/locales'; | 27 | import { $t } from '#/locales'; |
| 28 | #if (${table.templateType} == 2)## 树表接口 | 28 | #if (${table.templateType} == 2)## 树表接口 |
| 29 | import { handleTree } from '@vben/utils' | 29 | import { handleTree } from '@vben/utils' |
| 30 | -import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName}, import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}'; | 30 | +import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| 31 | #else## 标准表接口 | 31 | #else## 标准表接口 |
| 32 | -import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName}, import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}'; | 32 | +import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| 33 | +#end | ||
| 34 | +#if ($importEnable) | ||
| 35 | +import ${simpleClassName}Import from './modules/import-form.vue'; | ||
| 33 | #end | 36 | #end |
| 34 | 37 | ||
| 35 | #if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况 | 38 | #if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况 |
| @@ -73,8 +76,6 @@ const queryParams = reactive({ | @@ -73,8 +76,6 @@ const queryParams = reactive({ | ||
| 73 | }) | 76 | }) |
| 74 | const queryFormRef = ref() // 搜索的表单 | 77 | const queryFormRef = ref() // 搜索的表单 |
| 75 | const exportLoading = ref(false) // 导出的加载中 | 78 | const exportLoading = ref(false) // 导出的加载中 |
| 76 | -const importLoading = ref(false) // 导入的加载中 | ||
| 77 | -const importFileRef = ref<HTMLInputElement>() | ||
| 78 | 79 | ||
| 79 | /** 查询列表 */ | 80 | /** 查询列表 */ |
| 80 | async function getList() { | 81 | async function getList() { |
| @@ -121,6 +122,17 @@ const [FormModal, formModalApi] = useVbenModal({ | @@ -121,6 +122,17 @@ const [FormModal, formModalApi] = useVbenModal({ | ||
| 121 | connectedComponent: ${simpleClassName}Form, | 122 | connectedComponent: ${simpleClassName}Form, |
| 122 | destroyOnClose: true, | 123 | destroyOnClose: true, |
| 123 | }); | 124 | }); |
| 125 | +#if ($importEnable) | ||
| 126 | +const [ImportFormModal, importFormModalApi] = useVbenModal({ | ||
| 127 | + connectedComponent: ${simpleClassName}Import, | ||
| 128 | + destroyOnClose: true, | ||
| 129 | +}); | ||
| 130 | + | ||
| 131 | +/** 导入${table.classComment} */ | ||
| 132 | +function handleImport() { | ||
| 133 | + importFormModalApi.open(); | ||
| 134 | +} | ||
| 135 | +#end | ||
| 124 | 136 | ||
| 125 | /** 创建${table.classComment} */ | 137 | /** 创建${table.classComment} */ |
| 126 | function handleCreate() { | 138 | function handleCreate() { |
| @@ -192,43 +204,6 @@ try { | @@ -192,43 +204,6 @@ try { | ||
| 192 | } | 204 | } |
| 193 | } | 205 | } |
| 194 | 206 | ||
| 195 | -/** 导入模板下载 */ | ||
| 196 | -async function handleImportTemplateDownload() { | ||
| 197 | - const data = await import${simpleClassName}Template(); | ||
| 198 | - downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 199 | -} | ||
| 200 | - | ||
| 201 | -/** 导入按钮操作 */ | ||
| 202 | -function handleImport() { | ||
| 203 | - importFileRef.value?.click(); | ||
| 204 | -} | ||
| 205 | - | ||
| 206 | -/** 导入文件变更 */ | ||
| 207 | -async function handleImportFileChange(event: Event) { | ||
| 208 | - const target = event.target as HTMLInputElement; | ||
| 209 | - const file = target.files?.[0]; | ||
| 210 | - if (!file) { | ||
| 211 | - return; | ||
| 212 | - } | ||
| 213 | - importLoading.value = true; | ||
| 214 | - try { | ||
| 215 | - const formData = new FormData(); | ||
| 216 | - formData.append('file', file); | ||
| 217 | - const response: any = await import${simpleClassName}(formData); | ||
| 218 | - const data = response?.data ?? response ?? {}; | ||
| 219 | - let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';'; | ||
| 220 | - if (data.failureRows) { | ||
| 221 | - Object.keys(data.failureRows).forEach((rowNo) => { | ||
| 222 | - text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >'; | ||
| 223 | - }); | ||
| 224 | - } | ||
| 225 | - message.info(text); | ||
| 226 | - await getList(); | ||
| 227 | - } finally { | ||
| 228 | - target.value = ''; | ||
| 229 | - importLoading.value = false; | ||
| 230 | - } | ||
| 231 | -} | ||
| 232 | 207 | ||
| 233 | #if (${table.templateType} == 2) | 208 | #if (${table.templateType} == 2) |
| 234 | /** 切换树形展开/收缩状态 */ | 209 | /** 切换树形展开/收缩状态 */ |
| @@ -249,7 +224,9 @@ onMounted(() => { | @@ -249,7 +224,9 @@ onMounted(() => { | ||
| 249 | <template> | 224 | <template> |
| 250 | <Page auto-content-height> | 225 | <Page auto-content-height> |
| 251 | <FormModal @success="getList" /> | 226 | <FormModal @success="getList" /> |
| 252 | - <input ref="importFileRef" type="file" accept=".xls,.xlsx" class="hidden" @change="handleImportFileChange" /> | 227 | +#if ($importEnable) |
| 228 | + <ImportFormModal @success="getList" /> | ||
| 229 | +#end | ||
| 253 | 230 | ||
| 254 | <Card v-if="!hiddenSearchBar" class="mb-4"> | 231 | <Card v-if="!hiddenSearchBar" class="mb-4"> |
| 255 | <!-- 搜索工作栏 --> | 232 | <!-- 搜索工作栏 --> |
| @@ -355,23 +332,16 @@ onMounted(() => { | @@ -355,23 +332,16 @@ onMounted(() => { | ||
| 355 | > | 332 | > |
| 356 | {{ $t('ui.actionTitle.create', ['${table.classComment}']) }} | 333 | {{ $t('ui.actionTitle.create', ['${table.classComment}']) }} |
| 357 | </Button> | 334 | </Button> |
| 335 | +#if ($importEnable) | ||
| 358 | <Button | 336 | <Button |
| 359 | class="ml-2" | 337 | class="ml-2" |
| 360 | type="primary" | 338 | type="primary" |
| 361 | - :loading="importLoading" | ||
| 362 | @click="handleImport" | 339 | @click="handleImport" |
| 363 | v-access:code="['${permissionPrefix}:import']" | 340 | v-access:code="['${permissionPrefix}:import']" |
| 364 | > | 341 | > |
| 365 | 导入 | 342 | 导入 |
| 366 | </Button> | 343 | </Button> |
| 367 | - <Button | ||
| 368 | - class="ml-2" | ||
| 369 | - type="primary" | ||
| 370 | - @click="handleImportTemplateDownload" | ||
| 371 | - v-access:code="['${permissionPrefix}:import']" | ||
| 372 | - > | ||
| 373 | - 导入模板 | ||
| 374 | - </Button> | 344 | +#end |
| 375 | <Button | 345 | <Button |
| 376 | :icon="h(Download)" | 346 | :icon="h(Download)" |
| 377 | type="primary" | 347 | type="primary" |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/data.ts.vm
| @@ -134,6 +134,21 @@ export function useFormSchema(): VbenFormSchema[] { | @@ -134,6 +134,21 @@ export function useFormSchema(): VbenFormSchema[] { | ||
| 134 | ]; | 134 | ]; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | +#if ($importEnable) | ||
| 138 | +/** 导入的表单 */ | ||
| 139 | +export function useImportFormSchema(): VbenFormSchema[] { | ||
| 140 | + return [ | ||
| 141 | + { | ||
| 142 | + fieldName: 'file', | ||
| 143 | + label: '${table.classComment}数据', | ||
| 144 | + component: 'Upload', | ||
| 145 | + rules: 'required', | ||
| 146 | + help: '仅允许导入 xls、xlsx 格式文件', | ||
| 147 | + }, | ||
| 148 | + ]; | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +#end | ||
| 137 | /** 列表的搜索表单 */ | 152 | /** 列表的搜索表单 */ |
| 138 | export function useGridFormSchema(): VbenFormSchema[] { | 153 | export function useGridFormSchema(): VbenFormSchema[] { |
| 139 | return [ | 154 | return [ |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/import.vue.vm
0 → 100644
| 1 | +<script lang="ts" setup> | ||
| 2 | +import type { FileType } from 'ant-design-vue/es/upload/interface'; | ||
| 3 | + | ||
| 4 | +import { useVbenModal } from '@vben/common-ui'; | ||
| 5 | +import { downloadFileFromBlobPart } from '@vben/utils'; | ||
| 6 | + | ||
| 7 | +import { Button, message, Upload } from 'ant-design-vue'; | ||
| 8 | + | ||
| 9 | +import { useVbenForm } from '#/adapter/form'; | ||
| 10 | +import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}'; | ||
| 11 | +import { $t } from '#/locales'; | ||
| 12 | + | ||
| 13 | +import { useImportFormSchema } from '../data'; | ||
| 14 | + | ||
| 15 | +const emit = defineEmits(['success']); | ||
| 16 | + | ||
| 17 | +const [Form, formApi] = useVbenForm({ | ||
| 18 | + commonConfig: { | ||
| 19 | + formItemClass: 'col-span-2', | ||
| 20 | + labelWidth: 120, | ||
| 21 | + }, | ||
| 22 | + layout: 'horizontal', | ||
| 23 | + schema: useImportFormSchema(), | ||
| 24 | + showDefaultActions: false, | ||
| 25 | +}); | ||
| 26 | + | ||
| 27 | +const [Modal, modalApi] = useVbenModal({ | ||
| 28 | + async onConfirm() { | ||
| 29 | + const { valid } = await formApi.validate(); | ||
| 30 | + if (!valid) { | ||
| 31 | + return; | ||
| 32 | + } | ||
| 33 | + modalApi.lock(); | ||
| 34 | + // 提交表单 | ||
| 35 | + const data = await formApi.getValues(); | ||
| 36 | + try { | ||
| 37 | + await import${simpleClassName}(data.file); | ||
| 38 | + // 关闭并提示 | ||
| 39 | + await modalApi.close(); | ||
| 40 | + emit('success'); | ||
| 41 | + message.success($t('ui.actionMessage.operationSuccess')); | ||
| 42 | + } finally { | ||
| 43 | + modalApi.unlock(); | ||
| 44 | + } | ||
| 45 | + }, | ||
| 46 | +}); | ||
| 47 | + | ||
| 48 | +/** 上传前 */ | ||
| 49 | +function beforeUpload(file: FileType) { | ||
| 50 | + formApi.setFieldValue('file', file); | ||
| 51 | + return false; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +/** 下载模板 */ | ||
| 55 | +async function handleDownload() { | ||
| 56 | + const data = await import${simpleClassName}Template(); | ||
| 57 | + downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 58 | +} | ||
| 59 | +</script> | ||
| 60 | + | ||
| 61 | +<template> | ||
| 62 | + <Modal title="导入${table.classComment}" class="w-1/3"> | ||
| 63 | + <Form class="mx-4"> | ||
| 64 | + <template #file> | ||
| 65 | + <div class="w-full"> | ||
| 66 | + <Upload | ||
| 67 | + :max-count="1" | ||
| 68 | + accept=".xls,.xlsx" | ||
| 69 | + :before-upload="beforeUpload" | ||
| 70 | + > | ||
| 71 | + <Button type="primary"> 选择 Excel 文件 </Button> | ||
| 72 | + </Upload> | ||
| 73 | + </div> | ||
| 74 | + </template> | ||
| 75 | + </Form> | ||
| 76 | + <template #prepend-footer> | ||
| 77 | + <div class="flex flex-auto items-center"> | ||
| 78 | + <Button @click="handleDownload"> 下载导入模板 </Button> | ||
| 79 | + </div> | ||
| 80 | + </template> | ||
| 81 | + </Modal> | ||
| 82 | +</template> |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/index.vue.vm
| @@ -16,8 +16,6 @@ import { | @@ -16,8 +16,6 @@ import { | ||
| 16 | delete${simpleClassName}, | 16 | delete${simpleClassName}, |
| 17 | export${simpleClassName}, | 17 | export${simpleClassName}, |
| 18 | get${simpleClassName}List, | 18 | get${simpleClassName}List, |
| 19 | - import${simpleClassName}, | ||
| 20 | - import${simpleClassName}Template, | ||
| 21 | } from '#/api/${table.moduleName}/${table.businessName}'; | 19 | } from '#/api/${table.moduleName}/${table.businessName}'; |
| 22 | #else## 标准表接口 | 20 | #else## 标准表接口 |
| 23 | import { | 21 | import { |
| @@ -26,10 +24,11 @@ import { | @@ -26,10 +24,11 @@ import { | ||
| 26 | delete${simpleClassName}List,#end | 24 | delete${simpleClassName}List,#end |
| 27 | export${simpleClassName}, | 25 | export${simpleClassName}, |
| 28 | get${simpleClassName}Page, | 26 | get${simpleClassName}Page, |
| 29 | - import${simpleClassName}, | ||
| 30 | - import${simpleClassName}Template, | ||
| 31 | } from '#/api/${table.moduleName}/${table.businessName}'; | 27 | } from '#/api/${table.moduleName}/${table.businessName}'; |
| 32 | #end | 28 | #end |
| 29 | +#if ($importEnable) | ||
| 30 | +import ${simpleClassName}Import from './modules/import-form.vue'; | ||
| 31 | +#end | ||
| 33 | import { $t } from '#/locales'; | 32 | import { $t } from '#/locales'; |
| 34 | 33 | ||
| 35 | import { useGridColumns, useGridFormSchema } from './data'; | 34 | import { useGridColumns, useGridFormSchema } from './data'; |
| @@ -54,8 +53,17 @@ const [FormModal, formModalApi] = useVbenModal({ | @@ -54,8 +53,17 @@ const [FormModal, formModalApi] = useVbenModal({ | ||
| 54 | connectedComponent: Form, | 53 | connectedComponent: Form, |
| 55 | destroyOnClose: true, | 54 | destroyOnClose: true, |
| 56 | }); | 55 | }); |
| 57 | -const importLoading = ref(false); | ||
| 58 | -const importFileRef = ref<HTMLInputElement>(); | 56 | +#if ($importEnable) |
| 57 | +const [ImportFormModal, importFormModalApi] = useVbenModal({ | ||
| 58 | + connectedComponent: ${simpleClassName}Import, | ||
| 59 | + destroyOnClose: true, | ||
| 60 | +}); | ||
| 61 | + | ||
| 62 | +/** 导入${table.classComment} */ | ||
| 63 | +function handleImport() { | ||
| 64 | + importFormModalApi.open(); | ||
| 65 | +} | ||
| 66 | +#end | ||
| 59 | #if (${table.templateType} == 2)## 树表特有:控制表格展开收缩 | 67 | #if (${table.templateType} == 2)## 树表特有:控制表格展开收缩 |
| 60 | 68 | ||
| 61 | /** 切换树形展开/收缩状态 */ | 69 | /** 切换树形展开/收缩状态 */ |
| @@ -141,43 +149,6 @@ async function handleExport() { | @@ -141,43 +149,6 @@ async function handleExport() { | ||
| 141 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); | 149 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); |
| 142 | } | 150 | } |
| 143 | 151 | ||
| 144 | -/** 导入模板下载 */ | ||
| 145 | -async function handleImportTemplateDownload() { | ||
| 146 | - const data = await import${simpleClassName}Template(); | ||
| 147 | - downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 148 | -} | ||
| 149 | - | ||
| 150 | -/** 导入按钮操作 */ | ||
| 151 | -function handleImport() { | ||
| 152 | - importFileRef.value?.click(); | ||
| 153 | -} | ||
| 154 | - | ||
| 155 | -/** 导入文件变更 */ | ||
| 156 | -async function handleImportFileChange(event: Event) { | ||
| 157 | - const target = event.target as HTMLInputElement; | ||
| 158 | - const file = target.files?.[0]; | ||
| 159 | - if (!file) { | ||
| 160 | - return; | ||
| 161 | - } | ||
| 162 | - importLoading.value = true; | ||
| 163 | - try { | ||
| 164 | - const formData = new FormData(); | ||
| 165 | - formData.append('file', file); | ||
| 166 | - const response: any = await import${simpleClassName}(formData); | ||
| 167 | - const data = response?.data ?? response ?? {}; | ||
| 168 | - let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';'; | ||
| 169 | - if (data.failureRows) { | ||
| 170 | - Object.keys(data.failureRows).forEach((rowNo) => { | ||
| 171 | - text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >'; | ||
| 172 | - }); | ||
| 173 | - } | ||
| 174 | - message.info(text); | ||
| 175 | - handleRefresh(); | ||
| 176 | - } finally { | ||
| 177 | - target.value = ''; | ||
| 178 | - importLoading.value = false; | ||
| 179 | - } | ||
| 180 | -} | ||
| 181 | 152 | ||
| 182 | const [Grid, gridApi] = useVbenVxeGrid({ | 153 | const [Grid, gridApi] = useVbenVxeGrid({ |
| 183 | formOptions: { | 154 | formOptions: { |
| @@ -254,7 +225,9 @@ const [Grid, gridApi] = useVbenVxeGrid({ | @@ -254,7 +225,9 @@ const [Grid, gridApi] = useVbenVxeGrid({ | ||
| 254 | <template> | 225 | <template> |
| 255 | <Page auto-content-height> | 226 | <Page auto-content-height> |
| 256 | <FormModal @success="handleRefresh" /> | 227 | <FormModal @success="handleRefresh" /> |
| 257 | - <input ref="importFileRef" type="file" accept=".xls,.xlsx" class="hidden" @change="handleImportFileChange" /> | 228 | +#if ($importEnable) |
| 229 | + <ImportFormModal @success="handleRefresh" /> | ||
| 230 | +#end | ||
| 258 | #if ($table.templateType == 11) ## erp情况 | 231 | #if ($table.templateType == 11) ## erp情况 |
| 259 | <div> | 232 | <div> |
| 260 | #end | 233 | #end |
| @@ -292,19 +265,14 @@ const [Grid, gridApi] = useVbenVxeGrid({ | @@ -292,19 +265,14 @@ const [Grid, gridApi] = useVbenVxeGrid({ | ||
| 292 | onClick: handleExpand, | 265 | onClick: handleExpand, |
| 293 | }, | 266 | }, |
| 294 | #end | 267 | #end |
| 268 | +#if ($importEnable) | ||
| 295 | { | 269 | { |
| 296 | label: '导入', | 270 | label: '导入', |
| 297 | type: 'primary', | 271 | type: 'primary', |
| 298 | auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'], | 272 | auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'], |
| 299 | - disabled: importLoading.value, | ||
| 300 | onClick: handleImport, | 273 | onClick: handleImport, |
| 301 | }, | 274 | }, |
| 302 | - { | ||
| 303 | - label: '导入模板', | ||
| 304 | - type: 'primary', | ||
| 305 | - auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'], | ||
| 306 | - onClick: handleImportTemplateDownload, | ||
| 307 | - }, | 275 | +#end |
| 308 | { | 276 | { |
| 309 | label: $t('ui.actionTitle.export'), | 277 | label: $t('ui.actionTitle.export'), |
| 310 | type: 'primary', | 278 | type: 'primary', |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/api/api.ts.vm
| @@ -100,6 +100,7 @@ export function delete${simpleClassName}List(ids: number[]) { | @@ -100,6 +100,7 @@ export function delete${simpleClassName}List(ids: number[]) { | ||
| 100 | export function export${simpleClassName}(params: any) { | 100 | export function export${simpleClassName}(params: any) { |
| 101 | return requestClient.download('${baseURL}/export-excel', { params }); | 101 | return requestClient.download('${baseURL}/export-excel', { params }); |
| 102 | } | 102 | } |
| 103 | +#if ($importEnable) | ||
| 103 | 104 | ||
| 104 | /** 下载${table.classComment}导入模板 */ | 105 | /** 下载${table.classComment}导入模板 */ |
| 105 | export function import${simpleClassName}Template() { | 106 | export function import${simpleClassName}Template() { |
| @@ -110,6 +111,7 @@ export function import${simpleClassName}Template() { | @@ -110,6 +111,7 @@ export function import${simpleClassName}Template() { | ||
| 110 | export function import${simpleClassName}(data: FormData) { | 111 | export function import${simpleClassName}(data: FormData) { |
| 111 | return requestClient.post('${baseURL}/import', data); | 112 | return requestClient.post('${baseURL}/import', data); |
| 112 | } | 113 | } |
| 114 | +#end | ||
| 113 | 115 | ||
| 114 | ## 特殊:主子表专属逻辑 | 116 | ## 特殊:主子表专属逻辑 |
| 115 | #foreach ($subTable in $subTables) | 117 | #foreach ($subTable in $subTables) |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/import.vue.vm
0 → 100644
| 1 | +<script lang="ts" setup> | ||
| 2 | +import { ref } from 'vue'; | ||
| 3 | + | ||
| 4 | +import { useVbenModal } from '@vben/common-ui'; | ||
| 5 | +import { downloadFileFromBlobPart } from '@vben/utils'; | ||
| 6 | + | ||
| 7 | +import { ElButton, ElMessage, ElUpload } from 'element-plus'; | ||
| 8 | + | ||
| 9 | +import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}'; | ||
| 10 | + | ||
| 11 | +defineOptions({ name: '${simpleClassName}Import' }); | ||
| 12 | + | ||
| 13 | +const emit = defineEmits(['success']); | ||
| 14 | +const fileRef = ref<File | null>(null); | ||
| 15 | + | ||
| 16 | +const [Modal, modalApi] = useVbenModal({ | ||
| 17 | + async onConfirm() { | ||
| 18 | + if (!fileRef.value) { | ||
| 19 | + ElMessage.error('请上传文件'); | ||
| 20 | + return; | ||
| 21 | + } | ||
| 22 | + modalApi.lock(); | ||
| 23 | + try { | ||
| 24 | + const formData = new FormData(); | ||
| 25 | + formData.append('file', fileRef.value); | ||
| 26 | + const response: any = await import${simpleClassName}(formData); | ||
| 27 | + const data = response?.data ?? response ?? {}; | ||
| 28 | + let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';'; | ||
| 29 | + if (data.failureRows) { | ||
| 30 | + Object.keys(data.failureRows).forEach((rowNo) => { | ||
| 31 | + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >'; | ||
| 32 | + }); | ||
| 33 | + } | ||
| 34 | + ElMessage.info(text); | ||
| 35 | + await modalApi.close(); | ||
| 36 | + emit('success'); | ||
| 37 | + } finally { | ||
| 38 | + modalApi.unlock(); | ||
| 39 | + } | ||
| 40 | + }, | ||
| 41 | +}); | ||
| 42 | + | ||
| 43 | +/** 文件改变 */ | ||
| 44 | +function handleChange(file: any) { | ||
| 45 | + if (file.raw) { | ||
| 46 | + fileRef.value = file.raw; | ||
| 47 | + } | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +/** 下载导入模板 */ | ||
| 51 | +async function handleDownload() { | ||
| 52 | + const data = await import${simpleClassName}Template(); | ||
| 53 | + downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 54 | +} | ||
| 55 | +</script> | ||
| 56 | + | ||
| 57 | +<template> | ||
| 58 | + <Modal title="导入${table.classComment}" class="w-1/3"> | ||
| 59 | + <div class="mx-4"> | ||
| 60 | + <ElUpload | ||
| 61 | + :limit="1" | ||
| 62 | + accept=".xls,.xlsx" | ||
| 63 | + :on-change="handleChange" | ||
| 64 | + :auto-upload="false" | ||
| 65 | + > | ||
| 66 | + <ElButton type="primary"> 选择 Excel 文件 </ElButton> | ||
| 67 | + </ElUpload> | ||
| 68 | + </div> | ||
| 69 | + <template #prepend-footer> | ||
| 70 | + <div class="flex flex-auto items-center"> | ||
| 71 | + <ElButton @click="handleDownload"> 下载导入模板 </ElButton> | ||
| 72 | + </div> | ||
| 73 | + </template> | ||
| 74 | + </Modal> | ||
| 75 | +</template> |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/index.vue.vm
| @@ -26,10 +26,13 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | @@ -26,10 +26,13 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | ||
| 26 | import { $t } from '#/locales'; | 26 | import { $t } from '#/locales'; |
| 27 | #if (${table.templateType} == 2)## 树表接口 | 27 | #if (${table.templateType} == 2)## 树表接口 |
| 28 | import { handleTree,isEmpty } from '@vben/utils' | 28 | import { handleTree,isEmpty } from '@vben/utils' |
| 29 | -import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName}, import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | 29 | +import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; |
| 30 | #else## 标准表接口 | 30 | #else## 标准表接口 |
| 31 | import { isEmpty } from '@vben/utils'; | 31 | import { isEmpty } from '@vben/utils'; |
| 32 | -import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName}, import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | 32 | +import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; |
| 33 | +#end | ||
| 34 | +#if ($importEnable) | ||
| 35 | +import ${simpleClassName}Import from './modules/import-form.vue'; | ||
| 33 | #end | 36 | #end |
| 34 | 37 | ||
| 35 | #if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况 | 38 | #if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况 |
| @@ -73,8 +76,6 @@ const queryParams = reactive({ | @@ -73,8 +76,6 @@ const queryParams = reactive({ | ||
| 73 | }) | 76 | }) |
| 74 | const queryFormRef = ref() // 搜索的表单 | 77 | const queryFormRef = ref() // 搜索的表单 |
| 75 | const exportLoading = ref(false) // 导出的加载中 | 78 | const exportLoading = ref(false) // 导出的加载中 |
| 76 | -const importLoading = ref(false) // 导入的加载中 | ||
| 77 | -const importFileRef = ref<HTMLInputElement>() | ||
| 78 | 79 | ||
| 79 | /** 查询列表 */ | 80 | /** 查询列表 */ |
| 80 | const getList = async () => { | 81 | const getList = async () => { |
| @@ -121,6 +122,17 @@ const [FormModal, formModalApi] = useVbenModal({ | @@ -121,6 +122,17 @@ const [FormModal, formModalApi] = useVbenModal({ | ||
| 121 | connectedComponent: ${simpleClassName}Form, | 122 | connectedComponent: ${simpleClassName}Form, |
| 122 | destroyOnClose: true, | 123 | destroyOnClose: true, |
| 123 | }); | 124 | }); |
| 125 | +#if ($importEnable) | ||
| 126 | +const [ImportFormModal, importFormModalApi] = useVbenModal({ | ||
| 127 | + connectedComponent: ${simpleClassName}Import, | ||
| 128 | + destroyOnClose: true, | ||
| 129 | +}); | ||
| 130 | + | ||
| 131 | +/** 导入${table.classComment} */ | ||
| 132 | +function handleImport() { | ||
| 133 | + importFormModalApi.open(); | ||
| 134 | +} | ||
| 135 | +#end | ||
| 124 | 136 | ||
| 125 | /** 创建${table.classComment} */ | 137 | /** 创建${table.classComment} */ |
| 126 | function handleCreate() { | 138 | function handleCreate() { |
| @@ -190,43 +202,6 @@ try { | @@ -190,43 +202,6 @@ try { | ||
| 190 | } | 202 | } |
| 191 | } | 203 | } |
| 192 | 204 | ||
| 193 | -/** 导入模板下载 */ | ||
| 194 | -async function handleImportTemplateDownload() { | ||
| 195 | - const data = await import${simpleClassName}Template(); | ||
| 196 | - downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 197 | -} | ||
| 198 | - | ||
| 199 | -/** 导入按钮操作 */ | ||
| 200 | -function handleImport() { | ||
| 201 | - importFileRef.value?.click(); | ||
| 202 | -} | ||
| 203 | - | ||
| 204 | -/** 导入文件变更 */ | ||
| 205 | -async function handleImportFileChange(event: Event) { | ||
| 206 | - const target = event.target as HTMLInputElement; | ||
| 207 | - const file = target.files?.[0]; | ||
| 208 | - if (!file) { | ||
| 209 | - return; | ||
| 210 | - } | ||
| 211 | - importLoading.value = true; | ||
| 212 | - try { | ||
| 213 | - const formData = new FormData(); | ||
| 214 | - formData.append('file', file); | ||
| 215 | - const response: any = await import${simpleClassName}(formData); | ||
| 216 | - const data = response?.data ?? response ?? {}; | ||
| 217 | - let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';'; | ||
| 218 | - if (data.failureRows) { | ||
| 219 | - Object.keys(data.failureRows).forEach((rowNo) => { | ||
| 220 | - text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >'; | ||
| 221 | - }); | ||
| 222 | - } | ||
| 223 | - ElMessage.info(text); | ||
| 224 | - await getList(); | ||
| 225 | - } finally { | ||
| 226 | - target.value = ''; | ||
| 227 | - importLoading.value = false; | ||
| 228 | - } | ||
| 229 | -} | ||
| 230 | 205 | ||
| 231 | #if (${table.templateType} == 2) | 206 | #if (${table.templateType} == 2) |
| 232 | /** 切换树形展开/收缩状态 */ | 207 | /** 切换树形展开/收缩状态 */ |
| @@ -247,7 +222,9 @@ onMounted(() => { | @@ -247,7 +222,9 @@ onMounted(() => { | ||
| 247 | <template> | 222 | <template> |
| 248 | <Page auto-content-height> | 223 | <Page auto-content-height> |
| 249 | <FormModal @success="getList" /> | 224 | <FormModal @success="getList" /> |
| 250 | - <input ref="importFileRef" type="file" accept=".xls,.xlsx" class="hidden" @change="handleImportFileChange" /> | 225 | +#if ($importEnable) |
| 226 | + <ImportFormModal @success="getList" /> | ||
| 227 | +#end | ||
| 251 | 228 | ||
| 252 | <ContentWrap v-if="!hiddenSearchBar"> | 229 | <ContentWrap v-if="!hiddenSearchBar"> |
| 253 | <!-- 搜索工作栏 --> | 230 | <!-- 搜索工作栏 --> |
| @@ -356,23 +333,16 @@ onMounted(() => { | @@ -356,23 +333,16 @@ onMounted(() => { | ||
| 356 | > | 333 | > |
| 357 | {{ $t('ui.actionTitle.create', ['${table.classComment}']) }} | 334 | {{ $t('ui.actionTitle.create', ['${table.classComment}']) }} |
| 358 | </el-button> | 335 | </el-button> |
| 336 | +#if ($importEnable) | ||
| 359 | <el-button | 337 | <el-button |
| 360 | class="ml-2" | 338 | class="ml-2" |
| 361 | type="primary" | 339 | type="primary" |
| 362 | - :loading="importLoading" | ||
| 363 | @click="handleImport" | 340 | @click="handleImport" |
| 364 | v-access:code="['${permissionPrefix}:import']" | 341 | v-access:code="['${permissionPrefix}:import']" |
| 365 | > | 342 | > |
| 366 | 导入 | 343 | 导入 |
| 367 | </el-button> | 344 | </el-button> |
| 368 | - <el-button | ||
| 369 | - class="ml-2" | ||
| 370 | - type="primary" | ||
| 371 | - @click="handleImportTemplateDownload" | ||
| 372 | - v-access:code="['${permissionPrefix}:import']" | ||
| 373 | - > | ||
| 374 | - 导入模板 | ||
| 375 | - </el-button> | 345 | +#end |
| 376 | <el-button | 346 | <el-button |
| 377 | :icon="h(Download)" | 347 | :icon="h(Download)" |
| 378 | type="primary" | 348 | type="primary" |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/api/api.ts.vm
| @@ -113,6 +113,7 @@ export function delete${simpleClassName}List(ids: number[]) { | @@ -113,6 +113,7 @@ export function delete${simpleClassName}List(ids: number[]) { | ||
| 113 | export function export${simpleClassName}(params: any) { | 113 | export function export${simpleClassName}(params: any) { |
| 114 | return requestClient.download('${baseURL}/export-excel', { params }); | 114 | return requestClient.download('${baseURL}/export-excel', { params }); |
| 115 | } | 115 | } |
| 116 | +#if ($importEnable) | ||
| 116 | 117 | ||
| 117 | /** 下载${table.classComment}导入模板 */ | 118 | /** 下载${table.classComment}导入模板 */ |
| 118 | export function import${simpleClassName}Template() { | 119 | export function import${simpleClassName}Template() { |
| @@ -120,9 +121,10 @@ export function import${simpleClassName}Template() { | @@ -120,9 +121,10 @@ export function import${simpleClassName}Template() { | ||
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | /** 导入${table.classComment} */ | 123 | /** 导入${table.classComment} */ |
| 123 | -export function import${simpleClassName}(data: FormData) { | ||
| 124 | - return requestClient.post('${baseURL}/import', data); | 124 | +export function import${simpleClassName}(file: File) { |
| 125 | + return requestClient.upload('${baseURL}/import', { file }); | ||
| 125 | } | 126 | } |
| 127 | +#end | ||
| 126 | 128 | ||
| 127 | ## 特殊:主子表专属逻辑 | 129 | ## 特殊:主子表专属逻辑 |
| 128 | #foreach ($subTable in $subTables) | 130 | #foreach ($subTable in $subTables) |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/data.ts.vm
| @@ -137,6 +137,21 @@ export function useFormSchema(): VbenFormSchema[] { | @@ -137,6 +137,21 @@ export function useFormSchema(): VbenFormSchema[] { | ||
| 137 | ]; | 137 | ]; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | +#if ($importEnable) | ||
| 141 | +/** 导入的表单 */ | ||
| 142 | +export function useImportFormSchema(): VbenFormSchema[] { | ||
| 143 | + return [ | ||
| 144 | + { | ||
| 145 | + fieldName: 'file', | ||
| 146 | + label: '${table.classComment}数据', | ||
| 147 | + component: 'Upload', | ||
| 148 | + rules: 'required', | ||
| 149 | + help: '仅允许导入 xls、xlsx 格式文件', | ||
| 150 | + }, | ||
| 151 | + ]; | ||
| 152 | +} | ||
| 153 | + | ||
| 154 | +#end | ||
| 140 | /** 列表的搜索表单 */ | 155 | /** 列表的搜索表单 */ |
| 141 | export function useGridFormSchema(): VbenFormSchema[] { | 156 | export function useGridFormSchema(): VbenFormSchema[] { |
| 142 | return [ | 157 | return [ |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/import.vue.vm
0 → 100644
| 1 | +<script lang="ts" setup> | ||
| 2 | +import { useVbenModal } from '@vben/common-ui'; | ||
| 3 | +import { downloadFileFromBlobPart } from '@vben/utils'; | ||
| 4 | + | ||
| 5 | +import { ElButton, ElMessage, ElUpload } from 'element-plus'; | ||
| 6 | + | ||
| 7 | +import { useVbenForm } from '#/adapter/form'; | ||
| 8 | +import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}'; | ||
| 9 | +import { $t } from '#/locales'; | ||
| 10 | + | ||
| 11 | +import { useImportFormSchema } from '../data'; | ||
| 12 | + | ||
| 13 | +const emit = defineEmits(['success']); | ||
| 14 | + | ||
| 15 | +const [Form, formApi] = useVbenForm({ | ||
| 16 | + commonConfig: { | ||
| 17 | + formItemClass: 'col-span-2', | ||
| 18 | + labelWidth: 120, | ||
| 19 | + }, | ||
| 20 | + layout: 'horizontal', | ||
| 21 | + schema: useImportFormSchema(), | ||
| 22 | + showDefaultActions: false, | ||
| 23 | +}); | ||
| 24 | + | ||
| 25 | +const [Modal, modalApi] = useVbenModal({ | ||
| 26 | + async onConfirm() { | ||
| 27 | + const { valid } = await formApi.validate(); | ||
| 28 | + if (!valid) { | ||
| 29 | + return; | ||
| 30 | + } | ||
| 31 | + modalApi.lock(); | ||
| 32 | + // 提交表单 | ||
| 33 | + const data = await formApi.getValues(); | ||
| 34 | + try { | ||
| 35 | + await import${simpleClassName}(data.file); | ||
| 36 | + // 关闭并提示 | ||
| 37 | + await modalApi.close(); | ||
| 38 | + emit('success'); | ||
| 39 | + ElMessage.success($t('ui.actionMessage.operationSuccess')); | ||
| 40 | + } finally { | ||
| 41 | + modalApi.unlock(); | ||
| 42 | + } | ||
| 43 | + }, | ||
| 44 | +}); | ||
| 45 | + | ||
| 46 | +/** 文件改变时 */ | ||
| 47 | +function handleChange(file: any) { | ||
| 48 | + if (file.raw) { | ||
| 49 | + formApi.setFieldValue('file', file.raw); | ||
| 50 | + } | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +/** 下载模板 */ | ||
| 54 | +async function handleDownload() { | ||
| 55 | + const data = await import${simpleClassName}Template(); | ||
| 56 | + downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 57 | +} | ||
| 58 | +</script> | ||
| 59 | + | ||
| 60 | +<template> | ||
| 61 | + <Modal title="导入${table.classComment}" class="w-1/3"> | ||
| 62 | + <Form class="mx-4"> | ||
| 63 | + <template #file> | ||
| 64 | + <div class="w-full"> | ||
| 65 | + <ElUpload | ||
| 66 | + :limit="1" | ||
| 67 | + accept=".xls,.xlsx" | ||
| 68 | + :on-change="handleChange" | ||
| 69 | + :auto-upload="false" | ||
| 70 | + > | ||
| 71 | + <ElButton type="primary"> 选择 Excel 文件 </ElButton> | ||
| 72 | + </ElUpload> | ||
| 73 | + </div> | ||
| 74 | + </template> | ||
| 75 | + </Form> | ||
| 76 | + <template #prepend-footer> | ||
| 77 | + <div class="flex flex-auto items-center"> | ||
| 78 | + <ElButton @click="handleDownload"> 下载导入模板 </ElButton> | ||
| 79 | + </div> | ||
| 80 | + </template> | ||
| 81 | + </Modal> | ||
| 82 | +</template> |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/index.vue.vm
| @@ -16,8 +16,6 @@ import { | @@ -16,8 +16,6 @@ import { | ||
| 16 | delete${simpleClassName}, | 16 | delete${simpleClassName}, |
| 17 | export${simpleClassName}, | 17 | export${simpleClassName}, |
| 18 | get${simpleClassName}List, | 18 | get${simpleClassName}List, |
| 19 | - import${simpleClassName}, | ||
| 20 | - import${simpleClassName}Template, | ||
| 21 | } from '#/api/${table.moduleName}/${table.businessName}'; | 19 | } from '#/api/${table.moduleName}/${table.businessName}'; |
| 22 | #else## 标准表接口 | 20 | #else## 标准表接口 |
| 23 | import { | 21 | import { |
| @@ -26,10 +24,11 @@ import { | @@ -26,10 +24,11 @@ import { | ||
| 26 | delete${simpleClassName}List,#end | 24 | delete${simpleClassName}List,#end |
| 27 | export${simpleClassName}, | 25 | export${simpleClassName}, |
| 28 | get${simpleClassName}Page, | 26 | get${simpleClassName}Page, |
| 29 | - import${simpleClassName}, | ||
| 30 | - import${simpleClassName}Template, | ||
| 31 | } from '#/api/${table.moduleName}/${table.businessName}'; | 27 | } from '#/api/${table.moduleName}/${table.businessName}'; |
| 32 | #end | 28 | #end |
| 29 | +#if ($importEnable) | ||
| 30 | +import ${simpleClassName}Import from './modules/import-form.vue'; | ||
| 31 | +#end | ||
| 33 | import { $t } from '#/locales'; | 32 | import { $t } from '#/locales'; |
| 34 | 33 | ||
| 35 | import { useGridColumns, useGridFormSchema } from './data'; | 34 | import { useGridColumns, useGridFormSchema } from './data'; |
| @@ -54,8 +53,17 @@ const [FormModal, formModalApi] = useVbenModal({ | @@ -54,8 +53,17 @@ const [FormModal, formModalApi] = useVbenModal({ | ||
| 54 | connectedComponent: Form, | 53 | connectedComponent: Form, |
| 55 | destroyOnClose: true, | 54 | destroyOnClose: true, |
| 56 | }); | 55 | }); |
| 57 | -const importLoading = ref(false); | ||
| 58 | -const importFileRef = ref<HTMLInputElement>(); | 56 | +#if ($importEnable) |
| 57 | +const [ImportFormModal, importFormModalApi] = useVbenModal({ | ||
| 58 | + connectedComponent: ${simpleClassName}Import, | ||
| 59 | + destroyOnClose: true, | ||
| 60 | +}); | ||
| 61 | + | ||
| 62 | +/** 导入${table.classComment} */ | ||
| 63 | +function handleImport() { | ||
| 64 | + importFormModalApi.open(); | ||
| 65 | +} | ||
| 66 | +#end | ||
| 59 | #if (${table.templateType} == 2)## 树表特有:控制表格展开收缩 | 67 | #if (${table.templateType} == 2)## 树表特有:控制表格展开收缩 |
| 60 | 68 | ||
| 61 | /** 切换树形展开/收缩状态 */ | 69 | /** 切换树形展开/收缩状态 */ |
| @@ -139,43 +147,6 @@ async function handleExport() { | @@ -139,43 +147,6 @@ async function handleExport() { | ||
| 139 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); | 147 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); |
| 140 | } | 148 | } |
| 141 | 149 | ||
| 142 | -/** 导入模板下载 */ | ||
| 143 | -async function handleImportTemplateDownload() { | ||
| 144 | - const data = await import${simpleClassName}Template(); | ||
| 145 | - downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data }); | ||
| 146 | -} | ||
| 147 | - | ||
| 148 | -/** 导入按钮操作 */ | ||
| 149 | -function handleImport() { | ||
| 150 | - importFileRef.value?.click(); | ||
| 151 | -} | ||
| 152 | - | ||
| 153 | -/** 导入文件变更 */ | ||
| 154 | -async function handleImportFileChange(event: Event) { | ||
| 155 | - const target = event.target as HTMLInputElement; | ||
| 156 | - const file = target.files?.[0]; | ||
| 157 | - if (!file) { | ||
| 158 | - return; | ||
| 159 | - } | ||
| 160 | - importLoading.value = true; | ||
| 161 | - try { | ||
| 162 | - const formData = new FormData(); | ||
| 163 | - formData.append('file', file); | ||
| 164 | - const response: any = await import${simpleClassName}(formData); | ||
| 165 | - const data = response?.data ?? response ?? {}; | ||
| 166 | - let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';'; | ||
| 167 | - if (data.failureRows) { | ||
| 168 | - Object.keys(data.failureRows).forEach((rowNo) => { | ||
| 169 | - text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >'; | ||
| 170 | - }); | ||
| 171 | - } | ||
| 172 | - ElMessage.info(text); | ||
| 173 | - handleRefresh(); | ||
| 174 | - } finally { | ||
| 175 | - target.value = ''; | ||
| 176 | - importLoading.value = false; | ||
| 177 | - } | ||
| 178 | -} | ||
| 179 | 150 | ||
| 180 | const [Grid, gridApi] = useVbenVxeGrid({ | 151 | const [Grid, gridApi] = useVbenVxeGrid({ |
| 181 | formOptions: { | 152 | formOptions: { |
| @@ -252,7 +223,9 @@ const [Grid, gridApi] = useVbenVxeGrid({ | @@ -252,7 +223,9 @@ const [Grid, gridApi] = useVbenVxeGrid({ | ||
| 252 | <template> | 223 | <template> |
| 253 | <Page auto-content-height> | 224 | <Page auto-content-height> |
| 254 | <FormModal @success="handleRefresh" /> | 225 | <FormModal @success="handleRefresh" /> |
| 255 | - <input ref="importFileRef" type="file" accept=".xls,.xlsx" class="hidden" @change="handleImportFileChange" /> | 226 | +#if ($importEnable) |
| 227 | + <ImportFormModal @success="handleRefresh" /> | ||
| 228 | +#end | ||
| 256 | #if ($table.templateType == 11) ## erp情况 | 229 | #if ($table.templateType == 11) ## erp情况 |
| 257 | <div> | 230 | <div> |
| 258 | #end | 231 | #end |
| @@ -290,19 +263,14 @@ const [Grid, gridApi] = useVbenVxeGrid({ | @@ -290,19 +263,14 @@ const [Grid, gridApi] = useVbenVxeGrid({ | ||
| 290 | onClick: handleExpand, | 263 | onClick: handleExpand, |
| 291 | }, | 264 | }, |
| 292 | #end | 265 | #end |
| 266 | +#if ($importEnable) | ||
| 293 | { | 267 | { |
| 294 | label: '导入', | 268 | label: '导入', |
| 295 | type: 'primary', | 269 | type: 'primary', |
| 296 | auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'], | 270 | auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'], |
| 297 | - disabled: importLoading.value, | ||
| 298 | onClick: handleImport, | 271 | onClick: handleImport, |
| 299 | }, | 272 | }, |
| 300 | - { | ||
| 301 | - label: '导入模板', | ||
| 302 | - type: 'primary', | ||
| 303 | - auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'], | ||
| 304 | - onClick: handleImportTemplateDownload, | ||
| 305 | - }, | 273 | +#end |
| 306 | { | 274 | { |
| 307 | label: $t('ui.actionTitle.export'), | 275 | label: $t('ui.actionTitle.export'), |
| 308 | type: 'primary', | 276 | type: 'primary', |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java
| @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 10 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | 10 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| 11 | import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | 11 | import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; |
| 12 | import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | 12 | import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; |
| 13 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenVOTypeEnum; | ||
| 13 | import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; | 14 | import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; |
| 14 | import org.junit.jupiter.api.BeforeEach; | 15 | import org.junit.jupiter.api.BeforeEach; |
| 15 | import org.mockito.InjectMocks; | 16 | import org.mockito.InjectMocks; |
| @@ -19,8 +20,10 @@ import java.io.ByteArrayInputStream; | @@ -19,8 +20,10 @@ import java.io.ByteArrayInputStream; | ||
| 19 | import java.io.ByteArrayOutputStream; | 20 | import java.io.ByteArrayOutputStream; |
| 20 | import java.util.ArrayList; | 21 | import java.util.ArrayList; |
| 21 | import java.util.HashMap; | 22 | import java.util.HashMap; |
| 23 | +import java.util.LinkedHashSet; | ||
| 22 | import java.util.List; | 24 | import java.util.List; |
| 23 | import java.util.Map; | 25 | import java.util.Map; |
| 26 | +import java.util.Set; | ||
| 24 | 27 | ||
| 25 | import static org.junit.jupiter.api.Assertions.assertEquals; | 28 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 26 | 29 | ||
| @@ -41,16 +44,18 @@ public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest { | @@ -41,16 +44,18 @@ public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest { | ||
| 41 | 44 | ||
| 42 | @Spy | 45 | @Spy |
| 43 | protected CodegenProperties codegenProperties = new CodegenProperties() | 46 | protected CodegenProperties codegenProperties = new CodegenProperties() |
| 44 | - .setBasePackage("cn.iocoder.yudao"); | 47 | + .setBasePackage("cn.iocoder.yudao") |
| 48 | + .setVoType(CodegenVOTypeEnum.VO.getType()) | ||
| 49 | + .setDeleteBatchEnable(true) | ||
| 50 | + .setUnitTestEnable(true) | ||
| 51 | + .setImportEnable(false); | ||
| 45 | 52 | ||
| 46 | @BeforeEach | 53 | @BeforeEach |
| 47 | public void setUp() { | 54 | public void setUp() { |
| 48 | codegenEngine.setJakartaEnable(true); // 强制使用 jakarta,保证单测可以基于 jakarta 断言 | 55 | codegenEngine.setJakartaEnable(true); // 强制使用 jakarta,保证单测可以基于 jakarta 断言 |
| 49 | codegenEngine.initGlobalBindingMap(); | 56 | codegenEngine.initGlobalBindingMap(); |
| 50 | - // 单测强制使用 | ||
| 51 | - // 获取测试文件 resources 路径 | 57 | + // 获取测试文件 resources 路径,writeResult 调试用 |
| 52 | String absolutePath = FileUtil.getAbsolutePath("application-unit-test.yaml"); | 58 | String absolutePath = FileUtil.getAbsolutePath("application-unit-test.yaml"); |
| 53 | - // 系统不一样生成的文件也有差异,那就各自生成各自的 | ||
| 54 | resourcesPath = absolutePath.split("/target")[0] + "/src/test/resources/codegen/"; | 59 | resourcesPath = absolutePath.split("/target")[0] + "/src/test/resources/codegen/"; |
| 55 | } | 60 | } |
| 56 | 61 | ||
| @@ -82,17 +87,32 @@ public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest { | @@ -82,17 +87,32 @@ public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest { | ||
| 82 | return list; | 87 | return list; |
| 83 | } | 88 | } |
| 84 | 89 | ||
| 90 | + /** | ||
| 91 | + * 重新生成断言数据的开关,命令行加 {@code -Dcodegen.regenerate=true} 启用 | ||
| 92 | + */ | ||
| 93 | + private static final boolean REGENERATE = Boolean.parseBoolean(System.getProperty("codegen.regenerate", "false")); | ||
| 94 | + | ||
| 85 | @SuppressWarnings("rawtypes") | 95 | @SuppressWarnings("rawtypes") |
| 86 | - protected static void assertResult(Map<String, String> result, String path) { | 96 | + protected void assertResult(Map<String, String> result, String path) { |
| 97 | + if (REGENERATE) { | ||
| 98 | + writeResult(result, resourcesPath + path); | ||
| 99 | + return; | ||
| 100 | + } | ||
| 87 | String assertContent = ResourceUtil.readUtf8Str("codegen/" + path + "/assert.json"); | 101 | String assertContent = ResourceUtil.readUtf8Str("codegen/" + path + "/assert.json"); |
| 88 | List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class); | 102 | List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class); |
| 89 | - assertEquals(asserts.size(), result.size()); | ||
| 90 | - // 校验每个文件 | 103 | + Set<String> expectedFiles = asserts.stream() |
| 104 | + .map(m -> (String) m.get("filePath")) | ||
| 105 | + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); | ||
| 106 | + assertEquals(expectedFiles, result.keySet(), "生成文件集合不匹配"); | ||
| 107 | + // 校验每个文件;归一化 \r\n 为 \n,让断言不依赖文件落盘的换行风格 | ||
| 91 | asserts.forEach(assertMap -> { | 108 | asserts.forEach(assertMap -> { |
| 92 | String contentPath = (String) assertMap.get("contentPath"); | 109 | String contentPath = (String) assertMap.get("contentPath"); |
| 93 | String filePath = (String) assertMap.get("filePath"); | 110 | String filePath = (String) assertMap.get("filePath"); |
| 94 | - String content = ResourceUtil.readUtf8Str("codegen/" + path + "/" + contentPath); | ||
| 95 | - assertEquals(content, result.get(filePath), filePath + ":不匹配"); | 111 | + String expected = ResourceUtil.readUtf8Str("codegen/" + path + "/" + contentPath) |
| 112 | + .replace("\r\n", "\n"); | ||
| 113 | + String actual = result.get(filePath); | ||
| 114 | + assertEquals(expected, actual == null ? null : actual.replace("\r\n", "\n"), | ||
| 115 | + filePath + ":不匹配"); | ||
| 96 | }); | 116 | }); |
| 97 | } | 117 | } |
| 98 | 118 |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVben5AntdGeneralTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.service.codegen.inner; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | ||
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | ||
| 5 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | ||
| 6 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.DbType; | ||
| 8 | +import org.junit.jupiter.api.Test; | ||
| 9 | + | ||
| 10 | +import java.util.Arrays; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * {@link CodegenEngine} 的 Vue3 + Vben5 + AntD + General 单元测试 | ||
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + */ | ||
| 19 | +public class CodegenEngineVben5AntdGeneralTest extends CodegenEngineAbstractTest { | ||
| 20 | + | ||
| 21 | + private static final Integer FRONT_TYPE = CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(); | ||
| 22 | + | ||
| 23 | + @Test | ||
| 24 | + public void testExecute_one() { | ||
| 25 | + // 准备参数 | ||
| 26 | + CodegenTableDO table = getTable("student") | ||
| 27 | + .setFrontType(FRONT_TYPE) | ||
| 28 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 29 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 30 | + | ||
| 31 | + // 调用 | ||
| 32 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 33 | + // 断言 | ||
| 34 | + assertResult(result, "/vben5_antd_general_one"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void testExecute_one_importEnable() { | ||
| 39 | + // 开启 import 开关 | ||
| 40 | + codegenProperties.setImportEnable(true); | ||
| 41 | + codegenEngine.initGlobalBindingMap(); | ||
| 42 | + // 准备参数 | ||
| 43 | + CodegenTableDO table = getTable("student") | ||
| 44 | + .setFrontType(FRONT_TYPE) | ||
| 45 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 46 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 50 | + // 断言 | ||
| 51 | + assertResult(result, "/vben5_antd_general_one_importEnable"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 55 | + public void testExecute_tree() { | ||
| 56 | + // 准备参数 | ||
| 57 | + CodegenTableDO table = getTable("category") | ||
| 58 | + .setFrontType(FRONT_TYPE) | ||
| 59 | + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); | ||
| 60 | + List<CodegenColumnDO> columns = getColumnList("category"); | ||
| 61 | + | ||
| 62 | + // 调用 | ||
| 63 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 64 | + // 断言 | ||
| 65 | + assertResult(result, "/vben5_antd_general_tree"); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Test | ||
| 69 | + public void testExecute_master_normal() { | ||
| 70 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "/vben5_antd_general_master_normal"); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Test | ||
| 74 | + public void testExecute_master_erp() { | ||
| 75 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_ERP, "/vben5_antd_general_master_erp"); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Test | ||
| 79 | + public void testExecute_master_inner() { | ||
| 80 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_INNER, "/vben5_antd_general_master_inner"); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private void testExecute_master(CodegenTemplateTypeEnum templateType, String path) { | ||
| 84 | + // 准备参数 | ||
| 85 | + CodegenTableDO table = getTable("student") | ||
| 86 | + .setFrontType(FRONT_TYPE) | ||
| 87 | + .setTemplateType(templateType.getType()); | ||
| 88 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 89 | + // 准备参数(子表) | ||
| 90 | + CodegenTableDO contactTable = getTable("contact") | ||
| 91 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 92 | + .setFrontType(FRONT_TYPE) | ||
| 93 | + .setSubJoinColumnId(100L).setSubJoinMany(true); | ||
| 94 | + List<CodegenColumnDO> contactColumns = getColumnList("contact"); | ||
| 95 | + // 准备参数(班主任) | ||
| 96 | + CodegenTableDO teacherTable = getTable("teacher") | ||
| 97 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 98 | + .setFrontType(FRONT_TYPE) | ||
| 99 | + .setSubJoinColumnId(200L).setSubJoinMany(false); | ||
| 100 | + List<CodegenColumnDO> teacherColumns = getColumnList("teacher"); | ||
| 101 | + | ||
| 102 | + // 调用 | ||
| 103 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, | ||
| 104 | + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); | ||
| 105 | + // 断言 | ||
| 106 | + assertResult(result, path); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | +} |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVben5AntdSchemaTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.service.codegen.inner; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | ||
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | ||
| 5 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | ||
| 6 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.DbType; | ||
| 8 | +import org.junit.jupiter.api.Test; | ||
| 9 | + | ||
| 10 | +import java.util.Arrays; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * {@link CodegenEngine} 的 Vue3 + Vben5 + AntD + Schema 单元测试 | ||
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + */ | ||
| 19 | +public class CodegenEngineVben5AntdSchemaTest extends CodegenEngineAbstractTest { | ||
| 20 | + | ||
| 21 | + private static final Integer FRONT_TYPE = CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(); | ||
| 22 | + | ||
| 23 | + @Test | ||
| 24 | + public void testExecute_one() { | ||
| 25 | + // 准备参数 | ||
| 26 | + CodegenTableDO table = getTable("student") | ||
| 27 | + .setFrontType(FRONT_TYPE) | ||
| 28 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 29 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 30 | + | ||
| 31 | + // 调用 | ||
| 32 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 33 | + // 断言 | ||
| 34 | + assertResult(result, "/vben5_antd_schema_one"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void testExecute_one_importEnable() { | ||
| 39 | + // 开启 import 开关 | ||
| 40 | + codegenProperties.setImportEnable(true); | ||
| 41 | + codegenEngine.initGlobalBindingMap(); | ||
| 42 | + // 准备参数 | ||
| 43 | + CodegenTableDO table = getTable("student") | ||
| 44 | + .setFrontType(FRONT_TYPE) | ||
| 45 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 46 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 50 | + // 断言 | ||
| 51 | + assertResult(result, "/vben5_antd_schema_one_importEnable"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 55 | + public void testExecute_tree() { | ||
| 56 | + // 准备参数 | ||
| 57 | + CodegenTableDO table = getTable("category") | ||
| 58 | + .setFrontType(FRONT_TYPE) | ||
| 59 | + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); | ||
| 60 | + List<CodegenColumnDO> columns = getColumnList("category"); | ||
| 61 | + | ||
| 62 | + // 调用 | ||
| 63 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 64 | + // 断言 | ||
| 65 | + assertResult(result, "/vben5_antd_schema_tree"); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Test | ||
| 69 | + public void testExecute_master_normal() { | ||
| 70 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "/vben5_antd_schema_master_normal"); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Test | ||
| 74 | + public void testExecute_master_erp() { | ||
| 75 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_ERP, "/vben5_antd_schema_master_erp"); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Test | ||
| 79 | + public void testExecute_master_inner() { | ||
| 80 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_INNER, "/vben5_antd_schema_master_inner"); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private void testExecute_master(CodegenTemplateTypeEnum templateType, String path) { | ||
| 84 | + // 准备参数 | ||
| 85 | + CodegenTableDO table = getTable("student") | ||
| 86 | + .setFrontType(FRONT_TYPE) | ||
| 87 | + .setTemplateType(templateType.getType()); | ||
| 88 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 89 | + // 准备参数(子表) | ||
| 90 | + CodegenTableDO contactTable = getTable("contact") | ||
| 91 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 92 | + .setFrontType(FRONT_TYPE) | ||
| 93 | + .setSubJoinColumnId(100L).setSubJoinMany(true); | ||
| 94 | + List<CodegenColumnDO> contactColumns = getColumnList("contact"); | ||
| 95 | + // 准备参数(班主任) | ||
| 96 | + CodegenTableDO teacherTable = getTable("teacher") | ||
| 97 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 98 | + .setFrontType(FRONT_TYPE) | ||
| 99 | + .setSubJoinColumnId(200L).setSubJoinMany(false); | ||
| 100 | + List<CodegenColumnDO> teacherColumns = getColumnList("teacher"); | ||
| 101 | + | ||
| 102 | + // 调用 | ||
| 103 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, | ||
| 104 | + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); | ||
| 105 | + // 断言 | ||
| 106 | + assertResult(result, path); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | +} |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVben5EleGeneralTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.service.codegen.inner; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | ||
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | ||
| 5 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | ||
| 6 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.DbType; | ||
| 8 | +import org.junit.jupiter.api.Test; | ||
| 9 | + | ||
| 10 | +import java.util.Arrays; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * {@link CodegenEngine} 的 Vue3 + Vben5 + Element Plus + General 单元测试 | ||
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + */ | ||
| 19 | +public class CodegenEngineVben5EleGeneralTest extends CodegenEngineAbstractTest { | ||
| 20 | + | ||
| 21 | + private static final Integer FRONT_TYPE = CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(); | ||
| 22 | + | ||
| 23 | + @Test | ||
| 24 | + public void testExecute_one() { | ||
| 25 | + // 准备参数 | ||
| 26 | + CodegenTableDO table = getTable("student") | ||
| 27 | + .setFrontType(FRONT_TYPE) | ||
| 28 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 29 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 30 | + | ||
| 31 | + // 调用 | ||
| 32 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 33 | + // 断言 | ||
| 34 | + assertResult(result, "/vben5_ele_general_one"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void testExecute_one_importEnable() { | ||
| 39 | + // 开启 import 开关 | ||
| 40 | + codegenProperties.setImportEnable(true); | ||
| 41 | + codegenEngine.initGlobalBindingMap(); | ||
| 42 | + // 准备参数 | ||
| 43 | + CodegenTableDO table = getTable("student") | ||
| 44 | + .setFrontType(FRONT_TYPE) | ||
| 45 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 46 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 50 | + // 断言 | ||
| 51 | + assertResult(result, "/vben5_ele_general_one_importEnable"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 55 | + public void testExecute_tree() { | ||
| 56 | + // 准备参数 | ||
| 57 | + CodegenTableDO table = getTable("category") | ||
| 58 | + .setFrontType(FRONT_TYPE) | ||
| 59 | + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); | ||
| 60 | + List<CodegenColumnDO> columns = getColumnList("category"); | ||
| 61 | + | ||
| 62 | + // 调用 | ||
| 63 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 64 | + // 断言 | ||
| 65 | + assertResult(result, "/vben5_ele_general_tree"); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Test | ||
| 69 | + public void testExecute_master_normal() { | ||
| 70 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "/vben5_ele_general_master_normal"); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Test | ||
| 74 | + public void testExecute_master_erp() { | ||
| 75 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_ERP, "/vben5_ele_general_master_erp"); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Test | ||
| 79 | + public void testExecute_master_inner() { | ||
| 80 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_INNER, "/vben5_ele_general_master_inner"); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private void testExecute_master(CodegenTemplateTypeEnum templateType, String path) { | ||
| 84 | + // 准备参数 | ||
| 85 | + CodegenTableDO table = getTable("student") | ||
| 86 | + .setFrontType(FRONT_TYPE) | ||
| 87 | + .setTemplateType(templateType.getType()); | ||
| 88 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 89 | + // 准备参数(子表) | ||
| 90 | + CodegenTableDO contactTable = getTable("contact") | ||
| 91 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 92 | + .setFrontType(FRONT_TYPE) | ||
| 93 | + .setSubJoinColumnId(100L).setSubJoinMany(true); | ||
| 94 | + List<CodegenColumnDO> contactColumns = getColumnList("contact"); | ||
| 95 | + // 准备参数(班主任) | ||
| 96 | + CodegenTableDO teacherTable = getTable("teacher") | ||
| 97 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 98 | + .setFrontType(FRONT_TYPE) | ||
| 99 | + .setSubJoinColumnId(200L).setSubJoinMany(false); | ||
| 100 | + List<CodegenColumnDO> teacherColumns = getColumnList("teacher"); | ||
| 101 | + | ||
| 102 | + // 调用 | ||
| 103 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, | ||
| 104 | + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); | ||
| 105 | + // 断言 | ||
| 106 | + assertResult(result, path); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | +} |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVben5EleSchemaTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.service.codegen.inner; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | ||
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | ||
| 5 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | ||
| 6 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.DbType; | ||
| 8 | +import org.junit.jupiter.api.Test; | ||
| 9 | + | ||
| 10 | +import java.util.Arrays; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * {@link CodegenEngine} 的 Vue3 + Vben5 + Element Plus + Schema 单元测试 | ||
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + */ | ||
| 19 | +public class CodegenEngineVben5EleSchemaTest extends CodegenEngineAbstractTest { | ||
| 20 | + | ||
| 21 | + private static final Integer FRONT_TYPE = CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType(); | ||
| 22 | + | ||
| 23 | + @Test | ||
| 24 | + public void testExecute_one() { | ||
| 25 | + // 准备参数 | ||
| 26 | + CodegenTableDO table = getTable("student") | ||
| 27 | + .setFrontType(FRONT_TYPE) | ||
| 28 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 29 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 30 | + | ||
| 31 | + // 调用 | ||
| 32 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 33 | + // 断言 | ||
| 34 | + assertResult(result, "/vben5_ele_schema_one"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void testExecute_one_importEnable() { | ||
| 39 | + // 开启 import 开关 | ||
| 40 | + codegenProperties.setImportEnable(true); | ||
| 41 | + codegenEngine.initGlobalBindingMap(); | ||
| 42 | + // 准备参数 | ||
| 43 | + CodegenTableDO table = getTable("student") | ||
| 44 | + .setFrontType(FRONT_TYPE) | ||
| 45 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 46 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 50 | + // 断言 | ||
| 51 | + assertResult(result, "/vben5_ele_schema_one_importEnable"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 55 | + public void testExecute_tree() { | ||
| 56 | + // 准备参数 | ||
| 57 | + CodegenTableDO table = getTable("category") | ||
| 58 | + .setFrontType(FRONT_TYPE) | ||
| 59 | + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); | ||
| 60 | + List<CodegenColumnDO> columns = getColumnList("category"); | ||
| 61 | + | ||
| 62 | + // 调用 | ||
| 63 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 64 | + // 断言 | ||
| 65 | + assertResult(result, "/vben5_ele_schema_tree"); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Test | ||
| 69 | + public void testExecute_master_normal() { | ||
| 70 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "/vben5_ele_schema_master_normal"); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Test | ||
| 74 | + public void testExecute_master_erp() { | ||
| 75 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_ERP, "/vben5_ele_schema_master_erp"); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Test | ||
| 79 | + public void testExecute_master_inner() { | ||
| 80 | + testExecute_master(CodegenTemplateTypeEnum.MASTER_INNER, "/vben5_ele_schema_master_inner"); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private void testExecute_master(CodegenTemplateTypeEnum templateType, String path) { | ||
| 84 | + // 准备参数 | ||
| 85 | + CodegenTableDO table = getTable("student") | ||
| 86 | + .setFrontType(FRONT_TYPE) | ||
| 87 | + .setTemplateType(templateType.getType()); | ||
| 88 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 89 | + // 准备参数(子表) | ||
| 90 | + CodegenTableDO contactTable = getTable("contact") | ||
| 91 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 92 | + .setFrontType(FRONT_TYPE) | ||
| 93 | + .setSubJoinColumnId(100L).setSubJoinMany(true); | ||
| 94 | + List<CodegenColumnDO> contactColumns = getColumnList("contact"); | ||
| 95 | + // 准备参数(班主任) | ||
| 96 | + CodegenTableDO teacherTable = getTable("teacher") | ||
| 97 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | ||
| 98 | + .setFrontType(FRONT_TYPE) | ||
| 99 | + .setSubJoinColumnId(200L).setSubJoinMany(false); | ||
| 100 | + List<CodegenColumnDO> teacherColumns = getColumnList("teacher"); | ||
| 101 | + | ||
| 102 | + // 调用 | ||
| 103 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, | ||
| 104 | + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); | ||
| 105 | + // 断言 | ||
| 106 | + assertResult(result, path); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | +} |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java
| @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | ||
| 5 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | 5 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; |
| 6 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | 6 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; |
| 7 | import com.baomidou.mybatisplus.annotation.DbType; | 7 | import com.baomidou.mybatisplus.annotation.DbType; |
| 8 | -import org.junit.jupiter.api.Disabled; | ||
| 9 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
| 10 | 9 | ||
| 11 | import java.util.Arrays; | 10 | import java.util.Arrays; |
| @@ -17,7 +16,6 @@ import java.util.Map; | @@ -17,7 +16,6 @@ import java.util.Map; | ||
| 17 | * | 16 | * |
| 18 | * @author 芋道源码 | 17 | * @author 芋道源码 |
| 19 | */ | 18 | */ |
| 20 | -@Disabled | ||
| 21 | public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { | 19 | public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { |
| 22 | 20 | ||
| 23 | @Test | 21 | @Test |
| @@ -37,6 +35,23 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { | @@ -37,6 +35,23 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { | ||
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | @Test | 37 | @Test |
| 38 | + public void testExecute_vue2_one_importEnable() { | ||
| 39 | + // 开启 import 开关 | ||
| 40 | + codegenProperties.setImportEnable(true); | ||
| 41 | + codegenEngine.initGlobalBindingMap(); | ||
| 42 | + // 准备参数 | ||
| 43 | + CodegenTableDO table = getTable("student") | ||
| 44 | + .setFrontType(CodegenFrontTypeEnum.VUE2_ELEMENT_UI.getType()) | ||
| 45 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 46 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 50 | + // 断言 | ||
| 51 | + assertResult(result, "/vue2_one_importEnable"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 40 | public void testExecute_vue2_tree() { | 55 | public void testExecute_vue2_tree() { |
| 41 | // 准备参数 | 56 | // 准备参数 |
| 42 | CodegenTableDO table = getTable("category") | 57 | CodegenTableDO table = getTable("category") |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java
| @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | ||
| 5 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | 5 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; |
| 6 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | 6 | import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; |
| 7 | import com.baomidou.mybatisplus.annotation.DbType; | 7 | import com.baomidou.mybatisplus.annotation.DbType; |
| 8 | -import org.junit.jupiter.api.Disabled; | ||
| 9 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
| 10 | 9 | ||
| 11 | import java.util.Arrays; | 10 | import java.util.Arrays; |
| @@ -17,7 +16,6 @@ import java.util.Map; | @@ -17,7 +16,6 @@ import java.util.Map; | ||
| 17 | * | 16 | * |
| 18 | * @author 芋道源码 | 17 | * @author 芋道源码 |
| 19 | */ | 18 | */ |
| 20 | -@Disabled | ||
| 21 | public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { | 19 | public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { |
| 22 | 20 | ||
| 23 | @Test | 21 | @Test |
| @@ -37,6 +35,23 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { | @@ -37,6 +35,23 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { | ||
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | @Test | 37 | @Test |
| 38 | + public void testExecute_vue3_one_importEnable() { | ||
| 39 | + // 开启 import 开关 | ||
| 40 | + codegenProperties.setImportEnable(true); | ||
| 41 | + codegenEngine.initGlobalBindingMap(); | ||
| 42 | + // 准备参数 | ||
| 43 | + CodegenTableDO table = getTable("student") | ||
| 44 | + .setFrontType(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType()) | ||
| 45 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | ||
| 46 | + List<CodegenColumnDO> columns = getColumnList("student"); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | ||
| 50 | + // 断言 | ||
| 51 | + assertResult(result, "/vue3_one_importEnable"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 40 | public void testExecute_vue3_tree() { | 55 | public void testExecute_vue3_tree() { |
| 41 | // 准备参数 | 56 | // 准备参数 |
| 42 | CodegenTableDO table = getTable("category") | 57 | CodegenTableDO table = getTable("category") |
yudao-server/src/main/resources/application.yaml
| @@ -307,6 +307,7 @@ yudao: | @@ -307,6 +307,7 @@ yudao: | ||
| 307 | vo-type: 10 # VO 的类型,参见 CodegenVOTypeEnum 枚举类 | 307 | vo-type: 10 # VO 的类型,参见 CodegenVOTypeEnum 枚举类 |
| 308 | delete-batch-enable: true # 是否生成批量删除接口 | 308 | delete-batch-enable: true # 是否生成批量删除接口 |
| 309 | unit-test-enable: false # 是否生成单元测试 | 309 | unit-test-enable: false # 是否生成单元测试 |
| 310 | + import-enable: true # 是否生成 Excel 导入接口 | ||
| 310 | tenant: # 多租户相关配置项 | 311 | tenant: # 多租户相关配置项 |
| 311 | enable: true | 312 | enable: true |
| 312 | ignore-urls: | 313 | ignore-urls: |