diff --git a/.gitignore b/.gitignore index 33a4bc7e..a65ef9dd 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,4 @@ target/ .DS_Store devops-monitor-id_rsa.key +/claude/ diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/dynamic/DynamicRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/dynamic/DynamicRestController.java index 3c0afef2..937a3259 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/dynamic/DynamicRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/dynamic/DynamicRestController.java @@ -13,14 +13,7 @@ import com.red.circle.other.app.dto.clientobject.dynamic.DynamicListCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicMessageListCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicSendRestrictCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicTagCO; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicByTagLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicCommentCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicCommentLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicContentAddCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicLikeCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicMyLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicReportCmd; +import com.red.circle.other.app.dto.cmd.dynamic.*; import com.red.circle.other.app.service.dynamic.DynamicService; import java.util.List; import lombok.RequiredArgsConstructor; @@ -84,6 +77,20 @@ public class DynamicRestController extends BaseController { return dynamicService.listDynamicComment(cmd); } + /** + * 动态子评论列表. + * + * @eo.name 动态子评论列表. + * @eo.url /list/comment/children + * @eo.method get + * @eo.request-type formdata + */ + @GetMapping("/list/comment/children") + public PageResult listDynamicChildComment( + @Validated DynamicChildCommentLimitCmd cmd) { + return dynamicService.listDynamicChildComment(cmd); + } + /** * 动态内容详情. * diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicChildCommentQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicChildCommentQryExe.java new file mode 100644 index 00000000..777deb94 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicChildCommentQryExe.java @@ -0,0 +1,112 @@ +package com.red.circle.other.app.command.dynamic.query; + +import com.red.circle.framework.dto.PageResult; +import com.red.circle.other.app.dto.clientobject.dynamic.DynamicCommentListCO; +import com.red.circle.other.app.dto.cmd.dynamic.DynamicChildCommentLimitCmd; +import com.red.circle.other.domain.gateway.user.UserProfileGateway; +import com.red.circle.other.domain.model.user.UserProfile; +import com.red.circle.other.infra.database.cache.service.other.DynamicCacheService; +import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicComment; +import com.red.circle.other.infra.database.rds.service.dynamic.DynamicCommentLikeService; +import com.red.circle.other.infra.database.rds.service.dynamic.DynamicCommentService; +import com.red.circle.tool.core.collection.CollectionUtils; +import com.red.circle.tool.core.num.NumUtils; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 动态子评论列表查询. + * + * @author pengshigang + * @since 2025-01-29 + */ +@Component +@RequiredArgsConstructor +public class DynamicChildCommentQryExe { + + private final UserProfileGateway userProfileGateway; + private final DynamicCacheService dynamicCacheService; + private final DynamicCommentService dynamicCommentService; + private final DynamicCommentLikeService dynamicCommentLikeService; + + public PageResult execute(DynamicChildCommentLimitCmd cmd) { + + PageResult comments = pageData(cmd); + if (CollectionUtils.isEmpty(comments.getRecords())) { + return PageResult.newPageResult(0); + } + + Map userMap = userProfileGateway.mapByUserIds(getUserIds(comments)); + Map commentLikeMap = getCommentLikeMap(cmd, comments); + + return comments.convert(comment -> { + + DynamicCommentListCO listCO = new DynamicCommentListCO(); + UserProfile createUser = userMap.get(comment.getCreateUser()); + if (Objects.isNull(createUser)) { + return null; + } + listCO.setUserAvatar(createUser.getUserAvatar()); + listCO.setUserNickname(createUser.getUserNickname()); + listCO.setUserSex(createUser.getUserSex()); + listCO.setUserId(createUser.getId()); + listCO.setRootCommentId(comment.getRootCommentId()); + + UserProfile toUser = userMap.get(comment.getToUserId()); + if (Objects.nonNull(toUser)) { + listCO.setToUserId(toUser.getId()); + listCO.setToUserNickname(toUser.getUserNickname()); + } + + listCO.setLike(getLike(commentLikeMap, comment)); + listCO.setLikeStrQuantity(getLikeStrQuantity(comment)); + listCO.setId(comment.getId()); + listCO.setDynamicId(comment.getDynamicContentId()); + listCO.setContent(comment.getContent()); + listCO.setCreateTime(comment.getCreateTime()); + + return listCO; + + }); + } + + private Boolean getLike(Map commentLikeMap, DynamicComment comment) { + return Optional.ofNullable(commentLikeMap.get(comment.getId())).orElse(Boolean.FALSE); + } + + private Map getCommentLikeMap(DynamicChildCommentLimitCmd cmd, + PageResult comments) { + return dynamicCommentLikeService + .mapByCommentIdsByUserId(comments.getRecords().stream().map(DynamicComment::getId).collect( + Collectors.toSet()), cmd.getReqUserId()); + } + + private String getLikeStrQuantity(DynamicComment comment) { + return NumUtils.formatLong(Optional.ofNullable( + dynamicCacheService.getCommentLikeQuantity(comment.getDynamicContentId(), comment.getId())) + .orElse(0L)); + } + + private Set getUserIds(PageResult comments) { + + Set userIds = comments.getRecords().stream().map(DynamicComment::getCreateUser) + .filter(Objects::nonNull).collect(Collectors.toSet()); + + userIds.addAll(comments.getRecords().stream().map(DynamicComment::getToUserId) + .filter(Objects::nonNull) + .collect(Collectors.toSet())); + + return userIds; + } + + private PageResult pageData(DynamicChildCommentLimitCmd cmd) { + return dynamicCommentService.pageChildCommentsByTimeDesc(cmd.getPageReq(), + cmd.getRootCommentId()); + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicCommentQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicCommentQryExe.java index 17f309d5..473b7ecb 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicCommentQryExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/dynamic/query/DynamicCommentQryExe.java @@ -57,6 +57,9 @@ public class DynamicCommentQryExe { userProfileGateway.mapByUserIds(getUserIds(comments)); Map commentLikeMap = getCommentLikeMap(cmd, comments); + + // 批量查询所有根评论的子评论数量 + Map childCommentCountMap = getChildCommentCountMap(comments); return comments.convert(comment -> { @@ -89,6 +92,11 @@ public class DynamicCommentQryExe { listCO.setContent(comment.getContent()); listCO.setCreateTime(comment.getCreateTime()); + // 设置子评论数量(仅根评论有值) + if (Objects.isNull(comment.getRootCommentId())) { + listCO.setChildCommentCount(childCommentCountMap.getOrDefault(comment.getId(), 0)); + } + return listCO; }); @@ -124,7 +132,23 @@ public class DynamicCommentQryExe { } private PageResult pageData(DynamicCommentLimitCmd cmd) { - return dynamicCommentService.pageByTimeDesc(cmd.getPageReq(), cmd.getDynamicId()); + return dynamicCommentService.pageRootCommentsByTimeDesc(cmd.getPageReq(), cmd.getDynamicId()); + } + + /** + * 批量查询根评论的子评论数量 + */ + private Map getChildCommentCountMap(PageResult comments) { + Set rootCommentIds = comments.getRecords().stream() + .filter(comment -> Objects.isNull(comment.getRootCommentId())) + .map(DynamicComment::getId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(rootCommentIds)) { + return java.util.Collections.emptyMap(); + } + + return dynamicCommentService.mapChildCommentCount(rootCommentIds); } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/dynamic/DynamicServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/dynamic/DynamicServiceImpl.java index 20dcb0ec..53af19df 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/dynamic/DynamicServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/dynamic/DynamicServiceImpl.java @@ -16,6 +16,7 @@ import com.red.circle.other.app.command.dynamic.delete.DynamicCommentDelCmdExe; import com.red.circle.other.app.command.dynamic.delete.DynamicContentDelCmdExe; import com.red.circle.other.app.command.dynamic.delete.DynamicMessageAllDelCmdExe; import com.red.circle.other.app.command.dynamic.delete.DynamicMessageDelCmdExe; +import com.red.circle.other.app.command.dynamic.query.DynamicChildCommentQryExe; import com.red.circle.other.app.command.dynamic.query.DynamicCommentQryExe; import com.red.circle.other.app.command.dynamic.query.DynamicDetailsQryExe; import com.red.circle.other.app.command.dynamic.query.DynamicFollowQryExe; @@ -30,14 +31,8 @@ import com.red.circle.other.app.dto.clientobject.dynamic.DynamicListCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicMessageListCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicSendRestrictCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicTagCO; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicByTagLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicCommentCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicCommentLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicContentAddCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicLikeCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicMyLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicReportCmd; +import com.red.circle.other.app.dto.cmd.dynamic.*; + import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -66,6 +61,7 @@ public class DynamicServiceImpl implements DynamicService { private final DynamicPopularQryExe dynamicPopularQryExe; private final DynamicDetailsQryExe dynamicDetailsQryExe; private final DynamicCommentQryExe dynamicCommentQryExe; + private final DynamicChildCommentQryExe dynamicChildCommentQryExe; private final DynamicCommentDelCmdExe dynamicCommentDelExe; private final DynamicCommentLikeCmdExe dynamicCommentLikeExe; private final DynamicContentDelCmdExe dynamicContentDelExe; @@ -91,6 +87,11 @@ public class DynamicServiceImpl implements DynamicService { return dynamicCommentQryExe.execute(cmd); } + @Override + public PageResult listDynamicChildComment(DynamicChildCommentLimitCmd cmd) { + return dynamicChildCommentQryExe.execute(cmd); + } + @Override public DynamicListCO getDynamicDetails(IdLongCmd cmd) { return dynamicDetailsQryExe.execute(cmd); diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/dynamic/DynamicCommentListCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/dynamic/DynamicCommentListCO.java index 668abb86..996a39f3 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/dynamic/DynamicCommentListCO.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/dynamic/DynamicCommentListCO.java @@ -94,4 +94,9 @@ public class DynamicCommentListCO extends ClientObject { */ private Long rootCommentId; + /** + * 子评论数量(仅根评论有值) + */ + private Integer childCommentCount; + } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/dynamic/DynamicChildCommentLimitCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/dynamic/DynamicChildCommentLimitCmd.java new file mode 100644 index 00000000..7808aa1d --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/dynamic/DynamicChildCommentLimitCmd.java @@ -0,0 +1,35 @@ +package com.red.circle.other.app.dto.cmd.dynamic; + +import com.red.circle.common.business.dto.PageReq; +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 动态-子评论列表. + * + * @author pengshigang + * @since 2025-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DynamicChildCommentLimitCmd extends AppExtCommand { + + /** + * 页码. + * + * @eo.required + */ + @NotNull + private PageReq pageReq; + + /** + * 根评论id. + * + * @eo.required + */ + @NotNull + private Long rootCommentId; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/dynamic/DynamicService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/dynamic/DynamicService.java index 1ffc5b4e..a665d54c 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/dynamic/DynamicService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/dynamic/DynamicService.java @@ -10,14 +10,8 @@ import com.red.circle.other.app.dto.clientobject.dynamic.DynamicListCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicMessageListCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicSendRestrictCO; import com.red.circle.other.app.dto.clientobject.dynamic.DynamicTagCO; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicByTagLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicCommentCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicCommentLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicContentAddCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicLikeCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicMyLimitCmd; -import com.red.circle.other.app.dto.cmd.dynamic.DynamicReportCmd; +import com.red.circle.other.app.dto.cmd.dynamic.*; + import java.util.List; /** @@ -46,6 +40,11 @@ public interface DynamicService { */ PageResult listDynamicComment(DynamicCommentLimitCmd cmd); + /** + * 动态子评论列表. + */ + PageResult listDynamicChildComment(DynamicChildCommentLimitCmd cmd); + /** * 动态内容详情. */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/DynamicCommentService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/DynamicCommentService.java index 45e3db68..da906cac 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/DynamicCommentService.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/DynamicCommentService.java @@ -28,6 +28,22 @@ public interface DynamicCommentService extends BaseService { */ PageResult pageByTimeDesc(PageQuery pageQuery, Long contentId); + /** + * 分页查询根评论(按时间倒序) + * + * @param pageQuery 分页参数 + * @param contentId 动态内容ID + */ + PageResult pageRootCommentsByTimeDesc(PageQuery pageQuery, Long contentId); + + /** + * 分页查询子评论(按时间倒序) + * + * @param pageQuery 分页参数 + * @param rootCommentId 根评论ID + */ + PageResult pageChildCommentsByTimeDesc(PageQuery pageQuery, Long rootCommentId); + /** * 获得子评论数 * @@ -83,4 +99,12 @@ public interface DynamicCommentService extends BaseService { */ Map mapCommentQuantity(Collection contentIds); + /** + * 批量获取根评论的子评论数量 + * + * @param rootCommentIds 根评论ID集合 + * @return Map<根评论ID, 子评论数量> + */ + Map mapChildCommentCount(Collection rootCommentIds); + } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/impl/DynamicCommentServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/impl/DynamicCommentServiceImpl.java index 6a221720..b522e17b 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/impl/DynamicCommentServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/dynamic/impl/DynamicCommentServiceImpl.java @@ -51,6 +51,23 @@ public class DynamicCommentServiceImpl extends .page(pageQuery); } + @Override + public PageResult pageRootCommentsByTimeDesc(PageQuery pageQuery, Long contentId) { + return query() + .eq(DynamicComment::getDynamicContentId, contentId) + .isNull(DynamicComment::getRootCommentId) + .orderByDesc(DynamicComment::getCreateTime) + .page(pageQuery); + } + + @Override + public PageResult pageChildCommentsByTimeDesc(PageQuery pageQuery, Long rootCommentId) { + return query() + .eq(DynamicComment::getRootCommentId, rootCommentId) + .orderByDesc(DynamicComment::getCreateTime) + .page(pageQuery); + } + @Override public Integer getNumberByRootIdByNotUserId(Long rootCommentId, Long notUserId) { @@ -150,4 +167,32 @@ public class DynamicCommentServiceImpl extends return result; } + + @Override + public Map mapChildCommentCount(Collection rootCommentIds) { + if (CollectionUtils.isEmpty(rootCommentIds)) { + return Maps.newHashMap(); + } + + // 查询所有子评论 + List childComments = query() + .select(DynamicComment::getRootCommentId) + .in(DynamicComment::getRootCommentId, rootCommentIds) + .list(); + + Map result = Maps.newHashMap(); + + // 初始化所有根评论ID,默认0 + for (Long rootCommentId : rootCommentIds) { + result.put(rootCommentId, 0); + } + + // 统计每个根评论的子评论数量 + for (DynamicComment comment : childComments) { + Long rootCommentId = comment.getRootCommentId(); + result.put(rootCommentId, result.getOrDefault(rootCommentId, 0) + 1); + } + + return result; + } }