Переглянути джерело

bugfix:评论评价重构完成

lyx 3 місяців тому
батько
коміт
9afbbaf319
19 змінених файлів з 1373 додано та 4 видалено
  1. 97 0
      alien-entity/src/main/java/shop/alien/entity/store/CommonComment.java
  2. 110 0
      alien-entity/src/main/java/shop/alien/entity/store/CommonRating.java
  3. 21 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/CommonCommentVo.java
  4. 37 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/CommonRatingVo.java
  5. 40 0
      alien-entity/src/main/java/shop/alien/mapper/CommonCommentMapper.java
  6. 61 0
      alien-entity/src/main/java/shop/alien/mapper/CommonRatingMapper.java
  7. 35 0
      alien-entity/src/main/resources/mapper/CommonCommentMapper.xml
  8. 36 0
      alien-entity/src/main/resources/mapper/CommonRatingMapper.xml
  9. 90 0
      alien-store/src/main/java/shop/alien/store/controller/CommonCommentController.java
  10. 140 0
      alien-store/src/main/java/shop/alien/store/controller/CommonRatingController.java
  11. 16 0
      alien-store/src/main/java/shop/alien/store/service/CommonCommentService.java
  12. 73 0
      alien-store/src/main/java/shop/alien/store/service/CommonRatingService.java
  13. 28 2
      alien-store/src/main/java/shop/alien/store/service/LifeCommentService.java
  14. 103 0
      alien-store/src/main/java/shop/alien/store/service/impl/CommonCommentServiceImpl.java
  15. 441 0
      alien-store/src/main/java/shop/alien/store/service/impl/CommonRatingServiceImpl.java
  16. 2 0
      alien-store/src/main/java/shop/alien/store/util/CommonConstant.java
  17. 1 2
      alien-store/src/main/java/shop/alien/store/util/ai/AiFeedbackAssignUtils.java
  18. 21 0
      alien-util/src/main/java/shop/alien/util/common/constant/CommentSourceTypeEnum.java
  19. 21 0
      alien-util/src/main/java/shop/alien/util/common/constant/RatingBusinessTypeEnum.java

+ 97 - 0
alien-entity/src/main/java/shop/alien/entity/store/CommonComment.java

@@ -0,0 +1,97 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 评论表(商户仅可回复)
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("common_comment")
+@ApiModel(value = "CommonComment对象", description = "评论表(商户仅可回复)")
+public class CommonComment implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "评论来源类型:1-评价的评论 2-社区动态 3-活动留言")
+    @TableField("source_type")
+    private Integer sourceType;
+
+    @ApiModelProperty(value = "来源关联ID:source_type=1时=rating.id,=2时=动态ID")
+    @TableField("source_id")
+    private Long sourceId;
+
+    @ApiModelProperty(value = "评论发布者ID:用户=用户ID,商户=商户运营账号ID")
+    @TableField("user_id")
+    private Long userId;
+
+    @ApiModelProperty(value = "父评论ID:0=根评论,>0=回复某条评论")
+    @TableField("parent_id")
+    private Long parentId;
+
+    @ApiModelProperty(value = "评论纯文本内容")
+    @TableField("content")
+    private String content;
+
+    @ApiModelProperty(value = "评论图片URL(可选)")
+    @TableField("image_urls")
+    private String imageUrls;
+
+    @ApiModelProperty(value = "是否匿名:0-否 1-是(仅用户评论生效)")
+    @TableField("is_anonymous")
+    private Integer isAnonymous;
+
+    @ApiModelProperty(value = "评论主体:1-用户评论 2-商户评论(仅回复)")
+    @TableField("comment_type")
+    private Integer commentType;
+
+    @ApiModelProperty(value = "商户ID:comment_type=2时必填")
+    @TableField("merchant_id")
+    private Long merchantId;
+
+    @ApiModelProperty(value = "是否展示:0-隐藏 1-展示")
+    @TableField("is_show")
+    private Integer isShow;
+
+    @ApiModelProperty(value = "审核状态:0-待审核 1-通过 2-驳回")
+    @TableField("audit_status")
+    private Integer auditStatus;
+
+    @ApiModelProperty(value = "点赞数")
+    @TableField("like_count")
+    private Integer likeCount;
+
+    @ApiModelProperty(value = "回复数")
+    @TableField("reply_count")
+    private Integer replyCount;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "更新时间")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "扩展字段:如评论楼层")
+    @TableField(value = "ext_info", typeHandler = com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class)
+    private String extInfo;
+}
+

+ 110 - 0
alien-entity/src/main/java/shop/alien/entity/store/CommonRating.java

@@ -0,0 +1,110 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 评价表(仅用户可发布)
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("common_rating")
+@ApiModel(value = "CommonRating对象", description = "评价表(仅用户可发布)")
+public class CommonRating implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "业务类型:1-商铺评价")
+    @TableField("business_type")
+    private Integer businessType;
+
+    @ApiModelProperty(value = "业务关联ID:1-商铺ID")
+    @TableField("business_id")
+    private Integer businessId;
+
+    @ApiModelProperty(value = "评价用户ID(仅普通用户)")
+    @TableField("user_id")
+    private Long userId;
+
+    @ApiModelProperty(value = "评价文字内容")
+    @TableField("content")
+    private String content;
+
+    @ApiModelProperty(value = "核心评分(0.0-5.0)")
+    @TableField("score")
+    private Double score;
+
+    @ApiModelProperty(value = "多维度评分:如{\"口味\":5.0,\"服务\":4.0}")
+    @TableField(value = "other_score")
+    private String otherScore;
+
+    @ApiModelProperty(value = "评价图片URL,多个逗号分隔")
+    @TableField("image_urls")
+    private String imageUrls;
+
+    @ApiModelProperty(value = "是否匿名:0-否 1-是")
+    @TableField("is_anonymous")
+    private Integer isAnonymous;
+
+    @ApiModelProperty(value = "是否展示:0-隐藏 1-展示")
+    @TableField("is_show")
+    private Integer isShow;
+
+    @ApiModelProperty(value = "审核状态:0-待审核 1-通过 2-驳回")
+    @TableField("audit_status")
+    private Integer auditStatus;
+
+    @ApiModelProperty(value = "点赞数")
+    @TableField("like_count")
+    private Integer likeCount;
+
+    @ApiModelProperty(value = "评分1")
+    @TableField("score_one")
+    private Double scoreOne;
+
+    @ApiModelProperty(value = "评分2")
+    @TableField("score_two")
+    private Double scoreTwo;
+
+    @ApiModelProperty(value = "评分3")
+    @TableField("score_three")
+    private Double scoreThree;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}
+

+ 21 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/CommonCommentVo.java

@@ -0,0 +1,21 @@
+package shop.alien.entity.store.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.CommonComment;
+
+import java.util.List;
+
+@Data
+@ApiModel(value = "CommonCommentVo对象")
+public class CommonCommentVo extends CommonComment {
+    @ApiModelProperty(value = "子评论列表")
+    private List<CommonCommentVo> childCommonComments;
+    @ApiModelProperty(value = "评论用户头像")
+    private String headImg;
+    @ApiModelProperty(value = "评论用户昵称")
+    private String headName;
+    @ApiModelProperty(value = "是否点赞")
+    private String isLike;
+}

