Merge remote-tracking branch 'origin/main'

This commit is contained in:
2025-12-02 12:00:12 +08:00
22 changed files with 513 additions and 66 deletions

View File

@@ -16,6 +16,12 @@ public class ExportExcelFormat {
@NotNull(message = "excel表头不能为空")
private String title;
@Schema(description = "表头对应的数据属性类型")
private String locateType;
@Schema(description = "表头对应的数据属性类型数据值")
private String locateValue;
@Schema(description = "属性值对应的字典编码")
private String dictCode;
@@ -31,6 +37,8 @@ public class ExportExcelFormat {
ExportExcelFormat format = new ExportExcelFormat();
format.key = key;
format.title = title;
format.locateType = locateType;
format.locateValue = locateValue;
format.dictCode = dictCode;
format.dictData = dictData;
return format;

View File

@@ -6,6 +6,7 @@ import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Data
public class FlowNodeDto {
@@ -37,6 +38,12 @@ public class FlowNodeDto {
@Schema(description = "节点状态:finished/active/pending")
private String nodeStatus;
@Schema(description = "流程实例唯一ID")
private String processInstanceId;
@Schema(description = "用户输入参数")
private Map<String, Object> userParams;
@Schema(description = "创建人")
private Long creator;

View File

@@ -5,6 +5,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.sdm.common.entity.ExportExcelFormat;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
@@ -242,8 +243,17 @@ public class ExcelUtil {
* @param exportExcelFormats
* @return
*/
private static List<HeadVO> getExcelHeader(List<ExportExcelFormat> exportExcelFormats)
private static List<HeadVO> getExcelHeader(List<ExportExcelFormat> exportExcelFormats,List<ExportExcelFormat> filterFormats)
{
Map<String,ExportExcelFormat> showFormatMap = new HashMap<>();
if(filterFormats!=null && !filterFormats.isEmpty()) {
for (ExportExcelFormat exportExcelFormat : filterFormats) {
String key = exportExcelFormat.getKey();
if (showFormatMap.get(key) == null) {
showFormatMap.put(key, exportExcelFormat);
}
}
}
List<HeadVO> excelHeader = new ArrayList<>();
for(ExportExcelFormat exportExcelFormat : exportExcelFormats)
{
@@ -253,6 +263,10 @@ public class ExcelUtil {
excelHeaderInfo.setTitle(exportExcelFormat.getTitle());
excelHeaderInfo.setKeyType(exportExcelFormat.getKey());
headVO.setExcelHeaderInfo(excelHeaderInfo);
if(!showFormatMap.isEmpty() && !showFormatMap.containsKey(exportExcelFormat.getKey()))
{
excelHeaderInfo.setBShow(false);
}
excelHeader.add(headVO);
}
return excelHeader;
@@ -268,7 +282,7 @@ public class ExcelUtil {
ExcelSheet excelSheet = new ExcelSheet();
excelSheet.setSheetName("export sheet1");
//获取excel表头
List<HeadVO> excelHeader = getExcelHeader(exportExcelFormats);
List<HeadVO> excelHeader = getExcelHeader(exportExcelFormats,null);
excelSheet.setHeads(excelHeader);
//获取excel表行数据
@@ -363,7 +377,6 @@ public class ExcelUtil {
{
parent.addchildren(paraseData);
}
//paraseData.increaseLine();
}
String value = jsonObject.getString(key);
JSONObject dictObj = format.getDictData();
@@ -487,17 +500,56 @@ public class ExcelUtil {
paraseData.lastRow = rowIndex+paraseData.lines-1;
}
/**
* 表头第一个属性有效性检查
* @param topObject
* @param exportExcelFormats
*/
private static int filterExcelHeader(JSONObject topObject,List<ExportExcelFormat> exportExcelFormats)
{
Iterator<ExportExcelFormat> iterator = exportExcelFormats.iterator();
int filterCount = 0;
while (iterator.hasNext()) {
ExportExcelFormat format = iterator.next();
String locateType = format.getLocateType();
String locateValue = format.getLocateValue();
if(locateType!=null && !locateType.isEmpty())
{
if(!topObject.containsKey(locateType))
{
iterator.remove();
filterCount++;
}
else
{
if(!topObject.get(locateType).equals(locateValue)) {
iterator.remove();
filterCount++;
}
else {
break;
}
}
}
else
{
break;
}
}
return filterCount;
}
/**
* 导出有合并单元格excel
* @param dataArray
* @param exportExcelFormats
* @param response
*/
public static void exportExcelWithMerge(JSONArray dataArray,List<ExportExcelFormat> exportExcelFormats,HttpServletResponse response)
public static void exportExcelWithMerge(JSONArray dataArray,List<ExportExcelFormat> exportExcelFormats,List<ExportExcelFormat> filterFormat,HttpServletResponse response)
{
ExcelSheet excelSheet = new ExcelSheet();
excelSheet.setSheetName("export sheet1");
List<HeadVO> excelHeader = getExcelHeader(exportExcelFormats);
List<HeadVO> excelHeader = getExcelHeader(exportExcelFormats,filterFormat);
excelSheet.setHeads(excelHeader);
Map<Integer,List<ExcelCellValue>> paraseDataMap = new HashMap<>();
int rowNum = 1;

View File

@@ -28,6 +28,8 @@ public class MinioConfig {
// allocateDirect 单次缓冲的数据
private int directMemory;
private String lifecycleConfig;
// 初始化超级管理员客户端(用于 admin 操作:桶、用户、策略)
@Bean
public MinioAdminClient minioAdminClient() {

View File

@@ -21,10 +21,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.List;
@RestController
@@ -428,11 +430,29 @@ public class DataFileController implements IDataFeignClient {
IDataFileService.downloadFileToLocal(fileId,path);
}
/**
* 导出知识库
* @param knowledgeExportExcelFormat
* @param httpservletResponse
* @return
*/
@PostMapping("/exportKnowledgeList")
@Operation(summary = "导出知识库", description = "导出知识库")
public SdmResponse exportKnowledgeList(@RequestBody KnowledgeExportExcelFormat knowledgeExportExcelFormat , HttpServletResponse httpservletResponse) {
return IDataFileService.exportKnowledgeList(knowledgeExportExcelFormat, httpservletResponse);
}
/**
* only office 回调
* @param callbackData
* @return
*/
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})
@PostMapping("/onlyOfficeCallback")
@Operation(summary = "only office 回调", description = "only office 回调")
public ResponseEntity onlyOfficeCallback(@RequestBody CallbackData callbackData) {
return IDataFileService.onlyOfficeCallback(callbackData);
}
}

View File

@@ -0,0 +1,72 @@
package com.sdm.data.model.req;
import lombok.Data;
@Data
public class CallbackData {
/**
* 用户与文档的交互状态。0用户断开与文档共同编辑的连接1新用户连接到文档共同编辑2用户单击强制保存按钮
*/
// @IsArray()
// actions?:IActions[] =null;
/**
* 字段已在 4.2 后版本废弃,请使用 history 代替
*/
Object changeshistory;
/**
* 文档变更的历史记录,仅当 status 等于 2 或者 3 时该字段才有值。其中的 serverVersion 字段也是 refreshHistory 方法的入参
*/
Object history;
/**
* 文档编辑的元数据信息,用来跟踪显示文档更改记录,仅当 status 等于 2 或者 2 时该字段才有值。该字段也是 setHistoryData显示与特定文档版本对应的更改类似 Git 历史记录)方法的入参
*/
String changesurl;
/**
* url 字段下载的文档扩展名,文件类型默认为 OOXML 格式,如果启用了 assemblyFormatAsOriginhttps://api.onlyoffice.com/editors/save#assemblyFormatAsOrigin 服务器设置则文件以原始格式保存
*/
String filetype;
/**
* 文档强制保存类型。0对命令服务https://api.onlyoffice.com/editors/command/forcesave执行强制保存1每次保存完成时都会执行强制保存请求仅设置 forcesave 等于 true 时生效2强制保存请求由计时器使用服务器中的设置执行。该字段仅 status 等于 7 或者 7 时才有值
*/
Integer forcesavetype;
/**
* 文档标识符,类似 id在 Onlyoffice 服务内部唯一
*/
String key;
/**
* 文档状态。1文档编辑中2文档已准备好保存3文档保存出错4文档没有变化无需保存6正在编辑文档但保存了当前文档状态7强制保存文档出错
*/
Integer status;
/**
* 已编辑文档的链接,可以通过它下载到最新的文档,仅当 status 等于 2、3、6 或 7 时该字段才有值
*/
String url;
/**
* 自定义参数,对应指令服务的 userdata 字段
*/
Object userdata;
/**
* 打开文档进行编辑的用户标识列表,当文档被修改时,该字段将返回最后编辑文档的用户标识符,当 status 字段等于 2 或者 6 时有值
*/
String[] users;
/**
* 最近保存时间
*/
String lastsave;
/**
* 加密令牌
*/
String token;
}

View File

@@ -10,6 +10,7 @@ import com.sdm.common.entity.resp.data.FileMetadataInfoResp;
import com.sdm.data.model.req.*;
import com.sdm.data.model.resp.KKFileViewURLFromMinioResp;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -331,4 +332,6 @@ public interface IDataFileService {
*/
SdmResponse exportKnowledgeList(KnowledgeExportExcelFormat knowledgeExportExcelFormat, HttpServletResponse httpservletResponse);
ResponseEntity<Object> onlyOfficeCallback(CallbackData callbackData);
}

View File

@@ -139,7 +139,7 @@ public interface IMinioService {
String getMinioPresignedUrl(String objectKey);
String getMinioPresignedUrl(String objectKey, String bucketName);
Boolean chunkUpload(String bucketName, MultipartFile file, String fileName);
Boolean chunkUpload(String bucketName, MultipartFile file, String fileName,Map<String, String> tags);
Boolean merge(String tempBucketName,String tempFilePath,String mergeBucketName,String fileName);

View File

@@ -58,6 +58,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@@ -252,7 +253,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
Objects.equals(req.getChunk(),NumberConstants.ONE)){
// 第一步业务数据入表已经规定好这个文件的路径了
String finalFileName = req.getObjectKey();
Boolean b = minioService.chunkUpload(chunkBucket, req.getFile(), finalFileName);
Boolean b = minioService.chunkUpload(chunkBucket, req.getFile(), finalFileName,null);
if(!b){
return buildFailedResponse(resp,"单一文件上传失败",req);
}
@@ -264,7 +265,9 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
// 1. 保存当前分片到临时目录 1 2 3 4 ....temp
String chunkFileName =tempDirPath+req.getChunk()+ PermConstants.CHUNK_TEMPFILE_SUFFIX;
// 片文件上传到minio
Boolean b = minioService.chunkUpload(chunkBucket, req.getFile(), chunkFileName);
Map<String, String> tags = new HashMap<>();
tags.put("auto-expire", "1d");
Boolean b = minioService.chunkUpload(chunkBucket, req.getFile(), chunkFileName,tags);
if(!b){
deleteTempFileAfterFailed(tempDirPath,chunkBucket);
return buildFailedResponse(resp,"chunkUpload第"+req.getChunk()+"次失败",req);
@@ -2410,4 +2413,64 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
return response;
}
@Override
public ResponseEntity<Object> onlyOfficeCallback(CallbackData callbackData) {
log.info("调用回调接口,userdata{}",callbackData.getKey());
//状态监听
//参见https://api.onlyoffice.com/editors/callback
Integer status = callbackData.getStatus();
switch (status) {
case 1: {
//document is being edited 文档已经被编辑
break;
}
case 2: {
//document is ready for saving,文档已准备好保存
System.out.println("document is ready for saving");
String url = callbackData.getUrl();
log.info("回调地址为:{}",url);
try {
// saveFile(url); //保存文件
System.out.println(callbackData);
} catch (Exception e) {
System.out.println("保存文件异常");
}
System.out.println("save success.");
break;
}
case 3: {
//document saving error has occurred,保存出错
System.out.println("document saving error has occurred,保存出错");
break;
}
case 4: {
//document is closed with no changes,未保存退出
System.out.println("document is closed with no changes,未保存退出");
break;
}
case 6: {
//document is being edited, but the current document state is saved,编辑保存
String url = callbackData.getUrl();
try {
// saveFile(url); //保存文件
System.out.println(callbackData);
} catch (Exception e) {
System.out.println("保存文件异常");
}
System.out.println("save success.");
break;
}
case 7: {
//error has occurred while force saving the document. 强制保存文档出错
System.out.println("error has occurred while force saving the document. 强制保存文档出错");
}
default: {
}
}
// 返回响应
return ResponseEntity.<Object>ok(Collections.singletonMap("error", 0));
}
}

View File

@@ -34,6 +34,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
@@ -1609,5 +1610,10 @@ public class SystemFileIDataFileServiceImpl implements IDataFileService {
return response;
}
@Override
public ResponseEntity<Object> onlyOfficeCallback(CallbackData callbackData) {
return null;
}
}

View File

@@ -1,6 +1,7 @@
package com.sdm.data.service.minio;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.sdm.common.entity.constants.NumberConstants;
import com.sdm.common.log.CoreLogger;
import com.sdm.data.config.MinioConfig;
@@ -8,9 +9,7 @@ import com.sdm.data.service.IMinioService;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import io.minio.messages.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
@@ -37,6 +36,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
@@ -64,15 +64,18 @@ public class MinioService implements IMinioService {
} catch (Exception e) {
log.error("桶{}初始化失败", minioConfig.getSpdmBucket(), e);
}
try {
createBucketIfNotExists(minioConfig.getSecretBusinessBucket());
log.info("桶{}初始化完成", minioConfig.getSecretBusinessBucket());
} catch (Exception e) {
log.error("桶{}初始化失败", minioConfig.getSecretBusinessBucket(), e);
}
createBucketLifecycle(minioConfig.getSpdmBucket(),minioConfig.getLifecycleConfig());
}
public String getBucketName() {
return minioConfig.getSpdmBucket();
}
@@ -104,7 +107,7 @@ public class MinioService implements IMinioService {
throw new RuntimeException(e);
}
}
/**
* 创建目录默认使用spdmBucket
*
@@ -175,7 +178,7 @@ public class MinioService implements IMinioService {
throw new RuntimeException(e);
}
}
/**
* 递归删除指定目录下的所有对象默认使用spdmBucket
*
@@ -303,7 +306,7 @@ public class MinioService implements IMinioService {
throw new RuntimeException(e);
}
}
/**
* 重命名MinIO中的文件默认使用spdmBucket
*
@@ -391,7 +394,7 @@ public class MinioService implements IMinioService {
public InputStream getMinioInputStream(String objectName) {
return getMinioInputStream(objectName, minioConfig.getSpdmBucket());
}
public InputStream getMinioInputStream(String objectName, String bucketName) {
try {
return minioClient.getObject(
@@ -425,7 +428,7 @@ public class MinioService implements IMinioService {
}
return result;
}
/**
* 根据标签查询文件默认使用spdmBucket
*/
@@ -472,6 +475,77 @@ public class MinioService implements IMinioService {
}
}
private void createBucketLifecycle(String bucketName, String configJson) {
// configJson 示例: {"tag-based-expire-3d":"3d","tag-based-expire-7d":"7d"}
Map<String, String> targetRuleMap = JSONObject.parseObject(configJson, Map.class);
try {
LifecycleConfiguration existingConfig = null;
try {
existingConfig = minioClient.getBucketLifecycle(
GetBucketLifecycleArgs.builder().bucket(bucketName).build()
);
} catch (Exception e) {
existingConfig = null;
}
List<LifecycleRule> existingRules = existingConfig == null ? new ArrayList<>() : existingConfig.rules();
Map<String, LifecycleRule> retained = existingRules.stream()
.filter(rule -> rule.id() != null && targetRuleMap.containsKey(rule.id()))
.collect(Collectors.toMap(LifecycleRule::id, r -> r));
List<LifecycleRule> finalRules = new ArrayList<>(retained.values());
for (Map.Entry<String, String> entry : targetRuleMap.entrySet()) {
String ruleId = entry.getKey();
String v = entry.getValue();
if (v == null) continue;
String daysStr = v.replace("d", "").trim();
int expireDays;
try {
expireDays = Integer.parseInt(daysStr);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("invalid expire days for rule " + ruleId + ": " + v);
}
if (expireDays <= 0) {
throw new IllegalArgumentException("expireDays must be > 0 for rule " + ruleId);
}
if (retained.containsKey(ruleId)) {
continue;
}
// days 使用 Integer
Expiration expiration = new Expiration(
(ResponseDate) null,
Integer.valueOf(expireDays),
null
);
// 构建 Filter标签匹配
RuleFilter filter = new RuleFilter(new Tag("auto-expire", v));
LifecycleRule rule = new LifecycleRule(
Status.ENABLED, // status
null, // AbortIncompleteMultipartUpload (null)
expiration, // Expiration (非空,满足至少一个 action 的要求)
filter, // Filter (不得为 null)
ruleId, // ID
null, // NoncurrentVersionExpiration
null, // NoncurrentVersionTransition
null // Transition
);
finalRules.add(rule);
}
//(覆盖)规则
LifecycleConfiguration newConfig = new LifecycleConfiguration(finalRules);
minioClient.setBucketLifecycle(
SetBucketLifecycleArgs.builder()
.bucket(bucketName)
.config(newConfig)
.build()
);
} catch (Exception e) {
CoreLogger.error("设置 MinIO 生命周期失败:", e);
}
}
@Override
public String getMinioPresignedUrl(String objectKey) {
return getMinioPresignedUrl(objectKey, minioConfig.getSpdmBucket());
@@ -500,7 +574,7 @@ public class MinioService implements IMinioService {
* @date 2023/5/21 13:06
*/
@Override
public Boolean chunkUpload(String bucketName, MultipartFile file, String fileName) {
public Boolean chunkUpload(String bucketName, MultipartFile file, String fileName,Map<String, String> tags) {
InputStream inputStream = null;
try {
inputStream = file.getInputStream();

View File

@@ -114,4 +114,5 @@ minio:
secure: false
secret-business-bucket: secretbusiness # 存放保密业务代码、脚本的桶(仅超级管理员访问)
spdm-bucket: spdm # 普通业务数据桶(分配给用户读写权限)
directMemory: 16384 # 16kb
directMemory: 16384 # 16kb
lifecycleConfig: '{"auto-expire-1d":"1d"}'

View File

@@ -31,4 +31,6 @@ public interface SimulationDemandMapper extends BaseMapper<SimulationDemand> {
List<SpdmDemandMemberVo> getMemberList(@Param("demandIdList") List<String> demandIdList, @Param("memberType") Integer memberType);
SpdmDemandVo getDemandByName(@Param("tenantId") Long tenantId,@Param("demandName") String demandName);
List<SpdmDemandExtraVo> getDemandExtraList(@Param("demandIdList") List<String> demandIdList);
}

View File

@@ -43,9 +43,9 @@ public class SpdmDemandListReq {
*/
private String achieveStatus;
private String projectName;
private String projectId;
private String phaseName;
private String phaseId;
private String disciplineName;

View File

@@ -1,8 +1,6 @@
package com.sdm.project.model.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data

View File

@@ -0,0 +1,43 @@
package com.sdm.project.model.vo;
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 jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Data
public class SpdmDemandExtraVo extends BaseEntity {
/**
* 关联的需求id
*/
private String demandId;
/**
* 需求拓展属性编码
*/
private String propertyName;
/**
* 需求拓展属性值
*/
private String propertyValue;
/**
* 需求拓展属性值类型
*/
private String valueType;
/**
* 需求拓展属性class
*/
private String propertyClass;
}

View File

@@ -85,7 +85,7 @@ public class SpdmDemandVo extends BaseEntity {
/**
* 预留拓展属性
*/
private List<SpdmDemandExtraReq> extraList;
private List<SpdmDemandExtraVo> extraList;
/**
* 项目名称

View File

@@ -439,7 +439,12 @@ public class DemandServiceImpl extends BaseService implements IDemandService {
userMap = userList.stream().collect(Collectors.groupingBy(CIDUserResp::getUserId));
}
}
List<String> demandIdList = demandList.stream().map(SpdmDemandVo::getUuid).toList();
List<SpdmDemandExtraVo> demandExtraList = mapper.getDemandExtraList(demandIdList);
Map<String, List<SpdmDemandExtraVo>> demandExtraMap = Map.of();
if (CollectionUtils.isNotEmpty(demandExtraList)) {
demandExtraMap = demandExtraList.stream().collect(Collectors.groupingBy(SpdmDemandExtraVo::getDemandId));
}
for (SpdmDemandVo spdmDemandVo : demandList) {
eachTaskList = taskMap.get(spdmDemandVo.getUuid());
spdmDemandVo.setProgress(CollectionUtils.isEmpty(eachTaskList) ? 0 : eachTaskList.stream().mapToInt(SpdmTaskVo::getProgress).sum() / eachTaskList.size());
@@ -467,6 +472,7 @@ public class DemandServiceImpl extends BaseService implements IDemandService {
}
}
spdmDemandVo.setEMemberList(spdmEUserVoList);
spdmDemandVo.setExtraList(demandExtraMap.get(spdmDemandVo.getUuid()));
}
jsonObject.put("data", demandList);
return SdmResponse.success(jsonObject);

View File

@@ -91,6 +91,9 @@ public class ProjectServiceImpl extends BaseService implements IProjectService {
String firstNodeTag;
List<String> nodeTypeList = Arrays.asList(NodeTypeEnum.MACHINE.getValue(),NodeTypeEnum.WORKSPACE.getValue(),NodeTypeEnum.DISCIPLINE.getValue(),NodeTypeEnum.TASK.getValue(),NodeTypeEnum.PERFORMANCE.getValue());
@Override
@Transactional
public SdmResponse add(JSONObject jsonObject) {
@@ -1974,16 +1977,111 @@ public class ProjectServiceImpl extends BaseService implements IProjectService {
List<ExportExcelFormat> exportExcelFormats = taskTreeExportExcelFormat.getExcelHeaders();
SdmResponse taskRespond = getTaskTree(req);
SdmResponse response = new SdmResponse();
List<ProjectNodePo> allTopProjectNodeList = new ArrayList<>();
if(taskRespond.isSuccess()) {
List<ProjectNodePo> realTopProjectNodeList = (List<ProjectNodePo>) taskRespond.getData();
if (CollectionUtils.isEmpty(realTopProjectNodeList)) {
return response;
}
ExcelUtil.exportExcelWithMerge(JSONArray.from(taskRespond.getData()),exportExcelFormats,httpServletResponse);
// 补充空节点,暂时定死顺序:机台——》工位——》学科——》任务——》指标
for (ProjectNodePo projectNodePo : realTopProjectNodeList) {
if (NodeTypeEnum.MACHINE.getValue().equals(projectNodePo.getNodeType())) {
fillChildrenNode(projectNodePo);
allTopProjectNodeList.add(projectNodePo);
continue;
}
// 先补全前面类型节点
ProjectNodePo machineNode = new ProjectNodePo();
if (NodeTypeEnum.WORKSPACE.getValue().equals(projectNodePo.getNodeType())) {
machineNode.setNodeName(" ");
machineNode.setNodeCode(" ");
machineNode.setNodeType(NodeTypeEnum.MACHINE.getValue());
machineNode.setChildren(Collections.singletonList(projectNodePo));
fillChildrenNode(machineNode);
}else if (NodeTypeEnum.DISCIPLINE.getValue().equals(projectNodePo.getNodeType())) {
machineNode.setNodeName(" ");
machineNode.setNodeCode(" ");
machineNode.setNodeType(NodeTypeEnum.MACHINE.getValue());
NodeAllBase workspaceNode = new ProjectNodePo();
workspaceNode.setNodeName(" ");
workspaceNode.setNodeCode(" ");
workspaceNode.setNodeType(NodeTypeEnum.WORKSPACE.getValue());
workspaceNode.setChildren(Collections.singletonList(projectNodePo));
machineNode.setChildren(Collections.singletonList(workspaceNode));
fillChildrenNode(machineNode);
}else if (NodeTypeEnum.TASK.getValue().equals(projectNodePo.getNodeType())) {
machineNode.setNodeName(" ");
machineNode.setNodeCode(" ");
machineNode.setNodeType(NodeTypeEnum.MACHINE.getValue());
ProjectNodePo workspaceNode = new ProjectNodePo();
workspaceNode.setNodeName(" ");
workspaceNode.setNodeCode(" ");
workspaceNode.setNodeType(NodeTypeEnum.WORKSPACE.getValue());
ProjectNodePo disciplineNode = new ProjectNodePo();
disciplineNode.setNodeName(" ");
disciplineNode.setNodeCode(" ");
disciplineNode.setNodeType(NodeTypeEnum.DISCIPLINE.getValue());
disciplineNode.setChildren(Collections.singletonList(projectNodePo));
workspaceNode.setChildren(Collections.singletonList(disciplineNode));
machineNode.setChildren(Collections.singletonList(workspaceNode));
fillChildrenNode(machineNode);
}
allTopProjectNodeList.add(machineNode);
}
ExcelUtil.exportExcelWithMerge(JSONArray.from(allTopProjectNodeList),exportExcelFormats,new ArrayList<>(),httpServletResponse);
} else {
response = SdmResponse.failed(taskRespond.getMessage());
}
return response;
}
private NodeAllBase fillChildrenNode(NodeAllBase projectNodePo) {
String nodeType = projectNodePo.getNodeType();
if (StringUtils.isBlank(projectNodePo.getNodeCode())) {
projectNodePo.setNodeCode(" ");
}
List<NodeAllBase> childrenNodeList = projectNodePo.getChildren();
if (CollectionUtils.isEmpty(childrenNodeList)) {
return projectNodePo;
}
String childrenNodeType = nodeTypeList.get(nodeTypeList.indexOf(nodeType) + 1);
List<Long> removeIdList = new ArrayList<>();
List<ProjectNodePo> newNodeList = new ArrayList<>();
for (NodeAllBase childNode : childrenNodeList) {
if ((nodeType.equals(childNode.getNodeType()) || childrenNodeType.equals(childNode.getNodeType())) && CollectionUtils.isEmpty(childNode.getChildren())) {
continue;
}
if (!childrenNodeType.equals(childNode.getNodeType()) && nodeTypeList.indexOf(childrenNodeType) < nodeTypeList.indexOf(childNode.getNodeType())) {
ProjectNodePo emptyNode = new ProjectNodePo();
emptyNode.setNodeName(" ");
emptyNode.setNodeCode(" ");
emptyNode.setNodeType(childrenNodeType);
if (CollectionUtils.isEmpty(childNode.getChildren())) {
emptyNode.setChildren(Collections.singletonList(childNode));
}else {
emptyNode.setChildren(Collections.singletonList(fillChildrenNode(childNode)));
}
removeIdList.add(childNode.getId());
newNodeList.add(emptyNode);
}else {
fillChildrenNode(childNode);
}
}
if (CollectionUtils.isNotEmpty(removeIdList)) {
Iterator<NodeAllBase> iterator = childrenNodeList.iterator();
while (iterator.hasNext()) {
NodeAllBase nodeAllBase = iterator.next();
if (removeIdList.contains(nodeAllBase.getId())) { // 假设我们想删除所有偶数
iterator.remove(); // 使用迭代器的remove方法安全删除元素
}
}
}
if (CollectionUtils.isNotEmpty(newNodeList)) {
childrenNodeList.addAll(newNodeList);
}
return projectNodePo;
}
}

View File

@@ -926,7 +926,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
public SdmResponse startProcessInstance(SpdmTaskRunReq req) {
SimulationRun simulationRun = this.lambdaQuery().eq(SimulationRun::getUuid, req.getRunId()).one();
// 启动流程实例 多次执行会生成多个流程实例id更新算例run表、同时更新flowable流程参数的流程实例id
SdmResponse<ProcessInstanceResp> sdmResponse = flowableFeignClient.startByProcessDefinitionId(simulationRun.getProcessDefinitionId(), null);
SdmResponse<ProcessInstanceResp> sdmResponse = flowableFeignClient.startByProcessDefinitionId(simulationRun.getProcessDefinitionId(), Collections.emptyMap());
if (sdmResponse.getData() != null) {
this.lambdaUpdate().set(SimulationRun::getFlowInstanceId, sdmResponse.getData().getProcessInstanceId()).eq(SimulationRun::getUuid, req.getRunId()).update();
flowableFeignClient.updateNodeParamProcessInstanceId(simulationRun.getProcessDefinitionId(), sdmResponse.getData().getProcessInstanceId());
@@ -950,25 +950,17 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
definitionDTO.getFlowElements().stream().filter(i -> StringUtils.equals(i.getId(), flowNodeDto.getNodeId())).findFirst().ifPresent(i -> {
if (i.getExtensionElements() != null && i.getExtensionElements().getExecuteConfig() != null) {
Map<String, Object> params = new HashMap<>();
if ("HPC".equals(i.getExtensionElements().getExecuteConfig().getExecuteType())) {
// 计算节点 输出文件夹id 保存到用户输入参数
params.put("outputDirId", flowNodeDto.getOutputDirId());
} else if ("exportWordScript".equals(i.getExtensionElements().getExecuteConfig().getExecuteType())) {
// 脚本节点
// 处理脚本上传到当前节点文件夹下,获得 脚本文件id
// 脚本文件id 保存到用户输入参数
// 正则表达式 保存到用户输入参数
params.putAll(req.getInputParams());
// 脚本输出文件夹id 保存到用户输入参数
params.put("outputDirId", flowNodeDto.getOutputDirId());
}
// 输出文件夹id 保存到用户输入参数
params.put("outputDirId", flowNodeDto.getOutputDirId());
// 前端用户输入参数
params.putAll(req.getInputParams());
flowableFeignClient.saveParamsByDefinitionId(simulationRun.getProcessDefinitionId(), flowNodeDto.getNodeId(), params);
}
});
}
}
return null;
return SdmResponse.success();
}
@Override
@@ -979,28 +971,23 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
if (sdmResponse.getData() != null) {
List<FlowNodeDto> flowNodeDtoList = sdmResponse.getData();
SimulationRun simulationRun = this.lambdaQuery().eq(SimulationRun::getUuid, req.getRunId()).one();
if (simulationRun.getFlowInstanceId() != null) {
SdmResponse<ProcessInstanceDetailResponse> response = flowableFeignClient.getProcessAndNodeDetailByInstanceId(simulationRun.getFlowInstanceId());
if (response.getData() != null && CollectionUtils.isNotEmpty(response.getData().getNodes())) {
for (FlowNodeDto flowNodeDto : flowNodeDtoList) {
response.getData().getNodes().stream().filter(i -> StringUtils.equals(i.getId(), flowNodeDto.getNodeId())).findFirst().ifPresent(i -> {
flowNodeDto.setNodeStatus(i.getStatus());
});
}
SdmResponse<ProcessInstanceDetailResponse> response = flowableFeignClient.getProcessAndNodeDetailByInstanceId(simulationRun.getProcessDefinitionId(), simulationRun.getFlowInstanceId());
if (response.getData() != null && CollectionUtils.isNotEmpty(response.getData().getNodes())) {
for (FlowNodeDto flowNodeDto : flowNodeDtoList) {
response.getData().getNodes().stream().filter(i -> StringUtils.equals(i.getId(), flowNodeDto.getNodeId())).findFirst().ifPresent(i -> {
flowNodeDto.setNodeStatus(i.getStatus());
flowNodeDto.setUserParams(i.getUserParam());
flowNodeDto.setProcessInstanceId(simulationRun.getFlowInstanceId());
});
}
} else {
}
if (simulationRun.getFlowInstanceId() == null) {
flowNodeDtoList.forEach(node -> {
node.setNodeStatus("pending");
});
}
List<NodeStructureInfo> nodeStructureInfoList = flowableFeignClient.listNodesByProcessDefinitionId(simulationRun.getProcessDefinitionId()).getData();
if (CollectionUtils.isNotEmpty(nodeStructureInfoList)) {
for (FlowNodeDto flowNodeDto : flowNodeDtoList) {
nodeStructureInfoList.stream().filter(i -> StringUtils.equals(i.getId(), flowNodeDto.getNodeId())).findFirst().ifPresent(i -> {
});
}
}
return SdmResponse.success(flowNodeDtoList);
}
return SdmResponse.success(new ArrayList<>());

View File

@@ -19,9 +19,9 @@
</insert>
<insert id="addDemandExtra">
insert into simulation_demand_extra (uuid,demand_id,nodeId,property_name,property_value,value_type,property_class,creator,create_time) values
insert into simulation_demand_extra (demand_id,property_name,property_value,value_type,property_class,creator,create_time) values
<foreach collection='demandExtraList' item='extra' index='index' separator=','>
(#{extra.uuid},#{extra.demandId},#{extra.nodeId},#{extra.propertyName},#{extra.propertyValue},#{extra.valueType},#{extra.propertyClass},#{extra.creator},#{extra.createTime})
(#{extra.demandId},#{extra.propertyName},#{extra.propertyValue},#{extra.valueType},#{extra.propertyClass},#{extra.creator},#{extra.createTime})
</foreach>
</insert>
@@ -113,14 +113,11 @@
<if test="req.demandName != null and req.demandName != ''">
and demand_name like CONCAT('%',#{req.demandName},'%')
</if>
<if test="req.projectName != null and req.projectName != ''">
and project_name = #{req.projectName}
<if test="req.projectId != null and req.projectId != ''">
and project_id = #{req.projectId}
</if>
<if test="req.phaseName != null and req.phaseName != ''">
and phase_name = #{req.phaseName}
</if>
<if test="req.disciplineName != null and req.disciplineName != ''">
and disciplineName = #{req.disciplineName}
<if test="req.phaseId != null and req.phaseId != ''">
and phase_id = #{req.phaseId}
</if>
<if test="req.demandType != null and req.demandType != ''">
and demand_type = #{req.demandType}
@@ -152,4 +149,12 @@
select * from simulation_demand where tenant_id = #{tenantId} and demand_name = #{demandName} limit 1
</select>
<select id="getDemandExtraList" resultType="com.sdm.project.model.vo.SpdmDemandExtraVo">
select * from simulation_demand_extra where demand_id in (
<foreach collection='demandIdList' item='demandId' index='index' separator=','>
#{demandId}
</foreach>
)
</select>
</mapper>

View File

@@ -250,7 +250,7 @@ public class SimulationTaskPoolServiceImpl extends BaseService implements ISimul
else
{
JSONObject taskPool = (JSONObject) taskPoolResp.getData();
ExcelUtil.exportExcelWithMerge(taskPool.getJSONArray("nodes"),req.excelHeaders,httpServletResponse);
ExcelUtil.exportExcelWithMerge(taskPool.getJSONArray("nodes"),req.excelHeaders,new ArrayList<>(),httpServletResponse);
}
return ;
}