浏览代码

1.提交最美叙酱定时任务

jzp 4 天之前
父节点
当前提交
2bd65d0217

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

@@ -2,13 +2,18 @@ package com.fs.his.task;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateTime;
+import cn.hutool.http.HttpException;
+import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.fs.common.core.domain.R;
+import com.fs.FSApplication;
+import com.fs.common.config.RedisTenantContext;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.core.redis.RedisCacheTenant;
+import com.fs.common.exception.base.BaseException;
 import com.fs.common.service.impl.SmsServiceImpl;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
@@ -20,6 +25,7 @@ import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.QwIpadTotalVo;
 import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.core.config.TenantConfigContext;
 import com.fs.course.dto.BatchSendCourseAllDTO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseWatchLogService;
@@ -33,6 +39,7 @@ import com.fs.fastGpt.domain.*;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
 import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
 import com.fs.fastGpt.service.AiHookService;
+import com.fs.fastGpt.service.IFastGptChatMsgService;
 import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.framework.task.TenantTaskRunner;
 import com.fs.fastgptApi.util.AudioUtils;
@@ -60,24 +67,35 @@ import com.fs.huifuPay.service.HuiFuService;
 import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
 import com.fs.im.service.OpenIMService;
+import com.fs.ipad.IpadSendUtils;
+import com.fs.ipad.vo.*;
 import com.fs.qw.domain.QwCompany;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
 import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.param.QwExternalContactAddTagParam;
+import com.fs.qw.param.QwExternalContactParam;
 import com.fs.qw.service.*;
+import com.fs.qwApi.config.OpenQwConfig;
 import com.fs.sop.domain.QwSopTempVoice;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.utils.OrderContextHolder;
+import com.fs.wxwork.dto.*;
+import com.fs.wxwork.service.WxWorkService;
+import com.fs.wxwork.service.WxWorkServiceNew;
 import com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Test;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -85,11 +103,15 @@ import org.springframework.stereotype.Component;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -239,6 +261,10 @@ public class Task {
 
     @Autowired
     private IFsStoreOrderScrmService orderScrmService;
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
     /**
      * 定时任务,处理ai禁止回复之后的消息
      */
@@ -275,6 +301,316 @@ public class Task {
         }
     }*/
 
