Jelajahi Sumber

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

jzp 5 hari lalu
induk
melakukan
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.collection.CollectionUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateTime;
+import cn.hutool.http.HttpException;
+import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 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.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.service.impl.SmsServiceImpl;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
 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.service.ICompanyUserService;
 import com.fs.company.vo.QwIpadTotalVo;
 import com.fs.company.vo.QwIpadTotalVo;
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.core.config.TenantConfigContext;
 import com.fs.course.dto.BatchSendCourseAllDTO;
 import com.fs.course.dto.BatchSendCourseAllDTO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseWatchLogService;
 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.FastGptChatSessionMapper;
 import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
 import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
 import com.fs.fastGpt.service.AiHookService;
 import com.fs.fastGpt.service.AiHookService;
+import com.fs.fastGpt.service.IFastGptChatMsgService;
 import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.framework.task.TenantTaskRunner;
 import com.fs.framework.task.TenantTaskRunner;
 import com.fs.fastgptApi.util.AudioUtils;
 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.dto.*;
 import com.fs.im.service.IImService;
 import com.fs.im.service.IImService;
 import com.fs.im.service.OpenIMService;
 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.QwCompany;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
 import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
 import com.fs.qw.mapper.QwUserMapper;
 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.qw.service.*;
+import com.fs.qwApi.config.OpenQwConfig;
 import com.fs.sop.domain.QwSopTempVoice;
 import com.fs.sop.domain.QwSopTempVoice;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysConfigService;
 import com.fs.utils.OrderContextHolder;
 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 com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Test;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -85,11 +103,15 @@ import org.springframework.stereotype.Component;
 
 
 import java.text.ParseException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 @Slf4j
 @Slf4j
