Browse Source

app课程打卡积分奖励优化,销售后台消息提醒

wangxy 1 tuần trước cách đây
mục cha
commit
846135586d
34 tập tin đã thay đổi với 1552 bổ sung52 xóa
  1. 34 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseCheckinActivityController.java
  2. 29 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  3. 56 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyCheckinActivityController.java
  4. 11 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralGoodsController.java
  5. 14 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralOrderController.java
  6. 4 4
      fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinActivity.java
  7. 16 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinReceive.java
  8. 37 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinWarningQuery.java
  9. 143 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinWarningVO.java
  10. 8 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseCheckinActivityMapper.java
  11. 19 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseCheckinReceiveMapper.java
  12. 18 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseCheckinUserMapper.java
  13. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCoursePeriodDaysMapper.java
  14. 35 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseCheckinActivityService.java
  15. 18 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseCheckinReceiveService.java
  16. 347 6
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseCheckinActivityServiceImpl.java
  17. 33 12
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseCheckinPrizeServiceImpl.java
  18. 181 18
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseCheckinReceiveServiceImpl.java
  19. 1 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserTalentServiceImpl.java
  20. 15 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralGoods.java
  21. 7 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java
  22. 10 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralOrderCreateParam.java
  23. 21 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralOrderManuallyParam.java
  24. 25 0
      fs-service/src/main/java/com/fs/his/service/IFsIntegralGoodsService.java
  25. 7 0
      fs-service/src/main/java/com/fs/his/service/IFsIntegralOrderService.java
  26. 104 0
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java
  27. 179 5
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralOrderServiceImpl.java
  28. 7 0
      fs-service/src/main/resources/mapper/course/FsCourseCheckinActivityMapper.xml
  29. 33 1
      fs-service/src/main/resources/mapper/course/FsCourseCheckinReceiveMapper.xml
  30. 114 0
      fs-service/src/main/resources/mapper/course/FsCourseCheckinUserMapper.xml
  31. 5 0
      fs-service/src/main/resources/mapper/his/FsIntegralOrderMapper.xml
  32. 2 1
      fs-user-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  33. 4 3
      fs-user-app/src/main/java/com/fs/app/controller/IntegralController.java
  34. 14 0
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseFsUserController.java

+ 34 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseCheckinActivityController.java

@@ -8,8 +8,12 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsCourseCheckinActivity;
 import com.fs.course.domain.FsCourseCheckinPrize;
+import com.fs.course.domain.FsCourseCheckinReceive;
+import com.fs.course.domain.FsCourseCheckinWarningQuery;
+import com.fs.course.domain.FsCourseCheckinWarningVO;
 import com.fs.course.service.IFsCourseCheckinActivityService;
 import com.fs.course.service.IFsCourseCheckinPrizeService;
+import com.fs.course.service.IFsCourseCheckinReceiveService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -32,6 +36,9 @@ public class FsCourseCheckinActivityController extends BaseController {
     @Autowired
     private IFsCourseCheckinPrizeService fsCourseCheckinPrizeService;
 
+    @Autowired
+    private IFsCourseCheckinReceiveService fsCourseCheckinReceiveService;
+
     /**
      * 查询看课打卡活动列表
      */
@@ -118,4 +125,31 @@ public class FsCourseCheckinActivityController extends BaseController {
         List<FsCourseCheckinPrize> list = fsCourseCheckinPrizeService.selectFsCourseCheckinPrizeByActivityId(activityId);
         return AjaxResult.success(list);
     }
+
+    /**
+     * 复制活动
+     * 复制源活动,只修改活动时间
+     */
+    @PreAuthorize("@ss.hasPermi('course:checkinActivity:add')")
+    @Log(title = "看课打卡活动", businessType = BusinessType.INSERT)
+    @PostMapping("/copy")
+    public AjaxResult copyActivity(@RequestBody FsCourseCheckinActivity fsCourseCheckinActivity) {
+        try {
+            Long newActivityId = fsCourseCheckinActivityService.copyActivity(fsCourseCheckinActivity.getActivityId(), fsCourseCheckinActivity.getStartTime(), fsCourseCheckinActivity.getEndTime());
+            return AjaxResult.success("复制活动成功", newActivityId);
+        } catch (Exception e) {
+            return AjaxResult.error("复制活动失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 分页查询活动的领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:checkinReceive:query')")
+    @GetMapping("/prizeRecord")
+    public TableDataInfo receiveList(FsCourseCheckinReceive fsCourseCheckinReceive) {
+        startPage();
+        List<FsCourseCheckinReceive> list = fsCourseCheckinReceiveService.selectReceiveListByActivityAndType(fsCourseCheckinReceive.getActivityId(), fsCourseCheckinReceive.getPrizeType());
+        return getDataTable(list);
+    }
 }

+ 29 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -20,6 +20,7 @@ import com.fs.company.vo.QwIpadTotalVo;
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.dto.BatchSendCourseAllDTO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import com.fs.course.service.IFsCourseCheckinActivityService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.ITencentCloudCosService;
@@ -228,6 +229,9 @@ public class Task {
     @Autowired
     private IFsIntegralOrderService fsIntegralOrderService;
 
+    @Autowired
+    private IFsCourseCheckinActivityService fsCourseCheckinActivityService;
+
     @Value("${jst.shop_code:''}")
     private String shopCode;
 
@@ -1799,4 +1803,29 @@ public class Task {
         fsIntegralOrderService.createOmsIntegralOrder(omsList);
     }
 
+    /**
+     * 看课打卡状态自动更新
+     */
+    public void updateCourseCheckinActivityStatus() {
+        try {
+            fsCourseCheckinActivityService.updateActivityStatusByTime();
+            log.info("看课打卡状态自动更新成功");
+        } catch (Exception e) {
+            log.error("看课打卡状态自动更新失败,错误信息:{}", e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 看课打卡提醒消息发送
+     * 发送剩余一天提醒和打卡完成提醒给销售
+     */
+    public void sendCheckinRemindMsg() {
+        try {
+            fsCourseCheckinActivityService.sendCheckinRemindToSales();
+            log.info("看课打卡提醒消息发送成功");
+        } catch (Exception e) {
+            log.error("看课打卡提醒消息发送失败,错误信息:{}", e.getMessage(), e);
+        }
+    }
+
 }

+ 56 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyCheckinActivityController.java

@@ -0,0 +1,56 @@
+package com.fs.company.controller.company;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.course.domain.FsCourseCheckinActivity;
+import com.fs.course.domain.FsCourseCheckinWarningQuery;
+import com.fs.course.domain.FsCourseCheckinWarningVO;
+import com.fs.course.service.IFsCourseCheckinActivityService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.security.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/company/checkinActivity")
+public class CompanyCheckinActivityController extends BaseController {
+
+    @Autowired
+    private IFsCourseCheckinActivityService fsCourseCheckinActivityService;
+
+    /**
+     * 活动列表
+     */
+    @GetMapping("/activityList")
+    public TableDataInfo activityList() {
+        startPage();
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long companyId = loginUser.getCompany().getCompanyId();
+        List<FsCourseCheckinActivity> list = fsCourseCheckinActivityService.selectActivityListByCompanyId(companyId);
+        return getDataTable(list);
+    }
+
+    /**
+     * 活动预警管理列表
+     */
+    @GetMapping("/warningList")
+    public TableDataInfo warningList(FsCourseCheckinWarningQuery query) {
+        startPage();
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        query.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<FsCourseCheckinWarningVO> list = fsCourseCheckinActivityService.selectWarningList(query);
+        return getDataTable(list);
+    }
+
+
+    @PostMapping("/testSendMsg")
+    public  void  testSendMsg(){
+    	fsCourseCheckinActivityService.sendCheckinRemindToSales();
+    }
+}

+ 11 - 0
fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralGoodsController.java

@@ -3,6 +3,7 @@ package com.fs.hisStore.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
@@ -126,4 +127,14 @@ public class FsIntegralGoodsController extends BaseController
         redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.deleteFsIntegralGoodsByGoodsIds(goodsIds));
     }
+
+    /**
+     * 打卡活动未领取的积分商品
+     */
+    @GetMapping("/getCheckinPrizeGoodsListByUserId")
+    public AjaxResult getCheckinPrizeGoodsListByUserId(@RequestParam(required = false) List<Long> userIds,
+                                                        @RequestParam(required = false) String goodsName){
+        List<FsIntegralGoods> goodsList = fsIntegralGoodsService.selectCheckinPrizeGoodsListByUserIds(userIds, goodsName);
+        return AjaxResult.success(goodsList);
+    }
 }

+ 14 - 0
fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralOrderController.java

@@ -11,14 +11,18 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.domain.FsIntegralOrder;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.mapper.FsIntegralGoodsMapper;
 import com.fs.his.param.FsIntegralOrderCreateParam;
+import com.fs.his.param.FsIntegralOrderManuallyParam;
 import com.fs.his.param.FsIntegralOrderParam;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsIntegralOrderService;
@@ -51,6 +55,9 @@ public class FsIntegralOrderController extends BaseController
     @Autowired
     private IFsExpressService expressService;
 
+    @Autowired
+    private TokenService tokenService;
+
     @Autowired
     private FsIntegralGoodsMapper fsIntegralGoodsMapper;
     /**
@@ -179,4 +186,11 @@ public class FsIntegralOrderController extends BaseController
     {
         return toAjax(fsIntegralOrderService.deleteFsIntegralOrderByOrderIds(orderIds));
     }
+
+    @PostMapping("/createByManually")
+    @Log(title = "手动创建积分订单", businessType = BusinessType.INSERT)
+    public R createByManually(@RequestBody FsIntegralOrderManuallyParam param)
+    {
+        return fsIntegralOrderService.createOrderByManually(param);
+    }
 }

+ 4 - 4
fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinActivity.java

@@ -31,13 +31,13 @@ public class FsCourseCheckinActivity implements Serializable {
     private String activityName;
 
     /** 活动开始时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Excel(name = "活动开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "活动开始时间", width = 30, dateFormat = "yyyy-MM-dd")
     private Date startTime;
 
     /** 活动结束时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Excel(name = "活动结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "活动结束时间", width = 30, dateFormat = "yyyy-MM-dd")
     private Date endTime;
 
     /** 需要打卡天数 */

+ 16 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinReceive.java

@@ -104,6 +104,22 @@ public class FsCourseCheckinReceive implements Serializable {
     @Excel(name = "活动名称")
     private String activityName;
 
+    /** 积分商品名称(奖品类型为积分商品时) */
+    @Excel(name = "积分商品名称")
+    private String goodsName;
+
+    /**
+     * 公司名称
+     */
+    @Excel(name = "公司名称")
+    private String companyName;
+
+    /**
+     * 用户昵称
+     */
+    @Excel(name = "用户昵称")
+    private String userNickName;
+
     private String outBatchNo;
 
     private  String batchId;

+ 37 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinWarningQuery.java

@@ -0,0 +1,37 @@
+package com.fs.course.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 活动预警管理查询参数
+ *
+ * @author fs
+ * @date 2025-03-18
+ */
+@Data
+public class FsCourseCheckinWarningQuery implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 公司ID */
+    private Long companyId;
+
+    /** 活动ID */
+    private Long activityId;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 手机号 */
+    private String phone;
+
+    /** 综合状态:1-未完成打卡,2-已完成打卡未领取,3-已领取待发放,4-红包已到账,5-积分商品待发货,6-积分商品已发货 */
+    private Integer status;
+
+    /** 打卡时间(精确到年月日) */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date checkinTime;
+}

+ 143 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseCheckinWarningVO.java

@@ -0,0 +1,143 @@
+package com.fs.course.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 活动预警管理VO
+ *
+ * @author fs
+ * @date 2025-03-18
+ */
+@Data
+public class FsCourseCheckinWarningVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 打卡记录ID */
+    private Long id;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 活动ID */
+    private Long activityId;
+
+    /** 用户昵称 */
+    @Excel(name = "用户昵称")
+    private String userNickName;
+
+    /** 手机号 */
+    @Excel(name = "手机号")
+    private String phone;
+
+    /** 公司名称 */
+    @Excel(name = "公司")
+    private String companyName;
+
+    /** 项目名称 */
+    @Excel(name = "项目")
+    private String projectName;
+
+    /** 活动名称 */
+    @Excel(name = "活动名称")
+    private String activityName;
+
+    /** 活动开始时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "活动开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date activityStartTime;
+
+    /** 活动结束时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "活动结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date activityEndTime;
+
+    /** 需要打卡天数 */
+    private Integer checkinDays;
+
+    /** 已打卡天数 */
+    @Excel(name = "已打卡天数")
+    private Integer currentCheckinDays;
+
+    /** 打卡剩余天数 */
+    @Excel(name = "打卡剩余天数")
+    private Integer remainingDays;
+
+    /** 首次打卡时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date firstCheckinTime;
+
+    /** 最后打卡时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date lastCheckinTime;
+
+    /** 打卡时间(有最后打卡时间取最后,否则取首次打卡时间) */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "打卡时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date checkinTime;
+
+    /** 综合状态:1-未完成打卡,2-已完成打卡未领取,3-已领取待发放,4-红包已到账,5-积分商品待发货,6-积分商品已发货 */
+    @Excel(name = "状态", readConverterExp = "1=未完成打卡,2=已完成打卡未领取,3=已领取待发放,4=红包已到账,5=积分商品待发货,6=积分商品已发货")
+    private Integer status;
+
+    /** 综合状态文本 */
+    private String statusText;
+
+    /** 是否打卡完成:0-未完成,1-已完成 */
+    private Integer isCompleted;
+
+    /** 是否打卡完成文本 */
+    private String isCompletedText;
+
+    /** 奖励到账状态:0-待发放,1-已到账,2-发放失败 */
+    @Excel(name = "奖励到账状态", readConverterExp = "0=待发放,1=已到账,2=发放失败")
+    private Integer rewardStatus;
+
+    /** 奖励到账状态文本 */
+    private String rewardStatusText;
+
+    /** 积分商品订单状态:1-待发货,2-待收货,3-已完成,4-待支付,-1-取消 */
+    private Integer orderStatus;
+
+    /** 是否发货:0-未发货,1-已发货 */
+    @Excel(name = "是否发货", readConverterExp = "0=未发货,1=已发货")
+    private Integer isShipped;
+
+    /** 是否发货文本 */
+    private String isShippedText;
+
+    /** 领取记录ID */
+    private Long receiveId;
+
+    /** 奖品类型:1-红包,2-积分商品券 */
+    private Integer prizeType;
+
+    /** 奖品类型文本 */
+    private String prizeTypeText;
+
+    /** 奖品名称 */
+    private String prizeName;
+
+    /** 红包金额 */
+    private BigDecimal redpacketAmount;
+
+    /** 积分商品名称 */
+    private String goodsName;
+
+    /** 积分商品ID */
+    private Long goodsId;
+
+    /** 公司ID */
+    private Long companyId;
+
+    /** 项目ID */
+    private Long projectId;
+
+    /** 通知模板 */
+    private String notifyTemplate;
+}

+ 8 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseCheckinActivityMapper.java

@@ -74,4 +74,12 @@ public interface FsCourseCheckinActivityMapper {
                                                           @Param("companyId") Long companyId,
                                                           @Param("projectId") Long projectId,
                                                           @Param("currentDate") Date currentDate);
+
+    /**
+     * 根据公司ID查询活动列表
+     *
+     * @param companyId 公司ID
+     * @return 活动列表
+     */
+    List<FsCourseCheckinActivity> selectActivityListByCompanyId(@Param("companyId") Long companyId);
 }

