Parcourir la source

律师端代码

ldz il y a 3 semaines
Parent
commit
a584ec9d8d
37 fichiers modifiés avec 2312 ajouts et 5 suppressions
  1. 12 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReview.java
  2. 55 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReviewImage.java
  3. 51 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReviewLike.java
  4. 76 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReviewReply.java
  5. 104 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerReview.java
  6. 55 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerReviewImage.java
  7. 51 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerReviewLike.java
  8. 76 0
      alien-entity/src/main/java/shop/alien/entity/store/LawyerReviewReply.java
  9. 46 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationReviewDto.java
  10. 29 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationReviewReplyDto.java
  11. 46 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerReviewDto.java
  12. 29 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerReviewReplyDto.java
  13. 49 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationReviewReplyVo.java
  14. 57 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationReviewVo.java
  15. 49 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerReviewReplyVo.java
  16. 57 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerReviewVo.java
  17. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationReviewImageMapper.java
  18. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationReviewLikeMapper.java
  19. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationReviewReplyMapper.java
  20. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerReviewImageMapper.java
  21. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerReviewLikeMapper.java
  22. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerReviewMapper.java
  23. 16 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerReviewReplyMapper.java
  24. 22 0
      alien-entity/src/main/resources/mapper/LawyerConsultationReviewImageMapper.xml
  25. 21 0
      alien-entity/src/main/resources/mapper/LawyerConsultationReviewLikeMapper.xml
  26. 5 2
      alien-entity/src/main/resources/mapper/LawyerConsultationReviewMapper.xml
  27. 28 0
      alien-entity/src/main/resources/mapper/LawyerConsultationReviewReplyMapper.xml
  28. 22 0
      alien-entity/src/main/resources/mapper/LawyerReviewImageMapper.xml
  29. 21 0
      alien-entity/src/main/resources/mapper/LawyerReviewLikeMapper.xml
  30. 37 0
      alien-entity/src/main/resources/mapper/LawyerReviewMapper.xml
  31. 28 0
      alien-entity/src/main/resources/mapper/LawyerReviewReplyMapper.xml
  32. 79 1
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerConsultationReviewController.java
  33. 121 0
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerReviewController.java
  34. 51 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerConsultationReviewService.java
  35. 77 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerReviewService.java
  36. 394 2
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationReviewServiceImpl.java
  37. 452 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerReviewServiceImpl.java

+ 12 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReview.java

@@ -58,6 +58,18 @@ public class LawyerConsultationReview extends Model<LawyerConsultationReview> {
     @TableField("professional_level")
     private Integer professionalLevel;
 
+    @ApiModelProperty(value = "是否匿名评价, 0:否, 1:是")
+    @TableField("is_anonymous")
+    private Integer isAnonymous;
+
+    @ApiModelProperty(value = "点赞数")
+    @TableField("like_count")
+    private Integer likeCount;
+
+    @ApiModelProperty(value = "回复数")
+    @TableField("reply_count")
+    private Integer replyCount;
+
     @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
     @TableField("delete_flag")
     @TableLogic

+ 55 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReviewImage.java

@@ -0,0 +1,55 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 咨询评价图片
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_consultation_review_image")
+@ApiModel(value = "LawyerConsultationReviewImage对象", description = "咨询评价图片")
+public class LawyerConsultationReviewImage extends Model<LawyerConsultationReviewImage> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "评价ID")
+    @TableField("review_id")
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "图片URL")
+    @TableField("image_url")
+    private String imageUrl;
+
+    @ApiModelProperty(value = "图片排序")
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+}
+

+ 51 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReviewLike.java

@@ -0,0 +1,51 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 咨询评价点赞
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_consultation_review_like")
+@ApiModel(value = "LawyerConsultationReviewLike对象", description = "咨询评价点赞")
+public class LawyerConsultationReviewLike extends Model<LawyerConsultationReviewLike> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "评价ID(如果是对评价点赞,此字段有值)")
+    @TableField("review_id")
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "回复ID(如果是对回复点赞,此字段有值)")
+    @TableField("reply_id")
+    private Integer replyId;
+
+    @ApiModelProperty(value = "点赞用户ID")
+    @TableField("like_user_id")
+    private Integer likeUserId;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+}
+

+ 76 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationReviewReply.java

@@ -0,0 +1,76 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 咨询评价回复
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_consultation_review_reply")
+@ApiModel(value = "LawyerConsultationReviewReply对象", description = "咨询评价回复")
+public class LawyerConsultationReviewReply extends Model<LawyerConsultationReviewReply> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "评价ID")
+    @TableField("review_id")
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "回复用户ID")
+    @TableField("reply_user_id")
+    private Integer replyUserId;
+
+    @ApiModelProperty(value = "被回复用户ID(如果是回复别人的回复,则此字段有值)")
+    @TableField("target_user_id")
+    private Integer targetUserId;
+
+    @ApiModelProperty(value = "父回复ID(用于嵌套回复,如果是直接回复评价,则为0)")
+    @TableField("parent_reply_id")
+    private Integer parentReplyId;
+
+    @ApiModelProperty(value = "回复内容")
+    @TableField("reply_content")
+    private String replyContent;
+
+    @ApiModelProperty(value = "点赞数")
+    @TableField("like_count")
+    private Integer likeCount;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}
+

+ 104 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerReview.java

@@ -0,0 +1,104 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 律师评价表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_review")
+@ApiModel(value = "LawyerReview对象", description = "律师评价表")
+public class LawyerReview extends Model<LawyerReview> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "咨询订单ID")
+    @TableField("order_id")
+    private Integer orderId;
+
+    @ApiModelProperty(value = "评价用户ID")
+    @TableField("user_id")
+    private Integer userId;
+
+    @ApiModelProperty(value = "被评价律师ID")
+    @TableField("lawyer_id")
+    private Integer lawyerId;
+
+    @ApiModelProperty(value = "总体评分, 1-5星")
+    @TableField("overall_rating")
+    private Integer overallRating;
+
+    @ApiModelProperty(value = "服务态度评分, 1-5星")
+    @TableField("service_attitude_rating")
+    private Integer serviceAttitudeRating;
+
+    @ApiModelProperty(value = "响应时间评分, 1-5星")
+    @TableField("response_time_rating")
+    private Integer responseTimeRating;
+
+    @ApiModelProperty(value = "专业能力评分, 1-5星")
+    @TableField("professional_ability_rating")
+    private Integer professionalAbilityRating;
+
+    @ApiModelProperty(value = "评价内容")
+    @TableField("review_content")
+    private String reviewContent;
+
+    @ApiModelProperty(value = "是否匿名评价, 0:否, 1:是")
+    @TableField("is_anonymous")
+    private Integer isAnonymous;
+
+    @ApiModelProperty(value = "点赞数")
+    @TableField("like_count")
+    private Integer likeCount;
+
+    @ApiModelProperty(value = "回复数")
+    @TableField("reply_count")
+    private Integer replyCount;
+
+    @ApiModelProperty(value = "审核状态, 0:待审核, 1:已通过, 2:已拒绝")
+    @TableField("audit_status")
+    private Integer auditStatus;
+
+    @ApiModelProperty(value = "审核原因")
+    @TableField("audit_reason")
+    private String auditReason;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}
+

+ 55 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerReviewImage.java

@@ -0,0 +1,55 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 律师评价图片表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_review_image")
+@ApiModel(value = "LawyerReviewImage对象", description = "律师评价图片表")
+public class LawyerReviewImage extends Model<LawyerReviewImage> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "评价ID")
+    @TableField("review_id")
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "图片URL")
+    @TableField("image_url")
+    private String imageUrl;
+
+    @ApiModelProperty(value = "图片排序")
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+}
+

+ 51 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerReviewLike.java

@@ -0,0 +1,51 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 律师评价点赞表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_review_like")
+@ApiModel(value = "LawyerReviewLike对象", description = "律师评价点赞表")
+public class LawyerReviewLike extends Model<LawyerReviewLike> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "评价ID(如果是对评价点赞,此字段有值)")
+    @TableField("review_id")
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "回复ID(如果是对回复点赞,此字段有值)")
+    @TableField("reply_id")
+    private Integer replyId;
+
+    @ApiModelProperty(value = "点赞用户ID")
+    @TableField("like_user_id")
+    private Integer likeUserId;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+}
+

+ 76 - 0
alien-entity/src/main/java/shop/alien/entity/store/LawyerReviewReply.java

@@ -0,0 +1,76 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 律师评价回复表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("lawyer_review_reply")
+@ApiModel(value = "LawyerReviewReply对象", description = "律师评价回复表")
+public class LawyerReviewReply extends Model<LawyerReviewReply> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "评价ID")
+    @TableField("review_id")
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "回复用户ID")
+    @TableField("reply_user_id")
+    private Integer replyUserId;
+
+    @ApiModelProperty(value = "被回复用户ID(如果是回复别人的回复,则此字段有值)")
+    @TableField("target_user_id")
+    private Integer targetUserId;
+
+    @ApiModelProperty(value = "父回复ID(用于嵌套回复,如果是直接回复评价,则为0)")
+    @TableField("parent_reply_id")
+    private Integer parentReplyId;
+
+    @ApiModelProperty(value = "回复内容")
+    @TableField("reply_content")
+    private String replyContent;
+
+    @ApiModelProperty(value = "点赞数")
+    @TableField("like_count")
+    private Integer likeCount;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}
+

+ 46 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationReviewDto.java

