浏览代码

律师评论全流程重构

lutong 5 天之前
父节点
当前提交
386ccb1fa3

+ 8 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreComment.java

@@ -123,4 +123,12 @@ public class StoreComment extends Model<StoreComment> {
     @TableField("service_score")
     private Double serviceScore;
 
+    @ApiModelProperty(value = "订单id")
+    @TableField("order_id")
+    private Integer orderId;
+
+    @ApiModelProperty(value = "律师id")
+    @TableField("lawyer_id")
+    private Integer lawyerId;
+
 }

+ 411 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/controller/StoreCommentController.java

@@ -0,0 +1,411 @@
+package shop.alien.lawyer.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreComment;
+import shop.alien.entity.store.dto.OrderReviewDto;
+import shop.alien.entity.store.dto.ReviewCommentRequestDto;
+import shop.alien.entity.store.dto.ReviewReplyDto;
+import shop.alien.entity.store.vo.LifeUserOrderCommentVo;
+import shop.alien.entity.store.vo.OrderReviewDetailVo;
+import shop.alien.entity.store.vo.OrderReviewVo;
+import shop.alien.entity.store.vo.ReviewCommentVo;
+import shop.alien.entity.store.vo.StoreCommentCountVo;
+import shop.alien.entity.store.vo.StoreCommentVo;
+import shop.alien.entity.store.vo.StoreCommitPercentVo;
+import shop.alien.lawyer.service.StoreCommentService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 评论表 前端控制器
+ *
+ * @author ssk
+ * @since 2025-01-02
+ */
+@Slf4j
+@Api(tags = {"二期-评论/评价"})
+@ApiSort(11)
+@CrossOrigin
+@RestController
+@RequestMapping("/storeComment")
+@RequiredArgsConstructor
+public class StoreCommentController {
+
+    private final StoreCommentService storeCommentService;
+
+    @ApiOperation("评论/评价列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "pageSize", value = "页容", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价, 6:订单评论的评论)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "replyStatus", value = "回复状态(0:全部, 1:已回复, 2:未回复)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "commentLevel", value = "评论等级(0:全部, 1:好评, 2:中评, 3:差评)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "days", value = "查询时间, 多少天前", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "phoneId", value = "消息标识", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "userType", value = "评论的用户类型(0:商家, 其他:用户)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "tagId", value = "标签id)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "hasImage", value = "是否有图片(0否/1是)", dataType = "Boolean", paramType = "query")
+    })
+    @GetMapping("/getList")
+    public R<IPage<StoreCommentVo>> getList(Integer pageNum, Integer pageSize, Integer businessId, Integer businessType, Integer storeId, Integer replyStatus, Integer commentLevel, Integer days, String phoneId, Integer userType, Integer tagId,@RequestParam(required = false, defaultValue = "false") Boolean hasImage) {
+        log.info("StoreCommentController.getList?pageNum={}&pageSize={}&businessId={}&businessType={}&storeId={}&replyStatus={}&commentLevel={}&days={}&phoneId={}&userType={}&tagId={}&hasImage={}", pageNum, pageSize, businessId, businessType, storeId, replyStatus, commentLevel, days, phoneId, userType, tagId, hasImage);
+        return R.data(storeCommentService.getList(pageNum, pageSize, businessId, businessType, storeId, replyStatus, commentLevel, days, phoneId, userType, tagId, hasImage));
+    }
+
+    @ApiOperation("获取最新一条评论/评价")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "userType", value = "用户类型(0:商家, 其他:用户)", dataType = "String", paramType = "query")
+    })
+    @GetMapping("/getOne")
+    public R<StoreCommentVo> getOne(Integer businessId, Integer businessType, Integer storeId) {
+        log.info("StoreCommentController.getOne?businessId={}&businessType={}&storeId={}", businessId, businessType, storeId);
+        return R.data(storeCommentService.getOne(businessId, businessType, storeId));
+    }
+
+    @ApiOperation("评论/评价数量和评分")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "String", paramType = "query")
+    })
+    @GetMapping("/getCommitCountAndScore")
+    public R<Map<String, Object>> getCommitCountAndScore(Integer businessId, Integer businessType, Integer storeId, String phoneId, Integer days) {
+        log.info("StoreCommentController.getCommitCountAndScore?businessId={}&businessType={}&storeId={}&phoneId={}&days={}", businessId, businessType, storeId, phoneId, days);
+        return R.data(storeCommentService.getCommitCountAndScore(businessId, businessType, storeId, phoneId, days));
+    }
+
+    @ApiOperation(value = "新增评论(旧)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @ApiImplicitParams({@ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query"),
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query")
+    })
+    @PostMapping("/userComment")
+    public R<Integer> userComment(MultipartRequest multipartRequest,
+                                  Integer businessId,
+                                  Integer businessType,
+                                  Integer storeId,
+                                  Integer userId,
+                                  Integer replyId,
+                                  String commentContent) {
+        log.info("StoreCommentController.userComment?businessId={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}", businessId, businessType, storeId, userId, replyId, commentContent);
+        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+        log.info(String.valueOf(fileNameSet.size()));
+        return R.data(storeCommentService.userComment(multipartRequest, businessId, businessType, storeId, userId, replyId, commentContent));
+    }
+
+    @ApiOperation(value = "新增或修改评论/评价", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query"),
+            @ApiImplicitParam(name = "id", value = "主键", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "score", value = "评分", dataType = "Double", paramType = "query"),
+            @ApiImplicitParam(name = "otherScore", value = "其他评分", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "isAnonymous", value = "是否匿名(0:否(默认), 1:是)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "evaluationTags", value = "评价标签", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
+    })
+    @PostMapping("/saveComment")
+    public R<Integer> saveComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
+        log.info("StoreCommentController.saveComment?id={}&businessId={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}&evaluationTags={}&phoneId={}", id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId);
+        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+        log.info(String.valueOf(fileNameSet.size()));
+        return R.data(storeCommentService.addComment(multipartRequest, id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
+    }
+
+    @ApiOperation(value = "新增或修改评论/评价(new)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query"),
+            @ApiImplicitParam(name = "id", value = "主键", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "orderId", value = "订单id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "lawyerId", value = "律师id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "score", value = "评分", dataType = "Double", paramType = "query"),
+            @ApiImplicitParam(name = "otherScore", value = "其他评分", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "isAnonymous", value = "是否匿名(0:否(默认), 1:是)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "evaluationTags", value = "评价标签", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
+    })
+    @PostMapping("/saveCommentNew")
+    public R<Integer> saveCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
+        log.info("StoreCommentController.saveCommentNew?id={}&businessId={}&businessType={}&storeId={}&orderId={}&lawyerId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}&evaluationTags={}&phoneId={}", id, businessId, businessType, storeId, orderId, lawyerId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId);
+        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+        log.info(String.valueOf(fileNameSet.size()));
+        return R.data(storeCommentService.addCommentNew(multipartRequest, id, businessId, businessType, storeId, orderId, lawyerId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
+    }
+
+    @ApiOperation(value = "回复率, 评价比例")
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/getCommitPercent")
+    public R<StoreCommitPercentVo> getCommitPercent(@RequestParam("storeId") Integer storeId) {
+        return R.data(storeCommentService.getCommitPercent(storeId));
+    }
+
+    @ApiOperation(value = "删除评论/评价")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "评论主键", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/delete")
+    public R<Boolean> delete(Integer id) {
+        if (storeCommentService.removeById(id)) {
+            return R.success("删除成功");
+        }
+        return R.fail("删除失败");
+    }
+
+    @ApiOperation("未评价/已评价列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "pageSize", value = "页容", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "type", value = "1:未评价, 2:已评价", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "String", paramType = "query", required = true),
+    })
+    @GetMapping("/getCommentOrderPage")
+    public R<IPage<LifeUserOrderCommentVo>> getCommentOrderPage(Integer pageNum, Integer pageSize, Integer type, String userId) {
+        log.info("StoreCommentController.getCommentOrderPage?pageNum={}&pageSize={}&type={}&userId={}", pageNum, pageSize, type, userId);
+        return R.data(storeCommentService.getCommentOrderPage(pageNum, pageSize, type, userId));
+    }
+
+    @ApiOperation("获取店铺评价计数统计")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getAppraiseCount")
+    public R<StoreCommentCountVo> getAppraiseCount(@RequestParam("storeId") Integer storeId) {
+        log.info("StoreCommentController.getAppraiseCount?storeId={}", storeId);
+        return R.data(storeCommentService.getAppraiseCount(storeId));
+    }
+
+    // ==================== 订单评价相关接口(迁移自 OrderReviewController)====================
+
+    @ApiOperation("创建订单评价(只有订单用户才能评价)")
+    @ApiOperationSupport(order = 20)
+    @PostMapping("/orderReview/create")
+    public R<StoreComment> createOrderReview(@RequestBody OrderReviewDto reviewDto) {
+        log.info("StoreCommentController.createOrderReview?reviewDto={}", reviewDto);
+        if (reviewDto.getUserId() == null) {
+            return R.fail("用户未登录");
+        }
+        return storeCommentService.createOrderReview(reviewDto);
+    }
+
+    @ApiOperation("获取评价详情(包含评论和回复)")
+    @ApiOperationSupport(order = 21)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/orderReview/detail")
+    public R<OrderReviewDetailVo> getOrderReviewDetail(
+            @RequestParam Integer reviewId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("StoreCommentController.getOrderReviewDetail?reviewId={}, currentUserId={}", reviewId, currentUserId);
+        if (reviewId == null) {
+            return R.fail("评价ID不能为空");
+        }
+        return storeCommentService.getOrderReviewDetail(reviewId, currentUserId);
+    }
+
+    @ApiOperation("点赞评价")
+    @ApiOperationSupport(order = 22)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/orderReview/like")
+    public R<Boolean> likeOrderReview(@RequestBody StoreComment storeComment) {
+        Integer reviewId = storeComment.getId();
+        Integer userId = storeComment.getUserId();
+        log.info("StoreCommentController.likeOrderReview?reviewId={}, userId={}", reviewId, userId);
+        if (userId == null) {
+            return R.fail("用户未登录");
+        }
+        if (reviewId == null) {
+            return R.fail("评价ID不能为空");
+        }
+        return storeCommentService.likeOrderReview(reviewId, userId);
+    }
+
+    @ApiOperation("取消点赞评价")
+    @ApiOperationSupport(order = 23)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/orderReview/cancelLike")
+    public R<Boolean> cancelLikeOrderReview(@RequestBody StoreComment storeComment) {
+        Integer reviewId = storeComment.getId();
+        Integer userId = storeComment.getUserId();
+        log.info("StoreCommentController.cancelLikeOrderReview?reviewId={}, userId={}", reviewId, userId);
+        if (userId == null) {
+            return R.fail("用户未登录");
+        }
+        return storeCommentService.cancelLikeOrderReview(reviewId, userId);
+    }
+
+    @ApiOperation("分页查询评价列表")
+    @ApiOperationSupport(order = 24)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "页数(默认1)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "size", value = "页容(默认10)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "orderId", value = "订单ID", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "lawyerUserId", value = "律师用户ID", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "评价用户ID", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/orderReview/list")
+    public R<IPage<OrderReviewVo>> getOrderReviewList(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "10") int size,
+            @RequestParam(required = false) Integer orderId,
+            @RequestParam(required = false) Integer lawyerUserId,
+            @RequestParam(required = false) Integer userId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("StoreCommentController.getOrderReviewList?page={}, size={}, orderId={}, lawyerUserId={}, userId={}, currentUserId={}",
+                page, size, orderId, lawyerUserId, userId, currentUserId);
+        return storeCommentService.getOrderReviewList(page, size, orderId, lawyerUserId, userId, currentUserId);
+    }
+
+    @ApiOperation("根据订单ID查询评价")
+    @ApiOperationSupport(order = 25)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "orderId", value = "订单ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/orderReview/getByOrderId")
+    public R<OrderReviewVo> getOrderReviewByOrderId(
+            @RequestParam Integer orderId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("StoreCommentController.getOrderReviewByOrderId?orderId={}, currentUserId={}", orderId, currentUserId);
+        return storeCommentService.getOrderReviewByOrderId(orderId, currentUserId);
+    }
+
+    // ==================== 评价评论相关接口(迁移自 ReviewCommentController)====================
+
+    @ApiOperation("创建评论(其他用户对评价的评论)")
+    @ApiOperationSupport(order = 30)
+    @PostMapping("/reviewComment/create")
+    public R<StoreComment> createReviewComment(@RequestBody StoreComment comment) {
+        log.info("StoreCommentController.createReviewComment?comment={}", comment);
+        if (comment.getUserId() == null) {
+            return R.fail("用户未登录");
+        }
+        return storeCommentService.createReviewComment(comment);
+    }
+
+    @ApiOperation("根据评价ID查询评论列表")
+    @ApiOperationSupport(order = 31)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/reviewComment/list")
+    public R<List<ReviewCommentVo>> getReviewCommentListByReviewId(
+            @RequestParam Integer reviewId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("StoreCommentController.getReviewCommentListByReviewId?reviewId={}, currentUserId={}", reviewId, currentUserId);
+        return storeCommentService.getReviewCommentListByReviewId(reviewId, currentUserId);
+    }
+
+    @ApiOperation("点赞评论")
+    @ApiOperationSupport(order = 32)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "commentId", value = "评论ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/reviewComment/like")
+    public R<Boolean> likeReviewComment(@RequestBody ReviewCommentRequestDto requestDto) {
+        log.info("StoreCommentController.likeReviewComment?commentId={}, userId={}", requestDto.getCommentId(), requestDto.getUserId());
+        if (requestDto.getUserId() == null) {
+            return R.fail("用户未登录");
+        }
+        if (requestDto.getCommentId() == null) {
+            return R.fail("评论ID不能为空");
+        }
+        return storeCommentService.likeReviewComment(requestDto);
+    }
+
+    @ApiOperation("取消点赞评论")
+    @ApiOperationSupport(order = 33)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "commentId", value = "评论ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/reviewComment/cancelLike")
+    public R<Boolean> cancelLikeReviewComment(@RequestBody ReviewCommentRequestDto requestDto) {
+        log.info("StoreCommentController.cancelLikeReviewComment?commentId={}, userId={}", requestDto.getCommentId(), requestDto.getUserId());
+        if (requestDto.getUserId() == null) {
+            return R.fail("用户未登录");
+        }
+        if (requestDto.getCommentId() == null) {
+            return R.fail("评论ID不能为空");
+        }
+        return storeCommentService.cancelLikeReviewComment(requestDto);
+    }
+
+    @ApiOperation("创建回复(用户对评论的回复)")
+    @ApiOperationSupport(order = 34)
+    @PostMapping("/reviewComment/reply/create")
+    public R<StoreComment> createReviewReply(@RequestBody ReviewReplyDto replyDto) {
+        log.info("StoreCommentController.createReviewReply?replyDto={}", replyDto);
+        if (replyDto.getUserId() == null) {
+            return R.fail("用户未登录");
+        }
+        return storeCommentService.createReviewReply(replyDto);
+    }
+
+    @ApiOperation("根据首评ID查询回复列表")
+    @ApiOperationSupport(order = 35)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "headId", value = "首评ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/reviewComment/reply/list")
+    public R<List<ReviewCommentVo>> getReviewReplyListByHeadId(
+            @RequestParam Integer headId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("StoreCommentController.getReviewReplyListByHeadId?headId={}, currentUserId={}", headId, currentUserId);
+        return storeCommentService.getReviewReplyListByHeadId(headId, currentUserId);
+    }
+
+    @ApiOperation("删除回复")
+    @ApiOperationSupport(order = 36)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "replyId", value = "回复ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/reviewComment/reply/delete")
+    public R<Boolean> deleteReviewReply(
+            @RequestParam Integer replyId,
+            @RequestParam Integer userId) {
+        log.info("StoreCommentController.deleteReviewReply?replyId={}, userId={}", replyId, userId);
+        if (userId == null) {
+            return R.fail("用户未登录");
+        }
+        return storeCommentService.deleteReviewReply(replyId, userId);
+    }
+}