@@ -239,6 +261,10 @@ public class Task {
 
 
     @Autowired
     @Autowired
     private IFsStoreOrderScrmService orderScrmService;
     private IFsStoreOrderScrmService orderScrmService;
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
     /**
     /**
      * 定时任务,处理ai禁止回复之后的消息
      * 定时任务,处理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消耗统计
      * 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.common.utils.poi.ExcelUtil;
 import com.fs.company.vo.CompanyVO;
 import com.fs.company.vo.CompanyVO;
 import com.fs.framework.web.service.TokenService;
 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.domain.Live;
 import com.fs.live.service.ILiveService;
 import com.fs.live.service.ILiveService;
 import com.fs.live.vo.LiveListVo;
 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.core.config.TenantConfigContext;
 import com.fs.wxcid.utils.TenantHelper;
 import com.fs.wxcid.utils.TenantHelper;
 import lombok.extern.slf4j.Slf4j;
 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.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.task.TaskDecorator;
 import org.springframework.core.task.TaskDecorator;
@@ -39,6 +41,20 @@ public class AsyncCalleeConfig {
         return executor;
         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,在子线程中恢复
      * 在任务执行前捕获当前线程的租户ID,在子线程中恢复
@@ -46,25 +62,27 @@ public class AsyncCalleeConfig {
     public static class TenantContextTaskDecorator implements TaskDecorator {
     public static class TenantContextTaskDecorator implements TaskDecorator {
         @Override
         @Override
         public Runnable decorate(Runnable runnable) {
         public Runnable decorate(Runnable runnable) {
-            // 捕获当前线程的租户ID
-            Long tenantId = TenantHelper.getTenantId();
+            Long tenantId = resolveTenantId();
+            log.debug("TenantContextTaskDecorator 捕获租户ID: {}", tenantId);
             return () -> {
             return () -> {
+                if (tenantId == null) {
+                    log.warn("TenantContextTaskDecorator 租户ID为空, 跳过上下文设置");
+                    runnable.run();
+                    return;
+                }
                 try {
                 try {
-                    // 在子线程中设置租户ID
                     TenantHelper.setTenantId(tenantId);
                     TenantHelper.setTenantId(tenantId);
                     Object manager = SpringUtils.getBean("tenantDataSourceManager");
                     Object manager = SpringUtils.getBean("tenantDataSourceManager");
                     Method method = manager.getClass().getMethod("ensureSwitchByTenantId", Long.class);
                     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(
                     SecurityContextHolder.getContext().setAuthentication(
                             new UsernamePasswordAuthenticationToken(
                             new UsernamePasswordAuthenticationToken(
-                                    new TenantPrincipal(TenantHelper.getTenantId()),
+                                    new TenantPrincipal(tenantId),
                                     null,
                                     null,
                                     Collections.emptyList()
                                     Collections.emptyList()
                             )
                             )
                     );
                     );
-                    // 切换 Redis 租户上下文
-                    RedisTenantContext.setTenantId(TenantHelper.getTenantId());
+                    RedisTenantContext.setTenantId(tenantId);
                     runnable.run();
                     runnable.run();
                 } catch (InvocationTargetException e) {
                 } catch (InvocationTargetException e) {
                     throw new RuntimeException(e);
                     throw new RuntimeException(e);
@@ -74,7 +92,6 @@ public class AsyncCalleeConfig {
                     throw new RuntimeException(e);
                     throw new RuntimeException(e);
                 } finally {
                 } finally {
                     try {
                     try {
-                        // 清理子线程的租户ID
                         TenantHelper.removeTenantId();
                         TenantHelper.removeTenantId();
                         TenantConfigContext.clear();
                         TenantConfigContext.clear();
                         SecurityContextHolder.clearContext();
                         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.setNickName(qwExternalContacts.getName());
             fastGptChatSession.setCompanyId(user.getCompanyId());
             fastGptChatSession.setCompanyId(user.getCompanyId());
             fastGptChatSession.setLastTime(new Date());
             fastGptChatSession.setLastTime(new Date());
-            fastGptChatSession.setIsReply(0);
+            fastGptChatSession.setIsReply(1);
             fastGptChatSession.setUserId(String.valueOf(dto.getUser_id()));
             fastGptChatSession.setUserId(String.valueOf(dto.getUser_id()));
             fastGptChatSessionMapper.insertFastGptChatSession(fastGptChatSession);
             fastGptChatSessionMapper.insertFastGptChatSession(fastGptChatSession);
             addUserSex(qwExternalContacts);
             addUserSex(qwExternalContacts);
@@ -1557,7 +1557,7 @@ public class AiHookServiceImpl implements AiHookService {
                 FastGptChatSession ss = new FastGptChatSession();
                 FastGptChatSession ss = new FastGptChatSession();
                 ss.setSessionId(fastGptChatSession.getSessionId());
                 ss.setSessionId(fastGptChatSession.getSessionId());
                 ss.setRemindStatus(0);
                 ss.setRemindStatus(0);
-                ss.setIsReply(0);
+                ss.setIsReply(1);
                 ss.setUserId(String.valueOf(dto.getUser_id()));
                 ss.setUserId(String.valueOf(dto.getUser_id()));
                 fastGptChatSessionMapper.updateFastGptChatSession(ss);
                 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
     @Autowired
     private ICompanyUserCacheService companyUserCacheService;
     private ICompanyUserCacheService companyUserCacheService;
     @Autowired
     @Autowired
-    private ICompanyUserService companyUserService;
-    @Autowired
     private FsUserCourseVideoMapper userCourseVideoMapper;
     private FsUserCourseVideoMapper userCourseVideoMapper;
 
 
     @Autowired
     @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);
                                                                   @Param("corpId")String corpId,@Param("qwUserId") String qwUserId);
 
 
     void updateQwExternalContactByExternalUserIdAndUserId(@Param("map") QwExternalContact externalContact);
     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;
 package com.fs.qw.service;
 
 
 import com.alibaba.fastjson.JSON;
 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.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseLink;
 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.IQwSopTempVoiceService;
 import com.fs.sop.service.impl.SopUserLogsInfoServiceImpl;
 import com.fs.sop.service.impl.SopUserLogsInfoServiceImpl;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysConfigService;
+import com.fs.tenant.mapper.TenantInfoMapper;
 import com.fs.voice.utils.StringUtil;
 import com.fs.voice.utils.StringUtil;
+import com.fs.wxcid.utils.TenantHelper;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 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 org.springframework.stereotype.Service;
 
 
+import java.lang.reflect.Method;
 import java.time.LocalDate;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.LocalTime;
@@ -47,6 +55,7 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.Date;
 import java.util.List;
 import java.util.List;
 
 
+
 @Slf4j
 @Slf4j
 @Service
 @Service
 @AllArgsConstructor
 @AllArgsConstructor
@@ -92,11 +101,34 @@ public class AsyncQwAiChatSopService {
     @Autowired
     @Autowired
     private QwExternalContactInfoMapper qwExternalContactInfoMapper;
     private QwExternalContactInfoMapper qwExternalContactInfoMapper;
 
 
+    @Autowired
+    private TenantInfoMapper tenantInfoMapper;
+
     @Async("threadPoolTaskExecutor")
     @Async("threadPoolTaskExecutor")
     public void executeQwAiChatSop(QwSopAutoByTags qwSopAutoByTags, String userID,
     public void executeQwAiChatSop(QwSopAutoByTags qwSopAutoByTags, String userID,
                                    QwUser qwUser, String externalUserID, String externalContactName,
                                    QwUser qwUser, String externalUserID, String externalContactName,
                                    Long externalId, Long fsUserId, LocalDate currentDate, LocalTime localTime) {
                                    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;
         QwExternalContact contact;
         if(externalId != null){
         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);
     List<QwMandatoryRegistrParam> selectQwExternalContactMandatoryRegistrationByIds(String corpId);
 
 
     int batchUpdateQwExternalContactMandatoryRegistration(List<QwMandatoryRegistrParam> batchList);
     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.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 
 
@@ -216,6 +218,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     @Autowired
     @Autowired
     private QwExternalContactTransferCompanyAuditUserMapper transferCompanyAuditUserMapper;
     private QwExternalContactTransferCompanyAuditUserMapper transferCompanyAuditUserMapper;
 
 
+    @Lazy
     @Autowired
     @Autowired
     private AsyncQwAiChatSopService asyncQwAiChatSopService;
     private AsyncQwAiChatSopService asyncQwAiChatSopService;
     @Autowired
     @Autowired
@@ -6042,6 +6045,17 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     public int batchUpdateQwExternalContactMandatoryRegistration(List<QwMandatoryRegistrParam> batchList) {
     public int batchUpdateQwExternalContactMandatoryRegistration(List<QwMandatoryRegistrParam> batchList) {
         return qwExternalContactMapper.batchUpdateQwExternalContactMandatoryRegistration( 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
     @Override
     public R getRepeat(RepeatParam param) {
     public R getRepeat(RepeatParam param) {
         List<QwExternalContact> list = qwExternalContactMapper.selectList(new QueryWrapper<QwExternalContact>().eq("external_user_id", param.getExternalUserId()));
         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}
             and user_id = #{qwUserId}
         order by create_time desc limit 1
         order by create_time desc limit 1
     </select>
     </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 id="updateQwExternalContactByExternalUserIdAndUserId" parameterType="QwExternalContact">
         update qw_external_contact set application_external_user_id = #{map.applicationExternalUserId}
         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>
     </insert>
 
 
     <update id="updateBatchById">
     <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>
         </foreach>
     </update>
     </update>
+
 </mapper>
 </mapper>