浏览代码

add:app语音,app文本,福袋

ct 5 天之前
父节点
当前提交
4e2942160c
共有 25 个文件被更改,包括 1871 次插入15 次删除
  1. 111 0
      fs-company/src/main/java/com/fs/company/controller/qw/LuckyBagCollectRecordController.java
  2. 88 0
      fs-company/src/main/java/com/fs/company/controller/qw/LuckyBagController.java
  3. 18 1
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  4. 5 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRealLink.java
  5. 69 0
      fs-service/src/main/java/com/fs/course/domain/LuckyBag.java
  6. 151 0
      fs-service/src/main/java/com/fs/course/domain/LuckyBagCollectRecord.java
  7. 22 0
      fs-service/src/main/java/com/fs/course/param/LuckyBagActualRewardsParam.java
  8. 4 4
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiNewServiceImpl.java
  9. 4 4
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiServiceImpl.java
  10. 8 0
      fs-service/src/main/java/com/fs/his/domain/FsUserIntegralLogs.java
  11. 2 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserInformationCollectionMapper.java
  12. 26 0
      fs-service/src/main/java/com/fs/his/param/FsReceiveLuckyBagParam.java
  13. 2 0
      fs-service/src/main/java/com/fs/im/dto/OpenImMsgDTO.java
  14. 71 0
      fs-service/src/main/java/com/fs/qw/mapper/LuckyBagCollectRecordMapper.java
  15. 25 0
      fs-service/src/main/java/com/fs/qw/mapper/LuckyBagMapper.java
  16. 3 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  17. 63 0
      fs-service/src/main/java/com/fs/qw/service/ILuckyBagCollectRecordService.java
  18. 29 0
      fs-service/src/main/java/com/fs/qw/service/ILuckyBagService.java
  19. 63 0
      fs-service/src/main/java/com/fs/qw/service/impl/AsyncSopTestService.java
  20. 94 0
      fs-service/src/main/java/com/fs/qw/service/impl/LuckyBagCollectRecordServiceImpl.java
  21. 416 0
      fs-service/src/main/java/com/fs/qw/service/impl/LuckyBagServiceImpl.java
  22. 8 0
      fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java
  23. 311 6
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  24. 194 0
      fs-service/src/main/resources/mapper/qw/LuckyBagCollectRecordMapper.xml
  25. 84 0
      fs-service/src/main/resources/mapper/qw/LuckyBagMapper.xml

+ 111 - 0
fs-company/src/main/java/com/fs/company/controller/qw/LuckyBagCollectRecordController.java

@@ -0,0 +1,111 @@
+package com.fs.company.controller.qw;
+
+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.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.LuckyBagCollectRecord;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.qw.service.ILuckyBagCollectRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 福袋发放及领取记录Controller
+ *
+ * @author fs
+ * @date 2025-11-24
+ */
+@RestController
+@RequestMapping("/qw/luckyBagCollectRecord")
+public class LuckyBagCollectRecordController extends BaseController
+{
+    @Autowired
+    private ILuckyBagCollectRecordService luckyBagCollectRecordService;
+    @Autowired
+    private TokenService tokenService;
+    /**
+     * 查询福袋发放及领取记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:luckyBagCollectRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        luckyBagCollectRecord.setCompanyId(loginUser.getCompany().getCompanyId());
+        startPage();
+        List<LuckyBagCollectRecord> list = luckyBagCollectRecordService.selectLuckyBagCollectRecordList(luckyBagCollectRecord);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出福袋发放及领取记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:luckyBagCollectRecord:export')")
+    @Log(title = "福袋发放及领取记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        luckyBagCollectRecord.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<LuckyBagCollectRecord> list = luckyBagCollectRecordService.selectLuckyBagCollectRecordList(luckyBagCollectRecord);
+        // 数据转换处理
+        list.forEach(item -> {
+            item.setRewardTypeName(item.getRewardTypeName());
+            item.setCollectTypeName(item.getCollectTypeName());
+        });
+
+        ExcelUtil<LuckyBagCollectRecord> util = new ExcelUtil<LuckyBagCollectRecord>(LuckyBagCollectRecord.class);
+        return util.exportExcel(list, "福袋发放及领取记录数据");
+    }
+
+    /**
+     * 获取福袋发放及领取记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:luckyBagCollectRecord:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(luckyBagCollectRecordService.selectLuckyBagCollectRecordById(id));
+    }
+
+    /**
+     * 新增福袋发放及领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:luckyBagCollectRecord:add')")
+    @Log(title = "福袋发放及领取记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        return toAjax(luckyBagCollectRecordService.insertLuckyBagCollectRecord(luckyBagCollectRecord));
+    }
+
+    /**
+     * 修改福袋发放及领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:luckyBagCollectRecord:edit')")
+    @Log(title = "福袋发放及领取记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        return toAjax(luckyBagCollectRecordService.updateLuckyBagCollectRecord(luckyBagCollectRecord));
+    }
+
+    /**
+     * 删除福袋发放及领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:luckyBagCollectRecord:remove')")
+    @Log(title = "福袋发放及领取记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(luckyBagCollectRecordService.deleteLuckyBagCollectRecordByIds(ids));
+    }
+}

+ 88 - 0
fs-company/src/main/java/com/fs/company/controller/qw/LuckyBagController.java

@@ -0,0 +1,88 @@
+package com.fs.company.controller.qw;
+
+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.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.course.domain.LuckyBag;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.qw.service.ILuckyBagService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 福袋管理
+ *
+ * @author fs
+ * @date 2024-12-02
+ */
+@RestController
+@RequestMapping("/qw/luckyBag")
+public class LuckyBagController extends BaseController
+{
+    @Autowired
+    private ILuckyBagService luckyBagService;
+    @Autowired
+    private TokenService tokenService;
+
+//    @PreAuthorize("@ss.hasPermi('course:reward:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LuckyBag reward)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        reward.setCompanyId(String.valueOf(loginUser.getCompany().getCompanyId()));
+        List<LuckyBag> list = luckyBagService.selectLuckyBagList(reward);
+        return getDataTable(list);
+    }
+
+
+//    @PreAuthorize("@ss.hasPermi('luckybag:reward:add')")
+    @Log(title = "奖励配置", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody LuckyBag reward) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        reward.setCreateName(loginUser.getUser().getNickName());
+        reward.setCompanyId(String.valueOf(loginUser.getCompany().getCompanyId()));
+        reward.setUpdateBy(String.valueOf(loginUser.getUser().getUserId()));
+        reward.setCreateId(loginUser.getUser().getUserId());
+        reward.setCreateTime(new Date());
+        reward.setUpdateId(loginUser.getUser().getUserId());
+        reward.setUpdateTime(new Date());
+       return toAjax(luckyBagService.add(reward));
+    }
+
+
+//    @PreAuthorize("@ss.hasPermi('course:reward:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        LuckyBag reward = new LuckyBag();
+        reward.setId(id);
+        return AjaxResult.success(luckyBagService.selectLuckyBagList(reward));
+    }
+
+//    @PreAuthorize("@ss.hasPermi('course:reward:edit')")
+    @Log(title = "修改福袋配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LuckyBag reward) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        reward.setUpdateId(loginUser.getUser().getUserId());
+        reward.setUpdateTime(new Date());
+        return toAjax(luckyBagService.updateLuckyBag(reward));
+    }
+
+//    @PreAuthorize("@ss.hasPermi('course:reward:remove')")
+    @Log(title = "奖励配置", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(luckyBagService.deleteLuckyBagByIds(ids));
+    }
+}

+ 18 - 1
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -2,6 +2,7 @@ package com.fs.app.task;
 
 
 
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.app.service.IpadSendServer;
 import com.fs.app.service.IpadSendServer;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.core.redis.RedisCacheT;
