ソースを参照

自动转人工 加入字典数据 支付发送消息

yuhongqi 1 日 前
コミット
096c47912e

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

@@ -7,6 +7,7 @@ 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.entity.SysDictData;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.CustomException;
 import com.fs.common.service.impl.SmsServiceImpl;
@@ -80,6 +81,7 @@ 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.system.service.ISysDictTypeService;
 import com.fs.utils.OrderContextHolder;
 import com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
@@ -226,6 +228,9 @@ public class Task {
     @Autowired
     private ISysConfigService sysConfigService;
 
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
     @Autowired
     private ThreadPoolTaskExecutor threadPoolTaskExecutor;
     @Autowired
@@ -734,8 +739,36 @@ public class Task {
     }
 
     public void isArtificial() throws Exception {
-        fastGptChatSessionMapper.updateFastGptChatSessionByIsReply();
+        Integer artificialTime = resolveIsArtificialTimeMinutes();
+        if (artificialTime != null && artificialTime > 0) {
+            fastGptChatSessionMapper.updateFastGptChatSessionByIsReplyWithTime(artificialTime);
+        } else {
+            fastGptChatSessionMapper.updateFastGptChatSessionByIsReply();
+        }
+    }
 
+    /**
+     * 查询字典 is_artificial_time,返回大于 0 的有效分钟数(取第一条有效配置)
+     */
+    private Integer resolveIsArtificialTimeMinutes() {
+        List<SysDictData> dictList = dictTypeService.selectDictDataByType("is_artificial_time");
+        if (CollectionUtil.isEmpty(dictList)) {
+            return null;
+        }
+        for (SysDictData dictData : dictList) {
+            if (dictData == null || StringUtils.isBlank(dictData.getDictValue())) {
+                continue;
+            }
+            try {
+                int minutes = Integer.parseInt(dictData.getDictValue().trim());
+                if (minutes > 0) {
+                    return minutes;
+                }
+            } catch (NumberFormatException e) {
+                log.warn("is_artificial_time 字典值无效:{}", dictData.getDictValue());
+            }
+        }
+        return null;
     }
 
     public void expirationQwAppCountWay() {

+ 3 - 0
fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatSessionMapper.java

@@ -125,4 +125,7 @@ public interface FastGptChatSessionMapper
     @Update("UPDATE fastgpt_chat_session  SET is_artificial = 0 WHERE is_artificial = 1  AND TIMESTAMPDIFF(MINUTE, last_time, NOW()) > 10;")
     void updateFastGptChatSessionByIsReply();
 
+    @Update("UPDATE fastgpt_chat_session SET is_artificial = 0 WHERE is_artificial = 1 AND TIMESTAMPDIFF(MINUTE, last_time, NOW()) > #{time}")
+    void updateFastGptChatSessionByIsReplyWithTime(@Param("time") Integer time);
+
 }

+ 100 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -141,6 +141,9 @@ import com.fs.wxwork.dto.WxWorkResponseDTO;
 import com.fs.wxwork.dto.WxWorkSendTextMsgDTO;
 import com.fs.wxwork.dto.WxWorkUserId2VidDTO;
 import com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO;
+import com.fs.wxwork.dto.WxwSendCDNImgMsgDTO;
+import com.fs.wxwork.dto.WxwUploadCdnLinkImgDTO;
+import com.fs.wxwork.dto.WxwUploadCdnLinkImgRespDTO;
 import com.fs.wxwork.service.WxWorkService;
 import com.fs.ybPay.domain.OrderResult;
 import com.fs.ybPay.domain.RefundResult;
@@ -498,6 +501,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
     @Value("${cloud_host.company_name}")
     private String companyName;
+
+    private static final String PAY_SUCCESS_MSG =
+            "尊敬的VIP,感谢您的信任与购买~若后续遇到任何售后相关问题,欢迎您第一时间联系专属销售对接处理或拨打客服电话400-0909-575。我们将竭诚为您高效解决问题,保障您的权益。";
+
+    private static final String PAY_SUCCESS_MSG_REDIS_KEY = "fs:pay:success:msg:send:";
     @PostConstruct
     public void initErpServiceMap() {
         erpServiceMap = new HashMap<>();
@@ -3015,6 +3023,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 log.error("团购订单支付后处理失败,orderId={}", order.getId(), e);
             }
         }
+        if ("北京卓美".equals(companyName)) {
+            // 支付确认完成后异步推送企微感谢消息,与支付事务/回调线程分离
+            final Long paySuccessOrderId = order.getId();
+            CompletableFuture.runAsync(() -> safeSendPaySuccessMsgToWx(paySuccessOrderId));
+        }
         return "SUCCESS";
     }
 
