Эх сурвалжийг харах

Merge remote-tracking branch 'origin/master'

liude 1 жил өмнө
parent
commit
852a1e0255
38 өөрчлөгдсөн 1138 нэмэгдсэн , 103 устгасан
  1. 24 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/AttentionType.java
  2. 1 1
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/DynamicType.java
  3. 25 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/SystemInformType.java
  4. 25 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/AttentionDTO.java
  5. 30 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/AttentionTotalDTO.java
  6. 28 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/AttentionUserDTO.java
  7. 2 1
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/CarouselImagesDTO.java
  8. 21 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/NewMerchantInformDTO.java
  9. 98 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/OmsOrderReturnApplyDTO.java
  10. 24 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/OmsOrderReturnApplyIdsDTO.java
  11. 54 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/AddGoodsCommentParam.java
  12. 9 4
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/GoodsPagingParam.java
  13. 25 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/QueryAttentionParam.java
  14. 1 1
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/QueryDynamicContentParam.java
  15. 49 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/AttentionService.java
  16. 14 3
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/CommentService.java
  17. 10 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/GoodsService.java
  18. 8 0
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/IOmsOrderReturnApplyService.java
  19. 15 24
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/InformService.java
  20. 10 2
      vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/MerchantService.java
  21. 16 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/AttentionMapper.java
  22. 12 2
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/CommentMapper.java
  23. 7 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/OmsOrderPayHistoryMapper.java
  24. 4 3
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/OmsOrderReturnApplyMapper.java
  25. 47 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/entity/Attention.java
  26. 7 8
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/entity/OmsOrderReturnApply.java
  27. 20 2
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/IOmsOrderReturnApplyService.java
  28. 12 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/OmsOrderPayHistoryService.java
  29. 331 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/AttentionServiceImpl.java
  30. 30 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/CommentServiceImpl.java
  31. 3 3
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/DynamicContentServiceImpl.java
  32. 17 12
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/GoodsServiceImpl.java
  33. 28 25
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/InformServiceImpl.java
  34. 20 8
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/MerchantServiceImpl.java
  35. 36 0
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/OmsOrderPayHistoryServiceImpl.java
  36. 42 4
      vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/OmsOrderReturnApplyServiceImpl.java
  37. 18 0
      vehicle-server/src/main/resources/mapper/CommentMapper.xml
  38. 15 0
      vehicle-server/src/main/resources/mapper/OmsOrderPayHistoryMapper.xml

+ 24 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/AttentionType.java

@@ -0,0 +1,24 @@
+package com.chelvc.cloud.vehicle.api.constant;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author: igl
+ * @date: 2023/8/14 16:13
+ */
+@Getter
+@AllArgsConstructor
+public enum AttentionType {
+
+  ATTENTION(1, "关注"),
+  FANS(2, "粉丝"),
+  FRIEND(3, "好友");
+
+  @EnumValue
+  @JsonValue
+  private int value;
+  private String desc;
+}

+ 1 - 1
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/DynamicType.java

