From 895becd730017255ba69b3e45259a4448f63e595 Mon Sep 17 00:00:00 2001 From: zhuxinru Date: Tue, 9 Dec 2025 14:40:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=95=B0=E6=8D=AE=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E9=A2=84=E8=AD=A6=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5=20&=20?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=B5=81=E7=A8=8B=E8=8A=82=E7=82=B9=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/enums/MessageTemplateEnum.java | 1 + .../sdm/data/job/DataStorageMonitorJob.java | 55 +++++++++++++++++++ .../sdm/data/service/DataStorageAnalysis.java | 3 + .../service/impl/DataStorageAnalysisImpl.java | 33 ++++++++++- .../impl/DimensionTemplateServiceImpl.java | 46 +++++++++++++++- data/src/main/resources/application-dev.yml | 6 +- data/src/main/resources/application-local.yml | 4 ++ .../controller/SimulationRunController.java | 3 +- .../sdm/project/model/resp/FlowInfoDto.java | 15 +++++ .../service/ISimulationRunService.java | 3 +- .../impl/SimulationRunServiceImpl.java | 11 ++-- system/src/main/resources/application-dev.yml | 3 +- .../src/main/resources/application-local.yml | 7 +++ 13 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 data/src/main/java/com/sdm/data/job/DataStorageMonitorJob.java create mode 100644 project/src/main/java/com/sdm/project/model/resp/FlowInfoDto.java diff --git a/common/src/main/java/com/sdm/common/entity/enums/MessageTemplateEnum.java b/common/src/main/java/com/sdm/common/entity/enums/MessageTemplateEnum.java index 7b3e1a7b..ef15dd48 100644 --- a/common/src/main/java/com/sdm/common/entity/enums/MessageTemplateEnum.java +++ b/common/src/main/java/com/sdm/common/entity/enums/MessageTemplateEnum.java @@ -6,6 +6,7 @@ package com.sdm.common.entity.enums; public enum MessageTemplateEnum { TASK_ISSUE("任务通知", "收到一条下发的新任务:%s,请前去[任务管理-我执行的]进行处理"), + DATA_ALERT("数据通知", "您的数据存储空间已达阈值,可前往[系统管理-数据存储-存储设置]查看"), HPC_START("作业通知", "作业已发起"), HPC_END("作业通知", "作业已结束") ; diff --git a/data/src/main/java/com/sdm/data/job/DataStorageMonitorJob.java b/data/src/main/java/com/sdm/data/job/DataStorageMonitorJob.java new file mode 100644 index 00000000..2a92afe9 --- /dev/null +++ b/data/src/main/java/com/sdm/data/job/DataStorageMonitorJob.java @@ -0,0 +1,55 @@ +package com.sdm.data.job; + + +import com.alibaba.fastjson2.JSON; +import com.sdm.common.common.SdmResponse; +import com.sdm.common.common.ThreadLocalContext; +import com.sdm.common.entity.enums.MessageTemplateEnum; +import com.sdm.common.entity.req.system.SendMsgReq; +import com.sdm.common.feign.impl.system.MessageFeignClientImpl; +import com.sdm.data.model.entity.FileStorageQuota; +import com.sdm.data.service.DataStorageAnalysis; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +@RequiredArgsConstructor +public class DataStorageMonitorJob { + + private final DataStorageAnalysis dataStorageAnalysis; + private final MessageFeignClientImpl messageFeignClient; + + /** + * 定时筛选存储空间达到阈值的用户 发送告警消息 + */ + @Scheduled(cron = "${data.storage-monitor.cron:0 */1 * * * ?}") + public void checkDataStorageSpaceAndSendAlert() { + log.info("开始执行定时筛选存储空间达到阈值的用户任务"); + try { + SdmResponse> sdmResponse = dataStorageAnalysis.listAllUserQuotaForJob(); + if (CollectionUtils.isNotEmpty(sdmResponse.getData())) { + List fileStorageQuotaList = sdmResponse.getData(); + fileStorageQuotaList.forEach(quota -> { + SendMsgReq req = new SendMsgReq(); + req.setTitle(MessageTemplateEnum.DATA_ALERT.getTitle()); + req.setContent(MessageTemplateEnum.DATA_ALERT.getContent()); + req.setTenantId(String.valueOf(quota.getTenantId())); + req.setUserId(String.valueOf(quota.getUserId())); + log.info("[DataStorageMonitorJob] checkDataStorageSpaceAndSendAlert param:{}", JSON.toJSONString(req)); + messageFeignClient.sendMessage(req); + }); + } + log.info("定时筛选存储空间达到阈值的用户任务执行完成"); + } catch (Exception e) { + log.error("定时筛选存储空间达到阈值的用户任务执行失败", e); + } + + } + +} diff --git a/data/src/main/java/com/sdm/data/service/DataStorageAnalysis.java b/data/src/main/java/com/sdm/data/service/DataStorageAnalysis.java index c13629ce..2892ea72 100644 --- a/data/src/main/java/com/sdm/data/service/DataStorageAnalysis.java +++ b/data/src/main/java/com/sdm/data/service/DataStorageAnalysis.java @@ -3,6 +3,7 @@ package com.sdm.data.service; import com.sdm.common.common.SdmResponse; import com.sdm.common.entity.resp.PageDataResp; import com.sdm.data.model.entity.FileStorage; +import com.sdm.data.model.entity.FileStorageQuota; import com.sdm.data.model.req.AddUserQuotaEntity; import com.sdm.data.model.req.ListUserQuotaReq; import com.sdm.data.model.req.QueryBigFileReq; @@ -45,4 +46,6 @@ public interface DataStorageAnalysis { List getListBigFileId(QueryBigFileReq queryBigFileReq); + SdmResponse> listAllUserQuotaForJob(); + } diff --git a/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java b/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java index cfe580ee..d3943926 100644 --- a/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java +++ b/data/src/main/java/com/sdm/data/service/impl/DataStorageAnalysisImpl.java @@ -1,5 +1,6 @@ package com.sdm.data.service.impl; +import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson2.JSONObject; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; @@ -35,6 +36,7 @@ import org.springframework.util.CollectionUtils; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @@ -280,7 +282,7 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { // 构造最终结果,对于没有配额信息的用户添加默认值,并根据已使用存储量设置状态 List fullList = userIds.stream().map(userId -> { - FileStorageQuota quota = quotaMap.getOrDefault(userId, createDefaultFileStorageQuota(userId)); + FileStorageQuota quota = quotaMap.getOrDefault(userId, createDefaultFileStorageQuota(userId, tenantId)); // 设置已使用值 UserTotalFileSizeDTO usedStorage = usedStorageMap.get(userId); if (usedStorage != null) { @@ -324,13 +326,18 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { } // 辅助方法:创建默认的 FileStorageQuota 实例 - private FileStorageQuota createDefaultFileStorageQuota(Long userId) { + private FileStorageQuota createDefaultFileStorageQuota(Long userId, Long tenantId) { FileStorageQuota defaultQuota = new FileStorageQuota(); defaultQuota.setUserId(userId); + defaultQuota.setTenantId(tenantId); defaultQuota.setQuotaValue(2L); // 默认存储阈值 defaultQuota.setQuotaUnit("GB"); // 默认单位 defaultQuota.setUsedValue(0L); // 默认已使用值 defaultQuota.setStatus("NORMAL"); // 默认状态 + // 初始化到表里 存储告警查询使用 + if (CollectionUtils.isEmpty(fileStorageQuotaService.lambdaQuery().eq(FileStorageQuota::getUserId, userId).list())) { + fileStorageQuotaService.save(defaultQuota); + } return defaultQuota; } @@ -376,4 +383,26 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis { .map(FileStorage::getFileId) .collect(Collectors.toList()); } + + @Override + public SdmResponse> listAllUserQuotaForJob() { + List quotaList = fileStorageQuotaService.list(); + for (FileStorageQuota quota : quotaList) { + // fileStorageService 查询用户已使用的存储空间 + List userStorageList = fileStorageService.getTotalFileSizeByCreator(Arrays.asList(quota.getUserId()), null,quota.getTenantId()); + if (CollUtil.size(userStorageList) > 0) { + UserTotalFileSizeDTO usedStorage = userStorageList.get(0); + quota.setUsedValue(usedStorage.getTotalSize()); + // 根据配额和已使用量设置状态 + if (quota.getQuotaValue() != null && quota.getUsedValue() != null) { + // 将配额值转换为与已使用值相同的单位(字节)进行比较 + long quotaInBytes = convertToBytes(quota.getQuotaValue(), quota.getQuotaUnit()); + if (quotaInBytes <= quota.getUsedValue()) { + quota.setStatus("EXCEED"); + } + } + } + } + return SdmResponse.success(quotaList.stream().filter(i -> "EXCEED".equals(i.getStatus())).toList()); + } } \ No newline at end of file diff --git a/data/src/main/java/com/sdm/data/service/impl/DimensionTemplateServiceImpl.java b/data/src/main/java/com/sdm/data/service/impl/DimensionTemplateServiceImpl.java index a3a81e1e..9b7de3cb 100644 --- a/data/src/main/java/com/sdm/data/service/impl/DimensionTemplateServiceImpl.java +++ b/data/src/main/java/com/sdm/data/service/impl/DimensionTemplateServiceImpl.java @@ -14,8 +14,12 @@ import com.sdm.common.entity.req.data.DelDirReq; import com.sdm.common.entity.req.data.DelFileReq; import com.sdm.common.entity.req.data.UploadFilesReq; import com.sdm.common.entity.req.project.DelNodeReq; +import com.sdm.common.entity.req.system.UserQueryReq; import com.sdm.common.entity.resp.AllNodeByProjectIdAndTypeResp; +import com.sdm.common.entity.resp.system.CIDUserResp; import com.sdm.common.feign.impl.project.SimulationNodeFeignClientImpl; +import com.sdm.common.feign.impl.system.SysUserFeignClientImpl; +import com.sdm.common.utils.CidSysUserUtil; import com.sdm.common.utils.PageUtils; import com.sdm.data.model.entity.DimensionTemplate; import com.sdm.data.dao.DimensionTemplateMapper; @@ -40,9 +44,7 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Stream; /** @@ -68,6 +70,9 @@ public class DimensionTemplateServiceImpl extends ServiceImpl fileMetadataInfos = fileMetadataInfoService.listSimulationNodeFiles(parentDirId, dirInfos,req.isFilterEmptyData(),tenantId); + setCreatorNames(fileMetadataInfos); PageInfo page = new PageInfo<>(fileMetadataInfos); return PageUtils.getJsonObjectSdmResponse(fileMetadataInfos, page); } + private void setCreatorNames(List list) { + try { + if (ObjectUtils.isNotEmpty(list)) { + // 提取去重的 creatorId + List creatorIds = list.stream() + .map(FileMetadataInfo::getCreatorId) + .filter(Objects::nonNull) + .distinct() + .toList(); + + // 远程查询用户信息 + SdmResponse> userListSdmRsp = sysUserFeignClient.listUserByIds( + UserQueryReq.builder().userIds(creatorIds).build() + ); + // 批量设置 creatorName + if (userListSdmRsp.isSuccess() && CollectionUtils.isNotEmpty(userListSdmRsp.getData())) { + Map cidUserMap = CidSysUserUtil.getCidUserToMap(userListSdmRsp.getData()); + list.forEach(fileMetadataInfo -> { + Long creatorId = fileMetadataInfo.getCreatorId(); + CIDUserResp cidUser = cidUserMap.get(creatorId); + String username = Objects.isNull(cidUser) ? "" : org.apache.commons.lang3.StringUtils.firstNonBlank( + cidUser.getNickname(), + cidUser.getUsername(), + cidUser.getRealName() + ); + fileMetadataInfo.setCreatorName(username); + }); + } + } + } catch (Exception e) { + log.error("setCreatorNames error:{}",e.getMessage()); + } + } + @Override public SdmResponse createSimulationNodeDir(CreateDirReq req) { req.setDirType(DirTypeEnum.PROJECT_NODE_DIR.getValue()); diff --git a/data/src/main/resources/application-dev.yml b/data/src/main/resources/application-dev.yml index 7884761b..ce0385e3 100644 --- a/data/src/main/resources/application-dev.yml +++ b/data/src/main/resources/application-dev.yml @@ -125,4 +125,8 @@ security: - /data/downloadFile - /data/flowableUpFileToLocal - /data/flowableUpFileToLocalMerge - - /data/getFileBaseInfo \ No newline at end of file + - /data/getFileBaseInfo + +data: + storage-monitor: + cron: 0 0 9 * * ? \ No newline at end of file diff --git a/data/src/main/resources/application-local.yml b/data/src/main/resources/application-local.yml index 6927727e..612ed5d3 100644 --- a/data/src/main/resources/application-local.yml +++ b/data/src/main/resources/application-local.yml @@ -132,6 +132,10 @@ security: - /data/flowableUpFileToLocalMerge - /data/getFileBaseInfo +data: + storage-monitor: + cron: 0 0 9 * * ? + # 0单机处理,可以指向本地,1负载均衡轮询 serverType: 0 #serverIp: 192.168.65.161 diff --git a/project/src/main/java/com/sdm/project/controller/SimulationRunController.java b/project/src/main/java/com/sdm/project/controller/SimulationRunController.java index b6a19313..df090aef 100644 --- a/project/src/main/java/com/sdm/project/controller/SimulationRunController.java +++ b/project/src/main/java/com/sdm/project/controller/SimulationRunController.java @@ -16,6 +16,7 @@ import com.sdm.project.model.entity.SimulationRun; import com.sdm.project.model.entity.SimulationRunKeyResult; import com.sdm.project.model.req.*; import com.sdm.project.model.req.*; +import com.sdm.project.model.resp.FlowInfoDto; import com.sdm.project.model.resp.KeyResultAndTaskInfoResp; import com.sdm.project.model.resp.RunVersionInfoResp; import com.sdm.project.service.ISimulationRunService; @@ -230,7 +231,7 @@ public class SimulationRunController implements ISimulationRunFeignClient { * 任务执行 查询流程节点列表 */ @PostMapping("/listFlowNodes") - public SdmResponse> listFlowNodes(@RequestBody SpdmTaskRunReq req) { + public SdmResponse listFlowNodes(@RequestBody SpdmTaskRunReq req) { return runService.listFlowNodes(req); } diff --git a/project/src/main/java/com/sdm/project/model/resp/FlowInfoDto.java b/project/src/main/java/com/sdm/project/model/resp/FlowInfoDto.java new file mode 100644 index 00000000..513e51bf --- /dev/null +++ b/project/src/main/java/com/sdm/project/model/resp/FlowInfoDto.java @@ -0,0 +1,15 @@ +package com.sdm.project.model.resp; + +import com.sdm.common.entity.flowable.dto.ProcessInstanceInfo; +import com.sdm.common.entity.req.capability.FlowNodeDto; +import lombok.Data; + +import java.util.List; + +@Data +public class FlowInfoDto { + + private ProcessInstanceInfo processInfo; + private List flowNodeDtoList; + +} diff --git a/project/src/main/java/com/sdm/project/service/ISimulationRunService.java b/project/src/main/java/com/sdm/project/service/ISimulationRunService.java index acaec66c..b4a610c4 100644 --- a/project/src/main/java/com/sdm/project/service/ISimulationRunService.java +++ b/project/src/main/java/com/sdm/project/service/ISimulationRunService.java @@ -14,6 +14,7 @@ import com.sdm.project.model.entity.SimulationRun; import com.baomidou.mybatisplus.extension.service.IService; import com.sdm.project.model.entity.SimulationRunKeyResult; import com.sdm.project.model.req.*; +import com.sdm.project.model.resp.FlowInfoDto; import com.sdm.project.model.resp.KeyResultAndTaskInfoResp; import com.sdm.project.model.resp.RunVersionInfoResp; import jakarta.servlet.http.HttpServletResponse; @@ -68,5 +69,5 @@ public interface ISimulationRunService extends IService { SdmResponse saveNodeParams(SpdmNodeParamReq req); - SdmResponse> listFlowNodes(SpdmTaskRunReq req); + SdmResponse listFlowNodes(SpdmTaskRunReq req); } 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 68541fb2..9cd4304e 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 @@ -47,6 +47,7 @@ import com.sdm.project.model.po.ProjectNodePo; import com.sdm.project.model.po.RunNodePo; import com.sdm.project.model.po.TaskNodePo; import com.sdm.project.model.req.*; +import com.sdm.project.model.resp.FlowInfoDto; import com.sdm.project.model.resp.KeyResultAndTaskInfoResp; import com.sdm.project.model.resp.RunVersionInfoResp; import com.sdm.project.service.*; @@ -1254,7 +1255,8 @@ public class SimulationRunServiceImpl extends ServiceImpl> listFlowNodes(SpdmTaskRunReq req) { + public SdmResponse listFlowNodes(SpdmTaskRunReq req) { + FlowInfoDto flowInfoDto = new FlowInfoDto(); FlowNodeDto nodeReq = new FlowNodeDto(); nodeReq.setRunId(req.getRunId()); SdmResponse> sdmResponse = flowFeignClient.listSimulationFlowNode(nodeReq); @@ -1263,6 +1265,7 @@ public class SimulationRunServiceImpl extends ServiceImpl response = flowableFeignClient.getProcessAndNodeDetailByInstanceId(simulationRun.getProcessDefinitionId(), simulationRun.getFlowInstanceId(), simulationRun.getUuid()); if (response.getData() != null && CollectionUtils.isNotEmpty(response.getData().getNodes())) { + flowInfoDto.setProcessInfo(response.getData().getProcessInfo()); for (FlowNodeDto flowNodeDto : flowNodeDtoList) { response.getData().getNodes().stream().filter(i -> StringUtils.equals(i.getId(), flowNodeDto.getNodeId())).findFirst().ifPresent(i -> { flowNodeDto.setNodeStatus(i.getStatus()); @@ -1278,10 +1281,10 @@ public class SimulationRunServiceImpl extends ServiceImpl()); + return SdmResponse.success(); } public static void deleteFolder(File folder) { diff --git a/system/src/main/resources/application-dev.yml b/system/src/main/resources/application-dev.yml index 8e4d8790..5103d5d6 100644 --- a/system/src/main/resources/application-dev.yml +++ b/system/src/main/resources/application-dev.yml @@ -177,4 +177,5 @@ security: whitelist: paths: - /systemApprove/approveStatusNotice - - /user/getUserToken \ No newline at end of file + - /user/getUserToken + - /systemMsg/sendMessage \ No newline at end of file diff --git a/system/src/main/resources/application-local.yml b/system/src/main/resources/application-local.yml index abc62a85..78b0202f 100644 --- a/system/src/main/resources/application-local.yml +++ b/system/src/main/resources/application-local.yml @@ -173,6 +173,13 @@ cid: log: saveLog: /spdm-log/saveLog +security: + whitelist: + paths: + - /systemApprove/approveStatusNotice + - /user/getUserToken + - /systemMsg/sendMessage + # 0单机处理,可以指向本地,1负载均衡轮询 serverType: 0 #serverIp: 192.168.65.161