xuzhancheng hace 5 días
padre
commit
4c50ac6de4

+ 22 - 1
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/controller/admin/dynamictb/DynamicTbController.java

@@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
 import cn.start.tz.module.pressure2.controller.admin.reporttemplate.vo.ReportTemplateRespVO;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 import jakarta.annotation.Resource;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -370,7 +371,27 @@ public class DynamicTbController {
         return success(msg);
     }
 
+    @PostMapping("/export-zip")
+    @Operation(summary = "导出模板数据为 ZIP 压缩包")
+//    @PreAuthorize("@ss.hasPermission('pressure2:dynamic-tb:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportZip(@Valid @RequestBody DynamicTbExportReqVO reqVO,
+                          HttpServletResponse response) throws Exception {
+        byte[] zipBytes = dynamicTbService.exportZip(reqVO.getIds());
+        // 设置响应头,返回 zip 文件
+        response.setContentType("application/zip");
+        response.setHeader("Content-Disposition", "attachment; filename=\"dynamic_tb_export.zip\"");
+        response.getOutputStream().write(zipBytes);
+        response.getOutputStream().flush();
+    }
 
-
+    @PostMapping("/import-zip")
+    @Operation(summary = "从 ZIP 压缩包导入模板数据")
+//    @PreAuthorize("@ss.hasPermission('pressure2:dynamic-tb:import')")
+    @ApiAccessLog(operateType = IMPORT)
+    public CommonResult<Boolean> importZip(@RequestParam("file") MultipartFile file) throws Exception {
+        dynamicTbService.importZip(file.getBytes());
+        return success(true);
+    }
 
 }

+ 21 - 0
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/controller/admin/dynamictb/vo/DynamicTbExportReqVO.java

@@ -0,0 +1,21 @@
+package cn.start.tz.module.pressure2.controller.admin.dynamictb.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 承压动态报表表单 - 导出请求 VO
+ *
+ * @author 自动生成
+ */
+@Schema(description = "管理后台 - 承压动态报表表单导出 Request VO")
+@Data
+public class DynamicTbExportReqVO {
+
+    @Schema(description = "要导出的模板ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "请选择要导出的模板")
+    private List<String> ids;
+}

+ 1 - 1
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/controller/admin/dynamictb/vo/DynamicTbSaveReqVO.java

@@ -53,5 +53,5 @@ public class DynamicTbSaveReqVO {
     private List<FileRepsDTO> filePaths;
 
     @Schema(description = "复制续页配置")
-    private String copyConfig;
+    private Object copyConfig;
 }

+ 15 - 0
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/service/dynamictb/DynamicTbService.java

@@ -101,4 +101,19 @@ public interface DynamicTbService extends IService<DynamicTbDO>  {
      * 获取流转列表
      */
     List<BpmTaskRespVO> circulationRecord(String id);
+
+    /**
+     * 导出模板数据为 zip 压缩包
+     *
+     * @param ids 模板ID列表
+     * @return zip 文件字节数组
+     */
+    byte[] exportZip(List<String> ids) throws Exception;
+
+    /**
+     * 从 zip 压缩包导入模板数据
+     *
+     * @param zipBytes zip 文件字节数组
+     */
+    void importZip(byte[] zipBytes) throws Exception;
 }

+ 165 - 0
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/service/dynamictb/DynamicTbServiceImpl.java

@@ -40,13 +40,26 @@ import java.util.stream.Collectors;
 import cn.start.tz.module.pressure2.controller.admin.dynamictb.vo.*;
 import cn.start.tz.module.pressure2.controller.admin.dynamictbaudit.vo.*;
 import cn.start.tz.module.pressure2.dal.dataobject.dynamictb.DynamicTbDO;
+import cn.start.tz.module.pressure2.dal.dataobject.dynamictbcol.DynamicTbColDO;
+import cn.start.tz.module.pressure2.dal.dataobject.standardfile.StandardTemplateDO;
 import cn.start.tz.framework.common.pojo.PageResult;
 import cn.start.tz.framework.common.pojo.PageParam;
 import cn.start.tz.framework.common.util.object.BeanUtils;
 
 import cn.start.tz.module.pressure2.dal.mysql.dynamictb.DynamicTbMapper;
+import cn.start.tz.module.pressure2.dal.mysql.dynamictbcol.DynamicTbColMapper;
+import cn.start.tz.module.pressure2.dal.mysql.standardfile.StandardTemplateMapper;
+
+import com.alibaba.fastjson2.JSON;
 import lombok.extern.slf4j.Slf4j;
 
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
 import static cn.start.tz.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.start.tz.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static cn.start.tz.module.pressure2.enums.ErrorCodeConstants.*;
@@ -76,6 +89,10 @@ public class DynamicTbServiceImpl extends ServiceImpl<DynamicTbMapper, DynamicTb
     @Resource
     private DynamicTbFileMapper dynamicTbFileMapper;
     @Resource
+    private DynamicTbColMapper dynamicTbColMapper;
+    @Resource
+    private StandardTemplateMapper standardTemplateMapper;
+    @Resource
     private FileApi fileApi;
 
     @Override
@@ -95,6 +112,11 @@ public class DynamicTbServiceImpl extends ServiceImpl<DynamicTbMapper, DynamicTb
         validateDynamicTbExists(updateReqVO.getId());
         // 校验tbCode唯一性(排除自身)
         validateTbCodeUnique(updateReqVO.getTbCode(), updateReqVO.getId());
+        // 对象类型转字符串
+        if (updateReqVO.getCopyConfig() instanceof com.alibaba.fastjson2.JSONObject){
+            updateReqVO.setCopyConfig(JSON.toJSONString(updateReqVO.getCopyConfig()));
+        }
+
         // 更新
         DynamicTbDO updateObj = BeanUtils.toBean(updateReqVO, DynamicTbDO.class);
         dynamicTbMapper.updateById(updateObj);
@@ -435,6 +457,149 @@ public class DynamicTbServiceImpl extends ServiceImpl<DynamicTbMapper, DynamicTb
         return list;
     }
 