+ 37 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/CommonRatingVo.java

@@ -0,0 +1,37 @@
+package shop.alien.entity.store.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.CommonRating;
+
+import java.util.List;
+
+@Data
+@ApiModel(value = "CommonRatingVo对象")
+public class CommonRatingVo extends CommonRating {
+    @ApiModelProperty(name = "userImage", value = "用户头像")
+    private String userImage;
+    @ApiModelProperty(name = "userName", value = "用户名")
+    private String userName;
+    @ApiModelProperty(name = "isLike", value = "是否点赞")
+    private Integer isLike;
+    @ApiModelProperty(name = "storeName", value = "门店名称")
+    private String storeName;
+    @ApiModelProperty(name = "storeEvaluate", value = "门店评价")
+    private String storeEvaluate;
+    @ApiModelProperty(name = "storeScore", value = "门店评分")
+    private Double storeScore;
+    @ApiModelProperty(name = "scoreOne", value = "评分1")
+    private Double scoreOne;
+    @ApiModelProperty(name = "scoreTwo", value = "评分2")
+    private Double scoreTwo;
+    @ApiModelProperty(name = "scoreThree", value = "评分3")
+    private Double scoreThree;
+    @ApiModelProperty(name = "childCommonRatings", value = "评论")
+    private List<CommonCommentVo> childCommonComments;
+    @ApiModelProperty(name = "isCollect", value = "是否收藏")
+    private Integer isCollect;
+    @ApiModelProperty(name = "commentCount", value = "评论数量")
+    private Long commentCount;
+}

+ 40 - 0
alien-entity/src/main/java/shop/alien/mapper/CommonCommentMapper.java

@@ -0,0 +1,40 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import shop.alien.entity.store.CommonComment;
+import shop.alien.entity.store.vo.CommonCommentVo;
+
+import java.util.List;
+
+/**
+ * 评论表 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface CommonCommentMapper extends BaseMapper<CommonComment> {
+
+
+    @Select("select *,if(comment_type = 1,lu.user_image,su.head_img) headImg,\n" +
+            "if(comment_type = 1,lu.user_name ,su.nick_name ) headName," +
+            "if(llr.dianzan_id is null,'0','1') isLike\n" +
+            "from common_comment cc\n" +
+            "left join life_user lu on cc.user_id = lu.id and lu.delete_flag = 0\n" +
+            "left join store_user su on cc.merchant_id = su.store_id and su.delete_flag = 0\n" +
+            "left join life_like_record llr on\n" +
+            "llr.huifu_id = cc.id\n" +
+            "and llr.`type` = #{type}\n" +
+            "and llr.dianzan_id = #{dianzanId}\n" +
+            "and llr.delete_flag = 0\n" +
+            "${ew.customSqlSegment}")
+    List<CommonCommentVo> selectALlComment(@Param(Constants.WRAPPER)QueryWrapper<CommonCommentVo> wrapper,
+                                           @Param("type") String type,
+                                           @Param("dianzanId") Long dianzanId);
+}
+

+ 61 - 0
alien-entity/src/main/java/shop/alien/mapper/CommonRatingMapper.java

@@ -0,0 +1,61 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import shop.alien.entity.store.CommonRating;
+import shop.alien.entity.store.vo.StoreInfoScoreVo;
+
+import java.util.Map;
+
+/**
+ * 评价表 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface CommonRatingMapper extends BaseMapper<CommonRating> {
+
+    /**
+     * 获取评价数量和评价分数信息
+     *
+     * @param businessId 门店ID
+     * @param businessType 业务类型
+     * @return 评价数量和评价分数信息
+     */
+    @Select("SELECT " +
+            "IFNULL(SUM(score), 0) AS score, " +
+            "IFNULL(SUM(score_one), 0) AS scoreOne, " +
+            "IFNULL(SUM(score_two), 0) AS scoreTwo, " +
+            "IFNULL(SUM(score_three), 0) AS scoreThree, " +
+            "COUNT(0) AS total " +
+            "FROM `common_rating` " +  // FROM 后加空格,避免和表名拼接成 FROM`common_rating`
+            "WHERE business_type = #{businessType} " +
+            "AND delete_flag = 0 " +
+            "AND business_id = #{businessId}")
+    StoreInfoScoreVo getCommentCountAndScoreInfo(@Param("businessType")Integer businessType,@Param("businessId")Integer businessId);
+
+     /**
+     * 获取评价数量
+     */
+    @Select("SELECT\n" +
+//            "    -- 1. 总评论数(当前门店、根评论、未删除)\n" +
+//            "    COUNT(1) AS totalCount,\n" +
+            "    -- 2. 有图评论数(image_urls 不为 null 且不为空字符串)\n" +
+            "    SUM(CASE WHEN image_urls IS NOT NULL AND image_urls != '' THEN 1 ELSE 0 END) AS imageCount,\n" +
+            "    -- 3. 好评数(score >= 4.5)\n" +
+            "    SUM(CASE WHEN score >= 4.5 THEN 1 ELSE 0 END) AS goodCount,\n" +
+            "    -- 4. 中评数(score >= 3.0 AND score <= 4.0)\n" +
+            "    SUM(CASE WHEN score >= 3.0 AND score <= 4.0 THEN 1 ELSE 0 END) AS midCount,\n" +
+            "    -- 5. 差评数(score >= 0.5 AND score <= 2.5)\n" +
+            "    SUM(CASE WHEN score >= 0.5 AND score <= 2.5 THEN 1 ELSE 0 END) AS badCount\n" +
+            "FROM\n" +
+            "    common_rating\n" +
+            "   ${ew.customSqlSegment}\n")
+    Map<String, Object> getRatingCount(@Param(Constants.WRAPPER) QueryWrapper<CommonRating> wrapper);
+}
+

+ 35 - 0
alien-entity/src/main/resources/mapper/CommonCommentMapper.xml

@@ -0,0 +1,35 @@
+<?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="shop.alien.mapper.CommonCommentMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.CommonComment">
+        <id column="id" property="id" />
+        <result column="source_type" property="sourceType" />
+        <result column="source_id" property="sourceId" />
+        <result column="user_id" property="userId" />
+        <result column="parent_id" property="parentId" />
+        <result column="content" property="content" />
+        <result column="image_urls" property="imageUrls" />
+        <result column="is_anonymous" property="isAnonymous" />
+        <result column="comment_type" property="commentType" />
+        <result column="merchant_id" property="merchantId" />
+        <result column="is_show" property="isShow" />
+        <result column="audit_status" property="auditStatus" />
+        <result column="like_count" property="likeCount" />
+        <result column="reply_count" property="replyCount" />
+        <result column="create_time" property="createdTime" />
+        <result column="update_time" property="updatedTime" />
+        <result column="ext_info" property="extInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, source_type, source_id, user_id, parent_id, content, image_urls, is_anonymous,
+        comment_type, merchant_id, is_show, audit_status, like_count, reply_count,
+        create_time, update_time, ext_info
+    </sql>
+
+
+</mapper>
+

