|
@@ -72,6 +72,7 @@ import java.time.*;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.*;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.stream.Stream;
|
|
@@ -190,9 +191,6 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
@Autowired
|
|
|
private QwTagMapper qwTagMapper;
|
|
|
|
|
|
- @Autowired
|
|
|
- private QwExternalContactServiceImpl qwExternalContactService;
|
|
|
-
|
|
|
|
|
|
org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
|
|
|
|
|
@@ -416,7 +414,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
|
|
|
// 获取组公共信息(每组只需查一次)
|
|
|
QwExternalContact sample = group.get(0);
|
|
|
- QwUser qwUser = qwExternalContactService.getQwUserByRedis(sample.getCorpId(), sample.getUserId());
|
|
|
+ QwUser qwUser = this.getQwUserByRedis(sample.getCorpId(), sample.getUserId());
|
|
|
if (qwUser == null) {
|
|
|
logger.error("无企微员工信息: {}|{}", sample.getUserId(), sample.getCorpId());
|
|
|
return;
|
|
@@ -1189,142 +1187,593 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
|
|
|
@Override
|
|
|
public R addUserTag(QwExternalContactAddTagParam param) throws JSONException {
|
|
|
- int err = 0;
|
|
|
- int suc = 0;
|
|
|
- // 获取当前日期(只包含年月日)
|
|
|
+ // 获取当前日期和时间
|
|
|
LocalDate currentDate = LocalDate.now();
|
|
|
- // 获取当前系统时间 (HH:mm)
|
|
|
LocalTime localTime = LocalTime.now();
|
|
|
|
|
|
- List<Long> userIds = param.getUserIds();
|
|
|
- for (Long userId : userIds) {
|
|
|
+ // 使用线程安全的计数器
|
|
|
+ AtomicInteger suc = new AtomicInteger(0);
|
|
|
|
|
|
- QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(userId);
|
|
|
- QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
|
|
|
- qwEditUserTagParam.setAdd_tag(param.getTagIds());
|
|
|
- qwEditUserTagParam.setUserid(qwExternalContact.getUserId());
|
|
|
- qwEditUserTagParam.setExternal_userid(qwExternalContact.getExternalUserId());
|
|
|
+ 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;
|
|
|
try {
|
|
|
+ contacts = qwExternalContactMapper.selectQwExternalContactByIds(param.getUserIds());
|
|
|
+ if (contacts == null || contacts.isEmpty()) {
|
|
|
+ return R.error("成功:0,失败:" + param.getUserIds().size());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ return R.error("批量查询用户数据失败:"+e.getMessage());
|
|
|
+ }
|
|
|
|
|
|
- QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, param.getCorpId());
|
|
|
- if (qwResult.getErrcode() == 0) {
|
|
|
+ // 直接遍历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);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- //客户本身的标签集合+打的标签
|
|
|
- QwExternalContact qwExternal = new QwExternalContact();
|
|
|
- String tagIds = qwExternalContact.getTagIds();
|
|
|
+ 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);
|
|
|
+ }
|
|
|
|
|
|
- // 将标签字符串解析为 List //客户总标签
|
|
|
- List<String> tagIdsList = new ArrayList<>();
|
|
|
+ logger.info("客户添加标签addUserTag:" + qwExternalContact.getName() +
|
|
|
+ "|公司" + qwExternalContact.getCorpId() +
|
|
|
+ "|员工" + qwExternalContact.getUserId() +
|
|
|
+ "|总标签" + tagIdsList);
|
|
|
|
|
|
- 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);
|
|
|
+ // 插件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();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 将 param 中的标签 ID 加入集合
|
|
|
- if (param.getTagIds() != null && !param.getTagIds().isEmpty()) {
|
|
|
- uniqueIds.addAll(param.getTagIds());
|
|
|
+ // 批量更新数据库
|
|
|
+ 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());
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 将唯一标签集合设置回 qwExternal
|
|
|
- qwExternal.setTagIds(JSON.toJSONString(uniqueIds));
|
|
|
+ // 关闭线程池
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (qwExternal.getTagIds() != null && !qwExternal.getTagIds().isEmpty()) {
|
|
|
- tagIdsList = JSON.parseArray(qwExternal.getTagIds(), String.class);
|
|
|
- }
|
|
|
+ return R.ok("成功:" + suc.get() + ",失败:" + failList);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private String getErrorMsg(Integer code){
|
|
|
+
|
|
|
+ String msg="";
|
|
|
+ switch (code){
|
|
|
+ case 40003:
|
|
|
+ msg="无效的UserID(员工账号)";
|
|
|
+ break;
|
|
|
+ case 40096:
|
|
|
+ msg="不合法的外部联系人userid";
|
|
|
+ break;
|
|
|
+ case 45033:
|
|
|
+ msg="接口并发调用超过限制(**调用过于频繁请稍后再试**)";
|
|
|
+ break;
|
|
|
+ case 45035:
|
|
|
+ msg="当前客户有其他修改操作,请稍后重试(**比如其他地方修改客户信息**)";
|
|
|
+ break;
|
|
|
+ case 60020:
|
|
|
+ msg="不安全的访问IP";
|
|
|
+ break;
|
|
|
+ case 84061:
|
|
|
+ msg="不存在外部联系人的关系(**客户【不存在】于员工的好友列表中**)";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ msg=code.toString();
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R addTagByWatch(QwExtContactAddTagByWatchParam param) throws org.codehaus.jettison.json.JSONException {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 获取当前日期和时间
|
|
|
+ LocalDate currentDate = LocalDate.now();
|
|
|
+ LocalTime localTime = LocalTime.now();
|
|
|
+
|
|
|
+ // 使用线程安全的计数器
|
|
|
+ AtomicInteger suc = new AtomicInteger(0);
|
|
|
+
|
|
|
+ List<String> failList = new CopyOnWriteArrayList<>(); // 记录失败客户的名字
|
|
|
|
|
|
- qwExternal.setId(userId);
|
|
|
+ // 创建线程池
|
|
|
+ int threadCount = Math.min(8, Runtime.getRuntime().availableProcessors() * 2);
|
|
|
+ ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
|
|
|
|
|
- logger.info("客户添加标签addUserTag:"+qwExternalContact.getName()+"|公司"+qwExternalContact.getCorpId()+"|员工"+qwExternalContact.getUserId()+"|总标签"+tagIdsList);
|
|
|
|
|
|
- //插件sop
|
|
|
- processTagsAll(qwExternalContact,qwExternalContact.getCorpId(),tagIdsList,currentDate,localTime);
|
|
|
+ try {
|
|
|
+ // 使用线程安全的List来收集需要批量更新的数据
|
|
|
+ List<QwExternalContact> batchUpdateList = Collections.synchronizedList(new ArrayList<>());
|
|
|
+
|
|
|
+ // 存储Future对象以便检查所有任务完成情况
|
|
|
+ List<Future<?>> futures = new ArrayList<>();
|
|
|
|
|
|
- //新客对话
|
|
|
-// processTagsAllByAiChat(qwExternalContact,param.getCorpId(),tagIdsList);
|
|
|
|
|
|
- suc++;
|
|
|
- qwExternalContactMapper.updateQwExternalContact(qwExternal);
|
|
|
+ // 1. 批量查询所有用户数据
|
|
|
+ List<QwExternalContact> contacts;
|
|
|
+ try {
|
|
|
+ contacts = fsCourseWatchLogMapper.selectQwWatchLogFomExtContact(param.getLogIds());
|
|
|
+ if (contacts == null || contacts.isEmpty()) {
|
|
|
+ return R.error("成功:0,失败:" + param.getLogIds().size());
|
|
|
}
|
|
|
- else {
|
|
|
- err++;
|
|
|
+ } catch (Exception e) {
|
|
|
+ return R.error("批量查询用户数据失败:"+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, qwExternalContact.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();
|
|
|
}
|
|
|
- }catch (Exception e){
|
|
|
- logger.error("客户添加标签失败:"+qwEditUserTagParam+e.getMessage());
|
|
|
}
|
|
|
|
|
|
+ // 批量更新数据库
|
|
|
+ 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();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return R.ok("成功:" + suc + ",失败:" + err);
|
|
|
+ return R.ok("成功:" + suc.get() + ",失败:" + failList);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
@Override
|
|
|
public R delUserTag(QwExternalContactAddTagParam param) {
|
|
|
-
|
|
|
- // 获取当前日期(只包含年月日)
|
|
|
+ // 获取当前日期和时间
|
|
|
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) {
|
|
|
+ // 使用线程安全的计数器
|
|
|
+ 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<>());
|
|
|
|
|
|
- QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(userId);
|
|
|
+ // 存储Future对象以便检查所有任务完成情况
|
|
|
+ List<Future<?>> futures = new ArrayList<>();
|
|
|
|
|
|
- QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
|
|
|
- qwEditUserTagParam.setRemove_tag(param.getTagIds());
|
|
|
- qwEditUserTagParam.setUserid(qwExternalContact.getUserId());
|
|
|
- qwEditUserTagParam.setExternal_userid(qwExternalContact.getExternalUserId());
|
|
|
|
|
|
+ // 1. 批量查询所有用户数据
|
|
|
+ List<QwExternalContact> contacts;
|
|
|
try {
|
|
|
- QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, param.getCorpId());
|
|
|
- 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));
|
|
|
+ contacts = qwExternalContactMapper.selectQwExternalContactByIds(param.getUserIds());
|
|
|
+ if (contacts == null || contacts.isEmpty()) {
|
|
|
+ return R.error("成功:0,失败:" + param.getUserIds().size());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ return R.error("批量查询用户数据失败:"+e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 直接遍历contacts而不是userIds
|
|
|
+ for (QwExternalContact qwExternalContact : contacts) {
|
|
|
+ futures.add(executor.submit(() -> {
|
|
|
+ try {
|
|
|
+ QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
|
|
|
+ qwEditUserTagParam.setRemove_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();
|
|
|
+ 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(qwExternalContact.getId());
|
|
|
+ qwExternal.setTagIds(JSON.toJSONString(ids));
|
|
|
+
|
|
|
+
|
|
|
+ logger.info("客户移除标签delUserTag:"+qwExternalContact.getName()+"|公司"+qwExternalContact.getCorpId()+"|员工"+qwExternalContact.getUserId()+"|总标签"+ids);
|
|
|
+
|
|
|
+ //检查sop
|
|
|
+ processTagsAll(qwExternalContact,param.getCorpId(),ids,currentDate,localTime);
|
|
|
+
|
|
|
+ // 添加到批量更新列表
|
|
|
+ batchUpdateList.add(qwExternal);
|
|
|
+ }
|
|
|
+
|
|
|
+ suc.incrementAndGet();
|
|
|
+ } else {
|
|
|
+ failList.add("【"+qwExternalContact.getName()+"】" + "原因:(" + getErrorMsg(qwResult.getErrcode()) + ")\n");
|
|
|
}
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("客户移除标签delUserTag失败,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();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return R.ok("成功:" + suc.get() + ",失败:" + failList);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R delTagByWatch(QwExtContactAddTagByWatchParam param) {
|
|
|
+ // 获取当前日期和时间
|
|
|
+ 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);
|
|
|
+
|
|
|
|
|
|
- QwExternalContact qwExternal = new QwExternalContact();
|
|
|
- qwExternal.setId(userId);
|
|
|
- qwExternal.setTagIds(JSON.toJSONString(ids));
|
|
|
+ try {
|
|
|
+ // 使用线程安全的List来收集需要批量更新的数据
|
|
|
+ List<QwExternalContact> batchUpdateList = Collections.synchronizedList(new ArrayList<>());
|
|
|
|
|
|
- qwExternalContactMapper.updateQwExternalContact(qwExternal);
|
|
|
+ // 存储Future对象以便检查所有任务完成情况
|
|
|
+ List<Future<?>> futures = new ArrayList<>();
|
|
|
|
|
|
- logger.info("客户移除标签delUserTag:"+qwExternalContact.getName()+"|公司"+qwExternalContact.getCorpId()+"|员工"+qwExternalContact.getUserId()+"|总标签"+ids);
|
|
|
|
|
|
- //检查sop
|
|
|
- processTagsAll(qwExternalContact,param.getCorpId(),ids,currentDate,localTime);
|
|
|
+ // 1. 批量查询所有用户数据
|
|
|
+ List<QwExternalContact> contacts;
|
|
|
+ try {
|
|
|
+ contacts = fsCourseWatchLogMapper.selectQwWatchLogFomExtContact(param.getLogIds());
|
|
|
+ if (contacts == null || contacts.isEmpty()) {
|
|
|
+ return R.error("成功:0,失败:" + param.getLogIds().size());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ return R.error("批量查询用户数据失败:"+e.getMessage());
|
|
|
+ }
|
|
|
|
|
|
- //新客对话
|
|
|
-// processTagsAllByAiChat(qwExternalContact,param.getCorpId(),ids);
|
|
|
+ // 直接遍历contacts而不是userIds
|
|
|
+ for (QwExternalContact qwExternalContact : contacts) {
|
|
|
+ futures.add(executor.submit(() -> {
|
|
|
+ try {
|
|
|
+ QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
|
|
|
+ qwEditUserTagParam.setRemove_tag(param.getTagIds());
|
|
|
+ qwEditUserTagParam.setUserid(qwExternalContact.getUserId());
|
|
|
+ qwEditUserTagParam.setExternal_userid(qwExternalContact.getExternalUserId());
|
|
|
+
|
|
|
+ QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, qwExternalContact.getCorpId());
|
|
|
+ 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(qwExternalContact.getId());
|
|
|
+ qwExternal.setTagIds(JSON.toJSONString(ids));
|
|
|
+
|
|
|
+
|
|
|
+ logger.info("看课处客户移除标签delUserTag:"+qwExternalContact.getName()+"|公司"+qwExternalContact.getCorpId()+"|员工"+qwExternalContact.getUserId()+"|总标签"+ids);
|
|
|
+
|
|
|
+ //检查sop
|
|
|
+ processTagsAll(qwExternalContact,qwExternalContact.getCorpId(),ids,currentDate,localTime);
|
|
|
+
|
|
|
+ // 添加到批量更新列表
|
|
|
+ batchUpdateList.add(qwExternal);
|
|
|
+ }
|
|
|
+
|
|
|
+ suc.incrementAndGet();
|
|
|
+ } else {
|
|
|
+ failList.add("【"+qwExternalContact.getName()+"】" + "原因:(" + getErrorMsg(qwResult.getErrcode()) + ")\n");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("看课处客户移除标签delUserTag失败,userId: " + qwExternalContact.getId() +
|
|
|
+ ", externalUserId: " + qwExternalContact.getExternalUserId() +
|
|
|
+ ", 错误信息: " + e.getMessage());
|
|
|
+ failList.add("【"+qwExternalContact.getName()+"】" + "原因:(" + e.getMessage() + ")\n");
|
|
|
}
|
|
|
- suc++;
|
|
|
+ }));
|
|
|
+ }
|
|
|
|
|
|
- } else {
|
|
|
- err++;
|
|
|
+
|
|
|
+ // 等待所有任务完成
|
|
|
+ for (Future<?> future : futures) {
|
|
|
+ try {
|
|
|
+ future.get();
|
|
|
+ } catch (InterruptedException | ExecutionException e) {
|
|
|
+ logger.error("任务执行异常: " + e.getMessage());
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- }catch (Exception e){
|
|
|
- logger.error("移除标签失败:"+qwEditUserTagParam+e.getMessage());
|
|
|
+ // 批量更新数据库
|
|
|
+ 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();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
- return R.ok("成功:" + suc + ",失败:" + err);
|
|
|
+ return R.ok("成功:" + suc.get() + ",失败:" + failList);
|
|
|
}
|
|
|
|
|
|
public void insertQwExternalByMq(Long ExtId){
|
|
@@ -2796,8 +3245,18 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
if (i == 1) {
|
|
|
return;
|
|
|
}
|
|
|
- // 判断 SOP 任务的开始时间
|
|
|
- qwSopRuleTimeToolsCheck(sopStartLocalDate,currentDate,dateFormatter,userLogs,logsInfo,userLogsParamByDate,qwAutoSopTimeParam,timeFormatter,localTime);
|
|
|
+
|
|
|
+ if (Integer.valueOf(1).equals(ruleTimeVO.getIsFixed())){
|
|
|
+
|
|
|
+ qwSopRuleTimeToolsCheckByIsFixed(sopStartLocalDate,dateFormatter,userLogs,logsInfo,userLogsParamByDate);
|
|
|
+
|
|
|
+ }else {
|
|
|
+ // 判断 SOP 任务的开始时间
|
|
|
+ qwSopRuleTimeToolsCheck(sopStartLocalDate,currentDate,dateFormatter,userLogs,logsInfo,userLogsParamByDate,qwAutoSopTimeParam,timeFormatter,localTime);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -3407,8 +3866,17 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
logsInfo.setExternalUserName(qwExternalContact.getName());
|
|
|
logsInfo.setSopId(ruleTimeVO.getId());
|
|
|
|
|
|
- //检查营期
|
|
|
- qwSopRuleTimeToolsCheck(sopStartLocalDate,currentDate,dateFormatter,userLogs,logsInfo,userLogsParamByDate,qwAutoSopTimeParam,timeFormatter,localTime);
|
|
|
+
|
|
|
+ //如果是固定营期
|
|
|
+ if (Integer.valueOf(1).equals(ruleTimeVO.getIsFixed())){
|
|
|
+
|
|
|
+ qwSopRuleTimeToolsCheckByIsFixed(sopStartLocalDate,dateFormatter,userLogs,logsInfo,userLogsParamByDate);
|
|
|
+
|
|
|
+ }else {
|
|
|
+ //检查营期
|
|
|
+ qwSopRuleTimeToolsCheck(sopStartLocalDate,currentDate,dateFormatter,userLogs,logsInfo,userLogsParamByDate,qwAutoSopTimeParam,timeFormatter,localTime);
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
}
|
|
|
|
|
@@ -3423,30 +3891,6 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-// 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()){
|
|
@@ -3466,6 +3910,38 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+ //固定营期 以 SOP 任务的开始时间为营期
|
|
|
+ private void qwSopRuleTimeToolsCheckByIsFixed(LocalDate sopStartLocalDate,DateTimeFormatter dateFormatter,
|
|
|
+ SopUserLogs userLogs,SopUserLogsInfo logsInfo,
|
|
|
+ SopUserLogsParamByDate userLogsParamByDate){
|
|
|
+
|
|
|
+ String sopStartLocalDateStr = sopStartLocalDate.format(dateFormatter);
|
|
|
+
|
|
|
+ userLogs.setStartTime(sopStartLocalDateStr);
|
|
|
+ // 查询开始时间营期表
|
|
|
+ String unionSopStartId = sopUserLogsService.selectSopUserLogsByUnionSopId(userLogs);
|
|
|
+
|
|
|
+ // 如果营期表里有,则加入;否则创建新营期
|
|
|
+ if (!StringUtil.strIsNullOrEmpty(unionSopStartId)) {
|
|
|
+ logsInfo.setUserLogsId(unionSopStartId);
|
|
|
+ // 查询这个人是否已在该营期里
|
|
|
+ handleInsertSopUserLogsInfo(logsInfo);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // 没有营期记录就先插入
|
|
|
+ userLogsParamByDate.setStartTime(sopStartLocalDateStr);
|
|
|
+
|
|
|
+ sopUserLogsService.insertSopUserLogsByDate(userLogsParamByDate);
|
|
|
+
|
|
|
+ // 再次查询 拿营期主键
|
|
|
+ String unionSopStartIdNew = sopUserLogsService.selectSopUserLogsByUnionSopId(userLogs);
|
|
|
+ logsInfo.setUserLogsId(unionSopStartIdNew);
|
|
|
+
|
|
|
+ // 查询是否在营期里,如果没有再插入
|
|
|
+ handleInsertSopUserLogsInfo(logsInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
/**
|
|
|
* 新客对话
|
|
|
*/
|