@@ -175,7 +175,6 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
} ;
// 常量定义:提示文案
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 = " 部分用户关注成功(部分用户已关注) " ;
@@ -4014,18 +4013,12 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
* 幂等性保障:先查询已关注记录,避免重复插入
*
* @param nodeId 项目节点ID( uuid)
* @param userIdList 要关注项目的用户ID列表
* @return 统一响应结果
*/
@Override
@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. 查询项目节点是否存在
public SdmResponse followProject ( String nodeId ) {
// 1. 查询项目节点是否存在
SimulationNode projectNode = this . lambdaQuery ( )
. eq ( SimulationNode : : getUuid , nodeId )
. one ( ) ;
@@ -4034,38 +4027,31 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
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 ( ) ;
}
List < Long > validUserIdList = Collections . singletonList ( ThreadLocalContext . getUserId ( ) ) ;
// 4 . 校验幂等性,防止重复关注
// 2 . 校验幂等性,防止重复关注
Set < Long > existedFollowedUserIdSet = queryExistedFollowedUserIds ( nodeId , validUserIdList ) ;
// 5 . 过滤出未关注的用户ID
// 3 . 过滤出未关注的用户ID
List < Long > toFollowUserIdList = validUserIdList . stream ( )
. filter ( userId - > ! existedFollowedUserIdSet . contains ( userId ) )
. collect ( Collectors . toList ( ) ) ;
// 6 . 处理已全部关注的情况
// 4 . 处理已全部关注的情况
if ( CollectionUtils . isEmpty ( toFollowUserIdList ) ) {
log . info ( " 所有用户均已关注项目, nodeId: {},用户列表:{} " , nodeId , validUserIdList ) ;
return SdmResponse . success ( ALL_FOLLOWED_MSG ) ;
}
// 7 . 记录重复关注的用户
// 5 . 记录重复关注的用户
List < Long > repeatedUserIdList = validUserIdList . stream ( )
. filter ( existedFollowedUserIdSet : : contains )
. collect ( Collectors . toList ( ) ) ;
if ( ! CollectionUtils . isEmpty ( repeatedUserIdList ) ) {
if ( CollectionUtils . isNot Empty ( repeatedUserIdList ) ) {
log . error ( " 部分用户已关注项目, 跳过重复关注, nodeId: {}, 重复用户ID: {} " , nodeId , repeatedUserIdList ) ;
}
// 8 . 构建批量插入的关注关系列表(仅处理未关注用户)
// 6 . 构建批量插入的关注关系列表(仅处理未关注用户)
LocalDateTime currentTime = LocalDateTime . now ( ) ;
Long currentUserId = ThreadLocalContext . getUserId ( ) ;
List < SimulationNodeMember > attentionList = new ArrayList < > ( toFollowUserIdList . size ( ) ) ;
@@ -4080,7 +4066,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
attentionList . add ( member ) ;
}
// 9 . 批量保存未关注的用户关系
// 7 . 批量保存未关注的用户关系
try {
boolean saveResult = simulationNodeMemberService . saveBatch ( attentionList ) ;
if ( ! saveResult ) {
@@ -4092,9 +4078,8 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
return SdmResponse . failed ( " 关注项目失败: " + e . getMessage ( ) ) ;
}
// 10 . 返回结果(区分“全部成功”和“部分成功”)
// 8 . 返回结果(区分“全部成功”和“部分成功”)
String successMsg = CollectionUtils . isEmpty ( repeatedUserIdList ) ? " 项目关注成功 " : PARTIAL_FOLLOW_SUCCESS_MSG ;
log . info ( " 项目关注处理完成, nodeId: {},成功关注用户数:{},重复关注用户数:{} " , nodeId , toFollowUserIdList . size ( ) , repeatedUserIdList . size ( ) ) ;
return SdmResponse . success ( successMsg ) ;
}
@@ -4102,40 +4087,29 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
* 取消关注项目(批量为多个用户删除项目关注关系)
*
* @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. 校验项目是否存在
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 ) ;
}
// 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 ) ;
}
List < Long > validUserIdList = Collections . singletonList ( ThreadLocalContext . getUserId ( ) ) ;
// 4. 幂等性核心:先查询已存在的关注关系(仅查询需要删除的记录)
// 2. 幂等:先查询已存在的关注关系(仅查询需要删除的记录)
Set < Long > existedFollowedUserIdSet = queryExistedFollowedUserIds ( nodeId , validUserIdList ) ;
if ( CollectionUtils . isEmpty ( existedFollowedUserIdSet ) ) {
log . info ( " 取消关注项目失败, 无已关注的用户记录, nodeId: {},用户列表:{} " , nodeId , validUserIdList ) ;
return SdmResponse . success ( NO_UNFOLLOW_DATA_MSG ) ;
}
// 5 . 仅删除已存在的关注关系(避免无效删除操作)
// 3 . 仅删除已存在的关注关系(避免无效删除操作)
try {
LambdaUpdateWrapper < SimulationNodeMember > updateWrapper = new LambdaUpdateWrapper < SimulationNodeMember > ( )
. eq ( SimulationNodeMember : : getNodeId , nodeId )
@@ -4149,25 +4123,10 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
return SdmResponse . failed ( UNFOLLOW_DELETE_FAIL_MSG ) ;
}
// 6 . 返回结果
// 4 . 返回结果
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
*
@@ -4194,35 +4153,6 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
. 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();
// }
/**
* 通用分组统计方法 - 按指定键分组统计状态数量
*