Browse Source

Merge branch 'sit' of http://8.152.195.41:3000/alien/alien_cloud into store-plantform

qrs 3 weeks ago
parent
commit
a26a0236ae
36 changed files with 1300 additions and 459 deletions
  1. 34 2
      alien-entity/src/main/java/shop/alien/entity/store/LawyerUser.java
  2. 4 0
      alien-entity/src/main/java/shop/alien/entity/store/ReviewComment.java
  3. 27 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerLegalProblemScenarioStatusDto.java
  4. 27 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerRecommendedDto.java
  5. 114 0
      alien-entity/src/main/java/shop/alien/entity/store/excelVo/LawyerUserExcelVo.java
  6. 3 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/CommentAppealVo.java
  7. 39 1
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationOrderVO.java
  8. 32 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerReviewStatisticsVo.java
  9. 5 2
      alien-entity/src/main/java/shop/alien/entity/store/vo/ReviewCommentVo.java
  10. 4 2
      alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationOrderMapper.java
  11. 16 0
      alien-entity/src/main/java/shop/alien/mapper/OrderReviewMapper.java
  12. 3 1
      alien-entity/src/main/resources/mapper/CommentAppealMapper.xml
  13. 5 4
      alien-entity/src/main/resources/mapper/LawyerUserMapper.xml
  14. 28 0
      alien-entity/src/main/resources/mapper/OrderReviewMapper.xml
  15. 14 2
      alien-entity/src/main/resources/mapper/ReviewCommentMapper.xml
  16. 20 0
      alien-gateway/src/main/java/shop/alien/gateway/config/JwtTokenFilter.java
  17. 89 0
      alien-gateway/src/main/java/shop/alien/gateway/mapper/LawyerUserGatewayMapper.java
  18. 0 89
      alien-gateway/src/main/java/shop/alien/gateway/mapper/LawyerUserMapper.java
  19. 9 8
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerLegalProblemScenarioController.java
  20. 46 0
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerUserController.java
  21. 105 24
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/OrderReviewController.java
  22. 35 57
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/ReviewCommentController.java
  23. 9 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerLegalProblemScenarioService.java
  24. 32 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerUserService.java
  25. 36 26
      alien-lawyer/src/main/java/shop/alien/lawyer/service/OrderReviewService.java
  26. 6 25
      alien-lawyer/src/main/java/shop/alien/lawyer/service/ReviewCommentService.java
  27. 10 16
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/CommentAppealServiceImpl.java
  28. 1 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawFirmPaymentServiceImpl.java
  29. 55 11
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerClientConsultationOrderServiceImpl.java
  30. 60 7
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationOrderServiceImpl.java
  31. 34 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerLegalProblemScenarioServiceImpl.java
  32. 5 1
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserLogInServiceImpl.java
  33. 221 1
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserServiceImpl.java
  34. 5 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserViolationServiceImpl.java
  35. 54 3
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/OrderReviewServiceImpl.java
  36. 113 177
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/ReviewCommentServiceImpl.java

+ 34 - 2
alien-entity/src/main/java/shop/alien/entity/store/LawyerUser.java

@@ -8,6 +8,9 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
 import java.util.Date;
 import java.util.List;
 
@@ -141,8 +144,8 @@ public class LawyerUser extends Model<LawyerUser> {
     @TableField("law_firm")
     private String lawFirm;
 
-    @ApiModelProperty(value = "执业年限")
-    @TableField("practice_years")
+    @ApiModelProperty(value = "执业年限(根据执业开始日期自动计算)")
+    @TableField(exist = false)
     private Integer practiceYears;
 
     @ApiModelProperty(value = "执业开始日期")
@@ -150,6 +153,31 @@ public class LawyerUser extends Model<LawyerUser> {
     @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date practiceStartDate;
 
+    /**
+     * 获取执业年限(根据执业开始日期自动计算)
+     * 返回当前时间减去执业开始时间的年数
+     *
+     * @return 执业年限(年)
+     */
+    public Integer getPracticeYears() {
+        if (practiceStartDate == null) {
+            return null;
+        }
+        try {
+            // 将 Date 转换为 LocalDate
+            LocalDate startDate = practiceStartDate.toInstant()
+                    .atZone(ZoneId.systemDefault())
+                    .toLocalDate();
+            LocalDate currentDate = LocalDate.now();
+
+            // 计算年数差
+            long years = ChronoUnit.YEARS.between(startDate, currentDate);
+            return (int) Math.max(0, years); // 确保不为负数
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     @ApiModelProperty(value = "专业领域,多个用逗号分隔")
     @TableField("specialty_fields")
     private String specialtyFields;
@@ -305,5 +333,9 @@ public class LawyerUser extends Model<LawyerUser> {
     @TableField(exist = false)
     private String moneyStr;
 
+    @ApiModelProperty(value = "评价数(只统计评价,不包含评论)")
+    @TableField(exist = false)
+    private Integer reviewCount;
+
 }
 

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/store/ReviewComment.java

@@ -80,5 +80,9 @@ public class ReviewComment {
     @ApiModelProperty(value = "修改人ID")
     @TableField("updated_user_id")
     private Integer updatedUserId;
+
+    @ApiModelProperty(value = "登陆人")
+    @TableField(exist = false)
+    private Integer userId;
 }
 

+ 27 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerLegalProblemScenarioStatusDto.java

@@ -0,0 +1,27 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 设置法律场景启用/禁用状态请求对象
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerLegalProblemScenarioStatusDto对象", description = "设置法律场景启用/禁用状态请求对象")
+public class LawyerLegalProblemScenarioStatusDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "场景ID", required = true)
+    private Integer id;
+
+    @ApiModelProperty(value = "状态,0:禁用,1:启用", required = true)
+    private Integer status;
+}
+

+ 27 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerRecommendedDto.java

@@ -0,0 +1,27 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 设置律师推荐状态请求对象
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerRecommendedDto对象", description = "设置律师推荐状态请求对象")
+public class LawyerRecommendedDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "律师ID", required = true)
+    private Integer lawyerId;
+
+    @ApiModelProperty(value = "推荐状态,0:取消推荐,1:推荐", required = true)
+    private Integer isRecommended;
+}
+

+ 114 - 0
alien-entity/src/main/java/shop/alien/entity/store/excelVo/LawyerUserExcelVo.java

@@ -0,0 +1,114 @@
+package shop.alien.entity.store.excelVo;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 律师用户Excel导出对象
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "LawyerUserExcelVo对象", description = "律师用户Excel导出对象")
+public class LawyerUserExcelVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "主键")
+    private Integer id;
+
+    @ExcelProperty(value = "律师姓名", index = 0)
+    @ApiModelProperty(value = "律师姓名")
+    private String name;
+
+    @ExcelProperty(value = "律师手机号", index = 1)
+    @ApiModelProperty(value = "律师手机号")
+    private String phone;
+
+    @ExcelProperty(value = "律所名称", index = 2)
+    @ApiModelProperty(value = "律所名称")
+    private String firmName;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "律师执业证号")
+    private String lawyerCertificateNo;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "执业开始日期")
+    private String practiceStartDate;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "执业年限")
+    private Integer practiceYears;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "用户状态")
+    private String status;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "资质认证状态")
+    private String certificationStatus;
+
+    @ExcelProperty(value = "推荐状态", index = 3)
+    @ApiModelProperty(value = "推荐状态")
+    private String isRecommended;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "服务评分")
+    private Integer serviceScore;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "服务次数")
+    private Integer serviceCount;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "创建时间")
+    private String createdTime;
+
+    @ExcelProperty(value = "法律场景", index = 4)
+    @ApiModelProperty(value = "法律场景")
+    private String scenarioNames;
+
+    @ExcelProperty(value = "接单状态", index = 5)
+    @ApiModelProperty(value = "接单状态")
+    private String orderReceivingStatus;
+
+    @ExcelProperty(value = "收款账号", index = 6)
+    @ApiModelProperty(value = "收款账号")
+    private String paymentNum;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "律所ID")
+    private Integer firmId;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "用户状态值")
+    private Integer statusValue;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "资质认证状态值")
+    private Integer certificationStatusValue;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "是否推荐值")
+    private Integer isRecommendedValue;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "接单状态值")
+    private Integer orderReceivingStatusValue;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "创建时间原始值")
+    private Date createdTimeValue;
+}
+

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/CommentAppealVo.java

@@ -136,5 +136,8 @@ public class CommentAppealVo implements Serializable {
 
     @ApiModelProperty(value = "律师电话")
     private String lawyerPhone;
+
+    @ApiModelProperty(value = "申诉单号")
+    private String appealNumber;
 }
 

+ 39 - 1
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationOrderVO.java

@@ -10,6 +10,9 @@ import shop.alien.entity.store.LawyerLegalProblemScenario;
 
 import java.io.Serializable;
 import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
 import java.util.Date;
 import java.util.List;
 
@@ -56,7 +59,7 @@ public class LawyerConsultationOrderVO implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date endTime;
 
-    @ApiModelProperty(value = "订单状态, 0:待支付, 2:进行中, 3:已完成, 4:已取消")
+    @ApiModelProperty(value = "订单状态, 0:待支付,1.待接单 2:进行中, 3:已完成, 4:已取消,5.已退款")
     private Integer orderStatus;
 
     @ApiModelProperty(value = "支付状态, 0:未支付, 1:已支付")
@@ -235,5 +238,40 @@ public class LawyerConsultationOrderVO implements Serializable {
 
     @ApiModelProperty(value = "举报处理结果")
     private  String reportResult;
+
+    @ApiModelProperty(value = "律师年限")
+    private  Date practiceStartDate;
+
+    @ApiModelProperty(value = "未读消息数量")
+    private  Long unreadMessage;
+
+    @ApiModelProperty(value = "律师接单状态")
+    private int orderReceivingStatus;
+
+
+    /**
+     * 获取执业年限(根据执业开始日期自动计算)
+     * 返回当前时间减去执业开始时间的年数
+     *
+     * @return 执业年限(年)
+     */
+    public Integer getPracticeYears() {
+        if (practiceStartDate == null) {
+            return null;
+        }
+        try {
+            // 将 Date 转换为 LocalDate
+            LocalDate startDate = practiceStartDate.toInstant()
+                    .atZone(ZoneId.systemDefault())
+                    .toLocalDate();
+            LocalDate currentDate = LocalDate.now();
+
+            // 计算年数差
+            long years = ChronoUnit.YEARS.between(startDate, currentDate);
+            return (int) Math.max(0, years); // 确保不为负数
+        } catch (Exception e) {
+            return null;
+        }
+    }
 }
 

+ 32 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerReviewStatisticsVo.java

@@ -0,0 +1,32 @@
+package shop.alien.entity.store.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 律师评价统计数据VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LawyerReviewStatisticsVo对象", description = "律师评价统计数据VO")
+public class LawyerReviewStatisticsVo {
+
+    @ApiModelProperty(value = "全部评价数量")
+    private Integer totalCount;
+
+    @ApiModelProperty(value = "好评数量(4.5-5分)")
+    private Integer goodCount;
+
+    @ApiModelProperty(value = "中评数量(3-4分)")
+    private Integer mediumCount;
+
+    @ApiModelProperty(value = "差评数量(0-2.5分)")
+    private Integer badCount;
+
+    @ApiModelProperty(value = "有图评价数量")
+    private Integer imageCount;
+}
+

+ 5 - 2
alien-entity/src/main/java/shop/alien/entity/store/vo/ReviewCommentVo.java

