Explorar o código

授权红包----》1.好友欢迎语 2.一键群发 3.SOP

wjj hai 10 horas
pai
achega
208c1c12b0

+ 311 - 1
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -1,42 +1,61 @@
 package com.fs.app.service;
 
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.service.ICompanyMiniappService;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
 import com.fs.ipad.IpadSendUtils;
 import com.fs.ipad.vo.*;
+import com.fs.qw.domain.BindPhoneRedPacketRecord;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUserVideo;
+import com.fs.qw.domain.RedPacket;
+import com.fs.qw.mapper.BindPhoneRedPacketRecordMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.service.IQwUserVideoService;
+import com.fs.qw.service.IRedPacketService;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qwApi.param.QwExternalContactHParam;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.service.IQwSopLogsService;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
+import com.fs.system.service.ISysConfigService;
 import com.fs.wxwork.dto.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @Slf4j
 @Service
 @AllArgsConstructor
 public class IpadSendServer {
-
+    private static final Pattern LINK_PATTERN = Pattern.compile("link=([^&]+)");
     private final QwUserMapper qwUserMapper;
     private final IQwUserService qwUserService;
     private final IpadSendUtils ipadSendUtils;
@@ -47,6 +66,21 @@ public class IpadSendServer {
     private final RedisCache redisCache;
     private final ICompanyMiniappService companyMiniappService;
 
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private IRedPacketService redPacketService;
+
+    @Autowired
+    private BindPhoneRedPacketRecordMapper bindPhoneRedPacketRecordMapper;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Autowired
+    private FsUserMapper fsUserMapper;
+
     //private final LiveWatchLogMapper liveWatchLogMapper;
 
 
@@ -507,6 +541,31 @@ public class IpadSendServer {
                     // 语音
                     sendWxVideo(vo, content);
                     break;
+                case "14":
+                    log.info("===============进入授权手机号红包=============");
+                    // 记录授权手机号红包发送记录
+                    RedPacket redPacket = redPacketService.selectRedPacketById(content.getRedPacketId());
+                    if (ObjectUtil.isNotEmpty(redPacket) && redPacket.getStatus().equals("0")) {
+                        qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(),"手机号授权红包已禁用");
+                    } else if (ObjectUtil.isNotEmpty(qwSopLogs.getFsUserId())) {
+                        //查询用户领取记录
+                        BindPhoneRedPacketRecord record = new BindPhoneRedPacketRecord();
+                        record.setUserId(qwSopLogs.getFsUserId());
+                        record.setCollectType("1");
+                        List<BindPhoneRedPacketRecord> records = bindPhoneRedPacketRecordMapper.selectBindPhoneRedPacketRecordList(record);
+                        if (ObjectUtil.isNotEmpty(records)) {
+                            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(),"用户已领取过手机号授权红包");
+                        }
+                    }
+                    try{
+                        Long businessId = addRedPacketCollectRecord(redPacket,qwUser, content,qwSopLogs);
+                        content.setMiniprogramPage(quickProcess(content.getMiniprogramPage(),businessId));
+                        //手机号授权红包
+                        sendMiniProgram(vo, content, miniMap,qwUser.getCompanyId());
+                    }catch (Exception e){
+                        qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "手机号授权红包发放失败,请重新发送!");
+                    }
+                    break;
                 case "21":
                     content.setSendStatus(0);
                     content.setSendRemarks("短信待发送");
@@ -523,6 +582,257 @@ public class IpadSendServer {
         }
     }
 
