Browse Source

commit 点赞评论

Hai Lin 2 tuần trước cách đây
mục cha
commit
8951246839

+ 26 - 0
.idea/MyBatisCodeHelperDatasource.xml

@@ -95,6 +95,32 @@
                 </TableGenerateConfig>
               </value>
             </entry>
+            <entry key="csqz-client:family_moments_comment">
+              <value>
+                <TableGenerateConfig>
+                  <option name="generatedKey" value="id" />
+                  <option name="javaModelName" value="FamilyMomentsComment" />
+                  <option name="moduleName" value="mirage-service" />
+                  <option name="mybatisplusIdType" value="AUTO" />
+                  <option name="sequenceColumn" value="" />
+                  <option name="sequenceId" value="" />
+                  <option name="useActualColumnName" value="false" />
+                </TableGenerateConfig>
+              </value>
+            </entry>
+            <entry key="csqz-client:family_moments_like">
+              <value>
+                <TableGenerateConfig>
+                  <option name="generatedKey" value="id" />
+                  <option name="javaModelName" value="FamilyMomentsLike" />
+                  <option name="moduleName" value="mirage-service" />
+                  <option name="mybatisplusIdType" value="AUTO" />
+                  <option name="sequenceColumn" value="" />
+                  <option name="sequenceId" value="" />
+                  <option name="useActualColumnName" value="false" />
+                </TableGenerateConfig>
+              </value>
+            </entry>
             <entry key="csqz-client:family_relation_info">
               <value>
                 <TableGenerateConfig>

+ 73 - 7
mirage-service/src/main/java/com/mirage/mirageservice/controller/FamilyController.java

@@ -9,10 +9,7 @@ import com.mirage.mirageservice.domain.*;
 import com.mirage.mirageservice.enums.FamilyConfigEnum;
 import com.mirage.mirageservice.enums.FamilyRelationEnum;
 import com.mirage.mirageservice.enums.MomentsVisibleTypeEnum;
-import com.mirage.mirageservice.meta.AppContext;
-import com.mirage.mirageservice.meta.FamilyMomentsAndPublishInfo;
-import com.mirage.mirageservice.meta.MemberInfoRequest;
-import com.mirage.mirageservice.meta.MomentsRequest;
+import com.mirage.mirageservice.meta.*;
 import com.mirage.mirageservice.service.FamilyService;
 import com.mirage.mirageservice.service.WechatService;
 import lombok.extern.slf4j.Slf4j;
@@ -297,9 +294,78 @@ public class FamilyController {
         return familyService.newsRedDot(AppContext.getUid());
     }
 