@@ -14,7 +14,7 @@ import lombok.Getter;
 @AllArgsConstructor
 public enum DynamicType {
 
-    //ATTENTION(1, "关注"),
+    ATTENTION(1, "关注"),
     LATEST(2, "最新"),
     HOTTEST(3, "最热"),
     DISCOVER(4, "发现");

+ 25 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/SystemInformType.java

@@ -0,0 +1,25 @@
+package com.chelvc.cloud.vehicle.api.constant;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 系统通知类型
+ */
+
+@Getter
+@AllArgsConstructor
+public enum SystemInformType {
+
+    ORDER(1, "新订单通知"),
+    EVALUATE(2, "新点赞通知"),
+    COUPON(3, "新优惠券通知"),
+    COMMENT(4, "新评价通知"),
+    PAY(5, "新付款通知"),
+    ;
+
+    private Integer value;
+
+    private String desc;
+}

+ 25 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/AttentionDTO.java

@@ -0,0 +1,25 @@
+package com.chelvc.cloud.vehicle.api.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author: igl
+ * @date: 2023/8/14 14:18
+ */
+@Data
+public class AttentionDTO implements Serializable {
+
+  private static final long serialVersionUID = -8364585953806128909L;
+
+  /**
+   * 时间戳
+   */
+  private Long milliseconds;
+
+  /**
+   * 用户标识
+   */
+  private Long targetUserId;
+}

+ 30 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/AttentionTotalDTO.java

@@ -0,0 +1,30 @@
+package com.chelvc.cloud.vehicle.api.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author: igl
+ * @date: 2023/8/15 11:47
+ */
+@Data
+public class AttentionTotalDTO implements Serializable {
+
+  private static final long serialVersionUID = 3582381027065193024L;
+
+  /**
+   * 粉丝总数
+   */
+  private Long fansTotal;
+
+  /**
+   * 关注总数
+   */
+  private Long attentionTotal;
+
+  /**
+   * 好友
+   */
+  private Long friendTotal;
+}

+ 28 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/AttentionUserDTO.java

@@ -0,0 +1,28 @@
+package com.chelvc.cloud.vehicle.api.dto;
+
+import com.chelvc.cloud.uc.api.dto.UserDTO;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 扩展信息
+ *
+ * @author igl
+ * @date 2023/12/10 02:29
+ */
+@Data
+public class AttentionUserDTO implements Serializable {
+
+  private static final long serialVersionUID = -6263230284944185865L;
+
+  /**
+   * 用户信息
+   */
+  private UserDTO userDTO;
+
+  /**
+   * 关注状态(0-自己关注,对方未关注;1-对方已关注,自己未关注;2-互相关注)
+   */
+  private Integer flag;
+}

+ 2 - 1
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/CarouselImagesDTO.java

@@ -4,6 +4,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.SuperBuilder;
 
+import java.io.Serializable;
 import java.util.Date;
 
 /**
@@ -16,7 +17,7 @@ import java.util.Date;
 @SuperBuilder
 @NoArgsConstructor
 @AllArgsConstructor
-public class CarouselImagesDTO {
+public class CarouselImagesDTO implements Serializable {
     /**
      * 主键
      */

+ 21 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/NewMerchantInformDTO.java

@@ -0,0 +1,21 @@
+package com.chelvc.cloud.vehicle.api.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class NewMerchantInformDTO implements Serializable {
+
+    private static final long serialVersionUID = -6168480068452177194L;
+
+    /**
+     * 订单新通知数
+     */
+    private Integer orderNum;
+
+    /**
+     * 系统新通知数
+     */
+    private Integer systemNum;
+}

+ 98 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/OmsOrderReturnApplyDTO.java

@@ -0,0 +1,98 @@
+package com.chelvc.cloud.vehicle.api.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class OmsOrderReturnApplyDTO implements Serializable {
+
+    private static final long serialVersionUID = -7158413191077685950L;
+
+    private Long id;
+
+    /** 订单id */
+    private Long orderId;
+
+    /** 商户id */
+    private Long merchantId;
+
+    /** 收货地址表id */
+    private Long companyAddressId;
+
+    /** 退货商品id */
+    private Long productId;
+
+    /** 订单编号 */
+    private String orderSn;
+
+    /** 会员用户名 */
+    private String memberUsername;
+
+    /** 退款金额 */
+    private BigDecimal returnAmount;
+
+    /** 退货人姓名 */
+    private String returnName;
+
+    /** 退货人电话 */
+    private String returnPhone;
+
+    /** 申请状态:0->待处理;1->退货中;2->已完成;3->已拒绝 */
+    private Long status;
+
+    /** 处理时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+
+    private Date handleTime;
+
+    /** 商品图片 */
+
+    private String productPic;
+
+    /** 商品名称 */
+    private String productName;
+
+    /** 商品品牌 */
+    private String productBrand;
+
+    /** 商品销售属性:颜色:红色;尺码:xl; */
+    private String productAttr;
+
+    /** 退货数量 */
+    private Long productCount;
+
+    /** 商品单价 */
+    private BigDecimal productPrice;
+
+    /** 商品实际支付单价 */
+    private BigDecimal productRealPrice;
+
+    /** 原因 */
+    private String reason;
+
+    /** 描述 */
+    private String description;
+
+    /** 凭证图片,以逗号隔开 */
+    private String proofPics;
+
+    /** 处理备注 */
+    private String handleNote;
+
+    /** 处理人员 */
+    private String handleMan;
+
+    /** 收货人 */
+    private String receiveMan;
+
+    /** 收货时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date receiveTime;
+
+    /** 收货备注 */
+    private String receiveNote;
+}

+ 24 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/dto/OmsOrderReturnApplyIdsDTO.java

@@ -0,0 +1,24 @@
+package com.chelvc.cloud.vehicle.api.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class OmsOrderReturnApplyIdsDTO implements Serializable {
+
+    private static final long serialVersionUID = -6400571350996131623L;
+
+    /**
+     * 退款订单标识
+     */
+    private Long id;
+
+    /**
+     * 申请时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date createTime;
+}

+ 54 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/AddGoodsCommentParam.java

@@ -0,0 +1,54 @@
+package com.chelvc.cloud.vehicle.api.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 新增商品评价参数
+ */
+@Data
+public class AddGoodsCommentParam implements Serializable {
+
+    private static final long serialVersionUID = -3917954006275341904L;
+
+    /**
+     * 评价打分
+     */
+    private Double score;
+
+    /**
+     * 评价内容
+     */
+    private String content;
+
+    /**
+     * 上级评论标识
+     */
+    private Long parentId;
+
+    /**
+     * 附件列表(,隔开)
+     */
+    private String attachments;
+
+    /**
+     * 订单id
+     */
+    @NotNull(message = "订单信息不能为空")
+    private Long orderId;
+
+    /**
+     * 商品id
+     */
+    @NotNull(message = "商品信息不能为空")
+    private Long goodsId;
+
+    /**
+     * 商家id
+     */
+    @NotNull(message = "商家信息不能为空")
+    private Long merchantId;
+
+}

+ 9 - 4
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/GoodsPagingParam.java

@@ -1,9 +1,5 @@
 package com.chelvc.cloud.vehicle.api.param;
 
-import java.io.Serializable;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-
 import com.chelvc.cloud.vehicle.api.constant.GoodsStatus;
 import com.chelvc.framework.common.model.Paging;
 import lombok.AllArgsConstructor;
@@ -11,6 +7,10 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.SuperBuilder;
 
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+
 /**
  * 商品信息
  *
@@ -42,4 +42,9 @@ public class GoodsPagingParam implements Serializable {
      * 商品状态
      */
     private GoodsStatus status;
+    /**
+     * 商家ID
+     */
+    @NotNull(message = "商家ID不能为空")
+    private Long merchantId;
 }

+ 25 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/QueryAttentionParam.java

@@ -0,0 +1,25 @@
+package com.chelvc.cloud.vehicle.api.param;
+
+import com.chelvc.cloud.vehicle.api.constant.AttentionType;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * @author: igl
+ * @date: 2023/8/14 16:14
+ */
+@Data
+public class QueryAttentionParam implements Serializable {
+
+  private static final long serialVersionUID = -4730543402654742104L;
+
+  /**
+   * ATTENTION-关注
+   * FANS-粉丝
+   * FRIEND-好友
+   */
+  @NotNull(message = "请选择查询类型")
+  private AttentionType type;
+}

+ 1 - 1
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/QueryDynamicContentParam.java

@@ -22,7 +22,7 @@ public class QueryDynamicContentParam implements Serializable {
      */
     private String keyWord;
     /**
-     * 筛选类型 ATTENTION-关注;LATEST-最新;HOTTEST-最热
+     * 筛选类型 ATTENTION-关注;LATEST-最新;HOTTEST-最热;DISCOVER-发现
      */
     @NotNull(message = "筛选类型不能为空")
     private DynamicType type;

+ 49 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/AttentionService.java

@@ -0,0 +1,49 @@
+package com.chelvc.cloud.vehicle.api.service;
+
+import com.chelvc.cloud.vehicle.api.dto.AttentionTotalDTO;
+import com.chelvc.cloud.vehicle.api.dto.AttentionUserDTO;
+import com.chelvc.cloud.vehicle.api.param.QueryAttentionParam;
+import com.chelvc.framework.common.model.PagedDTO;
+import com.chelvc.framework.common.model.Pagination;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author: igl
+ * @date: 2023/8/14 10:11
+ */
+public interface AttentionService {
+
+  /**
+   * 关注用户
+   * @param userId
+   * @param targetUserId
+   */
+  void concern(Long userId, Long targetUserId);
+
+  /**
+   * 分页查看关注、粉丝、好友
+   *
+   * @param page
+   * @param param
+   * @author igl
+   * @date 2023/2/25 19:42
+   */
+  Pagination<AttentionUserDTO> page(PagedDTO page, QueryAttentionParam param, Long userId);
+
+  /**
+   * 查询用户是否关注
+   * @param userId
+   * @param userIds
+   * @return
+   */
+  Map<Long, Boolean> queryAttentionByUserIds(Long userId, List<Long> userIds);
+
+  /**
+   * 查看关注、粉丝、好友总数
+   * @author igl
+   * @date 2023/8/15 19:42
+   */
+  AttentionTotalDTO queryTotalByUserId(Long userId);
+}

+ 14 - 3
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/CommentService.java

@@ -1,10 +1,11 @@
 package com.chelvc.cloud.vehicle.api.service;
 
-import java.util.List;
-
 import com.chelvc.cloud.vehicle.api.dto.CommentDTO;
+import com.chelvc.cloud.vehicle.api.param.AddGoodsCommentParam;
 import com.chelvc.cloud.vehicle.api.param.CommentQueryParam;
 
+import java.util.List;
+
 /**
  * 商家评论业务接口
  *
@@ -16,8 +17,18 @@ public interface CommentService {
      * 获取商品评价列表
      *
      * @param goodsId 商品ID
+     * @param parentId   父级评论id
+     * @param merchantId   商户id
      * @param param   查询参数
      * @return 评价列表
      */
-    List<CommentDTO> listGoodsComments(Long goodsId, CommentQueryParam param);
+    List<CommentDTO> listGoodsComments(Long goodsId, Long parentId, Long merchantId, CommentQueryParam param);
+
+    /**
+     * 新增商品评价
+     *
+     * @param param   新增参数
+     * @param userId  用户标识
+     */
+    void addGoodsComments(AddGoodsCommentParam param, Long userId);
 }

+ 10 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/GoodsService.java

@@ -1,5 +1,7 @@
 package com.chelvc.cloud.vehicle.api.service;
 import java.util.List;
+
+import com.chelvc.cloud.vehicle.api.constant.GoodsStatus;
 import com.chelvc.cloud.vehicle.api.dto.GoodsDTO;
 import com.chelvc.cloud.vehicle.api.dto.GoodsDetailDTO;
 import com.chelvc.cloud.vehicle.api.param.*;
@@ -60,4 +62,12 @@ public interface GoodsService {
      * @return 商品分页信息
      */
     Pagination<GoodsDTO> getGoodsPaging(GoodsPagingParam param);
+
+    /**
+     * 修改商品状态
+     *
+     * @param ids    商品ID集合
+     * @param status 商品状态
+     */
+    void updateGoodsStatus(List<Long> ids, GoodsStatus status);
 }

+ 8 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/IOmsOrderReturnApplyService.java

@@ -0,0 +1,8 @@
+package com.chelvc.cloud.vehicle.api.service;
+
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderReturnApplyDTO;
+
+public interface IOmsOrderReturnApplyService {
+
+    OmsOrderReturnApplyDTO getOrderReturnApplyInfo(Long id);
+}

+ 15 - 24
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/InformService.java

@@ -1,5 +1,6 @@
 package com.chelvc.cloud.vehicle.api.service;
 
+import com.chelvc.cloud.vehicle.api.constant.SystemInformType;
 import com.chelvc.cloud.vehicle.api.dto.*;
 import com.chelvc.framework.common.model.Pagination;
 import com.chelvc.framework.common.model.Paging;
@@ -15,10 +16,10 @@ public interface InformService {
     Pagination<OmsOrderOperateHistoryDTO> selectOmsOrderOperateHistoryListByUserId(Long userId, Paging paging);
 
     /**
-     * 将新订单通知标识更改
+     * 将新系统通知标识未读改为已读
      *
      */
-    void changeUserOrderInformFlag(Long userId);
+    void changeSystemInformFlag(SystemInformType type, Long userId);
 
     /**
      * 查看是否有系统新消息
@@ -27,32 +28,34 @@ public interface InformService {
     NewInformDTO getNewInform(Long userId);
 
     /**
-     * 获取用户的支付通知列表
+     * (商家端)查看是否有系统新消息
      *
-     * @param paging 分页信息
-     * @return 用户的订单通知列表
      */
-    Pagination<OmsOrderPayHistoryDTO> selectOmsOrderPayHistoryListByUserId(Long userId, Paging paging);
+    NewMerchantInformDTO getMerchantNewInform(Long userId);
 
     /**
-     * 将新订单通知标识更改
+     * (商家端)获取订单退款申请列表
      *
+     * @param paging 分页信息
+     * @return 用户的订单通知列表
      */
-    void changeUserPayInformFlag(Long userId);
+    Pagination<OmsOrderReturnApplyIdsDTO> listOrderReturnApply(Long userId, Paging paging);
 
     /**
-     * 取用户的点赞回复通知列表
+     * 获取用户的支付通知列表
      *
      * @param paging 分页信息
      * @return 用户的订单通知列表
      */
-    Pagination<EvaluateDTO> selectEvaluateListByUserId(Long userId, Paging paging);
+    Pagination<OmsOrderDTO> selectOmsOrderPayHistoryListByUserId(Long userId, Paging paging);
 
     /**
-     * 将新点赞回复通知标识更改
+     * 取用户的点赞回复通知列表
      *
+     * @param paging 分页信息
+     * @return 用户的订单通知列表
      */
-    void changeEvaluateInformFlag(Long userId);
+    Pagination<EvaluateDTO> selectEvaluateListByUserId(Long userId, Paging paging);
 
     /**
      * 取用户的评价通知列表
@@ -62,12 +65,6 @@ public interface InformService {
      */
     Pagination<CommentDTO> selectCommentListByUserId(Long userId, Paging paging);
 
-    /**
-     * 将新评价通知标识更改
-     *
-     */
-    void changeCommentInformFlag(Long userId);
-
     /**
      * 取用户的优惠券通知列表
      *
@@ -75,10 +72,4 @@ public interface InformService {
      * @return 用户的评价通知列表
      */
     Pagination<UserCouponDTO> selectUserCouponListByUserId(Long userId, Paging paging);
-
-    /**
-     * 将优惠券通知标识更改
-     *
-     */
-    void changeUserCouponInformFlag(Long userId);
 }

+ 10 - 2
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/service/MerchantService.java

@@ -71,7 +71,7 @@ public interface MerchantService {
     /**
      * 修改商家
      *
-     * @param id    分类主键
+     * @param id    商家主键
      * @param param 修改参数
      */
     void updateMerchant(Long id, MerchantModifyParam param);
@@ -79,7 +79,7 @@ public interface MerchantService {
     /**
      * 删除商家
      *
-     * @param id    分类主键
+     * @param id    商家主键
      */
     void deleteMerchant(Long id);
 
@@ -90,4 +90,12 @@ public interface MerchantService {
      * @return 商家分页信息
      */
     Pagination<MerchantDTO> getMerchantPaging(MerchantPagingParam param);
+
+    /**
+     * 查询商家信息
+     *
+     * @param id 商家主键
+     * @return 商家信息
+     */
+    MerchantDTO getMerchant(Long id);
 }

+ 16 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/AttentionMapper.java

@@ -0,0 +1,16 @@
+package com.chelvc.cloud.vehicle.server.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.chelvc.cloud.vehicle.server.entity.Attention;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author: igl
+ * @date: 2023/8/14 10:12
+ */
+@Mapper
+@Repository
+public interface AttentionMapper extends BaseMapper<Attention> {
+
+}

+ 12 - 2
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/CommentMapper.java

@@ -1,7 +1,5 @@
 package com.chelvc.cloud.vehicle.server.dao;
 
-import java.util.List;
-
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.chelvc.cloud.vehicle.api.dto.CommentDTO;
 import com.chelvc.cloud.vehicle.api.param.CommentQueryParam;
@@ -9,6 +7,8 @@ import com.chelvc.cloud.vehicle.server.entity.Comment;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * 商家评价数据操作接口
  *
@@ -25,4 +25,14 @@ public interface CommentMapper extends BaseMapper<Comment> {
      * @return 评价列表
      */
     List<CommentDTO> listGoodsComments(@Param("goodsId") Long goodsId, @Param("param") CommentQueryParam param);
+
+    /**
+     * 获取商品评价列表
+     *
+     * @param goodsId 商品ID
+     * @param param   查询参数
+     * @return 评价列表
+     */
+    List<CommentDTO> getGoodsComments(@Param("goodsId") Long goodsId, @Param("parentId") Long parentId,
+                                       @Param("merchantId") Long merchantId, @Param("param") CommentQueryParam param);
 }

+ 7 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/OmsOrderPayHistoryMapper.java

@@ -1,9 +1,16 @@
 package com.chelvc.cloud.vehicle.server.dao;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderDTO;
 import com.chelvc.cloud.vehicle.server.entity.OmsOrderPayHistory;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 @Mapper
 public interface OmsOrderPayHistoryMapper extends BaseMapper<OmsOrderPayHistory> {
+    IPage<OmsOrderDTO> selectOmsOrderPayHistoryListByUserId(@Param("page") Page<OmsOrderDTO> page, @Param(Constants.WRAPPER) QueryWrapper<OmsOrderPayHistory> queryWrapper);
 }

+ 4 - 3
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/dao/OmsOrderReturnApplyMapper.java

@@ -1,10 +1,11 @@
 package com.chelvc.cloud.vehicle.server.dao;
 
-import java.util.List;
-
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.chelvc.cloud.vehicle.server.entity.OmsOrderReturnApply;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 订单退货申请Mapper接口
  * 
@@ -12,7 +13,7 @@ import org.apache.ibatis.annotations.Mapper;
  * @date 2023-11-08
  */
 @Mapper
-public interface OmsOrderReturnApplyMapper 
+public interface OmsOrderReturnApplyMapper extends BaseMapper<OmsOrderReturnApply>
 {
     /**
      * 查询订单退货申请

+ 47 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/entity/Attention.java

@@ -0,0 +1,47 @@
+package com.chelvc.cloud.vehicle.server.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 用户关注关系
+ * @author: igl
+ * @date: 2023/8/14 10:13
+ */
+@Data
+@TableName(value = "user_attention")
+public class Attention implements Serializable {
+
+  private static final long serialVersionUID = 3209107847982390085L;
+
+  /**
+   * 唯一标识
+   */
+  @TableId(value = "id", type = IdType.ASSIGN_ID)
+  private Long id;
+
+  /**
+   * 用户标识
+   */
+  @TableField(value = "user_id")
+  private Long userId;
+
+  /**
+   * 目标用户
+   */
+  @TableField(value = "target")
+  private Long target;
+
+  /**
+   * 创建时间
+   */
+  @TableField(value = "create_time")
+  private LocalDateTime createTime;
+
+}

+ 7 - 8
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/entity/OmsOrderReturnApply.java

@@ -1,20 +1,16 @@
 package com.chelvc.cloud.vehicle.server.entity;
 
-import java.math.BigDecimal;
-import java.util.Date;
-
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.chelvc.framework.database.entity.ModifyEntity;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-import lombok.ToString;
+import lombok.*;
 import lombok.experimental.SuperBuilder;
 
+import java.math.BigDecimal;
+import java.util.Date;
+
 /**
  * 订单退货申请对象 oms_order_return_apply
  * 
@@ -39,6 +35,9 @@ public class OmsOrderReturnApply extends ModifyEntity<Long>
     /** 订单id */
     private Long orderId;
 
+    /** 商户id */
+    private Long merchantId;
+
     /** 收货地址表id */
     private Long companyAddressId;
 

+ 20 - 2
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/IOmsOrderReturnApplyService.java

@@ -1,8 +1,11 @@
 package com.chelvc.cloud.vehicle.server.service;
 
-import java.util.List;
-
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderReturnApplyIdsDTO;
 import com.chelvc.cloud.vehicle.server.entity.OmsOrderReturnApply;
+import com.chelvc.framework.common.model.Pagination;
+import com.chelvc.framework.common.model.Paging;
+
+import java.util.List;
 
 /**
  * 订单退货申请Service接口
@@ -59,4 +62,19 @@ public interface IOmsOrderReturnApplyService
      * @return 结果
      */
     public int deleteOmsOrderReturnApplyById(Long id);
+
+    /**
+     * 查看商家端申请退款订单
+     * @param merchantId
+     * @param paging
+     * @return
+     */
+    Pagination<OmsOrderReturnApplyIdsDTO> listOrderReturnApply(Long merchantId, Paging paging);
+
+    /**
+     * 查看退款订单数
+     * @param userId
+     * @return
+     */
+    Integer queryReturnOrderNum(Long userId);
 }

+ 12 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/OmsOrderPayHistoryService.java

@@ -1,5 +1,9 @@
 package com.chelvc.cloud.vehicle.server.service;
 
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderDTO;
+import com.chelvc.framework.common.model.Pagination;
+import com.chelvc.framework.common.model.Paging;
+
 public interface OmsOrderPayHistoryService {
 
     /**
@@ -14,4 +18,12 @@ public interface OmsOrderPayHistoryService {
      * @param userId 用户id
      */
     void changeUserPayInformFlag(Long userId);
+
+    /**
+     * 查看支付信息
+     * @param userId
+     * @param paging
+     * @return
+     */
+    Pagination<OmsOrderDTO> selectOmsOrderPayHistoryListByUserId(Long userId, Paging paging);
 }

+ 331 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/AttentionServiceImpl.java

@@ -0,0 +1,331 @@
+package com.chelvc.cloud.vehicle.server.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.chelvc.cloud.uc.api.dto.UserDTO;
+import com.chelvc.cloud.uc.api.service.UserService;
+import com.chelvc.cloud.vehicle.api.constant.AttentionType;
+import com.chelvc.cloud.vehicle.api.dto.AttentionTotalDTO;
+import com.chelvc.cloud.vehicle.api.dto.AttentionUserDTO;
+import com.chelvc.cloud.vehicle.api.param.QueryAttentionParam;
+import com.chelvc.cloud.vehicle.api.service.AttentionService;
+import com.chelvc.cloud.vehicle.server.dao.AttentionMapper;
+import com.chelvc.cloud.vehicle.server.entity.Attention;
+import com.chelvc.framework.base.exception.ResourceUnavailableException;
+import com.chelvc.framework.common.model.PagedDTO;
+import com.chelvc.framework.common.model.Pagination;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author: igl
+ * @date: 2023/8/14 10:11
+ */
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class AttentionServiceImpl implements AttentionService {
+
+  private final static String ATTENTION_CACHE_KEY = "vehicle:user:attention:${userId}";
+  private final static String FANS_CACHE_KEY = "vehicle:user:fans:${userId}";
+  private final static String FRIEND_CACHE_KEY = "vehicle:user:friend:${userId}";
+  private final static String TEMP_FRIEND_CACHE_KEY = "vehicle:user:friend:${userId}";
+
+  private final RedisTemplate<String, Object> redisTemplate;
+  private final AttentionMapper attentionMapper;
+
+  @DubboReference
+  private final UserService userService;
+
+  @Override
+  public void concern(Long userId, Long targetUserId) {
+   if (userId == null || userId.equals(targetUserId)) {
+      throw new ResourceUnavailableException("不能自己关注自己");
+    }
+    /* LambdaQueryWrapper<Attention> wrapper = Wrappers.lambdaQuery();
+    wrapper.eq(Attention::getUserId, userId);
+    wrapper.eq(Attention::getTarget, targetUserId);
+    Attention attention = attentionMapper.selectOne(wrapper);
+    if(attention != null){
+      int i = attentionMapper.deleteById(attention.getId());
+      if(i != 1){
+        throw new ResourceUnavailableException("取消关注失败");
+      }
+      return;
+    }
+    attention = new Attention();
+    attention.setUserId(userId);
+    attention.setTarget(targetUserId);
+    attention.setCreateTime(LocalDateTime.now());
+    int insert = attentionMapper.insert(attention);
+    if(insert != 1){
+      throw new ResourceUnavailableException("关注失败");
+    }*/
+    boolean attention = attention(userId, targetUserId);
+    fans(targetUserId, userId, attention);
+    boolean b = checkAttention(targetUserId, userId);
+    if(attention && b){
+      redisTemplate.opsForZSet()
+          .add(getFriendCacheKey(userId), targetUserId, System.currentTimeMillis());
+      redisTemplate.opsForZSet()
+          .add(getFriendCacheKey(targetUserId), userId, System.currentTimeMillis());
+    } else if (!attention && b) {
+      redisTemplate.opsForZSet().remove(getFriendCacheKey(userId), targetUserId);
+      redisTemplate.opsForZSet().remove(getFriendCacheKey(targetUserId), userId);
+    }
+  }
+
+  public boolean checkAttention(Long userId, Long targetUserId){
+    String attentionCacheKey = getAttentionCacheKey(userId);
+    Long rank = redisTemplate.opsForZSet().rank(attentionCacheKey, targetUserId);
+    return rank != null;
+  }
+
+  @Override
+  public Pagination<AttentionUserDTO> page(PagedDTO page, QueryAttentionParam param, Long userId) {
+    if (userId == null) {
+      throw new ResourceUnavailableException("用户不存在");
+    }
+    Long pageCode = page.getPageCode();
+    Long pageSize = page.getPageSize();
+    long start = (pageCode - 1) * pageSize;
+    long end = pageCode * pageSize - 1;
+    AttentionType type = param.getType();
+    Long total = 0L;
+    List<AttentionUserDTO> list = new ArrayList<>();
+    String attentionCacheKey = getAttentionCacheKey(userId);
+    String fansCacheKey = getFansCacheKey(userId);
+    String friendCacheKey = getFriendCacheKey(userId);
+    switch (type) {
+      case ATTENTION:
+        if (Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))) {
+          setAttentionCache(attentionCacheKey, userId);
+          if (Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))) {
+            break;
+          }
+        }
+        total = queryCache(attentionCacheKey, list, start, end, AttentionType.ATTENTION, fansCacheKey);
+        break;
+      case FANS:
+        if (Boolean.FALSE.equals(redisTemplate.hasKey(fansCacheKey))) {
+          setFansCache(fansCacheKey, userId);
+          if (Boolean.FALSE.equals(redisTemplate.hasKey(fansCacheKey))) {
+            break;
+          }
+        }
+        total = queryCache(fansCacheKey, list, start, end, AttentionType.FANS, attentionCacheKey);
+        break;
+      case FRIEND:
+        if (Boolean.FALSE.equals(redisTemplate.hasKey(friendCacheKey))) {
+          setFriendCache(friendCacheKey, userId);
+          if (Boolean.FALSE.equals(redisTemplate.hasKey(friendCacheKey))) {
+            break;
+          }
+        }
+        total = queryCache(friendCacheKey, list, start, end, AttentionType.FRIEND, "");
+        break;
+    }
+    long quotient = total / pageSize;
+    long remainder = total % pageSize;
+    if(remainder > 0){
+      quotient += quotient;
+    }
+    return Pagination.<AttentionUserDTO>builder().total(total).pages(quotient)
+            .records(list).build();
+  }
+  public void setFriendCache(String cacheKey, Long userId){
+    String tempFriendCacheKey = getTempFriendCacheKey(userId);
+    redisTemplate.opsForZSet().intersectAndStore(getAttentionCacheKey(userId),
+            getFansCacheKey(userId), tempFriendCacheKey);
+    Set<Object> set = redisTemplate.opsForZSet().range(tempFriendCacheKey, 0, -1);
+    if (set != null && set.size() > 0) {
+      set.forEach(e ->{
+        redisTemplate.opsForZSet()
+            .add(cacheKey, e, System.currentTimeMillis());
+      });
+    }
+  }
+  @Override
+  public Map<Long, Boolean> queryAttentionByUserIds(Long userId, List<Long> userIds) {
+    if(userIds == null || userIds.size() == 0){
+      return null;
+    }
+    String attentionCacheKey = getAttentionCacheKey(userId);
+    if(Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))){
+      setAttentionCache(attentionCacheKey, userId);
+      if(Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))){
+        return null;
+      }
+    }
+    Map<Long, Boolean> map = new HashMap<>();
+    userIds.forEach(e -> {
+      Long rank = redisTemplate.opsForZSet().rank(attentionCacheKey, e);
+      if(rank == null){
+        map.put(e, false);
+      } else {
+        map.put(e, true);
+      }
+    });
+    return map;
+  }
+
+  @Override
+  public AttentionTotalDTO queryTotalByUserId(Long userId) {
+    if(userId == null){
+      throw new ResourceUnavailableException("用户不存在");
+    }
+    AttentionTotalDTO totalDTO = new AttentionTotalDTO();
+    String attentionCacheKey = getAttentionCacheKey(userId);
+    if(Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))){
+      setAttentionCache(attentionCacheKey, userId);
+    }
+    totalDTO.setAttentionTotal(redisTemplate.opsForZSet().zCard(attentionCacheKey));
+    String fansCacheKey = getFansCacheKey(userId);
+    if(Boolean.FALSE.equals(redisTemplate.hasKey(fansCacheKey))){
+      setFansCache(fansCacheKey, userId);
+    }
+    totalDTO.setFansTotal(redisTemplate.opsForZSet().zCard(fansCacheKey));
+    String friendCacheKey = getFriendCacheKey(userId);
+    if(Boolean.FALSE.equals(redisTemplate.hasKey(friendCacheKey))){
+      setFriendCache(friendCacheKey, userId);
+    }
+    totalDTO.setFriendTotal(redisTemplate.opsForZSet().zCard(friendCacheKey));
+    return totalDTO;
+  }
+
+  public Long queryCache(String cacheKey, List<AttentionUserDTO> list, Long start,
+                         Long end, AttentionType type, String key) {
+    Long total = redisTemplate.opsForZSet().zCard(cacheKey);
+    Set<Object> set = redisTemplate.opsForZSet()
+        .reverseRange(cacheKey, start, end);
+    if (set != null && set.size() > 0) {
+      List<Long> userIds = set.stream().map(e -> (Long) e).collect(Collectors.toList());
+      Map<Long, UserDTO> map = userService.queryUserByIds(userIds);
+      set.forEach(e -> {
+        AttentionUserDTO attentionUserDTO = new AttentionUserDTO();
+        attentionUserDTO.setUserDTO(map.get((Long)e));
+        switch (type){
+          case ATTENTION:
+            Long attention = redisTemplate.opsForZSet().rank(key, e);
+            if(attention == null){
+              //对方未关注
+              attentionUserDTO.setFlag(0);
+            } else {
+              attentionUserDTO.setFlag(2);
+            }
+            break;
+          case FANS:
+            Long fans = redisTemplate.opsForZSet().rank(key, e);
+            if(fans == null){
+              //自己未关注
+              attentionUserDTO.setFlag(1);
+            } else {
+              attentionUserDTO.setFlag(2);
+            }
+            break;
+          case FRIEND:
+            attentionUserDTO.setFlag(2);
+            break;
+        }
+        list.add(attentionUserDTO);
+      });
+    }
+    return total;
+  }
+
+  public void fans(Long userId, Long fansUserId, boolean b) {
+    String cacheKey = getFansCacheKey(userId);
+    if (Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey))) {
+      if (b) {
+        redisTemplate.opsForZSet()
+            .add(cacheKey, fansUserId, System.currentTimeMillis());
+      } else {
+        redisTemplate.opsForZSet().remove(cacheKey, fansUserId);
+      }
+      return;
+    }
+    setFansCache(cacheKey, userId);
+  }
+
+  public void setFansCache(String cacheKey, Long userId){
+    LambdaQueryWrapper<Attention> lwq = Wrappers.lambdaQuery();
+    lwq.eq(Attention::getTarget, userId);
+    lwq.orderByDesc(Attention::getCreateTime);
+    List<Attention> list = attentionMapper.selectList(lwq);
+    if (list != null && list.size() > 0) {
+      list.forEach(e -> {
+        LocalDateTime createTime = e.getCreateTime();
+        long milliseconds = createTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+        redisTemplate.opsForZSet().add(cacheKey, e.getUserId(), milliseconds);
+      });
+    }
+    redisTemplate.expire(cacheKey, 60 * 60 * 24 * 7, TimeUnit.SECONDS);
+  }
+
+  public boolean attention(Long userId, Long targetUserId) {
+    String cacheKey = getAttentionCacheKey(userId);
+    if (Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey))) {
+      return attentionOperate(cacheKey, userId, targetUserId);
+    }
+    setAttentionCache(cacheKey, userId);
+    return attentionOperate(cacheKey, userId, targetUserId);
+  }
+
+  public void setAttentionCache(String cacheKey, Long userId){
+    LambdaQueryWrapper<Attention> lwq = Wrappers.lambdaQuery();
+    lwq.eq(Attention::getUserId, userId);
+    lwq.orderByDesc(Attention::getCreateTime);
+    List<Attention> list = attentionMapper.selectList(lwq);
+    if (list != null && list.size() > 0) {
+      list.forEach(e -> {
+        LocalDateTime createTime = e.getCreateTime();
+        long milliseconds = createTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+        redisTemplate.opsForZSet().add(cacheKey, e.getTarget(), milliseconds);
+      });
+    }
+    redisTemplate.expire(cacheKey, 60 * 60 * 24 * 7, TimeUnit.SECONDS);
+  }
+
+  public boolean attentionOperate(String cacheKey, Long userId, Long targetUserId) {
+    Boolean b = redisTemplate.opsForZSet()
+        .add(cacheKey, targetUserId, System.currentTimeMillis());
+    if (Boolean.FALSE.equals(b)) {
+      LambdaQueryWrapper<Attention> lwq = Wrappers.lambdaQuery();
+      lwq.eq(Attention::getUserId, userId);
+      lwq.eq(Attention::getTarget, targetUserId);
+      attentionMapper.delete(lwq);
+      redisTemplate.opsForZSet().remove(cacheKey, targetUserId);
+      return false;
+    }
+    Attention entity = new Attention();
+    entity.setUserId(userId);
+    entity.setTarget(targetUserId);
+    entity.setCreateTime(LocalDateTime.now());
+    attentionMapper.insert(entity);
+    return true;
+  }
+
+  private String getAttentionCacheKey(Long userId) {
+    return ATTENTION_CACHE_KEY.replace("${userId}", String.valueOf(userId));
+  }
+
+  private String getTempFriendCacheKey(Long userId) {
+    return TEMP_FRIEND_CACHE_KEY.replace("${userId}", String.valueOf(userId));
+  }
+
+  private String getFansCacheKey(Long userId) {
+    return FANS_CACHE_KEY.replace("${userId}", String.valueOf(userId));
+  }
+
+  private String getFriendCacheKey(Long userId) {
+    return FRIEND_CACHE_KEY.replace("${userId}", String.valueOf(userId));
+  }
+}