+    public Long addRedPacketCollectRecord(RedPacket redPacket, QwUser qwUser, QwSopCourseFinishTempSetting.Setting content, QwSopLogs qwSopLogs) {
+
+        try{
+            String json = configService.selectConfigByKey("course.config");
+            CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+            Date updateTime = createUpdateTime(content, new Date(), config);
+            String companyUserId = String.valueOf(qwUser.getCompanyUserId()).trim();
+            String companyId = String.valueOf(qwUser.getCompanyId()).trim();
+            Long businessId = addRedPacketCollectRecord(qwUser,redPacket,content,qwSopLogs,updateTime,companyUserId,companyId,content.getChatId());
+            return businessId;
+        }catch (Exception e){
+            log.error("授权手机号红包创建失败:qwUser={},qwSopLogs={}",qwUser,qwSopLogs);
+            return null;
+        }
+    }
+
+    /**
+     * 优化版快速处理方法
+     */
+    public static String quickProcess(String miniprogramPage, Long businessId) {
+        if (miniprogramPage == null || businessId == null) {
+            return miniprogramPage;
+        }
+
+        try {
+            Matcher matcher = LINK_PATTERN.matcher(miniprogramPage);
+            if (matcher.find()) {
+                String encodedLink = matcher.group(1);
+
+                // 第一次URL解码
+                String decodedLink = java.net.URLDecoder.decode(encodedLink, "UTF-8");
+
+                // 处理多次转义的情况:如果解码后仍有转义字符,继续解码
+                String jsonStr = decodedLink;
+                while (jsonStr.contains("\\\"") || jsonStr.contains("\\\\")) {
+                    // 检查是否是合法的JSON格式
+                    if (jsonStr.trim().startsWith("{") && jsonStr.trim().endsWith("}")) {
+                        break; // 已经是JSON对象字符串,不需要再解码
+                    }
+                    // 尝试再次解码
+                    try {
+                        jsonStr = java.net.URLDecoder.decode(jsonStr, "UTF-8");
+                    } catch (Exception e) {
+                        // 如果解码失败,说明不是URL编码,跳出循环
+                        break;
+                    }
+                }
+
+                // 清理JSON字符串中的转义字符
+                jsonStr = cleanJsonString(jsonStr);
+
+                // 解析JSON
+                JSONObject linkJson = JSON.parseObject(jsonStr);
+
+                // 检查并添加businessId
+                if (!linkJson.containsKey("businessId") ||
+                        linkJson.getString("businessId") == null ||
+                        linkJson.getString("businessId").isEmpty()) {
+
+                    linkJson.put("businessId", businessId);
+
+                    // 重新编码(只编码一次)
+                    String updatedJson = linkJson.toJSONString();
+                    String updatedEncoded = java.net.URLEncoder.encode(updatedJson, "UTF-8");
+
+                    // 替换原link参数
+                    return miniprogramPage.replace(
+                            "link=" + encodedLink,
+                            "link=" + updatedEncoded
+                    );
+                }
+            }
+            return miniprogramPage;
+        } catch (Exception e) {
+            // 记录错误日志,这里可以替换为你的日志框架
+            System.err.println("处理小程序页面链接失败: " + e.getMessage());
+            e.printStackTrace();
+            // 根据业务需求,可以选择抛出异常或返回原字符串
+            // throw new RuntimeException("处理小程序页面链接失败", e);
+            return miniprogramPage; // 失败时返回原字符串,避免影响主流程
+        }
+    }
+
+    /**
+     * 清理JSON字符串中的多余转义
+     */
+    private static String cleanJsonString(String jsonStr) {
+        if (jsonStr == null || jsonStr.isEmpty()) {
+            return jsonStr;
+        }
+
+        String result = jsonStr;
+
+        // 移除多余的转义
+        result = result.replace("\\\"", "\"");
+        result = result.replace("\\\\", "\\");
+
+        // 处理开头和结尾的转义引号
+        if (result.startsWith("\"") && result.endsWith("\"")) {
+            result = result.substring(1, result.length() - 1);
+        }
+
+        return result;
+    }
+
+    /**
+     * 过期时间
+     *
+     * @param setting
+     * @param sendTime
+     * @param config
+     * @return
+     */
+    private Date createUpdateTime(QwSopCourseFinishTempSetting.Setting setting, Date sendTime, CourseConfig config) {
+
+        Integer expireDays = (setting.getExpiresDays() == null || setting.getExpiresDays() == 0)
+                ? config.getVideoLinkExpireDate()
+                : setting.getExpiresDays();
+
+//         使用 Java 8 时间 API 计算过期时间
+        LocalDateTime sendDateTime = sendTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        LocalDateTime expireDateTime = sendDateTime.plusDays(expireDays - 1);
+        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
+        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
+
+        return updateTime;
+    }
+
+    /**
+     * 增加授权手机号红包发放记录、领取记录
+     *
+     * @param companyId
+     * @param qwUser
+     * @param redPacket
+     * @param content
+     * @param qwSopLogs
+     * @param sendTime
+     * @param companyUserId
+     * @param chatId
+     */
+    private Long addRedPacketCollectRecord(QwUser qwUser, RedPacket redPacket, QwSopCourseFinishTempSetting.Setting content,
+                                          QwSopLogs qwSopLogs,
+                                          Date sendTime,
+                                          String companyUserId,
+                                          String companyId,
+                                          String chatId) {
+        try {
+            // 参数校验
+            if (content == null || qwSopLogs == null || sendTime == null) {
+                log.error("添加授权手机号红包记录失败:必要参数为空 [content:{}, qwSopLogs:{}, sendTime:{}]",
+                        content, qwSopLogs, sendTime);
+                return null;
+            }
+
+            // 验证授权手机号红包ID
+            if (content.getRedPacketId() == null) {
+                log.error("授权手机号红包ID为空");
+                return null;
+            }
+
+            // 查询授权手机号红包信息
+            if (redPacket == null) {
+                log.error("未找到对应的授权手机号红包信息 [luckyBagId:{}]", content.getRedPacketId());
+                return null;
+            }
+
+            // 检查授权手机号红包状态
+            if (redPacket.getStatus().equals("0")) {
+                log.error("授权手机号红包被禁用 [luckyBagId:{}]", content.getRedPacketId());
+                return null;
+            }
+
+            // 查询公司信息
+            Company company = (Company)redisCache.getCacheObject("redPacketCompanyId:"+companyId);
+            if (company == null) {
+                company = companyMapper.selectCompanyById(Long.valueOf(companyId));
+                redisCache.setCacheObject("redPacketCompanyId:"+companyId, company, 1 , TimeUnit.DAYS);
+                log.error("未找到对应的公司信息 [companyId:{}]", companyId);
+            }
+
+            // 构建授权手机号红包记录
+            BindPhoneRedPacketRecord bindPhoneRedPacketRecord = buildRePacketRecord(qwUser, content, qwSopLogs, sendTime,
+                    companyUserId, companyId, chatId, company, redPacket);
+            bindPhoneRedPacketRecord.setSendTime(new Date());
+            bindPhoneRedPacketRecord.setCollectType("0");
+            // 插入记录并返回ID
+            int result = bindPhoneRedPacketRecordMapper.insertBindPhoneRedPacketRecord(bindPhoneRedPacketRecord);
+            if (result <= 0) {
+                log.error("授权手机号红包记录插入失败 [luckyBagId:{}]", content.getRedPacketId());
+                return null;
+            }
+
+            // 返回新增记录的ID
+            Long recordId = bindPhoneRedPacketRecord.getId();
+            if (recordId == null) {
+                log.error("授权手机号红包记录插入成功但未返回ID [luckyBagId:{}]", content.getRedPacketId());
+                return null;
+            }
+
+            log.info("授权手机号红包记录添加成功 [recordId:{}, luckyBagId:{}]", recordId, content.getRedPacketId());
+            return recordId;
+
+        } catch (NumberFormatException e) {
+            log.error("ID转换失败 [companyId:{}, companyUserId:{}]", companyId, companyUserId, e);
+            return null;
+        } catch (Exception e) {
+            log.error("ID:" + (content != null ? content.getRedPacketId() : "unknown") + "-添加授权手机号红包记录失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 构建授权手机号红包记录对象
+     */
+    private BindPhoneRedPacketRecord buildRePacketRecord(QwUser qwUser,QwSopCourseFinishTempSetting.Setting content,
+                                                      QwSopLogs qwSopLogs,
+                                                      Date sendTime,
+                                                      String companyUserId,
+                                                      String companyId,
+                                                      String chatId,
+                                                      Company company,
+                                                      RedPacket redPacket) {
+        BindPhoneRedPacketRecord record = new BindPhoneRedPacketRecord();
+        record.setQwUserId(qwUser.getQwUserId());
+        record.setQwUserName(qwUser.getQwUserName());
+        record.setRedPacketId(content.getRedPacketId());
+        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);
+        }
+
+        record.setAmount(redPacket.getAmount());
+
+        return record;
+    }
+
     public void loginOut(QwUser user) {
         ipadSendUtils.loginOut(user.getUid(), user.getServerId());
     }

+ 68 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -80,6 +80,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
+    private static final String appActivityLink = "/pages_course/luckybag.html?link=";
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String appRealLink = "/pages/courseAnswer/index?link=";
     private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
@@ -1133,6 +1134,15 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         setting.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
                     }
 