+ 19 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseCheckinReceiveMapper.java

@@ -84,4 +84,23 @@ public interface FsCourseCheckinReceiveMapper {
      * @return 结果
      */
     int batchInsertFsCourseCheckinReceive(@Param("list") List<FsCourseCheckinReceive> receiveList);
+
+    /**
+     * 根据活动ID和奖品类型查询领取记录列表
+     * 包含用户信息(昵称)、公司名,积分商品类型时包含商品名称
+     *
+     * @param activityId 活动ID
+     * @param prizeType 奖品类型(1-红包,2-积分商品券)
+     * @return 领取记录列表
+     */
+    List<FsCourseCheckinReceive> selectReceiveListByActivityAndType(@Param("activityId") Long activityId, @Param("prizeType") Integer prizeType);
+
+    /**
+     * 查询打卡活动未领取的积分商品记录(支持多用户和商品名称模糊搜索)
+     *
+     * @param userIds 用户ID列表
+     * @param goodsName 商品名称
+     * @return 领取记录列表
+     */
+    List<FsCourseCheckinReceive> selectCheckinPrizeReceiveByUserIds(@Param("userIds") List<Long> userIds, @Param("goodsName") String goodsName);
 }

+ 18 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseCheckinUserMapper.java

@@ -1,6 +1,8 @@
 package com.fs.course.mapper;
 
 import com.fs.course.domain.FsCourseCheckinUser;
+import com.fs.course.domain.FsCourseCheckinWarningQuery;
+import com.fs.course.domain.FsCourseCheckinWarningVO;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -78,4 +80,20 @@ public interface FsCourseCheckinUserMapper {
      * @return 结果
      */
     int deleteFsCourseCheckinUserByActivityId(Long activityId);
+
+    /**
+     * 查询活动预警管理列表
+     *
+     * @param query 查询参数
+     * @return 预警列表
+     */
+    List<FsCourseCheckinWarningVO> selectWarningList(FsCourseCheckinWarningQuery query);
+
+    /**
+     * 查询需要发送打卡提醒的用户列表
+     *
+     * @param remindType 提醒类型:1-剩余一天提醒,2-打卡完成提醒
+     * @return 需要提醒的用户列表
+     */
+    List<FsCourseCheckinWarningVO> selectCheckinRemindList(@Param("remindType") Integer remindType);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/course/mapper/FsUserCoursePeriodDaysMapper.java

@@ -128,6 +128,6 @@ public interface FsUserCoursePeriodDaysMapper extends BaseMapper<FsUserCoursePer
     /**
      * 查询营期视频
      */
-    @Select("select * from fs_user_course_period_days where period_id = #{periodId} and video_id = #{videoId}")
+    @Select("select * from fs_user_course_period_days where period_id = #{periodId} and video_id = #{videoId} and del_flag = 0")
     FsUserCoursePeriodDays selectByPeriodAndVideoId(@Param("periodId") Long periodId, @Param("videoId") Long videoId);
 }

+ 35 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseCheckinActivityService.java

@@ -2,6 +2,8 @@ package com.fs.course.service;
 
 import com.fs.course.domain.FsCourseCheckinActivity;
 import com.fs.course.domain.FsCourseCheckinPrize;
+import com.fs.course.domain.FsCourseCheckinWarningQuery;
+import com.fs.course.domain.FsCourseCheckinWarningVO;
 
 import java.util.Date;
 import java.util.List;
@@ -104,4 +106,37 @@ public interface IFsCourseCheckinActivityService {
      * @return 结果
      */
     int stopActivity(Long activityId);
+
+    /**
+     * 复制活动
+     * 复制源活动,只修改活动时间
+     *
+     * @param activityId 源活动ID
+     * @param startTime  新的开始时间
+     * @param endTime    新的结束时间
+     * @return 新活动ID
+     */
+    Long copyActivity(Long activityId, Date startTime, Date endTime);
+
+    /**
+     * 查询活动预警管理列表
+     *
+     * @param query 查询参数
+     * @return 预警列表
+     */
+    List<FsCourseCheckinWarningVO> selectWarningList(FsCourseCheckinWarningQuery query);
+
+    /**
+     * 根据公司ID查询活动列表
+     *
+     * @param companyId 公司ID
+     * @return 活动列表
+     */
+    List<FsCourseCheckinActivity> selectActivityListByCompanyId(Long companyId);
+
+    /**
+     * 发送打卡提醒消息给销售
+     * 定时任务调用
+     */
+    void sendCheckinRemindToSales();
 }

+ 18 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseCheckinReceiveService.java

@@ -117,4 +117,22 @@ public interface IFsCourseCheckinReceiveService {
      * @return 结果
      */
     boolean sendNotify(Long receiveId);
+
+    /**
+     * 根据活动ID和奖品类型查询领取记录列表
+     * 包含用户信息(昵称)、公司名,积分商品类型时包含商品名称
+     *
+     * @param activityId 活动ID
+     * @param prizeType 奖品类型(1-红包,2-积分商品券)
+     * @return 领取记录列表
+     */
+    List<FsCourseCheckinReceive> selectReceiveListByActivityAndType(Long activityId, Integer prizeType);
+
+    /**
+     * 查询用户的奖励领取记录列表
+     *
+     * @param userId 用户ID
+     * @return 领取记录列表
+     */
+    List<FsCourseCheckinReceive> selectReceiveListByUserId(Long userId);
 }

+ 347 - 6
fs-service/src/main/java/com/fs/course/service/impl/FsCourseCheckinActivityServiceImpl.java

@@ -1,18 +1,31 @@
 package com.fs.course.service.impl;
 
+import cn.hutool.core.lang.TypeReference;
+import cn.hutool.json.JSONUtil;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DictUtils;
+import com.fs.common.utils.SecurityUtils;
 import com.fs.company.domain.Company;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.course.domain.FsCourseCheckinActivity;
 import com.fs.course.domain.FsCourseCheckinPrize;
