Selaa lähdekoodia

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

# Conflicts:
#	alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserService.java
zjy 3 viikkoa sitten
vanhempi
commit
e5fa567532
53 muutettua tiedostoa jossa 1156 lisäystä ja 302 poistoa
  1. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/LifeMessage.java
  2. 63 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreCommentSummaryInterest.java
  3. 12 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeGroupBuyMainVo.java
  4. 13 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserOrderCommentVo.java
  5. 6 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserOrderVo.java
  6. 2 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserViolationVo.java
  7. 2 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoVo.java
  8. 2 2
      alien-entity/src/main/java/shop/alien/entity/store/vo/WebSocketVo.java
  9. 2 2
      alien-entity/src/main/java/shop/alien/mapper/LifeBrowseRecordMapper.java
  10. 2 2
      alien-entity/src/main/java/shop/alien/mapper/LifeCouponMapper.java
  11. 81 20
      alien-entity/src/main/java/shop/alien/mapper/LifeFansMapper.java
  12. 63 0
      alien-entity/src/main/java/shop/alien/mapper/LifeGroupBuyMainMapper.java
  13. 12 3
      alien-entity/src/main/java/shop/alien/mapper/LifeUserDynamicsMapper.java
  14. 4 3
      alien-entity/src/main/java/shop/alien/mapper/LifeUserOrderMapper.java
  15. 44 35
      alien-entity/src/main/java/shop/alien/mapper/LifeUserViolationMapper.java
  16. 13 0
      alien-entity/src/main/java/shop/alien/mapper/StoreCashOutRecordMapper.java
  17. 2 2
      alien-entity/src/main/java/shop/alien/mapper/StoreCommentMapper.java
  18. 40 0
      alien-entity/src/main/java/shop/alien/mapper/StoreCommentSummaryInterestMapper.java
  19. 7 0
      alien-entity/src/main/java/shop/alien/mapper/StoreInfoMapper.java
  20. 1 0
      alien-entity/src/main/resources/mapper/LifeUserDynamicsMapper.xml
  21. 6 4
      alien-entity/src/main/resources/mapper/LifeUserOrderMapper.xml
  22. 1 0
      alien-entity/src/main/resources/mapper/ManagementInfoMapper.xml
  23. 11 0
      alien-gateway/src/main/java/shop/alien/gateway/controller/LifeUserController.java
  24. 52 0
      alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserLogTransactionService.java
  25. 6 28
      alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserService.java
  26. 1 1
      alien-job/src/main/java/shop/alien/job/feign/AlienStoreFeign.java
  27. 106 0
      alien-job/src/main/java/shop/alien/job/store/AiTagJob.java
  28. 13 1
      alien-job/src/main/java/shop/alien/job/store/LifeUserOrderJob.java
  29. 18 0
      alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java
  30. 4 0
      alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java
  31. 95 0
      alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java
  32. 7 0
      alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java
  33. 64 38
      alien-store/src/main/java/shop/alien/store/controller/AliController.java
  34. 11 11
      alien-store/src/main/java/shop/alien/store/controller/LifeGroupPackageController.java
  35. 2 2
      alien-store/src/main/java/shop/alien/store/controller/LifeUserOrderController.java
  36. 9 10
      alien-store/src/main/java/shop/alien/store/controller/StoreIncomeDetailsRecordController.java
  37. 14 0
      alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java
  38. 10 3
      alien-store/src/main/java/shop/alien/store/controller/StoreUserController.java
  39. 28 11
      alien-store/src/main/java/shop/alien/store/service/LifeUserOrderService.java
  40. 9 1
      alien-store/src/main/java/shop/alien/store/service/StoreIncomeDetailsRecordService.java
  41. 3 2
      alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponServiceImpl.java
  42. 31 4
      alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponStoreFriendServiceImpl.java
  43. 10 13
      alien-store/src/main/java/shop/alien/store/service/impl/LifeUserViolationServiceImpl.java
  44. 1 1
      alien-store/src/main/java/shop/alien/store/service/impl/PlatformStoreCouponServiceImpl.java
  45. 10 8
      alien-store/src/main/java/shop/alien/store/service/impl/StoreCashOutRecordServiceImpl.java
  46. 46 0
      alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java
  47. 39 60
      alien-store/src/main/java/shop/alien/store/service/impl/StoreIncomeDetailsRecordServiceImpl.java
  48. 28 8
      alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java
  49. 2 3
      alien-store/src/main/java/shop/alien/store/service/impl/StoreMenuServiceImpl.java
  50. 2 3
      alien-store/src/main/java/shop/alien/store/service/impl/StoreUserServiceImpl.java
  51. 16 15
      alien-store/src/main/java/shop/alien/store/util/ali/AliApi.java
  52. 78 3
      alien-store/src/main/java/shop/alien/store/util/ali/AliSms.java
  53. 51 2
      alien-util/src/main/java/shop/alien/util/ali/AliOSSUtil.java

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

@@ -34,7 +34,7 @@ public class LifeMessage {
     @ApiModelProperty(value = "发送内容")
     private String content;
 
-    @ApiModelProperty(value = "消息类型  1-文本  2-图片 3-链接  4-二手交易创建/确认/拒绝/取消  5-二手交易签到提醒  6-二手交易已签到")
+    @ApiModelProperty(value = "消息类型  1-文本  2-图片 3-链接  4-二手交易创建/确认/拒绝/取消  5-二手交易签到提醒  6-二手交易已签到  7-消息内容不合规  8-律师消息  9-二手交易修改交易请求  10-二手交易提醒进入实时定位")
     private String type;
 
     private Date currentTime;

+ 63 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreCommentSummaryInterest.java

@@ -0,0 +1,63 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * AI服务 店铺推荐趣味信息表
+ */
+@Data
+@JsonInclude
+@TableName("store_comment_summary_interest")
+@ApiModel(value = "store_comment_summary_interest", description = "store_comment_summary_interest")
+public class StoreCommentSummaryInterest {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "店铺ID(新增字段)")
+    @TableField("store_id")
+    private Integer storeId;
+
+    @ApiModelProperty(value = "店铺名称(对应表格“店铺名称”)")
+    @TableField("store_name")
+    private String storeName;
+
+    @ApiModelProperty(value = "总结内容(对应表格“总结内容”,允许为空)")
+    @TableField("summary")
+    private String summary;
+
+    @ApiModelProperty(value = "任务唯一标识(如 UUID,新增字段)")
+    @TableField("task_id")
+    private String taskId;
+
+    @ApiModelProperty(value = "删除标识")
+    @TableLogic
+    @TableField("delete_flag")
+    private Integer  deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}

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

