Browse Source

1、企微客户批量修改备注功能迁移

yfh 3 weeks ago
parent
commit
247242bd4f

+ 59 - 8
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java

@@ -7,6 +7,7 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.PubFun;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
@@ -23,10 +24,7 @@ import com.fs.his.service.IFsUserService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwTag;
 import com.fs.qw.param.*;
-import com.fs.qw.service.IQwExternalContactInfoService;
-import com.fs.qw.service.IQwExternalContactService;
-import com.fs.qw.service.IQwTagService;
-import com.fs.qw.service.IQwWatchLogService;
+import com.fs.qw.service.*;
 import com.fs.qw.vo.QwExternalContactVO;
 import com.fs.qw.vo.QwFsUserVO;
 import com.github.pagehelper.PageHelper;
@@ -40,10 +38,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
@@ -76,6 +71,10 @@ public class QwExternalContactController extends BaseController
     @Autowired
     private IQwExternalContactInfoService qwExternalContactInfoService;
 
+
+    @Autowired
+    private IQwUserServiceAsyncHelper qwUserServiceAsyncHelper;
+
     @Autowired
     private CompanyDeptServiceImpl companyDeptService;
 
@@ -575,5 +574,57 @@ public class QwExternalContactController extends BaseController
 
         return  qwExternalContactService.setCustomerCourseSopList(param);
     }
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:edit')")
+    @Log(title = "批量修改备注", businessType = BusinessType.UPDATE)
+    @PostMapping("/batchUpdateExternalContactNotes")
+    public R batchUpdateExternalContactNotes(@RequestBody QwExternalContactUpdateNoteParam param) throws JSONException {
+        if(param.isFilter()){
+            param.setUserIds(getList(param.getAddType(), param.getParam()));
+        }
+        if(param.getUserIds() == null || param.getUserIds().isEmpty()){
+            return R.error("修改用户为空");
+        }
+//        qwExternalContactService.batchUpdateExternalContactNotes(Param);
+        qwUserServiceAsyncHelper.batchUpdateExternalContactNotes(param);
+        return R.ok("正在批量修改备注中");
+    }
+
+
+
+    private List<Long> getList(Integer addType, QwExternalContactParam param){
+        if(addType == null){
+            return Collections.emptyList();
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if(addType == 0){
+            param.setCompanyId(loginUser.getCompany().getCompanyId());
+        }
+        if(addType == 1){
+            if(param.getQwUserId()==null){
+                return Collections.emptyList();
+            }
+            param.setCompanyId(loginUser.getCompany().getCompanyId());
+        }
+        if(addType == 2){
+            List<Long> combinedList = new ArrayList<>();
+            //本部门
+            Long deptId = loginUser.getUser().getDeptId();
+            if (deptId!=null){
+                combinedList.add(deptId);
+            }
+            //本部门的下级部门
+            List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+            if (!deptList.isEmpty()){
+                combinedList.addAll(deptList);
+            }
+
+            param.setCuDeptIdList(combinedList);
+            param.setUserType(loginUser.getUser().getUserType());
+            param.setCompanyId(loginUser.getCompany().getCompanyId());
+        }
+        List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(param);
+        if(list == null || list.isEmpty()) return Collections.emptyList();
+        return PubFun.listToNewList(list, QwExternalContactVO::getId);
+    }
 
 }

+ 2 - 1
fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java

@@ -62,7 +62,8 @@ public class FsCourseLink extends BaseEntity
 
     @ApiModelProperty(value = "营期课程id")
     private Long id;
-
+    // 识别编号
+    private String uNo;
 //    private String link_uuid;
 
 }

+ 3 - 0
fs-service/src/main/java/com/fs/qw/param/QwExternalContactUpdateNoteParam.java

@@ -10,4 +10,7 @@ public class QwExternalContactUpdateNoteParam {
     private String notes;
     private int type;
     private int nameType;
+    private Integer addType;
+    private boolean filter;
+    private QwExternalContactParam param;
 }

+ 323 - 0
fs-service/src/main/java/com/fs/qw/service/AsyncQwAiChatSopService.java

@@ -0,0 +1,323 @@
+package com.fs.qw.service;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.common.utils.date.DateUtil;
+import com.fs.company.service.ICompanyMiniappService;
+import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.FsCourseLink;
+import com.fs.course.domain.FsCourseRealLink;
+import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.mapper.FsCourseLinkMapper;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.fastGpt.domain.FastGptChatReplaceWords;
+import com.fs.fastGpt.mapper.FastGptChatReplaceWordsMapper;
+import com.fs.qw.domain.QwCompany;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.vo.QwSopRuleTimeVO;
+import com.fs.qw.vo.QwSopTempSetting;
+import com.fs.sop.domain.QwSopLogs;
+import com.fs.sop.domain.QwSopTempContent;
+import com.fs.sop.domain.QwSopTempVoice;
+import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.sop.mapper.QwSopMapper;
+import com.fs.sop.mapper.QwSopTempContentMapper;
+import com.fs.sop.params.QwSopAutoByTags;
+import com.fs.sop.service.IQwSopTempVoiceService;
+import com.fs.sop.service.impl.SopUserLogsInfoServiceImpl;
+import com.fs.system.service.ISysConfigService;
+import com.fs.voice.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+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.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class AsyncQwAiChatSopService {
+
+    private static final String miniappRealLink = "/pages_course/video.html?course=";
+
+    @Autowired
+    private QwSopMapper qwSopMapper;
+
+    @Autowired
+    private QwSopTempContentMapper qwSopTempContentMapper;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private SopUserLogsInfoServiceImpl sopUserLogsInfoService;
+    @Autowired
+    private FastGptChatReplaceWordsMapper fastGptChatReplaceWordsMapper;
+
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
+
+    @Autowired
+    private QwSopLogsMapper qwSopLogsMapper;
+
+    @Autowired
+    private FsCourseLinkMapper fsCourseLinkMapper;
+
+    @Autowired
+    private IQwCompanyService iQwCompanyService;
+
+    @Autowired
+    private ICompanyMiniappService companyMiniappService;
+
+
+    @Autowired
+    private IQwSopTempVoiceService sopTempVoiceService;
+
+    @Async("threadPoolTaskExecutor")
+    public void executeQwAiChatSop(QwSopAutoByTags qwSopAutoByTags, String userID,
+                                   QwUser qwUser, String externalUserID, String externalContactName,
+                                   Long externalId, Long fsUserId, LocalDate currentDate, LocalTime localTime) {
+
+        //新客对话任务
+        List<QwSopRuleTimeVO> qwSopAiRuleTimeVOS = qwSopMapper.selectQwAiSopAutoByTagsByForeach(qwSopAutoByTags);
+        List<FastGptChatReplaceWords> words = fastGptChatReplaceWordsMapper.selectAllFastGptChatReplaceWords();
+        List<QwSopLogs> sopLogsList = new ArrayList<>(Collections.emptyList());
+
+
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        if (config == null) {
+            log.error("配置为空-新客对话创建失败");
+            return ;
+        }
+
+        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(qwUser.getCorpId());
+
+        if (qwCompany == null ) {
+            log.error("企业微信主体未配置默认小程序-新客对话创建失败");
+            return ;
+        }
+
+        if (qwSopAiRuleTimeVOS != null && !qwSopAiRuleTimeVOS.isEmpty()){
+
+            qwSopAiRuleTimeVOS.forEach(item->{
+
+                List<QwSopTempContent> tempContentList = qwSopTempContentMapper.selectQwSopTempContentByTempIdAndRules(item.getTempId());
+
+                tempContentList.forEach(content->{
+
+                    QwSopLogs sopLogs = new QwSopLogs();
+                    sopLogs.setQwUserKey(qwUser.getId());
+                    sopLogs.setQwUserid(userID);
+                    sopLogs.setExternalUserId(externalUserID);
+                    sopLogs.setExternalId(externalId);
+                    sopLogs.setLogType(2);
+                    sopLogs.setSendStatus(3L);
+                    sopLogs.setCompanyId(qwUser.getCompanyId());
+                    sopLogs.setReceivingStatus(0L);
+                    sopLogs.setSopId(item.getId());
+                    sopLogs.setCorpId(qwUser.getCorpId());
+                    sopLogs.setFsUserId(fsUserId);
+                    sopLogs.setSort(99999999);
+                    sopLogs.setSendType(4);
+                    sopLogs.setExternalUserName(externalContactName);
+
+                    List<QwSopTempSetting.Content.Setting> settingList =new ArrayList<>();
+                    QwSopTempSetting.Content.Setting setting = JSON.parseObject(content.getContent(), QwSopTempSetting.Content.Setting.class);
+
+                    LocalDateTime dateTime = LocalDateTime.of(currentDate, localTime);
+                    LocalDateTime expiryDateTime = dateTime.plusMinutes(setting.getIntervalTime());
+                    String sendTime = DateUtil.formatLocalDateTime(expiryDateTime);
+                    sopLogs.setSendTime(sendTime);
+
+                    Date expirySendTime = Date.from(expiryDateTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant());
+
+                    //过滤违禁词
+                    if ("1".equals(setting.getContentType())) {
+                        sopUserLogsInfoService.replaceContent(setting.getContentType(), setting.getValue(), setting::setValue, words); // 替换 value
+                    }
+                    //过滤违禁词
+                    if ("3".equals(setting.getContentType())) {
+                        sopUserLogsInfoService.replaceContent(setting.getContentType(), setting.getLinkTitle(), setting::setLinkTitle, words); // 替换 linkTitle
+                        sopUserLogsInfoService.replaceContent(setting.getContentType(), setting.getLinkDescribe(), setting::setLinkDescribe, words); // 替换 linkTitle
+                    }
+                    switch (setting.getContentType()) {
+                        //文字和短链一起
+                        case "1":
+                        case "3":
+
+                            if ("1".equals(setting.getContentType())) {
+                                setting.setValue(setting.getValue()
+                                        .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText()));
+                            }
+
+
+                            break;
+                        //小程序单独
+                        case "4":
+                            addWatchLogIfNeededByNewChat(item.getId(), content.getVideoId(), content.getCourseId(), fsUserId,qwUser.getId(), qwUser.getCompanyUserId(), qwUser.getCompanyId(),
+                                    externalId, sendTime, expirySendTime);
+
+                            String linkByMiniApp = createLinkByMiniAppByNewChat(setting.getExpiresDays(), qwUser.getCorpId(), expirySendTime, content.getCourseId(), content.getVideoId(),
+                                    qwUser.getId(), String.valueOf(qwUser.getCompanyUserId()),String.valueOf(qwUser.getCompanyId()), externalId, config);
+
+
+                            setting.setMiniprogramAppid(qwCompany.getMiniAppId());
+
+                            String miniprogramTitle = setting.getMiniprogramTitle();
+                            int maxLength = 17;
+                            setting.setMiniprogramTitle(miniprogramTitle.length() > maxLength ? miniprogramTitle.substring(0, maxLength)+"..." : miniprogramTitle);
+                            setting.setMiniprogramPage(linkByMiniApp);
+                            break;
+                        case "7":
+
+                            createVoiceUrlByNewChat(setting, qwUser.getCompanyUserId());
+                            break;
+                        default:
+                            break;
+
+                    }
+
+                    settingList.add(setting);
+
+                    QwSopTempSetting.Content clonedContent=new QwSopTempSetting.Content();
+                    clonedContent.setContentType(setting.getContentType());
+                    clonedContent.setCourseId(Long.valueOf(content.getCourseId()));
+                    clonedContent.setVideoId(Long.valueOf(content.getVideoId()));
+                    clonedContent.setSetting(settingList);
+                    clonedContent.setType(content.getType());
+                    clonedContent.setCourseType(0);
+                    sopLogs.setContentJson(JSON.toJSONString(clonedContent));
+                    sopLogsList.add(sopLogs);
+                });
+
+
+            });
+
+            //批量插入 发送记录
+            if (!sopLogsList.isEmpty()) {
+                processAndInsertQwSopLogsBySendMsg(sopLogsList);
+            }
+        }
+
+    }
+
+    private void processAndInsertQwSopLogsBySendMsg(List<QwSopLogs> sopLogsList) {
+        // 定义批量插入的大小
+        int batchSize = 500;
+
+        // 循环处理外部用户 ID,每次处理批量大小的子集
+        for (int i = 0; i < sopLogsList.size(); i += batchSize) {
+
+            int endIndex = Math.min(i + batchSize, sopLogsList.size());
+            List<QwSopLogs> batchList = sopLogsList.subList(i, endIndex);  // 获取当前批次的子集
+
+            // 直接使用批次数据进行批量更新,不需要额外的 List
+            try {
+                qwSopLogsMapper.batchInsertQwSopLogsOneTouch(batchList);
+            } catch (Exception e) {
+                // 记录异常日志,方便后续排查问题
+                log.error("批量执行一键群发时发生异常,处理的批次起始索引为: " + i, e);
+            }
+        }
+    }
+    //插入观看记录
+    private Long addWatchLogIfNeededByNewChat(String sopId, Integer videoId, Integer courseId,
+                                     Long fsUserId, Long qwUserId, Long companyUserId,
+                                     Long companyId, Long externalId, String startTime, Date createTime) {
+
+        try {
+            FsCourseWatchLog watchLog = new FsCourseWatchLog();
+            watchLog.setVideoId(Long.valueOf(videoId));
+            watchLog.setQwExternalContactId(externalId);
+            watchLog.setSendType(2);
+            watchLog.setQwUserId(qwUserId);
+            watchLog.setSopId(sopId);
+            watchLog.setDuration(0L);
+            watchLog.setCourseId(Long.valueOf(courseId));
+            watchLog.setCompanyUserId(companyUserId);
+            watchLog.setCompanyId(companyId);
+            watchLog.setCreateTime(createTime);
+            watchLog.setUpdateTime(createTime);
+            watchLog.setLogType(3);
+            watchLog.setUserId(fsUserId);
+            watchLog.setCampPeriodTime(sopUserLogsInfoService.convertStringToDate(startTime, "yyyy-MM-dd HH:mm:ss"));
+
+            //存看课记录
+            fsCourseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
+            return watchLog.getLogId();
+        } catch (Exception e) {
+            log.error("一键群发失败-插入观看记录失败:" + e.getMessage());
+            return null;
+        }
+    }
+
+    private String createLinkByMiniAppByNewChat(Integer expiresDays, String corpId, Date sendTime,
+                                                Integer courseId, Integer videoId, Long qwUserId,
+                                       String companyUserId, String companyId, Long externalId, CourseConfig config) {
+
+        try {
+            FsCourseLink link = sopUserLogsInfoService.createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
+                    companyUserId, companyId, externalId, 3, null);
+
+            FsCourseRealLink courseMap = new FsCourseRealLink();
+            BeanUtils.copyProperties(link, courseMap);
+
+            String courseJson = JSON.toJSONString(courseMap);
+            String realLinkFull = miniappRealLink + courseJson;
+            link.setRealLink(realLinkFull);
+
+            Date updateTime = createUpdateTimeByNewChat(expiresDays, sendTime, config);
+
+            link.setUpdateTime(updateTime);
+            //存短链-
+            fsCourseLinkMapper.insertFsCourseLink(link);
+            return link.getRealLink();
+        }catch (Exception e){
+            log.error("创建新客对话短链失败:{}|{}|{}|{}|{}", corpId, sendTime, courseId, videoId, qwUserId);
+            log.error("e",e);
+        }
+            return null;
+    }
+
+    public Date createUpdateTimeByNewChat(Integer expiresDays, Date sendTime, CourseConfig config) {
+
+
+        Integer expDays = (expiresDays == null || expiresDays == 0)
+                ? config.getVideoLinkExpireDate()
+                : expiresDays;
+
+//         使用 Java 8 时间 API 计算过期时间
+        LocalDateTime sendDateTime = sendTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        LocalDateTime expireDateTime = sendDateTime.plusDays(expDays - 1);
+        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
+        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
+
+        return updateTime;
+    }
+
+    private void createVoiceUrlByNewChat(QwSopTempSetting.Content.Setting setting, Long companyUserId) {
+        QwSopTempVoice qwSopTempVoice = sopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId, setting.getValue());
+        if (qwSopTempVoice != null && qwSopTempVoice.getVoiceUrl() != null && qwSopTempVoice.getRecordType() == 1) {
+            setting.setVoiceUrl(qwSopTempVoice.getVoiceUrl());
+            setting.setVoiceDuration(String.valueOf(qwSopTempVoice.getDuration()));
+        } else if (qwSopTempVoice == null) {
+            qwSopTempVoice = new QwSopTempVoice();
+            qwSopTempVoice.setCompanyUserId(companyUserId);
+            qwSopTempVoice.setVoiceTxt(setting.getValue());
+            qwSopTempVoice.setRecordType(0);
+            sopTempVoiceService.insertQwSopTempVoice(qwSopTempVoice);
+        }
+    }
+
+}

