|
@@ -66,6 +66,7 @@ import com.fs.system.domain.SysConfig;
|
|
|
import com.fs.system.mapper.SysDictDataMapper;
|
|
import com.fs.system.mapper.SysDictDataMapper;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.voice.utils.StringUtil;
|
|
import com.fs.voice.utils.StringUtil;
|
|
|
|
|
+import com.fs.xiaoshouyi.service.XiaoShouYiTrackLinkCacheService;
|
|
|
import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
|
|
import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
|
|
|
import com.google.common.collect.Sets;
|
|
import com.google.common.collect.Sets;
|
|
|
import com.volcengine.service.vod.IVodService;
|
|
import com.volcengine.service.vod.IVodService;
|
|
@@ -262,7 +263,16 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private RedPacketMapper redPacketMapper;
|
|
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);
|
|
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获取,不存在则查数据库)
|
|
* 获取视频时长(优先从Redis获取,不存在则查数据库)
|