Selaa lähdekoodia

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	alien-lawyer/src/main/java/shop/alien/lawyer/service/LawFirmService.java
#	alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawFirmServiceImpl.java
Jxinyao 4 viikkoa sitten
vanhempi
commit
56b9ea704b
38 muutettua tiedostoa jossa 1716 lisäystä ja 145 poistoa
  1. 3 2
      alien-entity/src/main/java/shop/alien/entity/store/LawFirm.java
  2. 3 1
      alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationOrder.java
  3. 2 10
      alien-entity/src/main/java/shop/alien/entity/store/LawyerLegalProblemScenario.java
  4. 12 0
      alien-entity/src/main/java/shop/alien/entity/store/LifeSys.java
  5. 117 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreAliPayRefundLog.java
  6. 3 1
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationOrderDto.java
  7. 7 1
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerUserDto.java
  8. 1 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/SystemRegisterDto.java
  9. 132 0
      alien-entity/src/main/java/shop/alien/entity/store/excelVo/LawFirmExcelVo.java
  10. 10 3
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationOrderVO.java
  11. 18 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerUserVo.java
  12. 9 4
      alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationOrderMapper.java
  13. 54 0
      alien-entity/src/main/java/shop/alien/mapper/LawyerUserMapper.java
  14. 17 0
      alien-entity/src/main/java/shop/alien/mapper/StoreAliPayRefundLogMapper.java
  15. 84 1
      alien-entity/src/main/resources/mapper/LawyerUserMapper.xml
  16. 63 11
      alien-gateway/src/main/java/shop/alien/gateway/controller/LawyerUserLogInController.java
  17. 1 0
      alien-gateway/src/main/java/shop/alien/gateway/service/LawyerUserService.java
  18. 17 0
      alien-gateway/src/main/java/shop/alien/gateway/service/impl/LawyerUserServiceImpl.java
  19. 5 2
      alien-gateway/src/main/java/shop/alien/gateway/service/impl/SystemServiceImpl.java
  20. 24 6
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawFirmController.java
  21. 39 2
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerUserController.java
  22. 20 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/LawFirmService.java
  23. 17 1
      alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerUserService.java
  24. 708 5
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawFirmServiceImpl.java
  25. 54 21
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerClientConsultationOrderServiceImpl.java
  26. 3 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationOrderServiceImpl.java
  27. 56 10
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerLegalProblemScenarioServiceImpl.java
  28. 78 22
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserServiceImpl.java
  29. 18 2
      alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java
  30. 3 7
      alien-store/src/main/java/shop/alien/store/controller/LawyerAiInteractionLogController.java
  31. 15 12
      alien-store/src/main/java/shop/alien/store/controller/SystemController.java
  32. 1 1
      alien-store/src/main/java/shop/alien/store/service/LawyerAiInteractionLogService.java
  33. 17 0
      alien-store/src/main/java/shop/alien/store/service/StoreAliPayRefundLogService.java
  34. 6 6
      alien-store/src/main/java/shop/alien/store/service/impl/LawyerAiInteractionLogServiceImpl.java
  35. 7 4
      alien-store/src/main/java/shop/alien/store/service/impl/LawyerConsultationOrderServiceImpl.java
  36. 17 1
      alien-store/src/main/java/shop/alien/store/service/impl/LawyerUserServiceImpl.java
  37. 21 0
      alien-store/src/main/java/shop/alien/store/service/impl/StoreAliPayRefundLogServiceImpl.java
  38. 54 9
      alien-store/src/main/java/shop/alien/store/util/ali/AliApi.java

+ 3 - 2
alien-entity/src/main/java/shop/alien/entity/store/LawFirm.java

@@ -9,6 +9,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -190,8 +191,8 @@ public class LawFirm extends Model<LawFirm> implements Serializable {
     @TableField("payment_account")
     private String paymentAccount;
 
-    @ApiModelProperty(value = "律师事务所收款账号")
+    @ApiModelProperty(value = "平台佣金比例(百分比)")
     @TableField("platform_commission_ratio")
-    private Float platformCommissionRatio;
+    private BigDecimal platformCommissionRatio;
 }
 

+ 3 - 1
alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationOrder.java

@@ -131,6 +131,8 @@ public class LawyerConsultationOrder extends Model<LawyerConsultationOrder> {
     @TableField("place_id")
     private  Integer placeId;
 
-
+    @ApiModelProperty(value = "律师收益(订单金额-平台佣金)")
+    @TableField("lawyer_earnings")
+    private  Integer lawyerEarnings;
 }
 

+ 2 - 10
alien-entity/src/main/java/shop/alien/entity/store/LawyerLegalProblemScenario.java

@@ -27,10 +27,6 @@ public class LawyerLegalProblemScenario extends Model<LawyerLegalProblemScenario
     @TableId(value = "id", type = IdType.AUTO)
     private Integer id;
 
-    @ApiModelProperty(value = "编号")
-    @TableField("code")
-    private String code;
-
     @ApiModelProperty(value = "名称")
     @TableField("name")
     private String name;
@@ -43,13 +39,9 @@ public class LawyerLegalProblemScenario extends Model<LawyerLegalProblemScenario
     @TableField("parent_id")
     private Integer parentId;
 
-    @ApiModelProperty(value = "父类编号")
-    @TableField("parent_code")
-    private String parentCode;
-
     @ApiModelProperty(value = "父类名称")
-    @TableField("parentName")
-    private String parent_name;
+    @TableField("parent_name")
+    private String parentName;
 
     @ApiModelProperty(value = "排序字段, 数值越小越靠前")
     @TableField("sort_order")

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

@@ -51,4 +51,16 @@ public class LifeSys {
     @ApiModelProperty(value = "修改人ID")
     @TableField("updated_user_id")
     private Integer updatedUserId;
+
+    @ApiModelProperty(value = "禁用 0")
+    @TableField("disabled")
+    private Integer disabled;
+
+    @ApiModelProperty(value = "启用 1")
+    @TableField("enabled")
+    private Integer enabled;
+
+    @ApiModelProperty(value = "备注")
+    @TableField("remark")
+    private String remark;
 }

+ 117 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreAliPayRefundLog.java

@@ -0,0 +1,117 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 支付宝退款记录表
+ * </p>
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@JsonInclude
+@ApiModel(value = "StoreAliPayRefundLog对象", description = "支付宝退款记录表")
+@TableName("store_ali_pay_refund_log")
+public class StoreAliPayRefundLog extends Model<StoreAliPayRefundLog> {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "响应状态码:10000表示接口调用成功")
+    @TableField("response_code")
+    private String responseCode;
+
+    @ApiModelProperty(value = "响应状态描述")
+    @TableField("response_msg")
+    private String responseMsg;
+
+    @ApiModelProperty(value = "买家支付宝账号(邮箱形式,中间字符脱敏处理)")
+    @TableField("buyer_logon_id")
+    private String buyerLogonId;
+
+    @ApiModelProperty(value = "资金变动标识:Y表示用户账户发生实际资金变动,N表示用户账户未发生实际资金变动")
+    @TableField("fund_change")
+    private String fundChange;
+
+    @ApiModelProperty(value = "退款受理时间:支付宝系统处理该退款请求的时间")
+    @TableField("gmt_refund_pay")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date gmtRefundPay;
+
+    @ApiModelProperty(value = "商户订单号:商户系统生成的原交易订单唯一标识")
+    @TableField("out_trade_no")
+    private String outTradeNo;
+
+    @ApiModelProperty(value = "退款渠道明细列表:记录本次退款涉及的资金渠道及对应金额(JSON格式)")
+    @TableField("refund_detail_item_list")
+    private String refundDetailItemList;
+
+    @ApiModelProperty(value = "申请退款金额:商户发起的退款请求金额(单位:元)")
+    @TableField("refund_fee")
+    private String refundFee;
+
+    @ApiModelProperty(value = "实际退回金额:最终成功退回给买家的金额(单位:元)")
+    @TableField("send_back_fee")
+    private String sendBackFee;
+
+    @ApiModelProperty(value = "支付宝交易号:支付宝系统生成的原交易唯一标识")
+    @TableField("trade_no")
+    private String tradeNo;
+
+    @ApiModelProperty(value = "买家开放ID:支付宝为买家分配的唯一标识")
+    @TableField("buyer_open_id")
+    private String buyerOpenId;
+
+    @ApiModelProperty(value = "支付宝证书序列号:用于验证响应数据来源的真实性")
+    @TableField("alipay_cert_sn")
+    private String alipayCertSn;
+
+    @ApiModelProperty(value = "响应签名:支付宝对响应数据的加密签名")
+    @TableField("sign")
+    private String sign;
+
+    @ApiModelProperty(value = "退款原因:商户发起的退款原因")
+    @TableField("refund_reason")
+    private String refundReason;
+
+    @ApiModelProperty(value = "部分退款编号:标识一次退款请求,部分退款时必传")
+    @TableField("out_request_no")
+    private String outRequestNo;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}
+

+ 3 - 1
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationOrderDto.java

@@ -109,6 +109,8 @@ public class LawyerConsultationOrderDto extends Model<LawyerConsultationOrderDto
     @TableField("place_id")
     private  Integer placeId;
 
-
+    @ApiModelProperty(value = "律师收益(订单金额-平台佣金)")
+    @TableField("lawyer_earnings")
+    private  Integer lawyerEarnings;
 }
 

+ 7 - 1
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerUserDto.java