@@ -27,6 +27,18 @@ public class LifeGroupBuyMainVo extends LifeGroupBuyMain {
     @ApiModelProperty(value = "商家名称")
     private String storeName;
 
+    @ApiModelProperty(value = "商家评分")
+    private String scoreAvg;
+
+    @ApiModelProperty(value = "商家经营种类")
+    private String businessName;
+
+    @ApiModelProperty(value = "商家地址")
+    private String address;
+
+    @ApiModelProperty(value = "团购图片url")
+    private String imagePaths;
+
     @ApiModelProperty(value = "商家手机号")
     private String phone;
 

+ 13 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserOrderCommentVo.java

@@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import lombok.Data;
 import shop.alien.entity.store.LifeUserOrder;
 
+import java.util.Date;
+import java.util.List;
+
 @Data
 @JsonInclude
 public class LifeUserOrderCommentVo extends LifeUserOrder {
@@ -17,4 +20,14 @@ public class LifeUserOrderCommentVo extends LifeUserOrder {
     private String groupBuyType;
 
     private String storeType;
+
+    private String businessTypesName;
+
+    private String storeName;
+
+    private String score;
+
+    private Date commentDate;
+
+    private List<String> imgUrls;
 }

+ 6 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserOrderVo.java

@@ -193,4 +193,10 @@ public class LifeUserOrderVo {
     
     @ApiModelProperty(value = "订单状态值")
     private String orderStatusValue;
+
+    @ApiModelProperty(value = "图片id")
+    private String imgIds;
+
+    @ApiModelProperty(value = "图片地址列表")
+    private List<String> imgUrls;
 }

+ 2 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserViolationVo.java

@@ -27,4 +27,6 @@ public class LifeUserViolationVo extends LifeUserViolation {
     private String phone;
 
     private String nickName;
+
+    private String image;
 }

+ 2 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoVo.java

@@ -212,4 +212,6 @@ public class StoreInfoVo extends StoreInfo {
     @ApiModelProperty(value = "食品经营许可")
     private String foodLicenceImageUrl;
 
+    @ApiModelProperty(value = "动态数量")
+    private Integer dynamicsNum;
 }

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

@@ -17,7 +17,7 @@ public class WebSocketVo {
     @ApiModelProperty(value = "接收者id")
     private String receiverId;
 
-    @ApiModelProperty(value = "类别  message:消息  notice:公告  heartbeat:心跳  receipt:消息发送成功回调(用来记录消息id)")
+    @ApiModelProperty(value = "类别  message:消息  notice:公告  heartbeat:心跳  receipt:消息发送成功回调(用来记录消息id) position:二手交易实时定位")
     private String category;
 
     @ApiModelProperty(value = "公告类型  (0-系统通知和订单提醒之外的类型  1-系统通知 2-订单提醒)")
@@ -26,7 +26,7 @@ public class WebSocketVo {
     @ApiModelProperty(value = "是否已读  0:未读  1:已读")
     private Integer isRead;
 
-    @ApiModelProperty(value = "消息类型  1-文本  2-图片 3-链接分享  4-二手交易(确认/拒绝/取消)  5-二手交易签到提醒  6-二手交易已签到  7-消息内容不合规")
+    @ApiModelProperty(value = "消息类型  1-文本  2-图片 3-链接分享  4-二手交易(确认/拒绝/取消)  5-二手交易签到提醒  6-二手交易已签到  7-消息内容不合规  8-律师消息  9-二手交易修改交易请求  10-二手交易提醒进入实时定位")
     private String type;
 
     @ApiModelProperty(value = "消息内容")

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

@@ -12,7 +12,7 @@ import java.util.Map;
 public interface LifeBrowseRecordMapper extends BaseMapper<LifeBrowseRecord> {
 
     @Select("SELECT a.id,a.liulan_date liulanDate, b.store_type storeType, b.store_position storePosition, a.liulan_time liulanTime, " +
-            "c.img_url image, b.store_name storeName, b.store_address storeDetailAddress, b.id storeId, a.created_time, d.img_url entranceImage, dict.dict_detail storeTypeStr,b.score_avg scoreAvg,b.business_types_name businessTypesName " +
+            "c.img_url image, b.store_name storeName, b.store_address storeDetailAddress, b.id storeId, a.created_time, d.img_url entranceImage, dict.dict_detail storeTypeStr,ROUND(b.score_avg, 2) scoreAvg,b.business_types_name businessTypesName " +
             "FROM life_browse_record a " +
             "LEFT JOIN store_info b ON a.store_id = b.id " +
             "LEFT JOIN store_img c on b.id = c.store_id and c.img_type = 11 and c.delete_flag = 0 " +
@@ -20,7 +20,7 @@ public interface LifeBrowseRecordMapper extends BaseMapper<LifeBrowseRecord> {
             "left join store_dictionary dict on dict.type_name = 'storeType' and dict.dict_id = b.store_type and dict.delete_flag = 0 " +
             "WHERE a.user_id = #{userId} AND a.delete_flag = 0 AND b.delete_flag = 0 ORDER BY a.liulan_time desc")
     List<Map<String, Object>> getBrowseRecordByUserId(String userId);
-    @Select("select lbr.id,lgbm.group_name groupName,lgbm.id couponId,si.id storeId,original_price originalPrice,preferential_price preferentialPrice,lbr.liulan_date liulanDate,si.store_name storeName,si2.img_url\n" +
+    @Select("select lbr.id,lgbm.group_name groupName,lgbm.id couponId,si.id storeId,ROUND(b.score_avg, 2) scoreAvg, original_price originalPrice,preferential_price preferentialPrice,lbr.liulan_date liulanDate,si.store_name storeName,si2.img_url\n" +
             "from life_browse_record lbr \n" +
             "inner join life_group_buy_main lgbm on lgbm.id = lbr.coupon_id \n" +
             "and lgbm.delete_flag = 0 and lbr.delete_flag = 0\n" +

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

@@ -68,10 +68,10 @@ public interface LifeCouponMapper extends BaseMapper<LifeCoupon> {
 
     @Update(" UPDATE life_coupon\n" +
             "    SET \n" +
-            "        single_qty = single_qty - #{buyCount},\n" +
             "        status = CASE WHEN (single_qty - #{buyCount}) = 0 \n" +
             "                     THEN #{soldOutStatus} \n" +
-            "                     ELSE status END\n" +
+            "                     ELSE status END,\n" +
+            "        single_qty = single_qty - #{buyCount}\n" +
             "    WHERE \n" +
             "        id = #{couponId} \n" +
             "        AND single_qty >= #{buyCount}")

+ 81 - 20
alien-entity/src/main/java/shop/alien/mapper/LifeFansMapper.java

@@ -72,12 +72,12 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
             "        from life_fans " +
             "        where delete_flag = 0 and followed_id = #{fansId} " +
             "    ) " +
-            "    select info.id, info.store_name name, user.head_img image, concat('store_', user.phone) phoneId, info.store_blurb blurb, 1 blockedType,user.id blockedId" +
+            "    select user.id, user.nick_name name, user.head_img image, concat('store_', user.phone) phoneId, user.account_blurb blurb, 1 blockedType,user.id blockedId" +
             "    from follow foll " +
             "    join store_user user on foll.phone = user.phone " +
-            "    join store_info info on info.id = user.store_id " +
-            "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "    where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0 " +
+//            "    join store_info info on info.id = user.store_id " +
+//            "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
+            "    where foll.flag = 'store' and user.delete_flag = 0" +
             "    union " +
             "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId" +
             "    from follow foll " +
@@ -89,23 +89,84 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
             "${ew.customSqlSegment} ")
     IPage<LifeFansVo> getMyFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("blockerType") String blockerType, @Param("blockerId") String blockerId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
-    @Select("select foll.*, if(isnull(fans.id), 0, 1) isFollowThis, 1 as isFollowMe, count(fans2.id) fansNum, count(fans3.id) followNum from ( " +
-            "    with follow as ( " +
-            "    select substring_index(fans_id, '_', 1) as flag, substring_index(fans_id, '_', -1) as phone " +
-            "    from life_fans " +
-            "    where delete_flag = 0 and followed_id = #{fansId} " +
-            "    ) " +
-            "    select info.id, info.store_name name, user.head_img image, concat('store_', user.phone) phoneId, info.store_blurb blurb ,IFNULL(user.nick_name, user.name) username, user.account_blurb accountBlurb  " +
-            "    from follow foll " +
-            "    join store_user user on foll.phone = user.phone " +
-            "    join store_info info on info.id = user.store_id " +
-            "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "    where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0 " +
+//    @Select("select foll.*, if(isnull(fans.id), 0, 1) isFollowThis, 1 as isFollowMe, count(fans2.id) fansNum, count(fans3.id) followNum from ( " +
+//            "    with follow as ( " +
+//            "    select substring_index(fans_id, '_', 1) as flag, substring_index(fans_id, '_', -1) as phone " +
+//            "    from life_fans " +
+//            "    where delete_flag = 0 and followed_id = #{fansId} " +
+//            "    ) " +
+//            "    select info.id," +
+//            "    \"CASE \" +\n" +
+//            "        \"WHEN user.store_id IS NULL OR info.store_application_status = 0 THEN user.nick_name \" +\n" +
+//            "        \"ELSE info.store_name \" +\n" +
+//            "        \"END AS name, \" +\n" +
+//            "        \"CASE \" +\n" +
+//            "        \"WHEN user.store_id IS NULL OR info.store_application_status IN (0, 2) THEN user.account_blurb \" +\n" +
+//            "        \"ELSE info.store_blurb \" +\n" +
+//            "        \"END AS store_blurb, \" + " +
+//            "    user.head_img image, concat('store_', user.phone) phoneId" +
+//            "    from follow foll " +
+//            "    join store_user user on foll.phone = user.phone " +
+//            "    LEFT JOIN store_info info ON user.store_id IS NOT NULL AND info.id = user.store_id " +
+//            "    and info.delete_flag = 0" +
+//            "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
+//            "    where foll.flag = 'store' and user.delete_flag = 0 " +
+//            ") foll " +
+//            "left join life_fans fans on fans.followed_id = foll.phoneId and fans.fans_id = #{fansId} and fans.delete_flag = 0 " +
+//            "left join life_fans fans2 on fans2.followed_id = foll.phoneId and fans2.delete_flag = 0 " +
+//            "left join life_fans fans3 on fans3.fans_id = foll.phoneId and fans3.delete_flag = 0 " +
+//            "${ew.customSqlSegment} ")
+    @Select("SELECT " +
+            "foll.*, " +
+            "IF(isnull(fans.id), 0, 1) isFollowThis, " +
+            "1 AS isFollowMe, " +
+            "count(fans2.id) fansNum, " +
+            "count(fans3.id) followNum " +
+            "FROM " +
+            "( " +
+            "WITH follow AS ( " +
+            "SELECT " +
+            "substring_index(fans_id, '_', 1) AS flag, " +
+            "substring_index(fans_id, '_', -1) AS phone " +
+            "FROM " +
+            "life_fans " +
+            "WHERE " +
+            "delete_flag = 0 " +
+            "AND followed_id = #{fansId} " +
+            ") " +
+            "SELECT " +
+            "info.id, " +
+            "CASE " +
+            "WHEN user.store_id IS NULL OR info.store_application_status = 0 THEN user.nick_name " +
+            "ELSE info.store_name " +
+            "END AS name, " +
+            "CASE " +
+            "WHEN user.store_id IS NULL OR info.store_application_status IN (0, 2) THEN user.account_blurb " +
+            "ELSE info.store_blurb " +
+            "END AS blurb, " +
+            "user.head_img AS image, " +
+            "concat('store_', user.phone) AS phoneId " +
+            "FROM " +
+            "follow foll " +
+            "JOIN store_user user ON foll.phone = user.phone " +
+            "LEFT JOIN store_info info ON user.store_id IS NOT NULL " +
+            "AND info.id = user.store_id " +
+            "AND info.delete_flag = 0 " +
+            "LEFT JOIN store_img img ON img.store_id = user.store_id " +
+            "AND img.img_type = '10' " +
+            "AND img.delete_flag = 0 " +
+            "WHERE " +
+            "foll.flag = 'store' " +
+            "AND user.delete_flag = 0 " +
             ") foll " +
-            "left join life_fans fans on fans.followed_id = foll.phoneId and fans.fans_id = #{fansId} and fans.delete_flag = 0 " +
-            "left join life_fans fans2 on fans2.followed_id = foll.phoneId and fans2.delete_flag = 0 " +
-            "left join life_fans fans3 on fans3.fans_id = foll.phoneId and fans3.delete_flag = 0 " +
-            "${ew.customSqlSegment} ")
+            "LEFT JOIN life_fans fans ON fans.followed_id = foll.phoneId " +
+            "AND fans.fans_id = #{fansId} " +
+            "AND fans.delete_flag = 0 " +
+            "LEFT JOIN life_fans fans2 ON fans2.followed_id = foll.phoneId " +
+            "AND fans2.delete_flag = 0 " +
+            "LEFT JOIN life_fans fans3 ON fans3.fans_id = foll.phoneId " +
+            "AND fans3.delete_flag = 0 " +
+            "${ew.customSqlSegment}")
     IPage<LifeFansVo> getMyStoreFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
     @Select("select foll.*, if(isnull(fans.id), 0, 1) isFollowThis, 1 as isFollowMe, " +

+ 63 - 0
alien-entity/src/main/java/shop/alien/mapper/LifeGroupBuyMainMapper.java

@@ -1,5 +1,6 @@
 package shop.alien.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -8,10 +9,14 @@ 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 org.apache.poi.ss.formula.functions.T;
 import shop.alien.entity.store.LifeGroupBuyMain;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.store.vo.LifeGroupBuyMainVo;
 import shop.alien.entity.store.vo.LifeGroupBuyThaliVo;
 
+import java.util.List;
+
 /**
 * @author youch
 * @description 针对表【life_group_buy_main(团购主表)】的数据库操作Mapper
@@ -47,6 +52,64 @@ public interface LifeGroupBuyMainMapper extends BaseMapper<LifeGroupBuyMain> {
             @Param("buyCount") int buyCount,
             @Param("soldOutStatus") int soldOutStatus
     );
+
+    @Select("SELECT\n" +
+            "    g.id AS id,\n" +
+            "    g.group_no AS group_no,\n" +
+            "    g.group_type AS group_type,\n" +
+            "    g.status AS status,\n" +
+            "    g.approval_comments AS approval_comments,\n" +
+            "    g.store_id AS store_id,\n" +
+            "    g.image_id AS image_id,\n" +
+            "    g.group_name AS group_name,\n" +
+            "    g.start_time_type AS start_time_type,\n" +
+            "    g.start_time_value AS start_time_value,\n" +
+            "    g.end_time AS end_time,\n" +
+            "    g.inventory_num AS inventory_num,\n" +
+            "    g.quota_type AS quota_type,\n" +
+            "    g.quota_value AS quota_value,\n" +
+            "    g.original_price AS original_price,\n" +
+            "    g.preferential_price AS preferential_price,\n" +
+            "    g.effective_date_type AS effective_date_type,\n" +
+            "    g.effective_date_value AS effective_date_value,\n" +
+            "    g.disable_date_type AS disable_date_type,\n" +
+            "    g.disable_date_value AS disable_date_value,\n" +
+            "    g.write_off AS write_off,\n" +
+            "    g.reservation_rules AS reservation_rules,\n" +
+            "    g.use_rules AS use_rules,\n" +
+            "    g.applicable_num AS applicable_num,\n" +
+            "    g.other_rules AS other_rules,\n" +
+            "    g.invoice_type AS invoice_type,\n" +
+            "    g.invoice_describe AS invoice_describe,\n" +
+            "    g.insured_flag AS insured_flag,\n" +
+            "    g.insured_price AS insured_price,\n" +
+            "    g.coupon_id AS coupon_id,\n" +
+            "    g.delete_flag AS delete_flag,\n" +
+            "    g.created_time AS created_time,\n" +
+            "    g.updated_time AS updated_time,\n" +
+            "    g.created_user_id AS created_user_id,\n" +
+            "    g.updated_user_id AS updated_user_id,\n" +
+            "    s.store_name AS store_name,\n" +
+            "    s.store_address AS store_address,\n" +
+            "    s.store_tel AS store_tel,\n" +
+            "    ROUND(s.score_avg) AS scoreAvg,\n" +
+            "    s.business_types_name AS businessName,\n" +
+            "    s.query_address AS address,\n" +
+            "    IFNULL(GROUP_CONCAT(img.img_url SEPARATOR ','), '') AS imagePaths\n" +
+            "FROM\n" +
+            "    life_group_buy_main g\n" +
+            "LEFT JOIN store_info s \n" +
+            "    ON g.store_id = s.id \n" +
+            "    AND s.delete_flag = 0 \n" +
+            "    AND g.status = 5 \n" +
+            "LEFT JOIN store_img img \n" +
+            "    ON FIND_IN_SET(img.id, g.image_id) > 0 \n" +
+            "    AND img.delete_flag = 0\t\t \n" +
+            "WHERE\n" +
+            "    g.delete_flag = 0\n" +
+            "GROUP BY\n" +
+            "    g.id")
+    List<LifeGroupBuyMainVo> getLifeGroupInfo(@Param(Constants.WRAPPER) LambdaQueryWrapper<LifeGroupBuyMainVo> queryWrapper);
 }
 
 

+ 12 - 3
alien-entity/src/main/java/shop/alien/mapper/LifeUserDynamicsMapper.java

@@ -15,19 +15,28 @@ import java.util.List;
 public interface LifeUserDynamicsMapper extends BaseMapper<LifeUserDynamics> {
 
     @Select("select dyna1.* from (with dynamice as( " +
-            "select lud.id, lud.top_status, lud.top_time, lud.title, lud.phone_id phoneId, lud.context, lud.image_path, lud.address, lud.address_name, lud.address_context, lud.liulan_count, lud.dianzan_count, lud.type, lud.created_time, substring_index(lud.phone_id, '_', 1) flag, substring_index(lud.phone_id, '_', -1) phone, lud.draft , lud.address_province, lud.transfer_count from life_user_dynamics lud " +
+            "select lud.id, lud.top_status, lud.top_time, lud.title, lud.phone_id phoneId, " +
+            "lud.context, lud.image_path, lud.address, lud.address_name, lud.address_context, " +
+            "lud.liulan_count, lud.dianzan_count, lud.type, lud.created_time, substring_index(lud.phone_id, '_', 1) flag, " +
+            "substring_index(lud.phone_id, '_', -1) phone, lud.draft , lud.address_province, lud.transfer_count " +
+            "from life_user_dynamics lud " +
             "where lud.delete_flag = 0 and lud.enable_status = 0 and lud.draft = 0 and " +
-            "not exists (select 1 from life_user_violation luv where luv.delete_flag = 0 and luv.processing_status = 1 AND luv.dynamics_id = lud.id) order by lud.created_time desc) " +
+            "not exists (select 1 from life_user_violation luv where luv.delete_flag = 0 and luv.processing_status = 1 " +
+            "AND luv.dynamics_id = lud.id) order by lud.created_time desc) " +
             "select dynamice.*, info.store_name userName, user.head_img userImage, info.id storeUserId, user.id storeOrUserId, 0 isExpert " +
             "from dynamice " +
             "join store_user user on dynamice.phone = user.phone and user.delete_flag = 0 " +
+            "and user.status = 0 and user.logout_flag = 0 " +
             "join store_info info on info.id = user.store_id and info.delete_flag = 0 " +
+            "and info.store_status = 1 " +
             "left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0  " +
             "where dynamice.flag = 'store' " +
             "union " +
-            "select dynamice.*, user.user_name userName, user.user_image userImage, user.id storeUserId, user.id storeOrUserId, IF(lue.expert_code IS NOT NULL , 1, 0) AS isExpert " +
+            "select dynamice.*, user.user_name userName, user.user_image userImage, user.id storeUserId, user.id storeOrUserId, " +
+            "IF(lue.expert_code IS NOT NULL , 1, 0) AS isExpert " +
             "from dynamice " +
             "join life_user user on dynamice.phone = user.user_phone and user.delete_flag = 0 " +
+            "and user.logout_flag = 0 " +
             "left join life_user_expert  lue on lue.user_id = user.id and lue.delete_flag = 0 " +
             "where dynamice.flag = 'user') dyna1 order by dyna1.top_status desc, dyna1.top_time desc, created_time desc")
     List<LifeUserDynamicsVo> getLifeUserDynamicsList();

+ 4 - 3
alien-entity/src/main/java/shop/alien/mapper/LifeUserOrderMapper.java

@@ -1,7 +1,6 @@
 package shop.alien.mapper;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
@@ -39,7 +38,8 @@ public interface LifeUserOrderMapper extends BaseMapper<LifeUserOrder> {
             "from life_group_buy_main lgbm \n" +
             "\tunion all\n" +
             "-- 代金券\n" +
-            "\tselect id coupon_id,1 coupon_type,lc.name coupon_name, SUBSTRING_INDEX(image_path, ',', 1) AS image_id,0 effective_date_type,expiration_date effective_date_value \n" +
+            "\tselect id coupon_id,1 coupon_type,lc.name coupon_name, SUBSTRING_INDEX(image_path, ',', 1) AS image_id,\n" +
+            "case when expiration_type = 1 then 0 else 1 end effective_date_type,case when expiration_type = 1 then expiration_date else validity_period end  effective_date_value \n" +
             "from life_coupon lc \n" +
             ")\n" +
             "select luo.id,luo.buy_time,luo.status,luo.price,luo.final_price,luo.user_id,luo.store_id,luo.order_no,luo.pay_time,luo.cancel_time,luo.finish_time,luo.order_str,luo.expert_order_id,luo.order_appraise,\n" +
@@ -82,7 +82,8 @@ public interface LifeUserOrderMapper extends BaseMapper<LifeUserOrder> {
             "from life_group_buy_main lgbm \n" +
             "\tunion all\n" +
             "-- 代金券\n" +
-            "\tselect id coupon_id,1 coupon_type,lc.name coupon_name, SUBSTRING_INDEX(image_path, ',', 1) AS image_id,0 effective_date_type,expiration_date effective_date_value \n" +
+            "\tselect id coupon_id,1 coupon_type,lc.name coupon_name, SUBSTRING_INDEX(image_path, ',', 1) AS image_id,\n" +
+            "case when expiration_type = 1 then 0 else 1 end effective_date_type,case when expiration_type = 1 then expiration_date else validity_period end  effective_date_value \n" +
             "from life_coupon lc \n" +
             ")\n" +
             "select luo.id,luo.buy_time,luo.status,luo.price,luo.final_price,luo.user_id,luo.store_id,luo.order_no,luo.pay_time,luo.cancel_time,luo.finish_time,luo.order_str,luo.expert_order_id,luo.order_appraise,\n" +

+ 44 - 35
alien-entity/src/main/java/shop/alien/mapper/LifeUserViolationMapper.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.toolkit.Constants;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import shop.alien.entity.store.LifeUserViolation;
+import shop.alien.entity.store.dto.LifeUserViolationDto;
 import shop.alien.entity.store.vo.LifeUserViolationVo;
 
 import java.util.List;
@@ -20,53 +21,61 @@ import java.util.List;
  * @since 2025-04-29
  */
 public interface LifeUserViolationMapper extends BaseMapper<LifeUserViolation> {
-    
+
     /**
      * 分页查询用户举报信息
-     * 
-     * @param page 分页对象
+     *
+     * @param page         分页对象
      * @param queryWrapper 查询条件包装器
      * @return 分页结果
      */
     @Select("<script>" +
-            "WITH userInfo AS (" +
-            "    SELECT " +
-            "        su.phone, " +
-            "        su.id, " +
-            "        CASE su.delete_flag " +
-            "            WHEN 1 THEN CONCAT(su.nick_name, '(账号已注销)') " +
-            "            ELSE su.nick_name " +
-            "        END AS nick_name, " +
-            "        '1' AS type " +
-            "    FROM store_user su " +
-            "    UNION ALL " +
-            "    SELECT " +
-            "        lu.user_phone AS phone, " +
-            "        lu.id, " +
-            "        CASE lu.delete_flag " +
-            "            WHEN 1 THEN CONCAT(lu.user_name, '(账号已注销)') " +
-            "            ELSE lu.user_name " +
-            "        END AS nick_name, " +
-            "        '2' AS type " +
-            "    FROM life_user lu " +
-            ") " +
-            "SELECT " +
-            "    luv.*, " +
-            "    ui.nick_name AS nickname, " +
-            "    ui.phone " +
-            "FROM life_user_violation luv " +
-            "LEFT JOIN userInfo ui ON ui.type = luv.reporting_user_type " +
-            "    AND ui.id = luv.reporting_user_id " +
-            "    ${ew.customSqlSegment}" +
+            " WITH userInfo AS ( " +
+            " SELECT " +
+            " su.phone, " +
+            " su.id, " +
+            " CASE su.delete_flag " +
+            " WHEN 1 THEN CONCAT(su.nick_name, '(账号已注销)') " +
+            " ELSE su.nick_name " +
+            " END AS nick_name, " +
+            " '1' AS type " +
+            " FROM store_user su " +
+            " UNION ALL " +
+            " SELECT " +
+            " lu.user_phone AS phone, " +
+            " lu.id, " +
+            " CASE lu.delete_flag " +
+            " WHEN 1 THEN CONCAT(lu.user_name, '(账号已注销)') " +
+            " ELSE lu.user_name " +
+            " END AS nick_name, " +
+            " '2' AS type " +
+            " FROM life_user lu " +
+            " ) " +
+            " SELECT " +
+            " luv.*, " +
+            " ui.nick_name AS nickname, " +
+            " ui.phone, " +
+            " img.img_url image" +
+            " FROM life_user_violation luv " +
+            " LEFT JOIN userInfo ui ON ui.type = luv.reporting_user_type " +
+            " AND ui.id = luv.reporting_user_id " +
+            " left join store_img img on luv.id = img.store_id and img.delete_flag = 0 " +
+            " ${ew.customSqlSegment}" +
             "</script>")
     IPage<LifeUserViolationVo> getViolationPage(
-            IPage<LifeUserViolationVo> page, 
+            IPage<LifeUserViolationVo> page,
             @Param(Constants.WRAPPER) QueryWrapper<LifeUserViolationVo> queryWrapper
     );
-    
+
+    @Select("select luv.*, img.img_url image " +
+            "FROM life_user_violation luv " +
+            "left join store_img img on luv.id = img.store_id and img.delete_flag = 0 " +
+            "${ew.customSqlSegment}")
+    LifeUserViolationDto getDetailById(@Param(Constants.WRAPPER) QueryWrapper<LifeUserViolationDto> queryWrapper);
+
     /**
      * 查询用户举报信息列表
-     * 
+     *
      * @param queryWrapper 查询条件包装器
      * @return 举报信息列表
      */

+ 13 - 0
alien-entity/src/main/java/shop/alien/mapper/StoreCashOutRecordMapper.java

@@ -1,14 +1,27 @@
 package shop.alien.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import shop.alien.entity.store.StoreCashOutRecord;
 
+import java.util.List;
+
 /**
  * 商户提现记录表 Mapper 接口
  *
  * @author ssk
  * @since 2025-02-25
  */
+@Mapper
 public interface StoreCashOutRecordMapper extends BaseMapper<StoreCashOutRecord> {
 
+    @Select("select scor.*, If(su.alipay_account is not null,su.alipay_account,su.phone) settlementAccount\n" +
+            "from store_cash_out_record scor\n" +
+            "left join store_user su on su.store_id = scor.store_id and su.delete_flag = 0\n" +
+            "${ew.customSqlSegment}")
+    List<StoreCashOutRecord> selectCashoutRecordList(@Param(Constants.WRAPPER) QueryWrapper<StoreCashOutRecord> wrapper);
 }

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

@@ -167,7 +167,7 @@ WHERE
 		AND delete_flag = 0)
  */
     @Select("SELECT " +
-            "luo.*,lgbm.group_type groupBuyType,lgbm.group_name groupBuyName,lgbm.image_id groupBuyImgId,store.business_section storeType " +
+            "luo.*,lgbm.group_type groupBuyType,lgbm.group_name groupBuyName,lgbm.image_id groupBuyImgId,store.business_section storeType, store.business_types_name businessTypesName, store.store_name storeName " +
             "FROM life_user_order luo LEFT JOIN order_coupon_middle ocm ON luo.id = ocm.order_id LEFT JOIN life_group_buy_main lgbm ON ocm.coupon_id = lgbm.id LEFT JOIN store_info store on luo.store_id = store.id " +
             "WHERE luo.`status` in (2,7) " +
             "AND luo.coupon_type = 2 " +
@@ -177,7 +177,7 @@ WHERE
     IPage<LifeUserOrderCommentVo> getCommentOrderWPJPage(IPage<LifeUserOrderCommentVo> page, @Param("userId") String userId);
 
     @Select("SELECT " +
-            "luo.*,lgbm.group_type groupBuyType,lgbm.group_name groupBuyName,lgbm.image_id groupBuyImgId,store.business_section storeType " +
+            "luo.*,lgbm.group_type groupBuyType,lgbm.group_name groupBuyName,lgbm.image_id groupBuyImgId,store.business_section storeType, store.business_types_name businessTypesName, store.store_name storeName " +
             "FROM life_user_order luo LEFT JOIN order_coupon_middle ocm ON luo.id = ocm.order_id LEFT JOIN life_group_buy_main lgbm ON ocm.coupon_id = lgbm.id LEFT JOIN store_info store on luo.store_id = store.id " +
             "WHERE luo.`status` in (2,7) " +
             "AND luo.coupon_type = 2 " +

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

@@ -0,0 +1,40 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.StoreCommentSummaryInterest;
+
+import java.util.List;
+
+/**
+ * qxy
+ * AI 服务 店铺趣味信息
+ */
+@Mapper
+public interface StoreCommentSummaryInterestMapper extends BaseMapper<StoreCommentSummaryInterest> {
+    @Insert({
+            "<script>", // 开启动态 SQL 脚本
+            "INSERT INTO store_comment_summary_interest (",
+            "  id, store_id, store_name, summary, task_id, delete_flag, created_time, created_user_id,",
+            "  updated_time, updated_user_id",
+            ")",
+            "VALUES",
+            "<foreach collection='list' item='item' separator=','>",
+            "(",
+            "  #{item.id},",
+            "  #{item.storeId},",
+            "  #{item.storeName},",
+            "  #{item.summary},",
+            "  #{item.taskId},",
+            "  #{item.deleteFlag},",
+            "  #{item.createdTime},",
+            "  #{item.createdUserId},",
+            "  #{item.updatedTime},",
+            "  #{item.updatedUserId}",
+            ")",
+            "</foreach>",
+            "</script>" // 关闭动态 SQL 脚本
+    })
+    int insertBatchStoreCommentSummaryInterest(List<StoreCommentSummaryInterest> storeCommentSummaryInterests);
+}

+ 7 - 0
alien-entity/src/main/java/shop/alien/mapper/StoreInfoMapper.java

@@ -123,4 +123,11 @@ public interface StoreInfoMapper extends BaseMapper<StoreInfo> {
     @Select("SELECT a.* FROM store_info a " +
             "left join store_user b on a.id =b.store_id  where b.phone = #{phoneIdNew} limit 1")
     StoreMainInfoVo getStoreNameByPhone(String phoneIdNew);
+
+    @Select(
+            "select " +
+            "            ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(', REPLACE(#{position}, ',', ' '), ')' )), ST_GeomFromText(CONCAT('POINT(', REPLACE(store_position, ',', ' '), ')' ))) / 1000, 1) dist " +
+            "from store_info where id = #{storeId}"
+            )
+    Double getStoreDistance(@Param("position") String position,@Param("storeId") Integer storeId);
 }

+ 1 - 0
alien-entity/src/main/resources/mapper/LifeUserDynamicsMapper.xml

@@ -116,6 +116,7 @@
         user.nick_name userName,
         user.head_img userImage,
         info.id storeUserId,
+        info.store_name storeName,
         user.id storeOrUserId,
         0 isExpert,
         IF(llr.huifu_id IS NOT NULL or llr1.huifu_id IS NOT NULL, 1, 0) AS isLike

+ 6 - 4
alien-entity/src/main/resources/mapper/LifeUserOrderMapper.xml

@@ -57,6 +57,8 @@
         <result column="order_str" property="orderStr"/>
         <result column="expert_order_id" property="expertOrderId"/>
         <result column="order_appraise" property="orderAppraise"/>
+        <result column="user_id" property="userId"/>
+        <result column="imgIds" property="imgIds"/>
 
         <collection property="orderCouponMiddleList" ofType="shop.alien.entity.store.vo.OrderCouponMiddleVo">
             <id column="ocmId" property="id" />
@@ -73,12 +75,12 @@
     <!-- 查询用户订单详情 -->
     <select id="queryUserOrderDetail" resultMap="BaseResultMap">
         with total_coupon as(
-        select id coupon_id,2 coupon_type,lgbm.group_name coupon_name,preferential_price offprice,original_price, SUBSTRING_INDEX(image_id, ',', 1) AS image_id,
+        select id coupon_id,2 coupon_type,lgbm.group_name coupon_name,preferential_price offprice,original_price, SUBSTRING_INDEX(image_id, ',', 1) AS image_id, image_id AS imgIds,
                effective_date_type,effective_date_value,use_rules,reservation_rules,applicable_num,quota_type,quota_value,inventory_num single_qty
         from life_group_buy_main lgbm where lgbm.delete_flag = 0
         union all
-        select id coupon_id,1 coupon_type,lc.name coupon_name,lc.offprice offprice,price original_price,SUBSTRING_INDEX(image_path, ',', 1) AS image_id,
-               0 effective_date_type,expiration_date effective_date_value,use_rule use_rules,reservation_rules,applicable_num,1 quota_type,buy_limit quota_value,single_qty
+        select id coupon_id,1 coupon_type,lc.name coupon_name,lc.offprice offprice,price original_price,SUBSTRING_INDEX(image_path, ',', 1) AS image_id, image_path AS imgIds,
+        case when expiration_type = 1 then 0 else 1 end effective_date_type, case when expiration_type = 1 then expiration_date else validity_period end  effective_date_value,use_rule use_rules,reservation_rules,applicable_num,1 quota_type,buy_limit quota_value,single_qty
         from life_coupon lc where lc.delete_flag = 0
         )
         select luo.id,luo.order_no,luo.created_time , luo.price ,
@@ -134,7 +136,7 @@
         from life_group_buy_main lgbm where lgbm.delete_flag = 0
         union all
         select id coupon_id,1 coupon_type,lc.name coupon_name,lc.offprice offprice,SUBSTRING_INDEX(image_path, ',', 1) AS image_id,
-        0 effective_date_type,expiration_date effective_date_value,use_rule use_rules,reservation_rules,applicable_num,1 quota_type,buy_limit quota_value,single_qty,end_date
+        case when expiration_type = 1 then 0 else 1 end effective_date_type,case when expiration_type = 1 then expiration_date else validity_period end  effective_date_value,use_rule use_rules,reservation_rules,applicable_num,1 quota_type,buy_limit quota_value,single_qty,end_date
         from life_coupon lc where lc.delete_flag = 0
         )
         select luo.id,luo.order_no,luo.created_time , luo.price ,luo.final_price

+ 1 - 0
alien-entity/src/main/resources/mapper/ManagementInfoMapper.xml

@@ -253,6 +253,7 @@
         <if test="storeName != null and storeName != ''">
             AND store.store_name LIKE CONCAT('%', #{storeName}, '%')
         </if>
+        ORDER BY cash.created_time DESC
     </select>
 
     <select id="getCashOutDetail" resultType="shop.alien.entity.store.vo.ManagementInfoVo">

+ 11 - 0
alien-gateway/src/main/java/shop/alien/gateway/controller/LifeUserController.java

@@ -3,10 +3,12 @@ package shop.alien.gateway.controller;
 import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.vo.LifeUserVo;
 import shop.alien.gateway.config.BaseRedisService;
+import shop.alien.gateway.service.ActivityInviteConfigService;
 import shop.alien.gateway.service.LifeUserService;
 
 /**
@@ -24,6 +26,8 @@ public class LifeUserController {
 
     private final BaseRedisService baseRedisService;
 
+    private final ActivityInviteConfigService activityInviteConfigService;
+
     @ApiOperation("用户登录")
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({
@@ -50,6 +54,13 @@ public class LifeUserController {
         if (null == userVo) {
             return R.fail("登录失败");
         }
+
+        if(StringUtils.isNotBlank(inviteCode)){
+           String bindResult =  activityInviteConfigService.bindInviteCode(userVo.getId(), inviteCode);
+           if(StringUtils.isNotBlank(bindResult) && !bindResult.equals("绑定成功")){
+               return R.fail(bindResult);
+           }
+        }
         return R.data(userVo);
     }
 

+ 52 - 0
alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserLogTransactionService.java

@@ -0,0 +1,52 @@
+package shop.alien.gateway.service;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import shop.alien.entity.second.LifeUserLog;
+import shop.alien.gateway.mapper.LifeUserLogGatewayMapper;
+
+import java.util.List;
+
+/**
+ * 用户登录日志事务处理服务
+ * 独立的事务服务类,用于处理需要新事务的数据库操作
+ * 解决同类方法调用时 Spring AOP 代理不生效的问题
+ *
+ * @author alien-cloud
+ * @since 2024-01-01
+ */
+@Service
+@RequiredArgsConstructor
+public class LifeUserLogTransactionService {
+
+    private final LifeUserLogGatewayMapper lifeUserLogMapper;
+
+    /**
+     * 在新事务中插入用户登录日志
+     * 使用 REQUIRES_NEW 确保插入操作立即提交,便于后续查询
+     *
+     * @param lifeUserLog 用户登录日志对象
+     * @return int 插入成功的记录数
+     */
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public int insertLifeUserLog(LifeUserLog lifeUserLog) {
+        return lifeUserLogMapper.insert(lifeUserLog);
+    }
+
+    /**
+     * 在新事务中查询指定时间段内的用户登录日志
+     * 使用 REQUIRES_NEW 确保能读取到已提交的最新数据
+     *
+     * @param startDate 开始时间
+     * @param endDate 结束时间
+     * @param macIp MAC地址/IP
+     * @return List<LifeUserLog> 用户登录日志列表
+     */
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    public List<LifeUserLog> getLifeUserLogByDate(String startDate, String endDate, String macIp) {
+        return lifeUserLogMapper.getLifeUserLogByDate(startDate, endDate, macIp);
+    }
+}
+

+ 6 - 28
alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserService.java

@@ -47,6 +47,8 @@ public class LifeUserService extends ServiceImpl<LifeUserGatewayMapper, LifeUser
 
     private final SecondRiskControlRecordMapper secondRiskControlRecordMapper;
 
+    private final LifeUserLogTransactionService lifeUserLogTransactionService;
+
     @Autowired
     private RiskControlProperties riskControlProperties;
 
@@ -75,11 +77,6 @@ public class LifeUserService extends ServiceImpl<LifeUserGatewayMapper, LifeUser
                 String token = getToken(phoneNum, userVo.getUserName(), tokenMap);
                 userVo.setToken(token);
                 baseRedisService.setString("user_" + phoneNum, token);
-                // 生成邀请记录
-                if (StringUtils.isNotEmpty(inviteCode)) {
-                    activityInviteConfigService.bindInviteCode(lifeUser.getId(), inviteCode);
-                }
-
                 // 二手平台登录log,同一个macip登录多账号记录
                 addLifeUserLogInfo(user2, macIp);
 
@@ -98,11 +95,6 @@ public class LifeUserService extends ServiceImpl<LifeUserGatewayMapper, LifeUser
             String token = getToken(phoneNum, user.getUserName(), tokenMap);
             userVo.setToken(token);
             baseRedisService.setString("user_" + phoneNum, token);
-            if (StringUtils.isNotEmpty(inviteCode)) {
-                // 生成邀请记录
-                activityInviteConfigService.bindInviteCode(user.getId(), inviteCode);
-            }
-
             // 二手平台登录log,同一个macip登录多账号记录
             addLifeUserLogInfo(user, macIp);
 
@@ -155,13 +147,13 @@ public class LifeUserService extends ServiceImpl<LifeUserGatewayMapper, LifeUser
             lifeUserLog.setUserName(user.getUserName());
             lifeUserLog.setMacIp(macIp);
             lifeUserLog.setCreatedTime(new Date());
-            // 将插入操作放到新事务中,确保立即提交
-            int count = lifeUserLogMapper.insert(lifeUserLog);
+            // 通过独立服务类调用,确保事务代理生效,插入操作立即提交
+            int count = lifeUserLogTransactionService.insertLifeUserLog(lifeUserLog);
             if (count > 0) {
                 String startDate = LocalDateTime.now().minusHours(24L).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                 String endDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                // 使用一个新的事务来查询,此时能看到刚才插入的数据
-                List<LifeUserLog> lsit = getLifeUserLogByDateInNewTransaction(startDate, endDate, macIp);
+                // 通过独立服务类查询,确保能看到刚才插入并提交的数据
+                List<LifeUserLog> lsit = lifeUserLogTransactionService.getLifeUserLogByDate(startDate, endDate, macIp);
 
                 if (lsit.size() > riskControlProperties.getAccountAbnormal().getRegCount24h() && !isViolation(startDate, endDate, macIp, user.getId())) {
                     String detailInfo = lsit.stream()
@@ -179,20 +171,6 @@ public class LifeUserService extends ServiceImpl<LifeUserGatewayMapper, LifeUser
     }
 
     /**
-     * 在新事务中查询指定时间段内的用户登录日志
-     * 使用 REQUIRES_NEW 确保能读取到已提交的最新数据
-     *
-     * @param startDate 开始时间
-     * @param endDate 结束时间
-     * @param macIp MAC地址/IP
-     * @return List<LifeUserLog> 用户登录日志列表
-     */
-    @Transactional(propagation = Propagation.REQUIRES_NEW)
-    public List<LifeUserLog> getLifeUserLogByDateInNewTransaction(String startDate, String endDate, String macIp) {
-        return lifeUserLogMapper.getLifeUserLogByDate(startDate, endDate, macIp);
-    }
-
-    /**
      * 判断是否已存在违规记录
      * 检查指定时间段内是否已经记录过该用户的风控信息
      *

+ 1 - 1
alien-job/src/main/java/shop/alien/job/feign/AlienStoreFeign.java

@@ -50,7 +50,7 @@ public interface AlienStoreFeign {
      * @param refundReason 退款原因
      * @return
      */
-    @GetMapping("/processRefund")
+    @GetMapping("/ali/processRefund")
     public String processRefund(@RequestParam(value = "outTradeNo") String outTradeNo,
                                    @RequestParam(value = "refundAmount") String refundAmount,
                                    @RequestParam(value = "refundReason") String refundReason,

+ 106 - 0
alien-job/src/main/java/shop/alien/job/store/AiTagJob.java

@@ -15,8 +15,10 @@ import org.springframework.util.MultiValueMap;
 import org.springframework.web.client.RestTemplate;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.StoreCommentSummary;
+import shop.alien.entity.store.StoreCommentSummaryInterest;
 import shop.alien.entity.store.TagsMain;
 import shop.alien.entity.store.TagsSynonym;
+import shop.alien.mapper.StoreCommentSummaryInterestMapper;
 import shop.alien.mapper.StoreCommentSummaryMapper;
 import shop.alien.mapper.TagsMainMapper;
 import shop.alien.mapper.TagsSynonymMapper;
@@ -45,6 +47,8 @@ public class AiTagJob {
 
     private final StoreCommentSummaryMapper storeCommentSummaryMapper;
 
+    private final StoreCommentSummaryInterestMapper storeCommentSummaryInterestMapper;
+
     // 第三方接口地址 获取所有标签主表信息
     @Value("${third-party-tag.base-url}")
     private String tagMainUrl;
@@ -57,6 +61,10 @@ public class AiTagJob {
     @Value("${third-party-summary.base-url}")
     private String allSummaryUrl;
 
+    // 第三方接口地址 获取店铺趣味信息
+    @Value("${third-party-interest.base-url}")
+    private String allInterestUrl;
+
     // 第三方接口地址 登录接口URL
     @Value("${third-party-login.base-url}")
     private String loginUrl;
@@ -461,6 +469,104 @@ public class AiTagJob {
         return R.success("任务执行失败 状态码" + responseEntity.getStatusCodeValue());
     }
 
+    /**
+     * 拉取Ai服务获取趣味推荐信息表数据
+     */
+    @XxlJob("getStoreCommentSummaryInterestTask")
+    public R<String> getStoreCommentSummaryInterestTask() {
+        log.info("登录Ai服务获取token..." + loginUrl);
+        //构建请求参数
+        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+        formData.add("username", userName);    // 表单字段 1:用户名
+        formData.add("password", passWord);    // 表单字段 2:密码
+
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+        ResponseEntity<String> postForEntity = null;
+        try {
+            postForEntity = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
+        } catch (Exception e) {
+            log.error("类:PostMethod 方法:post", e);
+        }
+
+        if (postForEntity != null) {
+            if (postForEntity.getStatusCodeValue() == 200) {
+                log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+                String responseBody = postForEntity.getBody();
+                JSONObject jsonObject = JSONObject.parseObject(responseBody);
+                JSONObject dataJson = jsonObject.getJSONObject("data");
+                String accessToken = dataJson.getString("access_token");
+                //调用 获取AI服务 获取趣味推荐信息表 get请求
+                getStoreCommentSummaryInterestInfo(accessToken);
+                return R.success("任务执行成功");
+            } else {
+                log.error("请求AI服务 登录接口失败 http状态:" + postForEntity.getStatusCode());
+                return R.fail("请求AI服务 登录接口失败 http状态:" + postForEntity.getStatusCode());
+            }
+        }
+        XxlJobHelper.handleFail("登录任务执行失败 返回异常");
+        return R.fail("登录任务执行失败 返回异常");
+    }
+
+    public R<String> getStoreCommentSummaryInterestInfo(String token) {
+        log.info("开始从Ai服务获取数据 获取趣味推荐信息表...");
+        log.info("restTemplate:" + restTemplate + "url:" + allInterestUrl);
+        // 1. 构建请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Authorization", "Bearer " + token); // Token 认证
+        headers.set("accept", "*/*");
+        headers.set("connection", "Keep-Alive");
+        headers.set("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+        // 2. 构建请求实体(仅包含头信息,GET 请求通常无请求体)
+        HttpEntity<?> requestEntity = new HttpEntity<>(headers);
+
+        // 发送 GET 请求,响应体为 String 类型
+        ResponseEntity<String> responseEntity = restTemplate.exchange(
+                allInterestUrl,
+                HttpMethod.GET,  // 指定请求方法为 GET
+                requestEntity,
+                String.class     // 响应体类型
+        );
+
+        // 解析响应
+        if (responseEntity.getStatusCodeValue() == 200) {
+            String responseBody = responseEntity.getBody();
+            JSONObject jsonObject = JSONObject.parseObject(responseBody);
+            Integer code = jsonObject.getInteger("code");
+            String message = jsonObject.getString("message");
+            JSONArray dataArray = jsonObject.getJSONArray("data");
+            List<StoreCommentSummaryInterest> storeCommentSummaryInterests = new ArrayList<>();
+            for (int i = 0; i < dataArray.size(); i++) {
+                JSONObject tagObj = dataArray.getJSONObject(i);
+                StoreCommentSummaryInterest summary = new StoreCommentSummaryInterest();
+                summary.setId(tagObj.getInteger("id"));
+                summary.setStoreId(tagObj.getInteger("store_id"));
+                summary.setStoreName(tagObj.getString("store_name"));
+                summary.setSummary(tagObj.getString("summary"));
+                summary.setTaskId(tagObj.getString("task_id"));
+                summary.setDeleteFlag(tagObj.getInteger("delete_flag"));
+                summary.setCreatedTime(tagObj.getDate("created_time"));
+                summary.setCreatedUserId(tagObj.getInteger("created_user_id"));
+                summary.setUpdatedTime(tagObj.getDate("updated_time"));
+                summary.setUpdatedUserId(tagObj.getInteger("updated_user_id"));
+                storeCommentSummaryInterests.add(summary);
+            }
+            if (!CollectionUtils.isEmpty(storeCommentSummaryInterests)) {
+                int num = storeCommentSummaryInterestMapper.insertBatchStoreCommentSummaryInterest(storeCommentSummaryInterests);
+                XxlJobHelper.handleSuccess("拉取子标签数据成功 执行" + num + "条");
+                return R.success("拉取子标签数据成功 执行" + num + "条");
+            } else {
+                XxlJobHelper.handleSuccess("获取回显数据为空" + "状态码:" + responseEntity.getStatusCodeValue());
+                return R.success("请求成功 获取回显数据为空" + "状态码:" + responseEntity.getStatusCodeValue());
+            }
+        }
+        log.info("AI服务 获取趣味推荐信息数据请求失败,状态码:" + responseEntity.getStatusCodeValue());
+        XxlJobHelper.handleFail("任务执行失败 状态码" + responseEntity.getStatusCodeValue());
+        return R.success("任务执行失败 状态码" + responseEntity.getStatusCodeValue());
+    }
+
     class AnalysisRequest {
         private String start_time;
         private String end_time;

+ 13 - 1
alien-job/src/main/java/shop/alien/job/store/LifeUserOrderJob.java

@@ -15,6 +15,7 @@ import shop.alien.entity.store.vo.LifeUserOrderVo;
 import shop.alien.job.feign.AlienStoreFeign;
 import shop.alien.mapper.*;
 import shop.alien.util.common.UniqueRandomNumGenerator;
+import shop.alien.util.common.constant.CouponTypeEnum;
 import shop.alien.util.common.constant.DiscountCouponEnum;
 import shop.alien.util.common.constant.OrderStatusEnum;
 
@@ -181,7 +182,18 @@ public class LifeUserOrderJob {
                     guoqiDate = calendar.getTime();
                 } else {
                     // 指定时间段
-                    String goqiDate = effectiveDateValue.split(",")[1];
+                    String goqiDate = null;
+                    if(order.getCouponType() == CouponTypeEnum.COUPON.getCode()){
+                        // 1. 将字符串转换为 long 类型
+                        long timestamp = Long.parseLong(effectiveDateValue.split(",")[1]);
+                        // 2. 使用 timestamp 构建 Date 对象
+                        Date date = new Date(timestamp);
+                        // 如果你需要特定格式的字符串,可以再进行格式化
+                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                        goqiDate =sdf.format(date);
+                    } else {
+                        goqiDate = effectiveDateValue.split(",")[1];
+                    }
                     try {
                         guoqiDate = new SimpleDateFormat("yyyy-MM-dd").parse(goqiDate);
                     } catch (ParseException e) {

+ 18 - 0
alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java

@@ -141,4 +141,22 @@ public class SecondTradeRecordController {
         log.info("SecondTradeRecordController.getTradeRecord?sideId={}", sideId);
         return R.data(secondTradeRecordService.getTradeRecord(sideId));
     }
+
+    @ApiOperation("双方是否有交易中的状态")
+    @ApiOperationSupport(order = 10)
+    @ApiImplicitParams({@ApiImplicitParam(name = "sideId", value = "对方的id", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/hasInTradeRecord")
+    public R<SecondTradeRecord> hasInTradeRecord(@RequestParam int sideId) throws Exception {
+        log.info("SecondTradeRecordController.hasInTradeRecord?sideId={}", sideId);
+        return R.data(secondTradeRecordService.hasInTradeRecord(sideId));
+    }
+
+    @ApiOperation("修改交易信息")
+    @ApiOperationSupport(order = 11)
+    @ApiImplicitParams({@ApiImplicitParam(name = "type", value = "1-交易成功  2-交易失败", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/modifyTradeRecord")
+    public R<Boolean> modifyTradeRecord(int type, Integer tradeId, String transactionTime, String transactionLatitudeLongitude, String transactionLatitudeLongitudeAddress, String transactionLocation, String messageId) throws Exception {
+        log.info("SecondTradeRecordController.modifyTradeRecord?record={}", transactionTime);
+        return R.data(secondTradeRecordService.modifyTradeRecord(type, tradeId, transactionTime, transactionLatitudeLongitude, transactionLatitudeLongitudeAddress, transactionLocation, messageId));
+    }
 }

+ 4 - 0
alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java

@@ -34,4 +34,8 @@ public interface SecondTradeRecordService extends IService<SecondTradeRecord> {
     boolean tradeCompleteConfirm(int tradeId, int type, String evaluate) throws Exception;
 
     List<SecondTradeRecordVo> getTradeRecord(int sideId) throws Exception;
+
+    SecondTradeRecord hasInTradeRecord(Integer sideId) throws Exception;
+
+    boolean modifyTradeRecord(int type, Integer tradeId, String transactionTime, String transactionLatitudeLongitude, String transactionLatitudeLongitudeAddress, String transactionLocation, String messageId) throws Exception;
 }

+ 95 - 0
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;
@@ -201,6 +202,16 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             // 交易信息
             SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
 
+            // 判断商品是否正在交易中
+            if (type == 1) {
+                LambdaQueryWrapper<SecondTradeRecord> recordWrapper = new LambdaQueryWrapper<>();
+                recordWrapper.eq(SecondTradeRecord::getGoodsId, trade.getGoodsId());
+                recordWrapper.eq(SecondTradeRecord::getTradeStatus, 3);
+                if (secondTradeRecordMapper.selectCount(recordWrapper) > 0) {
+                    throw new BusinessException("该商品正在交易中");
+                }
+            }
+
             // 有定时任务: 超过交易时间还未确认的交易会自动取消并保存交易操作表  所以如果是已取消的交易  不需要进行这两步操作
             if (trade.getTradeStatus() != 6) {
                 // 修改交易状态
@@ -548,6 +559,90 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
         }
     }
 
+    @Override
+    public SecondTradeRecord hasInTradeRecord(Integer sideId) throws Exception {
+        try {
+            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
+            LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
+            wrapper.apply("((seller_id = " + userId + " and buyer_id = " + sideId + ") or " +
+                    "(seller_id = " + sideId + " and buyer_id = " + userId + "))");
+            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);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean modifyTradeRecord(int type, Integer tradeId, String transactionTime, String transactionLatitudeLongitude, String transactionLatitudeLongitudeAddress, String transactionLocation, String messageId) throws Exception {
+        try {
+            if (type == 1) {
+                LambdaUpdateWrapper<SecondTradeRecord> wrapper = new LambdaUpdateWrapper<>();
+                wrapper.set(SecondTradeRecord::getTransactionTime, transactionTime);
+                wrapper.set(SecondTradeRecord::getTransactionLatitudeLongitude, transactionLatitudeLongitude);
+                wrapper.set(SecondTradeRecord::getTransactionLatitudeLongitudeAddress, transactionLatitudeLongitudeAddress);
+                wrapper.set(SecondTradeRecord::getTransactionLocation, transactionLocation);
+                wrapper.eq(SecondTradeRecord::getId, tradeId);
+                secondTradeRecordMapper.update(null, wrapper);
+            }
+            // 修改待确认的消息
+            LifeMessage lastMessage = lifeMessageMapper.selectById(messageId);
+
+            JSONObject lastMessageContent = JSONObject.parseObject(lastMessage.getContent());
+            lastMessageContent.put("messageId", lastMessage.getId());
+            lastMessageContent.put("modifyStatus", type == 1 ? 3 : 2);
+            LifeMessage message = new LifeMessage();
+            message.setId(lastMessage.getId());
+            message.setContent(lastMessageContent.toJSONString());
+            lifeMessageMapper.updateById(message);
+
+            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
+
+            // 发起交易人信息
+            Integer userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
+            String phoneId = JwtUtil.getCurrentUserInfo().getString("userType") + "_" + JwtUtil.getCurrentUserInfo().getString("phone");
+
+            // 获取交易对方信息
+            LifeUser lifeUser = lifeUserMapper.selectById(Objects.equals(userId, trade.getBuyerId()) ? trade.getSellerId() : trade.getBuyerId());
+            String receiverId = "user_" + lifeUser.getUserPhone();
+
+            // 给买家与卖家发送交易消息
+            WebSocketVo webSocketVo = new WebSocketVo();
+            webSocketVo.setSenderId(phoneId);
+            webSocketVo.setReceiverId(receiverId);
+            webSocketVo.setCategory("message");
+            webSocketVo.setType("9");
+            webSocketVo.setIsRead(0);
+            webSocketVo.setText(lastMessageContent.toJSONString());
+            webSocketVo.setMessageId(lastMessage.getId());
+
+            alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
+            alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());
+            return true;
+        } catch (Exception e) {
+            log.error("SecondTradeRecordServiceImpl.modifyTradeRecord(): Error Msg={}", e.getMessage());
+            throw new Exception(e);
+        }
+    }
+
     private void sendSignInMessage(SecondTradeRecord tradeRecord) throws Exception {
         log.info("二手交易平台-创建交易时间小于十分钟,直接发送交易提醒---sendSignInMessage()---");
         try {

+ 7 - 0
alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java

@@ -88,6 +88,13 @@ public class WebSocketProcess implements ApplicationContextAware {
                 return;
             }
 
+            // 发送位置信息
+            if ("position".equals(webSocketVo.getCategory())) {
+                sendMessage(webSocketVo.getSenderId(), JSONObject.from(webSocketVo).toJSONString());
+                sendMessage(webSocketVo.getReceiverId(), JSONObject.from(webSocketVo).toJSONString());
+                return;
+            }
+
             log.info("webSocketVo----------------{}", JSONObject.from(webSocketVo).toJSONString());
             log.info("concurrentHashMap----------{}", concurrentHashMap.keySet());
 

+ 64 - 38
alien-store/src/main/java/shop/alien/store/controller/AliController.java

@@ -80,36 +80,36 @@ public class AliController {
     @GetMapping("/getIdInfo")
     public R getIdInfo(@RequestParam("name") String name, @RequestParam("idCard") String idCard, @RequestParam("appType") Integer appType) {
         log.info("AliController.getIdInfo?name={}&idCard={}", name, idCard);
-//        int size = 0;
-//        if (appType == 0) {
-//            //根据身份查询未注销的用户
-//            size = lifeUserService
-//                    .list(new LambdaQueryWrapper<LifeUser>()
-//                            .eq(LifeUser::getIdCard, idCard)
-//                            .eq(LifeUser::getRealName, name)
-//                            .eq(LifeUser::getLogoutFlag, 0))
-//                    .size();
-//        } else {
-//            //根据身份查询已入住或审核中的商家
-//            List<StoreUser> storeUserList = storeUserService
-//                    .list(new LambdaQueryWrapper<StoreUser>()
-//                            .eq(StoreUser::getIdCard, idCard)
-//                            .eq(StoreUser::getName, name));
-//            List<Integer> storeIds = storeUserList.stream()
-//                    .map(StoreUser::getStoreId)
-//                    .filter(Objects::nonNull)
-//                    .collect(Collectors.toList());
-//            if (!storeIds.isEmpty()) {
-//                size = storeInfoService
-//                        .list(new LambdaQueryWrapper<StoreInfo>()
-//                                .in(StoreInfo::getId, storeIds)
-//                                .notIn(StoreInfo::getStoreApplicationStatus, 2))
-//                        .size();
-//            }
-//        }
-//        if (size > 0) {
-//            return R.fail("该身份证已实名认证过");
-//        }
+        int size = 0;
+        if (appType == 0) {
+            //根据身份查询未注销的用户
+            size = lifeUserService
+                    .list(new LambdaQueryWrapper<LifeUser>()
+                            .eq(LifeUser::getIdCard, idCard)
+                            .eq(LifeUser::getRealName, name)
+                            .eq(LifeUser::getLogoutFlag, 0))
+                    .size();
+        } else {
+            //根据身份查询已入住或审核中的商家
+            List<StoreUser> storeUserList = storeUserService
+                    .list(new LambdaQueryWrapper<StoreUser>()
+                            .eq(StoreUser::getIdCard, idCard)
+                            .eq(StoreUser::getName, name));
+            List<Integer> storeIds = storeUserList.stream()
+                    .map(StoreUser::getStoreId)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toList());
+            if (!storeIds.isEmpty()) {
+                size = storeInfoService
+                        .list(new LambdaQueryWrapper<StoreInfo>()
+                                .in(StoreInfo::getId, storeIds)
+                                .notIn(StoreInfo::getStoreApplicationStatus, 2))
+                        .size();
+            }
+        }
+        if (size > 0) {
+            return R.fail("该身份证已实名认证过");
+        }
         if (aliPayConfig.getIdInfo(name, idCard)) {
             return R.success("身份验证成功");
         }
@@ -156,6 +156,29 @@ public class AliController {
         return R.fail("短信发送失败");
     }
 
+    @ApiOperation("校验短信验证码")
+    @ApiOperationSupport(order = 4)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "appType", value = "端区分(0:用户, 1:商家)", dataType = "Integer", paramType = "query", required = true, defaultValue = "0"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型 (0:登录, 1:修改密码, 2:注册, 3:修改手机号, 4:注销店铺, 5:注销账号, 6:忘记密码)", dataType = "Integer", paramType = "query", required = true, defaultValue = "0"),
+            @ApiImplicitParam(name = "code", value = "验证码", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/checkSmsCode")
+    public R checkSmsCode(
+            @RequestParam("phone") String phone,
+            @RequestParam("appType") Integer appType,
+            @RequestParam("businessType") Integer businessType,
+            @RequestParam("code") Integer code
+    ) {
+        log.info("AliController.checkSmsCode?phone={}&appType={}&businessType={}&code={}", phone, appType, businessType, code);
+        if (aliSmsConfig.checkSmsCode(phone, appType, businessType, code)) {
+            return R.success("验证码校验成功");
+        }
+        return R.fail("验证码校验失败");
+    }
+
+
     @ApiOperation("银行卡核验")
     @ApiOperationSupport(order = 5)
     @ApiImplicitParams({@ApiImplicitParam(name = "name", value = "姓名", dataType = "String", paramType = "query", required = true),
@@ -272,18 +295,21 @@ public class AliController {
         return R.data(aliApi.promotionPackagePay(price, subject));
     }
 
-    @ApiOperation("退款")
+    @ApiOperation("处理退款")
     @ApiOperationSupport(order = 13)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "outTradeNo", value = "订单号", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "outTradeNo", value = "订单号", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "refundAmount", value = "退款金额", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "refundReason", value = "退款原因", dataType = "String", paramType = "query", required = true)
+            @ApiImplicitParam(name = "refundReason", value = "退款原因", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "partialRefundCode", value = "部分退款编号", dataType = "String", paramType = "query")
     })
     @GetMapping("/processRefund")
-    public String processRefund(@RequestParam(value = "outTradeNo") String outTradeNo,
-                                @RequestParam(value = "refundAmount") String refundAmount,
-                                @RequestParam(value = "refundReason") String refundReason,
-                                @RequestParam(value = "partialRefundCode") String partialRefundCode) {
+    public String processRefund(@RequestParam("outTradeNo") String outTradeNo,
+                                @RequestParam("refundAmount") String refundAmount,
+                                @RequestParam("refundReason") String refundReason,
+                                @RequestParam(value = "partialRefundCode", required = false) String partialRefundCode) {
+        log.info("AliController.processRefund?outTradeNo={}, refundAmount={}, refundReason={}, partialRefundCode={}",
+                outTradeNo, refundAmount, refundReason, partialRefundCode);
         return aliApi.processRefund(outTradeNo, refundAmount, refundReason, partialRefundCode);
     }
-}
+}

+ 11 - 11
alien-store/src/main/java/shop/alien/store/controller/LifeGroupPackageController.java

@@ -12,11 +12,14 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LifeCoupon;
+import shop.alien.entity.store.LifeGroupBuyMain;
 import shop.alien.entity.store.StoreGroupInfo;
 import shop.alien.entity.store.StoreHotelGroupRoomInfo;
 import shop.alien.entity.store.vo.LifeCouponVo;
+import shop.alien.entity.store.vo.LifeGroupBuyMainVo;
 import shop.alien.entity.store.vo.LifeTuanGouParamVo;
 import shop.alien.mapper.LifeCouponMapper;
+import shop.alien.mapper.LifeGroupBuyMainMapper;
 import shop.alien.mapper.StoreGroupInfoMapper;
 import shop.alien.mapper.StoreHotelGroupRoomInfoMapper;
 import shop.alien.store.service.LifeCouponService;
@@ -49,6 +52,8 @@ public class LifeGroupPackageController {
 
     private final StoreHotelGroupRoomInfoMapper storeHotelGroupRoomInfoMapper;
 
+    private final LifeGroupBuyMainMapper lifeGroupBuyMainMapper;
+
     @ApiOperation("新建团购")
     @PostMapping("/addOrUpdateGroupPackage")
     public R<Boolean> addOrUpdateGroupPackage(@RequestBody LifeTuanGouParamVo lifeTuanGouParamVo) {
@@ -169,17 +174,12 @@ public class LifeGroupPackageController {
 
     @ApiOperation("猜你喜欢")
     @GetMapping("/getRecommendForYou")
-    private R<IPage<LifeCoupon>> getRecommendForYou() {
-        LambdaUpdateWrapper<LifeCoupon> wrapper = new LambdaUpdateWrapper<>();
-        List<LifeCoupon> lifeCoupons = lifeCouponMapper.selectList(wrapper);
+    private R<IPage<LifeGroupBuyMainVo>> getRecommendForYou() {
+        LambdaQueryWrapper<LifeGroupBuyMainVo> wrapper = new LambdaQueryWrapper<>();
+        List<LifeGroupBuyMainVo> lifeGroupBuyMains = lifeGroupBuyMainMapper.getLifeGroupInfo(wrapper);
         // 打乱数据顺序
-        Collections.shuffle(lifeCoupons);
-        Random random = new Random();
-        for (LifeCoupon coupon : lifeCoupons) {
-            // 生成 1 到 5 之间的随机整数
-            int randomScore = random.nextInt(5) + 1;
-            coupon.setRateScore(randomScore);
-        }
-        return R.data(ListToPage.setPage(lifeCoupons, 1, 4));
+        Collections.shuffle(lifeGroupBuyMains);
+//        Random random = new Random();
+        return R.data(ListToPage.setPage(lifeGroupBuyMains, 1, 4));
     }
 }

+ 2 - 2
alien-store/src/main/java/shop/alien/store/controller/LifeUserOrderController.java

@@ -29,9 +29,9 @@ public class LifeUserOrderController {
     @ApiOperation("创建订单")
     @ApiOperationSupport(order = 2)
     @PostMapping("/createUserOrder")
-    public R<Map<String, Object>> createUserOrder(@RequestBody LifeUserOrderDto LifeUserOrderDto) {
+    public R createUserOrder(@RequestBody LifeUserOrderDto LifeUserOrderDto) {
         log.info("userOrder.createUserOrder:{}", LifeUserOrderDto);
-        return R.data(lifeUserOrderService.createUserOrder(LifeUserOrderDto));
+        return lifeUserOrderService.createUserOrder(LifeUserOrderDto);
     }
 
     @ApiOperation("更新订单")

+ 9 - 10
alien-store/src/main/java/shop/alien/store/controller/StoreIncomeDetailsRecordController.java

@@ -39,29 +39,28 @@ public class StoreIncomeDetailsRecordController {
             @ApiImplicitParam(name = "withdrawalMoney", value = "提现金额", dataType = "Integer", paramType = "query", required = true)
     })
     @GetMapping("/cashOut")
+    @Deprecated
     public R cashOut(Integer storeId, String payPassword, Integer withdrawalMoney) {
         return storeIncomeDetailsRecordService.cashOut(storeId, payPassword, withdrawalMoney);
     }
 
-    @ApiOperation("提现申请-提现全部")
+    @ApiOperation("提现申请-提现全部/部分提现")
     @ApiOperationSupport(order = 2)
-    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true), @ApiImplicitParam(name = "payPassword", value = "支付密码", dataType = "String", paramType = "query", required = true)})
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "payPassword", value = "支付密码", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "withdrawalMoney", value = "提现金额", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/applyCashOut")
-    public R<Boolean> applyCashOut(Integer storeId, String payPassword) {
-        String s = storeIncomeDetailsRecordService.applyCashOut(storeId, payPassword);
-        if ("success".equals(s)) {
-            return R.success("提现成功");
-        }
-        return R.fail(s);
+    public R applyCashOut(Integer storeId, String payPassword, Integer withdrawalMoney) {
+           return storeIncomeDetailsRecordService.applyCashOut(storeId, payPassword, withdrawalMoney);
     }
 
-    @ApiOperation("提现审批-提现全部")
+    @ApiOperation("提现审批-提现全部/部分提现")
     @ApiOperationSupport(order = 2)
     @ApiImplicitParams({@ApiImplicitParam(name = "cashOutId", value = "提现申请记录ID", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "approveStatus", value = "审批状态", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "failReason", value = "失败原因", dataType = "String", paramType = "query", required = false)})
     @GetMapping("/approveCashOut")
-    public R<Boolean> approveCashOut(Integer cashOutId, String approveStatus, String failReason) {
+    public R approveCashOut(Integer cashOutId, String approveStatus, String failReason) {
         String s = storeIncomeDetailsRecordService.approveCashOut(cashOutId, approveStatus, failReason);
         if ("付款失败".equals(s)) {
             return R.fail("付款失败");

+ 14 - 0
alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java

@@ -12,6 +12,7 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.StoreInfoDto;
 import shop.alien.entity.store.vo.*;
+import shop.alien.mapper.StoreCommentSummaryInterestMapper;
 import shop.alien.mapper.TagsMainMapper;
 import shop.alien.mapper.WebAuditMapper;
 import shop.alien.store.config.BaseRedisService;
@@ -45,6 +46,8 @@ public class StoreInfoController {
 
     private final BaseRedisService baseRedisService;
 
+    private final StoreCommentSummaryInterestMapper storeCommentSummaryInterestMapper;
+
     @ApiOperation("获取所有门店")
     @ApiOperationSupport(order = 1)
     @GetMapping("/getAll")
@@ -653,4 +656,15 @@ public class StoreInfoController {
         return R.data(voList);
     }
 
+    @ApiOperation(value = "AI服务-门店趣味信息")
+    @GetMapping("/getStoreInterestInfo")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "int", paramType = "query")
+    })
+    public R<List<StoreCommentSummaryInterest>> getStoreInterestInfo(int storeId) {
+        log.info("StoreInfoController.getStoreInterestInfo?storeId={}", storeId);
+        List<StoreCommentSummaryInterest> list = storeCommentSummaryInterestMapper.selectList(new LambdaQueryWrapper<StoreCommentSummaryInterest>().eq(StoreCommentSummaryInterest :: getStoreId, storeId));
+        return R.data(list);
+    }
+
 }

+ 10 - 3
alien-store/src/main/java/shop/alien/store/controller/StoreUserController.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.StoreImg;
@@ -62,7 +63,13 @@ public class StoreUserController {
 
     @ApiOperation("修改密码/忘记密码/更换绑定手机号")
     @ApiOperationSupport(order = 2)
-    @ApiImplicitParams({@ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true), @ApiImplicitParam(name = "newPhone", value = "新手机号", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "oldPassword", value = "旧密码", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "newPassword", value = "新密码", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "confirmNewPassword", value = "新密码确认", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "verificationCode", value = "验证码", dataType = "String", paramType = "query", required = true), @ApiImplicitParam(name = "type", value = "类型:0:忘记密码,1:修改密码,2:更换绑定手机号", dataType = "Integer", paramType = "query", required = true)})
+    @ApiImplicitParams({@ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "newPhone", value = "新手机号", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "oldPassword", value = "旧密码", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "newPassword", value = "新密码", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "confirmNewPassword", value = "新密码确认", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "verificationCode", value = "验证码", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "type", value = "类型:0:忘记密码,1:修改密码,2:更换绑定手机号", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/updatePassword")
     public R<String> updatePassword(String phone, String newPhone, String oldPassword, String newPassword, String confirmNewPassword, String verificationCode, Integer type) {
         log.info("StoreUserController.updatePassword?phone={}&newPhone={}&oldPassword={}&newPassword={}&confirmNewPassword={}&verificationCode={}&type={}", phone, newPhone, oldPassword, newPassword, confirmNewPassword, verificationCode, type);
@@ -80,10 +87,10 @@ public class StoreUserController {
                 break;
         }
         String cacheCode = baseRedisService.getString("verification_store_" + businessType + "_" + phone);
-        if (null == cacheCode) {
+        if (StringUtils.isBlank(oldPassword) && null == cacheCode) {
             return R.fail("当验证码过期或未发送");
         }
-        if (!cacheCode.trim().equals(verificationCode.trim())) {
+        if (StringUtils.isBlank(oldPassword) && !cacheCode.trim().equals(verificationCode.trim())) {
             return R.fail("验证码错误");
         }
         return storeUserService.forgetOrModifyPassword(phone, newPhone, oldPassword, newPassword, confirmNewPassword, verificationCode, type);

+ 28 - 11
alien-store/src/main/java/shop/alien/store/service/LifeUserOrderService.java

@@ -39,6 +39,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.DecimalFormat;
 import java.time.Instant;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
@@ -505,6 +506,7 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
             lifeMessage.setSenderId("system");
             lifeMessage.setIsRead(0);
             lifeMessage.setNoticeType(2);
+            lifeMessage.setTitle("退款成功");
             lifeNoticeMapper.insert(lifeMessage);
 
             WebSocketVo websocketVo = new WebSocketVo();
@@ -546,13 +548,11 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
 
                 //判断当前时间在开始时间start_date和结束时间end_date之间,并且库存single_qty大于0,则修改状态status为5
                 lifeCouponMapper.update(null, new LambdaUpdateWrapper<LifeCoupon>()
-                        .set(LifeCoupon::getStatus, 5)
+                        .set(LifeCoupon::getStatus, CouponStatusEnum.ONGOING.getCode())
                         .eq(LifeCoupon::getId, couponId)
-                        .le(LifeCoupon::getStartDate, LocalDateTime.now())
-                        .ge(LifeCoupon::getEndDate, LocalDateTime.now())
+                        .le(LifeCoupon::getStartDate, LocalDate.now())
+                        .ge(LifeCoupon::getEndDate, LocalDate.now())
                         .gt(LifeCoupon::getSingleQty, 0));
-
-
             } else {
                 // 团购信息
                 lifeGroupBuyMainMapper.update(null, new LambdaUpdateWrapper<LifeGroupBuyMain>()
@@ -561,10 +561,10 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
 
                 //判断当前时间在开始时间start_date和结束时间end_date之间,并且库存single_qty大于0,则修改状态status为5
                 lifeGroupBuyMainMapper.update(null, new LambdaUpdateWrapper<LifeGroupBuyMain>()
-                        .set(LifeGroupBuyMain::getStatus, 5)
+                        .set(LifeGroupBuyMain::getStatus, CouponStatusEnum.ONGOING.getCode())
                         .eq(LifeGroupBuyMain::getId, couponId)
-                        .le(LifeGroupBuyMain::getStartTimeValue, LocalDateTime.now())
-                        .ge(LifeGroupBuyMain::getEndTime, LocalDateTime.now())
+                        .le(LifeGroupBuyMain::getStartTimeValue, LocalDate.now())
+                        .ge(LifeGroupBuyMain::getEndTime, LocalDate.now())
                         .gt(LifeGroupBuyMain::getInventoryNum, 0));
             }
         } catch (Exception e) {
@@ -730,7 +730,7 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
      * @param lifeUserOrderDto 构造数据用
      */
     @Transactional(rollbackFor = Exception.class)
-    public Map<String, Object> createUserOrder(LifeUserOrderDto lifeUserOrderDto) {
+    public R createUserOrder(LifeUserOrderDto lifeUserOrderDto) {
         Date date = new Date();
         //1.创建订单
         LifeUserOrder lifeUserOrder = new LifeUserOrder();
@@ -821,12 +821,12 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
         if (updateRows == 0) {
             log.error("couponid:" + lifeUserOrderDto.getCouponId() + " 库存不足,当前购买数量:" + buyCount);
             // 手动抛出异常,触发事务回滚(回滚之前创建的订单和优惠券状态变更)
-            throw new RuntimeException("库存不足,下单失败");
+            return R.fail("库存不足,下单失败");
         }
         returnMap.put("success", "下单成功");
         returnMap.put("orderNo", lifeUserOrderDto.getOrderNo());
         returnMap.put("lifeUserOrder", lifeUserOrder);
-        return returnMap;
+        return R.data(returnMap);
     }
 
     /**
@@ -943,6 +943,7 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
                 String sql = baseSql + " and ocm1.status not in  (" + OrderStatusEnum.WAIT_PAY.getStatus()
                         + "," + OrderStatusEnum.EXPIRE.getStatus()
                         + "," + OrderStatusEnum.CANCEL.getStatus()
+                        + "," + OrderStatusEnum.REFUND.getStatus()
                         + ")";
                 lifeUserOrderQueryWrapper.inSql("luo.id", sql);
             }
@@ -1154,6 +1155,22 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
         // 退款记录
         calcExpectIncome(lifeUserOrderVo);
         lifeUserOrderVo.setCouponCount(lifeUserOrderVo.getOrderCouponMiddleList().size());
+        // 查询订单图片列表
+        String imgIds = lifeUserOrderVo.getImgIds();
+        if(StringUtils.isNotEmpty(imgIds)){
+            LambdaQueryWrapper<StoreImg> storeImgLambdaQueryWrapper = new LambdaQueryWrapper<>();
+            List<String> imgIdList = Arrays.stream(imgIds.split(","))
+                    .map(String::trim)
+                    .collect(Collectors.toList());
+            storeImgLambdaQueryWrapper.in(StoreImg::getId, imgIdList);
+            List<StoreImg> storeImgList = storeImgMapper.selectList(storeImgLambdaQueryWrapper);
+            if(CollectionUtils.isNotEmpty(storeImgList)){
+                List<String> imgUrlList = storeImgList.stream()    // 转换为 Stream
+                        .map(StoreImg::getImgUrl)                  // 映射,提取 name 字段
+                        .collect(Collectors.toList());
+                lifeUserOrderVo.setImgUrls(imgUrlList);
+            }
+        }
         return R.data(lifeUserOrderVo);
     }
 

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

@@ -32,7 +32,15 @@ public interface StoreIncomeDetailsRecordService extends IService<StoreIncomeDet
      * @param storeId     门店id
      * @return 是否成功
      */
-    String applyCashOut(Integer storeId, String payPassword);
+    /**
+     * 提现申请
+     *
+     * @param storeId     门店id
+     * @param payPassword 支付密码
+     * @param withdrawalMoney 提现金额
+     * @return 是否成功
+     */
+    R applyCashOut(Integer storeId, String payPassword, Integer withdrawalMoney);
 
     /**
      * 提现审批

+ 3 - 2
alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponServiceImpl.java

@@ -344,7 +344,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
     @Override
     public List<LifeDiscountCouponVo> getStoreUserCouponList(String storeId, UserLoginInfo userLoginInfo) {
         List<LifeDiscountCouponVo> lifeDiscountCouponVos = new ArrayList<>();
-        try{
+        try {
             LocalDateTime now = LocalDateTime.now();
             //根据店铺id查询该店铺的优惠券,状态是开启领取的券
             List<LifeDiscountCoupon> lifeDiscountCoupons = lifeDiscountCouponMapper.selectList(new LambdaQueryWrapper<LifeDiscountCoupon>().eq(LifeDiscountCoupon::getStoreId, storeId).eq(LifeDiscountCoupon::getGetStatus, "1") //还有库存
@@ -1085,6 +1085,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         return lifeDiscountCouponMapper.selectPage(iPage, new LambdaQueryWrapper<LifeDiscountCoupon>()
                 .eq(LifeDiscountCoupon::getType, 3)
                 .like(!StringUtils.isEmpty(name), LifeDiscountCoupon::getName, name)
+                .orderByDesc(LifeDiscountCoupon::getCreatedTime)
                 .between(!StringUtils.isEmpty(createDate), LifeDiscountCoupon::getCreatedTime, createDate + " 00:00:00", createDate + " 23:59:59"));
     }
 
@@ -1128,7 +1129,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
     @Override
     public boolean issuePlatformCoupon(List<Integer> userIds, Integer couponId) {
         LifeDiscountCoupon lifeDiscountCoupon = this.getById(couponId);
-        if(lifeDiscountCoupon == null){
+        if (lifeDiscountCoupon == null) {
             //如果优惠券为空,则返回失败
             return false;
         }

+ 31 - 4
alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponStoreFriendServiceImpl.java

@@ -1,8 +1,10 @@
 package shop.alien.store.service.impl;
 
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -12,11 +14,9 @@ import org.springframework.beans.BeansException;
 import org.springframework.stereotype.Service;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.LifeDiscountCouponStoreFriendDto;
-import shop.alien.entity.store.vo.LifeDiscountCouponFriendRuleDetailVo;
-import shop.alien.entity.store.vo.LifeDiscountCouponFriendRuleVo;
-import shop.alien.entity.store.vo.LifeDiscountCouponStoreFriendVo;
-import shop.alien.entity.store.vo.LifeDiscountCouponVo;
+import shop.alien.entity.store.vo.*;
 import shop.alien.mapper.*;
+import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.service.LifeDiscountCouponStoreFriendService;
 import shop.alien.util.common.constant.DiscountCouponEnum;
 
@@ -66,6 +66,8 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
 
     private final LifeDiscountCouponFriendRuleDetailMapper lifeDiscountCouponFriendRuleDetailMapper;
 
+    private final WebSocketProcess webSocketProcess;
+
     @Override
     public List<LifeDiscountCouponStoreFriendVo> getFriendCouponList(UserLoginInfo userLoginInfo, String friendUserId) {
         List<LifeDiscountCouponStoreFriendVo> result = new ArrayList<>();
@@ -191,6 +193,31 @@ public class LifeDiscountCouponStoreFriendServiceImpl extends ServiceImpl<LifeDi
                 lifeDiscountCoupon.setSingleQty(lifeDiscountCoupon.getSingleQty() - couponDto.getSingleQty());
                 // 更新数据库中的优惠券库存信息
                 lifeDiscountCouponMapper.updateById(lifeDiscountCoupon);
+
+                int friendStoreId =  lifeDiscountCouponStoreFriendDto.getFriendStoreUserId();
+                LambdaQueryWrapper<StoreUser> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
+                storeUserLambdaQueryWrapper.eq(StoreUser::getStoreId, friendStoreId);
+                List<StoreUser> storeUserList = storeUserMapper.selectList(storeUserLambdaQueryWrapper);
+
+                if(CollectionUtils.isNotEmpty(storeUserList)){
+                    StoreUser friendStoreUser = storeUserList.get(0);
+                    String friendPhone = friendStoreUser.getPhone();
+                    if(StringUtils.isNotEmpty(friendPhone)){
+                        // 发送好友优惠券通知
+                        LifeNotice lifeMessage = new LifeNotice();
+                        String text = "您的好友"+userLoginInfo.getUserName()+"送了您"+couponDto.getSingleQty()+"张店铺优惠券,快去使用吧!";
+                        JSONObject jsonObject = new JSONObject();
+                        jsonObject.put("message", text);
+                        lifeMessage.setReceiverId("store_"+friendPhone);
+                        lifeMessage.setTitle("赠券通知");
+                        lifeMessage.setContext(jsonObject.toJSONString());
+                        lifeMessage.setNoticeType(1);
+                        lifeMessage.setIsRead(0);
+                        lifeMessage.setDeleteFlag(0);
+                        lifeMessage.setSenderId("system");
+                        lifeNoticeMapper.insert(lifeMessage);
+                    }
+                }
             }
             // 如果所有优惠券都成功处理,返回 true
             return true;

+ 10 - 13
alien-store/src/main/java/shop/alien/store/service/impl/LifeUserViolationServiceImpl.java

@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.google.common.collect.Lists;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -18,7 +17,6 @@ import org.springframework.util.CollectionUtils;
 import shop.alien.entity.second.SecondGoodsRecord;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.LifeUserViolationDto;
-import shop.alien.entity.store.excelVo.LifeUserOrderExcelVo;
 import shop.alien.entity.store.excelVo.LifeUserViolationExcelVO;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
 import shop.alien.entity.store.vo.LifeUserViolationVo;
@@ -30,20 +28,16 @@ import shop.alien.store.service.*;
 import shop.alien.store.util.FunctionMagic;
 import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.EnumUtil;
-import shop.alien.util.common.JwtUtil;
 
 import java.io.File;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
-import java.time.Instant;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
-import static shop.alien.util.common.constant.Constant.*;
-
 
 /**
  * <p>
@@ -85,6 +79,7 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
     private final StoreCommentMapper storeCommentMapper;
 
     private final SecondGoodsRecordMapper secondGoodsRecordMapper;
+    private final StoreImgService storeImgService;
 
     @Value("${spring.web.resources.excel-path}")
     private String excelPath;
@@ -315,9 +310,9 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
         QueryWrapper<LifeUserViolationVo> queryWrapper = new QueryWrapper<>();
 
         // 基础查询条件
-        queryWrapper.eq("luv.delete_flag", 0)
-                //排除二手的举报
-                .notIn("luv.report_context_type", Arrays.asList("4", "5"));
+        queryWrapper.eq("luv.delete_flag", 0);
+//                //排除二手的举报
+//                .notIn("luv.report_context_type", Arrays.asList("4", "5"));
 
         // 动态查询条件
         queryWrapper.like(StringUtils.isNotEmpty(nickName), "ui.nick_name", nickName)
@@ -527,10 +522,12 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
         if (entity == null) return null;
         LifeUserViolationDto dto = new LifeUserViolationDto();
         BeanUtils.copyProperties(entity, dto);
-        if (Objects.nonNull(entity.getReportEvidenceImg())) {
-            List<String> list = Arrays.stream(entity.getReportEvidenceImg().split(",")).map(String::trim).collect(Collectors.toList());
-            dto.setImageList(list);
-        }
+        LambdaQueryWrapper<StoreImg> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreImg::getStoreId, entity.getId());
+        queryWrapper.in(StoreImg::getImgType, 19);
+        List<StoreImg> storeImgList = storeImgService.list(queryWrapper);
+        List<String> collect = storeImgList.stream().map(StoreImg::getImgUrl).collect(Collectors.toList());
+        dto.setImageList(collect);
         // 处理举报人信息
         FunctionMagic.handleUserInfo(dto.getReportingUserType(), dto.getReportingUserId(), storeId -> storeUserService.getOne(FunctionMagic.idQueryWrapper(storeId)), lifeId -> lifeUserService.getOne(FunctionMagic.idQueryWrapper(lifeId)), user -> {
             if (user instanceof StoreUser) {

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

@@ -100,7 +100,7 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
     public IPage<LifeGroupBuyMainVo> getLifeGroupBuyMainList(Integer page, Integer size, String storeName, String status, String createdTime, String phone, String expiredState) {
         QueryWrapper<LifeGroupBuyMainVo> wrapper = new QueryWrapper<>();
         wrapper.like(StringUtils.isNotEmpty(storeName), "store.store_name", storeName);
-        if (status == null || status.equals("")) {
+        if (status == null || status.isEmpty()) {
             wrapper.in("life.status", 1, 2, 3, 4, 5, 6, 7);
         }
         if (status.equals("9")) {

+ 10 - 8
alien-store/src/main/java/shop/alien/store/service/impl/StoreCashOutRecordServiceImpl.java

@@ -3,6 +3,7 @@ package shop.alien.store.service.impl;
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
@@ -44,17 +45,18 @@ public class StoreCashOutRecordServiceImpl extends ServiceImpl<StoreCashOutRecor
 
     @Override
     public StoreCashOutRecordVo getCashOutRecordList(Integer storeId, String cashOutStartTime, String cashOutEndTime, Integer page, Integer size, String paymentStatus) {
-        LambdaQueryWrapper<StoreCashOutRecord> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCashOutRecord::getStoreId, storeId);
-        wrapper.eq(StringUtils.isNotBlank(paymentStatus), StoreCashOutRecord::getPaymentStatus, paymentStatus);
-        wrapper.le(StringUtils.isNotBlank(cashOutEndTime) , StoreCashOutRecord::getCreatedTime, cashOutEndTime + " 23:59:59");
-        wrapper.ge(StringUtils.isNotBlank(cashOutStartTime), StoreCashOutRecord::getCreatedTime, cashOutStartTime + " 00:00:00" );
-        wrapper.orderByDesc(StoreCashOutRecord::getCreatedTime);
-        List<StoreCashOutRecord> recordList = storeCashOutRecordMapper.selectList(wrapper);
+        QueryWrapper<StoreCashOutRecord> wrapper = new QueryWrapper<>();
+        wrapper.eq("scor.store_id", storeId);
+        wrapper.eq(StringUtils.isNotBlank(paymentStatus), "scor.payment_status", paymentStatus);
+        wrapper.le(StringUtils.isNotBlank(cashOutEndTime) , "scor.created_time", cashOutEndTime + " 23:59:59");
+        wrapper.ge(StringUtils.isNotBlank(cashOutStartTime), "scor.created_time", cashOutStartTime + " 00:00:00" );
+        wrapper.eq("scor.delete_flag", 0);
+        wrapper.orderByDesc("scor.created_time");
+        List<StoreCashOutRecord> recordList = storeCashOutRecordMapper.selectCashoutRecordList(wrapper);
         IPage<StoreCashOutRecord> storeCashOutRecordIPage = ListToPage.setPage(recordList, page, size);
         StoreCashOutRecordVo vo = new StoreCashOutRecordVo();
         vo.setCashOutRecordList( storeCashOutRecordIPage.getRecords());
-        vo.setCashOutAllMoney(new BigDecimal(recordList.stream().mapToInt(StoreCashOutRecord::getMoney).sum()).divide(new BigDecimal(100), 2, RoundingMode.DOWN));
+        vo.setCashOutAllMoney(new BigDecimal(recordList.stream().filter(item -> "1".equals(item.getPaymentStatus().toString())).mapToInt(StoreCashOutRecord::getMoney).sum()).divide(new BigDecimal(100), 2, RoundingMode.DOWN));
         vo.setCashOutNum(recordList.size());
         return vo;
     }

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

@@ -809,6 +809,52 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
                 record.setGroupBuyImgUrl(imgUrlBuilder.toString());
             }
         }
+
+
+        List<LifeUserOrderCommentVo> lifeUserOrderCommentVos =  commentOrderPage.getRecords();
+        if(CollectionUtils.isEmpty(lifeUserOrderCommentVos)){
+            return commentOrderPage;
+        }
+        List<String> orderIds = lifeUserOrderCommentVos.stream().map(LifeUserOrderCommentVo::getId).collect(Collectors.toList());
+        List<StoreComment> storeCommentList = storeCommentMapper.selectList(new QueryWrapper<StoreComment>().inSql("business_id", String.join(",", orderIds)).eq("business_type", 5));
+        if(CollectionUtils.isEmpty(storeCommentList)){
+            return commentOrderPage;
+        }
+        Map<Integer, StoreComment> commentIdToMap = storeCommentList.stream()
+                .collect(Collectors.toMap(
+                        StoreComment::getBusinessId,
+                        Function.identity(),
+                        (existing, replacement) -> existing  // 若有重复id(理论上不会),保留第一个
+                ));
+        if(CollectionUtils.isEmpty(commentIdToMap)){
+            return commentOrderPage;
+        }
+        for(LifeUserOrderCommentVo lifeUserOrderCommentVo : commentOrderPage.getRecords()){
+            Integer orderId = Integer.parseInt(lifeUserOrderCommentVo.getId());
+
+            if(commentIdToMap.containsKey(orderId)){
+                StoreComment storeComment = commentIdToMap.get(orderId);
+                lifeUserOrderCommentVo.setScore(storeComment.getScore().toString());
+                lifeUserOrderCommentVo.setCommentDate(storeComment.getCreatedTime());
+                String imgIds = storeComment.getImgId();
+
+                if(StringUtils.isNotEmpty(imgIds)){
+                    LambdaQueryWrapper<StoreImg> storeImgLambdaQueryWrapper = new LambdaQueryWrapper<>();
+                    List<String> imgIdList = Arrays.stream(imgIds.split(","))
+                            .map(String::trim)
+                            .collect(Collectors.toList());
+                    storeImgLambdaQueryWrapper.in(StoreImg::getId, imgIdList);
+                    List<StoreImg> storeImgList = storeImgMapper.selectList(storeImgLambdaQueryWrapper);
+                    if(CollectionUtils.isNotEmpty(storeImgList)){
+                        List<String> imgUrlList = storeImgList.stream()    // 转换为 Stream
+                                .map(StoreImg::getImgUrl)                  // 映射,提取 name 字段
+                                .collect(Collectors.toList());
+                        lifeUserOrderCommentVo.setImgUrls(imgUrlList);
+                    }
+                }
+            }
+        }
+
         return commentOrderPage;
     }
 }

+ 39 - 60
alien-store/src/main/java/shop/alien/store/service/impl/StoreIncomeDetailsRecordServiceImpl.java

@@ -15,7 +15,6 @@ import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.StoreIncomeDetailsRecordVo;
-import shop.alien.entity.store.vo.SystemConfigVo;
 import shop.alien.entity.store.vo.WebSocketVo;
 import shop.alien.mapper.*;
 import shop.alien.store.config.WebSocketProcess;
@@ -139,14 +138,12 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
                 if (Double.parseDouble(divide.toString()) < 0.1) {
                     return R.fail("金额不能小于0.1元");
                 }
-                StoreAliPayLog pay = new StoreAliPayLog();
-                if (StringUtils.isNotBlank(storeUser.getAlipayAccount())) {
-                    pay = aliApi.pay(storeUser.getName(), storeUser.getIdCard(), storeUser.getAlipayAccount(), divide.toString());
-                } else {
-                    pay = aliApi.payAccount(storeUser.getName(), storeUser.getIdCard(), null, divide.toString(), storeUser.getPhone());
-                }
+                StoreAliPayLog pay = aliApi.payAccount(storeUser.getName(), storeUser.getIdCard(), storeUser.getAlipayAccount(), divide.toString(), storeUser.getPhone());
                 //增加提现记录
                 StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
+                if (null == pay) {
+                    return R.fail("支付宝转账失败");
+                }
                 if (pay.getStoreAliPayErrorLog() == null) {
                     storeCashOutRecord.setStoreId(storeId);
                     storeCashOutRecord.setOrderNo(pay.getOutBizNo());
@@ -192,10 +189,19 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
      */
     @Transactional
     @Override
-    public String applyCashOut(Integer storeId, String payPassword) {
+    public R applyCashOut(Integer storeId, String payPassword, Integer withdrawalMoney) {
         StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeId).eq(StoreUser::getPayPassword, payPassword));
         if (storeUser != null) {
-            int freeze = 0;
+            if (storeUser.getMoney() <= withdrawalMoney) {
+                return R.fail("余额不足");
+            }
+            //调用支付宝转账
+            BigDecimal decimal = new BigDecimal(withdrawalMoney);
+            BigDecimal divide = decimal.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
+            if (Double.parseDouble(divide.toString()) < 0.1) {
+                return R.fail("金额不能小于0.1元");
+            }
+            /*int freeze = 0;
             //查询冻结配置
             SystemConfigVo systemConfigVo = storeDictService.getConfig("freeze");
             if (systemConfigVo != null) {
@@ -211,44 +217,22 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
             //当前时间-3天大于创建时间
             if (freeze > 0) {
                 wrapper.lt(StoreIncomeDetailsRecord::getCreatedTime, DateUtils.calcDays(new Date(), -freeze));
-            }
-            //未绑定提现记录的
-            wrapper.isNull(StoreIncomeDetailsRecord::getCashOutId);
-            wrapper.eq(StoreIncomeDetailsRecord::getStoreId, storeId);
-            List<StoreIncomeDetailsRecord> list = this.list(wrapper);
-            if (!list.isEmpty()) {
-                //总金额
-                Integer availableAmount = 0;
-                //手续费
-                Integer commission = 0;
-                for (StoreIncomeDetailsRecord record : list) {
-                    availableAmount += record.getMoney();
-                    commission += record.getCommission();
-                }
-                int money = availableAmount - commission;
-                list = list.stream().sorted(Comparator.comparing(StoreIncomeDetailsRecord::getCreatedTime)).collect(Collectors.toList());
-                Date startDate = list.get(0).getCreatedTime();
-                Date endDate = list.get(list.size() - 1).getCreatedTime();
-                //增加提现申请记录
-                StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
-                storeCashOutRecord.setStoreId(storeId);
-                storeCashOutRecord.setMoney(money);
-                storeCashOutRecord.setCommission(commission);
-                storeCashOutRecord.setCashOutType(0);
-                storeCashOutRecord.setPaymentStatus(3);
-                storeCashOutRecord.setDeleteFlag(0);
-                storeCashOutRecord.setIncomeStartTime(startDate);
-                storeCashOutRecord.setIncomeEndTime(endDate);
-                storeCashOutRecord.setStoreUserId(storeUser.getId());
-                storeCashOutRecordMapper.insert(storeCashOutRecord);
-                //关联提现记录
-                list.forEach(record -> record.setCashOutId(storeCashOutRecord.getId()));
-                this.saveOrUpdateBatch(list);
-                return "申请成功";
-            }
-            return "账单未到可提现时间";
+            }*/
+            //增加提现申请记录
+            StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
+            storeCashOutRecord.setStoreId(storeId);
+            storeCashOutRecord.setMoney(withdrawalMoney);
+//            storeCashOutRecord.setCommission(commission);
+            storeCashOutRecord.setCashOutType(0);
+            storeCashOutRecord.setPaymentStatus(3);
+            storeCashOutRecord.setDeleteFlag(0);
+            storeCashOutRecord.setIncomeStartTime(new Date());
+            storeCashOutRecord.setIncomeEndTime(new Date());
+            storeCashOutRecord.setStoreUserId(storeUser.getId());
+            storeCashOutRecordMapper.insert(storeCashOutRecord);
+            return R.data(storeCashOutRecord);
         }
-        return "支付密码错误";
+        return R.fail("支付密码错误");
     }
 
     @Transactional
@@ -276,8 +260,8 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
                 if (Double.parseDouble(divide.toString()) < 0.10) {
                     return "金额不能小于0.1元";
                 }
-                StoreAliPayLog pay = aliApi.pay(storeUser.getName(), storeUser.getIdCard(), storeUser.getPhone(), divide.toString());
-                if (pay != null) {
+                StoreAliPayLog pay = aliApi.payAccount(storeUser.getName(), storeUser.getIdCard(), storeUser.getAlipayAccount(), divide.toString(), storeUser.getPhone());
+                if (null != pay) {
                     // 提现成功,更新提现申请相关状态
                     storeCashOutRecord.setOrderNo(pay.getOutBizNo());
                     storeCashOutRecord.setAliOrderNo(pay.getOrderId());
@@ -285,17 +269,9 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
                     storeCashOutRecord.setApproveTime(new Date());// 审批时间
                     storeCashOutRecord.setPayDate(new Date());//支付时间
                     storeCashOutRecord.setPaymentDate(new Date());//支付到账时间
-                    Integer commission = storeCashOutRecord.getCommission();
-                    if (storeCashOutRecord.getCommission() == null) {
-                        commission = 0;
-                    }
                     storeCashOutRecordMapper.updateById(storeCashOutRecord);
-                    int deductMoney = storeCashOutRecord.getMoney() - commission;
-                    if (storeUser.getMoney() < deductMoney) {
-                        storeUserMapper.updateById(new StoreUser(storeUserId, 0));
-                    } else {
-                        storeUserMapper.updateById(new StoreUser(storeUserId, storeUser.getMoney() - storeCashOutRecord.getMoney() - commission));
-                    }
+                    // 在存钱包的时候已经去掉了手续费
+                    storeUserMapper.updateById(new StoreUser(storeUserId, storeUser.getMoney() - storeCashOutRecord.getMoney()));
                     // 提现成功通知
                     cashOutSendNotice(storeCashOutRecord, storeUser, failReason, "3");
                     return "付款成功";
@@ -415,7 +391,7 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
             Date startDate = DateUtils.calcDays(now, -3);
             jsonObject.put("date", df.format(startDate) + " ~ " + df.format(now));
         } else {
-            wrapper.isNotNull("sidr.cash_out_id");
+//            wrapper.isNotNull("sidr.cash_out_id");
             //已到账期, 当前时间-4~27天大于创建时间
             wrapper.between("sidr.created_time", DateUtils.calcDays(new Date(), -27), DateUtils.calcDays(new Date(), -4));
             Date startDate = DateUtils.calcDays(now, -27);
@@ -449,6 +425,9 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
             storeIncomeDetailsRecord.setMoneyStr(new BigDecimal(vo.getMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
             String format = df.format(storeIncomeDetailsRecord.getCreatedTime());
             storeIncomeDetailsRecord.setDate(format);
+            storeIncomeDetailsRecord.setCommissionRate(storeInfo.getCommissionRate());
+            storeIncomeDetailsRecord.setIncomeMoney(new BigDecimal(vo.getMoney()).add(new BigDecimal(vo.getCommission())).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
+            storeIncomeDetailsRecord.setCommissionStr(new BigDecimal(vo.getCommission()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
             vo.setCommissionRate(storeInfo.getCommissionRate());
         }
         jsonObject.put("data", ListToPage.setPage(list, page, size));
@@ -582,7 +561,7 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
         LambdaQueryWrapper<LifeUserOrder> wrapper = new LambdaQueryWrapper<>();
         LocalDate now = LocalDate.now();
         wrapper.eq(LifeUserOrder::getStoreId, storeId)
-                .notIn(LifeUserOrder::getStatus, OrderStatusEnum.CANCEL.getStatus(), OrderStatusEnum.WAIT_PAY.getStatus(), OrderStatusEnum.EXPIRE.getStatus())
+                .in(LifeUserOrder::getStatus, OrderStatusEnum.WAIT_USE.getStatus(), OrderStatusEnum.USED.getStatus(),OrderStatusEnum.COMPLETE.getStatus())
                 .between(LifeUserOrder::getBuyTime, now + " 00:00:00", now + " 23:59:59");
         return lifeUserOrderMapper.selectCount(wrapper);
     }

+ 28 - 8
alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java

@@ -1,7 +1,6 @@
 package shop.alien.store.service.impl;
 
 import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson2.util.DateUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -134,6 +133,8 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
 
     private final LifeFansMapper lifeFansMapper;
 
+    private final LifeBlacklistMapper lifeBlacklistMapper;
+
     @Resource
     private StoreIncomeDetailsRecordService storeIncomeDetailsRecordService;
 
@@ -1062,10 +1063,13 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         result.setStorePositionLatitude(result.getStorePosition().split(",")[1]);
         // 设置距离
         if ((jingdu != null && !jingdu.isEmpty()) && (weidu != null && !weidu.isEmpty())) {
-            double storeJing = Double.parseDouble(result.getStorePosition().split(",")[0]);
+            /*double storeJing = Double.parseDouble(result.getStorePosition().split(",")[0]);
             double storeWei = Double.parseDouble(result.getStorePosition().split(",")[1]);
-            double storeDistance = DistanceUtil.haversineCalculateDistance(Double.parseDouble(jingdu), Double.parseDouble(weidu), storeJing, storeWei);
-            result.setDistance(storeDistance);
+            double storeDistance = DistanceUtil.haversineCalculateDistance(Double.parseDouble(jingdu), Double.parseDouble(weidu), storeJing, storeWei);*/
+
+            Double distance = storeInfoMapper.getStoreDistance(jingdu + "," + weidu,result.getId());
+
+            result.setDistance(distance);
         }
         // 计算店铺到最近地铁站的距离
         JSONObject nearbySubway = gaoDeMapUtil.getNearbySubway(result.getStorePosition().split(",")[0], result.getStorePosition().split(",")[1]);
@@ -1195,7 +1199,17 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         dynamicsWrapper.eq("phone_id", "store_" + result.getStorePhone()).orderByDesc("lud.created_time");
         dynamicsWrapper.eq("lud.delete_flag", 0);
         //List<LifeUserDynamicsVo> storeDynamicslist = lifeUserDynamicsMapper.getStoreDynamicslist(userId, dynamicsWrapper);
-        List<LifeUserDynamicsVo> storeDynamicslist = lifeUserDynamicsMapper.getStoreDynamicslist(userId, "store_" + result.getStorePhone());
+
+        LambdaQueryWrapper<LifeBlacklist> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper1.eq(LifeBlacklist :: getBlockerId, userId);
+        lambdaQueryWrapper1.eq(LifeBlacklist :: getBlockedPhoneId, "store_" + result.getStorePhone());
+        LifeBlacklist blacklist = lifeBlacklistMapper.selectOne(lambdaQueryWrapper1);
+        List<LifeUserDynamicsVo> storeDynamicslist = new ArrayList<>();
+
+        //判断没有拉黑当前门店账户 查出门店动态
+        if(blacklist == null){
+            storeDynamicslist = lifeUserDynamicsMapper.getStoreDynamicslist(userId, "store_" + result.getStorePhone());
+        }
 
         List<String> followList = new ArrayList<>();
         List<String> fansList = new ArrayList<>();
@@ -1234,8 +1248,14 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
             }
         }
 
-        List<LifeUserDynamicsVo> storeDynamicslist2 = storeDynamicslist.stream().limit(10).collect(Collectors.toList());
+        // 返回动态最新的5条
+        List<LifeUserDynamicsVo> storeDynamicslist2 = storeDynamicslist.stream()
+                .limit(5).collect(Collectors.toList());
         result.setDynamicsList(storeDynamicslist2);
+        //设置动态条数
+        Integer dynamicsNum = storeDynamicslist2.size();
+        result.setDynamicsNum(dynamicsNum);
+
         // 获取店铺动态总数
         result.setTotalDynamicsNum(storeDynamicslist.size());
 
@@ -1436,7 +1456,7 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         }
         String fileName = UUID.randomUUID().toString().replace("-", "");
         String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeInfoExpiredRecordsExcelVos, StoreInfoExpiredRecordsExcelVo.class);
-        String url = aliOSSUtil.uploadFile(new File(filePath), "/excel/" + fileName + ".xlsx");
+        String url = aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
         new File(filePath).delete();
         return url;
     }
@@ -1883,7 +1903,7 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         // 修改注销标记为0
         storeIn.setLogoutFlag(0);
         // 注销状态变为可用
-        storeIn.setStoreStatus(0);
+        storeIn.setStoreStatus(1);
         // 清空注销原因
         storeIn.setLogoutReason("");
         // 清空注销code

+ 2 - 3
alien-store/src/main/java/shop/alien/store/service/impl/StoreMenuServiceImpl.java

@@ -45,7 +45,6 @@ public class StoreMenuServiceImpl extends ServiceImpl<StoreMenuMapper, StoreMenu
 
     private final LifeGroupBuyThaliMapper lifeGroupBuyThaliMapper;
 
-
     /**
      * 获取门店菜单
      *
@@ -188,7 +187,6 @@ public class StoreMenuServiceImpl extends ServiceImpl<StoreMenuMapper, StoreMenu
         return R.success("新增菜品成功");
     }
 
-
     /**
      * 菜品排序信息
      *
@@ -229,7 +227,7 @@ public class StoreMenuServiceImpl extends ServiceImpl<StoreMenuMapper, StoreMenu
         if (dishType == 0) {
             List<LifeGroupBuyThali> lifeGroupBuyThaliList = lifeGroupBuyThaliMapper.selectList(new LambdaQueryWrapper<LifeGroupBuyThali>().in(LifeGroupBuyThali::getDetailId, ids));
             if (CollectionUtil.isNotEmpty(lifeGroupBuyThaliList)) {
-                return R.fail("该菜品已被团购套餐引用,不能删除");
+                return R.fail("当前菜品存在于团购中,不可删除");
             }
             flag = this.removeByIds(ids);
         } else {
@@ -246,6 +244,7 @@ public class StoreMenuServiceImpl extends ServiceImpl<StoreMenuMapper, StoreMenu
         }
         return R.success("删除成功");
     }
+
     @Override
     public StoreMenuVo getMenuCountByStoreId(int storeId) {
         StoreMenuVo storeMenuVo = new StoreMenuVo();

+ 2 - 3
alien-store/src/main/java/shop/alien/store/service/impl/StoreUserServiceImpl.java

@@ -1,6 +1,5 @@
 package shop.alien.store.service.impl;
 
-import cn.hutool.core.date.DateTime;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -429,7 +428,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         StoreUser storeUserById = storeUserMapper.selectById(storeUser.getId());
         //初始化密码赋值
         storeUserById.setPassword(DEFAULT_PASSWORD);
-        storeUserById.setPayPassword(DEFAULT_PASSWORD);
+//        storeUserById.setPayPassword(DEFAULT_PASSWORD);
         storeUserMapper.updateById(storeUserById);
     }
 
@@ -624,7 +623,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         registerStoreUser.setMoney(0);
         registerStoreUser.setDeleteFlag(0);
         registerStoreUser.setStatus(0);
-        registerStoreUser.setIdCard("test");
+        registerStoreUser.setIdCard("");
         registerStoreUser.setPassType(2);
         registerStoreUser.setCreatedTime(new Date());
         registerStoreUser.setLogoutFlag(0);

+ 16 - 15
alien-store/src/main/java/shop/alien/store/util/ali/AliApi.java

@@ -49,6 +49,7 @@ public class AliApi {
     private final LifeUserService lifeUserService;
 
     private final StoreAliPayErrorLogService storeAliPayErrorLogService;
+    
 
     /**
      * 商家端appId
@@ -195,16 +196,6 @@ 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);
-
             } else {
                 log.warn("AliPayConfig.processRefund ERROR Msg={}", response.getBody());
                 JSONObject jsonObject = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_trade_refund_response");
@@ -356,15 +347,25 @@ public class AliApi {
             model.setOrderTitle("商家转账");
             // 设置收款方信息
             Participant payeeInfo = new Participant();
-            payeeInfo.setCertType("IDENTITY_CARD");
-            payeeInfo.setCertNo(idCard);
-            payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
-            if(account!=null){
+            // 智能判断收款方类型
+            if (account.startsWith("2088") && account.length() == 16) {
+                // 如果是商户ID格式(2088开头的16位数字)
+                payeeInfo.setIdentityType("ALIPAY_USER_ID");
+                log.info("检测到收款方为商户ID: {}", account);
+//                payeeInfo.setName("爱丽恩严(大连)商务科技有限公司");
+            } else {
+                // 默认为支付宝账号(手机号或邮箱)
+                payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
+                log.info("检测到收款方为支付宝账号: {}", account);
+                payeeInfo.setCertType("IDENTITY_CARD");
+                payeeInfo.setCertNo(idCard);
+                payeeInfo.setName(name);
+            }
+            if(null != account){
                 payeeInfo.setIdentity(account);
             }else{
                 payeeInfo.setIdentity(phone);
             }
-            payeeInfo.setName(name);
             model.setPayeeInfo(payeeInfo);
             // 设置业务备注
             model.setRemark("爱丽恩提现业务");

+ 78 - 3
alien-store/src/main/java/shop/alien/store/util/ali/AliSms.java

@@ -13,9 +13,6 @@ import shop.alien.store.config.BaseRedisService;
 import shop.alien.store.config.NacosConfig;
 import shop.alien.util.common.RandomCreateUtil;
 
-import java.util.Arrays;
-import java.util.List;
-
 /**
  * 阿里云验证码配置
  *
@@ -91,6 +88,10 @@ public class AliSms {
                     //忘记密码
                     businessTypeStr = "forget_password";
                     break;
+                case 7:
+                    //忘记支付密码
+                    businessTypeStr = "forget_pay_password";
+                    break;
                 default:
                     businessTypeStr = "login";
             }
@@ -135,4 +136,78 @@ public class AliSms {
         }
     }
 
+    /**
+     * 校验短信验证码
+     *
+     * @param phone        手机号
+     * @param appType      端区分(0:用户, 1:商家)
+     * @param businessType 业务类型 (0:登录, 1:修改密码, 2:注册, 3:修改手机号, 4:注销店铺, 5:注销账号, 6:忘记密码)
+     * @param code         用户输入的验证码
+     * @return 校验结果 true-校验成功 false-校验失败
+     */
+    public boolean checkSmsCode(String phone, Integer appType, Integer businessType, Integer code) {
+        log.info("AliSms.checkSmsCode?phone={}&appType={}&businessType={}&code={}", phone, appType, businessType, code);
+        try {
+            // 构建Redis key,与sendSms方法中的key格式保持一致
+            String appTypeStr = appType == 0 ? "user" : "store";
+            String businessTypeStr;
+            switch (businessType) {
+                case 0:
+                    businessTypeStr = "login";
+                    break;
+                case 1:
+                    businessTypeStr = "modify_password";
+                    break;
+                case 2:
+                    businessTypeStr = "register";
+                    break;
+                case 3:
+                    businessTypeStr = "modify_phone";
+                    break;
+                case 4:
+                    businessTypeStr = "cancel_store";
+                    break;
+                case 5:
+                    businessTypeStr = "cancel_account";
+                    break;
+                case 6:
+                    businessTypeStr = "forget_password";
+                    break;
+                case 7:
+                    businessTypeStr = "forget_pay_password";
+                    break;
+                default:
+                    businessTypeStr = "login";
+            }
+            
+            String verifyKey = "verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone;
+            
+            // 从Redis中获取验证码
+            String cacheCode = baseRedisService.getString(verifyKey);
+            
+            // 验证码不存在或已过期
+            if (cacheCode == null || cacheCode.trim().isEmpty()) {
+                log.warn("验证码不存在或已过期,phone={}, appType={}, businessType={}", phone, appType, businessType);
+                return false;
+            }
+            
+            // 比较验证码(去除空格)
+            boolean isValid = cacheCode.trim().equals(String.valueOf(code).trim());
+            
+            if (isValid) {
+                // 验证成功,删除验证码(防止重复使用)
+                baseRedisService.delete(verifyKey);
+                log.info("验证码校验成功,phone={}, appType={}, businessType={}", phone, appType, businessType);
+            } else {
+                log.warn("验证码校验失败,phone={}, appType={}, businessType={}, 期望值={}, 实际值={}", 
+                        phone, appType, businessType, cacheCode, code);
+            }
+            
+            return isValid;
+        } catch (Exception e) {
+            log.error("AliSms.checkSmsCode ERROR Msg={}", e.getMessage(), e);
+            return false;
+        }
+    }
+
 }

+ 51 - 2
alien-util/src/main/java/shop/alien/util/ali/AliOSSUtil.java

@@ -46,7 +46,23 @@ public class AliOSSUtil {
      * @return filePath
      */
     public String uploadFile(MultipartFile multipartFile, String ossFilePath) {
+        // 验证参数
+        if (multipartFile == null || multipartFile.isEmpty()) {
+            log.error("AliOSSUtil.uploadFile ERROR: multipartFile is null or empty");
+            return null;
+        }
+        
+        if (StringUtils.isEmpty(ossFilePath)) {
+            log.error("AliOSSUtil.uploadFile ERROR: ossFilePath is empty");
+            return null;
+        }
+        
         File convertFile = FileUtil.convert(multipartFile);
+        if (convertFile == null) {
+            log.error("AliOSSUtil.uploadFile ERROR: convertFile is null");
+            return null;
+        }
+        
         return uploadFile(convertFile, ossFilePath);
     }
 
@@ -58,6 +74,39 @@ public class AliOSSUtil {
      * @return filePath
      */
     public String uploadFile(File file, String ossFilePath) {
+        // 验证参数
+        if (file == null) {
+            log.error("AliOSSUtil.uploadFile ERROR: file is null");
+            return null;
+        }
+        
+        if (StringUtils.isEmpty(ossFilePath)) {
+            log.error("AliOSSUtil.uploadFile ERROR: ossFilePath is empty");
+            return null;
+        }
+        
+        // 检查文件是否存在且不为空
+        if (!file.exists()) {
+            log.error("AliOSSUtil.uploadFile ERROR: file does not exist, path: {}", file.getAbsolutePath());
+            return null;
+        }
+        
+        if (file.length() == 0) {
+            log.error("AliOSSUtil.uploadFile ERROR: file is empty, path: {}", file.getAbsolutePath());
+            return null;
+        }
+        
+        // 验证ossFilePath格式 - 不能以/开头
+        if (ossFilePath.startsWith("/")) {
+            log.error("AliOSSUtil.uploadFile ERROR: ossFilePath cannot start with '/': {}", ossFilePath);
+            return null;
+        }
+        
+        if (ossFilePath.contains("..") || ossFilePath.contains("\\")) {
+            log.error("AliOSSUtil.uploadFile ERROR: invalid ossFilePath format: {}", ossFilePath);
+            return null;
+        }
+
         // 创建OSSClient实例。
         // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
         ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
@@ -76,7 +125,7 @@ public class AliOSSUtil {
             }
             return null;
         } catch (Exception e) {
-            log.error("AliOSSUtil.uploadFile ERROR: {}", e.getMessage());
+            log.error("AliOSSUtil.uploadFile ERROR: {}", e.getMessage(), e);
             return null;
         } finally {
             if (ossClient != null) {
@@ -85,4 +134,4 @@ public class AliOSSUtil {
         }
     }
 
-}
+}