+import com.fs.course.domain.FsCourseCheckinWarningQuery;
+import com.fs.course.domain.FsCourseCheckinWarningVO;
+import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.mapper.FsCourseCheckinActivityMapper;
 import com.fs.course.mapper.FsCourseCheckinPrizeMapper;
 import com.fs.course.mapper.FsCourseCheckinReceiveMapper;
 import com.fs.course.mapper.FsCourseCheckinUserMapper;
 import com.fs.course.service.IFsCourseCheckinActivityService;
+import com.fs.course.service.IFsUserCompanyUserService;
+import com.fs.crm.domain.CrmMsg;
+import com.fs.crm.service.ICrmMsgService;
 import com.fs.his.domain.FsIntegralGoods;
+import com.fs.his.domain.FsIntegralOrder;
 import com.fs.his.mapper.FsIntegralGoodsMapper;
+import com.fs.his.mapper.FsIntegralOrderMapper;
+import com.fs.his.utils.PhoneUtil;
+import com.fs.his.utils.RedisCacheUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -20,7 +33,12 @@ import org.springframework.transaction.annotation.Transactional;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * 看课打卡活动Service业务层处理
@@ -46,9 +64,21 @@ public class FsCourseCheckinActivityServiceImpl implements IFsCourseCheckinActiv
     @Autowired
     private FsIntegralGoodsMapper fsIntegralGoodsMapper;
 
+    @Autowired
+    private FsIntegralOrderMapper fsIntegralOrderMapper;
+
     @Autowired
     private CompanyMapper companyMapper;
 
+    @Autowired
+    private ICrmMsgService crmMsgService;
+
+    @Autowired
+    private IFsUserCompanyUserService fsUserCompanyUserService;
+
+    @Autowired
+    private RedisCacheUtil redisCacheUtil;
+
 
     /**
      * 查询看课打卡活动
@@ -247,6 +277,12 @@ public class FsCourseCheckinActivityServiceImpl implements IFsCourseCheckinActiv
             }
             // 批量插入奖品
             fsCourseCheckinPrizeMapper.batchInsertFsCourseCheckinPrize(prizeList);
+            // 清除缓存
+            for (FsCourseCheckinPrize prize : prizeList) {
+                if (prize.getGoodsId() != null) {
+                    redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+                }
+            }
         }
         return result;
     }
@@ -283,6 +319,8 @@ public class FsCourseCheckinActivityServiceImpl implements IFsCourseCheckinActiv
         // 更新活动
         int result = updateFsCourseCheckinActivity(fsCourseCheckinActivity);
         if (result > 0 && prizeList != null) {
+            // 查询原有奖品用于清除缓存
+            List<FsCourseCheckinPrize> oldPrizeList = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeByActivityId(fsCourseCheckinActivity.getActivityId());
             // 删除原有奖品
             fsCourseCheckinPrizeMapper.deleteFsCourseCheckinPrizeByActivityId(fsCourseCheckinActivity.getActivityId());
             // 插入新奖品
@@ -294,6 +332,20 @@ public class FsCourseCheckinActivityServiceImpl implements IFsCourseCheckinActiv
                     setPrizeName(prize);
                 }
                 fsCourseCheckinPrizeMapper.batchInsertFsCourseCheckinPrize(prizeList);
+                // 清除新奖品缓存
+                for (FsCourseCheckinPrize prize : prizeList) {
+                    if (prize.getGoodsId() != null) {
+                        redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+                    }
+                }
+            }
+            // 清除旧奖品缓存
+            if (oldPrizeList != null) {
+                for (FsCourseCheckinPrize prize : oldPrizeList) {
+                    if (prize.getGoodsId() != null) {
+                        redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+                    }
+                }
             }
         }
         return result;
@@ -309,27 +361,41 @@ public class FsCourseCheckinActivityServiceImpl implements IFsCourseCheckinActiv
     @Transactional
     public int deleteFsCourseCheckinActivityByActivityIds(Long[] activityIds) {
         for (Long activityId : activityIds) {
+            // 查询奖品列表用于清除缓存
+            List<FsCourseCheckinPrize> prizeList = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeByActivityId(activityId);
             // 删除关联数据
             fsCourseCheckinPrizeMapper.deleteFsCourseCheckinPrizeByActivityId(activityId);
             fsCourseCheckinUserMapper.deleteFsCourseCheckinUserByActivityId(activityId);
             fsCourseCheckinReceiveMapper.deleteFsCourseCheckinReceiveByActivityId(activityId);
+            // 清除缓存
+            if (prizeList != null) {
+                for (FsCourseCheckinPrize prize : prizeList) {
+                    if (prize.getGoodsId() != null) {
+                        redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+                    }
+                }
+            }
         }
         return fsCourseCheckinActivityMapper.deleteFsCourseCheckinActivityByActivityIds(activityIds);
     }
 
-    /**
-     * 删除看课打卡活动信息
-     *
-     * @param activityId 看课打卡活动主键
-     * @return 结果
-     */
     @Override
     @Transactional
     public int deleteFsCourseCheckinActivityByActivityId(Long activityId) {
+        // 查询奖品列表用于清除缓存
+        List<FsCourseCheckinPrize> prizeList = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeByActivityId(activityId);
         // 删除关联数据
         fsCourseCheckinPrizeMapper.deleteFsCourseCheckinPrizeByActivityId(activityId);
         fsCourseCheckinUserMapper.deleteFsCourseCheckinUserByActivityId(activityId);
         fsCourseCheckinReceiveMapper.deleteFsCourseCheckinReceiveByActivityId(activityId);
+        // 清除缓存
+        if (prizeList != null) {
+            for (FsCourseCheckinPrize prize : prizeList) {
+                if (prize.getGoodsId() != null) {
+                    redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+                }
+            }
+        }
         return fsCourseCheckinActivityMapper.deleteFsCourseCheckinActivityByActivityId(activityId);
     }
 
@@ -412,4 +478,279 @@ public class FsCourseCheckinActivityServiceImpl implements IFsCourseCheckinActiv
                 return "";
         }
     }