@@ -30,12 +30,15 @@ public class ReviewCommentVo {
     @ApiModelProperty(value = "接收用户ID")
     private Integer receiveUserId;
 
-    @ApiModelProperty(value = "评论用户名称")
-    private String userName;
+    @ApiModelProperty(value = "评论用户名称(发送者)")
+    private String sendUserName;
 
     @ApiModelProperty(value = "评论用户头像")
     private String userAvatar;
 
+    @ApiModelProperty(value = "接收用户名称")
+    private String receiveUserName;
+
     @ApiModelProperty(value = "评论内容")
     private String commentContent;
 

+ 4 - 2
alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationOrderMapper.java

@@ -69,7 +69,7 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
 
 
     //写一个insertOrder的插入方法根据order的入参进行插入
-    @Insert("INSERT INTO `alien`.`lawyer_consultation_order`" +
+    @Insert("INSERT INTO `lawyer_consultation_order`" +
             " (`id`, " +
             "`order_number`," +
             " `client_user_id`," +
@@ -403,6 +403,7 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             "        lu.lawyer_certificate_no,\n" +
             "        lu.law_firm,\n" +
             "        lu.practice_years,\n" +
+            "        lu.practice_start_date,\n" +
             "        lu.specialty_fields,\n" +
             "        lu.certification_status,\n" +
             "        lu.service_score,\n" +
@@ -410,6 +411,7 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             "        lu.consultation_fee AS lawyer_consultation_fee,\n" +
             "        lu.province,\n" +
             "        lu.city,\n" +
+            "        lu.order_receiving_status,\n" +
             "        lu.district,\n" +
             "        lu.address,\n" +
             "        lu.head_img,\n" +
@@ -493,7 +495,7 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             "accept_orders_status "+
             "FROM " +
             "lawyer_consultation_order " +
-            "WHERE order_status = 2 " +
+            "WHERE order_status in (1,2) " +
             " and delete_flag = 0 " +
             "<if test='clientUserId != null'>" +
             "AND client_user_id = #{clientUserId} " +

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

@@ -112,5 +112,21 @@ public interface OrderReviewMapper extends BaseMapper<OrderReview> {
             @Param("type") Integer type,
             @Param("currentUserId") Integer currentUserId
     );
+
+    /**
+     * 统计律师的全部评价数量
+     *
+     * @param lawyerUserId 律师用户ID
+     * @return 全部评价数量
+     */
+    Integer getTotalReviewCountByLawyerUserId(@Param("lawyerUserId") Integer lawyerUserId);
+
+    /**
+     * 统计律师的有图评价数量
+     *
+     * @param lawyerUserId 律师用户ID
+     * @return 有图评价数量
+     */
+    Integer getImageReviewCountByLawyerUserId(@Param("lawyerUserId") Integer lawyerUserId);
 }
 

+ 3 - 1
alien-entity/src/main/resources/mapper/CommentAppealMapper.xml

@@ -33,6 +33,7 @@
         <result column="updated_time" property="updatedTime" />
         <result column="updated_user_id" property="updatedUserId" />
         <result column="audit_user_id" property="auditUserId" />
+        <result column="appeal_number" property="appealNumber" />
         <!-- 评价相关信息 -->
         <result column="review_user_id" property="reviewUserId" />
         <result column="review_user_name" property="reviewUserName" />
@@ -116,6 +117,7 @@
             ca.updated_time,
             ca.updated_user_id,
             ca.updated_user_id AS audit_user_id,
+            ca.appeal_number,
             orv.user_id AS review_user_id,
             CASE
                 WHEN orv.is_anonymous = 1 THEN '匿名用户'
@@ -133,7 +135,7 @@
             orv.created_time AS review_time,
             orv.review_images
         FROM comment_appeals ca
-        LEFT JOIN lawyer_order_review orv ON orv.id = ca.comment_id AND orv.delete_flag = 0
+        LEFT JOIN lawyer_order_review orv ON orv.id = ca.comment_id
         LEFT JOIN life_user lu ON lu.id = orv.user_id AND lu.delete_flag = 0
         WHERE ca.delete_flag = 0
         AND ca.id = #{id}

+ 5 - 4
alien-entity/src/main/resources/mapper/LawyerUserMapper.xml

@@ -113,17 +113,18 @@
         user.status,
         user.delete_flag,
         user.created_time,
+        user.is_recommended,
         firm.firm_name AS firmName,
         firmTwo.payment_account AS paymentNum,
         firmTwo.address AS address,
-        GROUP_CONCAT(a.name SEPARATOR ',') AS scenarioNames,
-        (SELECT GROUP_CONCAT(`name` SEPARATOR ',') FROM lawyer_legal_problem_scenario WHERE level = 1) AS firstLevelScenario
+        GROUP_CONCAT(DISTINCT a.name SEPARATOR ',') AS scenarioNames,
+        (SELECT GROUP_CONCAT(`name` SEPARATOR ',') FROM lawyer_legal_problem_scenario WHERE level = 1 AND delete_flag = 0) AS firstLevelScenario
         FROM
         lawyer_user user
         LEFT JOIN law_firm firm ON firm.id = user.firm_id
         LEFT JOIN law_firm_payment firmTwo ON firmTwo.firm_id = user.firm_id
-        LEFT JOIN lawyer_service_area area ON area.lawyer_user_id = user.id
-        LEFT JOIN lawyer_legal_problem_scenario a ON a.id = area.problem_scenario_id
+        LEFT JOIN lawyer_service_area area ON area.lawyer_user_id = user.id AND area.delete_flag = 0 AND area.status = 1
+        LEFT JOIN lawyer_legal_problem_scenario a ON a.id = area.problem_scenario_id AND a.delete_flag = 0 AND a.status = 1
         WHERE user.delete_flag = 0
         <if test="name != null and name != ''">AND user.name LIKE CONCAT('%', #{name}, '%')</if>
         <if test="phone != null and phone != ''">AND user.phone LIKE CONCAT('%', #{phone}, '%')</if>

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

@@ -215,6 +215,15 @@
         ORDER BY lco.end_time DESC
     </select>
 
+    <!-- 计算律师的平均评分(overallRating的平均值) -->
+    <select id="getAverageRatingByLawyerUserId" resultType="java.lang.Double">
+        SELECT AVG(overall_rating)
+        FROM lawyer_order_review
+        WHERE lawyer_user_id = #{lawyerUserId}
+        AND delete_flag = 0
+        AND overall_rating IS NOT NULL
+    </select>
+
     <!-- 统计律师的好评数(4.5-5分) -->
     <select id="getGoodReviewCountByLawyerUserId" resultType="java.lang.Integer">
         <![CDATA[
@@ -254,6 +263,25 @@
         ]]>
     </select>
 
+    <!-- 统计律师的全部评价数量 -->
+    <select id="getTotalReviewCountByLawyerUserId" resultType="java.lang.Integer">
+        SELECT COUNT(*)
+        FROM lawyer_order_review
+        WHERE lawyer_user_id = #{lawyerUserId}
+        AND delete_flag = 0
+    </select>
+
+    <!-- 统计律师的有图评价数量 -->
+    <select id="getImageReviewCountByLawyerUserId" resultType="java.lang.Integer">
+        SELECT COUNT(*)
+        FROM lawyer_order_review
+        WHERE lawyer_user_id = #{lawyerUserId}
+        AND delete_flag = 0
+        AND review_images IS NOT NULL
+        AND review_images != ''
+        AND TRIM(review_images) != ''
+    </select>
+
     <!-- 根据律师ID和类型分页查询评价列表(包含用户和律师信息) -->
     <select id="getReviewListByLawyerAndType" resultMap="OrderReviewVoResultMap">
         SELECT

+ 14 - 2
alien-entity/src/main/resources/mapper/ReviewCommentMapper.xml

@@ -8,8 +8,9 @@
         <result column="review_id" property="reviewId" />
         <result column="send_user_id" property="sendUserId" />
         <result column="receive_user_id" property="receiveUserId" />
-        <result column="user_name" property="userName" />
+        <result column="user_name" property="sendUserName" />
         <result column="user_avatar" property="userAvatar" />
+        <result column="receive_user_name" property="receiveUserName" />
         <result column="comment_content" property="commentContent" />
         <result column="like_count" property="likeCount" />
         <result column="reply_count" property="replyCount" />
@@ -28,6 +29,7 @@
             rc.receive_user_id,
             lu.user_name AS user_name,
             lu.user_image AS user_avatar,
+            lu2.user_name AS receive_user_name,
             rc.comment_content,
             rc.like_count,
             rc.reply_count,
@@ -40,6 +42,7 @@
             rc.created_time
         FROM lawyer_review_comment rc
         LEFT JOIN life_user lu ON lu.id = rc.send_user_id AND lu.delete_flag = 0
+        LEFT JOIN life_user lu2 ON lu2.id = rc.receive_user_id AND lu2.delete_flag = 0
         LEFT JOIN life_like_record llr ON CONVERT(llr.huifu_id, CHAR) = CONVERT(rc.id, CHAR)
             AND llr.type = '8' 
             AND CONVERT(llr.dianzan_id, CHAR) = CONVERT(#{currentUserId}, CHAR)
@@ -59,6 +62,7 @@
             rc.receive_user_id,
             lu.user_name AS user_name,
             lu.user_image AS user_avatar,
+            lu2.user_name AS receive_user_name,
             rc.comment_content,
             rc.like_count,
             rc.reply_count,
@@ -82,7 +86,7 @@
         ORDER BY rc.created_time ASC
     </select>
 
-    <!-- 根据评价ID查询评论数量 -->
+    <!-- 根据评价ID查询评论数量(只统计首评论) -->
     <select id="getCommentCountByReviewId" resultType="java.lang.Integer">
         SELECT COUNT(*)
         FROM lawyer_review_comment
@@ -91,5 +95,13 @@
         AND head_type = 0
     </select>
 
+    <!-- 根据评价ID查询总评论数量(包括首评论和子评论) -->
+    <select id="getTotalCommentCountByReviewId" resultType="java.lang.Integer">
+        SELECT COUNT(*)
+        FROM lawyer_review_comment
+        WHERE delete_flag = 0
+        AND review_id = #{reviewId}
+    </select>
+
 </mapper>
 

+ 20 - 0
alien-gateway/src/main/java/shop/alien/gateway/config/JwtTokenFilter.java

@@ -23,8 +23,10 @@ import org.springframework.stereotype.Component;
 import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
+import shop.alien.entity.store.LawyerUser;
 import shop.alien.entity.store.LifeUser;
 import shop.alien.entity.store.StoreUser;
+import shop.alien.gateway.mapper.LawyerUserGatewayMapper;
 import shop.alien.gateway.mapper.LifeUserGatewayMapper;
 import shop.alien.gateway.mapper.StoreUserGatewayMapper;
 import shop.alien.util.common.JwtUtil;
@@ -62,6 +64,9 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
     @Autowired
     private LifeUserGatewayMapper lifeUserMapper;
 
+    @Autowired
+    private LawyerUserGatewayMapper lawyerUserMapper;
+
     /**
      * 过滤器
      *
@@ -142,6 +147,21 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
                             map.put("code", 666);
                         }
                     }
+                    else if ("lawyer".equals(deviceType)) {
+                        //判断程序是否为用户禁用
+                        LawyerUser lawyerUser = lawyerUserMapper.selectOne(new LambdaQueryWrapper<LawyerUser>().eq(LawyerUser::getPhone, phone));
+                        //注销标记, 0:未注销, 1:已注销
+                        if (null != lawyerUser.getLogoutFlag() && lawyerUser.getLogoutFlag() == 1) {
+                            map.put("msg", "你的账号已注销");
+                            //别问, 问就是约定俗成
+                            map.put("code", 777);
+                        }
+                        if (!redisVal.equals(token)) {
+                            map.put("msg", "账号在别处登录");
+                            //别问, 问就是约定俗成
+                            map.put("code", 666);
+                        }
+                    }
                     map.put("success", false);
                     exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
                     return exchange.getResponse()

+ 89 - 0
alien-gateway/src/main/java/shop/alien/gateway/mapper/LawyerUserGatewayMapper.java

@@ -0,0 +1,89 @@
+package shop.alien.gateway.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Update;
+import shop.alien.entity.store.LawyerUser;
+
+/**
+ * <p>
+ * 律师用户 Mapper 接口
+ * </p>
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LawyerUserGatewayMapper extends BaseMapper<LawyerUser> {
+
+
+@Update("<script>" +
+        "UPDATE lawyer_user " +
+        "<set>" +
+        "<if test='firmId != null'>firm_id = #{firmId},</if>" +
+        "<if test='phone != null'>phone = #{phone},</if>" +
+        "<if test='name != null'>name = #{name},</if>" +
+        "<if test='idCard != null'>id_card = #{idCard},</if>" +
+        "<if test='password != null'>password = #{password},</if>" +
+        "<if test='payPassword != null'>pay_password = #{payPassword},</if>" +
+        "<if test='money != null'>money = #{money},</if>" +
+        "<if test='status != null'>status = #{status},</if>" +
+        "<if test='passType != null'>pass_type = #{passType},</if>" +
+        "<if test='deleteFlag != null'>delete_flag = #{deleteFlag},</if>" +
+        "<if test='createdTime != null'>created_time = #{createdTime},</if>" +
+        "<if test='createdUserId != null'>created_user_id = #{createdUserId},</if>" +
+        "<if test='updatedTime != null'>updated_time = #{updatedTime},</if>" +
+        "<if test='updatedUserId != null'>updated_user_id = #{updatedUserId},</if>" +
+        "<if test='logoutFlag != null'>logout_flag = #{logoutFlag},</if>" +
+        "<if test='logoutReason != null'>logout_reason = #{logoutReason},</if>" +
+        "<if test='logoutTime != null'>logout_time = #{logoutTime},</if>" +
+        "<if test='logoutCode != null'>logout_code = #{logoutCode},</if>" +
+        "<if test='nickName != null'>nick_name = #{nickName},</if>" +
+        "<if test='accountBlurb != null'>account_blurb = #{accountBlurb},</if>" +
+        "<if test='headImg != null'>head_img = #{headImg},</if>" +
+        "<if test='alipayAccount != null'>alipay_account = #{alipayAccount},</if>" +
+        "<if test='lawyerCertificateNo != null'>lawyer_certificate_no = #{lawyerCertificateNo},</if>" +
+        "<if test='lawFirm != null'>law_firm = #{lawFirm},</if>" +
+        "<if test='practiceYears != null'>practice_years = #{practiceYears},</if>" +
+        "<if test='practiceStartDate != null'>practice_start_date = #{practiceStartDate},</if>" +
+        "<if test='specialtyFields != null'>specialty_fields = #{specialtyFields},</if>" +
+        "<if test='certificationStatus != null'>certification_status = #{certificationStatus},</if>" +
+        "<if test='certificationFailReason != null'>certification_fail_reason = #{certificationFailReason},</if>" +
+        "<if test='certificationTime != null'>certification_time = #{certificationTime},</if>" +
+        "<if test='certificationReviewerId != null'>certification_reviewer_id = #{certificationReviewerId},</if>" +
+        "<if test='certificateImage != null'>certificate_image = #{certificateImage},</if>" +
+        "<if test='idCardFrontImage != null'>id_card_front_image = #{idCardFrontImage},</if>" +
+        "<if test='idCardBackImage != null'>id_card_back_image = #{idCardBackImage},</if>" +
+        "<if test='serviceScore != null'>service_score = #{serviceScore},</if>" +
+        "<if test='serviceCount != null'>service_count = #{serviceCount},</if>" +
+        "<if test='goodReviewCount != null'>good_review_count = #{goodReviewCount},</if>" +
+        "<if test='mediumReviewCount != null'>medium_review_count = #{mediumReviewCount},</if>" +
+        "<if test='badReviewCount != null'>bad_review_count = #{badReviewCount},</if>" +
+        "<if test='consultationFee != null'>consultation_fee = #{consultationFee},</if>" +
+        "<if test='agencyFee != null'>agency_fee = #{agencyFee},</if>" +
+        "<if test='province != null'>province = #{province},</if>" +
+        "<if test='city != null'>city = #{city},</if>" +
+        "<if test='district != null'>district = #{district},</if>" +
+        "<if test='address != null'>address = #{address},</if>" +
+        "<if test='email != null'>email = #{email},</if>" +
+        "<if test='gender != null'>gender = #{gender},</if>" +
+        "<if test='birthday != null'>birthday = #{birthday},</if>" +
+        "<if test='personalIntroduction != null'>personal_introduction = #{personalIntroduction},</if>" +
+        "<if test='educationBackground != null'>education_background = #{educationBackground},</if>" +
+        "<if test='workExperience != null'>work_experience = #{workExperience},</if>" +
+        "<if test='expertiseCases != null'>expertise_cases = #{expertiseCases},</if>" +
+        "<if test='isOnline != null'>is_online = #{isOnline},</if>" +
+        "<if test='lastOnlineTime != null'>last_online_time = #{lastOnlineTime},</if>" +
+        "<if test='isRecommended != null'>is_recommended = #{isRecommended},</if>" +
+        "<if test='recommendSort != null'>recommend_sort = #{recommendSort},</if>" +
+        "<if test='orderReceivingStatus != null'>order_receiving_status = #{orderReceivingStatus},</if>" +
+        "<if test='lawyerExpertiseAreaId != null'>lawyer_expertise_area_id = #{lawyerExpertiseAreaId},</if>" +
+        "<if test='commissionRate != null'>commission_rate = #{commissionRate},</if>" +
+        "<if test='paymentNum != null'>payment_num = #{paymentNum},</if>" +
+        "</set>" +
+        "WHERE id = #{id}" +
+        "</script>")
+Integer updateLawyerUser(LawyerUser user);
+
+}
+

+ 0 - 89
alien-gateway/src/main/java/shop/alien/gateway/mapper/LawyerUserMapper.java

@@ -1,89 +0,0 @@
-//package shop.alien.gateway.mapper;
-//
-//import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-//import org.apache.ibatis.annotations.Mapper;
-//import org.apache.ibatis.annotations.Update;
-//import shop.alien.entity.store.LawyerUser;
-//
-///**
-// * <p>
-// * 律师用户 Mapper 接口
-// * </p>
-// *
-// * @author system
-// * @since 2025-01-XX
-// */
-//@Mapper
-//public interface LawyerUserMapper extends BaseMapper<LawyerUser> {
-//
-//
-//@Update("<script>" +
-//        "UPDATE lawyer_user " +
-//        "<set>" +
-//        "<if test='firmId != null'>firm_id = #{firmId},</if>" +
-//        "<if test='phone != null'>phone = #{phone},</if>" +
-//        "<if test='name != null'>name = #{name},</if>" +
-//        "<if test='idCard != null'>id_card = #{idCard},</if>" +
-//        "<if test='password != null'>password = #{password},</if>" +
-//        "<if test='payPassword != null'>pay_password = #{payPassword},</if>" +
-//        "<if test='money != null'>money = #{money},</if>" +
-//        "<if test='status != null'>status = #{status},</if>" +
-//        "<if test='passType != null'>pass_type = #{passType},</if>" +
-//        "<if test='deleteFlag != null'>delete_flag = #{deleteFlag},</if>" +
-//        "<if test='createdTime != null'>created_time = #{createdTime},</if>" +
-//        "<if test='createdUserId != null'>created_user_id = #{createdUserId},</if>" +
-//        "<if test='updatedTime != null'>updated_time = #{updatedTime},</if>" +
-//        "<if test='updatedUserId != null'>updated_user_id = #{updatedUserId},</if>" +
-//        "<if test='logoutFlag != null'>logout_flag = #{logoutFlag},</if>" +
-//        "<if test='logoutReason != null'>logout_reason = #{logoutReason},</if>" +
-//        "<if test='logoutTime != null'>logout_time = #{logoutTime},</if>" +
-//        "<if test='logoutCode != null'>logout_code = #{logoutCode},</if>" +
-//        "<if test='nickName != null'>nick_name = #{nickName},</if>" +
-//        "<if test='accountBlurb != null'>account_blurb = #{accountBlurb},</if>" +
-//        "<if test='headImg != null'>head_img = #{headImg},</if>" +
-//        "<if test='alipayAccount != null'>alipay_account = #{alipayAccount},</if>" +
-//        "<if test='lawyerCertificateNo != null'>lawyer_certificate_no = #{lawyerCertificateNo},</if>" +
-//        "<if test='lawFirm != null'>law_firm = #{lawFirm},</if>" +
-//        "<if test='practiceYears != null'>practice_years = #{practiceYears},</if>" +
-//        "<if test='practiceStartDate != null'>practice_start_date = #{practiceStartDate},</if>" +
-//        "<if test='specialtyFields != null'>specialty_fields = #{specialtyFields},</if>" +
-//        "<if test='certificationStatus != null'>certification_status = #{certificationStatus},</if>" +
-//        "<if test='certificationFailReason != null'>certification_fail_reason = #{certificationFailReason},</if>" +
-//        "<if test='certificationTime != null'>certification_time = #{certificationTime},</if>" +
-//        "<if test='certificationReviewerId != null'>certification_reviewer_id = #{certificationReviewerId},</if>" +
-//        "<if test='certificateImage != null'>certificate_image = #{certificateImage},</if>" +
-//        "<if test='idCardFrontImage != null'>id_card_front_image = #{idCardFrontImage},</if>" +
-//        "<if test='idCardBackImage != null'>id_card_back_image = #{idCardBackImage},</if>" +
-//        "<if test='serviceScore != null'>service_score = #{serviceScore},</if>" +
-//        "<if test='serviceCount != null'>service_count = #{serviceCount},</if>" +
-//        "<if test='goodReviewCount != null'>good_review_count = #{goodReviewCount},</if>" +
-//        "<if test='mediumReviewCount != null'>medium_review_count = #{mediumReviewCount},</if>" +
-//        "<if test='badReviewCount != null'>bad_review_count = #{badReviewCount},</if>" +
-//        "<if test='consultationFee != null'>consultation_fee = #{consultationFee},</if>" +
-//        "<if test='agencyFee != null'>agency_fee = #{agencyFee},</if>" +
-//        "<if test='province != null'>province = #{province},</if>" +
-//        "<if test='city != null'>city = #{city},</if>" +
-//        "<if test='district != null'>district = #{district},</if>" +
-//        "<if test='address != null'>address = #{address},</if>" +
-//        "<if test='email != null'>email = #{email},</if>" +
-//        "<if test='gender != null'>gender = #{gender},</if>" +
-//        "<if test='birthday != null'>birthday = #{birthday},</if>" +
-//        "<if test='personalIntroduction != null'>personal_introduction = #{personalIntroduction},</if>" +
-//        "<if test='educationBackground != null'>education_background = #{educationBackground},</if>" +
-//        "<if test='workExperience != null'>work_experience = #{workExperience},</if>" +
-//        "<if test='expertiseCases != null'>expertise_cases = #{expertiseCases},</if>" +
-//        "<if test='isOnline != null'>is_online = #{isOnline},</if>" +
-//        "<if test='lastOnlineTime != null'>last_online_time = #{lastOnlineTime},</if>" +
-//        "<if test='isRecommended != null'>is_recommended = #{isRecommended},</if>" +
-//        "<if test='recommendSort != null'>recommend_sort = #{recommendSort},</if>" +
-//        "<if test='orderReceivingStatus != null'>order_receiving_status = #{orderReceivingStatus},</if>" +
-//        "<if test='lawyerExpertiseAreaId != null'>lawyer_expertise_area_id = #{lawyerExpertiseAreaId},</if>" +
-//        "<if test='commissionRate != null'>commission_rate = #{commissionRate},</if>" +
-//        "<if test='paymentNum != null'>payment_num = #{paymentNum},</if>" +
-//        "</set>" +
-//        "WHERE id = #{id}" +
-//        "</script>")
-//Integer updateLawyerUser(LawyerUser user);
-//
-//}
-//

+ 9 - 8
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerLegalProblemScenarioController.java

@@ -1,14 +1,13 @@
 package shop.alien.lawyer.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 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.LawyerImg;
 import shop.alien.entity.store.LawyerLegalProblemScenario;
+import shop.alien.entity.store.dto.LawyerLegalProblemScenarioStatusDto;
 import shop.alien.lawyer.service.LawyerLegalProblemScenarioService;
 import shop.alien.mapper.LawyerImgMapper;
 import shop.alien.util.myBaticsPlus.QueryBuilder;
@@ -92,12 +91,6 @@ public class LawyerLegalProblemScenarioController {
                 .build()
                 .list(lawyerLegalProblemScenarioService);
 
-        for (LawyerLegalProblemScenario item : list) {
-            Integer id = item.getId();
-            LawyerImg a = lawyerImgMapper.getLawyerImgById(id);
-            item.setImgUrl(ObjectUtils.isNotEmpty(a) ? a.getImgUrl() : "");
-        }
-
         return R.data(list);
     }
 
@@ -145,5 +138,13 @@ public class LawyerLegalProblemScenarioController {
         return lawyerLegalProblemScenarioService.getCategoryTreeByFirstLevelId(id);
     }
 
+    @ApiOperation("设置法律场景启用/禁用状态")
+    @ApiOperationSupport(order = 8)
+    @PostMapping("/setStatus")
+    public R<Boolean> setStatus(@RequestBody LawyerLegalProblemScenarioStatusDto request) {
+        log.info("LawyerLegalProblemScenarioController.setStatus?request={}", request);
+        return lawyerLegalProblemScenarioService.setStatus(request.getId(), request.getStatus());
+    }
+
 }
 

+ 46 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerUserController.java

@@ -7,10 +7,12 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawyerUser;
+import shop.alien.entity.store.dto.LawyerRecommendedDto;
 import shop.alien.entity.store.vo.LawyerUserVo;
 import shop.alien.lawyer.service.LawyerUserService;
 import shop.alien.util.myBaticsPlus.QueryBuilder;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 import java.util.Map;
 
@@ -254,6 +256,42 @@ public class LawyerUserController {
         return lawyerUserService.getLawyerList(name, phone, firmId, startTime, endTime, page, size);
     }
 
+    @ApiOperation("导出中台律师列表")
+    @ApiOperationSupport(order = 19)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "name", value = "姓名(支持模糊查询)", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "phone", value = "手机号(支持模糊查询)", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "firmId", value = "律所ID", dataType = "Integer", paramType = "query", required = false),
+            @ApiImplicitParam(name = "startTime", value = "开始日期(用于查询执业开始日期practice_start_date,格式:yyyy-MM-dd)", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "endTime", value = "结束日期(用于查询执业开始日期practice_start_date,格式:yyyy-MM-dd)", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "pageNum", value = "页码(可选,不传或传0则导出全部,传值则导出本页)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "pageSize", value = "页容(可选,与pageNum配合使用)", dataType = "Integer", paramType = "query")
+    })
+    @GetMapping(value = "/exportLawyerList", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+    public void exportLawyerList(
+            HttpServletResponse response,
+            @RequestParam(required = false) String name,
+            @RequestParam(required = false) String phone,
+            @RequestParam(required = false) Integer firmId,
+            @RequestParam(required = false) String startTime,
+            @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Integer pageNum,
+            @RequestParam(required = false) Integer pageSize) throws Exception {
+        log.info("LawyerUserController.exportLawyerList?name={},phone={},firmId={},startTime={},endTime={},pageNum={},pageSize={}",
+                name, phone, firmId, startTime, endTime, pageNum, pageSize);
+        try {
+            lawyerUserService.exportLawyerList(response, name, phone, firmId, startTime, endTime, pageNum, pageSize);
+        } catch (Exception e) {
+            log.error("导出律师列表异常", e);
+            if (!response.isCommitted()) {
+                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                response.setContentType("application/json;charset=UTF-8");
+                response.getWriter().write("{\"code\":500,\"msg\":\"导出失败:" + e.getMessage() + "\"}");
+            }
+            throw e;
+        }
+    }
+
 
 
 
@@ -285,5 +323,13 @@ public class LawyerUserController {
         return lawyerUserService.getLawyerInfoByPhone(phone);
     }
 
+    @ApiOperation("设置律师推荐状态")
+    @ApiOperationSupport(order = 18)
+    @PostMapping("/isRecommended")
+    public R<Boolean> isRecommended(@RequestBody LawyerRecommendedDto request) {
+        log.info("LawyerUserController.isRecommended?request={}", request);
+        return lawyerUserService.isRecommended(request.getLawyerId(), request.getIsRecommended());
+    }
+
 }
 

+ 105 - 24
alien-lawyer/src/main/java/shop/alien/lawyer/controller/OrderReviewController.java

@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.OrderReview;
 import shop.alien.entity.store.dto.OrderReviewDto;
+import shop.alien.entity.store.vo.LawyerReviewStatisticsVo;
 import shop.alien.entity.store.vo.OrderReviewDetailVo;
 import shop.alien.entity.store.vo.OrderReviewVo;
 import shop.alien.entity.store.vo.PendingReviewVo;
@@ -41,6 +42,60 @@ public class OrderReviewController {
         return orderReviewService.createReview(reviewDto);
     }
 
+    @ApiOperation("获取评价详情(包含评论和回复)")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/detail/reviewId")
+    public R<OrderReviewDetailVo> getReviewDetail(
+            @RequestParam Integer reviewId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("OrderReviewController.getReviewDetail?reviewId={}, currentUserId={}", reviewId, currentUserId);
+        if (reviewId == null) {
+            return R.fail("评价ID不能为空");
+        }
+        return orderReviewService.getReviewDetail(reviewId, currentUserId);
+    }
+
+    @ApiOperation("点赞评价")
+    @ApiOperationSupport(order = 8)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/like")
+    public R<Boolean> likeReview(@RequestBody OrderReview orderReview) {
+        Integer reviewId = orderReview.getId();
+        Integer userId = orderReview.getUserId();
+        log.info("OrderReviewController.likeReview?reviewId={}, userId={}", reviewId, userId);
+        if (userId == null) {
+            return R.fail("用户未登录");
+        }
+        if (reviewId == null) {
+            return R.fail("评价ID不能为空");
+        }
+        return orderReviewService.likeReview(reviewId, userId);
+    }
+
+    @ApiOperation("取消点赞评价")
+    @ApiOperationSupport(order = 9)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+    })
+    @PostMapping("/cancelLike")
+    public R<Boolean> cancelLikeReview(@RequestBody OrderReview orderReview) {
+        Integer reviewId = orderReview.getId();
+        Integer userId = orderReview.getUserId();
+        log.info("OrderReviewController.cancelLikeReview?reviewId={}, userId={}", reviewId, userId);
+        if (userId == null) {
+            return R.fail("用户未登录");
+        }
+        return orderReviewService.cancelLikeReview(reviewId, userId);
+    }
+
     @ApiOperation("分页查询评价列表")
     @ApiOperationSupport(order = 2)
     @ApiImplicitParams({
@@ -132,38 +187,64 @@ public class OrderReviewController {
         return orderReviewService.getMyReviewList(page, size, userId, currentUserId);
     }
 
-    @ApiOperation("点赞评价")
-    @ApiOperationSupport(order = 8)
+    @ApiOperation("获取律师评价统计数据(全部数量、好评数量、中评数量、差评数量、有图数量)")
+    @ApiOperationSupport(order = 9)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
-            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+            @ApiImplicitParam(name = "lawyerUserId", value = "律师用户ID", dataType = "int", paramType = "query", required = true)
     })