+                    break;
+                case "14" :
+                    //授权手机号红包
+                    String linkBy = createActivityLinkByMiniApp(setting, sopLogs, sopLogs.getCorpId(), new Date(), courseId, videoId
+                            , qwUserId, companyUserId, companyId, cachedCourseConfig, logVo.getChatId());
+                    setting.setMiniprogramAppid(miniAppId);
+                    setting.setMiniprogramTitle("手机授权");
+                    setting.setMiniprogramPage(linkBy);
+                    setting.setContentType("14");
                     break;
                 case "21"://短信看课
                     if (sopLogs.getFsUserId() != null && !Long.valueOf(0L).equals(sopLogs.getFsUserId())) {
@@ -2294,4 +2304,62 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private boolean isValidExternalContact(QwExternalContact externalContact) {
         return externalContact.getStatus() == 0 || externalContact.getStatus() == 2 || externalContact.getStatus() == 3;
     }
+
+
+    public String createActivityLinkByMiniApp(QwSopTempSetting.Content.Setting st, QwSopLogs sopLogs, String corpId, Date sendTime, Long courseId, Long videoId, String qwUserId, String companyUserId, String companyId, CourseConfig config, String chatId) {
+
+        FsCourseLink link = createActivityByLink(corpId, sendTime, courseId, videoId, qwUserId.toString(),
+                companyUserId, companyId, null, 3);
+        link.setChatId(chatId);
+
+        Date updateTime = createUpdateTime(st, sendTime, config);
+        link.setUpdateTime(updateTime);
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        st.setExternalUserId(sopLogs.getExternalUserId());
+        st.setChatId(chatId);
+        String json = configService.selectConfigByKey("phoneRedPacket.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 = appActivityLink + JSON.toJSONString(courseMap);
+        link.setRealLink(realLinkFull);
+
+        //存短链-
+        enqueueCourseLink(link);
+        return link.getRealLink();
+    }
+
+    public FsCourseLink createActivityByLink(String corpId, Date sendTime, Long courseId, Long videoId, String qwUserId,
+                                             String companyUserId, String companyId, String externalId, Integer type) {
+        // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(Long.parseLong(companyId));
+        link.setQwUserId(Long.parseLong(qwUserId));
+        link.setCompanyUserId(Long.parseLong(companyUserId));
+        link.setVideoId(videoId);
+        link.setCorpId(corpId);
+        link.setCourseId(courseId);
+        link.setQwExternalId(StringUtils.isNotEmpty(externalId)?Long.parseLong(externalId):null);
+        link.setLinkType(type); //小程序
+        link.setUNo(UUID.randomUUID().toString()); //小程序
+
+        String randomString = generateRandomStringWithLock();
+        if (StringUtil.strIsNullOrEmpty(randomString)) {
+            link.setLink(UUID.randomUUID().toString().replace("-", ""));
+        } else {
+            link.setLink(randomString);
+        }
+
+        link.setCreateTime(sendTime);
+
+        return link;
+    }
 }

+ 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)")
     private String projectCode;