+ 30 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/CommentServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.chelvc.cloud.uc.api.dto.UserDTO;
 import com.chelvc.cloud.uc.api.service.UserService;
 import com.chelvc.cloud.vehicle.api.dto.CommentDTO;
+import com.chelvc.cloud.vehicle.api.param.AddGoodsCommentParam;
 import com.chelvc.cloud.vehicle.api.param.CommentQueryParam;
 import com.chelvc.cloud.vehicle.server.dao.CommentMapper;
 import com.chelvc.cloud.vehicle.server.entity.Comment;
@@ -52,6 +53,35 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
         return comments;
     }
 
+    @Override
+    public List<CommentDTO> listGoodsComments(Long goodsId, Long parentId, Long merchantId, @NonNull CommentQueryParam param) {
+        if(parentId == null){
+            parentId = 0L;
+        }
+        if(goodsId == null && merchantId == null){
+            return new ArrayList<>();
+        }
+        // 获取商品评价列表
+        List<CommentDTO> comments = this.baseMapper.getGoodsComments(goodsId, parentId, merchantId, param);
+
+        // 加载评价用户信息
+        Set<Long> userIds = CollectionUtils.isEmpty(comments) ? Collections.emptySet() :
+                comments.stream().map(CommentDTO::getUserId).filter(Objects::nonNull).collect(Collectors.toSet());
+        if (!CollectionUtils.isEmpty(userIds)) {
+            Map<Long, UserDTO> users = this.userService.listUsers(userIds).stream()
+                    .collect(Collectors.toMap(UserDTO::getId, user -> user));
+            comments.forEach(comment -> comment.setUser(users.get(comment.getUserId())));
+        }
+        return comments;
+    }
+
+    @Override
+    public void addGoodsComments(AddGoodsCommentParam param, Long userId) {
+        Comment comment = BeanCopyUtil.copy(param, Comment.class);
+        comment.setUserId(userId);
+        baseMapper.insert(comment);
+    }
+
     @Override
     public Integer queryNewInformNum(Long userId) {
         LambdaQueryWrapper<Comment> lwq = Wrappers.lambdaQuery();

+ 3 - 3
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/DynamicContentServiceImpl.java

@@ -102,10 +102,10 @@ public class DynamicContentServiceImpl implements DynamicContentService, com.che
     IPage<DynamicContentDTO> result = null;
     if (Objects.equals(DynamicType.HOTTEST.getValue(), type)) {
       result = baseMapper.queryHot(page, queryHotWrapper(keyWord, userId));
-    } /*else if (Objects.equals(DynamicType.ATTENTION.getValue(), type)) {
+    } else if (Objects.equals(DynamicType.ATTENTION.getValue(), type)) {
       result = baseMapper
           .selectAttention(page, queryAttentionWrapper(keyWord), userId);
-    } */else if (Objects.equals(DynamicType.LATEST.getValue(), type)) {
+    } else if (Objects.equals(DynamicType.LATEST.getValue(), type)) {
       result = baseMapper
           .queryAll(page, queryAllWrapper(keyWord, userId));
     } else if (Objects.equals(DynamicType.DISCOVER.getValue(), type)) {
@@ -162,7 +162,7 @@ public class DynamicContentServiceImpl implements DynamicContentService, com.che
     lqw.like(StringUtils.isNotBlank(keyWord), "t1.text_content", keyWord);
     lqw.eq("t1.status", 0);
     lqw.inSql("t1.user_id",
-        "SELECT t2.target FROM collision_user.user_attention t2 WHERE t2.user_id = #{userId}");
+        "SELECT t2.target FROM attention t2 WHERE t2.user_id = #{userId}");
     lqw.orderByDesc("t1.create_time","t1.id");
     return lqw;
   }