-    // TODO 家族圈评论
-    // TODO 家族圈点赞
-    // TODO 自己发的家族圈
+    /**
+     * 家族圈点赞或取消.
+     *
+     * @param momentsRequest: momentId(家族圈id)
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/moment/likeOrNot", method = RequestMethod.POST)
+    public Object likeOrNot(@RequestBody MomentsLikeAndCommentRequest momentsRequest){
+        if(null == momentsRequest
+                || null == momentsRequest.getMomentId()
+                || null == momentsRequest.getLikeOrNot()){
+            throw new AppRuntimeException(AppCode.BAD_REQUEST);
+        }
+        FamilyMoments familyMoments = familyService.getMomentsById(momentsRequest.getMomentId());
+        if(null == familyMoments || familyMoments.getIsDeleted() == 1){
+            throw new AppRuntimeException("家族圈信息不存在或已删除!");
+        }
+        return familyService.likeMoment(AppContext.getUid(), momentsRequest.getLikeOrNot(), familyMoments);
+    }
+
+    /**
+     * 家族圈评论.
+     *
+     * @param momentsRequest
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/moment/comment", method = RequestMethod.POST)
+    public Object comment(@RequestBody MomentsLikeAndCommentRequest momentsRequest){
+        if(null == momentsRequest
+                || null == momentsRequest.getMomentId()
+                || StringUtils.isBlank(momentsRequest.getContent())){
+            throw new AppRuntimeException(AppCode.BAD_REQUEST);
+        }
+        FamilyMoments familyMoments = familyService.getMomentsById(momentsRequest.getMomentId());
+        if(null == familyMoments || familyMoments.getIsDeleted() == 1){
+            throw new AppRuntimeException("家族圈信息不存在或已删除!");
+        }
+        if(null != momentsRequest.getParentCommentId()){
+            FamilyMomentsComment momentsComment = familyService.getMomentsCommentById(momentsRequest.getParentCommentId());
+            if(null == momentsComment || momentsComment.getIsDeleted() == 1){
+                throw new AppRuntimeException("家族圈评论不存在或已删除!");
+            }
+        }
+        return familyService.commentMoment(AppContext.getUid(), familyMoments, momentsRequest);
+    }
+
+    /**
+     * 删除自己的评论.
+     *
+     * @param momentsRequest
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/moment/comment", method = RequestMethod.POST)
+    public Object deleteComment(@RequestBody MomentsLikeAndCommentRequest momentsRequest){
+        if(null == momentsRequest
+                || null == momentsRequest.getCommentId()){
+            throw new AppRuntimeException(AppCode.BAD_REQUEST);
+        }
+        FamilyMomentsComment momentsComment = familyService.getMomentsCommentById(momentsRequest.getCommentId());
+        if(null == momentsComment || momentsComment.getIsDeleted() == 1){
+            throw new AppRuntimeException("家族圈评论不存在或已删除!");
+        }
+        if(!AppContext.getUid().equals(momentsComment.getUid())){
+            throw new AppRuntimeException("无法删除别人的评论!");
+        }
+        return familyService.deleteComment(momentsRequest.getCommentId());
+    }
+    
+    // TODO 自己发的家族圈列表.
 
 
     private boolean checkVisibleLegitimacy(FamilyMemberInfo memberInfo, MomentsRequest momentsRequest){

+ 104 - 0
mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyMomentsComment.java

@@ -0,0 +1,104 @@
+package com.mirage.mirageservice.domain;
+
+import java.util.Date;
+
+/** 
+* Created by hzlinhai on 2025/10/24. 
+*/
+
+/**
+ * 家族圈评论表
+ */
+public class FamilyMomentsComment {
+    private Long id;
+
+    /**
+     * 家族圈信息id
+     */
+    private Long momentId;
+
+    /**
+     * 评论人uid
+     */
+    private Long uid;
+
+    /**
+     * 评论回复id
+     */
+    private Long parentCommentId;
+
+    /**
+     * 评论内容
+     */
+    private String content;
+
+    private Date gmtCreate;
+
+    private Date gmtModified;
+
+    private Integer isDeleted;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getMomentId() {
+        return momentId;
+    }
+
+    public void setMomentId(Long momentId) {
+        this.momentId = momentId;
+    }
+
+    public Long getUid() {
+        return uid;
+    }
+
+    public void setUid(Long uid) {
+        this.uid = uid;
+    }
+
+    public Long getParentCommentId() {
+        return parentCommentId;
+    }
+
+    public void setParentCommentId(Long parentCommentId) {
+        this.parentCommentId = parentCommentId;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Date getGmtCreate() {
+        return gmtCreate;
+    }
+
+    public void setGmtCreate(Date gmtCreate) {
+        this.gmtCreate = gmtCreate;
+    }
+
+    public Date getGmtModified() {
+        return gmtModified;
+    }
+
+    public void setGmtModified(Date gmtModified) {
+        this.gmtModified = gmtModified;
+    }
+
+    public Integer getIsDeleted() {
+        return isDeleted;
+    }
+
+    public void setIsDeleted(Integer isDeleted) {
+        this.isDeleted = isDeleted;
+    }
+}

+ 77 - 0
mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyMomentsLike.java

@@ -0,0 +1,77 @@
+package com.mirage.mirageservice.domain;
+
+import java.util.Date;
+
+/** 
+* Created by hzlinhai on 2025/10/24. 
+*/
+/**
+ * 家族圈点赞记录表
+ */
+public class FamilyMomentsLike {
+    private Long id;
+
+    /**
+    * 家族圈信息id
+    */
+    private Long momentId;
+
+    /**
+    * 点赞人id
+    */
+    private Long uid;
+
+    private Integer isDeleted;
+
+    private Date gmtCreate;
+
+    private Date gmtModified;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getMomentId() {
+        return momentId;
+    }
+
+    public void setMomentId(Long momentId) {
+        this.momentId = momentId;
+    }
+
+    public Long getUid() {
+        return uid;
+    }
+
+    public void setUid(Long uid) {
+        this.uid = uid;
+    }
+
+    public Integer getIsDeleted() {
+        return isDeleted;
+    }
+
+    public void setIsDeleted(Integer isDeleted) {
+        this.isDeleted = isDeleted;
+    }
+
+    public Date getGmtCreate() {
+        return gmtCreate;
+    }
+
+    public void setGmtCreate(Date gmtCreate) {
+        this.gmtCreate = gmtCreate;
+    }
+
+    public Date getGmtModified() {
+        return gmtModified;
+    }
+
+    public void setGmtModified(Date gmtModified) {
+        this.gmtModified = gmtModified;
+    }
+}

+ 26 - 0
mirage-service/src/main/java/com/mirage/mirageservice/mapper/mysql/FamilyMomentsCommentMapper.java

@@ -0,0 +1,26 @@
+package com.mirage.mirageservice.mapper.mysql;
+
+import com.mirage.mirageservice.domain.FamilyMomentsComment;
+import com.mirage.mirageservice.meta.MomentsCommentsResponse;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by hzlinhai on 2025/10/24.
+ */
+public interface FamilyMomentsCommentMapper {
+    int deleteByPrimaryKey(Long id);
+
+    int insert(FamilyMomentsComment record);
+
+    int insertSelective(FamilyMomentsComment record);
+
+    FamilyMomentsComment selectByPrimaryKey(Long id);
+
+    int updateByPrimaryKeySelective(FamilyMomentsComment record);
+
+    int updateByPrimaryKey(FamilyMomentsComment record);
+
+    List<MomentsCommentsResponse> selectCommentsByMomentId(@Param("momentId")Long momentId);
+}

+ 27 - 0
mirage-service/src/main/java/com/mirage/mirageservice/mapper/mysql/FamilyMomentsLikeMapper.java

@@ -0,0 +1,27 @@
+package com.mirage.mirageservice.mapper.mysql;
+import com.mirage.mirageservice.meta.MomentsLikeInfo;
+import org.apache.ibatis.annotations.Param;
+
+import com.mirage.mirageservice.domain.FamilyMomentsLike;
+
+import java.util.List;
+
+/** 
+* Created by hzlinhai on 2025/10/24. 
+*/
+public interface FamilyMomentsLikeMapper {
+    int deleteByPrimaryKey(Long id);
+
+    int insert(FamilyMomentsLike record);
+
+    int insertSelective(FamilyMomentsLike record);
+
+    FamilyMomentsLike selectByPrimaryKey(Long id);
+
+    int updateByPrimaryKeySelective(FamilyMomentsLike record);
+
+    int updateByPrimaryKey(FamilyMomentsLike record);
+    FamilyMomentsLike selectOneByMomentIdAndUidAndIsDeleted(@Param("momentId")Long momentId,@Param("uid")Long uid,@Param("isDeleted")Integer isDeleted);
+
+    List<MomentsLikeInfo> selectMomentLikeListAndMemberInfo(@Param("momentId")Long momentId);
+}

+ 22 - 2
mirage-service/src/main/java/com/mirage/mirageservice/meta/FamilyMomentsAndPublishInfo.java

@@ -4,17 +4,37 @@ import com.mirage.mirageservice.domain.FamilyMemberInfo;
 import com.mirage.mirageservice.domain.FamilyMoments;
 import lombok.Data;
 
+import java.util.List;
+
 /**
  * Created by hzlinhai on 2025/10/23.
  */
 @Data
 public class FamilyMomentsAndPublishInfo {
 
+    /**
+     * 家族圈信息
+     */
     private FamilyMoments familyMoments;
-
+    /**
+     * 发布者信息
+     */
     private FamilyMemberInfo publishMemberInfo;
+    /**
+     * 点赞信息
+     */
+    private List<MomentsLikeInfo> likeMomentList;
+    /**
+     * 评论信息(有多级结构)
+     */
+    private List<MomentsCommentsResponse> commentsResponseList;
 
     public FamilyMomentsAndPublishInfo(){}
 
-    public FamilyMomentsAndPublishInfo(FamilyMoments familyMoments, FamilyMemberInfo publishMemberInfo){}
+    public FamilyMomentsAndPublishInfo(FamilyMoments familyMoments, FamilyMemberInfo publishMemberInfo, List<MomentsLikeInfo> likeMomentList, List<MomentsCommentsResponse> commentsResponseList){
+        this.familyMoments = familyMoments;
+        this.publishMemberInfo = publishMemberInfo;
+        this.likeMomentList = likeMomentList;
+        this.commentsResponseList = commentsResponseList;
+    }
 }

+ 35 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/MomentsCommentsResponse.java

@@ -0,0 +1,35 @@
+package com.mirage.mirageservice.meta;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * Created by hzlinhai on 2025/10/24.
+ */
+@Data
+public class MomentsCommentsResponse {
+
+    private Long id;
+
+    private Long momentId;
+
+    private Long uid;
+
+    private Long parentCommentId;
+
+    private String content;
+
+    private Date gmtCreate;
+
+    private String name;
+
+    private Long mid;
+
+    private String headImgUrl;
+
+    private Integer level;
+
+    private Integer path;
+
+}

+ 29 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/MomentsLikeAndCommentRequest.java

@@ -0,0 +1,29 @@
+package com.mirage.mirageservice.meta;
+
+import lombok.Data;
+
+/**
+ * Created by hzlinhai on 2025/10/24.
+ */
+@Data
+public class MomentsLikeAndCommentRequest {
+
+    private Long commentId;
+    /**
+     * 家族圈id
+     */
+    private Long momentId;
+    /**
+     * 0:取消点赞 1:点赞
+     */
+    private Integer likeOrNot;
+
+    /**
+     * 评论内容
+     */
+    private String content;
+    /**
+     * 回复某一条评论的id
+     */
+    private Long parentCommentId;
+}

+ 20 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/MomentsLikeInfo.java

@@ -0,0 +1,20 @@
+package com.mirage.mirageservice.meta;
+
+import lombok.Data;
+
+/**
+ * Created by hzlinhai on 2025/10/24.
+ */
+@Data
+public class MomentsLikeInfo {
+
+    private Long momentsId;
+
+    private Long uid;
+
+    private Long mid;
+
+    private String name;
+
+    private String headImgUrl;
+}

+ 106 - 10
mirage-service/src/main/java/com/mirage/mirageservice/service/FamilyService.java

@@ -2,16 +2,14 @@ package com.mirage.mirageservice.service;
 
 import com.github.pagehelper.PageHelper;
 import com.google.common.collect.Lists;
+import com.mirage.core.annotation.RedisLock;
 import com.mirage.core.meta.PageResultVo;
 import com.mirage.core.meta.PageUtil;
 import com.mirage.core.utils.GsonUtil;
 import com.mirage.mirageservice.domain.*;
 import com.mirage.mirageservice.enums.FamilyRelationEnum;
 import com.mirage.mirageservice.enums.MomentsVisibleTypeEnum;
-import com.mirage.mirageservice.mapper.mysql.FamilyMemberInfoMapper;
-import com.mirage.mirageservice.mapper.mysql.FamilyMemberPhotoAlbumMapper;
-import com.mirage.mirageservice.mapper.mysql.FamilyMomentsMapper;
-import com.mirage.mirageservice.mapper.mysql.FamilyRelationInfoMapper;
+import com.mirage.mirageservice.mapper.mysql.*;
 import com.mirage.mirageservice.meta.*;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -44,6 +42,10 @@ public class FamilyService {
     private FamilyMemberPhotoAlbumMapper familyMemberPhotoAlbumMapper;
     @Resource
     private FamilyMomentsMapper familyMomentsMapper;
+    @Resource
+    private FamilyMomentsLikeMapper familyMomentsLikeMapper;
+    @Resource
+    private FamilyMomentsCommentMapper familyMomentsCommentMapper;
 
     public SelfFamilyCardResponse getSelfFamilyMember(Long uid){
         SelfFamilyCardResponse familyCardResponse = new SelfFamilyCardResponse();
@@ -409,7 +411,9 @@ public class FamilyService {
         }
         for(FamilyMoments moments : familyMoments){
             FamilyMemberInfo memberInfo = familyMemberInfoMapper.selectByUid(moments.getPublishUid());
-            result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo));
+            List<MomentsLikeInfo> likeInfoList = familyMomentsLikeMapper.selectMomentLikeListAndMemberInfo(moments.getId());
+            List<MomentsCommentsResponse> commentsResponses = familyMomentsCommentMapper.selectCommentsByMomentId(moments.getId());
+            result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo, likeInfoList, commentsResponses));
         }
         return result;
     }
