1、调整批量创建需求文件夹参数
2、新增查询项目人员负载接口
This commit is contained in:
@@ -140,4 +140,6 @@ public class SpdmProjectNodeEditReq extends BaseEntity {
|
||||
|
||||
private String commitmentDeadline;
|
||||
|
||||
private String referenceItem;
|
||||
|
||||
}
|
||||
|
||||
@@ -97,6 +97,11 @@ public interface ITaskService {
|
||||
|
||||
SdmResponse exportPerformanceByScript(HttpServletResponse response, PerformanceAnalysisExportExcelFormat req);
|
||||
|
||||
/**
|
||||
* 查询项目人员负载
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
SdmResponse<List<ProjectUserLoadResp>> queryProjectUserLoads(ProjectUserLoadReq req);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user