xgb 3 дней назад
Родитель
Сommit
953026718e
40 измененных файлов с 1424 добавлено и 53 удалено
  1. 0 2
      fs-admin/src/main/java/com/fs/live/controller/LiveCouponIssueController.java
  2. 45 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductPurchaseLimitScrm.java
  3. 4 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductScrm.java
  4. 27 0
      fs-service/src/main/java/com/fs/hisStore/domain/HsPrescribScrm.java
  5. 79 0
      fs-service/src/main/java/com/fs/hisStore/domain/MedicalRecord.java
  6. 46 0
      fs-service/src/main/java/com/fs/hisStore/domain/PrescriptionDeliveryItem.java
  7. 66 0
      fs-service/src/main/java/com/fs/hisStore/domain/PrescriptionInfo.java
  8. 63 0
      fs-service/src/main/java/com/fs/hisStore/domain/PrescriptionInfoDetails.java
  9. 72 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductPurchaseLimitScrmMapper.java
  10. 1 1
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java
  11. 29 0
      fs-service/src/main/java/com/fs/hisStore/param/CartPurchaseLimitCheckParam.java
  12. 24 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderBatchAuditParam.java
  13. 91 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreProductPurchaseLimitScrmService.java
  14. 243 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPurchaseLimitScrmServiceImpl.java
  15. 2 0
      fs-service/src/main/java/com/fs/live/domain/LiveCouponUser.java
  16. 2 0
      fs-service/src/main/java/com/fs/live/mapper/LiveCouponUserMapper.java
  17. 8 0
      fs-service/src/main/java/com/fs/live/mapper/LiveMsgMapper.java
  18. 7 0
      fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java
  19. 7 0
      fs-service/src/main/java/com/fs/live/mapper/LiveOrderPaymentMapper.java
  20. 9 1
      fs-service/src/main/java/com/fs/live/mapper/LiveWatchLogMapper.java
  21. 6 0
      fs-service/src/main/java/com/fs/live/param/MergedOrderQueryParam.java
  22. 9 0
      fs-service/src/main/java/com/fs/live/service/ILiveMsgService.java
  23. 2 0
      fs-service/src/main/java/com/fs/live/service/ILiveOrderService.java
  24. 13 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveCouponServiceImpl.java
  25. 77 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveMsgServiceImpl.java
  26. 133 25
      fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java
  27. 123 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java
  28. 5 0
      fs-service/src/main/java/com/fs/live/vo/HandleUserTagVO.java
  29. 4 4
      fs-service/src/main/java/com/fs/live/vo/LiveAfterSalesVo.java
  30. 30 0
      fs-service/src/main/java/com/fs/live/vo/LiveMsgExportVO.java
  31. 61 0
      fs-service/src/main/java/com/fs/live/vo/PaymentExportVO.java
  32. 41 0
      fs-service/src/main/java/com/fs/live/vo/PaymentImportVO.java
  33. 25 1
      fs-service/src/main/resources/mapper/hisStore/FsStoreProductScrmMapper.xml
  34. 9 4
      fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml
  35. 24 13
      fs-service/src/main/resources/mapper/live/LiveCouponUserMapper.xml
  36. 12 0
      fs-service/src/main/resources/mapper/live/LiveMsgMapper.xml
  37. 11 1
      fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml
  38. 8 0
      fs-service/src/main/resources/mapper/live/LiveOrderPaymentMapper.xml
  39. 1 0
      fs-service/src/main/resources/mapper/live/LiveUserRedRecordMapper.xml
  40. 5 1
      fs-service/src/main/resources/mapper/live/LiveWatchLogMapper.xml

+ 0 - 2
fs-admin/src/main/java/com/fs/live/controller/LiveCouponIssueController.java

@@ -1,8 +1,6 @@
 package com.fs.live.controller;
 
 import java.util.List;
-import java.util.Map;
-
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;

+ 45 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductPurchaseLimitScrm.java

@@ -0,0 +1,45 @@
+package com.fs.hisStore.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 商品限购对象 fs_store_product_purchase_limit
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+@Data
+public class FsStoreProductPurchaseLimitScrm implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 限购ID */
+    private Long id;
+
+    /** 商品ID */
+    @Excel(name = "商品ID")
+    private Long productId;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 已购买数量 */
+    @Excel(name = "已购买数量")
+    private Integer num;
+
+    /** 创建时间 */
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 更新时间 */
+    @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+}
+

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductScrm.java

@@ -343,4 +343,8 @@ public class FsStoreProductScrm extends BaseEntity
     @Excel(name = "所属小程序app_id")
     private String appIds;
 
+    /** 限购数量 */
+    @Excel(name = "限购数量")
+    private Integer purchaseLimit;
+
 }

+ 27 - 0
fs-service/src/main/java/com/fs/hisStore/domain/HsPrescribScrm.java

@@ -0,0 +1,27 @@
+package com.fs.hisStore.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import java.util.List;
+
+@Data
+@ApiModel(description = "红杉-完整医疗信息")
+@Accessors(chain = true)
+public class HsPrescribScrm {
+
+    @ApiModelProperty(value = "问诊信息")
+    @JsonProperty("medical_record")
+    private MedicalRecord medicalRecord;
+
+    @ApiModelProperty(value = "处方信息")
+    @JsonProperty("prescription_info")
+    private PrescriptionInfo prescriptionInfo;
+
+    @ApiModelProperty(value = "处方流转信息列表")
+    @JsonProperty("prescription_delivery")
+    private List<PrescriptionDeliveryItem> prescriptionDelivery;
+}
+

+ 79 - 0
fs-service/src/main/java/com/fs/hisStore/domain/MedicalRecord.java

@@ -0,0 +1,79 @@
+package com.fs.hisStore.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import java.util.List;
+
+@Data
+@ApiModel(description = "红杉-医院问诊信息")
+@Accessors(chain = true)
+public class MedicalRecord {
+
+    @ApiModelProperty(value = "医院名")
+    @JsonProperty("hospital_name")
+    private String hospitalName;
+
+    @ApiModelProperty(value = "科室名")
+    @JsonProperty("branch_title")
+    private String branchTitle;
+
+    @ApiModelProperty(value = "院内问诊标识")
+    @JsonProperty("book_no")
+    private String bookNo;
+
+    @ApiModelProperty(value = "患者姓名")
+    @JsonProperty("real_name")
+    private String realName;
+
+    @ApiModelProperty(value = "患者性别 1=男 2=女 0=未知")
+    @JsonProperty("sex")
+    private Integer sex;
+
+    @ApiModelProperty(value = "患者年龄")
+    @JsonProperty("age")
+    private Integer age;
+
+    @ApiModelProperty(value = "年龄单位 1-岁;2-月;3-天")
+    @JsonProperty("age_unit")
+    private Integer ageUnit;
+
+    @ApiModelProperty(value = "主诉")
+    @JsonProperty("recount")
+    private String recount;
+
+    @ApiModelProperty(value = "肝肾健康信息")
+    @JsonProperty("liver_kidney_normal")
+    private String liverKidneyNormal;
+
+    @ApiModelProperty(value = "妊娠哺乳信息")
+    @JsonProperty("pregnancy")
+    private String pregnancy;
+
+    @ApiModelProperty(value = "过敏史信息")
+    @JsonProperty("allergyhistory")
+    private String allergyhistory;
+
+    @ApiModelProperty(value = "家族病史信息")
+    @JsonProperty("family_history")
+    private String familyHistory;
+
+    @ApiModelProperty(value = "疾病史信息")
+    @JsonProperty("nowmedical")
+    private String nowmedical;
+
+    @ApiModelProperty(value = "诊断描述")
+    @JsonProperty("diagnose")
+    private List<String> diagnose;
+
+    @ApiModelProperty(value = "医保诊断编码信息")
+    @JsonProperty("diagnose_with_med_code")
+    private List<String> diagnoseWithMedCode;
+
+    @ApiModelProperty(value = "购药信息")
+    @JsonProperty("drug")
+    private List<String> drug;
+}
+

+ 46 - 0
fs-service/src/main/java/com/fs/hisStore/domain/PrescriptionDeliveryItem.java

@@ -0,0 +1,46 @@
+package com.fs.hisStore.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import java.util.List;
+
+@Data
+@ApiModel(description = "红杉-处方流转信息")
+@Accessors(chain = true)
+public class PrescriptionDeliveryItem {
+
+    @ApiModelProperty(value = "处理场景标识 00-电子处方;10-流转三方;20-药房配药;30-核销出库;40-患者收药")
+    @JsonProperty("scence")
+    private String scence;
+
+    @ApiModelProperty(value = "处理人角色标识 1-开方医生;2-审方药师;3-复核药师;4-出药操作员;5-流转操作员")
+    @JsonProperty("role_tag")
+    private String roleTag;
+
+    @ApiModelProperty(value = "处方状态")
+    @JsonProperty("status")
+    private String status;
+
+    @ApiModelProperty(value = "操作时间")
+    @JsonProperty("execute_time")
+    private Integer executeTime;
+
+    @ApiModelProperty(value = "处理建议")
+    @JsonProperty("result")
+    private String result;
+
+    @ApiModelProperty(value = "操作人姓名")
+    @JsonProperty("real_name")
+    private String realName;
+
+    @ApiModelProperty(value = "操作人科室")
+    @JsonProperty("branch_name")
+    private String branchName;
+
+    @ApiModelProperty(value = "其他信息")
+    @JsonProperty("extend")
+    private List<Object> extend;
+}