-    @PostMapping("/like")
-    public R<Boolean> likeReview(
-            @RequestParam Integer reviewId,
-            @RequestParam Integer userId) {
-        log.info("OrderReviewController.likeReview?reviewId={}, userId={}", reviewId, userId);
-        if (userId == null) {
-            return R.fail("用户未登录");
+    @GetMapping("/statistics")
+    public R<LawyerReviewStatisticsVo> getLawyerReviewStatistics(@RequestParam Integer lawyerUserId) {
+        log.info("OrderReviewController.getLawyerReviewStatistics?lawyerUserId={}", lawyerUserId);
+        if (lawyerUserId == null) {
+            return R.fail("律师ID不能为空");
         }
-        return orderReviewService.likeReview(reviewId, userId);
+        return orderReviewService.getLawyerReviewStatistics(lawyerUserId);
     }
 
-    @ApiOperation("取消点赞评价")
-    @ApiOperationSupport(order = 9)
+    @ApiOperation("根据律师ID分页查询评价列表(查询指定律师的所有评价)")
+    @ApiOperationSupport(order = 10)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "reviewId", value = "评价ID", dataType = "int", paramType = "query", required = true),
-            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+            @ApiImplicitParam(name = "page", value = "页数(默认1)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "size", value = "页容(默认10)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "lawyerUserId", value = "律师用户ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
     })
