Ver Fonte

1.提交济世百康浏览器看课、直播功能

jzp há 1 semana atrás
pai
commit
599a8154ed
48 ficheiros alterados com 1471 adições e 44 exclusões
  1. 7 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  2. 91 0
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  3. 236 2
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  4. 2 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  5. 3 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java
  6. 73 0
      fs-service/src/main/java/com/fs/course/dto/FsCourseLinkDTO.java
  7. 62 0
      fs-service/src/main/java/com/fs/course/dto/FsLiveLinkDTO.java
  8. 8 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseLinkMapper.java
  9. 1 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  10. 12 0
      fs-service/src/main/java/com/fs/course/param/FsCourseEncryptLinkParam.java
  11. 20 0
      fs-service/src/main/java/com/fs/course/param/FsCourseH5ListParam.java
  12. 8 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java
  13. 5 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseWatchLogService.java
  14. 112 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  15. 25 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  16. 35 0
      fs-service/src/main/java/com/fs/course/vo/FsSopMyCourseH5LinkVO.java
  17. 23 0
      fs-service/src/main/java/com/fs/course/vo/FsSopMyLiveH5LinkVO.java
  18. 17 0
      fs-service/src/main/java/com/fs/his/param/FsUserInfoParam.java
  19. 3 0
      fs-service/src/main/java/com/fs/live/domain/Live.java
  20. 2 0
      fs-service/src/main/java/com/fs/live/mapper/LiveMapper.java
  21. 0 1
      fs-service/src/main/java/com/fs/live/mapper/LiveVideoMapper.java
  22. 10 0
      fs-service/src/main/java/com/fs/live/param/FsLiveEncryptLinkParam.java
  23. 21 0
      fs-service/src/main/java/com/fs/live/param/FsLiveH5ListParam.java
  24. 8 0
      fs-service/src/main/java/com/fs/live/service/ILiveService.java
  25. 70 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java
  26. 4 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  27. 2 0
      fs-service/src/main/java/com/fs/qw/service/IQwUserService.java
  28. 5 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java
  29. 8 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java
  30. 243 0
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  31. 42 9
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatisSalerWatchServiceImpl.java
  32. 5 4
      fs-service/src/main/resources/application-config-druid-hcl.yml
  33. 3 2
      fs-service/src/main/resources/application-config-druid-hzyy.yml
  34. 99 0
      fs-service/src/main/resources/application-config-druid-jsbk.yml
  35. 5 4
      fs-service/src/main/resources/application-config-druid-jzzx.yml
  36. 3 2
      fs-service/src/main/resources/application-config-druid-qdtst.yml
  37. 3 2
      fs-service/src/main/resources/application-config-druid-sczy.yml
  38. 3 4
      fs-service/src/main/resources/application-druid-qdtst.yml
  39. 10 0
      fs-service/src/main/resources/mapper/course/FsCourseLinkMapper.xml
  40. 9 0
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  41. 9 0
      fs-service/src/main/resources/mapper/live/LiveMapper.xml
  42. 4 0
      fs-service/src/main/resources/mapper/live/LiveVideoMapper.xml
  43. 11 0
      fs-service/src/main/resources/mapper/qw/QwUserMapper.xml
  44. 12 0
      fs-service/src/main/resources/mapper/sop/QwSopLogsMapper.xml
  45. 42 0
      fs-user-app/src/main/java/com/fs/app/controller/CourseController.java
  46. 40 0
      fs-user-app/src/main/java/com/fs/app/controller/UserController.java
  47. 35 14
      fs-user-app/src/main/java/com/fs/app/controller/live/LiveController.java
  48. 20 0
      fs-user-app/src/main/java/com/fs/app/param/FsUserInfoParam.java

+ 7 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java

@@ -300,4 +300,11 @@ public class QwSopLogsController extends BaseController
     {
         return linkService.getWxaCodeGenerateScheme(param.getLinkStr(), param.getAppId());
     }
+
+    @PreAuthorize("@ss.hasPermi('qw:sopLogs:liveGenerate')")
+    @PostMapping("/generateLiveShortLink")
+    public R generateLiveShortLink(@RequestBody GenerateShortLinkParam param)
+    {
+        return linkService.getLiveWxaCodeGenerateScheme(param.getLinkStr(), param.getAppId());
+    }
 }

+ 91 - 0
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -17,6 +17,7 @@ import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.his.domain.FsUser;
@@ -78,6 +79,7 @@ public class IpadSendServer {
     @Autowired
     private LuckyBagCollectRecordMapper luckyBagCollectRecordMapper;
 
+    private final IFsCourseLinkService linkService;
 
     private static final List<String> PROJECT_NAMES = Arrays.asList("济南联志健康", "北京存在文化","宽益堂");
     private final LiveWatchLogMapper liveWatchLogMapper;
@@ -705,6 +707,18 @@ public class IpadSendServer {
                         qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "福袋发放失败,请重新发送!");
                     }
                     sendMiniProgram(vo, content, miniMap, qwUser.getCompanyId());
+                case "17":
+                    // 小程序H5看课
+                    sendMiniProgram(vo, content, miniMap);
+                    break;
+                case "18":
+                    // 发送直播卡片
+                    sendLiveMiniProgram(vo, content, miniMap);
+                    break;
+                case "19":
+                    // 发送直播短链
+                    sendLiveShortLink(vo, content, miniMap);
+                    break;
                 case "99":
                     // 群发
                     sendTxtAtMsg(vo);
@@ -720,6 +734,83 @@ public class IpadSendServer {
         }
     }
 
+    /**
+     * 发送直播短链
+     * @param vo
+     * @param content
+     * @param miniMap
+     */
+    private void sendLiveShortLink(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap) {
+        FsCoursePlaySourceConfig courseMaConfig = miniMap.get(content.getMiniprogramAppid());
+        String miniProgramPage = content.getMiniprogramPage();
+        miniProgramPage = miniProgramPage.replace(".html","");
+        String link = linkService.getGotoWxAppLink(miniProgramPage, courseMaConfig.getAppid());
+
+        TxtVo txtVo = TxtVo.builder().content(link).build();
+        txtVo.setBase(vo);
+        WxWorkResponseDTO<WxWorkSendTextMsgRespDTO> resp = ipadSendUtils.sendTxt(txtVo);
+        if (resp.getErrcode() != 0) {
+            log.debug("ID:{}-ipad接口请求返回异常:{}", vo.getId(), resp.getErrmsg());
+            content.setSendStatus(2);
+            content.setSendRemarks("发送失败:" + resp.getErrmsg());
+        }
+    }
+
+    /**
+     * 发送直播卡片
+     * @param vo
+     * @param content
+     * @param miniMap
+     */
+    private void sendLiveMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap) {
+        FsCoursePlaySourceConfig courseMaConfig = miniMap.get(content.getMiniprogramAppid());
+        // 小程序
+        MiniProgramVo miniProgramVo = MiniProgramVo.builder()
+                .desc(content.getMiniprogramTitle().replaceFirst("-.*", ""))
+                .title(courseMaConfig.getName())
+                .weappIconUrl(courseMaConfig.getImg())
+                .imgUrl(content.getMiniprogramPicUrl())
+                .username(courseMaConfig.getOriginalId() + "@app")
+                .pagepath(content.getMiniprogramPage())
+                .appid(content.getMiniprogramAppid())
+                .build();
+        miniProgramVo.setBase(vo);
+        WxWorkResponseDTO<WxWorkSendAppMsgRespDTO> resp = ipadSendUtils.sendMiniProgram(miniProgramVo);
+        if (resp.getErrcode() != 0) {
+            log.debug("ID:{}-ipad接口请求返回异常:{}", vo.getId(), resp.getErrmsg());
+            content.setSendStatus(2);
+            content.setSendRemarks("发送失败:" + resp.getErrmsg());
+        }
+
+    }
+
+    /**
+     * 发送看课H5
+     * @param vo
+     * @param content
+     * @param miniMap
+     */
+    private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content,Map<String, FsCoursePlaySourceConfig> miniMap) {
+        FsCoursePlaySourceConfig courseMaConfig = miniMap.get(content.getMiniprogramAppid());
+        // 小程序
+        MiniProgramVo miniProgramVo = MiniProgramVo.builder()
+                .desc(content.getMiniprogramTitle().replaceFirst("-.*", ""))
+                .title(courseMaConfig.getName())
+                .weappIconUrl(courseMaConfig.getImg())
+                .imgUrl(content.getMiniprogramPicUrl())
+                .username(courseMaConfig.getOriginalId() + "@app")
+                .pagepath(content.getMiniprogramPage())
+                .appid(content.getMiniprogramAppid())
+                .build();
+        miniProgramVo.setBase(vo);
+        WxWorkResponseDTO<WxWorkSendAppMsgRespDTO> resp = ipadSendUtils.sendMiniProgram(miniProgramVo);
+        if (resp.getErrcode() != 0) {
+            log.debug("ID:{}-ipad接口请求返回异常:{}", vo.getId(), resp.getErrmsg());
+            content.setSendStatus(2);
+            content.setSendRemarks("发送失败:" + resp.getErrmsg());
+        }
+    }
+
     public void loginOut(QwUser user) {
         ipadSendUtils.loginOut(user.getUid(), user.getServerId());
     }

