From e1771f81b6eae2ee04a07b3b398d3cd609128908 Mon Sep 17 00:00:00 2001 From: lidongyang <506508008@qq.com> Date: Mon, 23 Mar 2026 20:09:49 +0800 Subject: [PATCH] =?UTF-8?q?fix[project]:=20=E5=90=8C=E6=AD=A5=E5=BE=85?= =?UTF-8?q?=E5=8A=9E=E6=97=B6=EF=BC=8C=E4=B8=8B=E8=BD=BD=E5=BE=85=E5=8A=9E?= =?UTF-8?q?=E7=9A=84=E6=8A=A5=E5=91=8A=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/sdm/common/utils/FilesUtil.java | 120 ++++---- .../LyricVAttachmentConfigMapper.java | 8 + .../LyricVAttachmentConfigServiceImpl.java | 13 + .../lyric/LyricVAttachmentConfigService.java | 7 + .../SimulationLyricNodeController.java | 6 + .../model/entity/SimulationDemand.java | 7 + .../project/model/entity/SimulationTask.java | 4 +- .../project/model/req/SpdmAddDemandReq.java | 5 + .../sdm/project/model/vo/SpdmDemandVo.java | 5 + .../service/ILyricInternalService.java | 2 + .../service/ISimulationTaskService.java | 2 +- .../service/impl/DemandServiceImpl.java | 4 +- .../impl/LyricInternalServiceImpl.java | 267 +++++++++++++++++- .../project/service/impl/NodeServiceImpl.java | 91 +++++- .../impl/SimulationTaskServiceImpl.java | 81 ++++-- 15 files changed, 512 insertions(+), 110 deletions(-) create mode 100644 outbridge/src/main/java/com/sdm/outbridge/secondDao/LyricVAttachmentConfigMapper.java create mode 100644 outbridge/src/main/java/com/sdm/outbridge/service/impl/lyric/LyricVAttachmentConfigServiceImpl.java create mode 100644 outbridge/src/main/java/com/sdm/outbridge/service/lyric/LyricVAttachmentConfigService.java diff --git a/common/src/main/java/com/sdm/common/utils/FilesUtil.java b/common/src/main/java/com/sdm/common/utils/FilesUtil.java index cff63072..303b51ae 100644 --- a/common/src/main/java/com/sdm/common/utils/FilesUtil.java +++ b/common/src/main/java/com/sdm/common/utils/FilesUtil.java @@ -586,75 +586,75 @@ public class FilesUtil { /** * 从指定URL下载文件到本地 - * @param fileUrl 远程文件的URL地址 + * @param fileUrlList 远程文件的URL地址 * @param savePath 本地保存路径(包含文件名,例如:/opt/demand/report/有限元仿真结果报告.pdf) * @throws IOException 处理IO异常 */ - public static void downloadFile(String fileUrl, String savePath) throws IOException { - + public static void downloadFile(List fileUrlList, String savePath) throws IOException { createDirectoryIfNotExists(savePath); + for (String fileUrl : fileUrlList) { + // 声明连接和流对象 + HttpURLConnection connection = null; + BufferedInputStream in = null; + BufferedOutputStream out = null; - // 声明连接和流对象 - HttpURLConnection connection = null; - BufferedInputStream in = null; - BufferedOutputStream out = null; + try { + // 1. 创建URL对象 + URL url = new URL(fileUrl); - try { - // 1. 创建URL对象 - URL url = new URL(fileUrl); + // 2. 打开连接并设置属性 + connection = (HttpURLConnection) url.openConnection(); + // 设置连接超时时间(5秒) + connection.setConnectTimeout(5000); + // 设置读取超时时间(10秒) + connection.setReadTimeout(10000); + // 设置请求方法 + connection.setRequestMethod("GET"); + // 允许输入流 + connection.setDoInput(true); - // 2. 打开连接并设置属性 - connection = (HttpURLConnection) url.openConnection(); - // 设置连接超时时间(5秒) - connection.setConnectTimeout(5000); - // 设置读取超时时间(10秒) - connection.setReadTimeout(10000); - // 设置请求方法 - connection.setRequestMethod("GET"); - // 允许输入流 - connection.setDoInput(true); - - // 3. 检查响应码,200表示成功 - int responseCode = connection.getResponseCode(); - if (responseCode != HttpURLConnection.HTTP_OK) { - throw new IOException("下载失败,HTTP响应码:" + responseCode); - } - - // 4. 获取文件大小(用于进度显示) - long fileSize = connection.getContentLengthLong(); - log.info("文件大小:{}", formatFileSize(fileSize)); - - // 5. 创建输入输出流 - in = new BufferedInputStream(connection.getInputStream()); - out = new BufferedOutputStream(new FileOutputStream(savePath)); - - // 6. 缓冲区读写数据 - byte[] buffer = new byte[4096]; // 4KB缓冲区 - int bytesRead; - while ((bytesRead = in.read(buffer)) != -1) { - out.write(buffer, 0, bytesRead); - } - - log.info("文件下载完成!保存路径:{}",savePath); - - } finally { - // 7. 关闭所有流和连接,确保资源释放 - if (out != null) { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); + // 3. 检查响应码,200表示成功 + int responseCode = connection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) { + throw new IOException("下载失败,HTTP响应码:" + responseCode); } - } - if (in != null) { - try { - in.close(); - } catch (IOException e) { - e.printStackTrace(); + + // 4. 获取文件大小(用于进度显示) + long fileSize = connection.getContentLengthLong(); + log.info("文件大小:{}", formatFileSize(fileSize)); + + // 5. 创建输入输出流 + in = new BufferedInputStream(connection.getInputStream()); + out = new BufferedOutputStream(new FileOutputStream(savePath)); + + // 6. 缓冲区读写数据 + byte[] buffer = new byte[4096]; // 4KB缓冲区 + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + } + + log.info("文件下载完成!保存路径:{}",savePath); + + } finally { + // 7. 关闭所有流和连接,确保资源释放 + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (connection != null) { + connection.disconnect(); } - } - if (connection != null) { - connection.disconnect(); } } } diff --git a/outbridge/src/main/java/com/sdm/outbridge/secondDao/LyricVAttachmentConfigMapper.java b/outbridge/src/main/java/com/sdm/outbridge/secondDao/LyricVAttachmentConfigMapper.java new file mode 100644 index 00000000..7456ff0d --- /dev/null +++ b/outbridge/src/main/java/com/sdm/outbridge/secondDao/LyricVAttachmentConfigMapper.java @@ -0,0 +1,8 @@ +package com.sdm.outbridge.secondDao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sdm.outbridge.entity.LyricVAttachmentConfigToDM; + +public interface LyricVAttachmentConfigMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/outbridge/src/main/java/com/sdm/outbridge/service/impl/lyric/LyricVAttachmentConfigServiceImpl.java b/outbridge/src/main/java/com/sdm/outbridge/service/impl/lyric/LyricVAttachmentConfigServiceImpl.java new file mode 100644 index 00000000..3a84da82 --- /dev/null +++ b/outbridge/src/main/java/com/sdm/outbridge/service/impl/lyric/LyricVAttachmentConfigServiceImpl.java @@ -0,0 +1,13 @@ +package com.sdm.outbridge.service.impl.lyric; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sdm.outbridge.entity.LyricVAttachmentConfigToDM; +import com.sdm.outbridge.secondDao.LyricVAttachmentConfigMapper; +import com.sdm.outbridge.service.lyric.LyricVAttachmentConfigService; +import org.springframework.stereotype.Service; + +@Service +public class LyricVAttachmentConfigServiceImpl extends ServiceImpl + implements LyricVAttachmentConfigService { + +} \ No newline at end of file diff --git a/outbridge/src/main/java/com/sdm/outbridge/service/lyric/LyricVAttachmentConfigService.java b/outbridge/src/main/java/com/sdm/outbridge/service/lyric/LyricVAttachmentConfigService.java new file mode 100644 index 00000000..c3e2a162 --- /dev/null +++ b/outbridge/src/main/java/com/sdm/outbridge/service/lyric/LyricVAttachmentConfigService.java @@ -0,0 +1,7 @@ +package com.sdm.outbridge.service.lyric; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sdm.outbridge.entity.LyricVAttachmentConfigToDM; + +public interface LyricVAttachmentConfigService extends IService { +} \ No newline at end of file diff --git a/project/src/main/java/com/sdm/project/controller/SimulationLyricNodeController.java b/project/src/main/java/com/sdm/project/controller/SimulationLyricNodeController.java index 12907e67..9ae73743 100644 --- a/project/src/main/java/com/sdm/project/controller/SimulationLyricNodeController.java +++ b/project/src/main/java/com/sdm/project/controller/SimulationLyricNodeController.java @@ -225,5 +225,11 @@ public class SimulationLyricNodeController { return lyricInternalService.acceptTodoInfo(req); } + @GetMapping("/manuallySupplementTodoReport") + @Operation(summary = "手动补充待办报告文件", description = "手动补充待办报告文件") + public SdmResponse manuallySupplementTodoReport(@RequestParam(value = "taskId", required = false) String taskId) { + return lyricInternalService.manuallySupplementTodoReport(taskId); + } + } diff --git a/project/src/main/java/com/sdm/project/model/entity/SimulationDemand.java b/project/src/main/java/com/sdm/project/model/entity/SimulationDemand.java index 4a094bc8..6aff5f7d 100644 --- a/project/src/main/java/com/sdm/project/model/entity/SimulationDemand.java +++ b/project/src/main/java/com/sdm/project/model/entity/SimulationDemand.java @@ -6,11 +6,13 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; 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; import java.io.Serializable; +import java.util.List; @Data @EqualsAndHashCode(callSuper = false) @@ -88,4 +90,9 @@ public class SimulationDemand implements Serializable { @TableField("description") private String description; + + @Schema(description= "关联的待办的结果文件路径") + @TableField(exist = false) + private List reportFileUrlList; + } 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 a9a9c6a4..45277333 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 @@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import java.io.Serializable; +import java.util.List; + import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -221,7 +223,7 @@ public class SimulationTask implements Serializable { @Schema(description= "关联的待办的结果文件路径") @TableField(exist = false) - private String reportFileUrl; + private List reportFileUrlList; } diff --git a/project/src/main/java/com/sdm/project/model/req/SpdmAddDemandReq.java b/project/src/main/java/com/sdm/project/model/req/SpdmAddDemandReq.java index 07fd30e1..6d6f99b8 100644 --- a/project/src/main/java/com/sdm/project/model/req/SpdmAddDemandReq.java +++ b/project/src/main/java/com/sdm/project/model/req/SpdmAddDemandReq.java @@ -1,8 +1,10 @@ package com.sdm.project.model.req; +import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.sdm.common.entity.pojo.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -154,4 +156,7 @@ public class SpdmAddDemandReq extends BaseEntity { */ private Boolean isLyric=false; + @Schema(description= "关联的待办的结果文件路径") + private List reportFileUrlList; + } diff --git a/project/src/main/java/com/sdm/project/model/vo/SpdmDemandVo.java b/project/src/main/java/com/sdm/project/model/vo/SpdmDemandVo.java index 3d76a0e0..da7c64b8 100644 --- a/project/src/main/java/com/sdm/project/model/vo/SpdmDemandVo.java +++ b/project/src/main/java/com/sdm/project/model/vo/SpdmDemandVo.java @@ -1,10 +1,12 @@ package com.sdm.project.model.vo; +import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonProperty; import com.sdm.common.entity.pojo.BaseEntity; import com.sdm.common.entity.resp.system.CIDUserResp; import com.sdm.project.model.req.SpdmDemandExtraReq; import com.sdm.project.model.vo.SpdmDemandMemberVo; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -192,4 +194,7 @@ public class SpdmDemandVo extends BaseEntity { */ private String produceLine; + @Schema(description= "关联的待办的结果文件路径") + private List reportFileUrlList; + } diff --git a/project/src/main/java/com/sdm/project/service/ILyricInternalService.java b/project/src/main/java/com/sdm/project/service/ILyricInternalService.java index fd6ad7f9..88fbbea0 100644 --- a/project/src/main/java/com/sdm/project/service/ILyricInternalService.java +++ b/project/src/main/java/com/sdm/project/service/ILyricInternalService.java @@ -63,4 +63,6 @@ public interface ILyricInternalService { SdmResponse acceptTodoInfo(SpdmAcceptTodoInfoReq req); + SdmResponse manuallySupplementTodoReport(String taskId); + } diff --git a/project/src/main/java/com/sdm/project/service/ISimulationTaskService.java b/project/src/main/java/com/sdm/project/service/ISimulationTaskService.java index 2d904d97..7010f292 100644 --- a/project/src/main/java/com/sdm/project/service/ISimulationTaskService.java +++ b/project/src/main/java/com/sdm/project/service/ISimulationTaskService.java @@ -24,6 +24,6 @@ public interface ISimulationTaskService extends IService { SdmResponse editTaskForData(TaskEditNodeReq req); - void batchCreateTaskFromDemand(List demandList); + void batchCreateTaskFromDemand(List demandList,Boolean isDownloadFlag); } diff --git a/project/src/main/java/com/sdm/project/service/impl/DemandServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/DemandServiceImpl.java index d8eeeb2c..48d5d1ee 100644 --- a/project/src/main/java/com/sdm/project/service/impl/DemandServiceImpl.java +++ b/project/src/main/java/com/sdm/project/service/impl/DemandServiceImpl.java @@ -342,7 +342,7 @@ public class DemandServiceImpl extends BaseService implements IDemandService { if (req.getIsLyric()) { SimulationDemand demand = new SimulationDemand(); BeanUtils.copyProperties(req, demand); - simulationTaskService.batchCreateTaskFromDemand(Collections.singletonList(demand)); + simulationTaskService.batchCreateTaskFromDemand(Collections.singletonList(demand),false); } return SdmResponse.success(req.getUuid()); @@ -1821,7 +1821,7 @@ public class DemandServiceImpl extends BaseService implements IDemandService { if (req.getIsLyric()) { SimulationDemand demand = new SimulationDemand(); BeanUtils.copyProperties(req, demand); - simulationTaskService.batchCreateTaskFromDemand(Collections.singletonList(demand)); + simulationTaskService.batchCreateTaskFromDemand(Collections.singletonList(demand),false); } return SdmResponse.success(req.getUuid()); diff --git a/project/src/main/java/com/sdm/project/service/impl/LyricInternalServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/LyricInternalServiceImpl.java index 34f208df..6c524fc3 100644 --- a/project/src/main/java/com/sdm/project/service/impl/LyricInternalServiceImpl.java +++ b/project/src/main/java/com/sdm/project/service/impl/LyricInternalServiceImpl.java @@ -1,5 +1,6 @@ package com.sdm.project.service.impl; +import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; @@ -7,10 +8,7 @@ import com.sdm.common.common.ResultCode; import com.sdm.common.common.SdmResponse; import com.sdm.common.common.ThreadLocalContext; import com.sdm.common.constants.LyricParamConstants; -import com.sdm.common.entity.enums.AttachFileTypeEnum; -import com.sdm.common.entity.enums.DirTypeEnum; -import com.sdm.common.entity.enums.FilePermissionEnum; -import com.sdm.common.entity.enums.NodeTypeEnum; +import com.sdm.common.entity.enums.*; import com.sdm.common.entity.req.data.*; import com.sdm.common.entity.req.lyric.SpdmAcceptTodoInfoReq; import com.sdm.common.entity.req.project.SpdmNodeListReq; @@ -49,6 +47,7 @@ import com.sdm.project.dao.SimulationTaskMapper; import com.sdm.project.model.bo.TaskNodeTag; import com.sdm.project.model.entity.SimulationDemand; import com.sdm.project.model.entity.SimulationNode; +import com.sdm.project.model.entity.SimulationTask; import com.sdm.project.model.req.*; import com.sdm.project.model.req.ep.EpProjectQueryReq; import com.sdm.project.model.req.ep.EpSyncPhaseReq; @@ -68,6 +67,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.stereotype.Service; import org.springframework.transaction.interceptor.TransactionAspectSupport; @@ -91,6 +91,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static com.sdm.project.service.impl.NodeServiceImpl.SYNC_PROJECT_SOURCE; +import static com.sdm.project.service.impl.SimulationTaskServiceImpl.REPORT_PATH_PREFIX; @Service @Slf4j @@ -196,6 +197,9 @@ public class LyricInternalServiceImpl implements ILyricInternalService { @Autowired private LyricVProjectStationExcepTionToDMService lyricVProjectStationExcepTionToDMService; + @Autowired + private LyricVAttachmentConfigService lyricVAttachmentConfigService; + @Autowired private SimulationTaskExtraMapper simulationTaskExtraMapper; @@ -376,6 +380,43 @@ public class LyricInternalServiceImpl implements ILyricInternalService { return filterTodoList; } + /** + * 将列表中的字符串按逗号拆分,合并后去重 + * @param sourceList 原始字符串列表 + * @return 拆分去重后的新列表 + */ + public static List splitAndDistinct(List sourceList) { + // 1. 判空处理,避免空指针 + if (sourceList == null || sourceList.isEmpty()) { + return new ArrayList<>(); + } + + // 2. 使用LinkedHashSet保证去重且保留插入顺序 + Set tempSet = new LinkedHashSet<>(); + + // 3. 遍历原始列表,拆分每个字符串并添加到Set中 + for (String str : sourceList) { + // 跳过空字符串,避免拆分出空元素 + if (str == null || str.trim().isEmpty()) { + continue; + } + // 按逗号拆分字符串 + String[] splitArray = str.split(","); + // 遍历拆分后的数组,添加到Set(自动去重) + for (String item : splitArray) { + // 去除首尾空格(如果需要的话,不需要可删除trim()) + String cleanItem = item.trim(); + // 跳过拆分后为空的元素 + if (!cleanItem.isEmpty()) { + tempSet.add(cleanItem); + } + } + } + + // 4. 将Set转换为List返回 + return new ArrayList<>(tempSet); + } + /** * 核心同步逻辑:构建数据并执行批量操作 */ @@ -414,6 +455,34 @@ public class LyricInternalServiceImpl implements ILyricInternalService { List userList = pageDataRespSdmResponse.getData().getData(); usernameToUserIdMap = userList.stream().collect(Collectors.toMap(CIDUserResp::getUsername, CIDUserResp::getUserId)); } + // 构建一个需求todoId到resultFileId的映射 + Map resultFileIdMap = todoInfoList.stream().collect(Collectors.toMap(LyricVTodoEmulationInfoDM::getTodoId,LyricVTodoEmulationInfoDM::getResultFileId,(oldValue, newValue) -> oldValue)); + // 构建一个resultFileId到filePath的映射 + Map filePathMap = new HashMap<>(); + // 查询filePath + List resultFileIdStrList = todoInfoList.stream().map(LyricVTodoEmulationInfoDM::getResultFileId).filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultFileIdStrList)) { + resultFileIdStrList = splitAndDistinct(resultFileIdStrList); + List resultFileIdList = resultFileIdStrList.stream() + .map(str -> { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + System.out.println("跳过无效数字:" + str); + return null; // 转换失败返回null + } + }) + .filter(Objects::nonNull) // 过滤掉null值 + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultFileIdList)) { + List attachmentConfigToDMList = lyricVAttachmentConfigService.lambdaQuery().in(LyricVAttachmentConfigToDM::getId, resultFileIdList) + .list(); + if (CollectionUtils.isNotEmpty(attachmentConfigToDMList)) { + filePathMap = attachmentConfigToDMList.stream().collect(Collectors.toMap(LyricVAttachmentConfigToDM::getId,LyricVAttachmentConfigToDM::getFilePath,(oldValue, newValue) -> oldValue)); + } + } + } for (SimulationNode projectNode : projectNodeList) { String projectCode = projectNode.getNodeCode(); @@ -459,9 +528,34 @@ public class LyricInternalServiceImpl implements ILyricInternalService { executeBatchOperations(createDirItemList, updatePermissionList); if (CollectionUtils.isNotEmpty(demandToCreateTaskList)) { - simulationTaskService.batchCreateTaskFromDemand(demandToCreateTaskList); + for (SimulationDemand simulationDemand : demandToCreateTaskList) { + List reportFileUrlList = new ArrayList<>(); + String demandCode = simulationDemand.getDemandCode(); + String reportFileUrl = null; + if (StringUtils.isNotBlank(demandCode) && isConvertibleToLong(demandCode)) { + // resultFileId可能有多个,逗号隔开 + String resultFileIdStr = resultFileIdMap.get(Long.valueOf(demandCode)); + if (StringUtils.isNotBlank(resultFileIdStr)) { + try { + for (String resultFileId : Arrays.stream(resultFileIdStr.split(",")).toList()) { + reportFileUrl = filePathMap.get(Integer.parseInt(resultFileId)); + if (StringUtils.isBlank(reportFileUrl)) { + continue; + } + reportFileUrlList.add(reportFileUrl); + } + } catch (NumberFormatException e) { + log.error("跳过无效数字:{}",resultFileIdStr); + } + } + } + if (CollectionUtils.isEmpty(reportFileUrlList)) { + continue; + } + simulationDemand.setReportFileUrlList(reportFileUrlList); + } + simulationTaskService.batchCreateTaskFromDemand(demandToCreateTaskList,true); } - return SdmResponse.success(); } catch (Exception e) { log.error("syncTodoData 未知 error: {}", e.getMessage()); @@ -4147,11 +4241,170 @@ public class LyricInternalServiceImpl implements ILyricInternalService { SimulationDemand demand = new SimulationDemand(); BeanUtils.copyProperties(req, demand); - simulationTaskService.batchCreateTaskFromDemand(Collections.singletonList(demand)); + simulationTaskService.batchCreateTaskFromDemand(Collections.singletonList(demand),false); return SdmResponse.success(req.getUuid()); } + @Override + public SdmResponse manuallySupplementTodoReport(String taskId) { + List taskList; + if (StringUtils.isNotBlank(taskId)) { + // 任务id不为空,单个测试 + taskList = simulationTaskService.lambdaQuery().eq(SimulationTask::getUuid, taskId).isNotNull(SimulationTask::getDemandId).list(); + }else { + // 直接同步全部待办的报告到关联的任务文件夹下 + taskList = simulationTaskService.lambdaQuery().isNotNull(SimulationTask::getDemandId).list(); + } + + // 根据任务关联的需求id,查询视图中待办信息 + if (CollectionUtils.isEmpty(taskList)) { + log.error("taskList为空"); + return SdmResponse.failed("taskList为空"); + } + + List demandIdList = taskList.stream().map(SimulationTask::getDemandId).filter(StringUtils::isNotBlank).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(demandIdList)) { + log.error("demandIdList为空"); + return SdmResponse.failed("demandIdList为空"); + } + List demandList = demandMapper.getDemandListById(demandIdList); + if (CollectionUtils.isEmpty(demandList)) { + log.error("demandList为空"); + return SdmResponse.failed("demandList为空"); + } + List demandCodeList = demandList.stream().map(SpdmDemandVo::getDemandCode).filter(StringUtils::isNotBlank).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(demandCodeList)) { + log.error("demandCodeList为空"); + return SdmResponse.failed("demandCodeList为空"); + } + List todoInfoList = lyricVTodoInfoService.lambdaQuery().in(LyricVTodoEmulationInfoDM::getTodoId, demandCodeList).list(); + if (CollectionUtils.isEmpty(todoInfoList)) { + log.error("todoInfoList为空"); + return SdmResponse.failed("todoInfoList为空"); + } + + + // 构建一个需求todoId到resultFileId的映射 + Map resultFileIdMap = todoInfoList.stream().collect(Collectors.toMap(LyricVTodoEmulationInfoDM::getTodoId,LyricVTodoEmulationInfoDM::getResultFileId,(oldValue, newValue) -> oldValue)); + // 构建一个resultFileId到filePath的映射 + Map filePathMap = new HashMap<>(); + // 查询filePath + List resultFileIdStrList = todoInfoList.stream().map(LyricVTodoEmulationInfoDM::getResultFileId).filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultFileIdStrList)) { + resultFileIdStrList = splitAndDistinct(resultFileIdStrList); + List resultFileIdList = resultFileIdStrList.stream() + .map(str -> { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + System.out.println("跳过无效数字:" + str); + return null; // 转换失败返回null + } + }) + .filter(Objects::nonNull) // 过滤掉null值 + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultFileIdList)) { + List attachmentConfigToDMList = lyricVAttachmentConfigService.lambdaQuery().in(LyricVAttachmentConfigToDM::getId, resultFileIdList) + .list(); + if (CollectionUtils.isNotEmpty(attachmentConfigToDMList)) { + filePathMap = attachmentConfigToDMList.stream().collect(Collectors.toMap(LyricVAttachmentConfigToDM::getId,LyricVAttachmentConfigToDM::getFilePath,(oldValue, newValue) -> oldValue)); + } + } + } + + Map> taskMap = taskList.stream().collect(Collectors.groupingBy(SimulationTask::getDemandId)); + for (SpdmDemandVo simulationDemand : demandList) { + List reportFileUrlList = new ArrayList<>(); + String demandCode = simulationDemand.getDemandCode(); + String reportFileUrl = null; + if (StringUtils.isNotBlank(demandCode) && isConvertibleToLong(demandCode)) { + // resultFileId可能有多个,逗号隔开 + String resultFileIdStr = resultFileIdMap.get(Long.valueOf(demandCode)); + if (StringUtils.isNotBlank(resultFileIdStr)) { + try { + for (String resultFileId : Arrays.stream(resultFileIdStr.split(",")).toList()) { + reportFileUrl = filePathMap.get(Integer.parseInt(resultFileId)); + if (StringUtils.isBlank(reportFileUrl)) { + continue; + } + reportFileUrlList.add(reportFileUrl); + } + } catch (NumberFormatException e) { + log.error("手动跳过无效数字:{}",resultFileIdStr); + } + } + } + if (CollectionUtils.isEmpty(reportFileUrlList)) { + continue; + } + List eachTaskList = taskMap.get(simulationDemand.getUuid()); + if (CollectionUtils.isEmpty(eachTaskList)) { + continue; + } + for (SimulationTask simulationTask : eachTaskList) { + simulationTask.setReportFileUrlList(reportFileUrlList); + } + } + + + + log.info("共处理{}条任务的报告数据",taskList.size()); + for (SimulationTask task : taskList) { + // 异步下载待办的结果文件到任务文件夹下 + if (CollectionUtils.isEmpty(task.getReportFileUrlList())) { + continue; + } + TagReq tagReq = new TagReq(); + BeanUtils.copyProperties(task,tagReq); + tagReq.setTaskId(task.getUuid()); + tagReq.setTaskId(task.getTaskName() ); + CompletableFuture.runAsync(() -> { + String savePath = REPORT_PATH_PREFIX + task.getUuid(); + try { + FilesUtil.downloadFile(task.getReportFileUrlList(), savePath); + // 上传到minio + String fileName = ""; + FileInputStream fileInputStream = new FileInputStream(REPORT_PATH_PREFIX + task.getUuid() + File.separator + fileName); + byte[] fileData = fileInputStream.readAllBytes(); + MockMultipartFile multipartFile = new MockMultipartFile( + fileName, + fileName, + "application/octet-stream", + fileData); + UploadFilesReq fileReq = new UploadFilesReq(); + fileReq.setFile(multipartFile); + // 传任务uuid + fileReq.setUuid(task.getUuid()); + fileReq.setFileName(fileName); + fileReq.setFileTypeDictValue(String.valueOf(FileBizTypeEnum.REPORT_FILE.getValue())); + fileReq.setFileTypeDictClass(FileDictTagEnum.FILE_TYPE.getDictClass()); + fileReq.setDictTags(Arrays.asList(FileDictTagEnum.FILE_TYPE.getDictClassFieldName(), FileDictTagEnum.FILE_TYPE.getDictValueFieldName())); + fileReq.setTagReq(tagReq); + if (fileReq.getTagReq() != null) { + fileReq.setTagReqStr(JSON.toJSONString(fileReq.getTagReq())); + } + SdmResponse uploadRespond = dataFeignClient.uploadFiles(fileReq); + log.info("手动上传仿真报告到minio的响应值为:{}",uploadRespond); + } catch (IOException e) { + log.error("手动上传仿真报告到minio的异常:{}",e.getMessage()); + }finally { + try { + FilesUtil.deleteFolderNonRecursive(savePath); + } catch (IOException e) { + log.error("手动删除临时文件夹异常:{}",e.getMessage()); + } + } + }); + } + + + + + return SdmResponse.success(); + } + /** * 项目的当前阶段包含:设计,就是:项目承接主体+结构,否则就是:项目承接主体+技术中心+结构,所对应的人 * diff --git a/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java index 675bfdb7..f685cd9d 100644 --- a/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java +++ b/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java @@ -90,6 +90,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.sdm.project.service.impl.LyricInternalServiceImpl.splitAndDistinct; import static java.util.Collections.emptyList; @Slf4j @@ -209,6 +210,9 @@ public class NodeServiceImpl extends ServiceImpl dm.getTodoId() != null) + .filter(dm -> dm.getSubject() != null) .collect(Collectors.collectingAndThen( - Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LyricVTodoEmulationInfoDM::getTodoId))), + Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LyricVTodoEmulationInfoDM::getSubject))), ArrayList::new )); @@ -3669,16 +3673,15 @@ public class NodeServiceImpl extends ServiceImpl existingDemandCodeSet = allDemandList.stream() - .map(SpdmDemandVo::getDemandCode) + Set existingDemandNameSet = allDemandList.stream() + .map(SpdmDemandVo::getDemandName) .filter(StringUtils::isNotBlank) .collect(Collectors.toSet()); // 过滤已同步的待办 return todoInfoList.stream() .filter(todoInfo -> { - String todoIdStr = String.valueOf(todoInfo.getTodoId()); - return !existingDemandCodeSet.contains(todoIdStr); + return !existingDemandNameSet.contains(todoInfo.getSubject()); }) .collect(Collectors.toList()); } @@ -3724,13 +3727,45 @@ public class NodeServiceImpl extends ServiceImpl userList = pageDataRespSdmResponse.getData().getData(); usernameToUserIdMap = userList.stream().collect(Collectors.toMap(CIDUserResp::getUsername, CIDUserResp::getUserId)); } + + // 构建一个需求todoId到resultFileId的映射 + Map resultFileIdMap = todoInfoList.stream().collect(Collectors.toMap(LyricVTodoEmulationInfoDM::getTodoId,LyricVTodoEmulationInfoDM::getResultFileId,(oldValue, newValue) -> oldValue)); + // 构建一个resultFileId到filePath的映射 + Map filePathMap = new HashMap<>(); + // 查询filePath + List resultFileIdStrList = todoInfoList.stream().map(LyricVTodoEmulationInfoDM::getResultFileId).filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultFileIdStrList)) { + resultFileIdStrList = splitAndDistinct(resultFileIdStrList); + List resultFileIdList = resultFileIdStrList.stream() + .map(str -> { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + System.out.println("跳过无效数字:" + str); + return null; // 转换失败返回null + } + }) + .filter(Objects::nonNull) // 过滤掉null值 + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultFileIdList)) { + List attachmentConfigToDMList = lyricVAttachmentConfigService.lambdaQuery().in(LyricVAttachmentConfigToDM::getId, resultFileIdList) + .list(); + if (CollectionUtils.isNotEmpty(attachmentConfigToDMList)) { + filePathMap = attachmentConfigToDMList.stream().collect(Collectors.toMap(LyricVAttachmentConfigToDM::getId,LyricVAttachmentConfigToDM::getFilePath,(oldValue, newValue) -> oldValue)); + } + } + } + + + // 筛选出所有工位节点 for (LyricVTodoEmulationInfoDM todoItem : todoInfoList) { try { String demandUuid = RandomUtil.generateString(32); // 1. 构建基础需求信息 - SpdmAddDemandReq demandAddReq = buildDemandAddReq(todoItem, demandUuid, projectNodeMap, currentTimeStr,workspaceNodeMap,usernameToUserIdMap); + SpdmAddDemandReq demandAddReq = buildDemandAddReq(todoItem, demandUuid, projectNodeMap, currentTimeStr,workspaceNodeMap,usernameToUserIdMap,resultFileIdMap,filePathMap); // 2. 构建成员信息和权限信息 List memberList = buildDemandMemberList( @@ -3750,7 +3785,7 @@ public class NodeServiceImpl extends ServiceImpl projectNodeMap, String currentTimeStr, Map workspaceNodeMap, - Map usernameToUserIdMap) { + Map usernameToUserIdMap, + Map resultFileIdMap, + Map filePathMap) { SpdmAddDemandReq demandAddReq = new SpdmAddDemandReq(); // 基础属性 @@ -3798,6 +3835,30 @@ public class NodeServiceImpl extends ServiceImpl reportFileUrlList = new ArrayList<>(); + String demandCode = demandAddReq.getDemandCode(); + String reportFileUrl = null; + if (StringUtils.isNotBlank(demandCode) && isConvertibleToLong(demandCode)) { + // resultFileId可能有多个,逗号隔开 + String resultFileIdStr = resultFileIdMap.get(Long.valueOf(demandCode)); + if (StringUtils.isNotBlank(resultFileIdStr)) { + try { + for (String resultFileId : Arrays.stream(resultFileIdStr.split(",")).toList()) { + reportFileUrl = filePathMap.get(Integer.parseInt(resultFileId)); + if (StringUtils.isBlank(reportFileUrl)) { + continue; + } + reportFileUrlList.add(reportFileUrl); + } + } catch (NumberFormatException e) { + log.error("跳过无效数字:{}",resultFileIdStr); + } + } + } + if (CollectionUtils.isNotEmpty(reportFileUrlList)) { + demandAddReq.setReportFileUrlList(reportFileUrlList); + } return demandAddReq; } @@ -4001,7 +4062,9 @@ public class NodeServiceImpl extends ServiceImpl memberList, Long tenantId, Long currentUserId, - Map usernameToUserIdMap) { + Map usernameToUserIdMap, + Map resultFileIdMap, + Map filePathMap) { CompletableFuture.runAsync(() -> { try { ThreadLocalContext.setTenantId(tenantId); @@ -4024,7 +4087,13 @@ public class NodeServiceImpl extends ServiceImpl demandList) { + public void batchCreateTaskFromDemand(List demandList,Boolean isDownloadFlag) { log.info("从需求批量创建任务,需求数量:{}", demandList); if (CollectionUtils.isEmpty(demandList)) { return; @@ -224,30 +226,50 @@ public class SimulationTaskServiceImpl extends ServiceImpl { -// try { -// FilesUtil.downloadFile(task.getReportFileUrl(), REPORT_PATH_PREFIX + task.getUuid()); -// // 上传到minio -// UploadFilesReq fileReq = new UploadFilesReq(); -// fileReq.setSourceFiles(); -// fileReq.setUploadTaskId(); -// fileReq.setType(); -// fileReq.setFileType(); -// fileReq.setUuid(); -// fileReq.setFileTypeDictValue(); -// fileReq.setFileTypeDictClass(); -// fileReq.setDisciplineDictValue(); -// fileReq.setDisciplineTypeDictClass(); -// fileReq.setDictTags(); -// SdmResponse uploadRespond = dataFeignClient.uploadFiles(fileReq); -// } catch (IOException e) { -// throw new RuntimeException(e); -// } -// }); + if (CollectionUtils.isEmpty(task.getReportFileUrlList())) { + continue; + } + CompletableFuture.runAsync(() -> { + String savePath = REPORT_PATH_PREFIX + task.getUuid(); + try { + FilesUtil.downloadFile(task.getReportFileUrlList(), savePath); + // 上传到minio + String fileName = ""; + FileInputStream fileInputStream = new FileInputStream(REPORT_PATH_PREFIX + task.getUuid() + File.separator + fileName); + byte[] fileData = fileInputStream.readAllBytes(); + MockMultipartFile multipartFile = new MockMultipartFile( + fileName, + fileName, + "application/octet-stream", + fileData); + UploadFilesReq fileReq = new UploadFilesReq(); + fileReq.setFile(multipartFile); + // 传任务uuid + fileReq.setUuid(task.getUuid()); + fileReq.setFileName(fileName); + fileReq.setFileTypeDictValue(String.valueOf(FileBizTypeEnum.REPORT_FILE.getValue())); + fileReq.setFileTypeDictClass(FileDictTagEnum.FILE_TYPE.getDictClass()); + fileReq.setDictTags(Arrays.asList(FileDictTagEnum.FILE_TYPE.getDictClassFieldName(), FileDictTagEnum.FILE_TYPE.getDictValueFieldName())); + fileReq.setTagReq(tagReq); + if (fileReq.getTagReq() != null) { + fileReq.setTagReqStr(JSON.toJSONString(fileReq.getTagReq())); + } + SdmResponse uploadRespond = dataFeignClient.uploadFiles(fileReq); + log.info("上传仿真报告到minio的响应值为:{}",uploadRespond); + } catch (IOException e) { + log.error("上传仿真报告到minio的异常:{}",e.getMessage()); + }finally { + try { + FilesUtil.deleteFolderNonRecursive(savePath); + } catch (IOException e) { + log.error("删除临时文件夹异常:{}",e.getMessage()); + } + } + }); } // 批量更新任务权限(使用批量接口) batchUpdateTaskPermissions(tasksToCreate); @@ -274,6 +296,9 @@ public class SimulationTaskServiceImpl extends ServiceImpl