@@ -427,7 +431,9 @@ public class FamilyService {
         // 处理可见性
         for(FamilyMoments moments : familyMoments){
             if(Objects.equals(moments.getVisibleType(), MomentsVisibleTypeEnum.ALL_MEMBER.getType())){
-                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo));
+                List<MomentsLikeInfo> likeInfoList = familyMomentsLikeMapper.selectMomentLikeListAndMemberInfo(moments.getId());
+                List<MomentsCommentsResponse> commentsResponses = familyMomentsCommentMapper.selectCommentsByMomentId(moments.getId());
+                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo, likeInfoList, commentsResponses));
                 continue;
             }
             // 可见范围:0:全员 1:支系堂派 2:聚落 3:家族内男性 4:出生地
@@ -436,22 +442,30 @@ public class FamilyService {
                     && (memberInfo.getBranchFamilyHall().equals(moments.getVisibleValue())
                     || memberInfo.getBranchFamilyHall().contains(moments.getVisibleValue())
                     || moments.getVisibleValue().contains(memberInfo.getBranchFamilyHall()))){
-                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo));
+                List<MomentsLikeInfo> likeInfoList = familyMomentsLikeMapper.selectMomentLikeListAndMemberInfo(moments.getId());
+                List<MomentsCommentsResponse> commentsResponses = familyMomentsCommentMapper.selectCommentsByMomentId(moments.getId());
+                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo, likeInfoList, commentsResponses));
             } else if(Objects.equals(moments.getVisibleType(), MomentsVisibleTypeEnum.SPECIAL_CLUSTER_PLACE.getType())
                     && StringUtils.isNotBlank(memberInfo.getClusterPlace())
                     && (memberInfo.getClusterPlace().equals(moments.getVisibleValue())
                     || memberInfo.getClusterPlace().contains(moments.getVisibleValue())
                     || moments.getVisibleValue().equals(memberInfo.getClusterPlace()))){
-                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo));
+                List<MomentsLikeInfo> likeInfoList = familyMomentsLikeMapper.selectMomentLikeListAndMemberInfo(moments.getId());
+                List<MomentsCommentsResponse> commentsResponses = familyMomentsCommentMapper.selectCommentsByMomentId(moments.getId());
+                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo, likeInfoList, commentsResponses));
             } else if (Objects.equals(moments.getVisibleType(), MomentsVisibleTypeEnum.SPECIAL_SEX.getType())
                     && Integer.parseInt(moments.getVisibleValue()) == memberInfo.getSex()) {
-                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo));
+                List<MomentsLikeInfo> likeInfoList = familyMomentsLikeMapper.selectMomentLikeListAndMemberInfo(moments.getId());
+                List<MomentsCommentsResponse> commentsResponses = familyMomentsCommentMapper.selectCommentsByMomentId(moments.getId());
+                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo, likeInfoList, commentsResponses));
             } else if (Objects.equals(moments.getVisibleType(), MomentsVisibleTypeEnum.SPECIAL_BIRTH_PLACE.getType())
                     && StringUtils.isNotBlank(memberInfo.getBirthPlace())
                     && (memberInfo.getBirthPlace().contains(moments.getVisibleValue())
                     || moments.getVisibleValue().contains(memberInfo.getBirthPlace())
                     || memberInfo.getBirthPlace().equalsIgnoreCase(moments.getVisibleValue()))) {
-                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo));
+                List<MomentsLikeInfo> likeInfoList = familyMomentsLikeMapper.selectMomentLikeListAndMemberInfo(moments.getId());
+                List<MomentsCommentsResponse> commentsResponses = familyMomentsCommentMapper.selectCommentsByMomentId(moments.getId());
+                result.add(new FamilyMomentsAndPublishInfo(moments, memberInfo, likeInfoList, commentsResponses));
             }
         }
          // 最后一个id记录,用于红点提示
