Commit 60179ee6b907eaac1219b06f62ddef30911671e5
Committed by
GitHub
Merge pull request #1082 from itkdm/feat/codegen-import-detail-jdk17
feat(infra): 代码生成器为后端和 Vue3 模板添加 Excel 导入功能
Showing
9 changed files
with
256 additions
and
6 deletions
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
| @@ -72,6 +72,8 @@ public class CodegenEngine { | @@ -72,6 +72,8 @@ public class CodegenEngine { | ||
| 72 | .put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO")) | 72 | .put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO")) |
| 73 | .put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO")) | 73 | .put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO")) |
| 74 | .put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO")) | 74 | .put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO")) |
| 75 | + .put(javaTemplatePath("controller/vo/importExcelVO"), javaModuleImplVOFilePath("ImportExcelVO")) | ||
| 76 | + .put(javaTemplatePath("controller/vo/importRespVO"), javaModuleImplVOFilePath("ImportRespVO")) | ||
| 75 | .put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath()) | 77 | .put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath()) |
| 76 | .put(javaTemplatePath("dal/do"), | 78 | .put(javaTemplatePath("dal/do"), |
| 77 | javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO")) | 79 | javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO")) |
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 | +import org.springframework.web.multipart.MultipartFile; | ||
| 4 | import ${jakartaPackage}.annotation.Resource; | 5 | import ${jakartaPackage}.annotation.Resource; |
| 5 | import org.springframework.validation.annotation.Validated; | 6 | import org.springframework.validation.annotation.Validated; |
| 6 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end | 7 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end |
| @@ -160,6 +161,28 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | @@ -160,6 +161,28 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | ||
| 160 | } | 161 | } |
| 161 | #end | 162 | #end |
| 162 | 163 | ||
| 164 | + @GetMapping("/get-import-template") | ||
| 165 | + @Operation(summary = "获得导入${table.classComment}模板") | ||
| 166 | +#if ($sceneEnum.scene == 1) | ||
| 167 | + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") | ||
| 168 | +#end | ||
| 169 | + public void import${simpleClassName}Template(HttpServletResponse response) throws IOException { | ||
| 170 | + ExcelUtils.write(response, "${table.classComment}导入模板.xls", "数据", | ||
| 171 | + ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class, Collections.emptyList()); | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + @PostMapping("/import") | ||
| 175 | + @Operation(summary = "导入${table.classComment}") | ||
| 176 | + @Parameter(name = "file", description = "Excel 文件", required = true) | ||
| 177 | +#if ($sceneEnum.scene == 1) | ||
| 178 | + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") | ||
| 179 | +#end | ||
| 180 | + @ApiAccessLog(operateType = IMPORT) | ||
| 181 | + public CommonResult<${sceneEnum.prefixClass}${table.className}ImportRespVO> import${simpleClassName}(@RequestParam("file") MultipartFile file) throws Exception { | ||
| 182 | + 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)); | ||
| 184 | + } | ||
| 185 | + | ||
| 163 | ## 特殊:主子表专属逻辑 | 186 | ## 特殊:主子表专属逻辑 |
| 164 | #foreach ($subTable in $subTables) | 187 | #foreach ($subTable in $subTables) |
| 165 | #set ($index = $foreach.count - 1) | 188 | #set ($index = $foreach.count - 1) |
| @@ -268,4 +291,4 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | @@ -268,4 +291,4 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { | ||
| 268 | 291 | ||
| 269 | #end | 292 | #end |
| 270 | #end | 293 | #end |
| 271 | -} | ||
| 272 | \ No newline at end of file | 294 | \ No newline at end of file |
| 295 | +} |
yudao-module-infra/src/main/resources/codegen/java/controller/vo/importExcelVO.vm
0 → 100644
| 1 | +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; | ||
| 2 | + | ||
| 3 | +import cn.idev.excel.annotation.ExcelProperty; | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Builder; | ||
| 6 | +import lombok.Data; | ||
| 7 | +import lombok.NoArgsConstructor; | ||
| 8 | +#foreach ($column in $columns) | ||
| 9 | +#if (${column.createOperation} && "$!column.dictType" != "") | ||
| 10 | +import ${DictFormatClassName}; | ||
| 11 | +import ${DictConvertClassName}; | ||
| 12 | +#break | ||
| 13 | +#end | ||
| 14 | +#end | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * ${table.classComment} Excel 导入 VO | ||
| 18 | + */ | ||
| 19 | +@Data | ||
| 20 | +@Builder | ||
| 21 | +@AllArgsConstructor | ||
| 22 | +@NoArgsConstructor | ||
| 23 | +public class ${sceneEnum.prefixClass}${table.className}ImportExcelVO { | ||
| 24 | + | ||
| 25 | +## 逐个处理字段 | ||
| 26 | +#foreach ($column in $columns) | ||
| 27 | +#if (${column.createOperation}) | ||
| 28 | +#if ("$!column.dictType" != "") | ||
| 29 | + @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class) | ||
| 30 | + @DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 | ||
| 31 | +#else | ||
| 32 | + @ExcelProperty("${column.columnComment}") | ||
| 33 | +#end | ||
| 34 | + private ${column.javaType} ${column.javaField}; | ||
| 35 | + | ||
| 36 | +#end | ||
| 37 | +#end | ||
| 38 | +} |
yudao-module-infra/src/main/resources/codegen/java/controller/vo/importRespVO.vm
0 → 100644
| 1 | +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Builder; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import java.util.Map; | ||
| 8 | + | ||
| 9 | +@Schema(description = "${sceneEnum.name} - ${table.classComment}导入 Response VO") | ||
| 10 | +@Data | ||
| 11 | +@Builder | ||
| 12 | +public class ${sceneEnum.prefixClass}${table.className}ImportRespVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 15 | + private Integer successCount; | ||
| 16 | + | ||
| 17 | + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 18 | + private Integer failureCount; | ||
| 19 | + | ||
| 20 | + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 21 | + private Map<Integer, String> failureRows; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-infra/src/main/resources/codegen/java/service/service.vm
| @@ -27,6 +27,14 @@ public interface ${table.className}Service { | @@ -27,6 +27,14 @@ public interface ${table.className}Service { | ||
| 27 | ${primaryColumn.javaType} create${simpleClassName}(@Valid ${saveReqVOClass} ${saveReqVOVar}); | 27 | ${primaryColumn.javaType} create${simpleClassName}(@Valid ${saveReqVOClass} ${saveReqVOVar}); |
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| 30 | + * 导入${table.classComment} | ||
| 31 | + * | ||
| 32 | + * @param importList 导入信息 | ||
| 33 | + * @return 导入结果 | ||
| 34 | + */ | ||
| 35 | + ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList); | ||
| 36 | + | ||
| 37 | + /** | ||
| 30 | * 更新${table.classComment} | 38 | * 更新${table.classComment} |
| 31 | * | 39 | * |
| 32 | * @param ${updateReqVOVar} 更新信息 | 40 | * @param ${updateReqVOVar} 更新信息 |
| @@ -162,4 +170,4 @@ public interface ${table.className}Service { | @@ -162,4 +170,4 @@ public interface ${table.className}Service { | ||
| 162 | 170 | ||
| 163 | #end | 171 | #end |
| 164 | #end | 172 | #end |
| 165 | -} | ||
| 166 | \ No newline at end of file | 173 | \ No newline at end of file |
| 174 | +} |
yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm
| @@ -7,6 +7,7 @@ import org.springframework.validation.annotation.Validated; | @@ -7,6 +7,7 @@ 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 | +import java.util.concurrent.atomic.AtomicInteger; | ||
| 10 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; | 11 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; |
| 11 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; | 12 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; |
| 12 | ## 特殊:主子表专属逻辑 | 13 | ## 特殊:主子表专属逻辑 |
| @@ -93,6 +94,46 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | @@ -93,6 +94,46 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | ||
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | @Override | 96 | @Override |
| 97 | + @Transactional(rollbackFor = Exception.class) | ||
| 98 | + public ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList) { | ||
| 99 | + if (CollUtil.isEmpty(importList)) { | ||
| 100 | + return ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() | ||
| 101 | + .successCount(0) | ||
| 102 | + .failureCount(0) | ||
| 103 | + .failureRows(new LinkedHashMap<>()) | ||
| 104 | + .build(); | ||
| 105 | + } | ||
| 106 | + AtomicInteger successCount = new AtomicInteger(); | ||
| 107 | + Map<Integer, String> failureRows = new LinkedHashMap<>(); | ||
| 108 | + AtomicInteger index = new AtomicInteger(1); | ||
| 109 | + importList.forEach(importItem -> { | ||
| 110 | + int currentIndex = index.getAndIncrement(); | ||
| 111 | + try { | ||
| 112 | + create${simpleClassName}(BeanUtils.toBean(importItem, ${saveReqVOClass}.class)); | ||
| 113 | + successCount.incrementAndGet(); | ||
| 114 | + } catch (Exception ex) { | ||
| 115 | + failureRows.put(currentIndex, resolveImportFailureMessage(ex)); | ||
| 116 | + } | ||
| 117 | + }); | ||
| 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(); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + @Override | ||
| 96 | ## 特殊:主子表专属逻辑(非 ERP 模式) | 137 | ## 特殊:主子表专属逻辑(非 ERP 模式) |
| 97 | #if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) | 138 | #if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) |
| 98 | @Transactional(rollbackFor = Exception.class) | 139 | @Transactional(rollbackFor = Exception.class) |
| @@ -359,6 +400,9 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | @@ -359,6 +400,9 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | ||
| 359 | #else | 400 | #else |
| 360 | #if ( $subTable.subJoinMany) | 401 | #if ( $subTable.subJoinMany) |
| 361 | private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { | 402 | private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { |
| 403 | + if (CollUtil.isEmpty(list)) { | ||
| 404 | + return; | ||
| 405 | + } | ||
| 362 | list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean()); | 406 | list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean()); |
| 363 | ${subClassNameVars.get($index)}Mapper.insertBatch(list); | 407 | ${subClassNameVars.get($index)}Mapper.insertBatch(list); |
| 364 | } | 408 | } |
| @@ -416,4 +460,4 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | @@ -416,4 +460,4 @@ public class ${table.className}ServiceImpl implements ${table.className}Service | ||
| 416 | #end | 460 | #end |
| 417 | 461 | ||
| 418 | #end | 462 | #end |
| 419 | -} | ||
| 420 | \ No newline at end of file | 463 | \ No newline at end of file |
| 464 | +} |
yudao-module-infra/src/main/resources/codegen/sql/sql.vm
| 1 | ## 通用变量定义 | 1 | ## 通用变量定义 |
| 2 | -#set ($functionNames = ['查询', '创建', '更新', '删除', '导出']) | ||
| 3 | -#set ($functionOps = ['query', 'create', 'update', 'delete', 'export']) | 2 | +#set ($functionNames = ['查询', '创建', '更新', '删除', '导出', '导入']) |
| 3 | +#set ($functionOps = ['query', 'create', 'update', 'delete', 'export', 'import']) | ||
| 4 | ## | 4 | ## |
| 5 | ## 宏定义:生成按钮 SQL(通用部分) | 5 | ## 宏定义:生成按钮 SQL(通用部分) |
| 6 | #macro(insertButtonSql $parentIdVar) | 6 | #macro(insertButtonSql $parentIdVar) |
yudao-module-infra/src/main/resources/codegen/vue3/api/api.ts.vm
| @@ -98,6 +98,16 @@ export const ${simpleClassName}Api = { | @@ -98,6 +98,16 @@ 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 | + | ||
| 102 | + // 下载${table.classComment}导入模板 | ||
| 103 | + import${simpleClassName}Template: async () => { | ||
| 104 | + return await request.download({ url: `${baseURL}/get-import-template` }) | ||
| 105 | + }, | ||
| 106 | + | ||
| 107 | + // 导入${table.classComment} | ||
| 108 | + import${simpleClassName}: async (data: FormData) => { | ||
| 109 | + return await request.upload({ url: `${baseURL}/import`, data }) | ||
| 110 | + }, | ||
| 101 | ## 特殊:主子表专属逻辑 | 111 | ## 特殊:主子表专属逻辑 |
| 102 | #foreach ($subTable in $subTables) | 112 | #foreach ($subTable in $subTables) |
| 103 | #set ($index = $foreach.count - 1) | 113 | #set ($index = $foreach.count - 1) |
yudao-module-infra/src/main/resources/codegen/vue3/views/index.vue.vm
| @@ -93,6 +93,14 @@ | @@ -93,6 +93,14 @@ | ||
| 93 | <Icon icon="ep:plus" class="mr-5px" /> 新增 | 93 | <Icon icon="ep:plus" class="mr-5px" /> 新增 |
| 94 | </el-button> | 94 | </el-button> |
| 95 | <el-button | 95 | <el-button |
| 96 | + type="warning" | ||
| 97 | + plain | ||
| 98 | + @click="handleImport" | ||
| 99 | + v-hasPermi="['${permissionPrefix}:import']" | ||
| 100 | + > | ||
| 101 | + <Icon icon="ep:upload" class="mr-5px" /> 导入 | ||
| 102 | + </el-button> | ||
| 103 | + <el-button | ||
| 96 | type="success" | 104 | type="success" |
| 97 | plain | 105 | plain |
| 98 | @click="handleExport" | 106 | @click="handleExport" |
| @@ -238,6 +246,43 @@ | @@ -238,6 +246,43 @@ | ||
| 238 | /> | 246 | /> |
| 239 | </ContentWrap> | 247 | </ContentWrap> |
| 240 | 248 | ||
| 249 | + <!-- 导入弹窗 --> | ||
| 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> | ||
| 285 | + | ||
| 241 | <!-- 表单弹窗:添加/修改 --> | 286 | <!-- 表单弹窗:添加/修改 --> |
| 242 | <${simpleClassName}Form ref="formRef" @success="getList" /> | 287 | <${simpleClassName}Form ref="formRef" @success="getList" /> |
| 243 | ## 特殊:主子表专属逻辑 | 288 | ## 特殊:主子表专属逻辑 |
| @@ -263,6 +308,7 @@ | @@ -263,6 +308,7 @@ | ||
| 263 | import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' | 308 | import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' |
| 264 | import { isEmpty } from '@/utils/is' | 309 | import { isEmpty } from '@/utils/is' |
| 265 | import { dateFormatter } from '@/utils/formatTime' | 310 | import { dateFormatter } from '@/utils/formatTime' |
| 311 | +import type { UploadUserFile } from 'element-plus' | ||
| 266 | ## 特殊:树表专属逻辑 | 312 | ## 特殊:树表专属逻辑 |
| 267 | #if ( $table.templateType == 2 ) | 313 | #if ( $table.templateType == 2 ) |
| 268 | import { handleTree } from '@/utils/tree' | 314 | import { handleTree } from '@/utils/tree' |
| @@ -308,6 +354,10 @@ const queryParams = reactive({ | @@ -308,6 +354,10 @@ const queryParams = reactive({ | ||
| 308 | }) | 354 | }) |
| 309 | const queryFormRef = ref() // 搜索的表单 | 355 | const queryFormRef = ref() // 搜索的表单 |
| 310 | const exportLoading = ref(false) // 导出的加载中 | 356 | const exportLoading = ref(false) // 导出的加载中 |
| 357 | +const importDialogVisible = ref(false) // 导入弹窗 | ||
| 358 | +const importFormLoading = ref(false) // 导入的加载中 | ||
| 359 | +const uploadRef = ref() | ||
| 360 | +const fileList = ref<UploadUserFile[]>([]) | ||
| 311 | 361 | ||
| 312 | /** 查询列表 */ | 362 | /** 查询列表 */ |
| 313 | const getList = async () => { | 363 | const getList = async () => { |
| @@ -345,6 +395,58 @@ const openForm = (type: string, id?: number) => { | @@ -345,6 +395,58 @@ const openForm = (type: string, id?: number) => { | ||
| 345 | formRef.value.open(type, id) | 395 | formRef.value.open(type, id) |
| 346 | } | 396 | } |
| 347 | 397 | ||
| 398 | +/** 导入按钮操作 */ | ||
| 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() | ||
| 448 | +} | ||
| 449 | + | ||
| 348 | /** 删除按钮操作 */ | 450 | /** 删除按钮操作 */ |
| 349 | const handleDelete = async (id: number) => { | 451 | const handleDelete = async (id: number) => { |
| 350 | try { | 452 | try { |
| @@ -421,4 +523,4 @@ const toggleExpandAll = async () => { | @@ -421,4 +523,4 @@ const toggleExpandAll = async () => { | ||
| 421 | onMounted(() => { | 523 | onMounted(() => { |
| 422 | getList() | 524 | getList() |
| 423 | }) | 525 | }) |
| 424 | -</script> | ||
| 425 | \ No newline at end of file | 526 | \ No newline at end of file |
| 527 | +</script> |