@@ -37,6 +37,12 @@ public class LawyerUserDto implements Serializable {
     @TableField("phone")
     private String phone;
 
+    @ApiModelProperty(value = "密码")
+    private String passWord;
+
+    @ApiModelProperty(value = "是否密码登录")
+    private Boolean isPassword;
+
     @ApiModelProperty(value = "姓名")
     @TableField("name")
     private String name;
@@ -130,7 +136,7 @@ public class LawyerUserDto implements Serializable {
     @ApiModelProperty(value = "登录Token")
     private String token;
 
-    @ApiModelProperty(value = "登录Token")
+    @ApiModelProperty(value = "验证码")
     private String msgCode;
 }
 

+ 1 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/SystemRegisterDto.java

@@ -29,3 +29,4 @@ public class SystemRegisterDto {
 
 }
 
+

+ 132 - 0
alien-entity/src/main/java/shop/alien/entity/store/excelVo/LawFirmExcelVo.java

@@ -0,0 +1,132 @@
+package shop.alien.entity.store.excelVo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.excelVo.util.ExcelHeader;
+
+/**
+ * 律所表Excel导入导出对象
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "LawFirmExcelVo对象", description = "律所表Excel导入导出对象")
+public class LawFirmExcelVo {
+
+    @ExcelHeader("序号")
+    @ApiModelProperty(value = "序号")
+    private Integer serialNumber;
+
+    @ExcelHeader("律所名称")
+    @ApiModelProperty(value = "律所名称")
+    private String firmName;
+
+//    @ExcelHeader("统一社会信用代码")
+    @ApiModelProperty(value = "统一社会信用代码")
+    private String creditCode;
+
+//    @ExcelHeader("律所简称")
+    @ApiModelProperty(value = "律所简称")
+    private String shortName;
+
+//    @ExcelHeader("律所英文名称")
+    @ApiModelProperty(value = "律所英文名称")
+    private String englishName;
+
+//    @ExcelHeader("成立日期")
+    @ApiModelProperty(value = "成立日期")
+    private String establishmentDate;
+
+//    @ExcelHeader("律所类型")
+    @ApiModelProperty(value = "律所类型, 1:合伙制, 2:个人制, 3:国资制")
+    private String firmType;
+
+//    @ExcelHeader("律所规模")
+    @ApiModelProperty(value = "律所规模, 1:小型(1-10人), 2:中型(11-50人), 3:大型(51-200人), 4:超大型(200人以上)")
+    private String firmScale;
+
+//    @ExcelHeader("所属省份")
+    @ApiModelProperty(value = "所属省份")
+    private String province;
+
+//    @ExcelHeader("所属城市")
+    @ApiModelProperty(value = "所属城市")
+    private String city;
+
+//    @ExcelHeader("所属区县")
+    @ApiModelProperty(value = "所属区县")
+    private String district;
+
+    @ExcelHeader("详细地址")
+    @ApiModelProperty(value = "详细地址")
+    private String address;
+
+//    @ExcelHeader("联系电话")
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+
+//    @ExcelHeader("传真")
+    @ApiModelProperty(value = "传真")
+    private String fax;
+
+//    @ExcelHeader("邮箱")
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+//    @ExcelHeader("官网地址")
+    @ApiModelProperty(value = "官网地址")
+    private String website;
+
+//    @ExcelHeader("律所简介")
+    @ApiModelProperty(value = "律所简介")
+    private String introduction;
+
+//    @ExcelHeader("执业许可证号")
+    @ApiModelProperty(value = "执业许可证号")
+    private String practiceLicenseNo;
+
+    @ExcelHeader("负责人姓名")
+    @ApiModelProperty(value = "负责人姓名")
+    private String directorName;
+
+//    @ExcelHeader("负责人电话")
+    @ApiModelProperty(value = "负责人电话")
+    private String directorPhone;
+
+//    @ExcelHeader("负责人邮箱")
+    @ApiModelProperty(value = "负责人邮箱")
+    private String directorEmail;
+
+//    @ExcelHeader("律师总数")
+    @ApiModelProperty(value = "律师总数")
+    private Integer lawyerCount;
+
+//    @ExcelHeader("合伙人数量")
+    @ApiModelProperty(value = "合伙人数量")
+    private Integer partnerCount;
+
+    @ExcelHeader("律所状态")
+    @ApiModelProperty(value = "律所状态, 0:禁用, 1:启用")
+    private String status;
+
+//    @ExcelHeader("认证状态")
+    @ApiModelProperty(value = "认证状态, 0:未认证, 1:认证中, 2:已认证, 3:认证失败")
+    private String certificationStatus;
+
+    @ExcelHeader("律师事务所收款账号")
+    @ApiModelProperty(value = "律师事务所收款账号(多个账号用逗号分隔)")
+    private String paymentAccount;
+
+//    @ExcelHeader("平台佣金比例")
+    @ApiModelProperty(value = "平台佣金比例(百分比)")
+    private String platformCommissionRatio;
+
+//    @ExcelHeader("备注")
+    @ApiModelProperty(value = "备注")
+    private String remark;
+}
+

+ 10 - 3
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerConsultationOrderVO.java

@@ -9,6 +9,7 @@ import lombok.Data;
 import shop.alien.entity.store.LawyerLegalProblemScenario;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
 
@@ -148,10 +149,10 @@ public class LawyerConsultationOrderVO implements Serializable {
     @ApiModelProperty(value = "领域信息")
     private String expertiseAreaInfo;
 
-    @ApiModelProperty(value = "客户端用户ID")
+    @ApiModelProperty(value = "客户端用户姓名")
     private String clientUserName;
 
-    @ApiModelProperty(value = "客户端用户ID")
+    @ApiModelProperty(value = "客户端用户电话")
     private String clientUserPhone;
 
     @ApiModelProperty(value = "支付宝订单编号")
@@ -163,6 +164,12 @@ public class LawyerConsultationOrderVO implements Serializable {
     private String orderStr;
 
     @ApiModelProperty(value = "佣金比例")
-    private String commission_rate;
+    private String commissionRate;
+
+    @ApiModelProperty(value = "佣金比例(前端使用)")
+    private String commissionRateStr;
+
+    @ApiModelProperty(value = "律师收益(订单金额-平台佣金)")
+    private  Integer lawyerEarnings;
 }
 

+ 18 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LawyerUserVo.java

@@ -300,5 +300,23 @@ public class LawyerUserVo implements Serializable {
 
     @ApiModelProperty(value = "登录Token")
     private String token;
+
+    @ApiModelProperty(value = "一级法律场景id")
+    private String firstLevelScenarioId;
+
+    @ApiModelProperty(value = "一级法律场景")
+    private String firstLevelScenario;
+
+    @ApiModelProperty(value = "律师擅长法律场景id")
+    private String problemScenarioId;
+
+    @ApiModelProperty(value = "律师擅长法律场景")
+    private String scenarioNames;
+
+    @ApiModelProperty(value = "专业领域")
+    private String areaInfo;
+
+
+
 }
 

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

@@ -94,7 +94,8 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             " `updated_user_id`, " +
             "`alipay_no`," +
             "`order_str`," +
-            "place_id" +
+            "place_id," +
+            "lawyer_earnings" +
             ")"+
             "VALUES" +
             " (" +
@@ -122,7 +123,8 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             " #{updatedUserId}," +
             " #{alipayNo}," +
             " #{orderStr}," +
-            "#{placeId}" +
+            "#{placeId}," +
+            "#{lawyerEarnings}" +
             ")")
             int insertOrder(LawyerConsultationOrderDto order);
 
@@ -213,12 +215,15 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             "        lu.head_img,\n" +
             "        lu.nick_name,\n" +
             "        lu.personal_introduction,\n" +
-            "        lu.commission_rate,\n" +
+            "        lf.platform_commission_ratio as commission_rate,\n" +
+            "        CONCAT(TRIM(TRAILING '.' FROM TRIM(TRAILING '0' FROM CAST(lf.platform_commission_ratio AS CHAR))), '%') AS commissionRateStr, \n" +
             "        lea.expertise_area_info,\n" +
             "        lur.user_name client_user_name,\n" +
-            "        lur.user_phone client_user_phone\n" +
+            "        lur.user_phone client_user_phone,\n" +
+            "        lco.order_amount - lco.consultation_fee as lawyerEarnings\n" +
             "        FROM lawyer_consultation_order lco\n" +
             "        LEFT JOIN lawyer_user lu ON lco.lawyer_user_id = lu.id AND lu.delete_flag = 0\n" +
+            "        LEFT JOIN law_firm lf on lf.id = lu.firm_id\n" +
             "        left join lawyer_expertise_area lea on lea.id = lu.lawyer_expertise_area_id and lea.delete_flag = 0 " +
             "        left join life_user lur on lur.id = lco.client_user_id " +
             " ${ew.customSqlSegment}")

+ 54 - 0
alien-entity/src/main/java/shop/alien/mapper/LawyerUserMapper.java

@@ -1,9 +1,15 @@
 package shop.alien.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 import shop.alien.entity.store.LawyerUser;
+import shop.alien.entity.store.vo.LawyerUserVo;
+
+import java.util.List;
 
 /**
  * <p>
@@ -85,5 +91,53 @@ public interface LawyerUserMapper extends BaseMapper<LawyerUser> {
         "</script>")
 Integer updateLawyerUser(LawyerUser user);
 
+
+
+   @Select("<script>" +
+           "SELECT " +
+           "user.id, " +
+           "user.phone, " +
+           "user.`name`, " +
+           "user.firm_id, " +
+           "user.head_img, " +
+           "user.personal_introduction, " +
+           "user.order_receiving_status, " +
+           "user.practice_start_date, " +
+           "user.address , " +
+           "firm.firm_name  AS firmName, " +
+           "firm.payment_account AS paymentNum, " +
+           "GROUP_CONCAT(area.problem_scenario_id SEPARATOR ',') AS problemScenarioId, " +
+           "GROUP_CONCAT(a.name SEPARATOR ',') AS scenarioNames, " +
+           "(SELECT GROUP_CONCAT(`id` SEPARATOR ',') FROM lawyer_legal_problem_scenario WHERE level = 1) " +
+           "AS firstLevelScenarioId, " +
+           "(SELECT GROUP_CONCAT(`name` SEPARATOR ',') FROM lawyer_legal_problem_scenario WHERE level = 1) " +
+           "AS firstLevelScenario, " +
+           "b.expertise_area_info AS areaInfo " +
+           "FROM " +
+           "lawyer_user user " +
+           "LEFT JOIN law_firm firm ON 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_expertise_area b ON b.id = user.specialty_fields " +
+           "<where>" +
+           "<if test='lawyerId != null'>user.id = #{lawyerId} AND </if>" +
+           "firm.delete_flag = 0 AND " +
+           "user.delete_flag = 0 AND " +
+           "area.delete_flag = 0 AND " +
+           "a.delete_flag = 0 AND " +
+           "b.delete_flag = 0" +
+           "</where>" +
+           "GROUP BY " +
+           "user.id, user.phone, user.`name`, user.firm_id, user.head_img, " +
+           "user.personal_introduction, user.order_receiving_status, user.practice_start_date, " +
+           "firm.firm_name, firm.payment_account, b.expertise_area_info " +
+           "LIMIT 1 " +
+           "</script>")
+   LawyerUserVo selectInfo(@Param("lawyerId") Integer lawyerId);
+
+   List<LawyerUserVo> selectLawyerUserList(@Param("user") LawyerUserVo user);
+   
+   Long selectLawyerUserListCount(@Param("user") LawyerUserVo user);
+
 }
 

+ 17 - 0
alien-entity/src/main/java/shop/alien/mapper/StoreAliPayRefundLogMapper.java

@@ -0,0 +1,17 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.store.StoreAliPayRefundLog;
+
+/**
+ * <p>
+ * 支付宝退款记录表 Mapper 接口
+ * </p>
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface StoreAliPayRefundLogMapper extends BaseMapper<StoreAliPayRefundLog> {
+
+}
+

+ 84 - 1
alien-entity/src/main/resources/mapper/LawyerUserMapper.xml

@@ -28,7 +28,7 @@
         <result column="alipay_account" property="alipayAccount" />
         <result column="lawyer_certificate_no" property="lawyerCertificateNo" />
         <result column="law_firm" property="lawFirm" />
-        <result column="law_firm_id" property="lawFirmId" />
+<!--        <result column="law_firm_id" property="lawFirmId" />-->
         <result column="practice_years" property="practiceYears" />
         <result column="practice_start_date" property="practiceStartDate" />
         <result column="specialty_fields" property="specialtyFields" />
@@ -77,5 +77,88 @@
         is_online, last_online_time, is_recommended, recommend_sort
     </sql>
 
+    <!-- 律师列表查询结果映射 -->
+    <resultMap id="LawyerUserVoResultMap" type="shop.alien.entity.store.vo.LawyerUserVo">
+        <id column="id" property="id" />
+        <result column="phone" property="phone" />
+        <result column="name" property="name" />
+        <result column="firm_id" property="firmId" />
+        <result column="head_img" property="headImg" />
+        <result column="personal_introduction" property="personalIntroduction" />
+        <result column="order_receiving_status" property="orderReceivingStatus" />
+        <result column="practice_start_date" property="practiceStartDate" />
+        <result column="address" property="address" />
+        <result column="status" property="status" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="firmName" property="firmName" />
+        <result column="paymentNum" property="paymentNum" />
+        <result column="scenarioNames" property="scenarioNames" />
+        <result column="firstLevelScenario" property="firstLevelScenario" />
+        <result column="areaInfo" property="areaInfo" />
+    </resultMap>
+
+    <!-- 查询律师列表(分页) -->
+    <select id="selectLawyerUserList" resultMap="LawyerUserVoResultMap">
+        SELECT
+        user.id,
+        user.phone,
+        user.`name`,
+        user.firm_id,
+        user.head_img,
+        user.personal_introduction,
+        user.order_receiving_status,
+        user.practice_start_date,
+        user.address,
+        user.status,
+        user.delete_flag,
+        user.created_time,
+        firm.firm_name AS firmName,
+        firm.payment_account AS paymentNum,
+        GROUP_CONCAT(a.name SEPARATOR ',') AS scenarioNames,
+        (SELECT GROUP_CONCAT(`name` SEPARATOR ',') FROM lawyer_legal_problem_scenario WHERE level = 1) AS firstLevelScenario,
+        b.expertise_area_info AS areaInfo
+        FROM
+        lawyer_user user
+        LEFT JOIN law_firm firm ON 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_expertise_area b ON b.id = user.specialty_fields
+        WHERE user.delete_flag = 0
+        <if test="user != null">
+            <if test="user.id != null">AND user.id = #{user.id}</if>
+            <if test="user.name != null and user.name != ''">AND user.name LIKE CONCAT('%', #{user.name}, '%')</if>
+            <if test="user.phone != null and user.phone != ''">AND user.phone LIKE CONCAT('%', #{user.phone}, '%')</if>
+            <if test="user.status != null">AND user.status = #{user.status}</if>
+            <if test="user.firmId != null">AND user.firm_id = #{user.firmId}</if>
+            <if test="user.firmName != null and user.firmName != ''">AND firm.firm_name LIKE CONCAT('%', #{user.firmName}, '%')</if>
+        </if>
+        GROUP BY
+        user.id, user.phone, user.`name`, user.firm_id, user.head_img,
+        user.personal_introduction, user.order_receiving_status, user.practice_start_date,
+        user.address, user.status, user.delete_flag, user.created_time,
+        firm.firm_name, firm.payment_account, b.expertise_area_info
+        ORDER BY user.created_time DESC
+    </select>
+
+    <!-- 查询律师列表总数 -->
+    <select id="selectLawyerUserListCount" resultType="java.lang.Long">
+        SELECT COUNT(DISTINCT user.id)
+        FROM
+        lawyer_user user
+        LEFT JOIN law_firm firm ON firm.id = user.firm_id
+        WHERE user.delete_flag = 0
+        <if test="user != null">
+            <if test="user.id != null">AND user.id = #{user.id}</if>
+            <if test="user.name != null and user.name != ''">AND user.name LIKE CONCAT('%', #{user.name}, '%')</if>
+            <if test="user.phone != null and user.phone != ''">AND user.phone LIKE CONCAT('%', #{user.phone}, '%')</if>
+            <if test="user.status != null">AND user.status = #{user.status}</if>
+            <if test="user.firmId != null">AND user.firm_id = #{user.firmId}</if>
+            <if test="user.firmName != null and user.firmName != ''">AND firm.firm_name LIKE CONCAT('%', #{user.firmName}, '%')</if>
+            <if test="user.createdTime_Start != null">AND user.created_time &gt;= #{user.createdTime_Start}</if>
+            <if test="user.createdTime_End != null">AND user.created_time &lt;= #{user.createdTime_End}</if>
+        </if>
+    </select>
+
 </mapper>
 

+ 63 - 11
alien-gateway/src/main/java/shop/alien/gateway/controller/LawyerUserLogInController.java

@@ -1,17 +1,20 @@
 package shop.alien.gateway.controller;
 
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiOperationSupport;
-import io.swagger.annotations.ApiSort;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.LawyerUser;
 import shop.alien.entity.store.dto.LawyerUserDto;
 import shop.alien.entity.store.vo.LawyerUserVo;
+import shop.alien.gateway.mapper.LawyerUserMapper;
 import shop.alien.gateway.service.LawyerUserService;
 
+import java.util.Objects;
+import java.util.Optional;
+
 /**
  * 门店用户 前端控制器
  *
@@ -28,20 +31,69 @@ import shop.alien.gateway.service.LawyerUserService;
 public class LawyerUserLogInController {
 
     private final LawyerUserService lawyerUserService;
+    private final LawyerUserMapper lawyerUserMapper;
 
-    @ApiOperation("律师用户登录")
+    @ApiOperation("律师用户注册")
     @ApiOperationSupport(order = 1)
-    @PostMapping("/login")
-    public R<LawyerUserVo> login(@RequestBody LawyerUserDto lawyerUserDto) {
-        log.info("StoreUserController.login?lawyerUserDto={}", lawyerUserDto);
+    @PostMapping("/register")
+    public R<LawyerUserVo> register(@RequestBody LawyerUserDto lawyerUserDto) {
+        log.info("LawyerUserLogInController.login?lawyerUserDto={}", lawyerUserDto);
         return lawyerUserService.logIn(lawyerUserDto);
     }
 
     @ApiOperation("律师用户验证码校验")
     @ApiOperationSupport(order = 2)
     @PostMapping("/checkMsgCode")
-    public R<LawyerUserVo> checkMsgCode(@RequestBody LawyerUserDto lawyerUserDto) {
-        log.info("StoreUserController.login?lawyerUserDto={}", lawyerUserDto);
-        return lawyerUserService.logIn(lawyerUserDto);
+    public R checkMsgCode(@RequestBody LawyerUserDto lawyerUserDto) {
+        log.info("LawyerUserLogInController.checkMsgCode?lawyerUserDto={}", lawyerUserDto);
+        return lawyerUserService.checkMsgCode(lawyerUserDto);
+    }
+
+    @ApiOperation("律师用户登录")
+    @ApiOperationSupport(order = 3)
+    @GetMapping("/login")
+    public R<LawyerUserVo> login(@RequestBody LawyerUserDto lawyerUserDto) {
+        log.info("LawyerUserLogInController.login?lawyerUserDto={}", lawyerUserDto);
+        LawyerUser lawyerUser = lawyerUserMapper.selectOne(new LambdaQueryWrapper<LawyerUser>()
+                .eq(LawyerUser::getPhone, lawyerUserDto.getPhone()));
+        if (null == lawyerUser) {
+            return R.fail("当前账号不存在,请先去注册账号!");
+        }
+        if (lawyerUser.getStatus() == 0) {
+            return R.fail("账号被禁用");
+        }
+        return Optional.ofNullable(lawyerUser).
+                map(user -> lawyerUserDto.getIsPassword() ? checkPassword(user, lawyerUserDto.getPassWord()) : lawyerUserService.createToKen(user)).
+                orElseGet(() -> R.fail("手机号不存在"));
+    }
+
+    @ApiOperation("律师用户修改密码")
+    @ApiOperationSupport(order = 4)
+    @PostMapping("/updatePassWord")
+    public R updatePassWord(@RequestBody LawyerUserDto lawyerUserDto) {
+        log.info("LawyerUserLogInController.updatePassWord?lawyerUserDto={}", lawyerUserDto);
+        try {
+            LawyerUser lawyerUser = lawyerUserMapper.selectOne(new LambdaQueryWrapper<LawyerUser>()
+                    .eq(LawyerUser::getPhone, lawyerUserDto.getPhone()));
+            if (null == lawyerUser) {
+                return R.fail("当前账号不存在,请先去注册账号!");
+            }
+            if (lawyerUser.getStatus() == 0) {
+                return R.fail("账号被禁用");
+            }
+            LawyerUser update = new LawyerUser();
+            update.setPassword(lawyerUserDto.getPassWord());
+            update.setId(lawyerUser.getId());
+            lawyerUserMapper.updateById(update);
+            return R.success("修改成功");
+        }catch (Exception e){
+            return R.fail("修改密码失败");
+        }
+    }
+
+    private R<LawyerUserVo> checkPassword(LawyerUser lawyerUser, String password) {
+        return Objects.equals(password, lawyerUser.getPassword())
+                ? lawyerUserService.createToKen(lawyerUser)
+                : R.fail("密码错误");
     }
 }

+ 1 - 0
alien-gateway/src/main/java/shop/alien/gateway/service/LawyerUserService.java

@@ -22,5 +22,6 @@ public interface LawyerUserService extends IService<LawyerUser> {
      */
     R<LawyerUserVo> createToKen(LawyerUser lawyerUser);
     R<LawyerUserVo> logIn(LawyerUserDto lawyerUserDto);
+    R checkMsgCode(LawyerUserDto lawyerUserDto);
 
 }

