优化自动生成报告,从前节点获取图片文件
This commit is contained in:
@@ -28,9 +28,16 @@ import org.springframework.mock.web.MockMultipartFile;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sdm.common.entity.req.data.QueryDirReq;
|
||||
import com.sdm.common.entity.resp.PageDataResp;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @Description: 生成自动化报告脚本处理器
|
||||
@@ -40,6 +47,17 @@ import java.util.regex.Pattern;
|
||||
@Slf4j
|
||||
@Component("exportWordScript")
|
||||
public class ExportWordScriptHandler implements ExecutionHandler<Map<String, Object>,ExportWordScriptExecuteConfig> {
|
||||
|
||||
/**
|
||||
* 图片文件后缀正则(忽略大小写)
|
||||
*/
|
||||
private static final Pattern IMAGE_FILE_PATTERN = Pattern.compile("(?i).*\\.(png|jpg|jpeg|gif)$");
|
||||
|
||||
/**
|
||||
* 查询目录文件的默认分页大小
|
||||
*/
|
||||
private static final int QUERY_DIR_PAGE_SIZE = 1000;
|
||||
|
||||
@Autowired
|
||||
private IDataFeignClient dataFeignClient;
|
||||
|
||||
@@ -54,92 +72,242 @@ public class ExportWordScriptHandler implements ExecutionHandler<Map<String, Obj
|
||||
|
||||
@Override
|
||||
public void execute(DelegateExecution execution, Map<String, Object> params, ExportWordScriptExecuteConfig config) {
|
||||
String runId = (String) execution.getVariable("runId");
|
||||
String currentNodeId = execution.getCurrentActivityId();
|
||||
String processDefinitionId = execution.getProcessDefinitionId();
|
||||
|
||||
try {
|
||||
// 获取前置节点参数
|
||||
String beforeNodeId = config.getBeforeNodeId();
|
||||
String currentNodeId =execution.getCurrentActivityId();
|
||||
String fileRegularStr = config.getFileRegularStr();
|
||||
|
||||
// 获取当前流程实例参数
|
||||
String runId = (String) execution.getVariable("runId");
|
||||
Long userId = (Long) execution.getVariable("userId");
|
||||
String userName = (String) execution.getVariable("userName");
|
||||
Long tenantId = (Long) execution.getVariable("tenantId");
|
||||
ThreadLocalContext.setUserId(userId);
|
||||
ThreadLocalContext.setUserName(userName);
|
||||
ThreadLocalContext.setTenantId(tenantId);
|
||||
String processDefinitionId = execution.getProcessDefinitionId();
|
||||
log.info("ExportWordScriptHandler 开始执行 runId:{},userId:{},userName:{},tenantId:{},processDefinitionId:{}, beforeNodeId:{}, currentNodeId:{},fileRegularStr:{}", runId,userId,userName,tenantId,processDefinitionId, beforeNodeId, currentNodeId,fileRegularStr);
|
||||
// 1. 初始化线程上下文
|
||||
initThreadLocalContext(execution);
|
||||
logExecutionStart(runId, config, currentNodeId, processDefinitionId);
|
||||
|
||||
// 2. 构建项目信息请求
|
||||
ProjecInfoReq projecInfoReq = buildprojectInfoReq(params);
|
||||
log.info("ExportWordScriptHandler的请求参数 projectInfoReq:{}", projecInfoReq);
|
||||
|
||||
// 3. 获取性能指标
|
||||
List<SimulationPerformance> performanceList = fetchPerformanceList(runId);
|
||||
|
||||
// 4. 获取关键结果图片文件ID(优先从前置节点获取,否则从算列结果获取)
|
||||
String beforeNodeId = config.getBeforeNodeId();
|
||||
List<Long> keyResultImageFileIds = StringUtils.hasText(beforeNodeId)
|
||||
? fetchBeforeNodeImageFileIds(runId, beforeNodeId, processDefinitionId)
|
||||
: fetchKeyResultImageFileIds(runId);
|
||||
|
||||
SdmResponse<List<PerformanceResp>> runPerformance = simuluationPerformanceFeignClient.getRunPerformance(runId);
|
||||
if(!runPerformance.isSuccess()){
|
||||
log.error("获取算列性能指标失败");
|
||||
throw new RuntimeException("获取算列性能指标失败");
|
||||
}
|
||||
List<SimulationPerformance> performanceList = new ArrayList<>();
|
||||
for (PerformanceResp datum : runPerformance.getData()) {
|
||||
SimulationPerformance performance = new SimulationPerformance();
|
||||
BeanUtils.copyProperties(datum, performance);
|
||||
performanceList.add(performance);
|
||||
}
|
||||
log.info("ExportWordScriptHandler的返回参数 runPerformance:{}", runPerformance);
|
||||
|
||||
SdmResponse<List<Long>> simulationKeyResultFileIds = simulationRunFeignClient.getSimulationKeyResultFileIds(runId);
|
||||
if(!simulationKeyResultFileIds.isSuccess()){
|
||||
log.error("获取算列关键结果文件失败");
|
||||
throw new RuntimeException("获取算列关键结果文件失败");
|
||||
}
|
||||
log.info("ExportWordScriptHandler的返回参数 simulationKeyResultFileIds:{}", simulationKeyResultFileIds);
|
||||
|
||||
|
||||
ProcessNodeParam currentProcessNodeParam = processNodeParamService.lambdaQuery()
|
||||
.eq(ProcessNodeParam::getRunId, runId)
|
||||
.eq(ProcessNodeParam::getNodeId, currentNodeId)
|
||||
.eq(ProcessNodeParam::getProcessDefinitionId, processDefinitionId)
|
||||
.one();
|
||||
|
||||
|
||||
// 获取当前节点输出文件夹信息
|
||||
String currentNodeParamJson = currentProcessNodeParam.getParamJson();
|
||||
JSONObject currentParamJsonObject = JSONObject.parseObject(currentNodeParamJson);
|
||||
Long currentNodeOutputDirId = currentParamJsonObject.getLong("outputDirId");
|
||||
FileMetadataInfoResp currentNodeFileMetadataInfoResp = getFileBaseInfo(currentNodeOutputDirId);
|
||||
String currentNodeObjectKey = currentNodeFileMetadataInfoResp.getObjectKey();
|
||||
log.info("当前节点配置参数:{}", currentNodeParamJson);
|
||||
String currentNodeOutputDirPath = FlowableConfig.FLOWABLE_SIMULATION_BASEDIR + currentNodeObjectKey;
|
||||
log.info("当前节点输出文件夹:{}", currentNodeOutputDirPath);
|
||||
|
||||
// todo 生成脚本的接口
|
||||
SpdmReportReq req = new SpdmReportReq();
|
||||
req.setProjecInfoReq(projecInfoReq);
|
||||
req.setOutPutDirPath(currentNodeOutputDirPath);
|
||||
req.setImageFileIdList(simulationKeyResultFileIds.getData());
|
||||
req.setPerformanceList(performanceList);
|
||||
SdmResponse<Void> voidSdmResponse = simulationRunFeignClient.generateReportInternal(req);
|
||||
if(!voidSdmResponse.isSuccess()){
|
||||
log.error("生成自动化报告失败");
|
||||
throw new RuntimeException("生成自动化报告失败");
|
||||
}
|
||||
try {
|
||||
String reportPath = currentNodeOutputDirPath + "report.docx";
|
||||
log.info("报告路径:{}", reportPath);
|
||||
// 获取临时路径中脚本生成的报告
|
||||
uploadResultFileToMinio(currentNodeOutputDirPath + "report.docx",currentNodeOutputDirId);
|
||||
} catch (Exception ex) {
|
||||
log.error("生成自动化报告失败:{}", ex.getMessage(), ex);
|
||||
throw new RuntimeException("生成自动化报告失败");
|
||||
}
|
||||
// 5. 获取输出目录信息
|
||||
OutputDirInfo outputDirInfo = resolveOutputDirInfo(runId, currentNodeId, processDefinitionId);
|
||||
|
||||
// 6. 生成并上传报告
|
||||
generateAndUploadReport(projecInfoReq, performanceList, keyResultImageFileIds, outputDirInfo);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("执行ExportWordScript失败", e);
|
||||
throw new RuntimeException("执行ExportWordScript失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化线程上下文
|
||||
*/
|
||||
private void initThreadLocalContext(DelegateExecution execution) {
|
||||
Long userId = (Long) execution.getVariable("userId");
|
||||
String userName = (String) execution.getVariable("userName");
|
||||
Long tenantId = (Long) execution.getVariable("tenantId");
|
||||
|
||||
ThreadLocalContext.setUserId(userId);
|
||||
ThreadLocalContext.setUserName(userName);
|
||||
ThreadLocalContext.setTenantId(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录执行开始日志
|
||||
*/
|
||||
private void logExecutionStart(String runId, ExportWordScriptExecuteConfig config,
|
||||
String currentNodeId, String processDefinitionId) {
|
||||
Long userId = ThreadLocalContext.getUserId();
|
||||
String userName = ThreadLocalContext.getUserName();
|
||||
Long tenantId = ThreadLocalContext.getTenantId();
|
||||
|
||||
log.info("ExportWordScriptHandler 开始执行 runId:{},userId:{},userName:{},tenantId:{}," +
|
||||
"processDefinitionId:{}, beforeNodeId:{}, currentNodeId:{},fileRegularStr:{}",
|
||||
runId, userId, userName, tenantId, processDefinitionId,
|
||||
config.getBeforeNodeId(), currentNodeId, config.getFileRegularStr());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性能指标列表
|
||||
*/
|
||||
private List<SimulationPerformance> fetchPerformanceList(String runId) {
|
||||
SdmResponse<List<PerformanceResp>> response = simuluationPerformanceFeignClient.getRunPerformance(runId);
|
||||
checkResponse(response, "获取算列性能指标失败");
|
||||
|
||||
List<SimulationPerformance> performanceList = new ArrayList<>();
|
||||
for (PerformanceResp datum : response.getData()) {
|
||||
SimulationPerformance performance = new SimulationPerformance();
|
||||
BeanUtils.copyProperties(datum, performance);
|
||||
performanceList.add(performance);
|
||||
}
|
||||
|
||||
log.info("ExportWordScriptHandler的返回参数 runPerformance:{}", response);
|
||||
return performanceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关键结果-图片文件ID列表(从算列结果获取)
|
||||
*/
|
||||
private List<Long> fetchKeyResultImageFileIds(String runId) {
|
||||
SdmResponse<List<Long>> response = simulationRunFeignClient.getSimulationKeyResultFileIds(runId);
|
||||
checkResponse(response, "获取算列关键结果文件失败");
|
||||
|
||||
log.info("ExportWordScriptHandler的返回参数 simulationKeyResultFileIds:{}", response);
|
||||
return response.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从前置节点输出目录获取图片文件ID列表
|
||||
*/
|
||||
private List<Long> fetchBeforeNodeImageFileIds(String runId, String beforeNodeId, String processDefinitionId) {
|
||||
// 1. 获取前置节点输出目录ID
|
||||
Long beforeNodeOutputDirId = resolveNodeOutputDirId(runId, beforeNodeId, processDefinitionId);
|
||||
if (beforeNodeOutputDirId == null) {
|
||||
log.warn("前置节点输出目录不存在,beforeNodeId:{}", beforeNodeId);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 2. 查询目录下所有文件
|
||||
List<FileMetadataInfoResp> fileList = queryDirFiles(beforeNodeOutputDirId);
|
||||
if (CollectionUtils.isEmpty(fileList)) {
|
||||
log.info("前置节点输出目录下无文件,beforeNodeId:{}, dirId:{}", beforeNodeId, beforeNodeOutputDirId);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 3. 正则过滤图片文件并收集ID
|
||||
List<Long> imageFileIds = fileList.stream()
|
||||
.filter(file -> file.getOriginalName() != null
|
||||
&& IMAGE_FILE_PATTERN.matcher(file.getOriginalName()).matches())
|
||||
.map(FileMetadataInfoResp::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("从前置节点获取到图片文件数量:{}, beforeNodeId:{}", imageFileIds.size(), beforeNodeId);
|
||||
return imageFileIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析节点的输出目录ID
|
||||
*/
|
||||
private Long resolveNodeOutputDirId(String runId, String nodeId, String processDefinitionId) {
|
||||
ProcessNodeParam nodeParam = processNodeParamService.lambdaQuery()
|
||||
.eq(ProcessNodeParam::getRunId, runId)
|
||||
.eq(ProcessNodeParam::getNodeId, nodeId)
|
||||
.eq(ProcessNodeParam::getProcessDefinitionId, processDefinitionId)
|
||||
.one();
|
||||
|
||||
if (nodeParam == null || nodeParam.getParamJson() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject paramJsonObject = JSONObject.parseObject(nodeParam.getParamJson());
|
||||
return paramJsonObject.getLong("outputDirId");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询目录下的文件列表(只查文件,不含子目录)
|
||||
*/
|
||||
private List<FileMetadataInfoResp> queryDirFiles(Long dirId) {
|
||||
QueryDirReq req = new QueryDirReq();
|
||||
req.setFileId(dirId);
|
||||
req.setQueryTarget(2); // 只查文件
|
||||
req.setCurrent(1);
|
||||
req.setSize(QUERY_DIR_PAGE_SIZE);
|
||||
|
||||
SdmResponse<PageDataResp<List<FileMetadataInfoResp>>> response = dataFeignClient.queryDir(req);
|
||||
checkResponse(response, "查询目录文件失败,dirId:" + dirId);
|
||||
|
||||
// 处理空数据情况
|
||||
if (response.getData() == null || response.getData().getData() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return response.getData().getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析输出目录信息
|
||||
*/
|
||||
private OutputDirInfo resolveOutputDirInfo(String runId, String currentNodeId, String processDefinitionId) {
|
||||
ProcessNodeParam nodeParam = processNodeParamService.lambdaQuery()
|
||||
.eq(ProcessNodeParam::getRunId, runId)
|
||||
.eq(ProcessNodeParam::getNodeId, currentNodeId)
|
||||
.eq(ProcessNodeParam::getProcessDefinitionId, processDefinitionId)
|
||||
.one();
|
||||
|
||||
String paramJson = nodeParam.getParamJson();
|
||||
log.info("当前节点配置参数:{}", paramJson);
|
||||
|
||||
JSONObject paramJsonObject = JSONObject.parseObject(paramJson);
|
||||
Long outputDirId = paramJsonObject.getLong("outputDirId");
|
||||
|
||||
FileMetadataInfoResp fileMetadata = getFileBaseInfo(outputDirId);
|
||||
String outputDirPath = FlowableConfig.FLOWABLE_SIMULATION_BASEDIR + fileMetadata.getObjectKey();
|
||||
log.info("当前节点输出文件夹:{}", outputDirPath);
|
||||
|
||||
return new OutputDirInfo(outputDirId, outputDirPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成并上传报告
|
||||
*/
|
||||
private void generateAndUploadReport(ProjecInfoReq projecInfoReq,
|
||||
List<SimulationPerformance> performanceList,
|
||||
List<Long> keyResultImageFileIds,
|
||||
OutputDirInfo outputDirInfo) {
|
||||
// 构建报告请求
|
||||
SpdmReportReq req = new SpdmReportReq();
|
||||
req.setProjecInfoReq(projecInfoReq);
|
||||
req.setOutPutDirPath(outputDirInfo.getPath());
|
||||
req.setImageFileIdList(keyResultImageFileIds);
|
||||
req.setPerformanceList(performanceList);
|
||||
|
||||
// 调用生成报告接口
|
||||
SdmResponse<Void> response = simulationRunFeignClient.generateReportInternal(req);
|
||||
checkResponse(response, "生成自动化报告失败");
|
||||
|
||||
// 上传报告文件
|
||||
String reportPath = outputDirInfo.getPath() + "report.docx";
|
||||
log.info("报告路径:{}", reportPath);
|
||||
uploadResultFileToMinio(reportPath, outputDirInfo.getDirId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一校验远程调用响应
|
||||
*/
|
||||
private <T> void checkResponse(SdmResponse<T> response, String errorMessage) {
|
||||
if (!response.isSuccess()) {
|
||||
log.error(errorMessage);
|
||||
throw new RuntimeException(errorMessage+":"+response.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出目录信息内部类
|
||||
*/
|
||||
private static class OutputDirInfo {
|
||||
private final Long dirId;
|
||||
private final String path;
|
||||
|
||||
public OutputDirInfo(Long dirId, String path) {
|
||||
this.dirId = dirId;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Long getDirId() {
|
||||
return dirId;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
private static ProjecInfoReq buildprojectInfoReq(Map<String, Object> params) {
|
||||
ProjecInfoReq projectInfoReq = new ProjecInfoReq();
|
||||
projectInfoReq.setDepartment((String)params.get("department"));
|
||||
|
||||
Reference in New Issue
Block a user