-    @PostMapping("/cancelLike")
-    public R<Boolean> cancelLikeReview(
-            @RequestParam Integer reviewId,
-            @RequestParam Integer userId) {
-        log.info("OrderReviewController.cancelLikeReview?reviewId={}, userId={}", reviewId, userId);
-        if (userId == null) {
-            return R.fail("用户未登录");
+    @GetMapping("/list/byLawyer")
+    public R<IPage<OrderReviewVo>> getReviewListByLawyer(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "10") int size,
+            @RequestParam Integer lawyerUserId,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("OrderReviewController.getReviewListByLawyer?page={}, size={}, lawyerUserId={}, currentUserId={}",
+                page, size, lawyerUserId, currentUserId);
+        if (lawyerUserId == null) {
+            return R.fail("律师ID不能为空");
         }
-        return orderReviewService.cancelLikeReview(reviewId, userId);
+        return orderReviewService.getReviewList(page, size, null, lawyerUserId, null, currentUserId);
+    }
+
+    @ApiOperation("根据律师ID和类型分页查询评价列表(不包含评论)")
+    @ApiOperationSupport(order = 11)
+    @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 = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "type", value = "查询分类(1:好评,2:中评,3:差评,4:有图,为空时返回全部)", dataType = "int", paramType = "query", required = false),
+            @ApiImplicitParam(name = "currentUserId", value = "当前用户ID(用于判断是否已点赞)", dataType = "int", paramType = "query")
+    })
+    @GetMapping("/list/byLawyerAndType")
+    public R<IPage<OrderReviewVo>> getReviewListByLawyerAndType(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "10") int size,
+            @RequestParam Integer lawyerUserId,
+            @RequestParam(required = false) Integer type,
+            @RequestParam(required = false) Integer currentUserId) {
+        log.info("OrderReviewController.getReviewListByLawyerAndType?page={}, size={}, lawyerUserId={}, type={}, currentUserId={}",
+                page, size, lawyerUserId, type, currentUserId);
+        if (lawyerUserId == null) {
+            return R.fail("律师ID不能为空");
+        }
+        return orderReviewService.getReviewListByLawyerAndType(page, size, lawyerUserId, type, currentUserId);
     }
 }
 

+ 35 - 57
alien-lawyer/src/main/java/shop/alien/lawyer/controller/ReviewCommentController.java

@@ -6,13 +6,10 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.ReviewComment;
-import shop.alien.entity.store.dto.ReviewCommentDto;
 import shop.alien.entity.store.dto.ReviewCommentRequestDto;
 import shop.alien.entity.store.dto.ReviewReplyDto;
 import shop.alien.entity.store.vo.ReviewCommentVo;
-import shop.alien.entity.store.UserLoginInfo;
 import shop.alien.lawyer.service.ReviewCommentService;
-import shop.alien.util.common.TokenInfo;
 
 import java.util.List;
 
@@ -36,12 +33,12 @@ public class ReviewCommentController {
     @ApiOperation("创建评论(其他用户对评价的评论)")
     @ApiOperationSupport(order = 1)
     @PostMapping("/create")
-    public R<ReviewComment> createComment(@RequestBody ReviewCommentDto commentDto) {
-        log.info("ReviewCommentController.createComment?commentDto={}", commentDto);
-        if (commentDto.getUserId() == null) {
+    public R<ReviewComment> createComment(@RequestBody ReviewComment comment) {
+        log.info("ReviewCommentController.createComment?comment={}", comment);
+        if (comment.getUserId() == null) {
             return R.fail("用户未登录");
         }
-        return reviewCommentService.createComment(commentDto);
+        return reviewCommentService.createComment(comment);
     }
 
     @ApiOperation("根据评价ID查询评论列表")
@@ -58,21 +55,6 @@ public class ReviewCommentController {
         return reviewCommentService.getCommentListByReviewId(reviewId, currentUserId);
     }
 
-    @ApiOperation("删除评论(删除评论时,会级联删除该评论下的所有回复)")
-    @ApiOperationSupport(order = 3)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "commentId", value = "评论ID", dataType = "int", paramType = "query", required = true),
-            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
-    })
-    @PostMapping("/delete/commentId")
-    public R<Boolean> deleteComment(@RequestBody ReviewCommentRequestDto requestDto) {
-        log.info("ReviewCommentController.deleteComment?requestDto={}", requestDto);
-        if (requestDto.getUserId() == null) {
-            return R.fail("用户未登录");
-        }
-        return reviewCommentService.deleteComment(requestDto);
-    }
-
     @ApiOperation("点赞评论")
     @ApiOperationSupport(order = 4)
     @ApiImplicitParams({
@@ -80,11 +62,19 @@ public class ReviewCommentController {
             @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
     })
     @PostMapping("/like")
-    public R<Boolean> likeComment(@RequestBody ReviewCommentRequestDto requestDto) {
-        log.info("ReviewCommentController.likeComment?requestDto={}", requestDto);
-        if (requestDto.getUserId() == null) {
+    public R<Boolean> likeComment(@RequestBody ReviewComment reviewComment) {
+        Integer commentId = reviewComment.getId();
+        Integer userId = reviewComment.getUserId();
+        log.info("ReviewCommentController.likeComment?commentId={}, userId={}", commentId, userId);
+        if (userId == null) {
             return R.fail("用户未登录");
         }
+        if (commentId == null) {
+            return R.fail("评论ID不能为空");
+        }
+        ReviewCommentRequestDto requestDto = new ReviewCommentRequestDto();
+        requestDto.setCommentId(commentId);
+        requestDto.setUserId(userId);
         return reviewCommentService.likeComment(requestDto);
     }
 
@@ -95,11 +85,19 @@ public class ReviewCommentController {
             @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
     })
     @PostMapping("/cancelLike")
-    public R<Boolean> cancelLikeComment(@RequestBody ReviewCommentRequestDto requestDto) {
-        log.info("ReviewCommentController.cancelLikeComment?requestDto={}", requestDto);
-        if (requestDto.getUserId() == null) {
+    public R<Boolean> cancelLikeComment(@RequestBody ReviewComment reviewComment) {
+        Integer commentId = reviewComment.getId();
+        Integer userId = reviewComment.getUserId();
+        log.info("ReviewCommentController.cancelLikeComment?commentId={}, userId={}", commentId, userId);
+        if (userId == null) {
             return R.fail("用户未登录");
         }
+        if (commentId == null) {
+            return R.fail("评论ID不能为空");
+        }
+        ReviewCommentRequestDto requestDto = new ReviewCommentRequestDto();
+        requestDto.setCommentId(commentId);
+        requestDto.setUserId(userId);
         return reviewCommentService.cancelLikeComment(requestDto);
     }
 
@@ -145,38 +143,18 @@ public class ReviewCommentController {
         return reviewCommentService.deleteReply(replyId, userId);
     }
 
-    @ApiOperation("点赞回复")
-    @ApiOperationSupport(order = 9)
+    @ApiOperation(value = "删除评论(根据ID)", notes = "根据评论ID删除评论,userId有值时只能删除自己发布的评论,userId为空时允许删除任何评论(管理员删除)")
+    @ApiOperationSupport(order = 11)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "replyId", value = "回复ID", dataType = "int", paramType = "query", required = true),
-            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
+            @ApiImplicitParam(name = "id", value = "评论ID", dataType = "int", paramType = "body", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID(可选,有值时只能删除自己的评论,为空时允许删除任何评论)", dataType = "int", paramType = "body", required = false)
     })
-    @PostMapping("/reply/like")
-    public R<Boolean> likeReply(
-            @RequestParam Integer replyId,
-            @RequestParam Integer userId) {
-        log.info("ReviewCommentController.likeReply?replyId={}, userId={}", replyId, userId);
-        if (userId == null) {
-            return R.fail("用户未登录");
-        }
-        return reviewCommentService.likeReply(replyId, userId);
+    @PostMapping("/deleteReviewComment")
+    public R<Boolean> deleteReviewComment(@RequestBody ReviewComment reviewComment) {
+        log.info("ReviewCommentController.deleteReviewComment?reviewComment={}", reviewComment);
+        return reviewCommentService.deleteReviewComment(reviewComment);
     }
 
-    @ApiOperation("取消点赞回复")
-    @ApiOperationSupport(order = 10)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "replyId", value = "回复ID", dataType = "int", paramType = "query", required = true),
-            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "int", paramType = "query", required = true)
-    })
-    @PostMapping("/reply/cancelLike")
-    public R<Boolean> cancelLikeReply(
-            @RequestParam Integer replyId,
-            @RequestParam Integer userId) {
-        log.info("ReviewCommentController.cancelLikeReply?replyId={}, userId={}", replyId, userId);
-        if (userId == null) {
-            return R.fail("用户未登录");
-        }
-        return reviewCommentService.cancelLikeReply(replyId, userId);
-    }
+
 }
 

+ 9 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerLegalProblemScenarioService.java

@@ -43,5 +43,14 @@ public interface LawyerLegalProblemScenarioService extends IService<LawyerLegalP
      * @return R<LawyerLegalProblemScenario> 返回一级场景及其完整的树形结构(一级场景的children包含所有二级分类,每个二级分类的children包含其下的三级分类)
      */
     R<LawyerLegalProblemScenario> getCategoryTreeByFirstLevelId(Integer id);
+
+    /**
+     * 设置法律场景启用/禁用状态
+     *
+     * @param id 场景ID
+     * @param status 状态,0:禁用,1:启用
+     * @return R<Boolean> 操作结果
+     */
+    R<Boolean> setStatus(Integer id, Integer status);
 }
 

+ 32 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerUserService.java

@@ -7,6 +7,7 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawyerUser;
 import shop.alien.entity.store.vo.LawyerUserVo;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 import java.util.Map;
 
@@ -161,5 +162,36 @@ public interface LawyerUserService extends IService<LawyerUser> {
                                          String endTime,
                                          int page,
                                          int pageSize);
+
+    /**
+     * 设置律师推荐状态
+     *
+     * @param lawyerId 律师ID
+     * @param isRecommended 推荐状态,0:取消推荐,1:推荐
+     * @return R<Boolean> 操作结果
+     */
+    R<Boolean> isRecommended(Integer lawyerId, Integer isRecommended);
+
+    /**
+     * 导出中台律师列表
+     *
+     * @param response HttpServletResponse对象
+     * @param name 姓名(支持模糊查询)
+     * @param phone 手机号(支持模糊查询)
+     * @param firmId 律所ID
+     * @param startTime 开始日期
+     * @param endTime 结束日期
+     * @param pageNum 页码(可选,不传或传0则导出全部)
+     * @param pageSize 页容(可选,与pageNum配合使用)
+     * @throws Exception 导出异常
+     */
+    void exportLawyerList(HttpServletResponse response,
+                          String name,
+                          String phone,
+                          Integer firmId,
+                          String startTime,
+                          String endTime,
+                          Integer pageNum,
+                          Integer pageSize) throws Exception;
 }
 

+ 36 - 26
alien-lawyer/src/main/java/shop/alien/lawyer/service/OrderReviewService.java