+ 17 - 0
alien-gateway/src/main/java/shop/alien/gateway/service/impl/LawyerUserServiceImpl.java

@@ -3,6 +3,7 @@ package shop.alien.gateway.service.impl;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
@@ -133,4 +134,20 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
         }
     }
 
+    @Override
+    public R checkMsgCode(LawyerUserDto lawyerUserDto) {
+        String string = baseRedisService.getString("lawyer_" + lawyerUserDto.getPhone());
+        if (StringUtils.isNotEmpty(string)) {
+            if (lawyerUserDto.getMsgCode().equals(string)) {
+                LawyerUser lawyerUser = lawyerUserMapper.selectOne(new LambdaQueryWrapper<LawyerUser>()
+                        .eq(LawyerUser::getPhone, lawyerUserDto.getPhone()));
+                return R.data(lawyerUser);
+            }else {
+                return R.fail("验证码错误");
+            }
+        }else {
+            return R.fail("验证码已过期");
+        }
+    }
+
 }

+ 5 - 2
alien-gateway/src/main/java/shop/alien/gateway/service/impl/SystemServiceImpl.java

@@ -115,17 +115,20 @@ public class SystemServiceImpl implements SystemService {
         // 创建新用户
         LifeSys lifeSys = new LifeSys();
         lifeSys.setUserName(userName);
+        lifeSys.setUserPassword(password);
+        lifeSys.setRoleId(roleId);
+        lifeSys.setDeleteFlag(0);
+
         // 密码使用MD5加密后存储
 //        lifeSys.setUserPassword(encryptToMD5(password));
 //        if (StringUtils.hasText(roleId)) {
 //            lifeSys.setRoleId(roleId);
 //        }
-        lifeSys.setDeleteFlag(0); // 未删除
 
         // 保存用户
         int result = lifeSysMapper.insert(lifeSys);
         if (result > 0) {
-            return R.data(lifeSys, "注册成功");
+            return R.data(lifeSys, "账号添加成功");
         }
         return R.fail("注册失败,请稍后重试");
     }

+ 24 - 6
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawFirmController.java

@@ -5,11 +5,13 @@ import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawFirm;
 import shop.alien.lawyer.service.LawFirmService;
 import shop.alien.util.myBaticsPlus.QueryBuilder;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -119,12 +121,28 @@ public class LawFirmController {
         return R.data(pageResult);
     }
 
-    @ApiOperation("律所注册")
-    @ApiOperationSupport(order = 7)
-    @PostMapping("/register")
-    public R<LawFirm> register(@RequestBody LawFirm lawFirm) {
-        log.info("LawFirmController.register?lawFirm={}", lawFirm);
-        return lawFirmService.register(lawFirm);
+//    @ApiOperation("律所注册")
+//    @ApiOperationSupport(order = 7)
+//    @PostMapping("/register")
+//    public R<LawFirm> register(@RequestBody LawFirm lawFirm) {
+//        log.info("LawFirmController.register?lawFirm={}", lawFirm);
+//        return lawFirmService.register(lawFirm);
+//    }
+
+    @ApiOperation("导出律所数据到Excel")
+    @ApiOperationSupport(order = 8)
+    @GetMapping("/export")
+    public R<String> exportLawFirm(HttpServletResponse response) {
+        log.info("LawFirmController.exportLawFirm");
+        return lawFirmService.exportLawFirm(response);
+    }
+
+    @ApiOperation("从Excel导入律所数据")
+    @ApiOperationSupport(order = 9)
+    @PostMapping("/import")
+    public R<String> importLawFirm(MultipartFile file) {
+        log.info("LawFirmController.importLawFirm fileName={}", file.getOriginalFilename());
+        return lawFirmService.importLawFirm(file);
     }
 
     @ApiOperation("获取律所详情")

+ 39 - 2
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerUserController.java

@@ -224,12 +224,38 @@ public class LawyerUserController {
             @ApiImplicitParam(name = "lawyerId", value = "律师ID", dataType = "Integer", paramType = "query", required = true)
     })
     @GetMapping("/getLawyerInfo")
-    public R<LawyerUser> getLawyerInfo(@RequestParam Integer lawyerId) {
+    public R<LawyerUserVo> getLawyerInfo(@RequestParam Integer lawyerId) {
         log.info("LawyerUserController.getLawyerInfo?lawyerId={}", lawyerId);
         return lawyerUserService.getLawyerInfo(lawyerId);
     }
 
-    @ApiOperation("更新律师用户信息")
+
+    @ApiOperation("中台律师列表")
+    @ApiOperationSupport(order = 17)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "页码(默认1)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "pageSize", value = "每页数量(默认10)", dataType = "int", paramType = "query"),
+            @ApiImplicitParam(name = "id", value = "律师ID", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "name", value = "姓名(支持模糊查询)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "phone", value = "手机号(支持模糊查询)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "status", value = "用户状态, 0:禁用, 1:启用", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "firmId", value = "律所ID", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "firmName", value = "律所名称(支持模糊查询)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "createdTime_Start", value = "创建时间开始(范围查询)", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "createdTime_End", value = "创建时间结束(范围查询)", dataType = "String", paramType = "query")
+    })
+    @GetMapping("/getLawyerList")
+    public R<IPage<LawyerUserVo>> getLawyerList(@ModelAttribute LawyerUserVo lawyerUserVo,
+                                                 @RequestParam int page,
+                                                 @RequestParam int pageSize) {
+        log.info("LawyerUserController.getLawyerList?lawyerUserVo={},page={},pageSize={}", lawyerUserVo, page, pageSize);
+        return lawyerUserService.getLawyerList(page, pageSize, lawyerUserVo);
+    }
+
+
+
+
+    @ApiOperation("编辑新律师用户")
     @ApiOperationSupport(order = 15)
     @ApiImplicitParams({
             @ApiImplicitParam(name = "lawyerId", value = "律师ID", dataType = "Integer", paramType = "query", required = true),
@@ -246,5 +272,16 @@ public class LawyerUserController {
         return lawyerUserService.updateLawyerUser(lawyerUserVo);
     }
 
+    @ApiOperation("通过手机号查询律师信息")
+    @ApiOperationSupport(order = 16)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true)
+    })
+    @GetMapping("/getLawyerInfoByPhone")
+    public R<LawyerUser> getLawyerInfoByPhone(@RequestParam String phone) {
+        log.info("LawyerUserController.getLawyerInfoByPhone?phone={}", phone);
+        return lawyerUserService.getLawyerInfoByPhone(phone);
+    }
+
 }
 

+ 20 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawFirmService.java