@@ -0,0 +1,46 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 咨询评价DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerConsultationReviewDto对象", description = "咨询评价DTO")
+public class LawyerConsultationReviewDto {
+
+    @ApiModelProperty(value = "咨询订单ID", required = true)
+    private Integer consultationOrderId;
+
+    @ApiModelProperty(value = "被评价律师ID", required = true)
+    private Integer lawyerUserId;
+
+    @ApiModelProperty(value = "总体评分, 1-5星", required = true)
+    private Integer rating;
+
+    @ApiModelProperty(value = "服务态度评分, 1-5星", required = true)
+    private Integer serviceQuality;
+
+    @ApiModelProperty(value = "响应时间评分, 1-5星", required = true)
+    private Integer responseSpeed;
+
+    @ApiModelProperty(value = "专业能力评分, 1-5星", required = true)
+    private Integer professionalLevel;
+
+    @ApiModelProperty(value = "评价内容")
+    private String comment;
+
+    @ApiModelProperty(value = "评价图片URL列表")
+    private List<String> imageUrls;
+
+    @ApiModelProperty(value = "是否匿名评价, 0:否, 1:是")
+    private Integer isAnonymous;
+}
+

+ 29 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationReviewReplyDto.java

@@ -0,0 +1,29 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 咨询评价回复DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerConsultationReviewReplyDto对象", description = "咨询评价回复DTO")
+public class LawyerConsultationReviewReplyDto {
+
+    @ApiModelProperty(value = "评价ID", required = true)
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "回复内容", required = true)
+    private String replyContent;
+
+    @ApiModelProperty(value = "被回复用户ID(如果是回复别人的回复,则此字段有值)")
+    private Integer targetUserId;
+
+    @ApiModelProperty(value = "父回复ID(用于嵌套回复,如果是直接回复评价,则为0)")
+    private Integer parentReplyId;
+}
+

+ 46 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerReviewDto.java

@@ -0,0 +1,46 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 律师评价DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerReviewDto对象", description = "律师评价DTO")
+public class LawyerReviewDto {
+
+    @ApiModelProperty(value = "咨询订单ID", required = true)
+    private Integer orderId;
+
+    @ApiModelProperty(value = "被评价律师ID", required = true)
+    private Integer lawyerId;
+
+    @ApiModelProperty(value = "总体评分, 1-5星", required = true)
+    private Integer overallRating;
+
+    @ApiModelProperty(value = "服务态度评分, 1-5星", required = true)
+    private Integer serviceAttitudeRating;
+
+    @ApiModelProperty(value = "响应时间评分, 1-5星", required = true)
+    private Integer responseTimeRating;
+
+    @ApiModelProperty(value = "专业能力评分, 1-5星", required = true)
+    private Integer professionalAbilityRating;
+
+    @ApiModelProperty(value = "评价内容")
+    private String reviewContent;
+
+    @ApiModelProperty(value = "评价图片URL列表")
+    private List<String> imageUrls;
+
+    @ApiModelProperty(value = "是否匿名评价, 0:否, 1:是")
+    private Integer isAnonymous;
+}
+

+ 29 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerReviewReplyDto.java

@@ -0,0 +1,29 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 律师评价回复DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerReviewReplyDto对象", description = "律师评价回复DTO")
+public class LawyerReviewReplyDto {
+
+    @ApiModelProperty(value = "评价ID", required = true)
+    private Integer reviewId;
+
+    @ApiModelProperty(value = "回复内容", required = true)
+    private String replyContent;
+
+    @ApiModelProperty(value = "被回复用户ID(如果是回复别人的回复,则此字段有值)")
+    private Integer targetUserId;
+
+    @ApiModelProperty(value = "父回复ID(用于嵌套回复,如果是直接回复评价,则为0)")
+    private Integer parentReplyId;
+}
+

+ 49 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationReviewReplyVo.java

@@ -0,0 +1,49 @@
+package shop.alien.entity.store.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.LawyerConsultationReviewReply;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 咨询评价回复VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "LawyerConsultationReviewReplyVo对象", description = "咨询评价回复VO")
+public class LawyerConsultationReviewReplyVo extends LawyerConsultationReviewReply {
+
+    @ApiModelProperty(value = "回复用户名称")
+    @TableField(exist = false)
+    private String replyUserName;
+
+    @ApiModelProperty(value = "回复用户头像")
+    @TableField(exist = false)
+    private String replyUserImage;
+
+    @ApiModelProperty(value = "被回复用户名称")
+    @TableField(exist = false)
+    private String targetUserName;
+
+    @ApiModelProperty(value = "被回复用户头像")
+    @TableField(exist = false)
+    private String targetUserImage;
+
+    @ApiModelProperty(value = "子回复列表(嵌套回复)")
+    @TableField(exist = false)
+    private List<LawyerConsultationReviewReplyVo> childReplies;
+
+    @ApiModelProperty(value = "当前用户是否已点赞, 0:否, 1:是")
+    @TableField(exist = false)
+    private Integer isLiked;
+}
+

+ 57 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationReviewVo.java

@@ -0,0 +1,57 @@
+package shop.alien.entity.store.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.LawyerConsultationReview;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 咨询评价VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "LawyerConsultationReviewVo对象", description = "咨询评价VO")
+public class LawyerConsultationReviewVo extends LawyerConsultationReview {
+
+    @ApiModelProperty(value = "评价用户名称")
+    @TableField(exist = false)
+    private String clientUserName;
+
+    @ApiModelProperty(value = "评价用户头像")
+    @TableField(exist = false)
+    private String clientUserImage;
+
+    @ApiModelProperty(value = "被评价律师名称")
+    @TableField(exist = false)
+    private String lawyerUserName;
+
+    @ApiModelProperty(value = "被评价律师头像")
+    @TableField(exist = false)
+    private String lawyerUserImage;
+
+    @ApiModelProperty(value = "评价图片列表")
+    @TableField(exist = false)
+    private List<String> imageUrls;
+
+    @ApiModelProperty(value = "回复列表")
+    @TableField(exist = false)
+    private List<LawyerConsultationReviewReplyVo> replies;
+
+    @ApiModelProperty(value = "当前用户是否已点赞, 0:否, 1:是")
+    @TableField(exist = false)
+    private Integer isLiked;
+
+    @ApiModelProperty(value = "订单编号")
+    @TableField(exist = false)
+    private String orderNumber;
+}
+

+ 49 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerReviewReplyVo.java

@@ -0,0 +1,49 @@
+package shop.alien.entity.store.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.LawyerReviewReply;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 律师评价回复VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "LawyerReviewReplyVo对象", description = "律师评价回复VO")
+public class LawyerReviewReplyVo extends LawyerReviewReply {
+
+    @ApiModelProperty(value = "回复用户名称")
+    @TableField(exist = false)
+    private String replyUserName;
+
+    @ApiModelProperty(value = "回复用户头像")
+    @TableField(exist = false)
+    private String replyUserImage;
+
+    @ApiModelProperty(value = "被回复用户名称")
+    @TableField(exist = false)
+    private String targetUserName;
+
+    @ApiModelProperty(value = "被回复用户头像")
+    @TableField(exist = false)
+    private String targetUserImage;
+
+    @ApiModelProperty(value = "子回复列表(嵌套回复)")
+    @TableField(exist = false)
+    private List<LawyerReviewReplyVo> childReplies;
+
+    @ApiModelProperty(value = "当前用户是否已点赞, 0:否, 1:是")
+    @TableField(exist = false)
+    private Integer isLiked;
+}
+

+ 57 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerReviewVo.java

