Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -47,4 +47,9 @@ public class SpdmNodeListReq {
|
||||
*/
|
||||
private String exeStatus;
|
||||
|
||||
/**
|
||||
* 查询类型,0:所有,1:我关注的,2:我负责的(2026-02-13 逻辑待定)
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.sdm.project.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum NodeMemberTypeEnum {
|
||||
|
||||
|
||||
MANAGER("项目经理", 0),
|
||||
ATTENTION("项目关注人", 1);
|
||||
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Integer code;
|
||||
|
||||
NodeMemberTypeEnum(String name, Integer code) {
|
||||
this.name = name;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -420,5 +420,19 @@ public class SimulationNodeController implements ISimulationNodeFeignClient {
|
||||
return nodeService.getRunListByRunIdList(req);
|
||||
}
|
||||
|
||||
@SysLog("关注项目")
|
||||
@PostMapping("/followProject")
|
||||
@Operation(summary = "关注项目", description = "关注项目")
|
||||
public SdmResponse followProject(@RequestBody SpdmProjectFollowReq req) {
|
||||
return nodeService.followProject(req.getNodeId());
|
||||
}
|
||||
|
||||
@SysLog("取消关注项目")
|
||||
@PostMapping("/unFollowProject")
|
||||
@Operation(summary = "关注项目", description = "关注项目")
|
||||
public SdmResponse unFollowProject(@RequestBody SpdmProjectFollowReq req) {
|
||||
return nodeService.unFollowProject(req.getNodeId());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -102,12 +102,19 @@ public interface SimulationNodeMapper extends BaseMapper<SimulationNode> {
|
||||
|
||||
SpdmNodeVo getNodeByProjectIdAndName(@Param("projectId") String projectId, @Param("projectName") String projectName);
|
||||
|
||||
List<PerformanceNodePo> getPerformanceListByIdList(@Param("taskIdList") List<String> taskIdList);
|
||||
|
||||
List<SimulationNode> queryNodeCodeByTags(@Param("list")List<String> tag1List, @Param("tagKey")String tagKey,@Param("tagValue") String tagValue);
|
||||
|
||||
List<TaskNodePo> getTaskListByProjectNodeId(@Param("nodeId") String nodeId);
|
||||
|
||||
List<TaskNodePo> getTaskListByPhaseNodeId(@Param("nodeId") String nodeId);
|
||||
|
||||
|
||||
List<SpdmNodeVo> getNodeListByUserId(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
|
||||
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit, @Param("userId") Long userId,@Param("type") Integer type);
|
||||
|
||||
int getNodeListCountByUserId(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
|
||||
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("userId") Long userId,@Param("type") Integer type);
|
||||
|
||||
List<SpdmNodeMemberVo> getNodeMemberListByMemberType(@Param("nodeIdList") List<String> nodeIdList,@Param("userId") Long userId,@Param("memberType") Integer memberType);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.sdm.project.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.sdm.project.model.entity.SimulationNodeMember;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SimulationNodeMemberMapper extends BaseMapper<SimulationNodeMember> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.sdm.project.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("simulation_node_member")
|
||||
@ApiModel(value="SimulationNodeMember", description="")
|
||||
public class SimulationNodeMember implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "主键ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty(value = "节点ID")
|
||||
@TableField("nodeId")
|
||||
private String nodeId;
|
||||
|
||||
@ApiModelProperty(value = "身份标识")
|
||||
@TableField("identity")
|
||||
private String identity;
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty(value = "创建人")
|
||||
@TableField("creator")
|
||||
private Long creator;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
@TableField("create_time")
|
||||
private String createTime;
|
||||
|
||||
@ApiModelProperty(value = "更新人")
|
||||
@TableField("updater")
|
||||
private Long updater;
|
||||
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
@TableField("update_time")
|
||||
private String updateTime;
|
||||
|
||||
@ApiModelProperty(value = "类型:0:项目经理,1:项目关注人")
|
||||
@TableField("type")
|
||||
private Integer type;
|
||||
|
||||
}
|
||||
@@ -23,4 +23,7 @@ public class SpdmNodeRelateMemberReq extends BaseEntity {
|
||||
|
||||
private Long userId;
|
||||
|
||||
// 0:项目经理 ,1:项目关注人
|
||||
private Integer type;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.sdm.project.model.req;
|
||||
|
||||
import com.sdm.common.entity.pojo.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SpdmProjectFollowReq extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 关联的项目节点id
|
||||
*/
|
||||
private String nodeId;
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sdm.project.model.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.sdm.common.entity.pojo.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -67,6 +68,7 @@ public class SpdmAnalysisTaskVo extends BaseEntity {
|
||||
/**
|
||||
* 仿真负责人
|
||||
*/
|
||||
@JsonProperty("pMembers")
|
||||
private String pMembers;
|
||||
|
||||
private String tag1;
|
||||
|
||||
@@ -110,4 +110,10 @@ public class SpdmNodeVo extends BaseEntity {
|
||||
* 当前阶段
|
||||
*/
|
||||
private String currentPhase;
|
||||
|
||||
/**
|
||||
* 关注标识,0:未关注,1:已关注,默认为0
|
||||
*/
|
||||
private Integer attentionFlag = 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -92,4 +92,20 @@ public interface INodeService extends IService<SimulationNode> {
|
||||
|
||||
SdmResponse<List<SimulationRunResp>> getRunListByRunIdList(SpdmQueryRunInfoListReq req);
|
||||
|
||||
/**
|
||||
* 关注项目(批量为多个用户添加项目关注关系)
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
SdmResponse followProject(String nodeId);
|
||||
|
||||
/**
|
||||
* 取消关注项目(批量为多个用户删除项目关注关系)
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
SdmResponse unFollowProject(String nodeId);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.sdm.project.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.sdm.project.model.entity.SimulationNodeMember;
|
||||
|
||||
public interface ISimulationNodeMemberService extends IService<SimulationNodeMember> {
|
||||
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.sdm.project.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.sdm.common.common.ResultCode;
|
||||
@@ -25,6 +29,7 @@ import com.sdm.common.entity.resp.PageDataResp;
|
||||
import com.sdm.common.entity.resp.data.BatchCreateNormalDirResp;
|
||||
import com.sdm.common.entity.resp.project.SimulationNodeResp;
|
||||
import com.sdm.common.entity.resp.project.SimulationRunResp;
|
||||
import com.sdm.common.entity.resp.project.SpdmTaskVo;
|
||||
import com.sdm.common.entity.resp.system.CIDStaffResp;
|
||||
import com.sdm.common.entity.resp.system.CIDUserResp;
|
||||
import com.sdm.common.entity.resp.system.SysUserGroupDetailResp;
|
||||
@@ -40,6 +45,7 @@ import com.sdm.common.utils.excel.ExcelUtil;
|
||||
import com.sdm.outbridge.entity.*;
|
||||
import com.sdm.outbridge.service.lyric.*;
|
||||
import com.sdm.project.common.MemberTypeEnum;
|
||||
import com.sdm.project.common.NodeMemberTypeEnum;
|
||||
import com.sdm.project.dao.SimulationDemandMapper;
|
||||
import com.sdm.project.dao.SimulationNodeMapper;
|
||||
import com.sdm.project.dao.SimulationProjectMapper;
|
||||
@@ -76,6 +82,7 @@ import javax.annotation.Resource;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -137,6 +144,9 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
@Autowired
|
||||
private ISimulationTaskService taskService;
|
||||
|
||||
@Autowired
|
||||
private ISimulationNodeMemberService simulationNodeMemberService;
|
||||
|
||||
/**
|
||||
* 扩展属性名称常量
|
||||
*/
|
||||
@@ -164,6 +174,16 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
"workspaceNodeId"
|
||||
};
|
||||
|
||||
// 常量定义:提示文案
|
||||
private static final String FOLLOW_PROJECT_NOT_FOUND_MSG = "关注项目失败,原因为:未查询到项目";
|
||||
private static final String FOLLOW_SAVE_FAIL_MSG = "批量保存关注关系失败";
|
||||
private static final String PARTIAL_FOLLOW_SUCCESS_MSG = "部分用户关注成功(部分用户已关注)";
|
||||
private static final String ALL_FOLLOWED_MSG = "所有用户均已关注该项目,无需重复操作";
|
||||
private static final String UN_FOLLOW_PROJECT_NOT_FOUND_MSG = "取消关注项目失败,原因为:未查询到项目";
|
||||
private static final String UNFOLLOW_DELETE_FAIL_MSG = "取消关注项目失败,删除关系记录异常";
|
||||
private static final String NO_UNFOLLOW_DATA_MSG = "没有需要取消关注的用户关系记录,无需操作";
|
||||
private static final String UNFOLLOW_SUCCESS_MSG = "取消关注项目成功";
|
||||
|
||||
@Autowired
|
||||
private LyricVProjectToDmService lyricVProjectToDmService;
|
||||
|
||||
@@ -473,8 +493,37 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
int pos = (req.getCurrent() - 1) * req.getSize();
|
||||
int limit = req.getSize();
|
||||
Long tenantId = ThreadLocalContext.getTenantId();
|
||||
List<SpdmNodeVo> nodeList = nodeMapper.getNodeList(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(),
|
||||
tenantId, pos, limit);
|
||||
Long userId = ThreadLocalContext.getUserId();
|
||||
// 查询类型,0:所有,1:我关注的,2:我负责的
|
||||
Integer type = req.getType();
|
||||
List<SpdmNodeVo> nodeList;
|
||||
int total;
|
||||
// type=0,查询所有,使用原有查询逻辑 (type=2查询我负责的,逻辑待定,暂时先查询所有)
|
||||
if (type == null || type == 0 || type == 2) {
|
||||
nodeList = nodeMapper.getNodeList(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(),
|
||||
tenantId, pos, limit);
|
||||
// 设置关注标签
|
||||
if (CollectionUtils.isNotEmpty(nodeList)) {
|
||||
List<String> nodeIdList = nodeList.stream().map(SpdmNodeVo::getUuid).toList();
|
||||
List<SpdmNodeMemberVo> nodeMemberList = nodeMapper.getNodeMemberListByMemberType(nodeIdList,userId, NodeMemberTypeEnum.ATTENTION.getCode());
|
||||
if (CollectionUtils.isNotEmpty(nodeMemberList)) {
|
||||
List<String> attentNodeIdList = nodeMemberList.stream().map(SpdmNodeMemberVo::getNodeId).toList();
|
||||
for (SpdmNodeVo spdmNodeVo : nodeList) {
|
||||
if (!attentNodeIdList.contains(spdmNodeVo.getUuid())) {
|
||||
continue;
|
||||
}
|
||||
spdmNodeVo.setAttentionFlag(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
total = nodeMapper.getNodeListCount(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(), tenantId);
|
||||
}else {
|
||||
nodeList = nodeMapper.getNodeListByUserId(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(),
|
||||
tenantId, pos, limit,userId,type);
|
||||
nodeList.forEach(node -> node.setAttentionFlag(1));
|
||||
total = nodeMapper.getNodeListCountByUserId(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(), tenantId,userId,type);
|
||||
}
|
||||
|
||||
CoreLogger.info("getNodeList param:{},tenantId:{}", JSONObject.toJSONString(req), tenantId);
|
||||
if (CollectionUtils.isEmpty(nodeList)) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
@@ -482,7 +531,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
jsonObject.put("total", 0);
|
||||
return SdmResponse.success(jsonObject);
|
||||
}
|
||||
int total = nodeMapper.getNodeListCount(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(), ThreadLocalContext.getTenantId());
|
||||
|
||||
log.info("总数为:{}", total);
|
||||
Integer progressStatus;
|
||||
Integer achieveStatus;
|
||||
@@ -950,8 +999,11 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
// 批量创建文件夹
|
||||
batchCreateNodeDir(addNodeList);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(allNodeManagerList) && nodeMapper.addNodeMemberBatch(allNodeManagerList) <= 0) {
|
||||
return null;
|
||||
if (CollectionUtils.isNotEmpty(allNodeManagerList)) {
|
||||
allNodeManagerList.forEach(nodeManager -> nodeManager.setType(NodeMemberTypeEnum.MANAGER.getCode()));
|
||||
if (nodeMapper.addNodeMemberBatch(allNodeManagerList) <= 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(allExtraList)) {
|
||||
CompletableFuture.runAsync(() -> nodeMapper.addNodeExtraBatch(allExtraList));
|
||||
@@ -1332,6 +1384,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
allNodeManagerList.forEach(node -> {
|
||||
node.setCreateTime(curDateStr);
|
||||
node.setCreator(jobNumber);
|
||||
node.setType(NodeMemberTypeEnum.MANAGER.getCode());
|
||||
});
|
||||
if (nodeMapper.addNodeMemberBatch(allNodeManagerList) <= 0) {
|
||||
return false;
|
||||
@@ -3954,6 +4007,152 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
return SdmResponse.success(simulationRunResps);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关注项目(批量为多个用户添加项目关注关系)
|
||||
* 幂等性保障:先查询已关注记录,避免重复插入
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse followProject(String nodeId) {
|
||||
// 1. 查询项目节点是否存在
|
||||
SimulationNode projectNode = this.lambdaQuery()
|
||||
.eq(SimulationNode::getUuid, nodeId)
|
||||
.one();
|
||||
if (projectNode == null) {
|
||||
log.error("关注项目失败,根据nodeId:{} 未查询到项目节点", nodeId);
|
||||
return SdmResponse.failed(FOLLOW_PROJECT_NOT_FOUND_MSG);
|
||||
}
|
||||
|
||||
List<Long> validUserIdList = Collections.singletonList(ThreadLocalContext.getUserId());
|
||||
|
||||
// 2. 校验幂等性,防止重复关注
|
||||
Set<Long> existedFollowedUserIdSet = queryExistedFollowedUserIds(nodeId, validUserIdList);
|
||||
|
||||
// 3. 过滤出未关注的用户ID
|
||||
List<Long> toFollowUserIdList = validUserIdList.stream()
|
||||
.filter(userId -> !existedFollowedUserIdSet.contains(userId))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 4. 处理已全部关注的情况
|
||||
if (CollectionUtils.isEmpty(toFollowUserIdList)) {
|
||||
log.info("所有用户均已关注项目,nodeId:{},用户列表:{}", nodeId, validUserIdList);
|
||||
return SdmResponse.success(ALL_FOLLOWED_MSG);
|
||||
}
|
||||
|
||||
// 5. 记录重复关注的用户
|
||||
List<Long> repeatedUserIdList = validUserIdList.stream()
|
||||
.filter(existedFollowedUserIdSet::contains)
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(repeatedUserIdList)) {
|
||||
log.error("部分用户已关注项目,跳过重复关注,nodeId:{},重复用户ID:{}", nodeId, repeatedUserIdList);
|
||||
}
|
||||
|
||||
// 6. 构建批量插入的关注关系列表(仅处理未关注用户)
|
||||
LocalDateTime currentTime = LocalDateTime.now();
|
||||
Long currentUserId = ThreadLocalContext.getUserId();
|
||||
List<SimulationNodeMember> attentionList = new ArrayList<>(toFollowUserIdList.size());
|
||||
|
||||
for (Long userId : toFollowUserIdList) {
|
||||
SimulationNodeMember member = new SimulationNodeMember();
|
||||
member.setNodeId(nodeId);
|
||||
member.setUserId(userId);
|
||||
member.setType(NodeMemberTypeEnum.ATTENTION.getCode());
|
||||
member.setCreateTime(LocalDateTimeUtil.format(currentTime, DatePattern.NORM_DATETIME_PATTERN));
|
||||
member.setCreator(currentUserId);
|
||||
attentionList.add(member);
|
||||
}
|
||||
|
||||
// 7. 批量保存未关注的用户关系
|
||||
try {
|
||||
boolean saveResult = simulationNodeMemberService.saveBatch(attentionList);
|
||||
if (!saveResult) {
|
||||
log.error("批量保存项目关注关系失败,nodeId:{},待关注用户数:{}", nodeId, toFollowUserIdList.size());
|
||||
return SdmResponse.failed(FOLLOW_SAVE_FAIL_MSG);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("批量保存项目关注关系异常,nodeId:{}", nodeId, e);
|
||||
return SdmResponse.failed("关注项目失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
// 8. 返回结果(区分“全部成功”和“部分成功”)
|
||||
String successMsg = CollectionUtils.isEmpty(repeatedUserIdList) ? "项目关注成功" : PARTIAL_FOLLOW_SUCCESS_MSG;
|
||||
return SdmResponse.success(successMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消关注项目(批量为多个用户删除项目关注关系)
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse unFollowProject(String nodeId) {
|
||||
// 1. 校验项目是否存在
|
||||
SimulationNode projectNode = this.lambdaQuery().eq(SimulationNode::getUuid, nodeId).one();
|
||||
if (projectNode == null) {
|
||||
log.error("取消关注项目失败,根据nodeId:{} 未查询到项目节点", nodeId);
|
||||
return SdmResponse.failed(UN_FOLLOW_PROJECT_NOT_FOUND_MSG);
|
||||
}
|
||||
|
||||
List<Long> validUserIdList = Collections.singletonList(ThreadLocalContext.getUserId());
|
||||
|
||||
|
||||
// 2. 幂等:先查询已存在的关注关系(仅查询需要删除的记录)
|
||||
Set<Long> existedFollowedUserIdSet = queryExistedFollowedUserIds(nodeId, validUserIdList);
|
||||
if (CollectionUtils.isEmpty(existedFollowedUserIdSet)) {
|
||||
log.info("取消关注项目失败,无已关注的用户记录,nodeId:{},用户列表:{}", nodeId, validUserIdList);
|
||||
return SdmResponse.success(NO_UNFOLLOW_DATA_MSG);
|
||||
}
|
||||
|
||||
// 3. 仅删除已存在的关注关系(避免无效删除操作)
|
||||
try {
|
||||
LambdaUpdateWrapper<SimulationNodeMember> updateWrapper = new LambdaUpdateWrapper<SimulationNodeMember>()
|
||||
.eq(SimulationNodeMember::getNodeId, nodeId)
|
||||
.in(SimulationNodeMember::getUserId, existedFollowedUserIdSet) // 仅删除存在的记录
|
||||
.eq(SimulationNodeMember::getType, NodeMemberTypeEnum.ATTENTION.getCode());
|
||||
|
||||
// 执行删除
|
||||
simulationNodeMemberService.remove(updateWrapper);
|
||||
} catch (Exception e) {
|
||||
log.error("取消关注项目删除操作异常,nodeId:{},用户列表:{}", nodeId, existedFollowedUserIdSet, e);
|
||||
return SdmResponse.failed(UNFOLLOW_DELETE_FAIL_MSG);
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
return SdmResponse.success(UNFOLLOW_SUCCESS_MSG);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询已关注指定项目的用户ID
|
||||
*
|
||||
* @param nodeId 项目节点ID
|
||||
* @param validUserIdList 待校验的有效用户ID列表
|
||||
* @return 已关注的用户ID集合(便于快速判断)
|
||||
*/
|
||||
private Set<Long> queryExistedFollowedUserIds(String nodeId, List<Long> validUserIdList) {
|
||||
// 构建查询条件:nodeId匹配 + userId在列表中 + 类型为关注
|
||||
LambdaQueryWrapper<SimulationNodeMember> queryWrapper = new LambdaQueryWrapper<SimulationNodeMember>()
|
||||
.eq(SimulationNodeMember::getNodeId, nodeId)
|
||||
.in(SimulationNodeMember::getUserId, validUserIdList)
|
||||
.eq(SimulationNodeMember::getType, NodeMemberTypeEnum.ATTENTION.getCode());
|
||||
|
||||
// 只查询userId字段
|
||||
List<SimulationNodeMember> existedList = simulationNodeMemberService.list(queryWrapper);
|
||||
|
||||
// 转换为Set,便于快速判断是否存在
|
||||
if (CollectionUtils.isEmpty(existedList)) {
|
||||
return Set.of(); // 返回空集合,避免NPE
|
||||
}
|
||||
return existedList.stream()
|
||||
.map(SimulationNodeMember::getUserId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用分组统计方法 - 按指定键分组统计状态数量
|
||||
*
|
||||
|
||||
@@ -32,6 +32,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.NodeMemberTypeEnum;
|
||||
import com.sdm.project.common.TaskExeStatusEnum;
|
||||
import com.sdm.project.common.VersionEnum;
|
||||
import com.sdm.project.dao.SimulationNodeMapper;
|
||||
@@ -2044,7 +2045,10 @@ public class ProjectServiceImpl extends BaseService implements IProjectService {
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(projectNodeMemberList)) {
|
||||
projectNodeMemberList.forEach(projectNode -> projectNode.setCreateTime(createTime));
|
||||
projectNodeMemberList.forEach(projectNode -> {
|
||||
projectNode.setCreateTime(createTime);
|
||||
projectNode.setType(NodeMemberTypeEnum.MANAGER.getCode());
|
||||
});
|
||||
if (mapper.batchAddSimulationNodeMember(projectNodeMemberList) <= 0) {
|
||||
response = SdmResponse.failed("添加节点成员属性失败");
|
||||
}
|
||||
@@ -2246,7 +2250,10 @@ public class ProjectServiceImpl extends BaseService implements IProjectService {
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(projectNodeMemberList)) {
|
||||
projectNodeMemberList.forEach(projectNode -> projectNode.setCreateTime(createTime));
|
||||
projectNodeMemberList.forEach(projectNode -> {
|
||||
projectNode.setCreateTime(createTime);
|
||||
projectNode.setType(NodeMemberTypeEnum.MANAGER.getCode());
|
||||
});
|
||||
if (mapper.batchAddSimulationNodeMember(projectNodeMemberList) <= 0) {
|
||||
response = SdmResponse.failed("添加节点成员属性失败");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.sdm.project.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.sdm.project.dao.SimulationNodeMemberMapper;
|
||||
import com.sdm.project.model.entity.SimulationNodeMember;
|
||||
import com.sdm.project.service.ISimulationNodeMemberService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SimulationNodeMemberServiceImpl extends ServiceImpl<SimulationNodeMemberMapper, SimulationNodeMember> implements ISimulationNodeMemberService {
|
||||
|
||||
}
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
|
||||
<insert id="addNodeMemberBatch">
|
||||
insert into simulation_node_member (nodeId,identity,name,user_id,creator,create_time) values
|
||||
insert into simulation_node_member (nodeId,identity,name,user_id,creator,create_time,type) values
|
||||
<foreach collection='addNodeMemberList' item='addNodeMember' index='index' separator=','>
|
||||
(#{addNodeMember.nodeId},#{addNodeMember.identity},#{addNodeMember.name},#{addNodeMember.userId},#{addNodeMember.creator},#{addNodeMember.createTime})
|
||||
(#{addNodeMember.nodeId},#{addNodeMember.identity},#{addNodeMember.name},#{addNodeMember.userId},#{addNodeMember.creator},#{addNodeMember.createTime},#{addNodeMember.type})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
@@ -780,5 +780,92 @@
|
||||
select * from simulation_task where tag2 = #{nodeId}
|
||||
</select>
|
||||
|
||||
<select id="getNodeListByUserId" resultType="com.sdm.project.model.vo.SpdmNodeVo">
|
||||
SELECT sn.*
|
||||
FROM simulation_node sn
|
||||
LEFT JOIN simulation_node_member snm ON sn.uuid = snm.nodeId
|
||||
WHERE snm.user_id = #{userId}
|
||||
<choose>
|
||||
<when test="type == 1">
|
||||
AND (snm.type = 1)
|
||||
</when>
|
||||
<!-- 我负责的逻辑待定 -->
|
||||
<!-- <when test="type == 2">-->
|
||||
<!-- -->
|
||||
<!-- </when>-->
|
||||
</choose>
|
||||
AND sn.tenantId = #{tenantId}
|
||||
<if test="nodeType != null and nodeType != ''">
|
||||
and sn.nodeType = #{nodeType}
|
||||
</if>
|
||||
<if test="nodeSubType != null and nodeSubType != ''">
|
||||
and sn.nodeSubType = #{nodeSubType}
|
||||
</if>
|
||||
<if test="exeStatus != null and exeStatus != ''">
|
||||
and sn.exe_status = #{exeStatus}
|
||||
</if>
|
||||
<if test="nodeCode != null and nodeCode != ''">
|
||||
<bind name="searchKey1" value="'%' + nodeCode + '%'"/>
|
||||
and sn.nodeCode like #{searchKey1}
|
||||
</if>
|
||||
<if test="manager != null and manager != ''">
|
||||
<bind name="searchKey2" value="'%' + manager + '%'"/>
|
||||
and snm.name like #{searchKey2}
|
||||
</if>
|
||||
<if test="nodeName != null and nodeName != ''">
|
||||
<bind name="searchKey3" value="'%' + nodeName + '%'"/>
|
||||
and sn.nodeName like #{searchKey3}
|
||||
</if>
|
||||
order by create_time desc
|
||||
limit #{pos},#{limit}
|
||||
</select>
|
||||
|
||||
<select id="getNodeListCountByUserId" resultType="java.lang.Integer">
|
||||
SELECT count(1)
|
||||
FROM simulation_node sn
|
||||
LEFT JOIN simulation_node_member snm ON sn.uuid = snm.nodeId
|
||||
WHERE snm.user_id = #{userId}
|
||||
<choose>
|
||||
<when test="type == 1">
|
||||
AND snm.type = 1
|
||||
</when>
|
||||
<!-- 我负责的逻辑待定 -->
|
||||
<!-- <when test="type == 2">-->
|
||||
<!-- -->
|
||||
<!-- </when>-->
|
||||
</choose>
|
||||
AND sn.tenantId = #{tenantId}
|
||||
<if test="nodeType != null and nodeType != ''">
|
||||
and sn.nodeType = #{nodeType}
|
||||
</if>
|
||||
<if test="nodeSubType != null and nodeSubType != ''">
|
||||
and sn.nodeSubType = #{nodeSubType}
|
||||
</if>
|
||||
<if test="exeStatus != null and exeStatus != ''">
|
||||
and sn.exe_status = #{exeStatus}
|
||||
</if>
|
||||
<if test="nodeCode != null and nodeCode != ''">
|
||||
<bind name="searchKey1" value="'%' + nodeCode + '%'"/>
|
||||
and sn.nodeCode like #{searchKey1}
|
||||
</if>
|
||||
<if test="manager != null and manager != ''">
|
||||
<bind name="searchKey2" value="'%' + manager + '%'"/>
|
||||
and snm.name like #{searchKey2}
|
||||
</if>
|
||||
<if test="nodeName != null and nodeName != ''">
|
||||
<bind name="searchKey3" value="'%' + nodeName + '%'"/>
|
||||
and sn.nodeName like #{searchKey3}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getNodeMemberListByMemberType" resultType="com.sdm.project.model.vo.SpdmNodeMemberVo">
|
||||
select * from simulation_node_member
|
||||
where user_id = #{userId} and nodeId in (
|
||||
<foreach collection='nodeIdList' item='nodeId' index='index' separator=','>
|
||||
#{nodeId}
|
||||
</foreach>
|
||||
) and type = #{memberType}
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -49,6 +49,10 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class SimulationSystemConfigServiceImpl extends BaseService implements ISimulationSystemConfigService {
|
||||
|
||||
// 是否开启用户自定义配置表单权限开关 true 开 false:关(宜安)
|
||||
@Value("${formconfigure.selfSysUserConfigButton:true}")
|
||||
private Boolean selfSysUserConfigButton;
|
||||
|
||||
@Value("#{'${formconfigure.admin.role:ROLE_ADMIN}'.split(',')}")
|
||||
private List<String> adminRoleList;
|
||||
|
||||
@@ -379,6 +383,11 @@ public class SimulationSystemConfigServiceImpl extends BaseService implements IS
|
||||
}
|
||||
|
||||
private boolean isNormalRole(){
|
||||
log.info("isNormalRole selfSysUserConfigButton:{}",selfSysUserConfigButton);
|
||||
// 自定义表单关闭,直接就都是超管
|
||||
if(!selfSysUserConfigButton){
|
||||
return false;
|
||||
}
|
||||
// 查询是否是可以自定义表格的角色,ROLE_ADMIN 是管理员角色
|
||||
SdmResponse<List<CIDRoleResp>> roleResponse = sysUserService.queryUserRole(ThreadLocalContext.getUserId());
|
||||
if(!roleResponse.isSuccess()){
|
||||
|
||||
@@ -145,7 +145,8 @@ cid:
|
||||
user:
|
||||
listUser: /spdm-user/listUser
|
||||
queryUserDetail: /spdm-user/queryUserDetail
|
||||
listUserByIds: /dataManager/tree/node/listUserByIds
|
||||
listUserByIds: /spdm-user/listUserByIds
|
||||
listUserDetailByIds: /spdm-user/listUserDetailByIds
|
||||
queryUserRole: /spdm-user/queryUserRole
|
||||
queryGroup: /spdm-user/queryGroup
|
||||
queryGroupDetail: /spdm-user/queryGroupDetail
|
||||
@@ -164,6 +165,8 @@ cid:
|
||||
launchApprove: /spdm-flow/startFlow
|
||||
queryFlowTemplate: /spdm-flow/listProcessByGroup
|
||||
queryApproveDetail: /spdm-flow/queryFlowNodeDetail
|
||||
queryNewApproveDetail: /spdm-flow/queryNewFlowNodeDetail
|
||||
getTaskIdByNodeId: /spdm-flow/getTaskIdByNodeId
|
||||
stopApproveFlow: /spdm-flow/stopFlow
|
||||
group: SPDM
|
||||
# 单次批量查询cid审批流详情的条数
|
||||
@@ -190,3 +193,7 @@ security:
|
||||
- /tenant/list
|
||||
- /tenant/initNewTenant
|
||||
- /user/getUserByRoleCode
|
||||
|
||||
# 表单配置开关
|
||||
formconfigure:
|
||||
selfSysUserConfigButton: false
|
||||
135
task/src/main/resources/application-yian.yml
Normal file
135
task/src/main/resources/application-yian.yml
Normal file
@@ -0,0 +1,135 @@
|
||||
# 前后端联调使用该配置文件,本地调试使用local
|
||||
server:
|
||||
port: 7102
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: task
|
||||
datasource:
|
||||
username: root
|
||||
password: mysql
|
||||
jdbc-url: jdbc:mysql://192.168.0.88:3306/spdm_baseline?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
hikari:
|
||||
# 设置连接池能够容纳的最大连接数。建议值:CPU核心数 * 2 + 有效磁盘I/O数。一个常见的经验值是 10-20。
|
||||
maximum-pool-size: 20
|
||||
# 连接池在空闲时保持的最小连接数。
|
||||
minimum-idle: 5
|
||||
# 一个连接在被标记为空闲之前可以保持空闲状态的最长时间(毫秒)。当连接的空闲时间超过此值后,它可能会被连接池 evict(驱逐)。
|
||||
idle-timeout: 60000 # 1 min
|
||||
# 一个连接从被创建开始,其生命周期的最大时长(毫秒)。HikariCP的默认值就是30分钟,这是一个非常合理的设置。
|
||||
max-lifetime: 1800000 # 30 min(Hikari 默认)
|
||||
# 应用程序尝试从连接池获取一个连接时,等待的最长时间(毫秒)。建议值:30-60秒。
|
||||
connection-timeout: 30000 # 30s
|
||||
master:
|
||||
username: root
|
||||
password: mysql
|
||||
jdbc-url: jdbc:mysql://192.168.0.88:3306/spdm_baseline?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
slave:
|
||||
username: root
|
||||
password: mysql
|
||||
jdbc-url: jdbc:mysql://192.168.0.88:3306/spdm_baseline?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
enable: true
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.0.88:8848
|
||||
group: DEV_GROUP
|
||||
# server-addr: 127.0.0.1:8848
|
||||
enabled: true
|
||||
# username: nacos
|
||||
# password: ENC(+QKYnI6gAYu1SbLaZQTkZA==)
|
||||
data:
|
||||
redis:
|
||||
# Redis默认情况下有16个分片(库),这里配置具体使用的分片,默认是0
|
||||
database: 0
|
||||
# redis服务器地址(填写自己的服务器地址)
|
||||
host: 192.168.0.88
|
||||
# redis端口(默认6379)
|
||||
port: 6379
|
||||
#redis连接超时等待,10秒
|
||||
timeout: PT10S
|
||||
# redis访问密码(默认为空)
|
||||
password:
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池最大连接数(使用负值表示没有限制) 默认 8
|
||||
max-active: 50
|
||||
# 连接池中的最大空闲连接 默认 8
|
||||
max-idle: 20
|
||||
# 连接池中的最小空闲连接 默认 0
|
||||
min-idle: 1
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1,这里配置10s
|
||||
max-wait: PT10S
|
||||
# password:
|
||||
# sentinel:
|
||||
# master: mymaster
|
||||
# nodes: 10.18.109.50:26379,10.18.109.51:26379,10.18.109.52:26379
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件的最大值
|
||||
max-file-size: 500MB
|
||||
# 上传文件总的最大值
|
||||
max-request-size: 10240MB
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,info
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
group:
|
||||
readiness:
|
||||
include: discoveryComposite,ping,refreshScope
|
||||
health:
|
||||
redis:
|
||||
enabled: false
|
||||
db:
|
||||
enabled: false
|
||||
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
auto-mapping-behavior: full
|
||||
# cache-enabled: true
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
mapper-locations: classpath*:mapper/**/*.xml
|
||||
global-config:
|
||||
# 逻辑删除配置
|
||||
db-config:
|
||||
# 删除前
|
||||
logic-not-delete-value: 1
|
||||
# 删除后
|
||||
logic-delete-value: 0
|
||||
|
||||
#showSql
|
||||
#logging:
|
||||
# level:
|
||||
# com.sdm.dao: debug
|
||||
|
||||
lombok:
|
||||
anyConstructor:
|
||||
addConstructorProperties: true
|
||||
|
||||
file:
|
||||
rootPath: /data/home/sdm
|
||||
scriptPath : /opt/script
|
||||
approve:
|
||||
replyUrl: http:192.168.0.88:7102/simulation/task/taskpool/approveHandleNotice
|
||||
#logging:
|
||||
# config: ./config/logback.xml
|
||||
|
||||
security:
|
||||
whitelist:
|
||||
paths:
|
||||
- /taskpool/approveHandleNotice
|
||||
- /taskPerformance/getRunPerformance
|
||||
|
||||
simulationPool:
|
||||
baseline: baseline
|
||||
lyric: lyric
|
||||
chose: lyric
|
||||
Reference in New Issue
Block a user