Ver Fonte

Merge remote-tracking branch 'origin/master'

ZHAOXIAN há 1 ano atrás
pai
commit
db0d355d1f
41 ficheiros alterados com 1808 adições e 36 exclusões
  1. 5 0
      job-bytedance/pom.xml
  2. 48 5
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/controller/BytedanceController.java
  3. 15 3
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/controller/FeishuController.java
  4. 16 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/entity/AdvertiserAccount.java
  5. 78 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/entity/ByteDanceFlowDetailsReportDaily.java
  6. 19 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/entity/UserLoginRecord.java
  7. 22 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/enums/AccountTypeEnum.java
  8. 21 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/ByteDanceFlowDetailsReportMapper.java
  9. 20 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/BytedanceMiniAppMapper.java
  10. 2 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/BytedanceProductReportMapper.java
  11. 20 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/BytedanceProductUpdateMapper.java
  12. 18 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/UserLoginRecordMapper.java
  13. 53 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/ByteDanceFlowDetailsReportMapper.xml
  14. 19 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/BytedanceMiniAppMapper.xml
  15. 5 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/BytedanceProductReportMapper.xml
  16. 63 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/BytedanceProductUpdateMapper.xml
  17. 14 12
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/ReportsAdPushMapper.xml
  18. 22 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/UserLoginRecordMapper.xml
  19. 17 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IByteDanceFlowDetailsReportService.java
  20. 11 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IBytedanceMiniAppService.java
  21. 2 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IBytedanceProductReportService.java
  22. 8 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IBytedanceProductUpdateService.java
  23. 5 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IDateReportsPushService.java
  24. 16 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IUserLoginRecordService.java
  25. 15 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BindAppErrorWarnServiceImpl.java
  26. 160 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/ByteDanceFlowDetailsReportServiceImpl.java
  27. 153 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceMiniAppServiceImpl.java
  28. 6 1
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceProductReportServiceImpl.java
  29. 407 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceProductUpdateServiceImpl.java
  30. 54 9
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/DateReportsPushServiceImpl.java
  31. 50 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/UserLoginRecordServiceImpl.java
  32. 1 1
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/utils/HttpUtils.java
  33. 55 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/ByteDanceFlowDetailsReportJob.java
  34. 29 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedanceMiniAppJob.java
  35. 31 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedanceProductUploadJob.java
  36. 1 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedancePromoterReportJob.java
  37. 36 4
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedanceReportRetryJob.java
  38. 12 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/FeishuPushJob.java
  39. 62 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/utils/FeishuRobotUtil.java
  40. 206 0
      job-bytedance/src/main/java/cn/com/ctop/job/bytedance/utils/Redis2Config.java
  41. 11 1
      job-bytedance/src/main/resources/application.yml

+ 5 - 0
job-bytedance/pom.xml

@@ -178,6 +178,11 @@
             <artifactId>spring-boot-starter-data-redis</artifactId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>2.9.0</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-pool2</artifactId>
             <artifactId>commons-pool2</artifactId>
             <version>2.6.2</version>
             <version>2.6.2</version>

+ 48 - 5
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/controller/BytedanceController.java

@@ -1,9 +1,9 @@
 package cn.com.ctop.job.bytedance.controller;
 package cn.com.ctop.job.bytedance.controller;
 
 
-import cn.com.ctop.job.bytedance.data.service.IAdminAdvertiserListService;
-import cn.com.ctop.job.bytedance.data.service.IBytedanceAccountReportService;
-import cn.com.ctop.job.bytedance.data.service.IBytedanceProductReportService;
-import cn.com.ctop.job.bytedance.data.service.IBytedancePromoterReportService;
+import cn.com.ctop.job.bytedance.data.service.*;
+import cn.com.ctop.job.bytedance.data.entity.AdvertiserAccount;
+import cn.com.ctop.job.bytedance.data.enums.AccountTypeEnum;
+import cn.com.ctop.job.bytedance.data.service.*;
 import cn.com.ctop.job.bytedance.data.utils.Check;
 import cn.com.ctop.job.bytedance.data.utils.Check;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -38,16 +38,22 @@ public class BytedanceController {
     private IAdminAdvertiserListService adminAdvertiserListService;
     private IAdminAdvertiserListService adminAdvertiserListService;
 
 
     @Autowired
     @Autowired
+    private IByteDanceFlowDetailsReportService byteDanceFlowDetailsReportService;
+
+    @Autowired
     private IBytedanceAccountReportService accountReportService;
     private IBytedanceAccountReportService accountReportService;
 
 
     @Autowired
     @Autowired
     private IBytedancePromoterReportService promoterReportService;
     private IBytedancePromoterReportService promoterReportService;
 
 
+    @Autowired
+    private IBytedanceMiniAppService bytedanceMiniAppService;
+
 
 
     @GetMapping("/accountReport")
     @GetMapping("/accountReport")
     public void getChannel(String param) {
     public void getChannel(String param) {
 
 
-        List<JSONObject>  infos = adminAdvertiserListService.getAdvertiserInfos();
+        List<JSONObject> infos = adminAdvertiserListService.getAdvertiserInfos();
         System.err.println(infos);
         System.err.println(infos);
         adminAdvertiserListService.batchUpdateAdvertiserName(infos);
         adminAdvertiserListService.batchUpdateAdvertiserName(infos);
 
 
@@ -85,13 +91,50 @@ public class BytedanceController {
                 @Override
                 @Override
                 public void run() {
                 public void run() {
                     if (!Check.isNull(accessToken)) {
                     if (!Check.isNull(accessToken)) {
+                        productReportService.deleteBytedanceProductDailyReport(advertiserId, startDate, endDate);
                         productReportService.getBytedanceProductDailyReport(adverId, accessToken, startDate, endDate, 1, null, 1, null);
                         productReportService.getBytedanceProductDailyReport(adverId, accessToken, startDate, endDate, 1, null, 1, null);
                     }
                     }
                 }
                 }
             });
             });
         }
         }
+    }
+
+    @GetMapping("/maEcpm")
+    public void maEcpm(@RequestParam(required = false) String appId, String startDate, String endDate) {
+        if (Check.isNull(startDate) || Check.isNull(endDate)) {
+            return;
+        }
+        List<String> iaaAppIds = bytedanceMiniAppService.getIaaAppIds();
+        for (String iaaAppId : iaaAppIds) {
+            if (appId != null && !appId.equals(iaaAppId)) {
+                continue;
+            }
+            bytedanceMiniAppService.getMaEcpm(startDate, endDate, appId, 1, null, null);
+        }
+    }
+
+    @GetMapping("/flowDetailsReport")
+    public void flowDetailsReport(@RequestParam(required = false) Long advertiserId, String accessToken, String startDate, String endDate) {
+
+        byteDanceFlowDetailsReportService.getBytedanceFlowDetailsDailyReport(advertiserId, accessToken, AccountTypeEnum.AD.getValue(), startDate, endDate, 1, null);
 
 
     }
     }
 
 
+    @GetMapping("/generateFlowDetailsReport")
+    public void generateFlowDetailsReport(String startDate, String endDate) {
+        List<AdvertiserAccount> adAccount = byteDanceFlowDetailsReportService.getAdAccount();
+        adAccount.forEach(advertiserAccount -> {
+            dailyRetrExecutorService.submit(new Runnable() {
+
+                @Override
+                public void run() {
+                    if (!Check.isNull(advertiserAccount.getAccessToken())) {
+                        byteDanceFlowDetailsReportService.getBytedanceFlowDetailsDailyReport(advertiserAccount.getAdvertiserId(), advertiserAccount.getAccessToken(), AccountTypeEnum.AD.getValue(), startDate, endDate, 1, null);
+                    }
+                }
+            });
+
+        });
+    }
 
 
 }
 }

+ 15 - 3
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/controller/FeishuController.java

@@ -26,16 +26,28 @@ public class FeishuController {
     IUnbindWarnPushService unbindWarnPushService;
     IUnbindWarnPushService unbindWarnPushService;
     @Autowired
     @Autowired
     IBindAppErrorWarnService bindAppErrorWarnService;
     IBindAppErrorWarnService bindAppErrorWarnService;
+    @Autowired
+    IBytedanceProductUpdateService bytedanceProductUpdateService;
+
+    @Autowired
+    IUserLoginRecordService userLoginRecordService;
     @GetMapping("/test")
     @GetMapping("/test")
-    public void test(){
-        bindAppErrorWarnService.send();
-        System.out.println("---feishu test 收到---");
+    public void test() throws Exception {
+//        bytedanceProductUpdateService.initNew();
+        bytedanceProductUpdateService.run();
+
     }
     }
 
 
+
     @PostMapping("/sendUnbind")
     @PostMapping("/sendUnbind")
     public void sendUnbind(@RequestBody JSONObject obj){
     public void sendUnbind(@RequestBody JSONObject obj){
         JSONArray array = obj.getJSONArray("advertiserIds");
         JSONArray array = obj.getJSONArray("advertiserIds");
         List<String> list = array.toJavaList(String.class);
         List<String> list = array.toJavaList(String.class);
         unbindWarnPushService.send(list, false);
         unbindWarnPushService.send(list, false);
     }
     }
+
+    @PostMapping("/sendLoginTimes")
+    public String sendLoginTimes(){
+      return userLoginRecordService.queryUserLoginRecord();
+    }
 }
 }

+ 16 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/entity/AdvertiserAccount.java

@@ -0,0 +1,16 @@
+package cn.com.ctop.job.bytedance.data.entity;
+
+import lombok.Data;
+
+/**
+ * @author lining
+ * @ClassName AdvertiserAccount
+ * @description: TODO
+ * @date 2025年04月27日
+ * @version: 1.0
+ */
+@Data
+public class AdvertiserAccount {
+    private Long advertiserId;
+    private String accessToken;
+}

+ 78 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/entity/ByteDanceFlowDetailsReportDaily.java

@@ -0,0 +1,78 @@
+package cn.com.ctop.job.bytedance.data.entity;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author lining
+ * @ClassName ByteDanceFlowDetailsReport
+ * @description: TODO
+ * @date 2025年04月16日
+ * @version: 1.0
+ */
+@Data
+@Builder
+public class ByteDanceFlowDetailsReportDaily {
+    /**
+     * 广告主ID
+     */
+    private Long advertiserId;
+    /**
+     * 数据起始时间
+     */
+    private Integer statTimeDay;
+
+    /**
+     * 日终结余(单位元)
+     */
+    private BigDecimal balance;
+    /**
+     * 日终赠款结余(单位元)。包括冻结和实结订单pending部分
+     */
+    private BigDecimal grantBalance;
+    /**
+     * 日终非赠款结余(单位元)。包括冻结和实结订单pending部分
+     */
+    private BigDecimal nonGrantBalance;
+    /**
+     * 现金支出(单位元)
+     */
+    private BigDecimal cashCost;
+    /**
+     * 总支出(单位元)
+     */
+    private BigDecimal cost;
+
+    /**
+     * 冻结(单位元)
+     */
+    private BigDecimal frozen;
+    /**
+     * 总存入(单位元)
+     */
+    private BigDecimal income;
+    /**
+     * 赠款支出(单位元)
+     */
+    private BigDecimal rewardCost;
+
+    /**
+     * 共享返货支出(单位元)
+     */
+    private BigDecimal sharedWalletCost;
+    /**
+     * 账户消耗的子钱包的共享余额(单位元)
+     */
+    private BigDecimal companyWalletCost;
+    /**
+     * 总转入(单位元)
+     */
+    private BigDecimal transferIn;
+
+    /**
+     * 总转出(单位元)
+     */
+    private BigDecimal transferOut;
+}

+ 19 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/entity/UserLoginRecord.java

@@ -0,0 +1,19 @@
+package cn.com.ctop.job.bytedance.data.entity;
+
+import lombok.Data;
+
+/**
+ * @author lining
+ * @ClassName UserLoginRecord
+ * @description: TODO
+ * @date 2025年05月09日
+ * @version: 1.0
+ */
+@Data
+public class UserLoginRecord {
+    private Long uid;
+
+    private String openId;
+
+    private Long loginTimes;
+}