+ 85 - 0
fs-service/src/main/java/com/fs/qw/service/IQwUserServiceAsyncHelper.java

@@ -0,0 +1,85 @@
+package com.fs.qw.service;
+
+import com.fs.company.domain.Company;
+import com.fs.qw.param.QwExternalContactAddTagParam;
+import com.fs.qw.param.QwExternalContactUpdateNoteParam;
+import com.fs.qw.param.ResignedTransferParam;
+import com.fs.qw.param.TransferParam;
+import org.codehaus.jettison.json.JSONException;
+
+import java.io.IOException;
+import java.util.List;
+
+public interface IQwUserServiceAsyncHelper {
+
+    /**
+     * 同步企微员工和部门信息
+     * @param corpId
+     * @param company
+     */
+    void syncQwUserAsync(String corpId, Company company);
+
+    /**
+     * 同步企微用户名称
+     * @param corpId
+     * @param company
+     */
+    void syncNameQwUserAsync(String corpId, Company company);
+
+    /**
+     * 批量修改备注
+     * @param param
+     */
+    void batchUpdateExternalContactNotes(QwExternalContactUpdateNoteParam param);
+
+    /**
+     * 添加标签
+     * @param param
+     * @throws JSONException
+     */
+    void addUserTag(QwExternalContactAddTagParam param) throws JSONException;
+
+    /**
+     * 删除标签
+     */
+    void delUserTag(QwExternalContactAddTagParam param);
+
+    /**
+     * 同步我的客户
+     * @param id
+     * @throws IOException
+     */
+    void syncMyQwExternalContact(Long id) throws IOException;
+
+    /**
+     * 同步新客
+     * @param id
+     */
+    void  syncAddMyQwExternalContact(Long id);
+
+    /**
+     * 企业微信客户
+     * @param param
+     */
+    void transfer(TransferParam param);
+
+    /**
+     * 同步待转
+     * @param corpId
+     */
+    void syncQwExternalContactUnassigned(String corpId);
+
+    /**
+     * 企业微信客户分配客户
+     * @param param
+     */
+    void resignedTransfer(ResignedTransferParam param);
+
+    /**
+     * 同步群聊
+     * @param corpId
+     * @param qwUserIdList
+     * @throws Exception
+     */
+    void cogradientGroupChat(String corpId, List<String> qwUserIdList ) throws Exception;
+}

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

@@ -5607,4 +5607,21 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     public List<QwExternalContact> selectQwExternalContactByFsUserId(Long userId) {
         return qwExternalContactMapper.selectQwExternalContactByFsUserId(userId);
     }
+
+
+    public Boolean getSopAiChatByRedis(String qwUserId,String corpId,String externalUserId){
+
+        try {
+            String key =(String)redisCache.getCacheObject("qwNewChat:"+qwUserId+":"+corpId+":"+externalUserId);
+            if (!StringUtil.strIsNullOrEmpty(key)){
+                return true;
+            }else {
+                redisCache.setCacheObject("qwNewChat:"+qwUserId+":"+corpId+":"+externalUserId ,"1",1, TimeUnit.DAYS);
+                return false;
+            }
+        }catch (Exception e){
+            logger.info("获取getSopAiChatByRedis 异常"+e);
+        }
+        return false;
+    }
 }

+ 1286 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceAsyncHelperImpl.java