@@ -511,7 +525,89 @@ public class FamilyService {
         return false;
     }
 
+    public FamilyMoments getMomentsById(Long id){
+        if(null == id){
+            return null;
+        }
+        return familyMomentsMapper.selectByPrimaryKey(id);
+    }
+
+    @RedisLock(lockField = "#uid+'_'+#familyMoments.id", retries = -1)
+    public boolean likeMoment(Long uid, Integer likeOrNot, FamilyMoments familyMoments){
+        if(null == uid || null == familyMoments){
+            return false;
+        }
+        FamilyMomentsLike familyMomentsLike = familyMomentsLikeMapper.selectOneByMomentIdAndUidAndIsDeleted(familyMoments.getId(), uid, 0);
+        if(likeOrNot == 0){ //取消点赞
+            if(null == familyMomentsLike){
+                return true;
+            }
+            familyMomentsLike.setIsDeleted(1);
+            familyMomentsLike.setGmtModified(new Date());
+            familyMomentsLikeMapper.updateByPrimaryKeySelective(familyMomentsLike);
+            return true;
+        } else if (likeOrNot == 1) { // 点赞
+            if(null != familyMomentsLike){
+                return true;
+            }
+            familyMomentsLike = new FamilyMomentsLike();
+            familyMomentsLike.setMomentId(familyMomentsLike.getMomentId());
+            familyMomentsLike.setUid(uid);
+            familyMomentsLike.setIsDeleted(0);
+            familyMomentsLike.setGmtModified(new Date());
+            familyMomentsLike.setGmtCreate(new Date());
+            familyMomentsLikeMapper.insertSelective(familyMomentsLike);
+            return true;
+        }
+        return false;
+    }
+
+    public FamilyMomentsComment getMomentsCommentById(Long id){
+        if(null == id){
+            return null;
+        }
+        return familyMomentsCommentMapper.selectByPrimaryKey(id);
+    }
 