+ 36 - 0
alien-entity/src/main/resources/mapper/CommonRatingMapper.xml

@@ -0,0 +1,36 @@
+<?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="shop.alien.mapper.CommonRatingMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.CommonRating">
+        <id column="id" property="id" />
+        <result column="business_type" property="businessType" />
+        <result column="business_id" property="businessId" />
+        <result column="user_id" property="userId" />
+        <result column="content" property="content" />
+        <result column="score" property="score" />
+        <result column="other_score" property="otherScore" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />
+        <result column="image_urls" property="imageUrls" />
+        <result column="is_anonymous" property="isAnonymous" />
+        <result column="is_show" property="isShow" />
+        <result column="audit_status" property="auditStatus" />
+        <result column="like_count" property="likeCount" />
+        <result column="score_one" property="scoreOne" />
+        <result column="score_two" property="scoreTwo" />
+        <result column="score_three" property="scoreThree" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_user_id" property="createdUserId" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="updated_user_id" property="updatedUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, business_type, business_id, user_id, content, score, other_score, image_urls,
+        is_anonymous, is_show, audit_status, like_count, score_one, score_two, score_three,
+        delete_flag, created_user_id, updated_time, updated_user_id
+    </sql>
+
+</mapper>
+

+ 90 - 0
alien-store/src/main/java/shop/alien/store/controller/CommonCommentController.java

@@ -0,0 +1,90 @@
+package shop.alien.store.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiSort;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.CommonComment;
+import shop.alien.store.service.CommonCommentService;
+
+/**
+ * 评论表 前端控制器
+ *
+ * @author lyx
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"评论管理"})
+@ApiSort(13)
+@CrossOrigin
+@RestController
+@RequestMapping("/commonComment")
+@RequiredArgsConstructor
+public class CommonCommentController {
+
+    private final CommonCommentService commonCommentService;
+
+    /**
+     商户回复评论 实例:
+     {
+       "id": 10002,
+       "sourceType": 1,
+       "sourceId": 50008,
+       "userId": 999000,
+       "parentId": 10001,
+       "content": "感谢您的认可,我们会继续努力为您提供更好的服务!",
+       "imageUrls": "",
+       "isAnonymous": 0,
+       "commentType": 2,
+       "merchantId": 10086,
+       "isShow": 1,
+       "auditStatus": 1,
+       "likeCount": 8,
+       "replyCount": 0,
+       "createdTime": "2025-01-08 15:00:30",
+       "updatedTime": "2025-01-08 15:00:30",
+       "extInfo": "{\"floor\": 2, \"replyToUserId\": 888999}"
+     }
+     正常回复实例:
+     {
+     "sourceType": 1,
+     "sourceId": 50008, //回复评价需要填评价id,回复评论不需要
+     "userId": 888999, // 发布者id
+     "parentId": 0, // 0代表第一级
+     "content": "这家店的商品质量非常好,物流也很快,商家服务态度也很棒!",
+     "commentType": 1,
+     //   "merchantId": 10086, 为2商户评论需要填
+     }
+     */
+    @ApiOperation(value = "新增评论", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @PostMapping("/addComment")
+    public R addComment(@RequestBody CommonComment commonComment) {
+        Integer addComment = commonCommentService.addComment(commonComment);
+        if (addComment == 0) {
+            return R.success("新增评论成功");
+        }
+        if (addComment == 2) {
+            return R.fail("新增评论失败,评论内容包含敏感字符");
+        }
+        return R.fail("新增评论失败");
+    }
+
+    /**删除评论
+     * @param commentId 评论id
+     * @return 0:成功, 1:失败
+     */
+    @ApiOperation(value = "删除评论", notes = "0:成功, 1:失败")
+    @GetMapping("/deleteComment")
+    public R deleteComment(@RequestParam Long commentId) {
+        boolean b = commonCommentService.removeById(commentId);
+        if (b) {
+            return R.success("删除评论成功");
+        }
+        return R.fail("删除评论失败");
+    }
+
+}
+

+ 140 - 0
alien-store/src/main/java/shop/alien/store/controller/CommonRatingController.java

