Merge branch 'main' of http://192.168.65.198:3000/toolchaintechnologycenter/spdm-backend
This commit is contained in:
6
.idea/MarsCodeWorkspaceAppSettings.xml
generated
Normal file
6
.idea/MarsCodeWorkspaceAppSettings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="com.codeverse.userSettings.MarscodeWorkspaceAppSettingsState">
|
||||
<option name="progress" value="1.0" />
|
||||
</component>
|
||||
</project>
|
||||
74
.qoder/rules/rule.md
Normal file
74
.qoder/rules/rule.md
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
trigger: manual
|
||||
|
||||
# Java 开发规范与重构指南
|
||||
|
||||
作为我的 AI 编程伙伴,请在生成、修改或评审代码时严格遵循以下 10 条核心原则:
|
||||
|
||||
### 1. 单一职责原则 (SRP)
|
||||
|
||||
* **规则**:一个方法只做一件事。
|
||||
* **实践**:如果方法逻辑过长,请通过**拆分职责明确的私有方法**(Private Methods)来解耦。
|
||||
* **目标**:提升代码的可读性和方法复用率。
|
||||
|
||||
### 2. 卫语句优先 (Guard Clauses)
|
||||
|
||||
* **规则**:减少 `if-else` 嵌套深度。
|
||||
* **实践**:使用**卫语句提前返回**(Early Return)。先处理异常分支和边界条件,核心逻辑放在方法最后。
|
||||
* **示例**:
|
||||
```java
|
||||
if (user == null) return;
|
||||
// 执行核心逻辑...
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3. 重复逻辑抽取
|
||||
|
||||
* **规则**:不要重复你自己 (DRY)。
|
||||
* **实践**:将频繁出现的**参数校验、类型转换、对象构建**等模式封装为公共工具类或私有通用方法。
|
||||
|
||||
### 4. 数据封装 (Encapsulation)
|
||||
|
||||
* **规则**:避免多个相关变量散落在方法参数中。
|
||||
* **实践**:如果多个变量在逻辑上高度相关(如 `startTime`, `endTime`),应**封装为内部类或 DTO 对象**。
|
||||
|
||||
### 5. 统一异常处理
|
||||
|
||||
* **规则**:禁止散乱的 try-catch。
|
||||
* **实践**:使用**通用的响应校验方法**或全局异常拦截器。确保错误码和错误信息在整个系统中保持一致。
|
||||
|
||||
### 6. 参数对象化
|
||||
|
||||
* **规则**:控制方法入参数量。
|
||||
* **实践**:当方法参数**超过 3 个**时,必须封装为 Request 对象或 Context 对象。
|
||||
|
||||
### 7. 语义化命名
|
||||
|
||||
* **规则**:变量名应具备自解释性。
|
||||
* **实践**:**变量即文档**。使用准确的动词+名词组合,避免使用 `a`, `b`, `list1` 等无意义命名。
|
||||
|
||||
### 8. 消灭魔术值 (Magic Values)
|
||||
|
||||
* **规则**:禁止在逻辑判断中直接使用硬编码的数字或字符串。
|
||||
* **实践**:全面**拥抱枚举 (Enum) 或常量 (Static Final)**。
|
||||
|
||||
### 9. 声明式编程
|
||||
|
||||
* **规则**:提升集合处理的可读性。
|
||||
* **实践**:优先使用 **Java Stream API** 或函数式编程替代复杂的 `for/while` 循环。
|
||||
|
||||
### 10. 智能注释
|
||||
|
||||
* **规则**:避免“无效注释”。
|
||||
* **实践**:不要解释代码在做什么(What),而是解释**为什么要这么做(Why)**。如果代码本身足够清晰,则无需注释。
|
||||
|
||||
---
|
||||
|
||||
**当你为我生成代码时,请先自检是否违反了上述规则。如果我提交的代码不符合这些原则,请主动提示并给出重构建议。**
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
//package com.sdm.common.config;//package com.sdm.project.config.mybatis;
|
||||
//
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.beans.factory.annotation.Qualifier;
|
||||
//import org.springframework.boot.ApplicationRunner;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
//import javax.sql.DataSource;
|
||||
//import java.sql.Connection;
|
||||
//
|
||||
//@Slf4j
|
||||
//@Configuration
|
||||
//public class DataSourcePreWarmer {
|
||||
//
|
||||
// @Bean
|
||||
// public ApplicationRunner secondDataSourcePreWarmer(
|
||||
// @Qualifier("secondDataSource") DataSource secondDataSource) {
|
||||
// return args -> {
|
||||
// try (Connection conn = secondDataSource.getConnection()) {
|
||||
// log.info("✅ secondDataSource 预热成功,连接已建立: {}", conn);
|
||||
// } catch (Exception e) {
|
||||
// log.error("❌ secondDataSource 预热失败", e);
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// public ApplicationRunner mainDataSourcePreWarmer(
|
||||
// @Qualifier("masterDataSource") DataSource master,
|
||||
// @Qualifier("slaveDataSource") DataSource slave) {
|
||||
// return args -> {
|
||||
// try {
|
||||
// try (Connection c1 = master.getConnection()) {
|
||||
// log.info("✅ masterDataSource 预热成功: {}", c1);
|
||||
// }
|
||||
// try (Connection c2 = slave.getConnection()) {
|
||||
// log.info("✅ slaveDataSource 预热成功: {}", c2);
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("❌ 主从数据源预热失败", e);
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.sdm.project.common;
|
||||
package com.sdm.common.entity.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Getter;
|
||||
* 指标完成情况状态枚举
|
||||
*/
|
||||
@Getter
|
||||
public enum RunPerformanceStatusEnum {
|
||||
public enum PerformanceStatusEnum {
|
||||
|
||||
UNCOMPLETED("未完成", "0"),
|
||||
NOT_STARTED("不合格", "1"),
|
||||
@@ -18,7 +18,7 @@ public enum RunPerformanceStatusEnum {
|
||||
|
||||
private final String code;
|
||||
|
||||
RunPerformanceStatusEnum(String name, String code) {
|
||||
PerformanceStatusEnum(String name, String code) {
|
||||
this.name = name;
|
||||
this.code = code;
|
||||
}
|
||||
@@ -51,4 +51,14 @@ public class SimulationRunFeignClientImpl implements ISimulationRunFeignClient {
|
||||
return SdmResponse.failed("内部调用生成自动化报告失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SdmResponse updateStatusByProcessInstanceId(String processInstanceId, Integer statusCode) {
|
||||
try {
|
||||
return simulationRunFeignClient.updateStatusByProcessInstanceId(processInstanceId, statusCode);
|
||||
} catch (Exception e) {
|
||||
log.error("根据流程实例ID更新算例状态失败: processInstanceId={}, statusCode={}", processInstanceId, statusCode, e);
|
||||
return SdmResponse.failed("更新算例状态失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,14 @@ public interface ISimulationRunFeignClient {
|
||||
@PostMapping("/run/generateReportInternal")
|
||||
SdmResponse<Void> generateReportInternal(@RequestBody SpdmReportReq req);
|
||||
|
||||
/**
|
||||
* 根据流程实例ID更新算例状态
|
||||
*
|
||||
* @param processInstanceId 流程实例ID
|
||||
* @param statusCode 状态值(RUNNING/SUSPENDED/COMPLETED/CANCELLED/ERROR)
|
||||
* @return SdmResponse
|
||||
*/
|
||||
@PostMapping("/run/updateStatusByProcessInstanceId")
|
||||
SdmResponse updateStatusByProcessInstanceId(@RequestParam String processInstanceId, @RequestParam Integer statusCode);
|
||||
|
||||
}
|
||||
36
common/src/main/java/com/sdm/common/utils/CommonUtils.java
Normal file
36
common/src/main/java/com/sdm/common/utils/CommonUtils.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.sdm.common.utils;
|
||||
|
||||
public class CommonUtils {
|
||||
|
||||
/**
|
||||
* 检查字符串是否为有效的数字格式
|
||||
*/
|
||||
public static boolean isValidNumberFormat(String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 支持:
|
||||
// 1. 整数:123, -123, +123
|
||||
// 2. 小数:123.45, .45, 123.
|
||||
// 3. 科学计数法:1.23e10, 1.23E-10
|
||||
// 4. 排除:空字符串、纯空格、多个小数点、非法字符
|
||||
|
||||
// 去除首尾空格
|
||||
str = str.trim();
|
||||
|
||||
// 检查是否为空
|
||||
if (str.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否只包含数字、小数点、正负号、e/E
|
||||
if (!str.matches("^[+-]?[\\d.eE]+$")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更精确的正则表达式
|
||||
return str.matches("^[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?$");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.sdm.flowable.config;
|
||||
|
||||
import com.sdm.flowable.listener.GlobalStatusEventListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.flowable.spring.boot.EngineConfigurationConfigurer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Flowable流程引擎配置类
|
||||
* 用于注册全局事件监听器等配置
|
||||
*
|
||||
* @author SDM
|
||||
* @date 2026-01-23
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class FlowableEngineConfig {
|
||||
|
||||
/**
|
||||
* 注册全局事件监听器
|
||||
* 通过EngineConfigurationConfigurer可以在流程引擎初始化时添加监听器
|
||||
*/
|
||||
@Bean
|
||||
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> globalEventListenerConfigurer(
|
||||
GlobalStatusEventListener globalStatusEventListener) {
|
||||
return engineConfiguration -> {
|
||||
// 获取现有的事件监听器列表
|
||||
List<FlowableEventListener> eventListeners = engineConfiguration.getEventListeners();
|
||||
if (eventListeners == null) {
|
||||
eventListeners = new ArrayList<>();
|
||||
}
|
||||
|
||||
// 添加全局状态同步监听器
|
||||
eventListeners.add(globalStatusEventListener);
|
||||
engineConfiguration.setEventListeners(eventListeners);
|
||||
|
||||
log.info("✅ 已注册Flowable全局事件监听器: GlobalStatusEventListener");
|
||||
log.info(" 监听事件类型: PROCESS_COMPLETED, PROCESS_CANCELLED, ENTITY_SUSPENDED, ENTITY_ACTIVATED, JOB_MOVED_TO_DEADLETTER");
|
||||
log.info(" 状态映射: COMPLETED, CANCELLED, SUSPENDED, RUNNING, ERROR");
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public class HpcHandler implements ExecutionHandler<Map<String, Object>,HPCExecu
|
||||
if(!submitResp.isSuccess()|| StringUtils.isBlank(submitResp.getData())){
|
||||
// 推送失败消息
|
||||
sendMsg(ThreadLocalContext.getTenantId(),ThreadLocalContext.getUserId(),submitHpcTaskRemoteReq.getJobName(),"失败");
|
||||
log.error("HpcHandler submit failed,jobName:{}",params);
|
||||
log.error("HpcHandler submit failed:{}",JSONObject.toJSONString(params));
|
||||
throw new RuntimeException("HpcHandler submit failed,"+submitResp.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,35 +7,43 @@ public enum ProcessInstanceStateEnum {
|
||||
/**
|
||||
* 运行中
|
||||
*/
|
||||
RUNNING("running"),
|
||||
RUNNING(1,"running"),
|
||||
|
||||
/**
|
||||
* 已完成
|
||||
*/
|
||||
COMPLETED(2,"completed"),
|
||||
|
||||
/**
|
||||
* 错误
|
||||
*/
|
||||
ERROR(3,"error"),
|
||||
|
||||
/**
|
||||
* 挂起
|
||||
*/
|
||||
SUSPENDED("suspended"),
|
||||
|
||||
/**
|
||||
* 错误
|
||||
*/
|
||||
ERROR("error"),
|
||||
|
||||
/**
|
||||
* 已完成
|
||||
*/
|
||||
COMPLETED("completed"),
|
||||
SUSPENDED(4,"suspended"),
|
||||
|
||||
|
||||
/**
|
||||
* 已取消
|
||||
*/
|
||||
CANCELLED("cancelled");
|
||||
CANCELLED(5,"cancelled");
|
||||
|
||||
private final String code;
|
||||
private final Integer code;
|
||||
|
||||
ProcessInstanceStateEnum(String code) {
|
||||
private final String value;
|
||||
|
||||
ProcessInstanceStateEnum(Integer code, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.sdm.flowable.listener;
|
||||
|
||||
import com.sdm.common.feign.inter.project.ISimulationRunFeignClient;
|
||||
import com.sdm.flowable.enums.ProcessInstanceStateEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
|
||||
import org.flowable.job.api.Job;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 全局算例状态同步监听器
|
||||
* 作用:替代定时任务,实时推送状态
|
||||
* <p>
|
||||
* 监听Flowable流程引擎的全生命周期事件,实现算例状态的实时同步:
|
||||
* - PROCESS_COMPLETED: 流程正常完成
|
||||
* - PROCESS_CANCELLED: 流程被取消/终止
|
||||
* - ENTITY_SUSPENDED: 实体挂起(需过滤流程实例)
|
||||
* - ENTITY_ACTIVATED: 实体激活(需过滤流程实例)
|
||||
* - JOB_MOVED_TO_DEADLETTER: 作业移入死信队列(ERROR状态)
|
||||
* </p>
|
||||
*
|
||||
* @author SDM
|
||||
* @date 2026-01-23
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class GlobalStatusEventListener implements FlowableEventListener {
|
||||
|
||||
@Autowired
|
||||
private ISimulationRunFeignClient simulationRunFeignClient;
|
||||
|
||||
@Override
|
||||
public Set<FlowableEngineEventType> getTypes() {
|
||||
return new HashSet<>(Arrays.asList(
|
||||
FlowableEngineEventType.PROCESS_COMPLETED, // 流程完成
|
||||
FlowableEngineEventType.PROCESS_CANCELLED, // 流程取消(精确匹配,不需要判断deleteReason)
|
||||
FlowableEngineEventType.ENTITY_SUSPENDED, // 实体挂起(需过滤流程实例)
|
||||
FlowableEngineEventType.ENTITY_ACTIVATED, // 实体激活(需过滤流程实例)
|
||||
FlowableEngineEventType.JOB_MOVED_TO_DEADLETTER // 作业进入死信(ERROR状态)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(FlowableEvent event) {
|
||||
try {
|
||||
FlowableEngineEventType eventType = (FlowableEngineEventType) event.getType();
|
||||
|
||||
// 1. 流程正常完成
|
||||
if (eventType == FlowableEngineEventType.PROCESS_COMPLETED) {
|
||||
handleProcessCompleted((FlowableEngineEntityEvent) event);
|
||||
}
|
||||
// 2. 流程被取消(Flowable 7.x有独立的CANCELLED事件)
|
||||
else if (eventType == FlowableEngineEventType.PROCESS_CANCELLED) {
|
||||
handleProcessCancelled((FlowableEngineEntityEvent) event);
|
||||
}
|
||||
// 3. 实体挂起/激活(需要过滤,只处理流程实例级别)
|
||||
else if (eventType == FlowableEngineEventType.ENTITY_SUSPENDED ||
|
||||
eventType == FlowableEngineEventType.ENTITY_ACTIVATED) {
|
||||
handleSuspendOrActivate((FlowableEngineEntityEvent) event, eventType);
|
||||
}
|
||||
// 4. 作业进入死信队列(ERROR状态的金标准)
|
||||
else if (eventType == FlowableEngineEventType.JOB_MOVED_TO_DEADLETTER) {
|
||||
handleDeadLetter((FlowableEngineEntityEvent) event);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理Flowable事件异常: eventType={}", event.getType(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 内部逻辑方法 ---
|
||||
|
||||
/**
|
||||
* 处理流程正常完成事件
|
||||
* PROCESS_COMPLETED只表示流程走到EndEvent,不包括取消场景
|
||||
*/
|
||||
private void handleProcessCompleted(FlowableEngineEntityEvent event) {
|
||||
String processInstanceId = event.getProcessInstanceId();
|
||||
log.info("流程正常完成: processInstanceId={}", processInstanceId);
|
||||
doUpdate(processInstanceId, ProcessInstanceStateEnum.COMPLETED.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理流程取消事件
|
||||
* Flowable 7.x提供了独立的PROCESS_CANCELLED事件,更精确
|
||||
*/
|
||||
private void handleProcessCancelled(FlowableEngineEntityEvent event) {
|
||||
String processInstanceId = event.getProcessInstanceId();
|
||||
ExecutionEntity execution = (ExecutionEntity) event.getEntity();
|
||||
log.info("流程被取消: processInstanceId={}, deleteReason={}",
|
||||
processInstanceId, execution.getDeleteReason());
|
||||
doUpdate(processInstanceId, ProcessInstanceStateEnum.CANCELLED.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理实体挂起/激活事件
|
||||
* 关键:必须过滤,只处理流程实例级别的挂起/激活,忽略子流程或其他实体
|
||||
*/
|
||||
private void handleSuspendOrActivate(FlowableEngineEntityEvent event, FlowableEngineEventType eventType) {
|
||||
Object entity = event.getEntity();
|
||||
|
||||
// 只处理ExecutionEntity(流程执行实体)
|
||||
if (entity instanceof ExecutionEntity) {
|
||||
ExecutionEntity execution = (ExecutionEntity) entity;
|
||||
|
||||
// 关键判断:isProcessInstanceType()确保是流程实例本身,而非子分支
|
||||
if (execution.isProcessInstanceType()) {
|
||||
String processInstanceId = execution.getProcessInstanceId();
|
||||
Integer status = (eventType == FlowableEngineEventType.ENTITY_SUSPENDED) ? ProcessInstanceStateEnum.SUSPENDED.getCode() : ProcessInstanceStateEnum.RUNNING.getCode();
|
||||
|
||||
log.info("流程实例{}状态变更: processInstanceId={}",
|
||||
status.equals("SUSPENDED") ? "挂起" : "激活", processInstanceId);
|
||||
doUpdate(processInstanceId, status);
|
||||
} else {
|
||||
log.debug("忽略非流程实例级别的挂起/激活事件: executionId={}", execution.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理死信事件(ERROR状态的标准方式)
|
||||
* JOB_MOVED_TO_DEADLETTER是最精确的ERROR信号:
|
||||
* - 比JOB_EXECUTION_FAILURE准确(FAILURE只是重试中的失败)
|
||||
* - 表示引擎已放弃重试,必须人工干预
|
||||
* <p>
|
||||
* 前提条件:ServiceTask必须配置async="true"和R0/PT0S重试策略
|
||||
*/
|
||||
private void handleDeadLetter(FlowableEngineEntityEvent event) {
|
||||
Object entity = event.getEntity();
|
||||
|
||||
if (entity instanceof Job) {
|
||||
Job job = (Job) entity;
|
||||
String processInstanceId = job.getProcessInstanceId();
|
||||
String exceptionMessage = job.getExceptionMessage();
|
||||
|
||||
log.error("❌ 作业进入死信队列,流程ERROR: processInstanceId={}, jobId={}, exception={}",
|
||||
processInstanceId, job.getId(), exceptionMessage);
|
||||
|
||||
doUpdate(processInstanceId, ProcessInstanceStateEnum.ERROR.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正的更新数据库逻辑
|
||||
* 通过Feign调用project服务更新算例状态
|
||||
*/
|
||||
private void doUpdate(String processInstanceId, Integer statusCode) {
|
||||
if (processInstanceId == null) {
|
||||
log.warn("流程实例ID为空,跳过状态更新");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(">>> 更新算例状态 [{}] -> {}", processInstanceId, statusCode);
|
||||
try {
|
||||
simulationRunFeignClient.updateStatusByProcessInstanceId(processInstanceId, statusCode);
|
||||
} catch (Exception e) {
|
||||
log.error("更新算例状态失败: processInstanceId={}, status={}", processInstanceId, statusCode, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFailOnException() {
|
||||
// 返回false:即使监听器抛异常,也不影响流程继续执行
|
||||
// 这是容错设计,保证业务流程的稳定性
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFireOnTransactionLifecycleEvent() {
|
||||
// 返回false:在事务提交前触发,确保状态及时更新
|
||||
// 如果返回true,监听器会在事务提交后触发,可能导致状态更新滞后
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOnTransaction() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -472,11 +472,11 @@ public class ProcessService implements Iprocess{
|
||||
if (isRunning) {
|
||||
// --- 运行中 ---
|
||||
if (hasError) {
|
||||
status = ProcessInstanceStateEnum.ERROR.getCode(); // 有死信作业,视为异常
|
||||
status = ProcessInstanceStateEnum.ERROR.getValue(); // 有死信作业,视为异常
|
||||
} else if (isSuspended) {
|
||||
status = ProcessInstanceStateEnum.SUSPENDED.getCode(); // 被挂起
|
||||
status = ProcessInstanceStateEnum.SUSPENDED.getValue(); // 被挂起
|
||||
} else {
|
||||
status = ProcessInstanceStateEnum.RUNNING.getCode(); // 正常运行
|
||||
status = ProcessInstanceStateEnum.RUNNING.getValue(); // 正常运行
|
||||
}
|
||||
} else {
|
||||
// --- 已结束 (运行时查不到,历史表里有) ---
|
||||
@@ -484,11 +484,11 @@ public class ProcessService implements Iprocess{
|
||||
|
||||
if (deleteReason == null) {
|
||||
// 1. 正常走完结束节点,deleteReason 为空
|
||||
status = ProcessInstanceStateEnum.COMPLETED.getCode();
|
||||
status = ProcessInstanceStateEnum.COMPLETED.getValue();
|
||||
} else {
|
||||
// 2. 有删除原因,说明是被取消或强制终止的
|
||||
// 你可以根据 reason 的内容做更细的区分,或者统称为 cancelled
|
||||
status = ProcessInstanceStateEnum.CANCELLED.getCode();
|
||||
status = ProcessInstanceStateEnum.CANCELLED.getValue();
|
||||
}
|
||||
}
|
||||
info.setStatus(status);
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package com.sdm.outbridge.config; //// common模块:com.xxx.common.config.CommonConfig
|
||||
|
||||
import com.sdm.common.utils.AESUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.env.YamlPropertySourceLoader;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.io.support.DefaultPropertySourceFactory;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 加载common模块的自定义配置文件
|
||||
@@ -25,7 +31,48 @@ public class CommonConfig {
|
||||
}
|
||||
List<org.springframework.core.env.PropertySource<?>> sources = new YamlPropertySourceLoader()
|
||||
.load(resource.getResource().getFilename(), resource.getResource());
|
||||
return sources.get(0);
|
||||
org.springframework.core.env.PropertySource<?> originalSource = sources.get(0);
|
||||
org.springframework.core.env.PropertySource<?> decryptedSource =
|
||||
decryptPropertySource(originalSource);
|
||||
return decryptedSource;
|
||||
}
|
||||
}
|
||||
|
||||
private static org.springframework.core.env.PropertySource<?> decryptPropertySource(org.springframework.core.env.PropertySource<?> source) {
|
||||
// 只处理可枚举的属性源(yml加载后的源都是EnumerablePropertySource)
|
||||
if (!(source instanceof EnumerablePropertySource)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
EnumerablePropertySource<?> enumerableSource = (EnumerablePropertySource<?>) source;
|
||||
Map<String, Object> decryptedProperties = new HashMap<>();
|
||||
// 遍历所有配置项
|
||||
for (String propertyName : enumerableSource.getPropertyNames()) {
|
||||
Object value = enumerableSource.getProperty(propertyName);
|
||||
if (value != null && value instanceof String) {
|
||||
String strValue = (String) value;
|
||||
if (strValue.startsWith("ENC(") && strValue.endsWith(")")) {
|
||||
// 解密并替换值
|
||||
String spdmEnkey = StringUtils.isBlank(System.getProperty("spdm.enkey"))?
|
||||
System.getenv("spdm.enkey"):System.getProperty("spdm.enkey");
|
||||
String encryptedValue = strValue.substring(4, strValue.length() - 1);
|
||||
try {
|
||||
decryptedProperties.put(propertyName, AESUtil.decodeNew(encryptedValue, spdmEnkey));
|
||||
} catch (Exception e) {
|
||||
System.out.println("利元亨现场配置解密异常:"+e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
// 非加密值,直接保留
|
||||
decryptedProperties.put(propertyName, strValue);
|
||||
}
|
||||
} else {
|
||||
// 非字符串类型,直接保留
|
||||
decryptedProperties.put(propertyName, value);
|
||||
}
|
||||
}
|
||||
// 生成新的属性源(名称和原始源一致,确保覆盖)
|
||||
return new MapPropertySource(source.getName(), decryptedProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@ spring:
|
||||
datasource:
|
||||
second:
|
||||
username: EP_DM
|
||||
password: ENC(c04rt9Z6Ygz024EU9eWvig==)
|
||||
password: EP_DM@123.COM
|
||||
# todo 生产地址
|
||||
jdbc-url: jdbc:mysql://10.122.48.11:13306/easy_project?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
@@ -178,6 +178,7 @@ public class SimulationNodeController implements ISimulationNodeFeignClient {
|
||||
@PostMapping("/getAllUserTaskCompleteStatistics")
|
||||
@Operation(summary = "所有项目的人员任务完成情况统计", description = "所有项目的人员任务完成情况统计")
|
||||
public SdmResponse getAllUserTaskCompleteStatistics(@RequestBody @Validated GetAllUserTaskCompleteStatisticsReq req) {
|
||||
req.setTenantId(ThreadLocalContext.getTenantId());
|
||||
return nodeService.getAllUserTaskCompleteStatistics(req);
|
||||
}
|
||||
|
||||
@@ -188,7 +189,7 @@ public class SimulationNodeController implements ISimulationNodeFeignClient {
|
||||
@GetMapping("/getUserGroupProjectStatistics")
|
||||
@Operation(summary = "用户组项目统计", description = "用户组项目统计")
|
||||
public SdmResponse getUserGroupProjectStatistics(@Parameter(description = "用户组ID")@RequestParam( value = "userGroupId" )@NotNull(message = "用户组ID(userGroupId)为必传参数,请补充后重试") Long userGroupId, @Parameter(description = "用户ID")@RequestParam( value = "userId", required = false) Long userId) {
|
||||
return nodeService.getUserGroupProjectStatistics(userGroupId,userId);
|
||||
return nodeService.getUserGroupProjectStatistics(userGroupId,userId,ThreadLocalContext.getTenantId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,6 +202,7 @@ public class SimulationNodeController implements ISimulationNodeFeignClient {
|
||||
@PostMapping("/getUserGroupTaskCompleteStatistics")
|
||||
@Operation(summary = "用户组任务完成情况统计", description = "用户组任务完成情况统计")
|
||||
public SdmResponse getUserGroupTaskCompleteStatistics(@RequestBody @Validated GetUserGroupTaskCompleteStatisticsReq req) {
|
||||
req.setTenantId(ThreadLocalContext.getTenantId());
|
||||
return nodeService.getUserGroupTaskCompleteStatistics(req);
|
||||
}
|
||||
|
||||
|
||||
@@ -240,8 +240,8 @@ public class SimulationRunController implements ISimulationRunFeignClient {
|
||||
*/
|
||||
@PostMapping("/editReport")
|
||||
@Operation(summary = "编辑报告模板生成报告", description = "编辑报告模板生成报告")
|
||||
public void editReport(@RequestBody EditReportReq req) {
|
||||
runService.editReport(req);
|
||||
public SdmResponse editReport(@RequestBody EditReportReq req) {
|
||||
return runService.editReport(req);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,4 +395,13 @@ public class SimulationRunController implements ISimulationRunFeignClient {
|
||||
return runService.syncKeyResultToTask(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程实例ID更新算例状态 (内部调用)
|
||||
* 由Flowable全局事件监听器调用
|
||||
*/
|
||||
@PostMapping("/updateStatusByProcessInstanceId")
|
||||
public SdmResponse updateStatusByProcessInstanceId(@RequestParam String processInstanceId, @RequestParam Integer statusCode) {
|
||||
return runService.updateStatusByProcessInstanceId(processInstanceId, statusCode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public interface SimulationNodeMapper extends BaseMapper<SimulationNode> {
|
||||
|
||||
List<SpdmNodeVo> getNodeListByIds(@Param("nodeIdList") List<String> nodeIdList);
|
||||
|
||||
List<UserGroupProjectVo> getUserGroupProjectStatistics(@Param("userIds")Set<Long> userIds );
|
||||
List<UserGroupProjectVo> getUserGroupProjectStatistics(@Param("userIds")Set<Long> userIds, @Param("tenantId")Long tenantId);
|
||||
|
||||
List<UserGroupTaskCompleteVo> getUserGroupTaskCompleteStatistics(@Param("req") GetUserGroupTaskCompleteStatisticsReq req);
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.util.List;
|
||||
@Data
|
||||
@Schema(description = "所有项目的人员任务完成情况统计")
|
||||
public class GetAllUserTaskCompleteStatisticsReq {
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "用户列表")
|
||||
private List<Long> userIds;
|
||||
|
||||
@@ -20,6 +20,9 @@ public class GetUserGroupTaskCompleteStatisticsReq {
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "用户")
|
||||
private Set<Long> userIds;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public interface INodeService extends IService<SimulationNode> {
|
||||
|
||||
SdmResponse<List<AllNodeByProjectIdAndTypeResp>> getTaskRunList(List<String> uuids);
|
||||
|
||||
SdmResponse getUserGroupProjectStatistics(Long userGroupId, Long userId);
|
||||
SdmResponse getUserGroupProjectStatistics(Long userGroupId, Long userId,Long tenantId);
|
||||
|
||||
SdmResponse getUserGroupTaskCompleteStatistics(GetUserGroupTaskCompleteStatisticsReq req);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public interface ISimulationRunService extends IService<SimulationRun> {
|
||||
|
||||
void generateNewReport(SpdmReportReq req, HttpServletResponse response);
|
||||
|
||||
void editReport(EditReportReq req);
|
||||
SdmResponse editReport(EditReportReq req);
|
||||
|
||||
void editReportAndDownload(EditReportReq req, HttpServletResponse response);
|
||||
|
||||
@@ -110,4 +110,12 @@ public interface ISimulationRunService extends IService<SimulationRun> {
|
||||
|
||||
SdmResponse syncKeyResultToTask(KeyResultReq req);
|
||||
|
||||
/**
|
||||
* 根据流程实例ID更新算例状态
|
||||
* @param processInstanceId 流程实例ID
|
||||
* @param statusCode 状态值(RUNNING/SUSPENDED/COMPLETED/CANCELLED/ERROR)
|
||||
* @return SdmResponse
|
||||
*/
|
||||
SdmResponse updateStatusByProcessInstanceId(String processInstanceId, Integer statusCode);
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import com.sdm.common.common.ResultCode;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.entity.ExportExcelFormat;
|
||||
import com.sdm.common.entity.bo.DataDictionary;
|
||||
import com.sdm.common.entity.constants.TagConstant;
|
||||
import com.sdm.common.entity.enums.DirTypeEnum;
|
||||
import com.sdm.common.entity.enums.FilePermissionEnum;
|
||||
@@ -22,7 +21,6 @@ import com.sdm.common.entity.resp.AllNodeByProjectIdAndTypeResp;
|
||||
import com.sdm.common.entity.resp.PageDataResp;
|
||||
import com.sdm.common.entity.resp.project.SimulationNodeResp;
|
||||
import com.sdm.common.entity.resp.project.SimulationRunResp;
|
||||
import com.sdm.common.entity.resp.system.CIDStaffResp;
|
||||
import com.sdm.common.entity.resp.system.CIDUserResp;
|
||||
import com.sdm.common.entity.resp.system.SysUserGroupDetailResp;
|
||||
import com.sdm.common.feign.impl.data.DataClientFeignClientImpl;
|
||||
@@ -1440,7 +1438,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
}
|
||||
|
||||
@Override
|
||||
public SdmResponse getUserGroupProjectStatistics(Long userGroupId, Long userId) {
|
||||
public SdmResponse getUserGroupProjectStatistics(Long userGroupId, Long userId,Long tenantId) {
|
||||
Map<Long, String> userId2Nickname = getUserIdToNicknameMap(userGroupId);
|
||||
if (MapUtils.isEmpty(userId2Nickname)) {
|
||||
return SdmResponse.success();
|
||||
@@ -1453,7 +1451,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
userIds.add(userId);
|
||||
}
|
||||
|
||||
List<UserGroupProjectVo> userGroupProjectStatistics = this.baseMapper.getUserGroupProjectStatistics(userIds);
|
||||
List<UserGroupProjectVo> userGroupProjectStatistics = this.baseMapper.getUserGroupProjectStatistics(userIds,tenantId );
|
||||
if (CollectionUtils.isEmpty(userGroupProjectStatistics)) {
|
||||
return SdmResponse.success(new ArrayList<>());
|
||||
}
|
||||
|
||||
@@ -12,12 +12,8 @@ import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.config.FlowableConfig;
|
||||
import com.sdm.common.entity.constants.NumberConstants;
|
||||
import com.sdm.common.entity.enums.ApproveTypeEnum;
|
||||
import com.sdm.common.entity.enums.DirTypeEnum;
|
||||
import com.sdm.common.entity.enums.FileBizTypeEnum;
|
||||
import com.sdm.common.entity.enums.NodeTypeEnum;
|
||||
import com.sdm.common.entity.enums.*;
|
||||
import com.sdm.common.entity.flowable.dto.FlowElementDTO;
|
||||
import com.sdm.common.entity.flowable.dto.ProcessDefinitionDTO;
|
||||
import com.sdm.common.entity.req.capability.FlowNodeDto;
|
||||
@@ -60,7 +56,6 @@ import com.sdm.project.model.resp.KeyResultAndTaskInfoResp;
|
||||
import com.sdm.project.model.resp.RunVersionInfoResp;
|
||||
import com.sdm.project.model.vo.SpdmNodeVo;
|
||||
import com.sdm.common.entity.resp.project.SpdmTaskVo;
|
||||
import com.sdm.project.model.vo.SpdmTaskMemberVo;
|
||||
import com.sdm.project.service.*;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -84,7 +79,6 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sdm.common.service.BaseService.generateUuid;
|
||||
@@ -629,7 +623,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
runPerformance.setId(null);
|
||||
runPerformance.setRunId(simulationRun.getUuid());
|
||||
runPerformance.setUuid(RandomUtil.generateString(32));
|
||||
runPerformance.setCompleteStatus(RunPerformanceStatusEnum.UNCOMPLETED.getCode());
|
||||
runPerformance.setCompleteStatus(PerformanceStatusEnum.UNCOMPLETED.getCode());
|
||||
runPerformance.setCreator(userId);
|
||||
runPerformance.setCreateTime(null);
|
||||
runPerformanceList.add(runPerformance);
|
||||
@@ -1449,7 +1443,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
try {
|
||||
// 获取临时路径中脚本生成的报告
|
||||
String reportName = "report_" +
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) +
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +
|
||||
".docx";
|
||||
FileInputStream fileInputStream = new FileInputStream(TEMP_REPORT_PATH + randomId + File.separator + "report.docx");
|
||||
fileData = fileInputStream.readAllBytes();
|
||||
@@ -1561,7 +1555,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editReport(EditReportReq req) {
|
||||
public SdmResponse editReport(EditReportReq req) {
|
||||
log.info("编辑报告参数为:{}", req);
|
||||
SimulationRun simulationRun = this.lambdaQuery().eq(SimulationRun::getUuid, req.getRunId()).one();
|
||||
if (simulationRun != null) {
|
||||
@@ -1631,11 +1625,11 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
log.info("脚本运行状态:" + runningStatus);
|
||||
} catch (IOException | InterruptedException e) {
|
||||
log.error("执行脚本失败:" + e);
|
||||
return;
|
||||
return SdmResponse.failed("执行脚本失败");
|
||||
}
|
||||
if (runningStatus != 0) {
|
||||
log.error("执行脚本失败");
|
||||
return;
|
||||
return SdmResponse.failed("执行脚本失败");
|
||||
} else {
|
||||
log.info(commands + "执行脚本完成!");
|
||||
}
|
||||
@@ -1643,7 +1637,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
try {
|
||||
// 获取临时路径中脚本生成的报告
|
||||
String reportName = "report_" +
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) +
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +
|
||||
".docx";
|
||||
FileInputStream fileInputStream = new FileInputStream(TEMP_REPORT_PATH + randomId + File.separator + reportName);
|
||||
fileData = fileInputStream.readAllBytes();
|
||||
@@ -1667,15 +1661,17 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
throw new RuntimeException("生成自动化报告上传报告结果目录失败");
|
||||
}
|
||||
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("生成自动化报告失败");
|
||||
}
|
||||
// 删除临时路径
|
||||
log.info("删除临时路径:{},中。。。。。。", randomId);
|
||||
deleteFolder(new File(TEMP_REPORT_PATH + randomId));
|
||||
}
|
||||
}
|
||||
return SdmResponse.failed("算例不存在");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1762,7 +1758,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
try {
|
||||
// 获取临时路径中脚本生成的报告
|
||||
String reportName = "report_" +
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) +
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +
|
||||
".docx";
|
||||
FileInputStream fileInputStream = new FileInputStream(TEMP_REPORT_PATH + randomId + File.separator + reportName);
|
||||
fileData = fileInputStream.readAllBytes();
|
||||
@@ -2307,4 +2303,61 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
}
|
||||
return SdmResponse.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程实例ID更新算例状态
|
||||
* 由Flowable全局事件监听器调用,实现流程状态与算例状态的实时同步
|
||||
*
|
||||
* @param processInstanceId 流程实例ID
|
||||
* @param statusCode 状态值(RUNNING/SUSPENDED/COMPLETED/CANCELLED/ERROR)
|
||||
* @return SdmResponse
|
||||
*/
|
||||
@Override
|
||||
public SdmResponse updateStatusByProcessInstanceId(String processInstanceId, Integer statusCode) {
|
||||
log.info("根据流程实例ID更新算例状态: processInstanceId={}, statusCode={}", processInstanceId, statusCode);
|
||||
|
||||
if (StringUtils.isBlank(processInstanceId)) {
|
||||
log.error("流程实例ID为空");
|
||||
return SdmResponse.failed("流程实例ID为空");
|
||||
}
|
||||
|
||||
if (ObjectUtils.isEmpty(statusCode)) {
|
||||
log.error("状态值为空");
|
||||
return SdmResponse.failed("状态值为空");
|
||||
}
|
||||
|
||||
try {
|
||||
// 根据flowInstanceId查找算例
|
||||
SimulationRun run = this.lambdaQuery()
|
||||
.eq(SimulationRun::getFlowInstanceId, processInstanceId)
|
||||
.one();
|
||||
|
||||
if (run == null) {
|
||||
log.warn("未找到对应的算例: processInstanceId={}", processInstanceId);
|
||||
return SdmResponse.failed("未找到对应的算例");
|
||||
}
|
||||
|
||||
|
||||
// 更新算例状态
|
||||
boolean updated = this.lambdaUpdate()
|
||||
.set(SimulationRun::getStatus, statusCode)
|
||||
.set(SimulationRun::getUpdateTime, LocalDateTime.now())
|
||||
.set(statusCode.equals(RunStatusEnum.COMPLETED.getCode()) || statusCode.equals(RunStatusEnum.FAILED.getCode()),
|
||||
SimulationRun::getFinishTime, LocalDateTime.now())
|
||||
.eq(SimulationRun::getFlowInstanceId, processInstanceId)
|
||||
.update();
|
||||
|
||||
if (updated) {
|
||||
log.info("算例状态更新成功: runId={}, flowInstanceId={}, statusCode={}",
|
||||
run.getUuid(), processInstanceId, statusCode);
|
||||
return SdmResponse.success("状态更新成功");
|
||||
} else {
|
||||
log.error("算例状态更新失败: runId={}, flowInstanceId={}", run.getUuid(), processInstanceId);
|
||||
return SdmResponse.failed("状态更新失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新算例状态异常: processInstanceId={}, status={}", processInstanceId, statusCode, e);
|
||||
return SdmResponse.failed("更新状态异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ import com.sdm.common.utils.SystemOperate;
|
||||
import com.sdm.common.utils.excel.ExcelUtil;
|
||||
import com.sdm.project.bo.ExportOperate;
|
||||
import com.sdm.project.common.MemberTypeEnum;
|
||||
import com.sdm.project.common.RunPerformanceStatusEnum;
|
||||
import com.sdm.common.entity.enums.PerformanceStatusEnum;
|
||||
import com.sdm.project.common.TaskExeStatusEnum;
|
||||
import com.sdm.project.dao.SimulationDemandMapper;
|
||||
import com.sdm.project.dao.SimulationNodeMapper;
|
||||
@@ -2075,7 +2075,7 @@ public class TaskServiceImpl implements ITaskService {
|
||||
CommonGetCompleteFromPerformanceVo commonGetCompleteFromPerformanceVo = new CommonGetCompleteFromPerformanceVo();
|
||||
commonGetCompleteFromPerformanceVo.setNodeName(eachTaskVo.getDiscipline());
|
||||
commonGetCompleteFromPerformanceVo.setCompleteStatus(StringUtils.isNotBlank(performanceNodePo.getCompleteStatus()) ?
|
||||
performanceNodePo.getCompleteStatus() : RunPerformanceStatusEnum.UNCOMPLETED.getCode());
|
||||
performanceNodePo.getCompleteStatus() : PerformanceStatusEnum.UNCOMPLETED.getCode());
|
||||
commonCompleteStatisticsFromPerformance.add(commonGetCompleteFromPerformanceVo);
|
||||
}
|
||||
// 按tag分组统计指标状态
|
||||
@@ -2154,7 +2154,7 @@ public class TaskServiceImpl implements ITaskService {
|
||||
commonGetCompleteFromPerformanceVo.setTag(resultTagId);
|
||||
commonGetCompleteFromPerformanceVo.setNodeName(nodeMap.get(resultTagIdArr[resultTagIdArr.length - 1]));
|
||||
commonGetCompleteFromPerformanceVo.setCompleteStatus(StringUtils.isNotBlank(performanceNodePo.getCompleteStatus()) ?
|
||||
performanceNodePo.getCompleteStatus() : RunPerformanceStatusEnum.UNCOMPLETED.getCode());
|
||||
performanceNodePo.getCompleteStatus() : PerformanceStatusEnum.UNCOMPLETED.getCode());
|
||||
commonCompleteStatisticsFromPerformance.add(commonGetCompleteFromPerformanceVo);
|
||||
}
|
||||
// 按tag分组统计指标状态
|
||||
|
||||
@@ -339,7 +339,11 @@
|
||||
nodeId,
|
||||
user_id as userId
|
||||
from simulation_node_member
|
||||
where user_id in (
|
||||
left join simulation_node on simulation_node_member.nodeId = simulation_node.uuid
|
||||
where
|
||||
simulation_node.tenantId = #{tenantId}
|
||||
and
|
||||
user_id in (
|
||||
<foreach collection='userIds' item='userId' index='index' separator=','>
|
||||
#{userId}
|
||||
</foreach>
|
||||
@@ -354,6 +358,8 @@
|
||||
from simulation_task task
|
||||
left join simulation_task_member task_member on task.uuid = task_member.task_id
|
||||
<where>
|
||||
task.tenant_Id = #{req.tenantId}
|
||||
and
|
||||
task_member.user_id in
|
||||
(
|
||||
<foreach collection='req.userIds' item='userId' index='index' separator=','>
|
||||
@@ -406,7 +412,8 @@
|
||||
from simulation_task task
|
||||
left join simulation_task_member task_member on task.uuid = task_member.task_id
|
||||
<where>
|
||||
task_member.user_id in
|
||||
task.tenant_Id = #{req.tenantId}
|
||||
and task_member.user_id in
|
||||
(
|
||||
<foreach collection='req.userIds' item='userId' index='index' separator=','>
|
||||
#{userId}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -66,6 +67,9 @@ public class TaskPerformanceDto {
|
||||
@Schema(description = "标准")
|
||||
private String standard;
|
||||
|
||||
@Schema(description = "计算及结果值")
|
||||
private String resultValue;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private String tenantId;
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public class SimulationPerformance implements Serializable {
|
||||
@TableField("method")
|
||||
private String method;
|
||||
|
||||
@ApiModelProperty(value = "指标完成情况 未完成 不合格 风险可控 未分析 合格")
|
||||
@ApiModelProperty(value = "指标完成情况 未完成 不合格 风险可控 未分析 合格 ")
|
||||
@TableField("completeStatus")
|
||||
private String completeStatus;
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@ import com.alibaba.fastjson2.JSONArray;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.entity.ExportExcelFormat;
|
||||
import com.sdm.common.entity.enums.ApprovalFileDataStatusEnum;
|
||||
import com.sdm.common.entity.enums.PerformanceStatusEnum;
|
||||
import com.sdm.common.entity.req.data.KnowledgeExportExcelParam;
|
||||
import com.sdm.common.entity.req.performance.PerformanceExportExcelFormat;
|
||||
import com.sdm.common.entity.req.performance.PerformanceExportExcelParam;
|
||||
import com.sdm.common.entity.resp.PageDataResp;
|
||||
import com.sdm.common.entity.resp.task.PerformanceResp;
|
||||
import com.sdm.common.service.BaseService;
|
||||
import com.sdm.common.utils.CommonUtils;
|
||||
import com.sdm.common.utils.RandomUtil;
|
||||
import com.sdm.common.utils.excel.ExcelUtil;
|
||||
import com.sdm.task.model.dto.TaskPerformanceDto;
|
||||
@@ -31,7 +33,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -131,9 +135,48 @@ public class SimulationPerformanceServiceImpl extends ServiceImpl<SimulationPerf
|
||||
public SdmResponse editPerformance(TaskPerformanceDto performanceDto) {
|
||||
SimulationPerformance simulationPerformance = new SimulationPerformance();
|
||||
BeanUtils.copyProperties(performanceDto, simulationPerformance);
|
||||
// 目标值
|
||||
String targetValueStr = simulationPerformance.getTargetValue();
|
||||
// 分析值
|
||||
String resultValueStr = simulationPerformance.getResultValue();
|
||||
// 达标方式
|
||||
String method = simulationPerformance.getMethod();
|
||||
// 校验
|
||||
if (StringUtils.isNotBlank(targetValueStr) && StringUtils.isNotBlank(resultValueStr)) {
|
||||
if (!validateNumber(targetValueStr) || !validateNumber(resultValueStr)) {
|
||||
return SdmResponse.failed("请输入有效的目标值和分析值");
|
||||
}
|
||||
try {
|
||||
// 转换为BigDecimal(自动处理整数和小数)
|
||||
BigDecimal targetValue = new BigDecimal(targetValueStr);
|
||||
BigDecimal resultValue = new BigDecimal(resultValueStr);
|
||||
|
||||
int comparison = resultValue.compareTo(targetValue);
|
||||
boolean isPassed = switch (method) {
|
||||
case "≥" -> comparison >= 0;
|
||||
case ">" -> comparison > 0;
|
||||
case "<" -> comparison < 0;
|
||||
case "≤" -> comparison <= 0;
|
||||
default -> throw new IllegalArgumentException("无效运算符: " + method);
|
||||
};
|
||||
simulationPerformance.setCompleteStatus(isPassed ? PerformanceStatusEnum.STARTED.getCode() : PerformanceStatusEnum.NOT_STARTED.getCode());
|
||||
} catch (Exception e) {
|
||||
log.error("数字格式异常:", e);
|
||||
return SdmResponse.failed("请输入有效的目标值和分析值");
|
||||
}
|
||||
}
|
||||
return SdmResponse.success(this.updateById(simulationPerformance));
|
||||
}
|
||||
|
||||
private boolean validateNumber(String input) {
|
||||
String trimmed = input.trim();
|
||||
// 前置格式检查 - 验证是不是有效数字格式
|
||||
if (!CommonUtils.isValidNumberFormat(trimmed)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SdmResponse exportPerformance(PerformanceExportExcelFormat performanceExportExcelFormat, HttpServletResponse httpServletResponse) {
|
||||
SdmResponse response = new SdmResponse();
|
||||
|
||||
Reference in New Issue
Block a user