+ 264 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/StoreCommentService.java

@@ -0,0 +1,264 @@
+package shop.alien.lawyer.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreComment;
+import shop.alien.entity.store.dto.OrderReviewDto;
+import shop.alien.entity.store.dto.ReviewCommentRequestDto;
+import shop.alien.entity.store.dto.ReviewReplyDto;
+import shop.alien.entity.store.vo.LifeUserOrderCommentVo;
+import shop.alien.entity.store.vo.OrderReviewDetailVo;
+import shop.alien.entity.store.vo.OrderReviewVo;
+import shop.alien.entity.store.vo.ReviewCommentVo;
+import shop.alien.entity.store.vo.StoreCommentCountVo;
+import shop.alien.entity.store.vo.StoreCommentVo;
+import shop.alien.entity.store.vo.StoreCommitPercentVo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 评论表 服务类
+ *
+ * @author ssk
+ * @since 2025-01-02
+ */
+public interface StoreCommentService extends IService<StoreComment> {
+
+    /**
+     * 评论列表
+     *
+     * @param pageNum      页数
+     * @param pageSize     页容
+     * @param businessId   业务id
+     * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价, 6:订单评论的评论)
+     * @param storeId      门店id
+     * @param replyStatus  回复状态(0:全部, 1:已回复, 2:未回复)
+     * @param commentLevel 评论等级(0:全部, 1:好评, 2:中评, 3:差评)
+     * @param days         查询时间, 多少天前
+     * @param phoneId      消息标识
+     * @param userType     评论的用户类型(0:商家, 其他:用户)
+     * @param tagId        标签id
+     * @param hasImage     是否有图片(0否/1是)
+     * @return IPage<StoreComment>
+     */
+    IPage<StoreCommentVo> getList(Integer pageNum, Integer pageSize, Integer businessId, Integer businessType, Integer storeId, Integer replyStatus, Integer commentLevel, Integer days, String phoneId, Integer userType, Integer tagId, Boolean hasImage);
+
+    /**
+     * 获取最新一条评论/评价
+     *
+     * @param businessId   业务id
+     * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId      门店id
+     * @return StoreCommentVo
+     */
+    StoreCommentVo getOne(Integer businessId, Integer businessType, Integer storeId);
+
+    /**
+     * 评论/评价数量和评分
+     *
+     * @param businessId   业务id
+     * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId      门店id
+     * @return Integer
+     */
+    Map<String, Object> getCommitCountAndScore(Integer businessId, Integer businessType, Integer storeId, String phoneId, Integer days);
+
+    /**
+     * 评论
+     *
+     * @param multipartRequest 文件
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    Integer userComment(MultipartRequest multipartRequest, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent);
+
+    /**
+     * 新增或修改评论/评价
+     *
+     * @param multipartRequest 文件
+     * @param id               主键
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @param evaluationTags   评价标签
+     * @param phoneId          用户id
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
+
+    /**
+     * 新增或修改评论/评价
+     *
+     * @param multipartRequest 文件
+     * @param id               主键
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @param evaluationTags   评价标签
+     * @param phoneId          用户id
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
+
+    /**
+     * 回复率, 评价比例
+     *
+     * @param storeId 门店id
+     * @return StoreCommitPercentVo
+     */
+    StoreCommitPercentVo getCommitPercent(Integer storeId);
+
+    /**
+     * @param type 1:未评价, 2:已评价
+     */
+    IPage<LifeUserOrderCommentVo> getCommentOrderPage(Integer pageNum, Integer pageSize, Integer type, String userId);
+
+    /**
+     * 获取店铺评价计数统计
+     *
+     * @param storeId 门店id
+     * @return StoreCommentCountVo
+     */
+    StoreCommentCountVo getAppraiseCount(Integer storeId);
+
+    // ==================== 订单评价相关方法(迁移自 OrderReviewService)====================
+
+    /**
+     * 创建订单评价(只有订单用户才能评价)
+     *
+     * @param reviewDto 评价DTO
+     * @return R<StoreComment>
+     */
+    R<StoreComment> createOrderReview(OrderReviewDto reviewDto);
+
+    /**
+     * 获取评价详情(包含评论和回复)
+     *
+     * @param reviewId 评价ID
+     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
+     * @return R<OrderReviewDetailVo>
+     */
+    R<OrderReviewDetailVo> getOrderReviewDetail(Integer reviewId, Integer currentUserId);
+
+    /**
+     * 点赞评价
+     *
+     * @param reviewId 评价ID
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> likeOrderReview(Integer reviewId, Integer userId);
+
+    /**
+     * 取消点赞评价
+     *
+     * @param reviewId 评价ID
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> cancelLikeOrderReview(Integer reviewId, Integer userId);
+
+    /**
+     * 分页查询评价列表
+     *
+     * @param page 页码
+     * @param size 页大小
+     * @param orderId 订单ID(可选)
+     * @param lawyerUserId 律师用户ID(可选)
+     * @param userId 评价用户ID(可选)
+     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
+     * @return R<IPage<OrderReviewVo>>
+     */
+    R<IPage<OrderReviewVo>> getOrderReviewList(int page, int size, Integer orderId, Integer lawyerUserId, Integer userId, Integer currentUserId);
+
+    /**
+     * 根据订单ID查询评价
+     *
+     * @param orderId 订单ID
+     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
+     * @return R<OrderReviewVo>
+     */
+    R<OrderReviewVo> getOrderReviewByOrderId(Integer orderId, Integer currentUserId);
+
+    // ==================== 评价评论相关方法(迁移自 ReviewCommentService)====================
+
+    /**
+     * 创建评论(其他用户对评价的评论)
+     *
+     * @param comment 评论实体
+     * @return R<StoreComment>
+     */
+    R<StoreComment> createReviewComment(StoreComment comment);
+
+    /**
+     * 根据评价ID查询评论列表
+     *
+     * @param reviewId 评价ID
+     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
+     * @return R<List<ReviewCommentVo>>
+     */
+    R<List<ReviewCommentVo>> getReviewCommentListByReviewId(Integer reviewId, Integer currentUserId);
+
+    /**
+     * 点赞评论
+     *
+     * @param requestDto 请求DTO
+     * @return R<Boolean>
+     */
+    R<Boolean> likeReviewComment(ReviewCommentRequestDto requestDto);
+
+    /**
+     * 取消点赞评论
+     *
+     * @param requestDto 请求DTO
+     * @return R<Boolean>
+     */
+    R<Boolean> cancelLikeReviewComment(ReviewCommentRequestDto requestDto);
+
+    /**
+     * 创建回复(用户对评论的回复)
+     *
+     * @param replyDto 回复DTO
+     * @return R<StoreComment>
+     */
+    R<StoreComment> createReviewReply(ReviewReplyDto replyDto);
+
+    /**
+     * 根据首评ID查询回复列表
+     *
+     * @param headId 首评ID
+     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
+     * @return R<List<ReviewCommentVo>>
+     */
+    R<List<ReviewCommentVo>> getReviewReplyListByHeadId(Integer headId, Integer currentUserId);
+
+    /**
+     * 删除回复
+     *
+     * @param replyId 回复ID
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> deleteReviewReply(Integer replyId, Integer userId);
+
+}

+ 1728 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/StoreCommentServiceImpl.java

@@ -0,0 +1,1728 @@
+package shop.alien.lawyer.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+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.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+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.Lists;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.dto.OrderReviewDto;
+import shop.alien.entity.store.dto.ReviewCommentRequestDto;
+import shop.alien.entity.store.dto.ReviewReplyDto;
+import shop.alien.entity.store.vo.*;
+import shop.alien.lawyer.config.WebSocketProcess;
+import shop.alien.lawyer.service.StoreCommentService;
+import shop.alien.lawyer.service.StoreImgService;
+import shop.alien.lawyer.util.FileUploadUtil;
+import shop.alien.mapper.*;
+import shop.alien.util.common.DateUtils;
+import shop.alien.util.common.netease.ImageCheckUtil;
+import shop.alien.util.common.netease.TextCheckUtil;
+import shop.alien.util.common.safe.TextModerationResultVO;
+import shop.alien.util.common.safe.TextModerationUtil;
+import shop.alien.util.common.safe.TextReviewServiceEnum;
+
+import java.io.IOException;
+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 ssk
+ * @since 2025-01-02
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, StoreComment> implements StoreCommentService {
+
+    private final StoreCommentMapper storeCommentMapper;
+
+    private final LifeLikeRecordMapper lifeLikeRecordMapper;
+
+    private final FileUploadUtil fileUploadUtil;
+
+    private final StoreImgMapper storeImgMapper;
+
+    private final LifeUserViolationMapper lifeUserViolationMapper;
+
+    private final StoreUserMapper storeUserMapper;
+
+    private final LifeUserMapper lifeUserMapper;
+
+    private final StoreCommentAppealMapper storeCommentAppealMapper;
+
+    private final StoreInfoMapper storeInfoMapper;
+
+    private final LifeNoticeMapper lifeNoticeMapper;
+
+    private final WebSocketProcess webSocketProcess;
+
+    private final TagsSynonymMapper tagsSynonymMapper;
+
+    private final LifeUserOrderMapper lifeUserOrderMapper;
+
+    private final LawyerConsultationOrderMapper lawyerConsultationOrderMapper;
+    private final LawyerUserMapper lawyerUserMapper;
+
+    @Autowired
+    private TextModerationUtil textModerationUtil;
+    @Autowired
+    private StoreImgService storeImgService;
+
+    /**
+     * 评论列表
+     *
+     * @param pageNum      页数
+     * @param pageSize     页容
+     * @param businessId   业务id
+     * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价, 6:订单评论的评论)
+     * @param storeId      门店id
+     * @param replyStatus  回复状态(0:全部, 1:已回复, 2:未回复)
+     * @param commentLevel 评论等级(0:全部, 1:好评, 2:中评, 3:差评)
+     * @param days         查询时间, 多少天前
+     * @param phoneId      消息标识
+     * @param userType     评论的用户类型(0:商家, 其他:用户)
+     * @param tagId        标签id
+     * @param hasImage     是否有图片(0否/1是)
+     * @return IPage<StoreComment>
+     */
+    @Override
+    public IPage<StoreCommentVo> getList(Integer pageNum, Integer pageSize, Integer businessId, Integer businessType, Integer storeId, Integer replyStatus, Integer commentLevel, Integer days, String phoneId, Integer userType, Integer tagId, Boolean hasImage) {
+        IPage<StoreCommentVo> storeCommentIPage = new Page<>(pageNum, pageSize);
+        QueryWrapper<StoreCommentVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(null != businessId, "a.business_id", businessId);
+        queryWrapper.eq(null != businessType, "a.business_type", businessType);
+        queryWrapper.eq(null != storeId, "a.store_id", storeId);
+        //好评 a>=4
+        queryWrapper.ge(null != commentLevel && 1 == commentLevel, "a.score", 4.5);
+        //中评 a>=2&& a<4
+        queryWrapper.ge(null != commentLevel && 2 == commentLevel, "a.score", 3).le(null != commentLevel && 2 == commentLevel, "a.score", 4);
+        //差评 a<2
+        queryWrapper.ge(null != commentLevel && 3 == commentLevel, "a.score", 0.5).le(null != commentLevel && 3 == commentLevel, "a.score", 2.5);
+        if (null != days) {
+            Date date = DateUtils.calcDays(new Date(), -days);
+            queryWrapper.ge("a.created_time", DateUtils.formatDate(date, "yyyy-MM-dd"));
+        }
+        //通过当前登录人id 类型 查询举报业务id
+        List<LifeUserViolation> lifeUserViolations = new ArrayList<>();
+        if(businessType==2){
+            String userId;
+            if(phoneId.startsWith("store_")){
+                userId = phoneId.substring("store_".length());
+                StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getPhone,userId));
+                if(storeUser!=null){
+                    LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,storeUser.getId());
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,1);
+                    lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
+                    lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
+                }
+            }else{
+                userId = phoneId.substring("user_".length());
+                LifeUser lifeUser = lifeUserMapper.selectOne(new LambdaQueryWrapper<LifeUser>().eq(LifeUser::getUserPhone,userId));
+                if(lifeUser!=null){
+                    LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,lifeUser.getId());
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,2);
+                    lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
+                    lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
+                }
+            }
+        }
+        List<Integer> businessIds = lifeUserViolations.stream()
+                .filter(Objects::nonNull)
+                .map(LifeUserViolation::getBusinessId)
+                .filter(id -> id != null && !id.toString().isEmpty())
+                .collect(Collectors.toList());
+        if(businessIds!=null && businessIds.size()>0){
+            queryWrapper.notIn("a.id",businessIds);
+        }
+
+        //根据标签id查询表签字表拿到评论ids
+        if(tagId !=null){
+            List<TagsSynonym> tagsSynonymList = tagsSynonymMapper.selectList(new LambdaQueryWrapper<TagsSynonym>().eq(TagsSynonym::getMainTagId,tagId));
+            if(CollectionUtils.isNotEmpty(tagsSynonymList)){
+                List<Integer> commentIdList = tagsSynonymList.stream().filter(synonym -> synonym != null)
+                        .map(TagsSynonym::getCommentId).filter(commentId -> commentId != null).collect(Collectors.toList());
+                queryWrapper.in("a.id",commentIdList);
+            }
+        }
+
+        //先查询父级评论
+        queryWrapper.isNull(businessType != 1, "a.reply_id").eq("a.delete_flag", 0).orderByDesc("a.created_time");
+        IPage<StoreCommentVo> page = storeCommentMapper.getCommentPage(storeCommentIPage, queryWrapper);
+        List<StoreCommentVo> records = page.getRecords();
+        List<StoreCommentVo> storeCommentVoList = new ArrayList<>();
+
+        //评价图片
+        Set<Integer> imgIdList = new HashSet<>();
+        for (int i = 0; i < records.size(); i++) {
+            StoreCommentVo storeCommentVo = new StoreCommentVo();
+            BeanUtils.copyProperties(records.get(i), storeCommentVo);
+            //首评
+            storeCommentVo.setFirstComment(i == 0);
+            //有无图片
+            if (records.get(i).getImgId() != null) {
+                storeCommentVo.setHasImage(true);
+                String[] split = records.get(i).getImgId().split(",");
+                for (String s : split) {
+                    imgIdList.add(Integer.parseInt(s));
+                }
+            } else {
+                storeCommentVo.setHasImage(false);
+            }
+            //低分
+            storeCommentVo.setLowScore(records.get(i).getScore() <= 1);
+
+            QueryWrapper<StoreCommentAppealVo> storeCommentAppealVoQueryWrapper = new QueryWrapper<>();
+            storeCommentAppealVoQueryWrapper.eq("a.comment_id", storeCommentVo.getId()).eq("a.delete_flag", 0).orderByDesc("a.created_time").last("limit 1");
+            StoreCommentAppealVo commentDetail = storeCommentAppealMapper.getCommentDetail(storeCommentAppealVoQueryWrapper);
+            if (ObjectUtils.isNotEmpty(commentDetail)) {
+                storeCommentVo.setAppealFlag(1);
+                storeCommentVo.setAppealStatusStr(commentDetail.getAppealStatusStr());
+                storeCommentVo.setAppealStatus(commentDetail.getAppealStatus());
+            }else {
+                storeCommentVo.setAppealFlag(0);
+            }
+
+            //商家用户
+            if (StringUtils.isNotEmpty(records.get(i).getPhoneId())) {
+                if (records.get(i).getPhoneId().contains("store_")) {
+                    storeCommentVo.setStoreUserFlag(0);
+                    StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, records.get(i).getStoreId()));
+                    storeCommentVo.setStoreUserName(storeUser.getName());
+                    storeCommentVo.setStoreUserImg(storeUser.getHeadImg());
+                } else {
+                    storeCommentVo.setStoreUserFlag(1);
+                }
+            }
+            StoreInfo storeInfo = storeInfoMapper.selectById(records.get(i).getStoreId());
+            if (storeInfo != null) {
+                storeCommentVo.setStoreName(storeInfo.getStoreName());
+            }
+            storeCommentVoList.add(storeCommentVo);
+        }
+
+        //塞图片
+        if (!imgIdList.isEmpty()) {
+            List<StoreImg> storeImgList = storeImgMapper.selectList(new QueryWrapper<StoreImg>().in("id", imgIdList));
+
+            storeCommentVoList.forEach(storeCommentVo -> {
+                if (null != storeCommentVo.getImgId()) {
+                    storeCommentVo.setImgUrl(new ArrayList<>());
+                    for (StoreImg storeImg : storeImgList) {
+                        for (String s : storeCommentVo.getImgId().split(",")) {
+                            if (storeImg.getId().equals(Integer.parseInt(s))) {
+                                storeCommentVo.getImgUrl().add(storeImg.getImgUrl());
+                            }
+                        }
+                    }
+                }
+            });
+        }
+
+        //父级评论下拼接子评论
+        for (StoreCommentVo storeCommentVo : storeCommentVoList) {
+            storeCommentVo.setCommitCount(0);
+            //父级点赞状态
+            if (StringUtils.isNotEmpty(phoneId)) {
+                LambdaQueryWrapper<LifeLikeRecord> likeRecordQueryWrapper = new LambdaQueryWrapper<>();
+                likeRecordQueryWrapper.eq(LifeLikeRecord::getDianzanId, phoneId).eq(LifeLikeRecord::getHuifuId, storeCommentVo.getId());
+                Integer i = lifeLikeRecordMapper.selectCount(likeRecordQueryWrapper);
+                if (i > 0) {
+                    storeCommentVo.setIsLike(1);
+                } else {
+                    storeCommentVo.setIsLike(0);
+                }
+            }
+            QueryWrapper<StoreCommentVo> childQueryWrapper = new QueryWrapper<>();
+            if(businessIds!=null && businessIds.size()>0){
+                childQueryWrapper.notIn("a.id",businessIds);
+            }
+            childQueryWrapper.eq(null != businessId && 6 == businessId, "a.business_id", businessId).eq("a.delete_flag", 0).eq("a.reply_id", storeCommentVo.getId()).orderByDesc("a.created_time");
+            List<StoreCommentVo> childCommentList = storeCommentMapper.getCommentList(childQueryWrapper);
+            storeCommentVo.setCommitCount(storeCommentVo.getCommitCount() + childCommentList.size());
+            //评价的评论的评论
+            childCommentList.forEach(child -> {
+                QueryWrapper<StoreCommentVo> childQueryCommentWrapper = new QueryWrapper<>();
+                childQueryCommentWrapper
+//                        .eq(null != businessId && 6 == businessId, "a.business_id", businessId)
+                        .eq("a.delete_flag", 0).eq("a.reply_id", child.getId()).orderByDesc("a.created_time");
+                List<StoreCommentVo> childComment2List = storeCommentMapper.getCommentList(childQueryCommentWrapper);
+
+                //商家用户
+                for (StoreCommentVo commentVo : childComment2List) {
+                    if (StringUtils.isNotEmpty(commentVo.getPhoneId())) {
+                        if (commentVo.getPhoneId().contains("store_")) {
+                            commentVo.setStoreUserFlag(0);
+                            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, child.getStoreId()));
+                            commentVo.setStoreUserName(storeUser.getName());
+                            commentVo.setStoreUserImg(storeUser.getHeadImg());
+                        } else {
+                            commentVo.setStoreUserFlag(1);
+                        }
+                    }
+                }
+
+                child.setStoreComment(childComment2List);
+                storeCommentVo.setCommitCount(storeCommentVo.getCommitCount() + childComment2List.size());
+
+                //商家用户
+                if (StringUtils.isNotEmpty(child.getPhoneId())) {
+                    if (child.getPhoneId().contains("store_")) {
+                        child.setStoreUserFlag(0);
+                        StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, child.getStoreId()));
+                        child.setStoreUserName(storeUser.getName());
+                        child.setStoreUserImg(storeUser.getHeadImg());
+                    } else {
+                        child.setStoreUserFlag(1);
+                    }
+                }
+
+            });
+            //筛选商家评论
+            List<StoreCommentVo> storeCommentList = new ArrayList<>();
+            if (null != userType && userType == 0) {
+                List<StoreCommentVo> collect = childCommentList.stream().filter(childComment -> childComment.getPhoneId().contains("store_")).collect(Collectors.toList());
+                if (!collect.isEmpty()) {
+                    storeCommentList.add(collect.get(0));
+                    storeCommentVo.setStoreComment(storeCommentList);
+                }
+            } else {
+                storeCommentVo.setStoreComment(childCommentList);
+            }
+            //子级点赞状态
+            if (StringUtils.isNotEmpty(phoneId)) {
+                childCommentList.forEach(child -> {
+                    LambdaQueryWrapper<LifeLikeRecord> childlikeRecordQueryWrapper = new LambdaQueryWrapper<>();
+                    childlikeRecordQueryWrapper.eq(LifeLikeRecord::getDianzanId, phoneId).eq(LifeLikeRecord::getHuifuId, child.getId());
+                    if (lifeLikeRecordMapper.selectCount(childlikeRecordQueryWrapper) > 0) {
+                        child.setIsLike(1);
+                    } else {
+                        child.setIsLike(0);
+                    }
+                });
+            }
+        }
+        IPage<StoreCommentVo> resultPage = new Page<>();
+        resultPage.setCurrent(page.getCurrent());
+        resultPage.setSize(page.getSize());
+        resultPage.setTotal(page.getTotal());
+        resultPage.setPages(page.getPages());
+        //筛选有无评论
+        List<StoreCommentVo> collect = new ArrayList<>();
+        if (replyStatus != null) {
+            if (1 == replyStatus) {
+                //只查询有回复的评论
+                collect = storeCommentVoList.stream().filter(storeCommentVo -> ObjectUtils.isNotEmpty(storeCommentVo.getStoreComment())).collect(Collectors.toList());
+            } else if (2 == replyStatus) {
+                //只查询无回复的评论
+                collect = storeCommentVoList.stream().filter(storeCommentVo -> ObjectUtils.isEmpty(storeCommentVo.getStoreComment())).collect(Collectors.toList());
+            } else {
+                collect = storeCommentVoList;
+            }
+        }
+//        collect.forEach(item -> {
+//            item.setCommitCount(null != item.getStoreComment() ? item.getStoreComment().size() : 0);
+//        });
+        resultPage.setRecords(collect);
+        return resultPage;
+    }
+
+    /**
+     * 获取最新一条评论/评价
+     *
+     * @param businessId   业务id
+     * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId      门店id
+     * @return StoreCommentVo
+     */
+    @Override
+    public StoreCommentVo getOne(Integer businessId, Integer businessType, Integer storeId) {
+        AtomicReference<Integer> count = new AtomicReference<>(0);
+        QueryWrapper<StoreCommentVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(null != businessId, "a.business_id", businessId).eq(null != businessType, "a.business_type", businessType).eq(null != storeId, "a.store_id", storeId).eq("a.delete_flag", 0).orderByDesc("a.created_time");
+        List<StoreCommentVo> commentList = storeCommentMapper.getCommentList(queryWrapper);
+        count.updateAndGet(v -> v + commentList.size());
+        //父级评论下拼接子评论
+        for (StoreCommentVo storeCommentVo : commentList) {
+            QueryWrapper<StoreCommentVo> childQueryWrapper = new QueryWrapper<>();
+            childQueryWrapper.eq("a.delete_flag", 0).eq("a.reply_id", storeCommentVo.getId());
+            List<StoreCommentVo> childCommentList = storeCommentMapper.getCommentList(childQueryWrapper);
+            count.updateAndGet(v -> v + childCommentList.size());
+            //评价的评论的评论
+            childCommentList.forEach(child -> {
+                QueryWrapper<StoreCommentVo> childQueryCommentWrapper = new QueryWrapper<>();
+                childQueryCommentWrapper
+//                        .eq(null != businessId && 6 == businessId, "a.business_id", businessId)
+                        .eq("a.delete_flag", 0).eq("a.reply_id", child.getId()).orderByDesc("a.created_time");
+                List<StoreCommentVo> childComment2List = storeCommentMapper.getCommentList(childQueryCommentWrapper);
+                count.updateAndGet(v -> v + childComment2List.size());
+            });
+        }
+        if (!commentList.isEmpty()) {
+            StoreCommentVo storeCommentVo = commentList.get(0);
+            storeCommentVo.setCommitCount(Integer.parseInt(String.valueOf(count)));
+            return storeCommentVo;
+        }
+        return null;
+    }
+
+    /**
+     * 评论/评价数量和评分
+     *
+     * @param businessId   业务id
+     * @param businessType 业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId      门店id
+     * @return Integer
+     */
+    @Override
+    public Map<String, Object> getCommitCountAndScore(Integer businessId, Integer businessType, Integer storeId, String phoneId, Integer days) {
+        Map<String, Object> map = new HashMap<>();
+        AtomicReference<Integer> count = new AtomicReference<>(0);
+        QueryWrapper<StoreCommentVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(null != businessId, "a.business_id", businessId);
+        queryWrapper.eq(null != businessType, "a.business_type", businessType);
+        queryWrapper.eq(null != storeId, "a.store_id", storeId);
+
+        if (null != days) {
+            Date date = DateUtils.calcDays(new Date(), -days);
+            queryWrapper.ge("a.created_time", DateUtils.formatDate(date, "yyyy-MM-dd"));
+        }
+
+        //通过当前登录人id 类型 查询举报业务id
+        List<LifeUserViolation> lifeUserViolations = new ArrayList<>();
+        if(businessType==2){
+            String userId;
+            if(phoneId!=null && !phoneId.equals("") && phoneId.startsWith("store_")){
+                userId = phoneId.substring("store_".length());
+                StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getPhone,userId));
+                if(storeUser!=null){
+                    LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,storeUser.getId());
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,1);
+                    lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
+                    lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
+                }
+            }else if(phoneId!=null && !phoneId.equals("") && phoneId.startsWith("user_")){
+                userId = phoneId.substring("user_".length());
+                LifeUser lifeUser = lifeUserMapper.selectOne(new LambdaQueryWrapper<LifeUser>().eq(LifeUser::getUserPhone,userId));
+                if(lifeUser!=null){
+                    LambdaQueryWrapper<LifeUserViolation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserId,lifeUser.getId());
+                    lambdaQueryWrapper.eq(LifeUserViolation::getReportingUserType,2);
+                    lambdaQueryWrapper.ne(LifeUserViolation::getProcessingStatus,2);
+                    lifeUserViolations = lifeUserViolationMapper.selectList(lambdaQueryWrapper);
+                }
+            }
+        }
+
+        List<Integer> businessIds = lifeUserViolations.stream()
+                .filter(Objects::nonNull)
+                .map(LifeUserViolation::getBusinessId)
+                .filter(id -> id != null && !id.toString().isEmpty())
+                .collect(Collectors.toList());
+        if(businessIds!=null && businessIds.size()>0){
+            queryWrapper.notIn("a.id",businessIds);
+        }
+
+        //先查询父级评论
+        queryWrapper.isNull(businessType != 1, "a.reply_id").eq("a.delete_flag", 0).orderByDesc("a.created_time");
+        List<StoreCommentVo> storeCommentVoList = storeCommentMapper.getCommentList(queryWrapper);
+        count.updateAndGet(v -> v + storeCommentVoList.size());
+        //评分合计
+        Double sumScore = 0.0;
+        //父级评论下拼接子评论
+        for (StoreCommentVo storeCommentVo : storeCommentVoList) {
+            sumScore += storeCommentVo.getScore();
+            QueryWrapper<StoreCommentVo> childQueryWrapper = new QueryWrapper<>();
+            childQueryWrapper.eq("a.delete_flag", 0).eq("a.reply_id", storeCommentVo.getId());
+            List<StoreCommentVo> childCommentList = storeCommentMapper.getCommentList(childQueryWrapper);
+            count.updateAndGet(v -> v + childCommentList.size());
+            //评价的评论的评论
+            childCommentList.forEach(child -> {
+                QueryWrapper<StoreCommentVo> childQueryCommentWrapper = new QueryWrapper<>();
+                childQueryCommentWrapper
+//                        .eq(null != businessId && 6 == businessId, "a.business_id", businessId)
+                        .eq("a.delete_flag", 0).eq("a.reply_id", child.getId()).orderByDesc("a.created_time");
+                List<StoreCommentVo> childComment2List = storeCommentMapper.getCommentList(childQueryCommentWrapper);
+                count.updateAndGet(v -> v + childComment2List.size());
+            });
+        }
+        map.put("commitCount", count.toString());
+        map.put("img", storeCommentVoList.stream().filter(i -> i.getScore() >= 4.5).map(StoreCommentVo::getUserImage).distinct().limit(6).collect(Collectors.toList()));
+        if (sumScore == 0 || storeCommentVoList.isEmpty()) {
+            map.put("score", "0");
+        } else {
+            BigDecimal score = new BigDecimal(sumScore).divide(new BigDecimal(storeCommentVoList.size()), 2, BigDecimal.ROUND_HALF_UP);
+            map.put("score", score.toString());
+        }
+
+//        Map<String, Object> commentCountAndScore = storeCommentMapper.getCommentCountAndScore(businessId, businessType, storeId);
+//        Object scoreObj = commentCountAndScore.get("score");
+//        double scoreDouble = 0.0;
+//        if (scoreObj != null) {
+//            if (scoreObj instanceof Number) {
+//                scoreDouble = ((Number) scoreObj).doubleValue();
+//            } else if (scoreObj instanceof String) {
+//                scoreDouble = Double.parseDouble((String) scoreObj);
+//            }
+//        }
+//        if (scoreDouble == 0) {
+//            map.put("score", "0");
+//        } else {
+//            BigDecimal scoreBigDecimal = new BigDecimal(String.valueOf(scoreDouble)).divide(new BigDecimal(commentCountAndScore.get("rootCount").toString()), 2, BigDecimal.ROUND_HALF_UP);
+//            map.put("score", scoreBigDecimal.toString());
+//        }
+//        map.put("commitCount", commentCountAndScore.get("count").toString());
+        return map;
+    }
+
+    /**
+     * 评论
+     *
+     * @param multipartRequest 文件
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    @Override
+    public Integer userComment(MultipartRequest multipartRequest, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent) {
+        try {
+            Map<String, String> checkText = TextCheckUtil.check(commentContent);
+            if (null == checkText || checkText.get("result").equals("1")) {
+                return 2;
+            }
+            StoreComment storeComment = new StoreComment();
+            storeComment.setStoreId(storeId);
+            storeComment.setUserId(userId);
+            storeComment.setCommentContent(commentContent);
+            storeComment.setReplyId(replyId);
+            storeComment.setBusinessId(businessId);
+            storeComment.setBusinessType(businessType);
+            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
+            if (!fileNameSet.isEmpty()) {
+                StringBuilder imgId = new StringBuilder();
+                for (int i = 0; i < fileNameSet.size(); i++) {
+                    MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
+                    if (null != multipartFile) {
+                        byte[] fileByte;
+                        try {
+                            fileByte = multipartFile.getBytes();
+                        } catch (IOException e) {
+                            return 1;
+                        }
+                        String base64 = Base64.getEncoder().encodeToString(fileByte);
+                        Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
+                        if (checkImage != null && checkImage.get("result").equals("1")) {
+                            return 3;
+                        }
+                        StoreImg storeImg = new StoreImg();
+                        storeImg.setStoreId(storeComment.getStoreId());
+                        storeImg.setImgType(8);
+                        storeImg.setImgSort(i + 1);
+                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
+                        storeImgMapper.insert(storeImg);
+                        imgId.append(storeImg.getId()).append(",");
+                    }
+                }
+                if (!imgId.toString().isEmpty()) {
+                    storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
+                }
+            }
+            storeComment.setCreatedUserId(storeComment.getUserId());
+            return this.save(storeComment) ? 0 : 1;
+        } catch (Exception e) {
+            log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
+            return 1;
+        }
+
+    }
+
+    /**
+     * 新增或修改评论/评价
+     *
+     * @param multipartRequest 文件
+     * @param id               主键
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @param evaluationTags   评价标签
+     * @param phoneId          用户id
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    @Override
+    public Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
+        try {
+            List<String> servicesList = Lists.newArrayList();
+            servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
+            servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
+            TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
+            if ("high".equals(textCheckResult.getRiskLevel())) {
+                return 2;
+            }
+
+            /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
+            if (null == checkText || checkText.get("result").equals("1")) {
+                return 2;
+            }*/
+            StoreComment storeComment = new StoreComment();
+            storeComment.setId(id);
+            storeComment.setStoreId(storeId);
+            storeComment.setUserId(userId);
+            storeComment.setCommentContent(commentContent);
+            storeComment.setReplyId(replyId);
+            storeComment.setBusinessId(businessId);
+            storeComment.setBusinessType(businessType);
+            storeComment.setScore(score);
+
+            if (StringUtils.isNotEmpty(otherScore)) {
+                List<LifeCouponVo> lifeCouponVos = JSONArray.parseArray(otherScore, LifeCouponVo.class);
+                lifeCouponVos.stream().filter(i -> "口味".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setTasteScore(Double.valueOf(item.getRateScore())));
+                lifeCouponVos.stream().filter(i -> "环境".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setEnScore(Double.valueOf(item.getRateScore())));
+                lifeCouponVos.stream().filter(i -> "服务".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setServiceScore(Double.valueOf(item.getRateScore())));
+            }
+            storeComment.setOtherScore(otherScore);
+            storeComment.setIsAnonymous(isAnonymous);
+            storeComment.setEvaluationTags(evaluationTags);
+            storeComment.setPhoneId(phoneId);
+            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
+            if (!fileNameSet.isEmpty() && storeId != null) {
+                StringBuilder imgId = new StringBuilder();
+                for (int i = 0; i < fileNameSet.size(); i++) {
+                    MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
+                   //b
+                    System.out.println(multipartFile.getSize());
+                    //kb
+                    System.out.println(multipartFile.getSize() / 1024);
+                    if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
+                        byte[] fileByte;
+                        try {
+                            fileByte = multipartFile.getBytes();
+                        } catch (IOException e) {
+                            return 1;
+                        }
+                        String base64 = Base64.getEncoder().encodeToString(fileByte);
+                        Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
+                        if (checkImage != null && checkImage.get("result").equals("1")) {
+                            return 3;
+                        }
+                        StoreImg storeImg = new StoreImg();
+                        storeImg.setStoreId(storeComment.getStoreId());
+                        storeImg.setImgType(8);
+                        storeImg.setImgSort(i + 1);
+                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
+                        storeImgMapper.insert(storeImg);
+                        imgId.append(storeImg.getId()).append(",");
+                    }
+                }
+                if (!imgId.toString().isEmpty()) {
+                    storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
+                }
+            }
+            storeComment.setCreatedUserId(storeComment.getUserId());
+            int i = this.save(storeComment) ? 0 : 1;
+
+            //判断类型如果为5是评价 更新订单表orderAppraise为1 订单已评价
+            if(businessType == 5){
+                LambdaUpdateWrapper<LifeUserOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                lambdaUpdateWrapper.eq(LifeUserOrder :: getId, businessId );
+                lambdaUpdateWrapper.set(LifeUserOrder :: getOrderAppraise, 1);
+                lifeUserOrderMapper.update(null,lambdaUpdateWrapper);
+            }
+            StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
+            double total = storeInfoScoreVo.getTotal();
+            double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
+            double tasteScore = (total == 0 ? 0 : storeInfoScoreVo.getTasteScore() / total);
+            double enScore = (total == 0 ? 0 : storeInfoScoreVo.getEnScore() / total);
+            double serviceScore = (total == 0 ? 0 : storeInfoScoreVo.getServiceScore() / total);
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setId(storeId);
+            storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setTasteScore(new BigDecimal(tasteScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setEnScore(new BigDecimal(enScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setServiceScore(new BigDecimal(serviceScore).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());
+            }
+            return i;
+        } catch (Exception e) {
+            log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
+            return 1;
+        }
+
+    }
+
+    /**
+     * 新增或修改评论/评价
+     *
+     * @param multipartRequest 文件
+     * @param id               主键
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @param evaluationTags   评价标签
+     * @param phoneId          用户id
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    @Override
+    public Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
+        try {
+            List<String> servicesList = Lists.newArrayList();
+            servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
+            servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
+            TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
+            if ("high".equals(textCheckResult.getRiskLevel())) {
+                return 2;
+            }
+
+            /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
+            if (null == checkText || checkText.get("result").equals("1")) {
+                return 2;
+            }*/
+            StoreComment storeComment = new StoreComment();
+            storeComment.setId(id);
+            storeComment.setStoreId(storeId);
+            storeComment.setUserId(userId);
+            storeComment.setCommentContent(commentContent);
+            storeComment.setReplyId(replyId);
+            storeComment.setBusinessId(businessId);
+            storeComment.setBusinessType(businessType);
+            storeComment.setScore(score);
+            storeComment.setLawyerId(lawyerId);
+            storeComment.setOrderId(orderId);
+
+            if (StringUtils.isNotEmpty(otherScore)) {
+                List<LifeCouponVo> lifeCouponVos = JSONArray.parseArray(otherScore, LifeCouponVo.class);
+                lifeCouponVos.stream().filter(i -> "口味".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setTasteScore(Double.valueOf(item.getRateScore())));
+                lifeCouponVos.stream().filter(i -> "环境".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setEnScore(Double.valueOf(item.getRateScore())));
+                lifeCouponVos.stream().filter(i -> "服务".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setServiceScore(Double.valueOf(item.getRateScore())));
+            }
+            storeComment.setOtherScore(otherScore);
+            storeComment.setIsAnonymous(isAnonymous);
+            storeComment.setEvaluationTags(evaluationTags);
+            storeComment.setPhoneId(phoneId);
+            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
+            if (!fileNameSet.isEmpty() && storeId != null) {
+                StringBuilder imgId = new StringBuilder();
+                for (int i = 0; i < fileNameSet.size(); i++) {
+                    MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
+                    //b
+                    System.out.println(multipartFile.getSize());
+                    //kb
+                    System.out.println(multipartFile.getSize() / 1024);
+                    if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
+                        byte[] fileByte;
+                        try {
+                            fileByte = multipartFile.getBytes();
+                        } catch (IOException e) {
+                            return 1;
+                        }
+                        String base64 = Base64.getEncoder().encodeToString(fileByte);
+                        Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
+                        if (checkImage != null && checkImage.get("result").equals("1")) {
+                            return 3;
+                        }
+                        StoreImg storeImg = new StoreImg();
+                        storeImg.setStoreId(storeComment.getStoreId());
+                        storeImg.setImgType(8);
+                        storeImg.setImgSort(i + 1);
+                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
+                        storeImgMapper.insert(storeImg);
+                        imgId.append(storeImg.getId()).append(",");
+                    }
+                }
+                if (!imgId.toString().isEmpty()) {
+                    storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
+                }
+            }
+            storeComment.setCreatedUserId(storeComment.getUserId());
+            int i = this.save(storeComment) ? 0 : 1;
+
+            //判断类型如果为5是评价 更新订单表orderAppraise为1 订单已评价
+            if(businessType == 5){
+                LambdaUpdateWrapper<LifeUserOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                lambdaUpdateWrapper.eq(LifeUserOrder :: getId, businessId );
+                lambdaUpdateWrapper.set(LifeUserOrder :: getOrderAppraise, 1);
+                lifeUserOrderMapper.update(null,lambdaUpdateWrapper);
+            }
+            StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
+            double total = storeInfoScoreVo.getTotal();
+            double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
+            double tasteScore = (total == 0 ? 0 : storeInfoScoreVo.getTasteScore() / total);
+            double enScore = (total == 0 ? 0 : storeInfoScoreVo.getEnScore() / total);
+            double serviceScore = (total == 0 ? 0 : storeInfoScoreVo.getServiceScore() / total);
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setId(storeId);
+            storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setTasteScore(new BigDecimal(tasteScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setEnScore(new BigDecimal(enScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setServiceScore(new BigDecimal(serviceScore).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());
+            }
+            return i;
+        } catch (Exception e) {
+            log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
+            return 1;
+        }
+
+    }
+
+    /**
+     * 回复率, 评价比例
+     *
+     * @param storeId 门店id
+     * @return StoreCommitPercentVo
+     */
+    @Override
+    public StoreCommitPercentVo getCommitPercent(Integer storeId) {
+        StoreCommitPercentVo storeCommit = storeCommentMapper.getCommentByStoreId(storeId);
+        if (storeCommit != null) {
+            if ("0".equals(storeCommit.getAllCommentCount())) {
+                storeCommit.setHighPercent("0%");
+                storeCommit.setMidPercent("0%");
+                storeCommit.setLowPercent("0%");
+            } else {
+                double highPercentDouble = Double.parseDouble(storeCommit.getHighCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
+                BigDecimal highPercent = BigDecimal.valueOf(highPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
+                //好评
+                storeCommit.setHighPercent(highPercent + "%");
+                double midPercentDouble = Double.parseDouble(storeCommit.getMidCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
+                BigDecimal midPercent = BigDecimal.valueOf(midPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
+                //中评
+                storeCommit.setMidPercent(midPercent + "%");
+                double lowPercentDouble = Double.parseDouble(storeCommit.getLowCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
+                BigDecimal lowPercent = BigDecimal.valueOf(lowPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
+                //差评
+                storeCommit.setLowPercent(lowPercent + "%");
+            }
+            if ("0".equals(storeCommit.getRootCommentCount())) {
+                storeCommit.setReplyPercent("0%");
+            } else {
+                double replyPercentDouble = Double.parseDouble(storeCommit.getCommentCount()) / Double.parseDouble(storeCommit.getRootCommentCount());
+                BigDecimal replyPercent = BigDecimal.valueOf(replyPercentDouble).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
+                //回复率
+                storeCommit.setReplyPercent(replyPercent + "%");
+            }
+            return storeCommit;
+        }
+        return null;
+    }
+
+    @Override
+    public IPage<LifeUserOrderCommentVo> getCommentOrderPage(Integer pageNum, Integer pageSize, Integer type, String userId) {
+        IPage<LifeUserOrderCommentVo> lifeUserOrderCommentVoIPage = new Page<>(pageNum, pageSize);
+        IPage<LifeUserOrderCommentVo> commentOrderPage;
+        //1.未评价 2.已评价
+        if (type == 1) {
+            commentOrderPage = storeCommentMapper.getCommentOrderWPJPage(lifeUserOrderCommentVoIPage, userId);
+        } else {
+            commentOrderPage = storeCommentMapper.getCommentOrderYPJPage(lifeUserOrderCommentVoIPage, userId);
+        }
+        List<String> collect = commentOrderPage.getRecords().stream().map(LifeUserOrderCommentVo::getGroupBuyImgId).collect(Collectors.toList());
+
+        if (ObjectUtils.isNotEmpty(collect)) {
+            List<StoreImg> storeImgList = storeImgMapper.selectList(new QueryWrapper<StoreImg>().inSql("id", String.join(",", collect)));
+//            commentOrderPage.getRecords().forEach(i ->
+//                    i.setGroupBuyImgUrl(storeImgList.stream().filter(j -> j.getId().toString().equals(i.getGroupBuyImgId()))
+//                            .findFirst().map(StoreImg::getImgUrl).orElse(null)));
+            // 2. 优化分组:id唯一,直接映射为 Map<Integer, StoreImg>(避免List处理)
+            Map<Integer, StoreImg> imgIdToImgMap = storeImgList.stream()
+                    .collect(Collectors.toMap(
+                            StoreImg::getId,  // 键:图片id
+                            Function.identity(),  // 值:图片对象本身
+                            (existing, replacement) -> existing  // 若有重复id(理论上不会),保留第一个
+                    ));
+
+            // 3. 遍历订单评论记录,处理图片URL拼接
+            for (LifeUserOrderCommentVo record : commentOrderPage.getRecords()) {
+                String groupBuyImgId = record.getGroupBuyImgId();
+                // 空指针防护:如果imgId为空,直接设为空字符串
+                if (groupBuyImgId == null || groupBuyImgId.trim().isEmpty()) {
+                    record.setGroupBuyImgUrl("");
+                    continue;
+                }
+
+                // 分割imgId并一次性转换为Integer(避免重复解析)
+                List<Integer> imgIds = Arrays.stream(groupBuyImgId.split(","))
+                        .map(String::trim)  // 处理可能的空格
+                        .filter(idStr -> !idStr.isEmpty())  // 过滤空字符串(如连续逗号导致的)
+                        .map(idStr -> {
+                            try {
+                                return Integer.parseInt(idStr);
+                            } catch (NumberFormatException e) {
+                                // 处理非数字id的异常(如无效id)
+                                return null;
+                            }
+                        })
+                        .filter(Objects::nonNull)  // 过滤转换失败的null
+                        .collect(Collectors.toList());
+
+                // 拼接图片URL(使用StringBuilder高效拼接)
+                StringBuilder imgUrlBuilder = new StringBuilder();
+                for (Integer imgId : imgIds) {
+                    StoreImg storeImg = imgIdToImgMap.get(imgId);
+                    if (storeImg != null && storeImg.getImgUrl() != null) {
+                        if (imgUrlBuilder.length() > 0) {
+                            imgUrlBuilder.append(",");  // 非第一个元素前加逗号
+                        }
+                        imgUrlBuilder.append(storeImg.getImgUrl());
+                    }
+                }
+
+                // 设置最终的图片URL字符串(去掉末尾可能的逗号,这里通过逻辑避免了)
+                record.setGroupBuyImgUrl(imgUrlBuilder.toString());
+            }
+        }
+
+
+        List<LifeUserOrderCommentVo> lifeUserOrderCommentVos =  commentOrderPage.getRecords();
+        if(CollectionUtils.isEmpty(lifeUserOrderCommentVos)){
+            return commentOrderPage;
+        }
+        List<String> orderIds = lifeUserOrderCommentVos.stream().map(LifeUserOrderCommentVo::getId).collect(Collectors.toList());
+        List<StoreComment> storeCommentList = storeCommentMapper.selectList(new QueryWrapper<StoreComment>().inSql("business_id", String.join(",", orderIds)).eq("business_type", 5));
+        if(CollectionUtils.isEmpty(storeCommentList)){
+            return commentOrderPage;
+        }
+        Map<Integer, StoreComment> commentIdToMap = storeCommentList.stream()
+                .collect(Collectors.toMap(
+                        StoreComment::getBusinessId,
+                        Function.identity(),
+                        (existing, replacement) -> existing  // 若有重复id(理论上不会),保留第一个
+                ));
+        if(CollectionUtils.isEmpty(commentIdToMap)){
+            return commentOrderPage;
+        }
+        for(LifeUserOrderCommentVo lifeUserOrderCommentVo : commentOrderPage.getRecords()){
+            Integer orderId = Integer.parseInt(lifeUserOrderCommentVo.getId());
+
+            if(commentIdToMap.containsKey(orderId)){
+                StoreComment storeComment = commentIdToMap.get(orderId);
+                lifeUserOrderCommentVo.setScore(storeComment.getScore().toString());
+                lifeUserOrderCommentVo.setCommentDate(storeComment.getCreatedTime());
+                String imgIds = storeComment.getImgId();
+
+                if(StringUtils.isNotEmpty(imgIds)){
+                    LambdaQueryWrapper<StoreImg> storeImgLambdaQueryWrapper = new LambdaQueryWrapper<>();
+                    List<String> imgIdList = Arrays.stream(imgIds.split(","))
+                            .map(String::trim)
+                            .collect(Collectors.toList());
+                    storeImgLambdaQueryWrapper.in(StoreImg::getId, imgIdList);
+                    List<StoreImg> storeImgList = storeImgMapper.selectList(storeImgLambdaQueryWrapper);
+                    if(CollectionUtils.isNotEmpty(storeImgList)){
+                        List<String> imgUrlList = storeImgList.stream()    // 转换为 Stream
+                                .map(StoreImg::getImgUrl)                  // 映射,提取 name 字段
+                                .collect(Collectors.toList());
+                        lifeUserOrderCommentVo.setImgUrls(imgUrlList);
+                    }
+                }
+            }
+        }
+
+        return commentOrderPage;
+    }
+
+    /**
+     * 获取店铺评价计数统计
+     *
+     * @param storeId 门店id
+     * @return StoreCommentCountVo
+     */
+    @Override
+    public StoreCommentCountVo getAppraiseCount(Integer storeId) {
+        StoreCommentCountVo countVo = new StoreCommentCountVo();
+
+        // 查询条件:只统计当前门店、根评论(reply_id为null)、未删除的评论
+        LambdaQueryWrapper<StoreComment> totalWrapper = buildBaseStoreCommentWrapper(storeId);
+        countVo.setTotalCount(storeCommentMapper.selectCount(totalWrapper));
+
+        // 2. 有图评论数(img_id不为空且不为空字符串)
+        LambdaQueryWrapper<StoreComment> imageWrapper = buildBaseStoreCommentWrapper(storeId);
+        imageWrapper.isNotNull(StoreComment::getImgId)
+                .apply("img_id != ''");
+        countVo.setImageCount(storeCommentMapper.selectCount(imageWrapper));
+
+        // 3. 好评数(score >= 4.5)
+        LambdaQueryWrapper<StoreComment> goodWrapper = buildBaseStoreCommentWrapper(storeId);
+        goodWrapper.ge(StoreComment::getScore, 4.5);
+        countVo.setGoodCount(storeCommentMapper.selectCount(goodWrapper));
+
+        // 4. 中评数(score >= 3 && score <= 4)
+        LambdaQueryWrapper<StoreComment> midWrapper = buildBaseStoreCommentWrapper(storeId);
+        midWrapper.ge(StoreComment::getScore, 3.0)
+                .le(StoreComment::getScore, 4.0);
+        countVo.setMidCount(storeCommentMapper.selectCount(midWrapper));
+
+        // 5. 差评数(score >= 0.5 && score <= 2.5)
+        LambdaQueryWrapper<StoreComment> badWrapper = buildBaseStoreCommentWrapper(storeId);
+        badWrapper.ge(StoreComment::getScore, 0.5)
+                .le(StoreComment::getScore, 2.5);
+        countVo.setBadCount(storeCommentMapper.selectCount(badWrapper));
+
+        return countVo;
+    }
+
+    /**
+     * 构建当前门店根评论的查询条件
+     */
+    private LambdaQueryWrapper<StoreComment> buildBaseStoreCommentWrapper(Integer storeId) {
+        return new LambdaQueryWrapper<StoreComment>()
+                .eq(StoreComment::getStoreId, storeId)
+                .gt(StoreComment::getScore,0 )
+                .eq(StoreComment::getBusinessType, 5)
+                .eq(StoreComment::getDeleteFlag, 0);
+    }
+
+    // ==================== 订单评价相关方法实现(迁移自 OrderReviewService)====================
+
+    @Override
+    public R<StoreComment> createOrderReview(OrderReviewDto reviewDto) {
+        log.info("StoreCommentServiceImpl.createOrderReview?reviewDto={}", reviewDto);
+
+        // 参数校验
+        if (reviewDto == null) {
+            return R.fail("评价信息不能为空");
+        }
+        if (reviewDto.getOrderId() == null) {
+            return R.fail("订单ID不能为空");
+        }
+        Integer userId = reviewDto.getUserId();
+        if (userId == null) {
+            return R.fail("用户ID不能为空");
+        }
+
+        // 验证订单是否存在且属于该用户
+        LawyerConsultationOrder order = lawyerConsultationOrderMapper.selectById(reviewDto.getOrderId());
+        if (order == null) {
+            return R.fail("订单不存在");
+        }
+        if (!order.getClientUserId().equals(userId)) {
+            return R.fail("只能评价自己的订单");
+        }
+
+        // 检查订单是否已完成
+        if (order.getOrderStatus() == null || order.getOrderStatus() != 3) {
+            return R.fail("只能对已完成的订单进行评价");
+        }
+
+        // 检查是否已经评价过(使用 store_comment 表,business_type=5)
+        LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreComment::getOrderId, reviewDto.getOrderId())
+                .eq(StoreComment::getBusinessType, 5)
+                .eq(StoreComment::getDeleteFlag, 0);
+        StoreComment existingReview = this.getOne(queryWrapper);
+        if (existingReview != null) {
+            return R.success("该订单已经评价过了");
+        }
+
+        // 创建评价(使用 store_comment 表)
+        StoreComment review = new StoreComment();
+        review.setOrderId(reviewDto.getOrderId());
+        review.setLawyerId(order.getLawyerUserId());
+        review.setUserId(userId);
+        review.setCommentContent(reviewDto.getReviewContent());
+        review.setScore(reviewDto.getOverallRating());
+        review.setBusinessId(reviewDto.getOrderId()); // 订单ID作为业务ID
+        review.setBusinessType(5); // 订单评价
+        review.setIsAnonymous(reviewDto.getIsAnonymous() != null ? reviewDto.getIsAnonymous() : 0);
+        review.setLikeCount(0);
+        
+        // 处理评价图片:将JSON数组转换为img_id(这里需要根据实际情况处理)
+        if (reviewDto.getReviewImages() != null && !reviewDto.getReviewImages().isEmpty()) {
+            // 注意:这里需要将图片URL上传并获取img_id,暂时先不处理
+            // review.setImgId(...);
+        }
+        
+        review.setCreatedUserId(userId);
+        review.setCreatedTime(new Date());
+
+        boolean success = this.save(review);
+        if (success) {
+            log.info("创建评价成功,评价ID={}", review.getId());
+            // 更新律师评分
+            updateLawyerServiceScore(order.getLawyerUserId());
+            return R.data(review, "提交成功");
+        } else {
+            log.error("创建评价失败");
+            return R.fail("创建评价失败");
+        }
+    }
+
+    /**
+     * 更新律师服务评分和好评/中评/差评数量
+     */
+    private void updateLawyerServiceScore(Integer lawyerUserId) {
+        if (lawyerUserId == null) {
+            log.warn("更新律师评分失败:律师ID为空");
+            return;
+        }
+
+        try {
+            // 从 store_comment 表计算平均评分(business_type=5)
+            LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(StoreComment::getLawyerId, lawyerUserId)
+                    .eq(StoreComment::getBusinessType, 5)
+                    .eq(StoreComment::getDeleteFlag, 0)
+                    .isNotNull(StoreComment::getScore);
+            List<StoreComment> reviews = this.list(queryWrapper);
+            
+            Double averageRating = null;
+            if (!reviews.isEmpty()) {
+                double sum = reviews.stream()
+                        .filter(r -> r.getScore() != null)
+                        .mapToDouble(StoreComment::getScore)
+                        .sum();
+                averageRating = sum / reviews.size();
+            }
+
+            Double serviceScore;
+            if (averageRating != null) {
+                serviceScore = Math.floor(averageRating * 10.0) / 10.0;
+                serviceScore = Math.max(0.0, Math.min(5.0, serviceScore));
+            } else {
+                serviceScore = 0.0;
+            }
+
+            // 统计好评、中评、差评数量
+            long goodCount = reviews.stream()
+                    .filter(r -> r.getScore() != null && r.getScore() >= 4.5 && r.getScore() <= 5)
+                    .count();
+            long mediumCount = reviews.stream()
+                    .filter(r -> r.getScore() != null && r.getScore() >= 3.0 && r.getScore() < 4.5)
+                    .count();
+            long badCount = reviews.stream()
+                    .filter(r -> r.getScore() != null && r.getScore() >= 0.5 && r.getScore() < 3.0)
+                    .count();
+
+            // 更新律师评分
+            LambdaUpdateWrapper<LawyerUser> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(LawyerUser::getId, lawyerUserId);
+            updateWrapper.set(LawyerUser::getServiceScore, serviceScore);
+            updateWrapper.set(LawyerUser::getGoodReviewCount, (int) goodCount);
+            updateWrapper.set(LawyerUser::getMediumReviewCount, (int) mediumCount);
+            updateWrapper.set(LawyerUser::getBadReviewCount, (int) badCount);
+            int result = lawyerUserMapper.update(null, updateWrapper);
+
+            if (result > 0) {
+                log.info("更新律师评分成功,律师ID={}, 平均评分={}, 服务评分={}, 好评数={}, 中评数={}, 差评数={}",
+                        lawyerUserId, averageRating, serviceScore, goodCount, mediumCount, badCount);
+            }
+        } catch (Exception e) {
+            log.error("更新律师评分异常,律师ID={}, 错误信息={}", lawyerUserId, e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public R<OrderReviewDetailVo> getOrderReviewDetail(Integer reviewId, Integer currentUserId) {
+        log.info("StoreCommentServiceImpl.getOrderReviewDetail?reviewId={}, currentUserId={}", reviewId, currentUserId);
+
+        if (reviewId == null) {
+            return R.fail("评价ID不能为空");
+        }
+
+        // 查询评价详情(从 store_comment 表,business_type=5)
+        StoreComment review = this.getById(reviewId);
+        if (review == null || review.getDeleteFlag() == 1 || review.getBusinessType() != 5) {
+            return R.fail("评价不存在");
+        }
+
+        // 构建 OrderReviewDetailVo(需要关联用户和律师信息)
+        OrderReviewDetailVo detailVo = new OrderReviewDetailVo();
+        // TODO: 需要从 store_comment 查询并关联用户、律师信息,构建完整的 OrderReviewDetailVo
+        // 这里需要根据实际的查询需求来实现,可能需要自定义SQL查询
+        
+        // 查询评论列表(business_type=6,business_id=reviewId)
+        R<List<ReviewCommentVo>> commentsResult = getReviewCommentListByReviewId(reviewId, currentUserId);
+        if (commentsResult.getCode() == 200) {
+            detailVo.setComments(commentsResult.getData());
+        }
+
+        return R.data(detailVo);
+    }
+
+    @Override
+    public R<Boolean> likeOrderReview(Integer reviewId, Integer userId) {
+        log.info("StoreCommentServiceImpl.likeOrderReview?reviewId={}, userId={}", reviewId, userId);
+
+        // 验证评价是否存在
+        StoreComment review = this.getById(reviewId);
+        if (review == null || review.getDeleteFlag() == 1 || review.getBusinessType() != 5) {
+            return R.fail("评价不存在或已删除");
+        }
+
+        // 检查是否已点赞(type=7 表示订单评价点赞)
+        LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LifeLikeRecord::getType, "7")
+                .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
+                .eq(LifeLikeRecord::getHuifuId, String.valueOf(reviewId))
+                .eq(LifeLikeRecord::getDeleteFlag, 0);
+        List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
+
+        if (CollectionUtils.isEmpty(records)) {
+            // 插入点赞记录
+            LifeLikeRecord likeRecord = new LifeLikeRecord();
+            likeRecord.setDianzanId(String.valueOf(userId));
+            likeRecord.setHuifuId(String.valueOf(reviewId));
+            likeRecord.setType("7");
+            likeRecord.setCreatedTime(new Date());
+            likeRecord.setCreatedUserId(userId);
+            lifeLikeRecordMapper.insert(likeRecord);
+
+            // 更新评价点赞数
+            LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(StoreComment::getId, reviewId);
+            updateWrapper.setSql("like_count = like_count + 1");
+            int result = storeCommentMapper.update(null, updateWrapper);
+
+            if (result > 0) {
+                return R.data(true, "点赞成功");
+            } else {
+                return R.fail("点赞失败");
+            }
+        } else {
+            return R.data(true, "已点赞");
+        }
+    }
+
+    @Override
+    public R<Boolean> cancelLikeOrderReview(Integer reviewId, Integer userId) {
+        log.info("StoreCommentServiceImpl.cancelLikeOrderReview?reviewId={}, userId={}", reviewId, userId);
+
+        // 查询点赞记录
+        LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LifeLikeRecord::getType, "7")
+                .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
+                .eq(LifeLikeRecord::getHuifuId, String.valueOf(reviewId))
+                .eq(LifeLikeRecord::getDeleteFlag, 0);
+        List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
+
+        if (!CollectionUtils.isEmpty(records)) {
+            // 删除点赞记录(逻辑删除)
+            for (LifeLikeRecord record : records) {
+                lifeLikeRecordMapper.deleteById(record.getId());
+            }
+
+            // 更新评价点赞数
+            LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(StoreComment::getId, reviewId);
+            updateWrapper.setSql("like_count = GREATEST(0, like_count - 1)");
+            int result = storeCommentMapper.update(null, updateWrapper);
+
+            if (result > 0) {
+                return R.data(true, "取消点赞成功");
+            } else {
+                return R.fail("取消点赞失败");
+            }
+        } else {
+            return R.data(true, "未点赞");
+        }
+    }
+
+    @Override
+    public R<IPage<OrderReviewVo>> getOrderReviewList(int page, int size, Integer orderId, Integer lawyerUserId, Integer userId, Integer currentUserId) {
+        log.info("StoreCommentServiceImpl.getOrderReviewList?page={}, size={}, orderId={}, lawyerUserId={}, userId={}, currentUserId={}",
+                page, size, orderId, lawyerUserId, userId, currentUserId);
+
+        // 构建查询条件
+        LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreComment::getBusinessType, 5)
+                .eq(StoreComment::getDeleteFlag, 0);
+        
+        if (orderId != null) {
+            queryWrapper.eq(StoreComment::getOrderId, orderId);
+        }
+        if (lawyerUserId != null) {
+            queryWrapper.eq(StoreComment::getLawyerId, lawyerUserId);
+        }
+        if (userId != null) {
+            queryWrapper.eq(StoreComment::getUserId, userId);
+        }
+        
+        queryWrapper.orderByDesc(StoreComment::getCreatedTime);
+
+        // 分页查询
+        Page<StoreComment> pageObj = new Page<>(page, size);
+        IPage<StoreComment> commentPage = this.page(pageObj, queryWrapper);
+
+        // 转换为 OrderReviewVo(需要关联用户和律师信息)
+        // TODO: 需要自定义查询或手动构建 OrderReviewVo,关联用户和律师信息
+        Page<OrderReviewVo> resultPage = new Page<>(page, size);
+        resultPage.setTotal(commentPage.getTotal());
+        resultPage.setPages(commentPage.getPages());
+        
+        List<OrderReviewVo> voList = new ArrayList<>();
+        for (StoreComment comment : commentPage.getRecords()) {
+            OrderReviewVo vo = new OrderReviewVo();
+            vo.setId(comment.getId());
+            vo.setOrderId(comment.getOrderId());
+            vo.setUserId(comment.getUserId());
+            vo.setLawyerUserId(comment.getLawyerId());
+            vo.setOverallRating(comment.getScore());
+            vo.setReviewContent(comment.getCommentContent());
+            vo.setIsAnonymous(comment.getIsAnonymous());
+            vo.setLikeCount(comment.getLikeCount());
+            vo.setCreatedTime(comment.getCreatedTime());
+            // TODO: 需要查询并设置用户名称、头像、律师信息等
+            voList.add(vo);
+        }
+        resultPage.setRecords(voList);
+
+        return R.data(resultPage);
+    }
+
+    @Override
+    public R<OrderReviewVo> getOrderReviewByOrderId(Integer orderId, Integer currentUserId) {
+        log.info("StoreCommentServiceImpl.getOrderReviewByOrderId?orderId={}, currentUserId={}", orderId, currentUserId);
+
+        LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreComment::getOrderId, orderId)
+                .eq(StoreComment::getBusinessType, 5)
+                .eq(StoreComment::getDeleteFlag, 0)
+                .orderByDesc(StoreComment::getCreatedTime)
+                .last("LIMIT 1");
+        
+        StoreComment comment = this.getOne(queryWrapper);
+        if (comment == null) {
+            return R.fail("评价不存在");
+        }
+
+        // 转换为 OrderReviewVo
+        OrderReviewVo vo = new OrderReviewVo();
+        vo.setId(comment.getId());
+        vo.setOrderId(comment.getOrderId());
+        vo.setUserId(comment.getUserId());
+        vo.setLawyerUserId(comment.getLawyerId());
+        vo.setOverallRating(comment.getScore());
+        vo.setReviewContent(comment.getCommentContent());
+        vo.setIsAnonymous(comment.getIsAnonymous());
+        vo.setLikeCount(comment.getLikeCount());
+        vo.setCreatedTime(comment.getCreatedTime());
+        // TODO: 需要查询并设置用户名称、头像、律师信息等
+
+        return R.data(vo);
+    }
+
+    // ==================== 评价评论相关方法实现(迁移自 ReviewCommentService)====================
+
+    @Override
+    public R<StoreComment> createReviewComment(StoreComment comment) {
+        log.info("StoreCommentServiceImpl.createReviewComment?comment={}", comment);
+
+        // 参数校验
+        if (comment == null) {
+            return R.fail("评论信息不能为空");
+        }
+        if (comment.getBusinessId() == null) {
+            return R.fail("评价ID不能为空");
+        }
+        if (comment.getCommentContent() == null || comment.getCommentContent().trim().isEmpty()) {
+            return R.fail("评论内容不能为空");
+        }
+        Integer userId = comment.getUserId();
+        if (userId == null) {
+            return R.fail("用户ID不能为空");
+        }
+
+        // 验证评价是否存在(business_type=5)
+        StoreComment review = this.getById(comment.getBusinessId());
+        if (review == null || review.getDeleteFlag() == 1 || review.getBusinessType() != 5) {
+            return R.fail("评价不存在或已删除");
+        }
+
+        // 设置评论属性
+        comment.setBusinessType(6); // 订单评价的评论
+        comment.setBusinessId(review.getId()); // 评价ID作为业务ID
+        comment.setOrderId(review.getOrderId()); // 从评价中获取订单ID
+        comment.setLawyerId(review.getLawyerId()); // 从评价中获取律师ID
+        comment.setLikeCount(0);
+        comment.setReplyId(null); // 首评没有reply_id
+        comment.setCreatedUserId(userId);
+        comment.setCreatedTime(new Date());
+
+        boolean success = this.save(comment);
+        if (success) {
+            log.info("创建评论成功,评论ID={}", comment.getId());
+            return R.data(comment, "评论成功");
+        } else {
+            log.error("创建评论失败");
+            return R.fail("创建评论失败");
+        }
+    }
+
+    @Override
+    public R<List<ReviewCommentVo>> getReviewCommentListByReviewId(Integer reviewId, Integer currentUserId) {
+        log.info("StoreCommentServiceImpl.getReviewCommentListByReviewId?reviewId={}, currentUserId={}", reviewId, currentUserId);
+
+        if (reviewId == null) {
+            return R.fail("评价ID不能为空");
+        }
+
+        // 查询评论列表(business_type=6,business_id=reviewId,reply_id为null表示首评)
+        LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreComment::getBusinessId, reviewId)
+                .eq(StoreComment::getBusinessType, 6)
+                .isNull(StoreComment::getReplyId) // 首评
+                .eq(StoreComment::getDeleteFlag, 0)
+                .orderByDesc(StoreComment::getCreatedTime);
+        
+        List<StoreComment> comments = this.list(queryWrapper);
+
+        // 转换为 ReviewCommentVo 并加载回复列表
+        List<ReviewCommentVo> voList = new ArrayList<>();
+        for (StoreComment comment : comments) {
+            ReviewCommentVo vo = new ReviewCommentVo();
+            vo.setId(comment.getId());
+            vo.setReviewId(comment.getBusinessId());
+            vo.setSendUserId(comment.getUserId());
+            vo.setCommentContent(comment.getCommentContent());
+            vo.setLikeCount(comment.getLikeCount());
+            vo.setCreatedTime(comment.getCreatedTime());
+            // TODO: 需要查询并设置用户名称、头像等
+            
+            // 检查是否已点赞
+            if (currentUserId != null) {
+                LambdaQueryWrapper<LifeLikeRecord> likeWrapper = new LambdaQueryWrapper<>();
+                likeWrapper.eq(LifeLikeRecord::getType, "8")
+                        .eq(LifeLikeRecord::getDianzanId, String.valueOf(currentUserId))
+                        .eq(LifeLikeRecord::getHuifuId, String.valueOf(comment.getId()))
+                        .eq(LifeLikeRecord::getDeleteFlag, 0);
+                vo.setIsLiked(lifeLikeRecordMapper.selectCount(likeWrapper) > 0 ? 1 : 0);
+            } else {
+                vo.setIsLiked(0);
+            }
+
+            // 查询回复列表
+            R<List<ReviewCommentVo>> repliesResult = getReviewReplyListByHeadId(comment.getId(), currentUserId);
+            if (repliesResult.getCode() == 200) {
+                vo.setReplies(repliesResult.getData());
+            }
+
+            voList.add(vo);
+        }
+
+        return R.data(voList);
+    }
+
+    @Override
+    public R<Boolean> likeReviewComment(ReviewCommentRequestDto requestDto) {
+        log.info("StoreCommentServiceImpl.likeReviewComment?requestDto={}", requestDto);
+
+        Integer commentId = requestDto.getCommentId();
+        Integer userId = requestDto.getUserId();
+
+        if (commentId == null) {
+            return R.fail("评论ID不能为空");
+        }
+        if (userId == null) {
+            return R.fail("用户ID不能为空");
+        }
+
+        // 验证评论是否存在
+        StoreComment comment = this.getById(commentId);
+        if (comment == null || comment.getDeleteFlag() == 1 || comment.getBusinessType() != 6) {
+            return R.fail("评论不存在或已删除");
+        }
+
+        // 检查是否已点赞(type=8 表示评论点赞)
+        LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LifeLikeRecord::getType, "8")
+                .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
+                .eq(LifeLikeRecord::getHuifuId, String.valueOf(commentId))
+                .eq(LifeLikeRecord::getDeleteFlag, 0);
+        List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
+
+        if (CollectionUtils.isEmpty(records)) {
+            // 插入点赞记录
+            LifeLikeRecord likeRecord = new LifeLikeRecord();
+            likeRecord.setDianzanId(String.valueOf(userId));
+            likeRecord.setHuifuId(String.valueOf(commentId));
+            likeRecord.setType("8");
+            likeRecord.setCreatedTime(new Date());
+            likeRecord.setCreatedUserId(userId);
+            lifeLikeRecordMapper.insert(likeRecord);
+
+            // 更新评论点赞数
+            LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(StoreComment::getId, commentId);
+            updateWrapper.setSql("like_count = like_count + 1");
+            int result = storeCommentMapper.update(null, updateWrapper);
+
+            if (result > 0) {
+                return R.data(true, "点赞成功");
+            } else {
+                return R.fail("点赞失败");
+            }
+        } else {
+            return R.data(true, "已点赞");
+        }
+    }
+
+    @Override
+    public R<Boolean> cancelLikeReviewComment(ReviewCommentRequestDto requestDto) {
+        log.info("StoreCommentServiceImpl.cancelLikeReviewComment?requestDto={}", requestDto);
+
+        Integer commentId = requestDto.getCommentId();
+        Integer userId = requestDto.getUserId();
+        if (commentId == null) {
+            return R.fail("评论ID不能为空");
+        }
+        if (userId == null) {
+            return R.fail("用户ID不能为空");
+        }
+
+        // 查询点赞记录
+        LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LifeLikeRecord::getType, "8")
+                .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
+                .eq(LifeLikeRecord::getHuifuId, String.valueOf(commentId))
+                .eq(LifeLikeRecord::getDeleteFlag, 0);
+        List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
+
+        if (!CollectionUtils.isEmpty(records)) {
+            // 删除点赞记录(逻辑删除)
+            for (LifeLikeRecord record : records) {
+                lifeLikeRecordMapper.deleteById(record.getId());
+            }
+
+            // 更新评论点赞数
+            LambdaUpdateWrapper<StoreComment> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(StoreComment::getId, commentId);
+            updateWrapper.setSql("like_count = GREATEST(0, like_count - 1)");
+            int result = storeCommentMapper.update(null, updateWrapper);
+
+            if (result > 0) {
+                return R.data(true, "取消点赞成功");
+            } else {
+                return R.fail("取消点赞失败");
+            }
+        } else {
+            return R.data(true, "未点赞");
+        }
+    }
+
+    @Override
+    public R<StoreComment> createReviewReply(ReviewReplyDto replyDto) {
+        log.info("StoreCommentServiceImpl.createReviewReply?replyDto={}", replyDto);
+
+        // 参数校验
+        if (replyDto == null) {
+            return R.fail("回复信息不能为空");
+        }
+        if (replyDto.getCommentId() == null) {
+            return R.fail("评论ID不能为空");
+        }
+        if (replyDto.getReplyContent() == null || replyDto.getReplyContent().trim().isEmpty()) {
+            return R.fail("回复内容不能为空");
+        }
+        Integer userId = replyDto.getUserId();
+        if (userId == null) {
+            return R.fail("用户ID不能为空");
+        }
+
+        // 验证首评是否存在
+        StoreComment headComment = this.getById(replyDto.getCommentId());
+        if (headComment == null || headComment.getDeleteFlag() == 1 || headComment.getBusinessType() != 6) {
+            return R.fail("评论不存在或已删除");
+        }
+        // 验证是否为首评(reply_id为null表示首评)
+        if (headComment.getReplyId() != null) {
+            return R.fail("只能回复首评");
+        }
+
+        // 创建回复
+        StoreComment reply = new StoreComment();
+        reply.setBusinessId(headComment.getBusinessId()); // 评价ID
+        reply.setBusinessType(6); // 订单评价的评论
+        reply.setUserId(userId);
+        reply.setCommentContent(replyDto.getReplyContent());
+        reply.setOrderId(headComment.getOrderId());
+        reply.setLawyerId(headComment.getLawyerId());
+        reply.setReplyId(replyDto.getCommentId()); // 指向首评ID
+        reply.setLikeCount(0);
+        reply.setCreatedUserId(userId);
+        reply.setCreatedTime(new Date());
+
+        boolean success = this.save(reply);
+        if (success) {
+            log.info("创建回复成功,回复ID={}", reply.getId());
+            return R.data(reply, "回复成功");
+        } else {
+            log.error("创建回复失败");
+            return R.fail("创建回复失败");
+        }
+    }
+
+    @Override
+    public R<List<ReviewCommentVo>> getReviewReplyListByHeadId(Integer headId, Integer currentUserId) {
+        log.info("StoreCommentServiceImpl.getReviewReplyListByHeadId?headId={}, currentUserId={}", headId, currentUserId);
+
+        if (headId == null) {
+            return R.fail("首评ID不能为空");
+        }
+
+        // 查询回复列表(business_type=6,reply_id=headId)
+        LambdaQueryWrapper<StoreComment> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreComment::getReplyId, headId)
+                .eq(StoreComment::getBusinessType, 6)
+                .eq(StoreComment::getDeleteFlag, 0)
+                .orderByAsc(StoreComment::getCreatedTime);
+        
+        List<StoreComment> replies = this.list(queryWrapper);
+
+        // 转换为 ReviewCommentVo
+        List<ReviewCommentVo> voList = new ArrayList<>();
+        for (StoreComment reply : replies) {
+            ReviewCommentVo vo = new ReviewCommentVo();
+            vo.setId(reply.getId());
+            vo.setReviewId(reply.getBusinessId());
+            vo.setSendUserId(reply.getUserId());
+            vo.setCommentContent(reply.getCommentContent());
+            vo.setLikeCount(reply.getLikeCount());
+            vo.setCreatedTime(reply.getCreatedTime());
+            // TODO: 需要查询并设置用户名称、头像等
+            
+            // 检查是否已点赞
+            if (currentUserId != null) {
+                LambdaQueryWrapper<LifeLikeRecord> likeWrapper = new LambdaQueryWrapper<>();
+                likeWrapper.eq(LifeLikeRecord::getType, "8")
+                        .eq(LifeLikeRecord::getDianzanId, String.valueOf(currentUserId))
+                        .eq(LifeLikeRecord::getHuifuId, String.valueOf(reply.getId()))
+                        .eq(LifeLikeRecord::getDeleteFlag, 0);
+                vo.setIsLiked(lifeLikeRecordMapper.selectCount(likeWrapper) > 0 ? 1 : 0);
+            } else {
+                vo.setIsLiked(0);
+            }
+
+            voList.add(vo);
+        }
+
+        return R.data(voList);
+    }
+
+    @Override
+    public R<Boolean> deleteReviewReply(Integer replyId, Integer userId) {
+        log.info("StoreCommentServiceImpl.deleteReviewReply?replyId={}, userId={}", replyId, userId);
+
+        if (replyId == null) {
+            return R.fail("回复ID不能为空");
+        }
+        if (userId == null) {
+            return R.fail("用户ID不能为空");
+        }
+
+        // 查询回复
+        StoreComment reply = this.getById(replyId);
+        if (reply == null) {
+            return R.fail("回复不存在");
+        }
+        if (reply.getReplyId() == null) {
+            return R.fail("该记录不是回复");
+        }
+
+        // 验证是否为回复用户
+        if (!reply.getUserId().equals(userId)) {
+            return R.fail("只能删除自己的回复");
+        }
+
+        // 删除回复(逻辑删除)
+        boolean success = this.removeById(reply.getId());
+
+        if (success) {
+            log.info("删除回复成功,回复ID={}", replyId);
+            return R.data(true, "删除成功");
+        } else {
+            log.error("删除回复失败,回复ID={}", replyId);
+            return R.fail("删除回复失败");
+        }
+    }
+}