+ 17 - 12
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/GoodsServiceImpl.java

@@ -1,24 +1,18 @@
 package com.chelvc.cloud.vehicle.server.service.impl;
 
-import java.util.List;
-
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.chelvc.cloud.vehicle.api.constant.CategoryType;
 import com.chelvc.cloud.vehicle.api.constant.GoodsStatus;
-import com.chelvc.cloud.vehicle.api.constant.MerchantStatus;
-import com.chelvc.cloud.vehicle.api.dto.CouponDTO;
-import com.chelvc.cloud.vehicle.api.dto.FavoriteDTO;
 import com.chelvc.cloud.vehicle.api.dto.GoodsDTO;
 import com.chelvc.cloud.vehicle.api.dto.GoodsDetailDTO;
-import com.chelvc.cloud.vehicle.api.param.*;
-import com.chelvc.cloud.vehicle.server.copier.CouponCopier;
+import com.chelvc.cloud.vehicle.api.param.CommentQueryParam;
+import com.chelvc.cloud.vehicle.api.param.GoodsModifyParam;
+import com.chelvc.cloud.vehicle.api.param.GoodsPagingParam;
+import com.chelvc.cloud.vehicle.api.param.GoodsQueryParam;
 import com.chelvc.cloud.vehicle.server.copier.GoodsCopier;
 import com.chelvc.cloud.vehicle.server.dao.GoodsMapper;