@@ -0,0 +1,57 @@
+package shop.alien.entity.store.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.LawyerReview;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 律师评价VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "LawyerReviewVo对象", description = "律师评价VO")
+public class LawyerReviewVo extends LawyerReview {
+
+    @ApiModelProperty(value = "评价用户名称")
+    @TableField(exist = false)
+    private String userName;
+
+    @ApiModelProperty(value = "评价用户头像")
+    @TableField(exist = false)
+    private String userImage;
+
+    @ApiModelProperty(value = "被评价律师名称")
+    @TableField(exist = false)
+    private String lawyerName;
+
+    @ApiModelProperty(value = "被评价律师头像")
+    @TableField(exist = false)
+    private String lawyerImage;
+
+    @ApiModelProperty(value = "评价图片列表")
+    @TableField(exist = false)
+    private List<String> imageUrls;
+
+    @ApiModelProperty(value = "回复列表")
+    @TableField(exist = false)
+    private List<LawyerReviewReplyVo> replies;
+
+    @ApiModelProperty(value = "当前用户是否已点赞, 0:否, 1:是")
+    @TableField(exist = false)
+    private Integer isLiked;
+
+    @ApiModelProperty(value = "订单编号")
+    @TableField(exist = false)
+    private String orderNumber;
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationReviewImageMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerConsultationReviewImage;
+
+/**
+ * 咨询评价图片 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerConsultationReviewImageMapper extends BaseMapper<LawyerConsultationReviewImage> {
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationReviewLikeMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerConsultationReviewLike;
+
+/**
+ * 咨询评价点赞 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerConsultationReviewLikeMapper extends BaseMapper<LawyerConsultationReviewLike> {
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationReviewReplyMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerConsultationReviewReply;
+
+/**
+ * 咨询评价回复 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerConsultationReviewReplyMapper extends BaseMapper<LawyerConsultationReviewReply> {
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerReviewImageMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerReviewImage;
+
+/**
+ * 律师评价图片 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerReviewImageMapper extends BaseMapper<LawyerReviewImage> {
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerReviewLikeMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerReviewLike;
+
+/**
+ * 律师评价点赞 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerReviewLikeMapper extends BaseMapper<LawyerReviewLike> {
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerReviewMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerReview;
+
+/**
+ * 律师评价 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerReviewMapper extends BaseMapper<LawyerReview> {
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerReviewReplyMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LawyerReviewReply;
+
+/**
+ * 律师评价回复 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerReviewReplyMapper extends BaseMapper<LawyerReviewReply> {
+}
+

+ 22 - 0
alien-entity/src/main/resources/mapper/LawyerConsultationReviewImageMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerConsultationReviewImageMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerConsultationReviewImage">
+        <id column="id" property="id" />
+        <result column="review_id" property="reviewId" />
+        <result column="image_url" property="imageUrl" />
+        <result column="sort_order" property="sortOrder" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="created_user_id" property="createdUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, review_id, image_url, sort_order, delete_flag, created_time, created_user_id
+    </sql>
+
+</mapper>
+

+ 21 - 0
alien-entity/src/main/resources/mapper/LawyerConsultationReviewLikeMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerConsultationReviewLikeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerConsultationReviewLike">
+        <id column="id" property="id" />
+        <result column="review_id" property="reviewId" />
+        <result column="reply_id" property="replyId" />
+        <result column="like_user_id" property="likeUserId" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, review_id, reply_id, like_user_id, delete_flag, created_time
+    </sql>
+
+</mapper>
+

+ 5 - 2
alien-entity/src/main/resources/mapper/LawyerConsultationReviewMapper.xml

@@ -13,6 +13,9 @@
         <result column="service_quality" property="serviceQuality" />
         <result column="response_speed" property="responseSpeed" />
         <result column="professional_level" property="professionalLevel" />
+        <result column="is_anonymous" property="isAnonymous" />
+        <result column="like_count" property="likeCount" />
+        <result column="reply_count" property="replyCount" />
         <result column="delete_flag" property="deleteFlag" />
         <result column="created_time" property="createdTime" />
         <result column="created_user_id" property="createdUserId" />
@@ -23,8 +26,8 @@
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
         id, consultation_order_id, client_user_id, lawyer_user_id, rating, comment,
-        service_quality, response_speed, professional_level, delete_flag, created_time,
-        created_user_id, updated_time, updated_user_id
+        service_quality, response_speed, professional_level, is_anonymous, like_count, reply_count,
+        delete_flag, created_time, created_user_id, updated_time, updated_user_id
     </sql>
 
 </mapper>

+ 28 - 0
alien-entity/src/main/resources/mapper/LawyerConsultationReviewReplyMapper.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerConsultationReviewReplyMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerConsultationReviewReply">
+        <id column="id" property="id" />
+        <result column="review_id" property="reviewId" />
+        <result column="reply_user_id" property="replyUserId" />
+        <result column="target_user_id" property="targetUserId" />
+        <result column="parent_reply_id" property="parentReplyId" />
+        <result column="reply_content" property="replyContent" />
+        <result column="like_count" property="likeCount" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="created_user_id" property="createdUserId" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="updated_user_id" property="updatedUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, review_id, reply_user_id, target_user_id, parent_reply_id, reply_content,
+        like_count, delete_flag, created_time, created_user_id, updated_time, updated_user_id
+    </sql>
+
+</mapper>
+

+ 22 - 0
alien-entity/src/main/resources/mapper/LawyerReviewImageMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerReviewImageMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerReviewImage">
+        <id column="id" property="id" />
+        <result column="review_id" property="reviewId" />
+        <result column="image_url" property="imageUrl" />
+        <result column="sort_order" property="sortOrder" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="created_user_id" property="createdUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, review_id, image_url, sort_order, delete_flag, created_time, created_user_id
+    </sql>
+
+</mapper>
+

+ 21 - 0
alien-entity/src/main/resources/mapper/LawyerReviewLikeMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerReviewLikeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerReviewLike">
+        <id column="id" property="id" />
+        <result column="review_id" property="reviewId" />
+        <result column="reply_id" property="replyId" />
+        <result column="like_user_id" property="likeUserId" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, review_id, reply_id, like_user_id, delete_flag, created_time
+    </sql>
+
+</mapper>
+

+ 37 - 0
alien-entity/src/main/resources/mapper/LawyerReviewMapper.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerReviewMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerReview">
+        <id column="id" property="id" />
+        <result column="order_id" property="orderId" />
+        <result column="user_id" property="userId" />
+        <result column="lawyer_id" property="lawyerId" />
+        <result column="overall_rating" property="overallRating" />
+        <result column="service_attitude_rating" property="serviceAttitudeRating" />
+        <result column="response_time_rating" property="responseTimeRating" />
+        <result column="professional_ability_rating" property="professionalAbilityRating" />
+        <result column="review_content" property="reviewContent" />
+        <result column="is_anonymous" property="isAnonymous" />
+        <result column="like_count" property="likeCount" />
+        <result column="reply_count" property="replyCount" />
+        <result column="audit_status" property="auditStatus" />
+        <result column="audit_reason" property="auditReason" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="created_user_id" property="createdUserId" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="updated_user_id" property="updatedUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, order_id, user_id, lawyer_id, overall_rating, service_attitude_rating,
+        response_time_rating, professional_ability_rating, review_content, is_anonymous,
+        like_count, reply_count, audit_status, audit_reason, delete_flag, created_time,
+        created_user_id, updated_time, updated_user_id
+    </sql>
+
+</mapper>
+

+ 28 - 0
alien-entity/src/main/resources/mapper/LawyerReviewReplyMapper.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.LawyerReviewReplyMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LawyerReviewReply">
+        <id column="id" property="id" />
+        <result column="review_id" property="reviewId" />
+        <result column="reply_user_id" property="replyUserId" />
+        <result column="target_user_id" property="targetUserId" />
+        <result column="parent_reply_id" property="parentReplyId" />
+        <result column="reply_content" property="replyContent" />
+        <result column="like_count" property="likeCount" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="created_user_id" property="createdUserId" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="updated_user_id" property="updatedUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, review_id, reply_user_id, target_user_id, parent_reply_id, reply_content,
+        like_count, delete_flag, created_time, created_user_id, updated_time, updated_user_id
+    </sql>
+
+</mapper>
+

+ 79 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerConsultationReviewController.java

@@ -7,8 +7,14 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawyerConsultationReview;
+import shop.alien.entity.store.UserLoginInfo;
+import shop.alien.entity.store.dto.LawyerConsultationReviewDto;
+import shop.alien.entity.store.dto.LawyerConsultationReviewReplyDto;
+import shop.alien.entity.store.vo.LawyerConsultationReviewVo;
 import shop.alien.lawyer.service.LawyerConsultationReviewService;
+import shop.alien.util.common.TokenInfo;
 import shop.alien.util.myBaticsPlus.QueryBuilder;
+import springfox.documentation.annotations.ApiIgnore;
 
 import java.util.List;
 
@@ -23,7 +29,7 @@ import java.util.List;
 @ApiSort(19)
 @CrossOrigin
 @RestController
-@RequestMapping("/lawyer/consultationReview")
+@RequestMapping("/lawyer/consultationReview/createReview")
 @RequiredArgsConstructor
 public class LawyerConsultationReviewController {
 
@@ -111,5 +117,77 @@ public class LawyerConsultationReviewController {
                 .page(consultationReviewService);
         return R.data(pageResult);
     }
+
+    @ApiOperation("创建评价(包含图片)")
+    @ApiOperationSupport(order = 7)
+    @PostMapping("/createReview")
+    public R<LawyerConsultationReviewVo> createReview(@RequestBody LawyerConsultationReviewDto reviewDto,
+                                                       @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerConsultationReviewController.createReview?reviewDto={}, userId={}", reviewDto, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        if (userLoginInfo == null) {
+            return R.fail("用户未登录");
+        }
+        return consultationReviewService.createReview(reviewDto, userLoginInfo.getUserId());
+    }
+
+    @ApiOperation("获取评价详情")
+    @ApiOperationSupport(order = 8)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "Integer", paramType = "path", required = true)
+    })
+    @GetMapping("/detail/{reviewId}")
+    public R<LawyerConsultationReviewVo> getReviewDetail(@PathVariable Integer reviewId,
+                                                        @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerConsultationReviewController.getReviewDetail?reviewId={}, userId={}", reviewId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        return consultationReviewService.getReviewDetail(reviewId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+    }
+
+    @ApiOperation("分页查询评价列表(带详情)")
+    @ApiOperationSupport(order = 9)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "页数(默认1)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "size", value = "页容(默认10)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "lawyerUserId", value = "律师用户ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/list")
+    public R<IPage<LawyerConsultationReviewVo>> getReviewList(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "10") int size,
+            @RequestParam Integer lawyerUserId,
+            @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerConsultationReviewController.getReviewList?page={}, size={}, lawyerUserId={}, userId={}",
+                page, size, lawyerUserId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        return consultationReviewService.getReviewListWithDetail(page, size, lawyerUserId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+    }
+
+    @ApiOperation("添加回复")
+    @ApiOperationSupport(order = 10)
+    @PostMapping("/reply")
+    public R<Boolean> addReply(@RequestBody LawyerConsultationReviewReplyDto replyDto,
+                               @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerConsultationReviewController.addReply?replyDto={}, userId={}", replyDto, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        if (userLoginInfo == null) {
+            return R.fail("用户未登录");
+        }
+        return consultationReviewService.addReply(replyDto, userLoginInfo.getUserId());
+    }
+
+    @ApiOperation("点赞/取消点赞")
+    @ApiOperationSupport(order = 11)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID(如果是对评价点赞)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "replyId", value = "回复ID(如果是对回复点赞)", dataType = "Integer", paramType = "query")
+    })
+    @PostMapping("/like")
+    public R<Boolean> toggleLike(@RequestParam(required = false) Integer reviewId,
+                                 @RequestParam(required = false) Integer replyId,
+                                 @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerConsultationReviewController.toggleLike?reviewId={}, replyId={}, userId={}",
+                reviewId, replyId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        if (userLoginInfo == null) {
+            return R.fail("用户未登录");
+        }
+        return consultationReviewService.toggleLike(reviewId, replyId, userLoginInfo.getUserId());
+    }
 }
 

+ 121 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerReviewController.java

@@ -0,0 +1,121 @@
+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 shop.alien.entity.result.R;
+import shop.alien.entity.store.UserLoginInfo;
+import shop.alien.entity.store.dto.LawyerReviewDto;
+import shop.alien.entity.store.dto.LawyerReviewReplyDto;
+import shop.alien.entity.store.vo.LawyerReviewVo;
+import shop.alien.lawyer.service.LawyerReviewService;
+import shop.alien.util.common.TokenInfo;
+import springfox.documentation.annotations.ApiIgnore;
+
+/**
+ * 律师评价 前端控制器
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"律师平台-律师评价"})
+@ApiSort(20)
+@CrossOrigin
+@RestController
+@RequestMapping("/lawyer/review")
+@RequiredArgsConstructor
+public class LawyerReviewController {
+
+    private final LawyerReviewService lawyerReviewService;
+
+    @ApiOperation("创建评价(包含图片)")
+    @ApiOperationSupport(order = 1)
+    @PostMapping("/create")
+    public R<LawyerReviewVo> createReview(@RequestBody LawyerReviewDto reviewDto,
+                                          @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerReviewController.createReview?reviewDto={}, userId={}", reviewDto, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        if (userLoginInfo == null) {
+            return R.fail("用户未登录");
+        }
+        return lawyerReviewService.createReview(reviewDto, userLoginInfo.getUserId());
+    }
+
+    @ApiOperation("获取评价详情")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "Integer", paramType = "path", required = true)
+    })
+    @GetMapping("/detail/{reviewId}")
+    public R<LawyerReviewVo> getReviewDetail(@PathVariable Integer reviewId,
+                                             @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerReviewController.getReviewDetail?reviewId={}, userId={}", reviewId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        return lawyerReviewService.getReviewDetail(reviewId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+    }
+
+    @ApiOperation("分页查询评价列表(带详情)")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "页数(默认1)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "size", value = "页容(默认10)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "lawyerId", value = "律师ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/list")
+    public R<IPage<LawyerReviewVo>> getReviewList(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "10") int size,
+            @RequestParam Integer lawyerId,
+            @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerReviewController.getReviewList?page={}, size={}, lawyerId={}, userId={}",
+                page, size, lawyerId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        return lawyerReviewService.getReviewListWithDetail(page, size, lawyerId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+    }
+
+    @ApiOperation("添加回复")
+    @ApiOperationSupport(order = 4)
+    @PostMapping("/reply")
+    public R<Boolean> addReply(@RequestBody LawyerReviewReplyDto replyDto,
+                               @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerReviewController.addReply?replyDto={}, userId={}", replyDto, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        if (userLoginInfo == null) {
+            return R.fail("用户未登录");
+        }
+        return lawyerReviewService.addReply(replyDto, userLoginInfo.getUserId());
+    }
+
+    @ApiOperation("点赞/取消点赞")
+    @ApiOperationSupport(order = 5)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID(如果是对评价点赞)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "replyId", value = "回复ID(如果是对回复点赞)", dataType = "Integer", paramType = "query")
+    })
+    @PostMapping("/like")
+    public R<Boolean> toggleLike(@RequestParam(required = false) Integer reviewId,
+                                @RequestParam(required = false) Integer replyId,
+                                @ApiIgnore @TokenInfo UserLoginInfo userLoginInfo) {
+        log.info("LawyerReviewController.toggleLike?reviewId={}, replyId={}, userId={}",
+                reviewId, replyId, userLoginInfo != null ? userLoginInfo.getUserId() : null);
+        if (userLoginInfo == null) {
+            return R.fail("用户未登录");
+        }
+        return lawyerReviewService.toggleLike(reviewId, replyId, userLoginInfo.getUserId());
+    }
+
+    @ApiOperation("审核评价")
+    @ApiOperationSupport(order = 6)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "auditStatus", value = "审核状态, 1:通过, 2:拒绝", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "auditReason", value = "审核原因", dataType = "String", paramType = "query")
+    })
+    @PostMapping("/audit")
+    public R<Boolean> auditReview(@RequestParam Integer reviewId,
+                                  @RequestParam Integer auditStatus,
+                                  @RequestParam(required = false) String auditReason) {
+        log.info("LawyerReviewController.auditReview?reviewId={}, auditStatus={}, auditReason={}", reviewId, auditStatus, auditReason);
+        return lawyerReviewService.auditReview(reviewId, auditStatus, auditReason);
+    }
+}
+

+ 51 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerConsultationReviewService.java

@@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawyerConsultationReview;
+import shop.alien.entity.store.dto.LawyerConsultationReviewDto;
+import shop.alien.entity.store.dto.LawyerConsultationReviewReplyDto;
+import shop.alien.entity.store.vo.LawyerConsultationReviewVo;
 
 import java.util.List;
 
@@ -59,5 +62,53 @@ public interface LawyerConsultationReviewService extends IService<LawyerConsulta
      * @return R<Boolean>
      */
     R<Boolean> deleteConsultationReview(Integer id);
+
+    /**
+     * 创建评价(包含图片)
+     *
+     * @param reviewDto 评价DTO
+     * @param clientUserId 评价用户ID
+     * @return R<LawyerConsultationReviewVo>
+     */
+    R<LawyerConsultationReviewVo> createReview(LawyerConsultationReviewDto reviewDto, Integer clientUserId);
+
+    /**
+     * 获取评价详情
+     *
+     * @param reviewId 评价ID
+     * @param currentUserId 当前用户ID(用于判断是否点赞)
+     * @return R<LawyerConsultationReviewVo>
+     */
+    R<LawyerConsultationReviewVo> getReviewDetail(Integer reviewId, Integer currentUserId);
+
+    /**
+     * 分页查询评价列表(带用户信息和图片)
+     *
+     * @param pageNum 页码
+     * @param pageSize 页大小
+     * @param lawyerUserId 律师ID
+     * @param currentUserId 当前用户ID(用于判断是否点赞)
+     * @return R<IPage<LawyerConsultationReviewVo>>
+     */
+    R<IPage<LawyerConsultationReviewVo>> getReviewListWithDetail(int pageNum, int pageSize, Integer lawyerUserId, Integer currentUserId);
+
+    /**
+     * 添加回复
+     *
+     * @param replyDto 回复DTO
+     * @param replyUserId 回复用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> addReply(LawyerConsultationReviewReplyDto replyDto, Integer replyUserId);
+
+    /**
+     * 点赞/取消点赞
+     *
+     * @param reviewId 评价ID(如果是对评价点赞)
+     * @param replyId 回复ID(如果是对回复点赞)
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> toggleLike(Integer reviewId, Integer replyId, Integer userId);
 }
 

+ 77 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerReviewService.java

@@ -0,0 +1,77 @@
+package shop.alien.lawyer.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.LawyerReview;
+import shop.alien.entity.store.dto.LawyerReviewDto;
+import shop.alien.entity.store.dto.LawyerReviewReplyDto;
+import shop.alien.entity.store.vo.LawyerReviewVo;
+
+/**
+ * 律师评价 服务类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface LawyerReviewService extends IService<LawyerReview> {
+
+    /**
+     * 创建评价(包含图片)
+     *
+     * @param reviewDto 评价DTO
+     * @param userId 评价用户ID
+     * @return R<LawyerReviewVo>
+     */
+    R<LawyerReviewVo> createReview(LawyerReviewDto reviewDto, Integer userId);
+
+    /**
+     * 获取评价详情
+     *
+     * @param reviewId 评价ID
+     * @param currentUserId 当前用户ID(用于判断是否点赞)
+     * @return R<LawyerReviewVo>
+     */
+    R<LawyerReviewVo> getReviewDetail(Integer reviewId, Integer currentUserId);
+
+    /**
+     * 分页查询评价列表(带用户信息和图片)
+     *
+     * @param pageNum 页码
+     * @param pageSize 页大小
+     * @param lawyerId 律师ID
+     * @param currentUserId 当前用户ID(用于判断是否点赞)
+     * @return R<IPage<LawyerReviewVo>>
+     */
+    R<IPage<LawyerReviewVo>> getReviewListWithDetail(int pageNum, int pageSize, Integer lawyerId, Integer currentUserId);
+
+    /**
+     * 添加回复
+     *
+     * @param replyDto 回复DTO
+     * @param replyUserId 回复用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> addReply(LawyerReviewReplyDto replyDto, Integer replyUserId);
+
+    /**
+     * 点赞/取消点赞
+     *
+     * @param reviewId 评价ID(如果是对评价点赞)
+     * @param replyId 回复ID(如果是对回复点赞)
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> toggleLike(Integer reviewId, Integer replyId, Integer userId);
+
+    /**
+     * 审核评价
+     *
+     * @param reviewId 评价ID
+     * @param auditStatus 审核状态, 1:通过, 2:拒绝
+     * @param auditReason 审核原因
+     * @return R<Boolean>
+     */
+    R<Boolean> auditReview(Integer reviewId, Integer auditStatus, String auditReason);
+}
+