+    @Scheduled(cron = "0 0/5 * * * ?")
+    public void addTagByQwExtCreateTimeNew() {
+        if (saasTaskEnabled) {
+            tenantTaskRunner.runForEachTenant("addTagByQwExtCreateTime", this::addTagByQwExtCreateTime);
+        } else {
+            addTagByQwExtCreateTime();
+        }
+    }
+
+    /**
+     * 最美叙酱给客户打标签(其他客户关闭,临时用)
+     */
+    public void addTagByQwExtCreateTime() {
+        try {
+            Long tenantId = RedisTenantContext.getTenantId();
+            if(41L != tenantId) return;
+            QwExternalContact qwExternalContact = new QwExternalContact();
+            qwExternalContact.setIsReply(1);
+            qwExternalContact.setTagIds("etotXidAAAMrYqb-nEijbTYQs4PJDbLg");
+            List<QwExternalContact> qwExternalContacts = qwExternalContactService.selectQwExternalContactListBycreateTime(qwExternalContact);
+            if(qwExternalContacts.isEmpty()) return;
+            Date now = new Date();
+            Date oneHourAgo = new Date(now.getTime() - 10 * 60 * 60 * 1000);
+
+            List<QwExternalContact> filteredContacts = qwExternalContacts.stream()
+                    .filter(contact -> {
+                        if (contact.getCreateTime() == null) {
+                            return false;
+                        }
+                        return contact.getCreateTime().before(oneHourAgo);
+                    })
+                    .collect(Collectors.toList());
+
+            if (filteredContacts.isEmpty()) {
+                log.info("过滤后没有创建时间超过10小时的联系人");
+                return;
+            }
+
+            for (QwExternalContact qwExt : filteredContacts) {
+
+                QwExternalContactAddTagParam param = new QwExternalContactAddTagParam();
+                Long qwUserId = qwExt.getQwUserId();
+                if(qwUserId == null) continue;
+                QwUser user = qwUserService.selectQwUserById(qwUserId);
+
+
+                //添加需要打标签的客户
+                List<Long> list = new ArrayList<>();
+                list.add(qwExt.getId());
+                param.setUserIds(list);
+
+                try {
+                    String[] split = new String[]{"etotXidAAAwBK56Zp4OmU71zH8NqlA6Q"};
+                    param.setTagIds(Arrays.asList(split));
+                    param.setCorpId(user.getCorpId());
+                } catch (Exception e) {
+                    System.out.println("标签格式错误,租户41,外部联系人id:" + qwExt.getId());
+                }
+
+                String url = OpenQwConfig.baseApi + "/addTag?tenantId=41";
+                String result = HttpUtil.createPost(url)
+                        .body(JSON.toJSONString(param))
+                        .execute()
+                        .body();
+                System.out.println(result);
+            }
+        } catch (HttpException e) {
+            System.out.println("请求异常:" + e.getMessage());
+        }
+    }
+
+    @Scheduled(cron = "0 0/1 * * * ?")
+    public void sendMsgByQwExtCreateTimeNew() {
+        if (saasTaskEnabled) {
+            tenantTaskRunner.runForEachTenant("sendMsgByQwExtCreateTime", this::sendMsgByQwExtCreateTime);
+        } else {
+            sendMsgByQwExtCreateTime();
+        }
+    }
+
+    @Autowired
+    WxWorkServiceNew wxWorkService;
+
+    @Autowired
+    RedisCacheTenant<Long> redisCacheLong;
+
+    @Autowired
+    private IFastGptChatMsgService fastGptChatMsgService;
+
+    @Autowired
+    IpadSendUtils ipadSendUtils;
+
+    public void sendMsgByQwExtCreateTime() {
+        Long tenantId = RedisTenantContext.getTenantId();
+        if(41L != tenantId) return;
+        QwExternalContact qwExternalContact = new QwExternalContact();
+        qwExternalContact.setTagIds("etotXidAAAcNhR-YuTMgC9B2VxH9QU3g");
+        qwExternalContact.setCreateTime(new Date());
+        List<QwExternalContact> qwExternalContacts = qwExternalContactService.selectQwExternalContactListByCreateTimeNew(qwExternalContact);
+        if(qwExternalContacts.isEmpty()) return;
+        Date now = new Date();
+        Date oneHourAgo = new Date(now.getTime() - 2 * 60 * 1000);
+        List<QwExternalContact> filteredContacts = qwExternalContacts.stream()
+                .filter(contact -> {
+                    if (contact.getCreateTime() == null) {
+                        return false;
+                    }
+                    return contact.getCreateTime().before(oneHourAgo);
+                })
+                .collect(Collectors.toList());
+
+        for (QwExternalContact qwExt : filteredContacts) {
+
+            QwExternalContactAddTagParam param = new QwExternalContactAddTagParam();
+            Long qwUserId = qwExt.getQwUserId();
+            if(qwUserId == null) continue;
+            QwUser user = qwUserService.selectQwUserById(qwUserId);
+            QwCompany qwCompany = qwCompanyService.selectQwCompanyByCorpId(user.getCorpId());
+
+
+            FastGptChatSession fastGptChatSession = fastGptChatSessionMapper.selectFastGptChatSessionByQwExternalContactsAndUserId(qwExt.getId(), qwUserId);
+            if(fastGptChatSession == null){
+                if(qwExt.getType()!=null&&qwExt.getType()==1){
+                    fastGptChatSession = new FastGptChatSession();
+                    String chatId = UUID.randomUUID().toString();
+                    fastGptChatSession.setChatId(chatId);
+                    if(user.getFastGptRoleId() != null){
+                        fastGptChatSession.setKfId(user.getFastGptRoleId().toString());
+                    }
+                    fastGptChatSession.setStatus(1);
+                    fastGptChatSession.setRemindCount(0);
+                    fastGptChatSession.setRemindStatus(0);
+                    fastGptChatSession.setCreateTime(new Date());
+                    fastGptChatSession.setQwExtId(qwExt.getId());
+                    fastGptChatSession.setQwUserId(user.getId());
+                    fastGptChatSession.setIsArtificial(0);
+                    fastGptChatSession.setAvatar(qwExt.getAvatar());
+                    fastGptChatSession.setNickName(qwExt.getName());
+                    fastGptChatSession.setCompanyId(user.getCompanyId());
+                    fastGptChatSession.setLastTime(new Date());
+                    fastGptChatSession.setIsReply(0);
+                    fastGptChatSessionMapper.insertFastGptChatSession(fastGptChatSession);
+                }
+            }
+
+            BaseVo parentVo = new BaseVo();
+            assert fastGptChatSession != null;
+            if(fastGptChatSession.getSessionId() == null){
+                parentVo.setId(user.getId());
+            }else{
+                parentVo.setId(fastGptChatSession.getSessionId());
+            }
+            parentVo.setRoom(false);
+            parentVo.setUuid(user.getUid());
+            parentVo.setAgentId(qwCompany.getServerAgentId());
+            parentVo.setExId(qwExt.getExternalUserId());
+            parentVo.setServerId(user.getServerId());
+            parentVo.setCorpCode(parentVo.getCorpCode());
+            parentVo.setCorpId(parentVo.getCorpId());
+            parentVo.setQwUserId(user.getId());
+
+
+            FileVo voiceVo;
+            CompanyUser companyUser = companyUserMapper.selectCompanyUserById(user.getCompanyUserId());
+            if(companyUser == null) continue;
+            if("0".equals(companyUser.getSex())){
+                voiceVo = FileVo.builder()
+                        .url("https://kyt-1323137866.cos.ap-chongqing.myqcloud.com/test/1.silk")
+                        .voiceTime(36)
+                        .build();
+            }else{
+                voiceVo = FileVo.builder()
+                        .url("https://kyt-1323137866.cos.ap-chongqing.myqcloud.com/test/2.silk")
+                        .voiceTime(32)
+                        .build();
+            }
+
+
+            voiceVo.setBase(parentVo);
+            ipadSendUtils.sendVoice(voiceVo);
+
+            String content = "本次免费领取活动真实有效,明天上午十点您准时来直播间观看并免费领取。明天开播前我会把直播链接发给您,看完直播第一时间找我登记领取,好吧哥!";
+            TxtVo txtVo = TxtVo.builder().content(content).build();
+            txtVo.setBase(parentVo);
+            saveQwUserMsg(fastGptChatSession,1,content,user);
+            ipadSendUtils.sendTxt(txtVo);
+
+            FileVo imgVo = FileVo.builder().url("https://ylrz-1323137866.cos.ap-chongqing.myqcloud.com/ylrz/20260528/eb81adca120a45dcbf7ae31e3daacd74.png").build();
+            imgVo.setBase(parentVo);
+            ipadSendUtils.sendImg(imgVo);
+
+            FileVo imgVo1 = FileVo.builder().url("https://ysy-1329817240.cos.ap-guangzhou.myqcloud.com/ysy/20260527/1ee711bf934642cba3886a5f07ac3cdd.png").build();
+            imgVo1.setBase(parentVo);
+            ipadSendUtils.sendImg(imgVo1);
+
+
+            //添加需要打标签的客户
+            List<Long> list = new ArrayList<>();
+            list.add(qwExt.getId());
+            param.setUserIds(list);
+
+            try {
+                String[] split = new String[]{"etotXidAAAcNhR-YuTMgC9B2VxH9QU3g"};
+                param.setTagIds(Arrays.asList(split));
+                param.setCorpId(user.getCorpId());
+            } catch (Exception e) {
+                System.out.println("标签格式错误,租户41,外部联系人id:" + qwExt.getId());
+            }
+
+            String url = OpenQwConfig.baseApi + "/delTag?tenantId=41";
+            String result = HttpUtil.createPost(url)
+                    .body(JSON.toJSONString(param))
+                    .execute()
+                    .body();
+            System.out.println(result);
+        }
+    }
+
+
+    @Scheduled(cron = "0 10 9 * * ?")
+    public void sendMsgByQwExtCreateTimeTwoDayNew() {
+        if (saasTaskEnabled) {
+            tenantTaskRunner.runForEachTenant("sendMsgByQwExtCreateTimeTwoDay", this::sendMsgByQwExtCreateTimeTwoDay);
+        } else {
+            sendMsgByQwExtCreateTimeTwoDay();
+        }
+    }
+
+    public void sendMsgByQwExtCreateTimeTwoDay() {
+        Long tenantId = RedisTenantContext.getTenantId();
+        if(41L != tenantId) return;
+        // 昨天日期
+        Date yesterdayDate = Date.from(
+                LocalDate.now().minusDays(1)
+                        .atStartOfDay(ZoneId.systemDefault())
+                        .toInstant());
+
+        QwExternalContact qwExternalContact = new QwExternalContact();
+        qwExternalContact.setCreateTime(yesterdayDate);
+        List<QwExternalContact> qwExternalContacts = qwExternalContactService.selectQwExternalContactListByCreateTimeNew(qwExternalContact);
+        if(qwExternalContacts.isEmpty()) return;
+
+
+        for (QwExternalContact qwExt : qwExternalContacts) {
+            Long qwUserId = qwExt.getQwUserId();
+            if(qwUserId == null) continue;
+            QwUser user = qwUserService.selectQwUserById(qwUserId);
+            QwCompany qwCompany = qwCompanyService.selectQwCompanyByCorpId(user.getCorpId());
+            if(qwCompany == null) continue;
+
+
+            BaseVo parentVo = new BaseVo();
+            parentVo.setId(user.getId());
+            parentVo.setRoom(false);
+            parentVo.setUuid(user.getUid());
+            parentVo.setAgentId(qwCompany.getServerAgentId());
+            parentVo.setExId(qwExt.getExternalUserId());
+            parentVo.setServerId(user.getServerId());
+            parentVo.setCorpCode(parentVo.getCorpCode());
+            parentVo.setCorpId(parentVo.getCorpId());
+            parentVo.setQwUserId(user.getId());
+
+
+            FileVo voiceVo;
+            CompanyUser companyUser = companyUserMapper.selectCompanyUserById(user.getCompanyUserId());
+            if(companyUser == null) continue;
+            if("0".equals(companyUser.getSex())){
+                voiceVo = FileVo.builder()
+                        .url("https://kyt-1323137866.cos.ap-chongqing.myqcloud.com/test/13.silk")
+                        .voiceTime(19)
+                        .build();
+            }else{
+                voiceVo = FileVo.builder()
+                        .url("https://kyt-1323137866.cos.ap-chongqing.myqcloud.com/test/12.silk")
+                        .voiceTime(17)
+                        .build();
+            }
+
+            voiceVo.setBase(parentVo);
+            ipadSendUtils.sendVoice(voiceVo);
+        }
+    }
+    /** 存聊天记录  **/
+    private void saveQwUserMsg(FastGptChatSession fastGptChatSession,Integer sendType,String content,QwUser sendUser) {
+        if(content.isEmpty()){
+            return;
+        }
+        FastGptChatMsg fastGptChatMsgAi = new FastGptChatMsg();
+        fastGptChatMsgAi.setContent(content);
+        fastGptChatMsgAi.setSessionId(fastGptChatSession.getSessionId());
+        if(sendUser.getFastGptRoleId() != null){
+            fastGptChatMsgAi.setRoleId(Long.parseLong(fastGptChatSession.getKfId()));
+        }
+        fastGptChatMsgAi.setSendType(sendType);
+        fastGptChatMsgAi.setCompanyId(fastGptChatSession.getCompanyId());
+        fastGptChatMsgAi.setCompanyUserId(sendUser.getCompanyUserId());
+        fastGptChatMsgAi.setUserId(fastGptChatSession.getUserId());
+        fastGptChatMsgAi.setUserType(1);
+        fastGptChatMsgAi.setMsgType(1);
+        fastGptChatMsgAi.setStatus(0);
+        fastGptChatMsgAi.setAvatar(fastGptChatSession.getAvatar());
+        fastGptChatMsgAi.setNickName(fastGptChatSession.getNickName());
+        fastGptChatMsgAi.setCreateTime(new Date());
+        fastGptChatMsgAi.setExtId(fastGptChatSession.getQwExtId()+"");
+        fastGptChatMsgService.insertFastGptChatMsg(fastGptChatMsgAi);
+        log.info("新增消息:"+fastGptChatMsgAi);
+    }
+
+
+
     /**
      * sop任务token消耗统计
      */