+ 22 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/enums/AccountTypeEnum.java

@@ -0,0 +1,22 @@
+package cn.com.ctop.job.bytedance.data.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lining
+ * @ClassName FlowTransactionTypeEnum
+ * @description: TODO
+ * @date 2025年04月21日
+ * @version: 1.0
+ */
+@AllArgsConstructor
+@Getter
+public enum AccountTypeEnum {
+    AD("AD"),
+    LOCAL("LOCAL"),
+    STAR("STAR")
+    ;
+
+    private String value;
+}

+ 21 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/ByteDanceFlowDetailsReportMapper.java

@@ -0,0 +1,21 @@
+package cn.com.ctop.job.bytedance.data.mapper;
+
+import cn.com.ctop.job.bytedance.data.entity.AdvertiserAccount;
+import cn.com.ctop.job.bytedance.data.entity.ByteDanceFlowDetailsReportDaily;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author lining
+ * @ClassName ByteDanceFlowDetailsReportMapper
+ * @description: TODO
+ * @date 2025年04月17日
+ * @version: 1.0
+ */
+public interface ByteDanceFlowDetailsReportMapper {
+
+    List<AdvertiserAccount> getAdAccount();
+
+    void replaceDanceFlowDetailsReportDailies(@Param("list") List<ByteDanceFlowDetailsReportDaily> dailyList);
+}

+ 20 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/BytedanceMiniAppMapper.java

@@ -0,0 +1,20 @@
+package cn.com.ctop.job.bytedance.data.mapper;
+
+import cn.com.ctop.job.bytedance.data.entity.BytedanceAdvertiserReportDaily;
+import cn.com.ctop.job.bytedance.data.entity.BytedanceAdvertiserReportHour;
+import cn.com.ctop.job.bytedance.data.entity.BytedanceErrorLog;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface BytedanceMiniAppMapper {
+    List<String> getEcpmKeys(@Param("startDate") Integer startDate,
+                             @Param("endDate") Integer endDate,
+                             @Param("startTime") String startTime,
+                             @Param("endTime") String endTime);
+
+    List<String> getIaaAppIds();
+
+    List<JSONObject> getMaEcpmRetryJob();
+}

+ 2 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/BytedanceProductReportMapper.java

@@ -11,4 +11,6 @@ public interface BytedanceProductReportMapper {
     List<JSONObject> queryCostAccount(@Param("advertiserId") Long advertiserId, @Param("startDate") String startDate, @Param("endDate") String endDate);
     List<JSONObject> queryCostAccount(@Param("advertiserId") Long advertiserId, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
 
     void replaceProductReportDailies(List<BytedanceProductReportDaily> reports);
     void replaceProductReportDailies(List<BytedanceProductReportDaily> reports);
+
+    void deleteProductReportDailies(@Param("advertiserId") Long advertiserId,@Param("startDate") Integer startDate,@Param("endDate")  Integer endDate);
 }
 }

+ 20 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/BytedanceProductUpdateMapper.java

@@ -0,0 +1,20 @@
+package cn.com.ctop.job.bytedance.data.mapper;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface BytedanceProductUpdateMapper {
+
+    List<JSONObject> getIAPPlatformList();
+    List<JSONObject> getIAPVideoList();
+    List<JSONObject> getIAPProductTypeEnums();
+
+    List<JSONObject> getIAAPlatformList();
+    List<JSONObject> getIAAVideoList();
+    List<JSONObject> getIAAProductTypeEnums();
+
+    int updateInstanceId(@Param("advertiserId") String advertiserId, @Param("instanceId") String instanceId);
+
+}

+ 18 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/UserLoginRecordMapper.java

@@ -0,0 +1,18 @@
+package cn.com.ctop.job.bytedance.data.mapper;
+
+import cn.com.ctop.job.bytedance.data.entity.UserLoginRecord;
+
+import java.util.List;
+
+/**
+ * @author lining
+ * @ClassName UserLoginRecordMapper
+ * @description: TODO
+ * @date 2025年05月09日
+ * @version: 1.0
+ */
+public interface UserLoginRecordMapper {
+
+    List<UserLoginRecord> queryUserLoginRecord();
+
+}

+ 53 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/ByteDanceFlowDetailsReportMapper.xml

@@ -0,0 +1,53 @@
+<?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="cn.com.ctop.job.bytedance.data.mapper.ByteDanceFlowDetailsReportMapper">
+
+    <select id="getAdAccount" resultType="cn.com.ctop.job.bytedance.data.entity.AdvertiserAccount">
+        select
+            tb1.advertiser_id as advertiserId,
+            tb2.access_token as accessToken
+        from
+            deepthink.bytedance_advertiser_list tb1
+                left join deepthink.bytedance_auth_list tb2 on
+                tb1.admin_advertiser_id = tb2.admin_advertiser_id
+    </select>
+
+    <insert id="replaceDanceFlowDetailsReportDailies">
+        replace into bytedance_flow_details_report_daily (
+            advertiser_id,
+            stat_time_day,
+        balance,
+        grant_balance,
+        non_grant_balance,
+        cash_cost,
+        cost,
+        frozen,
+        income,
+        reward_cost,
+        shared_wallet_cost,
+        company_wallet_cost,
+        transfer_in,
+        transfer_out
+        )
+        values
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.advertiserId},
+            #{item.statTimeDay},
+            #{item.balance},
+            #{item.grantBalance},
+            #{item.nonGrantBalance},
+            #{item.cashCost},
+            #{item.cost},
+            #{item.frozen},
+            #{item.income},
+            #{item.rewardCost},
+            #{item.sharedWalletCost},
+            #{item.companyWalletCost},
+            #{item.transferIn},
+            #{item.transferOut}
+            )
+        </foreach>
+    </insert>
+</mapper>
+

+ 19 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/BytedanceMiniAppMapper.xml

@@ -0,0 +1,19 @@
+<?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="cn.com.ctop.job.bytedance.data.mapper.BytedanceMiniAppMapper">
+    <select id="getEcpmKeys" resultType="java.lang.String">
+        SELECT concat(event_timestamp,open_id,cost) as ecpm_keys from media_api.bytedance_webhook_ma_ecpm
+        where stat_date >=  #{startDate} and stat_date &lt;= #{endDate}
+          and event_time >= #{startTime} and event_time &lt;= #{endTime}
+    </select>
+
+    <select id="getIaaAppIds" resultType="java.lang.String">
+        select app_id from deepthink.mini_app_info where business_method in('IAA','MIX') and app_id like 'tt%'
+    </select>
+
+    <select id="getMaEcpmRetryJob" resultType="com.alibaba.fastjson.JSONObject">
+        SELECT is_send AS 'isSend', id AS 'id', start_date AS 'startDate', end_date AS 'endDate', data_dimension AS 'dataDimension', data_type AS 'dataType'
+        FROM media_api.bytedance_error_log where   data_dimension like 'ma_ecpm:%'
+    </select>
+
+</mapper>

+ 5 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/BytedanceProductReportMapper.xml

@@ -57,4 +57,9 @@
         </foreach>
         </foreach>
     </insert>
     </insert>
 
 
+    <delete id="deleteProductReportDailies">
+        DELETE FROM media_api.bytedance_product_report_daily
+        WHERE advertiser_id = ${advertiserId} and stat_time_day >= ${startDate} and stat_time_day &lt;= ${endDate}
+    </delete>
+
 </mapper>
 </mapper>

+ 63 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/BytedanceProductUpdateMapper.xml

@@ -0,0 +1,63 @@
+<?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="cn.com.ctop.job.bytedance.data.mapper.BytedanceProductUpdateMapper">
+    <update id="updateInstanceId">
+        update deepthink.bytedance_product_main_advertiser
+        set mini_instance_id = #{instanceId}
+        where advertiser_id = #{advertiserId}
+    </update>
+
+
+    <select id="getIAPPlatformList" resultType="com.alibaba.fastjson.JSONObject">
+        select t1.*, t3.access_token
+        FROM deepthink.bytedance_product_main_advertiser t1
+        left join deepthink.bytedance_advertiser_list t2 on t1.advertiser_id=t2.advertiser_id
+        left join deepthink.bytedance_auth_list t3 on t2.admin_advertiser_id=t3.admin_advertiser_id
+        where t1.`type`=2 and t1.`_status`=0
+    </select>
+    <select id="getIAAPlatformList" resultType="com.alibaba.fastjson.JSONObject">
+        select t1.*, t3.access_token
+        FROM deepthink.bytedance_product_main_advertiser t1
+        left join deepthink.bytedance_advertiser_list t2 on t1.advertiser_id=t2.advertiser_id
+        left join deepthink.bytedance_auth_list t3 on t2.admin_advertiser_id=t3.admin_advertiser_id
+        where t1.`type`=1 and t1.`_status`=0
+    </select>
+    <select id="getIAPVideoList" resultType="com.alibaba.fastjson.JSONObject">
+        select third.album_id, detail.platform_config, video.id as video_id, detail.id as video_detail_id, video.name as name, video.cover_img as img,ifnull(category.name, '其他') as 'theme',
+        '天津星链视界信息技术有限公司' as copyright_owner, '其他' as playlet_gender, video.update_sort as playlet_num, '2' as playlet_duration,
+        payinfo.sort as start_pay_playlet, '5' as membership_types, '1' as has_paid_content, '2' as has_motivation_types,
+        payinfo.maxpay as max_charge, payinfo.minpay as min_charge, maxpay as recommended_charge, maxpay as price,
+        2 as has_paid_content, 1 as has_motivation_content
+        FROM (select * from thirtpart.ly_third_videos where submission_status=2
+        and video_id in (select video_id from thirtpart.ly_video_audit_records where audit_status=2)
+        ) third
+        LEFT JOIN (select * from thirtpart.ly_video_details where platform_config is not null group by video_id) detail ON third.video_id = detail.video_id
+        LEFT JOIN (select * from thirtpart.ly_videos where play_platform like '%2%') video ON third.video_id = video.id and third.platform=2
+        LEFT JOIN thirtpart.ly_video_category category ON video.category_id = category.id
+        LEFT JOIN (select video_id, min(sort) as sort, max(pay_amount/100.0) as maxpay, min(pay_amount/100.0) as minpay from thirtpart.ly_video_details where is_pay=1 group by video_id) payinfo ON video.id = payinfo.video_id
+        where video.is_free = 1
+    </select>
+    <select id="getIAAVideoList" resultType="com.alibaba.fastjson.JSONObject">
+        select third.album_id, detail.platform_config, video.id as video_id, detail.id as video_detail_id, video.name as name, video.cover_img as img,ifnull(category.name, '其他') as 'theme',
+        '天津星链视界信息技术有限公司' as copyright_owner, '其他' as playlet_gender, video.update_sort as playlet_num, '2' as playlet_duration,
+        '5' as membership_types, '1' as has_paid_content, '2' as has_motivation_types,payinfo.sort as starting_unlock_episode
+        FROM (select * from thirtpart.ly_third_videos where submission_status=2
+        and video_id in (select video_id from thirtpart.ly_video_audit_records where audit_status=2)
+        ) third
+        LEFT JOIN (select * from thirtpart.ly_video_details where platform_config is not null group by video_id) detail ON third.video_id = detail.video_id
+        LEFT JOIN (select * from thirtpart.ly_videos where play_platform like '%2%') video ON third.video_id = video.id and third.platform=2
+        LEFT JOIN thirtpart.ly_video_category category ON video.category_id = category.id
+        LEFT JOIN (select video_id, max(sort) as sort from thirtpart.ly_video_details where is_pay=0 group by video_id) payinfo ON video.id = payinfo.video_id
+        where video.is_free = 0
+    </select>
+    <select id="getIAPProductTypeEnums" resultType="com.alibaba.fastjson.JSONObject">
+        select first_type_name, first_type_id, second_type_name, second_type_id, third_type_name, third_type_id
+        from deepthink.bytedance_product_group_types
+        where `type`=2
+    </select>
+    <select id="getIAAProductTypeEnums" resultType="com.alibaba.fastjson.JSONObject">
+        select first_type_name, first_type_id, second_type_name, second_type_id, third_type_name, third_type_id
+        from deepthink.bytedance_product_group_types
+        where `type`=1
+    </select>
+</mapper>