+ 236 - 2
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -89,6 +89,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private static final String appActivitlLink = "/pages_course/activity.html?link=";
     // 注册
     private static final String registeredRealLink = "/pages_course/register.html?link=";
+    private static final String h5LiveShortLink = "/pages_course/livingInvite.html?s=";
+
+    private static final String h5miniappLink = "/pages_course/shortLink.html?s=";
 
 //    private static final String miniappRealLink = "/pages/index/index?course=";
 
@@ -1281,6 +1284,58 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         }
                     }
                     break;
+                //直播h5跳转卡片
+                case "18":
+                    //直播h5跳转短链
+                case "19":
+                    String corpId = logVo.getCorpId();
+                    String shortH5Link = createH5LiveShortLink(setting, corpId,
+                            qwUserId, companyUserId, companyId);
+                    shortH5Link = shortH5Link.substring(0, shortH5Link.length() - 1);
+
+                    sopLogs.setSendType(Integer.valueOf(setting.getContentType()));
+                    clonedContent.setLiveId(setting.getLiveId());
+                    json = configService.selectConfigByKey("his.config");
+                    sysConfig= JSON.parseObject(json,FSSysConfig.class);
+
+                    if(isGroupChat){
+                        try{
+                            groupChat.getChatUserList().stream().filter(e -> e.getUserList() != null && !e.getUserList().isEmpty()).forEach(e -> {
+                                Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(e.getUserList(), GroupUserExternalVo::getUserId);
+                                GroupUserExternalVo vo = userMap.get(groupChat.getOwner());
+                                if (vo != null && vo.getId() != null) {
+                                    sopLogs.setFsUserId(vo.getFsUserId());
+                                    //写入直播待看课记录
+                                    createLiveWatchLogAndEnQueue(companyId,companyUserId,vo.getId().toString(), setting.getLiveId(),sysConfig.getAppId(),2,qwUserId,logVo.getCorpId());
+                                }
+                            });
+                            shortH5Link += ",\"chatId\":\"" + groupChat.getChatId() + "\"";
+                        }catch(Exception e){
+                            log.error("直播H5群聊新增报错,{}", e.getMessage(),e);
+                        }
+                    }else{
+                        try{
+                            createLiveWatchLogAndEnQueue(companyId,companyUserId,externalId, setting.getLiveId(),sysConfig.getAppId(),1,qwUserId,logVo.getCorpId());
+                            shortH5Link += ",\"externalId\":\"" + externalId + "\"";
+                        }catch(Exception e){
+                            log.error("直播H5个人新增报错,{}", e.getMessage(),e);
+                        }
+                    }
+
+                    shortH5Link += "}";
+                    miniprogramLiveTitle = setting.getMiniprogramTitle();
+                    maxLiveLength = 17;
+                    setting.setMiniprogramTitle(miniprogramLiveTitle.length() > maxLiveLength ? miniprogramLiveTitle.substring(0, maxLiveLength) + "..." : miniprogramLiveTitle);
+                    setting.setMiniprogramAppid(sysConfig.getAppId());
+                    setting.setMiniprogramPage(shortH5Link);
+
+
+                    try {
+                        setting.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(setting.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : setting.getMiniprogramPicUrl());
+                    } catch (Exception e) {
+                        log.error("赋值-小程序封面地址失败-" + e);
+                    }
+                    break;
                 default:
                     break;
             }
@@ -1413,8 +1468,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     /**
      * 处理直播消息
      */
-    public void handleLiveMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content, String companyUserId, String companyId,
-                                  boolean isGroupChat, String qwUserId, QwGroupChat groupChat, String externalId, SopUserLogsVo logVo, Long liveId) {
+    public void handleLiveMessage(QwSopLogs sopLogs,QwSopTempSetting.Content content, String companyUserId, String companyId,
+                                  boolean isGroupChat,String qwUserId,QwGroupChat groupChat,String externalId,SopUserLogsVo logVo,Long liveId){
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         if (clonedContent == null) {
@@ -1477,6 +1532,55 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         log.error("赋值-小程序封面地址失败-" + e);
                     }
 
+                    break;
+                //直播h5跳转卡片
+                case "18":
+                    //直播h5跳转短链
+                case "19":
+                    String corpId = logVo.getCorpId();
+                    String shortH5Link = createH5LiveShortLink(setting, corpId,
+                            qwUserId, companyUserId, companyId);
+
+                    sopLogs.setSendType(Integer.valueOf(setting.getContentType()));
+                    clonedContent.setLiveId(setting.getLiveId());
+                    json = configService.selectConfigByKey("his.config");
+                    sysConfig= JSON.parseObject(json,FSSysConfig.class);
+
+                    if(isGroupChat){
+                        try{
+                            groupChat.getChatUserList().stream().filter(e -> e.getUserList() != null && !e.getUserList().isEmpty()).forEach(e -> {
+                                Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(e.getUserList(), GroupUserExternalVo::getUserId);
+                                GroupUserExternalVo vo = userMap.get(groupChat.getOwner());
+                                if (vo != null && vo.getId() != null) {
+                                    sopLogs.setFsUserId(vo.getFsUserId());
+                                    //写入直播待看课记录
+                                    createLiveWatchLogAndEnQueue(companyId,companyUserId,vo.getId().toString(), setting.getLiveId(),sysConfig.getAppId(),2,qwUserId,logVo.getCorpId());
+                                }
+                            });
+                            shortH5Link += "&chatId=" + groupChat.getChatId();
+                        }catch(Exception e){
+                            log.error("直播小程序群聊新增报错,{}", e.getMessage(),e);
+                        }
+                    }else{
+                        try{
+                            createLiveWatchLogAndEnQueue(companyId,companyUserId,externalId, setting.getLiveId(),sysConfig.getAppId(),1,qwUserId,logVo.getCorpId());
+                            shortH5Link += "&externalId=" + externalId;
+                        }catch(Exception e){
+                            log.error("直播小程序个人新增报错,{}", e.getMessage(),e);
+                        }
+                    }
+
+                    miniprogramLiveTitle = setting.getMiniprogramTitle();
+                    maxLiveLength = 17;
+                    setting.setMiniprogramTitle(miniprogramLiveTitle.length() > maxLiveLength ? miniprogramLiveTitle.substring(0, maxLiveLength) + "..." : miniprogramLiveTitle);
+                    setting.setMiniprogramAppid(sysConfig.getAppId());
+                    setting.setMiniprogramPage(shortH5Link);
+
+                    try {
+                        setting.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(setting.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : setting.getMiniprogramPicUrl());
+                    } catch (Exception e) {
+                        log.error("赋值-小程序封面地址失败-" + e);
+                    }
                     break;
                 default:
                     break;
@@ -1741,6 +1845,44 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                 case "15": //app文本
                 case "16": //app语音
                     sopLogs.setAppSendStatus(0);
+                    break;
+                case "17":
+                    try {
+                        String sroth5link;
+                        addWatchLogIfNeeded(sopLogs, videoId, courseId, sendTime, qwUserId, companyUserId, companyId, externalId, logVo,2);
+
+                        sroth5link = createH5LinkByMiniApp(setting, logVo, sendTime, courseId, videoId,
+                                qwUserId, companyUserId, companyId, externalId, isOfficial, sopLogs.getFsUserId());
+
+                        if(sopLogs.getSendType()==1){
+                            setting.setMiniprogramAppid(miniAppId);
+                        }else {
+                            int miniType = getLevel(grade);
+                            //算主备小程序
+                            String finalAppId = getAppIdFromMiniMap(miniMap, companyId, sendMsgType, grade);
+
+                            if (StringUtil.strIsNullOrEmpty(finalAppId)) {
+                                finalAppId = miniAppId;
+                            }
+
+                            setting.setMiniType(miniType);
+                            if (!StringUtil.strIsNullOrEmpty(finalAppId)) {
+                                setting.setMiniprogramAppid(finalAppId);
+                            } else {
+                                log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
+                            }
+
+                        }
+
+                        setting.setMiniprogramTitle("邀请链接");
+                        setting.setMiniprogramPage(sroth5link);
+
+                        setting.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(setting.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : setting.getMiniprogramPicUrl());
+
+                    } catch (Exception e) {
+                        log.error("浏览器看课模板解析失败:" + e);
+                    }
+
                     break;
                 default:
                     break;
@@ -1920,7 +2062,99 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
         return record;
     }
+    private String createH5LinkByMiniApp(QwSopTempSetting.Content.Setting setting, SopUserLogsVo logVo, Date sendTime,
+                                         Long courseId, Long videoId, String qwUserId,
+                                         String companyUserId, String companyId, String externalId, String isOfficial, Long fsUserId) {
+        // 获取缓存的配置
+        CourseConfig config;
+        synchronized (configLock) {
+            config = cachedCourseConfig;
+        }
 
+        if (config == null) {
+            log.error("CourseConfig is not loaded.");
+            return "";
+        }
+//        if (StringUtils.isEmpty(config.getMiniprogramPage())){
+//            log.error("miniprogramPage is not loaded.");
+//            return "";
+//        }
+
+        // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(Long.parseLong(companyId));
+        link.setQwUserId(Long.valueOf(qwUserId));
+        link.setCompanyUserId(Long.parseLong(companyUserId));
+        link.setVideoId(videoId.longValue());
+        link.setCorpId(logVo.getCorpId());
+        link.setCourseId(courseId.longValue());
+        link.setQwExternalId(Long.parseLong(externalId));
+        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);
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        String courseJson = JSON.toJSONString(courseMap);
+        String realLinkFull = h5miniappLink + courseJson;
+        link.setRealLink(realLinkFull);
+
+
+        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());
+        link.setUpdateTime(updateTime);
+
+        //存短链-
+        enqueueCourseLink(link);
+        return link.getRealLink();
+    }
+
+    private String createH5LiveShortLink(QwSopTempSetting.Content.Setting setting, String corpId, String qwUserId, String companyUserId, String companyId) {
+
+        // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(Long.parseLong(companyId));
+        link.setQwUserId(Long.valueOf(qwUserId));
+        link.setCompanyUserId(Long.parseLong(companyUserId));
+        link.setLiveId(setting.getLiveId());
+        link.setCorpId(corpId);
+        link.setUNo(UUID.randomUUID().toString());
+
+        String randomString = generateRandomStringWithLock();
+        if (StringUtil.strIsNullOrEmpty(randomString)) {
+            link.setLink(UUID.randomUUID().toString().replace("-", ""));
+        } else {
+            link.setLink(randomString);
+        }
+
+        /*FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);*/
+
+        String courseJson = JSON.toJSONString(link);
+        String realLinkFull = h5LiveShortLink + courseJson;
+        link.setRealLink(realLinkFull);
+
+        //存短链-
+        enqueueCourseLink(link);
+        return link.getRealLink();
+
+    }
     private String getAppIdFromMiniMap(Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
                                        String companyId,
                                        int sendMsgType,

+ 2 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -19,6 +19,8 @@ public class CourseConfig implements Serializable {
     private Integer appAnswerIntegral; //app答题积分
     private Integer defaultLine;//默认看课线路
     private String realLinkDomainName;//真链域名
+    private String realLinkH5DomainName;//H5通用看课域名
+    private String realLinkH5LiveName;//H5通用直播域名
     private String authDomainName;//网页授权域名
     private String mpAppId;//看课公众号APPID
     private String registerDomainName;//注册域名

+ 3 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java

@@ -69,4 +69,7 @@ public class FsCourseLink extends BaseEntity
     @ApiModelProperty(value = "项目唯一标识(PS:MYHK)")
     private String projectCode;
 
+    //@ApiModelProperty(value = "直播id")
+    private Long liveId;
+
 }

+ 73 - 0
fs-service/src/main/java/com/fs/course/dto/FsCourseLinkDTO.java

@@ -0,0 +1,73 @@
+package com.fs.course.dto;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 短链对象 fs_course_link
+ *
+ * @author fs
+ * @date 2024-10-24
+ */
+@Data
+public class FsCourseLinkDTO extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 主键Id */
+    private Long linkId;
+
+    /** 链接后缀 */
+    @Excel(name = "链接后缀")
+    private String link;
+
+    /** 真实链接 */
+    @Excel(name = "真实链接")
+    private String realLink;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 客服id */
+    @Excel(name = "客服id")
+    private Long companyUserId;
+
+    /** 企微userId主键 */
+    @Excel(name = "企微userId主键")
+    private String qwUserId;
+
+    /** 课节id */
+    @Excel(name = "课节id")
+    private Long videoId;
+
+    /** 企微主体id */
+    @Excel(name = "企微主体id")
+    private String corpId;
+
+    private Long courseId;
+    /**
+    * 企微外部联系表主键
+    */
+    private Long qwExternalId;
+
+    private Integer linkType; //链接类型 0:正常链接  1:应急链接  3:小程序链接 4:app 5:官方
+
+    private Integer isRoom;//是否发群
+
+    private String chatId;
+//    private String link_uuid;
+    // 识别编号
+    private String uNo;
+
+    private String courseName;
+
+    /** 课程封面 */
+    private String courseUrl;
+
+    private String title;
+
+
+
+}