-import com.chelvc.cloud.vehicle.server.entity.Coupon;
-import com.chelvc.cloud.vehicle.server.entity.Favorite;
 import com.chelvc.cloud.vehicle.server.entity.Goods;
-import com.chelvc.cloud.vehicle.server.entity.Merchant;
 import com.chelvc.cloud.vehicle.server.service.CommentService;
 import com.chelvc.cloud.vehicle.server.service.CouponService;
 import com.chelvc.cloud.vehicle.server.service.GoodsService;
@@ -26,7 +20,6 @@ import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.base.util.ResourceUtils;
 import com.chelvc.framework.common.model.Pagination;
 import com.chelvc.framework.common.util.StringUtils;
-import com.chelvc.framework.database.context.DatabaseContextHolder;
 import com.chelvc.framework.database.util.PagingUtils;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
@@ -34,6 +27,10 @@ import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
 
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+import java.util.Objects;
+
 /**
  * 商品业务操作实现
  *
@@ -112,8 +109,16 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
     @Override
     public Pagination<GoodsDTO> getGoodsPaging(@NonNull GoodsPagingParam param) {
         Page<Goods> page = this.lambdaQuery()
+                .eq(Objects.nonNull(param.getMerchantId()), Goods::getMerchantId, param.getMerchantId())
+                .eq(Objects.nonNull(param.getCategoryId()), Goods::getCategoryId, param.getCategoryId())
+                .eq(Objects.nonNull(param.getStatus()), Goods::getStatus, param.getStatus())
                 .like(StringUtils.nonEmpty(param.getName()), Goods::getName, param.getName())
-                .orderByAsc(Goods::getStatus).page(PagingUtils.convert(param.getPaging()));
+                .orderByDesc(Goods::getCreateTime).page(PagingUtils.convert(param.getPaging()));
         return PagingUtils.convert(page, GoodsCopier.INSTANCE::copying);
     }
+
+    @Override
+    public void updateGoodsStatus(@NotEmpty List<Long> ids, @NonNull GoodsStatus status) {
+        this.lambdaUpdate().set(Goods::getStatus, status).in(Goods::getId, ids).update();
+    }
 }

+ 28 - 25
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/InformServiceImpl.java

@@ -1,12 +1,9 @@
 package com.chelvc.cloud.vehicle.server.service.impl;
 
+import com.chelvc.cloud.vehicle.api.constant.SystemInformType;
 import com.chelvc.cloud.vehicle.api.dto.*;
 import com.chelvc.cloud.vehicle.api.service.InformService;
-import com.chelvc.cloud.vehicle.server.service.UserCouponService;
-import com.chelvc.cloud.vehicle.server.service.CommentService;
-import com.chelvc.cloud.vehicle.server.service.DynamicEvaluateRecordService;
-import com.chelvc.cloud.vehicle.server.service.IOmsOrderOperateHistoryService;
-import com.chelvc.cloud.vehicle.server.service.OmsOrderPayHistoryService;
+import com.chelvc.cloud.vehicle.server.service.*;
 import com.chelvc.framework.common.model.Pagination;
 import com.chelvc.framework.common.model.Paging;
 import lombok.RequiredArgsConstructor;
@@ -29,14 +26,27 @@ public class InformServiceImpl implements InformService {
 
     private final CommentService commentService;
 
+    private final IOmsOrderReturnApplyService omsOrderReturnApplyService;
+
     @Override
     public Pagination<OmsOrderOperateHistoryDTO> selectOmsOrderOperateHistoryListByUserId(Long userId, Paging paging) {
         return omsOrderOperateHistoryService.selectOmsOrderOperateHistoryListByUserId(userId, paging);
     }
 
     @Override
-    public void changeUserOrderInformFlag(Long userId) {
-        omsOrderOperateHistoryService.changeUserOrderInformFlag(userId);
+    public void changeSystemInformFlag(SystemInformType type, Long userId) {
+        switch (type){
+            case PAY:
+                omsOrderPayHistoryService.changeUserPayInformFlag(userId);
+            case ORDER:
+                omsOrderOperateHistoryService.changeUserOrderInformFlag(userId);
+            case COUPON:
+                userCouponService.changeUserCouponInformFlag(userId);
+            case COMMENT:
+                commentService.changeCommentInformFlag(userId);
+            case EVALUATE:
+                dynamicEvaluateRecordService.changeEvaluateInformFlag(userId);
+        }
     }
 
     @Override
@@ -56,23 +66,26 @@ public class InformServiceImpl implements InformService {
     }
 
     @Override
-    public Pagination<OmsOrderPayHistoryDTO> selectOmsOrderPayHistoryListByUserId(Long userId, Paging paging) {
-        return null;
+    public NewMerchantInformDTO getMerchantNewInform(Long userId) {
+        NewMerchantInformDTO dto = new NewMerchantInformDTO();
+        Integer orderNum = omsOrderReturnApplyService.queryReturnOrderNum(userId);
+        dto.setOrderNum(orderNum);
+        return dto;
     }
 
     @Override
-    public void changeUserPayInformFlag(Long userId) {
-        omsOrderPayHistoryService.changeUserPayInformFlag(userId);
+    public Pagination<OmsOrderReturnApplyIdsDTO> listOrderReturnApply(Long userId, Paging paging) {
+        return omsOrderReturnApplyService.listOrderReturnApply(userId, paging);
     }
 
     @Override
-    public Pagination<EvaluateDTO> selectEvaluateListByUserId(Long userId, Paging paging) {
-        return dynamicEvaluateRecordService.selectEvaluateListByUserId(userId, paging);
+    public Pagination<OmsOrderDTO> selectOmsOrderPayHistoryListByUserId(Long userId, Paging paging) {
+        return omsOrderPayHistoryService.selectOmsOrderPayHistoryListByUserId(userId, paging);
     }
 
     @Override
-    public void changeEvaluateInformFlag(Long userId) {
-        dynamicEvaluateRecordService.changeEvaluateInformFlag(userId);
+    public Pagination<EvaluateDTO> selectEvaluateListByUserId(Long userId, Paging paging) {
+        return dynamicEvaluateRecordService.selectEvaluateListByUserId(userId, paging);
     }
 
     @Override
@@ -80,18 +93,8 @@ public class InformServiceImpl implements InformService {
         return commentService.selectCommentListByUserId(userId, paging);
     }
 
-    @Override
-    public void changeCommentInformFlag(Long userId) {
-        commentService.changeCommentInformFlag(userId);
-    }
-
     @Override
     public Pagination<UserCouponDTO> selectUserCouponListByUserId(Long userId, Paging paging) {
         return userCouponService.selectUserCouponListByUserId(userId, paging);
     }
-
-    @Override
-    public void changeUserCouponInformFlag(Long userId) {
-        userCouponService.changeUserCouponInformFlag(userId);
-    }
 }

+ 20 - 8
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/MerchantServiceImpl.java

@@ -1,8 +1,5 @@
 package com.chelvc.cloud.vehicle.server.service.impl;
 
-import java.util.List;
-import java.util.Objects;
-
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.chelvc.cloud.vehicle.api.constant.CategoryType;
@@ -10,11 +7,7 @@ import com.chelvc.cloud.vehicle.api.constant.MerchantStatus;
 import com.chelvc.cloud.vehicle.api.dto.GoodsDTO;
 import com.chelvc.cloud.vehicle.api.dto.MerchantDTO;
 import com.chelvc.cloud.vehicle.api.dto.MerchantDetailDTO;
-import com.chelvc.cloud.vehicle.api.param.GoodsQueryParam;
-import com.chelvc.cloud.vehicle.api.param.LocationQueryParam;
-import com.chelvc.cloud.vehicle.api.param.MerchantModifyParam;
-import com.chelvc.cloud.vehicle.api.param.MerchantPagingParam;
-import com.chelvc.cloud.vehicle.api.param.MerchantQueryParam;
+import com.chelvc.cloud.vehicle.api.param.*;
 import com.chelvc.cloud.vehicle.server.copier.MerchantCopier;
 import com.chelvc.cloud.vehicle.server.dao.MerchantMapper;
 import com.chelvc.cloud.vehicle.server.entity.Merchant;
@@ -29,6 +22,9 @@ import lombok.RequiredArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.List;
+import java.util.Objects;
+
 /**
  * 商家业务操作实现
  *
@@ -128,4 +124,20 @@ public class MerchantServiceImpl extends ServiceImpl<MerchantMapper, Merchant> i
                 .orderByDesc(Merchant::getCreateTime).page(PagingUtils.convert(param.getPaging()));
         return PagingUtils.convert(page, MerchantCopier.INSTANCE::copying);
     }
+
+    @Override
+    public MerchantDTO getMerchant(@NonNull Long id) {
+        Merchant merchant = ResourceUtils.required(this.getById(id), "商家不存在");
+        return this.convert(merchant);
+    }
+
+    /**
+     * 转换商家信息
+     *
+     * @param merchant 商家实例
+     * @return 商家信息
+     */
+    private MerchantDTO convert(Merchant merchant) {
+        return MerchantCopier.INSTANCE.copying(merchant);
+    }
 }