@@ -0,0 +1,1286 @@
+package com.fs.qw.service.impl;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyCompanyFsuserMapper;
+import com.fs.qw.domain.*;
+import com.fs.qw.mapper.*;
+import com.fs.qw.param.*;
+import com.fs.qw.service.AsyncQwAiChatSopService;
+import com.fs.qw.service.IQwDeptService;
+import com.fs.qw.service.IQwUserServiceAsyncHelper;
+import com.fs.qw.vo.QwSopRuleTimeVO;
+import com.fs.qwApi.Result.QwGroupChatListResult;
+import com.fs.qwApi.domain.*;
+import com.fs.qwApi.domain.inner.ExternalContact;
+import com.fs.qwApi.domain.inner.FollowUser;
+import com.fs.qwApi.domain.inner.QwCustomer;
+import com.fs.qwApi.domain.inner.Tag;
+import com.fs.qwApi.param.*;
+import com.fs.qwApi.service.QwApiService;
+import com.fs.sop.domain.SopUserLogs;
+import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.sop.mapper.QwSopMapper;
+import com.fs.sop.mapper.SopUserLogsInfoMapper;
+import com.fs.sop.params.DeleteQwSopParam;
+import com.fs.sop.params.QwSopAutoByTags;
+import com.fs.sop.params.SopUserLogsParamByDate;
+import com.fs.voice.utils.StringUtil;
+import com.fs.watch.mapper.WatchCompanyUserMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class QwUserServiceAsyncHelperImpl implements IQwUserServiceAsyncHelper {
+
+    @Autowired
+    private IQwDeptService qwDeptService;
+
+    @Autowired
+    private QwCompanyMapper qwCompanyMapper;
+
+    @Autowired
+    QwUserServiceImpl qwUserService;
+
+    @Autowired
+    QwApiService qwApiService;
+
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+
+    @Autowired
+    private QwSopMapper qwSopMapper;
+
+    @Autowired
+    QwExternalContactServiceImpl qwExternalContactService;
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    QwAutoTagsLogsMapper qwAutoTagsLogsMapper;
+
+    @Autowired
+    QwAutoTagsMapper qwAutoTagsMapper;
+
+    @Autowired
+    private QwSopLogsMapper qwSopLogsMapper;
+
+    @Autowired
+    private SopUserLogsInfoMapper sopUserLogsInfoMapper;
+
+    @Autowired
+    private QwExternalContactTransferLogMapper qwExternalContactTransferLogMapper;
+
+    @Autowired
+    private QwGroupChatServiceImpl qwGroupChatService;
+
+    @Autowired
+    private CompanyCompanyFsuserMapper companyCompanyFsuserMapper;
+
+    @Autowired
+    private WatchCompanyUserMapper watchCompanyUserMapper;
+
+    @Autowired
+    private AsyncQwAiChatSopService asyncQwAiChatSopService;
+
+    org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
+
+    /**
+     * 同步企微用户
+     *
+     * @param corpId
+     * @param company
+     */
+    @Async
+    @Override
+    public void syncQwUserAsync(String corpId, Company company) {
+        try {
+            log.info("同步企微用户Async");
+            List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByCompanyId(company.getCompanyId());
+            log.info("strings:{}", strings);
+            log.info("corpId:{}", corpId);
+            for (String string : strings) {
+                if (string.equals(corpId)) {
+                    log.info("瞒住条件");
+                    qwUserService.syncQwUser(string);
+                    qwDeptService.insertOrUpdateQwDept(string);
+                }
+            }
+            log.info("同步完成");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("同步企微员工和部门,同步失败");
+        }
+    }
+
+    /**
+     * 同步企微用户名称
+     *
+     * @param corpId
+     * @param company
+     */
+    @Async
+    @Override
+    public void syncNameQwUserAsync(String corpId, Company company) {
+        try {
+            log.info("同步企微用户名称Async");
+            List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByCompanyId(company.getCompanyId());
+            for (String string : strings) {
+                if (string.equals(corpId)) {
+                    qwUserService.syncQwUserName(string);
+                }
+            }
+            log.info("同步完成");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("同步企微用户名称,同步失败");
+        }
+
+    }
+
+    /**
+     * 批量修改备注
+     *
+     * @param param
+     */
+    @Override
+    @Async
+    public void batchUpdateExternalContactNotes(QwExternalContactUpdateNoteParam param) {
+        try {
+            log.info("批量修改备注Async");
+            List<String> failList = new CopyOnWriteArrayList<>(); // 记录失败客户的名字
+
+            AtomicInteger suc = new AtomicInteger();
+
+
+            List<QwExternalContact> contactList = qwExternalContactMapper.selectQwExternalContactByIds(param.getUserIds());
+
+            ExecutorService executorService = Executors.newFixedThreadPool(10); // 限制最大线程数
+            CountDownLatch latch = new CountDownLatch(contactList.size()); // 同步等待所有任务完成
+
+            AtomicReference<Integer> failReason = new AtomicReference<>(0);
+
+            contactList.forEach(item -> {
+                executorService.submit(() -> {
+                    try {
+                        String originalRemark = item.getRemark();
+                        String newRemark = "";
+
+                        if (StringUtil.strIsNullOrEmpty(originalRemark)) {
+                            originalRemark = "";
+                        }
+
+                        if (StringUtil.strIsNullOrEmpty(param.getNotes())) {
+                            newRemark = originalRemark;
+                        } else {
+
+                            String newNotes = "";
+
+                            switch (param.getNameType()) {
+                                case 1:
+                                    newNotes = item.getName() + "-" + param.getNotes();
+                                    break;
+                                case 2:
+                                    newNotes = param.getNotes() + "-" + item.getName();
+                                    break;
+                                case 3:
+                                    newNotes = param.getNotes();
+                                    break;
+                                default:
+                                    break;
+                            }
+
+                            switch (param.getType()) {
+                                case 1:
+                                    newRemark = (newNotes + originalRemark);
+                                    if (newRemark.length() > 20) {
+                                        newRemark = newRemark.substring(0, 20);
+                                    }
+                                    break;
+                                case 2:
+                                    int keepLength = 20 - newNotes.length();
+                                    if (originalRemark.length() > keepLength) {
+                                        originalRemark = originalRemark.substring(0, keepLength);
+                                    }
+                                    newRemark = originalRemark + param.getNotes();
+                                    break;
+                                case 3:
+                                    newRemark = newNotes;
+                                    break;
+                                default:
+                                    break;
+                            }
+
+                        }
+
+
+                        QwExternalContactRemarkParam remarkParam = new QwExternalContactRemarkParam();
+                        remarkParam.setRemark(newRemark);
+                        remarkParam.setUserid(item.getUserId());
+                        remarkParam.setExternal_userid(item.getExternalUserId());
+
+                        boolean success = false;
+                        for (int attempt = 1; attempt <= 3; attempt++) {
+                            try {
+                                QwExternalContactRemarkResult qwResult = qwApiService.externalcontactRemark(remarkParam, item.getCorpId());
+                                if (qwResult.getErrcode() == 0) {
+                                    item.setRemark(newRemark);
+                                    logger.info("成功添加备注:" + item.getName() + "|公司" + item.getCorpId() + "|员工" + item.getUserId() + "|备注" + param.getNotes() + "|类型" + param.getType());
+                                    suc.getAndIncrement();
+                                    qwExternalContactMapper.updateQwExternalContact(item);
+                                    success = true;
+                                    break;
+                                } else {
+                                    failReason.set(qwResult.getErrcode()); // 记录失败原因
+                                }
+                            } catch (Exception e) {
+                                logger.error("添加备注异常 [尝试第 " + attempt + " 次]:" + item.getName() + ",异常:" + e.getMessage(), e);
+                            }
+
+                            // 若不是最后一次尝试,则等待3秒再试
+                            if (attempt < 3) {
+                                try {
+                                    Thread.sleep(3000);
+                                } catch (InterruptedException e) {
+                                    logger.warn("线程等待被中断", e);
+                                    break;
+                                }
+                            }
+                        }
+
+                        if (!success) {
+                            logger.error(" 加备注失败:" + item.getName() + "|" + item.getExternalUserId() + "|" + item.getUserId());
+
+                            failList.add("【" + item.getName() + "】" + "原因:(" + getErrorMsg(failReason.get()) + ")\n");
+                        }
+
+                    } finally {
+                        latch.countDown();
+                    }
+                });
+            });
+
+            try {
+                latch.await();
+            } catch (InterruptedException e) {
+                logger.error("等待线程执行完成时被中断", e);
+            } finally {
+                executorService.shutdown();
+            }
+
+            String failNames = null;
+            if (!failList.isEmpty()) {
+                failNames = String.join(",", failList);
+            }
+            log.info("批量修改备注 成功:" + suc + ",失败:" + failNames);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("批量修改备注失败");
+        }
+    }
+
+    private String getErrorMsg(Integer code) {
+
+        String msg = "";
+        switch (code) {
+            case 40003:
+                msg = "无效的UserID(员工账号)";
+                break;
+            case 40096:
+                msg = "不合法的外部联系人userid";
+                break;
+            case 60020:
+                msg = "不安全的访问IP";
+                break;
+            case 84061:
+                msg = "不存在外部联系人的关系(客户【不存在】于员工的好友列表中)";
+                break;
+            default:
+                msg = code.toString();
+                break;
+
+        }
+        return msg;
+    }
+
+    /**
+     * 添加标签
+     *
+     * @param param
+     * @throws JSONException
+     */
+    @Override
+    @Async
+    public void addUserTag(QwExternalContactAddTagParam param) throws JSONException {
+        log.info("开始添加标签Async");
+        // 获取当前日期和时间
+        LocalDate currentDate = LocalDate.now();
+        LocalTime localTime = LocalTime.now();
+
+        // 使用线程安全的计数器
+        AtomicInteger suc = new AtomicInteger(0);
+
+        List<String> failList = new CopyOnWriteArrayList<>(); // 记录失败客户的名字
+
+        // 创建线程池
+        int threadCount = Math.min(8, Runtime.getRuntime().availableProcessors() * 2);
+        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
+
+
+        try {
+            // 使用线程安全的List来收集需要批量更新的数据
+            List<QwExternalContact> batchUpdateList = Collections.synchronizedList(new ArrayList<>());
+
+            // 存储Future对象以便检查所有任务完成情况
+            List<Future<?>> futures = new ArrayList<>();
+
+
+            // 1. 批量查询所有用户数据
+            List<QwExternalContact> contacts = new ArrayList<>();
+            try {
+                contacts = qwExternalContactMapper.selectQwExternalContactByIds(param.getUserIds());
+                if (contacts == null || contacts.isEmpty()) {
+                    log.info("成功:0,失败:" + param.getUserIds().size());
+
+//                    return R.error("成功:0,失败:" + param.getUserIds().size());
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.info("批量查询用户数据失败:" + e.getMessage());
+            }
+
+            // 直接遍历contacts而不是userIds
+            for (QwExternalContact qwExternalContact : contacts) {
+                futures.add(executor.submit(() -> {
+                    try {
+                        QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
+                        qwEditUserTagParam.setAdd_tag(param.getTagIds());
+                        qwEditUserTagParam.setUserid(qwExternalContact.getUserId());
+                        qwEditUserTagParam.setExternal_userid(qwExternalContact.getExternalUserId());
+
+                        QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, param.getCorpId());
+                        if (qwResult.getErrcode() == 0) {
+                            // 处理标签
+                            String tagIds = qwExternalContact.getTagIds();
+                            Set<String> uniqueIds = new HashSet<>();
+
+                            if (tagIds != null && !tagIds.isEmpty()) {
+                                List<String> parsedTags = JSON.parseArray(tagIds, String.class);
+                                if (parsedTags != null && !parsedTags.isEmpty()) {
+                                    uniqueIds.addAll(parsedTags);
+                                }
+                            }
+
+                            if (param.getTagIds() != null && !param.getTagIds().isEmpty()) {
+                                uniqueIds.addAll(param.getTagIds());
+                            }
+
+                            QwExternalContact qwExternal = new QwExternalContact();
+                            qwExternal.setTagIds(JSON.toJSONString(uniqueIds));
+                            qwExternal.setId(qwExternalContact.getId());
+
+                            List<String> tagIdsList = new ArrayList<>();
+                            if (qwExternal.getTagIds() != null && !qwExternal.getTagIds().isEmpty()) {
+                                tagIdsList = JSON.parseArray(qwExternal.getTagIds(), String.class);
+                            }
+
+                            logger.info("客户添加标签addUserTag:" + qwExternalContact.getName() +
+                                    "|公司" + qwExternalContact.getCorpId() +
+                                    "|员工" + qwExternalContact.getUserId() +
+                                    "|总标签" + tagIdsList);
+
+                            // 插件sop处理
+                            processTagsAll(qwExternalContact, qwExternalContact.getCorpId(),
+                                    tagIdsList, currentDate, localTime);
+
+                            // 添加到批量更新列表
+                            batchUpdateList.add(qwExternal);
+                            suc.incrementAndGet();
+                        } else {
+                            failList.add("【" + qwExternalContact.getName() + "】" + "原因:(" + getErrorMsg(qwResult.getErrcode()) + ")\n");
+                        }
+                    } catch (Exception e) {
+                        logger.error("客户添加标签失败,userId: " + qwExternalContact.getId() +
+                                ", externalUserId: " + qwExternalContact.getExternalUserId() +
+                                ", 错误信息: " + e.getMessage());
+                        failList.add("【" + qwExternalContact.getName() + "】" + "原因:(" + e.getMessage() + ")\n");
+                    }
+                }));
+            }
+
+
+            // 等待所有任务完成
+            for (Future<?> future : futures) {
+                try {
+                    future.get();
+                } catch (InterruptedException | ExecutionException e) {
+                    logger.error("任务执行异常: " + e.getMessage());
+                    Thread.currentThread().interrupt();
+                }
+            }
+
+            // 批量更新数据库
+            if (!batchUpdateList.isEmpty()) {
+                try {
+                    // 分批处理,避免单次批量过大
+                    int batchSize = 500; // 根据数据库性能调整
+                    for (int i = 0; i < batchUpdateList.size(); i += batchSize) {
+                        int end = Math.min(i + batchSize, batchUpdateList.size());
+                        List<QwExternalContact> subList = batchUpdateList.subList(i, end);
+                        qwExternalContactMapper.batchUpdateQwExternalContactByTags(subList);
+                    }
+                } catch (Exception e) {
+                    logger.error("批量更新失败: " + e.getMessage());
+                }
+            }
+
+            // 关闭线程池
+            executor.shutdown();
+
+        } catch (Exception e) {
+            failList.add("处理过程中发生异常:" + e.getMessage());
+        } finally {
+            // 7. 确保线程池关闭
+            try {
+                // 先尝试正常关闭
+                executor.shutdown();
+                if (!executor.awaitTermination(15, TimeUnit.SECONDS)) {
+                    // 超时后强制关闭
+                    executor.shutdownNow();
+                    logger.warn("线程池强制关闭");
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                executor.shutdownNow();
+            }
+        }
+        try {
+            Thread.sleep(3000);
+        } catch (InterruptedException ex) {
+            log.info("线程被中断");
+        }
+        log.info("添加标签成功:" + suc.get() + ",添加标签失败:" + failList);
+
+    }
+
+    /**
+     * 整合客户的标签的逻辑 ,新增和移除 都要移除和添加到营期里
+     */
+    public void processTagsAll(QwExternalContact qwExternalContact, String corpId, List<String> tagArr, LocalDate currentDate, LocalTime localTime) {
+
+        List<String> cleanedTagList = tagArr.stream()
+                .map(String::trim)   // 去除前后空格
+                .filter(s -> !s.isEmpty()) // 过滤掉空字符串(如果有)
+                .distinct()           // 去重
+                .collect(Collectors.toList());
+
+        QwSopAutoByTags qwSopAutoByTags = new QwSopAutoByTags();
+        qwSopAutoByTags.setQwUserId(String.valueOf(qwExternalContact.getQwUserId()));
+        qwSopAutoByTags.setCorpId(corpId);
+        qwSopAutoByTags.setTagsIdsSelectList(cleanedTagList);
+        qwSopAutoByTags.setSendType(2);
+
+        // 定义日期和时间格式化器
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
+
+
+        try {
+            //查询匹配这个客服所有正在执行的 SOP任务 ps:仅仅是AI插件的
+            List<QwSopRuleTimeVO> runRuleTime = qwSopMapper.selectQwSopByQwUserId(qwSopAutoByTags);
+
+            logger.info("查出来的客服 任务长度:" + runRuleTime.size());
+            //如果剩下的总标签 啥也没有
+            // 查询匹配这些Tag的SOP任务
+            if (cleanedTagList.isEmpty()) {
+
+                //这个人标签空了,以防万一 将这个客服下的这个人的所有sop里的他(可能没有) 全刷一遍
+                if (!runRuleTime.isEmpty()) {
+                    runRuleTime.forEach(runSop -> {
+
+                        logger.info("cleanedTagList-空了,将这个客服下的这个人的所有sop里的他(可能没有) 全刷一遍 sopId:{}", runSop.getId());
+                        qwExternalContactService.deleteBySopIdToContactIdTools(runSop.getId(), qwExternalContact.getUserId(), qwExternalContact.getCorpId(), qwExternalContact.getId());
+
+                    });
+                }
+            } else {
+                List<QwSopRuleTimeVO> qwSopRuleTimeVOS = qwSopMapper.selectQwSopAutoByTagsByForeachNotAuto(qwSopAutoByTags);
+
+                if (!qwSopRuleTimeVOS.isEmpty()) {
+
+                    //匹配上剩下的标签看看符合不符合
+                    qwSopRuleTimeVOS.forEach(ruleTimeVO -> {
+
+                        // 将排除的字符串转成列表
+                        List<String> excludedTagsList = new ArrayList<>();
+                        if (ruleTimeVO.getExcludeTags() != null && !ruleTimeVO.getExcludeTags().isEmpty()) {
+                            excludedTagsList = Arrays.asList(ruleTimeVO.getExcludeTags().split(","));
+                        }
+
+
+                        // 检查 combinedTagsList 是否包含排除列表中的任意一个标签
+                        boolean containsExcludedTag = cleanedTagList.stream()
+                                .anyMatch(excludedTagsList::contains);
+
+                        //含任意一个排除标签
+                        if (containsExcludedTag) {
+                            logger.info("该客户已匹配到规则,但是被排除,规则id:" + ruleTimeVO.getId() + "|cleanedTagList" + cleanedTagList + "|excludedTagsList" + excludedTagsList);
+                            qwExternalContactService.deleteBySopIdToContactIdTools(ruleTimeVO.getId(), qwExternalContact.getUserId(), qwExternalContact.getCorpId(), qwExternalContact.getId());
+
+                        } else {
+                            //检查 有可能在营期里 有可能不在。在不动,不在
+                            // 从数据库中取到的开始时间(Date类型),转换为 LocalDate
+                            Date sopStartTime = ruleTimeVO.getStartTime();
+                            //开始时间
+                            LocalDate sopStartLocalDate = sopStartTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+
+                            // 自动sop的规则
+                            QwAutoSopTimeParam qwAutoSopTimeParam = JSON.parseObject(ruleTimeVO.getAutoSopTime(), QwAutoSopTimeParam.class);
+
+                            // 用于查询/或新增
+                            SopUserLogs userLogs = new SopUserLogs();
+                            userLogs.setSopId(ruleTimeVO.getId());
+                            userLogs.setSopTempId(ruleTimeVO.getTempId());
+                            userLogs.setCorpId(ruleTimeVO.getCorpId());
+                            userLogs.setStatus(1);
+
+                            // 用于今天的新增
+                            SopUserLogsParamByDate userLogsParamByDate = new SopUserLogsParamByDate();
+                            userLogsParamByDate.setSopId(ruleTimeVO.getId());
+                            userLogsParamByDate.setSopTempId(ruleTimeVO.getTempId());
+                            userLogsParamByDate.setCorpId(ruleTimeVO.getCorpId());
+                            userLogsParamByDate.setStatus(1);
+
+                            // 设定用户信息
+                            userLogs.setQwUserId(qwExternalContact.getUserId());
+                            userLogs.setUserId(qwExternalContact.getQwUserId() + "|" + qwExternalContact.getCompanyUserId() + "|" + qwExternalContact.getCompanyId());
+                            userLogsParamByDate.setQwUserId(qwExternalContact.getUserId());
+                            userLogsParamByDate.setUserId(qwExternalContact.getQwUserId() + "|" + qwExternalContact.getCompanyUserId() + "|" + qwExternalContact.getCompanyId());
+
+                            // 创建 SopUserLogsInfo
+                            SopUserLogsInfo logsInfo = new SopUserLogsInfo();
+                            logsInfo.setQwUserId(qwExternalContact.getUserId());
+                            logsInfo.setCorpId(corpId);
+                            logsInfo.setExternalContactId(qwExternalContact.getExternalUserId());
+                            logsInfo.setExternalId(qwExternalContact.getId());
+                            logsInfo.setFsUserId(qwExternalContact.getFsUserId());
+                            logsInfo.setExternalUserName(qwExternalContact.getName());
+                            logsInfo.setSopId(ruleTimeVO.getId());
+
+                            logger.warn("sop任务的时间设置Tags:{}|{}|{}|{}", ruleTimeVO.getAutoSopTime(), ruleTimeVO.getId(), ruleTimeVO.getTags(), ruleTimeVO.getExcludeTags());
+
+                            //检查营期(如果开启了新客自动创建sop才检查营期,进入营期)
+                            if (ruleTimeVO.getIsAutoSop() == 1) {
+                                qwExternalContactService.qwSopRuleTimeToolsCheck(sopStartLocalDate, currentDate, dateFormatter, userLogs, logsInfo, userLogsParamByDate, qwAutoSopTimeParam, timeFormatter, localTime);
+                            }
+
+                        }
+
+                    });
+
+                    List<QwSopRuleTimeVO> qwSopRuleTimeVOSRemove = qwSopMapper.selectQwSopAutoByTagsByForeachRemoveNotAuto(qwSopAutoByTags);
+                    if (!qwSopRuleTimeVOSRemove.isEmpty()) {
+                        qwSopRuleTimeVOSRemove.forEach(vosRemove -> {
+                            logger.info("删除这个客户在这个客服的其他无关的sop任务" + vosRemove.getId() + "标签:" + tagArr + "id:" + qwExternalContact.getQwUserId());
+                            qwExternalContactService.deleteBySopIdToContactIdTools(vosRemove.getId(), qwExternalContact.getUserId(), qwExternalContact.getCorpId(), qwExternalContact.getId());
+
+                        });
+                    }
+
+//                    if (!runRuleTime.isEmpty() && !qwSopRuleTimeVOS.isEmpty()){
+//
+//                        //剔除掉 客服的其他任务里的,这个人的信息ps:可能没有
+//                        Set<String> qwSopRuleTimeVOIds = qwSopRuleTimeVOS.stream()
+//                                .map(QwSopRuleTimeVO::getId)
+//                                .filter(Objects::nonNull)       // 过滤掉 null
+//                                .map(String::trim)              // 去除前后空格
+//                                .collect(Collectors.toSet());
+//
+//                        if (!qwSopRuleTimeVOIds.isEmpty()){
+//
+//                            //在 qwSopRuleTimeVOS 中过滤掉包含在 runRuleTimeIds 中的 id
+//                            List<QwSopRuleTimeVO> notOverlapList = runRuleTime.stream()
+//                                    .filter(item -> item.getId() != null &&!qwSopRuleTimeVOIds.contains(item.getId().trim()))
+//                                    .collect(Collectors.toList());
+//
+//                            notOverlapList.forEach(notSop->{
+//                                logger.info("删除这个客户在这个客服的其他不符合的sop"+notSop.getId()+"标签:"+tagArr+"id:"+qwExternalContact.getQwUserId()+"排除的标签:"+qwSopRuleTimeVOIds);
+//
+//                                deleteBySopIdToContactIdTools(notSop.getId(),qwExternalContact.getUserId(),qwExternalContact.getCorpId(),qwExternalContact.getId());
+//
+//                            });
+//                        }
+//                    }
+                } else {
+                    //没匹配上任意一个(即这个剩下的标签匹配不上任意的sop),但是客服有任务-以防万一-删除这个客户在这个客服的sop
+                    if (!runRuleTime.isEmpty()) {
+                        runRuleTime.forEach(runSop -> {
+                            logger.info("没匹配上任意一个(即这个剩下的标签匹配不上任意的sop),但是客服有任务-以防万一-删除这个客户在这个客服的sop" + runSop.getId() + "标签:" + tagArr + "id:" + qwExternalContact.getQwUserId());
+                            qwExternalContactService.deleteBySopIdToContactIdTools(runSop.getId(), qwExternalContact.getUserId(), qwExternalContact.getCorpId(), qwExternalContact.getId());
+
+                        });
+                    }
+                }
+
+            }
+
+        } catch (Exception e) {
+            logger.error("改动了客户的标签的异常:qwExternalContact" + qwExternalContact + "|corpId" + corpId + "|cleanedTagList" + cleanedTagList);
+        }
+
+    }
+
+
+    /**
+     * 删除标签
+     *
+     * @param param
+     */
+    @Override
+    @Async
+    public void delUserTag(QwExternalContactAddTagParam param) {
+        try {
+            log.info("删除标签Async");
+            // 获取当前日期(只包含年月日)
+            LocalDate currentDate = LocalDate.now();
+            // 获取当前系统时间 (HH:mm)
+            LocalTime localTime = LocalTime.now();
+            int err = 0;
+            int suc = 0;
+            List<Long> userIds = param.getUserIds();
+            for (Long userId : userIds) {
+                QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(userId);
+                QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
+                qwEditUserTagParam.setRemove_tag(param.getTagIds());
+                qwEditUserTagParam.setUserid(qwExternalContact.getUserId());
+                qwEditUserTagParam.setExternal_userid(qwExternalContact.getExternalUserId());
+                try {
+                    QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, param.getCorpId());
+                    log.info("qw:" + qwResult);
+                    if (qwResult.getErrcode() == 0) {
+
+                        String tagIds = qwExternalContact.getTagIds();
+                        if (tagIds != null && tagIds != "") {
+                            List<String> ids = JSON.parseArray(tagIds, String.class);
+                            for (String tagId : param.getTagIds()) {
+                                ids.removeIf(str -> str.equals(tagId));
+                            }
+                            QwExternalContact qwExternal = new QwExternalContact();
+                            qwExternal.setId(userId);
+                            qwExternal.setTagIds(JSON.toJSONString(ids));
+                            qwExternalContactMapper.updateQwExternalContact(qwExternal);
+                            logger.info("客户移除标签delUserTag:" + qwExternalContact.getName() + "|公司" + qwExternalContact.getCorpId() + "|员工" + qwExternalContact.getUserId() + "|总标签" + ids);
+                            //检查sop
+                            processTagsAll(qwExternalContact, param.getCorpId(), ids, currentDate, localTime);
+                            //新客对话
+//                        processTagsAllByAiChat(qwExternalContact,param.getCorpId(),ids);
+                        }
+                        suc++;
+                    } else {
+                        err++;
+                    }
+                } catch (Exception e) {
+                    logger.error("移除标签失败:" + qwEditUserTagParam + e.getMessage());
+                }
+            }
+            log.info("成功:" + suc + ",失败:" + err);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("删除标签失败");
+        }
+    }
+
+    /**
+     * 同步我的客户
+     *
+     * @param id
+     */
+    @Override
+    @Async
+    public void syncMyQwExternalContact(Long id) {
+        try {
+            log.info("同步我的客户Async");
+            QwUser qwUser = qwUserMapper.selectQwUserById(id);
+            //对比同步客户信息
+            qwExternalContactService.getContactListResult(qwUser);
+            qwExternalContactService.syncMyQwExternalContactRecursion(qwUser, null);
+            log.info("同步我的企业微信客户成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("同步我的企业微信客户失败");
+        }
+    }
+
+    /**
+     * 同步新客
+     *
+     * @param id
+     */
+    @Override
+    @Async
+    public void syncAddMyQwExternalContact(Long id) {
+
+        try {
+            log.info("同步新客Async");
+            QwUser qwUser = qwUserMapper.selectQwUserById(id);
+            String userID = qwUser.getQwUserId();
+
+            QwExternalContactListResult contactListResult = qwApiService.getExternalcontactList(qwUser.getQwUserId(), qwUser.getCorpId());
+            if (contactListResult.getErrcode() == 0) {
+                //企微获取的id
+                List<String> externalUserid = contactListResult.getExternal_userid();
+                //库里的
+                List<String> qwExternalContactList = qwExternalContactMapper.selectQwExternalContactListAllNoDel(qwUser.getQwUserId(), qwUser.getCorpId());
+
+                List<String> addList = externalUserid.stream()
+                        .filter(externalUserId -> !qwExternalContactList.contains(externalUserId))
+                        .collect(Collectors.toList());
+
+
+                String qwUserId = qwUser.getQwUserId();
+                String corpId = qwUser.getCorpId();
+                Long companyId = qwUser.getCompanyId();
+                for (String ext : addList) {
+                    String externalUserID = ext;
+                    QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactUserIdAndExternalIdAndCompanyId(ext, qwUser.getQwUserId(), qwUser.getCorpId());
+
+                    if (qwExternalContact == null) {
+                        QwExternalContactResult followUsers = qwApiService.getExternalcontact(ext, qwUser.getCorpId());
+                        ExternalContact externalContact = followUsers.getExternal_contact();
+                        List<FollowUser> followUser = followUsers.getFollow_user();
+                        for (FollowUser followInfo : followUser) {
+                            if (followInfo.getUserid().equals(qwUserId)) {
+                                LocalDate currentDate = LocalDate.now();
+                                // 获取当前系统时间 (HH:mm)
+                                LocalTime localTime = LocalTime.now();
+                                qwExternalContact = new QwExternalContact();
+                                qwExternalContact.setUserId(qwUserId); // 设置属于用户ID
+                                qwExternalContact.setExternalUserId(ext); // 设置外部联系人ID
+                                qwExternalContact.setCorpId(corpId); // 设置企业ID
+                                qwExternalContact.setCompanyId(companyId); // 设置公司ID
+                                qwExternalContact.setCompanyUserId(qwUser.getCompanyUserId());
+                                qwExternalContact.setQwUserId(qwUser.getId());
+                                qwExternalContact.setName(externalContact.getName()); // 设置名称
+                                qwExternalContact.setAvatar(externalContact.getAvatar()); // 设置头像
+                                qwExternalContact.setType(externalContact.getType()); // 设置外部联系人类型(1微信用户,2企业微信用户)
+                                qwExternalContact.setGender(externalContact.getGender()); // 设置性别 (0-未知, 1-男性, 2-女性)
+                                qwExternalContact.setUnionid(externalContact.getUnionid());
+                                qwExternalContact.setDescription(followInfo.getDescription()); // 设置描述信息
+                                qwExternalContact.setRemark(followInfo.getRemark());
+                                List<Tag> tags = followInfo.getTags();
+                                List<String> tagIds = tags.stream()
+                                        .map(Tag::getTag_id)
+                                        .collect(Collectors.toList());
+                                Set<String> combinedTagsSet = new HashSet<>(tagIds);
+                                qwExternalContact.setTagIds(JSON.toJSONString(tagIds)); // 设置标签ID
+                                qwExternalContact.setRemarkMobiles(JSON.toJSONString(followInfo.getRemark_mobiles())); // 设置备注电话号码
+                                qwExternalContact.setState(followInfo.getState());
+                                if (followInfo.getState() != null && !followInfo.getState().isEmpty()) {
+                                    String s = "way:" + corpId + ":";
+                                    if (followInfo.getState().contains(s)) {
+                                        String wayId = followInfo.getState().substring(followInfo.getState().indexOf(s) + s.length());
+                                        qwExternalContact.setWayId(Long.parseLong(wayId));
+                                    }
+                                }
+                                qwExternalContact.setCreateTime(new Date());
+                                qwExternalContact.setRemarkCorpName(followInfo.getRemark_corp_name()); // 设置备注企业名称
+                                qwExternalContact.setAddWay(followInfo.getAdd_way()); // 设置来源
+                                qwExternalContact.setOperUserid(followInfo.getOper_userid()); // 设置oper用户ID
+                                qwExternalContactMapper.insertQwExternalContact(qwExternalContact);
+                                qwExternalContactService.SyncAddSendWelcome(qwExternalContact, qwUser, qwUser.getCorpId());
+                                //发送好友欢迎语
+//
+
+                                QwAutoTags qwAutoTags = qwAutoTagsMapper.selectQwAutoTagsByIdJSON(corpId, qwUser.getId());
+
+                                QwExternalContact contact = qwExternalContact;
+                                log.info("数据:{}", contact.getId());
+
+                                if (qwAutoTags != null) {
+                                    QwAutoTagsLogs qwAutoTagsLogs = new QwAutoTagsLogs();
+                                    qwAutoTagsLogs.setAutoTagId(qwAutoTags.getId());
+                                    qwAutoTagsLogs.setType(3L);
+                                    qwAutoTagsLogs.setQwUserid(qwUser.getId());
+                                    qwAutoTagsLogs.setExternalUserId(ext);
+
+                                    List<QwAutoTagsRulesTags> qwAutoTagsRulesTagsList = JSON.parseArray(qwAutoTags.getRulesTags(), QwAutoTagsRulesTags.class);
+                                    boolean isMatch = false;
+                                    //存分时段里符合条件的标签
+                                    Set<String> combinedTagsItem = new HashSet<>();
+                                    // 获取今天的星期数
+                                    DayOfWeek today = LocalDate.now().getDayOfWeek();
+                                    int todayIndex = today.getValue(); // 1: Monday, 2: Tuesday, ..., 7: Sunday
+                                    // 获取当前时间
+                                    LocalTime now = LocalTime.now();
+                                    // 遍历所有规则
+                                    String tagRemark = null;
+                                    for (QwAutoTagsRulesTags rulesTags : qwAutoTagsRulesTagsList) {
+
+                                        List<String> tagsItem = rulesTags.getTags();
+                                        List<Integer> week = rulesTags.getWeek();
+                                        String startTime = rulesTags.getStartTime();
+                                        String endTime = rulesTags.getEndTime();
+                                        String remarks = rulesTags.getRemarks();
+
+                                        // 检查今天是否在 week 集合中
+                                        boolean isTodayInWeek = week.contains(todayIndex);
+                                        // 转换时间字符串为 LocalTime
+                                        LocalTime start = LocalTime.parse(startTime);
+                                        LocalTime end = LocalTime.parse(endTime.equals("24:00") ? "23:59:59" : endTime);
+                                        // 检查当前时间是否在 startTime 和 endTime 之间
+                                        boolean isNowInTimeRange = !now.isBefore(start) && !now.isAfter(end);
+                                        // 如果当前时间和日期匹配规则,将 tagsItem 添加到 combinedTagsSet 中
+                                        if (isTodayInWeek && isNowInTimeRange) {
+
+                                            combinedTagsSet.addAll(tagsItem);
+                                            combinedTagsItem.addAll(tagsItem);
+                                            isMatch = true;
+                                            //如果备注不为空
+                                            if (rulesTags.getIsDay() != null && rulesTags.getIsDay() == 1) {
+                                                String DayDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
+                                                tagRemark = DayDate.substring(1);
+                                            }
+                                            //如果备注不为空
+                                            if (!StringUtil.strIsNullOrEmpty(remarks)) {
+                                                tagRemark = (tagRemark == null ? "" : (tagRemark + "-")) + remarks;
+                                            }
+                                        }
+                                    }
+                                    QwExternalContact qu = new QwExternalContact();
+                                    if (tagRemark != null) {
+                                        qu.setRemark(tagRemark + "-" + externalContact.getName());
+                                        QwExternalContactRemarkParam param = new QwExternalContactRemarkParam();
+                                        param.setRemark(qu.getRemark());
+                                        param.setUserid(userID);
+                                        param.setExternal_userid(externalUserID);
+                                        QwExternalContactRemarkResult remarkResult = qwApiService.externalcontactRemark(param, qwExternalContact.getCorpId());
+                                    }
+
+                                    // 如果有匹配的规则,使用 combinedTagsList
+                                    if (isMatch) {
+                                        QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
+                                        qwEditUserTagParam.setUserid(userID);
+                                        qwEditUserTagParam.setExternal_userid(externalUserID);
+                                        //添加标签的日志记录
+
+                                        List<String> combinedTags = new ArrayList<>(combinedTagsItem);
+                                        qwAutoTagsLogs.setEffectiveRules(JSON.toJSONString(combinedTags));
+                                        qwAutoTagsLogs.setAddTime(new Date());
+                                        qwAutoTagsLogs.setCompanyId(qwUser.getCompanyId());
+                                        qwAutoTagsLogs.setCorpId(qwUser.getCorpId());
+                                        //总标签 转换回列表
+                                        List<String> combinedTagsList = new ArrayList<>(combinedTagsSet);
+                                        // 设置标签
+                                        log.info("标签");
+                                        log.info("数据:{}", combinedTagsList);
+                                        qwEditUserTagParam.setAdd_tag(combinedTagsList);
+
+                                        // 企微加标签
+                                        QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, corpId);
+                                        if (qwResult.getErrcode() == 0) {
+                                            qwExternalContact.setTagIds(JSON.toJSONString(combinedTagsList));
+                                            qwAutoTagsLogsMapper.insertOrUpdateQwAutoTagsLogs(qwAutoTagsLogs);
+                                            if (!combinedTagsSet.isEmpty()) {
+                                                //分时段里符合的标签-再用来创建自动SOP
+                                                QwSopAutoByTags qwSopAutoByTags = new QwSopAutoByTags();
+                                                qwSopAutoByTags.setQwUserId(String.valueOf(qwUser.getId()));
+                                                qwSopAutoByTags.setCorpId(corpId);
+                                                qwSopAutoByTags.setTagsIdsSelectList(combinedTagsList);
+                                                qwSopAutoByTags.setSendType(2);
+                                                List<QwSopRuleTimeVO> qwSopRuleTimeVOS = qwSopMapper.selectQwSopAutoByTagsByForeach(qwSopAutoByTags);
+                                                logger.info("分时段里符合的标签-自动SOP条件:" + qwSopAutoByTags + "|" + qwUser.getQwUserId() + "|" + ext + "|");
+
+                                                if (qwSopRuleTimeVOS != null && !qwSopRuleTimeVOS.isEmpty()) {
+                                                    //SOP规则
+                                                    qwExternalContactService.qwSopRuleTimeTools(qwSopRuleTimeVOS, qwUserId, qwUser, corpId, ext, externalContact.getName(), contact, currentDate, localTime, combinedTagsList);
+                                                }
+                                                //aiSop任务
+                                                Boolean sopAiChatByRedis = qwExternalContactService.getSopAiChatByRedis(userID, corpId, externalUserID);
+                                                if (!sopAiChatByRedis){
+                                                    asyncQwAiChatSopService.executeQwAiChatSop(qwSopAutoByTags,userID,qwUser,externalUserID
+                                                            ,externalContact.getName(),contact.getId(),contact.getFsUserId(),currentDate,localTime);
+                                                }
+//                                            List<QwSopRuleTimeVO> qwSopAiRuleTimeVOS = qwSopMapper.selectQwAiSopAutoByTagsByForeach(qwSopAutoByTags);
+//                                            if (qwSopAiRuleTimeVOS != null && !qwSopAiRuleTimeVOS.isEmpty()) {
+//                                                qwAiSopRuleTimeTools(qwSopAiRuleTimeVOS, userID, qwUser, corpId, externalUserID, externalContact.getName(), contact);
+//                                            }
+                                            }
+                                        } else if (qwResult.getErrcode() == 45035) {
+                                            //加入补偿机制
+                                            qwExternalContactService.insertQwExternalErrRetryTool(corpId, JSON.toJSONString(qwEditUserTagParam), 1, qwResult.getErrmsg());
+
+                                        }
+
+
+                                        qu.setId(contact.getId());
+                                        qu.setTagIds(JSON.toJSONString(combinedTagsList));
+
+                                        qwExternalContactMapper.updateQwExternalContact(qu);
+
+
+                                    } else {
+                                        // 转换回列表
+                                        List<String> combinedTagsList = new ArrayList<>(combinedTagsSet);
+
+                                        logger.info("不符合分时段条件2--看全部标签是否有符合的:" + combinedTagsList + "|" + externalUserID + "|" + userID + "|" + corpId);
+
+                                        try {
+                                            if (!combinedTagsSet.isEmpty()) {
+                                                //分时段里符合的标签-再用来创建自动SOP
+                                                QwSopAutoByTags qwSopAutoByTags = new QwSopAutoByTags();
+                                                qwSopAutoByTags.setQwUserId(String.valueOf(qwUser.getId()));
+                                                qwSopAutoByTags.setCorpId(corpId);
+                                                qwSopAutoByTags.setTagsIdsSelectList(combinedTagsList);
+                                                qwSopAutoByTags.setSendType(2);
+                                                List<QwSopRuleTimeVO> qwSopRuleTimeVOS = qwSopMapper.selectQwSopAutoByTagsByForeach(qwSopAutoByTags);
+                                                if (qwSopRuleTimeVOS != null && !qwSopRuleTimeVOS.isEmpty()) {
+                                                    //SOP规则
+                                                    qwExternalContactService.qwSopRuleTimeTools(qwSopRuleTimeVOS, userID, qwUser, corpId, externalUserID, externalContact.getName(), contact, currentDate, localTime, combinedTagsList);
+                                                }
+                                                //aiSop任务
+                                                Boolean sopAiChatByRedis = qwExternalContactService.getSopAiChatByRedis(userID, corpId, externalUserID);
+                                                if (!sopAiChatByRedis){
+                                                    asyncQwAiChatSopService.executeQwAiChatSop(qwSopAutoByTags,userID,qwUser,externalUserID
+                                                            ,externalContact.getName(),contact.getId(),contact.getFsUserId(),currentDate,localTime);
+                                                }
+//                                            List<QwSopRuleTimeVO> qwSopAiRuleTimeVOS = qwSopMapper.selectQwAiSopAutoByTagsByForeach(qwSopAutoByTags);
+//                                            if (qwSopAiRuleTimeVOS != null && !qwSopAiRuleTimeVOS.isEmpty()) {
+//                                                qwAiSopRuleTimeTools(qwSopAiRuleTimeVOS, userID, qwUser, corpId, externalUserID, externalContact.getName(), contact);
+//                                            }
+                                            }
+                                        } catch (Exception e) {
+
+                                        }
+
+                                    }
+
+                                } else {
+                                    try {
+                                        // 转换回列表
+                                        List<String> combinedTagsList = new ArrayList<>(combinedTagsSet);
+
+                                        logger.error("不符合分时段条件2--看全部标签是否有符合的:" + combinedTagsList + "|" + externalUserID + "|" + userID + "|" + corpId);
+
+                                        try {
+                                            if (!combinedTagsSet.isEmpty()) {
+                                                //分时段里符合的标签-再用来创建自动SOP
+                                                QwSopAutoByTags qwSopAutoByTags = new QwSopAutoByTags();
+                                                qwSopAutoByTags.setQwUserId(String.valueOf(qwUser.getId()));
+                                                qwSopAutoByTags.setCorpId(corpId);
+                                                qwSopAutoByTags.setTagsIdsSelectList(combinedTagsList);
+                                                qwSopAutoByTags.setSendType(2);
+                                                List<QwSopRuleTimeVO> qwSopRuleTimeVOS = qwSopMapper.selectQwSopAutoByTagsByForeach(qwSopAutoByTags);
+                                                if (qwSopRuleTimeVOS != null && !qwSopRuleTimeVOS.isEmpty()) {
+                                                    //SOP规则
+                                                    qwExternalContactService.qwSopRuleTimeTools(qwSopRuleTimeVOS, userID, qwUser, corpId, externalUserID, externalContact.getName(), contact, currentDate, localTime, combinedTagsList);
+                                                }
+                                                //aiSop任务
+                                                Boolean sopAiChatByRedis = qwExternalContactService.getSopAiChatByRedis(userID, corpId, externalUserID);
+                                                if (!sopAiChatByRedis){
+                                                    asyncQwAiChatSopService.executeQwAiChatSop(qwSopAutoByTags,userID,qwUser,externalUserID
+                                                            ,externalContact.getName(),contact.getId(),contact.getFsUserId(),currentDate,localTime);
+                                                }
+//                                            List<QwSopRuleTimeVO> qwSopAiRuleTimeVOS = qwSopMapper.selectQwAiSopAutoByTagsByForeach(qwSopAutoByTags);
+//                                            if (qwSopAiRuleTimeVOS != null && !qwSopAiRuleTimeVOS.isEmpty()) {
+//                                                qwAiSopRuleTimeTools(qwSopAiRuleTimeVOS, userID, qwUser, corpId, externalUserID, externalContact.getName(), contact);
+//                                            }
+                                            }
+                                        } catch (Exception e) {
+                                            logger.error("用自带标签入营期出错" + combinedTagsList + "|" + externalUserID + "|" + userID + "|" + corpId);
+                                        }
+
+                                    } catch (Exception e) {
+                                        logger.error("打标签出错" + e.getMessage());
+                                    }
+
+                                }
+
+
+                            }
+                        }
+
+
+                    }
+
+                }
+
+                //库里有 企微没有的
+                List<String> notInExternalUseridList = qwExternalContactList.stream()
+                        .filter(externalUserId -> !externalUserid.contains(externalUserId))
+                        .collect(Collectors.toList());
+
+
+                if (!notInExternalUseridList.isEmpty()) {
+                    DeleteQwSopParam apiParam = new DeleteQwSopParam();
+                    apiParam.setQwUserId(qwUser.getQwUserId());
+                    apiParam.setCorpId(qwUser.getCorpId());
+                    apiParam.setExternalUserIds(notInExternalUseridList);
+
+                    // 批量删除 qw_external_contact 表中已经删除的客户的营期以及发送记录
+                    sopUserLogsInfoMapper.deleteByQwUserIdAndCorpIdToContactIdList(apiParam);
+                    sopUserLogsInfoMapper.deleteByQwUserIdAndCorpIdToContactIdByChatList(apiParam);
+                    //批量删除发送记录
+                    qwSopLogsMapper.deleteQwSopLogsByExternalUserIdList(apiParam);
+                    //批量更新状态
+                    batchUpdateQwExternalContact(notInExternalUseridList, qwUser.getQwUserId(), qwUser.getCorpId());
+                }
+            }
+            log.info("新客同步成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("新客同步失败");
+        }
+    }
+
+
+    private void batchUpdateQwExternalContact(List<String> notInExternalUseridList, String qwUserId, String corpId) {
+        // 定义批量插入的大小
+        int batchSize = 500;
+
+        // 循环处理外部用户 ID,每次处理批量大小的子集
+        for (int i = 0; i < notInExternalUseridList.size(); i += batchSize) {
+
+            int endIndex = Math.min(i + batchSize, notInExternalUseridList.size());
+            List<String> batchList = notInExternalUseridList.subList(i, endIndex);  // 获取当前批次的子集
+
+            // 直接使用批次数据进行批量更新,不需要额外的 List
+            try {
+                qwExternalContactMapper.batchUpdateQwExternalContactStatus(batchList, qwUserId, corpId);
+            } catch (Exception e) {
+                // 记录异常日志,方便后续排查问题
+                logger.error("批量更新数据时发生异常,处理的批次起始索引为: " + i, e);
+            }
+        }
+    }
+
+
+    /**
+     * 企业微信客户
+     *
+     * @param param
+     */
+    @Override
+    @Async
+    public void transfer(TransferParam param) {
+        try {
+            log.info("开始分配客户Async");
+            QwUser qwUser = qwUserMapper.selectQwUserById(param.getUserId());
+            Integer err = 0;
+            Integer suc = 0;
+            if (qwUser != null) {
+                List<Long> ids = param.getIds();
+                for (Long id : ids) {
+                    QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(id);
+                    if (qwExternalContact == null || qwExternalContact.getUserId().equals(qwUser.getQwUserId())) {
+                        err++;
+                    } else {
+                        QwTransferCustomerParam qwTransferCustomerParam = new QwTransferCustomerParam();
+                        String content = param.getContent();
+                        if (content == null || content.isEmpty()) {
+                            content = "您好,您的服务已升级,后续将由我的同事接替我的工作,继续为您服务。";
+                        }
+                        qwTransferCustomerParam.setTransfer_success_msg(content);
+                        qwTransferCustomerParam.setHandover_userid(qwExternalContact.getUserId());
+                        qwTransferCustomerParam.setTakeover_userid(qwUser.getQwUserId());
+                        qwTransferCustomerParam.setExternal_userid(Arrays.asList(qwExternalContact.getExternalUserId()));
+                        QwTransferCustomerResult qwTransferCustomerResult = qwApiService.transferCustomer(qwTransferCustomerParam, param.getCorpId());
+
+                        if (qwTransferCustomerResult.getErrcode() == 0) {
+                            List<QwCustomer> customer = qwTransferCustomerResult.getCustomer();
+                            if (customer != null && customer.size() > 0) {
+                                for (QwCustomer qwCustomer : customer) {
+                                    if (qwCustomer.getErrcode() == 0) {
+                                        QwExternalContactTransferLog qwExternalContactTransferLog = new QwExternalContactTransferLog();
+                                        // qwExternalContactTransferLog.setCompanyId(param.getCorpId());
+                                        qwExternalContactTransferLog.setExternalContactId(id);
+                                        qwExternalContactTransferLog.setCompanyUserId(qwExternalContact.getCompanyUserId());
+                                        qwExternalContactTransferLog.setCreateTime(new Date());
+                                        qwExternalContactTransferLog.setStatus(2);
+                                        qwExternalContactTransferLog.setQwUserId(qwUser.getId());
+                                        qwExternalContactTransferLog.setHandoverUserId(qwExternalContact.getUserId());
+                                        qwExternalContactTransferLog.setTakeoverUserId(qwUser.getQwUserId());
+                                        qwExternalContactTransferLog.setCorpId(param.getCorpId());
+                                        qwExternalContactTransferLog.setExternalUserId(qwCustomer.getExternal_userid());
+                                        qwExternalContactTransferLog.setHandoverQwUserId(qwExternalContact.getQwUserId());
+                                        qwExternalContactTransferLogMapper.insertQwExternalContactTransferLog(qwExternalContactTransferLog);
+                                        QwExternalContact qwExternal = new QwExternalContact();
+                                        qwExternal.setStatus(2);
+                                        qwExternal.setTransferStatus(2);
+                                        qwExternal.setId(qwExternalContact.getId());
+                                        qwExternalContactMapper.updateQwExternalContact(qwExternal);
+                                        suc++;
+                                    } else {
+                                        err++;
+                                    }
+                                }
+                            } else {
+                                err++;
+                            }
+                        } else {
+                            logger.error("在职转接失败-" + qwTransferCustomerResult.getErrmsg() + "|" + param.getCorpId());
+                            err++;
+                        }
+                    }
+                }
+            }
+            log.info("在职转接 分配客户成功");
+            log.info("接替成功:" + suc + ",接替失败:" + err);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("在职转接 分配客户失败");
+        }
+    }
+
+
+    @Override
+    @Async
+    public void syncQwExternalContactUnassigned(String corpId) {
+        try {
+            log.info("同步待转接Async");
+
+            QwUnassignedListParam qwUnassignedListParam = new QwUnassignedListParam();
+            qwUnassignedListParam.setPage_size(1000);
+            QwUnassignedListResult unassignedList = qwApiService.getUnassignedList(qwUnassignedListParam, corpId);
+
+            if (unassignedList.getErrcode() == 0) {
+                List<QwUnassignedListResult.InfoEntry> info = unassignedList.getInfo();
+                for (QwUnassignedListResult.InfoEntry infoEntry : info) {
+
+                    QwExternalContact qwExternalContact = new QwExternalContact();
+                    qwExternalContact.setExternalUserId(infoEntry.getExternal_userid());
+                    qwExternalContact.setUserId(infoEntry.getHandover_userid());
+                    qwExternalContact.setStatus(0);
+                    List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactList(qwExternalContact);
+                    if (qwExternalContacts != null && qwExternalContacts.size() > 0) {
+                        for (QwExternalContact externalContact : qwExternalContacts) {
+                            QwExternalContact q = new QwExternalContact();
+                            q.setId(externalContact.getId());
+                            q.setStatus(1);
+                            qwExternalContactMapper.updateQwExternalContact(q);
+                        }
+                    }
+                }
+            }
+            log.info("同步待转接成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("同步待转接失败");
+        }
+
+    }
+
+    @Override
+    @Async
+    public void resignedTransfer(ResignedTransferParam param) {
+        try {
+
+            log.info("离职继承分配客户Async");
+
+            QwUser qwUser = qwUserMapper.selectQwUserById(param.getUserId());
+            Integer err = 0;
+            Integer suc = 0;
+            if (qwUser != null) {
+                List<Long> ids = param.getIds();
+                for (Long id : ids) {
+                    QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(id);
+
+                    if (qwExternalContact == null || qwExternalContact.getUserId().equals(qwUser.getQwUserId())) {
+                        err++;
+                    } else {
+                        QwTransferCustomerResignedParam qwTransferCustomerParam = new QwTransferCustomerResignedParam();
+                        qwTransferCustomerParam.setHandover_userid(qwExternalContact.getUserId());
+                        qwTransferCustomerParam.setTakeover_userid(qwUser.getQwUserId());
+                        qwTransferCustomerParam.setExternal_userid(Arrays.asList(qwExternalContact.getExternalUserId()));
+                        QwTransferCustomerResignedResult qwTransferCustomerResignedParam = qwApiService.resignedTransferCustomer(qwTransferCustomerParam, param.getCorpId());
+
+                        if (qwTransferCustomerResignedParam.getErrcode() == 0) {
+                            List<QwCustomer> customer = qwTransferCustomerResignedParam.getCustomer();
+                            if (customer != null && customer.size() > 0) {
+                                for (QwCustomer qwCustomer : customer) {
+                                    if (qwCustomer.getErrcode() == 0) {
+                                        QwExternalContactTransferLog qwExternalContactTransferLog = new QwExternalContactTransferLog();
+                                        // qwExternalContactTransferLog.setCompanyId(param.getCorpId());
+                                        qwExternalContactTransferLog.setExternalContactId(id);
+                                        qwExternalContactTransferLog.setCompanyUserId(qwExternalContact.getCompanyUserId());
+                                        qwExternalContactTransferLog.setCreateTime(new Date());
+                                        qwExternalContactTransferLog.setStatus(2);
+                                        qwExternalContactTransferLog.setQwUserId(qwUser.getId());
+                                        qwExternalContactTransferLog.setHandoverUserId(qwExternalContact.getUserId());
+                                        qwExternalContactTransferLog.setTakeoverUserId(qwUser.getQwUserId());
+                                        qwExternalContactTransferLog.setCorpId(param.getCorpId());
+                                        qwExternalContactTransferLog.setExternalUserId(qwCustomer.getExternal_userid());
+                                        qwExternalContactTransferLogMapper.insertQwExternalContactTransferLog(qwExternalContactTransferLog);
+                                        QwExternalContact qwExternal = new QwExternalContact();
+                                        qwExternal.setStatus(2);
+                                        qwExternal.setTransferStatus(2);
+                                        qwExternal.setId(qwExternalContact.getId());
+                                        qwExternalContactMapper.updateQwExternalContact(qwExternal);
+                                        //查询是否绑定公司码
+                                        /*CompanyCompanyFsuser companyCompanyFsuser = companyCompanyFsuserMapper.getInfoByUserId(String.valueOf(qwExternalContact.getFsUserId()));
+                                        if (companyCompanyFsuser!=null){
+                                            //修改腕表客服
+                                            watchCompanyUserMapper.updateByCompanyUserId(qwUser.getCompanyUserId(),companyCompanyFsuser.getCompanyUserId());
+                                            //换绑公司码
+                                            companyCompanyFsuser.setCompanyUserId(qwUser.getCompanyUserId());
+                                            companyCompanyFsuser.setQwContactId(qwExternalContact.getId());
+                                            companyCompanyFsuserMapper.updateCompanyCompanyUser(companyCompanyFsuser);
+                                        }*/
+                                        suc++;
+                                    } else {
+                                        err++;
+                                    }
+                                }
+                            } else {
+                                err++;
+                            }
+                        } else {
+                            err++;
+                        }
+                    }
+                }
+            }
+            log.info("接替成功:" + suc + ",接替失败:" + err);
+            log.info("离职继承分配客户成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("离职继承分配客户失败");
+        }
+    }
+
+
+    @Override
+    @Async
+    public void cogradientGroupChat(String corpId, List<String> qwUserIdList) throws Exception {
+
+//        过滤群主的id集合
+        ArrayList<String> ownerFilterList = new ArrayList<>(qwUserIdList);
+        try {
+            QwGroupChatListResult qwGroupChatListResult = qwApiService.groupChatList(ownerFilterList, null, corpId);
+            qwGroupChatService.insertGroupChatList(qwGroupChatListResult, corpId, ownerFilterList);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("同步客户群列表失败");
+        }
+        log.info("同步客户群列表成功");
+    }
+}

+ 14 - 1
fs-service/src/main/java/com/fs/sop/domain/QwSopTempContent.java

@@ -1,6 +1,7 @@
 package com.fs.sop.domain;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.fs.common.annotation.Excel;
 import lombok.Data;
@@ -44,5 +45,17 @@ public class QwSopTempContent{
     @Excel(name = "链接过期时间")
     private String expiresDays;
 
-
+    @TableField(exist = false)
+    private Integer type;
+
+    /**
+     *  课程
+     */
+    @TableField(exist = false)
+    private Integer courseId;
+    /**
+     *  课节
+     */
+    @TableField(exist = false)
+    private Integer videoId;
 }

+ 7 - 0
fs-service/src/main/java/com/fs/sop/domain/QwSopTempVoice.java

@@ -55,6 +55,13 @@ public class QwSopTempVoice{
     /** 语音文件路径 */
     @Excel(name = "秒")
     private LocalDateTime createTime;
+    private LocalDateTime updateTime;
 
+    //@Excel(name = "是否录制完成")
+    private Integer recordType;
+
+    private Long qwUserId;
+
+    private String voicePrintUrl;
 
 }

+ 12 - 0
fs-service/src/main/java/com/fs/sop/mapper/QwSopTempContentMapper.java

@@ -90,4 +90,16 @@ public interface QwSopTempContentMapper extends BaseMapper<QwSopTempContent>{
             "\tt.company_id = 170 \n" +
             "\tAND c.content_type = 3")
     List<QwSopTempContentVO> updateSiFenTemp();
+
+    @Select("select   tc.id,\n" +
+            "  tc.content_type,\n" +
+            "  tc.content,\n" +
+            "  tr.course_id,\n" +
+            "  tr.video_id," +
+            "  tr.content_type as type " +
+            "FROM\n" +
+            "  qw_sop_temp_content tc " +
+            "left join qw_sop_temp_rules tr on  tc.rules_id=tr.id " +
+            "where tc.temp_id=#{tempId}")
+    List<QwSopTempContent> selectQwSopTempContentByTempIdAndRules(@Param("tempId") String tempId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/sop/mapper/QwSopTempVoiceMapper.java

@@ -77,4 +77,6 @@ public interface QwSopTempVoiceMapper extends BaseMapper<QwSopTempVoice>{
     List<QwSopTempVoice> getVoiceByText(@Param("companyUserId") Long companyUserId, @Param("textList") List<String> textList);
 
     List<QwSopTempVoice> selectAllByUserIds(@Param("userIdList") List<Long> userIdList);
+
+    QwSopTempVoice selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(@Param("companyUserId") Long companyUserId,@Param("voiceTxt") String voiceTxt);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopTempVoiceService.java

@@ -77,4 +77,6 @@ public interface IQwSopTempVoiceService extends IService<QwSopTempVoice>{
     void synchronousTemp(List<QwSopTempContent> collect, QwSopTempDay day);
 
     List<QwSopTempVoice> listByTempIdAndCompanyId(String tempId, List<Long> longs);
+
+    QwSopTempVoice selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(Long companyUserId, String voiceTxt);
 }

+ 6 - 2
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempVoiceServiceImpl.java

@@ -47,7 +47,7 @@ public class QwSopTempVoiceServiceImpl extends ServiceImpl<QwSopTempVoiceMapper,
     private final QwSopMapper qwSopMapper;
     private final QwSopTempDayMapper qwSopTempDayMapper;
     private final ICompanyUserService companyUserService;
-
+    private final QwSopTempVoiceMapper qwSopTempVoiceMapper;
     /**
      * 查询模板对应的销售语音文件
      *
@@ -275,5 +275,9 @@ public class QwSopTempVoiceServiceImpl extends ServiceImpl<QwSopTempVoiceMapper,
         log.info("语音生成成功,salesId: {}", salesId);
         return voice;
     }
-
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public QwSopTempVoice selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(Long companyUserId, String voiceTxt) {
+        return qwSopTempVoiceMapper.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId,voiceTxt);
+    }
 }

+ 25 - 21
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -597,7 +597,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             //小程序单独
                             case "4":
                                 String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
-                                        String.valueOf(qwUser.getId()), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
+                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
 
                                 if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())) {
                                     log.error("配置中无小程序id,采用默认的");
@@ -696,7 +696,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             //小程序单独
                             case "4":
                                 String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
-                                        String.valueOf(qwUser.getId()), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
+                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
 
                                 if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())) {
                                     log.error("配置中无小程序id,采用默认的");
@@ -804,7 +804,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
 
                                 String sortLink = generateShortLink(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                        qwUserId, companyUserId, companyId, finalDomainName,item.getExternalId(),config);
+                                        Long.valueOf(qwUserId), companyUserId, companyId, finalDomainName,item.getExternalId(),config);
 
                                 if (StringUtils.isNotEmpty(sortLink)) {
                                     if ("3".equals(st.getContentType())) {
@@ -837,7 +837,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );
 
                             String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                    qwUserId, companyUserId, companyId, item.getExternalId(), config);
+                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config);
 
                             String miniAppId = null;
 
@@ -876,7 +876,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );
 
                             QwCreateLinkByAppVO linkByApp = createLinkByApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                    qwUserId, companyUserId, companyId, item.getExternalId(), config,qwUser.getQwUserName(),contact.getFsUserId());
+                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config,qwUser.getQwUserName(),contact.getFsUserId());
                             st.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                             st.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
 
@@ -1177,7 +1177,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 companyId, item.getExternalId(),param.getStartTime(),dataTime );
 
                         String sortLink = generateShortLink(st, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
-                                String.valueOf(qwUser.getId()), companyUserId, companyId, domainName,item.getExternalId(),config);
+                                qwUser.getId(), companyUserId, companyId, domainName,item.getExternalId(),config);
 
                         if (StringUtils.isNotEmpty(sortLink)) {
                             if ("3".equals(st.getContentType())) {
@@ -1212,7 +1212,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             item.getExternalId(),item.getStartTime(),dataTime );
 
                     String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
-                            String.valueOf(qwUser.getId()), companyUserId, companyId, item.getExternalId(), config);
+                            qwUser.getId(), companyUserId, companyId, item.getExternalId(), config);
 
 
                     String miniAppId = null;
@@ -1269,7 +1269,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         }
     }
     // 提取通用替换逻辑的方法
-    private void replaceContent(String contentType, String content, Consumer<String> setter, List<FastGptChatReplaceWords> words) {
+    public void replaceContent(String contentType, String content, Consumer<String> setter, List<FastGptChatReplaceWords> words) {
         if (contentType != null && content != null && !content.isEmpty()) {
             for (FastGptChatReplaceWords word : words) {
                 if (content.contains(word.getContent())) {
@@ -1279,6 +1279,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
             }
         }
     }
+
     private void processAndInsertQwSopLogsBySendMsg(List<QwSopLogs> sopLogsList ) {
         // 定义批量插入的大小
         int batchSize = 500;
@@ -1331,11 +1332,11 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     }
 
     private String generateShortLink(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
-                                     Integer courseId, Integer videoId, String qwUserId,
+                                     Integer courseId, Integer videoId, Long qwUserId,
                                      String companyUserId, String companyId,String domainName, Long externalId,CourseConfig config) {
 
         FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
-                companyUserId, companyId, externalId,0);
+                companyUserId, companyId, externalId,0,null);
 
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link,courseMap);
@@ -1357,11 +1358,11 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     }
 
     private String createLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
-                                     Integer courseId, Integer videoId, String qwUserId,
+                                     Integer courseId, Integer videoId, Long qwUserId,
                                      String companyUserId, String companyId, Long externalId,CourseConfig config) {
 
         FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
-                                                companyUserId, companyId, externalId,3);
+                                                companyUserId, companyId, externalId,3,null);
 
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link,courseMap);
@@ -1379,12 +1380,12 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     }
 
     private QwCreateLinkByAppVO createLinkByApp(QwSopCourseFinishTempSetting.Setting setting, String corpId,
-                                                Date sendTime, Integer courseId, Integer videoId, String qwUserId,
+                                                Date sendTime, Integer courseId, Integer videoId, Long qwUserId,
                                                 String companyUserId, String companyId, Long externalId,
                                                 CourseConfig config,String qwUserName,Long fsUserId){
 
         FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
-                companyUserId, companyId, externalId,4);
+                companyUserId, companyId, externalId,4,null);
 
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link,courseMap);
@@ -1406,7 +1407,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         byAppVO.setAppMsgLink(appMsgLink);
 
             //异步生成app链接记录
-        asyncSopTestService.createFsCourseSopAppLink(link.getLink(),sendTime,updateTime,companyId,companyUserId,qwUserId,
+        asyncSopTestService.createFsCourseSopAppLink(link.getLink(),sendTime,updateTime,companyId,companyUserId,String.valueOf(qwUserId),
                 qwUserName,corpId,courseId,setting.getLinkTitle(),setting.getLinkImageUrl(),videoId,
                 setting.getLinkDescribe(),appMsgLink,externalId);
 
@@ -1443,29 +1444,32 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return updateTime;
     }
 
-    public FsCourseLink createFsCourseLink(String corpId, Date sendTime,Integer courseId,Integer videoId, String qwUserId,
-                                           String companyUserId, String companyId,Long externalId,Integer type){
+    public FsCourseLink createFsCourseLink(String corpId, Date sendTime, Integer courseId, Integer videoId, Long qwUserId,
+                                           String companyUserId, String companyId, Long externalId, Integer type, String chatId) {
         // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
         FsCourseLink link = new FsCourseLink();
         link.setCompanyId(Long.parseLong(companyId));
-        link.setQwUserId(Long.valueOf(qwUserId));
+        link.setQwUserId(qwUserId);
         link.setCompanyUserId(Long.parseLong(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)){
+        if (StringUtil.strIsNullOrEmpty(randomString)) {
             link.setLink(UUID.randomUUID().toString().replace("-", ""));
-        }else {
+        } else {
             link.setLink(randomString);
         }
+
         link.setCreateTime(sendTime);
 
         return link;
     }
+
     /**
      * 时间字符串转Date时间
      * @param dateString

+ 5 - 0
fs-service/src/main/resources/mapper/sop/QwSopTempVoiceMapper.xml

@@ -119,4 +119,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <delete id="remove">
         delete from qw_sop_temp_voice a where a.temp_id = #{tempId} and a.day_id =#{dayId}
     </delete>
+
+    <select id="selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt" resultType="com.fs.sop.domain.QwSopTempVoice">
+        select qw_user_id qwUserId,voice_url voiceUrl,voice_txt voiceTxt,user_voice_url userVoiceUrl,company_user_id companyUserId,
+               record_type recordType,duration from qw_sop_temp_voice where company_user_id = #{companyUserId} and voice_txt = #{voiceTxt}
+    </select>
 </mapper>