+ 394 - 2
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationReviewServiceImpl.java

@@ -6,14 +6,21 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.LawyerConsultationReview;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.dto.LawyerConsultationReviewDto;
+import shop.alien.entity.store.dto.LawyerConsultationReviewReplyDto;
+import shop.alien.entity.store.vo.LawyerConsultationReviewReplyVo;
+import shop.alien.entity.store.vo.LawyerConsultationReviewVo;
 import shop.alien.lawyer.service.LawyerConsultationReviewService;
-import shop.alien.mapper.LawyerConsultationReviewMapper;
+import shop.alien.mapper.*;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 咨询评价 服务实现类
@@ -28,6 +35,12 @@ import java.util.List;
 public class LawyerConsultationReviewServiceImpl extends ServiceImpl<LawyerConsultationReviewMapper, LawyerConsultationReview> implements LawyerConsultationReviewService {
 
     private final LawyerConsultationReviewMapper consultationReviewMapper;
+    private final LawyerConsultationReviewImageMapper reviewImageMapper;
+    private final LawyerConsultationReviewReplyMapper reviewReplyMapper;
+    private final LawyerConsultationReviewLikeMapper reviewLikeMapper;
+    private final LawyerUserMapper lawyerUserMapper;
+    private final LifeUserMapper lifeUserMapper;
+    private final LawyerConsultationOrderMapper consultationOrderMapper;
 
     @Override
     public R<IPage<LawyerConsultationReview>> getConsultationReviewList(int pageNum, int pageSize, Integer consultationOrderId,
@@ -90,5 +103,384 @@ public class LawyerConsultationReviewServiceImpl extends ServiceImpl<LawyerConsu
         }
         return R.fail("删除失败");
     }