+ 62 - 0
fs-service/src/main/java/com/fs/course/dto/FsLiveLinkDTO.java

@@ -0,0 +1,62 @@
+package com.fs.course.dto;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class FsLiveLinkDTO extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 主键Id */
+    private Long linkId;
+
+    /** 链接后缀 */
+    @Excel(name = "链接后缀")
+    private String link;
+
+    /** 真实链接 */
+    @Excel(name = "真实链接")
+    private String realLink;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 客服id */
+    @Excel(name = "客服id")
+    private Long companyUserId;
+
+    /** 企微userId主键 */
+    @Excel(name = "企微userId主键")
+    private String qwUserId;
+
+    /** 课节id */
+    @Excel(name = "直播id")
+    private Long liveId;
+
+    /** 企微主体id */
+    @Excel(name = "企微主体id")
+    private String corpId;
+
+    /**
+     * 企微外部联系表主键
+     */
+    private Long qwExternalId;
+
+    private Integer linkType; //链接类型 0:正常链接  1:应急链接  3:小程序链接 4:app 5:官方
+
+    private Integer isRoom;//是否发群
+
+    private String chatId;
+    //    private String link_uuid;
+    // 识别编号
+    private String uNo;
+
+    private String courseName;
+
+    /** 直播封面 */
+    private String liveUrl;
+
+    private String title;
+}

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

@@ -1,6 +1,8 @@
 package com.fs.course.mapper;
 
 import com.fs.course.domain.FsCourseLink;
+import com.fs.course.dto.FsCourseLinkDTO;
+import com.fs.course.param.FsCourseH5ListParam;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
@@ -78,4 +80,10 @@ public interface FsCourseLinkMapper
 
     @Select("select link_id,real_link from fs_course_link where create_time > '2025-03-07 12:00:00' and create_time < '2025-03-07 17:00:00'")
     List<FsCourseLink> selectFsCourseLinkListUpdate();
+
+    List<FsCourseLinkDTO> selectFsCourseLinkListByQwUserId(FsCourseH5ListParam param);
+
+
+    List<FsCourseLink> selectLinkByCourseIdAndExIdAndQwUserId(@Param("courseId") Long courseId,@Param("videoId") Long videoId,@Param("qwExternalContactId") Long qwExternalContactId,@Param("qwUserId") String qwUserId);
+
 }

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

@@ -749,4 +749,5 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
      */
     List<FsCourseReportVO> selectWatchStatistics(FsCourseWatchLogStatisticsListParam param);
 
+    List<FsSopMyCourseH5LinkVO> getSopCourseH5StudyList(@Param("userId") Long userId);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseEncryptLinkParam.java

@@ -0,0 +1,12 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "加解密")
+public class FsCourseEncryptLinkParam {
+
+   private String url;
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseH5ListParam.java

@@ -0,0 +1,20 @@
+package com.fs.course.param;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class FsCourseH5ListParam {
+
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer pageNum =1;
+    @ApiModelProperty(value = "页大小,默认为100")
+    private Integer pageSize = 100;
+
+    private String qwUserId;
+
+    private Long qwExternalId;
+
+    private Long userId;
+
+    private Long logId;
+}

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

@@ -2,6 +2,8 @@ package com.fs.course.service;
 
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsCourseLink;
+import com.fs.course.dto.FsCourseLinkDTO;
+import com.fs.course.param.FsCourseH5ListParam;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.qw.domain.QwUser;
@@ -104,4 +106,10 @@ public interface IFsCourseLinkService
     R getWxaCodeGenerateScheme(String linkStr,String appId);
 
     R getProjectCode();
+
+    R getLiveWxaCodeGenerateScheme(String linkStr, String appId);
+
+    List<FsCourseLinkDTO> selectFsCourseLinkListByQwUserId(FsCourseH5ListParam param);
+
+    R getLinkInfo(Long logId);
 }

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

@@ -1,6 +1,7 @@
 package com.fs.course.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.param.*;
 import com.fs.course.vo.*;
@@ -161,4 +162,8 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
      * @return
      */
     List<FsCourseReportVO> selectFsCourseReportVO(FsCourseWatchLogStatisticsListParam param);
+
+    R encryptLink(String url);
+
+    R decryptLink(String url);
 }

+ 112 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -19,10 +19,12 @@ import com.fs.core.config.WxMaConfiguration;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseMaConfig;
 import com.fs.course.domain.*;
+import com.fs.course.dto.FsCourseLinkDTO;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
 import com.fs.course.mapper.FsCourseLinkMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.param.FsCourseH5ListParam;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.course.service.IFsCourseLinkService;
@@ -73,6 +75,7 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static com.fs.course.utils.LinkUtil.generateRandomStringWithLock;
 import static com.fs.sop.service.impl.SopUserLogsInfoServiceImpl.convertStringToDate;
@@ -990,4 +993,113 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
         }
         return R.ok().put("code",code);
     }
