Jelajahi Sumber

1、sop发送app直播短链

yys 1 Minggu lalu
induk
melakukan
1c91992b0b

+ 3 - 2
fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java

@@ -271,8 +271,9 @@ public class QwSopLogsController extends BaseController
     {
        if (ObjectUtil.isNotEmpty(ids)){
            for (String id : ids) {
-               String key = "qw:logs:pad:send:id:" + id;
-               redisCache.deleteObject(key);
+               // 企微防重 + APP防重,再次发送时都必须清掉
+               redisCache.deleteObject("qw:logs:pad:send:id:" + id);
+               redisCache.deleteObject("qw:logs:pad:send:app:id:" + id);
            }
        }
         return toAjax(iQwSopLogsService.editCourseQwSopLogs(ids));

+ 43 - 27
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -622,8 +622,10 @@ public class IpadSendServer {
         }
 
         boolean noSop = qwSopLogs.getSendType() != 3 && qwSopLogs.getSendType() != 7;
+        // 一键群发直播(20)允许无 expiryTime,默认 12 小时,避免误判删除后连带作废 APP 待发
+        boolean oneClickLive = qwSopLogs.getSendType() != null && qwSopLogs.getSendType() == 20;
 
-        if (qwSopLogs.getExpiryTime() == null && noSop) {
+        if (qwSopLogs.getExpiryTime() == null && noSop && !oneClickLive) {
             // 作废消息
             log.warn("直播SOP_LOG_ID:{}, 直播SOP任务被删除", qwSopLogs.getId());
             qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "直播SOP任务被删除");
@@ -634,7 +636,7 @@ public class IpadSendServer {
         LocalDateTime expiryDateTime;
 
         // 判断是否过期
-        if(qwSopLogs.getSendType() == 3 || qwSopLogs.getSendType() == 7){
+        if(qwSopLogs.getSendType() == 3 || qwSopLogs.getSendType() == 7 || (oneClickLive && qwSopLogs.getExpiryTime() == null)){
             expiryDateTime = sendTime.plusHours(12);
         }else{
             expiryDateTime = sendTime.plusHours(qwSopLogs.getExpiryTime());
@@ -647,7 +649,11 @@ public class IpadSendServer {
             return false;
         }
 
-        if (setting.getCourseType() == null && noSop && setting.getType() == 2) {
+        // 纯直播内容(含APP直播24/25)不强制要求课程消息类型
+        boolean hasLiveContent = setting.getSetting() != null && setting.getSetting().stream().anyMatch(s ->
+                "12".equals(s.getContentType()) || "18".equals(s.getContentType()) || "19".equals(s.getContentType())
+                        || "20".equals(s.getContentType()) || "24".equals(s.getContentType()) || "25".equals(s.getContentType()));
+        if (setting.getCourseType() == null && noSop && setting.getType() == 2 && !hasLiveContent) {
             log.warn("直播SOP_LOG_ID:{}, 模板未选消息类型,不发送", qwSopLogs.getId());
             qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "直播模板未选消息类型,不发送");
             return false;
@@ -681,7 +687,7 @@ public class IpadSendServer {
         );
         Integer courseType = setting.getCourseType();
         String logId = qwSopLogs.getId();
-        if (liveWatchLog != null
+        if (liveWatchLog != null && courseType != null && courseType != 0
                 && !QwSopLogsServiceImpl.isCourseTypeValid(courseType, liveWatchLog.getLogType())) {
             log.warn("SOP_LOG_ID:{}, 看课状态未满足,不发送", qwSopLogs.getId());
             qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "看课状态未满足,不发送");
@@ -794,14 +800,21 @@ public class IpadSendServer {
                 case "23":
                     sendAppShortLink(vo, content, miniMap);
                     break;
+                case "24":
+                    // APP直播短链:已标记APP则交 SendAppMsg;未标记则兼容旧数据走企微短链
+                    if (qwSopLogs.getIsHaveApp() == 1) {
+                        content.setSendStatus(0);
+                        content.setSendRemarks("APP待发送");
+                    } else {
+                        sendAppShortLink(vo, content, miniMap);
+                    }
+                    break;
                 case "9":
                     // APP看课链接
                 case "15":
                     // APP文本
                 case "16":
                     // APP语音
-                case "24":
-                    // APP直播短链走 OpenIM IM 发送,企微侧跳过,交给 SendAppMsg
                 case "25":
                     // APP直播卡片走 OpenIM IM 发送,企微侧跳过,交给 SendAppMsg
                     content.setSendStatus(0);
@@ -1297,8 +1310,13 @@ public class IpadSendServer {
         }
 
         boolean noSop = qwSopLogs.getSendType() != 3 && qwSopLogs.getSendType() != 7;
+        // 一键群发(5/12/20)允许无 expiryTime,默认 12 小时有效,避免被误判为「SOP任务被删除」
+        boolean oneClickSend = qwSopLogs.getSendType() != null
+                && (qwSopLogs.getSendType() == 5 || qwSopLogs.getSendType() == 12 || qwSopLogs.getSendType() == 20);
+        boolean hasAppLiveContent = setting.getSetting() != null
+                && setting.getSetting().stream().anyMatch(s -> "24".equals(s.getContentType()) || "25".equals(s.getContentType()));
 
-        if (qwSopLogs.getExpiryTime() == null && noSop) {
+        if (qwSopLogs.getExpiryTime() == null && noSop && !oneClickSend) {
             // 作废消息
             log.info("SOP_LOG_ID:{}, SOP任务被删除", qwSopLogs.getId());
             qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "SOP任务被删除");
@@ -1309,7 +1327,7 @@ public class IpadSendServer {
         LocalDateTime expiryDateTime;
 
         // 判断是否过期
-        if(qwSopLogs.getSendType() == 3 || qwSopLogs.getSendType() == 7){
+        if(qwSopLogs.getSendType() == 3 || qwSopLogs.getSendType() == 7 || (oneClickSend && qwSopLogs.getExpiryTime() == null)){
             expiryDateTime = sendTime.plusHours(12);
         }else{
             expiryDateTime = sendTime.plusHours(qwSopLogs.getExpiryTime());
@@ -1322,25 +1340,7 @@ public class IpadSendServer {
             return false;
         }
 
-        if (setting.getCourseType() == null && noSop && setting.getType() == 2) {
-            log.info("SOP_LOG_ID:{}, 模板未选消息类型,不发送", qwSopLogs.getId());
-            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "模板未选消息类型,不发送");
-            return false;
-        }
-        if (setting.getVideoId() != null) {
-        Integer cacheValue = redisCache.getCacheObject("sopCourse:video:isPause:" + setting.getVideoId());
-        int isPause = (cacheValue != null) ? cacheValue : 0;
-        log.info("SOP_LOG_ID:{},判断课程({})当前状态:{}", qwSopLogs.getId(), setting.getVideoId(), isPause);
-        if (isPause == 1){
-            log.info("SOP_LOG_ID:{}, 课程暂停,不发送", qwSopLogs.getId());
-            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "课程暂停,AI不发送");
-            return false;
-        }
-        }
-
-        // APP直播短链(24)/卡片(25)走直播看课状态校验,避免落入课程看课逻辑
-        boolean hasAppLiveContent = setting.getSetting() != null
-                && setting.getSetting().stream().anyMatch(s -> "24".equals(s.getContentType()) || "25".equals(s.getContentType()));
+        // APP直播短链/卡片:不要求课程消息类型,走直播看课校验
         if (hasAppLiveContent) {
             Long queryLiveId = setting.getLiveId();
             if (queryLiveId == null && setting.getSetting() != null) {
@@ -1362,6 +1362,22 @@ public class IpadSendServer {
             return true;
         }
 
+        if (setting.getCourseType() == null && noSop && setting.getType() == 2) {
+            log.info("SOP_LOG_ID:{}, 模板未选消息类型,不发送", qwSopLogs.getId());
+            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "模板未选消息类型,不发送");
+            return false;
+        }
+        if (setting.getVideoId() != null) {
+        Integer cacheValue = redisCache.getCacheObject("sopCourse:video:isPause:" + setting.getVideoId());
+        int isPause = (cacheValue != null) ? cacheValue : 0;
+        log.info("SOP_LOG_ID:{},判断课程({})当前状态:{}", qwSopLogs.getId(), setting.getVideoId(), isPause);
+        if (isPause == 1){
+            log.info("SOP_LOG_ID:{}, 课程暂停,不发送", qwSopLogs.getId());
+            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "课程暂停,AI不发送");
+            return false;
+        }
+        }
+
         if (qwSopLogs.getSendType() != 12 && noSop) {
             // 客户的信息
 //            QwExternalContactHParam contactHParam = new QwExternalContactHParam();

+ 5 - 0
fs-ipad-task/src/main/java/com/fs/app/task/SendAppMsg.java

@@ -252,6 +252,11 @@ public class SendAppMsg {
                 if (fsUserId == null || resolvedCompanyUserId == null) {
                     log.warn("SendAppMsg-缺少IM发送参数, logId={}, fsUserId={}, companyUserId={}, externalId={}",
                             qwSopLogs.getId(), fsUserId, resolvedCompanyUserId, qwSopLogs.getExternalId());
+                    QwSopLogs missParamUpdate = new QwSopLogs();
+                    missParamUpdate.setId(qwSopLogs.getId());
+                    missParamUpdate.setAppSendStatus(2);
+                    missParamUpdate.setAppSendRemark("APP发送失败:缺少fsUserId或companyUserId");
+                    qwSopLogsService.updateQwSopLogs(missParamUpdate);
                     continue;
                 }
                 boolean txtSendStatus = true;

+ 13 - 10
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -191,6 +191,17 @@ public class SendMsg {
         for (QwSopLogs qwSopLogs : qwSopLogList) {
             long start2 = System.currentTimeMillis();
             QwSopCourseFinishTempSetting setting = JSON.parseObject(qwSopLogs.getContentJson(), QwSopCourseFinishTempSetting.class);
+            // APP专属消息:仅 is_have_app=1 时交给 SendAppMsg;未标记时仍走企微兼容发送
+            List<String> appTypeList = Arrays.asList("9", "15", "16", "24", "25");
+            boolean appOwned = qwSopLogs.getIsHaveApp() == 1;
+            boolean hasQwContent = setting.getSetting() != null && setting.getSetting().stream()
+                    .anyMatch(e -> e.getContentType() != null
+                            && !(appOwned && appTypeList.contains(e.getContentType())));
+            // 纯APP消息必须先跳过企微校验,避免 isSendLogsLive 作废后 SendAppMsg 再也捞不到
+            if (appOwned && !hasQwContent) {
+                log.info("纯APP消息跳过企微发送,交给SendAppMsg:{}", qwSopLogs.getId());
+                continue;
+            }
             //直播的sendType:20单独走判断 其他的走以前的逻辑
             boolean isSendLive = Integer.valueOf(20).equals(qwSopLogs.getSendType());
             if(isSendLive){
@@ -207,14 +218,6 @@ public class SendMsg {
                 }
             }
             log.info("进入发送消息状态:{}", qwSopLogs.getId());
-            // APP专属消息类型:由 SendAppMsg 处理,企微侧不占用待发送队列
-            List<String> appTypeList = Arrays.asList("9", "15", "16", "24", "25");
-            boolean hasQwContent = setting.getSetting() != null && setting.getSetting().stream()
-                    .anyMatch(e -> e.getContentType() != null && !appTypeList.contains(e.getContentType()));
-            if (!hasQwContent) {
-                log.info("纯APP消息跳过企微发送,交给SendAppMsg:{}", qwSopLogs.getId());
-                continue;
-            }
             String key = "qw:logs:pad:send:id:" + qwSopLogs.getId();
             Long time = redisCache.getCacheObject(key);
             // 判断这个消息有没有进入过发送,如果进了就不要再发了,防止重复发送,,,,, TODO 千万不能动!!!!!
@@ -228,8 +231,8 @@ public class SendMsg {
             // 循环发送消息里面的每一条消息
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
                 long start4 = System.currentTimeMillis();
-                // APP内容不走企微pad发送,仅标记待APP发送
-                if (appTypeList.contains(content.getContentType())) {
+                // 已标记APP内容不走企微pad发送,仅标记待APP发送
+                if (appOwned && appTypeList.contains(content.getContentType())) {
                     content.setSendStatus(0);
                     content.setSendRemarks("APP待发送");
                     continue;

+ 1 - 0
fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java

@@ -221,6 +221,7 @@ public class QwSopLogsServiceImpl extends ServiceImpl<QwSopLogsMapper, QwSopLogs
 
     @Override
     public int editCourseQwSopLogs(String[] ids) {
+        // SQL 已重置 send_status/app_send_status,并对 APP 类型消息补 is_have_app=1
         return qwSopLogsMapper.editCourseQwSopLogs(ids);
     }
 

+ 3 - 1
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -1545,9 +1545,11 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                 processQwSopLogsBySendMsg(param,param.getDraftStrategy());
                 log.info("一键群发操作日志2:{}", JSON.toJSONString(param));
                 break;
+            default:
+                return R.error("不支持的群发类型");
         }
 
-        return null;
+        return R.ok();
     }
 
     @Override

+ 21 - 1
fs-service/src/main/resources/mapper/sop/QwSopLogsMapper.xml

@@ -354,7 +354,27 @@
 
     <update id="editCourseQwSopLogs" parameterType="String">
         update qw_sop_logs
-        SET send_status = 3,  receiving_status = 0 , remark='再次补发记录', send_time = NOW(),real_send_time =null
+        SET send_status = 3,
+            receiving_status = 0,
+            remark = '再次补发记录',
+            send_time = NOW(),
+            real_send_time = null,
+            app_send_status = 0,
+            app_send_remark = null,
+            is_have_app = CASE
+                WHEN content_json LIKE '%"contentType":"9"%'
+                  OR content_json LIKE '%"contentType":"15"%'
+                  OR content_json LIKE '%"contentType":"16"%'
+                  OR content_json LIKE '%"contentType":"24"%'
+                  OR content_json LIKE '%"contentType":"25"%'
+                  OR content_json LIKE '%"contentType":9,%'
+                  OR content_json LIKE '%"contentType":15,%'
+                  OR content_json LIKE '%"contentType":16,%'
+                  OR content_json LIKE '%"contentType":24,%'
+                  OR content_json LIKE '%"contentType":25,%'
+                THEN 1
+                ELSE is_have_app
+            END
         where id in
         <foreach item="id" collection="array" open="(" separator="," close=")">
             #{id}