+
+    /**
+     * 复制活动
+     * 复制源活动,只修改活动时间
+     *
+     * @param activityId 源活动ID
+     * @param startTime  新的开始时间
+     * @param endTime    新的结束时间
+     * @return 新活动ID
+     */
+    @Override
+    @Transactional
+    public Long copyActivity(Long activityId, Date startTime, Date endTime) {
+        // 1. 查询源活动
+        FsCourseCheckinActivity sourceActivity = fsCourseCheckinActivityMapper.selectFsCourseCheckinActivityByActivityId(activityId);
+        if (sourceActivity == null) {
+            throw new RuntimeException("源活动不存在");
+        }
+        if (startTime == null || endTime == null) {
+            throw new RuntimeException("时间格式不正确");
+        }
+        if (endTime.before(startTime)) {
+            throw new RuntimeException("结束时间不能早于开始时间");
+        }
+
+        // 3. 计算打卡天数(根据时间范围自动计算)
+        int checkinDays = calculateCheckinDays(startTime, endTime);
+
+        // 4. 创建新活动
+        FsCourseCheckinActivity newActivity = new FsCourseCheckinActivity();
+        newActivity.setActivityName(sourceActivity.getActivityName() + "_复制");
+        newActivity.setStartTime(startTime);
+        newActivity.setEndTime(endTime);
+        newActivity.setCheckinDays(checkinDays); // 自动计算打卡天数
+        newActivity.setCompanyIds(sourceActivity.getCompanyIds());
+        newActivity.setProjectIds(sourceActivity.getProjectIds());
+        newActivity.setNotifyTemplate(sourceActivity.getNotifyTemplate());
+        newActivity.setStatus(0); // 未开始
+        newActivity.setCreateTime(DateUtils.getNowDate());
+        newActivity.setCreateBy(SecurityUtils.getUsername());
+        newActivity.setRemark(sourceActivity.getRemark());
+
+        // 4. 插入新活动
+        fsCourseCheckinActivityMapper.insertFsCourseCheckinActivity(newActivity);
+        Long newActivityId = newActivity.getActivityId();
+
+        // 5. 复制奖品
+        List<FsCourseCheckinPrize> prizeList = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeByActivityId(activityId);
+        if (prizeList != null && !prizeList.isEmpty()) {
+            for (FsCourseCheckinPrize prize : prizeList) {
+                FsCourseCheckinPrize newPrize = new FsCourseCheckinPrize();
+                newPrize.setActivityId(newActivityId);
+                newPrize.setPrizeType(prize.getPrizeType());
+                newPrize.setPrizeName(prize.getPrizeName());
+                newPrize.setRedpacketAmount(prize.getRedpacketAmount());
+                newPrize.setGoodsId(prize.getGoodsId());
+                newPrize.setSort(prize.getSort());
+                newPrize.setCreateTime(DateUtils.getNowDate());
+                newPrize.setCreateBy(SecurityUtils.getUsername());
+                newPrize.setRemark(prize.getRemark());
+                fsCourseCheckinPrizeMapper.insertFsCourseCheckinPrize(newPrize);
+                // 清除缓存
+                if (newPrize.getGoodsId() != null) {
+                    redisCacheUtil.delRedisKey("getIntegralGoodsById::" + newPrize.getGoodsId());
+                }
+            }
+        }
+
+        return newActivityId;
+    }
+
+    /**
+     * 查询活动预警管理列表
+     *
+     * @param query 查询参数
+     * @return 预警列表
+     */
+    @Override
+    public List<FsCourseCheckinWarningVO> selectWarningList(FsCourseCheckinWarningQuery query) {
+        if (query != null && query.getPhone() != null && !query.getPhone().isEmpty()) {
+            if (query.getPhone().length() <= 11) {
+                query.setPhone(PhoneUtil.encryptPhone(query.getPhone()));
+            }
+        }
+
+        List<FsCourseCheckinWarningVO> list = fsCourseCheckinUserMapper.selectWarningList(query);
+
+        Set<Long> userIds = list.stream()
+                .filter(vo -> vo.getPrizeType() != null && vo.getPrizeType() == 2 
+                        && vo.getGoodsId() != null && vo.getUserId() != null)
+                .map(FsCourseCheckinWarningVO::getUserId)
+                .collect(Collectors.toSet());
+
+        Map<String, Integer> orderStatusMap = new HashMap<>();
+        if (!userIds.isEmpty()) {
+            FsIntegralOrder orderQuery = new FsIntegralOrder();
+            orderQuery.setUserIds(new ArrayList<>(userIds));
+            List<FsIntegralOrder> orders = fsIntegralOrderMapper.selectFsIntegralOrderList(orderQuery);
+            
+            for (FsIntegralOrder order : orders) {
+                if (order.getUserId() != null && order.getItemJson() != null) {
+                    String itemJson = order.getItemJson();
+
+                    try {
+                        if (itemJson.startsWith("[")) {
+                            List<FsIntegralGoods> goodsList = JSONUtil.toBean(itemJson, new TypeReference<List<FsIntegralGoods>>() {}, false);
+                            for (FsIntegralGoods goods : goodsList) {
+                                if (goods.getGoodsId() != null) {
+                                    String key = order.getUserId() + "_" + goods.getGoodsId();
+                                    orderStatusMap.put(key, order.getStatus());
+                                }
+                            }
+                        } else {
+                            FsIntegralGoods goods = JSONUtil.toBean(itemJson, FsIntegralGoods.class);
+                            if (goods.getGoodsId() != null) {
+                                String key = order.getUserId() + "_" + goods.getGoodsId();
+                                orderStatusMap.put(key, order.getStatus());
+                            }
+                        }
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+
+        for (FsCourseCheckinWarningVO vo : list) {
+            if (vo.getCheckinDays() != null && vo.getCurrentCheckinDays() != null) {
+                vo.setRemainingDays(Math.max(0, vo.getCheckinDays() - vo.getCurrentCheckinDays()));
+            }
+
+            boolean isCheckinCompleted = vo.getCurrentCheckinDays() != null
+                    && vo.getCheckinDays() != null
+                    && vo.getCurrentCheckinDays() >= vo.getCheckinDays();
+            vo.setIsCompleted(isCheckinCompleted ? 1 : 0);
+
+            Integer orderStatus = null;
+            if (vo.getPrizeType() != null && vo.getPrizeType() == 2 
+                    && vo.getGoodsId() != null && vo.getUserId() != null) {
+                String key = vo.getUserId() + "_" + vo.getGoodsId();
+                orderStatus = orderStatusMap.get(key);
+            }
+            vo.setOrderStatus(orderStatus);
+
+            boolean isShipped = orderStatus != null && orderStatus >= 2;
+            vo.setIsShipped(isShipped ? 1 : 0);
+
+            if (!isCheckinCompleted) {
+                vo.setStatus(1);
+                vo.setStatusText("未完成打卡");
+            } else if (vo.getRewardStatus() == null) {
+                vo.setStatus(2);
+                vo.setStatusText("已完成打卡未领取");
+            } else if (vo.getRewardStatus() == 0) {
+                vo.setStatus(3);
+                vo.setStatusText("已领取待发放");
+            } else if (vo.getRewardStatus() == 1) {
+                if (vo.getPrizeType() != null && vo.getPrizeType() == 2) {
+                    if (isShipped) {
+                        vo.setStatus(6);
+                        vo.setStatusText("积分商品已发货");
+                    } else {
+                        vo.setStatus(5);
+                        vo.setStatusText("积分商品待发货");
+                    }
+                } else {
+                    vo.setStatus(4);
+                    vo.setStatusText("红包已到账");
+                }
+            }
+
+            if (vo.getPrizeType() != null) {
+                vo.setPrizeTypeText(vo.getPrizeType() == 1 ? "红包" : "积分商品券");
+            }
+
+            if (vo.getPhone() != null && !vo.getPhone().isEmpty()) {
+                if (vo.getPhone().length() > 11) {
+                    vo.setPhone(PhoneUtil.decryptPhone(vo.getPhone()));
+                }
+            }
+        }
+
+        if (query != null && query.getStatus() != null) {
+            list = list.stream()
+                    .filter(vo -> query.getStatus().equals(vo.getStatus()))
+                    .collect(Collectors.toList());
+        }
+
+        return list;
+    }
+
+    /**
+     * 根据公司ID查询活动列表
+     *
+     * @param companyId 公司ID
+     * @return 活动列表
+     */
+    @Override
+    public List<FsCourseCheckinActivity> selectActivityListByCompanyId(Long companyId) {
+        return fsCourseCheckinActivityMapper.selectActivityListByCompanyId(companyId);
+    }
+
+    /**
+     * 发送打卡提醒消息给销售
+     * 定时任务调用
+     */
+    @Override
+    public void sendCheckinRemindToSales() {
+        List<FsCourseCheckinWarningVO> oneDayLeftList = fsCourseCheckinUserMapper.selectCheckinRemindList(1);
+        for (FsCourseCheckinWarningVO vo : oneDayLeftList) {
+            sendRemindMsg(vo, 1);
+        }
+
+        List<FsCourseCheckinWarningVO> completedList = fsCourseCheckinUserMapper.selectCheckinRemindList(2);
+        for (FsCourseCheckinWarningVO vo : completedList) {
+            sendRemindMsg(vo, 2);
+        }
+    }
+
+    private void sendRemindMsg(FsCourseCheckinWarningVO vo, Integer remindType) {
+        FsUserCompanyUser userCompanyUser = fsUserCompanyUserService.selectByUserIdAndProjectId(vo.getUserId(), vo.getProjectId());
+        if (userCompanyUser == null || userCompanyUser.getCompanyUserId() == null) {
+            return;
+        }
+
+        String title;
+        String content;
+        String notifyTemplate = vo.getNotifyTemplate();
+
+        if (remindType == 1) {
+            title = "打卡提醒-剩余一天";
+            String nickName = vo.getUserNickName() != null ? vo.getUserNickName() : "用户";
+            if (notifyTemplate != null && !notifyTemplate.isEmpty()) {
+                content = notifyTemplate
+                        .replace("{用户昵称}", nickName)
+                        .replace("{剩余天数}", "1")
+                        .replace("{奖品名称}", vo.getPrizeName() != null ? vo.getPrizeName() : "");
+            } else {
+                content = String.format("用户【%s】再打卡1天即可领取【%s】",
+                        nickName,
+                        vo.getPrizeName() != null ? vo.getPrizeName() : "奖励");
+            }
+        } else {
+            title = "打卡提醒-打卡完成";
+            String nickName = vo.getUserNickName() != null ? vo.getUserNickName() : "用户";
+            Integer prizeType = vo.getPrizeType();
+            if (notifyTemplate != null && !notifyTemplate.isEmpty()) {
+                content = notifyTemplate
+                        .replace("{用户昵称}", nickName)
+                        .replace("{打卡天数}", vo.getCheckinDays() != null ? vo.getCheckinDays().toString() : "0")
+                        .replace("{奖品名称}", vo.getPrizeName() != null ? vo.getPrizeName() : "");
+            } else {
+                if (prizeType != null && prizeType == 2) {
+                    content = String.format("用户【%s】已完成打卡%d天,奖品为商品券【%s】,请通知用户使用商品券并按时发货",
+                            nickName,
+                            vo.getCheckinDays() != null ? vo.getCheckinDays() : 0,
+                            vo.getPrizeName() != null ? vo.getPrizeName() : "商品券");
+                } else {
+                    content = String.format("用户【%s】已完成打卡%d天,奖品:【%s】",
+                            nickName,
+                            vo.getCheckinDays() != null ? vo.getCheckinDays() : 0,
+                            vo.getPrizeName() != null ? vo.getPrizeName() : "奖励");
+                }
+            }
+        }
+
+        CrmMsg crmMsg = new CrmMsg();  
+        crmMsg.setMsgType(5);
+        crmMsg.setTitle(title);
+        crmMsg.setContent(content);
+        crmMsg.setCompanyId(vo.getCompanyId());
+        crmMsg.setCompanyUserId(userCompanyUser.getCompanyUserId());
+        crmMsg.setObjId(vo.getId());
+        crmMsg.setCreateTime(DateUtils.getNowDate());
+        crmMsgService.insertCrmMsg(crmMsg);
+    }
 }

+ 33 - 12
fs-service/src/main/java/com/fs/course/service/impl/FsCourseCheckinPrizeServiceImpl.java

@@ -6,6 +6,7 @@ import com.fs.course.mapper.FsCourseCheckinPrizeMapper;
 import com.fs.course.service.IFsCourseCheckinPrizeService;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.mapper.FsIntegralGoodsMapper;
+import com.fs.his.utils.RedisCacheUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -26,6 +27,9 @@ public class FsCourseCheckinPrizeServiceImpl implements IFsCourseCheckinPrizeSer
     @Autowired
     private FsIntegralGoodsMapper fsIntegralGoodsMapper;
 
+    @Autowired
+    private RedisCacheUtil redisCacheUtil;
+
     /**
      * 查询看课打卡活动奖品
      *
@@ -68,9 +72,12 @@ public class FsCourseCheckinPrizeServiceImpl implements IFsCourseCheckinPrizeSer
     @Override
     public int insertFsCourseCheckinPrize(FsCourseCheckinPrize fsCourseCheckinPrize) {
         fsCourseCheckinPrize.setCreateTime(DateUtils.getNowDate());
-        // 自动设置奖品名称
         setPrizeName(fsCourseCheckinPrize);
-        return fsCourseCheckinPrizeMapper.insertFsCourseCheckinPrize(fsCourseCheckinPrize);
+        int result = fsCourseCheckinPrizeMapper.insertFsCourseCheckinPrize(fsCourseCheckinPrize);
+        if (result > 0 && fsCourseCheckinPrize.getGoodsId() != null) {
+            redisCacheUtil.delRedisKey("getIntegralGoodsById::" + fsCourseCheckinPrize.getGoodsId());
+        }
+        return result;
     }
 
     /**
@@ -111,11 +118,18 @@ public class FsCourseCheckinPrizeServiceImpl implements IFsCourseCheckinPrizeSer
         if (prizeList == null || prizeList.isEmpty()) {
             return 0;
         }
-        // 自动设置奖品名称
         for (FsCourseCheckinPrize prize : prizeList) {
             setPrizeName(prize);
         }
-        return fsCourseCheckinPrizeMapper.batchInsertFsCourseCheckinPrize(prizeList);
+        int result = fsCourseCheckinPrizeMapper.batchInsertFsCourseCheckinPrize(prizeList);
+        if (result > 0) {
+            for (FsCourseCheckinPrize prize : prizeList) {
+                if (prize.getGoodsId() != null) {
+                    redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+                }
+            }
+        }
+        return result;
     }
 
     /**
@@ -127,9 +141,12 @@ public class FsCourseCheckinPrizeServiceImpl implements IFsCourseCheckinPrizeSer
     @Override
     public int updateFsCourseCheckinPrize(FsCourseCheckinPrize fsCourseCheckinPrize) {
         fsCourseCheckinPrize.setUpdateTime(DateUtils.getNowDate());
-        // 自动设置奖品名称
         setPrizeName(fsCourseCheckinPrize);
-        return fsCourseCheckinPrizeMapper.updateFsCourseCheckinPrize(fsCourseCheckinPrize);
+        int result = fsCourseCheckinPrizeMapper.updateFsCourseCheckinPrize(fsCourseCheckinPrize);
+        if (result > 0 && fsCourseCheckinPrize.getGoodsId() != null) {
+            redisCacheUtil.delRedisKey("getIntegralGoodsById::" + fsCourseCheckinPrize.getGoodsId());
+        }
+        return result;
     }
 
     /**
@@ -140,17 +157,21 @@ public class FsCourseCheckinPrizeServiceImpl implements IFsCourseCheckinPrizeSer
      */
     @Override
     public int deleteFsCourseCheckinPrizeByPrizeIds(Long[] prizeIds) {
+        for (Long prizeId : prizeIds) {
+            FsCourseCheckinPrize prize = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeByPrizeId(prizeId);
+            if (prize != null && prize.getGoodsId() != null) {
+                redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+            }
+        }
         return fsCourseCheckinPrizeMapper.deleteFsCourseCheckinPrizeByPrizeIds(prizeIds);
     }
 
-    /**
-     * 删除看课打卡活动奖品信息
-     *
-     * @param prizeId 看课打卡活动奖品主键
-     * @return 结果
-     */
     @Override
     public int deleteFsCourseCheckinPrizeByPrizeId(Long prizeId) {
+        FsCourseCheckinPrize prize = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeByPrizeId(prizeId);
+        if (prize != null && prize.getGoodsId() != null) {
+            redisCacheUtil.delRedisKey("getIntegralGoodsById::" + prize.getGoodsId());
+        }
         return fsCourseCheckinPrizeMapper.deleteFsCourseCheckinPrizeByPrizeId(prizeId);
     }
 

+ 181 - 18
fs-service/src/main/java/com/fs/course/service/impl/FsCourseCheckinReceiveServiceImpl.java

@@ -14,12 +14,15 @@ import com.fs.course.domain.*;
 import com.fs.course.mapper.*;
 import com.fs.course.param.FsCourseSendRewardUParam;
 import com.fs.course.service.IFsCourseCheckinReceiveService;
+import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserWx;
+import com.fs.his.mapper.FsIntegralGoodsMapper;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.his.service.IFsUserWxService;
+import com.fs.his.utils.RedisCacheUtil;
 import com.fs.system.service.ISysConfigService;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import lombok.extern.slf4j.Slf4j;
@@ -35,6 +38,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.math.BigDecimal;
 import java.time.OffsetDateTime;
 import java.util.*;
+import java.util.stream.Collectors;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -78,6 +82,12 @@ public class FsCourseCheckinReceiveServiceImpl implements IFsCourseCheckinReceiv
     @Autowired
     private CompanyMapper companyMapper;
 
+    @Autowired
+    private FsIntegralGoodsMapper fsIntegralGoodsMapper;
+
+    @Autowired
+    private RedisCacheUtil redisCacheUtil;
+
 
     @Autowired
     private IFsStorePaymentService paymentService;
@@ -131,7 +141,11 @@ public class FsCourseCheckinReceiveServiceImpl implements IFsCourseCheckinReceiv
     @Override
     public int insertFsCourseCheckinReceive(FsCourseCheckinReceive fsCourseCheckinReceive) {
         fsCourseCheckinReceive.setCreateTime(DateUtils.getNowDate());
-        return fsCourseCheckinReceiveMapper.insertFsCourseCheckinReceive(fsCourseCheckinReceive);
+        int result = fsCourseCheckinReceiveMapper.insertFsCourseCheckinReceive(fsCourseCheckinReceive);
+        if (result > 0 && fsCourseCheckinReceive.getGoodsId() != null) {
+            redisCacheUtil.delRedisKey("getIntegralGoodsById::" + fsCourseCheckinReceive.getGoodsId());
+        }
+        return result;
     }
 
     /**
@@ -145,7 +159,15 @@ public class FsCourseCheckinReceiveServiceImpl implements IFsCourseCheckinReceiv
         if (receiveList == null || receiveList.isEmpty()) {
             return 0;
         }
-        return fsCourseCheckinReceiveMapper.batchInsertFsCourseCheckinReceive(receiveList);
+        int result = fsCourseCheckinReceiveMapper.batchInsertFsCourseCheckinReceive(receiveList);
+        if (result > 0) {
+            for (FsCourseCheckinReceive receive : receiveList) {
+                if (receive.getGoodsId() != null) {
+                    redisCacheUtil.delRedisKey("getIntegralGoodsById::" + receive.getGoodsId());
+                }
+            }
+        }
+        return result;
     }
 
     /**
@@ -157,29 +179,32 @@ public class FsCourseCheckinReceiveServiceImpl implements IFsCourseCheckinReceiv
     @Override
     public int updateFsCourseCheckinReceive(FsCourseCheckinReceive fsCourseCheckinReceive) {
         fsCourseCheckinReceive.setUpdateTime(DateUtils.getNowDate());
-        return fsCourseCheckinReceiveMapper.updateFsCourseCheckinReceive(fsCourseCheckinReceive);
+        int result = fsCourseCheckinReceiveMapper.updateFsCourseCheckinReceive(fsCourseCheckinReceive);
+        if (result > 0 && fsCourseCheckinReceive.getGoodsId() != null) {
+            redisCacheUtil.delRedisKey("getIntegralGoodsById::" + fsCourseCheckinReceive.getGoodsId());
+        }
+        return result;
     }
 
-    /**
-     * 批量删除看课打卡奖品领取记录
-     *
-     * @param receiveIds 需要删除的看课打卡奖品领取记录主键集合
-     * @return 结果
-     */
     @Override
     public int deleteFsCourseCheckinReceiveByReceiveIds(Long[] receiveIds) {
+        for (Long receiveId : receiveIds) {
+            FsCourseCheckinReceive receive = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveByReceiveId(receiveId);
+            if (receive != null && receive.getGoodsId() != null) {
+                redisCacheUtil.delRedisKey("getIntegralGoodsById::" + receive.getGoodsId());
+            }
+        }
         return fsCourseCheckinReceiveMapper.deleteFsCourseCheckinReceiveByReceiveIds(receiveIds);
     }
 
-    /**
-     * 删除看课打卡奖品领取记录信息
-     *
-     * @param receiveId 看课打卡奖品领取记录主键
-     * @return 结果
-     */
     @Override
     public int deleteFsCourseCheckinReceiveByReceiveId(Long receiveId) {
-        return fsCourseCheckinReceiveMapper.deleteFsCourseCheckinReceiveByReceiveId(receiveId);
+        FsCourseCheckinReceive receive = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveByReceiveId(receiveId);
+        int result = fsCourseCheckinReceiveMapper.deleteFsCourseCheckinReceiveByReceiveId(receiveId);
+        if (result > 0 && receive != null && receive.getGoodsId() != null) {
+            redisCacheUtil.delRedisKey("getIntegralGoodsById::" + receive.getGoodsId());
+        }
+        return result;
     }
 
     /**
@@ -331,8 +356,14 @@ public class FsCourseCheckinReceiveServiceImpl implements IFsCourseCheckinReceiv
             }
 
             if (success) {
-                receive.setReceiveStatus(1); // 发放成功
-                receive.setReceiveTime(now);
+                if (receive.getPrizeType() == 1) {
+                    //红包类型
+                    receive.setReceiveStatus(1); // 发放成功
+                    receive.setReceiveTime(now);
+                }else {
+                    // 积分商品类型
+                    receive.setReceiveStatus(0); // 待发放
+                }
                 result.put("success", true);
                 result.put("msg", "发放成功");
             } else {
@@ -497,4 +528,136 @@ public class FsCourseCheckinReceiveServiceImpl implements IFsCourseCheckinReceiv
 
         return true;
     }
+
+    /**
+     * 根据活动ID和奖品类型查询领取记录列表
+     * 包含用户信息(昵称)、公司名,积分商品类型时包含商品名称
+     *
+     * @param activityId 活动ID
+     * @param prizeType 奖品类型(1-红包,2-积分商品券)
+     * @return 领取记录列表
+     */
+    @Override
+    public List<FsCourseCheckinReceive> selectReceiveListByActivityAndType(Long activityId, Integer prizeType) {
+        // 1. 查询领取记录列表
+        List<FsCourseCheckinReceive> list = fsCourseCheckinReceiveMapper.selectReceiveListByActivityAndType(activityId, prizeType);
+        if (list == null || list.isEmpty()) {
+            return list;
+        }
+
+        // 2. 第一次遍历:收集所有需要查询的ID
+        Set<Long> userIds = new HashSet<>();
+        Set<Long> companyIds = new HashSet<>();
+        Set<Long> goodsIds = new HashSet<>();
+
+        for (FsCourseCheckinReceive receive : list) {
+            if (receive.getUserId() != null) {
+                userIds.add(receive.getUserId());
+            }
+            if (receive.getCompanyId() != null) {
+                companyIds.add(receive.getCompanyId());
+            }
+            if (receive.getPrizeType() != null && receive.getPrizeType() == 2 && receive.getGoodsId() != null) {
+                goodsIds.add(receive.getGoodsId());
+            }
+        }
+
+        // 3. 批量查询并转成 Map
+        Map<Long, FsUser> userMap = new HashMap<>();
+        for (Long userId : userIds) {
+            FsUser user = fsUserMapper.selectFsUserByUserId(userId);
+            if (user != null) {
+                userMap.put(userId, user);
+            }
+        }
+
+        Map<Long, Company> companyMap = new HashMap<>();
+        for (Long companyId : companyIds) {
+            Company company = companyMapper.selectCompanyById(companyId);
+            if (company != null) {
+                companyMap.put(companyId, company);
+            }
+        }
+
+        Map<Long, FsIntegralGoods> goodsMap = new HashMap<>();
+        for (Long goodsId : goodsIds) {
+            FsIntegralGoods goods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(goodsId);
+            if (goods != null) {
+                goodsMap.put(goodsId, goods);
+            }
+        }
+
+        // 4. 第二次遍历:从 Map 中获取数据并填充
+        for (FsCourseCheckinReceive receive : list) {
+            if (receive.getUserId() != null) {
+                FsUser user = userMap.get(receive.getUserId());
+                if (user != null) {
+                    receive.setUserNickName(user.getNickName());
+                }
+            }
+
+            if (receive.getCompanyId() != null) {
+                Company company = companyMap.get(receive.getCompanyId());
+                if (company != null) {
+                    receive.setCompanyName(company.getCompanyName());
+                }
+            }
+
+            if (receive.getPrizeType() != null && receive.getPrizeType() == 2 && receive.getGoodsId() != null) {
+                FsIntegralGoods goods = goodsMap.get(receive.getGoodsId());
+                if (goods != null) {
+                    receive.setGoodsName(goods.getGoodsName());
+                }
+            }
+        }
+
+        return list;
+    }
+
+    @Override
+    public List<FsCourseCheckinReceive> selectReceiveListByUserId(Long userId) {
+        FsCourseCheckinReceive query = new FsCourseCheckinReceive();
+        query.setUserId(userId);
+        List<FsCourseCheckinReceive> list = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveList(query);
+        if (list == null || list.isEmpty()) {
+            return list;
+        }
+
+        Set<Long> activityIds = list.stream()
+                .filter(r -> r.getActivityId() != null)
+                .map(FsCourseCheckinReceive::getActivityId)
+                .collect(Collectors.toSet());
+
+        Map<Long, String> activityNameMap = new HashMap<>();
+        for (Long activityId : activityIds) {
+            FsCourseCheckinActivity activity = fsCourseCheckinActivityMapper.selectFsCourseCheckinActivityByActivityId(activityId);
+            if (activity != null) {
+                activityNameMap.put(activityId, activity.getActivityName());
+            }
+        }
+
+        Set<Long> goodsIds = list.stream()
+                .filter(r -> r.getGoodsId() != null)
+                .map(FsCourseCheckinReceive::getGoodsId)
+                .collect(Collectors.toSet());
+
+        Map<Long, String> goodsNameMap = new HashMap<>();
+        for (Long goodsId : goodsIds) {
+            FsIntegralGoods goods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(goodsId);
+            if (goods != null) {
+                goodsNameMap.put(goodsId, goods.getGoodsName());
+            }
+        }
+
+        for (FsCourseCheckinReceive receive : list) {
+            if (receive.getActivityId() != null) {
+                receive.setActivityName(activityNameMap.get(receive.getActivityId()));
+            }
+            if (receive.getGoodsId() != null) {
+                receive.setGoodsName(goodsNameMap.get(receive.getGoodsId()));
+            }
+        }
+
+        return list;
+    }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserTalentServiceImpl.java

@@ -160,7 +160,7 @@ public class FsUserTalentServiceImpl implements IFsUserTalentService
         fsUserTalent.setIsAudit(1l);
         fsUserTalent.setAuditTime(new Date());
         fsUserTalent.setStatus(1l);
-        fsUserTalent.setIsDel(1l);
+        fsUserTalent.setIsDel(0l);
         fsUserTalentMapper.insertFsUserTalent(fsUserTalent);
         return 1;
     }

+ 15 - 0
fs-service/src/main/java/com/fs/his/domain/FsIntegralGoods.java

@@ -70,4 +70,19 @@ public class FsIntegralGoods extends BaseEntity
      * 非数据库字段 仅用于订单信息存储购买数量
      */
     private Integer num;
+
+    /**
+     * 非数据库字段 是否为打卡活动积分奖品
+     */
+    private Boolean isCheckinPrize;
+
+    /**
+     * 非数据库字段 是否有待领取记录
+     */
+    private Boolean hasPendingReceive;
+
+    /**
+     * 非数据库字段 积分商品活动
+     */
+    private Long activityId;
 }

+ 7 - 0
fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java

@@ -11,6 +11,7 @@ import lombok.Data;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.Date;
+import java.util.List;
 
 /**
  * 积分商品订单对象 fs_integral_order
@@ -132,4 +133,10 @@ public class FsIntegralOrder
     private String deliveryType;
 
     private String extendOrderId;
+
+    /**
+     * 非数据库字段 用户id集合
+     */
+    @TableField(exist = false)
+    private List<Long> userIds;
 }