+
+    @Override
+    public List<FsCourseLinkDTO> selectFsCourseLinkListByQwUserId(FsCourseH5ListParam param) {
+
+        List<FsCourseLinkDTO> fsCourseLink = fsCourseLinkMapper.selectFsCourseLinkListByQwUserId(param);
+        // fsCourseLink 根据course_id 去重 并且 保留最新的一条create_time
+        fsCourseLink = fsCourseLink.stream()
+                .collect(Collectors.groupingBy(
+                        FsCourseLinkDTO::getCourseId,
+                        Collectors.collectingAndThen(
+                                Collectors.maxBy(Comparator.comparing(FsCourseLinkDTO::getCreateTime)),
+                                Optional::get
+                        )
+                ))
+                .values()
+                .stream()
+                .collect(Collectors.toList());
+
+
+        return fsCourseLink;
+    }
+
+    @Override
+    public R getLinkInfo(Long logId) {
+
+        FsCourseWatchLog log = fsCourseWatchLogMapper.selectById(logId);
+        // 根据
+        List<FsCourseLink>  list = fsCourseLinkMapper.selectLinkByCourseIdAndExIdAndQwUserId(log.getCourseId(),log.getVideoId(),log.getQwExternalContactId(),log.getQwUserId().toString());
+        if(list.isEmpty()){
+            // 群发的目前不支持
+            return R.error("未找到该课节");
+        }
+        // 筛选取 create_time 最大的一条
+        FsCourseLink link = list.stream().max(Comparator.comparing(FsCourseLink::getCreateTime)).get();
+        Map<String,Object> map = new HashMap<>();
+        map.put("link",link.getRealLink());
+        return R.ok().put("data",map);
+    }
+
+    @Override
+    public R getLiveWxaCodeGenerateScheme(String linkStr, String appId) {
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClients.createDefault();
+            if(linkStr != null && linkStr.contains(".html")){
+                linkStr = linkStr.replace(".html","");
+            }
+            String[] split = linkStr.split("\\?");
+            if (split.length == 2 && split[0].length() > 0 && split[1].length() > 0) {
+                //处理页面路径
+                String pageUrl = split[0];
+                if (pageUrl.startsWith("/")) {
+                    pageUrl = pageUrl.substring(1);
+                }
+                //处理参数
+                String query = split[1];
+                query = URLEncoder.encode(query, StandardCharsets.UTF_8.toString());
+//                String json = configService.selectConfigByKey("course.config");
+//                CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+//                String miniprogramAppid = config.getMiniprogramAppid();
+//                if (StringUtils.isBlank(miniprogramAppid)) {
+//                    return "未配置点播小程序id";
+//                }
+                //获取微信token
+                final WxMaService wxService = WxMaConfiguration.getMaService(appId);
+                String token = wxService.getAccessToken();
+                log.info("小程序TOKEN值-------->刷新前TOKEN:{}", token);
+                HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + token);
+                JSONObject bodyObj = new JSONObject();
+                bodyObj.put("path", pageUrl);
+                bodyObj.put("query", query);
+                log.info("微信小程序请求参数打印:{}", bodyObj.toJSONString());
+                StringEntity entity = new StringEntity(bodyObj.toJSONString(),"UTF-8");
+                httpPost.setEntity(entity);
+                httpPost.setHeader("Content-type", "application/json");
+                httpPost.setHeader("cache-control","max-age=0");
+                HttpEntity response = client.execute(httpPost).getEntity();
+                String responseString = EntityUtils.toString(response);
+                log.info("微信小程序接口响应数据:{}", responseString);
+                JSONObject jsonObject = JSONObject.parseObject(responseString);
+
+                if(TOKEN_VALID_CODE.equals(jsonObject.getString("errcode"))){
+                    Integer curVersion =  Integer.valueOf(version);
+                    synchronized (TOKEN_VALID_CODE){
+                        if(curVersion.equals(version)){
+                            log.info("小程序TOKEN:40001进入强制刷新-------->刷新前TOKEN:{}", token);
+                            wxService.getAccessToken(true);
+                            version = version.equals(Integer.MAX_VALUE) ? 0 : curVersion + 1;
+                            log.info("小程序TOKEN:40001进入强制刷新-------->刷新后TOKEN:{}", wxService.getAccessToken());
+                        }
+                        return getLiveWxaCodeGenerateScheme(linkStr,appId);
+                    }
+                }
+
+                if(null != jsonObject && !jsonObject.isEmpty() && jsonObject.containsKey("url_link")){
+                    return R.ok().put("urlLink",jsonObject.getString("url_link")) ;
+                }else {
+                    return R.error("获取失败:"+jsonObject.getString("errmsg"));
+                }
+            } else {
+                return R.error("页面链接错误,获取失败");
+            }
+
+        } catch (WxErrorException e) {
+            throw new RuntimeException(e);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 25 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java

@@ -9,6 +9,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DictUtils;
@@ -33,6 +34,7 @@ import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.utils.ConfigUtil;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.qw.Bean.MsgBean;
 import com.fs.qw.cache.IQwExternalContactCacheService;
 import com.fs.qw.cache.IQwUserCacheService;
@@ -1694,4 +1696,27 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
                 && startCal.get(Calendar.DAY_OF_YEAR) == endCal.get(Calendar.DAY_OF_YEAR);
     }
 
+    private final String courseUrl = "/pages/index/index?s=";
+
+    @Override
+    public R encryptLink(String url) {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+        String encryptionLink = PhoneUtil.encryptPhone(url);
+        Map<String, Object> data = new HashMap<>();
+        data.put("encryptionLink", config.getRealLinkH5DomainName()+courseUrl+encryptionLink);
+        return R.ok().put("data",data);
+    }
+
+    @Override
+    public R decryptLink(String url) {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        String decryptLink = PhoneUtil.decryptPhone(url);
+        Map<String, Object> data = new HashMap<>();
+        data.put("decryptLink", config.getRealLinkH5DomainName()+courseUrl+decryptLink);
+        return R.ok().put("data", data);
+    }
+
 }

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

@@ -0,0 +1,35 @@
+package com.fs.course.vo;
+
+import lombok.Data;
+
+
+@Data
+public class FsSopMyCourseH5LinkVO {
+
+    private static final long serialVersionUID = 1L;
+
+
+//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+//    private String updateTime;
+
+
+
+//    /** 课程标题 */
+//    @Excel(name = "课程标题")
+    private String courseName;
+
+    /** 课程封面 */
+    private String courseUrl;
+
+    private String title;
+
+//    private Long qwExternalId;
+
+    private Long logId;
+
+    private String qwUserName;
+
+
+
+
+}

+ 23 - 0
fs-service/src/main/java/com/fs/course/vo/FsSopMyLiveH5LinkVO.java

@@ -0,0 +1,23 @@
+package com.fs.course.vo;
+
+import lombok.Data;
+
+@Data
+public class FsSopMyLiveH5LinkVO {
+    private static final long serialVersionUID = 1L;
+
+    //    /** 课程标题 */
+//    @Excel(name = "课程标题")
+    private String courseName;
+
+    /** 课程封面 */
+    private String courseUrl;
+
+    private String title;
+
+//    private Long qwExternalId;
+
+    private Long logId;
+
+    private String qwUserName;
+}

+ 17 - 0
fs-service/src/main/java/com/fs/his/param/FsUserInfoParam.java

@@ -0,0 +1,17 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsUserInfoParam implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String qwUserId;
+
+    private String corpId;
+
+    private Long userId;
+}

+ 3 - 0
fs-service/src/main/java/com/fs/live/domain/Live.java

@@ -133,4 +133,7 @@ public class   Live extends BaseEntity {
 
     @TableField(exist = false)
     private List<LiveTagItemVO> liveTagList;
+
+    private Integer pageNum;
+    private Integer pageSize;
 }

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

@@ -239,4 +239,6 @@ public interface LiveMapper
             " order by create_time desc" +
             " </script>"})
     List<Live> listToLiveNoEnd(@Param("live") Live live);
+
+    List<Live> selectLiveListNew(Live live);
 }

+ 0 - 1
fs-service/src/main/java/com/fs/live/mapper/LiveVideoMapper.java

@@ -84,7 +84,6 @@ public interface LiveVideoMapper
     @Select("select * from live_video where live_id = #{liveId}")
     List<LiveVideo> selectByLiveId(@Param("liveId")Long liveId);
 
-    @Select("select * from live_video where live_id = #{liveId} and video_type = #{videoType}")
     @DataSource(DataSourceType.SLAVE)
     List<LiveVideo> selectByLiveIdAndType(@Param("liveId")Long liveId,@Param("videoType") Integer videoType);
 

+ 10 - 0
fs-service/src/main/java/com/fs/live/param/FsLiveEncryptLinkParam.java

@@ -0,0 +1,10 @@
+package com.fs.live.param;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "加解密")
+public class FsLiveEncryptLinkParam {
+    private String url;
+}

+ 21 - 0
fs-service/src/main/java/com/fs/live/param/FsLiveH5ListParam.java

@@ -0,0 +1,21 @@
+package com.fs.live.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class FsLiveH5ListParam {
+
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer pageNum =1;
+    @ApiModelProperty(value = "页大小,默认为100")
+    private Integer pageSize = 100;
+
+    private String qwUserId;
+
+    private Long qwExternalId;
+
+    private Long userId;
+
+    private Long logId;
+}

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

