diff --git a/1-sql/2026-02-10/simulation_task.sql b/1-sql/2026-02-10/simulation_task.sql new file mode 100644 index 00000000..06f65c09 --- /dev/null +++ b/1-sql/2026-02-10/simulation_task.sql @@ -0,0 +1,2 @@ +ALTER TABLE spdm_baseline.simulation_task ADD reportTemplate varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '报告模板uuid'; +ALTER TABLE spdm_baseline.simulation_task ADD reportContent mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '报告模板填充内容'; diff --git a/common/src/main/java/com/sdm/common/entity/req/project/EditReportReq.java b/common/src/main/java/com/sdm/common/entity/req/project/EditReportReq.java index 1ea2305b..52a18e05 100644 --- a/common/src/main/java/com/sdm/common/entity/req/project/EditReportReq.java +++ b/common/src/main/java/com/sdm/common/entity/req/project/EditReportReq.java @@ -1,18 +1,25 @@ package com.sdm.common.entity.req.project; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data public class EditReportReq { + @Schema(description= "算例uuid") private String runId; + @Schema(description= "报告模板uuid") private String reportTemplate; + @Schema(description= "报告模板内容") private String reportContent; + @Schema(description= "任务uuid") + private String taskId; + } \ No newline at end of file diff --git a/common/src/main/java/com/sdm/common/entity/resp/project/SpdmTaskVo.java b/common/src/main/java/com/sdm/common/entity/resp/project/SpdmTaskVo.java index 67463d12..dc77c667 100644 --- a/common/src/main/java/com/sdm/common/entity/resp/project/SpdmTaskVo.java +++ b/common/src/main/java/com/sdm/common/entity/resp/project/SpdmTaskVo.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.sdm.common.entity.pojo.BaseEntity; import com.sdm.common.entity.resp.system.CIDUserResp; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @@ -224,4 +225,10 @@ public class SpdmTaskVo extends BaseEntity { */ private String eUserId; + @Schema(description= "报告模板内容") + private String reportContent; + + @Schema(description= "任务uuid") + private String taskId; + } diff --git a/project/src/main/java/com/sdm/project/model/entity/SimulationTask.java b/project/src/main/java/com/sdm/project/model/entity/SimulationTask.java index 28bb6b7e..0a36011d 100644 --- a/project/src/main/java/com/sdm/project/model/entity/SimulationTask.java +++ b/project/src/main/java/com/sdm/project/model/entity/SimulationTask.java @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import java.io.Serializable; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -210,5 +211,13 @@ public class SimulationTask implements Serializable { @TableField("discipline") private String discipline; + @Schema(description= "报告模板uuid") + @TableField("reportTemplate") + private String reportTemplate; + + @Schema(description= "报告模板填充内容") + @TableField("reportContent") + private String reportContent; + } diff --git a/project/src/main/java/com/sdm/project/service/impl/SimulationRunServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/SimulationRunServiceImpl.java index 6562e59f..684c7180 100644 --- a/project/src/main/java/com/sdm/project/service/impl/SimulationRunServiceImpl.java +++ b/project/src/main/java/com/sdm/project/service/impl/SimulationRunServiceImpl.java @@ -915,6 +915,7 @@ public class SimulationRunServiceImpl extends ServiceImpl reportResponse = reportFeignClient.queryReportTemplateInfo(req.getReportTemplate()); - if (reportResponse.isSuccess()) { - Long reportTemplateFileId = reportResponse.getData().getFileId(); - // 获取报告模板名称 - GetFileBaseInfoReq getFileBaseInfoReq = new GetFileBaseInfoReq(); - getFileBaseInfoReq.setFileId(reportTemplateFileId); - SdmResponse fileBaseInfoResp = dataFeignClient.getFileBaseInfo(getFileBaseInfoReq); - String originalName = fileBaseInfoResp.getData().getOriginalName(); - // 下载到本地临时目录 - dataFeignClient.downloadFileToLocal(reportTemplateFileId, TEMP_REPORT_PATH + randomId); + String randomId = RandomUtil.generateString(16); + // 创建临时文件夹 + Path folder = Paths.get(TEMP_REPORT_PATH + randomId); + if (!Files.exists(folder) || !Files.isDirectory(folder)) { + if (!new File(TEMP_REPORT_PATH + randomId).mkdir()) { + log.error("创建临时文件夹:{}失败",TEMP_REPORT_PATH + randomId); + throw new RuntimeException("生成报告失败,原因为:创建临时文件夹失败"); + } + } + log.info("临时路径为:{}", randomId); - // 构建python命令 - List command = new ArrayList<>(); - command.add("python"); - command.add("/opt/script/modifyReport.py"); + // 根据文件id下载文件到临时目录 + SdmResponse reportResponse = reportFeignClient.queryReportTemplateInfo(req.getReportTemplate()); + if (reportResponse.isSuccess()) { + Long reportTemplateFileId = reportResponse.getData().getFileId(); + // 获取报告模板名称 + GetFileBaseInfoReq getFileBaseInfoReq = new GetFileBaseInfoReq(); + getFileBaseInfoReq.setFileId(reportTemplateFileId); + SdmResponse fileBaseInfoResp = dataFeignClient.getFileBaseInfo(getFileBaseInfoReq); + String originalName = fileBaseInfoResp.getData().getOriginalName(); + // 下载到本地临时目录 + dataFeignClient.downloadFileToLocal(reportTemplateFileId, TEMP_REPORT_PATH + randomId); + + // 构建python命令 + List command = new ArrayList<>(); + command.add("python"); + command.add("/opt/script/modifyReport.py"); // command.add(TEMP_REPORT_PATH + File.separator +"modifyReport.py"); - command.add(TEMP_REPORT_PATH + randomId); - command.add(TEMP_REPORT_PATH + randomId + File.separator + originalName); - String commands = String.join(" ", command); + command.add(TEMP_REPORT_PATH + randomId); + command.add(TEMP_REPORT_PATH + randomId + File.separator + originalName); + String commands = String.join(" ", command); - // 前端参数写入临时目录 - FileOutputStream projectInfoOutputStream = null; - try { - projectInfoOutputStream = new FileOutputStream(TEMP_REPORT_PATH + randomId + File.separator + "reportContent.json"); - projectInfoOutputStream.write(reportContent.getBytes(StandardCharsets.UTF_8)); - projectInfoOutputStream.flush(); - projectInfoOutputStream.close(); - } catch (Exception e) { - throw new RuntimeException(e); + // 前端参数写入临时目录 + FileOutputStream projectInfoOutputStream = null; + try { + projectInfoOutputStream = new FileOutputStream(TEMP_REPORT_PATH + randomId + File.separator + "reportContent.json"); + projectInfoOutputStream.write(reportContent.getBytes(StandardCharsets.UTF_8)); + projectInfoOutputStream.flush(); + projectInfoOutputStream.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + // 调用脚本 + log.info("执行 Python 命令: {}", commands); + int runningStatus = -1; + try { + log.info("开始同步执行脚本"); + Process process = Runtime.getRuntime().exec(commands); + log.info("开始获取脚本输出"); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + log.info("executePython:" + line); } + log.info("脚本执行完成"); + runningStatus = process.waitFor(); + log.info("脚本运行状态:" + runningStatus); + } catch (IOException | InterruptedException e) { + log.error("执行脚本失败:" + e); + return SdmResponse.failed("执行脚本失败"); + } + if (runningStatus != 0) { + log.error("执行脚本失败"); + return SdmResponse.failed("执行脚本失败"); + } else { + log.info(commands + "执行脚本完成!"); + } + byte[] fileData = null; + try { + // 获取临时路径中脚本生成的报告 + String reportName = "report_" + + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + + ".docx"; + FileInputStream fileInputStream = new FileInputStream(TEMP_REPORT_PATH + randomId + File.separator + reportName); + fileData = fileInputStream.readAllBytes(); - // 调用脚本 - log.info("执行 Python 命令: {}", commands); - int runningStatus = -1; - try { - log.info("开始同步执行脚本"); - Process process = Runtime.getRuntime().exec(commands); - log.info("开始获取脚本输出"); - BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - String line; - while ((line = reader.readLine()) != null) { - log.info("executePython:" + line); + // 创建临时MultipartFile + MockMultipartFile multipartFile = new MockMultipartFile( + reportName, + reportName, + "application/json", + fileData); + if (StringUtils.isNotEmpty(req.getTaskId())) { + // 上传到任务下的交付物文件夹的报告文件夹下 + Long parentId = getParentDirId(req.getTaskId(), FileBizTypeEnum.REPORT_FILE.getDirName()); + UploadFilesReq filesReq = new UploadFilesReq(); + filesReq.setFile(multipartFile); + filesReq.setFileName(reportName); + filesReq.setFileType(FileBizTypeEnum.REPORT_FILE.getValue()); + filesReq.setUuid(null); + filesReq.setDirId(parentId); + SdmResponse sdmResponse = uploadKeyResultFiles(filesReq); + if (!sdmResponse.isSuccess()) { + throw new RuntimeException("生成自动化报告上传任务报告结果目录失败"); } - log.info("脚本执行完成"); - runningStatus = process.waitFor(); - log.info("脚本运行状态:" + runningStatus); - } catch (IOException | InterruptedException e) { - log.error("执行脚本失败:" + e); - return SdmResponse.failed("执行脚本失败"); - } - if (runningStatus != 0) { - log.error("执行脚本失败"); - return SdmResponse.failed("执行脚本失败"); } else { - log.info(commands + "执行脚本完成!"); + // 上传到算例下的报告文件夹下 + KeyResultReq resultReq = new KeyResultReq(); + resultReq.setKeyResultType(KeyResultTypeEnum.DOCUMENT.getKeyResultType()); + resultReq.setRunId(req.getRunId()); + resultReq.setName(reportName); + + resultReq.setFile(multipartFile); + resultReq.setFileName(reportName); + resultReq.setFileType(FileBizTypeEnum.REPORT_FILE.getValue()); + SdmResponse sdmResponse = addSimulationKeyResult(resultReq); + if (!sdmResponse.isSuccess()) { + throw new RuntimeException("生成自动化报告上传算例报告结果目录失败"); + } } - byte[] fileData = null; + + fileInputStream.close(); + // 删除临时路径 + log.info("删除临时路径:{},中。。。。。。", randomId); + deleteFolder(new File(TEMP_REPORT_PATH + randomId)); + return SdmResponse.success(); + } catch (Exception ex) { + log.error("生成自动化报告失败:{}", ex.getMessage()); + throw new RuntimeException("生成自动化报告失败"); + } + } + return SdmResponse.failed("生成自动化报告失败"); + } + + @Override + public void editReportAndDownload(EditReportReq req, HttpServletResponse response) { + log.info("编辑报告参数为:{}", req); + String reportContent = req.getReportContent(); + if (StringUtils.isNotEmpty(req.getTaskId())) { + SimulationTask simulationTask = simulationTaskService.lambdaQuery().eq(SimulationTask::getUuid, req.getTaskId()).one(); + if (simulationTask != null) { + // 任务绑定报告模板 + simulationTask.setReportTemplate(req.getReportTemplate()); + simulationTask.setReportContent(reportContent); + simulationTaskService.updateById(simulationTask); + } + } else { + SimulationRun simulationRun = this.lambdaQuery().eq(SimulationRun::getUuid, req.getRunId()).one(); + if (simulationRun != null) { + // 算例绑定报告模板 + simulationRun.setReportTemplate(req.getReportTemplate()); + simulationRun.setReportContent(reportContent); + this.updateById(simulationRun); + } + } + + String randomId = RandomUtil.generateString(16); + // 创建临时文件夹 + Path folder = Paths.get(TEMP_REPORT_PATH + randomId); + if (!Files.exists(folder) || !Files.isDirectory(folder)) { + if (!new File(TEMP_REPORT_PATH + randomId).mkdir()) { + log.error("创建临时文件夹:{}失败",TEMP_REPORT_PATH + randomId); + throw new RuntimeException("生成报告失败,原因为:创建临时文件夹失败"); + } + } + log.info("临时路径为:{}", randomId); + + // 根据文件id下载文件到临时目录 + SdmResponse reportResponse = reportFeignClient.queryReportTemplateInfo(req.getReportTemplate()); + if (reportResponse.isSuccess()) { + Long reportTemplateFileId = reportResponse.getData().getFileId(); + // 获取报告模板名称 + GetFileBaseInfoReq getFileBaseInfoReq = new GetFileBaseInfoReq(); + getFileBaseInfoReq.setFileId(reportTemplateFileId); + SdmResponse fileBaseInfoResp = dataFeignClient.getFileBaseInfo(getFileBaseInfoReq); + String originalName = fileBaseInfoResp.getData().getOriginalName(); + // 下载到本地临时目录 + dataFeignClient.downloadFileToLocal(reportTemplateFileId, TEMP_REPORT_PATH + randomId); + + // 构建python命令 + List command = new ArrayList<>(); + command.add("python"); + command.add("/opt/script/modifyReport.py"); +// command.add(TEMP_REPORT_PATH + File.separator +"modifyReport.py"); + command.add(TEMP_REPORT_PATH + randomId); + command.add(TEMP_REPORT_PATH + randomId + File.separator + originalName); + String commands = String.join(" ", command); + + // 前端参数写入临时目录 + FileOutputStream projectInfoOutputStream = null; + try { + projectInfoOutputStream = new FileOutputStream(TEMP_REPORT_PATH + randomId + File.separator + "reportContent.json"); + projectInfoOutputStream.write(reportContent.getBytes(StandardCharsets.UTF_8)); + projectInfoOutputStream.flush(); + projectInfoOutputStream.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + // 调用脚本 + log.info("执行 Python 命令: {}", commands); + int runningStatus = -1; + try { + log.info("开始同步执行脚本"); + Process process = Runtime.getRuntime().exec(commands); + log.info("开始获取脚本输出"); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + log.info("executePython:" + line); + } + log.info("脚本执行完成"); + runningStatus = process.waitFor(); + log.info("脚本运行状态:" + runningStatus); + } catch (IOException | InterruptedException e) { + log.error("执行脚本失败:" + e); + return; + } + if (runningStatus != 0) { + log.error("执行脚本失败"); + return; + } else { + log.info(commands + "执行脚本完成!"); + } + byte[] fileData = null; + if (response != null) { try { // 获取临时路径中脚本生成的报告 String reportName = "report_" + @@ -1711,166 +1871,60 @@ public class SimulationRunServiceImpl extends ServiceImpl reportResponse = reportFeignClient.queryReportTemplateInfo(req.getReportTemplate()); - if (reportResponse.isSuccess()) { - Long reportTemplateFileId = reportResponse.getData().getFileId(); - // 获取报告模板名称 - GetFileBaseInfoReq getFileBaseInfoReq = new GetFileBaseInfoReq(); - getFileBaseInfoReq.setFileId(reportTemplateFileId); - SdmResponse fileBaseInfoResp = dataFeignClient.getFileBaseInfo(getFileBaseInfoReq); - String originalName = fileBaseInfoResp.getData().getOriginalName(); - // 下载到本地临时目录 - dataFeignClient.downloadFileToLocal(reportTemplateFileId, TEMP_REPORT_PATH + randomId); - - // 构建python命令 - List command = new ArrayList<>(); - command.add("python"); - command.add("/opt/script/modifyReport.py"); -// command.add(TEMP_REPORT_PATH + File.separator +"modifyReport.py"); - command.add(TEMP_REPORT_PATH + randomId); - command.add(TEMP_REPORT_PATH + randomId + File.separator + originalName); - String commands = String.join(" ", command); - - // 前端参数写入临时目录 - FileOutputStream projectInfoOutputStream = null; - try { - projectInfoOutputStream = new FileOutputStream(TEMP_REPORT_PATH + randomId + File.separator + "reportContent.json"); - projectInfoOutputStream.write(reportContent.getBytes(StandardCharsets.UTF_8)); - projectInfoOutputStream.flush(); - projectInfoOutputStream.close(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - // 调用脚本 - log.info("执行 Python 命令: {}", commands); - int runningStatus = -1; - try { - log.info("开始同步执行脚本"); - Process process = Runtime.getRuntime().exec(commands); - log.info("开始获取脚本输出"); - BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - String line; - while ((line = reader.readLine()) != null) { - log.info("executePython:" + line); - } - log.info("脚本执行完成"); - runningStatus = process.waitFor(); - log.info("脚本运行状态:" + runningStatus); - } catch (IOException | InterruptedException e) { - log.error("执行脚本失败:" + e); - return; - } - if (runningStatus != 0) { - log.error("执行脚本失败"); - return; - } else { - log.info(commands + "执行脚本完成!"); - } - byte[] fileData = null; - if (response != null) { - try { - // 获取临时路径中脚本生成的报告 - String reportName = "report_" + - LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + - ".docx"; - FileInputStream fileInputStream = new FileInputStream(TEMP_REPORT_PATH + randomId + File.separator + reportName); - fileData = fileInputStream.readAllBytes(); - + if (StringUtils.isNotEmpty(req.getTaskId())) { + // 上传到任务下的交付物文件夹的报告文件夹下 + Long parentId = getParentDirId(req.getTaskId(), FileBizTypeEnum.REPORT_FILE.getDirName()); + UploadFilesReq filesReq = new UploadFilesReq(); + filesReq.setFile(multipartFile); + filesReq.setFileName(reportName); + filesReq.setFileType(FileBizTypeEnum.REPORT_FILE.getValue()); + filesReq.setUuid(null); + filesReq.setDirId(parentId); + SdmResponse sdmResponse = uploadKeyResultFiles(filesReq); + if (!sdmResponse.isSuccess()) { + throw new RuntimeException("生成自动化报告上传任务报告结果目录失败"); + } + } else { // 上传到算例下的报告文件夹下 KeyResultReq resultReq = new KeyResultReq(); resultReq.setKeyResultType(KeyResultTypeEnum.DOCUMENT.getKeyResultType()); resultReq.setRunId(req.getRunId()); resultReq.setName(reportName); - // 创建临时MultipartFile - MockMultipartFile multipartFile = new MockMultipartFile( - reportName, - reportName, - "application/json", - fileData); + resultReq.setFile(multipartFile); resultReq.setFileName(reportName); resultReq.setFileType(FileBizTypeEnum.REPORT_FILE.getValue()); SdmResponse sdmResponse = addSimulationKeyResult(resultReq); if (!sdmResponse.isSuccess()) { - throw new RuntimeException("生成自动化报告上传报告结果目录失败"); + throw new RuntimeException("生成自动化报告上传算例报告结果目录失败"); } - - // 下载到本地 - // 设置响应头 - response.reset(); - response.setContentType("application/octet-stream;charset=UTF-8"); - response.addHeader("Content-Length", String.valueOf(fileData.length)); - // 写入响应流 - OutputStream outputStream = response.getOutputStream(); - outputStream.write(fileData); - outputStream.flush(); - outputStream.close(); - fileInputStream.close(); - } catch (Exception ex) { - log.error("生成自动化报告失败:{}", ex.getMessage()); - throw new RuntimeException("生成自动化报告失败"); } + + // 下载到本地 + // 设置响应头 + response.reset(); + response.setContentType("application/octet-stream;charset=UTF-8"); + response.addHeader("Content-Length", String.valueOf(fileData.length)); + // 写入响应流 + OutputStream outputStream = response.getOutputStream(); + outputStream.write(fileData); + outputStream.flush(); + outputStream.close(); + fileInputStream.close(); + } catch (Exception ex) { + log.error("生成自动化报告失败:{}", ex.getMessage()); + throw new RuntimeException("生成自动化报告失败"); } - // 删除临时路径 - log.info("删除临时路径:{},中。。。。。。", randomId); - deleteFolder(new File(TEMP_REPORT_PATH + randomId)); } + // 删除临时路径 + log.info("删除临时路径:{},中。。。。。。", randomId); + deleteFolder(new File(TEMP_REPORT_PATH + randomId)); } }