+ 14 - 12
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/ReportsAdPushMapper.xml

@@ -41,15 +41,18 @@
         ) tb2
         ) tb2
     </select>
     </select>
     <select id="tmpTopMovie" resultType="java.util.Map">
     <select id="tmpTopMovie" resultType="java.util.Map">
-        select ot1.*, ot2.cost_amount, ot2.real_cost_amount,
+        select case ot1.movie_source when 2 then movie_name else concat('欢瑞自制-', movie_name) end as movie_name,
+        ot1.rk, ot1.share_end_amount, ot1.end_amount,  ot2.cost_amount, ot2.real_cost_amount,
         concat(round(if(ifnull(cost_amount,0)=0, 0, end_amount/cost_amount*100), 2), '%') AS water_roi,
         concat(round(if(ifnull(cost_amount,0)=0, 0, end_amount/cost_amount*100), 2), '%') AS water_roi,
-        concat(round(if(ifnull(real_cost_amount,0)=0, 0, end_amount/real_cost_amount*100), 2), '%') AS real_roi
+        concat(round(if(ifnull(real_cost_amount,0)=0, 0, share_end_amount/real_cost_amount*100), 2), '%') AS real_roi
         FROM
         FROM
-        (select ifnull(COALESCE (tb2.movie_name, tb3.movie_name), tb1.movie_id) as movie_name,
-        rank() over (order by sum(end_amount) desc) as rk, sum(end_amount) as end_amount
+        (select ifnull(tb2.movie_name, tb1.movie_id) as movie_name, movie_source,
+        rank() over (order by sum(end_amount) desc) as rk, sum(end_amount) as end_amount, sum(share_end_amount) as share_end_amount
         from
         from
         (select
         (select
-        ifnull(sum(share_iaa_amount), 0) + ifnull(sum(share_pay_amount), 0) as end_amount, movie_id
+        ifnull(sum(iaa_amount), 0) + ifnull(sum(pay_amount), 0) as end_amount,
+        ifnull(sum(share_iaa_amount), 0) + ifnull(sum(share_pay_amount), 0) as share_end_amount,
+        movie_id
         from
         from
         application.user_data_report_daily udrd
         application.user_data_report_daily udrd
         where stat_date = ${date}
         where stat_date = ${date}
@@ -58,13 +61,12 @@
         order by end_amount desc
         order by end_amount desc
         ) tb1
         ) tb1
         left join
         left join
-        (select distinct movie_id, movie_name from deepthink.channel_changdunovel_info cci) tb2 on tb1.movie_id = tb2.movie_id
-        left JOIN
-        (select id, movie_name from hr_playlet.m_movie mm) tb3 on tb1.movie_id = tb3.id
+        (select distinct moive_id, movie_name, movie_source from deepthink.all_moive union
+        select series_id, ifnull(replace(series_name,REGEXP_SUBSTR(series_name, '[0-9]+$'),''),series_name),4 from media_api.kuaishou_drama_series_info) tb2 on tb1.movie_id=tb2.moive_id
         group by movie_name order by rk limit 10) ot1
         group by movie_name order by rk limit 10) ot1
         left join
         left join
-        (select product_name, round(ifnull(sum(cost_amount),0),2) as cost_amount, sum(real_cost_amount) as real_cost_amount
-        from application.media_product_report_daily where stat_date=${date} group by product_name
+        (select ifnull(replace(product_name,REGEXP_SUBSTR(product_name, '[0-9]+$'),''),product_name) as product_name, round(ifnull(sum(cost_amount),0),2) as cost_amount, sum(real_cost_amount) as real_cost_amount
+        from application.media_product_report_daily where stat_date=${date} group by ifnull(replace(product_name,REGEXP_SUBSTR(product_name, '[0-9]+$'),''),product_name)
         ) ot2 on ot1.movie_name=ot2.product_name
         ) ot2 on ot1.movie_name=ot2.product_name
         order by rk
         order by rk
     </select>
     </select>
@@ -221,9 +223,9 @@
         group by advertiser_id having count(distinct ma_appid)>1)
         group by advertiser_id having count(distinct ma_appid)>1)
         ) tb2
         ) tb2
         on tb1.advertiser_id = tb2.advertiser_id
         on tb1.advertiser_id = tb2.advertiser_id
-        left join (select distinct app_id, app_name from hr_playlet.m_mini_app_info) tb3
+        left join (select distinct app_id, app_name from deepthink.mini_app_info) tb3
         on tb1.ma_appid = tb3.app_id
         on tb1.ma_appid = tb3.app_id
-        left join (select distinct app_id, app_name from hr_playlet.m_mini_app_info) tb4
+        left join (select distinct app_id, app_name from deepthink.mini_app_info) tb4
         on tb2.ma_appid = tb4.app_id
         on tb2.ma_appid = tb4.app_id
         left join (select user_id, phonenumber, nick_name from deepthink.sys_user) tb5
         left join (select user_id, phonenumber, nick_name from deepthink.sys_user) tb5
         on tb2.user_id=tb5.user_id
         on tb2.user_id=tb5.user_id

+ 22 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/mapper/xml/UserLoginRecordMapper.xml

@@ -0,0 +1,22 @@
+<?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="cn.com.ctop.job.bytedance.data.mapper.UserLoginRecordMapper">
+
+    <select id="queryUserLoginRecord" resultType="cn.com.ctop.job.bytedance.data.entity.UserLoginRecord">
+        SELECT
+            lulr.uid,
+            lu.open_id,
+            COUNT(1) AS login_times
+        FROM
+            thirtpart.ly_user_login_record lulr
+                LEFT JOIN thirtpart.ly_user lu ON lulr.uid = lu.id
+                LEFT JOIN thirtpart.ly_user_black_list b ON lulr.uid = b.uid
+        WHERE
+            lulr.created_at >= UNIX_TIMESTAMP(CURDATE())
+          AND b.uid IS NULL
+        GROUP BY lulr.uid
+        HAVING login_times > 100
+        ORDER BY login_times DESC
+    </select>
+
+</mapper>

+ 17 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IByteDanceFlowDetailsReportService.java

@@ -0,0 +1,17 @@
+package cn.com.ctop.job.bytedance.data.service;
+
+import cn.com.ctop.job.bytedance.data.entity.AdvertiserAccount;
+
+import java.util.List;
+
+/**
+ * @author lining
+ * @ClassName IByteDanceFlowDetailsReportService
+ * @description: TODO
+ * @date 2025年04月16日
+ * @version: 1.0
+ */
+public interface IByteDanceFlowDetailsReportService {
+    List<AdvertiserAccount> getAdAccount();
+    void getBytedanceFlowDetailsDailyReport(Long advertiserId, String accessToken, String transactionType, String startDate, String endDate, Integer page, Long errorId);
+}

+ 11 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IBytedanceMiniAppService.java

@@ -0,0 +1,11 @@
+package cn.com.ctop.job.bytedance.data.service;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.List;
+
+public interface IBytedanceMiniAppService {
+    List<String> getIaaAppIds();
+    void getMaEcpm(String startDt, String endDt, String appId, Integer isLog, Long errId, Integer isSend);
+    List<JSONObject> getMaEcpmRetryJob();
+}

+ 2 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IBytedanceProductReportService.java

@@ -9,4 +9,6 @@ public interface IBytedanceProductReportService {
                                         Long errorId, Integer isLog, Integer isSend);
                                         Long errorId, Integer isLog, Integer isSend);
 
 
     List<JSONObject> getCostAccount(Long advertiserId, String startDate, String endDate);
     List<JSONObject> getCostAccount(Long advertiserId, String startDate, String endDate);
+
+    void deleteBytedanceProductDailyReport(Long advertiserId, String startDate, String endDate);
 }
 }

+ 8 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IBytedanceProductUpdateService.java

@@ -0,0 +1,8 @@
+package cn.com.ctop.job.bytedance.data.service;
+
+public interface IBytedanceProductUpdateService {
+
+    void run() throws Exception;
+
+    void initNew();
+}

+ 5 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IDateReportsPushService.java

@@ -2,4 +2,9 @@ package cn.com.ctop.job.bytedance.data.service;
 
 
 public interface IDateReportsPushService {
 public interface IDateReportsPushService {
     void send();
     void send();
+
+    /**
+     * 零点15执行的 比上一天多了个描述
+     */
+    void preSend();
 }
 }

+ 16 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/IUserLoginRecordService.java

@@ -0,0 +1,16 @@
+package cn.com.ctop.job.bytedance.data.service;
+
+import cn.com.ctop.job.bytedance.data.entity.UserLoginRecord;
+
+import java.util.List;
+
+/**
+ * @author lining
+ * @ClassName IUserLoginRecord
+ * @description: TODO
+ * @date 2025年05月09日
+ * @version: 1.0
+ */
+public interface IUserLoginRecordService {
+    String queryUserLoginRecord();
+}

+ 15 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BindAppErrorWarnServiceImpl.java