@@ -272,7 +273,23 @@ public class SendMsg {
                 new Thread(() -> {
                 new Thread(() -> {
                     try {
                     try {
                         List<QwSopTempSetting.Content.Setting> settings = JSON.parseArray(JSON.toJSONString(setting.getSetting()), QwSopTempSetting.Content.Setting.class).stream().filter(e -> "9".equals(e.getContentType())).collect(Collectors.toList());
                         List<QwSopTempSetting.Content.Setting> settings = JSON.parseArray(JSON.toJSONString(setting.getSetting()), QwSopTempSetting.Content.Setting.class).stream().filter(e -> "9".equals(e.getContentType())).collect(Collectors.toList());
-                        asyncSopTestService.asyncSendMsgBySopAppLinkNormalIM(settings, qwSopLogs.getCorpId(), user.getCompanyUserId(), qwSopLogs.getFsUserId());
+                        if (!settings.isEmpty()) {
+                            asyncSopTestService.asyncSendMsgBySopAppLinkNormalIM(settings, qwSopLogs.getCorpId(), user.getCompanyUserId(), qwSopLogs.getFsUserId());
+                        }
+
+                        //app文本消息
+                        log.info("开始发送app文本消息消息开始,消息{},用户{}", JSONObject.toJSONString(settings), user.getQwUserName());
+                        settings = JSON.parseArray(JSON.toJSONString(setting.getSetting()), QwSopTempSetting.Content.Setting.class).stream().filter(e -> "15".equals(e.getContentType())).collect(Collectors.toList());
+
+                        if (!settings.isEmpty()) {
+                            asyncSopTestService.asyncSendMsgBySopAppTxtNormalIM(settings, qwSopLogs.getCorpId(), qwUser.getCompanyUserId(), qwSopLogs.getFsUserId());
+                        }
+                        //app语音消息
+                        log.info("开始发送app语音消息消息开始,消息{},用户{}", JSONObject.toJSONString(settings), user.getQwUserName());
+                        settings = JSON.parseArray(JSON.toJSONString(setting.getSetting()), QwSopTempSetting.Content.Setting.class).stream().filter(e -> "16".equals(e.getContentType())).collect(Collectors.toList());
+                        if (!settings.isEmpty()) {
+                            asyncSopTestService.asyncSendMsgBySopAppMP3NormalIM(settings, qwSopLogs.getCorpId(), qwUser.getCompanyUserId(), qwSopLogs.getFsUserId());
+                        }
                     } catch (Exception e) {
                     } catch (Exception e) {
                         log.error("推送APP失败", e);
                         log.error("推送APP失败", e);
                     }
                     }

+ 5 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseRealLink.java

@@ -48,4 +48,9 @@ public class FsCourseRealLink implements Serializable
 
 
     @ApiModelProperty(value = "项目唯一标识(PS:MYHK)")
     @ApiModelProperty(value = "项目唯一标识(PS:MYHK)")
     private String projectCode;
     private String projectCode;
+
+    /**
+     * 业务id
+     */
+    private String businessId;
 }
 }

+ 69 - 0
fs-service/src/main/java/com/fs/course/domain/LuckyBag.java

@@ -0,0 +1,69 @@
+package com.fs.course.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+
+/**
+ * 奖励配置对象 fs_course_reward
+ *
+ * @author 杨衍生
+ * @date 2025-09-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class LuckyBag extends BaseEntity{
+
+    /** 主键ID */
+    private Long id;
+
+    /** 福袋名称 */
+    @Excel(name = "福袋名称")
+    private String name;
+
+    /** 奖励类型 (1:定值, 2:宝箱) */
+    @Excel(name = "奖励类型 (1:定值, 2:宝箱)")
+    private String type;
+
+    /**
+     * 是否删除 0-正常 1-删除
+     */
+    @Excel(name = "状态 (0:删除, 1:正常)")
+    private Long status;
+
+    /** 创建人ID */
+    @Excel(name = "创建人ID")
+    private Long createId;
+
+    /** 实际获得的奖励内容 */
+    @Excel(name = "实际获得的奖励内容")
+    private String actualRewards;
+
+    /** 实际获得的奖励内容 */
+    @Excel(name = "创建人")
+    private String createName;
+
+    @Excel(name = "所属公司")
+    private String companyId;
+
+    /** 创建人ID */
+    @Excel(name = "修改人ID")
+    private Long updateId;
+
+    /**
+     * 定额金额
+     */
+    private BigDecimal amount;
+
+    /** 状态 (0:禁用, 1:启用) */
+    private String dataStatus;
+
+    /**
+     * 奖励类型 1-定额 2-随机
+     */
+    private String rewardType;
+
+}

+ 151 - 0
fs-service/src/main/java/com/fs/course/domain/LuckyBagCollectRecord.java

@@ -0,0 +1,151 @@
+package com.fs.course.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 福袋发放及领取记录对象 lucky_bag_collect_record
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class LuckyBagCollectRecord extends BaseEntity{
+
+
+
+    /** 领取用户ID */
+    @Excel(name = "领取用户ID")
+    private Long userId;
+
+    /** 客户名称 */
+    @Excel(name = "客户名称")
+    private String userName;
+
+    // 福袋名称
+    @Excel(name = "福袋名称")
+    private String luckyBagName;
+
+    /** 业务类型:1-群福袋 2-个人福袋 */
+//    @Excel(name = "业务类型:1-群福袋 2-个人福袋")
+    private Long rewardType;
+
+    @Excel(name = "业务类型")
+    private String rewardTypeName;
+
+    /** 福袋表主键ID */
+//    @Excel(name = "福袋表主键ID")
+    private Long luckyBagId;
+
+    /** 销售ID */
+//    @Excel(name = "销售ID")
+    private Long companyUserId;
+
+    /** 客服名称 */
+    @Excel(name = "客服名称")
+    private String companyUserName;
+
+    /** 公司ID */
+    @Excel(name = "公司ID")
+    private Long companyId;
+
+    /** 公司名称 */
+    @Excel(name = "公司名称")
+    private String companyName;
+
+    /** 芳华币数量 */
+    @Excel(name = "芳华币数量")
+    private BigDecimal coinAmount;
+
+    /** 发放时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "发放时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date sendTime;
+
+    /** 领取时间 精确到时分秒*/
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "领取时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date collectTime;
+
+    /** 失效时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd  HH:mm:ss")
+    @Excel(name = "失效时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date expiryTime;
+
+    /** 领取状态(0-已发放 1-已领取 2-已失效) */
+//    @Excel(name = "领取状态(0-已发放 1-已领取 2-已失效,3-待发放)")
+    private String collectType;
+
+    @Excel(name = "领取状态")
+    private String collectTypeName;
+
+    /** 群聊名称 */
+    @Excel(name = "群聊名称")
+    private String externalUserName;
+
+    // 企微用户id
+    private String qwUserId;
+
+    /** 企微用户名称 */
+    @Excel(name = "企微员工名称")
+    private String qwUserName;
+
+
+    /** 群聊会话id */
+//    @Excel(name = "群聊会话id")
+    private String chatId;
+
+    /** 主键ID */
+    @Excel(name = "领取Id")
+    private Long id;
+
+    /** 关联id 关联群发记录id */
+//    @Excel(name = "关联id 关联群发记录id")
+    @Excel(name = "群领取Id")
+    private Long relationId;
+
+    /** 发送链接 */
+//    @Excel(name = "发送链接")
+    private String sendLink;
+
+    // 更新时间
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    // 在 getter 中进行转换
+    public String getRewardTypeName() {
+        if (this.rewardType == null) return "";
+        switch (this.rewardType.intValue()) {
+            case 1: return "群福袋";
+            case 2: return "个人福袋";
+            default: return "";
+        }
+    }
+
+    public String getCollectTypeName() {
+        if (this.collectType == null) {
+            return "";
+        }
+        switch (this.collectType) {
+            case "0":
+                return "已发放";
+            case "1":
+                return "已领取";
+            case "2":
+                return "已失效";
+            default:
+                return this.collectType;
+        }
+    }
+
+
+
+}

+ 22 - 0
fs-service/src/main/java/com/fs/course/param/LuckyBagActualRewardsParam.java

@@ -0,0 +1,22 @@
+package com.fs.course.param;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@Data
+public class LuckyBagActualRewardsParam {
+
+    @JsonProperty("type")
+    private Integer type;
+    @JsonProperty("name")
+    private String name;
+    @JsonProperty("amount")
+    private String amount;
+    @JsonProperty("probability")
+    private String probability;
+    @JsonProperty("code")
+    private String code;
+
+}

+ 4 - 4
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiNewServiceImpl.java

@@ -552,7 +552,7 @@ public class AiNewServiceImpl implements AiNewService {
                         String.valueOf(user.getId()),
                         String.valueOf(user.getId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyId()),
                         String.valueOf(user.getCompanyId()),
-                        String.valueOf(session.getQwExtId()));
+                        String.valueOf(session.getQwExtId()),2);
                 if (linkUrl != null && linkUrl.get("url") != null) {
                 if (linkUrl != null && linkUrl.get("url") != null) {
                     String s = (String)linkUrl.get("url");
                     String s = (String)linkUrl.get("url");
                     sendWebSocketMsg(s,msgVo,user,session);
                     sendWebSocketMsg(s,msgVo,user,session);
@@ -583,7 +583,7 @@ public class AiNewServiceImpl implements AiNewService {
                                 String.valueOf(user.getId()),
                                 String.valueOf(user.getId()),
                                 String.valueOf(user.getCompanyUserId()),
                                 String.valueOf(user.getCompanyUserId()),
                                 String.valueOf(user.getCompanyId()),
                                 String.valueOf(user.getCompanyId()),
-                                String.valueOf(session.getQwExtId()));
+                                String.valueOf(session.getQwExtId()),2);
                         if (linkUrl != null && linkUrl.get("url") != null) {
                         if (linkUrl != null && linkUrl.get("url") != null) {
                             String s = (String)linkUrl.get("url");
                             String s = (String)linkUrl.get("url");
                             sendWebSocketMsg(s,msgVo,user,session);
                             sendWebSocketMsg(s,msgVo,user,session);
@@ -1070,7 +1070,7 @@ public class AiNewServiceImpl implements AiNewService {
                         String.valueOf(user.getId()),
                         String.valueOf(user.getId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyId()),
                         String.valueOf(user.getCompanyId()),
-                        String.valueOf(session.getQwExtId()));
+                        String.valueOf(session.getQwExtId()),2);
                 if (linkUrl != null && linkUrl.get("url") != null) {
                 if (linkUrl != null && linkUrl.get("url") != null) {
                     String s = (String)linkUrl.get("url");
                     String s = (String)linkUrl.get("url");
                     sendWebTaskSocketMsg(s,sendId,user);
                     sendWebTaskSocketMsg(s,sendId,user);
@@ -1101,7 +1101,7 @@ public class AiNewServiceImpl implements AiNewService {
                             String.valueOf(user.getId()),
                             String.valueOf(user.getId()),
                             String.valueOf(user.getCompanyUserId()),
                             String.valueOf(user.getCompanyUserId()),
                             String.valueOf(user.getCompanyId()),
                             String.valueOf(user.getCompanyId()),
-                            String.valueOf(session.getQwExtId()));
+                            String.valueOf(session.getQwExtId()),2);
                     if (linkUrl != null && linkUrl.get("url") != null) {
                     if (linkUrl != null && linkUrl.get("url") != null) {
                         String s = (String)linkUrl.get("url");
                         String s = (String)linkUrl.get("url");
                         sendWebTaskSocketMsg(s,sendId,user);
                         sendWebTaskSocketMsg(s,sendId,user);

+ 4 - 4
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiServiceImpl.java

@@ -530,7 +530,7 @@ public class AiServiceImpl implements AiService {
                         String.valueOf(user.getId()),
                         String.valueOf(user.getId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyId()),
                         String.valueOf(user.getCompanyId()),
-                        String.valueOf(session.getQwExtId()));
+                        String.valueOf(session.getQwExtId()),2);
                 if (linkUrl != null && linkUrl.get("url") != null) {
                 if (linkUrl != null && linkUrl.get("url") != null) {
                     String s = (String)linkUrl.get("url");
                     String s = (String)linkUrl.get("url");
                     sendWebSocketMsg(s,msgVo,user,session);
                     sendWebSocketMsg(s,msgVo,user,session);
@@ -561,7 +561,7 @@ public class AiServiceImpl implements AiService {
                                 String.valueOf(user.getId()),
                                 String.valueOf(user.getId()),
                                 String.valueOf(user.getCompanyUserId()),
                                 String.valueOf(user.getCompanyUserId()),
                                 String.valueOf(user.getCompanyId()),
                                 String.valueOf(user.getCompanyId()),
-                                String.valueOf(session.getQwExtId()));
+                                String.valueOf(session.getQwExtId()),2);
                         if (linkUrl != null && linkUrl.get("url") != null) {
                         if (linkUrl != null && linkUrl.get("url") != null) {
                             String s = (String)linkUrl.get("url");
                             String s = (String)linkUrl.get("url");
                             sendWebSocketMsg(s,msgVo,user,session);
                             sendWebSocketMsg(s,msgVo,user,session);
@@ -1048,7 +1048,7 @@ public class AiServiceImpl implements AiService {
                         String.valueOf(user.getId()),
                         String.valueOf(user.getId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyUserId()),
                         String.valueOf(user.getCompanyId()),
                         String.valueOf(user.getCompanyId()),
-                        String.valueOf(session.getQwExtId()));
+                        String.valueOf(session.getQwExtId()),2);
                 if (linkUrl != null && linkUrl.get("url") != null) {
                 if (linkUrl != null && linkUrl.get("url") != null) {
                     String s = (String)linkUrl.get("url");
                     String s = (String)linkUrl.get("url");
                     sendWebTaskSocketMsg(s,sendId,user);
                     sendWebTaskSocketMsg(s,sendId,user);
@@ -1079,7 +1079,7 @@ public class AiServiceImpl implements AiService {
                             String.valueOf(user.getId()),
                             String.valueOf(user.getId()),
                             String.valueOf(user.getCompanyUserId()),
                             String.valueOf(user.getCompanyUserId()),
                             String.valueOf(user.getCompanyId()),
                             String.valueOf(user.getCompanyId()),
-                            String.valueOf(session.getQwExtId()));
+                            String.valueOf(session.getQwExtId()),2);
                     if (linkUrl != null && linkUrl.get("url") != null) {
                     if (linkUrl != null && linkUrl.get("url") != null) {
                         String s = (String)linkUrl.get("url");
                         String s = (String)linkUrl.get("url");
                         sendWebTaskSocketMsg(s,sendId,user);
                         sendWebTaskSocketMsg(s,sendId,user);

+ 8 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserIntegralLogs.java

@@ -5,6 +5,8 @@ import com.fs.common.core.domain.BaseEntity;
 import io.swagger.models.auth.In;
 import io.swagger.models.auth.In;
 import lombok.Data;
 import lombok.Data;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * 积分记录对象 fs_user_integral_logs
  * 积分记录对象 fs_user_integral_logs
  *
  *
@@ -42,4 +44,10 @@ public class FsUserIntegralLogs extends BaseEntity
     private Integer businessType;
     private Integer businessType;
 
 
     private Integer status;
     private Integer status;
+
+    private String nickName;
+
+    private String phone;
+
+    private BigDecimal commission;
 }
 }

+ 2 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserInformationCollectionMapper.java

@@ -100,4 +100,6 @@ public interface FsUserInformationCollectionMapper extends BaseMapper<FsUserInfo
     List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType2(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
     List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType2(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
     List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType1(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
     List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType1(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
     FsUserInformationCollection selectFsUserInformationCollectionByOrderCode(String orderCode);
     FsUserInformationCollection selectFsUserInformationCollectionByOrderCode(String orderCode);
+
+    List<FsUserInformationCollection> selectListByIsPayAndConfirmStatus();
 }
 }

+ 26 - 0
fs-service/src/main/java/com/fs/his/param/FsReceiveLuckyBagParam.java

@@ -0,0 +1,26 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+/**
+ * @description: TODO
+ * @author: Xgb
+ * @createDate: 2025/11/21
+ * @version: 1.0
+ */
+@Data
+public class FsReceiveLuckyBagParam {
+
+    // 记录id
+    private Long recordId;
+
+    // 用户id
+    private Long userId;
+
+    // 企微员工id
+    private String userName;
+
+    // 企微主体id
+    private String corpId;
+
+}

+ 2 - 0
fs-service/src/main/java/com/fs/im/dto/OpenImMsgDTO.java

@@ -30,6 +30,8 @@ public class OpenImMsgDTO {
         private String data;
         private String data;
         private String description;
         private String description;
         private String extension;
         private String extension;
+        private String sourceUrl;
+        private Integer duration;
     }
     }
     @Data
     @Data
     public static class ImData{
     public static class ImData{

+ 71 - 0
fs-service/src/main/java/com/fs/qw/mapper/LuckyBagCollectRecordMapper.java

@@ -0,0 +1,71 @@
+package com.fs.qw.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.LuckyBagCollectRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+
+/**
+ * 福袋发放及领取记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+public interface LuckyBagCollectRecordMapper extends BaseMapper<LuckyBagCollectRecord>{
+
+    int insertBagCollectRecord(LuckyBagCollectRecord reward);
+
+    /**
+     * 查询福袋发放及领取记录
+     *
+     * @param id 福袋发放及领取记录主键
+     * @return 福袋发放及领取记录
+     */
+    LuckyBagCollectRecord selectLuckyBagCollectRecordById(Long id);
+
+    /**
+     * 查询福袋发放及领取记录列表
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 福袋发放及领取记录集合
+     */
+    List<LuckyBagCollectRecord> selectLuckyBagCollectRecordList(LuckyBagCollectRecord luckyBagCollectRecord);
+
+    /**
+     * 新增福袋发放及领取记录
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 结果
+     */
+    int insertLuckyBagCollectRecord(LuckyBagCollectRecord luckyBagCollectRecord);
+
+    /**
+     * 修改福袋发放及领取记录
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 结果
+     */
+    int updateLuckyBagCollectRecord(LuckyBagCollectRecord luckyBagCollectRecord);
+
+    /**
+     * 删除福袋发放及领取记录
+     *
+     * @param id 福袋发放及领取记录主键
+     * @return 结果
+     */
+    int deleteLuckyBagCollectRecordById(Long id);
+
+    /**
+     * 批量删除福袋发放及领取记录
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteLuckyBagCollectRecordByIds(Long[] ids);
+
+    LuckyBagCollectRecord selectLuckyBagCollectRecordByRelationId(@Param("relationId") Long relationId,@Param("userId") Long userId);
+
+    int updateLuckyBagExpiryStatus();
+}

+ 25 - 0
fs-service/src/main/java/com/fs/qw/mapper/LuckyBagMapper.java

@@ -0,0 +1,25 @@
+package com.fs.qw.mapper;
+
+import com.fs.course.domain.LuckyBag;
+
+import java.util.List;
+
+/**
+ * app客服活码上架Mapper接口
+ *
+ * @author fs
+ * @date 2024-12-02
+ */
+public interface LuckyBagMapper
+{
+
+    int insertLuckyBag(LuckyBag reward);
+
+    List<LuckyBag> selectLuckyBagList(LuckyBag reward);
+
+    int updateLuckyBag(LuckyBag reward);
+
+    int deleteLuckyBagByIds(Long[] ids);
+
+    LuckyBag selectLuckyBagById(Long id);
+}

+ 3 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -503,4 +503,7 @@ public interface QwUserMapper extends BaseMapper<QwUser>
     List<QwUser> selectQwUserByServerIds(@Param("serverIds")List<String> serverIds);
     List<QwUser> selectQwUserByServerIds(@Param("serverIds")List<String> serverIds);
 
 
     int batchUpdateUnbind(@Param("ids")List<Long> ids);
     int batchUpdateUnbind(@Param("ids")List<Long> ids);
+
+    @Select("select * from qw_user where qw_user_id=#{qwUserId} and corp_id =#{corpId} limit 1")
+    QwUser selectQwUserEntityByQwUserIdAndCorId(@Param("qwUserId")String qwUserId,@Param("corpId") String corpId);
 }
 }

+ 63 - 0
fs-service/src/main/java/com/fs/qw/service/ILuckyBagCollectRecordService.java

@@ -0,0 +1,63 @@
+package com.fs.qw.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.LuckyBagCollectRecord;
+
+import java.util.List;
+
+/**
+ * 福袋发放及领取记录Service接口
+ *
+ * @author fs
+ * @date 2025-11-24
+ */
+public interface ILuckyBagCollectRecordService extends IService<LuckyBagCollectRecord> {
+    /**
+     * 查询福袋发放及领取记录
+     *
+     * @param id 福袋发放及领取记录主键
+     * @return 福袋发放及领取记录
+     */
+    LuckyBagCollectRecord selectLuckyBagCollectRecordById(Long id);
+
+    /**
+     * 查询福袋发放及领取记录列表
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 福袋发放及领取记录集合
+     */
+    List<LuckyBagCollectRecord> selectLuckyBagCollectRecordList(LuckyBagCollectRecord luckyBagCollectRecord);
+
+    /**
+     * 新增福袋发放及领取记录
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 结果
+     */
+    int insertLuckyBagCollectRecord(LuckyBagCollectRecord luckyBagCollectRecord);
+
+    /**
+     * 修改福袋发放及领取记录
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 结果
+     */
+    int updateLuckyBagCollectRecord(LuckyBagCollectRecord luckyBagCollectRecord);
+
+    /**
+     * 批量删除福袋发放及领取记录
+     *
+     * @param ids 需要删除的福袋发放及领取记录主键集合
+     * @return 结果
+     */
+    int deleteLuckyBagCollectRecordByIds(Long[] ids);
+
+    /**
+     * 删除福袋发放及领取记录信息
+     *
+     * @param id 福袋发放及领取记录主键
+     * @return 结果
+     */
+    int deleteLuckyBagCollectRecordById(Long id);
+}

+ 29 - 0
fs-service/src/main/java/com/fs/qw/service/ILuckyBagService.java

@@ -0,0 +1,29 @@
+package com.fs.qw.service;
+
+import com.fs.common.core.domain.R;
+import com.fs.course.domain.LuckyBag;
+import com.fs.his.domain.FsUser;
+import com.fs.his.param.FsReceiveLuckyBagParam;
+
+import java.util.List;
+
+
+
+public interface ILuckyBagService
+{
+
+
+    int add(LuckyBag reward);
+
+    List<LuckyBag> selectLuckyBagList(LuckyBag reward);
+
+    int updateLuckyBag(LuckyBag reward);
+
+    int deleteLuckyBagByIds(Long[] ids);
+
+    LuckyBag getLuckyBagInfo(Long luckyBagId);
+
+    R receiveLuckyBag(FsReceiveLuckyBagParam param, FsUser user);
+
+    R getLuckyBagInfoByRecordId(Long recordId);
+}

+ 63 - 0
fs-service/src/main/java/com/fs/qw/service/impl/AsyncSopTestService.java

@@ -1,5 +1,6 @@
 package com.fs.qw.service.impl;
 package com.fs.qw.service.impl;
 
 
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
@@ -7,6 +8,8 @@ import com.fs.course.domain.FsCourseSopAppLink;
 import com.fs.course.mapper.FsCourseSopAppLinkMapper;
 import com.fs.course.mapper.FsCourseSopAppLinkMapper;
 import com.fs.gtPush.service.uniPush2Service;
 import com.fs.gtPush.service.uniPush2Service;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.mapper.FsUserMapper;
+import com.fs.im.dto.OpenImMsgDTO;
+import com.fs.im.service.OpenIMService;
 import com.fs.qw.domain.QwSopUpdateStatus;
 import com.fs.qw.domain.QwSopUpdateStatus;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
@@ -29,6 +32,7 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
@@ -539,4 +543,63 @@ public class AsyncSopTestService {
 
 
     }
     }
 
 
+    @Autowired
+    private OpenIMService openIMService;
+    @Async("scheduledExecutorService")
+    public void  asyncSendMsgBySopAppTxtNormalIM(List<QwSopTempSetting.Content.Setting> setting,String cropId,Long companyUserId,Long fsUserId){
+
+        setting.forEach(item->{
+            try {
+                log.info("执行发送app文本消息:{}",item);
+                OpenImMsgDTO openImMsgDTO = new OpenImMsgDTO();
+                openImMsgDTO.setSendID("C"+companyUserId);
+                openImMsgDTO.setRecvID("U"+fsUserId);
+                openImMsgDTO.setContentType(101);
+                openImMsgDTO.setSessionType(1);
+                OpenImMsgDTO.Content imContent = new OpenImMsgDTO.Content();
+                imContent.setContent(item.getValue());
+                openImMsgDTO.setContent(imContent);
+                openIMService.openIMSendMsg(openImMsgDTO);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        });
+
+    }
+
+    @Async("scheduledExecutorService")
+    public void  asyncSendMsgBySopAppMP3NormalIM(List<QwSopTempSetting.Content.Setting> setting,String cropId,Long companyUserId,Long fsUserId){
+
+        setting.forEach(item->{
+            try {
+                if(StrUtil.isEmpty(item.getVoiceUrl())){
+                    log.info("执行发送app文本消息:{}",item);
+                    OpenImMsgDTO openImMsgDTO = new OpenImMsgDTO();
+                    openImMsgDTO.setSendID("C"+companyUserId);
+                    openImMsgDTO.setRecvID("U"+fsUserId);
+                    openImMsgDTO.setContentType(101);
+                    openImMsgDTO.setSessionType(1);
+                    OpenImMsgDTO.Content imContent = new OpenImMsgDTO.Content();
+                    imContent.setContent(item.getValue());
+                    openImMsgDTO.setContent(imContent);
+                    openIMService.openIMSendMsg(openImMsgDTO);
+                }else {
+                    log.info("执行发送app语音消息:{}",item);
+                    OpenImMsgDTO openImMsgDTO = new OpenImMsgDTO();
+                    openImMsgDTO.setSendID("C"+companyUserId);
+                    openImMsgDTO.setRecvID("U"+fsUserId);
+                    openImMsgDTO.setContentType(103);
+                    openImMsgDTO.setSessionType(1);
+                    OpenImMsgDTO.Content imContent = new OpenImMsgDTO.Content();
+                    imContent.setSourceUrl(item.getVoiceUrl());
+                    imContent.setDuration(Integer.parseInt(item.getVoiceDuration()));
+                    openImMsgDTO.setContent(imContent);
+                    openIMService.openIMSendMsg(openImMsgDTO);
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        });
+
+    }
 }
 }

+ 94 - 0
fs-service/src/main/java/com/fs/qw/service/impl/LuckyBagCollectRecordServiceImpl.java

@@ -0,0 +1,94 @@
+package com.fs.qw.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.course.domain.LuckyBagCollectRecord;
+import com.fs.qw.mapper.LuckyBagCollectRecordMapper;
+import com.fs.qw.service.ILuckyBagCollectRecordService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 福袋发放及领取记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-11-24
+ */
+@Service
+public class LuckyBagCollectRecordServiceImpl extends ServiceImpl<LuckyBagCollectRecordMapper, LuckyBagCollectRecord> implements ILuckyBagCollectRecordService {
+
+    /**
+     * 查询福袋发放及领取记录
+     *
+     * @param id 福袋发放及领取记录主键
+     * @return 福袋发放及领取记录
+     */
+    @Override
+    public LuckyBagCollectRecord selectLuckyBagCollectRecordById(Long id)
+    {
+        return baseMapper.selectLuckyBagCollectRecordById(id);
+    }
+
+    /**
+     * 查询福袋发放及领取记录列表
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 福袋发放及领取记录
+     */
+    @Override
+    public List<LuckyBagCollectRecord> selectLuckyBagCollectRecordList(LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        return baseMapper.selectLuckyBagCollectRecordList(luckyBagCollectRecord);
+    }
+
+    /**
+     * 新增福袋发放及领取记录
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 结果
+     */
+    @Override
+    public int insertLuckyBagCollectRecord(LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        luckyBagCollectRecord.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertLuckyBagCollectRecord(luckyBagCollectRecord);
+    }
+
+    /**
+     * 修改福袋发放及领取记录
+     *
+     * @param luckyBagCollectRecord 福袋发放及领取记录
+     * @return 结果
+     */
+    @Override
+    public int updateLuckyBagCollectRecord(LuckyBagCollectRecord luckyBagCollectRecord)
+    {
+        luckyBagCollectRecord.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateLuckyBagCollectRecord(luckyBagCollectRecord);
+    }
+
+    /**
+     * 批量删除福袋发放及领取记录
+     *
+     * @param ids 需要删除的福袋发放及领取记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteLuckyBagCollectRecordByIds(Long[] ids)
+    {
+        return baseMapper.deleteLuckyBagCollectRecordByIds(ids);
+    }
+
+    /**
+     * 删除福袋发放及领取记录信息
+     *
+     * @param id 福袋发放及领取记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteLuckyBagCollectRecordById(Long id)
+    {
+        return baseMapper.deleteLuckyBagCollectRecordById(id);
+    }
+}

+ 416 - 0
fs-service/src/main/java/com/fs/qw/service/impl/LuckyBagServiceImpl.java

@@ -0,0 +1,416 @@
+package com.fs.qw.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.common.BeanCopyUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.DateUtils;
+import com.fs.course.domain.LuckyBag;
+import com.fs.course.domain.LuckyBagCollectRecord;
+import com.fs.course.param.LuckyBagActualRewardsParam;
+import com.fs.his.domain.FsUser;
+import com.fs.his.domain.FsUserIntegralLogs;
+import com.fs.his.mapper.FsUserMapper;
+import com.fs.his.param.FsReceiveLuckyBagParam;
+import com.fs.his.service.impl.FsUserIntegralLogsServiceImpl;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.domain.QwGroupChat;
+import com.fs.qw.domain.QwGroupChatUser;
+import com.fs.qw.mapper.*;
+import com.fs.qw.service.ILuckyBagService;
+import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.impl.SysConfigServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.*;
+
+@Slf4j
+@Service
+public class LuckyBagServiceImpl implements ILuckyBagService
+{
+
+    @Autowired
+    private LuckyBagMapper luckyBagMapper;
+
+    @Autowired
+    private LuckyBagCollectRecordMapper luckyBagCollectRecordMapper;
+
+    @Autowired
+    private FsUserIntegralLogsServiceImpl fsUserIntegralLogsService;
+
+    @Autowired
+    private QwGroupChatMapper qwGroupChatMapper;
+    @Autowired
+    private QwGroupChatUserMapper qwGroupChatUserMapper;
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+    @Autowired
+    private FsUserMapper userMapper;
+    @Autowired
+    private SysConfigServiceImpl sysConfigService;
+
+    @Override
+    public int add(LuckyBag reward) {
+
+       checkParam(reward);
+        return luckyBagMapper.insertLuckyBag(reward);
+    }
+
+    @Override
+    public List<LuckyBag> selectLuckyBagList(LuckyBag reward) {
+        return luckyBagMapper.selectLuckyBagList(reward);
+    }
+
+    @Override
+    public int updateLuckyBag(LuckyBag reward) {
+        checkParam(reward);
+        return luckyBagMapper.updateLuckyBag(reward);
+    }
+
+    @Override
+    public int deleteLuckyBagByIds(Long[] ids) {
+        return luckyBagMapper.deleteLuckyBagByIds(ids);
+    }
+
+    @Override
+    public LuckyBag getLuckyBagInfo(Long luckyBagId) {
+        return luckyBagMapper.selectLuckyBagById(luckyBagId);
+    }
+
+    /**
+     * @Description: 领取福袋奖励
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/20 17:27
+     */
+    @Override
+    @Transactional
+    public R receiveLuckyBag(FsReceiveLuckyBagParam param, FsUser user) {
+
+        Long userId = param.getUserId();
+        LuckyBagCollectRecord record = luckyBagCollectRecordMapper.selectLuckyBagCollectRecordById(param.getRecordId());
+        // 校验福袋 用户信息
+        LuckyBagCollectRecord info;
+        R r=checkRecordParam(record, param);
+        if(!r.get("code").equals(200)){
+            return r;
+        }else {
+            info=(LuckyBagCollectRecord)r.get("info");
+        }
+        // 查询福袋信息
+        LuckyBag luckyBag = luckyBagMapper.selectLuckyBagById(record.getLuckyBagId());
+        if(luckyBag==null){
+            log.warn("未找到对应的福袋信息 [luckyBagId:{}]", record.getLuckyBagId());
+            return R.error().put("msg","未找到对应的福袋信息");
+        }
+        if(luckyBag.getStatus()==0){
+            log.warn("该福袋已下架 [luckyBagId:{}]", record.getLuckyBagId());
+            return R.error().put("msg","该福袋已下架");
+        }
+        if(luckyBag.getDataStatus().equals("0")){ // 禁用
+            log.warn("该福袋已禁用 [luckyBagId:{}]", record.getLuckyBagId());
+            return R.error().put("msg","该福袋已禁用");
+        }
+
+        // 获取方法币数量
+        Long coinAmount ;
+        if("1".equals(luckyBag.getType())){ // 定值
+            coinAmount= luckyBag.getAmount().longValue();
+        }else {
+            coinAmount =findIntegral(luckyBag.getActualRewards());
+        }
+
+        // 登记日志 有ClickHouse 不支持回滚
+        Long balance = user.getIntegral()+coinAmount;
+
+        FsUserIntegralLogs fsUserIntegralLogs = new FsUserIntegralLogs();
+        fsUserIntegralLogs.setUserId(userId);
+        fsUserIntegralLogs.setLogType(30); // 福袋获取获得芳华币
+        fsUserIntegralLogs.setIntegral(coinAmount);
+        fsUserIntegralLogs.setPhone(user.getPhone());
+        fsUserIntegralLogs.setBalance(balance);
+        fsUserIntegralLogs.setCreateTime(new Date());
+        fsUserIntegralLogs.setNickName(user.getNickName());
+        //写入积分日志
+        fsUserIntegralLogsService.insertFsUserIntegralLogs(fsUserIntegralLogs);
+
+        //给用户增加积分
+        FsUser updateUser = new FsUser();
+        updateUser.setUserId(userId);
+        updateUser.setIntegral(balance);
+        userMapper.updateFsUser(updateUser);
+
+        // 更新状态
+        LuckyBagCollectRecord recordUpdate = new LuckyBagCollectRecord();
+        recordUpdate.setId(info.getId());
+        recordUpdate.setCollectType("1");
+        recordUpdate.setCollectTime(new Date());
+        recordUpdate.setUpdateTime(new Date());
+        recordUpdate.setCoinAmount(BigDecimal.valueOf(coinAmount));
+        if(StringUtils.isBlank(info.getUserName())){
+            recordUpdate.setUserName(user.getNickName());
+        }
+        if(info.getUserId()==null){
+            recordUpdate.setUserId(userId);
+            recordUpdate.setUserName(user.getNickName());
+        }else if(info.getUserId()==0){// 有用户id为0的数据需要处理
+            recordUpdate.setUserId(userId);
+        }
+        // 个人领取
+        luckyBagCollectRecordMapper.updateLuckyBagCollectRecord(recordUpdate);
+        if(record.getRewardType()==1L){ // 群福袋 两条记录
+            recordUpdate.setId(record.getId()); // 群福袋
+            recordUpdate.setCollectType(""); // 状态不更新
+            recordUpdate.setUserId(null);
+            recordUpdate.setUserName("");
+            luckyBagCollectRecordMapper.updateLuckyBagCollectRecord(recordUpdate);
+        }
+
+        Map<String,Object> map = new HashMap<>();
+        map.put("balance",balance);
+        map.put("coinAmount",coinAmount);
+        return R.ok().put("data",map);
+    }
+
+    /**
+     * @Description: 是否领取成功
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/21 13:58
+     */
+    @Override
+    public R getLuckyBagInfoByRecordId(Long recordId) {
+
+        LuckyBagCollectRecord record = luckyBagCollectRecordMapper.selectLuckyBagCollectRecordById(recordId);
+        if(record==null){
+            return R.error().put("msg","未找到该福袋信息");
+        }
+        Map<String,Object> map = new HashMap<>();
+        map.put("collectType",record.getCollectType());// 领取状态(0-已发放 1-已领取 2-已失效)
+        if(record.getExpiryTime().before(new Date())){
+            map.put("isExpiry",false); // 失效
+        }else {
+            map.put("isExpiry",true);
+        }
+        return R.ok().put("data",map);
+    }
+
+    /**
+     * @Description: 校验信息,判断是否可以领取
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/21 9:09
+     */
+    private R checkRecordParam(LuckyBagCollectRecord record,FsReceiveLuckyBagParam param) {
+
+        //未注册提示
+//        String noRegisterMsg = "由于您还未完成注册,请联系伴学助手完成注册即可观看!";
+        // 校验用户信息
+        if(record==null){
+            log.error("未找到该福袋信息");
+            return R.error().put("msg","未找到该福袋信息");
+        }
+
+        LuckyBagCollectRecord info;
+        if(record.getRewardType()==1L){// 群福袋
+            // 根据 关联id 和 userId 查询领取记录
+            info = luckyBagCollectRecordMapper.selectLuckyBagCollectRecordByRelationId(record.getId(), param.getUserId());
+            // 判断是否群成员 是的话生成一条记录
+            if(info==null){
+                if(record.getExpiryTime().before(DateUtils.getNowDate())){
+                    log.error("该福袋已失效");
+                    return R.error().put("msg","该福袋已失效");
+                }
+                QwGroupChat qwGroupChat = qwGroupChatMapper.selectQwGroupChatByChatId(record.getChatId());
+                if(qwGroupChat == null){
+                    log.error("未查询到该群信息");
+                    return R.error().put("msg","未查询到该群信息");
+                }
+                SopUserLogsInfo sopUserLogsInfo =  new SopUserLogsInfo();
+                sopUserLogsInfo.setChatId(record.getChatId());
+                List<QwGroupChatUser> qwGroupChatUsers = qwGroupChatUserMapper.selectByChatId(sopUserLogsInfo);
+                if(qwGroupChatUsers == null || qwGroupChatUsers.isEmpty()){
+                    log.error("SOP任务群参数异常");
+                    return R.error().put("msg","SOP任务群参数异常");
+                }
+                QwExternalContact qwExternalContact =
+                        qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+                                .eq("user_id", qwGroupChat.getOwner())
+                                .eq("fs_user_id", param.getUserId())
+                                .eq("corp_id", param.getCorpId())
+                                .eq("status",0));
+                if(qwExternalContact==null){
+                    log.error("客户企微QwExternalContact未绑定fsUserId,{}",param.getUserId());
+                    return R.error().put("msg","客户未注册");
+                }
+                if(qwGroupChatUsers.stream().noneMatch(e -> e.getUserId().equals(qwExternalContact.getExternalUserId()))){
+                    log.error("客户不在群:{},里面:{}", qwGroupChat.getChatId(), qwExternalContact.getExternalUserId());
+                    return  R.error().put("msg","客户不在群");
+                }
+
+                info= BeanCopyUtils.copy(record, LuckyBagCollectRecord.class);
+                assert info != null;
+                info.setId(null);
+                info.setUserId(param.getUserId());
+                info.setUserName(param.getUserName());
+                info.setRelationId(param.getRecordId());
+                luckyBagCollectRecordMapper.insertLuckyBagCollectRecord(info);
+            }else {
+                log.error("该用户已领取过福袋");
+                return R.error().put("msg","该用户已领取过福袋");
+            }
+
+        }else {// 个人福袋
+            // 校验用户信息 没有领取过的不校验,谁领取到福袋就是谁的
+            if(record.getUserId()!=null && record.getUserId()!=0L && !Objects.equals(record.getUserId(), param.getUserId())){
+                log.error("专属福袋,用户id不一致record.getUserId:{},param.getUserId:{}", record.getUserId(), param.getUserId());
+                return R.error().put("msg","专属福袋,用户id不一致");
+            }
+            info=record;
+        }
+
+        if("1".equals(info.getCollectType())){
+            log.error("该用户已领取过福袋");
+            return R.error().put("msg","该用户已领取过福袋");
+        }
+
+        // 判断福袋是否失效
+        if("2".equals(info.getCollectType())){
+            log.error("该福袋已失效");
+            return  R.error().put("msg","该福袋已失效");
+        }
+        if(record.getExpiryTime().before(DateUtils.getNowDate())){
+            // 更新福袋状态失效
+            LuckyBagCollectRecord updateRecord = new LuckyBagCollectRecord();
+            updateRecord.setId(info.getId());
+            updateRecord.setCollectType("2"); // 已失效
+            luckyBagCollectRecordMapper.updateLuckyBagCollectRecord(updateRecord);
+            if(record.getRewardType()==1L){// 群福袋
+                updateRecord.setId(info.getRelationId());
+                luckyBagCollectRecordMapper.updateLuckyBagCollectRecord(updateRecord);
+            }
+            log.error("该福袋已失效");
+            return R.error().put("msg","该福袋已失效");
+        }
+
+        // 检查次数限制
+        // 动态计算时间范围
+        LuckyBagCollectRecord luckyBagCollectRecord = new LuckyBagCollectRecord();
+        luckyBagCollectRecord.setUserId(param.getUserId());
+        luckyBagCollectRecord.setCollectType("1");// 已领取
+        luckyBagCollectRecord.setCompanyUserId(record.getCompanyUserId());
+        LocalDate endDate = LocalDate.now();
+        LocalDate startDate = endDate.minusDays(6); // 包含今天
+        Map<String, Object> params = new HashMap<>();
+        params.put("beginSendTime", startDate.toString());
+        params.put("endSendTime", endDate.toString());
+        luckyBagCollectRecord.setParams(params);
+        List<LuckyBagCollectRecord> luckyBagCollectRecords= luckyBagCollectRecordMapper.selectLuckyBagCollectRecordList(luckyBagCollectRecord);
+        int recordCount = luckyBagCollectRecords != null ? luckyBagCollectRecords.size() : 0;
+
+        Integer maxCount;
+        // 查询福袋领取数量
+        // 查询福袋配置项
+        SysConfig config = sysConfigService.selectConfigByConfigKey("luckyBag.config");
+        if (config == null || StringUtils.isEmpty(config.getConfigValue())) {
+            log.warn("未找到有效的系统配置 [configKey: luckyBag.config]");
+            throw new ServiceException("系统配置不存在或无效");
+        }
+        try {
+            Map<String, Object> configMap = JSONObject.parseObject(config.getConfigValue(), Map.class);
+            Object maxCountObj = configMap.get("weekLimit");
+            if (maxCountObj == null) {
+                log.warn("系统配置中缺少 weekLimit 参数");
+                throw new ServiceException("系统配置缺失 weekLimit 参数");
+            }
+            maxCount = Integer.parseInt(maxCountObj.toString());
+            // 继续后续逻辑处理...
+        } catch (NumberFormatException e) {
+            log.error("解析 weekLimit 配置失败: {}", e.getMessage());
+            throw new ServiceException("系统配置 weekLimit 格式错误");
+        }
+        if(recordCount>=maxCount){
+            log.error("单个客服每周(7天)给同客户发送数量超过次数限制");
+            return R.error().put("msg","单个客服每周(7天)给同客户发送数量超过次数限制");
+        }
+
+        return R.ok().put("info", info);
+    }
+
+    private void checkParam(LuckyBag reward) {
+        String type = reward.getType();
+        if ("1".equals(type)) {
+            BigDecimal amount = reward.getAmount();
+            if (amount == null && amount.compareTo(BigDecimal.ZERO) == 0) {
+                // amount不为null且不为0的逻辑处理
+                throw new ServiceException("定值不能为空");
+            }
+        }
+        if ("2".equals(type)) {
+            List<LuckyBagActualRewardsParam> actualRewardsParams = JSONArray.parseArray(reward.getActualRewards(), LuckyBagActualRewardsParam.class);
+            if (actualRewardsParams.isEmpty()) {
+                throw new ServiceException("配置不能为空");
+            }
+        }
+    }
+
+    /**
+     * @Description: 算法规则 copy from 天降宝箱规则
+     * @Param:
+     * @Return:
+     * @Author yfh
+     * @Date 2025/11/20 17:05
+     */
+    private Long findIntegral(String listString) {
+        List<Map> items = JSONObject.parseArray(listString, Map.class);
+
+        // 根据probability概率随机选择一个项
+        Map<String, Object> selectedItem = new HashMap<>();
+
+        // 1. 提取并转换概率值
+        List<Double> probabilities = new ArrayList<>();
+        double totalProbability = 0.0;
+
+        for (Map item : items) {
+            String probStr = (String) item.get("probability");
+            // 移除百分号并转换为小数
+            double prob = Double.parseDouble(probStr.replace("%", "")) / 100.0;
+            probabilities.add(prob);
+            totalProbability += prob;
+        }
+
+        // 2. 验证概率总和(应该是1.0,即100%)
+        if (Math.abs(totalProbability - 1.0) > 0.0001) {
+            for (int i = 0; i < probabilities.size(); i++) {
+                probabilities.set(i, probabilities.get(i) / totalProbability);
+            }
+        }
+
+        // 3. 生成随机数并选择
+        double random = Math.random();
+        double cumulativeProbability = 0.0;
+
+        for (int i = 0; i < probabilities.size(); i++) {
+            cumulativeProbability += probabilities.get(i);
+            if (random <= cumulativeProbability) {
+                selectedItem = items.get(i);
+                break;
+            }
+        }
+
+        return Long.parseLong(selectedItem.get("amount").toString());
+    }
+
+}

+ 8 - 0
fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java

@@ -125,6 +125,14 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
 
 
         //app显示标题 app用的参数
         //app显示标题 app用的参数
         private String title;
         private String title;
+
+        //福袋id
+        private Long luckyBagId;
+
+        /**
+         * 业务id
+         */
+        private String businessId;
         @Override
         @Override
         public Setting clone() {
         public Setting clone() {
             try {
             try {

+ 311 - 6
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.config.FSSysConfig;
 import com.fs.common.config.FSSysConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
@@ -18,10 +19,7 @@ import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
-import com.fs.course.domain.FsCourseDomainName;
-import com.fs.course.domain.FsCourseLink;
-import com.fs.course.domain.FsCourseRealLink;
-import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.domain.*;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
 import com.fs.course.mapper.FsCourseLinkMapper;
 import com.fs.course.mapper.FsCourseLinkMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
@@ -30,6 +28,8 @@ import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.fastGpt.domain.FastGptChatReplaceWords;
 import com.fs.fastGpt.domain.FastGptChatReplaceWords;
 import com.fs.fastGpt.mapper.FastGptChatReplaceWordsMapper;
 import com.fs.fastGpt.mapper.FastGptChatReplaceWordsMapper;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
 import com.fs.live.domain.LiveWatchLog;
 import com.fs.live.domain.LiveWatchLog;
 import com.fs.live.mapper.LiveWatchLogMapper;
 import com.fs.live.mapper.LiveWatchLogMapper;
 import com.fs.qw.domain.*;
 import com.fs.qw.domain.*;
@@ -61,6 +61,8 @@ import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.fs.sop.vo.QwCreateLinkByAppVO;
 import com.fs.sop.vo.QwCreateLinkByAppVO;
 import com.fs.sop.vo.SopUserLogsInfoVOE;
 import com.fs.sop.vo.SopUserLogsInfoVOE;
 import com.fs.sop.vo.SopUserLogsVo;
 import com.fs.sop.vo.SopUserLogsVo;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.fs.voice.utils.StringUtil;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
@@ -91,7 +93,9 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String appRealLink = "/pages/courseAnswer/index?link=";
     private static final String appRealLink = "/pages/courseAnswer/index?link=";
+    private static final String appActivitlLink = "/pages_course/activity.html?link=";
     private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
     private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
+    private static final String registeredRealLink = "/pages_course/register.html?link=";
 //    private static final String miniappRealLink = "/pages/index/index?course=";
 //    private static final String miniappRealLink = "/pages/index/index?course=";
 
 
     @Autowired
     @Autowired
@@ -175,6 +179,15 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     @Autowired
     @Autowired
     LiveWatchLogMapper liveWatchLogMapper;
     LiveWatchLogMapper liveWatchLogMapper;
 
 
+    @Autowired
+    private LuckyBagMapper luckyBagMapper;
+
+    @Autowired
+    private LuckyBagCollectRecordMapper luckyBagCollectRecordMapper;
+
+    @Autowired
+    private FsUserMapper fsUserMapper;
+
 
 
 
 
     @Override
     @Override
@@ -1321,7 +1334,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
             switch (finalSendType){
             switch (finalSendType){
                 case 5:
                 case 5:
                     List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,
                     List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,
-                            contact,dataTime, finalDomainName,miniMap,companies);
+                            contact,dataTime, finalDomainName,miniMap,companies,sopLogs);
                     setting.setSetting(list);
                     setting.setSetting(list);
                     break;
                     break;
                 case 9:
                 case 9:
@@ -1385,7 +1398,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                                                       CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
                                                                       CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
                                                                       QwExternalContact contact,Date dataTime,String domainName,
                                                                       QwExternalContact contact,Date dataTime,String domainName,
                                                                       Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
                                                                       Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
-                                                                      List<Company> companies ){
+                                                                      List<Company> companies,QwSopLogs sopLogs ){
         List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
         List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
 
 
         for (QwSopCourseFinishTempSetting.Setting st : list) {
         for (QwSopCourseFinishTempSetting.Setting st : list) {
@@ -1512,6 +1525,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     }
                     }
 
 
                     break;
                     break;
+
                 //直播小程序单独
                 //直播小程序单独
                 case "12":
                 case "12":
                     String sortLiveLink;
                     String sortLiveLink;
@@ -1540,6 +1554,124 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     }
                     }
 
 
                     break;
                     break;
+                case "15":
+                    //app语音
+                    try {
+                        qwSop = qwSopMapper.selectQwSopById(param.getSopId());
+                        createVoiceUrl(st, companyUserId, qwSop);
+                        if (qwUser.getCompanyUserId() != null) {
+                            createVoiceUrlToIm(st, String.valueOf(qwUser.getCompanyUserId()), qwSop);
+                        }
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    break;
+                case "16":
+                    //app文本
+                    String txt = StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText();
+                    st.setValue(st.getValue()
+                            .replaceAll("#客服称呼#", txt)
+                            .replaceAll("#销售称呼#", txt)
+                            .replaceAll("#客户称呼#", StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus()) ? "同学" : contact.getStageStatus()));
+                    try {
+                        replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    break;
+                case "14":
+                    LuckyBag luckyBag = luckyBagMapper.selectLuckyBagById(st.getLuckyBagId());
+                    if(ObjectUtil.isNotEmpty(luckyBag)&&luckyBag.getDataStatus().equals("0")){
+                        sopLogs.setSendStatus(5L);
+                        sopLogs.setReceivingStatus(0L);
+                        sopLogs.setRemark("福袋配置被禁用");
+                    }else
+                    if (ObjectUtil.isNotEmpty(sopLogs.getFsUserId())){
+                        //获取配置并校验
+                        SysConfig luckBagConfig = configService.selectConfigByConfigKey("luckyBag.config");
+                        if (ObjectUtil.isEmpty(luckBagConfig)) {
+                            sopLogs.setSendStatus(5L);
+                            sopLogs.setReceivingStatus(0L);
+                            sopLogs.setRemark("福袋配置不存在");
+                        }
+                        // 2. 解析配置值
+                        JSONObject jsonObject;
+                        try {
+                            jsonObject = JSON.parseObject(luckBagConfig.getConfigValue());
+                            Integer count = jsonObject.getInteger("weekLimit");
+
+                            // 查询用户记录并校验次数
+                            LuckyBagCollectRecord queryRecord = new LuckyBagCollectRecord();
+                            queryRecord.setUserId(sopLogs.getFsUserId());
+                            queryRecord.setCollectType("1");
+                            // 动态计算时间范围
+                            LocalDate endDate = LocalDate.now();
+                            LocalDate startDate = endDate.minusDays(6); // 包含今天
+
+                            Map<String, Object> params = new HashMap<>();
+                            params.put("beginSendTime", startDate.toString());
+                            params.put("endSendTime", endDate.toString());
+                            queryRecord.setParams(params);
+                            List<LuckyBagCollectRecord> luckyBagCollectRecords =
+                                    luckyBagCollectRecordMapper.selectLuckyBagCollectRecordList(queryRecord);
+
+                            // 判断是否超过限制
+                            if (luckyBagCollectRecords.size() >= count) {
+                                sopLogs.setSendStatus(5L);
+                                sopLogs.setReceivingStatus(0L);
+                                sopLogs.setRemark("超过福袋发放次数");
+                            }
+
+                        } catch (Exception e) {
+                            // 处理配置解析异常
+                            sopLogs.setSendStatus(5L);
+                            sopLogs.setReceivingStatus(0L);
+                            sopLogs.setRemark("福袋配置解析失败");
+                        }
+                    }
+
+                    linkByMiniApp = createActivityLinkByMiniApp(st,sopLogs, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
+                            String.valueOf(qwUser.getId()), companyUserId, companyId, item.getExternalId(), config,null);
+
+                    miniAppId = null;
+
+                    if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                        Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                        if (integerListMap != null) {
+                            effectiveGrade = (item.getGrade() == null) ? 5 : item.getGrade();
+                            listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
+
+                            //评级是6 S级,则走A类小程序
+                            if (effectiveGrade==6){
+                                listIndex=2;
+                            }
+
+                            List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);
+
+                            if (miniapps != null && !miniapps.isEmpty()) {
+                                CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                    miniAppId = companyMiniapp.getAppId();
+                                }
+                            }
+                        }
+                    }
+
+                    if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
+                        miniAppId = qwCompany.getMiniAppId();
+                    }
+
+                    if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
+                        st.setMiniprogramAppid(miniAppId);
+                    } else {
+                        log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
+                    }
+
+                    st.setMiniprogramTitle("福袋发放");
+
+                    st.setMiniprogramPage(linkByMiniApp);
+                    break;
+
                 default:
                 default:
                     break;
                     break;
 
 
@@ -1549,6 +1681,134 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return  list;
         return  list;
     }
     }
 
 
+    public String createActivityLinkByMiniApp(QwSopCourseFinishTempSetting.Setting st, QwSopLogs sopLogs, String corpId, Date sendTime, Integer courseId, Integer videoId, String qwUserId, String companyUserId, String companyId, Long externalId, CourseConfig config, String chatId) {
+        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, Long.valueOf(qwUserId),
+                companyUserId, companyId, null, 3, chatId);
+        Date updateTime = createUpdateTime(st, sendTime, config);
+        link.setUpdateTime(updateTime);
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+        Long businessId = addLuckyBagCollectRecord(st,sopLogs,updateTime,companyUserId,companyId,chatId);
+        courseMap.setBusinessId(String.valueOf(businessId));
+        st.setBusinessId(String.valueOf(businessId));
+        st.setExternalUserId(sopLogs.getExternalUserId());
+        String json = configService.selectConfigByKey("luckyBag.config");
+        Map<String, Object> luckyBagConfig = JSON.parseObject(json, Map.class);
+        Object miniprogramPicUrl = luckyBagConfig.get("miniprogramPicUrl");
+        if(miniprogramPicUrl != null){
+            st.setMiniprogramPicUrl(miniprogramPicUrl.toString());
+        }
+        courseMap.setQwExternalId(sopLogs.getExternalId());
+        String realLinkFull = appActivitlLink + JSON.toJSONString(courseMap);
+        link.setRealLink(realLinkFull);
+        log.error("存入fs_course_link:" + registeredRealLink );
+        log.error("QwSopCourseFinishTempSetting.Setting:{}" ,st );
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+        return link.getRealLink();
+    }
+
+    /**
+     * 增加福袋发放记录、领取记录
+     *
+     * @param content
+     * @param qwSopLogs
+     * @param sendTime
+     * @param companyUserId
+     * @param companyId
+     * @param chatId
+     */
+    private Long addLuckyBagCollectRecord(QwSopCourseFinishTempSetting.Setting content,
+                                          QwSopLogs qwSopLogs,
+                                          Date sendTime,
+                                          String companyUserId,
+                                          String companyId,
+                                          String chatId) {
+        try {
+            // 参数校验
+            if (content == null || qwSopLogs == null || sendTime == null) {
+                log.warn("添加福袋记录失败:必要参数为空 [content:{}, qwSopLogs:{}, sendTime:{}]",
+                        content, qwSopLogs, sendTime);
+                return null;
+            }
+
+            if (StringUtils.isEmpty(companyId) || StringUtils.isEmpty(companyUserId)) {
+                log.warn("公司ID或用户ID为空 [companyId:{}, companyUserId:{}]", companyId, companyUserId);
+                return null;
+            }
+
+            // 验证福袋ID
+            if (content.getLuckyBagId() == null) {
+                log.warn("福袋ID为空");
+                return null;
+            }
+
+            // 查询福袋信息
+            LuckyBag luckyBag = luckyBagMapper.selectLuckyBagById(content.getLuckyBagId());
+            if (luckyBag == null) {
+                log.warn("未找到对应的福袋信息 [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            // 检查福袋状态
+            if (luckyBag.getDataStatus() != null && luckyBag.getDataStatus().equals(0)) {
+                log.warn("福袋被禁用 [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            // 查询公司信息
+            Company company = companyMapper.selectCompanyById(Long.valueOf(companyId));
+            if (company == null) {
+                log.warn("未找到对应的公司信息 [companyId:{}]", companyId);
+                return null;
+            }
+
+            // 构建福袋记录
+            LuckyBagCollectRecord luckyBagCollectRecord = buildLuckyBagRecord(content, qwSopLogs, sendTime,
+                    companyUserId, companyId, chatId, company, luckyBag);
+
+            // 插入记录并返回ID
+            int result = luckyBagCollectRecordMapper.insertLuckyBagCollectRecord(luckyBagCollectRecord);
+            if (result <= 0) {
+                log.warn("福袋记录插入失败 [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            // 返回新增记录的ID
+            Long recordId = luckyBagCollectRecord.getId();
+            if (recordId == null) {
+                log.warn("福袋记录插入成功但未返回ID [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            log.info("福袋记录添加成功 [recordId:{}, luckyBagId:{}]", recordId, content.getLuckyBagId());
+            return recordId;
+
+        } catch (NumberFormatException e) {
+            log.error("ID转换失败 [companyId:{}, companyUserId:{}]", companyId, companyUserId, e);
+            return null;
+        } catch (Exception e) {
+            log.error("ID:" + (content != null ? content.getLuckyBagId() : "unknown") + "-添加福袋记录失败", e);
+            return null;
+        }
+    }
+
+    private void createVoiceUrlToIm(QwSopCourseFinishTempSetting.Setting st, String companyUserId, QwSop qwSop) {
+        QwSopTempVoice qwSopTempVoice = sopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(Long.valueOf(companyUserId), st.getValue());
+        if (qwSopTempVoice != null && qwSopTempVoice.getVoiceUrl() != null && qwSopTempVoice.getRecordType() == 1) {
+            st.setVoiceUrl(qwSopTempVoice.getUserVoiceUrl());
+            st.setVoiceDuration(String.valueOf(qwSopTempVoice.getDuration()));
+        } else if (qwSopTempVoice == null) {
+            if(st.getValue() != null){
+                qwSopTempVoice = new QwSopTempVoice();
+                qwSopTempVoice.setCompanyUserId(Long.valueOf(companyUserId));
+                qwSopTempVoice.setVoiceTxt(st.getValue());
+                qwSopTempVoice.setRecordType(0);
+                sopTempVoiceService.insertQwSopTempVoice(qwSopTempVoice);
+            }
+        }
+    }
+
     private List<QwSopCourseFinishTempSetting.Setting> parseSettings(String jsonData) {
     private List<QwSopCourseFinishTempSetting.Setting> parseSettings(String jsonData) {
         try {
         try {
             if (jsonData.startsWith("[") && jsonData.endsWith("]")) {
             if (jsonData.startsWith("[") && jsonData.endsWith("]")) {
@@ -1829,4 +2089,49 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
 
     }
     }
 
 
+    /**
+     * 构建福袋记录对象
+     */
+    private LuckyBagCollectRecord buildLuckyBagRecord(QwSopCourseFinishTempSetting.Setting content,
+                                                      QwSopLogs qwSopLogs,
+                                                      Date sendTime,
+                                                      String companyUserId,
+                                                      String companyId,
+                                                      String chatId,
+                                                      Company company,
+                                                      LuckyBag luckyBag) {
+        LuckyBagCollectRecord record = new LuckyBagCollectRecord();
+        QwUser qwUser = qwUserMapper.selectQwUserEntityByQwUserIdAndCorId(qwSopLogs.getQwUserid(),qwSopLogs.getCorpId());
+        record.setQwUserId(qwUser.getQwUserId());
+        record.setQwUserName(qwUser.getQwUserName());
+        record.setLuckyBagId(content.getLuckyBagId());
+        record.setExpiryTime(sendTime);
+        record.setCollectType("3");
+        record.setCompanyId(Long.valueOf(companyId));
+        record.setUserId(qwSopLogs.getFsUserId());
+        if (ObjectUtil.isNotEmpty(qwSopLogs.getFsUserId())){
+            FsUser fsUser = fsUserMapper.selectFsUserByUserId(qwSopLogs.getFsUserId());
+            record.setUserName(ObjectUtil.isNotEmpty(fsUser)?fsUser.getNickName():null);
+        }
+        record.setCompanyName(company.getCompanyName());
+        record.setCompanyUserId(Long.valueOf(companyUserId));
+        record.setSendLink(content.getMiniprogramPage());
+
+        // 设置奖励类型和聊天信息
+        if (StringUtils.isNotEmpty(chatId)) {
+            record.setRewardType(1L);
+            record.setChatId(chatId);
+            record.setExternalUserName(qwSopLogs.getExternalUserName());
+        } else {
+            record.setRewardType(2L);
+        }
+
+        // 设置币种金额
+        if (luckyBag.getRewardType() != null && luckyBag.getRewardType().equals("1")) {
+            record.setCoinAmount(luckyBag.getAmount());
+        }
+
+        return record;
+    }
+
 }
 }

+ 194 - 0
fs-service/src/main/resources/mapper/qw/LuckyBagCollectRecordMapper.xml

@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.qw.mapper.LuckyBagCollectRecordMapper">
+
+    <resultMap type="LuckyBagCollectRecord" id="LuckyBagCollectRecordResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="userName"    column="user_name"    />
+        <result property="rewardType"    column="reward_type"    />
+        <result property="luckyBagId"    column="lucky_bag_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyName"    column="company_name"    />
+        <result property="coinAmount"    column="coin_amount"    />
+        <result property="sendTime"    column="send_time"    />
+        <result property="collectTime"    column="collect_time"    />
+        <result property="expiryTime"    column="expiry_time"    />
+        <result property="collectType"    column="collect_type"    />
+        <result property="externalUserName"    column="external_user_name"    />
+        <result property="chatId"    column="chat_id"    />
+        <result property="relationId"    column="relation_id"    />
+        <result property="sendLink"    column="send_link"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="qwUserId"    column="qw_user_id"    />
+        <result property="qwUserName"    column="qw_user_name"    />
+    </resultMap>
+
+    <sql id="selectLuckyBagCollectRecordVo">
+        select id, user_id, user_name, reward_type, lucky_bag_id, company_user_id, company_id, company_name, coin_amount, send_time, collect_time, expiry_time, collect_type, external_user_name, chat_id, relation_id, send_link, update_time, create_time,qw_user_id, qw_user_name from lucky_bag_collect_record
+    </sql>
+
+    <select id="selectLuckyBagCollectRecordList" parameterType="LuckyBagCollectRecord" resultMap="LuckyBagCollectRecordResult">
+        select
+        r.id,r.user_id,r.user_name,r.reward_type,r.lucky_bag_id,r.company_user_id,r.company_id,r.company_name,r.coin_amount,r.send_time,r.collect_time,r.expiry_time,r.collect_type,r.external_user_name,r.chat_id,r.relation_id,r.send_link,r.update_time,r.create_time,r.qw_user_id,r.qw_user_name,
+        cu.user_name as companyUserName,
+        b.name as luckyBagName
+        from lucky_bag_collect_record r
+        left join lucky_bag b
+        on r.lucky_bag_id = b.id
+        left join company_user cu
+        on r.company_user_id = cu.user_id
+        <where>
+            <if test="userId != null "> and r.user_id = #{userId}</if>
+            <if test="userName != null  and userName != ''"> and r.user_name like concat('%', #{userName}, '%')</if>
+            <if test="rewardType != null "> and r.reward_type = #{rewardType}</if>
+            <if test="luckyBagId != null "> and r.lucky_bag_id = #{luckyBagId}</if>
+            <if test="companyUserId != null "> and r.company_user_id = #{companyUserId}</if>
+            <if test="companyId != null "> and r.company_id = #{companyId}</if>
+            <if test="companyName != null  and companyName != ''"> and r.company_name like concat('%', #{companyName}, '%')</if>
+            <if test="coinAmount != null "> and r.coin_amount = #{coinAmount}</if>
+             <if test="params.beginSendTime != null and params.endSendTime != null">and r.send_time between concat(#{params.beginSendTime}, ' 00:00:00') and concat(#{params.endSendTime}, ' 23:59:59')</if>
+            <if test="params.beginCollectTime != null and params.endCollectTime != null">and r.collect_time between concat(#{params.beginCollectTime}, ' 00:00:00') and concat(#{params.endCollectTime}, ' 23:59:59')</if>
+            <if test="params.beginExpiryTime != null and params.endExpiryTime != null">and r.expiry_time between concat(#{params.beginExpiryTime}, ' 00:00:00') and concat(#{params.endExpiryTime}, ' 23:59:59')</if>
+            <if test="collectType != null  and collectType != ''"> and r.collect_type = #{collectType}</if>
+            <if test="externalUserName != null  and externalUserName != ''"> and r.external_user_name like concat('%', #{externalUserName}, '%')</if>
+            <if test="chatId != null  and chatId != ''"> and r.chat_id = #{chatId}</if>
+            <if test="relationId != null "> and r.relation_id = #{relationId}</if>
+            <if test="sendLink != null  and sendLink != ''"> and r.send_link = #{sendLink}</if>
+            <if test="qwUserName != null  and qwUserName != ''"> and r.qw_user_name like concat('%', #{qwUserName}, '%')</if>
+        </where>
+        order by r.send_time desc,r.lucky_bag_id desc
+    </select>
+
+    <select id="selectLuckyBagCollectRecordById" parameterType="Long" resultMap="LuckyBagCollectRecordResult">
+        <include refid="selectLuckyBagCollectRecordVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectLuckyBagCollectRecordByRelationId"
+            resultType="com.fs.course.domain.LuckyBagCollectRecord">
+        <include refid="selectLuckyBagCollectRecordVo"/>
+        where relation_id = #{relationId} and user_id = #{userId} limit 1
+    </select>
+
+
+    <insert id="insertBagCollectRecord" parameterType="FsAppContactWay" useGeneratedKeys="true" keyProperty="id">
+        INSERT INTO lucky_bag_collect_record
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="luckyBagId != null">lucky_bag_id,</if>
+            <if test="sendTime != null">send_time,</if>
+            <if test="collectTime != null">collect_time,</if>
+            <if test="expiryTime != null">expiry_time,</if>
+            <if test="collectType != null and collectType != ''">collect_type,</if>
+            <if test="externalUserName != null and externalUserName != ''">external_user_name,</if>
+            <if test="chatId != null and chatId != ''">chat_id,</if>
+            <if test="sendLink != null and sendLink != ''">send_link,</if>
+        </trim>
+        <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
+            <if test="luckyBagId != null">#{luckyBagId},</if>
+            <if test="sendTime != null">#{sendTime},</if>
+            <if test="collectTime != null">#{collectTime},</if>
+            <if test="expiryTime != null">#{expiryTime},</if>
+            <if test="collectType != null and collectType != ''">#{collectType},</if>
+            <if test="externalUserName != null and externalUserName != ''">#{externalUserName},</if>
+            <if test="chatId != null and chatId != ''">#{chatId},</if>
+            <if test="sendLink != null and sendLink != ''">#{sendLink},</if>
+        </trim>
+    </insert>
+
+
+    <insert id="insertLuckyBagCollectRecord" parameterType="LuckyBagCollectRecord" useGeneratedKeys="true" keyProperty="id">
+        insert into lucky_bag_collect_record
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="userName != null">user_name,</if>
+            <if test="rewardType != null">reward_type,</if>
+            <if test="luckyBagId != null">lucky_bag_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyName != null">company_name,</if>
+            <if test="coinAmount != null">coin_amount,</if>
+            <if test="sendTime != null">send_time,</if>
+            <if test="collectTime != null">collect_time,</if>
+            <if test="expiryTime != null">expiry_time,</if>
+            <if test="collectType != null">collect_type,</if>
+            <if test="externalUserName != null">external_user_name,</if>
+            <if test="chatId != null">chat_id,</if>
+            <if test="relationId != null">relation_id,</if>
+            <if test="sendLink != null">send_link,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="qwUserId != null">qw_user_id,</if>
+            <if test="qwUserName != null">qw_user_name,</if>
+
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="userName != null">#{userName},</if>
+            <if test="rewardType != null">#{rewardType},</if>
+            <if test="luckyBagId != null">#{luckyBagId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyName != null">#{companyName},</if>
+            <if test="coinAmount != null">#{coinAmount},</if>
+            <if test="sendTime != null">#{sendTime},</if>
+            <if test="collectTime != null">#{collectTime},</if>
+            <if test="expiryTime != null">#{expiryTime},</if>
+            <if test="collectType != null">#{collectType},</if>
+            <if test="externalUserName != null">#{externalUserName},</if>
+            <if test="chatId != null">#{chatId},</if>
+            <if test="relationId != null">#{relationId},</if>
+            <if test="sendLink != null">#{sendLink},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="qwUserId != null">#{qwUserId},</if>
+            <if test="qwUserName != null">#{qwUserName},</if>
+         </trim>
+    </insert>
+
+    <update id="updateLuckyBagCollectRecord" parameterType="LuckyBagCollectRecord">
+        update lucky_bag_collect_record
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="userName != null">user_name = #{userName},</if>
+            <if test="rewardType != null">reward_type = #{rewardType},</if>
+            <if test="luckyBagId != null">lucky_bag_id = #{luckyBagId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyName != null">company_name = #{companyName},</if>
+            <if test="coinAmount != null">coin_amount = #{coinAmount},</if>
+            <if test="sendTime != null">send_time = #{sendTime},</if>
+            <if test="collectTime != null">collect_time = #{collectTime},</if>
+            <if test="expiryTime != null">expiry_time = #{expiryTime},</if>
+            <if test="collectType != null">collect_type = #{collectType},</if>
+            <if test="externalUserName != null">external_user_name = #{externalUserName},</if>
+            <if test="chatId != null">chat_id = #{chatId},</if>
+            <if test="relationId != null">relation_id = #{relationId},</if>
+            <if test="sendLink != null">send_link = #{sendLink},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
+            <if test="qwUserName != null">qw_user_name = #{qwUserName},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteLuckyBagCollectRecordById" parameterType="Long">
+        delete from lucky_bag_collect_record where id = #{id}
+    </delete>
+
+    <delete id="deleteLuckyBagCollectRecordByIds" parameterType="String">
+        delete from lucky_bag_collect_record where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <update id="updateLuckyBagExpiryStatus">
+        update lucky_bag_collect_record set collect_type = 2 where expiry_time &lt;= NOW()  and collect_type != 1
+    </update>
+
+</mapper>

+ 84 - 0
fs-service/src/main/resources/mapper/qw/LuckyBagMapper.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.qw.mapper.LuckyBagMapper">
+
+    <insert id="insertLuckyBag" parameterType="LuckyBag" useGeneratedKeys="true" keyProperty="id">
+        insert into lucky_bag
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null and name != ''">name,</if>
+            <if test="type != null">type,</if>
+            <if test="status != null">status,</if>
+            <if test="createId != null">create_id,</if>
+            <if test="updateId != null">update_id,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="actualRewards != null and actualRewards != ''">actual_rewards,</if>
+            <if test="createName != null and createName != ''">create_name,</if>
+            <if test="companyId != null and companyId != ''">company_id,</if>
+            <if test="amount != null and amount != ''">amount,</if>
+            <if test="dataStatus != null and dataStatus != ''">data_status,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null and name != ''">#{name},</if>
+            <if test="type != null">#{type},</if>
+            <if test="status != null">#{status},</if>
+            <if test="createId != null">#{createId},</if>
+            <if test="updateId != null">#{updateId},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="actualRewards != null and actualRewards != ''">#{actualRewards},</if>
+            <if test="createName != null and createName != ''">#{createName},</if>
+            <if test="companyId != null and companyId != ''">#{companyId},</if>
+            <if test="amount != null and amount != ''">#{amount},</if>
+            <if test="dataStatus != null and dataStatus != ''">#{dataStatus},</if>
+        </trim>
+    </insert>
+    <update id="updateLuckyBag" parameterType="LuckyBag">
+        UPDATE lucky_bag
+        <set>
+            <if test="name != null and name != ''">name = #{name},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="createId != null">create_id = #{createId},</if>
+            <if test="updateId != null">update_id = #{updateId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="actualRewards != null and actualRewards != ''">actual_rewards = #{actualRewards},</if>
+            <if test="createName != null and createName != ''">create_name = #{createName},</if>
+            <if test="companyId != null and companyId != ''">company_id = #{companyId},</if>
+            <if test="amount != null">amount = #{amount},</if>
+            <if test="dataStatus != null and dataStatus != ''">data_status=#{dataStatus},</if>
+        </set>
+        WHERE id = #{id}
+    </update>
+    <update id="deleteLuckyBagByIds">
+        UPDATE lucky_bag SET status = '0' WHERE id IN
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+    <sql id="selectLuckyBagVo">
+        select id, name, type,status, create_id,update_id, create_time, update_time, actual_rewards,company_id,amount,data_status from lucky_bag
+    </sql>
+    <select id="selectLuckyBagList" resultType="com.fs.course.domain.LuckyBag">
+        <include refid="selectLuckyBagVo"/>
+        <where>
+            and status='1'
+            <if test="companyId != null and companyId != ''">and company_id = #{companyId}</if>
+            <if test="id != null "> and id = #{id}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="createId != null "> and create_id = #{createId}</if>
+            <if test="dataStatus != null and dataStatus != ''">and data_status=#{dataStatus}</if>
+        </where>
+        order by id desc
+    </select>
+    <select id="selectLuckyBagById" resultType="com.fs.course.domain.LuckyBag">
+        <include refid="selectLuckyBagVo"/>
+        where id = #{id}
+    </select>
+
+
+
+</mapper>