@@ -2,9 +2,13 @@ package shop.alien.lawyer.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawFirm;
 
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
 /**
  * 律所表 服务类
  *
@@ -57,6 +61,22 @@ public interface LawFirmService extends IService<LawFirm> {
     R<LawFirm> register(LawFirm lawFirm);
 
     /**
+     * 导出律所数据到Excel
+     *
+     * @param response HTTP响应
+     * @return R<String> 返回文件路径或成功信息
+     */
+    R<String> exportLawFirm(HttpServletResponse response);
+
+    /**
+     * 导入律所数据从Excel
+     *
+     * @param file Excel文件
+     * @return R<String> 返回导入结果信息
+     */
+    R<String> importLawFirm(MultipartFile file);
+
+    /**
      * 获取律所详情
      *
      * @param id 律所ID

+ 17 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerUserService.java

@@ -6,6 +6,7 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawyerUser;
 import shop.alien.entity.store.vo.LawyerUserVo;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -129,7 +130,7 @@ public interface LawyerUserService extends IService<LawyerUser> {
      * @param lawyerId 律师ID
      * @return R<LawyerUser> 律师信息
      */
-    R<LawyerUser> getLawyerInfo(Integer lawyerId);
+    R<LawyerUserVo> getLawyerInfo(Integer lawyerId);
 
     /**
      * 更新律师用户信息
@@ -138,5 +139,20 @@ public interface LawyerUserService extends IService<LawyerUser> {
      * @return R<LawyerUser> 更新后的律师信息
      */
     R<LawyerUser> updateLawyerUser(LawyerUserVo lawyerUserVo);
+
+    /**
+     * 通过手机号查询律师信息
+     *
+     * @param phone 手机号
+     * @return R<LawyerUser> 律师信息
+     */
+    R<LawyerUser> getLawyerInfoByPhone(String phone);
+
+    /**
+     * 获取中台律师列表
+     *
+     * @return R<LawyerUser> 律师信息
+     */
+    R<IPage<LawyerUserVo>> getLawyerList(int page, int pageSize, LawyerUserVo lawyerUserVo);
 }
 

+ 708 - 5
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawFirmServiceImpl.java

@@ -6,14 +6,34 @@ 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.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawFirm;
+import shop.alien.entity.store.excelVo.LawFirmExcelVo;
+import shop.alien.entity.store.excelVo.util.ExcelHeader;
 import shop.alien.lawyer.service.LawFirmService;
 import shop.alien.mapper.LawFirmMapper;
 
