Преглед изворни кода

生成侧边栏发送销售易课程链接

cgp пре 20 часа
родитељ
комит
161b02f578

+ 1 - 1
fs-admin/src/main/java/com/fs/his/task/JhmTask.java

@@ -174,7 +174,7 @@ public class JhmTask {
         List<JHMOrderDetail> allOrders = new ArrayList<>();
         int page = 1;
         int pageSize = 100;
-        long sevenDaysAgo = System.currentTimeMillis() / 1000 - 7 * 24 * 3600;
+        long sevenDaysAgo = System.currentTimeMillis() / 1000 - 30 * 24 * 3600;
         long now = System.currentTimeMillis() / 1000;
 
         ParameterizedTypeReference<JHMBaseResponse<JHMOrderInfoData>> responseType =

+ 2 - 1
fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -160,7 +160,8 @@ public class ApisFsUserCourseVideoController extends BaseController {
         if (qwUser==null||qwUser.getCompanyId()==null){
             return R.error("无权限");
         }
-        return fsUserCourseVideoService.createRoomMiniLink(param);
+        // return fsUserCourseVideoService.createRoomMiniLink(param); 这个方法已弃用
+        return fsUserCourseVideoService.createSaleEasyRoomMiniLink(param,qwUser.getCompanyUserId());//生成销售易群发课程链接
     }
 
 }

+ 6 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -1,6 +1,7 @@
 package com.fs.course.service;
 
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.param.*;
@@ -239,4 +240,9 @@ public interface IFsUserCourseVideoService
      * 飞书看课流量统计
      */
     void getFeiShuInternetTraffic(Long identifier, Long companyUserId, Long videoId, String uuid, BigDecimal bufferRate);
+
+    /**
+     * 侧边栏发销售易课程链接(群发)
+     * */
+    R createSaleEasyRoomMiniLink(FsCourseLinkMiniParam param,Long companyUserId);
 }

+ 157 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -66,6 +66,7 @@ import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysDictDataMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
+import com.fs.xiaoshouyi.service.XiaoShouYiTrackLinkCacheService;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import com.google.common.collect.Sets;
 import com.volcengine.service.vod.IVodService;
@@ -262,7 +263,16 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     private RedPacketMapper redPacketMapper;
 
+    @Autowired
+    private XiaoShouYiTrackLinkCacheService xiaoShouYiTrackLinkCacheService;
+
+    @Autowired
+    private FsUserCourseMapper courseMapper;
 