@@ -0,0 +1,140 @@
+package shop.alien.store.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.CommonRating;
+import shop.alien.store.service.CommonCommentService;
+import shop.alien.store.service.CommonRatingService;
+
+/**
+ * 评价表 前端控制器
+ *
+ * @author lyx
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"评价管理"})
+@ApiSort(12)
+@CrossOrigin
+@RestController
+@RequestMapping("/commonRating")
+@RequiredArgsConstructor
+public class CommonRatingController {
+
+    private final CommonRatingService commonRatingService;
+    private final CommonCommentService commonCommentService;
+
+    @ApiOperation("分页查询评价列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "pageSize", value = "页容", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "businessType", value = "业务类型:1-店铺", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessId", value = "业务关联ID", dataType = "Long", paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Long", paramType = "query"),
+            @ApiImplicitParam(name = "auditStatus", value = "审核状态:0-待审核 1-通过 2-驳回", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "searchScore", value = "搜索评分:0-全部,1-好评 2-中评 3-差评,4-有图", dataType = "Integer", paramType = "query")
+    })
+    @GetMapping("/getList")
+    public R getList(
+            @RequestParam(defaultValue = "1") Integer pageNum,
+            @RequestParam(defaultValue = "10") Integer pageSize,
+            @RequestParam(required = false) Integer businessType,
+            @RequestParam(required = false) Long businessId,
+            @RequestParam(required = false) Long userId,
+            @RequestParam(required = false) Integer auditStatus,
+            @RequestParam(defaultValue = "0") Integer searchScore) {
+        log.info("CommonRatingController.getList?pageNum={}&pageSize={}&businessType={}&businessId={}&userId={}&auditStatus={}&searchScore={}",
+                pageNum, pageSize, businessType, businessId, userId, auditStatus, searchScore);
+        return commonRatingService.getRatingList(pageNum, pageSize, businessType, businessId, userId, auditStatus, searchScore);
+    }
+
+    @ApiOperation("获取全部评价数量(好评,中评,差评)")
+    @ApiImplicitParams({
+           @ApiImplicitParam(name = "storeId", value = "店铺ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getRatingCount")
+    public R getRatingCount(@RequestParam Integer businessId, @RequestParam Integer businessType) {
+        log.info("CommonRatingController.getRatingCount?businessId={}&businessType={}", businessId, businessType);
+        return R.data(commonRatingService.getRatingCount(businessId, businessType));
+    }
+
+//
+//    @ApiOperation("根据ID获取评价详情")
+//    @ApiImplicitParam(name = "id", value = "评价ID", dataType = "Long", paramType = "path", required = true)
+//    @GetMapping("/getById/{id}")
+//    public R<CommonRating> getById(@PathVariable Long id) {
+//        log.info("CommonRatingController.getById?id={}", id);
+//        return R.data(commonRatingService.getById(id));
+//    }
+//
+    @ApiOperation(value = "新增评价", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @PostMapping("/addRating")
+    public R<Integer> add(@RequestBody CommonRating commonRating) {
+        log.info("CommonRatingController.add?commonRating={}", commonRating);
+        return R.data(commonRatingService.saveCommonRating(commonRating));
+    }
+
+    @ApiOperation("获取评价详情,和所有回复")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "评价主键", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "当前用户ID", dataType = "Long", paramType = "query", required = true)
+    })
+    @GetMapping("/getRatingDetail")
+    public R getCommentDetail(@RequestParam Integer ratingId, @RequestParam Long userId) {
+        log.info("CommonRatingController.getRatingDetail?id={}&userId={}", ratingId, userId);
+        if (ratingId == null) {
+            throw new IllegalArgumentException("参数[ratingId]不能为空");
+        }
+        if (userId == null) {
+            throw new IllegalArgumentException("参数[userId]不能为空");
+        }
+        return R.data(commonRatingService.getRatingDetail(ratingId, userId));
+    }
+
+//
+//    @ApiOperation("更新评价")
+//    @PutMapping("/update")
+//    public R<Boolean> update(@RequestBody CommonRating commonRating) {
+//        log.info("CommonRatingController.update?commonRating={}", commonRating);
+//        return R.data(commonRatingService.updateById(commonRating));
+//    }
+//
+//    @ApiOperation("删除评价")
+//    @ApiImplicitParam(name = "id", value = "评价ID", dataType = "Long", paramType = "path", required = true)
+//    @DeleteMapping("/delete/{id}")
+//    public R<Boolean> delete(@PathVariable Long id) {
+//        log.info("CommonRatingController.delete?id={}", id);
+//        return R.data(commonRatingService.removeById(id));
+//    }
+//
+//    @ApiOperation("获取平均评分")
+//    @ApiImplicitParams({
+//            @ApiImplicitParam(name = "businessType", value = "业务类型", dataType = "Integer", paramType = "query", required = true),
+//            @ApiImplicitParam(name = "businessId", value = "业务ID", dataType = "Long", paramType = "query", required = true)
+//    })
+//    @GetMapping("/getAverageScore")
+//    public R<Double> getAverageScore(
+//            @RequestParam Integer businessType,
+//            @RequestParam Long businessId) {
+//        log.info("CommonRatingController.getAverageScore?businessType={}&businessId={}", businessType, businessId);
+//        return R.data(commonRatingService.getAverageScore(businessType, businessId));
+//    }
+//
+//    @ApiOperation("获取评价数量")
+//    @ApiImplicitParams({
+//            @ApiImplicitParam(name = "businessType", value = "业务类型", dataType = "Integer", paramType = "query", required = true),
+//            @ApiImplicitParam(name = "businessId", value = "业务ID", dataType = "Long", paramType = "query", required = true)
+//    })
+//    @GetMapping("/getRatingCount")
+//    public R<Long> getRatingCount(
+//            @RequestParam Integer businessType,
+//            @RequestParam Long businessId) {
+//        log.info("CommonRatingController.getRatingCount?businessType={}&businessId={}", businessType, businessId);
+//        return R.data(commonRatingService.getRatingCount(businessType, businessId));
+//    }
+
+}
+

+ 16 - 0
alien-store/src/main/java/shop/alien/store/service/CommonCommentService.java

@@ -0,0 +1,16 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.CommonComment;
+
+/**
+ * 评论表 服务类
+ *
+ * @author  lyx
+ * @since 2025-01-XX
+ */
+public interface CommonCommentService extends IService<CommonComment> {
+
+    Integer addComment(CommonComment commonComment);
+}
+

+ 73 - 0
alien-store/src/main/java/shop/alien/store/service/CommonRatingService.java

@@ -0,0 +1,73 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.CommonRating;
+
+/**
+ * 评价表 服务类
+ *
+ * @author lyx
+ * @since 2025-01-XX
+ */
+public interface CommonRatingService extends IService<CommonRating> {
+
+    /**
+     * 新增评价
+     *
+     * @param commonRating 评价信息
+     * @return 是否成功
+     */
+    Integer saveCommonRating(CommonRating commonRating);
+
+/*        *
+     * 分页查询评价列表
+     *
+     * @param pageNum      页数
+     * @param pageSize     页容
+     * @param businessType 业务类型:1-订单评价 2-商品评价 3-店铺评价 4-活动评价
+     * @param businessId   业务关联ID
+     * @param userId       用户ID
+     * @param auditStatus  审核状态:0-待审核 1-通过 2-驳回
+     * @param searchScore  搜索评分:0-全部,1-好评 2-中评 3-差评,4-有图
+     * @return IPage<CommonRating>
+     */
+    R getRatingList(Integer pageNum, Integer pageSize, Integer businessType, Long businessId, Long userId, Integer auditStatus, Integer searchScore);
+
+     /**
+     * 获取店铺评价数量(好评,中评,差评)
+     *
+     * @param businessId  业务ID
+     * @param businessType 业务类型:1-订单评价 2-商品评价 3-店铺评价 4-活动评价
+     * @return 评价数量
+     */
+    Object getRatingCount(Integer businessId, Integer businessType);
+
+     /**
+     * 获取评价详情
+     *
+     * @param ratingId 评价ID
+     * @return 评价详情
+     */
+    Object getRatingDetail(Integer ratingId, Long userId);
+
+
+  /*  /**
+     * 根据业务类型和业务ID获取平均评分
+     *
+     * @param businessType 业务类型
+     * @param businessId   业务ID
+     * @return 平均评分
+
+    Double getAverageScore(Integer businessType, Long businessId);
+
+    *
+     * 根据业务类型和业务ID获取评价数量
+     *
+     * @param businessType 业务类型
+     * @param businessId   业务ID
+     * @return 评价数量
+
+    Long getRatingCount(Integer businessType, Long businessId);*/
+}
+

+ 28 - 2
alien-store/src/main/java/shop/alien/store/service/LifeCommentService.java