@@ -217,4 +217,12 @@ public interface ILiveService
      * @return
      */
     List<CompanyVO> getCompanyDropList();
+
+    R liveEncryptLink(String url);
+
+    R liveDecryptLink(String url);
+
+    R getLiveQwUserInfo(Long qwUserId);
+
+    List<Live> selectLiveListNew(Live live);
 }

+ 70 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -13,14 +13,17 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.core.page.PageRequest;
 import com.fs.common.core.redis.service.StockDeductService;
 import com.fs.common.exception.base.BaseException;
+import com.fs.company.domain.Company;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.vo.CompanyVO;
 import com.fs.core.config.WxMaConfiguration;
+import com.fs.course.config.CourseConfig;
 import com.fs.his.domain.FsStoreProduct;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserWx;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.mapper.FsUserWxMapper;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.hisStore.domain.FsStoreProductScrm;
 import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
 import com.fs.live.dto.TemplateMessageSendRequestDTO;
@@ -39,6 +42,8 @@ import com.fs.live.param.LiveReplayParam;
 import com.fs.live.service.*;
 import com.fs.live.utils.ProcessManager;
 import com.fs.live.vo.*;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageInfo;
@@ -141,6 +146,13 @@ public class LiveServiceImpl implements ILiveService
 
     private static volatile Integer version = 0;
 
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    private final String liveUrl = "/living/#/?s=";
 
     @Override
     public Live selectLiveDbByLiveId(Long liveId) {
@@ -179,6 +191,64 @@ public class LiveServiceImpl implements ILiveService
        return  companyMapper.getCompanyDropList();
     }
 
+    /**
+     * 加密链接
+     * @param url
+     * @return
+     */
+    @Override
+    public R liveEncryptLink(String url) {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+        String encryptionLink = PhoneUtil.encryptPhone(url);
+        Map<String, Object> data = new HashMap<>();
+        data.put("encryptionLink", config.getRealLinkH5LiveName()+liveUrl+encryptionLink);
+        return R.ok().put("data",data);
+    }
+
+    /**
+     * 解密链接
+     * @param url
+     * @return
+     */
+    @Override
+    public R liveDecryptLink(String url) {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        String decryptLink = PhoneUtil.decryptPhone(url);
+        Map<String, Object> data = new HashMap<>();
+        data.put("decryptLink", config.getRealLinkH5LiveName()+liveUrl+decryptLink);
+        return R.ok().put("data", data);
+    }
+
+    @Override
+    public R getLiveQwUserInfo(Long qwUserId) {
+        QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+
+        // 使用 Optional 处理 qwUser 和 company 的空值情况
+        String companyName = Optional.ofNullable(qwUser)
+                .map(QwUser::getCompanyId)
+                .map(companyId -> companyMapper.selectCompanyById(companyId))
+                .map(Company::getCompanyName)
+                .orElse("无");
+
+        String qwUserName = Optional.ofNullable(qwUser)
+                .map(QwUser::getQwUserName)
+                .orElse("无");
+
+        // 直接构建返回结果
+        return R.ok()
+                .put("qwUserName", qwUserName)
+                .put("companyName", companyName);
+
+    }
+
+    @Override
+    public List<Live> selectLiveListNew(Live live) {
+        return baseMapper.selectLiveListNew(live);
+    }
+
 
     /**
      * 查询直播

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

@@ -511,4 +511,8 @@ public interface QwUserMapper extends BaseMapper<QwUser>
 
     @Select("select * from qw_user where ipad_status = 1 and corp_id=#{corpId} and qw_user_id=#{qwUserId} limit 1 ")
     QwUser selectQwUserAppKeyAndIdByCorpIdAndUserIdAndIpad(@Param("corpId")String corpId,@Param("qwUserId") String qwUserId);
+
+    List<QwUser> selectQwUserByQwUserIds(@Param("list") List<String> userIdsLong);
+
+    QwUserVO getQwUserCompanyInfo(@Param("qwUserId") Long qwUserId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/qw/service/IQwUserService.java

@@ -209,4 +209,6 @@ public interface IQwUserService
     R unbindQwUserByServerIds(List<String> serverIds);
 
     R updateQwUserFastGptRoleStatusById(Long id);
+
+    QwUserVO getQwUserCompanyInfo(Long qwUserId);
 }

+ 5 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java

@@ -1643,6 +1643,11 @@ public class QwUserServiceImpl implements IQwUserService
         return R.error("修改失败,未找到企微!");
     }
 
+    @Override
+    public QwUserVO getQwUserCompanyInfo(Long qwUserId) {
+        return qwUserMapper.getQwUserCompanyInfo( qwUserId);
+    }
+
     /**
      * 根据销售公司和企微ID查询企微用户
      */

+ 8 - 0
fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java

@@ -6,10 +6,12 @@ import com.fs.common.enums.DataSourceType;
 import com.fs.qw.domain.QwApiSopLogToken;
 import com.fs.qw.param.SopMsgParam;
 import com.fs.sop.domain.QwSopLogs;
+import com.fs.sop.domain.SopUserLogs;
 import com.fs.sop.params.*;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.sop.vo.QwSopLogsListCVO;
 import com.fs.sop.vo.QwSopLogsListVOByUserInfo;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
 import org.apache.ibatis.annotations.MapKey;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
@@ -357,4 +359,10 @@ public interface QwSopLogsMapper extends BaseMapper<QwSopLogs> {
 
     @DataSource(DataSourceType.SOP)
     void updateGroupSopStatus();
+
+    @DataSource(DataSourceType.SOP)
+    @MapKey("id")
+    Map<String, SopUserLogs> queryAllPeriodNew(StatsWatchLogPageListDTO param);
+
+
 }

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

@@ -98,6 +98,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     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 registeredRealLink = "/pages_course/register.html?link=";
+    private static final String h5LiveShortLink = "/pages_course/livingInvite.html?s=";
+    private static final String h5miniappLink = "/pages_course/shortLink.html?s=";
 //    private static final String miniappRealLink = "/pages/index/index?course=";
 
     @Autowired
@@ -578,6 +580,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     if (vo == null) return null;
                     QwSopLogs sopLogs = new QwSopLogs();
 
+                    String qwUserId = qwUser.getQwUserId();
                     sopLogs.setQwUserid(qwUser.getQwUserId());
                     sopLogs.setExternalUserId(vo.getExternalUserId());
                     sopLogs.setLogType(2);
@@ -803,6 +806,49 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 createVoiceUrl(st, companyUserId, qwSop);
                                 sopLogs.setAppSendStatus(0);
                                 break;
+                            case "17": //h5看课
+                                try {
+                                    addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(), Long.valueOf(groupUser.getFsUserId()), qwUserId, companyUserId, companyId, groupUser.getId(), param.getStartTime(), createTime,2);
+
+                                    String sroth5link = createH5LinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                            qwUserId, companyUserId, companyId, groupUser.getId(), config);
+
+
+                                    miniAppId = null;
+                                    if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                                        Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                                        if (integerListMap != null) {
+                                            int listIndexTemp = 1;
+                                            List<CompanyMiniapp> miniapps = integerListMap.get(listIndexTemp);
+                                            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(sroth5link);
+
+                                    st.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(st.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : st.getMiniprogramPicUrl());
+
+
+                                } catch (Exception e) {
+                                    log.error("浏览器看课模板解析失败:" + e);
+                                }
+                                break;
                             //群公告
                             case "11":
                                 sopLogs.setSendType(21); // 设置为群公告类型
@@ -831,6 +877,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     }
                     QwSopLogs sopLogs = new QwSopLogs();
 
+                    String qwUserId = qwUser.getQwUserId();
                     sopLogs.setQwUserid(qwUser.getQwUserId());
                     sopLogs.setExternalUserId(groupChat.getChatId());
                     sopLogs.setLogType(2);
@@ -1454,6 +1501,50 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 throw new RuntimeException(e);
                             }
                             sopLogs.setAppSendStatus(0);
+                            break;
+                        case "17":
+                            try {
+                                addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime,2 );
+
+                                String sroth5link = createH5LinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                        qwUserId, companyUserId, companyId,  item.getExternalId(), config);
+
+
+                                miniAppId = null;
+                                if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                                    Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                                    if (integerListMap != null) {
+                                        int listIndexTemp = 1;
+                                        List<CompanyMiniapp> miniapps = integerListMap.get(listIndexTemp);
+                                        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(sroth5link);
+
+                                st.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(st.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : st.getMiniprogramPicUrl());
+
+
+                            } catch (Exception e) {
+                                log.error("浏览器看课模板解析失败:" + e);
+                            }
+
                             break;
                         //群公告(仅用于一键群发,个人不应该有群公告)
                         case "11":
@@ -2076,6 +2167,79 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
                     st.setMiniprogramPage(linkByMiniApp);
                     break;
