1、调整批量创建需求文件夹参数

2、新增查询项目人员负载接口
This commit is contained in:
2026-01-26 12:57:54 +08:00
parent 59650e5151
commit 3437d934db
7 changed files with 278 additions and 56 deletions

View File

@@ -140,4 +140,6 @@ public class SpdmProjectNodeEditReq extends BaseEntity {
private String commitmentDeadline;
private String referenceItem;
}

View File

@@ -97,6 +97,11 @@ public interface ITaskService {
SdmResponse exportPerformanceByScript(HttpServletResponse response, PerformanceAnalysisExportExcelFormat req);
/**
* 查询项目人员负载
* @param req
* @return
*/
SdmResponse<List<ProjectUserLoadResp>> queryProjectUserLoads(ProjectUserLoadReq req);
}

View File

@@ -193,18 +193,12 @@ public class DemandServiceImpl extends BaseService implements IDemandService {
}
}
// CreateDirReq createDirReq = new CreateDirReq();
// createDirReq.setUuId(uuid);
// createDirReq.setParentUuId(null);
// createDirReq.setDirName(req.getDemandName());
// createDirReq.setDirType(DirTypeEnum.PROJECT_NODE_DIR.getValue());
// log.info("创建需求时,调用创建文件夹的参数为:{}", createDirReq);
// SdmResponse response = dataClientFeignClient.createDir(createDirReq);
// log.info("创建需求时,调用创建文件夹的返回值为:{}", response);
BatchCreateNormalDirReq batchCreateNormalDirReq = new BatchCreateNormalDirReq();
batchCreateNormalDirReq.setParentUUId(req.getProjectId());
batchCreateNormalDirReq.setFolderNames(Collections.singletonList(req.getDemandName()));
FolderItemReq folderItemReq = new FolderItemReq();
folderItemReq.setFolderName(req.getDemandName());
folderItemReq.setFolderUuid(req.getUuid());
batchCreateNormalDirReq.setFolderItems(Collections.singletonList(folderItemReq));
log.info("手动同步待办创建文件夹参数: {}", batchCreateNormalDirReq);
SdmResponse dirCreateResp = dataFeignClient.batchCreateNormalDirs(batchCreateNormalDirReq);
log.info("手动同步待办创建文件夹响应: {}", dirCreateResp);

View File