@@ -2,6 +2,7 @@ package shop.alien.store.service;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
@@ -58,6 +59,10 @@ public class LifeCommentService {
 
     private final StoreStaffConfigMapper storeStaffConfigMapper;
 
+    private final  CommonRatingMapper commonRatingMapper;
+
+    private final CommonCommentMapper commonCommentMapper;
+
     /**
      * 点赞操作
      * <p>
@@ -182,12 +187,22 @@ public class LifeCommentService {
                 updateWrapper.eq(StoreStaffConfig::getId, huifuId)
                         .setSql("like_count = like_count + 1");
                 return storeStaffConfigMapper.update(null, updateWrapper);
-            } if (CommonConstant.LIKE_TYPE_STORE.equals(type)) {
+            } else if (CommonConstant.LIKE_TYPE_STORE.equals(type)) {
                 // 类型1:评论
                 LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
                 updateWrapper.eq(StoreComment::getId, huifuId)
                         .setSql("like_count = like_count + 1");
                 return storeCommentMapper.update(null, updateWrapper);
+            } else if (CommonConstant.RATING_LIKE.equals(type)) {
+                // 11-评价点赞:更新评价表点赞数
+                return commonRatingMapper.update(null, new UpdateWrapper<CommonRating>()
+                        .setSql("like_count = like_count + 1")
+                        .eq("id", huifuId));
+            } else if (CommonConstant.COMMENT_LIKE.equals(type)) {
+                // 12-评论点赞:更新评论表点赞数
+                return commonCommentMapper.update(null, new UpdateWrapper<CommonComment>()
+                        .setSql("like_count = like_count + 1")
+                        .eq("id", huifuId));
             } else {
                 log.warn("未知的点赞类型,type={},huifuId={}", type, huifuId);
                 return 0;
@@ -347,7 +362,18 @@ public class LifeCommentService {
                         .gt(StoreComment::getLikeCount, 0)
                         .setSql("like_count = like_count - 1");
                 return storeCommentMapper.update(null, updateWrapper);
-        } else {
+            }  else if (CommonConstant.RATING_LIKE.equals(type)) {
+                // 11-评价点赞:更新评价表点赞数
+                return commonRatingMapper.update(null, new UpdateWrapper<CommonRating>()
+                        .setSql("like_count = like_count - 1")
+                        .eq("id", huifuId));
+            } else if (CommonConstant.COMMENT_LIKE.equals(type)) {
+                // 12-评论点赞:更新评论表点赞数
+                return commonCommentMapper.update(null, new UpdateWrapper<CommonComment>()
+                        .setSql("like_count = like_count - 1")
+                        .eq("id", huifuId));
+            }
+            else {
                 log.warn("未知的点赞类型,type={},huifuId={}", type, huifuId);
                 return 0;
             }

+ 103 - 0
alien-store/src/main/java/shop/alien/store/service/impl/CommonCommentServiceImpl.java

@@ -0,0 +1,103 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import shop.alien.entity.store.CommonComment;
+import shop.alien.mapper.CommonCommentMapper;
+import shop.alien.store.service.CommonCommentService;
+import shop.alien.util.common.safe.TextModerationResultVO;
+import shop.alien.util.common.safe.TextModerationUtil;
+
+/**
+ * 评论表 服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class CommonCommentServiceImpl extends ServiceImpl<CommonCommentMapper, CommonComment> implements CommonCommentService {
+
+    @Autowired
+    private TextModerationUtil textModerationUtil;
+
+    @Override
+    public Integer addComment(CommonComment commonComment) {
+        TextModerationResultVO textCheckResult = null;
+        try {
+            textCheckResult = textModerationUtil.invokeFunction(commonComment.getContent(), CommonRatingServiceImpl.SERVICES_LIST);
+            if ("high".equals(textCheckResult.getRiskLevel())) {
+                return 2;
+            }
+            return this.save(commonComment) ? 0 : 1;
+        } catch (Exception e) {
+            return 1;
+        }
+    }
+//
+//    @Override
+//    public IPage<CommonComment> getCommentList(Integer pageNum, Integer pageSize, Integer sourceType, Long sourceId, Long parentId, Integer commentType, Integer auditStatus) {
+//        Page<CommonComment> page = new Page<>(pageNum, pageSize);
+//        LambdaQueryWrapper<CommonComment> wrapper = new LambdaQueryWrapper<>();
+//
+//        if (sourceType != null) {
+//            wrapper.eq(CommonComment::getSourceType, sourceType);
+//        }
+//        if (sourceId != null) {
+//            wrapper.eq(CommonComment::getSourceId, sourceId);
+//        }
+//        if (parentId != null) {
+//            wrapper.eq(CommonComment::getParentId, parentId);
+//        }
+//        if (commentType != null) {
+//            wrapper.eq(CommonComment::getCommentType, commentType);
+//        }
+//        if (auditStatus != null) {
+//            wrapper.eq(CommonComment::getAuditStatus, auditStatus);
+//        }
+//
+//        wrapper.eq(CommonComment::getIsShow, 1);
+//        wrapper.orderByDesc(CommonComment::getCreatedTime);
+//
+//        return this.page(page, wrapper);
+//    }
+//
+//    @Override
+//    public List<CommonComment> getRootComments(Integer sourceType, Long sourceId) {
+//        LambdaQueryWrapper<CommonComment> wrapper = new LambdaQueryWrapper<>();
+//        wrapper.eq(CommonComment::getSourceType, sourceType)
+//                .eq(CommonComment::getSourceId, sourceId)
+//                .eq(CommonComment::getParentId, 0)
+//                .eq(CommonComment::getIsShow, 1)
+//                .eq(CommonComment::getAuditStatus, 1)
+//                .orderByDesc(CommonComment::getCreatedTime);
+//
+//        return this.list(wrapper);
+//    }
+//
+//    @Override
+//    public List<CommonComment> getReplyList(Long parentId) {
+//        LambdaQueryWrapper<CommonComment> wrapper = new LambdaQueryWrapper<>();
+//        wrapper.eq(CommonComment::getParentId, parentId)
+//                .eq(CommonComment::getIsShow, 1)
+//                .eq(CommonComment::getAuditStatus, 1)
+//                .orderByAsc(CommonComment::getCreatedTime);
+//
+//        return this.list(wrapper);
+//    }
+//
+//    @Override
+//    public void incrementReplyCount(Long parentId) {
+//        LambdaUpdateWrapper<CommonComment> updateWrapper = new LambdaUpdateWrapper<>();
+//        updateWrapper.eq(CommonComment::getId, parentId)
+//                .setSql("reply_count = reply_count + 1");
+//        this.update(updateWrapper);
+//    }
+}
+

+ 441 - 0
alien-store/src/main/java/shop/alien/store/service/impl/CommonRatingServiceImpl.java

@@ -0,0 +1,441 @@
+package shop.alien.store.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.ImmutableList;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.vo.CommonCommentVo;
+import shop.alien.entity.store.vo.CommonRatingVo;
+import shop.alien.entity.store.vo.StoreInfoScoreVo;
+import shop.alien.entity.store.vo.WebSocketVo;
+import shop.alien.mapper.*;
+import shop.alien.store.config.WebSocketProcess;
+import shop.alien.store.service.CommonRatingService;
+import shop.alien.store.util.CommonConstant;
+import shop.alien.util.common.constant.CommentSourceTypeEnum;
+import shop.alien.util.common.constant.RatingBusinessTypeEnum;
+import shop.alien.util.common.safe.TextModerationResultVO;
+import shop.alien.util.common.safe.TextModerationUtil;
+import shop.alien.util.common.safe.TextReviewServiceEnum;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 评价表 服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, CommonRating> implements CommonRatingService {
+
+    @Autowired
+    private TextModerationUtil textModerationUtil;
+
+    private final  CommonRatingMapper commonRatingMapper;
+    private final StoreInfoMapper storeInfoMapper;
+    private final StoreUserMapper storeUserMapper;
+    private final LifeNoticeMapper lifeNoticeMapper;
+    private final WebSocketProcess webSocketProcess;
+    private final LifeUserMapper lifeUserMapper;
+    private final CommonCommentMapper commonCommentMapper;
+    private final LifeLikeRecordMapper lifeLikeRecordMapper;
+    private final LifeCollectMapper lifeCollectMapper;
+
+
+    public static final List<String> SERVICES_LIST = ImmutableList.of(
+            TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService(),
+            TextReviewServiceEnum.LLM_QUERY_MODERATION.getService()
+    );
+
+
+
+    @Override
+    public Integer saveCommonRating(CommonRating commonRating) {
+        // 1. 文本审核
+        try {
+            TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commonRating.getContent(), SERVICES_LIST);
+            if ("high".equals(textCheckResult.getRiskLevel())) {
+                return 2;
+            }
+            // 手动存评分1,2,3
+            if (StringUtils.isNotEmpty(commonRating.getOtherScore())) {
+                JSONObject parse = JSONObject.parse(commonRating.getOtherScore());
+                commonRating.setScoreOne(parse.getDouble("scoreOne"));
+                commonRating.setScoreTwo(parse.getDouble("scoreTwo"));
+                commonRating.setScoreThree(parse.getDouble("scoreThree"));
+            }
+            int i = this.save(commonRating) ? 0 : 1;
+            // 对不同的businessType进行不同的处理,
+            doBusinessWithType(commonRating);
+            return i;
+        } catch (Exception e) {
+            log.error("CommonRatingService.saveCommonRating ERROR Msg={}", e.getMessage());
+            return 1;
+        }
+    }
+
+    /**
+     * 根据不同的businessType进行不同的处理
+     * @param commonRating 评价信息
+     */
+    private void doBusinessWithType(CommonRating commonRating) throws Exception {
+        Integer businessId = commonRating.getBusinessId();
+        Double score = commonRating.getScore();
+        if(1 == commonRating.getBusinessType()){
+            // 更新门店评价信息
+            StoreInfoScoreVo storeInfoScoreVo = commonRatingMapper.getCommentCountAndScoreInfo(commonRating.getBusinessType(),businessId);
+            double total = storeInfoScoreVo.getTotal();
+            double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
+            double scoreOne = (total == 0 ? 0 : storeInfoScoreVo.getScoreOne() / total);
+            double scoreTwo = (total == 0 ? 0 : storeInfoScoreVo.getScoreTwo() / total);
+            double scoreThree = (total == 0 ? 0 : storeInfoScoreVo.getScoreThree() / total);
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setId(businessId);
+            storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setScoreOne(new BigDecimal(scoreOne).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setScoreTwo(new BigDecimal(scoreTwo).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setScoreThree(new BigDecimal(scoreThree).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfoMapper.updateById(storeInfo);
+            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()).eq(StoreUser::getDeleteFlag, 0));
+
+            // 如果差评,则发送差评提醒
+            if(score != null && score >= 0.5 && score <= 2.5){
+                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                String commonDate = simpleDateFormat.format(new Date());
+                LifeNotice lifeMessage = new LifeNotice();
+                lifeMessage.setReceiverId("store_" + storeUser.getPhone());
+                String text = "在"+commonDate+",您的店铺有一条差评记录,您可查看评价内容是否属实,如不属实,可向平台进行申诉。";
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("message", text);
+                lifeMessage.setContext(jsonObject.toJSONString());
+                lifeMessage.setTitle("差评通知");
+                lifeMessage.setSenderId("system");
+                lifeMessage.setIsRead(0);
+                lifeMessage.setNoticeType(1);
+                lifeNoticeMapper.insert(lifeMessage);
+
+                WebSocketVo websocketVo = new WebSocketVo();
+                websocketVo.setSenderId("system");
+                websocketVo.setReceiverId("store_" + storeUser.getPhone());
+                websocketVo.setCategory("notice");
+                websocketVo.setNoticeType("1");
+                websocketVo.setIsRead(0);
+                websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
+                webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());
+            }
+        }
+
+    }
+
+    @Override
+    public R getRatingList(Integer pageNum, Integer pageSize, Integer businessType, Long businessId, Long userId, Integer auditStatus, Integer searchScore) {
+        Page<CommonRating> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
+        
+        if (businessType != null) {
+            wrapper.eq(CommonRating::getBusinessType, businessType);
+        }
+        if (businessId != null) {
+            wrapper.eq(CommonRating::getBusinessId, businessId);
+        }
+        if (auditStatus != null) {
+            wrapper.eq(CommonRating::getAuditStatus, auditStatus);
+        }
+        if (searchScore != null) {
+            if(searchScore == 1){
+                // 1-好评
+                wrapper.ge(CommonRating::getScore, 4.5);
+            }else if(searchScore == 2){
+                // 2-中评
+                wrapper.ge(CommonRating::getScore, 3.5);
+                wrapper.lt(CommonRating::getScore, 4.5);
+            }else if(searchScore == 3){
+                // 3-差评
+                wrapper.lt(CommonRating::getScore, 3.5);
+            }else if(searchScore == 4){
+                // 4-有图
+                wrapper.isNotNull(CommonRating::getImageUrls);
+            }
+        }
+        
+        wrapper.eq(CommonRating::getIsShow, 1);
+        wrapper.orderByDesc(CommonRating::getId);
+        IPage<CommonRating> page1 = this.page(page, wrapper);
+        return doListBusinessWithType(page1, businessType,userId);
+    }
+
+    @Override
+    public Object getRatingCount(Integer businessId, Integer businessType) {
+        // 查询全部评价记录
+        LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(CommonRating::getBusinessId, businessId);
+        wrapper.eq(CommonRating::getBusinessType, businessType);
+        wrapper.eq(CommonRating::getIsShow, 1);
+        List<CommonRating> commonRatings = commonRatingMapper.selectList(wrapper);
+        List<Long> collect = commonRatings.stream().map(x -> x.getId()).collect(Collectors.toList());
+        // 获取评价统计信息(总评论数、有图评论数、好评数、中评数、差评数)
+        Map<String, Object> ratingCount = commonRatingMapper.getRatingCount(new QueryWrapper<CommonRating>().in("id", collect));
+        if(RatingBusinessTypeEnum.STORE_RATING.getBusinessType() == businessType){
+            // 1店铺评分
+            StoreInfo storeInfo = storeInfoMapper.selectById(businessId);
+            ratingCount.put("storeScore", storeInfo.getScoreAvg());
+
+            // 2统计评价数量
+            AtomicReference<Integer> count = new AtomicReference<>(0);
+            count.updateAndGet(v -> v + collect.size());
+            // 1.查询评价的评论的记录
+            LambdaQueryWrapper<CommonComment> commentWrapper = new LambdaQueryWrapper<CommonComment>()
+                    .eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())
+                    .in(CommonComment::getSourceId, collect);
+            List<Long> collect1 = commonCommentMapper.selectList(commentWrapper).stream().map(x -> x.getId()).collect(Collectors.toList());
+            if(!collect1.isEmpty()) {
+                count.updateAndGet(v -> v + collect1.size());
+                // 2.在再评论的表中查询评论的回复(根评论)
+                Integer allCommentsOnCommentsNum = getAllCommentsOnCommentsNum(collect1);
+                count.updateAndGet(v -> v + allCommentsOnCommentsNum);
+            }
+            ratingCount.put("totalCount", count.get());
+
+            // 3用户图片
+            List<Long> collect2 = commonRatings.stream().filter(i -> i.getScore() >= 4.5).map(CommonRating::getUserId).distinct().limit(6).collect(Collectors.toList());
+            if(!collect2.isEmpty()) {
+                List<LifeUser> lifeUsers = lifeUserMapper.selectList(new QueryWrapper<LifeUser>().lambda().in(LifeUser::getId, collect2));
+                ratingCount.put("img", lifeUsers.stream().map(LifeUser::getUserImage).collect(Collectors.toList()));
+            } else {
+                ratingCount.put("img", new ArrayList<>());
+            }
+
+
+        }
+        return ratingCount;
+    }
+
+    @Override
+    public Object getRatingDetail(Integer ratingId, Long userId) {
+        CommonRating commonRating = commonRatingMapper.selectById(ratingId);
+        if(commonRating == null){
+            throw new IllegalArgumentException("评价不存在");
+        }
+        CommonRatingVo commonRatingVo = new CommonRatingVo();
+        BeanUtils.copyProperties(commonRating, commonRatingVo);
+        LifeUser lifeUser = lifeUserMapper.selectById(Integer.parseInt(commonRating.getUserId().toString()));
+        // 设置评论用户信息
+        commonRatingVo.setUserImage(lifeUser.getUserImage());
+        commonRatingVo.setUserName(lifeUser.getUserName());
+        // 查询当前用户点赞列表(仅评价)
+        List<LifeLikeRecord> lifeLikeRecords = lifeLikeRecordMapper.selectList(new QueryWrapper<LifeLikeRecord>().lambda()
+                .eq(LifeLikeRecord::getDianzanId, userId)
+                .eq(LifeLikeRecord::getHuifuId, ratingId)
+                .eq(LifeLikeRecord::getDeleteFlag, 0)
+                .eq(LifeLikeRecord::getType, CommonConstant.RATING_LIKE));
+        if(lifeLikeRecords.size() > 0){
+            commonRatingVo.setIsLike(1);
+        } else {
+            commonRatingVo.setIsLike(0);
+        }
+        // 根据业务类型处理
+        if(commonRatingVo.getBusinessType().equals(RatingBusinessTypeEnum.STORE_RATING.getBusinessType())){
+            // 1店铺信息
+            StoreInfo storeInfo = storeInfoMapper.selectById(commonRatingVo.getBusinessId());
+            if( null != storeInfo) {
+                commonRatingVo.setStoreName(storeInfo.getStoreName());
+                commonRatingVo.setStoreEvaluate(storeInfo.getStoreEvaluate());
+                commonRatingVo.setStoreScore(storeInfo.getScoreAvg());
+                commonRatingVo.setScoreOne(storeInfo.getScoreOne());
+                commonRatingVo.setScoreTwo(storeInfo.getScoreTwo());
+                commonRatingVo.setScoreThree(storeInfo.getScoreThree());
+            }
+            // 1.1 查询是否收藏该店铺
+            LambdaQueryWrapper<LifeCollect> collectWrapper = new LambdaQueryWrapper<LifeCollect>()
+                    .eq(LifeCollect::getUserId, userId)
+                    .eq(LifeCollect::getStoreId, storeInfo.getId())
+                    .eq(LifeCollect::getDeleteFlag, 0);
+            LifeCollect lifeCollect = lifeCollectMapper.selectOne(collectWrapper);
+            if(lifeCollect != null){
+                commonRatingVo.setIsCollect(1);
+            } else {
+                commonRatingVo.setIsCollect(0);
+            }
+            // 2查询一级评价
+            QueryWrapper<CommonCommentVo> commentWrapper = new QueryWrapper<CommonCommentVo>()
+                    .eq("cc.source_type", CommentSourceTypeEnum.STORE_COMMENT.getType())
+                    .eq("cc.source_id", ratingId)
+                    .eq("cc.parent_id", 0);
+            List<CommonCommentVo> commonComments = commonCommentMapper.selectALlComment(commentWrapper,CommonConstant.COMMENT_LIKE, userId);
+
+            // 定义评论总数
+            AtomicReference<Long> count = new AtomicReference<>(0L);
+            count.updateAndGet(v -> v + commonComments.size());
+            List<CommonCommentVo> commonCommentVos = new ArrayList<>();
+            for (CommonCommentVo commonComment : commonComments) {
+//                CommonCommentVo commonCommentVo = new CommonCommentVo();
+//                BeanUtils.copyProperties(commonComment, commonCommentVo);
+                // 递归获取所有子评论(扁平化)
+                List<CommonCommentVo> allChildComments = getChildCommentsRecursively(commonComment.getId(), userId);
+                count.updateAndGet(v -> v + allChildComments.size());
+                // 一级评论本身的商家/用户标识和商家信息
+                // setStoreUserInfo(first);
+
+                // 按时间排序后绑定子评论列表
+                allChildComments.sort(Comparator.comparing(CommonCommentVo::getCreatedTime));
+
+                commonComment.setChildCommonComments(allChildComments);
+                commonCommentVos.add(commonComment);
+            }
+            commonRatingVo.setCommentCount(count.get());
+            commonRatingVo.setChildCommonComments(commonCommentVos);
+        }
+        return commonRatingVo;
+    }
+
+    private List<CommonCommentVo> getChildCommentsRecursively(Long id, Long userId) {
+        List<CommonCommentVo> allChildComments = new ArrayList<>();
+
+        // 查询直接回复当前评论的所有记录
+        QueryWrapper<CommonCommentVo> wrapper = new QueryWrapper<>();
+        wrapper.eq("cc.delete_flag", 0)
+                .eq("cc.parent_id", id)
+                .orderByAsc("cc.created_time");
+        List<CommonCommentVo> directChildren = commonCommentMapper.selectALlComment(wrapper,CommonConstant.COMMENT_LIKE, userId);
+
+        if (CollectionUtils.isEmpty(directChildren)) {
+            return allChildComments;
+        }
+        // 处理每个直接子评论
+        for (CommonCommentVo child : directChildren) {
+            // 设置商家/用户标识
+//            setStoreUserInfo(child);
+            // 递归获取该子评论的所有子评论
+            List<CommonCommentVo> grandChildren = getChildCommentsRecursively(child.getId(), userId);
+            // 将当前子评论添加到结果列表
+            allChildComments.add(child);
+            // 将该子评论的所有子评论也添加到结果列表(扁平化)
+            allChildComments.addAll(grandChildren);
+        }
+
+        return allChildComments;
+    }
+
+    @NotNull
+    private Integer getAllCommentsOnCommentsNum(List<Long> collect1) {
+        LambdaQueryWrapper<CommonComment> commentReplyWrapper = new LambdaQueryWrapper<CommonComment>()
+                .in(CommonComment::getParentId, collect1);
+        List<Long> collect2 = commonCommentMapper.selectList(commentReplyWrapper).stream().map(x -> x.getId()).collect(Collectors.toList());
+        if(collect2.isEmpty()){
+            return 0;
+        } else {
+            return collect2.size() + getAllCommentsOnCommentsNum(collect2);
+        }
+    }
+
+    private R doListBusinessWithType(IPage<CommonRating> page1, Integer businessType, Long userId) {
+        if(businessType == RatingBusinessTypeEnum.STORE_RATING.getBusinessType()){
+            // 1查询评价用户信息
+            Set<Long> userIdSet = page1.getRecords().stream()
+                    .map(CommonRating::getUserId)
+                    .collect(Collectors.toSet());
+            List<LifeUser> lifeUsers = lifeUserMapper.selectList(
+                    new QueryWrapper<LifeUser>().lambda()
+                            .in(LifeUser::getId, userIdSet));
+            Map<Integer, LifeUser> lifeUserMap = lifeUsers.stream()
+                    .collect(Collectors.toMap(LifeUser::getId, Function.identity()));
+            // 2查询当前用户点赞列表(仅评价)
+            List<LifeLikeRecord> lifeLikeRecords = lifeLikeRecordMapper.selectList(
+                    new QueryWrapper<LifeLikeRecord>().lambda()
+                    .eq(LifeLikeRecord::getDianzanId, userId)
+                    .eq(LifeLikeRecord::getType, CommonConstant.RATING_LIKE));
+            Map<String, LifeLikeRecord> likeRecordMap = lifeLikeRecords.stream()
+                    .collect(Collectors.toMap(LifeLikeRecord::getHuifuId, Function.identity()));
+
+
+            // 1.查询评价的评论的记录个数
+            Set<Long> ratingIdSet = page1.getRecords().stream()
+                    .map(CommonRating::getId)
+                    .collect(Collectors.toSet());
+            LambdaQueryWrapper<CommonComment> commentWrapper = new LambdaQueryWrapper<CommonComment>()
+                    .eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())
+                    .in(CommonComment::getSourceId, ratingIdSet);
+            // 评价id对应的所有评论 定义Map存储「评价ID -> 该评价下的总评论数」
+            Map<Long, Long> ratingCommentCountMap = commonCommentMapper.selectList(commentWrapper).stream()
+                    .collect(Collectors.groupingBy(CommonComment::getSourceId, Collectors.counting()));
+            IPage<CommonRatingVo> result = new Page<>(page1.getPages(), page1.getSize(), page1.getTotal());
+            List resultList = new ArrayList();
+
+            for (CommonRating record : page1.getRecords()) {
+                CommonRatingVo commonRatingVo = new CommonRatingVo();
+                BeanUtil.copyProperties(record, commonRatingVo);
+                // 判断用户信息
+                if(lifeUserMap.containsKey(Integer.parseInt(record.getUserId().toString()))){
+                    LifeUser lifeUser = lifeUserMap.get(Integer.parseInt(record.getUserId().toString()));
+                    // 设置评论用户信息
+                    commonRatingVo.setUserImage(lifeUser.getUserImage());
+                    commonRatingVo.setUserName(lifeUser.getUserName());
+                }
+                // 判断当前登录人是否点赞过
+                commonRatingVo.setIsLike(0);
+                if(likeRecordMap.containsKey(record.getId().toString())){
+                    commonRatingVo.setIsLike(1);
+                }
+                // 3.1 从映射中获取该评价的总评论数(默认0)
+                commonRatingVo.setCommentCount(ratingCommentCountMap.getOrDefault(record.getId(), 0L));
+                resultList.add(commonRatingVo);
+            }
+            result.setRecords(resultList);
+            return R.data(result);
+        }
+        return null;
+    }
+/*
+    @Override
+    public Double getAverageScore(Integer businessType, Long businessId) {
+        LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(CommonRating::getBusinessType, businessType)
+                .eq(CommonRating::getBusinessId, businessId)
+                .eq(CommonRating::getIsShow, 1)
+                .eq(CommonRating::getAuditStatus, 1);
+        
+        return this.list(wrapper).stream()
+                .map(CommonRating::getScore)
+                .filter(score -> score != null)
+                .mapToDouble(BigDecimal::doubleValue)
+                .average()
+                .orElse(0.0);
+    }
+
+    @Override
+    public Long getRatingCount(Integer businessType, Long businessId) {
+        LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(CommonRating::getBusinessType, businessType)
+                .eq(CommonRating::getBusinessId, businessId)
+                .eq(CommonRating::getIsShow, 1)
+                .eq(CommonRating::getAuditStatus, 1);
+        
+        return (long) this.count(wrapper);
+    }*/
+}
+