+
+    /**
+     * 业务id
+     */
+    private String businessId;
 }

+ 174 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -2,6 +2,7 @@ package com.fs.qw.service.impl;
 
 
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONException;
@@ -12,7 +13,11 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.service.ICompanyConfigService;
+import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.FsCourseRealLink;
 import com.fs.course.domain.FsCourseSop;
 import com.fs.course.domain.FsCourseSopLogs;
 import com.fs.course.domain.FsCourseWatchLog;
@@ -52,6 +57,7 @@ import com.fs.qwApi.domain.inner.*;
 import com.fs.qwApi.param.*;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.domain.QwSop;
+import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.domain.SopUserLogs;
 import com.fs.sop.domain.SopUserLogsInfo;
 import com.fs.sop.mapper.QwSopLogsMapper;
@@ -104,6 +110,8 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
     private static final String miniappRealLink = "/pages_course/video.html?course=";
 
+    private static final String appActivityLink = "/pages_course/luckybag.html?link=";
+
     @Autowired
     private AsyncQwAiChatSopService asyncQwAiChatSopService;
 
@@ -217,6 +225,15 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     @Autowired
     private FsUserInformationCollectionMapper fsUserInformationCollectionMapper;
 
+    @Autowired
+    private RedPacketMapper redPacketMapper;
+
+    @Autowired
+    private BindPhoneRedPacketRecordMapper bindPhoneRedPacketRecordMapper;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
 
     Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -3772,11 +3789,168 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                 }
             }
 