+                case "17": //h5看课
+                    try {
+                        addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(), item.getFsUserId(), String.valueOf(qwUser.getId()), companyUserId, companyId,
+                                item.getExternalId(), item.getStartTime(), dataTime,2);
+                        String sroth5link = createH5LinkByMiniApp(st, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
+                                String.valueOf(qwUser.getId()), companyUserId, companyId, item.getExternalId(), config);
+
+                        miniAppId = null;
+                        if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                            Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                            if (integerListMap != null) {
+                                int listIndexTemp = 1;
+                                List<CompanyMiniapp> miniapps = integerListMap.get(listIndexTemp);
+                                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(sroth5link);
+
+                        st.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(st.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : st.getMiniprogramPicUrl());
+
+
+                    } catch (Exception e) {
+                        log.error("浏览器看课模板解析失败:" + e);
+                    }
+                    break;
+                //直播h5跳转卡片
+                case "18":
+                    //直播h5跳转短链
+                case "19":
+                    sopLogs.setSendType(Integer.valueOf(st.getContentType()));
+                    Long qwUserId = qwUser.getId();
+                    String corpId = param.getCorpId();
+                    String shortH5Link = createH5LiveShortLink(st, corpId,
+                            qwUserId, companyUserId, companyId);
+
+                    miniprogramLiveTitle = st.getMiniprogramTitle();
+                    maxLiveLength = 17;
+                    st.setMiniprogramTitle(miniprogramLiveTitle.length() > maxLiveLength ? miniprogramLiveTitle.substring(0, maxLiveLength) + "..." : miniprogramLiveTitle);
+
+                    json = configService.selectConfigByKey("his.config");
+                    sysConfig= JSON.parseObject(json,FSSysConfig.class);
+                    //todo 发个人看课记录处理
+                    try {
+                        createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),2, String.valueOf(qwUser.getId()),param.getCorpId());
+                    } catch (Exception e) {
+                        log.error("群聊创建直播看课记录失败!", e);
+                    }
+
+                    st.setMiniprogramAppid(sysConfig.getAppId());
+                    st.setMiniprogramPage(shortH5Link);
+
+                    try {
+                        st.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(st.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : st.getMiniprogramPicUrl());
+                    } catch (Exception e) {
+                        log.error("赋值-小程序封面地址失败-" + e);
+                    }
+                    break;
 
                 default:
                     break;
@@ -2086,6 +2250,85 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return  list;
     }
 
+    /**
+     * 创建看课短链
+     * @param setting
+     * @param corpId
+     * @param sendTime
+     * @param courseId
+     * @param videoId
+     * @param qwUserId
+     * @param companyUserId
+     * @param companyId
+     * @param externalId
+     * @param config
+     * @return
+     */
+    String createH5LinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
+                                 Integer courseId, Integer videoId, String qwUserId,
+                                 String companyUserId, String companyId, Long externalId, CourseConfig config) {
+
+        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, Long.valueOf(qwUserId),
+                companyUserId, companyId, externalId, 3, null);
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        String courseJson = JSON.toJSONString(courseMap);
+        String realLinkFull = h5miniappLink + courseJson;
+        link.setRealLink(realLinkFull);
+
+        Date updateTime = createUpdateTime(setting, sendTime, config);
+
+        link.setUpdateTime(updateTime);
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+        return link.getRealLink();
+    }
+
+    /**
+     * 创建直播短链
+     * @param setting
+     * @param corpId
+     * @param qwUserId
+     * @param companyUserId
+     * @param companyId
+     * @return
+     */
+    private String createH5LiveShortLink(QwSopCourseFinishTempSetting.Setting setting, String corpId, Long qwUserId, String companyUserId, String companyId) {
+
+        // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(Long.parseLong(companyId));
+        link.setQwUserId(Long.valueOf(qwUserId));
+        link.setCompanyUserId(Long.parseLong(companyUserId));
+        link.setLiveId(Long.valueOf(setting.getLiveId()));
+        link.setCorpId(corpId);
+        link.setUNo(UUID.randomUUID().toString());
+
+        String randomString = generateRandomStringWithLock();
+        if (StringUtil.strIsNullOrEmpty(randomString)) {
+            link.setLink(UUID.randomUUID().toString().replace("-", ""));
+        } else {
+            link.setLink(randomString);
+        }
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        String courseJson = JSON.toJSONString(link);
+        String realLinkFull = h5LiveShortLink + courseJson;
+        link.setRealLink(realLinkFull);
+
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+
+        return link.getRealLink();
+
+
+    }
+
+
     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);

+ 42 - 9
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisSalerWatchServiceImpl.java

@@ -7,6 +7,7 @@ import com.fs.company.domain.CompanyDept;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyDeptMapper;
 import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.config.cloud.CloudHostProper;
 import com.fs.qw.cache.QwSopCacheService;
 import com.fs.qw.cache.QwUserCacheService;
 import com.fs.qw.domain.QwUser;
@@ -65,6 +66,9 @@ public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService
     @Autowired
     private QwSopCacheService qwSopCacheService;
 
+    @Autowired
+    private CloudHostProper cloudHostProper;
+
     @Autowired
     public FsStatisSalerWatchServiceImpl(FsStatisSalerWatchMapper fsStatisSalerWatchMapper,
                                          CompanyUserMapper companyUserMapper,
@@ -247,16 +251,45 @@ public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService
             return Collections.emptyList();
         }
         List<FsStatisSopWatch> fsStatisSopWatches = fsStatisSalerWatchMapper.queryPeriodListExport(param);