+import org.apache.poi.ss.usermodel.DateUtil;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
 /**
  * 律所表 服务实现类
  *
@@ -159,25 +179,708 @@ public class LawFirmServiceImpl extends ServiceImpl<LawFirmMapper, LawFirm> impl
     }
 
     @Override
+    public R<String> exportLawFirm(HttpServletResponse response) {
+        log.info("LawFirmServiceImpl.exportLawFirm");
+        try {
+            // 查询所有未删除的律所
+            LambdaQueryWrapper<LawFirm> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(LawFirm::getDeleteFlag, 0);
+            queryWrapper.orderByDesc(LawFirm::getCreatedTime);
+            List<LawFirm> lawFirmList = this.list(queryWrapper);
+
+            if (lawFirmList.isEmpty()) {
+                return R.fail("暂无数据可导出");
+            }
+
+            // 按律所名称分组
+            Map<String, List<LawFirm>> firmNameMap = lawFirmList.stream()
+                    .collect(Collectors.groupingBy(LawFirm::getFirmName));
+
+            // 转换为ExcelVo,相同律所名称的每个账号一行
+            List<LawFirmExcelVo> excelVoList = new ArrayList<>();
+            int serialNumber = 0;
+            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+            SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+            for (Map.Entry<String, List<LawFirm>> entry : firmNameMap.entrySet()) {
+                List<LawFirm> firms = entry.getValue();
+                // 合并所有账号
+                String allPaymentAccounts = firms.stream()
+                        .map(LawFirm::getPaymentAccount)
+                        .filter(Objects::nonNull)
+                        .filter(acc -> !acc.trim().isEmpty())
+                        .distinct()
+                        .collect(Collectors.joining(","));
+
+                // 为每个账号创建一行(如果账号为空,至少创建一行)
+                if (firms.isEmpty()) {
+                    continue;
+                }
+
+                // 如果账号为空或只有一个账号,创建一行
+                if (allPaymentAccounts.isEmpty() || !allPaymentAccounts.contains(",")) {
+                    LawFirm firstFirm = firms.get(0);
+                    LawFirmExcelVo excelVo = convertToExcelVo(firstFirm, ++serialNumber, dateFormat, dateTimeFormat);
+                    excelVo.setPaymentAccount(allPaymentAccounts);
+                    excelVoList.add(excelVo);
+                } else {
+                    // 多个账号,每个账号一行
+                    String[] accounts = allPaymentAccounts.split(",");
+                    for (int i = 0; i < accounts.length; i++) {
+                        LawFirm firstFirm = firms.get(0);
+                        LawFirmExcelVo excelVo = convertToExcelVo(firstFirm, ++serialNumber, dateFormat, dateTimeFormat);
+                        excelVo.setPaymentAccount(accounts[i].trim());
+                        excelVoList.add(excelVo);
+                    }
+                }
+            }
+
+            // 生成Excel
+            generateExcelWithMerge(response, excelVoList, firmNameMap);
+
+            return R.success("导出成功");
+        } catch (Exception e) {
+            log.error("导出律所数据失败", e);
+            return R.fail("导出失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<String> importLawFirm(MultipartFile file) {
+        log.info("LawFirmServiceImpl.importLawFirm fileName={}", file.getOriginalFilename());
+        try {
+            if (file == null || file.isEmpty()) {
+                return R.fail("文件不能为空");
+            }
+
+            String fileName = file.getOriginalFilename();
+            if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
+                return R.fail("文件格式不正确,请上传Excel文件");
+            }
+
+            List<LawFirmExcelVo> excelVoList = new ArrayList<>();
+            List<String> errorMessages = new ArrayList<>();
+
+            // 使用POI读取Excel
+            try (InputStream inputStream = file.getInputStream();
+                 Workbook workbook = new XSSFWorkbook(inputStream)) {
+                Sheet sheet = workbook.getSheetAt(0);
+
+                // 获取表头
+                Row headerRow = sheet.getRow(0);
+                if (headerRow == null) {
+                    return R.fail("Excel文件格式不正确,缺少表头");
+                }
+
+                // 构建字段映射(表头名称 -> 列索引)
+                Map<String, Integer> headerMap = new HashMap<>();
+                Field[] fields = LawFirmExcelVo.class.getDeclaredFields();
+                for (int i = 0; i < headerRow.getLastCellNum(); i++) {
+                    Cell cell = headerRow.getCell(i);
+                    if (cell != null) {
+                        String headerName = cell.getStringCellValue().trim();
+                        headerMap.put(headerName, i);
+                    }
+                }
+
+                // 读取数据行
+                for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+                    Row row = sheet.getRow(rowIndex);
+                    if (row == null) {
+                        continue;
+                    }
+
+                    // 检查是否为空行
+                    boolean isEmptyRow = true;
+                    for (int i = 0; i < row.getLastCellNum(); i++) {
+                        Cell cell = row.getCell(i);
+                        if (cell != null && cell.getCellType() != CellType.BLANK) {
+                            isEmptyRow = false;
+                            break;
+                        }
+                    }
+                    if (isEmptyRow) {
+                        continue;
+                    }
+
+                    LawFirmExcelVo excelVo = new LawFirmExcelVo();
+
+                    // 读取每个字段
+                    for (Field field : fields) {
+                        if (!field.isAnnotationPresent(ExcelHeader.class)) {
+                            continue;
+                        }
+                        ExcelHeader excelHeader = field.getAnnotation(ExcelHeader.class);
+                        String headerName = excelHeader.value();
+                        Integer colIndex = headerMap.get(headerName);
+                        if (colIndex == null) {
+                            continue;
+                        }
+
+                        Cell cell = row.getCell(colIndex);
+                        if (cell == null) {
+                            continue;
+                        }
+
+                        field.setAccessible(true);
+                        try {
+                            String cellValue = getCellValueAsString(cell);
+                            if (cellValue != null && !cellValue.trim().isEmpty()) {
+                                // 根据字段类型设置值
+                                Class<?> fieldType = field.getType();
+                                if (fieldType == String.class) {
+                                    field.set(excelVo, cellValue.trim());
+                                } else if (fieldType == Integer.class) {
+                                    try {
+                                        field.set(excelVo, Integer.parseInt(cellValue.trim()));
+                                    } catch (NumberFormatException e) {
+                                        // 忽略
+                                    }
+                                }
+                            }
+                        } catch (Exception e) {
+                            log.warn("读取字段{}失败:{}", headerName, e.getMessage());
+                        }
+                    }
+
+                    // 校验数据
+                    String errorMsg = validateExcelData(excelVo, rowIndex + 1);
+                    if (errorMsg != null) {
+                        errorMessages.add(errorMsg);
+                    } else {
+                        excelVoList.add(excelVo);
+                    }
+                }
+            }
+
+            if (!errorMessages.isEmpty()) {
+                return R.fail("数据校验失败:\n" + String.join("\n", errorMessages));
+            }
+
+            if (excelVoList.isEmpty()) {
+                return R.fail("Excel文件中没有有效数据");
+            }
+
+            // 收集所有导入数据中的收款账号(用于检查重复)
+            Set<String> allImportAccounts = new HashSet<>();
+            Map<String, String> accountToFirmNameMap = new HashMap<>(); // 账号 -> 律所名称,用于错误提示
+
+            // 先收集所有账号,检查导入数据中的重复
+            for (LawFirmExcelVo excelVo : excelVoList) {
+                String paymentAccount = excelVo.getPaymentAccount();
+                if (StringUtils.hasText(paymentAccount)) {
+                    // 账号可能包含多个,用逗号分隔
+                    String[] accounts = paymentAccount.split(",");
+                    for (String account : accounts) {
+                        String trimmedAccount = account.trim();
+                        if (!trimmedAccount.isEmpty()) {
+                            if (allImportAccounts.contains(trimmedAccount)) {
+                                // 发现重复账号
+                                String existingFirmName = accountToFirmNameMap.get(trimmedAccount);
+                                return R.fail(String.format("导入数据中存在重复的收款账号[%s],律所[%s]和律所[%s]使用了相同的账号,无法导入",
+                                        trimmedAccount, existingFirmName, excelVo.getFirmName()));
+                            }
+                            allImportAccounts.add(trimmedAccount);
+                            accountToFirmNameMap.put(trimmedAccount, excelVo.getFirmName());
+                        }
+                    }
+                }
+            }
+
+            // 检查数据库中是否已存在这些账号
+            if (!allImportAccounts.isEmpty()) {
+                // 查询数据库中所有已存在的收款账号
+                LambdaQueryWrapper<LawFirm> queryWrapper = new LambdaQueryWrapper<>();
+                queryWrapper.eq(LawFirm::getDeleteFlag, 0);
+                queryWrapper.isNotNull(LawFirm::getPaymentAccount);
+                queryWrapper.ne(LawFirm::getPaymentAccount, "");
+                List<LawFirm> existingLawFirms = this.list(queryWrapper);
+
+                // 收集数据库中所有已存在的账号
+                Set<String> existingAccounts = new HashSet<>();
+                for (LawFirm firm : existingLawFirms) {
+                    String paymentAccount = firm.getPaymentAccount();
+                    if (StringUtils.hasText(paymentAccount)) {
+                        String[] accounts = paymentAccount.split(",");
+                        for (String account : accounts) {
+                            String trimmedAccount = account.trim();
+                            if (!trimmedAccount.isEmpty()) {
+                                existingAccounts.add(trimmedAccount);
+                            }
+                        }
+                    }
+                }
+
+                // 检查导入的账号是否已存在
+                Set<String> duplicateAccounts = new HashSet<>();
+                for (String importAccount : allImportAccounts) {
+                    if (existingAccounts.contains(importAccount)) {
+                        duplicateAccounts.add(importAccount);
+                    }
+                }
+
+                if (!duplicateAccounts.isEmpty()) {
+                    String duplicateAccountList = String.join("、", duplicateAccounts);
+                    return R.fail(String.format("收款账号[%s]在数据库中已存在,无法导入。请检查并修改账号后重新导入", duplicateAccountList));
+                }
+            }
+
+            // 按律所名称分组,合并账号
+            Map<String, List<LawFirmExcelVo>> firmNameMap = excelVoList.stream()
+                    .collect(Collectors.groupingBy(LawFirmExcelVo::getFirmName));
+
+            int successCount = 0;
+            int failCount = 0;
+            List<String> importErrors = new ArrayList<>();
+
+            for (Map.Entry<String, List<LawFirmExcelVo>> entry : firmNameMap.entrySet()) {
+                String firmName = entry.getKey();
+                List<LawFirmExcelVo> voList = entry.getValue();
+
+                // 合并账号
+                String paymentAccounts = voList.stream()
+                        .map(LawFirmExcelVo::getPaymentAccount)
+                        .filter(Objects::nonNull)
+                        .filter(acc -> !acc.trim().isEmpty())
+                        .distinct()
+                        .collect(Collectors.joining(","));
+
+                // 使用第一个数据作为主数据
+                LawFirmExcelVo firstVo = voList.get(0);
+                LawFirm lawFirm = convertToLawFirm(firstVo);
+                lawFirm.setPaymentAccount(paymentAccounts);
+
+                // 校验统一社会信用代码是否已存在
+//                LambdaQueryWrapper<LawFirm> creditCodeWrapper = new LambdaQueryWrapper<>();
+//                creditCodeWrapper.eq(LawFirm::getCreditCode, lawFirm.getCreditCode());
+//                creditCodeWrapper.eq(LawFirm::getDeleteFlag, 0);
+//                long creditCodeCount = this.count(creditCodeWrapper);
+//                if (creditCodeCount > 0) {
+//                    importErrors.add("律所[" + firmName + "]的统一社会信用代码[" + lawFirm.getCreditCode() + "]已存在");
+//                    failCount++;
+//                    continue;
+//                }
+
+                // 设置默认值
+                if (lawFirm.getStatus() == null) {
+                    lawFirm.setStatus(1);
+                }
+//                if (lawFirm.getCertificationStatus() == null) {
+//                    lawFirm.setCertificationStatus(0);
+//                }
+                if (lawFirm.getDeleteFlag() == null) {
+                    lawFirm.setDeleteFlag(0);
+                }
+//                if (lawFirm.getIsRecommended() == null) {
+//                    lawFirm.setIsRecommended(0);
+//                }
+//                if (lawFirm.getLawyerCount() == null) {
+//                    lawFirm.setLawyerCount(0);
+//                }
+//                if (lawFirm.getPartnerCount() == null) {
+//                    lawFirm.setPartnerCount(0);
+//                }
+//                if (lawFirm.getPlatformCommissionRatio() == null) {
+//                    lawFirm.setPlatformCommissionRatio(new BigDecimal("3.00"));
+//                }
+
+                // 保存
+                boolean result = this.save(lawFirm);
+                if (result) {
+                    successCount++;
+                } else {
+                    importErrors.add("律所[" + firmName + "]保存失败");
+                    failCount++;
+                }
+            }
+
+            String resultMsg = String.format("导入完成:成功%d条,失败%d条", successCount, failCount);
+            if (!importErrors.isEmpty()) {
+                resultMsg += "\n失败详情:\n" + String.join("\n", importErrors);
+            }
+
+            return R.success(resultMsg);
+        } catch (Exception e) {
+            log.error("导入律所数据失败", e);
+            return R.fail("导入失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 生成带合并单元格的Excel
+     */
+    private void generateExcelWithMerge(HttpServletResponse response, List<LawFirmExcelVo> excelVoList,
+                                        Map<String, List<LawFirm>> firmNameMap) throws IOException {
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        Sheet sheet = workbook.createSheet("律所列表");
+
+        // 获取字段
+        Field[] fields = LawFirmExcelVo.class.getDeclaredFields();
+        List<Field> excelFields = Arrays.stream(fields)
+                .filter(f -> f.isAnnotationPresent(ExcelHeader.class))
+                .collect(Collectors.toList());
+
+        // 创建表头样式
+        Font headerFont = workbook.createFont();
+        headerFont.setBold(true);
+        CellStyle headerCellStyle = workbook.createCellStyle();
+        headerCellStyle.setFont(headerFont);
+        headerCellStyle.setAlignment(HorizontalAlignment.CENTER);
+        headerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+
+        // 创建数据样式
+        CellStyle dataCellStyle = workbook.createCellStyle();
+        dataCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        dataCellStyle.setWrapText(true);
+
+        // 创建表头
+        Row headerRow = sheet.createRow(0);
+        for (int i = 0; i < excelFields.size(); i++) {
+            Field field = excelFields.get(i);
+            ExcelHeader excelHeader = field.getAnnotation(ExcelHeader.class);
+            Cell cell = headerRow.createCell(i);
+            cell.setCellValue(excelHeader.value());
+            cell.setCellStyle(headerCellStyle);
+        }
+
+        // 填充数据
+        int rowNum = 1;
+        Map<String, Integer> firmNameRowMap = new HashMap<>(); // 记录每个律所名称的第一行
+        Map<String, Integer> firmNameCountMap = new HashMap<>(); // 记录每个律所名称的行数
+
+        for (LawFirmExcelVo excelVo : excelVoList) {
+            Row row = sheet.createRow(rowNum);
+            String firmName = excelVo.getFirmName();
+
+            if (!firmNameRowMap.containsKey(firmName)) {
+                firmNameRowMap.put(firmName, rowNum);
+                // 计算该律所名称有多少行
+                long count = excelVoList.stream()
+                        .filter(vo -> firmName.equals(vo.getFirmName()))
+                        .count();
+                firmNameCountMap.put(firmName, (int) count);
+            }
+
+            for (int i = 0; i < excelFields.size(); i++) {
+                Field field = excelFields.get(i);
+                field.setAccessible(true);
+                Cell cell = row.createCell(i);
+                cell.setCellStyle(dataCellStyle);
+                try {
+                    Object value = field.get(excelVo);
+                    if (value != null) {
+                        cell.setCellValue(value.toString());
+                    }
+                } catch (IllegalAccessException e) {
+                    log.error("获取字段值失败", e);
+                }
+            }
+            rowNum++;
+        }
+
+        // 合并相同律所名称的单元格(除了账号列)
+        int firmNameColIndex = -1;
+        int paymentAccountColIndex = -1;
+        for (int i = 0; i < excelFields.size(); i++) {
+            Field field = excelFields.get(i);
+            ExcelHeader excelHeader = field.getAnnotation(ExcelHeader.class);
+            if ("律所名称".equals(excelHeader.value())) {
+                firmNameColIndex = i;
+            } else if ("律师事务所收款账号".equals(excelHeader.value())) {
+                paymentAccountColIndex = i;
+            }
+        }
+
+        // 合并律所名称列
+        if (firmNameColIndex >= 0) {
+            for (Map.Entry<String, Integer> entry : firmNameRowMap.entrySet()) {
+                String firmName = entry.getKey();
+                int firstRow = entry.getValue();
+                int rowCount = firmNameCountMap.get(firmName);
+                if (rowCount > 1) {
+                    sheet.addMergedRegion(new CellRangeAddress(firstRow, firstRow + rowCount - 1, firmNameColIndex, firmNameColIndex));
+                }
+            }
+        }
+
+        // 合并其他列(除了账号列)
+        for (int i = 0; i < excelFields.size(); i++) {
+            if (i == firmNameColIndex || i == paymentAccountColIndex) {
+                continue;
+            }
+            for (Map.Entry<String, Integer> entry : firmNameRowMap.entrySet()) {
+                String firmName = entry.getKey();
+                int firstRow = entry.getValue();
+                int rowCount = firmNameCountMap.get(firmName);
+                if (rowCount > 1) {
+                    sheet.addMergedRegion(new CellRangeAddress(firstRow, firstRow + rowCount - 1, i, i));
+                }
+            }
+        }
+
+        // 设置列宽
+        for (int i = 0; i < excelFields.size(); i++) {
+            sheet.setColumnWidth(i, 20 * 256);
+        }
+
+        // 设置响应头
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setCharacterEncoding("utf-8");
+        String fileName = URLEncoder.encode("律所列表", "UTF-8").replaceAll("\\+", "%20");
+        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
+
+        // 输出
+        OutputStream outputStream = response.getOutputStream();
+        workbook.write(outputStream);
+        workbook.close();
+        outputStream.close();
+    }
+
+    /**
+     * 转换为ExcelVo
+     */
+    private LawFirmExcelVo convertToExcelVo(LawFirm lawFirm, int serialNumber,
+                                           SimpleDateFormat dateFormat, SimpleDateFormat dateTimeFormat) {
+        LawFirmExcelVo excelVo = new LawFirmExcelVo();
+        BeanUtils.copyProperties(lawFirm, excelVo);
+        excelVo.setSerialNumber(serialNumber);
+
+        // 格式化日期
+        if (lawFirm.getEstablishmentDate() != null) {
+            excelVo.setEstablishmentDate(dateFormat.format(lawFirm.getEstablishmentDate()));
+        }
+
+        // 格式化类型
+        if (lawFirm.getFirmType() != null) {
+            switch (lawFirm.getFirmType()) {
+                case 1:
+                    excelVo.setFirmType("合伙制");
+                    break;
+                case 2:
+                    excelVo.setFirmType("个人制");
+                    break;
+                case 3:
+                    excelVo.setFirmType("国资制");
+                    break;
+            }
+        }
+
+        // 格式化规模
+        if (lawFirm.getFirmScale() != null) {
+            switch (lawFirm.getFirmScale()) {
+                case 1:
+                    excelVo.setFirmScale("小型(1-10人)");
+                    break;
+                case 2:
+                    excelVo.setFirmScale("中型(11-50人)");
+                    break;
+                case 3:
+                    excelVo.setFirmScale("大型(51-200人)");
+                    break;
+                case 4:
+                    excelVo.setFirmScale("超大型(200人以上)");
+                    break;
+            }
+        }
+
+        // 格式化状态
+        if (lawFirm.getStatus() != null) {
+            excelVo.setStatus(lawFirm.getStatus() == 1 ? "启用" : "禁用");
+        }
+
+        // 格式化认证状态
+        if (lawFirm.getCertificationStatus() != null) {
+            switch (lawFirm.getCertificationStatus()) {
+                case 0:
+                    excelVo.setCertificationStatus("未认证");
+                    break;
+                case 1:
+                    excelVo.setCertificationStatus("认证中");
+                    break;
+                case 2:
+                    excelVo.setCertificationStatus("已认证");
+                    break;
+                case 3:
+                    excelVo.setCertificationStatus("认证失败");
+                    break;
+            }
+        }
+
+        // 格式化佣金比例
+        if (lawFirm.getPlatformCommissionRatio() != null) {
+            excelVo.setPlatformCommissionRatio(lawFirm.getPlatformCommissionRatio().toString() + "%");
+        }
+
+        return excelVo;
+    }
+
+    /**
+     * 校验Excel数据
+     */
+    private String validateExcelData(LawFirmExcelVo excelVo, int rowIndex) {
+        if (!StringUtils.hasText(excelVo.getFirmName())) {
+            return "第" + rowIndex + "行:律所名称不能为空";
+        }
+//        if (!StringUtils.hasText(excelVo.getCreditCode())) {
+//            return "第" + rowIndex + "行:统一社会信用代码不能为空";
+//        }
+//        if (!StringUtils.hasText(excelVo.getPhone())) {
+//            return "第" + rowIndex + "行:联系电话不能为空";
+//        }
+        if (!StringUtils.hasText(excelVo.getDirectorName())) {
+            return "第" + rowIndex + "行:负责人姓名不能为空";
+        }
+//        if (!StringUtils.hasText(excelVo.getDirectorPhone())) {
+//            return "第" + rowIndex + "行:负责人电话不能为空";
+//        }
+
+        // 校验邮箱格式
+//        if (StringUtils.hasText(excelVo.getEmail())) {
+//            if (!excelVo.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
+//                return "第" + rowIndex + "行:邮箱格式不正确";
+//            }
+//        }
+//        if (StringUtils.hasText(excelVo.getDirectorEmail())) {
+//            if (!excelVo.getDirectorEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
+//                return "第" + rowIndex + "行:负责人邮箱格式不正确";
+//            }
+//        }
+
+        return null;
+    }
+
+    /**
+     * 转换为LawFirm实体
+     */
+    private LawFirm convertToLawFirm(LawFirmExcelVo excelVo) {
+        LawFirm lawFirm = new LawFirm();
+        BeanUtils.copyProperties(excelVo, lawFirm);
+
+        // 解析类型
+        if (StringUtils.hasText(excelVo.getFirmType())) {
+            switch (excelVo.getFirmType()) {
+                case "合伙制":
+                    lawFirm.setFirmType(1);
+                    break;
+                case "个人制":
+                    lawFirm.setFirmType(2);
+                    break;
+                case "国资制":
+                    lawFirm.setFirmType(3);
+                    break;
+            }
+        }
+
+        // 解析规模
+        if (StringUtils.hasText(excelVo.getFirmScale())) {
+            if (excelVo.getFirmScale().contains("小型")) {
+                lawFirm.setFirmScale(1);
+            } else if (excelVo.getFirmScale().contains("中型")) {
+                lawFirm.setFirmScale(2);
+            } else if (excelVo.getFirmScale().contains("大型") && !excelVo.getFirmScale().contains("超大型")) {
+                lawFirm.setFirmScale(3);
+            } else if (excelVo.getFirmScale().contains("超大型")) {
+                lawFirm.setFirmScale(4);
+            }
+        }
+
+        // 解析状态
+        if (StringUtils.hasText(excelVo.getStatus())) {
+            lawFirm.setStatus("启用".equals(excelVo.getStatus()) ? 1 : 0);
+        }
+
+        // 解析认证状态
+        if (StringUtils.hasText(excelVo.getCertificationStatus())) {
+            switch (excelVo.getCertificationStatus()) {
+                case "未认证":
+                    lawFirm.setCertificationStatus(0);
+                    break;
+                case "认证中":
+                    lawFirm.setCertificationStatus(1);
+                    break;
+                case "已认证":
+                    lawFirm.setCertificationStatus(2);
+                    break;
+                case "认证失败":
+                    lawFirm.setCertificationStatus(3);
+                    break;
+            }
+        }
+
+        // 解析日期
+        if (StringUtils.hasText(excelVo.getEstablishmentDate())) {
+            try {
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                lawFirm.setEstablishmentDate(dateFormat.parse(excelVo.getEstablishmentDate()));
+            } catch (Exception e) {
+                log.warn("解析成立日期失败:{}", excelVo.getEstablishmentDate());
+            }
+        }
+
+        // 解析佣金比例
+        if (StringUtils.hasText(excelVo.getPlatformCommissionRatio())) {
+            try {
+                String ratio = excelVo.getPlatformCommissionRatio().replace("%", "").trim();
+                lawFirm.setPlatformCommissionRatio(new BigDecimal(ratio));
+            } catch (Exception e) {
+                log.warn("解析佣金比例失败:{}", excelVo.getPlatformCommissionRatio());
+            }
+        }
+
+        return lawFirm;
+    }
+
+    /**
+     * 获取单元格值作为字符串
+     */
+    private String getCellValueAsString(Cell cell) {
+        if (cell == null) {
+            return null;
+        }
+        switch (cell.getCellType()) {
+            case STRING:
+                return cell.getStringCellValue();
+            case NUMERIC:
+                if (DateUtil.isCellDateFormatted(cell)) {
+                    return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
+                } else {
+                    double numericValue = cell.getNumericCellValue();
+                    // 如果是整数,返回整数格式
+                    if (numericValue == (long) numericValue) {
+                        return String.valueOf((long) numericValue);
+                    } else {
+                        return String.valueOf(numericValue);
+                    }
+                }
+            case BOOLEAN:
+                return String.valueOf(cell.getBooleanCellValue());
+            case FORMULA:
+                return cell.getCellFormula();
+            default:
+                return null;
+        }
+    }
+
+    @Override
     public R<LawFirm> getLawFirmDetail(Integer id) {
         log.info("LawFirmServiceImpl.getLawFirmDetail?id={}", id);
-        
+
         if (id == null) {
             return R.fail("律所ID不能为空");
         }
-        
+
         // 使用 MyBatis-Plus 的 getById 方法获取律所详情
         LawFirm lawFirm = this.getById(id);
-        
+
         if (lawFirm == null) {
             return R.fail("律所不存在");
         }
-        
+
         // 检查是否已删除
         if (lawFirm.getDeleteFlag() != null && lawFirm.getDeleteFlag() == 1) {
             return R.fail("律所已被删除");
         }
-        
+
         return R.data(lawFirm, "查询成功");
     }
 }