+    public boolean commentMoment(Long uid, FamilyMoments familyMoments, MomentsLikeAndCommentRequest request){
+        if(null == uid
+                || null == familyMoments
+                || null == request
+                || null == request.getMomentId()
+                || StringUtils.isBlank(request.getContent())){
+            return false;
+        }
+        if(null != request.getParentCommentId()){
+            FamilyMomentsComment momentsComment = familyMomentsCommentMapper.selectByPrimaryKey(request.getParentCommentId());
+            if(null == momentsComment || momentsComment.getIsDeleted() == 1){
+                return false;
+            }
+        }
+        FamilyMomentsComment familyMomentsComment = new FamilyMomentsComment();
+        familyMomentsComment.setMomentId(familyMoments.getId());
+        familyMomentsComment.setContent(request.getContent());
+        familyMomentsComment.setUid(uid);
+        familyMomentsComment.setParentCommentId(request.getParentCommentId());
+        familyMomentsComment.setIsDeleted(0);
+        familyMomentsComment.setGmtCreate(new Date());
+        familyMomentsComment.setGmtModified(new Date());
+        familyMomentsCommentMapper.insertSelective(familyMomentsComment);
+        return true;
+    }
+
+    public boolean deleteComment(Long commentId){
+        if(null == commentId){
+            return false;
+        }
+        FamilyMomentsComment familyMomentsComment = familyMomentsCommentMapper.selectByPrimaryKey(commentId);
+        if(null == familyMomentsComment || familyMomentsComment.getIsDeleted() == 1){
+            return true;
+        }
+        familyMomentsComment.setIsDeleted(1);
+        familyMomentsComment.setGmtModified(new Date());
+        familyMomentsCommentMapper.updateByPrimaryKeySelective(familyMomentsComment);
+        return true;
+    }
 }
 
 