+    private final BlockingQueue<FsCourseWatchLog> watchLogsQueue = new LinkedBlockingQueue<>(20000);
+
+
+    private static final String gjminiappLink = "/pages/course/learning?course=";
 
     /**
      * 查询课堂视频
@@ -3725,6 +3735,153 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         asyncDeductTraffic(company, trafficLog);
     }
 
+    /**
+     * 侧边栏发销售易课程链接(群发)
+     * */
+    @Override
+    public R createSaleEasyRoomMiniLink(FsCourseLinkMiniParam param,Long companyUserId) {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
+
+        if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
+            return R.error("员工未绑定 销售公司 或 销售 请先绑定");
+        }
+
+        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(param.getCorpId());
+
+        if (qwCompany == null ) {
+            return  R.error().put("msg","企业不存在,请联系管理员");
+        }
+        String corpId = param.getCorpId();
+        Long courseId = param.getCourseId();
+        String qwUserId = param.getQwUserId();
+        Date createTime = DateUtils.getNowDate();
+        Long externalUserId = param.getExternalUserId();
+        Long videoId = param.getVideoId();
+        Long companyId = qwCompany.getId();
+        //生成群发链接;在生成阶段不生成看课记录,客户点击观看才生成
+        //addWatchLogIfNeeded(param.getFsUserId(), param.getVideoId(), param.getCourseId(),createTime, param.getQwUserId(), companyUserId, companyUser.getCompanyId(), param.getExternalUserId());
+
+        Map<String, String> linkMap = createH5GjLinkByMiniApp(corpId, createTime, courseId.intValue(), videoId.intValue(),
+                qwUserId, companyUserId, companyId, externalUserId, config);
+        String link = linkMap.get("url");
+        String linkNo = linkMap.get("link");
+
+        FsUserCourse userCourse = courseMapper.selectFsUserCourseByCourseId(courseId);
+        if (userCourse == null){
+            throw new CustomException("课程不存在,请检查");
+        }
+        String imgUrl = userCourse.getImgUrl();
+        String linkTitle = userCourse.getTitle();
+        String templateTitle = "【课程】" + linkTitle;
+        String templateContent = "点击查看课程";
+        String xsyCommonLink= xiaoShouYiTrackLinkCacheService.applyTrackRedirectUrl(corpId, String.valueOf(companyUserId), qwUserId, courseId, videoId, String.valueOf(externalUserId), link, imgUrl,linkTitle,templateTitle,templateContent,linkNo);
+        JSONObject news = new JSONObject(true);
+        // 获取配置的小程序id
+        QwAppMiniProgramRelation qwAppMiniProgramRelation = qwAppMiniProgramRelationMapper.selectQwAppMiniProgramRelationByAgentIdAndCorpId(param.getAppAgentId(), param.getCorpId());
+        if (qwAppMiniProgramRelation == null){
+            log.error("createSaleEasyRoomMiniLink()未找到侧边栏配置的小程序,appAgentId:{},corpId:{}", param.getAppAgentId(), param.getCorpId());
+            news.put("miniprogramAppid", qwCompany.getMiniAppId());
+        }else{
+            news.put("miniprogramAppid", qwAppMiniProgramRelation.getMiniAppId());
+        }
+        news.put("miniprogramTitle", param.getTitle());
+        news.put("miniprogramPicUrl", config.getSidebarImageUrl());
+        news.put("miniprogramPage", xsyCommonLink);
+
+        return R.ok().put("data",news);
+    }
+
+    private Map<String, String> createH5GjLinkByMiniApp(String corpId, Date sendTime,
+                                                        Integer courseId, Integer videoId, String qwUserId,
+                                                        Long companyUserId, Long 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 = gjminiappLink + courseJson;
+        if (StringUtils.isNotEmpty(config.getRealLinkGjDomainName())) {
+            realLinkFull = config.getRealLinkGjDomainName() + realLinkFull;
+        }
+        link.setRealLink(realLinkFull);
+
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+        Map<String, String> result = new HashMap<>();
+        result.put("url", link.getRealLink());
+        result.put("link", link.getLink());
+        return result;
+    }
+
+    public FsCourseLink createFsCourseLink(String corpId, Date sendTime, Integer courseId, Integer videoId, Long qwUserId,
+                                           Long companyUserId, Long companyId, Long externalId, Integer type, String chatId) {
+        // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(companyId);
+        link.setQwUserId(qwUserId);
+        link.setCompanyUserId(companyUserId);
+        link.setVideoId(videoId.longValue());
+        link.setCorpId(corpId);
+        link.setCourseId(courseId.longValue());
+        link.setChatId(chatId);
+        link.setQwExternalId(externalId);
+        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);
+        link.setProjectCode(cloudHostProper.getProjectCode());
+
+        return link;
+    }
+
+    private void addWatchLogIfNeeded(Long fsUserId, Long videoId, Long courseId,
+                                     Date sendTime, String qwUserId, Long companyUserId,
+                                     Long companyId, Long externalId) {
+        FsCourseWatchLog watchLog = new FsCourseWatchLog();
+        watchLog.setVideoId(videoId);
+        watchLog.setQwExternalContactId(externalId);
+        watchLog.setSendType(2);
+        watchLog.setQwUserId(Long.parseLong(qwUserId));
+        watchLog.setDuration(0L);
+        watchLog.setCourseId(courseId);
+        watchLog.setCompanyUserId(companyUserId);
+        watchLog.setCompanyId(companyId);
+        watchLog.setCreateTime(sendTime);
+        watchLog.setUpdateTime(new Date());
+        watchLog.setLogType(3);
+        watchLog.setUserId(fsUserId);
+        enqueueWatchLog(watchLog);
+    }
+
+    /**
+     * 将 FsCourseWatchLog 放入队列
+     */
+    private void enqueueWatchLog(FsCourseWatchLog watchLog) {
+        try {
+            boolean offered = watchLogsQueue.offer(watchLog, 5, TimeUnit.SECONDS);
+            if (!offered) {
+                log.error("FsCourseWatchLog 队列已满,无法添加日志: {}", JSON.toJSONString(watchLog));
+                // 处理队列已满的情况,例如记录到失败队列或持久化存储
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.error("插入 FsCourseWatchLog 队列时被中断: {}", e.getMessage(), e);
+        }
+    }
+
 
     /**
      * 获取视频时长(优先从Redis获取,不存在则查数据库)

+ 26 - 0
fs-service/src/main/java/com/fs/xiaoshouyi/service/XiaoShouYiTrackLinkCacheService.java

@@ -181,6 +181,32 @@ public class XiaoShouYiTrackLinkCacheService {
         }
     }
 
+    /**
+     * 企业微信侧边栏 手动一键群发 尝试将原始短链替换为销售易追踪链接。
+     * 失败时不抛异常,按手动群发逻辑更新 sopLogs 状态并返回 null。
+     */
+    public String applyTrackRedirectUrl(String corpId, String companyUserId, String qwUserId,
+                                        Long courseId, Long videoId, String externalId, String rawLink, String imgUrl,
+                                        String linkTitle, String smsTemplateTitle, String smsTemplateContent,
+                                        String linkNo) {
+        try {
+
+            String xsyRedirectUrl = resolveAndCacheTrackRedirectUrl(
+                    corpId, companyUserId, qwUserId, courseId, videoId, externalId,
+                    rawLink, imgUrl, linkTitle, smsTemplateTitle, smsTemplateContent, linkNo);
+            log.info("销售易追踪链接处理成功。 qwUserId={}, externalId={}, redirectUrl={}",
+                    qwUserId,
+                    externalId, xsyRedirectUrl);
+            return xsyRedirectUrl;
+        } catch (XiaoShouYiSendVideoLimitExceededException e) {
+            return null;
+        } catch (Exception e) {
+            log.error("销售易素材处理失败,不影响主流程, externalId={}, rawLink={}",
+                    externalId,  rawLink, e);
+            return null;
+        }
+    }
+
     private String waitCacheFromRedis(String cacheKey, String extraParams, int waitSeconds) {
         long deadline = System.currentTimeMillis() + waitSeconds * 1000L;
         while (System.currentTimeMillis() < deadline) {