+ 10 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralOrderCreateParam.java

@@ -15,5 +15,15 @@ public class FsIntegralOrderCreateParam {
     private Long goodsId;
     private Long companyUserId;
 
+    /**
+     * 打卡积分商品活动id
+     */
+    private Long activityId;
+
+    /**
+     * 是否是app端入口
+     */
+    private Long isAPP;
+
 
 }

+ 21 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralOrderManuallyParam.java

@@ -0,0 +1,21 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class FsIntegralOrderManuallyParam {
+    private Long userId;
+    private Long addressId;
+    private Long companyId;
+    private Long companyUserId;
+    private Integer payType;
+    private BigDecimal payMoney;
+    private Long activityId;
+
+    @NotNull(message = "商品ID列表不能为空")
+    private List<Long> goodsIds;
+}

+ 25 - 0
fs-service/src/main/java/com/fs/his/service/IFsIntegralGoodsService.java

@@ -78,4 +78,29 @@ public interface IFsIntegralGoodsService
      * 获取选择积分商品列表
      */
     List<FsIntegralGoodsChooseVO> getChooseIntegralGoodsListByMap(Map<String, Object> params);
+
+    /**
+     * 查询积分商品详情(包含打卡活动标识)
+     *
+     * @param goodsId 积分商品主键
+     * @return 积分商品
+     */
+    FsIntegralGoods selectFsIntegralGoodsByIdWithCheckinFlag(Long goodsId,Long userId,Long isAPP);
+
+    /**
+     * 查询打卡活动未领取奖励的商品列表
+     *
+     * @param userId 用户ID
+     * @return 商品列表
+     */
+    List<FsIntegralGoods> selectCheckinPrizeGoodsListByUserId(Long userId);
+
+    /**
+     * 查询打卡活动未领取奖励的商品列表(支持多用户和商品名称模糊搜索)
+     *
+     * @param userIds 用户ID列表
+     * @param goodsName 商品名称
+     * @return 商品列表
+     */
+    List<FsIntegralGoods> selectCheckinPrizeGoodsListByUserIds(List<Long> userIds, String goodsName);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/his/service/IFsIntegralOrderService.java

