feat(ai-companion-comment): 新增删除评论功能并优化VO字段顺序

This commit is contained in:
2026-03-20 17:14:28 +08:00
parent 40d846ec0d
commit db38fe819c
5 changed files with 94 additions and 6 deletions

View File

@@ -8,6 +8,7 @@ import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.common.ResultUtils; import com.yolo.keyborad.common.ResultUtils;
import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.model.dto.comment.CommentAddReq; import com.yolo.keyborad.model.dto.comment.CommentAddReq;
import com.yolo.keyborad.model.dto.comment.CommentDeleteReq;
import com.yolo.keyborad.model.dto.comment.CommentLikeReq; import com.yolo.keyborad.model.dto.comment.CommentLikeReq;
import com.yolo.keyborad.model.dto.comment.CommentPageReq; import com.yolo.keyborad.model.dto.comment.CommentPageReq;
import com.yolo.keyborad.model.dto.comment.CommentReportReq; import com.yolo.keyborad.model.dto.comment.CommentReportReq;
@@ -56,6 +57,18 @@ public class AiCompanionCommentController {
return ResultUtils.success(commentId); return ResultUtils.success(commentId);
} }
@PostMapping("/delete")
@Operation(summary = "删除评论", description = "删除当前用户自己发布的评论;若删除根评论,其下回复将不会继续展示")
public BaseResponse<Boolean> deleteComment(@RequestBody CommentDeleteReq req) {
if (req == null || req.getCommentId() == null) {
throw new BusinessException(ErrorCode.COMMENT_ID_EMPTY);
}
Long userId = StpUtil.getLoginIdAsLong();
commentService.deleteComment(userId, req.getCommentId());
return ResultUtils.success(true);
}
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "分页查询评论", description = "分页查询AI陪聊角色的评论列表包含当前用户是否已点赞状态") @Operation(summary = "分页查询评论", description = "分页查询AI陪聊角色的评论列表包含当前用户是否已点赞状态")
public BaseResponse<IPage<CommentVO>> pageComments(@RequestBody CommentPageReq req) { public BaseResponse<IPage<CommentVO>> pageComments(@RequestBody CommentPageReq req) {

View File

@@ -0,0 +1,16 @@
package com.yolo.keyborad.model.dto.comment;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/*
* @author: ziin
* @date: 2026/3/20
*/
@Data
@Schema(description = "删除评论请求")
public class CommentDeleteReq {
@Schema(description = "评论ID", requiredMode = Schema.RequiredMode.REQUIRED)
private Long commentId;
}

View File

@@ -23,6 +23,9 @@ public class CommentVO {
@Schema(description = "发表评论的用户ID") @Schema(description = "发表评论的用户ID")
private Long userId; private Long userId;
@Schema(description = "发表评论的用户UID")
private Long userUid;
@Schema(description = "用户昵称") @Schema(description = "用户昵称")
private String userName; private String userName;

View File

@@ -23,6 +23,14 @@ public interface KeyboardAiCompanionCommentService extends IService<KeyboardAiCo
*/ */
Long addComment(Long userId, Long companionId, String content, Long parentId, Long rootId); Long addComment(Long userId, Long companionId, String content, Long parentId, Long rootId);
/**
* 删除评论
*
* @param userId 当前用户ID
* @param commentId 评论ID
*/
void deleteComment(Long userId, Long commentId);
/** /**
* 分页查询评论 * 分页查询评论
* *

View File

@@ -1,9 +1,12 @@
package com.yolo.keyborad.service.impl; package com.yolo.keyborad.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.mapper.KeyboardAiCompanionCommentMapper; import com.yolo.keyborad.mapper.KeyboardAiCompanionCommentMapper;
import com.yolo.keyborad.model.entity.KeyboardAiCompanionComment; import com.yolo.keyborad.model.entity.KeyboardAiCompanionComment;
import com.yolo.keyborad.model.entity.KeyboardUser; import com.yolo.keyborad.model.entity.KeyboardUser;
@@ -13,10 +16,11 @@ import com.yolo.keyborad.service.KeyboardAiCompanionCommentLikeService;
import com.yolo.keyborad.service.UserService; import com.yolo.keyborad.service.UserService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -29,6 +33,12 @@ import java.util.stream.Collectors;
@Service @Service
public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardAiCompanionCommentMapper, KeyboardAiCompanionComment> implements KeyboardAiCompanionCommentService { public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardAiCompanionCommentMapper, KeyboardAiCompanionComment> implements KeyboardAiCompanionCommentService {
private static final short ACTIVE_STATUS = 1;
private static final short DELETED_STATUS = -1;
private static final long MAX_REPLY_PREVIEW_COUNT = 999L;
@Resource @Resource
private UserService userService; private UserService userService;
@@ -43,19 +53,27 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
comment.setContent(content); comment.setContent(content);
comment.setParentId(parentId); comment.setParentId(parentId);
comment.setRootId(rootId); comment.setRootId(rootId);
comment.setStatus((short) 1); comment.setStatus(ACTIVE_STATUS);
comment.setLikeCount(0); comment.setLikeCount(0);
comment.setCreatedAt(new Date()); comment.setCreatedAt(new Date());
this.save(comment); this.save(comment);
return comment.getId(); return comment.getId();
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteComment(Long userId, Long commentId) {
KeyboardAiCompanionComment comment = getActiveComment(commentId);
validateDeletePermission(userId, comment.getUserId());
softDeleteComment(commentId);
}
@Override @Override
public IPage<CommentVO> pageComments(Long companionId, Integer pageNum, Integer pageSize) { public IPage<CommentVO> pageComments(Long companionId, Integer pageNum, Integer pageSize) {
Page<KeyboardAiCompanionComment> page = new Page<>(pageNum, pageSize); Page<KeyboardAiCompanionComment> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<KeyboardAiCompanionComment> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<KeyboardAiCompanionComment> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(KeyboardAiCompanionComment::getCompanionId, companionId) queryWrapper.eq(KeyboardAiCompanionComment::getCompanionId, companionId)
.eq(KeyboardAiCompanionComment::getStatus, 1) .eq(KeyboardAiCompanionComment::getStatus, ACTIVE_STATUS)
.isNull(KeyboardAiCompanionComment::getParentId) .isNull(KeyboardAiCompanionComment::getParentId)
.orderByDesc(KeyboardAiCompanionComment::getCreatedAt); .orderByDesc(KeyboardAiCompanionComment::getCreatedAt);
IPage<KeyboardAiCompanionComment> entityPage = this.page(page, queryWrapper); IPage<KeyboardAiCompanionComment> entityPage = this.page(page, queryWrapper);
@@ -87,7 +105,7 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
Page<KeyboardAiCompanionComment> page = new Page<>(pageNum, pageSize); Page<KeyboardAiCompanionComment> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<KeyboardAiCompanionComment> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<KeyboardAiCompanionComment> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(KeyboardAiCompanionComment::getCompanionId, companionId) queryWrapper.eq(KeyboardAiCompanionComment::getCompanionId, companionId)
.eq(KeyboardAiCompanionComment::getStatus, 1) .eq(KeyboardAiCompanionComment::getStatus, ACTIVE_STATUS)
.isNull(KeyboardAiCompanionComment::getParentId) .isNull(KeyboardAiCompanionComment::getParentId)
.orderByDesc(KeyboardAiCompanionComment::getCreatedAt); .orderByDesc(KeyboardAiCompanionComment::getCreatedAt);
IPage<KeyboardAiCompanionComment> entityPage = this.page(page, queryWrapper); IPage<KeyboardAiCompanionComment> entityPage = this.page(page, queryWrapper);
@@ -105,7 +123,7 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
// 查询所有回复 // 查询所有回复
LambdaQueryWrapper<KeyboardAiCompanionComment> replyWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<KeyboardAiCompanionComment> replyWrapper = new LambdaQueryWrapper<>();
replyWrapper.in(KeyboardAiCompanionComment::getRootId, topCommentIds) replyWrapper.in(KeyboardAiCompanionComment::getRootId, topCommentIds)
.eq(KeyboardAiCompanionComment::getStatus, 1) .eq(KeyboardAiCompanionComment::getStatus, ACTIVE_STATUS)
.orderByAsc(KeyboardAiCompanionComment::getCreatedAt); .orderByAsc(KeyboardAiCompanionComment::getCreatedAt);
allReplies = this.list(replyWrapper); allReplies = this.list(replyWrapper);
@@ -121,7 +139,7 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
repliesMap = repliesMap.entrySet().stream() repliesMap = repliesMap.entrySet().stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getKey,
e -> e.getValue().stream().limit(999).collect(Collectors.toList()) e -> e.getValue().stream().limit(MAX_REPLY_PREVIEW_COUNT).collect(Collectors.toList())
)); ));
} }
@@ -178,6 +196,35 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
}); });
} }
private KeyboardAiCompanionComment getActiveComment(Long commentId) {
KeyboardAiCompanionComment comment = this.getById(commentId);
if (comment == null || comment.getStatus() == null || comment.getStatus() != ACTIVE_STATUS) {
throw new BusinessException(ErrorCode.COMMENT_NOT_FOUND);
}
return comment;
}
private void validateDeletePermission(Long userId, Long ownerId) {
if (!userId.equals(ownerId)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
}
private void softDeleteComment(Long commentId) {
KeyboardAiCompanionComment updateEntity = new KeyboardAiCompanionComment();
updateEntity.setStatus(DELETED_STATUS);
updateEntity.setUpdatedAt(new Date());
LambdaUpdateWrapper<KeyboardAiCompanionComment> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(KeyboardAiCompanionComment::getId, commentId)
.eq(KeyboardAiCompanionComment::getStatus, ACTIVE_STATUS);
boolean updated = this.update(updateEntity, updateWrapper);
if (!updated) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "删除评论失败");
}
}
/** /**
* 将评论实体转换为VO * 将评论实体转换为VO
*/ */
@@ -201,6 +248,7 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
// 填充用户信息 // 填充用户信息
KeyboardUser user = userMap.get(entity.getUserId()); KeyboardUser user = userMap.get(entity.getUserId());
if (user != null) { if (user != null) {
vo.setUserUid(user.getUid());
vo.setUserName(user.getNickName()); vo.setUserName(user.getNickName());
vo.setUserAvatar(user.getAvatarUrl()); vo.setUserAvatar(user.getAvatarUrl());
} }