Преглед изворни кода

Merge branch 'wyp/1224-feishuCard' of Server/long-article-recommend into master

wangyunpeng пре 6 месеци
родитељ
комит
f83c2996b5

+ 28 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/common/enums/FieshuTableColumnDataTypeEnum.java

@@ -0,0 +1,28 @@
+package com.tzld.longarticle.recommend.server.common.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum FieshuTableColumnDataTypeEnum {
+    TEXT("text"),
+    LARK_MD("lark_md"),
+    NUMBER("number"),
+    DATE("date"),
+    OPTIONS("options"),
+    ;
+
+    private String type;
+
+    FieshuTableColumnDataTypeEnum(String type) {
+        this.type = type;
+    }
+
+    public static FieshuTableColumnDataTypeEnum from(String type) {
+        for (FieshuTableColumnDataTypeEnum typeEnum : FieshuTableColumnDataTypeEnum.values()) {
+            if (typeEnum.getType().equals(type)) {
+                return typeEnum;
+            }
+        }
+        return null;
+    }
+}

+ 2 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/mapper/aigc/AigcBaseMapper.java

@@ -55,6 +55,8 @@ public interface AigcBaseMapper {
 
     PublishContentDTO getPublishContentById(String publishContentId);
 
+    List<PublishContentDTO> getPublishContentByIdIn(List<String> publishContentIds);
+
     List<PublishContentDTO> getPublishContentBySourceIdIn(List<String> sourceIds);
 
     List<CrawlerPlan> getColdCrawlerPlan(Long timeStart, Long timeEnd, List<String> planTags);

+ 137 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/model/vo/FeishuTableDTO.java

@@ -0,0 +1,137 @@
+package com.tzld.longarticle.recommend.server.model.vo;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tzld.longarticle.recommend.server.common.enums.FieshuTableColumnDataTypeEnum;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FeishuTableDTO {
+    private Header header;
+    private List<Element> elements;
+
+    @Data
+    public static class Element {
+        private String tag;
+        private long page_size;
+        private String row_height;
+        private HeaderStyle header_style;
+        private List<Column> columns;
+        private List<JSONObject> rows;
+    }
+
+    @Data
+    public static class Column {
+        private String name;
+        private String display_name;
+        private String data_type;
+        private String horizontal_align;
+        private String vertical_align;
+        private String width;
+        private String format;
+        private String dateFormat;
+    }
+
+    @Data
+    public static class HeaderStyle {
+        private String text_align;
+        private String text_size;
+        private String background_style;
+        private String text_color;
+        private boolean bold;
+        private long lines;
+    }
+
+    @Data
+    public static class Header {
+        private String template;
+        private Title title;
+    }
+
+    @Data
+    public static class Title {
+        private String content;
+        private String tag;
+    }
+
+    public static FeishuTableDTO createTable(String title, List<Column> columns, List<JSONObject> rows) {
+        String tableStr = "{\n" +
+                "    \"header\":\n" +
+                "    {\n" +
+                "        \"template\": \"blue\",\n" +
+                "        \"title\":\n" +
+                "        {\n" +
+                "            \"content\": \"" + title + "\",\n " +
+                "            \"tag\": \"plain_text\"\n" +
+                "        }\n" +
+                "    },\n" +
+                "    \"elements\":\n" +
+                "    [\n" +
+                "        {\n" +
+                "            \"tag\": \"table\",\n" +
+                "            \"page_size\": " + rows.size() + ",\n" +
+                "            \"row_height\": \"low\",\n" +
+                "            \"header_style\":\n" +
+                "            {\n" +
+                "                \"text_align\": \"left\",\n" +
+                "                \"text_size\": \"normal\",\n" +
+                "                \"background_style\": \"none\",\n" +
+                "                \"text_color\": \"grey\",\n" +
+                "                \"bold\": true,\n" +
+                "                \"lines\": 1\n" +
+                "            },\n" +
+                "            \"columns\":\n" +
+                JSONObject.toJSONString(columns) +
+                "            ,\n" +
+                "            \"rows\":\n" +
+                JSONObject.toJSONString(rows) +
+                "        }\n" +
+                "    ]\n" +
+                "}";
+        return JSONObject.parseObject(tableStr, FeishuTableDTO.class);
+    }
+
+    public static Column createFeishuColumns(
+            String dataType,
+            String columnName,
+            String displayName,
+            String numberFormat) {
+
+        String width = "auto";
+        String verticalAlign = "top";
+        String horizontalAlign = "left";
+        Column column = new Column();
+
+        if (FieshuTableColumnDataTypeEnum.TEXT.getType().equals(dataType)) {
+            column.setName(columnName);
+            column.setDisplay_name(displayName);
+            column.setWidth(width);
+            column.setData_type(dataType);
+            column.setVertical_align(verticalAlign);
+            column.setHorizontal_align(horizontalAlign);
+        } else if (FieshuTableColumnDataTypeEnum.LARK_MD.getType().equals(dataType)) {
+            column.setName(columnName);
+            column.setDisplay_name(displayName);
+            column.setData_type(dataType);
+        } else if (FieshuTableColumnDataTypeEnum.NUMBER.getType().equals(dataType)) {
+            column.setName(columnName);
+            column.setDisplay_name(displayName);
+            column.setData_type(dataType);
+            column.setFormat(numberFormat);
+            column.setWidth(width);
+        } else if (FieshuTableColumnDataTypeEnum.DATE.getType().equals(dataType)) {
+            column.setName(columnName);
+            column.setDisplay_name(displayName);
+            column.setData_type(dataType);
+            column.setDateFormat("YYYY/MM/DD");
+        } else if (FieshuTableColumnDataTypeEnum.OPTIONS.getType().equals(dataType)) {
+            column.setName(columnName);
+            column.setDisplay_name(displayName);
+            column.setData_type(dataType);
+        }
+
+        return column;
+    }
+}
+

+ 122 - 55
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recommend/ArticleAuditService.java

@@ -2,7 +2,9 @@ package com.tzld.longarticle.recommend.server.service.recommend;
 
 import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.google.common.collect.Lists;
+import com.tzld.longarticle.recommend.server.common.enums.FieshuTableColumnDataTypeEnum;
 import com.tzld.longarticle.recommend.server.common.enums.StatusEnum;
 import com.tzld.longarticle.recommend.server.common.enums.aigc.PublishContentStatusEnum;
 import com.tzld.longarticle.recommend.server.common.enums.aigc.PublishPlanInputSourceTypesEnum;
@@ -22,6 +24,7 @@ import com.tzld.longarticle.recommend.server.model.entity.crawler.Article;
 import com.tzld.longarticle.recommend.server.model.entity.longArticle.*;
 import com.tzld.longarticle.recommend.server.model.param.ArticleDangerFindDeleteParam;
 import com.tzld.longarticle.recommend.server.model.param.PublishContentParam;
+import com.tzld.longarticle.recommend.server.model.vo.FeishuTableDTO;
 import com.tzld.longarticle.recommend.server.remote.WxAccessTokenRemoteService;
 import com.tzld.longarticle.recommend.server.remote.WxArticleDeleteService;
 import com.tzld.longarticle.recommend.server.remote.pq.PQVideoAuditResultService;
@@ -324,49 +327,63 @@ public class ArticleAuditService {
         Map<String, PublishAccountTypeDTO> accountTypeMap = accountTypeList.stream()
                 .collect(Collectors.toMap(PublishAccountTypeDTO::getGhId, Function.identity()));
         // 删除文章
+        List<JSONObject> alarmList = new ArrayList<>();
         for (String publishContentId : publishContentIds) {
-            String pushId = publishPushIdMap.get(publishContentId);
-            if (!StringUtils.hasText(pushId)) {
-                deleteFailAlarm(publishContentId, "无推送记录", 0, accountTypeMap);
-                continue;
-            }
-            PublishGzhPushDTO publishGzhPushDTO = pushDTOMap.get(pushId);
-            if (Objects.isNull(publishGzhPushDTO)) {
-                deleteFailAlarm(publishContentId, "无推送记录", 0, accountTypeMap);
-                continue;
-            }
-            String publishAccountId = pushAccountMap.get(pushId);
-            String ghId = publishAccountMap.get(publishAccountId);
-            List<PublishGzhPushContentRelDTO> relList = groupPushRelMap.get(pushId).stream()
-                    .sorted(Comparator.comparing(PublishGzhPushContentRelDTO::getId)).collect(Collectors.toList());
-            int index = 1;
-            for (int i = 0; i < relList.size(); i++) {
-                if (relList.get(i).getPublishContentId().equals(publishContentId)) {
-                    index = i + 1;
-                    break;
+            try {
+                String pushId = publishPushIdMap.get(publishContentId);
+                if (!StringUtils.hasText(pushId)) {
+                    deleteFailAlarmAdd(alarmList, publishContentId, "无推送记录", 0);
+                    continue;
                 }
+                PublishGzhPushDTO publishGzhPushDTO = pushDTOMap.get(pushId);
+                if (Objects.isNull(publishGzhPushDTO)) {
+                    deleteFailAlarmAdd(alarmList, publishContentId, "无推送记录", 0);
+                    continue;
+                }
+                String publishAccountId = pushAccountMap.get(pushId);
+                String ghId = publishAccountMap.get(publishAccountId);
+                List<PublishGzhPushContentRelDTO> relList = groupPushRelMap.get(pushId).stream()
+                        .sorted(Comparator.comparing(PublishGzhPushContentRelDTO::getId)).collect(Collectors.toList());
+                int index = 1;
+                for (int i = 0; i < relList.size(); i++) {
+                    if (relList.get(i).getPublishContentId().equals(publishContentId)) {
+                        index = i + 1;
+                        break;
+                    }
+                }
+                if (!publishGzhPushDTO.getPushType().equals(PushTypeEnum.AUTO_GROUP_PUBLISH.getVal())) {
+                    PushTypeEnum pushTypeEnum = PushTypeEnum.from(publishGzhPushDTO.getPushType());
+                    deleteFailAlarmAdd(alarmList, publishContentId, "推送类型为" + pushTypeEnum.getDescription(), index);
+                    continue;
+                }
+                String groupPushMsgId = pushIdMap.get(pushId);
+                if (!StringUtils.hasText(groupPushMsgId)) {
+                    deleteFailAlarmAdd(alarmList, publishContentId, "无推送MsgId", index);
+                    continue;
+                }
+                LongArticleAuditDelete delete = new LongArticleAuditDelete();
+                delete.setGhId(ghId);
+                delete.setMsgId(groupPushMsgId);
+                delete.setPushId(pushId);
+                delete.setPushType(publishGzhPushDTO.getPushType());
+                delete.setPublishContentId(publishContentId);
+                delete.setIndex(index);
+                delete.setStatus(StatusEnum.ZERO.getCode());
+                delete.setCreateTimestamp(System.currentTimeMillis());
+                longArticleAuditDeleteRepository.save(delete);
+            } catch (Exception e) {
+                log.error("buildArticleAuditDelete error", e);
             }
-            if (!publishGzhPushDTO.getPushType().equals(PushTypeEnum.AUTO_GROUP_PUBLISH.getVal())) {
-                PushTypeEnum pushTypeEnum = PushTypeEnum.from(publishGzhPushDTO.getPushType());
-                deleteFailAlarm(publishContentId, "推送类型为" + pushTypeEnum.getDescription(), index, accountTypeMap);
-                continue;
-            }
-            String groupPushMsgId = pushIdMap.get(pushId);
-            if (!StringUtils.hasText(groupPushMsgId)) {
-                deleteFailAlarm(publishContentId, "无推送MsgId", index, accountTypeMap);
-                continue;
-            }
-            LongArticleAuditDelete delete = new LongArticleAuditDelete();
-            delete.setGhId(ghId);
-            delete.setMsgId(groupPushMsgId);
-            delete.setPushId(pushId);
-            delete.setPushType(publishGzhPushDTO.getPushType());
-            delete.setPublishContentId(publishContentId);
-            delete.setIndex(index);
-            delete.setStatus(StatusEnum.ZERO.getCode());
-            delete.setCreateTimestamp(System.currentTimeMillis());
-            longArticleAuditDeleteRepository.save(delete);
         }
+        deleteFailAlarm(alarmList, accountTypeMap);
+    }
+
+    private void deleteFailAlarmAdd(List<JSONObject> alarmList, String publishContentId, String errMsg, Integer index) {
+        JSONObject alarm = new JSONObject();
+        alarm.put("publishContentId", publishContentId);
+        alarm.put("errMsg", errMsg);
+        alarm.put("index", index);
+        alarmList.add(alarm);
     }
 
     /**
@@ -378,6 +395,7 @@ public class ArticleAuditService {
         List<PublishAccountTypeDTO> accountTypeList = aigcBaseMapper.getAccountTypeList();
         Map<String, PublishAccountTypeDTO> accountTypeMap = accountTypeList.stream()
                 .collect(Collectors.toMap(PublishAccountTypeDTO::getGhId, Function.identity()));
+        List<JSONObject> alarmList = new ArrayList<>();
         for (LongArticleAuditDelete delete : dealList) {
             try {
                 if (Objects.equals(delete.getPushType(), PushTypeEnum.AUTO_GROUP_PUBLISH.getVal())) {
@@ -392,7 +410,7 @@ public class ArticleAuditService {
                         delete.setFailReason(result.getFailReason());
                     }
                 } else {
-                    deleteFailAlarm(delete.getPublishContentId(), "非自动群发", delete.getIndex(), accountTypeMap);
+                    deleteFailAlarmAdd(alarmList, delete.getPublishContentId(), "非自动群发", delete.getIndex());
                     delete.setStatus(ArticleDeleteStatusEnum.SUCCESS.getCode());
                 }
                 delete.setFinishTimestamp(System.currentTimeMillis());
@@ -401,26 +419,75 @@ public class ArticleAuditService {
                 log.error("articleVideoDelete ghId:{} error", delete.getGhId(), e);
             }
         }
+        deleteFailAlarm(alarmList, accountTypeMap);
         return ReturnT.SUCCESS;
     }
 
-    private void deleteFailAlarm(String publishContentId, String typeMsg, Integer index,
+    private void deleteFailAlarm(List<JSONObject> alarmList,
                                  Map<String, PublishAccountTypeDTO> accountTypeMap) {
-        PublishContentDTO publishContent = aigcBaseMapper.getPublishContentById(publishContentId);
-        PublishAccount publishAccount = publishAccountRepository.getById(publishContent.getPublishAccountId());
-        String publishTime = DateUtils.timestampToYMDStr(publishContent.getPublishTimestamp() / 1000, "yyyyMMdd");
-        PublishAccountTypeDTO accountTypeDTO = accountTypeMap.get(publishAccount.getGhId());
-        String accountType = Objects.nonNull(accountTypeDTO) ? accountTypeDTO.getAccountSourceName() : "未知";
+        List<String> publishContentIds = alarmList.stream().map(o -> o.getString("publishContentId"))
+                .collect(Collectors.toList());
+        List<PublishContentDTO> publishContents = aigcBaseMapper.getPublishContentByIdIn(publishContentIds);
+        Map<String, PublishContentDTO> publishContentMap = publishContents.stream()
+                .collect(Collectors.toMap(PublishContentDTO::getId, Function.identity()));
+        List<String> publishAccountIds = publishContents.stream().map(PublishContentDTO::getPublishAccountId)
+                .collect(Collectors.toList());
+        List<PublishAccount> publishAccounts = publishAccountRepository.getByIdIn(publishAccountIds);
+        Map<String, PublishAccount> publishAccountMap = publishAccounts.stream()
+                .collect(Collectors.toMap(PublishAccount::getId, Function.identity()));
+        List<FeishuTableDTO.Column> columns = buildArticleDeleteFailColumns();
+        List<JSONObject> rows = new ArrayList<>();
+        for (JSONObject alarm : alarmList) {
+            String publishContentId = alarm.getString("publishContentId");
+            PublishContentDTO publishContent = publishContentMap.get(publishContentId);
+            String publishTime = DateUtils.timestampToYMDStr(publishContent.getPublishTimestamp() / 1000, "yyyyMMdd");
+            PublishAccount publishAccount = publishAccountMap.get(publishContent.getPublishAccountId());
+            PublishAccountTypeDTO accountTypeDTO = accountTypeMap.get(publishAccount.getGhId());
+            String accountType = Objects.nonNull(accountTypeDTO) ? accountTypeDTO.getAccountSourceName() : "未知";
+
+            JSONObject row = new JSONObject();
+            row.put("account_name", publishAccount.getName());
+            row.put("gh_id", publishAccount.getGhId());
+            row.put("account_type", accountType);
+            row.put("publish_time", publishTime);
+            row.put("index", String.valueOf(alarm.getInteger("index")));
+            row.put("title", publishContent.getTitle());
+            row.put("err_msg", alarm.getString("errMsg"));
+            rows.add(row);
+        }
+        FeishuTableDTO tableDTO = FeishuTableDTO.createTable("文章删除失败", columns, rows);
+        JSONObject content = JSONObject.parseObject(JSONObject.toJSONString(tableDTO));
         // 无法自动删除 发送飞书通知 人工删除
-        FeishuMessageSender.sendWebHookMessage(FeishuRobotIdEnum.ARTICLE_DELETE.getRobotId(),
-                "【文章删除失败】\n" +
-                        "账号名称: " + publishAccount.getName() + "\n" +
-                        "账号ghId: " + publishAccount.getGhId() + "\n" +
-                        "账号来源: " + accountType + "\n" +
-                        "发布日期: " + publishTime + "\n" +
-                        "位置: " + index + "\n" +
-                        "标题: " + publishContent.getTitle() + "\n" +
-                        "原因: " + typeMsg);
+        JSONObject bodyParam = new JSONObject();
+        bodyParam.put("msg_type", "interactive");
+        bodyParam.put("card", content);
+        FeishuMessageSender.sendWebHookMessage(FeishuRobotIdEnum.ARTICLE_DELETE.getRobotId(), bodyParam);
+    }
+
+    private List<FeishuTableDTO.Column> buildArticleDeleteFailColumns() {
+        List<FeishuTableDTO.Column> columns = new ArrayList<>();
+        FeishuTableDTO.Column accountNameColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "account_name", "账号名称", null);
+        columns.add(accountNameColumn);
+        FeishuTableDTO.Column accountGhIdColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "gh_id", "账号ghId", null);
+        columns.add(accountGhIdColumn);
+        FeishuTableDTO.Column accountTypeColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "account_type", "账号来源", null);
+        columns.add(accountTypeColumn);
+        FeishuTableDTO.Column publishTimeColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "publish_time", "发布日期", null);
+        columns.add(publishTimeColumn);
+        FeishuTableDTO.Column indexColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "index", "位置", null);
+        columns.add(indexColumn);
+        FeishuTableDTO.Column titleColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "title", "标题", null);
+        columns.add(titleColumn);
+        FeishuTableDTO.Column errMsgColumn = FeishuTableDTO.createFeishuColumns(
+                FieshuTableColumnDataTypeEnum.TEXT.getType(), "err_msg", "原因", null);
+        columns.add(errMsgColumn);
+        return columns;
     }
 
     public void titleDangerFindDelete(ArticleDangerFindDeleteParam param) {

+ 24 - 8
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/util/feishu/FeishuMessageSender.java

@@ -88,24 +88,40 @@ public class FeishuMessageSender implements InitializingBean {
         if (!"prod".equals(staticEnv)) {
             return;
         }
+        JSONObject content = new JSONObject();
+        content.put("text", msg);
+        JSONObject bodyParam = new JSONObject();
+        bodyParam.put("msg_type", "text");
+        bodyParam.put("content", content);
         String webhookUrl = webHookUrl + robotId;
-        String hrc = request(msg, webhookUrl);
+        String hrc = request(bodyParam, webhookUrl);
         if (hrc == null) {
             // 重试一次
-            hrc = request(msg, webhookUrl);
+            hrc = request(bodyParam, webhookUrl);
         }
         if (hrc == null) {
             log.error("sendWebHookMessage,hrc is null");
         }
     }
 
-    public static String request(String msg, String webhookUrl) {
+    public static void sendWebHookMessage(String robotId, JSONObject bodyParam) {
+        // 使用自定义群机器人webhook方式,支持外部群
+        if (!"prod".equals(staticEnv)) {
+            return;
+        }
+        String webhookUrl = webHookUrl + robotId;
+        String hrc = request(bodyParam, webhookUrl);
+        if (hrc == null) {
+            // 重试一次
+            hrc = request(bodyParam, webhookUrl);
+        }
+        if (hrc == null) {
+            log.error("sendWebHookMessage,hrc is null");
+        }
+    }
+
+    public static String request(JSONObject bodyParam, String webhookUrl) {
         long start = System.currentTimeMillis();
-        JSONObject content = new JSONObject();
-        content.put("text", msg);
-        JSONObject bodyParam = new JSONObject();
-        bodyParam.put("msg_type", "text");
-        bodyParam.put("content", content);
         try {
             HttpPost httpPost = new HttpPost(webhookUrl);
             StringEntity stringEntity = new StringEntity(bodyParam.toJSONString(), StandardCharsets.UTF_8);

+ 12 - 0
long-article-recommend-service/src/main/resources/mapper/aigc/AigcBaseMapper.xml

@@ -261,6 +261,18 @@
         where content.id = #{publishContentId}
     </select>
 
+    <select id="getPublishContentByIdIn"
+            resultType="com.tzld.longarticle.recommend.server.model.dto.PublishContentDTO">
+        select content.id, content.publish_timestamp, content.publish_account_id, output.output as title
+        from publish_content content
+                 join publish_content_output output
+                      on content.id = output.publish_content_id and output.content_type = 3 AND output.select_status = 1
+        where content.id in
+        <foreach collection="publishContentIds" item="item" open="(" close=")" separator=",">
+            #{item}
+        </foreach>
+    </select>
+
     <select id="getPublishContentBySourceIdIn"
             resultType="com.tzld.longarticle.recommend.server.model.dto.PublishContentDTO">
         select id, plan_id, source_type, source_id, crawler_channel_content_id, publish_account_id, publish_timestamp