@@ -119,4 +119,11 @@ public interface IFsIntegralOrderService
      * 超时30分钟订单
      */
     List<FsIntegralOrder> selectOutTimeOrderList();
+
+    /**
+     * 手动创建积分订单
+     * @param param 参数
+     * @return 结果
+     */
+    R createOrderByManually(FsIntegralOrderManuallyParam param);
 }

+ 104 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java

@@ -7,6 +7,10 @@ import com.fs.common.utils.DateUtils;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseAnswerReward;
 import com.fs.his.domain.FsChineseMedicine;
+import com.fs.course.domain.FsCourseCheckinPrize;
+import com.fs.course.domain.FsCourseCheckinReceive;
+import com.fs.course.mapper.FsCourseCheckinPrizeMapper;
+import com.fs.course.mapper.FsCourseCheckinReceiveMapper;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.domain.FsUser;
 import com.fs.his.mapper.FsIntegralGoodsMapper;
@@ -21,6 +25,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
 import java.util.*;
 
 /**
@@ -37,6 +42,10 @@ public class FsIntegralGoodsServiceImpl implements IFsIntegralGoodsService
     private FsIntegralGoodsMapper fsIntegralGoodsMapper;
     @Autowired
     private FsUserMapper fsUserMapper;
+    @Autowired
+    private FsCourseCheckinPrizeMapper fsCourseCheckinPrizeMapper;
+    @Autowired
+    private FsCourseCheckinReceiveMapper fsCourseCheckinReceiveMapper;
 
     @Autowired
     private ISysConfigService configService;
@@ -256,4 +265,99 @@ public class FsIntegralGoodsServiceImpl implements IFsIntegralGoodsService
     public List<FsIntegralGoodsChooseVO> getChooseIntegralGoodsListByMap(Map<String, Object> params) {
         return fsIntegralGoodsMapper.getChooseIntegralGoodsListByMap(params);
     }
+
+    /**
+     * 查询积分商品详情(包含打卡活动标识)
+     *
+     * @param goodsId 积分商品主键
+     * @return 积分商品
+     */
+    @Override
+    public FsIntegralGoods selectFsIntegralGoodsByIdWithCheckinFlag(Long goodsId,Long userId, Long isAPP) {
+        FsIntegralGoods goods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(goodsId);
+        if (goods == null) {
+            return null;
+        }
+        if(isAPP==1){
+            FsCourseCheckinPrize prizeQuery = new FsCourseCheckinPrize();
+            prizeQuery.setGoodsId(goodsId);
+            prizeQuery.setPrizeType(2);
+            List<FsCourseCheckinPrize> prizeList = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeList(prizeQuery);
+
+            if (prizeList != null && !prizeList.isEmpty()) {
+                goods.setIsCheckinPrize(true);
+                FsCourseCheckinReceive receiveQuery = new FsCourseCheckinReceive();
+                receiveQuery.setGoodsId(goodsId);
+                receiveQuery.setUserId(userId);
+                receiveQuery.setReceiveStatus(0);
+                List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveList(receiveQuery);
+                if (receiveList != null && !receiveList.isEmpty()){
+                    goods.setHasPendingReceive(true);
+                    goods.setActivityId(prizeList.get(0).getActivityId());
+//                    //还未领取奖励则金额显示为0
+//                    goods.setCash(BigDecimal.valueOf(0.00));
+//                    goods.setIntegral(0L);
+//                    fsIntegralGoodsMapper.updateFsIntegralGoods(goods);
+                }else {
+                    goods.setHasPendingReceive(false);
+                }
+            } else {
+                goods.setIsCheckinPrize(false);
+                goods.setHasPendingReceive(false);
+            }
+        }
+        return goods;
+    }
+
+    @Override
+    public List<FsIntegralGoods> selectCheckinPrizeGoodsListByUserId(Long userId) {
+        FsCourseCheckinReceive receiveQuery = new FsCourseCheckinReceive();
+        receiveQuery.setUserId(userId);
+        receiveQuery.setReceiveStatus(0);
+        receiveQuery.setPrizeType(2);
+        List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveList(receiveQuery);
+
+        if (receiveList == null || receiveList.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        List<FsIntegralGoods> goodsList = new ArrayList<>();
+        for (FsCourseCheckinReceive receive : receiveList) {
+            if (receive.getGoodsId() != null) {
+                FsIntegralGoods goods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(receive.getGoodsId());
+                if (goods != null) {
+                    goods.setIsCheckinPrize(true);
+                    goods.setHasPendingReceive(true);
+                    goods.setActivityId(receive.getActivityId());
+                    goodsList.add(goods);
+                }
+            }
+        }
+
+        return goodsList;
+    }
+
+    @Override
+    public List<FsIntegralGoods> selectCheckinPrizeGoodsListByUserIds(List<Long> userIds, String goodsName) {
+        List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveMapper.selectCheckinPrizeReceiveByUserIds(userIds, goodsName);
+
+        if (receiveList == null || receiveList.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        List<FsIntegralGoods> goodsList = new ArrayList<>();
+        for (FsCourseCheckinReceive receive : receiveList) {
+            if (receive.getGoodsId() != null) {
+                FsIntegralGoods goods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(receive.getGoodsId());
+                if (goods != null) {
+                    goods.setIsCheckinPrize(true);
+                    goods.setHasPendingReceive(true);
+                    goods.setActivityId(receive.getActivityId());
+                    goodsList.add(goods);
+                }
+            }
+        }
+
+        return goodsList;
+    }
 }

+ 179 - 5
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralOrderServiceImpl.java

@@ -23,6 +23,11 @@ import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.util.WechatApi;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCourseCheckinPrize;
+import com.fs.course.domain.FsCourseCheckinReceive;
+import com.fs.course.mapper.FsCourseCheckinPrizeMapper;
+import com.fs.course.mapper.FsCourseCheckinReceiveMapper;
+import com.fs.his.utils.RedisCacheUtil;
 import com.fs.erp.domain.ErpOrder;
 import com.fs.erp.domain.ErpOrderPayment;
 import com.fs.erp.dto.ErpOrderResponse;
@@ -172,6 +177,14 @@ public class FsIntegralOrderServiceImpl implements IFsIntegralOrderService
     @Qualifier("k9OrderScrmServiceImpl")
     private IErpOrderService k9OrderService;
 
+    @Autowired
+    private FsCourseCheckinPrizeMapper fsCourseCheckinPrizeMapper;
+    @Autowired
+    private FsCourseCheckinReceiveMapper fsCourseCheckinReceiveMapper;
+
+    @Autowired
+    private RedisCacheUtil redisCacheUtil;
+
     //ERP 类型到服务的映射
     private Map<Integer, IErpOrderService> erpServiceMap;
 
@@ -312,7 +325,32 @@ public class FsIntegralOrderServiceImpl implements IFsIntegralOrderService
         if(integralGoods.getStock()<=0L){
             return R.error("库存不足");
         }
-        if(user.getIntegral()<integralGoods.getIntegral()){
+
+        Long totalIntegral = integralGoods.getIntegral();
+        BigDecimal totalCash = integralGoods.getCash();
+        Long activityId = param.getActivityId();
+
+        if(param.getIsAPP() != null && param.getIsAPP() == 1){
+            FsCourseCheckinPrize prizeQuery = new FsCourseCheckinPrize();
+            prizeQuery.setGoodsId(param.getGoodsId());
+            prizeQuery.setPrizeType(2);
+            List<FsCourseCheckinPrize> prizeList = fsCourseCheckinPrizeMapper.selectFsCourseCheckinPrizeList(prizeQuery);
+            if(ObjectUtil.isNotEmpty(prizeList)){
+                FsCourseCheckinReceive receiveQuery = new FsCourseCheckinReceive();
+                receiveQuery.setUserId(param.getUserId());
+                receiveQuery.setActivityId(param.getActivityId());
+                receiveQuery.setGoodsId(param.getGoodsId());
+                receiveQuery.setReceiveStatus(0);
+                List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveList(receiveQuery);
+                if(ObjectUtil.isNotEmpty(receiveList)){
+                    totalIntegral = 0L;
+                    totalCash = BigDecimal.ZERO;
+                    activityId = param.getActivityId();
+                }
+            }
+        }
+
+        if(totalIntegral > 0 && user.getIntegral() < totalIntegral){
             return R.error("积分不足");
         }
 
@@ -322,17 +360,19 @@ public class FsIntegralOrderServiceImpl implements IFsIntegralOrderService
         }
 
         integralGoods.setNum(1);
+        integralGoods.setIntegral(totalIntegral);
+        integralGoods.setCash(totalCash);
         List<FsIntegralGoods> goodsItem = new ArrayList<>();
         goodsItem.add(integralGoods);
 
         // 创建订单
-        return createOrder(user, address, integralGoods.getIntegral(),integralGoods.getCash(), goodsItem,param.getCompanyUserId());
+        return createOrder(user, address, totalIntegral, totalCash, goodsItem, param.getCompanyUserId(), param.getGoodsId(), activityId);
     }
 
     /**
      * 创建订单
      */