@@ -27,6 +27,33 @@ public interface OrderReviewService extends IService<OrderReview> {
     R<OrderReview> createReview(OrderReviewDto reviewDto);
 
     /**
+     * 获取评价详情(包含评论和回复)
+     *
+     * @param reviewId 评价ID
+     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
+     * @return R<OrderReviewDetailVo>
+     */
+    R<OrderReviewDetailVo> getReviewDetail(Integer reviewId, Integer currentUserId);
+
+    /**
+     * 点赞评价
+     *
+     * @param reviewId 评价ID
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> likeReview(Integer reviewId, Integer userId);
+
+    /**
+     * 取消点赞评价
+     *
+     * @param reviewId 评价ID
+     * @param userId 用户ID
+     * @return R<Boolean>
+     */
+    R<Boolean> cancelLikeReview(Integer reviewId, Integer userId);
+
+    /**
      * 分页查询评价列表
      *
      * @param pageNum 页码
@@ -39,20 +66,12 @@ public interface OrderReviewService extends IService<OrderReview> {
      */
     R<IPage<OrderReviewVo>> getReviewList(int pageNum, int pageSize, Integer orderId, Integer lawyerUserId, Integer userId, Integer currentUserId);
 
-    /**
-     * 获取评价详情(包含评论和回复)
-     *
-     * @param reviewId 评价ID
-     * @param currentUserId 当前用户ID(用于判断是否已点赞,可为null)
-     * @return R<OrderReviewDetailVo>
-     */
-    R<OrderReviewDetailVo> getReviewDetail(Integer reviewId, Integer currentUserId);
 
     /**
      * 删除评价(删除评价时,会级联删除该评价下的所有评论和回复)
      *
      * @param reviewId 评价ID
-     * @param userId 用户ID(验证是否为评价用户
+     * @param userId 用户ID(可选,有值时只能删除自己的评价,为空时允许删除任何评价)
      * @return R<Boolean>
      */
     R<Boolean> deleteReview(Integer reviewId, Integer userId);
@@ -88,23 +107,6 @@ public interface OrderReviewService extends IService<OrderReview> {
     R<IPage<OrderReviewVo>> getMyReviewList(int pageNum, int pageSize, Integer userId, Integer currentUserId);
 
     /**
-     * 点赞评价
-     *
-     * @param reviewId 评价ID
-     * @param userId 用户ID
-     * @return R<Boolean>
-     */
-    R<Boolean> likeReview(Integer reviewId, Integer userId);
-
-    /**
-     * 取消点赞评价
-     *
-     * @param reviewId 评价ID
-     * @param userId 用户ID
-     * @return R<Boolean>
-     */
-    R<Boolean> cancelLikeReview(Integer reviewId, Integer userId);
-    /**
      * 根据律师ID和类型分页查询评价列表(不包含评论)
      *
      * @param pageNum 页码
@@ -116,5 +118,13 @@ public interface OrderReviewService extends IService<OrderReview> {
      */
     R<IPage<OrderReviewVo>> getReviewListByLawyerAndType(int pageNum, int pageSize, Integer lawyerUserId, Integer type, Integer currentUserId);
 
+    /**
+     * 获取律师评价统计数据
+     *
+     * @param lawyerUserId 律师用户ID
+     * @return R<LawyerReviewStatisticsVo>
+     */
+    R<shop.alien.entity.store.vo.LawyerReviewStatisticsVo> getLawyerReviewStatistics(Integer lawyerUserId);
+
 }
 

+ 6 - 25
alien-lawyer/src/main/java/shop/alien/lawyer/service/ReviewCommentService.java

@@ -3,7 +3,6 @@ package shop.alien.lawyer.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.ReviewComment;
-import shop.alien.entity.store.dto.ReviewCommentDto;
 import shop.alien.entity.store.dto.ReviewCommentRequestDto;
 import shop.alien.entity.store.dto.ReviewReplyDto;
 import shop.alien.entity.store.vo.ReviewCommentVo;
@@ -21,11 +20,10 @@ public interface ReviewCommentService extends IService<ReviewComment> {
     /**
      * 创建评论(其他用户对评价的评论)
      *
-     * @param commentDto 评论DTO
-     *
+     * @param comment 评论实体
      * @return R<ReviewComment>
      */
-    R<ReviewComment> createComment(ReviewCommentDto commentDto);
+    R<ReviewComment> createComment(ReviewComment comment);
 
     /**
      * 根据评价ID查询评论列表
@@ -37,14 +35,6 @@ public interface ReviewCommentService extends IService<ReviewComment> {
     R<List<ReviewCommentVo>> getCommentListByReviewId(Integer reviewId, Integer currentUserId);
 
     /**
-     * 删除评论(删除评论时,会级联删除该评论下的所有回复)
-     *
-     * @param requestDto 请求DTO
-     * @return R<Boolean>
-     */
-    R<Boolean> deleteComment(ReviewCommentRequestDto requestDto);
-
-    /**
      * 点赞评论
      *
      * @param requestDto 请求DTO
@@ -87,21 +77,12 @@ public interface ReviewCommentService extends IService<ReviewComment> {
     R<Boolean> deleteReply(Integer replyId, Integer userId);
 
     /**
-     * 点赞回复
-     *
-     * @param replyId 回复ID
-     * @param userId 用户ID
-     * @return R<Boolean>
-     */
-    R<Boolean> likeReply(Integer replyId, Integer userId);
-
-    /**
-     * 取消点赞回复
+     * 删除评论(根据ID,物理删除)
+     * userId有值时只能删除自己发布的评论,userId为空时允许删除任何评论(管理员删除)
      *
-     * @param replyId 回复ID
-     * @param userId 用户ID
+     * @param reviewComment 评论对象(包含id和userId,userId可选)
      * @return R<Boolean>
      */
-    R<Boolean> cancelLikeReply(Integer replyId, Integer userId);
+    R<Boolean> deleteReviewComment(ReviewComment reviewComment);
 }
 

+ 10 - 16
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/CommentAppealServiceImpl.java

@@ -156,7 +156,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             }
 
             // 发送通知