+ 0 - 2
fs-admin/src/main/java/com/fs/live/controller/LiveController.java

@@ -11,8 +11,6 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.vo.CompanyVO;
 import com.fs.framework.web.service.TokenService;
-import com.fs.hisStore.task.LiveTask;
-import com.fs.hisStore.task.MallStoreTask;
 import com.fs.live.domain.Live;
 import com.fs.live.service.ILiveService;
 import com.fs.live.vo.LiveListVo;

+ 42 - 9
fs-service/src/main/java/com/fs/company/config/AsyncCalleeConfig.java

@@ -6,6 +6,8 @@ import com.fs.common.utils.spring.SpringUtils;
 import com.fs.core.config.TenantConfigContext;
 import com.fs.wxcid.utils.TenantHelper;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.task.TaskDecorator;
@@ -39,6 +41,20 @@ public class AsyncCalleeConfig {
         return executor;
     }
 
+    @Bean
+    public BeanPostProcessor threadPoolTaskExecutorPostProcessor() {
+        return new BeanPostProcessor() {
+            @Override
+            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+                if ("threadPoolTaskExecutor".equals(beanName) && bean instanceof ThreadPoolTaskExecutor) {
+                    ((ThreadPoolTaskExecutor) bean).setTaskDecorator(new TenantContextTaskDecorator());
+                    log.info("已为 threadPoolTaskExecutor 设置 TenantContextTaskDecorator");
+                }
+                return bean;
+            }
+        };
+    }
+
     /**
      * 租户上下文任务装饰器
      * 在任务执行前捕获当前线程的租户ID,在子线程中恢复
@@ -46,25 +62,27 @@ public class AsyncCalleeConfig {
     public static class TenantContextTaskDecorator implements TaskDecorator {
         @Override
         public Runnable decorate(Runnable runnable) {
-            // 捕获当前线程的租户ID
-            Long tenantId = TenantHelper.getTenantId();
+            Long tenantId = resolveTenantId();
+            log.debug("TenantContextTaskDecorator 捕获租户ID: {}", tenantId);
             return () -> {
+                if (tenantId == null) {
+                    log.warn("TenantContextTaskDecorator 租户ID为空, 跳过上下文设置");
+                    runnable.run();
+                    return;
+                }
                 try {
-                    // 在子线程中设置租户ID
                     TenantHelper.setTenantId(tenantId);
                     Object manager = SpringUtils.getBean("tenantDataSourceManager");
                     Method method = manager.getClass().getMethod("ensureSwitchByTenantId", Long.class);
-                    method.invoke(manager, TenantHelper.getTenantId());
-                    // 设置租户到 SecurityContext,供 TenantKeyRedisSerializer 自动为 Redis Key 加 tenantid 前缀
+                    method.invoke(manager, tenantId);
                     SecurityContextHolder.getContext().setAuthentication(
                             new UsernamePasswordAuthenticationToken(
-                                    new TenantPrincipal(TenantHelper.getTenantId()),
+                                    new TenantPrincipal(tenantId),
                                     null,
                                     Collections.emptyList()
                             )
                     );
-                    // 切换 Redis 租户上下文
-                    RedisTenantContext.setTenantId(TenantHelper.getTenantId());
+                    RedisTenantContext.setTenantId(tenantId);
                     runnable.run();
                 } catch (InvocationTargetException e) {
                     throw new RuntimeException(e);
@@ -74,7 +92,6 @@ public class AsyncCalleeConfig {
                     throw new RuntimeException(e);
                 } finally {
                     try {
-                        // 清理子线程的租户ID
                         TenantHelper.removeTenantId();
                         TenantConfigContext.clear();
                         SecurityContextHolder.clearContext();
@@ -88,5 +105,21 @@ public class AsyncCalleeConfig {
                 }
             };
         }
+
+        private Long resolveTenantId() {
+            Long tenantId = TenantHelper.getTenantId();
+            if (tenantId != null) {
+                return tenantId;
+            }
+            try {
+                tenantId = com.fs.common.utils.SecurityUtils.getTenantId();
+                if (tenantId != null) {
+                    return tenantId;
+                }
+            } catch (Exception ignored) {
+            }
+            tenantId = RedisTenantContext.getTenantId();
+            return tenantId;
+        }
     }
 }

+ 2 - 2
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -1548,7 +1548,7 @@ public class AiHookServiceImpl implements AiHookService {
             fastGptChatSession.setNickName(qwExternalContacts.getName());
             fastGptChatSession.setCompanyId(user.getCompanyId());
             fastGptChatSession.setLastTime(new Date());
-            fastGptChatSession.setIsReply(0);
+            fastGptChatSession.setIsReply(1);
             fastGptChatSession.setUserId(String.valueOf(dto.getUser_id()));
             fastGptChatSessionMapper.insertFastGptChatSession(fastGptChatSession);
             addUserSex(qwExternalContacts);
@@ -1557,7 +1557,7 @@ public class AiHookServiceImpl implements AiHookService {
                 FastGptChatSession ss = new FastGptChatSession();
                 ss.setSessionId(fastGptChatSession.getSessionId());
                 ss.setRemindStatus(0);
-                ss.setIsReply(0);
+                ss.setIsReply(1);
                 ss.setUserId(String.valueOf(dto.getUser_id()));
                 fastGptChatSessionMapper.updateFastGptChatSession(ss);
             }

+ 0 - 2
fs-service/src/main/java/com/fs/hisStore/service/impl/FsUserScrmServiceImpl.java

@@ -105,8 +105,6 @@ public class FsUserScrmServiceImpl implements IFsUserScrmService
     @Autowired
     private ICompanyUserCacheService companyUserCacheService;
     @Autowired
-    private ICompanyUserService companyUserService;
-    @Autowired
     private FsUserCourseVideoMapper userCourseVideoMapper;
 
     @Autowired

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

@@ -665,4 +665,8 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
                                                                   @Param("corpId")String corpId,@Param("qwUserId") String qwUserId);
 
     void updateQwExternalContactByExternalUserIdAndUserId(@Param("map") QwExternalContact externalContact);
+
+    List<QwExternalContact> selectQwExternalContactListBycreateTime(QwExternalContact qwExternalContact);
+
+    List<QwExternalContact> selectQwExternalContactListByCreateTimeNew(QwExternalContact qwExternalContact);
 }

+ 33 - 1
fs-service/src/main/java/com/fs/qw/service/AsyncQwAiChatSopService.java

@@ -1,8 +1,11 @@
 package com.fs.qw.service;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.common.config.RedisTenantContext;
+import com.fs.common.core.domain.model.TenantPrincipal;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseLink;
@@ -30,14 +33,19 @@ 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.tenant.mapper.TenantInfoMapper;
 import com.fs.voice.utils.StringUtil;
+import com.fs.wxcid.utils.TenantHelper;
 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.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Service;
 
+import java.lang.reflect.Method;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -47,6 +55,7 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
+
 @Slf4j
 @Service
 @AllArgsConstructor
@@ -92,11 +101,34 @@ public class AsyncQwAiChatSopService {
     @Autowired
     private QwExternalContactInfoMapper qwExternalContactInfoMapper;
 
+    @Autowired
+    private TenantInfoMapper tenantInfoMapper;
+
     @Async("threadPoolTaskExecutor")
     public void executeQwAiChatSop(QwSopAutoByTags qwSopAutoByTags, String userID,
                                    QwUser qwUser, String externalUserID, String externalContactName,
                                    Long externalId, Long fsUserId, LocalDate currentDate, LocalTime localTime) {
-
+        Long tenantId = RedisTenantContext.getTenantId();
+        if (tenantId != null) {
+            try {
+                TenantHelper.setTenantId(tenantId);
+                Object manager = SpringUtils.getBean("tenantDataSourceManager");
+                Method method = manager.getClass().getMethod("ensureSwitchByTenantId", Long.class);
+                method.invoke(manager, tenantId);
+                // 设置租户到 SecurityContext,供 TenantKeyRedisSerializer 自动为 Redis Key 加 tenantid 前缀
+                SecurityContextHolder.getContext().setAuthentication(
+                        new UsernamePasswordAuthenticationToken(
+                                new TenantPrincipal(TenantHelper.getTenantId()),
+                                null,
+                                Collections.emptyList()
+                        )
+                );
+                // 切换 Redis 租户上下文
+                RedisTenantContext.setTenantId(TenantHelper.getTenantId());
+            } catch (Exception e) {
+                log.error("callerResult4EasyCall 切换租户数据源失败: tenantId={}", TenantHelper.getTenantId(), e);
+            }
+        }
 
         QwExternalContact contact;
         if(externalId != null){

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

@@ -265,4 +265,8 @@ public interface IQwExternalContactService extends IService<QwExternalContact> {
     List<QwMandatoryRegistrParam> selectQwExternalContactMandatoryRegistrationByIds(String corpId);
 
     int batchUpdateQwExternalContactMandatoryRegistration(List<QwMandatoryRegistrParam> batchList);
+
+    List<QwExternalContact> selectQwExternalContactListBycreateTime(QwExternalContact qwExternalContact);
+
+    List<QwExternalContact> selectQwExternalContactListByCreateTimeNew(QwExternalContact qwExternalContact);
 }

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

@@ -77,7 +77,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -216,6 +218,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     @Autowired
     private QwExternalContactTransferCompanyAuditUserMapper transferCompanyAuditUserMapper;
 
+    @Lazy
     @Autowired
     private AsyncQwAiChatSopService asyncQwAiChatSopService;
     @Autowired
@@ -6042,6 +6045,17 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     public int batchUpdateQwExternalContactMandatoryRegistration(List<QwMandatoryRegistrParam> batchList) {
         return qwExternalContactMapper.batchUpdateQwExternalContactMandatoryRegistration( batchList);
     }
+
+    @Override
+    public List<QwExternalContact> selectQwExternalContactListBycreateTime(QwExternalContact qwExternalContact) {
+        return qwExternalContactMapper.selectQwExternalContactListBycreateTime(qwExternalContact);
+    }
+
+    @Override
+    public List<QwExternalContact> selectQwExternalContactListByCreateTimeNew(QwExternalContact qwExternalContact) {
+        return qwExternalContactMapper.selectQwExternalContactListByCreateTimeNew(qwExternalContact);
+    }
+
     @Override
     public R getRepeat(RepeatParam param) {
         List<QwExternalContact> list = qwExternalContactMapper.selectList(new QueryWrapper<QwExternalContact>().eq("external_user_id", param.getExternalUserId()));

+ 14 - 0
fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

@@ -836,6 +836,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             and user_id = #{qwUserId}
         order by create_time desc limit 1
     </select>
+    <select id="selectQwExternalContactListBycreateTime" resultMap="QwExternalContactResult">
+        select qw.* from qw_external_contact qw left join fastgpt_chat_session fc on qw.id = fc.qw_ext_id
+        where qw.create_time is not null and qw.corp_id = 'wwd9ecb73d85949846'
+        <if test="tagIds != null  and tagIds != ''"> and qw.tag_ids like concat('%', #{tagIds}, '%')</if>
+        <if test="isReply != null  and isReply != ''"> and fc.is_reply = #{isReply}</if>
+    </select>
+
+    <select id="selectQwExternalContactListByCreateTimeNew" resultMap="QwExternalContactResult">
+        select qw.* from qw_external_contact qw left join fastgpt_chat_session fc on qw.id = fc.qw_ext_id
+        where qw.create_time is not null and qw.corp_id = 'wwd9ecb73d85949846'
+        <if test="createTime != null"> and date_format(qw.create_time,'%Y-%m-%d') = date_format(#{createTime},'%Y-%m-%d') </if>
+        <if test="tagIds != null  and tagIds != ''"> and qw.tag_ids like concat('%', #{tagIds}, '%')</if>
+        <if test="isReply != null  and isReply != ''"> and fc.is_reply = #{isReply}</if>
+    </select>
 
     <update id="updateQwExternalContactByExternalUserIdAndUserId" parameterType="QwExternalContact">
         update qw_external_contact set application_external_user_id = #{map.applicationExternalUserId}

+ 19 - 7
fs-service/src/main/resources/mapper/third/TencentWordDetailMapper.xml

@@ -23,13 +23,25 @@
     </insert>
 
     <update id="updateBatchById">
-        <foreach collection="list" item="item" separator=";">
-            update tencent_word_detail
-            <set>
-                <if test="item.a != null">a = #{item.a},</if>
-                update_time = now()
-            </set>
-            where id = #{item.id}
+        UPDATE tencent_word_detail
+        <trim prefix="SET" suffixOverrides=",">
+            <trim prefix="a = CASE" suffix="END,">
+                <foreach collection="list" item="item">
+                    <if test="item.a != null">
+                        WHEN id = #{item.id} THEN #{item.a}
+                    </if>
+                </foreach>
+            </trim>
+            update_time = CASE
+            <foreach collection="list" item="item">
+                WHEN id = #{item.id} THEN now()
+            </foreach>
+            END
+        </trim>
+        WHERE id IN
+        <foreach collection="list" item="item" open="(" close=")" separator=",">
+            #{item.id}
         </foreach>
     </update>
+
 </mapper>