-    private R createOrder(FsUser user, FsUserAddress address, Long totalIntegral, BigDecimal totalCash, List<FsIntegralGoods> goodsItem, Long companyUserId) {
+    private R createOrder(FsUser user, FsUserAddress address, Long totalIntegral, BigDecimal totalCash, List<FsIntegralGoods> goodsItem, Long companyUserId,Long goodsId,Long activityId) {
         FsIntegralOrder order = new FsIntegralOrder();
         String orderSn = null;
         try{
@@ -403,7 +443,25 @@ public class FsIntegralOrderServiceImpl implements IFsIntegralOrderService
                 logs.setCreateTime(new Date());
                 fsUserIntegralLogsMapper.insertFsUserIntegralLogs(logs);
             }
-
+            //如何是打卡活动的积分商品则修改领取状态
+            if(activityId!=null&&goodsId!=null){
+                FsCourseCheckinReceive receiveQuery = new FsCourseCheckinReceive();
+                receiveQuery.setUserId(order.getUserId());
+                receiveQuery.setActivityId(activityId);
+                receiveQuery.setGoodsId(goodsId);
+                receiveQuery.setReceiveStatus(0);
+                List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveList(receiveQuery);
+                if(ObjectUtil.isNotEmpty(receiveList)){
+                    FsCourseCheckinReceive receive = receiveList.get(0);
+                    receive.setReceiveStatus(1);
+                    receive.setReceiveTime(new Date());
+                    receive.setUpdateTime(new Date());
+                    fsCourseCheckinReceiveMapper.updateFsCourseCheckinReceive(receive);
+                    if(receive.getGoodsId() != null){
+                        redisCacheUtil.delRedisKey("getIntegralGoodsById::" + receive.getGoodsId());
+                    }
+                }
+            }
             // 积分支付
             if (order.getPayType() == 1) {
                 // 首次完成积分商城下单
@@ -481,7 +539,7 @@ public class FsIntegralOrderServiceImpl implements IFsIntegralOrderService
             return R.error("积分不足");
         }
 
-        return createOrder(user, address, totalIntegral, totalCash, goodsItem, null);
+        return createOrder(user, address, totalIntegral, totalCash, goodsItem, null, null,null);
     }
 
     @Override
@@ -1144,4 +1202,120 @@ public class FsIntegralOrderServiceImpl implements IFsIntegralOrderService
         BeanUtils.copyProperties(original, cloned);
         return cloned;
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R createOrderByManually(FsIntegralOrderManuallyParam param) {
+        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
+        if (Objects.isNull(user)) {
+            return R.error("用户不存在");
+        }
+
+        FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
+
+        List<FsIntegralGoods> goodsList = new ArrayList<>();
+        Long totalIntegral = 0L;
+        BigDecimal totalCash = BigDecimal.ZERO;
+
+        for (Long goodsId : param.getGoodsIds()) {
+            FsIntegralGoods goods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(goodsId);
+            if (goods == null) {
+                return R.error("商品不存在: " + goodsId);
+            }
+            if (goods.getStock() <= 0L) {
+                return R.error("商品库存不足: " + goods.getGoodsName());
+            }
+            goods.setNum(1);
+            goodsList.add(goods);
+            totalIntegral += goods.getIntegral() != null ? goods.getIntegral() : 0L;
+            totalCash = totalCash.add(goods.getCash() != null ? goods.getCash() : BigDecimal.ZERO);
+            FsCourseCheckinReceive receiveQuery = new FsCourseCheckinReceive();
+            receiveQuery.setUserId(user.getUserId());
+            receiveQuery.setGoodsId(goodsId);
+            receiveQuery.setReceiveStatus(0);
+            List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveMapper.selectFsCourseCheckinReceiveList(receiveQuery);
+            if (ObjectUtil.isNotEmpty(receiveList)) {
+                FsCourseCheckinReceive receive = receiveList.get(0);
+                receive.setReceiveStatus(1);
+                receive.setReceiveTime(new Date());
+                receive.setUpdateTime(new Date());
+                fsCourseCheckinReceiveMapper.updateFsCourseCheckinReceive(receive);
+                if (receive.getGoodsId() != null) {
+                    redisCacheUtil.delRedisKey("getIntegralGoodsById::" + receive.getGoodsId());
+                }
+            }
+        }
+
+        if (param.getPayMoney() != null) {
+            totalCash = param.getPayMoney();
+        }
+
+        Long activityId = param.getActivityId();
+
+
+        for (FsIntegralGoods goods : goodsList) {
+            if (fsIntegralGoodsMapper.subStock(goods.getGoodsId(), 1) <= 0) {
+                throw new CustomException("商品库存不足: " + goods.getGoodsName());
+            }
+        }
+
+        FsIntegralOrder order = new FsIntegralOrder();
+        String orderSn = null;
+        try {
+            orderSn = OrderCodeUtils.getOrderSn();
+        } catch (Exception e) {
+            orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
+        }
+        if (StringUtils.isEmpty(orderSn)) {
+            throw new CustomException("订单生成失败,请重试");
+        }
+
+        if (totalCash.compareTo(BigDecimal.ZERO) > 0) {
+            order.setPayType(totalIntegral > 0 ? 3 : 2);
+            order.setStatus(4);
+            order.setIsPay(0);
+            order.setPayMoney(totalCash);
+        } else {
+            order.setPayType(1);
+            order.setStatus(1);
+            order.setIsPay(1);
+            order.setPayTime(LocalDateTime.now());
+        }
+
+        order.setOrderCode(orderSn);
+        order.setUserId(user.getUserId());
+        if (!goodsList.isEmpty()) {
+            order.setBarCode(goodsList.get(0).getBarCode());
+        }
+        order.setIntegral(totalIntegral.toString());
+        order.setItemJson(JSONUtil.toJsonStr(goodsList));
+        if (address != null) {
+            order.setUserName(address.getRealName());
+            order.setUserAddress(address.getProvince() + address.getCity() + address.getDistrict() + address.getDetail());
+            order.setUserPhone(address.getPhone());
+        }
+        order.setCreateTime(new Date());
+        order.setCompanyUserId(param.getCompanyUserId());
+        order.setCompanyId(param.getCompanyId());
+
+        if (fsIntegralOrderMapper.insertFsIntegralOrder(order) > 0) {
+            if (order.getPayType() != 2 && totalIntegral > 0) {
+                FsUser userMap = new FsUser();
+                userMap.setUserId(user.getUserId());
+                userMap.setIntegral(user.getIntegral() - totalIntegral);
+                fsUserMapper.updateFsUser(userMap);
+                FsUserIntegralLogs logs = new FsUserIntegralLogs();
+                logs.setIntegral(-totalIntegral);
+                logs.setUserId(order.getUserId());
+                logs.setBalance(userMap.getIntegral());
+                logs.setLogType(5);
+                logs.setBusinessId(order.getOrderId().toString());
+                logs.setCreateTime(new Date());
+                fsUserIntegralLogsMapper.insertFsUserIntegralLogs(logs);
+            }
+            return R.ok("订单创建成功").put("order", order);
+        } else {
+            throw new CustomException("订单创建失败");
+        }
+    }
 }

+ 7 - 0
fs-service/src/main/resources/mapper/course/FsCourseCheckinActivityMapper.xml