+
+    @Override
+    public R<LawyerConsultationReviewVo> createReview(LawyerConsultationReviewDto reviewDto, Integer clientUserId) {
+        log.info("LawyerConsultationReviewServiceImpl.createReview?reviewDto={}, clientUserId={}", reviewDto, clientUserId);
+        try {
+            // 检查订单是否存在且属于该用户
+            LawyerConsultationOrder order = consultationOrderMapper.selectById(reviewDto.getConsultationOrderId());
+            if (order == null || !order.getClientUserId().equals(clientUserId)) {
+                return R.fail("订单不存在或不属于当前用户");
+            }
+
+            // 检查是否已经评价过
+            LambdaQueryWrapper<LawyerConsultationReview> checkWrapper = new LambdaQueryWrapper<>();
+            checkWrapper.eq(LawyerConsultationReview::getConsultationOrderId, reviewDto.getConsultationOrderId())
+                    .eq(LawyerConsultationReview::getDeleteFlag, 0);
+            long count = this.count(checkWrapper);
+            if (count > 0) {
+                return R.fail("该订单已评价,不能重复评价");
+            }
+
+            // 创建评价
+            LawyerConsultationReview review = new LawyerConsultationReview();
+            review.setConsultationOrderId(reviewDto.getConsultationOrderId());
+            review.setClientUserId(clientUserId);
+            review.setLawyerUserId(reviewDto.getLawyerUserId());
+            review.setRating(reviewDto.getRating());
+            review.setServiceQuality(reviewDto.getServiceQuality());
+            review.setResponseSpeed(reviewDto.getResponseSpeed());
+            review.setProfessionalLevel(reviewDto.getProfessionalLevel());
+            review.setComment(reviewDto.getComment());
+            review.setIsAnonymous(reviewDto.getIsAnonymous() != null ? reviewDto.getIsAnonymous() : 0);
+            review.setLikeCount(0);
+            review.setReplyCount(0);
+            review.setCreatedUserId(clientUserId);
+
+            boolean saved = this.save(review);
+            if (!saved) {
+                return R.fail("创建评价失败");
+            }
+
+            // 保存评价图片
+            if (reviewDto.getImageUrls() != null && !reviewDto.getImageUrls().isEmpty()) {
+                for (int i = 0; i < reviewDto.getImageUrls().size(); i++) {
+                    LawyerConsultationReviewImage image = new LawyerConsultationReviewImage();
+                    image.setReviewId(review.getId());
+                    image.setImageUrl(reviewDto.getImageUrls().get(i));
+                    image.setSortOrder(i + 1);
+                    image.setCreatedUserId(clientUserId);
+                    reviewImageMapper.insert(image);
+                }
+            }
+
+            // 更新律师评分统计
+            updateLawyerRatingStats(reviewDto.getLawyerUserId());
+
+            // 返回评价详情
+            return getReviewDetail(review.getId(), clientUserId);
+        } catch (Exception e) {
+            log.error("创建评价失败", e);
+            return R.fail("创建评价失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<LawyerConsultationReviewVo> getReviewDetail(Integer reviewId, Integer currentUserId) {
+        log.info("LawyerConsultationReviewServiceImpl.getReviewDetail?reviewId={}, currentUserId={}", reviewId, currentUserId);
+        try {
+            LawyerConsultationReview review = this.getById(reviewId);
+            if (review == null || review.getDeleteFlag() == 1) {
+                return R.fail("评价不存在");
+            }
+
+            LawyerConsultationReviewVo vo = new LawyerConsultationReviewVo();
+            BeanUtils.copyProperties(review, vo);
+
+            // 查询评价图片
+            LambdaQueryWrapper<LawyerConsultationReviewImage> imageWrapper = new LambdaQueryWrapper<>();
+            imageWrapper.eq(LawyerConsultationReviewImage::getReviewId, reviewId)
+                    .eq(LawyerConsultationReviewImage::getDeleteFlag, 0)
+                    .orderByAsc(LawyerConsultationReviewImage::getSortOrder);
+            List<LawyerConsultationReviewImage> images = reviewImageMapper.selectList(imageWrapper);
+            vo.setImageUrls(images.stream().map(LawyerConsultationReviewImage::getImageUrl).collect(Collectors.toList()));
+
+            // 查询用户信息
+            if (review.getIsAnonymous() == 0) {
+                LifeUser clientUser = lifeUserMapper.selectById(review.getClientUserId());
+                if (clientUser != null) {
+                    vo.setClientUserName(clientUser.getUserName());
+                    vo.setClientUserImage(clientUser.getUserImage());
+                }
+            } else {
+                vo.setClientUserName("匿名用户");
+            }
+
+            LawyerUser lawyerUser = lawyerUserMapper.selectById(review.getLawyerUserId());
+            if (lawyerUser != null) {
+                vo.setLawyerUserName(lawyerUser.getName());
+                vo.setLawyerUserImage(lawyerUser.getHeadImg());
+            }
+
+            // 查询订单信息
+            LawyerConsultationOrder order = consultationOrderMapper.selectById(review.getConsultationOrderId());
+            if (order != null) {
+                vo.setOrderNumber(order.getOrderNumber());
+            }
+
+            // 查询回复列表
+            List<LawyerConsultationReviewReplyVo> replies = getReplyList(reviewId, currentUserId);
+            vo.setReplies(replies);
+
+            // 查询是否已点赞
+            if (currentUserId != null) {
+                LambdaQueryWrapper<LawyerConsultationReviewLike> likeWrapper = new LambdaQueryWrapper<>();
+                likeWrapper.eq(LawyerConsultationReviewLike::getReviewId, reviewId)
+                        .eq(LawyerConsultationReviewLike::getLikeUserId, currentUserId)
+                        .eq(LawyerConsultationReviewLike::getDeleteFlag, 0);
+                long likeCount = reviewLikeMapper.selectCount(likeWrapper);
+                vo.setIsLiked(likeCount > 0 ? 1 : 0);
+            } else {
+                vo.setIsLiked(0);
+            }
+
+            return R.data(vo);
+        } catch (Exception e) {
+            log.error("获取评价详情失败", e);
+            return R.fail("获取评价详情失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<IPage<LawyerConsultationReviewVo>> getReviewListWithDetail(int pageNum, int pageSize, Integer lawyerUserId, Integer currentUserId) {
+        log.info("LawyerConsultationReviewServiceImpl.getReviewListWithDetail?pageNum={}, pageSize={}, lawyerUserId={}, currentUserId={}",
+                pageNum, pageSize, lawyerUserId, currentUserId);
+        try {
+            Page<LawyerConsultationReview> page = new Page<>(pageNum, pageSize);
+            LambdaQueryWrapper<LawyerConsultationReview> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(LawyerConsultationReview::getLawyerUserId, lawyerUserId)
+                    .eq(LawyerConsultationReview::getDeleteFlag, 0)
+                    .orderByDesc(LawyerConsultationReview::getCreatedTime);
+            IPage<LawyerConsultationReview> pageResult = this.page(page, queryWrapper);
+
+            // 转换为VO
+            Page<LawyerConsultationReviewVo> voPage = new Page<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
+            List<LawyerConsultationReviewVo> voList = new ArrayList<>();
+            for (LawyerConsultationReview review : pageResult.getRecords()) {
+                R<LawyerConsultationReviewVo> detailResult = getReviewDetail(review.getId(), currentUserId);
+                if (detailResult.getCode() == 200 && detailResult.getData() != null) {
+                    voList.add(detailResult.getData());
+                }
+            }
+            voPage.setRecords(voList);
+            return R.data(voPage);
+        } catch (Exception e) {
+            log.error("获取评价列表失败", e);
+            return R.fail("获取评价列表失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<Boolean> addReply(LawyerConsultationReviewReplyDto replyDto, Integer replyUserId) {
+        log.info("LawyerConsultationReviewServiceImpl.addReply?replyDto={}, replyUserId={}", replyDto, replyUserId);
+        try {
+            // 检查评价是否存在
+            LawyerConsultationReview review = this.getById(replyDto.getReviewId());
+            if (review == null || review.getDeleteFlag() == 1) {
+                return R.fail("评价不存在");
+            }
+
+            // 创建回复
+            LawyerConsultationReviewReply reply = new LawyerConsultationReviewReply();
+            reply.setReviewId(replyDto.getReviewId());
+            reply.setReplyUserId(replyUserId);
+            reply.setTargetUserId(replyDto.getTargetUserId());
+            reply.setParentReplyId(replyDto.getParentReplyId() != null ? replyDto.getParentReplyId() : 0);
+            reply.setReplyContent(replyDto.getReplyContent());
+            reply.setLikeCount(0);
+            reply.setCreatedUserId(replyUserId);
+
+            boolean saved = reviewReplyMapper.insert(reply) > 0;
+            if (!saved) {
+                return R.fail("添加回复失败");
+            }
+
+            // 更新评价的回复数
+            review.setReplyCount((review.getReplyCount() == null ? 0 : review.getReplyCount()) + 1);
+            this.updateById(review);
+
+            return R.success("添加回复成功");
+        } catch (Exception e) {
+            log.error("添加回复失败", e);
+            return R.fail("添加回复失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<Boolean> toggleLike(Integer reviewId, Integer replyId, Integer userId) {
+        log.info("LawyerConsultationReviewServiceImpl.toggleLike?reviewId={}, replyId={}, userId={}", reviewId, replyId, userId);
+        try {
+            if (reviewId == null && replyId == null) {
+                return R.fail("评价ID和回复ID不能同时为空");
+            }
+
+            LambdaQueryWrapper<LawyerConsultationReviewLike> queryWrapper = new LambdaQueryWrapper<>();
+            if (reviewId != null) {
+                queryWrapper.eq(LawyerConsultationReviewLike::getReviewId, reviewId);
+            }
+            if (replyId != null) {
+                queryWrapper.eq(LawyerConsultationReviewLike::getReplyId, replyId);
+            }
+            queryWrapper.eq(LawyerConsultationReviewLike::getLikeUserId, userId)
+                    .eq(LawyerConsultationReviewLike::getDeleteFlag, 0);
+
+            LawyerConsultationReviewLike existingLike = reviewLikeMapper.selectOne(queryWrapper);
+
+            if (existingLike != null) {
+                // 取消点赞
+                existingLike.setDeleteFlag(1);
+                reviewLikeMapper.updateById(existingLike);
+                // 更新点赞数
+                if (reviewId != null) {
+                    LawyerConsultationReview review = this.getById(reviewId);
+                    if (review != null) {
+                        review.setLikeCount(Math.max(0, (review.getLikeCount() == null ? 0 : review.getLikeCount()) - 1));
+                        this.updateById(review);
+                    }
+                } else if (replyId != null) {
+                    LawyerConsultationReviewReply reply = reviewReplyMapper.selectById(replyId);
+                    if (reply != null) {
+                        reply.setLikeCount(Math.max(0, (reply.getLikeCount() == null ? 0 : reply.getLikeCount()) - 1));
+                        reviewReplyMapper.updateById(reply);
+                    }
+                }
+                return R.success("取消点赞成功");
+            } else {
+                // 添加点赞
+                LawyerConsultationReviewLike like = new LawyerConsultationReviewLike();
+                like.setReviewId(reviewId);
+                like.setReplyId(replyId);
+                like.setLikeUserId(userId);
+                reviewLikeMapper.insert(like);
+                // 更新点赞数
+                if (reviewId != null) {
+                    LawyerConsultationReview review = this.getById(reviewId);
+                    if (review != null) {
+                        review.setLikeCount((review.getLikeCount() == null ? 0 : review.getLikeCount()) + 1);
+                        this.updateById(review);
+                    }
+                } else if (replyId != null) {
+                    LawyerConsultationReviewReply reply = reviewReplyMapper.selectById(replyId);
+                    if (reply != null) {
+                        reply.setLikeCount((reply.getLikeCount() == null ? 0 : reply.getLikeCount()) + 1);
+                        reviewReplyMapper.updateById(reply);
+                    }
+                }
+                return R.success("点赞成功");
+            }
+        } catch (Exception e) {
+            log.error("点赞操作失败", e);
+            return R.fail("点赞操作失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 获取回复列表(包含嵌套回复)
+     */
+    private List<LawyerConsultationReviewReplyVo> getReplyList(Integer reviewId, Integer currentUserId) {
+        LambdaQueryWrapper<LawyerConsultationReviewReply> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LawyerConsultationReviewReply::getReviewId, reviewId)
+                .eq(LawyerConsultationReviewReply::getParentReplyId, 0)
+                .eq(LawyerConsultationReviewReply::getDeleteFlag, 0)
+                .orderByAsc(LawyerConsultationReviewReply::getCreatedTime);
+        List<LawyerConsultationReviewReply> replies = reviewReplyMapper.selectList(queryWrapper);
+
+        List<LawyerConsultationReviewReplyVo> voList = new ArrayList<>();
+        for (LawyerConsultationReviewReply reply : replies) {
+            LawyerConsultationReviewReplyVo vo = convertReplyToVo(reply, currentUserId);
+            // 查询子回复
+            LambdaQueryWrapper<LawyerConsultationReviewReply> childWrapper = new LambdaQueryWrapper<>();
+            childWrapper.eq(LawyerConsultationReviewReply::getParentReplyId, reply.getId())
+                    .eq(LawyerConsultationReviewReply::getDeleteFlag, 0)
+                    .orderByAsc(LawyerConsultationReviewReply::getCreatedTime);
+            List<LawyerConsultationReviewReply> childReplies = reviewReplyMapper.selectList(childWrapper);
+            List<LawyerConsultationReviewReplyVo> childVoList = new ArrayList<>();
+            for (LawyerConsultationReviewReply childReply : childReplies) {
+                childVoList.add(convertReplyToVo(childReply, currentUserId));
+            }
+            vo.setChildReplies(childVoList);
+            voList.add(vo);
+        }
+        return voList;
+    }
+
+    /**
+     * 转换回复为VO
+     */
+    private LawyerConsultationReviewReplyVo convertReplyToVo(LawyerConsultationReviewReply reply, Integer currentUserId) {
+        LawyerConsultationReviewReplyVo vo = new LawyerConsultationReviewReplyVo();
+        BeanUtils.copyProperties(reply, vo);
+
+        // 查询回复用户信息
+        LifeUser replyUser = lifeUserMapper.selectById(reply.getReplyUserId());
+        if (replyUser != null) {
+            vo.setReplyUserName(replyUser.getUserName());
+            vo.setReplyUserImage(replyUser.getUserImage());
+        }
+
+        // 查询被回复用户信息
+        if (reply.getTargetUserId() != null) {
+            LifeUser targetUser = lifeUserMapper.selectById(reply.getTargetUserId());
+            if (targetUser != null) {
+                vo.setTargetUserName(targetUser.getUserName());
+                vo.setTargetUserImage(targetUser.getUserImage());
+            }
+        }
+
+        // 查询是否已点赞
+        if (currentUserId != null) {
+            LambdaQueryWrapper<LawyerConsultationReviewLike> likeWrapper = new LambdaQueryWrapper<>();
+            likeWrapper.eq(LawyerConsultationReviewLike::getReplyId, reply.getId())
+                    .eq(LawyerConsultationReviewLike::getLikeUserId, currentUserId)
+                    .eq(LawyerConsultationReviewLike::getDeleteFlag, 0);
+            long likeCount = reviewLikeMapper.selectCount(likeWrapper);
+            vo.setIsLiked(likeCount > 0 ? 1 : 0);
+        } else {
+            vo.setIsLiked(0);
+        }
+
+        return vo;
+    }
+
+    /**
+     * 更新律师评分统计
+     */
+    private void updateLawyerRatingStats(Integer lawyerUserId) {
+        try {
+            // 查询该律师的所有评价
+            LambdaQueryWrapper<LawyerConsultationReview> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(LawyerConsultationReview::getLawyerUserId, lawyerUserId)
+                    .eq(LawyerConsultationReview::getDeleteFlag, 0);
+            List<LawyerConsultationReview> reviews = this.list(queryWrapper);
+
+            if (reviews.isEmpty()) {
+                return;
+            }
+
+            // 计算平均分
+            double totalRating = 0;
+            int goodCount = 0;
+            int mediumCount = 0;
+            int badCount = 0;
+
+            for (LawyerConsultationReview review : reviews) {
+                totalRating += review.getRating();
+                if (review.getRating() >= 4) {
+                    goodCount++;
+                } else if (review.getRating() >= 3) {
+                    mediumCount++;
+                } else {
+                    badCount++;
+                }
+            }
+
+            double avgRating = totalRating / reviews.size();
+            int serviceScore = (int) (avgRating * 20); // 转换为0-100分
+
+            // 更新律师信息
+            LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerUserId);
+            if (lawyerUser != null) {
+                lawyerUser.setServiceScore(serviceScore);
+                lawyerUser.setServiceCount(reviews.size());
+                lawyerUser.setGoodReviewCount(goodCount);
+                lawyerUser.setMediumReviewCount(mediumCount);
+                lawyerUser.setBadReviewCount(badCount);
+                lawyerUserMapper.updateById(lawyerUser);
+            }
+        } catch (Exception e) {
+            log.error("更新律师评分统计失败", e);
+        }
+    }
 }
 

+ 452 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerReviewServiceImpl.java

@@ -0,0 +1,452 @@
+package shop.alien.lawyer.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.dto.LawyerReviewDto;
+import shop.alien.entity.store.dto.LawyerReviewReplyDto;
+import shop.alien.entity.store.vo.LawyerReviewReplyVo;
+import shop.alien.entity.store.vo.LawyerReviewVo;
+import shop.alien.lawyer.service.LawyerReviewService;
+import shop.alien.mapper.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 律师评价 服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Transactional
+@Service
+@RequiredArgsConstructor
+public class LawyerReviewServiceImpl extends ServiceImpl<LawyerReviewMapper, LawyerReview> implements LawyerReviewService {
+
+    private final LawyerReviewImageMapper reviewImageMapper;
+    private final LawyerReviewReplyMapper reviewReplyMapper;
+    private final LawyerReviewLikeMapper reviewLikeMapper;
+    private final LawyerUserMapper lawyerUserMapper;
+    private final LifeUserMapper lifeUserMapper;
+    private final LawyerConsultationOrderMapper consultationOrderMapper;
+
+    @Override
+    public R<LawyerReviewVo> createReview(LawyerReviewDto reviewDto, Integer userId) {
+        log.info("LawyerReviewServiceImpl.createReview?reviewDto={}, userId={}", reviewDto, userId);
+        try {
+            // 检查订单是否存在且属于该用户
+            LawyerConsultationOrder order = consultationOrderMapper.selectById(reviewDto.getOrderId());
+            if (order == null || !order.getClientUserId().equals(userId)) {
+                return R.fail("订单不存在或不属于当前用户");
+            }
+
+            // 检查是否已经评价过
+            LambdaQueryWrapper<LawyerReview> checkWrapper = new LambdaQueryWrapper<>();
+            checkWrapper.eq(LawyerReview::getOrderId, reviewDto.getOrderId())
+                    .eq(LawyerReview::getDeleteFlag, 0);
+            long count = this.count(checkWrapper);
+            if (count > 0) {
+                return R.fail("该订单已评价,不能重复评价");
+            }
+
+            // 创建评价
+            LawyerReview review = new LawyerReview();
+            review.setOrderId(reviewDto.getOrderId());
+            review.setUserId(userId);
+            review.setLawyerId(reviewDto.getLawyerId());
+            review.setOverallRating(reviewDto.getOverallRating());
+            review.setServiceAttitudeRating(reviewDto.getServiceAttitudeRating());
+            review.setResponseTimeRating(reviewDto.getResponseTimeRating());
+            review.setProfessionalAbilityRating(reviewDto.getProfessionalAbilityRating());
+            review.setReviewContent(reviewDto.getReviewContent());
+            review.setIsAnonymous(reviewDto.getIsAnonymous() != null ? reviewDto.getIsAnonymous() : 0);
+            review.setLikeCount(0);
+            review.setReplyCount(0);
+            review.setAuditStatus(0); // 待审核
+            review.setCreatedUserId(userId);
+
+            boolean saved = this.save(review);
+            if (!saved) {
+                return R.fail("创建评价失败");
+            }
+
+            // 保存评价图片
+            if (reviewDto.getImageUrls() != null && !reviewDto.getImageUrls().isEmpty()) {
+                for (int i = 0; i < reviewDto.getImageUrls().size(); i++) {
+                    LawyerReviewImage image = new LawyerReviewImage();
+                    image.setReviewId(review.getId());
+                    image.setImageUrl(reviewDto.getImageUrls().get(i));
+                    image.setSortOrder(i + 1);
+                    image.setCreatedUserId(userId);
+                    reviewImageMapper.insert(image);
+                }
+            }
+
+            // 更新律师评分统计
+            updateLawyerRatingStats(reviewDto.getLawyerId());
+
+            // 返回评价详情
+            return getReviewDetail(review.getId(), userId);
+        } catch (Exception e) {
+            log.error("创建评价失败", e);
+            return R.fail("创建评价失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<LawyerReviewVo> getReviewDetail(Integer reviewId, Integer currentUserId) {
+        log.info("LawyerReviewServiceImpl.getReviewDetail?reviewId={}, currentUserId={}", reviewId, currentUserId);
+        try {
+            LawyerReview review = this.getById(reviewId);
+            if (review == null || review.getDeleteFlag() == 1) {
+                return R.fail("评价不存在");
+            }
+
+            LawyerReviewVo vo = new LawyerReviewVo();
+            BeanUtils.copyProperties(review, vo);
+
+            // 查询评价图片
+            LambdaQueryWrapper<LawyerReviewImage> imageWrapper = new LambdaQueryWrapper<>();
+            imageWrapper.eq(LawyerReviewImage::getReviewId, reviewId)
+                    .eq(LawyerReviewImage::getDeleteFlag, 0)
+                    .orderByAsc(LawyerReviewImage::getSortOrder);
+            List<LawyerReviewImage> images = reviewImageMapper.selectList(imageWrapper);
+            vo.setImageUrls(images.stream().map(LawyerReviewImage::getImageUrl).collect(Collectors.toList()));
+
+            // 查询用户信息
+            if (review.getIsAnonymous() == 0) {
+                LifeUser user = lifeUserMapper.selectById(review.getUserId());
+                if (user != null) {
+                    vo.setUserName(user.getUserName());
+                    vo.setUserImage(user.getUserImage());
+                }
+            } else {
+                vo.setUserName("匿名用户");
+            }
+
+            LawyerUser lawyerUser = lawyerUserMapper.selectById(review.getLawyerId());
+            if (lawyerUser != null) {
+                vo.setLawyerName(lawyerUser.getName());
+                vo.setLawyerImage(lawyerUser.getHeadImg());
+            }
+
+            // 查询订单信息
+            LawyerConsultationOrder order = consultationOrderMapper.selectById(review.getOrderId());
+            if (order != null) {
+                vo.setOrderNumber(order.getOrderNumber());
+            }
+
+            // 查询回复列表
+            List<LawyerReviewReplyVo> replies = getReplyList(reviewId, currentUserId);
+            vo.setReplies(replies);
+
+            // 查询是否已点赞
+            if (currentUserId != null) {
+                LambdaQueryWrapper<LawyerReviewLike> likeWrapper = new LambdaQueryWrapper<>();
+                likeWrapper.eq(LawyerReviewLike::getReviewId, reviewId)
+                        .eq(LawyerReviewLike::getLikeUserId, currentUserId)
+                        .eq(LawyerReviewLike::getDeleteFlag, 0);
+                long likeCount = reviewLikeMapper.selectCount(likeWrapper);
+                vo.setIsLiked(likeCount > 0 ? 1 : 0);
+            } else {
+                vo.setIsLiked(0);
+            }
+
+            return R.data(vo);
+        } catch (Exception e) {
+            log.error("获取评价详情失败", e);
+            return R.fail("获取评价详情失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<IPage<LawyerReviewVo>> getReviewListWithDetail(int pageNum, int pageSize, Integer lawyerId, Integer currentUserId) {
+        log.info("LawyerReviewServiceImpl.getReviewListWithDetail?pageNum={}, pageSize={}, lawyerId={}, currentUserId={}",
+                pageNum, pageSize, lawyerId, currentUserId);
+        try {
+            Page<LawyerReview> page = new Page<>(pageNum, pageSize);
+            LambdaQueryWrapper<LawyerReview> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(LawyerReview::getLawyerId, lawyerId)
+                    .eq(LawyerReview::getDeleteFlag, 0)
+                    .eq(LawyerReview::getAuditStatus, 1) // 只显示已审核通过的
+                    .orderByDesc(LawyerReview::getCreatedTime);
+            IPage<LawyerReview> pageResult = this.page(page, queryWrapper);
+
+            // 转换为VO
+            Page<LawyerReviewVo> voPage = new Page<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
+            List<LawyerReviewVo> voList = new ArrayList<>();
+            for (LawyerReview review : pageResult.getRecords()) {
+                R<LawyerReviewVo> detailResult = getReviewDetail(review.getId(), currentUserId);
+                if (detailResult.getCode() == 200 && detailResult.getData() != null) {
+                    voList.add(detailResult.getData());
+                }
+            }
+            voPage.setRecords(voList);
+            return R.data(voPage);
+        } catch (Exception e) {
+            log.error("获取评价列表失败", e);
+            return R.fail("获取评价列表失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<Boolean> addReply(LawyerReviewReplyDto replyDto, Integer replyUserId) {
+        log.info("LawyerReviewServiceImpl.addReply?replyDto={}, replyUserId={}", replyDto, replyUserId);
+        try {
+            // 检查评价是否存在
+            LawyerReview review = this.getById(replyDto.getReviewId());
+            if (review == null || review.getDeleteFlag() == 1) {
+                return R.fail("评价不存在");
+            }
+
+            // 创建回复
+            LawyerReviewReply reply = new LawyerReviewReply();
+            reply.setReviewId(replyDto.getReviewId());
+            reply.setReplyUserId(replyUserId);
+            reply.setTargetUserId(replyDto.getTargetUserId());
+            reply.setParentReplyId(replyDto.getParentReplyId() != null ? replyDto.getParentReplyId() : 0);
+            reply.setReplyContent(replyDto.getReplyContent());
+            reply.setLikeCount(0);
+            reply.setCreatedUserId(replyUserId);
+
+            boolean saved = reviewReplyMapper.insert(reply) > 0;
+            if (!saved) {
+                return R.fail("添加回复失败");
+            }
+
+            // 更新评价的回复数
+            review.setReplyCount((review.getReplyCount() == null ? 0 : review.getReplyCount()) + 1);
+            this.updateById(review);
+
+            return R.success("添加回复成功");
+        } catch (Exception e) {
+            log.error("添加回复失败", e);
+            return R.fail("添加回复失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<Boolean> toggleLike(Integer reviewId, Integer replyId, Integer userId) {
+        log.info("LawyerReviewServiceImpl.toggleLike?reviewId={}, replyId={}, userId={}", reviewId, replyId, userId);
+        try {
+            if (reviewId == null && replyId == null) {
+                return R.fail("评价ID和回复ID不能同时为空");
+            }
+
+            LambdaQueryWrapper<LawyerReviewLike> queryWrapper = new LambdaQueryWrapper<>();
+            if (reviewId != null) {
+                queryWrapper.eq(LawyerReviewLike::getReviewId, reviewId);
+            }
+            if (replyId != null) {
+                queryWrapper.eq(LawyerReviewLike::getReplyId, replyId);
+            }
+            queryWrapper.eq(LawyerReviewLike::getLikeUserId, userId)
+                    .eq(LawyerReviewLike::getDeleteFlag, 0);
+
+            LawyerReviewLike existingLike = reviewLikeMapper.selectOne(queryWrapper);
+
+            if (existingLike != null) {
+                // 取消点赞
+                existingLike.setDeleteFlag(1);
+                reviewLikeMapper.updateById(existingLike);
+                // 更新点赞数
+                if (reviewId != null) {
+                    LawyerReview review = this.getById(reviewId);
+                    if (review != null) {
+                        review.setLikeCount(Math.max(0, (review.getLikeCount() == null ? 0 : review.getLikeCount()) - 1));
+                        this.updateById(review);
+                    }
+                } else if (replyId != null) {
+                    LawyerReviewReply reply = reviewReplyMapper.selectById(replyId);
+                    if (reply != null) {
+                        reply.setLikeCount(Math.max(0, (reply.getLikeCount() == null ? 0 : reply.getLikeCount()) - 1));
+                        reviewReplyMapper.updateById(reply);
+                    }
+                }
+                return R.success("取消点赞成功");
+            } else {
+                // 添加点赞
+                LawyerReviewLike like = new LawyerReviewLike();
+                like.setReviewId(reviewId);
+                like.setReplyId(replyId);
+                like.setLikeUserId(userId);
+                reviewLikeMapper.insert(like);
+                // 更新点赞数
+                if (reviewId != null) {
+                    LawyerReview review = this.getById(reviewId);
+                    if (review != null) {
+                        review.setLikeCount((review.getLikeCount() == null ? 0 : review.getLikeCount()) + 1);
+                        this.updateById(review);
+                    }
+                } else if (replyId != null) {
+                    LawyerReviewReply reply = reviewReplyMapper.selectById(replyId);
+                    if (reply != null) {
+                        reply.setLikeCount((reply.getLikeCount() == null ? 0 : reply.getLikeCount()) + 1);
+                        reviewReplyMapper.updateById(reply);
+                    }
+                }
+                return R.success("点赞成功");
+            }
+        } catch (Exception e) {
+            log.error("点赞操作失败", e);
+            return R.fail("点赞操作失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<Boolean> auditReview(Integer reviewId, Integer auditStatus, String auditReason) {
+        log.info("LawyerReviewServiceImpl.auditReview?reviewId={}, auditStatus={}, auditReason={}", reviewId, auditStatus, auditReason);
+        try {
+            LawyerReview review = this.getById(reviewId);
+            if (review == null || review.getDeleteFlag() == 1) {
+                return R.fail("评价不存在");
+            }
+
+            review.setAuditStatus(auditStatus);
+            review.setAuditReason(auditReason);
+            boolean updated = this.updateById(review);
+            if (updated) {
+                // 如果审核通过,更新律师评分统计
+                if (auditStatus == 1) {
+                    updateLawyerRatingStats(review.getLawyerId());
+                }
+                return R.success("审核成功");
+            }
+            return R.fail("审核失败");
+        } catch (Exception e) {
+            log.error("审核评价失败", e);
+            return R.fail("审核评价失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 获取回复列表(包含嵌套回复)
+     */
+    private List<LawyerReviewReplyVo> getReplyList(Integer reviewId, Integer currentUserId) {
+        LambdaQueryWrapper<LawyerReviewReply> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LawyerReviewReply::getReviewId, reviewId)
+                .eq(LawyerReviewReply::getParentReplyId, 0)
+                .eq(LawyerReviewReply::getDeleteFlag, 0)
+                .orderByAsc(LawyerReviewReply::getCreatedTime);
+        List<LawyerReviewReply> replies = reviewReplyMapper.selectList(queryWrapper);
+
+        List<LawyerReviewReplyVo> voList = new ArrayList<>();
+        for (LawyerReviewReply reply : replies) {
+            LawyerReviewReplyVo vo = convertReplyToVo(reply, currentUserId);
+            // 查询子回复
+            LambdaQueryWrapper<LawyerReviewReply> childWrapper = new LambdaQueryWrapper<>();
+            childWrapper.eq(LawyerReviewReply::getParentReplyId, reply.getId())
+                    .eq(LawyerReviewReply::getDeleteFlag, 0)
+                    .orderByAsc(LawyerReviewReply::getCreatedTime);
+            List<LawyerReviewReply> childReplies = reviewReplyMapper.selectList(childWrapper);
+            List<LawyerReviewReplyVo> childVoList = new ArrayList<>();
+            for (LawyerReviewReply childReply : childReplies) {
+                childVoList.add(convertReplyToVo(childReply, currentUserId));
+            }
+            vo.setChildReplies(childVoList);
+            voList.add(vo);
+        }
+        return voList;
+    }
+
+    /**
+     * 转换回复为VO
+     */
+    private LawyerReviewReplyVo convertReplyToVo(LawyerReviewReply reply, Integer currentUserId) {
+        LawyerReviewReplyVo vo = new LawyerReviewReplyVo();
+        BeanUtils.copyProperties(reply, vo);
+
+        // 查询回复用户信息
+        LifeUser replyUser = lifeUserMapper.selectById(reply.getReplyUserId());
+        if (replyUser != null) {
+            vo.setReplyUserName(replyUser.getUserName());
+            vo.setReplyUserImage(replyUser.getUserImage());
+        }
+
+        // 查询被回复用户信息
+        if (reply.getTargetUserId() != null) {
+            LifeUser targetUser = lifeUserMapper.selectById(reply.getTargetUserId());
+            if (targetUser != null) {
+                vo.setTargetUserName(targetUser.getUserName());
+                vo.setTargetUserImage(targetUser.getUserImage());
+            }
+        }
+
+        // 查询是否已点赞
+        if (currentUserId != null) {
+            LambdaQueryWrapper<LawyerReviewLike> likeWrapper = new LambdaQueryWrapper<>();
+            likeWrapper.eq(LawyerReviewLike::getReplyId, reply.getId())
+                    .eq(LawyerReviewLike::getLikeUserId, currentUserId)
+                    .eq(LawyerReviewLike::getDeleteFlag, 0);
+            long likeCount = reviewLikeMapper.selectCount(likeWrapper);
+            vo.setIsLiked(likeCount > 0 ? 1 : 0);
+        } else {
+            vo.setIsLiked(0);
+        }
+
+        return vo;
+    }
+
+    /**
+     * 更新律师评分统计
+     */
+    private void updateLawyerRatingStats(Integer lawyerId) {
+        try {
+            // 查询该律师的所有已审核通过的评价
+            LambdaQueryWrapper<LawyerReview> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(LawyerReview::getLawyerId, lawyerId)
+                    .eq(LawyerReview::getDeleteFlag, 0)
+                    .eq(LawyerReview::getAuditStatus, 1); // 只统计已审核通过的
+            List<LawyerReview> reviews = this.list(queryWrapper);
+
+            if (reviews.isEmpty()) {
+                return;
+            }
+
+            // 计算平均分
+            double totalRating = 0;
+            int goodCount = 0;
+            int mediumCount = 0;
+            int badCount = 0;
+
+            for (LawyerReview review : reviews) {
+                totalRating += review.getOverallRating();
+                if (review.getOverallRating() >= 4) {
+                    goodCount++;
+                } else if (review.getOverallRating() >= 3) {
+                    mediumCount++;
+                } else {
+                    badCount++;
+                }
+            }
+
+            double avgRating = totalRating / reviews.size();
+            int serviceScore = (int) (avgRating * 20); // 转换为0-100分
+
+            // 更新律师信息
+            LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerId);
+            if (lawyerUser != null) {
+                lawyerUser.setServiceScore(serviceScore);
+                lawyerUser.setServiceCount(reviews.size());
+                lawyerUser.setGoodReviewCount(goodCount);
+                lawyerUser.setMediumReviewCount(mediumCount);
+                lawyerUser.setBadReviewCount(badCount);
+                lawyerUserMapper.updateById(lawyerUser);
+            }
+        } catch (Exception e) {
+            log.error("更新律师评分统计失败", e);
+        }
+    }
+}
+