+ 36 - 0
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/OmsOrderPayHistoryServiceImpl.java

@@ -1,17 +1,38 @@
 package com.chelvc.cloud.vehicle.server.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.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.chelvc.cloud.vehicle.api.dto.DynamicContentDTO;
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderDTO;
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderPayHistoryDTO;
 import com.chelvc.cloud.vehicle.server.dao.OmsOrderPayHistoryMapper;
+import com.chelvc.cloud.vehicle.server.entity.DynamicContent;
+import com.chelvc.cloud.vehicle.server.entity.OmsOrder;
+import com.chelvc.cloud.vehicle.server.entity.OmsOrderOperateHistory;
 import com.chelvc.cloud.vehicle.server.entity.OmsOrderPayHistory;
+import com.chelvc.cloud.vehicle.server.service.IOmsOrderService;
 import com.chelvc.cloud.vehicle.server.service.OmsOrderPayHistoryService;
+import com.chelvc.framework.common.model.Pagination;
+import com.chelvc.framework.common.model.Paging;
+import com.chelvc.framework.database.util.PagingUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 @Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
 public class OmsOrderPayHistoryServiceImpl extends ServiceImpl<OmsOrderPayHistoryMapper, OmsOrderPayHistory> implements OmsOrderPayHistoryService {
 
+    private final IOmsOrderService omsOrderService;
+
     @Override
     public Integer queryNewInformNum(Long userId) {
         LambdaQueryWrapper<OmsOrderPayHistory> lwq = Wrappers.lambdaQuery();
@@ -28,4 +49,19 @@ public class OmsOrderPayHistoryServiceImpl extends ServiceImpl<OmsOrderPayHistor
         lwq.set(OmsOrderPayHistory::getFlag, 1);
         baseMapper.update(null, lwq);
     }
+
+    @Override
+    public Pagination<OmsOrderDTO> selectOmsOrderPayHistoryListByUserId(Long userId, Paging paging) {
+        Page<OmsOrderDTO> page = new Page<>(paging.getIndex(), paging.getSize());
+        IPage<OmsOrderDTO> result = baseMapper.selectOmsOrderPayHistoryListByUserId(page, queryWrapper(userId));
+        return Pagination.<OmsOrderDTO>builder().total(result.getTotal()).pages(result.getPages())
+                .records(result.getRecords()).build();
+    }
+
+    private QueryWrapper<OmsOrderPayHistory> queryWrapper(Long userId) {
+        QueryWrapper<OmsOrderPayHistory> lqw = Wrappers.query();
+        lqw.eq("t1.user_id", userId);
+        lqw.orderByDesc("t1.create_time","t1.id");
+        return lqw;
+    }
 }

