Преглед изворни кода

Merge remote-tracking branch 'origin/master'

lyx пре 2 недеља
родитељ
комит
d4f8f8ae3c
26 измењених фајлова са 597 додато и 132 уклоњено
  1. 67 0
      alien-entity/src/main/java/shop/alien/entity/second/SecondGoodsAudit.java
  2. 17 5
      alien-entity/src/main/java/shop/alien/entity/second/SecondTradeRecord.java
  3. 5 0
      alien-entity/src/main/java/shop/alien/entity/store/LifeUserDynamics.java
  4. 2 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserDynamicsVo.java
  5. 9 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreSalesDetailsVo.java
  6. 6 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/WebsocketVo.java
  7. 2 1
      alien-entity/src/main/java/shop/alien/mapper/LifeBlacklistMapper.java
  8. 1 1
      alien-entity/src/main/java/shop/alien/mapper/LifeUserDynamicsMapper.java
  9. 2 1
      alien-entity/src/main/java/shop/alien/mapper/StoreSalesDetailsMapper.java
  10. 25 0
      alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsAuditMapper.java
  11. 12 0
      alien-second/src/main/java/shop/alien/second/controller/SearchGoodsController.java
  12. 35 10
      alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java
  13. 5 0
      alien-second/src/main/java/shop/alien/second/service/SecondGoodsService.java
  14. 7 4
      alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java
  15. 121 49
      alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java
  16. 61 14
      alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java
  17. 16 0
      alien-store/src/main/java/shop/alien/store/config/BaseRedisService.java
  18. 21 0
      alien-store/src/main/java/shop/alien/store/config/SpringContext.java
  19. 31 29
      alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java
  20. 15 5
      alien-store/src/main/java/shop/alien/store/controller/LifeMessageController.java
  21. 2 2
      alien-store/src/main/java/shop/alien/store/controller/StoreUserController.java
  22. 4 4
      alien-store/src/main/java/shop/alien/store/job/StoreMembershipCardJob.java
  23. 2 1
      alien-store/src/main/java/shop/alien/store/service/impl/LifeMessageServiceImpl.java
  24. 3 1
      alien-store/src/main/java/shop/alien/store/service/impl/StoreSalesDetailsServiceImpl.java
  25. 6 1
      alien-store/src/main/java/shop/alien/store/service/impl/StoreUserServiceImpl.java
  26. 120 4
      alien-store/src/main/java/shop/alien/store/task/ScheduledTask.java

+ 67 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondGoodsAudit.java

@@ -0,0 +1,67 @@
+package shop.alien.entity.second;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 二手商品审核记录
+ */
+@Data
+@JsonInclude
+@TableName("second_goods_audit")
+public class SecondGoodsAudit implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // 商品状态常量
+    public static final int GOODS_STATUS_SUCCESS = 1; // 审核成功
+    public static final int GOODS_STATUS_FAILED = 2;  // 审核失败
+
+    // 删除标记常量
+    public static final int DELETE_FLAG_NO = 0;  // 未删除
+    public static final int DELETE_FLAG_YES = 1; // 已删除
+
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键ID")
+    private Integer id;
+
+    @TableField("goods_id")
+    @ApiModelProperty(value = "商品ID")
+    private Integer goodsId;
+
+    @TableField("goods_status")
+    @ApiModelProperty(value = "商品状态 1:审核成功 2:审核失败")
+    private Integer goodsStatus;
+
+    @TableField("failed_reason")
+    @ApiModelProperty(value = "审核描述(失败原因)")
+    private String failedReason;
+
+    @TableField("delete_flag")
+    @ApiModelProperty(value = "删除标记 0:未删除 1:已删除")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "创建时间")
+    private Date createdTime;
+
+    @TableField("created_user_id")
+    @ApiModelProperty(value = "创建人ID")
+    private Integer createdUserId;
+
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "修改时间")
+    private Date updatedTime;
+
+    @TableField("updated_user_id")
+    @ApiModelProperty(value = "修改人ID")
+    private Integer updatedUserId;
+}

+ 17 - 5
alien-entity/src/main/java/shop/alien/entity/second/SecondTradeRecord.java

