Parcourir la source

Merge branch 'wyp/1226-articleDeleteHTML' of Server/long-article-recommend into master

wangyunpeng il y a 6 mois
Parent
commit
9e93870eb3

+ 26 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/mapper/crawler/ArticleMapper.java

@@ -0,0 +1,26 @@
+package com.tzld.longarticle.recommend.server.mapper.crawler;
+
+import com.tzld.longarticle.recommend.server.model.entity.crawler.Article;
+import com.tzld.longarticle.recommend.server.model.vo.ArticleDeleteListVO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+import java.util.Set;
+
+@Mapper
+public interface ArticleMapper {
+    void updateArticleAigcId(String wxsn, String publishContentId, String channelContentId);
+
+    void updateArticleSourceRootId(String wxsn, String sourcePublishContentId, String rootPublishContentId, String rootProduceContentId);
+
+    List<Article> getWaitingFindArticle(Long timestamp);
+
+    List<Article> getByTitleMd5InAndTypeEqualsAndStatusEquals(List<String> titleMd5s, String type, Integer status);
+
+    List<Article> getByGhIdInAndAppMsgIdInAndItemIndexAndTypeEqualsAndStatusEquals(
+            Set<String> ghIdList, Set<String> appMsgIdList, Integer itemIndex, String type, Integer status);
+
+    int articleDeleteListCount(String title);
+
+    List<ArticleDeleteListVO> articleDeleteList(String title, int offset, Integer pageSize);
+}

+ 1 - 12
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/mapper/crawler/CrawlerBaseMapper.java

@@ -2,13 +2,12 @@ package com.tzld.longarticle.recommend.server.mapper.crawler;
 
 import com.tzld.longarticle.recommend.server.model.dto.ArticleMatchVideos;
 import com.tzld.longarticle.recommend.server.model.dto.GetOffVideos;
-import com.tzld.longarticle.recommend.server.model.entity.longArticle.LongArticlesText;
 import com.tzld.longarticle.recommend.server.model.dto.LongArticlesVideoDTO;
 import com.tzld.longarticle.recommend.server.model.entity.crawler.AccountAvgInfo;
 import com.tzld.longarticle.recommend.server.model.entity.crawler.AccountCorrelation;
-import com.tzld.longarticle.recommend.server.model.entity.crawler.Article;
 import com.tzld.longarticle.recommend.server.model.entity.crawler.ArticleDetailInfo;
 import com.tzld.longarticle.recommend.server.model.entity.longArticle.LongArticlesRootSourceId;
+import com.tzld.longarticle.recommend.server.model.entity.longArticle.LongArticlesText;
 
 import java.util.List;
 import java.util.Set;