+    // ==================== 导入导出 ====================
+
+    @Override
+    public byte[] exportZip(List<String> ids) throws Exception {
+        // 1. 查询所有要导出的 DynamicTbDO
+        List<DynamicTbDO> tbList = dynamicTbMapper.selectBatchIds(ids);
+        if (CollUtil.isEmpty(tbList)) {
+            throw exception(DYNAMIC_TB_NOT_EXISTS);
+        }
+
+        // 2. 查询所有关联的 DynamicTbColDO
+        List<DynamicTbColDO> allCols = new ArrayList<>();
+        for (DynamicTbDO tb : tbList) {
+            List<DynamicTbColDO> cols = dynamicTbColMapper.selectList(
+                    new LambdaQueryWrapperX<DynamicTbColDO>().eq(DynamicTbColDO::getTbId, tb.getId()));
+            allCols.addAll(cols);
+        }
+
+        // 3. 查询所有关联的 StandardTemplateDO(id 与 DynamicTbDO.id 相同)
+        List<String> templateIds = tbList.stream().map(DynamicTbDO::getId).toList();
+        List<StandardTemplateDO> templates = new ArrayList<>();
+        if (!templateIds.isEmpty()) {
+            templates = standardTemplateMapper.selectBatchIds(templateIds);
+        }
+
+        // 4. 创建 zip
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (ZipOutputStream zipOut = new ZipOutputStream(baos)) {
+
+            // 写入 tb_data.json
+            zipOut.putNextEntry(new ZipEntry("tb_data.json"));
+            zipOut.write(JSON.toJSONBytes(tbList));
+            zipOut.closeEntry();
+
+            // 写入 col_data.json
+            zipOut.putNextEntry(new ZipEntry("col_data.json"));
+            zipOut.write(JSON.toJSONBytes(allCols));
+            zipOut.closeEntry();
+
+            // 写入 template_data.json
+            zipOut.putNextEntry(new ZipEntry("template_data.json"));
+            zipOut.write(JSON.toJSONBytes(templates));
+            zipOut.closeEntry();
+
+            // 写入模板文件(从 fileUrl 下载文件内容)
+            for (StandardTemplateDO template : templates) {
+                if (StrUtil.isNotEmpty(template.getFileUrl())) {
+                    try {
+                        byte[] fileBytes = fileApi.getFileByPath(template.getFileUrl()).getCheckedData();
+                        if (fileBytes != null && fileBytes.length > 0) {
+                            // 文件名使用模板ID+原始文件名后缀
+                            String entryName = "files/" + template.getId();
+                            zipOut.putNextEntry(new ZipEntry(entryName));
+                            zipOut.write(fileBytes);
+                            zipOut.closeEntry();
+                        }
+                    } catch (Exception e) {
+                        log.warn("导出模板文件失败, templateId={}, fileUrl={}", template.getId(), template.getFileUrl(), e);
+                    }
+                }
+            }
+
+            zipOut.finish();
+        }
 
+        return baos.toByteArray();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void importZip(byte[] zipBytes) throws Exception {
+        List<DynamicTbDO> tbList = new ArrayList<>();
+        List<DynamicTbColDO> colList = new ArrayList<>();
+        List<StandardTemplateDO> templateList = new ArrayList<>();
+        // 文件数据: templateId -> fileBytes
+        Map<String, byte[]> fileMap = new HashMap<>();
+
+        // 1. 解析 zip 包
+        try (ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(zipBytes))) {
+            ZipEntry entry;
+            while ((entry = zipIn.getNextEntry()) != null) {
+                String entryName = entry.getName();
+                byte[] entryBytes = zipIn.readAllBytes();
+
+                if ("tb_data.json".equals(entryName)) {
+                    tbList = JSON.parseArray(new String(entryBytes, StandardCharsets.UTF_8), DynamicTbDO.class);
+                } else if ("col_data.json".equals(entryName)) {
+                    colList = JSON.parseArray(new String(entryBytes, StandardCharsets.UTF_8), DynamicTbColDO.class);
+                } else if ("template_data.json".equals(entryName)) {
+                    templateList = JSON.parseArray(new String(entryBytes, StandardCharsets.UTF_8), StandardTemplateDO.class);
+                } else if (entryName.startsWith("files/")) {
+                    // 提取模板ID作为文件名
+                    String templateId = entryName.substring("files/".length());
+                    fileMap.put(templateId, entryBytes);
+                }
+                zipIn.closeEntry();
+            }
+        }
+
+        // 2. 导入 DynamicTbDO(通过 tbCode 判断新增还是更新)
+        for (DynamicTbDO tbDO : tbList) {
+            // 通过 tbCode 查找是否已存在
+            DynamicTbDO existing = dynamicTbMapper.selectOne(
+                    new LambdaQueryWrapperX<DynamicTbDO>().eq(DynamicTbDO::getTbCode, tbDO.getTbCode()));
+            if (existing != null) {
+                // 更新:保留原有ID
+                tbDO.setId(existing.getId());
+                dynamicTbMapper.updateById(tbDO);
+            } else {
+                // 新增:使用导出的ID
+                dynamicTbMapper.insert(tbDO);
+            }
+        }
+
+        // 3. 导入 DynamicTbColDO(先删后插)
+        for (DynamicTbDO tbDO : tbList) {
+            // 删除原有的列定义
+            dynamicTbColMapper.delete(new LambdaQueryWrapperX<DynamicTbColDO>()
+                    .eq(DynamicTbColDO::getTbId, tbDO.getId()));
+        }
+        // 批量插入列定义
+        for (DynamicTbColDO colDO : colList) {
+            if (colDO.getTbId() != null) {
+                dynamicTbColMapper.insert(colDO);
+            }
+        }
+
+        // 4. 导入 StandardTemplateDO
+        for (StandardTemplateDO templateDO : templateList) {
+            // 上传文件获取新的 fileUrl
+            byte[] fileBytes = fileMap.get(templateDO.getId());
+            if (fileBytes != null && fileBytes.length > 0) {
+                String newFileUrl = fileApi.createFile(fileBytes);
+                templateDO.setFileUrl(newFileUrl);
+            }
+
+            StandardTemplateDO existingTemplate = standardTemplateMapper.selectById(templateDO.getId());
+            if (existingTemplate != null) {
+                standardTemplateMapper.updateById(templateDO);
+            } else {
+                standardTemplateMapper.insert(templateDO);
+            }
+        }
+    }
 
 }