@@ -127,4 +127,11 @@
         and date(end_time) &gt;= date(#{currentDate})
     </select>
 
+    <!-- 根据公司ID查询活动列表 -->
+    <select id="selectActivityListByCompanyId" resultMap="FsCourseCheckinActivityResult">
+        <include refid="selectFsCourseCheckinActivityVo"/>
+        where  find_in_set(#{companyId}, company_ids)
+        order by create_time desc
+    </select>
+
 </mapper>

+ 33 - 1
fs-service/src/main/resources/mapper/course/FsCourseCheckinReceiveMapper.xml

@@ -30,7 +30,8 @@
         select receive_id, r.activity_id, r.prize_id, r.user_id, r.company_id, r.project_id,
                r.prize_type, r.prize_name, r.redpacket_amount, r.goods_id,
                r.receive_status, r.receive_time,
-               r.notify_status, r.notify_time, r.create_time, r.update_time,r.out_batch_no,r.batch_id
+               r.notify_status, r.notify_time,
+               r.create_time, r.update_time,r.out_batch_no,r.batch_id
         from fs_course_checkin_receive r
     </sql>
 
@@ -167,4 +168,35 @@
         </foreach>
     </insert>
 
+    <select id="selectReceiveListByActivityAndType" resultMap="FsCourseCheckinReceiveResult">
+        select
+            r.receive_id, r.activity_id, r.prize_id, r.user_id, r.company_id, r.project_id,
+            r.prize_type, r.prize_name, r.redpacket_amount, r.goods_id,
+            r.receive_status, r.receive_time, r.notify_status, r.notify_time,
+            r.create_time, r.update_time, r.out_batch_no, r.batch_id
+        from fs_course_checkin_receive r
+        where r.activity_id = #{activityId}
+        <if test="prizeType != null">
+            and r.prize_type = #{prizeType}
+        </if>
+        order by r.create_time desc
+    </select>
+
+    <select id="selectCheckinPrizeReceiveByUserIds" resultMap="FsCourseCheckinReceiveResult">
+        <include refid="selectFsCourseCheckinReceiveVo"/>
+        left join fs_integral_goods g on r.goods_id = g.goods_id
+        where r.receive_status = 0
+        and r.prize_type = 2
+        <if test="userIds != null and userIds.size() > 0">
+            and r.user_id in
+            <foreach item="userId" collection="userIds" open="(" separator="," close=")">
+                #{userId}
+            </foreach>
+        </if>
+        <if test="goodsName != null and goodsName != ''">
+            and g.goods_name like concat('%', #{goodsName}, '%')
+        </if>
+        order by r.create_time desc
+    </select>
+
 </mapper>

+ 114 - 0
fs-service/src/main/resources/mapper/course/FsCourseCheckinUserMapper.xml

@@ -114,4 +114,118 @@
         delete from fs_course_checkin_user where activity_id = #{activityId}
     </delete>
 
+    <resultMap type="com.fs.course.domain.FsCourseCheckinWarningVO" id="FsCourseCheckinWarningResult">
+        <result property="id" column="id"/>
+        <result property="userId" column="user_id"/>
+        <result property="activityId" column="activity_id"/>
+        <result property="userNickName" column="nick_name"/>
+        <result property="phone" column="phone"/>
+        <result property="companyName" column="company_name"/>
+        <result property="projectName" column="project_name"/>
+        <result property="activityName" column="activity_name"/>
+        <result property="activityStartTime" column="activity_start_time"/>
+        <result property="activityEndTime" column="activity_end_time"/>
+        <result property="checkinDays" column="checkin_days_required"/>
+        <result property="currentCheckinDays" column="checkin_days"/>
+        <result property="firstCheckinTime" column="first_checkin_time"/>
+        <result property="lastCheckinTime" column="last_checkin_time"/>
+        <result property="checkinTime" column="checkin_time"/>
+        <result property="receiveId" column="receive_id"/>
+        <result property="rewardStatus" column="receive_status"/>
+        <result property="prizeType" column="prize_type"/>
+        <result property="prizeName" column="prize_name"/>
+        <result property="redpacketAmount" column="redpacket_amount"/>
+        <result property="goodsId" column="goods_id"/>
+        <result property="goodsName" column="goods_name"/>
+        <result property="companyId" column="company_id"/>
+        <result property="projectId" column="project_id"/>
+        <result property="notifyTemplate" column="notify_template"/>
+    </resultMap>
+
+    <select id="selectWarningList" resultMap="FsCourseCheckinWarningResult">
+        SELECT
+            u.user_id,
+            u.nick_name,
+            u.phone,
+            c.company_name,
+            (SELECT dict_label FROM sys_dict_data WHERE dict_type = 'sys_course_project' AND dict_value = cu.project_id LIMIT 1) AS project_name,
+            a.activity_id,
+            a.activity_name,
+            a.start_time AS activity_start_time,
+            a.end_time AS activity_end_time,
+            a.checkin_days AS checkin_days_required,
+            cu.checkin_days,
+            cu.first_checkin_time,
+            cu.last_checkin_time,
+            (CASE WHEN cu.last_checkin_time IS NOT NULL THEN cu.last_checkin_time ELSE cu.first_checkin_time END) AS checkin_time,
+            r.receive_id,
+            r.receive_status,
+            ap.prize_type,
+            ap.prize_name,
+            r.redpacket_amount,
+            r.goods_id
+        FROM fs_course_checkin_user cu
+        LEFT JOIN fs_user u ON cu.user_id = u.user_id
+        LEFT JOIN company c ON cu.company_id = c.company_id
+        LEFT JOIN fs_course_checkin_activity a ON cu.activity_id = a.activity_id
+        left JOIN fs_course_checkin_prize ap ON a.activity_id = ap.activity_id
+        LEFT JOIN fs_course_checkin_receive r ON cu.activity_id = r.activity_id AND cu.user_id = r.user_id
+        <where>
+            <if test="companyId != null">
+                AND cu.company_id = #{companyId}
+            </if>
+            <if test="activityId != null">
+                AND cu.activity_id = #{activityId}
+            </if>
+            <if test="userId != null">
+                AND cu.user_id = #{userId}
+            </if>
+            <if test="phone != null and phone != ''">
+                AND u.phone LIKE CONCAT('%', #{phone}, '%')
+            </if>
+            <if test="checkinTime != null">
+                AND DATE(CASE WHEN cu.last_checkin_time IS NOT NULL THEN cu.last_checkin_time ELSE cu.first_checkin_time END) = DATE(#{checkinTime})
+            </if>
+        </where>
+        ORDER BY (CASE WHEN cu.last_checkin_time IS NOT NULL THEN cu.last_checkin_time ELSE cu.first_checkin_time END) DESC
+    </select>
+
+    <select id="selectCheckinRemindList" resultMap="FsCourseCheckinWarningResult">
+        SELECT
+            cu.id,
+            cu.user_id,
+            cu.company_id,
+            cu.project_id,
+            cu.checkin_days,
+            u.nick_name,
+            a.activity_id,
+            a.checkin_days AS checkin_days_required,
+            a.notify_template,
+            ap.prize_type,
+            ap.prize_name
+        FROM fs_course_checkin_user cu
+        LEFT JOIN fs_user u ON cu.user_id = u.user_id
+        LEFT JOIN fs_course_checkin_activity a ON cu.activity_id = a.activity_id
+        LEFT JOIN fs_course_checkin_prize ap ON a.activity_id = ap.activity_id
+        WHERE a.status = 1
+        <if test="remindType == 1">
+            AND cu.checkin_days = a.checkin_days - 1
+            AND NOT EXISTS (
+                SELECT 1 FROM crm_msg msg 
+                WHERE msg.obj_id = cu.id 
+                AND msg.msg_type = 5 
+                AND msg.title LIKE '%剩余一天%'
+            )
+        </if>
+        <if test="remindType == 2">
+            AND cu.checkin_days >= a.checkin_days
+            AND NOT EXISTS (
+                SELECT 1 FROM crm_msg msg 
+                WHERE msg.obj_id = cu.id 
+                AND msg.msg_type = 5 
+                AND msg.title LIKE '%打卡完成%'
+            )
+        </if>
+    </select>
+
 </mapper>

+ 5 - 0
fs-service/src/main/resources/mapper/his/FsIntegralOrderMapper.xml

@@ -49,6 +49,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="companyUserId != null  and companyUserId != ''"> and company_user_id = #{companyUserId}</if>
             <if test="companyId != null  and companyId != ''"> and company_id = #{companyId}</if>
             <if test="createTime != null "> and create_time = #{createTime}</if>
+            <if test="userIds != null and !userIds.isEmpty()"> and user_id in
+                 <foreach item="item" index="index" collection="userIds" separator="," open="(" close=")">
+                    #{item}
+                </foreach>
+            </if>
         </where>
     </select>
 

+ 2 - 1
fs-user-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -213,7 +213,8 @@ public class CompanyUserController extends AppBaseController {
                     }
                 }
             }
-            user.setPhone(param.getPhone());
+            //手机号加密
+            user.setPhone(encryptPhone(param.getPhone()));
             fsUserService.updateFsUser(user);
         }
         List<CompanyUserUser> list = companyUserUserService.selectCompanyUserUserList(map);

+ 4 - 3
fs-user-app/src/main/java/com/fs/app/controller/IntegralController.java

@@ -61,12 +61,13 @@ public class IntegralController extends  AppBaseController {
         return R.ok().put("data",listPageInfo);
     }
 
+    @Login
     @ApiOperation("获取积分商品详情")
     @GetMapping("/getIntegralGoodsById")
     @Cacheable(value = "getIntegralGoodsById", key = "#goodsId")
-    public R getIntegralGoodsById(@RequestParam("goodsId")Long goodsId, HttpServletRequest request){
-        FsIntegralGoods goods=goodsService.selectFsIntegralGoodsByGoodsId(goodsId);
-        return R.ok().put("data",goods);
+    public R getIntegralGoodsById(@RequestParam("goodsId")Long goodsId, @RequestParam(value = "isAPP", required = false, defaultValue = "0") Long isAPP, HttpServletRequest request){
+        FsIntegralGoods goods = goodsService.selectFsIntegralGoodsByIdWithCheckinFlag(goodsId,Long.parseLong(getUserId()),isAPP);
+        return R.ok().put("data", goods);
     }
 
     @Login

+ 14 - 0
fs-user-app/src/main/java/com/fs/app/controller/course/CourseFsUserController.java

@@ -13,6 +13,7 @@ import com.fs.app.annotation.Login;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.course.domain.FsCourseCheckinReceive;
 import com.fs.course.dto.BatchSendCourseDTO;
 import com.fs.course.param.*;
 import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
@@ -37,6 +38,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
+import java.util.List;
 import java.util.Map;
 
 @Api("会员-看课接口")
@@ -234,4 +236,16 @@ public class CourseFsUserController extends AppBaseController {
         return R.ok().put("data", result);
     }
 
+    /**
+     * 用户的奖励领取记录
+     */
+    @ApiOperation("用户的奖励领取记录")
+    @Login
+    @GetMapping("/receiveUserList")
+    public R receiveUserList() {
+        Long userId = Long.parseLong(getUserId());
+        List<FsCourseCheckinReceive> receiveList = fsCourseCheckinReceiveService.selectReceiveListByUserId(userId);
+        return R.ok().put("data", receiveList);
+    }
+
 }