+ 54 - 21
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerClientConsultationOrderServiceImpl.java

@@ -201,51 +201,84 @@ public class LawyerClientConsultationOrderServiceImpl extends ServiceImpl<Lawyer
 
     /**
      * 获取咨询订单详情
+     * <p>
+     * 查询订单基本信息、律师信息和律师问题场景信息
+     * </p>
      *
      * @param lawyerOrderId 订单ID
-     * @return 咨询订单详情VO
+     * @return 咨询订单详情VO,如果订单不存在或参数为空则返回空对象
      */
     @Override
     public LawyerConsultationOrderVO getConsultationOrderDetail(String lawyerOrderId) {
-        log.info("LawyerConsultationOrderServiceImpl.getConsultationOrderDetail?lawyerOrderId={}", lawyerOrderId);
-
-        LawyerConsultationOrderVO orderVO = new LawyerConsultationOrderVO();
+        log.info("获取咨询订单详情,订单ID={}", lawyerOrderId);
 
         // 参数校验
         if (!StringUtils.hasText(lawyerOrderId)) {
-            return orderVO;
+            log.warn("获取咨询订单详情失败:订单ID为空");
+            return new LawyerConsultationOrderVO();
         }
 
         // 查询订单信息
         LawyerConsultationOrder order = consultationOrderMapper.selectById(lawyerOrderId);
         if (order == null) {
-            return orderVO;
+            log.warn("获取咨询订单详情失败:订单不存在,订单ID={}", lawyerOrderId);
+            return new LawyerConsultationOrderVO();
         }
 
         // 复制订单基本信息
+        LawyerConsultationOrderVO orderVO = new LawyerConsultationOrderVO();
         BeanUtils.copyProperties(order, orderVO);
 
-        // 查询并填充律师信息
-        Integer lawyerUserId = order.getLawyerUserId();
-        if (lawyerUserId != null) {
-            LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerUserId);
-            if (lawyerUser != null) {
-                fillLawyerInfo(orderVO, lawyerUser);
-            }
+        // 填充律师相关信息
+        fillLawyerRelatedInfo(orderVO, order.getLawyerUserId());
 
+        return orderVO;
+    }
 
-            // 查询律师问题场景
-            List<Integer> lawyerIdList = Collections.singletonList(lawyerUserId);
-            Map<String, List<String>> serviceAreaMap = getLawyerServiceArea(lawyerIdList);
-            String lawyerUserIdStr = String.valueOf(lawyerUserId);
-            if (!serviceAreaMap.isEmpty() && serviceAreaMap.containsKey(lawyerUserIdStr)) {
-                orderVO.setLawyerLegalProblemScenarioList(serviceAreaMap.get(lawyerUserIdStr));
-            }
+    /**
+     * 填充律师相关信息到订单VO
+     * <p>
+     * 包括律师基本信息和律师问题场景列表
+     * </p>
+     *
+     * @param orderVO    订单VO对象
+     * @param lawyerUserId 律师用户ID
+     */
+    private void fillLawyerRelatedInfo(LawyerConsultationOrderVO orderVO, Integer lawyerUserId) {
+        if (lawyerUserId == null) {
+            return;
         }
 
-        return orderVO;
+        // 查询并填充律师基本信息
+        LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerUserId);
+        if (lawyerUser != null) {
+            fillLawyerInfo(orderVO, lawyerUser);
+        }
+
+        // 查询并填充律师问题场景
+        fillLawyerServiceAreaForOrder(orderVO, lawyerUserId);
     }
 