+ 42 - 4
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/OmsOrderReturnApplyServiceImpl.java

@@ -1,14 +1,24 @@
 package com.chelvc.cloud.vehicle.server.service.impl;
 
-import java.util.Date;
-import java.util.List;
-
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderReturnApplyDTO;
+import com.chelvc.cloud.vehicle.api.dto.OmsOrderReturnApplyIdsDTO;
 import com.chelvc.cloud.vehicle.server.dao.OmsOrderReturnApplyMapper;
 import com.chelvc.cloud.vehicle.server.entity.OmsOrderReturnApply;
 import com.chelvc.cloud.vehicle.server.service.IOmsOrderReturnApplyService;
+import com.chelvc.framework.common.model.Pagination;
+import com.chelvc.framework.common.model.Paging;
+import com.chelvc.framework.common.util.BeanCopyUtil;
+import com.chelvc.framework.database.util.PagingUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+
 /**
  * 订单退货申请Service业务层处理
  * 
@@ -16,7 +26,8 @@ import org.springframework.stereotype.Service;
  * @date 2023-11-08
  */
 @Service
-public class OmsOrderReturnApplyServiceImpl implements IOmsOrderReturnApplyService
+public class OmsOrderReturnApplyServiceImpl extends ServiceImpl<OmsOrderReturnApplyMapper, OmsOrderReturnApply> implements
+        IOmsOrderReturnApplyService, com.chelvc.cloud.vehicle.api.service.IOmsOrderReturnApplyService
 {
     @Autowired
     private OmsOrderReturnApplyMapper omsOrderReturnApplyMapper;
@@ -93,4 +104,31 @@ public class OmsOrderReturnApplyServiceImpl implements IOmsOrderReturnApplyServi
     {
         return omsOrderReturnApplyMapper.deleteOmsOrderReturnApplyById(id);
     }
+
+    @Override
+    public Pagination<OmsOrderReturnApplyIdsDTO> listOrderReturnApply(Long merchantId, Paging paging) {
+        Page<OmsOrderReturnApply> page = this.lambdaQuery()
+                .eq(OmsOrderReturnApply::getMerchantId, merchantId)
+                .orderByAsc(OmsOrderReturnApply::getCreateTime).page(PagingUtils.convert(paging));
+        List<OmsOrderReturnApply> omsOrderReturnApplies = page.getRecords();
+        List<OmsOrderReturnApplyIdsDTO> copy = BeanCopyUtil.copy(omsOrderReturnApplies, OmsOrderReturnApplyIdsDTO.class);
+        return PagingUtils.convert(page, copy);
+    }
+
+    @Override
+    public Integer queryReturnOrderNum(Long merchantId) {
+        LambdaQueryWrapper<OmsOrderReturnApply> lwq = Wrappers.lambdaQuery();
+        lwq.eq(OmsOrderReturnApply::getMerchantId, merchantId);
+        lwq.eq(OmsOrderReturnApply::getStatus, 0);
+        return baseMapper.selectCount(lwq);
+    }
+
+    @Override
+    public OmsOrderReturnApplyDTO getOrderReturnApplyInfo(Long id) {
+        OmsOrderReturnApply omsOrderReturnApply = omsOrderReturnApplyMapper.selectOmsOrderReturnApplyById(id);
+        if (omsOrderReturnApply == null){
+            return null;
+        }
+        return BeanCopyUtil.copy(omsOrderReturnApply, OmsOrderReturnApplyDTO.class);
+    }
 }