@@ -61,12 +61,12 @@ public class SecondTradeRecord extends Model<SecondTradeRecord> {
     private BigDecimal transactionAmount;
 
     @ApiModelProperty(value = "买家是否签到  0-未签到  1-已签到")
-    @TableField("buyer_signin")
-    private Integer buyerSignin;
+    @TableField("buyer_sign_in")
+    private Integer buyerSignIn;
 
     @ApiModelProperty(value = "卖家是否签到  0-未签到  1-已签到")
-    @TableField("seller_signin")
-    private Integer sellerSignin;
+    @TableField("seller_sign_in")
+    private Integer sellerSignIn;
 
     @ApiModelProperty(value = "买家交易状态  1-交易成功  2-交易失败")
     @TableField("buyer_transaction_status")
@@ -76,7 +76,7 @@ public class SecondTradeRecord extends Model<SecondTradeRecord> {
     @TableField("seller_transaction_status")
     private Integer sellerTransactionStatus;
 
-    @ApiModelProperty(value = "交易状态  0-待交易  1-交易成功  2-交易失败")
+    @ApiModelProperty(value = "交易状态  0-待交易  1-交易成功  2-交易失败  3-交易取消")
     @TableField("trade_status")
     private Integer tradeStatus;
 
@@ -84,6 +84,18 @@ public class SecondTradeRecord extends Model<SecondTradeRecord> {
     @TableField("buyer_evaluate")
     private String buyerEvaluate;
 
+    @ApiModelProperty(value = "取消交易id")
+    @TableField("cancel_id")
+    private Integer cancelId;
+
+    @ApiModelProperty(value = "取消交易原因(字典表_cancelTradeReason)")
+    @TableField("cancel_reason")
+    private String cancelReason;
+
+    @ApiModelProperty(value = "取消交易原因补充")
+    @TableField("cancel_reason_supplement")
+    private String cancelReasonSupplement;
+
     @ApiModelProperty(value = "卖家评价")
     @TableField("seller_evaluate")
     private String sellerEvaluate;

+ 5 - 0
alien-entity/src/main/java/shop/alien/entity/store/LifeUserDynamics.java

@@ -45,6 +45,11 @@ public class LifeUserDynamics {
     private String address;
 
     /**
+     * 地址详情
+     */
+    private String addressContext;
+
+    /**
      * 地址名称
      */
     private String addressName;

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

@@ -43,4 +43,6 @@ public class LifeUserDynamicsVo extends LifeUserDynamics {
     @ApiModelProperty(value = "内容")
     private String context;
 
+    @ApiModelProperty(value = "地址详情")
+    private String addressContext;
 }

+ 9 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreSalesDetailsVo.java

@@ -55,6 +55,9 @@ public class StoreSalesDetailsVo {
     @ApiModelProperty(value = "1-代金券  2-套餐")
     private Integer type;
 
+    @ApiModelProperty(value = "代金券套餐类型 (查询用)")
+    private List<String> typeList;
+
     @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
     @ApiModelProperty(value = "支付时间-开始时间")
     private Date payStartTime;
@@ -62,4 +65,10 @@ public class StoreSalesDetailsVo {
     @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
     @ApiModelProperty(value = "支付时间-结束时间")
     private Date payEndTime;
+
+    @ApiModelProperty(value = "预计收入")
+    private String expecteDrevenue;
+
+    @ApiModelProperty(value = "实付款")
+    private String finalPrice;
 }

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

@@ -14,9 +14,15 @@ public class WebsocketVo {
     @ApiModelProperty(value = "接收者id")
     private String receiverId;
 
+    @ApiModelProperty(value = "类别(消息-message 公告-notice 心跳-heartbeat)")
+    private String category;
+
     @ApiModelProperty(value = "消息类型  1-文本  2-图片  3-链接")
     private String type;
 
     @ApiModelProperty(value = "消息内容")
     private String text;
+
+    @ApiModelProperty(value = "消息id")
+    private Integer messageId;
 }

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

@@ -2,6 +2,7 @@ package shop.alien.mapper;
 
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import shop.alien.entity.store.LifeBlacklist;
 import shop.alien.entity.store.vo.LifeBlacklistVo;
@@ -34,5 +35,5 @@ public interface LifeBlacklistMapper extends BaseMapper<LifeBlacklist> {
             "left join life_user user on user.id = black.blocked_id and black.blocked_type = '2' and user.delete_flag = 0 " +
             "left join store_user suser on suser.id = black.blocked_id and black.blocked_type = '1' and suser.delete_flag = 0 " +
             "where black.blocker_type = #{userType} and black.blocker_id = #{userId} and black.delete_flag = 0 ")
-    List<LifeBlacklistVo> getPhoneIdByUserId(String userType, String userId);
+    List<LifeBlacklistVo> getPhoneIdByUserId(@Param("userType") String userType, @Param("userId") String userId);
 }

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

@@ -15,7 +15,7 @@ import java.util.List;
 public interface LifeUserDynamicsMapper extends BaseMapper<LifeUserDynamics> {
 
     @Select("with dynamice as( " +
-            "    select id, title, phone_id phoneId, context, image_path, address, liulan_count, dianzan_count, type, created_time, substring_index(phone_id, '_', 1) flag, substring_index(phone_id, '_', -1) phone, draft " +
+            "    select id, title, phone_id phoneId, context, image_path, address,address_context, liulan_count, dianzan_count, type, created_time, substring_index(phone_id, '_', 1) flag, substring_index(phone_id, '_', -1) phone, draft " +
             "    from life_user_dynamics " +
             "    where delete_flag = 0 and draft = 0 order by created_time desc" +
             ") " +

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

@@ -18,7 +18,8 @@ import shop.alien.entity.store.vo.StoreSalesDetailsVo;
 @Mapper
 public interface StoreSalesDetailsMapper extends BaseMapper<LifeUserOrder> {
 
-    @Select("select coupon.name couponName, luser.user_phone userPhone, lorder.order_no orderNo, lorder.pay_time payTime, lorder.price, lorder.status " +
+    @Select("select coupon.name couponName, luser.user_phone userPhone, lorder.order_no orderNo, lorder.pay_time payTime, lorder.price, " +
+            "lorder.final_price finalPrice, (lorder.final_price*0.97)  expecteDrevenue, lorder.status " +
             "from life_user_order lorder " +
             "join life_coupon coupon on coupon.id = lorder.quan_id " +
             "join life_user luser on luser.id = lorder.user_id ${ew.customSqlSegment}")

+ 25 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsAuditMapper.java

@@ -0,0 +1,25 @@
+package shop.alien.mapper.second;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import shop.alien.entity.second.SecondGoodsAudit;
+
+/**
+ * 二手商品审核记录映射器
+ */
+@Mapper
+public interface SecondGoodsAuditMapper extends BaseMapper<SecondGoodsAudit> {
+
+    /**
+     * 根据商品ID查询最新审核记录
+     *
+     * @param goodsId 商品ID
+     * @return 最新审核记录
+     */
+    @Select("SELECT * FROM second_goods_audit " +
+            "WHERE goods_id = #{goodsId} AND delete_flag = 0 " +
+            "ORDER BY created_time DESC LIMIT 1")
+    SecondGoodsAudit getLatestByGoodsId(@Param("goodsId") Integer goodsId);
+}

+ 12 - 0
alien-second/src/main/java/shop/alien/second/controller/SearchGoodsController.java

@@ -69,4 +69,16 @@ public class SearchGoodsController {
         return R.data(secondGoodsService.getCollectTop10(), "获取成功");
     }
 
+    /**
+     * 查询商品列表
+     */
+    @GetMapping("/getGoodsListByUserId")
+    @ApiOperation("查询商品列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "goodsStatus", value = "商品状态 0:草稿 1:审核中 2:审核失败 3:已上架 4:已下架 5:已售出", dataType = "Integer", paramType = "query")})
+    public R<List<SecondGoods>> getGoodsListByUserId(Integer userId, Integer goodsStatus) {
+        return R.data(secondGoodsService.getGoodsListByUserId(userId, goodsStatus), "获取成功");
+    }
+
 }

+ 35 - 10
alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java

@@ -35,7 +35,7 @@ public class SecondTradeRecordController {
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({@ApiImplicitParam(name = "sideId", value = "对方的id", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/getTradeRecord")
-    public R<List<SecondTradeRecord>> getTradeRecord(@RequestParam int sideId) {
+    public R<List<SecondTradeRecord>> getTradeRecord(@RequestParam int sideId) throws Exception {
         log.info("SecondTradeRecordController.getTradeRecord?sideId={}", sideId);
         return R.data(secondTradeRecordService.getTradeRecord(sideId));
     }
@@ -43,32 +43,57 @@ public class SecondTradeRecordController {
     @ApiOperation("创建交易")
     @ApiOperationSupport(order = 2)
     @PostMapping("/createTrade")
-    public R<Boolean> createTrade(@RequestBody SecondTradeRecord entity) {
+    public R<Boolean> createTrade(@RequestBody SecondTradeRecord entity) throws Exception {
         log.info("SecondTradeRecordController.createTrade?entity={}", entity.toString());
         if (secondTradeRecordService.createTrade(entity)) return R.success("创建成功");
         return R.fail("创建失败");
     }
 
-    @ApiOperation("交易签到")
+
+    @ApiOperation("确认商品是否可以交易")
     @ApiOperationSupport(order = 3)
-    @ApiImplicitParams({@ApiImplicitParam(name = "tradeId", value = "交易id", dataType = "Integer", paramType = "query", required = true)})
-    @GetMapping("/tradeSignin")
-    public R<Boolean> tradeSignin(@RequestParam int tradeId) {
-        log.info("SecondTradeRecordController.tradeSignin?tradeId={}", tradeId);
-        if (secondTradeRecordService.tradeSignin(tradeId)) return R.success("签到成功");
+    @ApiImplicitParams({@ApiImplicitParam(name = "goodsId", value = "商品id", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/goodsTradeConfirm")
+    public R<Boolean> goodsTradeConfirm(@RequestParam int goodsId) throws Exception {
+        log.info("SecondTradeRecordController.goodsTradeConfirm?goodsId={}", goodsId);
+        return R.data(secondTradeRecordService.goodsTradeConfirm(goodsId));
+    }
+
+    @ApiOperation("交易签到")
+    @ApiOperationSupport(order = 4)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "tradeId", value = "交易id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "messageId", value = "消息id", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/tradeSignIn")
+    public R<Boolean> tradeSignIn(@RequestParam int tradeId, int messageId) throws Exception {
+        log.info("SecondTradeRecordController.tradeSignIn?tradeId={}, messageId={}", tradeId, messageId);
+        if (secondTradeRecordService.tradeSignIn(tradeId, messageId)) return R.success("签到成功");
         return R.fail("签到失败");
     }
 
     @ApiOperation("交易确认")
-    @ApiOperationSupport(order = 4)
+    @ApiOperationSupport(order = 5)
     @ApiImplicitParams({
             @ApiImplicitParam(name = "tradeId", value = "交易id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "type", value = "0-失败  1-成功", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "evaluate", value = "评价", dataType = "String", paramType = "query")})
     @GetMapping("/tradeConfirm")
-    public R<Boolean> tradeConfirm(@RequestParam int tradeId, @RequestParam int type, @RequestParam String evaluate) {
+    public R<Boolean> tradeConfirm(@RequestParam int tradeId, @RequestParam int type, @RequestParam String evaluate) throws Exception {
         log.info("SecondTradeRecordController.tradeConfirm?tradeId={}, type={}, evaluate={}", tradeId, type, evaluate);
         if (secondTradeRecordService.tradeConfirm(tradeId, type, evaluate)) return R.success("交易确认成功");
         return R.fail("交易确认失败");
     }
+
+    @ApiOperation("取消交易")
+    @ApiOperationSupport(order = 6)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "tradeId", value = "交易id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "cancelReason", value = "取消原因", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "cancelReasonSupplement", value = "取消原因补充", dataType = "String", paramType = "query")})
+    @GetMapping("/cancelTrade")
+    public R<Boolean> cancelTrade(@RequestParam int tradeId, @RequestParam String cancelReason, String cancelReasonSupplement) throws Exception {
+        log.info("SecondTradeRecordController.cancelTrade?tradeId={}, cancelReason={}, cancelReasonSupplement={}", tradeId, cancelReason, cancelReasonSupplement);
+        if (secondTradeRecordService.cancelTrade(tradeId, cancelReason, cancelReasonSupplement)) return R.success("取消交易成功");
+        return R.fail("取消交易失败");
+    }
 }

+ 5 - 0
alien-second/src/main/java/shop/alien/second/service/SecondGoodsService.java

@@ -2,6 +2,8 @@ package shop.alien.second.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.models.auth.In;
+import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.vo.SecondGoodsVo;
 import shop.alien.entity.second.vo.SellGoodsVo;
@@ -19,6 +21,7 @@ public interface SecondGoodsService extends IService<SecondGoods> {
      * @param editFlag 编辑标识 0:创建 1:编辑
      * @return 是否成功保存
      */
+    @Transactional
     boolean createBasicInfo(SecondGoodsVo goods, Integer editFlag) throws Exception;
 
     /**
@@ -144,4 +147,6 @@ public interface SecondGoodsService extends IService<SecondGoods> {
      * @return 分页后的商品交易列表
      */
     IPage<SellGoodsVo> getTransactionList(IPage<SellGoodsVo> page, Integer userId);
+
+    List<SecondGoods> getGoodsListByUserId(Integer userId, Integer goodsStatus);
 }

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

@@ -16,12 +16,15 @@ import java.util.List;
  * @since 2025-07-07
  */
 public interface SecondTradeRecordService extends IService<SecondTradeRecord> {
-    List<SecondTradeRecord> getTradeRecord(int sideId);
+    List<SecondTradeRecord> getTradeRecord(int sideId) throws Exception;
 
-    boolean createTrade(SecondTradeRecord entity);
+    boolean createTrade(SecondTradeRecord entity) throws Exception;
 
-    boolean tradeSignin(int tradeId);
+    boolean tradeSignIn(int tradeId, int messageId) throws Exception;
 
-    boolean tradeConfirm(int tradeId, int type, String evaluate);
+    boolean tradeConfirm(int tradeId, int type, String evaluate) throws Exception;
 
+    boolean goodsTradeConfirm(int goodsId) throws Exception;
+
+    boolean cancelTrade(int tradeId, String cancelReason, String cancelReasonSupplement) throws Exception;
 }

+ 121 - 49
alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java

@@ -1,6 +1,7 @@
 package shop.alien.second.service.impl;
 
 import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -13,11 +14,13 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.second.SecondGoods;
+import shop.alien.entity.second.SecondGoodsAudit;
 import shop.alien.entity.second.vo.SecondGoodsVo;
 import shop.alien.entity.second.vo.SellGoodsVo;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.LifeUserVo;
 import shop.alien.mapper.*;
+import shop.alien.mapper.second.SecondGoodsAuditMapper;
 import shop.alien.mapper.second.SecondGoodsMapper;
 import shop.alien.second.service.SecondGoodsService;
 import shop.alien.util.common.VideoUtils;
@@ -56,6 +59,11 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     private final SecondGoodsMapper secondGoodsMapper;
 
     /**
+     * 二手商品审核Mapper
+     */
+    private final SecondGoodsAuditMapper secondGoodsAuditMapper;
+
+    /**
      * 用户信息Mapper
      */
     private final LifeUserMapper lifeUserMapper;
@@ -111,60 +119,54 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
 
     @Override
     public boolean createBasicInfo(SecondGoodsVo goodsDTO,Integer editFlag) throws Exception {
-        // 实现基本信息保存逻辑
-        SecondGoods goods = new SecondGoods();
-        BeanUtils.copyProperties(goodsDTO, goods);
-
-        if (editFlag == 1){
-            goods.setId(goodsDTO.getId());
-            // 保存商品基本信息
-            if (!updateById(goods)) {
-                return false; // 保存失败直接返回
-            }
-        } else {
-            // 保存商品基本信息
-            if (!save(goods)) {
-                return false; // 保存失败直接返回
+        try {
+            // 实现基本信息保存逻辑
+            SecondGoods goods = new SecondGoods();
+            BeanUtils.copyProperties(goodsDTO, goods);
+
+            if (editFlag == 1) {
+                goods.setId(goodsDTO.getId());
+                goods = secondGoodsMapper.selectById(goodsDTO.getId());
+                // 保存商品基本信息
+                if (!updateById(goods)) {
+                    return false; // 保存失败直接返回
+                }
+            } else {
+                // 保存商品基本信息
+                if (!save(goods)) {
+                    return false; // 保存失败直接返回
+                }
             }
-        }
 
-        // 获取保存后的商品ID,用于后续业务处理
-        Integer savedGoodsId = goods.getId();
-        if (savedGoodsId == null) {
-            return false; // 如果获取不到ID,视为操作失败
-        }
-
-        // 保存商品图片信息
-        if (!saveStoreImages(savedGoodsId, goodsDTO.getImgUrl())) {
-            return false;
-        }
-        // 二手业务安全验证(调取阿里)
-        if (!checkSafety(goods)) {
-            return false;
-        }
+            // 获取保存后的商品ID,用于后续业务处理
+            Integer savedGoodsId = goods.getId();
+            if (savedGoodsId == null) {
+                return false; // 如果获取不到ID,视为操作失败
+            }
 
-        // 执行内容审核(图片和文本)
-        if (!performContentReviews(goods, goodsDTO)) {
-            return true; // 审核不通过时已设置状态,返回成功但标记为审核失败
-        }
+            // 保存商品图片信息
+            if (!saveStoreImages(savedGoodsId, goodsDTO.getImgUrl())) {
+                return false;
+            }
 
-        // 如果所有审核都通过,设置为上架状态
-        goods.setGoodsStatus(3); // 上架
-        goods.setReleaseTime(new Date()); // 上架时间
-        updateById(goods);
+            // 执行内容审核(图片和文本)
+            if (!performContentReviews(goods, goodsDTO)) {
+                return true; // 审核不通过时已设置状态,返回成功但标记为审核失败
+            }
 
-        // 发送消息
-        sendMessage(goods);
-        return true;
-    }
+            // 如果所有审核都通过,设置为上架状态
+            goods.setGoodsStatus(3); // 上架
+            goods.setReleaseTime(new Date()); // 上架时间
+            updateById(goods);
 
-    /**
-     * 二手业务安全验证 (调取阿里)
-     * @param goods 商品信息
-     * @return 验证结果
-     */
-    private boolean checkSafety(SecondGoods goods) {
-        return true;
+            // 发送消息
+            sendMessage(goods);
+            return true;
+        } catch (Exception e) {
+            // 记录异常日志
+            log.error("创建或更新二手商品基本信息时发生异常", e);
+            return false;
+        }
     }
     /**
      * 执行内容审核(图片和文本)
@@ -183,6 +185,10 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             // 文本审核不通过或存在高风险
             goods.setGoodsStatus(2); // 审核失败
             goods.setFailedReason("文本审核不通过:" + (textCheckResult.getRiskWords() != null ? textCheckResult.getRiskWords() : "存在高风险内容"));
+            // 插入审核记录
+            createGoodsAudit(goods, textCheckResult.getRiskWords());
+            // 发送审核失败消息
+            sendFailedMsg(goods);
             return false;
         }
 
@@ -196,6 +202,10 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                     // 文本审核不通过或存在高风险
                     goods.setGoodsStatus(2); // 审核失败
                     goods.setFailedReason("图片审核不通过:图片中包含" + (response.getDescriptions() != null ? response.getDescriptions() : "高风险内容"));
+                    // 插入审核记录
+                    createGoodsAudit(goods, response.getDescriptions());
+                    // 发送审核失败消息
+                    sendFailedMsg(goods);
                     return false;
                 }
             }
@@ -208,6 +218,27 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
+     * 创建商品审核记录
+     *
+     * @param goods 商品
+     * @param riskWords 文本审核结果
+     */
+    private void createGoodsAudit(SecondGoods goods, String riskWords) {
+        // 保存审核结果
+        secondGoodsMapper.updateById(goods);
+        // 插入审核记录
+        SecondGoodsAudit auditRecord = new SecondGoodsAudit();
+        auditRecord.setGoodsId(goods.getId());
+        auditRecord.setGoodsStatus(2); // 审核失败
+        auditRecord.setFailedReason("文本审核不通过:" + (riskWords != null ? riskWords : "存在高风险内容"));
+        auditRecord.setCreatedUserId(goods.getUserId());
+        auditRecord.setUpdatedUserId(goods.getUserId());
+        auditRecord.setCreatedTime(new Date());
+        auditRecord.setUpdatedTime(new Date());
+        secondGoodsAuditMapper.insert(auditRecord);
+    }
+
+    /**
      * 保存商品图片信息
      * @param savedGoodsId 保存后的商品ID
      * @param imgUrl 图片URL列表
@@ -261,12 +292,36 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
         lifeNotice.setReceiverId("user_"+ phone);
         lifeNotice.setBusinessId(goods.getId());
         lifeNotice.setTitle("商品发布通知");
-        lifeNotice.setContext("您有一笔新二手商品发成功,请及时查看");
+        lifeNotice.setContext("恭喜您的商品发成功");
         lifeNotice.setNoticeType(1); // 系统通知
         lifeNotice.setIsRead(0);
         lifeNoticeMapper.insert(lifeNotice);
     }
 
+
+    /**
+     * 发送审核失败消息
+     * @param goods 商品审核信息
+     */
+    private void sendFailedMsg(SecondGoods goods) {
+        // 根据 goods.getUserId() 获取用户信息
+        LifeUser lifeUser = lifeUserMapper.selectById(goods.getUserId());
+        String phone = lifeUser.getUserPhone();
+        // 调取feign接口 发送消息 life_notice表
+        LifeNotice lifeNotice = new LifeNotice();
+        lifeNotice.setSenderId("system");
+        lifeNotice.setReceiverId("user_"+ phone);
+        lifeNotice.setBusinessId(goods.getId());
+        lifeNotice.setTitle("商品审核通知");
+        // TODO: 失败原因本期为固定文案,实际原因暂不保存
+//        lifeNotice.setContext("商品审核失败,原因为:" + goods.getFailedReason());
+        lifeNotice.setContext("抱歉您的商品发布失败,图片或文字存在违规行为。请您修改后从新发布");
+        lifeNotice.setNoticeType(1); // 系统通知
+        lifeNotice.setIsRead(0);
+        lifeNoticeMapper.insert(lifeNotice);
+    }
+
+
     /**
      * 判断并获取商品封面图(若第一个链接是视频,则取第一帧)
      * @param imgUrl 商品图片/视频链接列表
@@ -609,6 +664,23 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
         return result;
     }
 
+    @Override
+    public List<SecondGoods> getGoodsListByUserId(Integer userId, Integer goodsStatus) {
+        // 获取商品屏蔽列表
+        List<SecondGoods> shieldedGoodsList = getShieldedGoodsList(userId);
+        // 提取屏蔽商品ID
+        List<Integer> shieldedGoodsIds = shieldedGoodsList.stream()
+                .map(SecondGoods::getId)
+                .collect(Collectors.toList());
+
+        LambdaQueryWrapper<SecondGoods> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SecondGoods::getUserId, userId);
+        queryWrapper.eq(SecondGoods::getGoodsStatus, goodsStatus);
+        queryWrapper.notIn(CollectionUtil.isNotEmpty(shieldedGoodsIds), SecondGoods::getId, shieldedGoodsIds);
+        queryWrapper.orderByDesc(SecondGoods::getReleaseTime);
+        return secondGoodsMapper.selectList(queryWrapper);
+    }
+
     /**
      * 查询搜索结果
      * @param page 分页参数

+ 61 - 14
alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java

@@ -1,17 +1,22 @@
 package shop.alien.second.service.impl;
 
+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.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.SecondTradeRecord;
+import shop.alien.entity.store.LifeMessage;
+import shop.alien.mapper.LifeMessageMapper;
 import shop.alien.mapper.second.SecondGoodsMapper;
 import shop.alien.mapper.second.SecondTradeRecordMapper;
 import shop.alien.second.service.SecondTradeRecordService;
 import shop.alien.util.common.JwtUtil;
 
+import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 
@@ -30,9 +35,10 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
 
     private final SecondTradeRecordMapper secondTradeRecordMapper;
     private final SecondGoodsMapper secondGoodsMapper;
+    private final LifeMessageMapper lifeMessageMapper;
 
     @Override
-    public List<SecondTradeRecord> getTradeRecord(int sideId) {
+    public List<SecondTradeRecord> getTradeRecord(int sideId) throws Exception {
         try {
             int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
             QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
@@ -40,8 +46,8 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             wrapper.orderByDesc("created_time");
             return secondTradeRecordMapper.selectList(wrapper);
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.getTradeRecord===", e.fillInStackTrace());
-            return null;
+            log.error("SecondTradeRecordServiceImpl.getTradeRecord Error Mgs={}", e.getMessage());
+            throw new Exception(e);
         }
     }
 
@@ -51,7 +57,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
      * @return 操作结果
      */
     @Override
-    public boolean createTrade(SecondTradeRecord entity) {
+    public boolean createTrade(SecondTradeRecord entity) throws Exception {
         try {
             secondTradeRecordMapper.insert(entity);
             SecondGoods goods = new SecondGoods();
@@ -60,34 +66,44 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             secondGoodsMapper.updateById(goods);
             return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.createTrade===", e.fillInStackTrace());
+            log.error("SecondTradeRecordServiceImpl.createTrade Error Mgs={}", e.getMessage());
+            throw new Exception(e);
         }
-        return false;
     }
 
     @Override
-    public boolean tradeSignin(int tradeId) {
+    public boolean tradeSignIn(int tradeId, int messageId) throws Exception {
         try {
             int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
             SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
             SecondTradeRecord record = new SecondTradeRecord();
             record.setId(tradeId);
             if (userId == tradeRecord.getBuyerId()) {
-                record.setBuyerSignin(1);
+                record.setBuyerSignIn(1);
             } else if (userId == tradeRecord.getSellerId()) {
-                record.setSellerSignin(1);
+                record.setSellerSignIn(1);
             } else {
                 return false;
             }
             secondTradeRecordMapper.updateById(record);
+
+//            LifeMessage message = new LifeMessage();
+//            message.setId(messageId);
+//            message.setContent(messageContent);
+//            message.setType("6");
+//            message.setCreatedTime(new Date());
+//            lifeMessageMapper.updateById(message);
+            lifeMessageMapper.deleteById(messageId);
+
+            return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.tradeSignin===", e.fillInStackTrace());
+            log.error("SecondTradeRecordServiceImpl.tradeSignIn Error Mgs={}", e.getMessage());
+            throw new Exception(e);
         }
-        return true;
     }
 
     @Override
-    public boolean tradeConfirm(int tradeId, int type, String evaluate) {
+    public boolean tradeConfirm(int tradeId, int type, String evaluate) throws Exception {
         try {
             int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
             SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
@@ -104,9 +120,40 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
                 return false;
             }
             secondTradeRecordMapper.updateById(record);
+            return true;
+        } catch (Exception e) {
+            log.error("SecondTradeRecordServiceImpl.tradeConfirm Error Mgs={}", e.getMessage());
+            throw new Exception(e);
+        }
+    }
+
+    @Override
+    public boolean goodsTradeConfirm(int goodsId) throws Exception {
+        try {
+            LambdaQueryWrapper<SecondTradeRecord> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(SecondTradeRecord::getGoodsId, goodsId);
+            queryWrapper.in(SecondTradeRecord::getTradeStatus, 0, 1);
+            return secondTradeRecordMapper.selectCount(queryWrapper) == 0;
+        } catch (Exception e) {
+            log.error("SecondTradeRecordServiceImpl.goodsTrade Error Mgs={}", e.getMessage());
+            throw new Exception(e);
+        }
+    }
+
+    @Override
+    public boolean cancelTrade(int tradeId, String cancelReason, String cancelReasonSupplement) throws Exception {
+        try {
+            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
+            SecondTradeRecord record = new SecondTradeRecord();
+            record.setId(tradeId);
+            record.setTradeStatus(3);
+            record.setCancelId(userId);
+            record.setCancelReason(cancelReason);
+            record.setCancelReasonSupplement(cancelReasonSupplement);
+            return secondTradeRecordMapper.updateById(record) > 0;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.tradeConfirm===", e.fillInStackTrace());
+            log.error("SecondTradeRecordServiceImpl.cancelTrade Error Mgs={}", e.getMessage());
+            throw new Exception(e);
         }
-        return true;
     }
 }

+ 16 - 0
alien-store/src/main/java/shop/alien/store/config/BaseRedisService.java

@@ -4,8 +4,11 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.geo.*;
 import org.springframework.data.redis.connection.RedisGeoCommands;
 import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.data.redis.core.script.RedisScript;
 import org.springframework.stereotype.Component;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -32,6 +35,19 @@ public class BaseRedisService {
     }
 
     /**
+     * 取出并删除列表中的所有元素(原子操作)
+     */
+    public List<String> popBatchFromList(String key) {
+        String luaScript =
+                "local elements = redis.call('LRANGE', KEYS[1], 0, -1) " +
+                        "redis.call('DEL', KEYS[1]) " +
+                        "return elements ";
+
+        RedisScript<List> script = RedisScript.of(luaScript, List.class);
+        return stringRedisTemplate.execute(script, Collections.singletonList(key));
+    }
+
+    /**
      * 添加List, 所有
      *
      * @param key   键

+ 21 - 0
alien-store/src/main/java/shop/alien/store/config/SpringContext.java

@@ -0,0 +1,21 @@
+package shop.alien.store.config;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringContext implements ApplicationContextAware {
+
+    private static ApplicationContext context;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        context = applicationContext;
+    }
+
+    public static <T> T getBean(Class<T> beanClass) {
+        return context.getBean(beanClass);
+    }
+}

+ 31 - 29
alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java

@@ -1,12 +1,9 @@
 package shop.alien.store.config;
 
 import com.alibaba.fastjson2.JSONObject;
-import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.ObjectUtils;
-import shop.alien.entity.result.R;
 import shop.alien.entity.store.LifeMessage;
 import shop.alien.entity.store.vo.WebsocketVo;
 import shop.alien.mapper.LifeMessageMapper;
@@ -28,8 +25,9 @@ import java.util.concurrent.ConcurrentHashMap;
 @ServerEndpoint(value = "/socket/{sendId}")
 public class WebSocketProcess {
 
-    @Autowired
-    private LifeMessageMapper lifeMessageMapper;
+    private final LifeMessageMapper lifeMessageMapper = SpringContext.getBean(LifeMessageMapper.class);
+
+    private final BaseRedisService baseRedisService = SpringContext.getBean(BaseRedisService.class);
 
     /*
      * 持有每个webSocket对象,以key-value存储到线程安全ConcurrentHashMap,
@@ -49,7 +47,7 @@ public class WebSocketProcess {
         //每新建立一个连接,就把当前客户id为key,this为value存储到map中
         this.session = session;
         concurrentHashMap.put(id, this);
-        log.info("Open a websocket. id={}", id);
+        log.info("WebSocketProcess.onOpen() Open a websocket. id={}", id);
     }
 
     /**
@@ -59,47 +57,52 @@ public class WebSocketProcess {
     public void onClose(Session session, @PathParam("sendId") String id) {
         //客户端连接关闭时,移除map中存储的键值对
         concurrentHashMap.remove(id);
-        log.info("close a websocket, concurrentHashMap remove sessionId= {}", id);
+        log.info("WebSocketProcess.onClose() close a websocket, concurrentHashMap remove sessionId= {}", id);
+    }
+
+    /**
+     * 连接发生异常时候触发
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error("WebSocketProcess.onError() Error Mgs=", error);
     }
 
     /**
      * 接收到客户端消息时触发
      */
     @OnMessage
-    public R<String> onMessage(String message) throws Exception {
+    public void onMessage(String message) throws Exception {
         try {
+            // 过滤心跳
             WebsocketVo websocketVo = JSONObject.parseObject(message, WebsocketVo.class);
-            JSONObject jsonObject = new JSONObject();
-            jsonObject.put("type", websocketVo.getType());
-            jsonObject.put("text", websocketVo.getText());
-            sendMessage(websocketVo.getReceiverId(), jsonObject.toJSONString());
+            if (null == websocketVo || "heartbeat".equals(websocketVo.getCategory())) return;
+
+            // 记录已读消息id
+            if ("receipt".equals(websocketVo.getCategory())) {
+                baseRedisService.setListRight("readMessageIdKey", String.valueOf(websocketVo.getMessageId()));
+                return;
+            }
 
+            // 保存消息记录
             LifeMessage lifeMessage = new LifeMessage();
             lifeMessage.setSenderId(websocketVo.getSenderId());
             lifeMessage.setReceiverId(websocketVo.getReceiverId());
             lifeMessage.setContent(websocketVo.getText());
             lifeMessage.setType(websocketVo.getType());
             lifeMessageMapper.insert(lifeMessage);
-            return R.success("发送成功");
+
+            // 发送消息
+            websocketVo.setMessageId(lifeMessage.getId());
+            websocketVo.setCategory("message");
+            sendMessage(websocketVo.getReceiverId(), JSONObject.from(websocketVo).toJSONString());
         } catch (Exception e) {
-            log.error("WebSocketController_sendMsgToClientById Error Mgs={}", e.getMessage());
+            log.error("WebSocketProcess.onMessage() Error Mgs={}", e.getMessage());
         }
-        return R.fail("发送失败");
-    }
-
-    /**
-     * 连接发生异常时候触发
-     */
-    @OnError
-    public void onError(Session session, Throwable error) {
-        log.error("Error while websocket. ", error);
     }
 
     /**
      * 发送消息到指定客户端
-     *
-     * @param id
-     * @param message
      */
     public void sendMessage(String id, String message) throws Exception {
         //根据id,从map中获取存储的webSocket对象
@@ -109,10 +112,10 @@ public class WebSocketProcess {
             if (webSocketProcess.session.isOpen()) {
                 webSocketProcess.session.getBasicRemote().sendText(message);
             } else {
-                log.error("websocket session={} is closed ", id);
+                log.error("WebSocketProcess.sendMessage() websocket session={} is closed ", id);
             }
         } else {
-            log.error("websocket session={} is not exit ", id);
+            log.error("WebSocketProcess.sendMessage() websocket session={} is not exit ", id);
         }
     }
 
@@ -120,7 +123,6 @@ public class WebSocketProcess {
      * 发送消息到所有客户端
      */
     public void sendAllMessage(String msg) throws Exception {
-//        log.info("online client count={}", concurrentHashMap.size());
         Set<Map.Entry<String, WebSocketProcess>> entries = concurrentHashMap.entrySet();
         for (Map.Entry<String, WebSocketProcess> entry : entries) {
             String cid = entry.getKey();

+ 15 - 5
alien-store/src/main/java/shop/alien/store/controller/LifeMessageController.java

@@ -6,6 +6,7 @@ import io.swagger.annotations.*;
 import io.swagger.models.auth.In;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.Nullable;
 import org.springframework.messaging.handler.annotation.MessageMapping;
 import org.springframework.messaging.handler.annotation.SendTo;
 import org.springframework.web.bind.annotation.*;
@@ -14,6 +15,7 @@ import shop.alien.entity.store.LifeMessage;
 import shop.alien.entity.store.vo.LifeMessageVo;
 import shop.alien.mapper.LifeMessageMapper;
 import shop.alien.store.service.LifeMessageService;
+import shop.alien.store.task.ScheduledTask;
 
 import java.util.List;
 
@@ -29,18 +31,20 @@ import java.util.List;
 public class LifeMessageController {
 
     private final LifeMessageService lifeMessageService;
+    private final ScheduledTask scheduledTask;
 
     @ApiOperation("消息列表")
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({
             @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "friendType", value = "聊天类型 1-聊过 2-未聊过", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "friendType", value = "聊天类型  0-搜索 1-聊过 2-未聊过", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "search", value = "搜索字段", dataType = "Integer", paramType = "query")})
     @GetMapping("/getMessageList")
     public R<List<LifeMessageVo>> getMessageList(@RequestParam String receiverId,
                                                   @RequestParam int friendType,
-                                                  @RequestParam String search) throws Exception {
+                                                  String search) throws Exception {
         log.info("LifeMessageController.getMessageList?receiverId={}, friendType={}, search={}", receiverId, friendType, search);
+        scheduledTask.secondTradeRemind();
         return R.data(lifeMessageService.getMessageList(receiverId, friendType, search));
     }
 
@@ -64,7 +68,9 @@ public class LifeMessageController {
 
     @ApiOperation("消息详情")
     @ApiOperationSupport(order = 4)
-    @ApiImplicitParams({@ApiImplicitParam(name = "当前登录人", value = "receiverId", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "当前登录人", value = "receiverId", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/getMessageListByReceiverId")
     public R<List<LifeMessageVo>> getMessageListByReceiverId(@RequestParam String receiverId, @RequestParam String senderId) throws Exception {
         log.info("LifeMessageController.getMessageListByReceiverId?receiverId={}, senderId={}", receiverId, senderId);
@@ -73,7 +79,9 @@ public class LifeMessageController {
 
     @ApiOperation("消息已读")
     @ApiOperationSupport(order = 5)
-    @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/read")
     public R<Boolean> read(@RequestParam String receiverId, @RequestParam String senderId) throws Exception {
         log.info("LifeMessageController.read?receiverId={}, senderId={}", receiverId, senderId);
@@ -83,7 +91,9 @@ public class LifeMessageController {
 
     @ApiOperation("删除消息")
     @ApiOperationSupport(order = 6)
-    @ApiImplicitParams({@ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
     @GetMapping("/deleteMessageByPhoneId")
     public R<Integer> deleteMessageByPhoneId(@RequestParam String senderId, @RequestParam String receiverId) throws Exception {
         log.info("LifeMessageController.deleteMessageByPhoneId?senderId={},receiverId={}", senderId, receiverId);

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

@@ -106,9 +106,9 @@ public class StoreUserController {
         boolean flag = false;
         flag = storeUserService.forgetOrModifyPassword(phone, newPhone, oldPassword, newPassword, confirmNewPassword, verificationCode, type);
         if(flag){
-            return R.success("密码修改成功");
+            return R.success("修改成功");
         }else {
-            return R.success("密码修改失败");
+            return R.success("修改失败");
         }
     }
 

+ 4 - 4
alien-store/src/main/java/shop/alien/store/job/StoreMembershipCardJob.java

@@ -130,10 +130,10 @@ public class StoreMembershipCardJob {
             if (null != storeUser.getLogoutTime()) {
                 // 获取申请注销时间
                 Date logoutTime = storeUser.getLogoutTime();
-                // 获取申请注销 7 天后的时间
+                // 获取申请注销 8 天后的时间
                 Calendar calendar = Calendar.getInstance();
                 calendar.setTime(logoutTime);
-                calendar.add(Calendar.DAY_OF_YEAR, 7);
+                calendar.add(Calendar.DAY_OF_YEAR, 8);
                 Date sevenDay = calendar.getTime();
                 // 获取当前时间
                 Date date = new Date();
@@ -151,10 +151,10 @@ public class StoreMembershipCardJob {
             if (null != storeInfo.getLogoutTime()) {
                 // 获取申请注销时间
                 Date logoutTime = storeInfo.getLogoutTime();
-                // 获取申请注销 7 天后的时间
+                // 获取申请注销 8 天后的时间
                 Calendar calendar = Calendar.getInstance();
                 calendar.setTime(logoutTime);
-                calendar.add(Calendar.DAY_OF_YEAR, 7);
+                calendar.add(Calendar.DAY_OF_YEAR, 8);
                 Date sevenDay = calendar.getTime();
                 // 获取当前时间
                 Date date = new Date();

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

@@ -229,6 +229,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
             LifeMessageVo vo = new LifeMessageVo();
             if (!CollectionUtils.isEmpty(lifeMessagePageList)) {
                 vo.setUserName(lifeMessagePageList.get(0).getUserName());
+                vo.setCreatedTime(lifeMessagePageList.get(0).getCreatedTime());
                 lifeMessagePageList = lifeMessagePageList.stream().filter(item -> !notDisturbList.contains(item.getPhoneId())).collect(Collectors.toList());
                 vo.setNotReadCount(lifeMessagePageList.stream().filter(item -> 0 == item.getIsRead()).count());
             }
@@ -268,7 +269,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
             wrapper = new QueryWrapper<>();
             wrapper.eq("num", 1);
             wrapper.apply("(sender_id not in (" + friendsIdsStr + ") and receiver_id not in (" + friendsIdsStr + "))");
-            wrapper.orderByDesc("created_time");
+            wrapper.orderByDesc("message.created_time");
 //        IPage<LifeMessageVo> ipage = new Page<>(1, Integer.MAX_VALUE);
             List<LifeMessageVo> lifeMessageVoList = lifeMessageMapper.getLifeMessagePageByPhoneId(receiverId, wrapper);
 

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

@@ -28,9 +28,11 @@ public class StoreSalesDetailsServiceImpl implements StoreSalesDetailsService {
         wrapper.eq("coupon.delete_flag", 0);
         wrapper.eq("luser.delete_flag", 0);
         wrapper.eq(null != storeSalesDetailsVo.getStoreId(), "lorder.store_id", storeSalesDetailsVo.getStoreId());
-        wrapper.eq(null != storeSalesDetailsVo.getType(), "coupon.type", storeSalesDetailsVo.getType());
+        wrapper.in(CollectionUtils.isNotEmpty(storeSalesDetailsVo.getTypeList()), "coupon.type", storeSalesDetailsVo.getTypeList());
         wrapper.ge(null != storeSalesDetailsVo.getPayStartTime(), "lorder.pay_time", storeSalesDetailsVo.getPayStartTime());
         if (null != storeSalesDetailsVo.getPayEndTime()) {
+            wrapper.ge(null != storeSalesDetailsVo.getPayEndTime(), "lorder.pay_time", storeSalesDetailsVo.getPayEndTime());
+        }else{
             wrapper.le("lorder.pay_time", Date.from(storeSalesDetailsVo.getPayEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().plusHours(23).plusMinutes(59).plusSeconds(59).atZone(ZoneId.systemDefault()).toInstant()));
         }
         wrapper.eq(StringUtils.isNotEmpty(storeSalesDetailsVo.getStatus()), "lorder.status", storeSalesDetailsVo.getStatus());

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

@@ -534,13 +534,14 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         StoreUser storeUser = storeUserMapper.selectOne(storeUserLambdaQueryWrapper);
         Map<String, String> storeMap = new HashMap<>();
         if (storeUser != null) {
+            storeMap.put("status",storeUser.getStatus().toString());
             if (null != storeUser.getStoreId()) {
                 StoreInfo storeInfo = storeInfoMapper.selectById(storeUser.getStoreId());
                 if (1 != storeInfo.getLogoutFlag()) {
                     //vaule为0代表有商铺未注销
                     storeMap.put("accountStore", "0");
                 } else {
-                    //vaule为1代表注销
+                    //vaule为1代表绑定店铺注销
                     storeMap.put("accountStore", "1");
                 }
             } else if (storeUser.getMoney() != null && storeUser.getMoney() > 0) {
@@ -614,6 +615,8 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
                 storeUser.setStatus(-1);
                 // 添加注销申请时间
                 storeUser.setLogoutTime(new Date());
+                // 更新logout_flag状态为1
+                storeUser.setLogoutFlag(1);
                 int num = storeUserMapper.updateById(storeUser);
                 if (num > 0) {
                     // 发送通知
@@ -645,6 +648,8 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         storeUser.setLogoutReason(null);
         // 清空注销申请时间
         storeUser.setLogoutTime(null);
+        // 更新logout_flag状态为0
+        storeUser.setLogoutFlag(0);
         int num = storeUserMapper.updateById(storeUser);
             if (num > 0) {
                 // 发送通知

+ 120 - 4
alien-store/src/main/java/shop/alien/store/task/ScheduledTask.java

@@ -1,15 +1,20 @@
 package shop.alien.store.task;
 
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
+import shop.alien.entity.second.SecondTradeRecord;
 import shop.alien.entity.store.*;
-import shop.alien.mapper.LifeCouponMapper;
-import shop.alien.mapper.LifeMessageMapper;
-import shop.alien.mapper.LifeUserOrderMapper;
+import shop.alien.entity.store.vo.WebsocketVo;
+import shop.alien.mapper.*;
+import shop.alien.mapper.second.SecondTradeRecordMapper;
+import shop.alien.store.config.BaseRedisService;
+import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.service.*;
 import shop.alien.util.common.AlipayTradeRefund;
 import shop.alien.util.common.DateUtils;
@@ -17,6 +22,8 @@ import shop.alien.store.util.ali.AliApi;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -45,6 +52,16 @@ public class ScheduledTask {
 
     private final LifeUserService lifeUserService;
 
+    private final SecondTradeRecordMapper secondTradeRecordMapper;
+
+    private final LifeNoticeMapper lifeNoticeMapper;
+
+    private final LifeUserMapper lifeUserMapper;
+
+    private final WebSocketProcess webSocketProcess;
+
+    private final BaseRedisService baseRedisService;
+
     @Scheduled(cron = "0 */10 * * * ?")
     public void sendDiscountCouponRemind() {
         //查询
@@ -176,7 +193,7 @@ public class ScheduledTask {
      * 自动转账
      * 一分钟执行一次
      */
-//    @Scheduled(cron = "0 */1 * * * ?")
+    @Scheduled(cron = "0 */1 * * * ?")
     public void autoTransferAccounts() {
         //获取已到账期
         LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
@@ -274,4 +291,103 @@ public class ScheduledTask {
             }
         }
     }
+
+    /**
+     * 二手交易平台 - 交易时间前的十分钟和十五分钟之间  给买家和卖家发送通知提醒
+     */
+    @Scheduled(cron = "0 */5 * * * ?")
+    public void secondTradeRemind() throws Exception {
+        LocalDateTime now = LocalDateTime.now();
+        // 五分钟后
+        LocalDateTime fiveMinutesLater = now.plusMinutes(5);
+
+        // 查询所有待交易
+        LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SecondTradeRecord::getTradeStatus, 0);
+        List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
+
+        for (SecondTradeRecord tradeRecord : tradeRecordList) {
+            // 十分钟前
+            LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusMinutes(10);
+            // 交易时间前的十分钟和十五分钟之间
+            if ((now.isBefore(tenMinutesAgo) && fiveMinutesLater.isAfter(tenMinutesAgo))
+                    || now.isEqual(tenMinutesAgo) || fiveMinutesLater.isEqual(tenMinutesAgo)) {
+
+                // 给买家发送消息
+                LifeMessage lifeMessage = new LifeMessage();
+                lifeMessage.setSenderId(String.valueOf(tradeRecord.getSellerId()));
+                lifeMessage.setReceiverId(String.valueOf(tradeRecord.getBuyerId()));
+                lifeMessage.setContent("签到");
+                lifeMessage.setType("5");
+                lifeMessageMapper.insert(lifeMessage);
+
+                // 给卖家发送消息
+                lifeMessage = new LifeMessage();
+                lifeMessage.setSenderId(String.valueOf(tradeRecord.getBuyerId()));
+                lifeMessage.setReceiverId(String.valueOf(tradeRecord.getSellerId()));
+                lifeMessage.setContent("签到");
+                lifeMessage.setType("5");
+                lifeMessageMapper.insert(lifeMessage);
+
+                // 给买家发送通知
+                LifeNotice lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(String.valueOf(tradeRecord.getBuyerId()));
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("交易提醒");
+                lifeNotice.setContext("您有一笔交易即将开始, 请及时前往查看");
+                lifeNotice.setNoticeType(1);
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给卖家发送通知
+                lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(String.valueOf(tradeRecord.getSellerId()));
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("交易提醒");
+                lifeNotice.setContext("您有一笔交易即将开始, 请及时前往查看");
+                lifeNotice.setNoticeType(1);
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给买家推送通知
+                LifeUser user = lifeUserMapper.selectById(tradeRecord.getBuyerId());
+                WebsocketVo websocketVo = new WebsocketVo();
+                websocketVo.setSenderId("system");
+                websocketVo.setCategory("notice");
+                websocketVo.setType("5");
+                websocketVo.setText("签到");
+                if (user != null) {
+                    websocketVo.setReceiverId("user_" + user.getUserPhone());
+                    webSocketProcess.sendMessage("user_" + user.getUserPhone(), JSONObject.from(websocketVo).toJSONString());
+                }
+
+                // 给卖家推送通知
+                user = lifeUserMapper.selectById(tradeRecord.getSellerId());
+                if (user != null) {
+                    websocketVo.setReceiverId("user_" + user.getUserPhone());
+                    webSocketProcess.sendMessage("user_" + user.getUserPhone(), JSONObject.from(websocketVo).toJSONString());
+                }
+            }
+        }
+    }
+
+    /**
+     * 每五秒从redis中读取已读的消息id 并将数据库设为已读
+     */
+    @Scheduled(cron = "*/5 * * * * ?")
+    public void readMessage() {
+        try {
+            if (CollectionUtil.isEmpty(baseRedisService.getList("readMessageIdKey"))) return;
+
+            List<String> dataList = baseRedisService.popBatchFromList("readMessageIdKey");
+            if (CollectionUtil.isNotEmpty(dataList)) {
+                LambdaUpdateWrapper<LifeMessage> wrapper = new LambdaUpdateWrapper<>();
+                wrapper.in(LifeMessage::getId, dataList)
+                        .set(LifeMessage::getIsRead, 1);
+                lifeMessageMapper.update(null, wrapper);
+            }
+        } catch (Exception e) {
+            log.error("ScheduledTask.readMessage Error Mgs={}", e.getMessage());
+        }
+    }
 }