@@ -23,12 +22,6 @@ public interface CrawlerBaseMapper {
 
     void updateAccountAvgInfoStatus(String ghId, String date);
 
-    void updateArticleAigcId(String wxsn, String publishContentId, String channelContentId);
-
-    void updateArticleSourceRootId(String wxsn, String sourcePublishContentId, String rootPublishContentId, String rootProduceContentId);
-
-    List<Article> getWaitingFindArticle(Long timestamp);
-
     Integer countGetOffVideos();
 
     List<GetOffVideos> pageGetOffVideos(int offset, int pageSize);
@@ -49,12 +42,8 @@ public interface CrawlerBaseMapper {
 
     List<LongArticlesVideoDTO> getLongArticlesVideo(List<String> traceIds);
 
-    List<Article> getByTitleMd5InAndTypeEqualsAndStatusEquals(List<String> titleMd5s, String type, Integer status);
-
     List<ArticleDetailInfo> getAllByWxSnIn(List<String> wxSnList);
 
     List<AccountAvgInfo> getAllByGhIdIn(Set<String> ghIdList);
 
-    List<Article> getByGhIdInAndAppMsgIdInAndItemIndexAndTypeEqualsAndStatusEquals(
-            Set<String> ghIdList, Set<String> appMsgIdList, Integer itemIndex, String type, Integer status);
 }

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

@@ -0,0 +1,17 @@
+package com.tzld.longarticle.recommend.server.model.vo;
+
+import lombok.Data;
+
+@Data
+public class ArticleDeleteListVO {
+
+    private String dateStr;
+    private String title;
+    private String ghId;
+    private String accountName;
+    private String accountSourceType;
+    private String planType;
+    private Integer index;
+    private String link;
+
+}

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

@@ -15,6 +15,7 @@ import com.tzld.longarticle.recommend.server.common.enums.recommend.ArticleDelet
 import com.tzld.longarticle.recommend.server.common.enums.recommend.ArticleMatchContentStatusEnum;
 import com.tzld.longarticle.recommend.server.common.enums.recommend.FeishuRobotIdEnum;
 import com.tzld.longarticle.recommend.server.mapper.aigc.AigcBaseMapper;
+import com.tzld.longarticle.recommend.server.mapper.crawler.ArticleMapper;
 import com.tzld.longarticle.recommend.server.mapper.longArticle.LongArticleBaseMapper;
 import com.tzld.longarticle.recommend.server.model.cgi.PQVideoAuditResult;
 import com.tzld.longarticle.recommend.server.model.dto.*;
@@ -22,8 +23,10 @@ import com.tzld.longarticle.recommend.server.model.entity.aigc.PublishAccount;
 import com.tzld.longarticle.recommend.server.model.entity.aigc.PublishContent;
 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.ArticleCategoryListParam;
 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.ArticleDeleteListVO;
 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;
@@ -31,11 +34,13 @@ import com.tzld.longarticle.recommend.server.remote.pq.PQVideoAuditResultService
 import com.tzld.longarticle.recommend.server.remote.pq.PQVideoAuditStartProcessService;
 import com.tzld.longarticle.recommend.server.repository.aigc.PublishAccountRepository;
 import com.tzld.longarticle.recommend.server.repository.aigc.PublishContentRepository;
+import com.tzld.longarticle.recommend.server.repository.aigc.PublishPlanRepository;
 import com.tzld.longarticle.recommend.server.repository.crawler.ArticleRepository;
 import com.tzld.longarticle.recommend.server.repository.longArticle.*;
 import com.tzld.longarticle.recommend.server.util.DateUtils;
 import com.tzld.longarticle.recommend.server.util.Md5Util;
 import com.tzld.longarticle.recommend.server.util.feishu.FeishuMessageSender;
+import com.tzld.longarticle.recommend.server.util.page.Page;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.extern.slf4j.Slf4j;
@@ -84,7 +89,9 @@ public class ArticleAuditService {
     @Autowired
     private PublishContentRepository publishContentRepository;
     @Autowired
-    private LongArticlesTextRepository longArticlesTextRepository;
+    private ArticleMapper articleMapper;
+    @Autowired
+    private PublishPlanRepository publishPlanRepository;
 
 
     @XxlJob("articleVideoAudit")
@@ -204,7 +211,7 @@ public class ArticleAuditService {
             // 暂时不做删除 先发送通知
             if (longArticleVideoAudit.getStatus().equals(PQVideoAuditResultEnum.REJECT.getStatus())) {
                 FeishuMessageSender.sendWebHookMessage(FeishuRobotIdEnum.ARTICLE_DELETE.getRobotId(),
-                        "视频审核不通过【"+sensitiveLevelEnum.getDescription()+"】\n" +
+                        "视频审核不通过【" + sensitiveLevelEnum.getDescription() + "】\n" +
                                 "traceId:" + longArticleVideoAudit.getTraceId() + "\n" +
                                 "视频id:" + longArticleVideoAudit.getVideoId() + "\n" +
                                 "管理后台地址:https://admin.piaoquantv.com/cms/post-detail/" + longArticleVideoAudit.getVideoId() + "/detail\n" +
@@ -540,4 +547,95 @@ public class ArticleAuditService {
         articleUnsafeTitleRepository.save(unsafeTitle);
     }
 
+    public Page<ArticleDeleteListVO> articleDeleteList(ArticleCategoryListParam param) {
+        int offset = (param.getPageNum() - 1) * param.getPageSize();
+        int count = articleMapper.articleDeleteListCount(param.getTitle());
+        List<ArticleDeleteListVO> list = articleMapper.articleDeleteList(param.getTitle(), offset, param.getPageSize());
+        buildArticleDeleteListVO(list);
+        Page<ArticleDeleteListVO> page = new Page<>(param.getPageNum(), param.getPageSize());
+        page.setTotalSize(count);
+        page.setObjs(list);
+        return page;
+    }
+
+    private void buildArticleDeleteListVO(List<ArticleDeleteListVO> list) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        List<PublishAccountTypeDTO> accountTypeList = aigcBaseMapper.getAccountTypeList();
+        Map<String, PublishAccountTypeDTO> accountTypeMap = accountTypeList.stream()
+                .collect(Collectors.toMap(PublishAccountTypeDTO::getGhId, Function.identity()));
+        List<String> ghIds = list.stream().map(ArticleDeleteListVO::getGhId).distinct().collect(Collectors.toList());
+        List<PublishAccount> publishAccountList = publishAccountRepository.getAllByGhIdIn(ghIds);
+        Map<String, PublishAccount> publishAccountMap = publishAccountList.stream().collect(Collectors.toMap(PublishAccount::getGhId, o -> o));
+        // 获取发布内容
+        List<PublishContentParam> publishContentParamList = list.stream().map(article -> {
+            PublishContentParam item = new PublishContentParam();
+            item.setTitle(article.getTitle());
+            PublishAccount account = publishAccountMap.get(article.getGhId());
+            if (Objects.nonNull(account)) {
+                item.setPublishAccountId(account.getId());
+                return item;
+            }
+            return null;
+        }).filter(Objects::nonNull).collect(Collectors.toList());
+        List<PublishContentDTO> publishContents = new ArrayList<>();
+        for (List<PublishContentParam> partitions : Lists.partition(publishContentParamList, 100)) {
+            publishContents.addAll(aigcBaseMapper.getPublishContentByTitle(partitions));
+        }
+        Map<String, Map<String, Map<Long, PublishContentDTO>>> publishContentMap = publishContents.stream()
+                .filter(o -> Objects.nonNull(o.getPublishTimestamp()))
+                .sorted(Comparator.comparingLong(PublishContentDTO::getPublishTimestamp))
+                .collect(Collectors.groupingBy(PublishContentDTO::getPublishAccountId,
+                        Collectors.groupingBy(PublishContentDTO::getTitle,
+                                Collectors.toMap(PublishContentDTO::getPublishTimestamp, o -> o,
+                                        (existing, replacement) -> replacement))));
+        List<String> publishContentIds = publishContents.stream().map(PublishContentDTO::getId).collect(Collectors.toList());
+        List<PublishGzhPushContentRelDTO> pushContentRelList = aigcBaseMapper.getPushContentRelByPublishContentIdIn(publishContentIds);
+        Map<String, String> publishPushIdMap = pushContentRelList.stream()
+                .collect(Collectors.toMap(PublishGzhPushContentRelDTO::getPublishContentId,
+                        PublishGzhPushContentRelDTO::getPushId,
+                        (o1, o2) -> o2));
+        List<String> pushIds = pushContentRelList.stream().map(PublishGzhPushContentRelDTO::getPushId).collect(Collectors.toList());
+        List<PublishGzhPushDTO> pushList = aigcBaseMapper.getPushByPushIdIn(pushIds);
+        Map<String, PublishGzhPushDTO> pushDTOMap = pushList.stream()
+                .collect(Collectors.toMap(PublishGzhPushDTO::getPushId, Function.identity()));
+        for (ArticleDeleteListVO item : list) {
+            PublishAccountTypeDTO accountTypeDTO = accountTypeMap.get(item.getGhId());
+            if (Objects.nonNull(accountTypeDTO)) {
+                item.setAccountSourceType(accountTypeDTO.getAccountSourceName());
+            }
+            PublishAccount account = publishAccountMap.get(item.getGhId());
+            if (Objects.isNull(account)) {
+                continue;
+            }
+            Map<String, Map<Long, PublishContentDTO>> titleMap = publishContentMap.get(account.getId());
+            if (Objects.isNull(titleMap)) {
+                continue;
+            }
+            Map<Long, PublishContentDTO> publishTimeContentMap = titleMap.get(item.getTitle());
+            if (Objects.isNull(publishTimeContentMap)) {
+                continue;
+            }
+            PublishContentDTO publishContent = null;
+            List<String> hisPublishTimeStrList = publishTimeContentMap.keySet().stream()
+                    .map(o -> DateUtils.timestampToYMDStr(o / 1000, "yyyyMMdd")).collect(Collectors.toList());
+            String publishTime = DateUtils.findNearestDate(hisPublishTimeStrList, item.getDateStr(), "yyyyMMdd");
+            for (Map.Entry<Long, PublishContentDTO> entry : publishTimeContentMap.entrySet()) {
+                String str = DateUtils.timestampToYMDStr(entry.getKey() / 1000, "yyyyMMdd");
+                if (publishTime.equals(str)) {
+                    publishContent = entry.getValue();
+                }
+            }
+            if (Objects.isNull(publishContent)) {
+                continue;
+            }
+            String pushId = publishPushIdMap.get(publishContent.getId());
+            PublishGzhPushDTO pushDTO = pushDTOMap.get(pushId);
+            if (Objects.isNull(pushDTO)) {
+                continue;
+            }
+            item.setPlanType(PushTypeEnum.from(pushDTO.getPushType()).getDescription());
+        }
+    }
 }

+ 6 - 3
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recommend/ArticleService.java

@@ -6,6 +6,7 @@ import com.tzld.longarticle.recommend.server.common.enums.StatusEnum;
 import com.tzld.longarticle.recommend.server.common.enums.aigc.PublishContentTypeEnum;
 import com.tzld.longarticle.recommend.server.common.enums.recommend.ArticlePoolPromotionSourceStatusEnum;
 import com.tzld.longarticle.recommend.server.mapper.aigc.AigcBaseMapper;
+import com.tzld.longarticle.recommend.server.mapper.crawler.ArticleMapper;
 import com.tzld.longarticle.recommend.server.mapper.crawler.CrawlerBaseMapper;
 import com.tzld.longarticle.recommend.server.mapper.longArticle.LongArticleBaseMapper;
 import com.tzld.longarticle.recommend.server.model.dto.CrawlerContent;
@@ -54,6 +55,8 @@ public class ArticleService {
     @Autowired
     CrawlerBaseMapper crawlerBaseMapper;
     @Autowired
+    ArticleMapper articleMapper;
+    @Autowired
     LongArticleBaseMapper longArticleBaseMapper;
     @Autowired
     ArticlePoolPromotionSourceRepository articlePoolPromotionSourceRepository;
@@ -78,7 +81,7 @@ public class ArticleService {
             minTimestamp = DateUtils.getTodayStart() - 86400 * 7;
         }
         while (true) {
-            List<Article> articleList = crawlerBaseMapper.getWaitingFindArticle(minTimestamp);
+            List<Article> articleList = articleMapper.getWaitingFindArticle(minTimestamp);
             if (CollectionUtils.isEmpty(articleList)) {
                 return;
             }
@@ -132,13 +135,13 @@ public class ArticleService {
             return;
         }
         // 更新 official_article_v2
-        crawlerBaseMapper.updateArticleAigcId(wxSn, publishContentId, channelContentId);
+        articleMapper.updateArticleAigcId(wxSn, publishContentId, channelContentId);
         // 查找记录根记录
         long start = System.currentTimeMillis();
         RootPublishContentVO result = getRootPublishContent(channelContentId, null, publishContentId, null, 0);
         log.info("syncAigcIdByWxSn getRootPublishContent finish cost:{}", System.currentTimeMillis() - start);
         // 更新source root publish_content_id
-        crawlerBaseMapper.updateArticleSourceRootId(wxSn, result.getSourcePublishContentId(), result.getRootPublishContentId(),
+        articleMapper.updateArticleSourceRootId(wxSn, result.getSourcePublishContentId(), result.getRootPublishContentId(),
                 result.getRootProduceContentId());
     }
 

+ 5 - 2
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recommend/recall/RecallService.java

@@ -8,6 +8,7 @@ import com.tzld.longarticle.recommend.server.common.ThreadPoolFactory;
 import com.tzld.longarticle.recommend.server.common.enums.StatusEnum;
 import com.tzld.longarticle.recommend.server.common.enums.aigc.PublishPlanInputSourceTypesEnum;
 import com.tzld.longarticle.recommend.server.common.enums.recommend.*;
+import com.tzld.longarticle.recommend.server.mapper.crawler.ArticleMapper;
 import com.tzld.longarticle.recommend.server.mapper.crawler.CrawlerBaseMapper;
 import com.tzld.longarticle.recommend.server.mapper.longArticle.LongArticleBaseMapper;
 import com.tzld.longarticle.recommend.server.model.dto.Content;
@@ -78,6 +79,8 @@ public class RecallService implements ApplicationContextAware {
     @Autowired
     CrawlerBaseMapper crawlerBaseMapper;
     @Autowired
+    ArticleMapper articleMapper;
+    @Autowired
     AccountCorrelationRepository accountCorrelationRepository;
     @Autowired
     ArticlePoolPromotionSourceRepository articlePoolPromotionSourceRepository;
@@ -361,7 +364,7 @@ public class RecallService implements ApplicationContextAware {
         List<Article> hisArticleList = new ArrayList<>();
         List<List<String>> titleMd5Partition = Lists.partition(new ArrayList<>(titleMd5List), 1000);
         for (List<String> titleMd5s : titleMd5Partition) {
-            hisArticleList.addAll(crawlerBaseMapper.getByTitleMd5InAndTypeEqualsAndStatusEquals(titleMd5s, type, 1));
+            hisArticleList.addAll(articleMapper.getByTitleMd5InAndTypeEqualsAndStatusEquals(titleMd5s, type, 1));
         }
         if (CollectionUtils.isEmpty(hisArticleList)) {
             return result;
@@ -379,7 +382,7 @@ public class RecallService implements ApplicationContextAware {
         // 获取历史已发布文章所属头条内容
         Set<String> ghIds = hisArticleList.stream().map(Article::getGhId).collect(Collectors.toSet());
         Set<String> appMsgIds = hisArticleList.stream().map(Article::getAppMsgId).collect(Collectors.toSet());
-        List<Article> firstIndexHisArticleList = crawlerBaseMapper.getByGhIdInAndAppMsgIdInAndItemIndexAndTypeEqualsAndStatusEquals(
+        List<Article> firstIndexHisArticleList = articleMapper.getByGhIdInAndAppMsgIdInAndItemIndexAndTypeEqualsAndStatusEquals(
                 ghIds, appMsgIds, 1, type, 1);
         Map<String, Map<String, Article>> firstIndexHisArticleMap = firstIndexHisArticleList.stream()
                 .collect(Collectors.groupingBy(Article::getGhId, Collectors.toMap(Article::getAppMsgId, o -> o)));

+ 8 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/web/recommend/ArticleAuditController.java

@@ -1,8 +1,11 @@
 package com.tzld.longarticle.recommend.server.web.recommend;
 
 import com.tzld.longarticle.recommend.server.common.response.CommonResponse;
+import com.tzld.longarticle.recommend.server.model.param.ArticleCategoryListParam;
 import com.tzld.longarticle.recommend.server.model.param.ArticleDangerFindDeleteParam;
+import com.tzld.longarticle.recommend.server.model.vo.ArticleDeleteListVO;
 import com.tzld.longarticle.recommend.server.service.recommend.ArticleAuditService;
+import com.tzld.longarticle.recommend.server.util.page.Page;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -32,6 +35,11 @@ public class ArticleAuditController {
         return CommonResponse.success(service.saveDeleteRecord(videoId));
     }
 
+    @PostMapping("/articleDeleteList")
+    public CommonResponse<Page<ArticleDeleteListVO>> articleDeleteList(@RequestBody ArticleCategoryListParam param) {
+        return CommonResponse.success(service.articleDeleteList(param));
+    }
+
     @PostMapping("/titleDangerFindDelete")
     public CommonResponse<Void> titleDangerFindDelete(@RequestBody ArticleDangerFindDeleteParam param) {
         service.titleDangerFindDelete(param);

+ 78 - 0
long-article-recommend-service/src/main/resources/mapper/crawler/ArticleMapper.xml

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzld.longarticle.recommend.server.mapper.crawler.ArticleMapper">
+
+
+    <update id="updateArticleAigcId">
+        update official_articles_v2
+        set publish_content_id = #{publishContentId},
+            channel_content_id = #{channelContentId}
+        where wx_sn = #{wxsn}
+    </update>
+
+    <update id="updateArticleSourceRootId">
+        update official_articles_v2
+        set source_publish_content_id = #{sourcePublishContentId},
+            root_publish_content_id = #{rootPublishContentId},
+            root_produce_content_id = #{rootProduceContentId}
+        where wx_sn = #{wxsn}
+    </update>
+
+    <select id="getWaitingFindArticle"
+            resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.Article">
+        select * from official_articles_v2 where publish_timestamp > #{timestamp} order by publish_timestamp limit 100
+    </select>
+
+    <select id="getByTitleMd5InAndTypeEqualsAndStatusEquals"
+            resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.Article">
+        select wx_sn, ghId, accountName, appMsgId, title, ItemIndex, publish_timestamp, show_view_count
+        from official_articles_v2
+        where title_md5 in
+        <foreach collection="titleMd5s" item="item" separator="," open="(" close=")">
+            #{item}
+        </foreach>
+        and Type = #{type} and status = #{status}
+    </select>
+
+    <select id="getByGhIdInAndAppMsgIdInAndItemIndexAndTypeEqualsAndStatusEquals"
+            resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.Article">
+        select ghId, appMsgId, show_view_count
+        from official_articles_v2
+        where ghId in
+        <foreach collection="ghIdList" item="item" separator="," open="(" close=")">
+            #{item}
+        </foreach>
+        and appMsgId in
+        <foreach collection="appMsgIdList" item="item" separator="," open="(" close=")">
+            #{item}
+        </foreach>
+        and itemIndex = #{itemIndex}
+        and Type = #{type}
+        and status = #{status}
+    </select>
+
+    <select id="articleDeleteListCount" resultType="java.lang.Integer">
+        select count(1)
+        from official_articles_v2
+        <where>
+            <if test="title != null and title != ''">
+                and title like concat('%', #{title}, '%')
+            </if>
+        </where>
+    </select>
+
+    <select id="articleDeleteList"
+            resultType="com.tzld.longarticle.recommend.server.model.vo.ArticleDeleteListVO">
+        select FROM_UNIXTIME(publish_timestamp, "%Y%m%d" ) as dateStr, ghId,
+               accountName, title, itemIndex as `index`, ContentUrl as link
+        from official_articles_v2
+        <where>
+            <if test="title != null and title != ''">
+                and title like concat('%', #{title}, '%')
+            </if>
+        </where>
+        order by publish_timestamp desc
+        limit #{offset}, #{pageSize}
+    </select>
+
+</mapper>

+ 0 - 46
long-article-recommend-service/src/main/resources/mapper/crawler/CrawlerBaseMapper.xml

@@ -67,36 +67,6 @@
         update account_avg_info_v3 set status = 0 where gh_id = #{ghId} and update_time != #{date}
     </update>
 
-    <update id="updateArticleAigcId">
-        update official_articles_v2
-        set publish_content_id = #{publishContentId},
-            channel_content_id = #{channelContentId}
-        where wx_sn = #{wxsn}
-    </update>
-    <update id="updateArticleSourceRootId">
-        update official_articles_v2
-        set source_publish_content_id = #{sourcePublishContentId},
-            root_publish_content_id = #{rootPublishContentId},
-            root_produce_content_id = #{rootProduceContentId}
-        where wx_sn = #{wxsn}
-    </update>
-
-    <select id="getWaitingFindArticle"
-            resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.Article">
-        select * from official_articles_v2 where publish_timestamp > #{timestamp} order by publish_timestamp limit 100
-    </select>
-
-    <select id="getByTitleMd5InAndTypeEqualsAndStatusEquals"
-            resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.Article">
-        select wx_sn, ghId, accountName, appMsgId, title, ItemIndex, publish_timestamp, show_view_count
-        from official_articles_v2
-        where title_md5 in
-        <foreach collection="titleMd5s" item="item" separator="," open="(" close=")">
-            #{item}
-        </foreach>
-        and Type = #{type} and status = #{status}
-    </select>
-
     <select id="getAllByWxSnIn"
             resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.ArticleDetailInfo">
         select wx_sn, recall_dt, first_level, fission_0
@@ -116,21 +86,5 @@
             #{item}
         </foreach>
     </select>
-    <select id="getByGhIdInAndAppMsgIdInAndItemIndexAndTypeEqualsAndStatusEquals"
-            resultType="com.tzld.longarticle.recommend.server.model.entity.crawler.Article">
-        select ghId, appMsgId, show_view_count
-        from official_articles_v2
-        where ghId in
-        <foreach collection="ghIdList" item="item" separator="," open="(" close=")">
-            #{item}
-        </foreach>
-        and appMsgId in
-        <foreach collection="appMsgIdList" item="item" separator="," open="(" close=")">
-            #{item}
-        </foreach>
-        and itemIndex = #{itemIndex}
-        and Type = #{type}
-        and status = #{status}
-    </select>
 
 </mapper>

+ 254 - 0
long-article-recommend-service/src/main/resources/static/internal/articleDelete.html

@@ -0,0 +1,254 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>违规文章删除</title>
+    <!-- 引入 Bootstrap 样式 -->
+    <link href="https://gcore.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
+    <script src="https://gcore.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
+</head>
+<style>
+    /* 限制内容显示为省略号 */
+    .ellipsis-container {
+        position: relative;
+        display: inline-block;
+        max-width: 500px;
+    }
+
+    .text-ellipsis {
+        display: inline-block;
+        max-width: 200px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+    }
+
+    /* 悬浮显示完整内容 */
+    .tooltip-content {
+        display: none; /* 初始隐藏 */
+        position: absolute;
+        left: 0;
+        top: 100%;
+        z-index: 10;
+        background-color: #fff;
+        border: 1px solid #ddd;
+        padding: 5px;
+        box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
+        white-space: normal;
+        max-width: 500px;
+        word-wrap: break-word;
+        color: #000; /* 防止文字颜色被继承 */
+    }
+
+    .ellipsis-container:hover .tooltip-content {
+        display: block; /* 悬停时显示完整内容 */
+    }
+</style>
+<body>
+<div class="container mt-5">
+    <!-- 查询部分 -->
+    <div class="card">
+        <div class="card-header bg-primary text-white">
+            <h5>查询数据</h5>
+        </div>
+        <div class="card-body">
+            <div class="row g-3 align-items-center">
+                <div class="col-md-2">
+                    <label for="titleInput" class="form-label">标题</label>
+                </div>
+                <div class="col-md-8">
+                    <input type="text" class="form-control" id="titleInput" placeholder="请输入标题">
+                </div>
+                <div class="col-md-2">
+                    <button class="btn btn-success w-100" onclick="queryData(1)">查询</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 数据展示表格 -->
+    <div class="card mt-4">
+        <div class="card-header bg-secondary text-white">
+            <h5>数据列表</h5>
+        </div>
+        <div class="table-responsive">
+            <table class="table table-bordered table-hover">
+                <thead class="table-light">
+                <tr>
+                    <th style="width: 10%; white-space: nowrap;">发布日期</th>
+                    <th style="width: 20%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">标题</th>
+                    <th style="width: 10%; white-space: nowrap;">账号名称</th>
+                    <th style="width: 17%; white-space: nowrap;">账号来源</th>
+                    <th style="width: 10%; white-space: nowrap;">操作计划类型</th>
+                    <th style="width: 5%; white-space: nowrap;">位置</th>
+                    <th style="width: 18%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">链接</th>
+                    <th style="width: 10%; white-space: nowrap;">操作</th>
+                </tr>
+                </thead>
+                <tbody id="dataTableBody">
+                <!-- 动态数据填充 -->
+                </tbody>
+            </table>
+
+            <!-- 分页控件 -->
+            <nav aria-label="Page navigation">
+                <ul class="pagination justify-content-center" id="pagination">
+                    <!-- 分页按钮将在这里生成 -->
+                </ul>
+            </nav>
+        </div>
+    </div>
+</div>
+
+<!-- JavaScript 脚本 -->
+<script>
+    let currentPage = 1; // 当前页码
+    const pageSize = 50; // 每页显示的数据条数
+
+    window.onload = function () {
+        queryData(currentPage); // 页面加载后自动执行查询,查询第一页数据
+    };
+
+    // 查询数据:调用后端接口,支持分页
+    function queryData(page) {
+        currentPage = page; // 更新当前页码
+        const title = document.getElementById('titleInput').value;
+
+        // 调用后端查询接口
+        fetch(`/articleAudit/articleDeleteList`, {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json',
+                'Access-Control-Allow-Origin': '*'
+            },
+            body: JSON.stringify({title: title, pageNum: currentPage, pageSize: pageSize})
+        })
+            .then(response => response.json())
+            .then(data => {
+                console.log('查询结果:', data);
+                populateTable(data.data.objs); // 渲染数据表格
+                totalPage = Math.ceil(data.data.totalSize / pageSize);
+                renderPagination(totalPage); // 渲染分页控件
+            })
+            .catch(error => {
+                console.error('查询失败:', error);
+                alert('查询失败,请检查接口连接!');
+            });
+    }
+
+    // 渲染数据到表格
+    function populateTable(data) {
+        const tableBody = document.getElementById('dataTableBody');
+        tableBody.innerHTML = ''; // 清空旧数据
+
+        data.forEach(item => {
+            const row = `
+                    <tr>
+                        <td>${item.dateStr}</td>
+                        <td>
+                            <div class="ellipsis-container">
+                                <span class="text-ellipsis">${item.title}</span>
+                                <div class="tooltip-content">${item.title}</div>
+                            </div>
+                        </td>
+                        <td>${item.accountName}</td>
+                        <td>${item.accountSourceType}</td>
+                        <td>${item.planType}</td>
+                        <td>${item.index}</td>
+                        <td>
+                            <div class="ellipsis-container">
+                                <a href="${item.link}" target="_blank" rel="noopener noreferrer" class="text-ellipsis">${item.link}</a>
+                                <div class="tooltip-content">${item.link}</div>
+                            </div>
+                        </td>
+                        <td>
+                            <button class="btn btn-primary btn-sm text-nowrap" onclick="submitData('${item.title}')">标记违规</button>
+                        </td>
+                    </tr>
+                `;
+            tableBody.insertAdjacentHTML('beforeend', row);
+        });
+    }
+
+    // 渲染分页控件
+    function renderPagination(totalPages) {
+        const pagination = document.getElementById('pagination');
+        pagination.innerHTML = ''; // 清空旧分页
+
+        const maxVisiblePages = 5; // 最多显示的页码按钮数量
+        let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
+        let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
+
+        // 上一页按钮
+        pagination.insertAdjacentHTML('beforeend', `
+        <li class="page-item ${currentPage === 1 ? 'disabled' : ''}">
+            <a class="page-link" href="#" onclick="queryData(${currentPage - 1})">上一页</a>
+        </li>
+    `);
+
+        // 显示前面的省略号(如果有的话)
+        if (startPage > 1) {
+            pagination.insertAdjacentHTML('beforeend', `
+            <li class="page-item">
+                <a class="page-link" href="#" onclick="queryData(1)">1</a>
+            </li>
+            <li class="page-item disabled">
+                <span class="page-link">...</span>
+            </li>
+        `);
+        }
+
+        // 数字页码按钮
+        for (let i = startPage; i <= endPage; i++) {
+            pagination.insertAdjacentHTML('beforeend', `
+            <li class="page-item ${currentPage === i ? 'active' : ''}">
+                <a class="page-link" href="#" onclick="queryData(${i})">${i}</a>
+            </li>
+        `);
+        }
+
+        // 显示后面的省略号(如果有的话)
+        if (endPage < totalPages) {
+            pagination.insertAdjacentHTML('beforeend', `
+            <li class="page-item disabled">
+                <span class="page-link">...</span>
+            </li>
+            <li class="page-item">
+                <a class="page-link" href="#" onclick="queryData(${totalPages})">${totalPages}</a>
+            </li>
+        `);
+        }
+
+        // 下一页按钮
+        pagination.insertAdjacentHTML('beforeend', `
+        <li class="page-item ${currentPage === totalPages ? 'disabled' : ''}">
+            <a class="page-link" href="#" onclick="queryData(${currentPage + 1})">下一页</a>
+        </li>
+    `);
+    }
+
+    // 提交删除:调用后端接口
+    function submitData(title) {
+        // 调用后端更新接口
+        fetch('/articleAudit/titleDangerFindDelete', { // 替换为实际接口
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json',
+                'Access-Control-Allow-Origin': '*'
+            },
+            body: JSON.stringify({title: title})
+        })
+            .then(response => response.json())
+            .then(data => {
+                console.log('删除结果:', data);
+                alert('删除成功!');
+            })
+            .catch(error => {
+                console.error('删除失败:', error);
+                alert('删除失败,请检查接口连接!');
+            });
+    }
+</script>
+</body>
+</html>