+ 18 - 0
vehicle-server/src/main/resources/mapper/CommentMapper.xml

@@ -22,4 +22,22 @@
         </where>
         order by create_time desc limit #{param.size}
     </select>
+
+    <select id="getGoodsComments" resultMap="SIMPLE_COMMENT_RESULT_MAP">
+        select id, user_id, score, content, attachments, create_time
+        from `comment`
+        <where>
+            parent_id = #{parentId}
+            <if test="goodsId != null">
+                and goods_id = #{goodsId}
+            </if>
+            <if test="merchantId != null">
+                and merchant_id = #{merchantId}
+            </if>
+            <if test="param.offset != null">
+                and id > #{param.offset}
+            </if>
+        </where>
+        order by create_time desc limit #{param.size}
+    </select>
 </mapper>

+ 15 - 0
vehicle-server/src/main/resources/mapper/OmsOrderPayHistoryMapper.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.chelvc.cloud.vehicle.server.dao.OmsOrderPayHistoryMapper">
+
+
+    <select id="selectOmsOrderPayHistoryListByUserId" resultType="com.chelvc.cloud.vehicle.api.dto.OmsOrderDTO">
+        select t2.*
+        from oms_order_pay_history t1
+        left join oms_order t2 on t1.order_id = t2.id
+        ${ew.getCustomSqlSegment}
+    </select>
+
+</mapper>