+            if ("redPacket".equals(att.getMsgtype())) {
+                //授权红包
+                log.error("====授权红包进入====== 参数:{}",att.getMsgtype());
+                att.setMsgtype("miniprogram");
+                try {
+                    String mediaId =(String)redisCache.getCacheObject("phoneRedPacket:"+corpId);
+                    if (!StringUtil.strIsNullOrEmpty(mediaId)) {
+                        log.error("数据进入mediaId={},corpId={}",mediaId,corpId);
+                        att.setMiniprogram(new SendWelcomeMsgParam.Attachment.MiniProgramAttachment());
+                        att.getMiniprogram().setAppid(qwCompany.getMiniAppId());
+                        att.getMiniprogram().setPic_media_id(mediaId);
+                        att.getMiniprogram().setTitle("手机授权");
+                        //新增授权手机号红包发放记录
+                        String course = configService.selectConfigByKey("course.config");
+                        CourseConfig config = JSON.parseObject(course, CourseConfig.class);
+                        LocalDateTime sendDateTime = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+                        LocalDateTime expireDateTime = sendDateTime.plusDays(config.getVideoLinkExpireDate() - 1);
+                        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
+                        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
+                        log.error("开始记录时间={}",updateTime);
+                        FsCourseRealLink courseMap = new FsCourseRealLink();
+                        String json = configService.selectConfigByKey("phoneRedPacket.config");
+                        Map<String, Object> luckyBagConfig = JSON.parseObject(json, Map.class);
+                        Object miniprogramPicUrl = luckyBagConfig.get("miniprogramPicUrl");
+                        log.error("进入到增加记录中》》》》》》》》》》");
+                        Long businessId = addRedPacketCollectRecord(att.getRedPacket().getId(), miniprogramPicUrl.toString(), qwUser, null, updateTime, String.valueOf(qwUser.getCompanyUserId()), String.valueOf(qwUser.getCompanyId()));
+                        log.error("增加成功》》》》》》》》》》={}",businessId);
+                        courseMap.setBusinessId(String.valueOf(businessId));
+                        courseMap.setCompanyId(qwUser.getCompanyId());
+                        courseMap.setCompanyUserId(qwUser.getCompanyUserId());
+                        courseMap.setQwExternalId(qwExternalId);
+                        courseMap.setCorpId(corpId);
+                        courseMap.setQwUserId(Long.valueOf(String.valueOf(qwUser.getId())));
+                        String linkUrl = appActivityLink + JSON.toJSONString(courseMap);
+
+                        if (!StringUtil.strIsNullOrEmpty(linkUrl)) {
+                            att.getMiniprogram().setPage(linkUrl);
+                        }
+                    } else {
+                        logger.error("查到课程相关信息:"+corpId+":"+att.getMiniprogram().getCourseId());
+                    }
+
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    logger.error("欢迎语生成手机号授权红包消息失败:"+e.getMessage()+"|"+corpId+"|"+att.getMiniprogram().getCourseId());
+                }
+            }
+
         });
 
         return attachments;
     }
 