+ 66 - 0
fs-service/src/main/java/com/fs/hisStore/domain/PrescriptionInfo.java

@@ -0,0 +1,66 @@
+package com.fs.hisStore.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import java.util.List;
+
+@Data
+@ApiModel(description = "红杉-处方信息")
+@Accessors(chain = true)
+public class PrescriptionInfo {
+
+    @ApiModelProperty(value = "开单医生")
+    @JsonProperty("billing_doctor_name")
+    private String billingDoctorName;
+
+    @ApiModelProperty(value = "审核医生|药师")
+    @JsonProperty("reviewer_admin_name")
+    private String reviewerAdminName;
+
+    @ApiModelProperty(value = "复核医生|药师")
+    @JsonProperty("audit_admin_name")
+    private String auditAdminName;
+
+    @ApiModelProperty(value = "处方订单号")
+    @JsonProperty("order_no")
+    private String orderNo;
+
+    @ApiModelProperty(value = "处方状态")
+    @JsonProperty("prescription_status")
+    private String prescriptionStatus;
+
+    @ApiModelProperty(value = "处方流转状态名")
+    @JsonProperty("prescription_status_name")
+    private String prescriptionStatusName;
+
+    @ApiModelProperty(value = "电子处方地址")
+    @JsonProperty("prescription_url")
+    private String prescriptionUrl;
+
+    @ApiModelProperty(value = "下单时间")
+    @JsonProperty("create_time")
+    private Integer createTime;
+
+    @ApiModelProperty(value = "下单时间")
+    @JsonProperty("create_time_str")
+    private String createTimeStr;
+
+    @ApiModelProperty(value = "三方订单号")
+    @JsonProperty("third_order_no")
+    private String thirdOrderNo;
+
+    @ApiModelProperty(value = "处方来源类型 00-普通门诊;01-门诊慢病;02-特种病;03-门诊统筹")
+    @JsonProperty("prescription_from_type")
+    private String prescriptionFromType;
+
+    @ApiModelProperty(value = "处方去向 00-未分配;01-院内药房;10-院外药房;20-医保中心;30-配送中心;40-三方电商")
+    @JsonProperty("prescription_flow")
+    private String prescriptionFlow;
+
+    @ApiModelProperty(value = "药品详情")
+    @JsonProperty("details")
+    private List<PrescriptionInfoDetails> details;
+}

+ 63 - 0
fs-service/src/main/java/com/fs/hisStore/domain/PrescriptionInfoDetails.java

@@ -0,0 +1,63 @@
+package com.fs.hisStore.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import java.util.List;
+
+@Data
+@ApiModel(description = "处方药品详情")
+@Accessors(chain = true)
+public class PrescriptionInfoDetails {
+
+    @ApiModelProperty(value = "处方号")
+    @JsonProperty("pre_code")
+    private String preCode;
+
+    @ApiModelProperty(value = "药品id")
+    @JsonProperty("id")
+    private Integer id;
+
+    @ApiModelProperty(value = "药品名称")
+    @JsonProperty("name")
+    private String name;
+
+    @ApiModelProperty(value = "规格")
+    @JsonProperty("format")
+    private String format;
+
+    @ApiModelProperty(value = "用药频次")
+    @JsonProperty("frequency")
+    private String frequency;
+
+    @ApiModelProperty(value = "用法")
+    @JsonProperty("usage")
+    private String usage;
+
+    @ApiModelProperty(value = "总量")
+    @JsonProperty("total")
+    private Integer total;
+
+    @ApiModelProperty(value = "单位")
+    @JsonProperty("unit")
+    private String unit;
+
+    @ApiModelProperty(value = "单次剂量(每日剂量)")
+    @JsonProperty("dose")
+    private String dose;
+
+    @ApiModelProperty(value = "用药要求")
+    @JsonProperty("requirements")
+    private String requirements;
+
+    @ApiModelProperty(value = "中草药处方详情")
+    @JsonProperty("log")
+    private List<String> log;
+
+    @ApiModelProperty(value = "药品条码")
+    @JsonProperty("bar_code")
+    private String barCode;
+}
+

+ 72 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductPurchaseLimitScrmMapper.java

@@ -0,0 +1,72 @@
+package com.fs.hisStore.mapper;
+
+import java.util.List;
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 商品限购Mapper接口
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+public interface FsStoreProductPurchaseLimitScrmMapper
+{
+    /**
+     * 查询商品限购
+     *
+     * @param id 商品限购ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 查询商品限购列表
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 商品限购集合
+     */
+    public List<FsStoreProductPurchaseLimitScrm> selectFsStoreProductPurchaseLimitList(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 根据商品ID和用户ID查询限购记录
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectByProductIdAndUserId(@Param("productId") Long productId, @Param("userId") Long userId);
+
+    /**
+     * 新增商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int insertFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 修改商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int updateFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 删除商品限购
+     *
+     * @param id 商品限购ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 批量删除商品限购
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitByIds(Long[] ids);
+}
+

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java

@@ -78,7 +78,7 @@ public interface FsStoreProductScrmMapper
     @Select({"<script> " +
             "select p.*,pc.cate_name, fs.store_name from fs_store_product_scrm p left join fs_store_product_category_scrm pc on p.cate_id=pc.cate_id  " +
             "left join fs_store fs on fs.store_id = p.store_id " +
-            "where 1=1 " +
+            "where 1=1 and p.is_del= 0 " +
             "<if test = 'maps.productName != null and  maps.productName !=\"\"    '> " +
             "and p.product_name like CONCAT('%',#{maps.productName},'%') " +
             "</if>" +

+ 29 - 0
fs-service/src/main/java/com/fs/hisStore/param/CartPurchaseLimitCheckParam.java

@@ -0,0 +1,29 @@
+package com.fs.hisStore.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 购物车结算前限购校验参数
+ */
+@Data
+public class CartPurchaseLimitCheckParam {
+    
+    @Data
+    public static class ProductItem {
+        @NotNull(message = "商品ID不能为空")
+        @ApiModelProperty(value = "商品ID", required = true)
+        private Long productId;
+        
+        @NotNull(message = "商品数量不能为空")
+        @ApiModelProperty(value = "商品数量", required = true)
+        private Integer num;
+    }
+    
+    @NotNull(message = "商品列表不能为空")
+    @ApiModelProperty(value = "选中的商品列表", required = true)
+    private List<ProductItem> products;
+}

+ 24 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderBatchAuditParam.java

@@ -0,0 +1,24 @@
+package com.fs.hisStore.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 批量审核订单参数
+ *
+ * @author fs
+ * @date 2024
+ */
+@Data
+public class FsStoreOrderBatchAuditParam {
+    /**
+     * 订单ID列表
+     */
+    private List<Long> orderIds;
+
+    /**
+     * 审核状态 1-是,0-否
+     */
+    private Integer isAudit;
+}

+ 91 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreProductPurchaseLimitScrmService.java

@@ -0,0 +1,91 @@
+package com.fs.hisStore.service;
+
+import java.util.List;
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+
+/**
+ * 商品限购Service接口
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+public interface IFsStoreProductPurchaseLimitScrmService
+{
+    /**
+     * 查询商品限购
+     *
+     * @param id 商品限购ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 查询商品限购列表
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 商品限购集合
+     */
+    public List<FsStoreProductPurchaseLimitScrm> selectFsStoreProductPurchaseLimitList(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 根据商品ID和用户ID查询限购记录
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectByProductIdAndUserId(Long productId, Long userId);
+
+    /**
+     * 新增商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int insertFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 修改商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int updateFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 批量删除商品限购
+     *
+     * @param ids 需要删除的商品限购ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitByIds(Long[] ids);
+
+    /**
+     * 删除商品限购信息
+     *
+     * @param id 商品限购ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 增加用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 增加的数量
+     * @return 结果
+     */
+    public int increasePurchaseLimit(Long productId, Long userId, Integer num);
+
+    /**
+     * 减少用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 减少的数量
+     * @return 结果
+     */
+    public int decreasePurchaseLimit(Long productId, Long userId, Integer num);
+}
+

+ 243 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPurchaseLimitScrmServiceImpl.java

@@ -0,0 +1,243 @@
+package com.fs.hisStore.service.impl;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.fs.common.constant.LiveKeysConstant;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.DateUtils;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.mapper.FsStoreProductAttrScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductPurchaseLimitScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
+import com.fs.hisStore.service.IFsStoreProductPurchaseLimitScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 商品限购Service业务层处理
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+@Service
+public class FsStoreProductPurchaseLimitScrmServiceImpl implements IFsStoreProductPurchaseLimitScrmService
+{
+    @Autowired
+    private FsStoreProductPurchaseLimitScrmMapper fsStoreProductPurchaseLimitMapper;
+
+    @Autowired
+    private RedisCache redisCache;
+    @Autowired
+    private FsStoreProductScrmMapper fsStoreProductScrmMapper;
+    @Autowired
+    private FsStoreProductAttrScrmMapper fsStoreProductAttrScrmMapper;
+    @Autowired
+    private FsStoreProductAttrValueScrmMapper fsStoreProductAttrValueScrmMapper;
+
+
+    /**
+     * 查询商品限购
+     *
+     * @param id 商品限购ID
+     * @return 商品限购
+     */
+    @Override
+    public FsStoreProductPurchaseLimitScrm selectFsStoreProductPurchaseLimitById(Long id)
+    {
+        return fsStoreProductPurchaseLimitMapper.selectFsStoreProductPurchaseLimitById(id);
+    }
+
+    /**
+     * 查询商品限购列表
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 商品限购
+     */
+    @Override
+    public List<FsStoreProductPurchaseLimitScrm> selectFsStoreProductPurchaseLimitList(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit)
+    {
+        return fsStoreProductPurchaseLimitMapper.selectFsStoreProductPurchaseLimitList(fsStoreProductPurchaseLimit);
+    }
+
+    /**
+     * 根据商品ID和用户ID查询限购记录
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @return 商品限购
+     */
+    @Override
+    public FsStoreProductPurchaseLimitScrm selectByProductIdAndUserId(Long productId, Long userId)
+    {
+        return fsStoreProductPurchaseLimitMapper.selectByProductIdAndUserId(productId, userId);
+    }
+
+    /**
+     * 新增商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    @Override
+    public int insertFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit)
+    {
+        fsStoreProductPurchaseLimit.setCreateTime(DateUtils.getNowDate());
+        return fsStoreProductPurchaseLimitMapper.insertFsStoreProductPurchaseLimit(fsStoreProductPurchaseLimit);
+    }
+
+    /**
+     * 修改商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    @Override
+    public int updateFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit)
+    {
+        fsStoreProductPurchaseLimit.setUpdateTime(DateUtils.getNowDate());
+        return fsStoreProductPurchaseLimitMapper.updateFsStoreProductPurchaseLimit(fsStoreProductPurchaseLimit);
+    }
+
+    /**
+     * 批量删除商品限购
+     *
+     * @param ids 需要删除的商品限购ID
+     * @return 结果
+     */
+    @Override
+    public int deleteFsStoreProductPurchaseLimitByIds(Long[] ids)
+    {
+        return fsStoreProductPurchaseLimitMapper.deleteFsStoreProductPurchaseLimitByIds(ids);
+    }
+
+    /**
+     * 删除商品限购信息
+     *
+     * @param id 商品限购ID
+     * @return 结果
+     */
+    @Override
+    public int deleteFsStoreProductPurchaseLimitById(Long id)
+    {
+        return fsStoreProductPurchaseLimitMapper.deleteFsStoreProductPurchaseLimitById(id);
+    }
+
+    /**
+     * 增加用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 增加的数量
+     * @return 结果
+     */
+    @Override
+    public int increasePurchaseLimit(Long productId, Long userId, Integer num)
+    {
+        String cacheKey = String.format(LiveKeysConstant.PRODUCT_DETAIL_CACHE, productId);
+        Map<String, Object> cachedData = redisCache.getCacheObject(cacheKey);
+
+        FsStoreProductScrm product;
+        List<FsStoreProductAttrScrm> productAttr;
+        List<FsStoreProductAttrValueScrm> productValues;
+
+        if (cachedData != null) {
+            // 从缓存中获取数据
+            product = (FsStoreProductScrm) cachedData.get("product");
+        } else {
+            // 缓存中没有,从数据库查询
+            product = fsStoreProductScrmMapper.selectFsStoreProductById(productId);
+            if(product==null){
+                return -1;
+            }
+            productAttr = fsStoreProductAttrScrmMapper.selectFsStoreProductAttrByProductId(productId);
+            productValues = fsStoreProductAttrValueScrmMapper.selectFsStoreProductAttrValueByProductId(productId);
+
+            // 将数据存入缓存
+            Map<String, Object> cacheData = new HashMap<>();
+            cacheData.put("product", product);
+            cacheData.put("productAttr", productAttr);
+            cacheData.put("productValues", productValues);
+            redisCache.setCacheObject(cacheKey, cacheData, LiveKeysConstant.PRODUCT_DETAIL_CACHE_EXPIRE, TimeUnit.SECONDS);
+        }
+        if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
+            FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
+            if (limit == null) {
+                // 创建新记录
+                limit = new FsStoreProductPurchaseLimitScrm();
+                limit.setProductId(productId);
+                limit.setUserId(userId);
+                limit.setNum(num);
+                return insertFsStoreProductPurchaseLimit(limit);
+            } else {
+                // 更新现有记录
+                limit.setNum(limit.getNum() + num);
+                return updateFsStoreProductPurchaseLimit(limit);
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * 减少用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 减少的数量
+     * @return 结果
+     */
+    @Override
+    public int decreasePurchaseLimit(Long productId, Long userId, Integer num)
+    {
+        String cacheKey = String.format(LiveKeysConstant.PRODUCT_DETAIL_CACHE, productId);
+        Map<String, Object> cachedData = redisCache.getCacheObject(cacheKey);
+
+        FsStoreProductScrm product;
+        List<FsStoreProductAttrScrm> productAttr;
+        List<FsStoreProductAttrValueScrm> productValues;
+
+        if (cachedData != null) {
+            // 从缓存中获取数据
+            product = (FsStoreProductScrm) cachedData.get("product");
+        } else {
+            // 缓存中没有,从数据库查询
+            product = fsStoreProductScrmMapper.selectFsStoreProductById(productId);
+            if(product==null){
+                return -1;
+            }
+            productAttr = fsStoreProductAttrScrmMapper.selectFsStoreProductAttrByProductId(productId);
+            productValues = fsStoreProductAttrValueScrmMapper.selectFsStoreProductAttrValueByProductId(productId);
+
+            // 将数据存入缓存
+            Map<String, Object> cacheData = new HashMap<>();
+            cacheData.put("product", product);
+            cacheData.put("productAttr", productAttr);
+            cacheData.put("productValues", productValues);
+            redisCache.setCacheObject(cacheKey, cacheData, LiveKeysConstant.PRODUCT_DETAIL_CACHE_EXPIRE, TimeUnit.SECONDS);
+        }
+        if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
+            FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
+            if (limit != null) {
+                int newNum = limit.getNum() - num;
+                if (newNum <= 0) {
+                    // 如果数量为0或负数,删除记录
+                    return deleteFsStoreProductPurchaseLimitById(limit.getId());
+                } else {
+                    // 更新数量
+                    limit.setNum(newNum);
+                    return updateFsStoreProductPurchaseLimit(limit);
+                }
+            }
+            return 0;
+        }
+        return -1;
+    }
+}
+

+ 2 - 0
fs-service/src/main/java/com/fs/live/domain/LiveCouponUser.java

@@ -73,5 +73,7 @@ public class LiveCouponUser extends BaseEntity
     @Excel(name = "商品ID")
     private Long goodsId;
 
+    private String nickName;
 
+    private String phone;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveCouponUserMapper.java

@@ -72,4 +72,6 @@ public interface LiveCouponUserMapper
             " </if>" +
             "</script>")
     List<LiveCouponUser> curCoupon(@Param("coupon") CouponPO coupon);
+
+    int refundCoupon(Long couponUserId);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveMsgMapper.java

@@ -84,4 +84,12 @@ public interface LiveMsgMapper
     Map<String, BigDecimal> selectDashboardCount(@Param("liveId") Long liveId);
 
     List<LiveMsg> selectLiveMsgSingleList(LiveMsg liveMsg);
+
+    /**
+     * 查询直播评论用于导出
+     *
+     * @param liveId 直播ID
+     * @return 评论列表
+     */
+    List<com.fs.live.vo.LiveMsgExportVO> selectLiveMsgForExport(@Param("liveId") Long liveId);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java

@@ -159,6 +159,13 @@ public interface LiveOrderMapper {
     String selectLiveOrderProductStatistics(@Param("maps")LiveOrderParam param);
 
     List<LiveOrder> selectLiveOrderInId(@Param("ids") Long[] ids);
+
+    /**
+     * 根据订单ID列表批量查询订单
+     * @param orderIds 订单ID列表
+     * @return 订单列表
+     */
+    List<LiveOrder> selectLiveOrderByOrderIds(@Param("orderIds") List<Long> orderIds);
     @Select({"<script> " +
             "select o.*,cts.name as scheduleName,u.nickname,u.phone,cc.push_code,cc.create_time as customer_create_time," +
             "cc.source,cc.customer_code, c.company_name ,cu.nick_name as company_user_nick_name ," +

+ 7 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveOrderPaymentMapper.java

@@ -82,4 +82,11 @@ public interface LiveOrderPaymentMapper {
 
     @Select("select * from live_order_payment where business_id= #{orderId} and status=1 order by create_time desc limit 1")
     LiveOrderPayment selectLiveOrderLatestPayByOrderId(@Param("orderId") Long orderId);
+
+    /**
+     * 根据交易单号列表批量查询支付记录
+     * @param bankTransactionIds 交易单号列表
+     * @return 支付记录列表
+     */
+    List<LiveOrderPayment> selectByBankTransactionIds(@Param("bankTransactionIds") List<String> bankTransactionIds);
 }

+ 9 - 1
fs-service/src/main/java/com/fs/live/mapper/LiveWatchLogMapper.java

@@ -11,7 +11,7 @@ import java.util.List;
 
 /**
  * 直播间观看用户Mapper接口
- * 
+ *
  * @author fs
  * @date 2025-01-18
  */
@@ -72,6 +72,14 @@ public interface LiveWatchLogMapper extends BaseMapper<LiveWatchLog> {
 
     List<LiveWatchLog> selectLiveWatchLogByLiveId(@Param("liveId")Long liveId);
 
+    /**
+     * 根据直播间ID和外部联系人ID查询看课记录
+     * @param liveId 直播间ID
+     * @param externalContactId 外部联系人ID
+     * @return 看课记录
+     */
+    LiveWatchLog selectLiveWatchLogByLiveIdAndExternalId(@Param("liveId")Long liveId, @Param("externalContactId")Long externalContactId);
+
     List<LiveWatchLogListVO> selectLiveWatchLogListInfo(LiveWatchLog liveWatchLog);
 
     /**

+ 6 - 0
fs-service/src/main/java/com/fs/live/param/MergedOrderQueryParam.java

@@ -120,5 +120,11 @@ public class MergedOrderQueryParam extends BaseQueryParam implements Serializabl
     private String erpPhoneNumber;
     /** 汇付商户订单号 */
     private String hfshh;
+
+    /** 分页偏移量(在外部计算后传入,不在SQL中计算) */
+    private Integer offset;
+
+    /** 分页偏移量(在外部计算后传入,不在SQL中计算) */
+    private Integer exportFlag;
 }
 

+ 9 - 0
fs-service/src/main/java/com/fs/live/service/ILiveMsgService.java

@@ -69,4 +69,13 @@ public interface ILiveMsgService
     List<LiveMsg> listRecentMsg(Long id);
 
     List<LiveMsg> selectLiveMsgSingleList(LiveMsg liveMsg);
+
+    /**
+     * 导出直播评论
+     *
+     * @param liveId 直播ID
+     * @param userId 用户ID(用于Redis加锁)
+     * @return 评论列表
+     */
+    List<com.fs.live.vo.LiveMsgExportVO> exportLiveMsgComments(Long liveId, Long userId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/live/service/ILiveOrderService.java

@@ -270,4 +270,6 @@ public interface ILiveOrderService {
     Long isExistPayedRecord(Long orderId);
 
     void payConfirmPayment(Long existPayedRecordId);
+
+    void updateTime(LiveOrder order);
 }

+ 13 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveCouponServiceImpl.java

@@ -350,9 +350,22 @@ public class LiveCouponServiceImpl implements ILiveCouponService
         userRecord.setIsDel(0);
         userRecord.setGoodsId(coupon.getGoodsId());
         userRecord.setType("live-"+coupon.getLiveId());
+        //库存 remain_count
+        issue.setRemainCount(issue.getRemainCount()-1);
+        liveCouponIssueService.updateLiveCouponIssue(issue);
+
         liveCouponUserService.insertLiveCouponUser(userRecord);
         liveCouponIssueUserService.insertLiveCouponIssueUser(record);
 
+        // 更新优惠卷数量
+        if (issue.getRemainCount() > 0) {
+            LiveCouponIssue liveCouponIssue = new LiveCouponIssue();
+            liveCouponIssue.setId(issue.getId());
+            liveCouponIssue.setRemainCount(issue.getRemainCount() - 1);
+            liveCouponIssueMapper.updateLiveCouponIssue(liveCouponIssue);
+        }
+
+
         // 对于非无门槛优惠券,记录到Redis(防止重复领取)
         if (!isNoThresholdCoupon) {
             redisCache.hashPut(String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_COUPON, coupon.getLiveId(), coupon.getCouponIssueId()), String.valueOf(coupon.getUserId()), JSONUtil.toJsonStr(record));

+ 77 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveMsgServiceImpl.java

@@ -1,15 +1,23 @@
 package com.fs.live.service.impl;
 
 
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.live.domain.LiveMsg;
 import com.fs.live.mapper.LiveMsgMapper;
 import com.fs.live.service.ILiveMsgService;
+import com.fs.live.vo.LiveMsgExportVO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Service;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 直播讨论Service业务层处理
@@ -20,11 +28,21 @@ import java.util.List;
 @Service
 public class LiveMsgServiceImpl implements ILiveMsgService
 {
+    private static final Logger log = LoggerFactory.getLogger(LiveMsgServiceImpl.class);
+
     @Autowired
     private LiveMsgMapper liveMsgMapper;
     @Autowired
     private LiveDataServiceImpl liveDataService;
 
+    @Autowired(required = false)
+    private RedisTemplate<String, Object> redisTemplate;
+
+    /** Redis锁前缀 */
+    private static final String LOCK_PREFIX = "live:msg:export:lock:";
+    /** 锁过期时间(秒) */
+    private static final long LOCK_EXPIRE_TIME = 300; // 5分钟
+
     /**
      * 查询直播讨论
      *
@@ -108,4 +126,63 @@ public class LiveMsgServiceImpl implements ILiveMsgService
     public List<LiveMsg> selectLiveMsgSingleList(LiveMsg liveMsg) {
         return liveMsgMapper.selectLiveMsgSingleList(liveMsg);
     }
+
+    @Override
+    public List<LiveMsgExportVO> exportLiveMsgComments(Long liveId, Long userId) {
+        if (liveId == null) {
+            throw new CustomException("直播ID不能为空");
+        }
+        if (userId == null) {
+            throw new CustomException("用户ID不能为空");
+        }
+
+        // Redis锁的key:用户ID + 直播间ID
+        String lockKey = LOCK_PREFIX + userId + ":" + liveId;
+        String lockValue = String.valueOf(System.currentTimeMillis());
+
+        try {
+            // 尝试获取锁
+            Boolean lockAcquired = false;
+            if (redisTemplate != null) {
+                lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
+            }
+
+            if (redisTemplate != null && !lockAcquired) {
+                log.warn("用户{}正在导出直播间{}的评论,请勿重复操作", userId, liveId);
+                throw new CustomException("正在导出中,请勿重复操作");
+            }
+
+            try {
+                // 查询评论数据
+                List<LiveMsgExportVO> list = liveMsgMapper.selectLiveMsgForExport(liveId);
+                log.info("用户{}导出直播间{}的评论,共{}条", userId, liveId, list != null ? list.size() : 0);
+                return list != null ? list : Collections.emptyList();
+            } finally {
+                // 释放锁
+                if (redisTemplate != null && lockAcquired) {
+                    // 使用Lua脚本确保只删除自己的锁
+                    String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
+                            "return redis.call('del', KEYS[1]) " +
+                            "else return 0 end";
+                    DefaultRedisScript<Long> script = new DefaultRedisScript<>();
+                    script.setScriptText(luaScript);
+                    script.setResultType(Long.class);
+                    redisTemplate.execute(script, Collections.singletonList(lockKey), lockValue);
+                }
+            }
+        } catch (CustomException e) {
+            throw e;
+        } catch (Exception e) {
+            log.error("导出直播评论失败,liveId: {}, userId: {}", liveId, userId, e);
+            // 确保异常时也释放锁
+            if (redisTemplate != null) {
+                try {
+                    redisTemplate.delete(lockKey);
+                } catch (Exception ex) {
+                    log.error("释放Redis锁失败", ex);
+                }
+            }
+            throw new CustomException("导出失败:" + e.getMessage());
+        }
+    }
 }

+ 133 - 25
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -90,7 +90,6 @@ import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
 import com.fs.huifuPay.service.HuiFuService;
 import com.fs.live.domain.*;
 import com.fs.live.dto.LiveOrderComputeDTO;
-import com.fs.live.dto.LiveOrderCustomerExportDTO;
 import com.fs.live.dto.LiveOrderDeliveryNoteDTO;
 import com.fs.live.dto.LiveOrderItemDTO;
 import com.fs.live.enums.LiveAfterSalesStatusEnum;
@@ -203,6 +202,9 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
     @Autowired
     private LiveUserLotteryRecordMapper liveUserLotteryRecordMapper;
 
+    @Autowired
+    private IFsStoreProductPurchaseLimitScrmService purchaseLimitService;
+
     @Autowired
     ICompanyUserService companyUserService;
 
@@ -299,6 +301,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
 
     @Autowired
     private FsWxExpressTaskMapper fsWxExpressTaskMapper;
+    @Autowired
+    private LiveCouponUserMapper liveCouponUserMapper;
 
     //ERP 类型到服务的映射
     private Map<Integer, IErpOrderService> erpServiceMap;
@@ -697,8 +701,27 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
     @Override
     @Transactional
     public String payConfirm(Integer type,Long orderId,String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
+        // 使用 Redis setNx 加分布式锁,基于订单ID或支付单号
+        String lockKey;
+        if (type.equals(1) && StringUtils.isNotEmpty(payCode)) {
+            lockKey = "livePayConfirm:lock:" + payCode;
+        } else if (orderId != null) {
+            lockKey = "livePayConfirm:lock:" + orderId;
+        } else {
+            lockKey = "livePayConfirm:lock:" + System.currentTimeMillis();
+        }
+
+        boolean lockAcquired = false;
         Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
         try {
+            // 尝试获取锁,锁过期时间设置为30秒
+            lockAcquired = redisCache.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
+            if (!lockAcquired) {
+                // 如果获取锁失败,说明有其他线程正在处理该订单,直接返回
+                log.info("支付确认处理中,订单ID: {}, 支付单号: {}", orderId, payCode);
+                return "SUCCESS";
+            }
+
             LiveOrder order=null;
             if(type.equals(1)){
                 LiveOrderPayment storePayment = liveOrderPaymentMapper.selectLiveOrderPaymentByPaymentCode(payCode);
@@ -762,6 +785,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             baseMapper.updateLiveOrder(order);
             try {
                 this.updateLiveWatchLog(order);
+                // 记录限购数量(订单创建成功后记录)
+                purchaseLimitService.increasePurchaseLimit(order.getProductId(), Long.valueOf(order.getUserId()), Integer.valueOf(order.getTotalNum()));
                 this.createOmsOrderCall(order);
             } catch (Exception e) {
                 log.error("推送erp失败:{}",e.getMessage());
@@ -777,6 +802,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             err.setMsg("支付错误:"+e.getMessage());
             err.setCreateTime(DateUtils.getNowDate());
             liveOrderPaymentErrorMapper.insertLiveOrderPaymentError(err);
+        } finally {
+            // 释放锁
+            if (lockAcquired) {
+                redisCache.deleteObject(lockKey);
+            }
         }
         return "SUCCESS";
     }
@@ -1161,15 +1191,15 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
 
 
             //模板消息支付成功发布事件
-            TemplateBean templateBean = TemplateBean.builder()
-                    .orderId(order.getOrderId().toString())
-                    .orderCode(order.getOrderCode().toString())
-                    .remark("您的订单已签收成功")
-                    .finishTime(order.getFinishTime())
-                    .userId(Long.valueOf(order.getUserId()))
-                    .templateType(TemplateListenEnum.TYPE_3.getValue())
-                    .build();
-            publisher.publishEvent(new TemplateEvent(this, templateBean));
+//            TemplateBean templateBean = TemplateBean.builder()
+//                    .orderId(order.getOrderId().toString())
+//                    .orderCode(order.getOrderCode().toString())
+//                    .remark("您的订单已签收成功")
+//                    .finishTime(order.getFinishTime())
+//                    .userId(Long.valueOf(order.getUserId()))
+//                    .templateType(TemplateListenEnum.TYPE_3.getValue())
+//                    .build();
+//            publisher.publishEvent(new TemplateEvent(this, templateBean));
             return R.ok("操作成功");
         } else {
             return R.error("非法操作");
@@ -1402,6 +1432,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 userService.subTuiMoney(storeOrder);
             }
         }
+        // 删除限购记录
+        deletePurchaseLimitRecordsForLiveOrder(order);
 
         return R.ok();
     }
@@ -1621,6 +1653,14 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 userService.subLiveTuiMoney(liveOrder);
             }
         }
+        //优惠券返回
+        if(order.getUserCouponId()!=null){
+            // 退券
+            order.setCouponUserId(Long.parseLong(order.getUserId()));
+            this.refundCoupon(order);
+        }
+        // 删除限购记录
+        deletePurchaseLimitRecordsForLiveOrder(order);
 
         return R.ok();
     }
@@ -3628,6 +3668,20 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         this.payConfirm(1, null, payment.getPayCode(), payment.getTradeNo(), payment.getBankSerialNo(), payment.getBankSerialNo());
     }
 
+    @Override
+    public void updateTime(LiveOrder order) {
+        LiveOrder liveOrder = new LiveOrder();
+        liveOrder.setOrderId(order.getOrderId());
+        liveOrder.setUpdateTime(order.getUpdateTime());
+        liveOrderMapper.updateLiveOrder(liveOrder);
+    }
+
+    public void deStockIncSale(List<FsStoreCartQueryVO> cartInfo) {
+        for (FsStoreCartQueryVO storeCartVO : cartInfo) {
+            fsStoreProductService.decProductStock(storeCartVO.getProductId(),
+                    storeCartVO.getProductAttrValueId(), storeCartVO.getCartNum());
+        }
+    }
 
     @Override
     @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
@@ -3657,22 +3711,19 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         if(!"1".equals(fsStoreProduct.getIsAudit()) ) return R.error("商品已下架,购买失败");
         if(liveOrder.getTotalNum() == null || StringUtils.isEmpty(liveOrder.getTotalNum())) liveOrder.setTotalNum("1");
         if(goods.getStock() == null) return R.error("直播间商品库存不足");
-        if(fsStoreProduct.getStock() < Integer.parseInt(liveOrder.getTotalNum()) || goods.getStock() < Integer.parseInt(liveOrder.getTotalNum())) return R.error("抱歉,这款商品已被抢光,暂时无库存~");
-
-        FsStoreProductAttrValueScrm attrValue = null;
-        if (!Objects.isNull(liveOrder.getAttrValueId())) {
-            attrValue = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueById(liveOrder.getAttrValueId());
-        }
-        if (attrValue != null) {
-            attrValue.setStock(attrValue.getStock() - Integer.parseInt(liveOrder.getTotalNum()));
-            attrValue.setSales(attrValue.getSales() + Integer.parseInt(liveOrder.getTotalNum()));
-            fsStoreProductAttrValueMapper.updateFsStoreProductAttrValue(attrValue);
+        FsStoreProductAttrValueScrm attrValue = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueById(liveOrder.getAttrValueId());
+        if(fsStoreProduct.getStock() < Integer.parseInt(liveOrder.getTotalNum()) || goods.getStock() < Integer.parseInt(liveOrder.getTotalNum()) || attrValue.getStock() < Integer.parseInt(liveOrder.getTotalNum())){
+            return R.error("抱歉,这款商品已被抢光,暂时无库存~");
         }
-        // 更改店铺库存
-        fsStoreProduct.setStock(fsStoreProduct.getStock()-Integer.parseInt(liveOrder.getTotalNum()));
-        fsStoreProduct.setSales(fsStoreProduct.getSales()+Integer.parseInt(liveOrder.getTotalNum()));
-        fsStoreProductScrmMapper.incStockDecSales(Long.valueOf("-" + liveOrder.getTotalNum()),fsStoreProduct.getProductId());
 
+
+        // 检查限购
+        Long userId = Long.parseLong(liveOrder.getUserId());
+        Integer purchaseNum = Integer.parseInt(liveOrder.getTotalNum());
+        checkPurchaseLimitForLiveOrder(userId, liveOrder.getProductId(), purchaseNum);
+
+        // 使用 deStockIncSale 方法处理库存和销量
+        deStockIncSale(liveOrder.getProductId(), liveOrder.getAttrValueId(), purchaseNum);
         // 更新直播间库存
         goods.setStock(goods.getStock()-Integer.parseInt(liveOrder.getTotalNum()));
         goods.setSales(goods.getSales()+Integer.parseInt(liveOrder.getTotalNum()));
@@ -3700,6 +3751,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         BigDecimal payPrice = fsStoreProduct.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
         if (attrValue != null) {
             payPrice = attrValue.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
+            fsStoreProduct.setPrice(payPrice);
         }
         // 直播不需要服务费 0915 1735 左
 //        String config=configService.selectConfigByKey("store.config");
@@ -3758,11 +3810,13 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                     dto.setBarCode(fsStoreProductAttrValue.getBarCode());
                     dto.setGroupBarCode(fsStoreProductAttrValue.getGroupBarCode());
                 }
+                dto.setPrice(fsStoreProduct.getPrice());
                 if (attrValue != null) {
                     dto.setBarCode(attrValue.getBarCode());
                     dto.setGroupBarCode(attrValue.getGroupBarCode());
+                    dto.setPrice(attrValue.getPrice());
                 }
-                dto.setPrice(fsStoreProduct.getPrice());
+                //dto.setPrice(fsStoreProduct.getPrice());
                 dto.setProductName(fsStoreProduct.getProductName());
                 dto.setNum(Long.valueOf(liveOrder.getTotalNum()));
 
@@ -3773,6 +3827,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 liveOrderItem.setNum(Long.valueOf(liveOrder.getTotalNum()));
                 liveOrderItem.setJsonInfo(JSON.toJSONString(dto));
                 liveOrderItemMapper.insertLiveOrderItem(liveOrderItem);
+
+
                 redisCache.deleteObject("orderKey:" + liveOrder.getOrderKey());
                 //添加支付到期时间
                 Calendar calendar = Calendar.getInstance();
@@ -3943,6 +3999,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             goods.setStock(goods.getStock()+Long.parseLong(liveOrder.getTotalNum()));
             // 更新商品库存
             liveGoodsMapper.updateLiveGoods(goods);
+
             // 退券
             this.refundCoupon(order);
             TemplateBean templateBean = TemplateBean.builder()
@@ -3960,6 +4017,57 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         }
     }
 
+    /**
+     * 检查限购(用于直播订单)
+     * @param userId 用户ID
+     * @param productId 商品ID
+     * @param num 购买数量
+     */
+    /**
+     * 减库存加销量(直播订单)
+     */
+    private void deStockIncSale(Long productId, Long attrValueId, Integer num) {
+        // 使用 productService.decProductStock 方法,该方法已包含库存检查逻辑
+        fsStoreProductService.decProductStock(productId, attrValueId, num);
+    }
+
+    private void checkPurchaseLimitForLiveOrder(Long userId, Long productId, Integer num) {
+        // 查询商品信息
+        FsStoreProductScrm product = fsStoreProductService.selectFsStoreProductById(productId);
+        if (product == null) {
+            return;
+        }
+
+        // 如果商品没有设置限购,直接返回
+        if (product.getPurchaseLimit() == null || product.getPurchaseLimit() <= 0) {
+            return;
+        }
+
+        // 查询用户已购买的数量
+        FsStoreProductPurchaseLimitScrm purchaseLimit = purchaseLimitService.selectByProductIdAndUserId(productId, userId);
+        int purchasedNum = 0;
+        if (purchaseLimit != null) {
+            purchasedNum = purchaseLimit.getNum();
+        }
+
+        // 检查是否超过限购数量
+        if (purchasedNum + num > product.getPurchaseLimit()) {
+            int productTotalNum = purchasedNum + num;
+            throw new CustomException("该商品限购" + product.getPurchaseLimit() + "件,您已购买" + productTotalNum + "件,无法继续购买");
+        }
+    }
+
+    /**
+     * 删除限购记录(用于直播订单)
+     * @param liveOrder 订单
+     */
+    private void deletePurchaseLimitRecordsForLiveOrder(LiveOrder liveOrder) {
+        // 减少限购数量
+        Long userId = Long.parseLong(liveOrder.getUserId());
+        Integer num = Integer.parseInt(liveOrder.getTotalNum());
+        purchaseLimitService.decreasePurchaseLimit(liveOrder.getProductId(), userId, num);
+    }
+
     private void refundCoupon(LiveOrder order) {
         if(order.getCouponUserId()!=null){
             LiveCouponUser couponUser=liveCouponUserService.selectLiveCouponUserById(order.getUserCouponId());

+ 123 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java

@@ -30,6 +30,8 @@ import com.fs.live.vo.*;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qwApi.domain.QwResult;
 import com.fs.qwApi.param.QwEditUserTagParam;
+import com.fs.qwApi.param.QwExternalContactRemarkParam;
+import com.fs.qwApi.domain.QwExternalContactRemarkResult;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.qw.domain.QwGroupChat;
 import com.fs.qw.domain.QwGroupChatUser;
@@ -46,9 +48,12 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 /**
@@ -934,6 +939,8 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
                     if (null != liveTagItemVO) {
                         tags.add(liveTagItemVO.getQwTagRealId());
                     }
+                    // 设置完课标志
+                    addItem.setIsCompleted(true);
                     break;
                 //3待看课
                 case 3:
@@ -1053,6 +1060,10 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
                     updateContact.setTagIds(JSON.toJSONString(new ArrayList<>(uniqueTagIds)));
                     qwExternalContactMapper.updateQwExternalContact(updateContact);
 
+                    // 处理完课备注更新逻辑
+                    Boolean isCompleted = userTagVO.getIsCompleted() != null && userTagVO.getIsCompleted();
+                    updateRemarkForCompletedCourse(userTagVO.getLiveId(), userTagVO.getExternalId(), qwExternalContact, isCompleted);
+
                     successCount++;
                     log.info("成功为用户打标签: externalId={}, userId={}, externalUserId={}, tags={}",
                             userTagVO.getExternalId(),
@@ -1080,6 +1091,118 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
                 userTagVOS.size(), successCount, failCount);
     }
 
+    /**
+     * 更新完课备注
+     * 如果用户完课,在备注中添加或更新完课日期
+     * 格式:MMdd完课-原有备注
+     *
+     * @param liveId 直播间ID
+     * @param externalId 外部联系人ID
+     * @param qwExternalContact 企微外部联系人信息
+     * @param isCompleted 完课标志(如果为true,不再查询数据库)
+     */
+    private void updateRemarkForCompletedCourse(Long liveId, Long externalId, QwExternalContact qwExternalContact, Boolean isCompleted) {
+        try {
+            // 如果liveId为空,跳过
+            if (liveId == null || externalId == null) {
+                return;
+            }
+
+            //
+            boolean completed = false;
+            if (isCompleted != null) {
+                // 使用传入的完课标志
+                completed = isCompleted;
+            }
+
+            if (!completed) {
+                // 未完课,不改动备注
+                log.debug("用户未完课,不更新备注: liveId={}, externalId={}",
+                        liveId, externalId);
+                return;
+            }
+
+            // 完课,需要更新备注
+            String currentRemark = qwExternalContact.getRemark();
+            String newRemark = buildCompletedCourseRemark(currentRemark);
+
+            // 如果备注没有变化,跳过更新
+            if (newRemark.equals(currentRemark)) {
+                log.debug("备注无需更新: liveId={}, externalId={}, remark={}",
+                        liveId, externalId, currentRemark);
+                return;
+            }
+
+            // 调用企微API更新备注
+            QwExternalContactRemarkParam remarkParam = new QwExternalContactRemarkParam();
+            remarkParam.setUserid(qwExternalContact.getUserId());
+            remarkParam.setExternal_userid(qwExternalContact.getExternalUserId());
+            remarkParam.setRemark(newRemark);
+
+            QwExternalContactRemarkResult remarkResult = qwApiService.externalcontactRemark(remarkParam, qwExternalContact.getCorpId());
+
+            if (remarkResult != null && remarkResult.getErrcode() == 0) {
+                // 更新成功,同步更新数据库
+                QwExternalContact updateContact = new QwExternalContact();
+                updateContact.setId(qwExternalContact.getId());
+                updateContact.setRemark(newRemark);
+                qwExternalContactMapper.updateQwExternalContact(updateContact);
+
+                log.info("成功更新完课备注: liveId={}, externalId={}, oldRemark={}, newRemark={}",
+                        liveId, externalId, currentRemark, newRemark);
+            } else {
+                String errorMsg = remarkResult != null ? remarkResult.getErrmsg() : "未知错误";
+                log.error("更新完课备注失败: liveId={}, externalId={}, error={}",
+                        liveId, externalId, errorMsg);
+            }
+        } catch (Exception e) {
+            log.error("更新完课备注异常: liveId={}, externalId={}, error={}",
+                    liveId, externalId, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 构建完课备注
+     * 格式:MMdd完课-原有备注
+     * 如果已有完课标记,则更新日期部分
+     *
+     * @param currentRemark 当前备注
+     * @return 新的备注
+     */
+    private String buildCompletedCourseRemark(String currentRemark) {
+        // 获取当前日期(MMdd格式)
+        SimpleDateFormat dateFormat = new SimpleDateFormat("MMdd");
+        String todayDate = dateFormat.format(new Date());
+        String completedPrefix = todayDate + "完课";
+
+        // 如果备注为空,直接返回完课标记
+        if (StringUtils.isEmpty(currentRemark)) {
+            return completedPrefix;
+        }
+
+        // 使用正则表达式匹配已有的完课标记格式:MMdd完课-xxx
+        // 匹配模式:4位数字(MMdd)+ "完课" + "-" + 后续内容
+        Pattern pattern = Pattern.compile("^(\\d{4})完课-(.+)$");
+        Matcher matcher = pattern.matcher(currentRemark);
+
+        if (matcher.matches()) {
+            // 已有完课标记,更新日期部分
+            String existingDate = matcher.group(1);
+            String remainingRemark = matcher.group(2);
+
+            // 如果日期相同,不需要更新
+            if (todayDate.equals(existingDate)) {
+                return currentRemark;
+            }
+
+            // 更新日期
+            return completedPrefix + "-" + remainingRemark;
+        } else {
+            // 没有完课标记,添加完课标记到前面
+            return completedPrefix + "-" + currentRemark;
+        }
+    }
+
     /**
      * 更新用户观看时长(心跳时调用)- 异步执行
      * @param liveId 直播间ID

+ 5 - 0
fs-service/src/main/java/com/fs/live/vo/HandleUserTagVO.java

@@ -26,4 +26,9 @@ public class HandleUserTagVO {
      * 打标签列表
      */
     private List<String> tags;
+
+    /**
+     * 是否完课标志(logType == 2 表示完课)
+     */
+    private Boolean isCompleted;
 }

+ 4 - 4
fs-service/src/main/java/com/fs/live/vo/LiveAfterSalesVo.java

@@ -143,11 +143,11 @@ public class LiveAfterSalesVo {
     /** 创建时间 */
     @Excel(name = "下单开始时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTimeBegin;
+    private String createTimeBegin;
     /** 创建时间 */
     @Excel(name = "下单结束时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTimeEnd;
+    private String createTimeEnd;
 
 
 
@@ -160,10 +160,10 @@ public class LiveAfterSalesVo {
 
     @Excel(name ="产品名称")
     private String productName;
-    
+
     /** 产品名称查询参数(用于搜索) */
     private String productNameQuery;
-    
+
     @Excel(name ="产品编码")
     private String productBarCode;
     @Excel(name ="规格")

+ 30 - 0
fs-service/src/main/java/com/fs/live/vo/LiveMsgExportVO.java

@@ -0,0 +1,30 @@
+package com.fs.live.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 直播评论导出VO
+ *
+ * @author fs
+ * @date 2026-01-13
+ */
+@Data
+public class LiveMsgExportVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 用户昵称 */
+    @Excel(name = "用户昵称")
+    private String nickName;
+
+    /** 评论内容 */
+    @Excel(name = "评论内容")
+    private String msg;
+
+    /** 发送时间 */
+    @Excel(name = "发送时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+}

+ 61 - 0
fs-service/src/main/java/com/fs/live/vo/PaymentExportVO.java

@@ -0,0 +1,61 @@
+package com.fs.live.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 支付导出VO
+ *
+ * @author fs
+ * @date 2026-01-08
+ */
+@Data
+public class PaymentExportVO {
+
+    /** 支付时间 */
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date payTime;
+
+    /** 交易单号 */
+    @Excel(name = "交易单号")
+    private String bankTransactionId;
+
+    /** 商户单号 */
+    @Excel(name = "商户单号")
+    private String tradeNo;
+
+    /** 商户号 */
+    @Excel(name = "商户号")
+    private String merchantNo;
+
+    /** 支付金额 */
+    @Excel(name = "支付金额")
+    private BigDecimal payMoney;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private String status;
+
+    /** 订单状态 */
+    @Excel(name = "订单状态")
+    private String orderStatus;
+
+    /** 物流单号 */
+    @Excel(name = "物流单号")
+    private String deliverySn;
+
+    /** 物流公司 */
+    @Excel(name = "物流公司")
+    private String deliveryName;
+
+    /** 商品名称 */
+    @Excel(name = "商品名称")
+    private String productName;
+
+    /** 支付订单号(带前缀) */
+    @Excel(name = "支付订单号")
+    private String payCodeWithPrefix;
+}

+ 41 - 0
fs-service/src/main/java/com/fs/live/vo/PaymentImportVO.java

@@ -0,0 +1,41 @@
+package com.fs.live.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 支付导入VO
+ *
+ * @author fs
+ * @date 2026-01-08
+ */
+@Data
+public class PaymentImportVO {
+
+    /** 支付时间 */
+    @Excel(name = "支付时间")
+    private Date payTime;
+
+    /** 交易单号 */
+    @Excel(name = "交易单号", required = true)
+    private String bankTransactionId;
+
+    /** 商户单号 */
+    @Excel(name = "商户单号")
+    private String tradeNo;
+
+    /** 商户号 */
+    @Excel(name = "商户号")
+    private String merchantNo;
+
+    /** 支付金额 */
+    @Excel(name = "支付金额")
+    private BigDecimal payMoney;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private String status;
+}

+ 25 - 1
fs-service/src/main/resources/mapper/hisStore/FsStoreProductScrmMapper.xml

@@ -465,7 +465,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <delete id="deleteFsStoreProductByIds" parameterType="String">
-        update fs_store_product_scrm set id_del = 1 where product_id in
+        update fs_store_product_scrm set is_del = 1 where product_id in
         <foreach item="productId" collection="array" open="(" separator="," close=")">
             #{productId}
         </foreach>
@@ -513,6 +513,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test='config.isAudit == "1"'>
             and p.is_audit = '1'
         </if>
+        <if test='appId != null and appId = "" '>
+            and ((FIND_IN_SET(#{appId}, p.app_ids) > 0))
+        </if>
         and p.is_new=1 and p.is_display=1 order by p.sort desc limit #{count}
     </select>
     <select id="selectFsStoreProductHotQuery" resultType="com.fs.hisStore.vo.FsStoreProductListQueryVO">
@@ -524,6 +527,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test='config.isAudit == "1" '>
         and p.is_audit = '1'
         </if>
+        <if test='appId != null and appId = "" '>
+            and ((FIND_IN_SET(#{appId}, p.app_ids) > 0))
+        </if>
         and  p.is_hot=1 and p.is_display=1 order by p.sort desc limit #{count}
     </select>
     <select id="selectFsStoreProductGoodListQuery" resultType="com.fs.hisStore.vo.FsStoreProductListQueryVO">
@@ -535,6 +541,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test='config.isAudit == "1" '>
         and p.is_audit = '1'
         </if>
+        <if test = 'param.appId != null and param.appId != ""'>
+        and ((FIND_IN_SET(#{param.appId}, p.app_ids) > 0))
+        </if>
         and  p.is_good=1 and p.is_display=1 order by p.sort desc
     </select>
 
@@ -544,4 +553,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         #{item}
     </foreach>
     </select>
+    <select id="selectFsStoreProductTotalMoneyByIds" resultType="java.math.BigDecimal">
+        WITH product_temp AS (
+        <foreach collection="productInfos" item="item" index="index" separator=" UNION ALL ">
+            SELECT
+            #{item.productId} as product_id,
+            #{item.num} as num
+        </foreach>
+        )
+        SELECT
+        SUM(p.price * pt.num) as totalMoney
+        FROM
+        fs_store_product_scrm p
+        INNER JOIN
+        product_temp pt ON p.product_id = pt.product_id
+    </select>
 </mapper>

+ 9 - 4
fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml

@@ -90,7 +90,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="refundType != null "> and las.refund_type = #{refundType}</if>
             <if test="status != null "> and las.status = #{status}</if>
             <if test="salesStatus != null "> and las.sales_status = #{salesStatus}</if>
-            <if test="orderStatus != null "> and las.order_status = #{orderStatus}</if>
+            <if test="orderStatus != null "> and lo.status = #{orderStatus}</if>
             <if test="reasons != null  and reasons != ''"> and las.reasons = #{reasons}</if>
             <if test="explains != null  and explains != ''"> and las.explains = #{explains}</if>
             <if test="explainImg != null  and explainImg != ''"> and las.explain_img = #{explainImg}</if>
@@ -99,7 +99,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="deliveryName != null  and deliveryName != ''"> and las.delivery_name like concat('%', #{deliveryName}, '%')</if>
             <if test="status != null "> and las.status = #{status}</if>
             <if test="salesStatus != null "> and las.sales_status = #{salesStatus}</if>
-            <if test="orderStatus != null "> and las.order_status = #{orderStatus}</if>
+            <!--<if test="orderStatus != null "> and las.order_status = #{orderStatus}</if>-->
             <if test="deliveryStatus != null and deliveryStatus!= ''"> and las.order_status = #{deliveryStatus}</if>
             <if test="isDel != null  and isDel != ''"> and las.is_del = #{isDel}</if>
             <if test="userId != null "> and las.user_id = #{userId}</if>
@@ -110,6 +110,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="companyUserId != null "> and las.company_user_id = #{companyUserId}</if>
             <if test="deptId != null "> and cu.dept_id = #{deptId}</if>
             <if test="userPhone != null "> and lo.user_phone like concat(#{userPhone},'%')</if>
+            <if test="createTimeBegin != null and createTimeBegin != ''"> and date_format(las.create_time,'%y%m%d') &gt;= date_format(#{createTimeBegin},'%y%m%d')</if>
+            <if test="createTimeEnd != null and createTimeEnd != ''"> and date_format(las.create_time,'%y%m%d') &lt;= date_format(#{createTimeEnd},'%y%m%d')</if>
         </where>
         <if test="productName != null and productName != ''">
         group by las.id
@@ -119,7 +121,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectLiveAfterSalesVoListExport" parameterType="com.fs.live.vo.LiveAfterSalesVo" resultType="com.fs.live.vo.LiveAfterSalesVo">
         select las.id, las.live_id, las.store_id, las.refund_amount,
         las.refund_type, las.reasons, las.explains, las.explain_img, las.delivery_code, las.delivery_sn, las.delivery_name, las.status, las.sales_status,
-        las.order_status, las.create_time, las.is_del, las.user_id, las.consignee, las.phone_number, las.address, las.company_id, las.company_user_id, las.dept_id,
+        las.order_status, lo.create_time, las.is_del, las.user_id, las.consignee, las.phone_number, las.address, las.company_id, las.company_user_id, las.dept_id,
         cu.nick_name as company_user_nick_name, c.company_name,lo.order_id,lo.order_code,lo.user_phone,lo.item_json,lo.pay_time as orderPayTime,
         lo.user_address,lo.user_name,lo.pay_price,lo.total_postage,lop.bank_serial_no,lo.delivery_sn as orderDeliveryId,lo.delivery_name as orderDeliveryName,
         lo.delivery_code as orderDeliverySn,lo.status as orderStatus,lop.bank_transaction_id,lo.pay_money,lop.pay_code as payCode
@@ -132,8 +134,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         left join live_order_item loi on loi.order_id = lo.order_id
         </if>
 
-        where 1=1 and las.status =4 and lop.bank_transaction_id is not null
+        where 1=1 and las.is_del = 0 and lo.status = -2 and lop.bank_transaction_id is not null
             <if test="hfOrderCode != null and hfOrderCode != ''"> and lop.pay_code = #{hfOrderCode}</if>
+            <if test="bankTransactionId != null and bankTransactionId != ''"> and lop.bank_transaction_id = #{bankTransactionId}</if>
             <if test="liveId != null and liveId != ''"> and las.live_id = #{liveId}</if>
             <if test="companyUserNickName != null and companyUserNickName != ''"> and cu.nick_name like concat(#{companyUserNickName},'%')</if>
             <if test="storeId != null and storeId != ''"> and las.store_id = #{storeId}</if>
@@ -163,6 +166,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="companyUserId != null "> and las.company_user_id = #{companyUserId}</if>
             <if test="deptId != null "> and cu.dept_id = #{deptId}</if>
             <if test="userPhone != null "> and lo.user_phone like concat(#{userPhone},'%')</if>
+            <if test="createTimeBegin != null and createTimeBegin != ''"> and date_format(las.create_time,'%y%m%d') &gt;= date_format(#{createTimeBegin},'%y%m%d')</if>
+            <if test="createTimeEnd != null and createTimeEnd != ''"> and date_format(las.create_time,'%y%m%d') &lt;= date_format(#{createTimeEnd},'%y%m%d')</if>
 
         <if test="productName != null and productName != ''">
         group by las.id

+ 24 - 13
fs-service/src/main/resources/mapper/live/LiveCouponUserMapper.xml

@@ -27,20 +27,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </sql>
 
     <select id="selectLiveCouponUserList" parameterType="LiveCouponUser" resultMap="LiveCouponUserResult">
-        <include refid="selectLiveCouponUserVo"/>
+        select lcu.id, lcu.coupon_id, lcu.user_id, lcu.coupon_title, lcu.coupon_price, lcu.use_min_price, lcu.create_time, lcu.update_time, lcu.limit_time,
+               lcu.use_time, lcu.type, lcu.status, lcu.is_fail, lcu.is_del,lcu.goods_id, fu.nick_name,fu.phone
+        from live_coupon_user lcu LEFT JOIN fs_user fu ON lcu.user_id = fu.user_id
         <where>
-            <if test="couponId != null "> and coupon_id = #{couponId}</if>
-            <if test="userId != null "> and user_id = #{userId}</if>
-            <if test="couponTitle != null  and couponTitle != ''"> and coupon_title = #{couponTitle}</if>
-            <if test="couponPrice != null "> and coupon_price = #{couponPrice}</if>
-            <if test="useMinPrice != null "> and use_min_price = #{useMinPrice}</if>
-            <if test="limitTime != null "> and limit_time = #{limitTime}</if>
-            <if test="useTime != null "> and use_time = #{useTime}</if>
-            <if test="type != null  and type != ''"> and type = #{type}</if>
-            <if test="status != null "> and status = #{status}</if>
-            <if test="isFail != null "> and is_fail = #{isFail}</if>
-            <if test="isDel != null "> and is_del = #{isDel}</if>
-            <if test="goodsId != null "> and goods_id = #{goodsId}</if>
+            <if test="couponId != null "> and lcu.coupon_id = #{couponId}</if>
+            <if test="userId != null "> and lcu.user_id = #{userId}</if>
+            <if test="couponTitle != null  and couponTitle != ''"> and lcu.coupon_title = #{couponTitle}</if>
+            <if test="couponPrice != null "> and lcu.coupon_price = #{couponPrice}</if>
+            <if test="useMinPrice != null "> and lcu.use_min_price = #{useMinPrice}</if>
+            <if test="limitTime != null "> and lcu.limit_time = #{limitTime}</if>
+            <if test="useTime != null "> and lcu.use_time = #{useTime}</if>
+            <if test="type != null  and type != ''"> and lcu.type = #{type}</if>
+            <if test="status != null "> and lcu.status = #{status}</if>
+            <if test="isFail != null "> and lcu.is_fail = #{isFail}</if>
+            <if test="isDel != null "> and lcu.is_del = #{isDel}</if>
+            <if test="goodsId != null "> and lcu.goods_id = #{goodsId}</if>
         </where>
     </select>
 
@@ -106,6 +108,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where id = #{id}
     </update>
 
+    <update id="refundCoupon">
+        UPDATE live_coupon_user
+        SET
+            `status` = 0,
+            `is_fail` = 0
+        WHERE
+            `id` = #{couponUserId}
+    </update>
+
     <delete id="deleteLiveCouponUserById" parameterType="Long">
         delete from live_coupon_user where id = #{id}
     </delete>

+ 12 - 0
fs-service/src/main/resources/mapper/live/LiveMsgMapper.xml

@@ -109,4 +109,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{msgId}
         </foreach>
     </delete>
+
+    <!-- 导出直播评论数据 -->
+    <select id="selectLiveMsgForExport" resultType="com.fs.live.vo.LiveMsgExportVO">
+        SELECT
+            nick_name as nickName,
+            msg,
+            create_time as createTime
+        FROM live_msg
+        WHERE live_id = #{liveId}
+        ORDER BY create_time ASC
+        LIMIT 30000
+    </select>
 </mapper>

+ 11 - 1
fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml

@@ -198,7 +198,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             a.pay_remain,	a.delivery_status,	a.delivery_pay_status,	a.delivery_pay_time,	a.delivery_type,
             a.delivery_pay_money,	a.delivery_import_time,	a.delivery_send_time,	a.is_after_sales,	a.dept_id,
             a.channel,	a.source,	a.bill_price,	a.total_postage,	a.pay_postage,	a.gain_integral,a.coupon_price,
-            a.use_integral,	a.pay_integral,	a.back_integral,	a.is_edit_money,	b.product_info as product_introduce,a.customer_id,a.app_id
+            a.use_integral,	a.pay_integral,	a.back_integral,	a.is_edit_money,	b.product_info as product_introduce,a.customer_id,a.app_id,a.coupon_user_id
         FROM
             live_order a LEFT JOIN fs_store_product_scrm b ON a.product_id = b.product_id
                          left join company_user cu on a.company_user_id = cu.user_id
@@ -281,6 +281,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="customerId != null">customer_id,</if>
             <if test="couponPrice != null">coupon_price,</if>
             <if test="appId != null and appId != ''">app_id,</if>
+            <if test="couponUserId != null and couponUserId != ''">coupon_user_id,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="liveId != null">#{liveId},</if>
@@ -354,6 +355,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="customerId != null">#{customerId},</if>
             <if test="couponPrice != null">#{couponPrice},</if>
             <if test="appId != null and appId != ''">#{appId},</if>
+            <if test="couponUserId != null and couponUserId != ''">#{couponUserId},</if>
          </trim>
     </insert>
 
@@ -483,6 +485,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </foreach>
     </select>
 
+    <select id="selectLiveOrderByOrderIds" resultMap="LiveOrderResult">
+        <include refid="selectLiveOrderVo"/>
+        where order_id IN
+        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
+            #{orderId}
+        </foreach>
+    </select>
+
     <select id="selectLiveOrderListVO" resultType="com.fs.live.vo.LiveOrderVO">
 
     select o.*,u.phone,u.register_code,u.register_date,u.source, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber

+ 8 - 0
fs-service/src/main/resources/mapper/live/LiveOrderPaymentMapper.xml

@@ -223,4 +223,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{paymentId}
         </foreach>
     </delete>
+
+    <select id="selectByBankTransactionIds" resultMap="LiveOrderPaymentResult">
+        <include refid="selectLiveOrderPaymentVo"/>
+        where bank_transaction_id in
+        <foreach item="bankTransactionId" collection="bankTransactionIds" open="(" separator="," close=")">
+            #{bankTransactionId}
+        </foreach>
+    </select>
 </mapper>

+ 1 - 0
fs-service/src/main/resources/mapper/live/LiveUserRedRecordMapper.xml

@@ -26,6 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="liveId != null "> and live_id = #{liveId}</if>
             <if test="userId != null "> and user_id = #{userId}</if>
             <if test="createTime != null "> and create_time = #{createTime}</if>
+            <if test="redId != null"> and red_id = #{redId}</if>
         </where>
 
         order by create_time desc

+ 5 - 1
fs-service/src/main/resources/mapper/live/LiveWatchLogMapper.xml

@@ -211,6 +211,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select * from live_watch_log where live_id = #{liveId}
     </select>
 
+    <select id="selectLiveWatchLogByLiveIdAndExternalId" resultType="com.fs.live.domain.LiveWatchLog">
+        select * from live_watch_log where live_id = #{liveId} and external_contact_id = #{externalContactId} limit 1
+    </select>
+
     <select id="selectLiveWatchLogListInfo"   parameterType="LiveWatchLog" resultType="com.fs.live.vo.LiveWatchLogListVO">
         select
         t2.nick_name as userName,
@@ -336,4 +340,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{item.logId}
         </foreach>
     </update>
-</mapper>
+</mapper>