-            sendAuditNotification(appeal, orderReview, status);
+            sendAuditNotification(appeal, orderReview, status, reviewReasons);
 
             return R.success("申诉" + statusText);
         } else {
@@ -200,9 +200,9 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
 
             com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
             jsonObject.put("message", message);
-            jsonObject.put("orderNumber", orderReview.getOrderNumber());
-            jsonObject.put("appealId", appeal.getId());
-            jsonObject.put("status", "pending"); // 待审核状态
+//            jsonObject.put("orderNumber", orderReview.getOrderNumber());
+//            jsonObject.put("appealId", appeal.getId());
+//            jsonObject.put("status", "pending"); // 待审核状态
             lifeNotice.setContext(jsonObject.toJSONString());
 
             lifeNoticeMapper.insert(lifeNotice);
@@ -222,16 +222,16 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
      * @param orderReview 评价记录
      * @param status      审核状态 1:已通过, 2:已驳回
      */
-    private void sendAuditNotification(CommentAppeal appeal, OrderReview orderReview, Integer status) {
+    private void sendAuditNotification(CommentAppeal appeal, OrderReview orderReview, Integer status, String reviewReasons) {
         try {
             if (status == 1) {
                 // 审核通过:给评价用户发通知(评价被删除)
                 sendNotificationToReviewUser(orderReview, appeal);
                 // 审核通过:给律师发通知(申诉成功)
-                sendNotificationToLawyer(orderReview, appeal, true);
+                sendNotificationToLawyer(orderReview, appeal, true, null);
             } else {
                 // 审核驳回:给律师发通知(申诉失败)
-                sendNotificationToLawyer(orderReview, appeal, false);
+                sendNotificationToLawyer(orderReview, appeal, false, reviewReasons);
             }
         } catch (Exception e) {
             log.error("发送审核通知失败,appealId={}, status={}, error={}", appeal.getId(), status, e.getMessage(), e);
@@ -253,8 +253,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             }
 
             String receiverId = "user_" + lifeUser.getUserPhone();
-            String message = String.format("您对订单编号为"+ orderReview.getOrderNumber() +"的评价,律师已进行申诉,经核实,您的评价不实,平台已删除此条评价及回复。",
-                    orderReview.getOrderNumber());
+            String message = String.format("您对订单编号为"+ orderReview.getOrderNumber() +"的评价,律师已进行申诉,经核实,您的评价不实,平台已删除此条评价及回复。");
 
             LifeNotice lifeNotice = new LifeNotice();
             lifeNotice.setReceiverId(receiverId);
@@ -267,8 +266,6 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
 
             com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
             jsonObject.put("message", message);
-            jsonObject.put("orderNumber", orderReview.getOrderNumber());
-            jsonObject.put("appealId", appeal.getId());
             lifeNotice.setContext(jsonObject.toJSONString());
 
             lifeNoticeMapper.insert(lifeNotice);
@@ -288,7 +285,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
      * @param appeal      申诉记录
      * @param isSuccess   是否成功
      */
-    private void sendNotificationToLawyer(OrderReview orderReview, CommentAppeal appeal, boolean isSuccess) {
+    private void sendNotificationToLawyer(OrderReview orderReview, CommentAppeal appeal, boolean isSuccess, String reviewReasons) {
         try {
             LawyerUser lawyerUser = lawyerUserMapper.selectById(orderReview.getLawyerUserId());
             if (lawyerUser == null) {
@@ -301,7 +298,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             String title = isSuccess ? "申诉成功通知" : "申诉失败通知";
             String message = isSuccess 
                     ? String.format("您的编号"+ orderReview.getOrderNumber() +"的订单,提交的差评申诉信息,经核实,评价内容不实,平台已删除此条评价。")
-                    : String.format("您的编号"+ orderReview.getOrderNumber() +"的订单,提交的差评申诉信息,经核实,评价内容属实。失败原因:"+ appeal.getReviewReasons() +"。");
+                    : String.format("您的编号"+ orderReview.getOrderNumber() +"的订单,提交的差评申诉信息,经核实,评价内容属实。失败原因:"+ reviewReasons +"。");
 
             LifeNotice lifeNotice = new LifeNotice();
             lifeNotice.setReceiverId(receiverId);
@@ -314,9 +311,6 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
 
             com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
             jsonObject.put("message", message);
-            jsonObject.put("orderNumber", orderReview.getOrderNumber());
-            jsonObject.put("appealId", appeal.getId());
-            jsonObject.put("status", isSuccess ? "success" : "rejected");
             lifeNotice.setContext(jsonObject.toJSONString());
 
             lifeNoticeMapper.insert(lifeNotice);

+ 1 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawFirmPaymentServiceImpl.java

@@ -31,3 +31,4 @@ public class LawFirmPaymentServiceImpl extends ServiceImpl<LawFirmPaymentMapper,
 
 
 
+

+ 55 - 11
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerClientConsultationOrderServiceImpl.java

@@ -16,11 +16,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.LawyerConsultationOrder;
-import shop.alien.entity.store.LawyerServiceArea;
-import shop.alien.entity.store.LawyerUser;
-import shop.alien.entity.store.LifeNotice;
-import shop.alien.entity.store.LifeUser;
+import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.LawyerConsultationOrderDto;
 import shop.alien.entity.store.dto.PayStatusRequest;
 import shop.alien.entity.store.vo.LawyerConsultationOrderVO;
@@ -31,12 +27,7 @@ import shop.alien.lawyer.service.LawyerClientConsultationOrderService;
 import shop.alien.lawyer.service.LawyerConsultationOrderService;
 import shop.alien.lawyer.service.LawyerUserService;
 import shop.alien.lawyer.service.OrderExpirationService;
-import shop.alien.mapper.LawyerConsultationOrderMapper;
-import shop.alien.mapper.LawyerExpertiseAreaMapper;
-import shop.alien.mapper.LawyerServiceAreaMapper;
-import shop.alien.mapper.LawyerUserMapper;
-import shop.alien.mapper.LifeNoticeMapper;
-import shop.alien.mapper.LifeUserMapper;
+import shop.alien.mapper.*;
 import shop.alien.util.common.constant.LawyerStatusEnum;
 import shop.alien.util.common.constant.OrderActionType;
 import com.alibaba.fastjson2.JSON;
@@ -70,6 +61,7 @@ public class LawyerClientConsultationOrderServiceImpl extends ServiceImpl<Lawyer
     private final LifeNoticeMapper lifeNoticeMapper;
     private final LifeUserMapper lifeUserMapper;
     private final WebSocketProcess webSocketProcess;
+    private final LifeMessageMapper lifeMessageMapper;
 
     /**
      * 系统发送者ID常量
@@ -375,6 +367,8 @@ public class LawyerClientConsultationOrderServiceImpl extends ServiceImpl<Lawyer
             fillLawyerServiceArea(voPage);
             // 为待支付订单计算倒计时(30分钟有效期)
             calculateCountdownForPendingOrders(voPage);
+            //填充未读消息
+            fillUnreadMessage(voPage,lawyerId);
         }
 
         // 获取统计信息
@@ -391,6 +385,56 @@ public class LawyerClientConsultationOrderServiceImpl extends ServiceImpl<Lawyer
     }
 
     /**
+     * 填充未读消息数量
+     *
+     * @param voPage 订单VO分页对象
+     */
+    private void fillUnreadMessage(IPage<LawyerConsultationOrderVO> voPage,String lawyerId) {
+        List<LawyerConsultationOrderVO> orderList = voPage.getRecords();
+        if (CollectionUtils.isEmpty(orderList)) {
+            return;
+        }
+
+        // 提取所有律师ID,并加上lawyer_前缀
+        List<String> lawyerIdList = orderList.stream()
+                .map(LawyerConsultationOrderVO::getLawyerPhone)
+                .filter(Objects::nonNull)
+                .map(phone -> "lawyer_" + phone)
+                .distinct()
+                .collect(Collectors.toList());
+
+        if (CollectionUtils.isEmpty(lawyerIdList)) {
+            return;
+        }
+
+        LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerId);
+        String phone = lawyerUser.getPhone();
+
+        LambdaQueryWrapper<LifeMessage> lifeMessageLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lifeMessageLambdaQueryWrapper.in(LifeMessage::getSenderId, lawyerIdList);
+        lifeMessageLambdaQueryWrapper.eq(LifeMessage::getDeleteFlag, 0);
+        lifeMessageLambdaQueryWrapper.eq(LifeMessage::getIsRead, 0);
+        lifeMessageLambdaQueryWrapper.eq(LifeMessage::getReceiverId, "lawyer_" + phone);
+        List<LifeMessage> lifeMessageList = lifeMessageMapper.selectList(lifeMessageLambdaQueryWrapper);
+
+        // 按照senderId进行分组,返回senderId和数量的map
+        Map<String, Long> senderIdCountMap = lifeMessageList.stream()
+                .collect(Collectors.groupingBy(LifeMessage::getSenderId, Collectors.counting()));
+
+        // 填充问题场景
+        orderList.forEach(order -> {
+            String userPhone = "user_" + order.getClientUserPhone();
+
+            if(!senderIdCountMap.isEmpty()&&senderIdCountMap.containsKey(userPhone)&&order.getOrderStatus() == 2){
+                long messageCount = senderIdCountMap.get(userPhone);
+                order.setUnreadMessage(messageCount);
+            } else{
+                order.setUnreadMessage(0L);
+            }
+        });
+    }
+
+    /**
      * 构建空结果Map
      *
      * @param pageNum  页码

+ 60 - 7
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationOrderServiceImpl.java

@@ -17,12 +17,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.LawFirm;
-import shop.alien.entity.store.LawyerConsultationOrder;
-import shop.alien.entity.store.LawyerServiceArea;
-import shop.alien.entity.store.LawyerUser;
-import shop.alien.entity.store.LifeNotice;
-import shop.alien.entity.store.LifeUser;
+import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.LawyerConsultationOrderDto;
 import shop.alien.entity.store.dto.PayStatusRequest;
 import shop.alien.entity.store.vo.LawyerConsultationOrderVO;
@@ -69,6 +64,8 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
     private final LifeUserMapper lifeUserMapper;
     private final WebSocketProcess webSocketProcess;
 
+    private final LifeMessageMapper lifeMessageMapper;
+
     /**
      * 系统发送者ID
      */
@@ -603,10 +600,13 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
         IPage<LawyerConsultationOrderVO> voPage = consultationOrderMapper.getLawyerConsultationOrderList(
                 page, queryWrapper);
 
-        // 填充法律场景信息和倒计时
         if (voPage != null) {
+            // 填充法律场景信息和倒计时
             fillLegalSceneArea(voPage);
             calculateCountdownForPendingOrders(voPage);
+
+            //填充未读消息
+            fillUnreadMessage(voPage,userId);
         }
 
         // 判断工作日信息
@@ -843,6 +843,58 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
         });
     }
 
+
+
+    /**
+     * 填充未读消息数量
+     *
+     * @param voPage 订单VO分页对象
+     */
+    private void fillUnreadMessage(IPage<LawyerConsultationOrderVO> voPage,String userId) {
+        List<LawyerConsultationOrderVO> orderList = voPage.getRecords();
+        if (CollectionUtils.isEmpty(orderList)) {
+            return;
+        }
+
+        // 提取所有律师ID,并加上lawyer_前缀
+        List<String> lawyerIdList = orderList.stream()
+                .map(LawyerConsultationOrderVO::getLawyerPhone)
+                .filter(Objects::nonNull)
+                .map(phone -> "lawyer_" + phone)
+                .distinct()
+                .collect(Collectors.toList());
+
+        if (CollectionUtils.isEmpty(lawyerIdList)) {
+            return;
+        }
+
+        LifeUser lifeUser = lifeUserMapper.selectById(userId);
+        String phone = lifeUser.getUserPhone();
+
+        LambdaQueryWrapper<LifeMessage> lifeMessageLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lifeMessageLambdaQueryWrapper.in(LifeMessage::getSenderId, lawyerIdList);
+        lifeMessageLambdaQueryWrapper.eq(LifeMessage::getDeleteFlag, 0);
+        lifeMessageLambdaQueryWrapper.eq(LifeMessage::getIsRead, 0);
+        lifeMessageLambdaQueryWrapper.eq(LifeMessage::getReceiverId, "user_" + phone);
+        List<LifeMessage> lifeMessageList = lifeMessageMapper.selectList(lifeMessageLambdaQueryWrapper);
+
+        // 按照senderId进行分组,返回senderId和数量的map
+        Map<String, Long> senderIdCountMap = lifeMessageList.stream()
+                .collect(Collectors.groupingBy(LifeMessage::getSenderId, Collectors.counting()));
+
+        // 填充问题场景
+        orderList.forEach(order -> {
+            String lawyerPhone = "lawyer_" + order.getLawyerPhone();
+            if(!senderIdCountMap.isEmpty()&&senderIdCountMap.containsKey(lawyerPhone)&&order.getOrderStatus() == 2){
+                long messageCount = senderIdCountMap.get(lawyerPhone);
+                order.setUnreadMessage(messageCount);
+            } else {
+                order.setUnreadMessage(0L);
+            }
+        });
+    }
+
+
     /**
      * 批量查询律师问题场景
      *
@@ -1263,6 +1315,7 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
             LambdaQueryWrapper<LawyerConsultationOrder> allRevenueWrapper = new LambdaQueryWrapper<>();
             allRevenueWrapper.eq(LawyerConsultationOrder::getLawyerUserId, lawyerConsultationOrderVO.getLawyerUserId())
                     .eq(LawyerConsultationOrder::getPaymentStatus, 1) // 已支付
+                    .in(LawyerConsultationOrder::getOrderStatus, 2,3) // 订单状态=3(已完成)2(进行中)
                     .eq(LawyerConsultationOrder::getDeleteFlag, 0);
             
             // 添加时间段筛选条件(根据支付时间)

+ 34 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerLegalProblemScenarioServiceImpl.java

@@ -161,5 +161,39 @@ public class LawyerLegalProblemScenarioServiceImpl extends ServiceImpl<LawyerLeg
         return R.data(firstLevel);
     }
 
+    @Override
+    public R<Boolean> setStatus(Integer id, Integer status) {
+        log.info("LawyerLegalProblemScenarioServiceImpl.setStatus?id={},status={}", id, status);
+
+        // 参数校验
+        if (id == null) {
+            log.warn("设置法律场景状态失败:场景ID为空");
+            return R.fail("场景ID不能为空");
+        }
+
+        if (status == null || (status != 0 && status != 1)) {
+            log.warn("设置法律场景状态失败:状态参数无效,status={}", status);
+            return R.fail("状态参数无效,必须为0(禁用)或1(启用)");
+        }
+
+        // 查询场景信息
+        LawyerLegalProblemScenario scenario = this.getById(id);
+        if (scenario == null) {
+            log.warn("设置法律场景状态失败:场景不存在,场景ID={}", id);
+            return R.fail("场景不存在");
+        }
+
+        // 更新状态
+        scenario.setStatus(status);
+        boolean result = this.updateById(scenario);
+        if (result) {
+            log.info("设置法律场景状态成功:场景ID={},状态={}", id, status);
+            return R.success("设置成功");
+        } else {
+            log.warn("设置法律场景状态失败:更新数据库失败,场景ID={},状态={}", id, status);
+            return R.fail("设置失败");
+        }
+    }
+
 }
 

+ 5 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserLogInServiceImpl.java

@@ -42,6 +42,9 @@ public class LawyerUserLogInServiceImpl extends ServiceImpl<LawyerUserMapper, La
     @Value("${jwt.expiration-time}")
     private String effectiveTime;
 
+    @Value("${order.lawyerFee}")
+    private String lawyerFee;
+
     /**
      * 设定初始化默认密码
      */
@@ -111,8 +114,9 @@ public class LawyerUserLogInServiceImpl extends ServiceImpl<LawyerUserMapper, La
             user.setDeleteFlag(0);
             user.setIsOnline(1);
             user.setIsRecommended(0);
-            user.setOrderReceivingStatus(0);
+            user.setOrderReceivingStatus(1);
             user.setPassType(2);
+            user.setConsultationFee(Integer.parseInt(lawyerFee));
             lawyerUserMapper.insert(user);
             List<Integer> problemScenarioIds = lawyerUserDto.getProblemScenarioIds();
             for (int i = 0; i < problemScenarioIds.size(); i++) {

+ 221 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserServiceImpl.java

@@ -8,13 +8,13 @@ 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 org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
+import shop.alien.entity.store.excelVo.LawyerUserExcelVo;
 import shop.alien.entity.store.vo.LawyerUserVo;
 import shop.alien.lawyer.config.BaseRedisService;
 import shop.alien.lawyer.service.LawyerLegalProblemScenarioService;
@@ -23,7 +23,10 @@ import shop.alien.lawyer.service.LawyerUserSearchHistoryService;
 import shop.alien.lawyer.service.LawyerUserService;
 import shop.alien.mapper.*;
 import shop.alien.util.common.ListToPage;
+import shop.alien.util.excel.EasyExcelUtil;
 
+import javax.servlet.http.HttpServletResponse;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -48,6 +51,7 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
     private final LawFirmMapper lawFirmMapper;
     private final BaseRedisService baseRedisService;
     private final LawFirmPaymentMapper lawFirmPaymentmapper;
+    private final OrderReviewMapper orderReviewMapper;
 
     @Override
     public R<IPage<LawyerUser>> getLawyerUserList(int pageNum, int pageSize, String name, String phone, Integer status) {
@@ -202,6 +206,8 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
         // 为每个律师设置关联的法律问题场景列表
         if (pageResult.getRecords() != null && !pageResult.getRecords().isEmpty()) {
             setLawyerScenarios(pageResult.getRecords());
+            // 设置律师评价数
+            setLawyerReviewCounts(pageResult.getRecords());
         }
 
         return R.data(pageResult);
@@ -283,6 +289,52 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
                 .collect(Collectors.toMap(LawyerLegalProblemScenario::getId, s -> s, (k1, k2) -> k1));
     }
 
+    /**
+     * 批量设置律师的评价数(只统计评价,不包含评论)
+     *
+     * @param lawyers 律师列表
+     */
+    private void setLawyerReviewCounts(List<LawyerUser> lawyers) {
+        if (CollectionUtils.isEmpty(lawyers)) {
+            return;
+        }
+
+        List<Integer> lawyerIds = lawyers.stream()
+                .map(LawyerUser::getId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        if (lawyerIds.isEmpty()) {
+            return;
+        }
+
+        try {
+            // 批量查询每个律师的评价数
+            LambdaQueryWrapper<OrderReview> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.in(OrderReview::getLawyerUserId, lawyerIds)
+                    .eq(OrderReview::getDeleteFlag, 0)
+                    .select(OrderReview::getLawyerUserId);
+            List<OrderReview> reviews = orderReviewMapper.selectList(queryWrapper);
+
+            // 按律师ID分组统计评价数
+            Map<Integer, Long> reviewCountMap = reviews.stream()
+                    .filter(r -> r.getLawyerUserId() != null)
+                    .collect(Collectors.groupingBy(OrderReview::getLawyerUserId, Collectors.counting()));
+
+            // 为每个律师设置评价数
+            lawyers.forEach(lawyer -> {
+                Long count = reviewCountMap.get(lawyer.getId());
+                lawyer.setReviewCount(count != null ? count.intValue() : 0);
+            });
+
+            log.debug("批量设置律师评价数完成,律师数量={}", lawyers.size());
+        } catch (Exception e) {
+            log.error("批量设置律师评价数失败,错误信息={}", e.getMessage(), e);
+            // 设置失败时,将所有律师的评价数设置为0
+            lawyers.forEach(lawyer -> lawyer.setReviewCount(0));
+        }
+    }
+
 
     @Override
     public R<IPage<LawyerUser>> getRecommendedLawyersBySession(String sessionId, Integer messageId) {
@@ -352,6 +404,8 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
         // 为每个律师设置关联的法律问题场景列表
         if (pageResult.getRecords() != null && !pageResult.getRecords().isEmpty()) {
             setLawyerScenarios(pageResult.getRecords());
+            // 设置律师评价数
+            setLawyerReviewCounts(pageResult.getRecords());
         }
 
         return R.data(pageResult);
@@ -691,5 +745,171 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
 
         return R.data(ListToPage.setPage(list, page, size));
     }
+
+    @Override
+    public R<Boolean> isRecommended(Integer lawyerId, Integer isRecommended) {
+        log.info("LawyerUserServiceImpl.isRecommended?lawyerId={},isRecommended={}", lawyerId, isRecommended);
+
+        // 参数校验
+        if (lawyerId == null) {
+            log.warn("设置律师推荐状态失败:律师ID为空");
+            return R.fail("律师ID不能为空");
+        }
+
+        if (isRecommended == null || (isRecommended != 0 && isRecommended != 1)) {
+            log.warn("设置律师推荐状态失败:推荐状态参数无效,isRecommended={}", isRecommended);
+            return R.fail("推荐状态参数无效,必须为0(取消推荐)或1(推荐)");
+        }
+
+        // 查询律师信息
+        LawyerUser lawyerUser = this.getById(lawyerId);
+        if (lawyerUser == null) {
+            log.warn("设置律师推荐状态失败:律师不存在,律师ID={}", lawyerId);
+            return R.fail("律师不存在");
+        }
+
+        // 更新推荐状态
+        lawyerUser.setIsRecommended(isRecommended);
+        boolean result = this.updateById(lawyerUser);
+        if (result) {
+            log.info("设置律师推荐状态成功:律师ID={},推荐状态={}", lawyerId, isRecommended);
+            return R.success("设置成功");
+        } else {
+            log.warn("设置律师推荐状态失败:更新数据库失败,律师ID={},推荐状态={}", lawyerId, isRecommended);
+            return R.fail("设置失败");
+        }
+    }
+
+    @Override
+    public void exportLawyerList(HttpServletResponse response,
+                                 String name,
+                                 String phone,
+                                 Integer firmId,
+                                 String startTime,
+                                 String endTime,
+                                 Integer pageNum,
+                                 Integer pageSize) throws Exception {
+        log.info("LawyerUserServiceImpl.exportLawyerList?name={},phone={},firmId={},startTime={},endTime={},pageNum={},pageSize={}",
+                name, phone, firmId, startTime, endTime, pageNum, pageSize);
+
+        // 如果pageNum为null或0,则导出全部数据(设置一个很大的pageSize)
+        int page = (pageNum == null || pageNum == 0) ? 1 : pageNum;
+        int size = (pageNum == null || pageNum == 0) ? Integer.MAX_VALUE : (pageSize == null ? 10 : pageSize);
+
+        // 调用查询接口获取数据
+        R<IPage<LawyerUserVo>> result = getLawyerList(name, phone, firmId, startTime, endTime, page, size);
+
+        if (result == null || !result.isSuccess()) {
+            log.warn("获取律师列表失败:{}", result != null ? result.getMsg() : "返回结果为空");
+            throw new RuntimeException(result != null ? result.getMsg() : "获取数据失败,请稍后重试");
+        }
+
+        IPage<LawyerUserVo> pageResult = result.getData();
+        if (pageResult == null || pageResult.getRecords() == null || pageResult.getRecords().isEmpty()) {
+            log.warn("律师列表导出:无数据可导出");
+            throw new IllegalArgumentException("暂无数据可导出");
+        }
+
+        List<LawyerUserVo> voList = pageResult.getRecords();
+        log.info("律师列表导出:查询到{}条数据,导出{}条数据", pageResult.getTotal(), voList.size());
+
+        // 转换为Excel VO
+        List<LawyerUserExcelVo> excelVoList = convertToExcelVo(voList);
+
+        // 使用EasyExcelUtil导出
+        EasyExcelUtil.exportExcel(response, excelVoList, LawyerUserExcelVo.class, "中台律师列表", "中台律师列表");
+    }
+
+    /**
+     * 将LawyerUserVo转换为LawyerUserExcelVo
+     *
+     * @param voList LawyerUserVo列表
+     * @return LawyerUserExcelVo列表
+     */
+    private List<LawyerUserExcelVo> convertToExcelVo(List<LawyerUserVo> voList) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+        return voList.stream().map(vo -> {
+            LawyerUserExcelVo excelVo = new LawyerUserExcelVo();
+            excelVo.setId(vo.getId());
+            excelVo.setName(vo.getName());
+            excelVo.setPhone(vo.getPhone());
+            excelVo.setFirmName(vo.getFirmName());
+//            excelVo.setLawyerCertificateNo(vo.getLawyerCertificateNo());
+//            excelVo.setPracticeYears(vo.getPracticeYears());
+//            excelVo.setServiceScore(vo.getServiceScore());
+//            excelVo.setServiceCount(vo.getServiceCount());
+            excelVo.setFirmId(vo.getFirmId());
+
+            // 转换执业开始日期
+//            if (vo.getPracticeStartDate() != null) {
+//                excelVo.setPracticeStartDate(dateFormat.format(vo.getPracticeStartDate()));
+//            }
+//
+//            // 转换用户状态
+//            if (vo.getStatus() != null) {
+//                excelVo.setStatusValue(vo.getStatus());
+//                excelVo.setStatus(vo.getStatus() == 1 ? "启用" : "禁用");
+//            }
+
+            // 转换资质认证状态
+//            if (vo.getCertificationStatus() != null) {
+//                excelVo.setCertificationStatusValue(vo.getCertificationStatus());
+//                switch (vo.getCertificationStatus()) {
+//                    case 0:
+//                        excelVo.setCertificationStatus("未认证");
+//                        break;
+//                    case 1:
+//                        excelVo.setCertificationStatus("认证中");
+//                        break;
+//                    case 2:
+//                        excelVo.setCertificationStatus("已认证");
+//                        break;
+//                    case 3:
+//                        excelVo.setCertificationStatus("认证失败");
+//                        break;
+//                    default:
+//                        excelVo.setCertificationStatus("未知");
+//                }
+//            }
+
+            // 转换是否推荐
+            if (vo.getIsRecommended() != null) {
+                excelVo.setIsRecommendedValue(vo.getIsRecommended());
+                excelVo.setIsRecommended(vo.getIsRecommended() == 1 ? "推荐" : "不推荐");
+            }
+
+            // 转换法律场景
+            if (vo.getScenarioNames() != null && !vo.getScenarioNames().isEmpty()) {
+                excelVo.setScenarioNames(vo.getScenarioNames());
+            } else {
+                excelVo.setScenarioNames("");
+            }
+
+            // 转换接单状态
+            if (vo.getOrderReceivingStatus() != null) {
+                excelVo.setOrderReceivingStatusValue(vo.getOrderReceivingStatus());
+                excelVo.setOrderReceivingStatus(vo.getOrderReceivingStatus() == 1 ? "接单中" : "不接单");
+            } else {
+                excelVo.setOrderReceivingStatus("未知");
+            }
+
+            // 设置收款账号
+            if (vo.getPaymentNum() != null && !vo.getPaymentNum().isEmpty()) {
+                excelVo.setPaymentNum(vo.getPaymentNum());
+            } else {
+                excelVo.setPaymentNum("");
+            }
+
+            // 转换创建时间
+//            if (vo.getCreatedTime() != null) {
+//                excelVo.setCreatedTimeValue(vo.getCreatedTime());
+//                excelVo.setCreatedTime(dateTimeFormat.format(vo.getCreatedTime()));
+//            }
+
+            return excelVo;
+        }).collect(Collectors.toList());
+    }
 }
 

+ 5 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserViolationServiceImpl.java

@@ -946,6 +946,8 @@ public class LawyerUserViolationServiceImpl extends ServiceImpl<LawyerUserViolat
      */
     private void processReportEvidenceImages(LawyerUserViolationVo vo, LawyerUserViolationDto dto) {
         if (Objects.isNull(vo.getReportEvidenceImg())) {
+            dto.setImage("");
+            dto.setImageList(new ArrayList<>());
             return;
         }
 
@@ -957,6 +959,9 @@ public class LawyerUserViolationServiceImpl extends ServiceImpl<LawyerUserViolat
         if (!imageList.isEmpty()) {
             dto.setImage(imageList.get(0));
             dto.setImageList(imageList);
+        } else {
+            dto.setImage("");
+            dto.setImageList(new ArrayList<>());
         }
     }
 

+ 54 - 3
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/OrderReviewServiceImpl.java

@@ -18,6 +18,7 @@ import shop.alien.entity.store.LifeLikeRecord;
 import shop.alien.entity.store.OrderReview;
 import shop.alien.entity.store.ReviewComment;
 import shop.alien.entity.store.dto.OrderReviewDto;
+import shop.alien.entity.store.vo.LawyerReviewStatisticsVo;
 import shop.alien.entity.store.vo.OrderReviewDetailVo;
 import shop.alien.entity.store.vo.OrderReviewVo;
 import shop.alien.entity.store.vo.PendingReviewVo;
@@ -210,9 +211,17 @@ public class OrderReviewServiceImpl extends ServiceImpl<OrderReviewMapper, Order
         // 处理评价图片JSON字符串转换为列表
         if (result.getRecords() != null) {
             for (OrderReviewVo vo : result.getRecords()) {
-                if (vo.getReviewImages() != null && !vo.getReviewImages().isEmpty()) {
-                    // 如果已经是列表,则不需要转换
-                    // 这里假设VO中的reviewImages已经是List<String>类型
+                // 处理评价图片:从JSON字符串解析为List
+                if (vo.getReviewImagesJson() != null && !vo.getReviewImagesJson().trim().isEmpty()) {
+                    try {
+                        List<String> images = JSON.parseArray(vo.getReviewImagesJson(), String.class);
+                        vo.setReviewImages(images != null ? images : new ArrayList<>());
+                    } catch (Exception e) {
+                        log.warn("解析评价图片失败:{}", e.getMessage());
+                        vo.setReviewImages(new ArrayList<>());
+                    }
+                } else {
+                    vo.setReviewImages(new ArrayList<>());
                 }
             }
         }
@@ -567,5 +576,47 @@ public class OrderReviewServiceImpl extends ServiceImpl<OrderReviewMapper, Order
 
         return R.data(result);
     }
+
+    @Override
+    public R<LawyerReviewStatisticsVo> getLawyerReviewStatistics(Integer lawyerUserId) {
+        log.info("OrderReviewServiceImpl.getLawyerReviewStatistics?lawyerUserId={}", lawyerUserId);
+
+        if (lawyerUserId == null) {
+            return R.fail("律师ID不能为空");
+        }
+
+        try {
+            LawyerReviewStatisticsVo statistics = new LawyerReviewStatisticsVo();
+
+            // 统计全部评价数量
+            Integer totalCount = orderReviewMapper.getTotalReviewCountByLawyerUserId(lawyerUserId);
+            statistics.setTotalCount(totalCount != null ? totalCount : 0);
+
+            // 统计好评数量
+            Integer goodCount = orderReviewMapper.getGoodReviewCountByLawyerUserId(lawyerUserId);
+            statistics.setGoodCount(goodCount != null ? goodCount : 0);
+
+            // 统计中评数量
+            Integer mediumCount = orderReviewMapper.getMediumReviewCountByLawyerUserId(lawyerUserId);
+            statistics.setMediumCount(mediumCount != null ? mediumCount : 0);
+
+            // 统计差评数量
+            Integer badCount = orderReviewMapper.getBadReviewCountByLawyerUserId(lawyerUserId);
+            statistics.setBadCount(badCount != null ? badCount : 0);
+
+            // 统计有图评价数量
+            Integer imageCount = orderReviewMapper.getImageReviewCountByLawyerUserId(lawyerUserId);
+            statistics.setImageCount(imageCount != null ? imageCount : 0);
+
+            log.info("获取律师评价统计数据成功,律师ID={}, 全部={}, 好评={}, 中评={}, 差评={}, 有图={}",
+                    lawyerUserId, statistics.getTotalCount(), statistics.getGoodCount(),
+                    statistics.getMediumCount(), statistics.getBadCount(), statistics.getImageCount());
+
+            return R.data(statistics);
+        } catch (Exception e) {
+            log.error("获取律师评价统计数据异常,律师ID={}, 错误信息={}", lawyerUserId, e.getMessage(), e);
+            return R.fail("获取统计数据失败");
+        }
+    }
 }
 

+ 113 - 177
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/ReviewCommentServiceImpl.java

@@ -12,7 +12,6 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.store.LifeLikeRecord;
 import shop.alien.entity.store.OrderReview;
 import shop.alien.entity.store.ReviewComment;
-import shop.alien.entity.store.dto.ReviewCommentDto;
 import shop.alien.entity.store.dto.ReviewCommentRequestDto;
 import shop.alien.entity.store.dto.ReviewReplyDto;
 import shop.alien.entity.store.vo.ReviewCommentVo;
@@ -23,6 +22,7 @@ import shop.alien.mapper.ReviewCommentMapper;
 
 import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 评价评论 服务实现类
@@ -48,49 +48,54 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
     }
 
     @Override
-    public R<ReviewComment> createComment(ReviewCommentDto commentDto) {
-        log.info("ReviewCommentServiceImpl.createComment?commentDto={}", commentDto);
-
+    public R<ReviewComment> createComment(ReviewComment comment) {
+        log.info("ReviewCommentServiceImpl.createComment?comment={}", comment);
         // 参数校验
-        if (commentDto == null) {
+        if (comment == null) {
             return R.fail("评论信息不能为空");
         }
-        if (commentDto.getReviewId() == null) {
+        if (comment.getReviewId() == null) {
             return R.fail("评价ID不能为空");
         }
-        if (commentDto.getCommentContent() == null || commentDto.getCommentContent().trim().isEmpty()) {
+        if (comment.getCommentContent() == null || comment.getCommentContent().trim().isEmpty()) {
             return R.fail("评论内容不能为空");
         }
-        Integer userId=commentDto.getUserId() ;
+        Integer userId = comment.getSendUserId();
         if (userId == null) {
             return R.fail("用户ID不能为空");
         }
 
         // 验证评价是否存在
-        OrderReview review = orderReviewService.getById(commentDto.getReviewId());
+        OrderReview review = orderReviewService.getById(comment.getReviewId());
         if (review == null || review.getDeleteFlag() == 1) {
             return R.fail("评价不存在或已删除");
         }
 
-        // 创建评论
-        ReviewComment comment = new ReviewComment();
-        comment.setReviewId(commentDto.getReviewId());
-        comment.setSendUserId(userId);
-        // 接收用户ID为评价的创建者
-        comment.setReceiveUserId(review.getUserId());
-        comment.setCommentContent(commentDto.getCommentContent());
-        comment.setLikeCount(0);
-        comment.setReplyCount(0);
-        comment.setHeadType(0); // 0:是首评
+        // 设置评论属性
+        // 接收用户ID为评价的创建者(如果未设置)
+        if (comment.getReceiveUserId() == null) {
+            comment.setReceiveUserId(review.getUserId());
+        }
+        // 设置默认值
+        if (comment.getLikeCount() == null) {
+            comment.setLikeCount(0);
+        }
+        if (comment.getReplyCount() == null) {
+            comment.setReplyCount(0);
+        }
+        if (comment.getHeadType() == null) {
+            comment.setHeadType(0); // 0:是首评
+        }
         comment.setCreatedUserId(userId);
         comment.setCreatedTime(new Date());
 
         boolean success = this.save(comment);
         if (success) {
-            // 更新评价的评论数
+            // 更新评价的评论数(包括首评论和子评论)
             review.setCommentCount((review.getCommentCount() == null ? 0 : review.getCommentCount()) + 1);
             orderReviewService.updateById(review);
-            
+            log.info("更新评价评论数成功,评价ID={}, 评论数={}", comment.getReviewId(), review.getCommentCount());
+
             log.info("创建评论成功,评论ID={}", comment.getId());
             return R.data(comment, "评论成功");
         } else {
@@ -108,7 +113,7 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
         }
 
         List<ReviewCommentVo> comments = reviewCommentMapper.getCommentListByReviewId(reviewId, currentUserId);
-        
+
         // 为每个首评加载回复列表
         if (comments != null && !comments.isEmpty()) {
             for (ReviewCommentVo comment : comments) {
@@ -116,65 +121,8 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
                 comment.setReplies(replies);
             }
         }
-        
-        return R.data(comments);
-    }
-
-    @Override
-    public R<Boolean> deleteComment(ReviewCommentRequestDto requestDto) {
-        log.info("ReviewCommentServiceImpl.deleteComment?requestDto={}", requestDto);
-
-        Integer commentId = requestDto.getCommentId();
-        Integer userId = requestDto.getUserId();
-
-        if (commentId == null) {
-            return R.fail("评论ID不能为空");
-        }
-        if (userId == null) {
-            return R.fail("用户ID不能为空");
-        }
-
-        // 查询评论
-        ReviewComment comment = this.getById(commentId);
-        if (comment == null) {
-            return R.fail("评论不存在");
-        }
-
-        // 验证是否为评论用户
-        if (!comment.getSendUserId().equals(userId)) {
-            return R.fail("只能删除自己的评论");
-        }
-
-        // 删除评论下的所有回复(逻辑删除)
-        LambdaUpdateWrapper<ReviewComment> replyUpdateWrapper = new LambdaUpdateWrapper<>();
-        replyUpdateWrapper.eq(ReviewComment::getHeadId, commentId)
-                .eq(ReviewComment::getHeadType, 1)
-                .eq(ReviewComment::getDeleteFlag, 0);
-        replyUpdateWrapper.set(ReviewComment::getDeleteFlag, 1);
-        replyUpdateWrapper.set(ReviewComment::getUpdatedUserId, userId);
-        replyUpdateWrapper.set(ReviewComment::getUpdatedTime, new Date());
-        this.update(replyUpdateWrapper);
 
-        // 删除评论(逻辑删除)
-        comment.setDeleteFlag(1);
-        comment.setUpdatedUserId(userId);
-        comment.setUpdatedTime(new Date());
-        boolean success = this.updateById(comment);
-
-        if (success) {
-            // 更新评价的评论数
-            OrderReview review = orderReviewService.getById(comment.getReviewId());
-            if (review != null) {
-                review.setCommentCount((review.getCommentCount() == null ? 0 : review.getCommentCount()) - 1);
-                orderReviewService.updateById(review);
-            }
-            
-            log.info("删除评论成功,评论ID={}", commentId);
-            return R.data(true, "删除成功");
-        } else {
-            log.error("删除评论失败,评论ID={}", commentId);
-            return R.fail("删除评论失败");
-        }
+        return R.data(comments);
     }
 
     @Override
@@ -256,17 +204,13 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
         if (!CollectionUtils.isEmpty(records)) {
             // 删除点赞记录(逻辑删除)
             for (LifeLikeRecord record : records) {
-                record.setDeleteFlag(1);
-                record.setUpdatedUserId(userId);
-                record.setUpdatedTime(new Date());
-                lifeLikeRecordMapper.updateById(record);
+                lifeLikeRecordMapper.deleteById(record.getId());
             }
 
-            // 更新评论点赞数
+            // 更新评论点赞数(移除 gt 条件,确保即使为 0 也能正确更新)
             LambdaUpdateWrapper<ReviewComment> updateWrapper = new LambdaUpdateWrapper<>();
             updateWrapper.eq(ReviewComment::getId, commentId);
-            updateWrapper.gt(ReviewComment::getLikeCount, 0);
-            updateWrapper.setSql("like_count = like_count - 1");
+            updateWrapper.setSql("like_count = GREATEST(0, like_count - 1)");
             int result = reviewCommentMapper.update(null, updateWrapper);
 
             if (result > 0) {
@@ -326,7 +270,15 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
             // 更新首评的回复数
             headComment.setReplyCount((headComment.getReplyCount() == null ? 0 : headComment.getReplyCount()) + 1);
             this.updateById(headComment);
-            
+
+            // 更新评价的评论数(包括子评论)
+            OrderReview review = orderReviewService.getById(reply.getReviewId());
+            if (review != null) {
+                review.setCommentCount((review.getCommentCount() == null ? 0 : review.getCommentCount()) + 1);
+                orderReviewService.updateById(review);
+                log.info("更新评价评论数成功,评价ID={}, 评论数={}", reply.getReviewId(), review.getCommentCount());
+            }
+
             log.info("创建回复成功,回复ID={}", reply.getId());
             return R.data(reply, "回复成功");
         } else {
@@ -373,19 +325,27 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
         }
 
         // 删除回复(逻辑删除)
-        reply.setDeleteFlag(1);
-        reply.setUpdatedUserId(userId);
-        reply.setUpdatedTime(new Date());
-        boolean success = this.updateById(reply);
+        boolean success = this.removeById(reply.getId());
 
         if (success) {
             // 更新首评的回复数
             ReviewComment headComment = this.getById(reply.getHeadId());
             if (headComment != null) {
                 headComment.setReplyCount((headComment.getReplyCount() == null ? 0 : headComment.getReplyCount()) - 1);
+                headComment.setReplyCount(Math.max(0, headComment.getReplyCount())); // 确保回复数不为负数
                 this.updateById(headComment);
             }
-            
+
+            // 更新评价的评论数(包括子评论)
+            OrderReview review = orderReviewService.getById(reply.getReviewId());
+            if (review != null) {
+                Integer currentCount = review.getCommentCount() == null ? 0 : review.getCommentCount();
+                review.setCommentCount(Math.max(0, currentCount - 1)); // 确保评论数不为负数
+                orderReviewService.updateById(review);
+                log.info("更新评价评论数成功,评价ID={}, 原评论数={}, 新评论数={}",
+                        reply.getReviewId(), currentCount, review.getCommentCount());
+            }
+
             log.info("删除回复成功,回复ID={}", replyId);
             return R.data(true, "删除成功");
         } else {
@@ -394,105 +354,81 @@ public class ReviewCommentServiceImpl extends ServiceImpl<ReviewCommentMapper, R
         }
     }
 
-    @Override
-    public R<Boolean> likeReply(Integer replyId, Integer userId) {
-        log.info("ReviewCommentServiceImpl.likeReply?replyId={}, userId={}", replyId, userId);
 
-        if (replyId == null) {
-            return R.fail("回复ID不能为空");
-        }
-        if (userId == null) {
-            return R.fail("用户ID不能为空");
+    @Override
+    public R<Boolean> deleteReviewComment(ReviewComment reviewComment) {
+        Integer id = reviewComment.getId();
+        Integer userId = reviewComment.getUserId();
+        log.info("ReviewCommentServiceImpl.deleteReviewComment?id={}, userId={}", id, userId);
+        if (id == null) {
+            return R.fail("评论ID不能为空");
         }
 
-        // 验证回复是否存在
-        ReviewComment reply = this.getById(replyId);
-        if (reply == null || reply.getDeleteFlag() == 1) {
-            return R.fail("回复不存在或已删除");
-        }
-        if (reply.getHeadType() != 1) {
-            return R.fail("该记录不是回复");
+        // 查询评论
+        ReviewComment comment = this.getById(id);
+        if (comment == null) {
+            return R.fail("评论不存在");
         }
 
-        // 检查是否已点赞
-        LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(LifeLikeRecord::getType, "8")
-                .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
-                .eq(LifeLikeRecord::getHuifuId, String.valueOf(replyId))
-                .eq(LifeLikeRecord::getDeleteFlag, 0);
-        List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
-
-        if (CollectionUtils.isEmpty(records)) {
-            // 插入点赞记录
-            LifeLikeRecord likeRecord = new LifeLikeRecord();
-            likeRecord.setDianzanId(String.valueOf(userId));
-            likeRecord.setHuifuId(String.valueOf(replyId));
-            likeRecord.setType("8");
-            likeRecord.setCreatedTime(new Date());
-            likeRecord.setCreatedUserId(userId);
-            lifeLikeRecordMapper.insert(likeRecord);
-
-            // 更新回复点赞数
-            LambdaUpdateWrapper<ReviewComment> updateWrapper = new LambdaUpdateWrapper<>();
-            updateWrapper.eq(ReviewComment::getId, replyId);
-            updateWrapper.setSql("like_count = like_count + 1");
-            int result = reviewCommentMapper.update(null, updateWrapper);
-
-            if (result > 0) {
-                log.info("点赞回复成功,回复ID={}", replyId);
-                return R.data(true, "点赞成功");
-            } else {
-                return R.fail("点赞失败");
+        // 当userId有值时,验证是否为评论用户(只能删除自己的评论)
+        if (userId != null) {
+            if (!comment.getSendUserId().equals(userId)) {
+                return R.fail("只能删除自己的评论");
             }
-        } else {
-            return R.data(true, "已点赞");
         }
-    }
-
-    @Override
-    public R<Boolean> cancelLikeReply(Integer replyId, Integer userId) {
-        log.info("ReviewCommentServiceImpl.cancelLikeReply?replyId={}, userId={}", replyId, userId);
 
-        if (replyId == null) {
-            return R.fail("回复ID不能为空");
-        }
-        if (userId == null) {
-            return R.fail("用户ID不能为空");
+        // 计算需要减少的评论数
+        int commentCountToReduce = 1; // 至少减少1(当前评论本身)
+
+        // 判断是否为首评论(headType == 0 表示是首评论)
+        if (comment.getHeadType() != null && comment.getHeadType() == 0) {
+            // 如果是首评论,需要先删除所有子评论
+            LambdaQueryWrapper<ReviewComment> childQueryWrapper = new LambdaQueryWrapper<>();
+            childQueryWrapper.eq(ReviewComment::getHeadId, id)
+                    .eq(ReviewComment::getHeadType, 1)
+                    .eq(ReviewComment::getDeleteFlag, 0);
+            List<ReviewComment> childComments = this.list(childQueryWrapper);
+
+            if (!CollectionUtils.isEmpty(childComments)) {
+                // 批量删除子评论
+                List<Integer> childIds = childComments.stream()
+                        .map(ReviewComment::getId)
+                        .collect(Collectors.toList());
+                boolean deleteChildrenResult = this.removeByIds(childIds);
+                if (!deleteChildrenResult) {
+                    log.warn("删除子评论失败,首评论ID={}, 子评论数量={}", id, childIds.size());
+                    return R.fail("删除子评论失败");
+                }
+                // 增加需要减少的评论数(包括所有子评论)
+                commentCountToReduce += childComments.size();
+                log.info("删除首评论下的子评论成功,首评论ID={}, 子评论数量={}", id, childIds.size());
+            }
         }
 
-        // 查询点赞记录
-        LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(LifeLikeRecord::getType, "8")
-                .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
-                .eq(LifeLikeRecord::getHuifuId, String.valueOf(replyId))
-                .eq(LifeLikeRecord::getDeleteFlag, 0);
-        List<LifeLikeRecord> records = lifeLikeRecordMapper.selectList(queryWrapper);
-
-        if (!CollectionUtils.isEmpty(records)) {
-            // 删除点赞记录(逻辑删除)
-            for (LifeLikeRecord record : records) {
-                record.setDeleteFlag(1);
-                record.setUpdatedUserId(userId);
-                record.setUpdatedTime(new Date());
-                lifeLikeRecordMapper.updateById(record);
+        // 删除评论本身(物理删除)
+        boolean result = this.removeById(id);
+        if (result) {
+            // 更新评价的评论数(包括首评论和子评论)
+            OrderReview review = orderReviewService.getById(comment.getReviewId());
+            if (review != null) {
+                Integer currentCount = review.getCommentCount() == null ? 0 : review.getCommentCount();
+                review.setCommentCount(Math.max(0, currentCount - commentCountToReduce)); // 确保评论数不为负数
+                orderReviewService.updateById(review);
+                log.info("更新评价评论数成功,评价ID={}, 原评论数={}, 减少数量={}, 新评论数={}",
+                        comment.getReviewId(), currentCount, commentCountToReduce, review.getCommentCount());
             }
 
-            // 更新回复点赞数
-            LambdaUpdateWrapper<ReviewComment> updateWrapper = new LambdaUpdateWrapper<>();
-            updateWrapper.eq(ReviewComment::getId, replyId);
-            updateWrapper.gt(ReviewComment::getLikeCount, 0);
-            updateWrapper.setSql("like_count = like_count - 1");
-            int result = reviewCommentMapper.update(null, updateWrapper);
-
-            if (result > 0) {
-                log.info("取消点赞回复成功,回复ID={}", replyId);
-                return R.data(true, "取消点赞成功");
+            if (userId != null) {
+                log.info("删除评论成功,评论ID={}, userId={}, 是否首评论={}, 减少评论数={}", id, userId,
+                        comment.getHeadType() != null && comment.getHeadType() == 0, commentCountToReduce);
             } else {
-                return R.fail("取消点赞失败");
+                log.info("管理员删除评论成功,评论ID={}, 是否首评论={}, 减少评论数={}", id,
+                        comment.getHeadType() != null && comment.getHeadType() == 0, commentCountToReduce);
             }
-        } else {
-            return R.data(true, "未点赞");
+            return R.success("删除成功");
         }
+        log.warn("删除评论失败,评论ID={}, userId={}", id, userId);
+        return R.fail("删除失败");
     }
 }