+ 26 - 0
alien-store/src/main/java/shop/alien/store/controller/StoreCommentController.java

@@ -126,6 +126,32 @@ public class StoreCommentController {
         return R.data(storeCommentService.addComment(multipartRequest, id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
     }
 
+    @ApiOperation(value = "新增或修改评论/评价(new)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query"),
+            @ApiImplicitParam(name = "id", value = "主键", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "orderId", value = "订单id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "lawyerId", value = "律师id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "score", value = "评分", dataType = "Double", paramType = "query"),
+            @ApiImplicitParam(name = "otherScore", value = "其他评分", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "isAnonymous", value = "是否匿名(0:否(默认), 1:是)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "evaluationTags", value = "评价标签", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
+    })
+    @PostMapping("/saveCommentNew")
+    public R<Integer> saveCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
+        log.info("StoreCommentController.saveComment?id={}&businessId={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}&evaluationTags={}&phoneId={}", id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId);
+        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+        log.info(String.valueOf(fileNameSet.size()));
+        return R.data(storeCommentService.addCommentNew(multipartRequest, id, businessId, businessType, storeId,storeId,storeId, orderId, lawyerId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
+    }
+
     @ApiOperation(value = "回复率, 评价比例")
     @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/getCommitPercent")

+ 20 - 0
alien-store/src/main/java/shop/alien/store/service/StoreCommentService.java

@@ -93,6 +93,26 @@ public interface StoreCommentService extends IService<StoreComment> {
     Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
 
     /**
+     * 新增或修改评论/评价
+     *
+     * @param multipartRequest 文件
+     * @param id               主键
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @param evaluationTags   评价标签
+     * @param phoneId          用户id
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
+
+    /**
      * 回复率, 评价比例
      *
      * @param storeId 门店id

+ 145 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java

@@ -704,6 +704,151 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
     }
 
     /**
+     * 新增或修改评论/评价
+     *
+     * @param multipartRequest 文件
+     * @param id               主键
+     * @param businessId       业务id
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @param evaluationTags   评价标签
+     * @param phoneId          用户id
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    @Override
+    public Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
+        try {
+            List<String> servicesList = Lists.newArrayList();
+            servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
+            servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
+            TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
+            if ("high".equals(textCheckResult.getRiskLevel())) {
+                return 2;
+            }
+
+            /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
+            if (null == checkText || checkText.get("result").equals("1")) {
+                return 2;
+            }*/
+            StoreComment storeComment = new StoreComment();
+            storeComment.setId(id);
+            storeComment.setStoreId(storeId);
+            storeComment.setUserId(userId);
+            storeComment.setCommentContent(commentContent);
+            storeComment.setReplyId(replyId);
+            storeComment.setBusinessId(businessId);
+            storeComment.setBusinessType(businessType);
+            storeComment.setScore(score);
+
+            if (StringUtils.isNotEmpty(otherScore)) {
+                List<LifeCouponVo> lifeCouponVos = JSONArray.parseArray(otherScore, LifeCouponVo.class);
+                lifeCouponVos.stream().filter(i -> "口味".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setTasteScore(Double.valueOf(item.getRateScore())));
+                lifeCouponVos.stream().filter(i -> "环境".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setEnScore(Double.valueOf(item.getRateScore())));
+                lifeCouponVos.stream().filter(i -> "服务".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setServiceScore(Double.valueOf(item.getRateScore())));
+            }
+            storeComment.setOtherScore(otherScore);
+            storeComment.setIsAnonymous(isAnonymous);
+            storeComment.setEvaluationTags(evaluationTags);
+            storeComment.setPhoneId(phoneId);
+            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
+            if (!fileNameSet.isEmpty() && storeId != null) {
+                StringBuilder imgId = new StringBuilder();
+                for (int i = 0; i < fileNameSet.size(); i++) {
+                    MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
+                    //b
+                    System.out.println(multipartFile.getSize());
+                    //kb
+                    System.out.println(multipartFile.getSize() / 1024);
+                    if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
+                        byte[] fileByte;
+                        try {
+                            fileByte = multipartFile.getBytes();
+                        } catch (IOException e) {
+                            return 1;
+                        }
+                        String base64 = Base64.getEncoder().encodeToString(fileByte);
+                        Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
+                        if (checkImage != null && checkImage.get("result").equals("1")) {
+                            return 3;
+                        }
+                        StoreImg storeImg = new StoreImg();
+                        storeImg.setStoreId(storeComment.getStoreId());
+                        storeImg.setImgType(8);
+                        storeImg.setImgSort(i + 1);
+                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
+                        storeImgMapper.insert(storeImg);
+                        imgId.append(storeImg.getId()).append(",");
+                    }
+                }
+                if (!imgId.toString().isEmpty()) {
+                    storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
+                }
+            }
+            storeComment.setCreatedUserId(storeComment.getUserId());
+            int i = this.save(storeComment) ? 0 : 1;
+
+            //判断类型如果为5是评价 更新订单表orderAppraise为1 订单已评价
+            if(businessType == 5){
+                LambdaUpdateWrapper<LifeUserOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                lambdaUpdateWrapper.eq(LifeUserOrder :: getId, businessId );
+                lambdaUpdateWrapper.set(LifeUserOrder :: getOrderAppraise, 1);
+                lifeUserOrderMapper.update(null,lambdaUpdateWrapper);
+            }
+            StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
+            double total = storeInfoScoreVo.getTotal();
+            double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
+            double tasteScore = (total == 0 ? 0 : storeInfoScoreVo.getTasteScore() / total);
+            double enScore = (total == 0 ? 0 : storeInfoScoreVo.getEnScore() / total);
+            double serviceScore = (total == 0 ? 0 : storeInfoScoreVo.getServiceScore() / total);
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setId(storeId);
+            storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setTasteScore(new BigDecimal(tasteScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setEnScore(new BigDecimal(enScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setServiceScore(new BigDecimal(serviceScore).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());
+            }
+            return i;
+        } catch (Exception e) {
+            log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
+            return 1;
+        }
+
+    }
+
+    /**
      * 回复率, 评价比例
      *
      * @param storeId 门店id