@@ -525,14 +525,17 @@ public class LyricInternalServiceImpl implements ILyricInternalService {
List<UpdatePermissionReq> updatePermissionList) {
// 批量创建文件夹
if (CollectionUtils.isNotEmpty(createDirItemList)) {
// BatchCreateDirReq batchCreateDirReq = new BatchCreateDirReq();
// batchCreateDirReq.setItems(createDirItemList);
// batchCreateDirReq.setDirType(DirTypeEnum.PROJECT_NODE_DIR.getValue());
// SdmResponse dirCreateResp = dataFeignClient.batchCreateDir(batchCreateDirReq);
for (BatchCreateDirItem batchCreateDirItem : createDirItemList) {
BatchCreateNormalDirReq batchCreateNormalDirReq = new BatchCreateNormalDirReq();
batchCreateNormalDirReq.setParentUUId(batchCreateDirItem.getParentDirNodeInfo().getUuId());
batchCreateNormalDirReq.setFolderNames(batchCreateDirItem.getChildDirNodeInfos().stream().map(DirNodeInfo::getDirName).toList());
List<FolderItemReq> folderItemReqList = new ArrayList<>();
for (DirNodeInfo dirNodeInfo : batchCreateDirItem.getChildDirNodeInfos()) {
FolderItemReq folderItemReq = new FolderItemReq();
folderItemReq.setFolderName(dirNodeInfo.getDirName());
folderItemReq.setFolderUuid(dirNodeInfo.getUuId());
folderItemReqList.add(folderItemReq);
}
batchCreateNormalDirReq.setFolderItems(folderItemReqList);
log.info("手动同步待办创建文件夹参数: {}", batchCreateNormalDirReq);
SdmResponse dirCreateResp = dataFeignClient.batchCreateNormalDirs(batchCreateNormalDirReq);
log.info("手动同步待办创建文件夹响应: {}", dirCreateResp);

View File

@@ -2302,7 +2302,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
// 6. 批量创建文件夹
SdmResponse dirCreateResponse = batchCreateDemandDirs(
processResult.getDemandDirNodeList(), projectNodeId, projectNodeName);
processResult.getDemandDirNodeList(), projectNodeId);
if (!dirCreateResponse.isSuccess()) {
log.error("项目{}批量创建需求文件夹失败:{}", projectNum, dirCreateResponse.getMessage());
return SdmResponse.failed("同步待办失败:创建文件夹失败");
@@ -2567,32 +2567,21 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
* 批量创建需求文件夹
*/
private SdmResponse batchCreateDemandDirs(List<DirNodeInfo> demandDirNodeList,
String projectNodeId,
String projectNodeName) {
String projectNodeId) {
if (CollectionUtils.isEmpty(demandDirNodeList)) {
log.info("无需求文件夹需要创建");
return SdmResponse.success();
}
// 构建项目目录节点
// DirNodeInfo projectDirNodeInfo = new DirNodeInfo();
// projectDirNodeInfo.setUuId(projectNodeId);
// projectDirNodeInfo.setParentUuId(null);
// projectDirNodeInfo.setUuIdOwnType(NodeTypeEnum.PROJECT.getValue());
// projectDirNodeInfo.setDirName(projectNodeName);
// 构建批量创建请求
// BatchCreateDirItem demandCreateDirItem = new BatchCreateDirItem();
// demandCreateDirItem.setParentDirNodeInfo(projectDirNodeInfo);
// demandCreateDirItem.setChildDirNodeInfos(demandDirNodeList);
//
// BatchCreateDirReq batchCreateDirReq = new BatchCreateDirReq();
// batchCreateDirReq.setItems(Collections.singletonList(demandCreateDirItem));
// batchCreateDirReq.setDirType(DirTypeEnum.PROJECT_NODE_DIR.getValue());
BatchCreateNormalDirReq batchCreateNormalDirReq = new BatchCreateNormalDirReq();
batchCreateNormalDirReq.setParentUUId(projectNodeId);
batchCreateNormalDirReq.setFolderNames(demandDirNodeList.stream().map(DirNodeInfo::getDirName).toList());
List<FolderItemReq> folderItemReqList = new ArrayList<>();
for (DirNodeInfo dirNodeInfo : demandDirNodeList) {
FolderItemReq folderItemReq = new FolderItemReq();
folderItemReq.setFolderName(dirNodeInfo.getDirName());
folderItemReq.setFolderUuid(dirNodeInfo.getUuId());
folderItemReqList.add(folderItemReq);
}
batchCreateNormalDirReq.setFolderItems(folderItemReqList);
log.info("批量创建需求文件夹请求参数:{}", batchCreateNormalDirReq);
try {
SdmResponse response = dataFeignClient.batchCreateNormalDirs(batchCreateNormalDirReq);

View File

@@ -3332,33 +3332,262 @@ public class TaskServiceImpl implements ITaskService {
return response;
}
/**
* 查询项目节点列表
*/
private List<SimulationNode> queryProjectNodes(Long tenantId, List<String> projectIdList) {
return nodeService.lambdaQuery()
.in(CollectionUtils.isNotEmpty(projectIdList), SimulationNode::getUuid, projectIdList)
.eq(SimulationNode::getNodeType, NodeTypeEnum.PROJECT.getValue())
.eq(SimulationNode::getTenantId, tenantId)
.orderByDesc(SimulationNode::getCreateTime)
.list();
}
/**
* 查询任务数据并构建映射关系
*/
private TaskData queryAndBuildTaskData(Long tenantId, List<String> projectIdList, String beginTime, String endTime) {
// 查询任务列表
List<SimulationTask> taskList = simulationTaskService.lambdaQuery()
.in(SimulationTask::getTag1, projectIdList)
.eq(SimulationTask::getTenantId, tenantId)
.ge(StringUtils.isNotBlank(beginTime), SimulationTask::getBeginTime, beginTime)
.le(StringUtils.isNotBlank(endTime), SimulationTask::getEndTime, endTime)
.list();
// 构建任务映射项目ID -> 任务列表)
Map<String, List<SimulationTask>> projectTaskMap = CollectionUtils.isEmpty(taskList)
? new HashMap<>()
: taskList.stream().collect(Collectors.groupingBy(SimulationTask::getTag1));
// 构建任务成员映射任务ID -> 用户ID集合
Map<String, Set<Long>> taskMemberMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(taskList)) {
List<String> taskIdList = taskList.stream().map(SimulationTask::getUuid).collect(Collectors.toList());
List<SpdmTaskMemberVo> taskMemberList = mapper.getMemberList(taskIdList, null);
if (CollectionUtils.isNotEmpty(taskMemberList)) {
taskMemberMap = taskMemberList.stream()
.collect(Collectors.groupingBy(
SpdmTaskMemberVo::getTaskId,
Collectors.mapping(SpdmTaskMemberVo::getUserId, Collectors.toSet())
));
}
}
return new TaskData(projectTaskMap, taskMemberMap);
}
/**
* 构建项目用户负载响应列表
*/
private List<ProjectUserLoadResp> buildProjectUserLoadResponse(List<SimulationNode> projectNodeList, TaskData taskData) {
List<ProjectUserLoadResp> responseList = new ArrayList<>();
Set<String> processedProjectNames = new HashSet<>(); // 记录已处理的项目名称,避免重复
for (SimulationNode projectNode : projectNodeList) {
String projectName = projectNode.getNodeName();
// 跳过已处理的项目
if (processedProjectNames.contains(projectName)) {
log.info("{}已作为参考项目查询过", projectName);
continue;
}
processedProjectNames.add(projectName);
// 构建当前项目的响应对象
ProjectUserLoadResp currentProjectResp = buildSingleProjectResp(projectNode, taskData);
responseList.add(currentProjectResp);
// 处理参考项目
handleReferenceProject(projectNode, projectNodeList, taskData, responseList, processedProjectNames);
}
return responseList;
}
/**
* 构建单个项目的响应对象
*/
private ProjectUserLoadResp buildSingleProjectResp(SimulationNode projectNode, TaskData taskData) {
ProjectUserLoadResp resp = new ProjectUserLoadResp();
resp.setProjectName(projectNode.getNodeName());
resp.setRelateProjectName(projectNode.getReferenceItem());
// 获取该项目的任务列表
List<SimulationTask> taskList = taskData.getProjectTaskMap().get(projectNode.getUuid());
if (CollectionUtils.isEmpty(taskList)) {
return resp; // 无任务时返回基础信息
}
// 填充任务相关信息
resp.setTaskNum(taskList.size());
resp.setTaskList(taskList);
// 计算用户数量
Set<Long> userIdSet = calculateUserIds(taskList, taskData.getTaskMemberMap());
resp.setUserNum(userIdSet.size());
// 计算工作量
double totalWorkload = taskList.stream()
.filter(task -> task.getDays() != null)
.mapToDouble(SimulationTask::getDays)
.sum();
resp.setWorkload(totalWorkload);
return resp;
}
/**
* 处理参考项目
*/
private void handleReferenceProject(SimulationNode currentNode,
List<SimulationNode> allProjectNodeList, // 新增:传入所有项目节点列表
TaskData taskData,
List<ProjectUserLoadResp> responseList,
Set<String> processedProjectNames) {
String referenceProjectName = currentNode.getReferenceItem();
if (StringUtils.isBlank(referenceProjectName)) {
return;
}
log.info("当前项目{}的参考项目为:{}", currentNode.getNodeName(), referenceProjectName);
// 修正从所有项目节点列表中查找参考项目而不是currentNode
Optional<SimulationNode> referenceNodeOpt = allProjectNodeList.stream()
.filter(node -> referenceProjectName.equals(node.getNodeName())) // 修正node是SimulationNode有getNodeName()
.findFirst();
if (referenceNodeOpt.isEmpty()) {
log.warn("未找到参考项目:{}", referenceProjectName);
return;
}
SimulationNode referenceNode = referenceNodeOpt.get();
String refProjectName = referenceNode.getNodeName();
// 避免重复处理参考项目
if (processedProjectNames.contains(refProjectName)) {
return;
}
processedProjectNames.add(refProjectName);
// 构建参考项目响应对象并添加到列表
ProjectUserLoadResp referenceResp = buildSingleProjectResp(referenceNode, taskData);
responseList.add(referenceResp);
}
/**
* 计算任务关联的用户ID集合
*/
private Set<Long> calculateUserIds(List<SimulationTask> taskList, Map<String, Set<Long>> taskMemberMap) {
Set<Long> userIdSet = new HashSet<>();
for (SimulationTask task : taskList) {
Set<Long> taskUserIds = taskMemberMap.get(task.getUuid());
if (CollectionUtils.isNotEmpty(taskUserIds)) {
userIdSet.addAll(taskUserIds);
}
}
return userIdSet;
}
/**
* 封装任务相关的映射关系
*/
private static class TaskData {
private final Map<String, List<SimulationTask>> projectTaskMap;
private final Map<String, Set<Long>> taskMemberMap;
public TaskData(Map<String, List<SimulationTask>> projectTaskMap, Map<String, Set<Long>> taskMemberMap) {
this.projectTaskMap = projectTaskMap;
this.taskMemberMap = taskMemberMap;
}
public Map<String, List<SimulationTask>> getProjectTaskMap() {
return projectTaskMap;
}
public Map<String, Set<Long>> getTaskMemberMap() {
return taskMemberMap;
}
}
/**
* 查询参考项目节点列表
*/
private List<SimulationNode> queryReferenceProjects(Long tenantId, List<String> referenceProjectNames) {
return nodeService.lambdaQuery()
.in(SimulationNode::getNodeName, referenceProjectNames)
.eq(SimulationNode::getNodeType, NodeTypeEnum.PROJECT.getValue())
.eq(SimulationNode::getTenantId, tenantId)
.list();
}
/**
* 补充参考项目到项目节点列表(核心新增逻辑的优化封装)
*/
private void supplementReferenceProjects(Long tenantId, List<SimulationNode> baseProjectNodeList) {
// 提取所有非空的参考项目名称
List<String> referenceProjectNames = baseProjectNodeList.stream()
.filter(node -> StringUtils.isNotBlank(node.getReferenceItem()))
.map(SimulationNode::getReferenceItem)
.distinct() // 去重,避免重复查询
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(referenceProjectNames)) {
return;
}
// 查询参考项目节点列表
List<SimulationNode> referenceProjectList = queryReferenceProjects(tenantId, referenceProjectNames);
if (CollectionUtils.isEmpty(referenceProjectList)) {
return;
}
// 构建原项目ID的HashSet
Set<String> baseProjectIdSet = baseProjectNodeList.stream()
.map(SimulationNode::getUuid)
.collect(Collectors.toSet());
// 补充未包含的参考项目
for (SimulationNode referenceProject : referenceProjectList) {
String refProjectId = referenceProject.getUuid();
if (!baseProjectIdSet.contains(refProjectId)) {
baseProjectNodeList.add(referenceProject);
log.debug("补充参考项目[{}]到项目列表中", referenceProject.getNodeName());
}
}
}
/**
* 查询项目人员负载
* 按项目、任务、任务成员以及参考项目的信息进行数据组装
* @param req
* @return
*/
@Override
public SdmResponse<List<ProjectUserLoadResp>> queryProjectUserLoads(ProjectUserLoadReq req) {
Long tenantId = ThreadLocalContext.getTenantId();
List<String> projectIdList = req.getProjectIdList();
String beginTime = req.getBeginTime();
String endTime = req.getEndTime();
// 根据项目id、开始/结束时间查询:参考项目、及对应的任务信息
List<SimulationNode> projectNodeList = nodeService.lambdaQuery().in(CollectionUtils.isNotEmpty(projectIdList), SimulationNode::getProjectId, projectIdList)
.eq(SimulationNode::getNodeType, NodeTypeEnum.PROJECT.getValue())
.eq(SimulationNode::getTenantId,tenantId).list();
// 1. 查询项目节点列表
List<SimulationNode> projectNodeList = queryProjectNodes(tenantId, projectIdList);
if (CollectionUtils.isEmpty(projectNodeList)) {
return SdmResponse.success(new ArrayList<>());
}
// 根据查询出来的项目,过滤出所有的任务
List<String> realProjectIdList;
// 2. 补充参考项目到节点列表仅当传入projectIdList时执行
if (CollectionUtils.isNotEmpty(projectIdList)) {
realProjectIdList = projectIdList;
}else {
realProjectIdList = projectNodeList.stream().map(SimulationNode::getUuid).toList();
supplementReferenceProjects(tenantId, projectNodeList);
}
// 根据查询出来的项目,过滤出所有的人员数量
List<ProjectNodeMemberPo> projectMemberList = projectMapper.getProjectMemberList(realProjectIdList);
List<SimulationTask> taskList = simulationTaskService.lambdaQuery().in(SimulationTask::getTag1, realProjectIdList).eq(SimulationTask::getTenantId, tenantId).list();
if (CollectionUtils.isNotEmpty(taskList)) {
List<SpdmTaskMemberVo> taskMemberList = mapper.getMemberList(taskList.stream().map(SimulationTask::getUuid).toList(),null);
}
return SdmResponse.success(new ArrayList<>());
// 3. 处理项目ID列表兼容未传projectIdList的情况
List<String> realProjectIdList = CollectionUtils.isNotEmpty(projectIdList)
? projectIdList
: projectNodeList.stream().map(SimulationNode::getUuid).collect(Collectors.toList());
// 4. 查询任务列表并构建映射
TaskData taskData = queryAndBuildTaskData(tenantId, realProjectIdList, req.getBeginTime(), req.getEndTime());
// 5. 构建返回结果
return SdmResponse.success(buildProjectUserLoadResponse(projectNodeList, taskData));
}
}

View File

@@ -7,13 +7,13 @@
<insert id="addNodeBatch" useGeneratedKeys="true" keyProperty="id">
insert into simulation_node
(uuid,ownRootNodeUuid,nodeName,nodeCode,englishName,nodeType,nodeSubType,nodeStatus,parentId,folderId,nodeLevel,beginTime,endTime,finishTime,progress,
achieveStatus,exe_status,tenantId,description,detailImgUrl,creator,create_time,tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,projectId,projectSource,commitmentDeadline)
achieveStatus,exe_status,tenantId,description,detailImgUrl,creator,create_time,tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,projectId,projectSource,commitmentDeadline,referenceItem)
values
<foreach collection='addNodeList' item='addNode' index='index' separator=','>
(#{addNode.uuid},#{addNode.ownRootNodeUuid},#{addNode.nodeName},#{addNode.nodeCode},#{addNode.englishName},#{addNode.nodeType},#{addNode.nodeSubType},'0',#{addNode.pid},
'',1,#{addNode.beginTime},#{addNode.endTime},'',#{addNode.progressStatus},#{addNode.achieveStatus},#{addNode.exeStatus},#{addNode.tenantId},#{addNode.description},
#{addNode.detailImgUrl},#{addNode.creator},#{addNode.createTime},#{addNode.tag1},#{addNode.tag2},
#{addNode.tag3},#{addNode.tag4},#{addNode.tag5},#{addNode.tag6},#{addNode.tag7},#{addNode.tag8},#{addNode.tag9},#{addNode.tag10},#{addNode.projectId},#{addNode.projectSource},#{addNode.commitmentDeadline})
#{addNode.tag3},#{addNode.tag4},#{addNode.tag5},#{addNode.tag6},#{addNode.tag7},#{addNode.tag8},#{addNode.tag9},#{addNode.tag10},#{addNode.projectId},#{addNode.projectSource},#{addNode.commitmentDeadline},#{addNode.referenceItem})
</foreach>
</insert>