@@ -7473,6 +7486,93 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     }
 
 
+    /**
+     * 支付成功后异步推送企微感谢消息;异常仅记录日志,不影响支付主流程。
+     */
+    private void safeSendPaySuccessMsgToWx(Long orderId) {
+        if (orderId == null) {
+            return;
+        }
+        try {
+            sendPaySuccessMsgToWx(orderId);
+        } catch (Exception e) {
+            log.error("推送支付成功企微消息失败,orderId:{}", orderId, e);
+        }
+    }
+
+    /**
+     * 支付成功后向用户发送感谢文案及配图(Redis 去重,防止支付回调重试重复发送)。
+     */
+    private void sendPaySuccessMsgToWx(Long orderId) {
+        boolean isSend = redisCache.setIfAbsent(PAY_SUCCESS_MSG_REDIS_KEY + orderId, "1", 24, TimeUnit.HOURS);
+        if (!isSend) {
+            return;
+        }
+        FsStoreOrderScrm order = fsStoreOrderMapper.selectFsStoreOrderById(orderId);
+        if (order == null || order.getUserId() == null) {
+            return;
+        }
+        List<QwExternalContact> qwExternalContact = qwExternalContactMapper.selectQwExternalContactByFsUserIdAndCompany(order.getUserId(), order.getCompanyUserId());
+        if (qwExternalContact == null || qwExternalContact.isEmpty()) {
+            return;
+        }
+        for (QwExternalContact externalContact : qwExternalContact) {
+            Long qwUserId = externalContact.getQwUserId();
+            if (qwUserId == null) {
+                continue;
+            }
+            QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+            if (qwUser == null || qwUser.getUid() == null || qwUser.getServerId() == null
+                    || qwUser.getServerStatus() != 1 || qwUser.getIpadStatus() != 1) {
+                continue;
+            }
+            WxWorkUserId2VidDTO wxWorkUserId2VidDTO = new WxWorkUserId2VidDTO();
+            wxWorkUserId2VidDTO.setOpenid(Collections.singletonList(externalContact.getExternalUserId()));
+            wxWorkUserId2VidDTO.setUuid(qwUser.getUid());
+            WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> vidResp = wxWorkService.UserId2Vid(wxWorkUserId2VidDTO, qwUser.getServerId());
+            List<WxWorkVid2UserIdRespDTO> data = vidResp.getData();
+            if (data == null || data.isEmpty()) {
+                continue;
+            }
+            Long sendId = data.get(0).getUser_id();
+            WxWorkSendTextMsgDTO textMsgDto = new WxWorkSendTextMsgDTO();
+            textMsgDto.setSend_userid(sendId);
+            textMsgDto.setUuid(qwUser.getUid());
+            textMsgDto.setContent(PAY_SUCCESS_MSG);
+            textMsgDto.setIsRoom(false);
+            wxWorkService.SendTextMsg(textMsgDto, qwUser.getServerId());
+            /** 支付成功企微消息配图,在配置文件中设置 store.pay-success.image-url */
+            String paySuccessImageUrl = "https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/vip-ele.jpg";
+            if (StringUtils.isNotEmpty(paySuccessImageUrl)) {
+                sendWxImageMsg(sendId, qwUser.getUid(), qwUser.getServerId(), paySuccessImageUrl);
+            } else {
+                log.warn("支付成功企微配图未配置,跳过图片发送,orderId:{}", orderId);
+            }
+            return;
+        }
+    }
+
+    private void sendWxImageMsg(Long sendId, String uuid, Long serverId, String imageUrl) {
+        WxwUploadCdnLinkImgDTO uploadDto = new WxwUploadCdnLinkImgDTO();
+        uploadDto.setUuid(uuid);
+        uploadDto.setUrl(imageUrl);
+        WxWorkResponseDTO<WxwUploadCdnLinkImgRespDTO> uploadResp = wxWorkService.uploadCdnLinkImg(uploadDto, serverId);
+        if (uploadResp == null || !"成功".equals(uploadResp.getErrmsg()) || uploadResp.getData() == null) {
+            log.warn("支付成功消息图片上传CDN失败,sendId:{},imageUrl:{}", sendId, imageUrl);
+            return;
+        }
+        WxwUploadCdnLinkImgRespDTO imgData = uploadResp.getData();
+        WxwSendCDNImgMsgDTO imgMsgDto = new WxwSendCDNImgMsgDTO();
+        imgMsgDto.setSend_userid(sendId);
+        imgMsgDto.setUuid(uuid);
+        imgMsgDto.setIsRoom(false);
+        imgMsgDto.setCdnkey(imgData.getCdn_key());
+        imgMsgDto.setAeskey(imgData.getAes_key());
+        imgMsgDto.setMd5(imgData.getMd5());
+        imgMsgDto.setFileSize(imgData.getSize());
+        wxWorkService.SendCDNImgMsg(imgMsgDto, serverId);
+    }
+
     @Override
     public R sendExpressInfoToWx(@PathVariable Long orderId) {
         boolean isSend = redisCache.setIfAbsent("fs:express:info:send:" + orderId, "1", 2, TimeUnit.MINUTES);