|
|
@@ -5,7 +5,6 @@ import cn.hutool.json.JSONUtil;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
import com.fs.common.constant.Constants;
|
|
|
import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
@@ -17,37 +16,42 @@ import com.fs.company.mapper.*;
|
|
|
import com.fs.company.param.ExecutionContext;
|
|
|
import com.fs.company.service.*;
|
|
|
import com.fs.company.service.impl.*;
|
|
|
-import com.fs.company.service.impl.call.node.AiAddWxTaskNode;
|
|
|
import com.fs.company.service.impl.call.node.AiAddWxTaskNewNode;
|
|
|
+import com.fs.company.service.impl.call.node.AiAddWxTaskNode;
|
|
|
import com.fs.company.service.impl.call.node.AiQwAddWxTaskNode;
|
|
|
import com.fs.company.service.impl.call.node.WorkflowNodeFactory;
|
|
|
+import com.fs.company.util.ObjectPlaceholderResolver;
|
|
|
import com.fs.company.vo.CompanyWxClient4WorkFlowVO;
|
|
|
+import com.fs.company.vo.SendMsgVo;
|
|
|
import com.fs.course.config.CourseConfig;
|
|
|
import com.fs.course.config.RedisKeyScanner;
|
|
|
+import com.fs.course.config.WxConfig;
|
|
|
import com.fs.course.domain.FsCourseLink;
|
|
|
-import com.fs.course.domain.FsCourseRealLink;
|
|
|
import com.fs.course.mapper.FsCourseLinkMapper;
|
|
|
+import com.fs.crm.domain.CrmCustomer;
|
|
|
import com.fs.crm.param.SmsSendBatchParam;
|
|
|
+import com.fs.crm.service.ICrmCustomerService;
|
|
|
import com.fs.enums.ExecutionStatusEnum;
|
|
|
import com.fs.enums.NodeTypeEnum;
|
|
|
-import com.fs.company.util.ObjectPlaceholderResolver;
|
|
|
-import com.fs.company.vo.SendMsgVo;
|
|
|
-import com.fs.course.config.WxConfig;
|
|
|
-import com.fs.crm.domain.CrmCustomer;
|
|
|
-import com.fs.crm.service.ICrmCustomerService;
|
|
|
import com.fs.qw.domain.QwExternalContact;
|
|
|
import com.fs.qw.domain.QwUser;
|
|
|
import com.fs.qw.mapper.QwExternalContactMapper;
|
|
|
import com.fs.qw.mapper.QwUserMapper;
|
|
|
-import com.fs.qw.vo.QwSopCourseFinishTempSetting;
|
|
|
import com.fs.qwApi.Result.QwAddContactWayResult;
|
|
|
import com.fs.qwApi.domain.QwLinkCreateResult;
|
|
|
import com.fs.qwApi.param.QwAddContactWayParam;
|
|
|
import com.fs.qwApi.param.QwLinkCreateParam;
|
|
|
import com.fs.qwApi.service.QwApiService;
|
|
|
+import com.fs.sop.mapper.QwSopTempRulesMapper;
|
|
|
+import com.fs.sop.vo.QwSopTempRulesWithDayVO;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.utils.ShortCodeGeneratorUtils;
|
|
|
import com.fs.voice.utils.StringUtil;
|
|
|
+import com.fs.wx.sop.domain.WxSopLogs;
|
|
|
+import com.fs.wx.sop.mapper.WxSopLogsMapper;
|
|
|
+import com.fs.wx.sop.mapper.WxSopMapper;
|
|
|
+import com.fs.wx.sop.mapper.WxSopUserMapper;
|
|
|
+import com.fs.wx.sop.vo.WxSopUserMsgGenVO;
|
|
|
import com.fs.wxcid.dto.friend.AddContactParam;
|
|
|
import com.fs.wxcid.service.FriendService;
|
|
|
import com.fs.wxcid.vo.AddContactVo;
|
|
|
@@ -58,7 +62,6 @@ import com.fs.wxwork.dto.WxWorkResponseDTO;
|
|
|
import com.fs.wxwork.service.WxWorkService;
|
|
|
import com.google.gson.JsonObject;
|
|
|
import com.google.gson.JsonParser;
|
|
|
-import lombok.AllArgsConstructor;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.redisson.api.RLock;
|
|
|
@@ -66,10 +69,11 @@ import org.redisson.api.RedissonClient;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
-import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
+import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
+import java.time.LocalTime;
|
|
|
import java.time.ZoneId;
|
|
|
import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
@@ -133,6 +137,11 @@ public class WxTaskService {
|
|
|
private final FsCourseLinkMapper fsCourseLinkMapper;
|
|
|
private final ISysConfigService configService;
|
|
|
|
|
|
+ private final WxSopUserMapper wxSopUserMapper;
|
|
|
+ private final WxSopMapper wxSopMapper;
|
|
|
+ private final WxSopLogsMapper wxSopLogsMapper;
|
|
|
+ private final QwSopTempRulesMapper qwSopTempRulesMapper;
|
|
|
+
|
|
|
|
|
|
private static final String REAL_CID_LINK_PREFIX = "/pages_cidAddQw/cidAddQw.html?link=";
|
|
|
private static final String REAL_CID_H5LINK_PREFIX = "/pages_cidAddQwH5/cidAddQw.html?link=";
|
|
|
@@ -2097,4 +2106,117 @@ public class WxTaskService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 个微SOP消息生成(文本类型)
|
|
|
+ * 每小时触发,查询活跃的WxSOP营期及客户,生成文本消息待发送记录
|
|
|
+ *
|
|
|
+ * @param currentTime 当前整点时间
|
|
|
+ */
|
|
|
+ public void generateWxSopMsgByTime(LocalDateTime currentTime) {
|
|
|
+ long startTimeMillis = System.currentTimeMillis();
|
|
|
+ log.info("====== 个微SOP文本消息生成开始, currentTime: {} ======", currentTime);
|
|
|
+
|
|
|
+ List<WxSopUserMsgGenVO> msgGenList = wxSopUserMapper.selectActiveWxSopUserForMsgGen();
|
|
|
+ if (msgGenList == null || msgGenList.isEmpty()) {
|
|
|
+ log.info("个微SOP消息生成: 没有需要处理的活跃营期。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ log.info("个微SOP消息生成: 查询到 {} 条营期客户记录。", msgGenList.size());
|
|
|
+
|
|
|
+ Map<String, List<QwSopTempRulesWithDayVO>> rulesCache = new HashMap<>();
|
|
|
+ List<WxSopLogs> logsToInsert = new ArrayList<>();
|
|
|
+
|
|
|
+ for (WxSopUserMsgGenVO vo : msgGenList) {
|
|
|
+ if (vo.getTempId() == null || vo.getTempId().isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDate startDate = vo.getStartTime();
|
|
|
+ LocalDate currentDate = currentTime.toLocalDate();
|
|
|
+ long daysBetween = ChronoUnit.DAYS.between(startDate, currentDate);
|
|
|
+ long targetDay = daysBetween + 1;
|
|
|
+
|
|
|
+ List<QwSopTempRulesWithDayVO> rulesList = rulesCache.computeIfAbsent(vo.getTempId(),
|
|
|
+ qwSopTempRulesMapper::listByTempIdWithDayNum);
|
|
|
+ if (rulesList == null || rulesList.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<QwSopTempRulesWithDayVO> dayRules = rulesList.stream()
|
|
|
+ .filter(r -> r.getDayNum() != null && r.getDayNum() == targetDay)
|
|
|
+ .filter(r -> r.getContentType() != null && r.getContentType() == 1)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (dayRules.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (QwSopTempRulesWithDayVO rule : dayRules) {
|
|
|
+ LocalTime ruleTime;
|
|
|
+ try {
|
|
|
+ ruleTime = LocalTime.parse(rule.getTime());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("个微SOP消息生成: 解析时间失败, ruleId: {}, time: {}", rule.getId(), rule.getTime());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ LocalDateTime ruleDateTime = LocalDateTime.of(currentDate, ruleTime);
|
|
|
+ if (ruleDateTime.isBefore(currentTime) && ruleDateTime.plusHours(1).isBefore(currentTime)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime startRange = currentTime.plusMinutes(60);
|
|
|
+ LocalDateTime endRange = startRange.plusMinutes(60);
|
|
|
+ if (ruleDateTime.isBefore(startRange) || !ruleDateTime.isBefore(endRange)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rule.getTextContent() == null || rule.getTextContent().isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ WxSopLogs sopLogs = new WxSopLogs();
|
|
|
+ sopLogs.setType(vo.getType());
|
|
|
+ sopLogs.setSopId(vo.getSopId());
|
|
|
+ sopLogs.setSopUserId(vo.getSopUserId());
|
|
|
+ sopLogs.setSendType(2);
|
|
|
+ sopLogs.setGenerateType(0);
|
|
|
+ sopLogs.setAccountId(vo.getAccountId());
|
|
|
+ sopLogs.setWxContactId(vo.getWxContactId());
|
|
|
+ sopLogs.setFsUserId(vo.getFsUserId());
|
|
|
+ sopLogs.setSendStatus(0);
|
|
|
+ sopLogs.setSendSort(10000000);
|
|
|
+ sopLogs.setSendTime(ruleDateTime);
|
|
|
+
|
|
|
+ String contentJson = buildTextContentJson(rule.getTextContent());
|
|
|
+ sopLogs.setContentJson(contentJson);
|
|
|
+ sopLogs.setCreateTime(new Date());
|
|
|
+ sopLogs.setUpdateTime(new Date());
|
|
|
+
|
|
|
+ logsToInsert.add(sopLogs);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!logsToInsert.isEmpty()) {
|
|
|
+ wxSopLogsMapper.batchInsertWxSopLogs(logsToInsert);
|
|
|
+ log.info("个微SOP消息生成: 批量写入 {} 条文本消息。", logsToInsert.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ long endTimeMillis = System.currentTimeMillis();
|
|
|
+ log.info("====== 个微SOP文本消息生成完成, 耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildTextContentJson(String text) {
|
|
|
+ if (text == null || text.isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ com.alibaba.fastjson.JSONObject item = new com.alibaba.fastjson.JSONObject();
|
|
|
+ item.put("contentType", "1");
|
|
|
+ item.put("value", text);
|
|
|
+ com.alibaba.fastjson.JSONArray settingsArray = new com.alibaba.fastjson.JSONArray();
|
|
|
+ settingsArray.add(item);
|
|
|
+ com.alibaba.fastjson.JSONObject wrapper = new com.alibaba.fastjson.JSONObject();
|
|
|
+ wrapper.put("settings", settingsArray);
|
|
|
+ return com.alibaba.fastjson.JSON.toJSONString(wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
}
|