-        Map<String, QwSopLogs> stringQwSopLogsMap = qwSopLogsMapper.queryAllPeriod();
-
-        for (FsStatisSopWatch item : fsStatisSopWatches) {
-            if(item.getPeriodId() != null) {
-                QwSopLogs qwSopLogs = stringQwSopLogsMap.get(item.getPeriodId());
-                if(qwSopLogs != null) {
-                    item.setPeriodName(qwSopLogs.getSopTitle());
+        if("九州在线".equals(cloudHostProper.getCompanyName())){
+            Map<String, SopUserLogs> stringQwSopLogsMap = qwSopLogsMapper.queryAllPeriodNew(param);
+
+            // 提取非空的用户ID并批量查询
+            List<String> userIds = stringQwSopLogsMap.values().stream()
+                    .filter(qwSopLogs -> qwSopLogs.getQwUserId() != null)
+                    .map(SopUserLogs::getQwUserId)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            // 批量查询用户信息并构建映射
+            Map<String, String> userNameMap = qwUserMapper.selectQwUserByQwUserIds(userIds).stream()
+                    .collect(Collectors.toMap(QwUser::getQwUserId, QwUser::getQwUserName));
+
+            // 设置周期名称
+            fsStatisSopWatches.forEach(item -> {
+                if (item.getPeriodId() != null) {
+                    SopUserLogs sopUserLogs = stringQwSopLogsMap.get(item.getPeriodId());
+                    if (sopUserLogs != null && sopUserLogs.getQwUserId() != null) {
+                        item.setPeriodName(userNameMap.getOrDefault(sopUserLogs.getQwUserId() , "-") + "_" + sopUserLogs.getStartTime());
+                    }
+                } else {
+                    item.setPeriodName("空营期");
+                }
+                item.setFinishedRate(item.getFinishedRate() * 100);
+                item.setRegRate(item.getRegRate() * 100);
+            });
+        }else{
+            Map<String, QwSopLogs> stringQwSopLogsMap = qwSopLogsMapper.queryAllPeriod();
+
+            for (FsStatisSopWatch item : fsStatisSopWatches) {
+                if(item.getPeriodId() != null) {
+                    QwSopLogs qwSopLogs = stringQwSopLogsMap.get(item.getPeriodId());
+                    if(qwSopLogs != null) {
+                        item.setPeriodName(qwSopLogs.getSopTitle());
+                    }
+                } else {
+                    item.setPeriodName("空营期");
                 }
-            } else {
-                item.setPeriodName("空营期");
             }
         }
         return fsStatisSopWatches;

+ 5 - 4
fs-service/src/main/resources/application-config-druid-hcl.yml

@@ -74,15 +74,15 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: hcl-1323137866
   app_id: 1323137866
   region: ap-chongqing
   proxy: hcl
 tmp_secret_config:
-  secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
-  secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: fs-1319721001
   app_id: 1319721001
   region: ap-chongqing
@@ -98,6 +98,7 @@ headerImg:
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
   aiApi:
+  wxIpadUrl:
   voiceApi:
   commonApi:
 wx_miniapp_temp:

+ 3 - 2
fs-service/src/main/resources/application-config-druid-hzyy.yml

@@ -74,8 +74,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: hzyy-1323137866
   app_id: 1323137866
   region: ap-chongqing
@@ -98,6 +98,7 @@ headerImg:
 ipad:
   ipadUrl: http://139.159.133.223:8667
   aiApi: http://49.232.181.28:3000/api
+  wxIpadUrl:
   voiceApi:
   commonApi:
 wx_miniapp_temp:

+ 99 - 0
fs-service/src/main/resources/application-config-druid-jsbk.yml

@@ -0,0 +1,99 @@
+baidu:
+  token: 1
+  back-domain: https://www.xxxx.com
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  miniapp:
+    configs:
+      - appid: w   #中康智慧
+        secret: 5
+        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+      - appid: w   #中康未来智慧药房
+        secret: 9
+        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+  cp:
+    corpId: wwb
+    appConfigs:
+      - agentId: 100005
+        secret: ec7okROXJqkNafq66aKNv0asTzQIG0CYrj3vyBbo
+        token: PPKOdAloMO
+        aesKey: PKvaxtpSvNGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
+  pay:
+    appId: wx #微信公众号或者小程序等的appid
+    mchId: 1611045 #微信支付商户号
+    mchKey: 8cab128997a3547c10898b877f38 #微信支付商户密钥
+    subAppId:  #服务商模式下的子商户公众账号ID
+    subMchId:  #服务商模式下的子商户号
+    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl: https://usepp.his.runtzh.com/app/wxpay/wxPayNotify
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId: wxa8d8d6606847d23b # 第一个公众号的appid   //公众号名称 济世百康云中心
+        secret: 99fc38771e111e640c654626cbf7c5e9 # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVcw03qZy6Wllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+aifabu:  #爱链接
+  appKey: 7b471be905ab17ef358c610dd117601d008
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+  #  account: tcloud
+  #  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  commonApi: http://172.16.16.4:8010
+  h5CommonApi: http://172.16.16.4:8010
+  jwt:
+    # 加密秘钥
+    secret: f4y2x52034348j86b67cde581c0f5625
+    # token有效时长,7天,单位秒
+    expire: 31536000
+    header: AppToken
+nuonuo:
+  key: 10924508
+  secret: A2EB20764D304D16
+# 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
+  bucket: jsbk-1323137866
+  app_id: 1323137866
+  region: ap-chongqing
+  proxy: jsbk
+cloud_host:
+  company_name: 济世百康
+  projectCode: jsbk
+  spaceName: jsbk-2114522511
+  volcengineUrl: https://jsbkvolcengine.ylrztop.com
+#看课授权时显示的头像
+headerImg:
+  imgUrl: https://jsbk-1323137866.cos.ap-chongqing.myqcloud.com/app/jsbk.jpg
+ipad:
+  ipadUrl: http://jsbkipad.sywktxd.cn
+  aiApi:
+  wxIpadUrl:
+  voiceApi:
+  commonApi:
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+

+ 5 - 4
fs-service/src/main/resources/application-config-druid-jzzx.yml

@@ -48,8 +48,8 @@ wx:
         aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
   # 开放平台app微信授权配置
   open:
-    app-id: wxe4d352ea8ddbcf3c
-    secret: be6c179d79fcf97cbfb0b36c08877220
+    app-id: wxd72ddf1598f258f0
+    secret: d94f333b3931c09123b3893a1c2e7fa7
 aifabu:  #爱链接
   appKey: 7b471be905ab17e00f3b858c6710dd117601d008
 watch:
@@ -78,8 +78,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: jiuzhou-1323137866
   app_id: 1323137866
   region: ap-chongqing
@@ -101,6 +101,7 @@ headerImg:
 ipad:
   ipadUrl: http://ipad.jiuzhouzaixian.com
   aiApi: http://49.232.181.28:3000/api
+  wxIpadUrl:
   voiceApi:
   commonApi:
 wx_miniapp_temp:

+ 3 - 2
fs-service/src/main/resources/application-config-druid-qdtst.yml

@@ -74,8 +74,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: qdtst-1323137866
   app_id: 1323137866
   region: ap-chongqing
@@ -98,6 +98,7 @@ headerImg:
 ipad:
   ipadUrl:
   aiApi:
+  wxIpadUrl:
   voiceApi:
   commonApi:
 wx_miniapp_temp:

+ 3 - 2
fs-service/src/main/resources/application-config-druid-sczy.yml

@@ -78,8 +78,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: sczy-1323137866
   app_id: 1323137866
   region: ap-chongqing
@@ -101,6 +101,7 @@ headerImg:
 ipad:
   ipadUrl: http://ipad.beijingzhuomei.com
   aiApi:
+  wxIpadUrl:
   voiceApi:
   commonApi:
 wx_miniapp_temp:

+ 3 - 4
fs-service/src/main/resources/application-druid-qdtst.yml

@@ -47,10 +47,9 @@ spring:
                 # 从库数据源
                 slave:
                     # 从数据源开关/默认关闭
-                    enabled: false
-                    url:
-                    username:
-                    password:
+                    url: jdbc:mysql://10.206.0.2:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_1q2w3e4r5t6y
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量

+ 10 - 0
fs-service/src/main/resources/mapper/course/FsCourseLinkMapper.xml

@@ -47,6 +47,16 @@
         where link_id = #{linkId}
     </select>
 
+    <select id="selectFsCourseLinkListByQwUserId" resultType="com.fs.course.dto.FsCourseLinkDTO">
+        select l.link_id,l.real_link,l.create_time,l.update_time,l.company_id,l.company_user_id,l.qw_user_id,l.video_id,l.corp_id,l.course_id,l.qw_external_id,l.link_type,l.chat_id,l.is_room,l.u_no,
+               c.img_url courseUrl,c.course_name courseName,c.title
+        from fs_course_link l left join fs_user_course c on  c.course_id=l.course_id where create_time &gt;= CURDATE() AND create_time &lt; CURDATE() + INTERVAL 1 DAY
+                                                                                       and l.qw_user_id = #{qwUserId} and l.qw_external_id = #{qwExternalId}
+    </select>
+    <select id="selectLinkByCourseIdAndExIdAndQwUserId" resultType="FsCourseLink">
+        select l.link_id,l.real_link,l.create_time,l.update_time,l.company_id,l.company_user_id,l.qw_user_id,l.video_id,l.corp_id,l.course_id,l.qw_external_id,l.link_type,l.chat_id,l.is_room,l.u_no from  fs_course_link l where l.course_id=#{courseId} and l.qw_external_id=#{qwExternalContactId} and l.qw_user_id=#{qwUserId} and l.video_id = #{videoId}
+    </select>
+
     <insert id="insertFsCourseLink" parameterType="FsCourseLink" useGeneratedKeys="true" keyProperty="linkId">
         insert into fs_course_link
         <trim prefix="(" suffix=")" suffixOverrides=",">

+ 9 - 0
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -1339,4 +1339,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </choose>
         ORDER BY accessCount desc
     </select>
+    <select id="getSopCourseH5StudyList" resultType="com.fs.course.vo.FsSopMyCourseH5LinkVO">
+        select  c.img_url courseUrl,v.title courseName,c.title,l.log_id logId,u.qw_user_name qwUserName from fs_course_watch_log l
+             left join fs_user_course c on c.course_id = l.course_id
+             left join qw_user u on l.qw_user_id = u.id
+             left join fs_user_course_video v on l.video_id =v.video_id
+        where l.user_id = #{userId}  AND l.create_time &gt;= CURDATE()
+          AND l.create_time &lt; CURDATE() + INTERVAL 1 DAY
+        order by l.create_time desc
+    </select>
 </mapper>

+ 9 - 0
fs-service/src/main/resources/mapper/live/LiveMapper.xml

@@ -363,6 +363,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         a.company_id is null)
         order by create_time desc
     </select>
+    <select id="selectLiveListNew" resultType="com.fs.live.domain.Live">
+        <include refid="selectLiveVo"/>
+        where is_audit = 1 and is_del = 0 and is_show = 1 and status != 3
+                               and (company_id = #{companyId} or company_id is null)
+        <if test="liveName != null">
+            and live_name like concat('%',#{liveName},'%')
+        </if>
+
+    </select>
 
     <select id="selectLiveIdsByCompanyParam" resultType="java.lang.Long">
         SELECT l.live_id

+ 4 - 0
fs-service/src/main/resources/mapper/live/LiveVideoMapper.xml

@@ -44,6 +44,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectLiveVideoVo"/>
         where video_id = #{videoId} and company_id = #{companyId} and company_user_id = #{companyUserId}
     </select>
+    <select id="selectByLiveIdAndType" resultType="com.fs.live.domain.LiveVideo">
+        <include refid="selectLiveVideoVo"/>
+        where live_id = #{liveId} and video_type = #{videoType}
+    </select>
 
     <insert id="insertLiveVideo" parameterType="LiveVideo" useGeneratedKeys="true" keyProperty="videoId">
         insert into live_video

+ 11 - 0
fs-service/src/main/resources/mapper/qw/QwUserMapper.xml

@@ -231,6 +231,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
     </select>
 
+    <select id="selectQwUserByQwUserIds" resultType="com.fs.qw.domain.QwUser">
+        <include refid="selectQwUserVo"/>
+        WHERE qw_user_id IN
+        <foreach item="userId" collection="list" open="(" separator="," close=")">
+            #{userId}
+        </foreach>
+    </select>
 
     <select id="selectQwWorkTaskList" resultType="com.fs.qw.domain.QwWorkTask">
         select
@@ -328,5 +335,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              #{serverId}
          </foreach>
     </select>
+    <select id="getQwUserCompanyInfo" resultType="com.fs.qw.vo.QwUserVO">
+        select qu.qw_user_id,qu.qw_user_name,c.company_name from qw_user qu left join company c on qu.company_id = c.company_id
+        where qu.id = #{qwUserId}
+    </select>
 
 </mapper>

+ 12 - 0
fs-service/src/main/resources/mapper/sop/QwSopLogsMapper.xml

@@ -780,6 +780,18 @@
     <select id="queryAllPeriod" resultType="com.fs.sop.domain.QwSopLogs">
         select id,concat(qw_user_id,'-',start_time) as sop_title from sop_user_logs
     </select>
+    <select id="queryAllPeriodNew" resultType="com.fs.sop.domain.SopUserLogs">
+        select id,start_time as startTime,qw_user_id as qwUserId from sop_user_logs
+        <where>
+            <if test="userIds != null and !userIds.isEmpty()">
+                AND (
+                <foreach collection="userIds" item="userId" separator=" OR ">
+                    FIND_IN_SET(#{userId}, REPLACE(user_id, '|', ',')) > 0
+                </foreach>
+                )
+            </if>
+        </where>
+    </select>
     <select id="selectQwSopLogsCountByQwUserId" resultType="java.lang.Long">
         select count(1) from qw_sop_logs
         <where>

+ 42 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseController.java

@@ -8,6 +8,7 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.*;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.param.*;
 import com.fs.course.service.*;
 import com.fs.course.vo.*;
@@ -50,6 +51,12 @@ public class CourseController extends  AppBaseController{
     private IFsCourseSopAppLinkService courseSopAppLinkService;
     @Autowired
     ITencentCloudCosService tencentCloudCosService;
+    @Autowired
+    private IFsCourseWatchLogService courseWatchLogService;
+    @Autowired
+    private IFsCourseLinkService linkService;
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
 
 //    @Cacheable(value="getCourseCate" )
     @ApiOperation("获取分类")
@@ -355,4 +362,39 @@ public class CourseController extends  AppBaseController{
         log.info("zyp \n【发放APP奖励】:{}",param);
         return courseVideoService.sendAppReward(param);
     }
+
+    @ApiOperation("加密链接参数")
+    @PostMapping("/encryptLink")
+    @Login
+    public R encryptLink(@RequestBody FsCourseEncryptLinkParam param) {
+        return courseWatchLogService.encryptLink(param.getUrl());
+    }
+
+    @ApiOperation("解密链接参数")
+    @PostMapping("/decryptLink")
+    public R decryptLink(@RequestBody FsCourseEncryptLinkParam param) {
+        return courseWatchLogService.decryptLink(param.getUrl());
+    }
+
+
+    @ApiOperation("获取我的sop课程")
+    @PostMapping("/getSopCourseH5StudyList")
+    public R getSopCourseH5StudyList(@RequestBody FsCourseH5ListParam  param ){
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        long userId = Long.parseLong(getUserId());
+//        long userId = param.getUserId();
+        List<FsSopMyCourseH5LinkVO> list = fsCourseWatchLogMapper.getSopCourseH5StudyList(userId);
+
+//        FsCourseLinkDTO linkVO = linkService.selectFsCourseLinkListByQwUserId(param);
+
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+    @ApiOperation("获取我的sop课程详情")
+    @PostMapping("/getSopCourseH5StudyInfo")
+    public R getSopCourseH5StudyInfo(@RequestBody FsCourseH5ListParam  param ){
+        // 查询看课记录
+        return linkService.getLinkInfo(param.getLogId());
+    }
 }

+ 40 - 0
fs-user-app/src/main/java/com/fs/app/controller/UserController.java

@@ -10,6 +10,7 @@ import com.fs.app.annotation.Login;
 import com.fs.app.param.FsDoctorRegisterParam;
 import com.fs.app.param.FsUserEditParam;
 import com.fs.app.param.FsUserPhoneUpdateParam;
+import com.fs.app.param.FsUserInfoParam;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.exception.CustomException;
@@ -31,7 +32,11 @@ import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserCouponCountUVO;
 import com.fs.his.vo.FsUserCouponListUVO;
 import com.fs.his.vo.UserVo;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.service.IQwAppContactWayService;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwUserService;
+import com.fs.qw.vo.QwUserVO;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import com.github.pagehelper.PageHelper;
@@ -84,9 +89,15 @@ public class UserController extends  AppBaseController {
     @Autowired
     private IFsUserCourseVideoService courseVideoService;
 
+    @Autowired
+    private IQwUserService qwUserService;
 
     @Autowired
     private IFsUserService fsUserService;
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
     @Login
     @ApiOperation("获取用户信息")
     @PostMapping("/friendsSearch")
@@ -410,4 +421,33 @@ public class UserController extends  AppBaseController {
         }
         return R.error("授权失败,请联系管理员");
     }
+
+    /**
+     * @Description: 获取用户信息,包含经销商
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2026/1/9 13:37
+     */
+    @Login
+    @ApiOperation("获取用户信息")
+    @GetMapping("/getUserInfoByQwUser")
+    public R getUserInfoByQwUser(FsUserInfoParam param , HttpServletRequest request){
+        FsUser user=userService.selectFsUserByUserId(Long.parseLong(getUserId()));
+        if(user != null && param.getQwExternalId() != null){
+            QwExternalContact qwExternalContact = qwExternalContactService.selectQwExternalContactById(param.getQwExternalId());
+            if(qwExternalContact != null && qwExternalContact.getFsUserId() == null){
+                QwExternalContact qwExtContact = new QwExternalContact();
+                qwExtContact.setId(qwExternalContact.getId());
+                qwExtContact.setFsUserId(user.getUserId());
+                qwExternalContactService.updateQwExternalContactBindUserId(qwExtContact);
+            }
+        }
+//        FsUser user=userService.selectFsUserByUserId(param.getUserId());
+        QwUserVO qwUserVO =qwUserService.getQwUserCompanyInfo(Long.parseLong(param.getQwUserId()));
+        Map<String,Object> map=new HashMap<>();
+        map.put("user",user);
+        map.put("qwUser",qwUserVO);
+        return R.ok().put("data",map);
+    }
 }

+ 35 - 14
fs-user-app/src/main/java/com/fs/app/controller/live/LiveController.java

@@ -15,29 +15,20 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.common.utils.http.HttpUtils;
-import com.fs.company.domain.Company;
-import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.service.ICompanyUserService;
-import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.service.IFsStoreOrderScrmService;
-import com.fs.live.domain.LiveOrder;
-import java.math.BigDecimal;
-import java.util.Date;
-import com.fs.erp.domain.ErpDeliverys;
-import com.fs.erp.domain.ErpOrderQuery;
-import com.fs.erp.dto.ErpOrderQueryRequert;
-import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import com.fs.live.domain.*;
 import com.fs.live.mapper.LiveVideoMapper;
 import com.fs.live.mapper.LiveWatchUserMapper;
+import com.fs.live.param.FsLiveEncryptLinkParam;
 import com.fs.live.param.LiveNotifyParam;
 import com.fs.live.service.*;
 import com.fs.live.vo.LiveVo;
@@ -52,15 +43,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
 import java.util.*;
-import java.util.stream.Collectors;
-
-import static com.fs.hisStore.constants.StoreConstants.DELIVERY;
 
 
 @Api("直播信息接口")
@@ -209,6 +196,22 @@ public class LiveController extends AppBaseController {
 	}
 
 
+	@Login
+	@ApiOperation("直播间列表")
+	@PostMapping("/newLiveList")
+	@ApiResponse(code = 200, message = "", response = LiveInfoVo.class)
+	public R liveCompanyList(@RequestBody Live live) {
+		try {
+			PageHelper.startPage(live.getPageNum() , live.getPageSize());
+			List<Live> list = liveService.selectLiveListNew(live);
+			PageInfo<Live> result = new PageInfo<>(list);
+			return R.ok().put("data", result);
+		} catch (Exception e) {
+			return R.error("操作异常");
+		}
+	}
+
+
 	@Login
 	@ApiOperation("聊天记录(最新30条)")
 	@GetMapping("/msgList")
@@ -410,6 +413,24 @@ public class LiveController extends AppBaseController {
 	}
 
 
+	@ApiOperation("加密链接参数")
+	@PostMapping("/encryptLink")
+	@Login
+	public R encryptLink(@RequestBody FsLiveEncryptLinkParam param) {
+		return liveService.liveEncryptLink(param.getUrl());
+	}
+
+	@ApiOperation("解密链接参数")
+	@PostMapping("/decryptLink")
+	public R decryptLink(@RequestBody FsLiveEncryptLinkParam param) {
+		return liveService.liveDecryptLink(param.getUrl());
+	}
+
+	@ApiOperation("获取微信小程序企微信息")
+	@PostMapping("/getLiveQwUserInfo/{qwUserId}")
+	public R getLiveQwUserInfo(@PathVariable Long qwUserId) {
+		return liveService.getLiveQwUserInfo(qwUserId);
+	}
 
 
 }

+ 20 - 0
fs-user-app/src/main/java/com/fs/app/param/FsUserInfoParam.java

@@ -0,0 +1,20 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsUserInfoParam implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String qwUserId;
+
+    private String corpId;
+
+    private Long userId;
+
+    //外部联系人id
+    private Long qwExternalId;
+}