|
@@ -0,0 +1,315 @@
|
|
|
|
|
+package com.fs.qw.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.fs.course.domain.FsCourseWatchLog;
|
|
|
|
|
+import com.fs.course.service.IFsUserCourseVideoService;
|
|
|
|
|
+import com.fs.course.vo.FsUserCourseVideoTagVO;
|
|
|
|
|
+import com.fs.qw.domain.*;
|
|
|
|
|
+import com.fs.qw.mapper.QwExternalContactMapper;
|
|
|
|
|
+import com.fs.qw.mapper.QwTagMapper;
|
|
|
|
|
+import com.fs.qw.mapper.QwUserMapper;
|
|
|
|
|
+import com.fs.qw.service.IQwCourseFinishTagRtyService;
|
|
|
|
|
+import com.fs.qw.service.IQwExternalContactService;
|
|
|
|
|
+import com.fs.qw.service.IQwTagGroupService;
|
|
|
|
|
+import com.fs.qw.service.IQwTagService;
|
|
|
|
|
+import com.fs.qw.vo.QwTagGroupAddParam;
|
|
|
|
|
+import com.fs.qw.vo.QwTagVO;
|
|
|
|
|
+import com.fs.qwApi.domain.QwAddTagResult;
|
|
|
|
|
+import com.fs.qwApi.domain.QwResult;
|
|
|
|
|
+import com.fs.qwApi.domain.inner.InTag;
|
|
|
|
|
+import com.fs.qwApi.domain.inner.TagData;
|
|
|
|
|
+import com.fs.qwApi.param.QwAddTagParam;
|
|
|
|
|
+import com.fs.qwApi.param.QwEditUserTagParam;
|
|
|
|
|
+import com.fs.qwApi.service.QwApiService;
|
|
|
|
|
+import com.fs.voice.utils.StringUtil;
|
|
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import java.time.LocalDate;
|
|
|
|
|
+import java.time.LocalTime;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+@AllArgsConstructor
|
|
|
|
|
+public class AsyncFinishCourseTakeTag {
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IQwExternalContactService iQwExternalContactService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private QwApiService qwApiService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private QwExternalContactMapper qwExternalContactMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IFsUserCourseVideoService videoService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IQwTagService tagService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private QwTagMapper qwTagMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IQwTagGroupService qwTagGroupService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private QwExternalContactServiceImpl qwExternalContactService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IQwCourseFinishTagRtyService tagRtyService;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 完课打把标签统一方法
|
|
|
|
|
+ */
|
|
|
|
|
+ @Async("scheduledExecutorService")
|
|
|
|
|
+ public void finishCourseTakeTag(FsCourseWatchLog watchLog, QwUser qwUserByRedisForId) {
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ FsUserCourseVideoTagVO tagVO = videoService.selectFsUserCourseVideoByCourseVideoId(watchLog.getVideoId());
|
|
|
|
|
+
|
|
|
|
|
+ // 主体的标签是否超过1万个
|
|
|
|
|
+ int tagNum = tagService.countQwTagNumByCorpId(qwUserByRedisForId.getCorpId());
|
|
|
|
|
+ //将要打的标签
|
|
|
|
|
+ String videoTagId="";
|
|
|
|
|
+ //视频的 课程和课节的 标签描述 不为空,总标签数小于等于10000
|
|
|
|
|
+ if (tagVO!=null && !StringUtil.strIsNullOrEmpty(tagVO.getVideoDescription())
|
|
|
|
|
+ && !StringUtil.strIsNullOrEmpty(tagVO.getCourseDescription())
|
|
|
|
|
+ && tagNum <= 10000) {
|
|
|
|
|
+ log.info("满足打标签条件-,{},{}",tagVO,tagNum);
|
|
|
|
|
+ //根据 描述去查 主体里的标签库 是否有这个标签,没有就新建(不能超过1W),有就直接用
|
|
|
|
|
+ QwTagVO qwTagVO = qwTagMapper.selectQwTagByName(tagVO.getVideoDescription(), qwUserByRedisForId.getCorpId());
|
|
|
|
|
+ QwTagGroup tagGroup = qwTagGroupService.selectQwTagGroupByCourseName(tagVO.getCourseDescription());
|
|
|
|
|
+ //如果标签组和标签都为空 则新建标签
|
|
|
|
|
+ if (tagGroup==null && qwTagVO == null) {
|
|
|
|
|
+ QwTagGroupAddParam qwTagGroup=new QwTagGroupAddParam();
|
|
|
|
|
+
|
|
|
|
|
+ qwTagGroup.setName(tagVO.getCourseDescription());
|
|
|
|
|
+ qwTagGroup.setCorpId(qwUserByRedisForId.getCorpId());
|
|
|
|
|
+
|
|
|
|
|
+ List<QwTag> QwTags = new ArrayList<>();
|
|
|
|
|
+ QwTag tag = new QwTag();
|
|
|
|
|
+ tag.setName(tagVO.getVideoDescription());
|
|
|
|
|
+ QwTags.add(tag);
|
|
|
|
|
+ qwTagGroup.setTag(QwTags);
|
|
|
|
|
+
|
|
|
|
|
+ //添加 标签/标签组
|
|
|
|
|
+ int i = qwTagGroupService.insertQwTagGroupParam(qwTagGroup);
|
|
|
|
|
+
|
|
|
|
|
+ // 加好了之后再去查 标签id
|
|
|
|
|
+ QwTagVO qwTagNew = qwTagMapper.selectQwTagByName(tagVO.getVideoDescription(), qwUserByRedisForId.getCorpId());
|
|
|
|
|
+
|
|
|
|
|
+ //获取到的 标签id
|
|
|
|
|
+ videoTagId= qwTagNew.getTagId();
|
|
|
|
|
+
|
|
|
|
|
+ }else
|
|
|
|
|
+ //如果标签组不为空,这个标签没查到,则只在这个标签下 在这个标签组里新增一个标签
|
|
|
|
|
+ if (tagGroup!=null && qwTagVO == null) {
|
|
|
|
|
+
|
|
|
|
|
+ QwAddTagParam qwAddTagParam = new QwAddTagParam();
|
|
|
|
|
+ qwAddTagParam.setGroup_id(tagGroup.getGroupId());
|
|
|
|
|
+ TagData tagData = new TagData();
|
|
|
|
|
+ tagData.setName(tagVO.getVideoDescription());
|
|
|
|
|
+ List<TagData> list = Arrays.asList(tagData);
|
|
|
|
|
+ qwAddTagParam.setTag(list);
|
|
|
|
|
+ QwAddTagResult result = qwApiService.addTag(qwAddTagParam, qwUserByRedisForId.getCorpId());
|
|
|
|
|
+ if (result.getErrcode() == 0) {
|
|
|
|
|
+ List<InTag> addTag = result.getTag_group().getTag();
|
|
|
|
|
+ if (addTag != null && addTag.size() > 0) {
|
|
|
|
|
+ QwTag addQwTag = new QwTag();
|
|
|
|
|
+ addQwTag.setGroupId(tagGroup.getGroupId());
|
|
|
|
|
+ addQwTag.setTagId(addTag.get(0).getId());
|
|
|
|
|
+ addQwTag.setOrder(addTag.get(0).getOrder());
|
|
|
|
|
+ addQwTag.setName(addTag.get(0).getName());
|
|
|
|
|
+ addQwTag.setCorpId(qwUserByRedisForId.getCorpId());
|
|
|
|
|
+ addQwTag.setCreateTime(new Date(addTag.get(0).getCreate_time()));
|
|
|
|
|
+ addQwTag.setTagFrom(1);
|
|
|
|
|
+ qwTagMapper.insertQwTag(addQwTag);
|
|
|
|
|
+
|
|
|
|
|
+ //获取到的 标签id
|
|
|
|
|
+ videoTagId= addQwTag.getTagId();
|
|
|
|
|
+ }
|
|
|
|
|
+ }else {
|
|
|
|
|
+ log.error("完课打标签-添加标签失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ //都不为空,拿到标签id
|
|
|
|
|
+ if (tagGroup != null && qwTagVO!=null) {
|
|
|
|
|
+ videoTagId=qwTagVO.getTagId();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }else {
|
|
|
|
|
+ log.error("完课打标签-获取标签组失败:-"+tagVO+"数量:-"+tagNum+"视频:"+videoTagId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (!StringUtil.strIsNullOrEmpty(videoTagId)){
|
|
|
|
|
+
|
|
|
|
|
+ Long qwExternalContactId = watchLog.getQwExternalContactId();
|
|
|
|
|
+ QwExternalContact externalContact = iQwExternalContactService.selectQwExternalContactByRemark(qwExternalContactId);
|
|
|
|
|
+
|
|
|
|
|
+ if (externalContact != null) {
|
|
|
|
|
+
|
|
|
|
|
+ //组装标签
|
|
|
|
|
+ List<String> tagIds11111=new ArrayList<>();
|
|
|
|
|
+ tagIds11111.add(videoTagId);
|
|
|
|
|
+
|
|
|
|
|
+ QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
|
|
|
|
|
+ qwEditUserTagParam.setAdd_tag(tagIds11111);
|
|
|
|
|
+ qwEditUserTagParam.setUserid(externalContact.getUserId());
|
|
|
|
|
+ qwEditUserTagParam.setExternal_userid(externalContact.getExternalUserId());
|
|
|
|
|
+
|
|
|
|
|
+ for (int attempt = 1; attempt <= 3; attempt++) { // 增加到3次重试
|
|
|
|
|
+ try {
|
|
|
|
|
+ QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, qwUserByRedisForId.getCorpId());
|
|
|
|
|
+ if (qwResult.getErrcode() == 0) {
|
|
|
|
|
+
|
|
|
|
|
+ // 处理标签
|
|
|
|
|
+ String oldtagIds = externalContact.getTagIds();
|
|
|
|
|
+ Set<String> uniqueIds = new HashSet<>();
|
|
|
|
|
+
|
|
|
|
|
+ if (oldtagIds != null && !oldtagIds.isEmpty()) {
|
|
|
|
|
+ List<String> parsedTags = JSON.parseArray(oldtagIds, String.class);
|
|
|
|
|
+ if (parsedTags != null && !parsedTags.isEmpty()) {
|
|
|
|
|
+ uniqueIds.addAll(parsedTags);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (qwEditUserTagParam.getAdd_tag() != null && !qwEditUserTagParam.getAdd_tag().isEmpty()) {
|
|
|
|
|
+ uniqueIds.addAll(qwEditUserTagParam.getAdd_tag());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ QwExternalContact qwExternal = new QwExternalContact();
|
|
|
|
|
+ qwExternal.setTagIds(JSON.toJSONString(uniqueIds));
|
|
|
|
|
+ qwExternal.setId(externalContact.getId());
|
|
|
|
|
+//先不走打标签走sop逻辑
|
|
|
|
|
+// List<String> tagIdsList = new ArrayList<>();
|
|
|
|
|
+// if (qwExternal.getTagIds() != null && !qwExternal.getTagIds().isEmpty()) {
|
|
|
|
|
+// tagIdsList = JSON.parseArray(qwExternal.getTagIds(), String.class);
|
|
|
|
|
+// }
|
|
|
|
|
+//
|
|
|
|
|
+// LocalDate currentDate = LocalDate.now();
|
|
|
|
|
+// // 获取当前系统时间 (HH:mm)
|
|
|
|
|
+// LocalTime localTime = LocalTime.now();
|
|
|
|
|
+// // 插件sop处理
|
|
|
|
|
+// qwExternalContactService.processTagsAll(externalContact, externalContact.getCorpId(),
|
|
|
|
|
+// tagIdsList, currentDate, localTime);
|
|
|
|
|
+
|
|
|
|
|
+ qwExternalContactMapper.updateQwExternalContact(externalContact);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("客户完课添加标签addUserTag:" + externalContact.getName() +"|"+externalContact.getId()+
|
|
|
|
|
+ "|公司" + externalContact.getCorpId() +
|
|
|
|
|
+ "|员工" + externalContact.getUserId() +
|
|
|
|
|
+ "|添加的标签" + JSON.toJSONString(tagIds11111));
|
|
|
|
|
+ break;
|
|
|
|
|
+ } else {
|
|
|
|
|
+
|
|
|
|
|
+ // 根据错误码智能处理
|
|
|
|
|
+ if (isRateLimitError(qwResult.getErrcode())) {
|
|
|
|
|
+ // 保存到重试表
|
|
|
|
|
+ saveToRetryTableTag(externalContact, videoTagId);
|
|
|
|
|
+
|
|
|
|
|
+ // 智能延迟
|
|
|
|
|
+ if (attempt < 3) {
|
|
|
|
|
+ smartDelayByErrorCode(qwResult.getErrcode(), attempt);
|
|
|
|
|
+ continue; // 继续重试
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ log.error("完课加标签失败:{}|{}|{}|{}|{}|原因{}",
|
|
|
|
|
+ externalContact.getName(), externalContact.getExternalUserId(),
|
|
|
|
|
+ externalContact.getCorpId(), externalContact.getUserId(),
|
|
|
|
|
+ videoTagId, qwResult.getErrmsg());
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("添加标签异常 [尝试第 {} 次]:{}|{}|{}|{}|{}|{}",
|
|
|
|
|
+ attempt, externalContact.getName(), externalContact.getExternalUserId(),
|
|
|
|
|
+ externalContact.getCorpId(), externalContact.getUserId(),
|
|
|
|
|
+ videoTagId, e.getMessage());
|
|
|
|
|
+
|
|
|
|
|
+ if (attempt < 3) {
|
|
|
|
|
+ smartDelayByErrorCode(-1, attempt);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 若不是最后一次尝试,则等待3秒再试
|
|
|
|
|
+ if (attempt < 2) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Thread.sleep(3000);
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ log.warn("线程等待被中断", e);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }else {
|
|
|
|
|
+ log.error("完课加标签失败无客户信息:" + watchLog);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }else {
|
|
|
|
|
+ log.error("完课打标签-获取标签id失败,{},{}",videoTagId,watchLog);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }catch (Exception e){
|
|
|
|
|
+ log.error("完课打标签失败,{}",watchLog,e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存到重试表-标签
|
|
|
|
|
+ */
|
|
|
|
|
+ private void saveToRetryTableTag(QwExternalContact externalContact, String tagId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ QwCourseFinishTagRty tagRty=new QwCourseFinishTagRty();
|
|
|
|
|
+ tagRty.setQwUserId(externalContact.getUserId());
|
|
|
|
|
+ tagRty.setCorpId(externalContact.getCorpId());
|
|
|
|
|
+ tagRty.setExternalUserId(externalContact.getExternalUserId());
|
|
|
|
|
+ tagRty.setExternalId(externalContact.getId());
|
|
|
|
|
+ tagRty.setTagIds(tagId);
|
|
|
|
|
+ tagRty.setCreateTime(new Date());
|
|
|
|
|
+ tagRtyService.insertQwCourseFinishTagRty(tagRty);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("保存重试记录失败", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 根据错误码智能延迟
|
|
|
|
|
+ */
|
|
|
|
|
+ private void smartDelayByErrorCode(Integer errcode, int attempt) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ long delayMs;
|
|
|
|
|
+ if (errcode == 45033) { // 并发限制
|
|
|
|
|
+ delayMs = 5000 + attempt * 2000L; // 递增延迟
|
|
|
|
|
+ } else if (errcode == 60020) { // 频率限制
|
|
|
|
|
+ delayMs = 3000 + attempt * 1000L;
|
|
|
|
|
+ } else if (errcode == -1) { // 系统繁忙
|
|
|
|
|
+ delayMs = 2000;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ delayMs = 1000; // 默认延迟
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("因错误码 {} 延迟 {}ms", errcode, delayMs);
|
|
|
|
|
+ Thread.sleep(delayMs);
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断是否为频率限制类错误
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean isRateLimitError(Integer errcode) {
|
|
|
|
|
+ return errcode == 45033 || errcode == 60020 || errcode == -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|