1、关注/取消关注项目接口
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(), req.getUserIdList());
|
||||
}
|
||||
|
||||
@SysLog("取消关注项目")
|
||||
@PostMapping("/unFollowProject")
|
||||
@Operation(summary = "关注项目", description = "关注项目")
|
||||
public SdmResponse unFollowProject(@RequestBody SpdmProjectFollowReq req) {
|
||||
return nodeService.unFollowProject(req.getNodeId(), req.getUserIdList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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,21 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 关注项目的用户id集合
|
||||
*/
|
||||
List<Long> userIdList;
|
||||
|
||||
}
|
||||
@@ -110,4 +110,10 @@ public class SpdmNodeVo extends BaseEntity {
|
||||
* 当前阶段
|
||||
*/
|
||||
private String currentPhase;
|
||||
|
||||
/**
|
||||
* 关注标识,0:未关注,1:已关注,默认为0
|
||||
*/
|
||||
private Integer attentionFlag = 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -92,4 +92,22 @@ public interface INodeService extends IService<SimulationNode> {
|
||||
|
||||
SdmResponse<List<SimulationRunResp>> getRunListByRunIdList(SpdmQueryRunInfoListReq req);
|
||||
|
||||
/**
|
||||
* 关注项目(批量为多个用户添加项目关注关系)
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @param userIdList 要关注项目的用户ID列表
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
SdmResponse followProject(String nodeId, List<Long> userIdList);
|
||||
|
||||
/**
|
||||
* 取消关注项目(批量为多个用户删除项目关注关系)
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @param userIdList 要关注项目的用户ID列表
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
SdmResponse unFollowProject(String nodeId, List<Long> userIdList);
|
||||
|
||||
}
|
||||
|
||||
@@ -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,17 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
"workspaceNodeId"
|
||||
};
|
||||
|
||||
// 常量定义:提示文案
|
||||
private static final String PARAM_ERROR_MSG = "参数不正确";
|
||||
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 +494,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 +532,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 +1000,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 +1385,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 +4008,221 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
|
||||
return SdmResponse.success(simulationRunResps);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关注项目(批量为多个用户添加项目关注关系)
|
||||
* 幂等性保障:先查询已关注记录,避免重复插入
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @param userIdList 要关注项目的用户ID列表
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse followProject(String nodeId, List<Long> userIdList) {
|
||||
// 1. 参数校验
|
||||
if (StringUtils.isEmpty(nodeId) || CollectionUtils.isEmpty(userIdList)) {
|
||||
log.warn("关注项目参数异常,nodeId:{},userIdList:{}", nodeId, userIdList);
|
||||
return SdmResponse.failed(PARAM_ERROR_MSG);
|
||||
}
|
||||
|
||||
// 2. 查询项目节点是否存在
|
||||
SimulationNode projectNode = this.lambdaQuery()
|
||||
.eq(SimulationNode::getUuid, nodeId)
|
||||
.one();
|
||||
if (projectNode == null) {
|
||||
log.error("关注项目失败,根据nodeId:{} 未查询到项目节点", nodeId);
|
||||
return SdmResponse.failed(FOLLOW_PROJECT_NOT_FOUND_MSG);
|
||||
}
|
||||
|
||||
// 3. 过滤无效用户ID(null/负数)
|
||||
List<Long> validUserIdList = userIdList.stream()
|
||||
.filter(userId -> userId != null && userId > 0)
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(validUserIdList)) {
|
||||
log.info("无有效用户ID需要关注项目,nodeId:{}", nodeId);
|
||||
return SdmResponse.success();
|
||||
}
|
||||
|
||||
// 4. 校验幂等性,防止重复关注
|
||||
Set<Long> existedFollowedUserIdSet = queryExistedFollowedUserIds(nodeId, validUserIdList);
|
||||
|
||||
// 5. 过滤出未关注的用户ID
|
||||
List<Long> toFollowUserIdList = validUserIdList.stream()
|
||||
.filter(userId -> !existedFollowedUserIdSet.contains(userId))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 6. 处理已全部关注的情况
|
||||
if (CollectionUtils.isEmpty(toFollowUserIdList)) {
|
||||
log.info("所有用户均已关注项目,nodeId:{},用户列表:{}", nodeId, validUserIdList);
|
||||
return SdmResponse.success(ALL_FOLLOWED_MSG);
|
||||
}
|
||||
|
||||
// 7. 记录重复关注的用户
|
||||
List<Long> repeatedUserIdList = validUserIdList.stream()
|
||||
.filter(existedFollowedUserIdSet::contains)
|
||||
.collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(repeatedUserIdList)) {
|
||||
log.error("部分用户已关注项目,跳过重复关注,nodeId:{},重复用户ID:{}", nodeId, repeatedUserIdList);
|
||||
}
|
||||
|
||||
// 8. 构建批量插入的关注关系列表(仅处理未关注用户)
|
||||
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);
|
||||
}
|
||||
|
||||
// 9. 批量保存未关注的用户关系
|
||||
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());
|
||||
}
|
||||
|
||||
// 10. 返回结果(区分“全部成功”和“部分成功”)
|
||||
String successMsg = CollectionUtils.isEmpty(repeatedUserIdList) ? "项目关注成功" : PARTIAL_FOLLOW_SUCCESS_MSG;
|
||||
log.info("项目关注处理完成,nodeId:{},成功关注用户数:{},重复关注用户数:{}", nodeId, toFollowUserIdList.size(), repeatedUserIdList.size());
|
||||
return SdmResponse.success(successMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消关注项目(批量为多个用户删除项目关注关系)
|
||||
*
|
||||
* @param nodeId 项目节点ID(uuid)
|
||||
* @param userIdList 要取消关注的用户ID列表
|
||||
* @return 统一响应结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SdmResponse unFollowProject(String nodeId, List<Long> userIdList) {
|
||||
// 1. 参数校验
|
||||
if (StringUtils.isEmpty(nodeId) || CollectionUtils.isEmpty(userIdList)) {
|
||||
log.warn("取消关注项目参数异常,nodeId:{},userIdList:{}", nodeId, userIdList);
|
||||
return SdmResponse.failed(PARAM_ERROR_MSG);
|
||||
}
|
||||
|
||||
// 2. 校验项目是否存在
|
||||
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);
|
||||
}
|
||||
|
||||
// 3. 过滤无效用户ID(null/负数),避免无效SQL条件
|
||||
List<Long> validUserIdList = userIdList.stream().filter(userId -> userId != null && userId > 0).collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(validUserIdList)) {
|
||||
log.info("取消关注项目无有效用户ID,nodeId:{}", nodeId);
|
||||
return SdmResponse.success(NO_UNFOLLOW_DATA_MSG);
|
||||
}
|
||||
|
||||
// 4. 幂等性核心:先查询已存在的关注关系(仅查询需要删除的记录)
|
||||
Set<Long> existedFollowedUserIdSet = queryExistedFollowedUserIds(nodeId, validUserIdList);
|
||||
if (CollectionUtils.isEmpty(existedFollowedUserIdSet)) {
|
||||
log.info("取消关注项目失败,无已关注的用户记录,nodeId:{},用户列表:{}", nodeId, validUserIdList);
|
||||
return SdmResponse.success(NO_UNFOLLOW_DATA_MSG);
|
||||
}
|
||||
|
||||
// 5. 仅删除已存在的关注关系(避免无效删除操作)
|
||||
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);
|
||||
}
|
||||
|
||||
// 6. 返回结果
|
||||
return SdmResponse.success(UNFOLLOW_SUCCESS_MSG);
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public SdmResponse unFollowProject(String nodeId, List<Long> userIdList) {
|
||||
// if (StringUtils.isBlank(nodeId) || CollectionUtils.isEmpty(userIdList)) {
|
||||
// return SdmResponse.failed("参数不正确");
|
||||
// }
|
||||
// SimulationNode projectNode = this.lambdaQuery().eq(SimulationNode::getUuid, nodeId).one();
|
||||
// if (ObjectUtils.isEmpty(projectNode)) {
|
||||
// log.error("followProject根据nodeId:{},未查询到项目", nodeId);
|
||||
// return SdmResponse.failed("取消关注项目失败,原因为:未查询到项目");
|
||||
// }
|
||||
// simulationNodeMemberService.lambdaUpdate().eq(SimulationNodeMember::getNodeId,nodeId).in(SimulationNodeMember::getUserId,userIdList).remove();
|
||||
// return SdmResponse.success();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 批量查询已关注指定项目的用户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());
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public SdmResponse followProject(String nodeId, List<Long> userIdList) {
|
||||
// if (StringUtils.isBlank(nodeId) || CollectionUtils.isEmpty(userIdList)) {
|
||||
// return SdmResponse.failed("参数不正确");
|
||||
// }
|
||||
// SimulationNode projectNode = this.lambdaQuery().eq(SimulationNode::getUuid, nodeId).one();
|
||||
// if (ObjectUtils.isEmpty(projectNode)) {
|
||||
// log.error("followProject根据nodeId:{},未查询到项目", nodeId);
|
||||
// return SdmResponse.failed("关注项目失败,原因为:未查询到项目");
|
||||
// }
|
||||
// if (CollectionUtils.isNotEmpty(userIdList)) {
|
||||
// List<SimulationNodeMember> attentionList = new ArrayList<>();
|
||||
// String curDateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
// Long jobNumber = ThreadLocalContext.getUserId();
|
||||
// // 关注
|
||||
// for (Long userId : userIdList) {
|
||||
// SimulationNodeMember simulationNodeMember = new SimulationNodeMember();
|
||||
// simulationNodeMember.setNodeId(nodeId);
|
||||
// simulationNodeMember.setUserId(userId);
|
||||
// simulationNodeMember.setType(NodeMemberTypeEnum.ATTENTION.getCode());
|
||||
// simulationNodeMember.setCreateTime(curDateStr);
|
||||
// simulationNodeMember.setCreator(jobNumber);
|
||||
// attentionList.add(simulationNodeMember);
|
||||
// }
|
||||
// simulationNodeMemberService.saveBatch(attentionList);
|
||||
// }
|
||||
// return SdmResponse.success();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 通用分组统计方法 - 按指定键分组统计状态数量
|
||||
*
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user