+ 2 - 0
alien-store/src/main/java/shop/alien/store/util/CommonConstant.java

@@ -109,4 +109,6 @@ public class CommonConstant {
     public static final String LIKE_TYPE_LAWYER_SCORE = "7";
     public static final String LIKE_TYPE_STAFF = "8";
     public static final String LIKE_TYPE_STORE = "9";
+    public static final String RATING_LIKE = "11";
+    public static final String COMMENT_LIKE = "12";
 }

+ 1 - 2
alien-store/src/main/java/shop/alien/store/util/ai/AiFeedbackAssignUtils.java

@@ -14,7 +14,6 @@ import org.springframework.util.StringUtils;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.multipart.MultipartFile;
 import shop.alien.entity.store.LifeFeedback;
-import shop.alien.store.feign.AlienAIFeign;
 
 import java.io.IOException;
 import java.util.HashMap;
@@ -41,7 +40,7 @@ public class AiFeedbackAssignUtils {
     private String assignStaffUrl;
 
     // 语音识别接口地址(从配置中读取,如果没有配置则使用默认值)
-    @Value("${feign.alienAI.url}")
+    @Value("${feign.alienAI.url:}")
     private String aiServiceBaseUrl;
 
     /**登录的语音识别文件登录

+ 21 - 0
alien-util/src/main/java/shop/alien/util/common/constant/CommentSourceTypeEnum.java

@@ -0,0 +1,21 @@
+package shop.alien.util.common.constant;
+
+
+public enum CommentSourceTypeEnum {
+    STORE_COMMENT(1, "店铺评价");
+
+    private final Integer type;
+    private final String info;
+
+    CommentSourceTypeEnum(Integer type, String info) {
+        this.type = type;
+        this.info = info;
+    }
+    public Integer getType() {
+        return type;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+}

+ 21 - 0
alien-util/src/main/java/shop/alien/util/common/constant/RatingBusinessTypeEnum.java

@@ -0,0 +1,21 @@
+package shop.alien.util.common.constant;
+
+public enum RatingBusinessTypeEnum {
+    STORE_RATING(1, "门店评价")
+    ;
+    private final int businessType;
+    private final String info;
+
+    RatingBusinessTypeEnum(int businessType, String info) {
+        this.businessType = businessType;
+        this.info = info;
+    }
+
+    public int getBusinessType() {
+        return businessType;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+}