@@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
@@ -46,6 +47,20 @@ public class BindAppErrorWarnServiceImpl implements IBindAppErrorWarnService {
         Long last30DayLong = Long.parseLong(last30Day.substring(0, 10).replaceAll("-", ""));
         Long last30DayLong = Long.parseLong(last30Day.substring(0, 10).replaceAll("-", ""));
 
 
         List<Map<String, String>> bindAppErrorWarnList = reportsPushMapper.bindAppErrorData(last30DayLong);
         List<Map<String, String>> bindAppErrorWarnList = reportsPushMapper.bindAppErrorData(last30DayLong);
+
+        List<String> excludeAdvertiserIds = Arrays.asList(
+                "1828195222746121",
+                "1828195223251978",
+                "1827747808620748",
+                "1828195223976330",
+                "1823380338347136",
+                "1823380339959123",
+                "1823380339196992",
+                "1827747810800964",
+                "1829811636122179"
+        );
+        bindAppErrorWarnList.removeIf(i -> excludeAdvertiserIds.contains(String.valueOf(i.get("advertiser_id"))));
+
         if (Check.isNull(bindAppErrorWarnList)){
         if (Check.isNull(bindAppErrorWarnList)){
             log.info(">>>> 没有绑定错误的广告账号,任务结束");
             log.info(">>>> 没有绑定错误的广告账号,任务结束");
             return;
             return;

+ 160 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/ByteDanceFlowDetailsReportServiceImpl.java

@@ -0,0 +1,160 @@
+package cn.com.ctop.job.bytedance.data.service.impl;
+
+import cn.com.ctop.job.bytedance.data.entity.AdvertiserAccount;
+import cn.com.ctop.job.bytedance.data.entity.ByteDanceFlowDetailsReportDaily;
+import cn.com.ctop.job.bytedance.data.entity.BytedanceErrorLog;
+import cn.com.ctop.job.bytedance.data.mapper.ByteDanceFlowDetailsReportMapper;
+import cn.com.ctop.job.bytedance.data.mapper.BytedancePromoterReportMapper;
+import cn.com.ctop.job.bytedance.data.service.IByteDanceFlowDetailsReportService;
+import cn.com.ctop.job.bytedance.data.utils.AlertUtils;
+import cn.com.ctop.job.bytedance.data.utils.Check;
+import cn.com.ctop.job.bytedance.data.utils.HttpUtils;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author lining
+ * @ClassName ByteDanceFlowDetailsReportServiceImpl
+ * @description: TODO
+ * @date 2025年04月16日
+ * @version: 1.0
+ */
+@Service
+@Slf4j
+public class ByteDanceFlowDetailsReportServiceImpl implements IByteDanceFlowDetailsReportService {
+
+    @Resource
+    private ByteDanceFlowDetailsReportMapper byteDanceFlowDetailsReportMapper;
+
+    @Autowired
+    private BytedancePromoterReportMapper promoterReportMapper;
+
+    @Override
+    public List<AdvertiserAccount> getAdAccount() {
+        return byteDanceFlowDetailsReportMapper.getAdAccount();
+    }
+
+    @Override
+    public void getBytedanceFlowDetailsDailyReport(Long advertiserId, String accessToken, String accountType, String startDate, String endDate, Integer page, Long errorId) {
+        String url = "https://ad.oceanengine.com/open_api/2/advertiser/fund/daily_stat/";
+        Map<String, Object> paramsMap = new HashMap<>();
+        paramsMap.put("advertiser_id", advertiserId);
+        paramsMap.put("start_date", startDate);
+        paramsMap.put("end_date", endDate);
+        /**
+         * 账户业务类型,可选值:
+         * AD AD广告主(默认)
+         * LOCAL 本地推
+         * STAR 星图
+         */
+        paramsMap.put("account_type", accountType);
+        paramsMap.put("page", page);
+        paramsMap.put("page_size", 100);
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Access-Token", accessToken);
+        headers.put("Content-Type", "application/json");
+        String s = HttpUtils.httpGet(url, paramsMap, headers);
+        JSONObject result = JSONObject.parseObject(s);
+        if (Check.isNull(result)) {
+            log.info("账户id:{},广告流水详情请求结果返回为空", advertiserId);
+            return;
+        }
+
+        List<ByteDanceFlowDetailsReportDaily> dailies = new ArrayList<>();
+        Integer code = result.getInteger("code");
+        Integer totalPage = 1;
+        if (code == 0) {
+            JSONObject data = result.getJSONObject("data");
+            if (!Check.isNull(data)) {
+                JSONArray list = data.getJSONArray("list");
+                totalPage = data.getJSONObject("page_info").getIntValue("total_page");
+                if (!Check.isNull(list)) {
+                    for (int i = 0; i < list.size(); i++) {
+                        JSONObject object = list.getJSONObject(i);
+                        String advertiser_id = object.getString("advertiser_id");
+                        String date = object.getString("date").replace("-", "");
+                        BigDecimal balance = object.getBigDecimal("balance");
+                        BigDecimal grant_balance = object.getBigDecimal("grant_balance");
+                        BigDecimal non_grant_balance = object.getBigDecimal("non_grant_balance");
+                        BigDecimal cash_cost = object.getBigDecimal("cash_cost");
+                        BigDecimal cost = object.getBigDecimal("cost");
+                        BigDecimal frozen = object.getBigDecimal("frozen");
+                        BigDecimal income = object.getBigDecimal("income");
+                        BigDecimal reward_cost = object.getBigDecimal("reward_cost");
+                        BigDecimal shared_wallet_cost = object.getBigDecimal("shared_wallet_cost");
+                        BigDecimal company_wallet_cost = object.getBigDecimal("company_wallet_cost");
+                        BigDecimal transfer_in = object.getBigDecimal("transfer_in");
+                        BigDecimal transfer_out = object.getBigDecimal("transfer_out");
+
+
+                        ByteDanceFlowDetailsReportDaily daily = ByteDanceFlowDetailsReportDaily.builder()
+                                .advertiserId(Long.parseLong(advertiser_id))
+                                .statTimeDay(Integer.parseInt(date))
+                                .balance(balance)
+                                .grantBalance(grant_balance)
+                                .nonGrantBalance(non_grant_balance)
+                                .cashCost(cash_cost)
+                                .cost(cost)
+                                .frozen(frozen)
+                                .income(income)
+                                .rewardCost(reward_cost)
+                                .sharedWalletCost(shared_wallet_cost)
+                                .companyWalletCost(company_wallet_cost)
+                                .transferIn(transfer_in)
+                                .transferOut(transfer_out)
+                                .build();
+                        dailies.add(daily);
+                    }
+
+                    if (!Check.isNull(dailies)) {
+                        log.info("账户id:{},流水日报请求结果返回成功", advertiserId);
+                        byteDanceFlowDetailsReportMapper.replaceDanceFlowDetailsReportDailies(dailies);
+                    }
+                }
+
+            }
+        }else{
+            //增加错误日志保存
+            log.info("账户id:{},日期:{}流水日报请求结果失败,返回数据:{}", advertiserId, startDate, result);
+            insertErrorLog(advertiserId, startDate, endDate);
+            return;
+        }
+
+        if (page < totalPage) {
+            try {
+                Thread.sleep(500L);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            getBytedanceFlowDetailsDailyReport(advertiserId, accessToken, accountType, startDate, endDate, page + 1, errorId);
+        }else{
+            log.info("账户ID:{},日期:{},流水日报详情数据日报请求成功", advertiserId, startDate);
+
+            if(errorId != null){
+                promoterReportMapper.deleteInfoByErrorId(errorId);
+            }
+            //send message to feishu
+//            AlertUtils.sendMessage(advertiserId, startDate, endDate, 1, "flow_details_daily", 1,null);
+        }
+    }
+
+    private void insertErrorLog(Long advertiserId, String startDate, String endDate) {
+        BytedanceErrorLog errorInfo = new BytedanceErrorLog();
+        errorInfo.setAdvertiserId(advertiserId);
+        errorInfo.setStartDate(startDate);
+        errorInfo.setEndDate(endDate);
+        errorInfo.setDataDimension("flow_details");
+        errorInfo.setDataType("daily");
+        promoterReportMapper.replaceErrorInfo(errorInfo);
+    }
+}

+ 153 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceMiniAppServiceImpl.java

@@ -0,0 +1,153 @@
+package cn.com.ctop.job.bytedance.data.service.impl;
+
+import cn.com.ctop.job.bytedance.data.entity.BytedanceErrorLog;
+import cn.com.ctop.job.bytedance.data.mapper.BytedanceMiniAppMapper;
+import cn.com.ctop.job.bytedance.data.mapper.BytedancePromoterReportMapper;
+import cn.com.ctop.job.bytedance.data.service.IBytedanceMiniAppService;
+import cn.com.ctop.job.bytedance.data.utils.Check;
+import cn.com.ctop.job.bytedance.data.utils.DateUtils;
+import cn.com.ctop.job.bytedance.data.utils.HttpUtils;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class BytedanceMiniAppServiceImpl implements IBytedanceMiniAppService {
+    @Resource
+    private RedisTemplate redis2Template_db5;
+
+    @Autowired
+    private BytedanceMiniAppMapper bytedanceMiniAppMapper;
+
+    @Autowired
+    private BytedancePromoterReportMapper promoterReportMapper;
+
+    @Override
+    public List<String> getIaaAppIds() {
+        return bytedanceMiniAppMapper.getIaaAppIds();
+    }
+
+    @Override
+    public List<JSONObject> getMaEcpmRetryJob() {
+        return bytedanceMiniAppMapper.getMaEcpmRetryJob();
+    }
+
+    @Override
+    public void getMaEcpm(String startDt, String endDt, String appId, Integer isLog, Long errId, Integer isSend) {
+        try {
+            Long dataRangeSeconds = 3600L;
+            String startTime = startDt + (startDt.contains(" ") ? "" : " 00:00:00");
+            Long startT = DateUtils.getTimestampFormat("yyyy-MM-dd HH:mm:ss", startTime);
+            String endTime = endDt + (endDt.contains(" ") ? "" : " 23:59:59");
+            Long endT = DateUtils.getTimestampFormat("yyyy-MM-dd HH:mm:ss", endTime) + 1;
+            boolean hasMoreTime = true;
+            while (hasMoreTime) {
+                Long thisEndT = startT + dataRangeSeconds;
+                if (thisEndT >= endT) {
+                    thisEndT = endT;
+                }
+                String endEventTime = DateUtils.formatTimestamp("yyyy-MM-dd HH:mm:ss", thisEndT);
+                Integer endEventDate = Integer.parseInt(DateUtils.formatTimestamp("yyyyMMdd", thisEndT));
+                String startEventTime = DateUtils.formatTimestamp("yyyy-MM-dd HH:mm:ss", startT);
+                Integer startEventDate = Integer.parseInt(DateUtils.formatTimestamp("yyyyMMdd", startT));
+                List<String> ecpmKeys = bytedanceMiniAppMapper.getEcpmKeys(startEventDate, endEventDate, startEventTime, endEventTime);
+                String nextCursor = null;
+                boolean hasMore = true;
+                while (hasMore) {
+                    log.info("抖小ma_ecpm拉取 [{}] {}~{} {}", appId, startEventTime, endEventTime, nextCursor);
+                    String url = "https://open.douyin.com/api/traffic/v2/rt_ecpm/query/";
+                    Object tokenObj = redis2Template_db5.opsForValue().get("client-token-key_" + appId);
+                    if (tokenObj == null) {
+                        log.error("抖小ma_ecpm拉取获取token为空 [{}] {}~{} {}", appId, startEventTime, endEventTime, nextCursor);
+                        return;
+                    }
+                    Map<String, Object> params = new JSONObject();
+                    params.put("start_date", startEventTime);
+                    params.put("end_date", endEventTime);
+                    params.put("page_size", 500);
+                    if (nextCursor != null) {
+                        params.put("cursor", nextCursor);
+                    }
+                    HashMap<String, String> headers = new HashMap<>();
+                    headers.put("access-token", tokenObj.toString());
+                    headers.put("Content-Type", "application/json; charset=UTF-8");
+
+                    String s = HttpUtils.httpPostRequest(url, params, headers);
+                    JSONObject jsonObject = JSONObject.parseObject(s);
+                    JSONArray content = new JSONArray();
+                    if (!Check.isNull(jsonObject)) {
+                        Integer code = jsonObject.getInteger("err_no");
+                        if (code == 0) {
+                            JSONObject data = jsonObject.getJSONObject("data");
+
+                            nextCursor = data.getString("next_cursor");
+                            JSONArray result = data.getJSONArray("records");
+                            if (!Check.isNull(result)) {
+                                for (int i = 0; i < result.size(); i++) {
+                                    JSONObject resultJson = result.getJSONObject(i);
+                                    String eventTime = resultJson.getString("event_time");
+                                    String openId = resultJson.getString("open_id");
+                                    String cost = resultJson.getString("cost");
+                                    if (ecpmKeys.contains(eventTime + openId + cost)) {
+                                        continue;
+                                    }
+                                    content.add(resultJson);
+                                }
+                            } else {
+                                hasMore = false;
+                            }
+                        } else {
+                            log.error("[{}]抖小ma_ecpm拉取失败{}~{},返回信息:{}", appId, startEventTime, endEventTime, s);
+                            insertErrorLog(isLog, startEventTime, endTime, "ma_ecpm:" + appId, "daily", s);
+                            return;
+                        }
+                    } else {
+                        log.error("[{}]抖小ma_ecpm拉取返回数据为空{}~{}", appId, startEventTime, endEventTime);
+                        insertErrorLog(isLog, startEventTime, endTime, "ma_ecpm:" + appId, "daily", "数据返回空");
+                        return;
+                    }
+
+                    if (!content.isEmpty()) {
+                        String pushUrl = "https://push.artlinkworld.cn/bytedance/push/miniapp/webhook";
+                        JSONObject pushParam = new JSONObject();
+                        pushParam.put("content", content.toJSONString());
+                        pushParam.put("client_key", appId);
+                        pushParam.put("event", "ma_ecpm");
+                        HttpUtils.httpPostRequest(pushUrl, pushParam, null);
+                    }
+                }
+                hasMoreTime = thisEndT < endT;
+                startT = thisEndT;
+                if (errId != null) {
+                    promoterReportMapper.deleteInfoByErrorId(errId);
+                }
+            }
+            log.info("[{}]抖小ma_ecpm拉取完成{}~{}.", appId, startDt, endDt);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void insertErrorLog(Integer isLog, String startDate, String endDate, String dataDimension, String dataType, String msg) {
+        if (isLog != null && 1 == isLog) {
+            BytedanceErrorLog errorInfo = new BytedanceErrorLog();
+            errorInfo.setAdvertiserId(-1L);
+            errorInfo.setStartDate(startDate);
+            errorInfo.setEndDate(endDate);
+            errorInfo.setDataDimension(dataDimension);
+            errorInfo.setDataType(dataType);
+            errorInfo.setMsg(msg);
+            promoterReportMapper.replaceErrorInfo(errorInfo);
+        }
+    }
+
+}

+ 6 - 1
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceProductReportServiceImpl.java

@@ -30,6 +30,11 @@ public class BytedanceProductReportServiceImpl implements IBytedanceProductRepor
     private BytedanceProductReportMapper productReportMapper;
     private BytedanceProductReportMapper productReportMapper;
 
 
     @Override
     @Override
+    public void deleteBytedanceProductDailyReport(Long advertiserId, String startDate, String endDate) {
+        productReportMapper.deleteProductReportDailies(advertiserId, Integer.parseInt(startDate.replace("-", "")), Integer.parseInt(endDate.replace("-", "")));
+    }
+
+    @Override
     public void getBytedanceProductDailyReport(Long advertiserId, String accessToken, String startDate, String endDate, Integer page,
     public void getBytedanceProductDailyReport(Long advertiserId, String accessToken, String startDate, String endDate, Integer page,
                                                Long errorId, Integer isLog, Integer isSend) {
                                                Long errorId, Integer isLog, Integer isSend) {
         try {
         try {
@@ -98,7 +103,7 @@ public class BytedanceProductReportServiceImpl implements IBytedanceProductRepor
                     promoterReportMapper.deleteInfoByErrorId(errorId);
                     promoterReportMapper.deleteInfoByErrorId(errorId);
                 }
                 }
                 if (isSend != null && 1 == isSend) {
                 if (isSend != null && 1 == isSend) {
-                    AlertUtils.sendMessage(advertiserId, startDate, endDate, 1, "product_daily", 1,null);
+                    AlertUtils.sendMessage(advertiserId, startDate, endDate, 1, "product_daily", 1, null);
                 }
                 }
             }
             }
         } catch (Exception e) {
         } catch (Exception e) {

+ 407 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceProductUpdateServiceImpl.java

@@ -0,0 +1,407 @@
+package cn.com.ctop.job.bytedance.data.service.impl;
+
+import cn.com.ctop.job.bytedance.data.mapper.BytedanceProductUpdateMapper;
+import cn.com.ctop.job.bytedance.data.service.IBytedanceProductUpdateService;
+import cn.com.ctop.job.bytedance.data.utils.Check;
+import cn.com.ctop.job.bytedance.data.utils.HttpUtils;
+import cn.com.ctop.job.bytedance.utils.FeishuRobotUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+@Slf4j
+@Service
+public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdateService {
+    @Resource
+    BytedanceProductUpdateMapper bytedanceProductUpdateMapper;
+
+    public static final String APP_ID = "ttba3acc87250c6f7901";
+    public static final String HOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/92e2445e-76df-44fb-8f61-f55ac94f49bd";
+
+    @Override
+    public void run() throws Exception {
+        List<String> errors = new ArrayList<>();
+        log.info("付费商品库更新中...");
+        iapProductUpdate(errors);
+        log.info("付费商品库更新完成");
+        log.info("免费商品库更新中...");
+        iaaProductUpdate(errors);
+        log.info("免费商品库更新完成");
+        if (!Check.isNull(errors)){
+//            List<String> users = Arrays.asList(
+//                    "44fbaed6" //zhaotx
+//                    ,"58e7a98a"  //xsq
+//            );
+            FeishuRobotUtil.sendTextToWebhook(StringUtils.join(errors, "\n"), HOOK_URL);
+        }
+
+    }
+
+
+    @Override
+    public void initNew(){
+        List<JSONObject> iapPlatformList = bytedanceProductUpdateMapper.getIAPPlatformList();
+        List<JSONObject> iaaPlatformList = bytedanceProductUpdateMapper.getIAAPlatformList();
+        initNew(iaaPlatformList);
+        initNew(iapPlatformList);
+    }
+
+    public void initNew(List<JSONObject> platformList)  {
+        //为广告主账户创建新的字节小程序
+        //step1 查询表里广告主是否都有自己的字节小程序、
+        //step2 如果没有,创建新的字节小程序
+        for (JSONObject obj : platformList){
+            if (obj.containsKey("mini_instance_id") && !Check.isNull(obj.get("mini_instance_id"))){
+                //已经有字节小程序了
+                continue;
+            }
+            String createLinkUrl = "https://api.oceanengine.com/open_api/v3.0/tools/micro_app/create/";
+            String advertiser_id = obj.getString("advertiser_id");
+            String access_token = obj.getString("access_token");
+            Map<String, String> headers = new HashMap<>();
+            headers.put("Access-Token", access_token);
+            JSONObject requestBody = new JSONObject();
+            requestBody.put("advertiser_id", Long.parseLong(advertiser_id));
+            requestBody.put("app_id", obj.getString("mi_appid"));
+            requestBody.put("remark", "商品库管理用");
+            requestBody.put("tag_info", "1050107001");
+            JSONObject app_page = new JSONObject();
+            app_page.put("link", "");
+            app_page.put("link_remark", "init");
+            app_page.put("start_page", "pages/index/index");
+            app_page.put("start_param", "link_id=574391");
+            requestBody.put("app_page", app_page);
+
+            String res = HttpUtils.httpPostRequest(createLinkUrl, requestBody, headers);
+            if (res == null || res.isEmpty()){
+                System.out.println("创建字节小程序失败");
+                return;
+            }else {
+                JSONObject jsonObject = JSONObject.parseObject(res);
+                int code = jsonObject.getIntValue("code");
+                if (code != 0) {
+                    System.out.println("创建字节小程序失败,code: " + code + ", msg: " + jsonObject.getString("message"));
+                    break;
+                }else {
+                    String instanceId = jsonObject.getJSONObject("data").getString("instance_id");
+                    //更新表
+                    bytedanceProductUpdateMapper.updateInstanceId(advertiser_id, instanceId);
+                }
+            }
+        }
+    }
+
+    private void iapProductUpdate(List<String> errorBlanket){
+        //IAP
+        List<JSONObject> iapPlatformList = bytedanceProductUpdateMapper.getIAPPlatformList();
+        List<JSONObject> iapVideoList = bytedanceProductUpdateMapper.getIAPVideoList();
+        List<JSONObject> iapProductTypeEnums = bytedanceProductUpdateMapper.getIAPProductTypeEnums();
+        Map<String, Map<String, String>> advertiserToLinkMap = new HashMap<>();
+
+        for (JSONObject obj : iapPlatformList){
+            String advertiserId = obj.getString("advertiser_id");
+            String accessToken = obj.getString("access_token");
+            String instanceId = obj.getString("mini_instance_id");
+            if (instanceId == null){
+                errorBlanket.add("没有找到字节小程序的实例ID: " + advertiserId);
+                System.out.println("没有找到字节小程序的实例ID: " + advertiserId);
+                continue;
+            }
+            Map<String, String> albumIdToLinkMap = getBytedancePlayletPromoteLink(advertiserId, accessToken, instanceId, iapVideoList, errorBlanket);
+            advertiserToLinkMap.put(advertiserId, albumIdToLinkMap);
+        }
+
+        Map<String, JSONObject> iapProductTypeMap = iapProductTypeEnums.stream().collect(Collectors.toMap(
+                obj -> obj.getString("third_type_name"),
+                obj -> obj,
+                (existing, replacement) -> replacement
+        ));
+        for (JSONObject obj : iapVideoList){
+            String theme = obj.getString("theme");
+            if (!iapProductTypeMap.containsKey(theme)){
+                errorBlanket.add("上传商品:没有找到对应的产品类型:" + theme);
+                System.out.println(">>>>没有找到对应的产品类型:" + theme);
+                System.out.println("\n\n\n");
+                continue;
+            }
+            for (JSONObject platform : iapPlatformList) {
+                String url = "https://ad.oceanengine.com/open_api/2/dpa/product/update/";
+                Map<String, String> headers = new HashMap<>();
+                headers.put("Access-Token", platform.getString("access_token"));
+                headers.put("Content-Type", "application/json");
+
+                JSONObject request = new JSONObject();
+                String album_id = obj.getString("album_id");
+                request.put("product_id", obj.getLongValue("album_id"));
+                JSONObject product_info = new JSONObject();
+                product_info.put("name", obj.getString("name"));
+                product_info.put("image_url", obj.getString("img"));
+                product_info.put("status", 1);
+                product_info.put("stock", 1);
+                JSONObject productType = iapProductTypeMap.get(theme);
+                product_info.put("first_category_id", productType.getString("first_type_id"));
+                product_info.put("sub_category_id", productType.getString("second_type_id"));
+                product_info.put("third_category_id", productType.getString("third_type_id"));
+                product_info.put("first_category", productType.getString("first_type_name"));
+                product_info.put("sub_category", productType.getString("second_type_name"));
+                product_info.put("third_category", productType.getString("third_type_name"));
+                request.put("advertiser_id", platform.getLongValue("advertiser_id"));
+                request.put("platform_id", platform.getLongValue("platform_id"));
+                JSONObject profession = new JSONObject();
+                profession.put("copyright_owner", obj.getString("copyright_owner"));
+                profession.put("playlet_gender", "3");
+                profession.put("playlet_num", obj.getString("playlet_num"));
+                profession.put("playlet_duration", obj.getString("playlet_duration"));
+                profession.put("start_pay_playlet", obj.getString("start_pay_playlet"));
+                if (platform.getDouble("max_charge") > 0.0){
+                    profession.put("max_charge", platform.getString("max_charge"));
+                }
+                if (platform.getDouble("min_charge") > 0.0){
+                    profession.put("min_charge", platform.getString("min_charge"));
+                }
+                if (platform.getDouble("recommended_charge") > 0.0){
+                    profession.put("recommended_charge", platform.getString("recommended_charge"));
+                }
+                profession.put("has_paid_content", "1");
+                profession.put("has_motivation_content", "2");
+                profession.put("membership_types", platform.getString("membership_types"));
+                profession.put("micro_app_link", advertiserToLinkMap.get(platform.getString("advertiser_id")).get(album_id));
+                //price_info
+                JSONObject price_info = new JSONObject();
+                price_info.put("price", platform.getDoubleValue("single_price"));
+                product_info.put("price_info", price_info);
+                product_info.put("profession", profession);
+                request.put("product_info", product_info);
+
+
+//                System.out.println("请求地址:" + url);
+//                System.out.println("请求头:" + headers);
+//                System.out.println("请求参数:" + request.toJSONString());
+                String res = HttpUtils.httpPostRequest(url, request, headers);
+//                System.out.println(res);
+                JSONObject btRes = JSONObject.parseObject(res);
+                int code = btRes.getIntValue("code");
+                if (code != 0){
+                    errorBlanket.add("上传付费商品失败,code: " + code + ", msg: " + btRes.getString("message")+", 关联剧目: " + obj.getString("name"));
+                }
+//                System.out.println("\n\n\n");
+            }
+        }
+    }
+
+    private void iaaProductUpdate(List<String> errorBlanket){
+        //IAA
+        List<JSONObject> iaaPlatformList = bytedanceProductUpdateMapper.getIAAPlatformList();
+        List<JSONObject> iaaVideoList = bytedanceProductUpdateMapper.getIAAVideoList();
+        List<JSONObject> iaaProductTypeEnums = bytedanceProductUpdateMapper.getIAAProductTypeEnums();
+
+        Map<String, Map<String, String>> advertiserToLinkMap = new HashMap<>();
+
+        for (JSONObject obj : iaaPlatformList){
+            String advertiserId = obj.getString("advertiser_id");
+            String accessToken = obj.getString("access_token");
+            String instanceId = obj.getString("mini_instance_id");
+            if (instanceId == null){
+                errorBlanket.add("没有找到字节小程序的实例ID: " + advertiserId);
+                System.out.println("没有找到字节小程序的实例ID: " + advertiserId);
+                continue; //todo
+            }
+            Map<String, String> albumIdToLinkMap = getBytedancePlayletPromoteLink(advertiserId, accessToken, instanceId, iaaVideoList, errorBlanket);
+            advertiserToLinkMap.put(advertiserId, albumIdToLinkMap);
+        }
+
+        Map<String, JSONObject> iaaProductTypeMap = iaaProductTypeEnums.stream().collect(Collectors.toMap(
+                obj -> obj.getString("third_type_name"),
+                obj -> obj,
+                (existing, replacement) -> replacement
+        ));
+        for (JSONObject obj : iaaVideoList){
+            String theme = obj.getString("theme");
+            if (!iaaProductTypeMap.containsKey(theme)){
+                errorBlanket.add("上传商品:没有找到对应的产品类型:" + theme);
+                System.out.println(">>>>没有找到对应的产品类型:" + theme);
+                System.out.println("\n\n\n");
+                continue;
+            }
+
+
+            for (JSONObject platform : iaaPlatformList) {
+                String url = "https://ad.oceanengine.com/open_api/2/dpa/product/update/";
+                Map<String, String> headers = new HashMap<>();
+                headers.put("Access-Token", platform.getString("access_token"));
+                headers.put("Content-Type", "application/json");
+                String album_id = obj.getString("album_id");
+                JSONObject request = new JSONObject();
+                request.put("product_id", obj.getLongValue("album_id"));
+                JSONObject product_info = new JSONObject();
+                product_info.put("name", obj.getString("name"));
+                product_info.put("image_url", obj.getString("img"));
+                product_info.put("status", 1);
+                product_info.put("stock", 1);
+                JSONObject productType = iaaProductTypeMap.get(theme);
+                product_info.put("first_category_id", productType.getString("first_type_id"));
+                product_info.put("sub_category_id", productType.getString("second_type_id"));
+                product_info.put("third_category_id", productType.getString("third_type_id"));
+                product_info.put("first_category", productType.getString("first_type_name"));
+                product_info.put("sub_category", productType.getString("second_type_name"));
+                product_info.put("third_category", productType.getString("third_type_name"));
+                JSONObject profession = new JSONObject();
+                profession.put("copyright_owner", obj.getString("copyright_owner"));
+                profession.put("playlet_gender", "3");
+                profession.put("playlet_num", obj.getString("playlet_num"));
+                profession.put("playlet_duration", obj.getString("playlet_duration"));
+                profession.put("has_paid_content", "2");
+                profession.put("has_motivation_content", "2");
+                profession.put("membership_types", "5");
+                profession.put("starting_unlock_episode", obj.getString("starting_unlock_episode"));
+                profession.put("micro_app_link", advertiserToLinkMap.get(platform.getString("advertiser_id")).get(album_id));
+                product_info.put("profession", profession);
+                request.put("product_info", product_info);
+                request.put("advertiser_id", platform.getLongValue("advertiser_id"));
+                request.put("platform_id", platform.getLongValue("platform_id"));
+
+//                System.out.println("请求地址:" + url);
+//                System.out.println("请求头:" + headers);
+//                System.out.println("请求参数:" + request.toJSONString());
+                String res = HttpUtils.httpPostRequest(url, request, headers);
+                JSONObject btRes = JSONObject.parseObject(res);
+                int code = btRes.getIntValue("code");
+                if (code != 0){
+                    errorBlanket.add("上传免费商品失败,code: " + code + ", msg: " + btRes.getString("message")+", 关联剧目: " + obj.getString("name"));
+                }
+//                System.out.println(res);
+//                System.out.println("\n\n\n");
+            }
+        }
+    }
+
+    /**
+     *
+     * @param advertiserId 商品库主账户ID,也是创建字节小程序的ID
+     * @param accessToken 广告账号的access_token
+     * @param instanceId 字节小程序的实例ID
+     * @return map key: album_id, value: 对应的字节小程序推广链接,sslocal开头
+     */
+    private Map<String, String> getBytedancePlayletPromoteLink(String advertiserId, String accessToken, String instanceId, List<JSONObject> requests, List<String> errorBlanket){
+        JSONArray playletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket);
+        if (playletDetailInfo == null || playletDetailInfo.isEmpty()){
+            return null;
+        }
+        List<String> reqAlbumIds = requests.stream()
+                .map(obj -> obj.getString("album_id"))
+                .collect(Collectors.toList());
+        Map<String, String> res = new HashMap<>(reqAlbumIds.size());
+
+        for (int i = 0; i < playletDetailInfo.size(); i++) {
+            JSONObject obj = playletDetailInfo.getJSONObject(i);
+            String startParam = obj.getString("start_param");
+            for (String album_id : reqAlbumIds){
+                if (startParam.contains("tt_album_id="+album_id)){
+                    res.put(album_id, obj.getString("link"));
+                }
+            }
+        }
+        List<JSONObject> unfound = requests.stream()
+                .filter(obj -> !res.containsKey(obj.getString("album_id")))
+                .collect(Collectors.toList());
+        if (unfound.isEmpty()){
+            return res;
+        }
+        //没有找到对应的album_id,需要新建链接
+        for (JSONObject obj : unfound){
+            String editLinkUrl = "https://api.oceanengine.com/open_api/v3.0/tools/micro_app/update/";
+            Map<String, String> headers = new HashMap<>();
+            headers.put("Access-Token", accessToken);
+            JSONObject requestBody = new JSONObject();
+            requestBody.put("advertiser_id", Long.parseLong(advertiserId));
+            requestBody.put("instance_id", Long.parseLong(instanceId));
+            JSONObject app_page = new JSONObject();
+            String name = obj.getString("name");
+            app_page.put("link", "");
+            app_page.put("remark", "生成商品用-"+name);
+            app_page.put("link_remark", "生成商品用-"+name);
+            app_page.put("operate_type", "NEW");
+            app_page.put("start_page", "pages/index/index");
+            String video_id = obj.getString("video_id");
+            String album_id = obj.getString("album_id");
+            String video_detail_id = obj.getString("video_detail_id");
+            String platform_config = obj.getString("platform_config");
+            JSONObject pconfig = JSONObject.parseObject(platform_config);
+            String tt_episode_id = pconfig.getJSONObject("douyinyun").getString("episode_id");
+            String start_param = "tt_album_id=" + album_id + "&video_id=" + video_id + "&video_detail_id=" + video_detail_id + "&tt_episode_id=" + tt_episode_id + "&source=link&type=1";
+            app_page.put("start_param", start_param);
+            JSONArray app_page_list = new JSONArray();
+            app_page_list.add(app_page);
+            requestBody.put("app_page", app_page_list);
+            requestBody.put("tag_info", "1050107001");
+//            System.out.println("\n\n请求地址:" + editLinkUrl);
+//            System.out.println("请求头:" + headers);
+//            System.out.println("请求参数:" + requestBody.toJSONString());
+
+            String rr = HttpUtils.httpPostRequest(editLinkUrl, requestBody, headers);
+            if (rr == null || rr.isEmpty()){
+                errorBlanket.add("创建字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+                System.out.println("创建字节小程序推广链接失败");
+                return res;
+            }else {
+                JSONObject jsonObject = JSONObject.parseObject(rr);
+                int code = jsonObject.getIntValue("code");
+                if (code != 0) {
+                    errorBlanket.add("创建字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+                    System.out.println("创建字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message"));
+                    continue;
+                }else {
+                    String instanceid = jsonObject.getJSONObject("data").getString("instance_id");
+                    JSONArray newPlayletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceid, errorBlanket);
+                    if (newPlayletDetailInfo == null || newPlayletDetailInfo.isEmpty()){
+                        continue;
+                    }
+                    for (int i = 0; i < newPlayletDetailInfo.size(); i++) {
+                        JSONObject link = newPlayletDetailInfo.getJSONObject(i);
+                        String startParam = link.getString("start_param");
+                        if (startParam.contains("tt_album_id="+album_id)){
+                            res.put(album_id, link.getString("link"));
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+
+    }
+
+    private JSONArray getPlayletDetail(String advertiserId, String accessToken, String instanceId, List<String> errorBlanket) {
+        String getPlayletDetailUrl = "https://api.oceanengine.com/open_api/v3.0/tools/asset_link/list/";
+        getPlayletDetailUrl = getPlayletDetailUrl.replace("${ADVERTISER_ID}", advertiserId);
+        getPlayletDetailUrl = getPlayletDetailUrl.replace("${INSTANCE_ID}", instanceId);
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Access-Token", accessToken);
+        Map<String, Object> params = new HashMap<>();
+        params.put("advertiser_id", advertiserId);
+        params.put("page", "1");
+        params.put("page_size", "100");
+        params.put("filtering", "{\"instance_id\":" + instanceId + "}");
+        String res = HttpUtils.httpGet(getPlayletDetailUrl, params, headers);
+        if (res == null || res.isEmpty()) {
+            errorBlanket.add("获取字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+            return null;
+        }else {
+            JSONObject jsonObject = JSONObject.parseObject(res);
+            int code = jsonObject.getIntValue("code");
+            if (code != 0) {
+                errorBlanket.add("获取字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+                System.out.println("获取字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message"));
+                return null;
+            }else {
+                return jsonObject.getJSONObject("data").getJSONArray("list");
+            }
+        }
+
+    }
+
+}

+ 54 - 9
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/DateReportsPushServiceImpl.java

@@ -33,10 +33,20 @@ public class DateReportsPushServiceImpl implements IDateReportsPushService {
     @Autowired
     @Autowired
     ReportsAdPushMapper reportsPushMapper;
     ReportsAdPushMapper reportsPushMapper;
 
 
-    private static final String TEMPLATE_VERSION = "1.0.2";
+    private static final String TEMPLATE_VERSION = "1.0.3";
     private static final String TEMPLATE_ID = "AAqRhJzMBoO0E";
     private static final String TEMPLATE_ID = "AAqRhJzMBoO0E";
     @Override
     @Override
     public void send() {
     public void send() {
+        sendParam("");
+    }
+
+    @Override
+    public void preSend() {
+        sendParam("注:当天ROI数据有微小1%-2%差异,以次日9点推送为准");
+    }
+
+
+    private void sendParam(String description){
         String token;
         String token;
         try {
         try {
             token = FeishuRobotUtil.getTenantToken(APP_ID, APP_KEY);
             token = FeishuRobotUtil.getTenantToken(APP_ID, APP_KEY);
@@ -107,7 +117,7 @@ public class DateReportsPushServiceImpl implements IDateReportsPushService {
             JSONObject obj = new JSONObject();
             JSONObject obj = new JSONObject();
             obj.put("rank", String.valueOf(movie.get("rk")));
             obj.put("rank", String.valueOf(movie.get("rk")));
             obj.put("movieName", String.valueOf(movie.get("movie_name")));
             obj.put("movieName", String.valueOf(movie.get("movie_name")));
-            obj.put("endAmount", String.valueOf(movie.get("end_amount")));
+            obj.put("endAmount", String.valueOf(movie.get("share_end_amount")));
             obj.put("realROI", String.valueOf(movie.get("real_roi")));
             obj.put("realROI", String.valueOf(movie.get("real_roi")));
             movieRankTable.add(obj);
             movieRankTable.add(obj);
         }
         }
@@ -130,20 +140,28 @@ public class DateReportsPushServiceImpl implements IDateReportsPushService {
         template_variable.put("dateIndicatorTable", dateIndicatorTable);
         template_variable.put("dateIndicatorTable", dateIndicatorTable);
         template_variable.put("movieRankTable", movieRankTable);
         template_variable.put("movieRankTable", movieRankTable);
         template_variable.put("deptRank", deptRank);
         template_variable.put("deptRank", deptRank);
+        template_variable.put("description", description);
 
 
         List<String> userIds = Arrays.asList(
         List<String> userIds = Arrays.asList(
                 "44fbaed6" //zhaotx
                 "44fbaed6" //zhaotx
-                ,"ebeeced9" //yumeng
-                ,"265g9ef1" //wangshu
-                ,"ee518161" //zhaozhicheng
-                ,"c5f6b59d" //yuyang
-                ,"d834552b" //hemenghao
-                ,"a3235a61" //louzijun
-                ,"58e7a98a"  //xsq
+//                ,"ebeeced9" //yumeng
+//                ,"265g9ef1" //wangshu
+//                ,"ee518161" //zhaozhicheng
+//                ,"c5f6b59d" //yuyang
+//                ,"d834552b" //hemenghao
+//                ,"a3235a61" //louzijun
+//                ,"58e7a98a"  //xsq
         );
         );
         for (String userId : userIds) {
         for (String userId : userIds) {
             sendToFeishu(token, template_variable, userId);
             sendToFeishu(token, template_variable, userId);
         }
         }
+
+        List<String> chatid = Arrays.asList(
+                "oc_275f17aa4bf8fae649ef281a2b9250f6"
+        );
+        for (String chat : chatid) {
+            sendToChatGroup(token, template_variable, chat);
+        }
     }
     }
 
 
     private void sendToFeishu(String token, JSONObject template_variable, String receive_id) {
     private void sendToFeishu(String token, JSONObject template_variable, String receive_id) {
@@ -172,4 +190,31 @@ public class DateReportsPushServiceImpl implements IDateReportsPushService {
             log.error("发送飞书消息失败", e);
             log.error("发送飞书消息失败", e);
         }
         }
     }
     }
+
+    private void sendToChatGroup(String token, JSONObject template_variable, String chatid) {
+        JSONObject content = new JSONObject();
+        JSONObject contentData = new JSONObject();
+        contentData.put("template_id",TEMPLATE_ID);
+        contentData.put("template_version_name", TEMPLATE_VERSION);
+        contentData.put("template_variable", template_variable);
+        content.put("type", "template");
+        content.put("data", contentData);
+
+        JSONObject request = new JSONObject();
+        request.put("receive_id", chatid);
+        request.put("msg_type", "interactive");
+        request.put("content", content.toJSONString());
+        //发送
+        try (CloseableHttpClient client = HttpClients.createDefault()){
+            HttpPost httpPost = new HttpPost("https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id");
+            httpPost.setHeader("Authorization", "Bearer "+token);
+            HttpEntity entity = new StringEntity(request.toJSONString(), "UTF-8");
+            httpPost.setEntity(entity);
+            httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
+            CloseableHttpResponse respon = client.execute(httpPost);
+            System.out.println("发送结果: "+ EntityUtils.toString(respon.getEntity(), "UTF-8"));
+        }catch (IOException e){
+            log.error("发送飞书消息失败", e);
+        }
+    }
 }
 }

+ 50 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/UserLoginRecordServiceImpl.java

@@ -0,0 +1,50 @@
+package cn.com.ctop.job.bytedance.data.service.impl;
+
+import cn.com.ctop.job.bytedance.data.entity.UserLoginRecord;
+import cn.com.ctop.job.bytedance.data.mapper.UserLoginRecordMapper;
+import cn.com.ctop.job.bytedance.data.service.IUserLoginRecordService;
+import cn.com.ctop.job.bytedance.data.utils.DateUtils;
+import cn.com.ctop.job.bytedance.utils.FeishuRobotUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author lining
+ * @ClassName UserLoginRecordServiceImpl
+ * @description: TODO
+ * @date 2025年05月09日
+ * @version: 1.0
+ */
+@Service
+@Slf4j
+public class UserLoginRecordServiceImpl implements IUserLoginRecordService {
+    public static final String WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/cddc4569-c5bb-4764-b79e-7d2e896a97b1";
+    @Autowired
+    private UserLoginRecordMapper userLoginRecordMapper;
+    @Override
+    public String queryUserLoginRecord() {
+        List<UserLoginRecord> userLoginRecords = userLoginRecordMapper.queryUserLoginRecord();
+
+        String date = DateUtils.getNowDate("YYYY-MM-dd HH:mm:ss");
+        StringBuilder text = new StringBuilder(date);
+        text.append("\n");
+        if (userLoginRecords != null && userLoginRecords.size() > 0){
+            userLoginRecords.forEach(userLoginRecord -> {
+                text.append("用户ID:").append(userLoginRecord.getUid()).append("\n")
+                        .append("用户openid:").append(userLoginRecord.getOpenId()).append("\n")
+                        .append("登录次数:").append(userLoginRecord.getLoginTimes()).append("\n");
+            });
+            log.info("登录次数消息:{}", text);
+            try {
+                FeishuRobotUtil.sendTextToWebhook(text.toString(), WEBHOOK_URL);
+            } catch (Exception e) {
+                log.error("发送飞书消息失败", e);
+            }
+        }
+
+        return text.toString();
+    }
+}

+ 1 - 1
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/utils/HttpUtils.java

@@ -122,7 +122,7 @@ public class HttpUtils {
                 return httpPostRequest(newUrl, param, headers);
                 return httpPostRequest(newUrl, param, headers);
             } else if (statusCode == HttpStatus.SC_OK) {
             } else if (statusCode == HttpStatus.SC_OK) {
                 respentity = response.getEntity();
                 respentity = response.getEntity();
-                strReturn = EntityUtils.toString(respentity);
+                strReturn = EntityUtils.toString(respentity,"UTF-8");
                 return strReturn;
                 return strReturn;
             }
             }
         } catch (Exception e) {
         } catch (Exception e) {

+ 55 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/ByteDanceFlowDetailsReportJob.java

@@ -0,0 +1,55 @@
+package cn.com.ctop.job.bytedance.handler;
+
+import cn.com.ctop.job.bytedance.data.enums.AccountTypeEnum;
+import cn.com.ctop.job.bytedance.data.service.IByteDanceFlowDetailsReportService;
+import cn.com.ctop.job.bytedance.data.utils.Check;
+import cn.com.ctop.job.bytedance.data.utils.DateUtils;
+import com.xxl.job.core.context.XxlJobHelper;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @author lining
+ * @ClassName ByteDanceFlowDetailsReportJob
+ * @description: TODO
+ * @date 2025年04月16日
+ * @version: 1.0
+ */
+@Slf4j
+@Component
+public class ByteDanceFlowDetailsReportJob {
+
+    @Autowired
+    private IByteDanceFlowDetailsReportService byteDanceFlowDetailsReportService;
+
+    private static ExecutorService executorService = Executors.newFixedThreadPool(2);
+
+    @XxlJob("flowDetailsDaily")
+    public void flowDetailsDaily() throws Exception {
+        String param = XxlJobHelper.getJobParam(); // 执行参数
+        if (Check.isNull(param)) {
+            log.error("入参为空");
+            return;
+        }
+
+        String nowDate = DateUtils.getNowDate("yyyy-MM-dd");
+        String data = DateUtils.getAnotherDay("yyyy-MM-dd", nowDate, -1);
+        String[] s = param.split("_");
+        Long advertiserId = Long.valueOf(s[0]);
+        String accessToken = s[1];
+
+        executorService.submit(new Runnable() {
+            @Override
+            public void run() {
+                if (!Check.isNull(accessToken)) {
+                    byteDanceFlowDetailsReportService.getBytedanceFlowDetailsDailyReport(advertiserId, accessToken, AccountTypeEnum.AD.getValue(), data, data, 1, null);
+                }
+            }
+        });
+    }
+}

+ 29 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedanceMiniAppJob.java

@@ -0,0 +1,29 @@
+package cn.com.ctop.job.bytedance.handler;
+
+
+import cn.com.ctop.job.bytedance.data.service.IBytedanceMiniAppService;
+import cn.com.ctop.job.bytedance.data.utils.DateUtils;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+@Slf4j
+@Component
+public class BytedanceMiniAppJob {
+    @Autowired
+    private IBytedanceMiniAppService bytedanceMiniAppService;
+
+    @XxlJob("yesterdayMaEcpm")
+    public void yesterdayMaEcpm() throws Exception {
+        List<String> iaaAppIds = bytedanceMiniAppService.getIaaAppIds();
+        for (String iaaAppId : iaaAppIds) {
+            String date = DateUtils.getNowAddDate("yyyy-MM-dd", -1);
+            bytedanceMiniAppService.getMaEcpm(date, date, iaaAppId, 1, null, null);
+        }
+    }
+
+}

+ 31 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedanceProductUploadJob.java

@@ -0,0 +1,31 @@
+package cn.com.ctop.job.bytedance.handler;
+
+import cn.com.ctop.job.bytedance.data.service.IBytedanceProductUpdateService;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class BytedanceProductUploadJob {
+    @Autowired
+    IBytedanceProductUpdateService bytedanceProductUpdateService;
+
+    /**
+     * 创建和更新推广链
+     * @throws Exception
+     */
+    @XxlJob("productUploadJob")
+    public void productUploadJob() throws Exception {
+        bytedanceProductUpdateService.run();
+    }
+
+    /**
+     * 初始化推广链接用的字节小程序
+     */
+    @XxlJob("initProductLinkApp")
+    public void initProductLinkApp(){
+        bytedanceProductUpdateService.initNew();
+    }
+}

+ 1 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedancePromoterReportJob.java

@@ -105,6 +105,7 @@ public class BytedancePromoterReportJob {
         productDailyExecutor.submit(new Runnable() {
         productDailyExecutor.submit(new Runnable() {
             @Override
             @Override
             public void run() {
             public void run() {
+                productReportService.deleteBytedanceProductDailyReport(advertiserId, data, data);
                 productReportService.getBytedanceProductDailyReport(advertiserId, accessToken, data, data, 1, null, 1, null);
                 productReportService.getBytedanceProductDailyReport(advertiserId, accessToken, data, data, 1, null, 1, null);
             }
             }
         });
         });

+ 36 - 4
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/BytedanceReportRetryJob.java

@@ -1,10 +1,9 @@
 package cn.com.ctop.job.bytedance.handler;
 package cn.com.ctop.job.bytedance.handler;
 
 
 
 
-import cn.com.ctop.job.bytedance.data.service.IBytedanceAccountReportService;
-import cn.com.ctop.job.bytedance.data.service.IBytedanceProductReportService;
-import cn.com.ctop.job.bytedance.data.service.IBytedancePromoterReportService;
-import cn.com.ctop.job.bytedance.data.service.IChannelService;
+import cn.com.ctop.job.bytedance.data.service.*;
+import cn.com.ctop.job.bytedance.data.enums.AccountTypeEnum;
+import cn.com.ctop.job.bytedance.data.service.*;
 import cn.com.ctop.job.bytedance.data.utils.Check;
 import cn.com.ctop.job.bytedance.data.utils.Check;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import com.xxl.job.core.handler.annotation.XxlJob;
@@ -37,6 +36,12 @@ public class BytedanceReportRetryJob {
     @Autowired
     @Autowired
     private IChannelService channelService;
     private IChannelService channelService;
 
 
+    @Autowired
+    private IBytedanceMiniAppService miniAppService;
+
+    @Autowired
+    private IByteDanceFlowDetailsReportService byteDanceFlowDetailsReportService;
+
 
 
     private static ExecutorService hourAccountRetrExecutorService = Executors.newFixedThreadPool(2);
     private static ExecutorService hourAccountRetrExecutorService = Executors.newFixedThreadPool(2);
     private static ExecutorService dailyAccountRetrExecutorService = Executors.newFixedThreadPool(2);
     private static ExecutorService dailyAccountRetrExecutorService = Executors.newFixedThreadPool(2);
@@ -46,6 +51,8 @@ public class BytedanceReportRetryJob {
 
 
     private static ExecutorService productDailyRetrExecutor = Executors.newFixedThreadPool(2);
     private static ExecutorService productDailyRetrExecutor = Executors.newFixedThreadPool(2);
 
 
+    private static ExecutorService flowDailyRetrExecutor = Executors.newFixedThreadPool(2);
+
 
 
     @XxlJob("retryReport")
     @XxlJob("retryReport")
     public void retryReport() throws Exception {
     public void retryReport() throws Exception {
@@ -115,6 +122,14 @@ public class BytedanceReportRetryJob {
                         });
                         });
                     }
                     }
 
 
+                } else if ("flow_details".equals(dataDimension)) { //日报流水详情
+                    flowDailyRetrExecutor.submit(new Runnable() {
+
+                        @Override
+                        public void run() {
+                            byteDanceFlowDetailsReportService.getBytedanceFlowDetailsDailyReport(advertiserId, accessToken, AccountTypeEnum.AD.getValue(), startDate, endDate, 1, id);
+                        }
+                    });
                 }
                 }
 
 
 
 
@@ -147,6 +162,23 @@ public class BytedanceReportRetryJob {
             log.info("常读重试列表为空");
             log.info("常读重试列表为空");
         }
         }
 
 
+        List<JSONObject> maEcpmRetryJob = miniAppService.getMaEcpmRetryJob();
+        if (!Check.isNull(maEcpmRetryJob)) {
+            for (int i = 0; i < maEcpmRetryJob.size(); i++) {
+                JSONObject jsonObject = maEcpmRetryJob.get(i);
+                Long id = jsonObject.getLong("id");
+                String startDate = jsonObject.getString("startDate");
+                String endDate = jsonObject.getString("endDate");
+                String dataDimension = jsonObject.getString("dataDimension");
+                Integer isSend = jsonObject.getInteger("isSend");
+                if (dataDimension != null && dataDimension.startsWith("ma_ecpm:")) {
+                    String appId = dataDimension.split(":")[1];
+                    miniAppService.getMaEcpm(startDate, endDate, appId, 1, id, isSend);
+                }
+            }
+        } else {
+            log.info("抖小IAA重试列表为空");
+        }
 
 
     }
     }
 
 

+ 12 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/handler/FeishuPushJob.java

@@ -21,6 +21,8 @@ public class FeishuPushJob {
     ITotalRankPushService totalRankPushService;
     ITotalRankPushService totalRankPushService;
     @Autowired
     @Autowired
     IDateReportsPushService dateReportsPushService;
     IDateReportsPushService dateReportsPushService;
+    @Autowired
+    IUserLoginRecordService userLoginRecordService;
 
 
     @XxlJob("unbindWarnPush")
     @XxlJob("unbindWarnPush")
     public void unbindWarnPush(){
     public void unbindWarnPush(){
@@ -46,4 +48,14 @@ public class FeishuPushJob {
     public void dateReportsPush(){
     public void dateReportsPush(){
         dateReportsPushService.send();
         dateReportsPushService.send();
     }
     }
+
+    @XxlJob("loginRecordPush")
+    public void loginRecordPush(){
+        userLoginRecordService.queryUserLoginRecord();
+    }
+
+    @XxlJob("preDateReportsPush")
+    public void preDataReportsPush(){
+        dateReportsPushService.preSend();
+    }
 }
 }

+ 62 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/utils/FeishuRobotUtil.java

@@ -80,6 +80,23 @@ public class FeishuRobotUtil {
         if (Check.isNull(telephones)){
         if (Check.isNull(telephones)){
             return null;
             return null;
         }
         }
+        Map<String, String> map = new HashMap<>();
+        int size = telephones.size();
+        int pageSize = 30;
+        int pageNum = size / pageSize + (size % pageSize == 0 ? 0 : 1);
+        for (int i = 0; i < pageNum; i++) {
+            int start = i * pageSize;
+            int end = Math.min(start + pageSize, size);
+            List<String> subList = telephones.subList(start, end);
+            Map<String, String> subMap = getFsUserIdOnePage(token, subList);
+            if (!Check.isNull(subMap)){
+                map.putAll(subMap);
+            }
+        }
+        return map;
+    }
+
+    private static Map<String, String> getFsUserIdOnePage(String token, List<String> telephones) throws IOException {
         //获取token
         //获取token
         String url = "https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id?user_id_type=user_id";
         String url = "https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id?user_id_type=user_id";
         HttpPost httpPost = new HttpPost(url);
         HttpPost httpPost = new HttpPost(url);
@@ -114,4 +131,49 @@ public class FeishuRobotUtil {
             return null;
             return null;
         }
         }
     }
     }
+
+    public static void sendTextToDt(String text, List<String> userIds) throws IOException {
+        JSONObject content = new JSONObject();
+        content.put("text", text);
+        String token = getFsZtTenantToken();
+
+        for (String userId : userIds){
+            JSONObject request = new JSONObject();
+            request.put("receive_id", userId);
+            request.put("msg_type", "text");
+            request.put("content", content.toJSONString());
+            //发送
+            try (CloseableHttpClient client = HttpClients.createDefault()){
+                HttpPost httpPost = new HttpPost("https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id");
+                httpPost.setHeader("Authorization", "Bearer "+token);
+                HttpEntity entity = new StringEntity(request.toJSONString(), "UTF-8");
+                httpPost.setEntity(entity);
+                httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
+                CloseableHttpResponse respon = client.execute(httpPost);
+//            System.out.println("发送结果: "+ EntityUtils.toString(respon.getEntity(), "UTF-8"));
+            }catch (IOException e){
+                System.out.println("发送飞书消息失败");
+            }
+        }
+    }
+
+    public static void sendTextToWebhook(String text, String url) throws IOException {
+        JSONObject content = new JSONObject();
+        content.put("text", text);
+        JSONObject request = new JSONObject();
+        request.put("msg_type", "text");
+        request.put("content", content.toJSONString());
+        //发送
+        try (CloseableHttpClient client = HttpClients.createDefault()){
+            HttpPost httpPost = new HttpPost(url);
+            HttpEntity entity = new StringEntity(request.toJSONString(), "UTF-8");
+            httpPost.setEntity(entity);
+            httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
+            CloseableHttpResponse respon = client.execute(httpPost);
+//            System.out.println("发送结果: "+ EntityUtils.toString(respon.getEntity(), "UTF-8"));
+        }catch (IOException e){
+            System.out.println("发送飞书消息失败");
+        }
+
+    }
 }
 }

+ 206 - 0
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/utils/Redis2Config.java

@@ -0,0 +1,206 @@
+package cn.com.ctop.job.bytedance.utils;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import redis.clients.jedis.JedisPoolConfig;
+
+@Configuration
+public class Redis2Config {
+
+    @Value("${spring.redis2.host}")
+    private String host;
+
+    @Value("${spring.redis2.port}")
+    private int port;
+
+    @Value("${spring.redis2.database}")
+    private int database;
+
+    @Value("${spring.redis2.password}")
+    private String password;
+
+    @Value("${spring.redis2.pool.max-idle}")
+    private int maxIdle;
+
+    @Value("${spring.redis2.pool.min-idle}")
+    private int minIdle;
+
+    @Value("${spring.redis2.pool.max-active}")
+    private int maxActive;
+
+    @Value("${spring.redis2.pool.max-wait}")
+    private int maxWait;
+
+
+    /**
+     * JedisPoolConfig 连接池
+     * @return
+     */
+    public JedisPoolConfig redis2PoolConfig() {
+        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+        // 最大空闲数
+        jedisPoolConfig.setMaxIdle(maxIdle);
+        jedisPoolConfig.setMinIdle(minIdle);
+        // 连接池的最大数据库连接数
+        jedisPoolConfig.setMaxTotal(maxActive);
+        // 最大建立连接等待时间
+        jedisPoolConfig.setMaxWaitMillis(maxWait);
+        return jedisPoolConfig;
+    }
+
+    private JedisConnectionFactory redis2ConnectionFactory(JedisPoolConfig redisPoolConfig, int database){
+
+        JedisConnectionFactory JedisConnectionFactory = new JedisConnectionFactory(redisPoolConfig);
+
+        JedisConnectionFactory.setHostName(host);
+        JedisConnectionFactory.setPort(port);
+        JedisConnectionFactory.setPassword(password);
+        JedisConnectionFactory.setDatabase(database);
+        JedisConnectionFactory.afterPropertiesSet();
+        return JedisConnectionFactory;
+    }
+
+    private RedisTemplate buildRedis2Template(RedisConnectionFactory connectionFactory){
+
+        RedisTemplate template = new RedisTemplate();
+        template.setConnectionFactory(connectionFactory);
+
+        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+
+        template.setKeySerializer(stringSerializer);
+        template.setValueSerializer(stringSerializer);
+        template.setHashKeySerializer(stringSerializer);
+        template.setHashValueSerializer(jackson2JsonRedisSerializer);
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
+    @Bean(name = "redis2TemplateDefault")
+    public RedisTemplate redis2TemplateDefault() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), database));
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    @Bean(name = "redis2Template_db2")
+    public RedisTemplate redis2Template_db2() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), 2));
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    @Bean(name = "redis2Template_db5")
+    public RedisTemplate redis2Template_db5() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), 5));
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    @Bean(name = "redis2Template_db6")
+    public RedisTemplate redis2Template_db6() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), 6));
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    @Bean(name = "redis2Template_db7")
+    public RedisTemplate redis2Template_db7() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), 7));
+        return redisTemplate;
+    }
+
+    @Bean(name = "redis2Template_db8")
+    public RedisTemplate redis2Template_db8() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), 8));
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    @Bean(name = "redis2Template_db9")
+    public RedisTemplate redis2Template_db9() {
+        RedisTemplate redisTemplate = buildRedis2Template(redis2ConnectionFactory(redis2PoolConfig(), 9));
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public void setDatabase(int database) {
+        this.database = database;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public void setMaxIdle(int maxIdle) {
+        this.maxIdle = maxIdle;
+    }
+
+    public void setMinIdle(int minIdle) {
+        this.minIdle = minIdle;
+    }
+
+    public void setMaxActive(int maxActive) {
+        this.maxActive = maxActive;
+    }
+
+    public void setMaxWait(int maxWait) {
+        this.maxWait = maxWait;
+    }
+
+    public String getHost() {
+
+        return host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public int getDatabase() {
+        return database;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public int getMaxIdle() {
+        return maxIdle;
+    }
+
+    public int getMinIdle() {
+        return minIdle;
+    }
+
+    public int getMaxActive() {
+        return maxActive;
+    }
+
+    public int getMaxWait() {
+        return maxWait;
+    }
+}

+ 11 - 1
job-bytedance/src/main/resources/application.yml

@@ -81,7 +81,7 @@ spring:
       datasource:
       datasource:
         master:
         master:
           url: jdbc:mysql://172.16.0.117:3390/media_api?characterEncoding=UTF-8&useUnicode=true&useSSL=false
           url: jdbc:mysql://172.16.0.117:3390/media_api?characterEncoding=UTF-8&useUnicode=true&useSSL=false
-         # url: jdbc:mysql://8.147.135.80:3390/media_api?characterEncoding=UTF-8&useUnicode=true&allowMultiQueries=true&useSSL=false
+          #url: jdbc:mysql://8.147.135.80:3390/media_api?characterEncoding=UTF-8&useUnicode=true&allowMultiQueries=true&useSSL=false
           username: data
           username: data
           password: hr@2025..
           password: hr@2025..
           driver-class-name: com.mysql.jdbc.Driver
           driver-class-name: com.mysql.jdbc.Driver
@@ -109,6 +109,16 @@ spring:
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
         max-wait: -1ms
         max-wait: -1ms
 
 
+  redis2:
+    database: 0
+    host: r-2zelacjrljt205nsb1pd.redis.rds.aliyuncs.com
+    password: Huanrui@2025!@
+    pool:
+      max-active: 10
+      max-idle: 10
+      max-wait: 80
+      min-idle: 8
+    port: 6379
 
 
 
 
 #mybatis plus 设置
 #mybatis plus 设置