+    /**
+     * 填充律师问题场景信息到订单VO
+     *
+     * @param orderVO     订单VO对象
+     * @param lawyerUserId 律师用户ID
+     */
+    private void fillLawyerServiceAreaForOrder(LawyerConsultationOrderVO orderVO, Integer lawyerUserId) {
+        List<Integer> lawyerIdList = Collections.singletonList(lawyerUserId);
+        Map<String, List<String>> serviceAreaMap = getLawyerServiceArea(lawyerIdList);
+
+        if (serviceAreaMap.isEmpty()) {
+            return;
+        }
+
+        String lawyerUserIdStr = String.valueOf(lawyerUserId);
+        List<String> serviceAreaList = serviceAreaMap.get(lawyerUserIdStr);
+        if (CollectionUtils.isNotEmpty(serviceAreaList)) {
+            orderVO.setLawyerLegalProblemScenarioList(serviceAreaList);
+        }
+    }
 
     /**
      * 查询咨询订单信息(律师端)

+ 3 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationOrderServiceImpl.java

@@ -1011,16 +1011,19 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
 
             // 构建返回结果
             Map<String, Object> allRevenueMap = new HashMap<>();
+            allRevenueMap.put("name", "全部收益");
             allRevenueMap.put("orderCount", revenueVO.getAllOrderCount());
             allRevenueMap.put("totalRevenue", revenueVO.getAllRevenue());
             resultMap.put("allRevenue", allRevenueMap);
 
             Map<String, Object> inProgressMap = new HashMap<>();
+            inProgressMap.put("name", "进行中");
             inProgressMap.put("orderCount", revenueVO.getInProgressOrderCount());
             inProgressMap.put("totalRevenue", revenueVO.getInProgressRevenue());
             resultMap.put("inProgress", inProgressMap);
 
             Map<String, Object> completedMap = new HashMap<>();
+            completedMap.put("name", "已完成");
             completedMap.put("orderCount", revenueVO.getCompletedOrderCount());
             completedMap.put("totalRevenue", revenueVO.getCompletedRevenue());
             resultMap.put("completed", completedMap);

+ 56 - 10
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerLegalProblemScenarioServiceImpl.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
@@ -30,21 +31,20 @@ import java.util.stream.Collectors;
 public class LawyerLegalProblemScenarioServiceImpl extends ServiceImpl<LawyerLegalProblemScenarioMapper, LawyerLegalProblemScenario> implements LawyerLegalProblemScenarioService {
 
     @Override
-    public R<LawyerLegalProblemScenario> addLawyerLegalProblemScenario(LawyerLegalProblemScenario LawyerLegalProblemScenario) {
-        log.info("LawyerLegalProblemScenarioServiceImpl.addLawyerLegalProblemScenario?LawyerLegalProblemScenario={}", LawyerLegalProblemScenario);
-        boolean result = this.save(LawyerLegalProblemScenario);
+    public R<LawyerLegalProblemScenario> addLawyerLegalProblemScenario(LawyerLegalProblemScenario lawyerLegalProblemScenario) {
+        boolean result = this.save(lawyerLegalProblemScenario);
         if (result) {
-            return R.data(LawyerLegalProblemScenario);
+            return R.data(lawyerLegalProblemScenario);
         }
         return R.fail("新增失败");
     }
 
     @Override
-    public R<LawyerLegalProblemScenario> editLawyerLegalProblemScenario(LawyerLegalProblemScenario LawyerLegalProblemScenario) {
-        log.info("LawyerLegalProblemScenarioServiceImpl.editLawyerLegalProblemScenario?LawyerLegalProblemScenario={}", LawyerLegalProblemScenario);
-        boolean result = this.updateById(LawyerLegalProblemScenario);
+    public R<LawyerLegalProblemScenario> editLawyerLegalProblemScenario(LawyerLegalProblemScenario lawyerLegalProblemScenario) {
+        log.info("LawyerLegalProblemScenarioServiceImpl.editLawyerLegalProblemScenario?LawyerLegalProblemScenario={}", lawyerLegalProblemScenario);
+        boolean result = this.updateById(lawyerLegalProblemScenario);
         if (result) {
-            return R.data(LawyerLegalProblemScenario);
+            return R.data(lawyerLegalProblemScenario);
         }
         return R.fail("修改失败");
     }
@@ -52,12 +52,58 @@ public class LawyerLegalProblemScenarioServiceImpl extends ServiceImpl<LawyerLeg
     @Override
     public R<Boolean> deleteLawyerLegalProblemScenario(Integer id) {
         log.info("LawyerLegalProblemScenarioServiceImpl.deleteLawyerLegalProblemScenario?id={}", id);
-        boolean result = this.removeById(id);
+        
+        // 参数校验
+        if (id == null) {
+            log.warn("删除法律问题场景失败:ID为空");
+            return R.fail("场景ID不能为空");
+        }
+        
+        // 查询要删除的场景
+        LawyerLegalProblemScenario scenario = this.getById(id);
+        if (scenario == null) {
+            log.warn("删除法律问题场景失败:场景不存在,id={}", id);
+            return R.fail("场景不存在");
+        }
+        
+        // 递归删除所有子场景
+        List<Integer> allIdsToDelete = new ArrayList<>();
+        allIdsToDelete.add(id);
+        collectChildIds(id, allIdsToDelete);
+        
+        log.info("准备删除场景及其子场景,共{}个,ids={}", allIdsToDelete.size(), allIdsToDelete);
+        
+        // 批量删除所有场景(包括当前场景和所有子场景)
+        boolean result = this.removeByIds(allIdsToDelete);
         if (result) {
-            return R.success("删除成功");
+            log.info("删除法律问题场景成功,共删除{}个场景", allIdsToDelete.size());
+            return R.success("删除成功,共删除" + allIdsToDelete.size() + "个场景");
         }
         return R.fail("删除失败");
     }
+    
+    /**
+     * 递归收集所有子场景的ID
+     *
+     * @param parentId 父场景ID
+     * @param idsList  用于收集所有子场景ID的列表
+     */
+    private void collectChildIds(Integer parentId, List<Integer> idsList) {
+        // 查询所有直接子场景(parentId = 当前场景ID)
+        QueryWrapper<LawyerLegalProblemScenario> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("parent_id", parentId)
+                .eq("delete_flag", 0);
+        List<LawyerLegalProblemScenario> children = this.list(queryWrapper);
+        
+        if (!CollectionUtils.isEmpty(children)) {
+            for (LawyerLegalProblemScenario child : children) {
+                Integer childId = child.getId();
+                idsList.add(childId);
+                // 递归查找子场景的子场景
+                collectChildIds(childId, idsList);
+            }
+        }
+    }
 
     @Override
     public R<LawyerLegalProblemScenario> getCategoryTreeByFirstLevelId(Integer id) {

+ 78 - 22
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerUserServiceImpl.java

@@ -15,6 +15,7 @@ import org.springframework.util.StringUtils;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.LawyerUserVo;
+import shop.alien.lawyer.config.BaseRedisService;
 import shop.alien.lawyer.service.LawyerLegalProblemScenarioService;
 import shop.alien.lawyer.service.LawyerServiceAreaService;
 import shop.alien.lawyer.service.LawyerUserSearchHistoryService;
@@ -22,6 +23,7 @@ import shop.alien.lawyer.service.LawyerUserService;
 import shop.alien.mapper.LawFirmMapper;
 import shop.alien.mapper.LawyerConsultationOrderMapper;
 import shop.alien.mapper.LawyerUserMapper;
+import shop.alien.util.common.ListToPage;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -44,6 +46,7 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
     private final LawyerLegalProblemScenarioService lawyerLegalProblemScenarioService;
     private final LawyerConsultationOrderMapper lawyerConsultationOrderMapper;
     private final LawFirmMapper lawFirmMapper;
+    private final BaseRedisService baseRedisService;
 
     @Override
     public R<IPage<LawyerUser>> getLawyerUserList(int pageNum, int pageSize, String name, String phone, Integer status) {
@@ -356,14 +359,13 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
     /**
      * 获取AI推荐律师列表
      *
-     * @param page       页码
-     * @param size       页大小
-     * @param categoryId 分类ID
-     * @return R<IPage<LawyerUser>> 推荐律师列表
+     * @param page 页码
+     *             pageSize 页大小
+     *             categoryId 分类ID
      */
     @Override
     public R<IPage<LawyerUser>> getAiRecommendList(int page, int size, Integer categoryId) {
-        log.info("LawyerUserServiceImpl.getAiRecommendList?page={},size={},categoryId={}",
+        log.info("LawyerUserController.aiRecommendList?page={},size={},categoryId={}",
                 page, size, categoryId);
 
         // 构建查询条件
@@ -432,6 +434,12 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
             return R.fail("律师不存在");
         }
 
+        String key = "lawyer_" + lawyerUser.getPhone();
+        String redisVerificationCode = baseRedisService.getString(key);
+        //对redisVerificationCode进行校验,如果不是空的话清除redis中的记录
+        if (redisVerificationCode != null) {
+            baseRedisService.delete(key);
+        }
         // 检查是否已经注销
         if (lawyerUser.getLogoutFlag() != null && lawyerUser.getLogoutFlag() == 1) {
             log.warn("注销律师用户失败:律师已注销,律师ID={}, 律师姓名={}", id, lawyerUser.getName());
@@ -444,20 +452,20 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
             return R.fail("该律师账号已删除");
         }
 
-        List<LawyerConsultationOrder> orderList = lawyerConsultationOrderMapper.selectOrder(null, id);
+        List<LawyerConsultationOrder> list=lawyerConsultationOrderMapper.selectOrder(null, id);
+
 
-        if (!CollectionUtils.isEmpty(orderList)) {
+        if (!CollectionUtils.isEmpty( list)){
             // 提示前端有未完成订单 1:有未完成订单  0:无未完成订单
             resultMap.put("unfinishedOrder", 1);
         }
 
-        if (lawyerUser.getOrderReceivingStatus() != null && lawyerUser.getOrderReceivingStatus() == 1) {
+        if (lawyerUser.getOrderReceivingStatus() != null && lawyerUser.getOrderReceivingStatus() == 1){
             // 提示前端接单状态为接单中 1:接单中  0:未接单
             resultMap.put("orderReceivingStatus", 1);
         }
 
-        // 只有无未完成订单且状态为禁用时,才执行注销操作
-        if (CollectionUtils.isEmpty(orderList) && lawyerUser.getStatus() == 0) {
+        if (CollectionUtils.isEmpty( list) || lawyerUser.getStatus() == 0){
             // 设置注销相关字段
             lawyerUser.setLogoutFlag(1); // 注销标记:1-已注销
             lawyerUser.setLogoutTime(new Date()); // 注销时间
@@ -491,7 +499,7 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
     }
 
     @Override
-    public R<LawyerUser> getLawyerInfo(Integer lawyerId) {
+    public R<LawyerUserVo> getLawyerInfo(Integer lawyerId) {
         log.info("LawyerUserServiceImpl.getLawyerInfo?lawyerId={}", lawyerId);
 
         // 参数校验
@@ -513,38 +521,86 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
             return R.fail("律师信息已删除");
         }
 
-        LawFirm lawFirm = lawFirmMapper.selectById(lawyer.getFirmId());
-        if (lawFirm != null) {
-            // 如果需要在返回对象中设置律所信息,可以在这里处理
-            // 目前直接返回 LawyerUser 对象
-        }
-
-        return R.data(lawyer);
+        LawyerUserVo result=lawyerUserMapper.selectInfo(lawyerId);
+        return R.data(result);
     }
 
+
     @Override
     public R<LawyerUser> updateLawyerUser(LawyerUserVo lawyerUserVo) {
         log.info("LawyerUserServiceImpl.updateLawyerUser?lawyerUserVo={}", lawyerUserVo);
-        
+
         // 参数校验
         if (lawyerUserVo == null || lawyerUserVo.getId() == null) {
             log.warn("更新律师用户信息失败:参数为空或律师ID为空");
             return R.fail("律师ID不能为空");
         }
-        
+
         LawyerUser lawyerUser = new LawyerUser();
         BeanUtils.copyProperties(lawyerUserVo, lawyerUser);
-        
+
         Integer result = lawyerUserMapper.updateLawyerUser(lawyerUser);
         if (result <= 0) {
             log.warn("更新律师用户信息失败:更新数据库失败,律师ID={}", lawyerUserVo.getId());
             return R.fail("修改律师信息失败");
         }
-        
+
+//        lawFirmMapper.updateById(lawyerUser)
+
         // 查询更新后的律师信息
         LawyerUser updatedLawyer = this.getById(lawyerUserVo.getId());
         log.info("更新律师用户信息成功,律师ID={}", lawyerUserVo.getId());
         return R.data(updatedLawyer);
     }
+
+    @Override
+    public R<LawyerUser> getLawyerInfoByPhone(String phone) {
+        log.info("LawyerUserServiceImpl.getLawyerInfoByPhone?phone={}", phone);
+
+        // 参数校验
+        if (!StringUtils.hasText(phone)) {
+            log.warn("查询律师信息失败:手机号为空");
+            return R.fail("手机号不能为空");
+        }
+
+        // 构建查询条件
+        LambdaQueryWrapper<LawyerUser> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(LawyerUser::getPhone, phone)
+                .eq(LawyerUser::getDeleteFlag, 0)
+                .orderByDesc(LawyerUser::getCreatedTime)
+                .last("LIMIT 1");
+
+        // 查询律师信息
+        LawyerUser lawyerUser = lawyerUserMapper.selectOne(queryWrapper);
+
+        if (lawyerUser == null) {
+            log.warn("查询律师信息失败:律师不存在,手机号={}", phone);
+            return R.fail("律师不存在");
+        }
+
+        return R.data(lawyerUser);
+    }
+
+    @Override
+    public R<IPage<LawyerUserVo>> getLawyerList(int page, int pageSize, LawyerUserVo lawyerUserVo) {
+        log.info("LawyerUserServiceImpl.getLawyerList?page={},pageSize={},lawyerUserVo={}",
+                page, pageSize, lawyerUserVo);
+
+//        int pageNum = page > 0 ? page : 1;
+//        int pageSizeNum = pageSize > 0 ? pageSize : 10;
+
+        // 确保 lawyerUserVo 不为 null
+        if (lawyerUserVo == null) {
+            lawyerUserVo = new LawyerUserVo();
+        }
+
+        
+        // 查询分页数据(在SQL层面使用LIMIT进行分页)
+        List<LawyerUserVo> list = lawyerUserMapper.selectLawyerUserList(lawyerUserVo);
+        if (list == null) {
+            list = new ArrayList<>();
+        }
+        return R.data(ListToPage.setPage(list, page, pageSize));
+    }
 }
 

+ 18 - 2
alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java

@@ -32,6 +32,7 @@ import shop.alien.second.service.SecondTradeRecordService;
 import shop.alien.util.common.JwtUtil;
 
 import java.time.*;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;
@@ -566,8 +567,23 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
             wrapper.apply("((seller_id = " + userId + " and buyer_id = " + sideId + ") or " +
                     "(seller_id = " + sideId + " and buyer_id = " + userId + "))");
-            wrapper.orderByDesc(SecondTradeRecord::getTransactionTime);
-            return secondTradeRecordMapper.selectOne(wrapper);
+            wrapper.orderByAsc(SecondTradeRecord::getTransactionTime);
+            List<SecondTradeRecord> list = secondTradeRecordMapper.selectList(wrapper);
+            if (list.isEmpty()) return null;
+
+            // 取出所有的交易时间
+            List<Date> dates = list.stream().map(SecondTradeRecord::getTransactionTime).collect(Collectors.toList());
+            if (dates.isEmpty()) return null;
+
+            // 取出距离当前时间最近的交易时间
+            Date now = new Date();
+            Date minDate = dates.stream()
+                    .min(Comparator.comparingLong(date ->
+                            Math.abs(date.getTime() - now.getTime())))
+                    .orElse(null);
+
+            list = list.stream().filter(item -> item.getTransactionTime().equals(minDate)).collect(Collectors.toList());
+            return list.isEmpty() ? null : list.get(0);
          } catch (Exception e) {
             log.error("SecondTradeRecordServiceImpl.hasInTradeRecord(): Error Msg={}", e.getMessage());
             throw new Exception(e);

+ 3 - 7
alien-store/src/main/java/shop/alien/store/controller/LawyerAiInteractionLogController.java

@@ -139,13 +139,9 @@ public class LawyerAiInteractionLogController {
             @ApiImplicitParam(name = "sceneId", value = "场景ID", dataType = "Integer", paramType = "query")
     })
     @PostMapping("/saveChatLog")
-    public R<Map<String, Object>> saveChatLog(
-            @RequestParam String queryText,
-            @RequestParam String responseText,
-            @RequestParam Integer clientUserId,
-            @RequestParam Integer sceneId) {
-        log.info("LawyerAiInteractionLogController.sendAIMessage?queryText={},responseText={},clientUserId={},sceneId{}", queryText, responseText, clientUserId, sceneId);
-        return aiInteractionLogService.saveChatLog(queryText, responseText, clientUserId, sceneId);
+    public R<Map<String, Object>> saveChatLog(@RequestBody LawyerAiInteractionLog aiInteractionLog) {
+        log.info("LawyerAiInteractionLogController.saveChatLog?aiInteractionLog={}", aiInteractionLog);
+        return aiInteractionLogService.saveChatLog(aiInteractionLog);
     }
 
     @ApiOperation("删除聊天记录")

+ 15 - 12
alien-store/src/main/java/shop/alien/store/controller/SystemController.java

@@ -53,17 +53,20 @@ public class SystemController {
         return R.success("退出成功");
     }
 
-    @ApiOperation("系统用户注册")
-    @ApiOperationSupport(order = 3)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "userName", value = "用户名", dataType = "String", paramType = "body", required = true),
-            @ApiImplicitParam(name = "password", value = "密码", dataType = "String", paramType = "body", required = true),
-            @ApiImplicitParam(name = "roleId", value = "角色id", dataType = "String", paramType = "body", required = false),
-    })
-    @PostMapping(value = "/register")
-    public R<LifeSys> register(@RequestBody SystemRegisterDto registerDto) {
-        log.info("SystemController.register?userName={},roleId={}", registerDto.getUserName(), registerDto.getRoleId());
-        return systemService.register(registerDto.getUserName(), registerDto.getPassword(), registerDto.getRoleId());
-    }
+/**
+ * 废弃
+  */
+//    @ApiOperation("系统用户注册")
+//    @ApiOperationSupport(order = 3)
+//    @ApiImplicitParams({
+//            @ApiImplicitParam(name = "userName", value = "用户名", dataType = "String", paramType = "body", required = true),
+//            @ApiImplicitParam(name = "password", value = "密码", dataType = "String", paramType = "body", required = true),
+//            @ApiImplicitParam(name = "roleId", value = "角色id", dataType = "String", paramType = "body", required = false),
+//    })
+//    @PostMapping(value = "/register")
+//    public R<LifeSys> register(@RequestBody SystemRegisterDto registerDto) {
+//        log.info("SystemController.register?userName={},roleId={}", registerDto.getUserName(), registerDto.getRoleId());
+//        return systemService.register(registerDto.getUserName(), registerDto.getPassword(), registerDto.getRoleId());
+//    }
 
 }

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/LawyerAiInteractionLogService.java

@@ -79,7 +79,7 @@ public interface LawyerAiInteractionLogService extends IService<LawyerAiInteract
      * @param clientUserId 客户端用户ID
      * @return R<Map<String, Object>>
      */
-    R<Map<String, Object>> saveChatLog(String queryText, String responseText, Integer clientUserId , Integer sceneId);
+    R<Map<String, Object>> saveChatLog(LawyerAiInteractionLog aiInteractionLog);
 
     R<Map<String, Object>> updatedLog(Integer id);
 

+ 17 - 0
alien-store/src/main/java/shop/alien/store/service/StoreAliPayRefundLogService.java

@@ -0,0 +1,17 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.StoreAliPayRefundLog;
+
+/**
+ * <p>
+ * 支付宝退款记录表 服务类
+ * </p>
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface StoreAliPayRefundLogService extends IService<StoreAliPayRefundLog> {
+
+}
+

+ 6 - 6
alien-store/src/main/java/shop/alien/store/service/impl/LawyerAiInteractionLogServiceImpl.java

@@ -125,8 +125,8 @@ public class LawyerAiInteractionLogServiceImpl extends ServiceImpl<LawyerAiInter
     }
 
     @Override
-    public R<Map<String, Object>> saveChatLog(String queryText, String responseText, Integer clientUserId ,Integer sceneId) {
-        log.info("LawyerAiInteractionLogServiceImpl.sendAIMessage?message={},responseText={},clientUserId={}", queryText, responseText, clientUserId);
+    public R<Map<String, Object>> saveChatLog(LawyerAiInteractionLog aiInteractionLog) {
+        log.info("LawyerAiInteractionLogController.saveChatLog?aiInteractionLog={}", aiInteractionLog);
         Map<String, Object> result = new HashMap<>();
 //        LawyerAiInteractionLogVo log = new LawyerAiInteractionLogVo();
 //        log.setClientUserId(clientUserId);
@@ -138,12 +138,12 @@ public class LawyerAiInteractionLogServiceImpl extends ServiceImpl<LawyerAiInter
 //        log.setUpdatedTime(new Date());
 //        int num =aiInteractionLogMapper.insertLog(log);
         LawyerAiInteractionLog log = new LawyerAiInteractionLog();
-        log.setClientUserId(clientUserId);
-        log.setQueryText(queryText);
-        log.setResponseText(responseText);
+        log.setClientUserId(aiInteractionLog.getClientUserId());
+        log.setQueryText(aiInteractionLog.getQueryText());
+        log.setResponseText(aiInteractionLog.getResponseText());
         log.setInteractionTime(new Date());
         log.setDeleteFlag(0);
-        log.setSceneId(sceneId);
+        log.setSceneId(aiInteractionLog.getSceneId());
         log.setCreatedTime(new Date());
         log.setUpdatedTime(new Date());
         //向表中插入一条新的数据,插入成功后获取插入该条数据的id

+ 7 - 4
alien-store/src/main/java/shop/alien/store/service/impl/LawyerConsultationOrderServiceImpl.java

@@ -460,12 +460,15 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
         order.setOrderNumber(orderNumber);
         log.info("生成订单编号:orderNumber={}", orderNumber);
 
-        // 计算本单收益(咨询费用
+        // 计算本单收益(平台收益
         Integer consultationFee = calculateConsultationFee(lawyerUserId, orderAmount);
         order.setConsultationFee(consultationFee);
         log.info("计算咨询费用:lawyerUserId={}, orderAmount={}, consultationFee={}", 
                 lawyerUserId, orderAmount, consultationFee);
 
+        // 计算律师收益(订单金额-平台收益)
+        Integer lawyerEarnings =  orderAmount - consultationFee;
+        order.setLawyerEarnings(lawyerEarnings);
         // 插入订单
         int insertCount = consultationOrderMapper.insertOrder(order);
         if (insertCount > 0) {
@@ -515,9 +518,9 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
             Integer firmId = lawyerUser.getFirmId();
             if (firmId != null && firmId > 0) {
                 LawFirm lawyerFirm = lawFirmMapper.selectById(firmId);
-                if (lawyerFirm != null && lawyerFirm.getPlatformCommissionRatio() != null 
-                        && lawyerFirm.getPlatformCommissionRatio() > 0) {
-                    commissionRate = lawyerFirm.getPlatformCommissionRatio();
+                if (lawyerFirm != null && lawyerFirm.getPlatformCommissionRatio() != null
+                        && lawyerFirm.getPlatformCommissionRatio().floatValue() > 0) {
+                    commissionRate = lawyerFirm.getPlatformCommissionRatio().floatValue();
                 }
             }
         }

+ 17 - 1
alien-store/src/main/java/shop/alien/store/service/impl/LawyerUserServiceImpl.java

@@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 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.LawyerLegalProblemScenario;
@@ -209,7 +210,22 @@ public class LawyerUserServiceImpl extends ServiceImpl<LawyerUserMapper, LawyerU
                 .eq("status", 1)
                 .select("lawyer_user_id");
         List<LawyerServiceArea> serviceAreas = lawyerServiceAreaService.list(areaQuery);
-        return serviceAreas.stream()
+
+        if (!CollectionUtils.isEmpty(serviceAreas)) {
+           return serviceAreas.stream()
+                    .map(LawyerServiceArea::getLawyerUserId)
+                    .filter(Objects::nonNull)
+                    .distinct()
+                    .collect(Collectors.toList());
+        }
+        QueryWrapper<LawyerServiceArea> areaQueryNew = new QueryWrapper<>();
+        areaQueryNew
+                .eq("delete_flag", 0)
+                .eq("status", 1)
+                .select("lawyer_user_id");
+        List<LawyerServiceArea> serviceAreasNew = lawyerServiceAreaService.list(areaQueryNew);
+
+        return serviceAreasNew.stream()
                 .map(LawyerServiceArea::getLawyerUserId)
                 .filter(Objects::nonNull)
                 .distinct()

+ 21 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreAliPayRefundLogServiceImpl.java

@@ -0,0 +1,21 @@
+package shop.alien.store.service.impl;
+
+import shop.alien.entity.store.StoreAliPayRefundLog;
+import shop.alien.mapper.StoreAliPayRefundLogMapper;
+import shop.alien.store.service.StoreAliPayRefundLogService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 支付宝退款记录表 服务实现类
+ * </p>
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Service
+public class StoreAliPayRefundLogServiceImpl extends ServiceImpl<StoreAliPayRefundLogMapper, StoreAliPayRefundLog> implements StoreAliPayRefundLogService {
+
+}
+

+ 54 - 9
alien-store/src/main/java/shop/alien/store/util/ali/AliApi.java

@@ -1,5 +1,7 @@
 package shop.alien.store.util.ali;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayClient;
@@ -17,16 +19,19 @@ import org.springframework.stereotype.Component;
 import shop.alien.entity.store.LifeUser;
 import shop.alien.entity.store.StoreAliPayErrorLog;
 import shop.alien.entity.store.StoreAliPayLog;
+import shop.alien.entity.store.StoreAliPayRefundLog;
 import shop.alien.entity.store.StoreUser;
 import shop.alien.store.service.LifeUserService;
 import shop.alien.store.service.StoreAliPayErrorLogService;
 import shop.alien.store.service.StoreAliPayLogService;
+import shop.alien.store.service.StoreAliPayRefundLogService;
 import shop.alien.store.service.StoreUserService;
 import shop.alien.util.common.RandomCreateUtil;
 import shop.alien.util.common.UniqueRandomNumGenerator;
 import shop.alien.util.common.UrlEncode;
 import shop.alien.util.system.OSUtil;
 
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
@@ -50,6 +55,8 @@ public class AliApi {
 
     private final StoreAliPayErrorLogService storeAliPayErrorLogService;
 
+    private final StoreAliPayRefundLogService storeAliPayRefundLogService;
+
     /**
      * 商家端appId
      */
@@ -195,15 +202,53 @@ public class AliApi {
             String refundReslut = "";
             if (response.isSuccess()) {
                 refundReslut = "调用成功";
-                // 保存退款信息进入到支付宝记录表
-                JSONObject jsonObject = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_fund_trans_uni_transfer_response");
-                StoreAliPayLog storeAliPayLog = new StoreAliPayLog();
-                storeAliPayLog.setTransAmount(refundAmount);
-                storeAliPayLog.setOutBizNo(jsonObject.getString("out_biz_no"));
-                storeAliPayLog.setOrderId(jsonObject.getString("order_id"));
-                storeAliPayLog.setPayFundOrderId(jsonObject.getString("pay_fund_order_id"));
-                storeAliPayLog.setTransDate(jsonObject.getString("trans_date"));
-                storeAliPayLogService.save(storeAliPayLog);
+                // 保存退款信息进入到退款记录表
+                JSONObject responseBody = JSONObject.parseObject(response.getBody());
+                JSONObject refundResponse = responseBody.getJSONObject("alipay_trade_refund_response");
+                
+                StoreAliPayRefundLog refundLog = new StoreAliPayRefundLog();
+                // 响应基本信息
+                refundLog.setResponseCode(refundResponse.getString("code"));
+                refundLog.setResponseMsg(refundResponse.getString("msg"));
+                // 买家信息
+                refundLog.setBuyerLogonId(refundResponse.getString("buyer_logon_id"));
+                refundLog.setBuyerOpenId(refundResponse.getString("buyer_open_id"));
+                // 资金变动信息
+                refundLog.setFundChange(refundResponse.getString("fund_change"));
+                // 订单信息
+                refundLog.setOutTradeNo(refundResponse.getString("out_trade_no"));
+                refundLog.setTradeNo(refundResponse.getString("trade_no"));
+                // 退款金额信息
+                refundLog.setRefundFee(refundResponse.getString("refund_fee"));
+                refundLog.setSendBackFee(refundResponse.getString("send_back_fee"));
+                // 退款渠道明细(转换为JSON字符串)
+                if (refundResponse.containsKey("refund_detail_item_list")) {
+                    JSONArray refundDetailList = refundResponse.getJSONArray("refund_detail_item_list");
+                    if (refundDetailList != null) {
+                        refundLog.setRefundDetailItemList(JSON.toJSONString(refundDetailList));
+                    }
+                }
+                // 退款时间(字符串转Date)
+                String gmtRefundPayStr = refundResponse.getString("gmt_refund_pay");
+                if (StringUtils.isNotBlank(gmtRefundPayStr)) {
+                    try {
+                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                        refundLog.setGmtRefundPay(sdf.parse(gmtRefundPayStr));
+                    } catch (ParseException e) {
+                        log.warn("解析退款时间失败: {}", gmtRefundPayStr, e);
+                    }
+                }
+                // 退款原因和部分退款编号(从请求参数中获取)
+                refundLog.setRefundReason(refundReason);
+                refundLog.setOutRequestNo(partialRefundCode);
+                // 证书和签名信息
+                refundLog.setAlipayCertSn(responseBody.getString("alipay_cert_sn"));
+                refundLog.setSign(responseBody.getString("sign"));
+                // 标准字段
+                refundLog.setDeleteFlag(0);
+                refundLog.setCreatedTime(new Date());
+                
+                storeAliPayRefundLogService.save(refundLog);
 
             } else {
                 log.warn("AliPayConfig.processRefund ERROR Msg={}", response.getBody());