+ 175 - 0
mirage-service/src/main/resources/com/mirage/mirageservice/mapper/mysql/FamilyMomentsCommentMapper.xml

@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.mirage.mirageservice.mapper.mysql.FamilyMomentsCommentMapper">
+  <resultMap id="BaseResultMap" type="com.mirage.mirageservice.domain.FamilyMomentsComment">
+    <!--@mbg.generated-->
+    <!--@Table family_moments_comment-->
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="moment_id" jdbcType="BIGINT" property="momentId" />
+    <result column="uid" jdbcType="BIGINT" property="uid" />
+    <result column="parent_comment_id" jdbcType="BIGINT" property="parentCommentId" />
+    <result column="content" jdbcType="VARCHAR" property="content" />
+    <result column="gmt_create" jdbcType="TIMESTAMP" property="gmtCreate" />
+    <result column="gmt_modified" jdbcType="TIMESTAMP" property="gmtModified" />
+    <result column="is_deleted" jdbcType="INTEGER" property="isDeleted" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--@mbg.generated-->
+    id, moment_id, `uid`, parent_comment_id, content, gmt_create, gmt_modified, is_deleted
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    <!--@mbg.generated-->
+    select 
+    <include refid="Base_Column_List" />
+    from family_moments_comment
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    <!--@mbg.generated-->
+    delete from family_moments_comment
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyMomentsComment" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_moments_comment (moment_id, `uid`, parent_comment_id, 
+      content, gmt_create, gmt_modified, 
+      is_deleted)
+    values (#{momentId,jdbcType=BIGINT}, #{uid,jdbcType=BIGINT}, #{parentCommentId,jdbcType=BIGINT}, 
+      #{content,jdbcType=VARCHAR}, #{gmtCreate,jdbcType=TIMESTAMP}, #{gmtModified,jdbcType=TIMESTAMP}, 
+      #{isDeleted,jdbcType=INTEGER})
+  </insert>
+  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyMomentsComment" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_moments_comment
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="momentId != null">
+        moment_id,
+      </if>
+      <if test="uid != null">
+        `uid`,
+      </if>
+      <if test="parentCommentId != null">
+        parent_comment_id,
+      </if>
+      <if test="content != null">
+        content,
+      </if>
+      <if test="gmtCreate != null">
+        gmt_create,
+      </if>
+      <if test="gmtModified != null">
+        gmt_modified,
+      </if>
+      <if test="isDeleted != null">
+        is_deleted,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="momentId != null">
+        #{momentId,jdbcType=BIGINT},
+      </if>
+      <if test="uid != null">
+        #{uid,jdbcType=BIGINT},
+      </if>
+      <if test="parentCommentId != null">
+        #{parentCommentId,jdbcType=BIGINT},
+      </if>
+      <if test="content != null">
+        #{content,jdbcType=VARCHAR},
+      </if>
+      <if test="gmtCreate != null">
+        #{gmtCreate,jdbcType=TIMESTAMP},
+      </if>
+      <if test="gmtModified != null">
+        #{gmtModified,jdbcType=TIMESTAMP},
+      </if>
+      <if test="isDeleted != null">
+        #{isDeleted,jdbcType=INTEGER},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.mirage.mirageservice.domain.FamilyMomentsComment">
+    <!--@mbg.generated-->
+    update family_moments_comment
+    <set>
+      <if test="momentId != null">
+        moment_id = #{momentId,jdbcType=BIGINT},
+      </if>
+      <if test="uid != null">
+        `uid` = #{uid,jdbcType=BIGINT},
+      </if>
+      <if test="parentCommentId != null">
+        parent_comment_id = #{parentCommentId,jdbcType=BIGINT},
+      </if>
+      <if test="content != null">
+        content = #{content,jdbcType=VARCHAR},
+      </if>
+      <if test="gmtCreate != null">
+        gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
+      </if>
+      <if test="gmtModified != null">
+        gmt_modified = #{gmtModified,jdbcType=TIMESTAMP},
+      </if>
+      <if test="isDeleted != null">
+        is_deleted = #{isDeleted,jdbcType=INTEGER},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.mirage.mirageservice.domain.FamilyMomentsComment">
+    <!--@mbg.generated-->
+    update family_moments_comment
+    set moment_id = #{momentId,jdbcType=BIGINT},
+      `uid` = #{uid,jdbcType=BIGINT},
+      parent_comment_id = #{parentCommentId,jdbcType=BIGINT},
+      content = #{content,jdbcType=VARCHAR},
+      gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
+      gmt_modified = #{gmtModified,jdbcType=TIMESTAMP},
+      is_deleted = #{isDeleted,jdbcType=INTEGER}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+
+  <select id="selectCommentsByMomentId" resultType="com.mirage.mirageservice.meta.MomentsCommentsResponse">
+    WITH RECURSIVE comment_tree AS (
+      SELECT
+        com.id,
+        com.moment_id,
+        com.uid,
+        com.parent_comment_id,
+        com.content,
+        com.gmt_create,
+        minfo.name,
+        minfo.id as 'mid',
+              minfo.head_img_url,
+        1 AS level,
+        CAST(com.id AS CHAR(255)) AS path
+      FROM family_moments_comment com, family_member_info minfo
+      WHERE
+        com.moment_id = #{momentId,jdbcType=BIGINT}
+        AND com.parent_comment_id IS NULL
+        AND minfo.uid = com.uid
+        AND com.is_deleted = 0
+      UNION ALL
+      -- 递归查询:获取子评论(回复)
+      SELECT
+        c.id,
+        c.moment_id,
+        c.uid,
+        c.parent_comment_id,
+        c.content,
+        c.gmt_create,
+        mi.name,
+        mi.id as 'mid',
+              mi.head_img_url,
+        ct.level + 1 AS level,
+        CONCAT(ct.path, ',', c.id) AS path
+      FROM family_moments_comment c
+             INNER JOIN comment_tree ct ON c.parent_comment_id = ct.id
+             INNER JOIN family_member_info mi ON c.uid = mi.uid
+      WHERE
+        c.is_deleted = 0
+    )
+    SELECT * FROM comment_tree
+    ORDER BY path;
+  </select>
+</mapper>

+ 127 - 0
mirage-service/src/main/resources/com/mirage/mirageservice/mapper/mysql/FamilyMomentsLikeMapper.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.mirage.mirageservice.mapper.mysql.FamilyMomentsLikeMapper">
+  <resultMap id="BaseResultMap" type="com.mirage.mirageservice.domain.FamilyMomentsLike">
+    <!--@mbg.generated-->
+    <!--@Table family_moments_like-->
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="moment_id" jdbcType="BIGINT" property="momentId" />
+    <result column="uid" jdbcType="BIGINT" property="uid" />
+    <result column="is_deleted" jdbcType="INTEGER" property="isDeleted" />
+    <result column="gmt_create" jdbcType="TIMESTAMP" property="gmtCreate" />
+    <result column="gmt_modified" jdbcType="TIMESTAMP" property="gmtModified" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--@mbg.generated-->
+    id, moment_id, `uid`, is_deleted, gmt_create, gmt_modified
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    <!--@mbg.generated-->
+    select 
+    <include refid="Base_Column_List" />
+    from family_moments_like
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    <!--@mbg.generated-->
+    delete from family_moments_like
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyMomentsLike" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_moments_like (moment_id, `uid`, is_deleted, 
+      gmt_create, gmt_modified)
+    values (#{momentId,jdbcType=BIGINT}, #{uid,jdbcType=BIGINT}, #{isDeleted,jdbcType=INTEGER}, 
+      #{gmtCreate,jdbcType=TIMESTAMP}, #{gmtModified,jdbcType=TIMESTAMP})
+  </insert>
+  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyMomentsLike" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_moments_like
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="momentId != null">
+        moment_id,
+      </if>
+      <if test="uid != null">
+        `uid`,
+      </if>
+      <if test="isDeleted != null">
+        is_deleted,
+      </if>
+      <if test="gmtCreate != null">
+        gmt_create,
+      </if>
+      <if test="gmtModified != null">
+        gmt_modified,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="momentId != null">
+        #{momentId,jdbcType=BIGINT},
+      </if>
+      <if test="uid != null">
+        #{uid,jdbcType=BIGINT},
+      </if>
+      <if test="isDeleted != null">
+        #{isDeleted,jdbcType=INTEGER},
+      </if>
+      <if test="gmtCreate != null">
+        #{gmtCreate,jdbcType=TIMESTAMP},
+      </if>
+      <if test="gmtModified != null">
+        #{gmtModified,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.mirage.mirageservice.domain.FamilyMomentsLike">
+    <!--@mbg.generated-->
+    update family_moments_like
+    <set>
+      <if test="momentId != null">
+        moment_id = #{momentId,jdbcType=BIGINT},
+      </if>
+      <if test="uid != null">
+        `uid` = #{uid,jdbcType=BIGINT},
+      </if>
+      <if test="isDeleted != null">
+        is_deleted = #{isDeleted,jdbcType=INTEGER},
+      </if>
+      <if test="gmtCreate != null">
+        gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
+      </if>
+      <if test="gmtModified != null">
+        gmt_modified = #{gmtModified,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.mirage.mirageservice.domain.FamilyMomentsLike">
+    <!--@mbg.generated-->
+    update family_moments_like
+    set moment_id = #{momentId,jdbcType=BIGINT},
+      `uid` = #{uid,jdbcType=BIGINT},
+      is_deleted = #{isDeleted,jdbcType=INTEGER},
+      gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
+      gmt_modified = #{gmtModified,jdbcType=TIMESTAMP}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+
+<!--auto generated by MybatisCodeHelper on 2025-10-24-->
+  <select id="selectOneByMomentIdAndUidAndIsDeleted" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from family_moments_like
+        where moment_id=#{momentId,jdbcType=BIGINT} and `uid`=#{uid,jdbcType=BIGINT} and
+        is_deleted=#{isDeleted,jdbcType=INTEGER}
+    </select>
+
+  <select id="selectMomentLikeListAndMemberInfo" resultType="com.mirage.mirageservice.meta.MomentsLikeInfo">
+    select
+      li.moment_id,
+      li.uid,
+      info.id,
+      info.name,
+      info.head_img_url
+    from family_moments_like li, family_member_info info
+    WHERE li.moment_id = #{momentId,jdbcType=BIGINT} and li.uid = info.uid and li.is_deleted = 0 ORDER BY li.gmt_create desc
+  </select>
+</mapper>

+ 26 - 0
sql.sql

@@ -96,3 +96,29 @@ CREATE TABLE `family_moments` (
   PRIMARY KEY (`id`),
   KEY `idx_publish_time` (`publish_time` DESC)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='家族圈';
+
+CREATE TABLE `family_moments_comment` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `moment_id` bigint NOT NULL COMMENT '家族圈信息id',
+  `uid` bigint NOT NULL COMMENT '评论人uid',
+  `parent_comment_id` bigint DEFAULT NULL COMMENT '评论回复id',
+  `content` varchar(512) NOT NULL COMMENT '评论内容',
+  `gmt_create` timestamp NOT NULL,
+  `gmt_modified` timestamp NOT NULL,
+  `is_deleted` int NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  KEY `idx_moment_id` (`moment_id`),
+  KEY `idx_uid` (`uid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='家族圈评论表';
+
+CREATE TABLE `family_moments_like` (
+   `id` bigint NOT NULL AUTO_INCREMENT,
+   `moment_id` bigint NOT NULL COMMENT '家族圈信息id',
+   `uid` bigint NOT NULL COMMENT '点赞人id',
+   `is_deleted` int NOT NULL DEFAULT '0',
+   `gmt_create` timestamp NOT NULL,
+   `gmt_modified` timestamp NOT NULL,
+   PRIMARY KEY (`id`),
+   KEY `idx_moment_id` (`moment_id`),
+   KEY `idx_uid` (`uid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='家族圈点赞记录表';