+    /**
+     * 增加授权手机号红包发放记录、领取记录
+     *
+     * @param companyId
+     * @param qwUser
+     * @param sendTime
+     * @param companyUserId
+     */
+    private Long addRedPacketCollectRecord(Long redPacketId, String miniprogramPicUrl,
+                                           QwUser qwUser,
+                                           Long userId,
+                                           Date sendTime,
+                                           String companyUserId,
+                                           String companyId) {
+        try {
+            if (StringUtils.isEmpty(companyId) || StringUtils.isEmpty(companyUserId)) {
+                log.error("公司ID或用户ID为空 [companyId:{}, companyUserId:{}]", companyId, companyUserId);
+                return null;
+            }
+
+            // 验证授权手机号红包ID
+            if (redPacketId == null) {
+                log.error("授权手机号红包ID为空");
+                return null;
+            }
+
+            RedPacket redPacket = redPacketMapper.selectRedPacketById(redPacketId);
+            // 查询授权手机号红包信息
+            if (redPacket == null) {
+                log.error("未找到对应的授权手机号红包信息 [luckyBagId:{}]", redPacketId);
+                return null;
+            }
+
+            // 检查授权手机号红包状态
+            if (redPacket.getStatus().equals("0")) {
+                log.error("授权手机号红包被禁用 [luckyBagId:{}]", redPacketId);
+                return null;
+            }
+            // 查询公司信息
+            Company company = companyMapper.selectCompanyById(Long.valueOf(companyId));
+            if (company == null) {
+                log.error("未找到对应的公司信息 [companyId:{}]", companyId);
+                return null;
+            }
+
+
+
+            // 构建授权手机号红包记录
+            BindPhoneRedPacketRecord bindPhoneRedPacketRecord = buildRePacketRecord(redPacketId, miniprogramPicUrl,qwUser,userId,sendTime,
+                    companyUserId, companyId,  company, redPacket);
+            bindPhoneRedPacketRecord.setSendTime(new Date());
+            // 插入记录并返回ID
+            int result = bindPhoneRedPacketRecordMapper.insertBindPhoneRedPacketRecord(bindPhoneRedPacketRecord);
+            if (result <= 0) {
+                log.error("授权手机号红包记录插入失败 [luckyBagId:{}]", redPacketId);
+                return null;
+            }
+
+            // 返回新增记录的ID
+            Long recordId = bindPhoneRedPacketRecord.getId();
+            if (recordId == null) {
+                log.error("授权手机号红包记录插入成功但未返回ID [luckyBagId:{}]", redPacketId);
+                return null;
+            }
+
+            log.info("授权手机号红包记录添加成功 [recordId:{}, luckyBagId:{}]", recordId, redPacketId);
+            return recordId;
+
+        } catch (NumberFormatException e) {
+            log.error("ID转换失败 [companyId:{}, companyUserId:{}]", companyId, companyUserId, e);
+            return null;
+        } catch (Exception e) {
+            log.error("ID:" + (redPacketId != null ? redPacketId : "unknown") + "-添加授权手机号红包记录失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 构建授权手机号红包记录对象
+     */
+    private BindPhoneRedPacketRecord buildRePacketRecord(Long redPacketId,String miniprogramPage,
+                                                         QwUser qwUser,
+                                                         Long userId,
+                                                         Date sendTime,
+                                                         String companyUserId,
+                                                         String companyId,
+                                                         Company company,
+                                                         RedPacket redPacket) {
+        BindPhoneRedPacketRecord record = new BindPhoneRedPacketRecord();
+        record.setQwUserId(qwUser.getQwUserId());
+        record.setQwUserName(qwUser.getQwUserName());
+        record.setRedPacketId(redPacketId);
+        record.setCollectType("0");
+        record.setSendTime(new Date());
+        record.setCompanyId(Long.valueOf(companyId));
+        record.setUserId(userId);
+        if (ObjectUtil.isNotEmpty(userId)){
+            FsUser fsUser = fsUserMapper.selectFsUserByUserId(userId);
+            record.setUserName(ObjectUtil.isNotEmpty(fsUser)?fsUser.getNickName():null);
+        }
+        record.setCompanyName(company.getCompanyName());
+        record.setCompanyUserId(Long.valueOf(companyUserId));
+        record.setSendLink(miniprogramPage);
+        record.setRewardType(2L);
+        record.setAmount(redPacket.getAmount());
+
+        return record;
+    }
+
     //添加watchLog记录
     private void addWatchLogIfNeeded(Integer videoId, Integer courseId,
                                      String qwUserId, String companyUserId,

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

@@ -112,6 +112,9 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
         // 原因
         private String sendRemarks;
 
+        //授权红包id
+        private Long redPacketId;
+
         // 短信CODE
         private String smsTemplateCode;
 
@@ -128,6 +131,11 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
          */
         private String smsTemplateContent;
 
+        /**
+         * 群id
+         */
+        private String chatId;
+
         @Override
         public Setting clone() {
             try {

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

@@ -150,6 +150,9 @@ public class QwSopTempSetting implements Serializable{
             //app显示标题 app用的参数
             private String title;
 
+            //授权红包id
+            private Long redPacketId;
+
             // 短信CODE
             private String smsTemplateCode;
 
@@ -166,6 +169,11 @@ public class QwSopTempSetting implements Serializable{
              */
             private String smsTemplateContent;
 
+            /**
+             * 群id
+             */
+            private String chatId;
+
 
             @Override
             public Setting clone() {

+ 8 - 0
fs-service/src/main/java/com/fs/qwApi/param/SendWelcomeMsgParam.java

@@ -21,6 +21,14 @@ public class SendWelcomeMsgParam {
         private MiniProgramAttachment miniprogram; // 小程序附件详情
         private VideoAttachment video; // 视频附件详情
         private FileAttachment file; // 文件附件详情
+
+        private RedPacketAttachment redPacket; // 文件附件详情
+        @Data
+        // 内部类,用于图片附件
+        public static class RedPacketAttachment {
+            private Long id; // 授权手机号红包id
+            private Long name; // 授权手机号红包名称
+        }
         @Data
         // 内部类,用于图片附件
         public static class ImageAttachment {

+ 38 - 0
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -85,6 +85,7 @@ import static com.fs.course.utils.LinkUtil.generateRandomStringWithLock;
 @Service
 public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
+    private static final String appActivityLink = "/pages_course/luckybag.html?link=";
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
     private static final String miniappRealLink = "/pages_course/video.html?course=";
@@ -952,6 +953,14 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
                             }
 
+                            break;
+                        case "14":
+                            String appId = qwCompany.getMiniAppId();
+                            linkByMiniApp = createActivityLinkByMiniApp(st,sopLogs, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                    qwUserId, companyUserId, companyId, config,null);
+                            st.setMiniprogramAppid(appId);
+                            st.setMiniprogramTitle("手机授权");
+                            st.setMiniprogramPage(linkByMiniApp);
                             break;
                         case "21":
                             if (sopLogs.getFsUserId() != null && !Long.valueOf(0L).equals(sopLogs.getFsUserId())) {
@@ -1803,5 +1812,34 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
     }
 
+    public String createActivityLinkByMiniApp(QwSopCourseFinishTempSetting.Setting st, QwSopLogs sopLogs, String corpId, Date sendTime, Integer courseId, Integer videoId, String qwUserId, String companyUserId, String companyId,  CourseConfig config, String chatId) {
+        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, Long.parseLong(qwUserId),
+                companyUserId, companyId, null, 3, chatId);
+
+        Date updateTime = createUpdateTime(st, sendTime, config);
+        link.setUpdateTime(updateTime);
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        st.setExternalUserId(sopLogs.getExternalUserId());
+        st.setChatId(chatId);
+
+        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 = appActivityLink + JSON.toJSONString(courseMap);
+        link.setRealLink(realLinkFull);
+        log.error("存入fs_course_link:" + registeredRealLink );
+        log.error("QwSopCourseFinishTempSetting.Setting:{}" ,st );
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+        return link.getRealLink();
+    }
+
 
 }