pudongliang 4 месяцев назад
Родитель
Сommit
b5bb1149c1
29 измененных файлов с 2180 добавлено и 170 удалено
  1. 1 1
      portal/src/views/ad-plan-conf/index.vue
  2. 1 1
      src/main/java/com/moka/gdtauto/BaseCodeGenerator.java
  3. 88 0
      src/main/java/com/moka/gdtauto/controller/DailyAdgroupReportController.java
  4. 11 5
      src/main/java/com/moka/gdtauto/controller/DailyCreativeReportController.java
  5. 416 0
      src/main/java/com/moka/gdtauto/entity/BaseDailyAdgroupReport.java
  6. 6 4
      src/main/java/com/moka/gdtauto/entity/BaseDailyCreativeReport.java
  7. 21 0
      src/main/java/com/moka/gdtauto/entity/RepDailyAdgroupReport.java
  8. 21 0
      src/main/java/com/moka/gdtauto/entity/ReqDailyAdgroupReport.java
  9. 18 0
      src/main/java/com/moka/gdtauto/mapper/RepDailyAdgroupReportMapper.java
  10. 12 2
      src/main/java/com/moka/gdtauto/mapper/RepDailyCreativeReportMapper.java
  11. 18 0
      src/main/java/com/moka/gdtauto/mapper/ReqDailyAdgroupReportMapper.java
  12. 12 2
      src/main/java/com/moka/gdtauto/mapper/ReqDailyCreativeReportMapper.java
  13. 3 0
      src/main/java/com/moka/gdtauto/service/AdPlanService.java
  14. 55 53
      src/main/java/com/moka/gdtauto/service/DailyAdgroupReportService.java
  15. 436 0
      src/main/java/com/moka/gdtauto/service/DailyCreativeReportService.java
  16. 16 0
      src/main/java/com/moka/gdtauto/service/RepDailyAdgroupReportService.java
  17. 16 0
      src/main/java/com/moka/gdtauto/service/ReqDailyAdgroupReportService.java
  18. 21 0
      src/main/java/com/moka/gdtauto/service/impl/AdPlanServiceImpl.java
  19. 20 0
      src/main/java/com/moka/gdtauto/service/impl/RepDailyAdgroupReportServiceImp.java
  20. 20 0
      src/main/java/com/moka/gdtauto/service/impl/ReqDailyAdgroupReportServiceImp.java
  21. 16 16
      src/main/java/com/moka/gdtauto/task/DailyReportSyncTask.java
  22. 6 7
      src/main/java/com/moka/gdtauto/util/TargetConfUtil.java
  23. 198 0
      src/main/resources/mapper/RepDailyAdgroupReportMapper.xml
  24. 202 2
      src/main/resources/mapper/RepDailyCreativeReportMapper.xml
  25. 198 0
      src/main/resources/mapper/ReqDailyAdgroupReportMapper.xml
  26. 202 2
      src/main/resources/mapper/ReqDailyCreativeReportMapper.xml
  27. 13 0
      src/test/java/com/moka/gdtauto/service/AdPlanDailyReportSyncTest.java
  28. 133 0
      src/test/java/com/moka/gdtauto/service/AdPlanServiceTest.java
  29. 0 75
      src/test/java/com/moka/gdtauto/service/DailyReportTest.java

+ 1 - 1
portal/src/views/ad-plan-conf/index.vue

@@ -286,7 +286,7 @@
                 年龄:大于等于50岁<br />
                 性别:男性<br />
                 排除已转化用户:同集团(自定义转化行为:指定页面曝光,加企业微信客服)(转化时间区间:1个月)<br />
-                排除人群:44241932, 44135417, 44107982, 43712084<br />
+                排除人群:44106830,44107982,43712084,44241932<br />
                 不限:学历,婚恋育儿状态,用户消费能力,应用安装,设备品牌型号,操作系统版本,联网方式,移动运营商,定向人群,设备价格,微信再营销
               </p>
             </el-collapse-item>

+ 1 - 1
src/main/java/com/moka/gdtauto/BaseCodeGenerator.java

@@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
 
 public class BaseCodeGenerator {
 
-    public final static String TABLE_NAMES = "ad_auto_execute_log";
+    public final static String TABLE_NAMES = "rep_daily_adgroup_report,req_daily_adgroup_report";
     public static void main(String[] args) {
         String url = "jdbc:mysql://rm-uf65d6xsxrp743w3aio.mysql.rds.aliyuncs.com:3306/gdt_auto?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true";
         FastAutoGenerator.create(url, "gdt_auto", "QA_GDT_AUTO%$PDL")

+ 88 - 0
src/main/java/com/moka/gdtauto/controller/DailyAdgroupReportController.java

@@ -0,0 +1,88 @@
+package com.moka.gdtauto.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.moka.gdtauto.annotation.AuthUser;
+import com.moka.gdtauto.common.Result;
+import com.moka.gdtauto.entity.BaseDailyAdgroupReport;
+import com.moka.gdtauto.entity.SysUser;
+import com.moka.gdtauto.service.DailyAdgroupReportService;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 广告日报表 Controller
+ *
+ * @author moka
+ * @since 2026-03-03
+ */
+@Tag(name = "广告日报表", description = "双口径(REQUEST_TIME/REPORTING_TIME)动态创意日报表查询与同步")
+@Slf4j
+@RestController
+@RequestMapping("/api/gdt/daily-adgroup-report")
+@RequiredArgsConstructor
+public class DailyAdgroupReportController {
+
+    private final DailyAdgroupReportService dailyReportService;
+
+    /**
+     * 手动触发同步(指定账户、日期范围、时间口径)
+     */
+    @Operation(summary = "手动同步日报表", description = "指定账户和日期范围,将腾讯广告日报数据同步到本地数据库")
+    @PostMapping("/sync")
+    public Result<Void> sync(
+            @Parameter(description = "工号") @RequestParam String jobNumber,
+            @Parameter(description = "组织账户ID") @RequestParam Long orgAccountId,
+            @Parameter(description = "广告账户ID") @RequestParam Long accountId,
+            @Parameter(description = "账号组ID") @RequestParam(defaultValue = "0") Long groupId,
+            @Parameter(description = "账号组名称") @RequestParam(required = false) String groupName,
+            @Parameter(description = "开始日期 yyyy-MM-dd") @RequestParam String startDate,
+            @Parameter(description = "结束日期 yyyy-MM-dd") @RequestParam String endDate,
+            @Parameter(description = "时间口径 REQUEST_TIME / REPORTING_TIME")
+            @RequestParam(defaultValue = "REQUEST_TIME") String timeLine,
+            @AuthUser SysUser user) {
+        try {
+            int saved = dailyReportService.syncReport(jobNumber, orgAccountId, accountId,
+                    groupId, groupName, startDate, endDate, timeLine);
+            return Result.<Void>success("同步成功,共写入 " + saved + " 条数据").withCount(saved);
+        } catch (Exception e) {
+            log.error("日报表同步失败 accountId={} timeLine={}", accountId, timeLine, e);
+            return Result.fail("同步失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 分页查询日报表
+     */
+    @Operation(summary = "查询日报表列表", description = "分页查询指定口径的动态创意日报数据")
+    @GetMapping("/list")
+    public Result<?> list(
+            @Parameter(description = "时间口径 REQUEST_TIME / REPORTING_TIME")
+            @RequestParam(defaultValue = "REQUEST_TIME") String timeLine,
+            @Parameter(description = "账号组ID(可选)") @RequestParam(required = false) Long groupId,
+            @Parameter(description = "广告账户ID(可选)") @RequestParam(required = false) Long accountId,
+            @Parameter(description = "动态创意ID(可选)") @RequestParam(required = false) Long dynamicCreativeId,
+            @Parameter(description = "开始日期 yyyy-MM-dd(可选)") @RequestParam(required = false) String startDate,
+            @Parameter(description = "结束日期 yyyy-MM-dd(可选)") @RequestParam(required = false) String endDate,
+            @Parameter(description = "页码") @RequestParam(defaultValue = "1") long page,
+            @Parameter(description = "每页数量") @RequestParam(defaultValue = "20") long pageSize) {
+        try {
+            Page<? extends BaseDailyAdgroupReport> result =
+                    dailyReportService.listReports(timeLine, groupId, accountId, dynamicCreativeId, startDate, endDate, page, pageSize);
+            return Result.success(result.getRecords(), "查询成功")
+                    .withPage(page, pageSize, result.getTotal());
+        } catch (Exception e) {
+            log.error("查询日报表失败 timeLine={} groupId={} accountId={} dynamicCreativeId={}", timeLine, groupId, accountId, dynamicCreativeId, e);
+            return Result.fail("查询失败:" + e.getMessage());
+        }
+    }
+}

+ 11 - 5
src/main/java/com/moka/gdtauto/controller/DailyReportController.java → src/main/java/com/moka/gdtauto/controller/DailyCreativeReportController.java

@@ -1,17 +1,23 @@
 package com.moka.gdtauto.controller;
 
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.moka.gdtauto.annotation.AuthUser;
 import com.moka.gdtauto.common.Result;
 import com.moka.gdtauto.entity.BaseDailyCreativeReport;
 import com.moka.gdtauto.entity.SysUser;
-import com.moka.gdtauto.service.DailyReportService;
+import com.moka.gdtauto.service.DailyCreativeReportService;
+
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 动态创意日报表 Controller
@@ -22,11 +28,11 @@ import org.springframework.web.bind.annotation.*;
 @Tag(name = "动态创意日报表", description = "双口径(REQUEST_TIME/REPORTING_TIME)动态创意日报表查询与同步")
 @Slf4j
 @RestController
-@RequestMapping("/api/gdt/daily-report")
+@RequestMapping("/api/gdt/daily-creative-report")
 @RequiredArgsConstructor
-public class DailyReportController {
+public class DailyCreativeReportController {
 
-    private final DailyReportService dailyReportService;
+    private final DailyCreativeReportService dailyReportService;
 
     /**
      * 手动触发同步(指定账户、日期范围、时间口径)

+ 416 - 0
src/main/java/com/moka/gdtauto/entity/BaseDailyAdgroupReport.java

@@ -0,0 +1,416 @@
+package com.moka.gdtauto.entity;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import lombok.Data;
+
+/**
+ * 动态创意日报表 - 基类(供 req/rep 两张表共用)
+ *
+ * @author moka
+ * @since 2026-03-03
+ */
+@Data
+public abstract class BaseDailyAdgroupReport {
+
+    /** 主键ID */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /** 广告主账号ID */
+    private Long accountId;
+
+    private Long adgroupId;
+    private String adgroupName;
+
+    /** 账号组ID(来自 AccountGroup.id) */
+    private Long groupId;
+
+    /** 账号组名称 */
+    private String groupName;
+
+    /** 日期 */
+    private LocalDate date;
+
+    // ── 基础曝光点击 ──────────────────────────────────────────────────────────
+    /** 曝光次数 */
+    private Long viewCount;
+    /** 曝光人数 */
+    private Long viewUserCount;
+    /** 人均曝光次数 */
+    private BigDecimal avgViewPerUser;
+    /** 点击次数 */
+    private Long validClickCount;
+    /** 点击人数 */
+    private Long clickUserCount;
+    /** 点击均价(分) */
+    private Long cpc;
+    /** 点击率 */
+    private BigDecimal ctr;
+    /** 可转化点击次数 */
+    private Long valuableClickCount;
+    /** 可转化点击成本(分) */
+    private Long valuableClickCost;
+    /** 可转化点击率 */
+    private BigDecimal valuableClickRate;
+
+    // ── 花费 ─────────────────────────────────────────────────────────────────
+    /** 花费(分) */
+    private Long cost;
+    /** 一键起量消耗(分) */
+    private Long acquisitionCost;
+    /** 千次展现均价(分) */
+    private Long thousandDisplayPrice;
+
+    // ── 转化 ─────────────────────────────────────────────────────────────────
+    /** 目标转化量 */
+    private Long conversionsCount;
+    /** 目标转化率 */
+    private BigDecimal conversionsRate;
+    /** 目标转化成本(分) */
+    private Long conversionsCost;
+    /** 深度目标转化量 */
+    private Long deepConversionsCount;
+    /** 深度目标转化率 */
+    private BigDecimal deepConversionsRate;
+    /** 深度转化成本(分) */
+    private Long deepConversionsCost;
+    /** 目标转化量(曝光归因) */
+    private Long conversionsByDisplayCount;
+    /** 目标转化率(曝光归因) */
+    private BigDecimal conversionsByDisplayRate;
+    /** 目标转化成本(曝光归因,分) */
+    private Long conversionsByDisplayCost;
+    /** 目标转化量(点击归因) */
+    private Long conversionsByClickCount;
+    /** 目标转化率(点击归因) */
+    private BigDecimal conversionsByClickRate;
+    /** 目标转化成本(点击归因,分) */
+    private Long conversionsByClickCost;
+    /** 目标转化量(在线预览) */
+    private Long previewConversionsCount;
+    /** 深度目标转化量(在线预览) */
+    private Long previewDeepConversionsCount;
+
+    // ── 视频播放 ──────────────────────────────────────────────────────────────
+    /** 视频有效播放次数 */
+    private Long videoOuterPlayCount;
+    /** 视频有效播放人数 */
+    private Long videoOuterPlayUserCount;
+    /** 人均播放次数 */
+    private BigDecimal avgUserPlayCount;
+    /** 平均有效播放时长(秒) */
+    private BigDecimal videoOuterPlayTimeCount;
+    /** 平均有效播放进度 */
+    private BigDecimal videoOuterPlayTimeAvgRate;
+    /** 有效播放率 */
+    private BigDecimal videoOuterPlayRate;
+    /** 有效播放成本(分) */
+    private Long videoOuterPlayCost;
+    /** 10%进度播放次数 */
+    private Long videoOuterPlay10Count;
+    /** 25%进度播放次数 */
+    private Long videoOuterPlay25Count;
+    /** 50%进度播放次数 */
+    private Long videoOuterPlay50Count;
+    /** 75%进度播放次数 */
+    private Long videoOuterPlay75Count;
+    /** 90%进度播放次数 */
+    private Long videoOuterPlay90Count;
+    /** 95%进度播放次数 */
+    private Long videoOuterPlay95Count;
+    /** 100%进度播放次数 */
+    private Long videoOuterPlay100Count;
+    /** 3s播放完成次数 */
+    private Long videoOuterPlay3sCount;
+    /** 3s播放完成率 */
+    private BigDecimal videoOuterPlay3sRate;
+    /** 5s播放完成次数 */
+    private Long videoOuterPlay5sCount;
+    /** 7s播放完成次数 */
+    private Long videoOuterPlay7sCount;
+
+    // ── 互动 ─────────────────────────────────────────────────────────────────
+    /** 阅读次数 */
+    private Long readCount;
+    /** 阅读成本(分) */
+    private Long readCost;
+    /** 评论次数 */
+    private Long commentCount;
+    /** 评论成本(分) */
+    private Long commentCost;
+    /** 点赞次数 */
+    private Long praiseCount;
+    /** 点赞成本(分) */
+    private Long praiseCost;
+    /** 分享次数 */
+    private Long forwardCount;
+    /** 分享成本(分) */
+    private Long forwardCost;
+    /** 不感兴趣点击次数 */
+    private Long noInterestCount;
+
+    // ── 素材点击 ──────────────────────────────────────────────────────────────
+    /** 素材点击次数 */
+    private Long liveStreamCrtClickCnt;
+    /** 外层图片点击次数 */
+    private Long clickImageCount;
+    /** 头像点击次数 */
+    private Long clickHeadCount;
+    /** 文字链点击次数 */
+    private Long clickDetailCount;
+    /** 本地门店点击次数 */
+    private Long clickPoiCount;
+    /** 顶部运营位点击次数 */
+    private Long zoneHeaderClickCount;
+    /** 官方信息区点击次数 */
+    private Long basicInfoClientCount;
+    /** 官方账号区点击次数 */
+    private Long accountInfoClickCount;
+    /** 官方账号区直播中头像点击次数 */
+    private Long clkAccountLivingStatusPv;
+    /** 官方账号区小程序组件点击次数 */
+    private Long clkAccountinfoWeappPv;
+    /** 官方账号区视频号组件点击次数 */
+    private Long clkAccountinfoFinderPv;
+    /** 官方账号区公众号组件点击次数 */
+    private Long clkAccountinfoBizPv;
+    /** 官方账号区系列tab总点击次数 */
+    private Long clkAccountInfoProducttabPv;
+    /** 官方账号区商品卡总点击次数 */
+    private Long clkAccountInfoProductdetailPv;
+    /** 热门活动区点击次数 */
+    private Long activityInfoClickCount;
+
+    // ── 线索 ─────────────────────────────────────────────────────────────────
+    /** 综合销售线索人数 */
+    private Long overallLeadsPurchaseCount;
+    /** 有效线索次数 */
+    private Long effectiveLeadsCount;
+    /** 有效线索成本(分) */
+    private Long effectiveCost;
+    /** 有效线索人数 */
+    private Long effectLeadsPurchaseCount;
+    /** 有效线索成本人数(分) */
+    private Long effectLeadsPurchaseCost;
+
+    // ── 落地页 ────────────────────────────────────────────────────────────────
+    /** 落地页曝光次数 */
+    private Long platformPageViewCount;
+    /** 落地页曝光率 */
+    private BigDecimal platformPageViewRate;
+    /** 落地页组件点击次数 */
+    private Long lanButtonClickCount;
+    /** 落地页组件点击人数 */
+    private Long lanJumpButtonClickers;
+    /** 落地页点击成本(分) */
+    private Long lanButtonClickCost;
+    /** 落地页点击率(人数) */
+    private BigDecimal lanJumpButtonCtr;
+    /** 落地页点击成本人数(分) */
+    private Long lanJumpButtonClickCost;
+
+    // ── 关键页面 ──────────────────────────────────────────────────────────────
+    /** 关键页面访问次数 */
+    private Long keyPageViewCount;
+    /** 关键页面访问次数(曝光归因) */
+    private Long keyPageViewByDisplayCount;
+    /** 关键页面访问次数(点击归因) */
+    private Long keyPageViewByClickCount;
+    /** 关键页面访问人数 */
+    private Long keyPageUv;
+    /** 关键页面访问成本(分) */
+    private Long keyPageViewCost;
+    /** 关键页面访问率 */
+    private BigDecimal keyPageViewRate;
+
+    // ── 商品页 ────────────────────────────────────────────────────────────────
+    /** 商品页浏览次数 */
+    private Long landingCommodityDetailExpPv;
+    /** 商品页浏览次数(曝光归因) */
+    private Long appCommodityPageViewByDisplayCount;
+    /** 商品页浏览次数(点击归因) */
+    private Long appCommodityPageViewByClickCount;
+    /** 商品页浏览人数 */
+    private Long viewCommodityPageUv;
+    /** 商品页浏览率 */
+    private BigDecimal webCommodityPageViewRate;
+    /** 商品页浏览成本(分) */
+    private Long webCommodityPageViewCost;
+
+    // ── 导航 ─────────────────────────────────────────────────────────────────
+    /** 自有页导航次数 */
+    private Long ownPageNavigationCount;
+    /** 自有页导航成本(分) */
+    private Long ownPageNaviCost;
+    /** 平台页导航次数 */
+    private Long platformPageNavigationCount;
+    /** 平台页导航成本(分) */
+    private Long platformPageNavigationCost;
+    /** 平台页门店点击次数 */
+    private Long platformShopNavigationCount;
+    /** 平台页门店页导航成本(分) */
+    private Long platformShopNavigationCost;
+
+    // ── 活动页/加粉 ───────────────────────────────────────────────────────────
+    /** 活动页面访问次数 */
+    private Long activePageViews;
+    /** 活动页面访问人数 */
+    private Long activePageViewers;
+    /** 活动页面互动次数 */
+    private Long activePageInteractionAmount;
+    /** 活动页面互动人数 */
+    private Long activePageInteractionUsers;
+    /** 加粉引导页浏览次数 */
+    private Long guideToFollowPageViews;
+    /** 加粉引导页浏览人数 */
+    private Long guideToFollowPageViewers;
+    /** 加粉引导页互动次数 */
+    private Long guideToFollowPageInteractionAmount;
+    /** 加粉引导页互动人数 */
+    private Long guideToFollowPageInteractionUsers;
+    /** 落地页曝光人数 */
+    private Long platformKeyPageViewUserCount;
+
+    // ── 在线咨询 ──────────────────────────────────────────────────────────────
+    /** 在线咨询次数 */
+    private Long pageConsultCount;
+    /** 在线咨询人数 */
+    private Long consultUvCount;
+    /** 在线咨询率 */
+    private BigDecimal pageConsultRate;
+    /** 在线咨询成本(分) */
+    private Long pageConsultCost;
+    /** 咨询留资人数 */
+    private Long consultLeaveInfoUsers;
+    /** 咨询留咨成本(分) */
+    private Long consultLeaveInfoCost;
+    /** 潜在客户线索次数-咨询 */
+    private Long potentialConsultCount;
+    /** 有效线索次数-咨询 */
+    private Long effectiveConsultCount;
+    /** 附加创意智能咨询次数 */
+    private Long toolConsultCount;
+
+    // ── 表单预约 ──────────────────────────────────────────────────────────────
+    /** 表单预约次数 */
+    private Long pageReservationCount;
+    /** 表单预约次数(曝光归因) */
+    private Long pageReservationByDisplayCount;
+    /** 表单预约次数(点击归因) */
+    private Long pageReservationByClickCount;
+    /** 表单预约人数 */
+    private Long reservationUv;
+    /** 表单预约金额(分) */
+    private Long reservationAmount;
+    /** 表单预约成本(分) */
+    private Long pageReservationCost;
+    /** 表单预约成本人数(分) */
+    private Long pageReservationCostWithPeople;
+    /** 表单预约率 */
+    private BigDecimal pageReservationRate;
+    /** 表单预约ROI */
+    private BigDecimal pageReservationRoi;
+    /** 公众号内表单预约人数 */
+    private Long bizReservationUv;
+    /** 公众号内表单预约率 */
+    private BigDecimal bizReservationFollowRate;
+    /** 附加创意表单预约次数 */
+    private Long externalFormReservationCount;
+    /** 潜在客户线索次数-表单 */
+    private Long potentialReserveCount;
+    /** 意向表单人数 */
+    private Long reservationCheckUv;
+    /** 意向表单成本(分) */
+    private Long reservationCheckUvCost;
+    /** 意向表单率(人数) */
+    private BigDecimal reservationCheckUvRate;
+    /** 有效线索次数-表单 */
+    private Long effectiveReserveCount;
+    /** 有效线索人数-表单 */
+    private Long validLeadsUv;
+    /** 排程人数 */
+    private Long tryOutIntentionUv;
+    /** 无效线索人数 */
+    private Long ineffectiveLeadsUv;
+
+    // ── 优惠券 ────────────────────────────────────────────────────────────────
+    /** 领券次数 */
+    private Long couponGetPv;
+    /** 领券成本(分) */
+    private Long couponGetCost;
+    /** 领券率 */
+    private BigDecimal couponGetRate;
+    /** 平台页卡券点击次数 */
+    private Long platformCouponClickCount;
+    /** 平台页卡券购买次数 */
+    private Long purchaseAmountWithCoupon;
+    /** 平台页卡券购买率 */
+    private BigDecimal couponPurchaseRate;
+    /** 平台页卡券购买成本(分) */
+    private Long purchaseAmountWithCouponCost;
+    /** 优惠券使用次数 */
+    private Long couponUsageNumber;
+
+    // ── 电话直拨 ──────────────────────────────────────────────────────────────
+    /** 电话直拨次数 */
+    private Long pagePhoneCallDirectCount;
+    /** 电话直拨率 */
+    private BigDecimal pagePhoneCallDirectRate;
+    /** 电话直拨成本(分) */
+    private Long pagePhoneCallDirectCost;
+    /** 潜在客户线索次数-电话 */
+    private Long potentialPhoneCount;
+    /** 潜在客户人数-电话 */
+    private Long potentialCustomerPhoneUv;
+    /** 有效线索次数-电话 */
+    private Long effectivePhoneCount;
+    /** 有效线索人数-电话 */
+    private Long validPhoneUv;
+
+    // ── ROI收益(LTV) ────────────────────────────────────────────────────────
+    /** 1天收益(分) */
+    @TableField("income_val_1")
+    private Long incomeVal1;
+    /** 1天ROI */
+    @TableField("income_roi_1")
+    private BigDecimal incomeRoi1;
+    /** 3天收益(分) */
+    @TableField("income_val_3")
+    private Long incomeVal3;
+    /** 3天ROI */
+    @TableField("income_roi_3")
+    private BigDecimal incomeRoi3;
+    /** 7天收益(分) */
+    @TableField("income_val_7")
+    private Long incomeVal7;
+    /** 7天ROI */
+    @TableField("income_roi_7")
+    private BigDecimal incomeRoi7;
+    /** 14天收益(分) */
+    @TableField("income_val_14")
+    private Long incomeVal14;
+    /** 14天ROI */
+    @TableField("income_roi_14")
+    private BigDecimal incomeRoi14;
+    /** 24小时收益(分) */
+    @TableField("income_val_24h")
+    private Long incomeVal24h;
+    /** 1天24小时ROI */
+    @TableField("income_roi_1_24h")
+    @com.alibaba.fastjson2.annotation.JSONField(name = "incomeRoi124h")
+    private BigDecimal incomeRoi124h;
+
+    // ── 审计字段 ──────────────────────────────────────────────────────────────
+    /** 创建时间 */
+    private LocalDateTime createdTime;
+
+    /** 更新时间 */
+    private LocalDateTime updatedTime;
+}

+ 6 - 4
src/main/java/com/moka/gdtauto/entity/BaseDailyCreativeReport.java

@@ -1,13 +1,14 @@
 package com.moka.gdtauto.entity;
 
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
-import lombok.Data;
 
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
+import lombok.Data;
 
 /**
  * 动态创意日报表 - 基类(供 req/rep 两张表共用)
@@ -33,6 +34,7 @@ public abstract class BaseDailyCreativeReport {
 
     /** 动态创意ID */
     private Long dynamicCreativeId;
+    private String dynamicCreativeName;
 
     /** 日期 */
     private LocalDate date;

+ 21 - 0
src/main/java/com/moka/gdtauto/entity/RepDailyAdgroupReport.java

@@ -0,0 +1,21 @@
+package com.moka.gdtauto.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * <p>
+ * 广告日报表(统计时间口径 REPORTING_TIME)
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+@Getter
+@Setter
+@ToString
+@TableName("rep_daily_adgroup_report")
+public class RepDailyAdgroupReport extends BaseDailyAdgroupReport {}

+ 21 - 0
src/main/java/com/moka/gdtauto/entity/ReqDailyAdgroupReport.java

@@ -0,0 +1,21 @@
+package com.moka.gdtauto.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * <p>
+ * 广告日报表(请求时间口径 REQUEST_TIME)
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+@Getter
+@Setter
+@ToString
+@TableName("req_daily_adgroup_report")
+public class ReqDailyAdgroupReport extends BaseDailyAdgroupReport {}

+ 18 - 0
src/main/java/com/moka/gdtauto/mapper/RepDailyAdgroupReportMapper.java

@@ -0,0 +1,18 @@
+package com.moka.gdtauto.mapper;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.moka.gdtauto.entity.RepDailyAdgroupReport;
+
+/**
+ * <p>
+ * 广告日报表(统计时间口径 REPORTING_TIME) Mapper 接口
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+public interface RepDailyAdgroupReportMapper extends BaseMapper<RepDailyAdgroupReport> {
+    void upsert(@Param("report") RepDailyAdgroupReport report);
+}

+ 12 - 2
src/main/java/com/moka/gdtauto/mapper/RepDailyCreativeReportMapper.java

@@ -1,10 +1,13 @@
 package com.moka.gdtauto.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.moka.gdtauto.entity.RepDailyCreativeReport;
+import java.util.List;
+
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.moka.gdtauto.entity.RepDailyCreativeReport;
+
 /**
  * 动态创意日报表 Mapper(统计时间口径 REPORTING_TIME)
  *
@@ -21,4 +24,11 @@ public interface RepDailyCreativeReportMapper extends BaseMapper<RepDailyCreativ
      * @param report 报表数据
      */
     void upsert(@Param("report") RepDailyCreativeReport report);
+
+    /**
+     * 批量插入或更新(ON DUPLICATE KEY UPDATE)
+     *
+     * @param list 报表数据列表
+     */
+    void batchUpsert(@Param("list") List<RepDailyCreativeReport> list);
 }

+ 18 - 0
src/main/java/com/moka/gdtauto/mapper/ReqDailyAdgroupReportMapper.java

@@ -0,0 +1,18 @@
+package com.moka.gdtauto.mapper;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.moka.gdtauto.entity.ReqDailyAdgroupReport;
+
+/**
+ * <p>
+ * 广告日报表(请求时间口径 REQUEST_TIME) Mapper 接口
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+public interface ReqDailyAdgroupReportMapper extends BaseMapper<ReqDailyAdgroupReport> {
+    void upsert(@Param("report") ReqDailyAdgroupReport report);
+}

+ 12 - 2
src/main/java/com/moka/gdtauto/mapper/ReqDailyCreativeReportMapper.java

@@ -1,10 +1,13 @@
 package com.moka.gdtauto.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.moka.gdtauto.entity.ReqDailyCreativeReport;
+import java.util.List;
+
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.moka.gdtauto.entity.ReqDailyCreativeReport;
+
 /**
  * 动态创意日报表 Mapper(请求时间口径 REQUEST_TIME)
  *
@@ -21,4 +24,11 @@ public interface ReqDailyCreativeReportMapper extends BaseMapper<ReqDailyCreativ
      * @param report 报表数据
      */
     void upsert(@Param("report") ReqDailyCreativeReport report);
+
+    /**
+     * 批量插入或更新(ON DUPLICATE KEY UPDATE)
+     *
+     * @param list 报表数据列表
+     */
+    void batchUpsert(@Param("list") List<ReqDailyCreativeReport> list);
 }

+ 3 - 0
src/main/java/com/moka/gdtauto/service/AdPlanService.java

@@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.moka.gdtauto.entity.AdPlan;
 import com.moka.gdtauto.entity.AdPlanConf;
+import com.tencent.ads.model.v3.WriteTargetingSetting;
+import com.tencent.ads.v3.TencentAds;
 
 /**
  * 广告计划服务接口
@@ -18,6 +20,7 @@ public interface AdPlanService extends IService<AdPlan> {
     //修改预算
     void updateAdgroupDailyBudget(AdPlanConf conf, AdPlan plan, Long dailyBudget) throws Exception;
 
+    void updateAdgroupTargeting(TencentAds tencentAds, AdPlanConf conf, AdPlan plan, WriteTargetingSetting targeting) throws Exception;
     /**
      * 创建广告计划
      * 

+ 55 - 53
src/main/java/com/moka/gdtauto/service/DailyReportService.java → src/main/java/com/moka/gdtauto/service/DailyAdgroupReportService.java

@@ -1,34 +1,36 @@
 package com.moka.gdtauto.service;
 
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.List;
+
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.moka.gdtauto.client.TencentAdsApiClientFactory;
 import com.moka.gdtauto.entity.AccountGroup;
 import com.moka.gdtauto.entity.AccountGroupAccountRelationship;
-import com.moka.gdtauto.entity.BaseDailyCreativeReport;
-import com.moka.gdtauto.entity.RepDailyCreativeReport;
-import com.moka.gdtauto.entity.ReqDailyCreativeReport;
+import com.moka.gdtauto.entity.BaseDailyAdgroupReport;
+import com.moka.gdtauto.entity.RepDailyAdgroupReport;
+import com.moka.gdtauto.entity.ReqDailyAdgroupReport;
 import com.moka.gdtauto.mapper.AccountGroupAccountRelationshipMapper;
 import com.moka.gdtauto.mapper.AccountGroupMapper;
-import com.moka.gdtauto.mapper.RepDailyCreativeReportMapper;
-import com.moka.gdtauto.mapper.ReqDailyCreativeReportMapper;
+import com.moka.gdtauto.mapper.RepDailyAdgroupReportMapper;
+import com.moka.gdtauto.mapper.ReqDailyAdgroupReportMapper;
 import com.tencent.ads.model.v3.DailyReportsGetResponseData;
 import com.tencent.ads.model.v3.ReportDateRange;
 import com.tencent.ads.model.v3.ReportStruct;
 import com.tencent.ads.model.v3.TimeLine;
 import com.tencent.ads.v3.TencentAds;
+
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.Arrays;
-import java.util.List;
 
 /**
- * 动态创意日报表 Service
+ * 广告日报表 Service
  * 支持双口径(REQUEST_TIME / REPORTING_TIME)同步与查询
  *
  * @author moka
@@ -37,18 +39,18 @@ import java.util.List;
 @Slf4j
 @Service
 @RequiredArgsConstructor
-public class DailyReportService {
+public class DailyAdgroupReportService {
 
     private final TencentAdsApiClientFactory clientFactory;
     private final TencentAccountService accountService;
     private final AccountGroupAccountRelationshipMapper relationshipMapper;
     private final AccountGroupMapper accountGroupMapper;
-    private final ReqDailyCreativeReportMapper reqMapper;
-    private final RepDailyCreativeReportMapper repMapper;
+    private final ReqDailyAdgroupReportMapper reqMapper;
+    private final RepDailyAdgroupReportMapper repMapper;
 
     /** 同步时请求的指标字段 */
     private static final List<String> SYNC_FIELDS = Arrays.asList(
-            "dynamic_creative_id", "date",
+            "adgroup_id", "date",
             // 曝光点击
             "view_count", "view_user_count", "avg_view_per_user",
             "valid_click_count", "click_user_count", "cpc", "ctr",
@@ -107,7 +109,7 @@ public class DailyReportService {
         dateRange.setStartDate(startDate);
         dateRange.setEndDate(endDate);
 
-        List<String> groupBy = Arrays.asList("dynamic_creative_id", "date");
+        List<String> groupBy = Arrays.asList("adgroup_id", "date");
 
         long page = 1L;
         long pageSize = 1000L;
@@ -115,7 +117,7 @@ public class DailyReportService {
 
         while (true) {
             DailyReportsGetResponseData response = tencentAds.dailyReports().dailyReportsGet(
-                    "REPORT_LEVEL_DYNAMIC_CREATIVE",
+                    "REPORT_LEVEL_ADGROUP",
                     dateRange,
                     groupBy,
                     SYNC_FIELDS,
@@ -138,11 +140,11 @@ public class DailyReportService {
                     continue;
                 }
                 if (TimeLine.REQUEST_TIME.getValue().equals(timeLine)) {
-                    ReqDailyCreativeReport entity = toReqEntity(accountId, groupId, groupName, rs);
+                    ReqDailyAdgroupReport entity = toReqEntity(accountId, groupId, groupName, rs);
                     reqMapper.upsert(entity);
                 } else {
-                    RepDailyCreativeReport entity = toRepEntity(accountId, groupId, groupName, rs);
-                    repMapper.upsert(entity);
+                    ReqDailyAdgroupReport entity = toRepEntity(accountId, groupId, groupName, rs);
+                    reqMapper.upsert(entity);
                 }
                 totalSaved++;
             }
@@ -169,7 +171,6 @@ public class DailyReportService {
      */
     public int syncAllAccounts(String startDate, String endDate, String timeLine) {
         // 查询所有账号组-账户关系
-        // TODO for test
         LambdaQueryWrapper<AccountGroupAccountRelationship> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(AccountGroupAccountRelationship::getGroupId, 1L);
         List<AccountGroupAccountRelationship> relationships = relationshipMapper.selectList(null);
@@ -229,82 +230,83 @@ public class DailyReportService {
      * @param pageSize  每页大小
      * @return 分页结果
      */
-    public Page<? extends BaseDailyCreativeReport> listReports(
-            String timeLine, Long groupId, Long accountId, Long dynamicCreativeId,
+    public Page<? extends BaseDailyAdgroupReport> listReports(
+            String timeLine, Long groupId, Long accountId, Long adgroupId,
             String startDate, String endDate, long pageNum, long pageSize) {
 
         if ("REPORTING_TIME".equals(timeLine)) {
-            LambdaQueryWrapper<RepDailyCreativeReport> wrapper = buildRepWrapper(groupId, accountId, dynamicCreativeId, startDate, endDate);
+            LambdaQueryWrapper<RepDailyAdgroupReport> wrapper = buildRepWrapper(groupId, accountId, adgroupId, startDate, endDate);
             return repMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
         } else {
-            LambdaQueryWrapper<ReqDailyCreativeReport> wrapper = buildReqWrapper(groupId, accountId, dynamicCreativeId, startDate, endDate);
+            LambdaQueryWrapper<ReqDailyAdgroupReport> wrapper = buildReqWrapper(groupId, accountId, adgroupId, startDate, endDate);
             return reqMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
         }
     }
 
-    private LambdaQueryWrapper<ReqDailyCreativeReport> buildReqWrapper(
-            Long groupId, Long accountId, Long dynamicCreativeId, String startDate, String endDate) {
-        LambdaQueryWrapper<ReqDailyCreativeReport> wrapper = new LambdaQueryWrapper<>();
+    private LambdaQueryWrapper<ReqDailyAdgroupReport> buildReqWrapper(
+            Long groupId, Long accountId, Long adgroupId, String startDate, String endDate) {
+        LambdaQueryWrapper<ReqDailyAdgroupReport> wrapper = new LambdaQueryWrapper<>();
         if (groupId != null) {
-            wrapper.eq(ReqDailyCreativeReport::getGroupId, groupId);
+            wrapper.eq(ReqDailyAdgroupReport::getGroupId, groupId);
         }
         if (accountId != null) {
-            wrapper.eq(ReqDailyCreativeReport::getAccountId, accountId);
+            wrapper.eq(ReqDailyAdgroupReport::getAccountId, accountId);
         }
-        if (dynamicCreativeId != null) {
-            wrapper.eq(ReqDailyCreativeReport::getDynamicCreativeId, dynamicCreativeId);
+        if (adgroupId != null) {
+            wrapper.eq(ReqDailyAdgroupReport::getAdgroupId, adgroupId);
         }
         if (StringUtils.hasText(startDate)) {
-            wrapper.ge(ReqDailyCreativeReport::getDate, LocalDate.parse(startDate));
+            wrapper.ge(ReqDailyAdgroupReport::getDate, LocalDate.parse(startDate));
         }
         if (StringUtils.hasText(endDate)) {
-            wrapper.le(ReqDailyCreativeReport::getDate, LocalDate.parse(endDate));
+            wrapper.le(ReqDailyAdgroupReport::getDate, LocalDate.parse(endDate));
         }
-        wrapper.orderByDesc(ReqDailyCreativeReport::getDate);
+        wrapper.orderByDesc(ReqDailyAdgroupReport::getDate);
         return wrapper;
     }
 
-    private LambdaQueryWrapper<RepDailyCreativeReport> buildRepWrapper(
-            Long groupId, Long accountId, Long dynamicCreativeId, String startDate, String endDate) {
-        LambdaQueryWrapper<RepDailyCreativeReport> wrapper = new LambdaQueryWrapper<>();
+    private LambdaQueryWrapper<RepDailyAdgroupReport> buildRepWrapper(
+            Long groupId, Long accountId, Long adgroupId, String startDate, String endDate) {
+        LambdaQueryWrapper<RepDailyAdgroupReport> wrapper = new LambdaQueryWrapper<>();
         if (groupId != null) {
-            wrapper.eq(RepDailyCreativeReport::getGroupId, groupId);
+            wrapper.eq(RepDailyAdgroupReport::getGroupId, groupId);
         }
         if (accountId != null) {
-            wrapper.eq(RepDailyCreativeReport::getAccountId, accountId);
+            wrapper.eq(RepDailyAdgroupReport::getAccountId, accountId);
         }
-        if (dynamicCreativeId != null) {
-            wrapper.eq(RepDailyCreativeReport::getDynamicCreativeId, dynamicCreativeId);
+        if (adgroupId != null) {
+            wrapper.eq(RepDailyAdgroupReport::getAdgroupId, adgroupId);
         }
         if (StringUtils.hasText(startDate)) {
-            wrapper.ge(RepDailyCreativeReport::getDate, LocalDate.parse(startDate));
+            wrapper.ge(RepDailyAdgroupReport::getDate, LocalDate.parse(startDate));
         }
         if (StringUtils.hasText(endDate)) {
-            wrapper.le(RepDailyCreativeReport::getDate, LocalDate.parse(endDate));
+            wrapper.le(RepDailyAdgroupReport::getDate, LocalDate.parse(endDate));
         }
-        wrapper.orderByDesc(RepDailyCreativeReport::getDate);
+        wrapper.orderByDesc(RepDailyAdgroupReport::getDate);
         return wrapper;
     }
 
     // ─── 映射方法 ─────────────────────────────────────────────────────────────
 
-    private ReqDailyCreativeReport toReqEntity(Long accountId, Long groupId, String groupName, ReportStruct rs) {
-        ReqDailyCreativeReport e = new ReqDailyCreativeReport();
+    private ReqDailyAdgroupReport toReqEntity(Long accountId, Long groupId, String groupName, ReportStruct rs) {
+        ReqDailyAdgroupReport e = new ReqDailyAdgroupReport();
         fillFields(e, accountId, groupId, groupName, rs);
         return e;
     }
 
-    private RepDailyCreativeReport toRepEntity(Long accountId, Long groupId, String groupName, ReportStruct rs) {
-        RepDailyCreativeReport e = new RepDailyCreativeReport();
+    private ReqDailyAdgroupReport toRepEntity(Long accountId, Long groupId, String groupName, ReportStruct rs) {
+        ReqDailyAdgroupReport e = new ReqDailyAdgroupReport();
         fillFields(e, accountId, groupId, groupName, rs);
         return e;
     }
 
-    private void fillFields(BaseDailyCreativeReport e, Long accountId, Long groupId, String groupName, ReportStruct rs) {
+    private void fillFields(BaseDailyAdgroupReport e, Long accountId, Long groupId, String groupName, ReportStruct rs) {
         e.setAccountId(accountId);
         e.setGroupId(groupId);
         e.setGroupName(groupName);
-        e.setDynamicCreativeId(rs.getDynamicCreativeId());
+        e.setAdgroupId(rs.getAdgroupId());
+        e.setAdgroupName(rs.getAdgroupName());
         e.setDate(LocalDate.parse(rs.getDate()));
         // 基础
         e.setViewCount(rs.getViewCount());

+ 436 - 0
src/main/java/com/moka/gdtauto/service/DailyCreativeReportService.java

@@ -0,0 +1,436 @@
+package com.moka.gdtauto.service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.moka.gdtauto.client.TencentAdsApiClientFactory;
+import com.moka.gdtauto.common.Constant;
+import com.moka.gdtauto.entity.AdPlanConf;
+import com.moka.gdtauto.entity.AdPlanCreative;
+import com.moka.gdtauto.entity.BaseDailyCreativeReport;
+import com.moka.gdtauto.entity.RepDailyCreativeReport;
+import com.moka.gdtauto.entity.ReqDailyCreativeReport;
+import com.moka.gdtauto.mapper.AccountGroupAccountRelationshipMapper;
+import com.moka.gdtauto.mapper.AccountGroupMapper;
+import com.moka.gdtauto.mapper.RepDailyCreativeReportMapper;
+import com.moka.gdtauto.mapper.ReqDailyCreativeReportMapper;
+import com.tencent.ads.model.v3.DailyReportsFilteringStruct;
+import com.tencent.ads.model.v3.DailyReportsGetResponseData;
+import com.tencent.ads.model.v3.FilterOperator;
+import com.tencent.ads.model.v3.ReportDateRange;
+import com.tencent.ads.model.v3.ReportStruct;
+import com.tencent.ads.model.v3.TimeLine;
+import com.tencent.ads.v3.TencentAds;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 动态创意日报表 Service
+ * 支持双口径(REQUEST_TIME / REPORTING_TIME)同步与查询
+ *
+ * @author moka
+ * @since 2026-03-03
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DailyCreativeReportService {
+
+    private final TencentAdsApiClientFactory clientFactory;
+    private final TencentAccountService accountService;
+    private final AccountGroupAccountRelationshipMapper relationshipMapper;
+    private final AccountGroupMapper accountGroupMapper;
+    private final ReqDailyCreativeReportMapper reqMapper;
+    private final RepDailyCreativeReportMapper repMapper;
+    private final AdPlanConfService adPlanConfService;
+    private final AdPlanCreativeService adPlanCreativeService;
+
+    /** 同步时请求的指标字段 */
+    private static final List<String> SYNC_FIELDS = Arrays.asList("account_id",
+            "dynamic_creative_id", "date",
+            // 曝光点击
+            "view_count", "view_user_count", "avg_view_per_user",
+            "valid_click_count", "click_user_count", "cpc", "ctr",
+            "valuable_click_count", "valuable_click_cost", "valuable_click_rate",
+            // 花费
+            "cost", "thousand_display_price",
+            // 转化
+            "conversions_count", "conversions_rate", "conversions_cost",
+            "deep_conversions_count", "deep_conversions_rate", "deep_conversions_cost",
+            "conversions_by_display_count", "conversions_by_click_count",
+            "preview_conversions_count", "preview_deep_conversions_count",
+            // 视频
+            "video_outer_play_count", "video_outer_play_user_count", "avg_user_play_count",
+            "video_outer_play_time_count", "video_outer_play_rate", "video_outer_play_cost",
+            "video_outer_play3s_count", "video_outer_play3s_rate",
+            "video_outer_play25_count", "video_outer_play50_count",
+            "video_outer_play75_count", "video_outer_play100_count",
+            // 互动
+            "read_count", "comment_count", "praise_count", "forward_count",
+            // 落地页
+            "platform_page_view_count", "platform_page_view_rate",
+            "lan_button_click_count", "lan_jump_button_clickers",
+            // 关键页面
+            "key_page_view_count", "key_page_uv",
+            // ROI/LTV
+            "income_val_1", "income_roi_1",
+            "income_val_3", "income_roi_3",
+            "income_val_7", "income_roi_7",
+            "income_val_14", "income_roi_14",
+            "income_val_24h", "income_roi_1_24h"
+    );
+
+    // ─── 同步方法 ─────────────────────────────────────────────────────────────
+
+    /**
+     * 同步指定账户的日报表(分页拉取直到全量完成)
+     *
+     * @param jobNumber    工号(用于获取 access_token)
+     * @param orgAccountId 组织账户ID
+     * @param accountId    广告账户ID
+     * @param groupId      账号组ID
+     * @param groupName    账号组名称
+     * @param startDate    开始日期 yyyy-MM-dd
+     * @param endDate      结束日期 yyyy-MM-dd
+     * @param timeLine     时间口径 REQUEST_TIME / REPORTING_TIME
+     * @return 成功写入行数
+     */
+    public void syncReport(AdPlanConf conf,
+                          String startDate, String endDate, String timeLine) throws Exception {
+        log.info("开始同步日报表 timeLine={} [{}, {}]", timeLine, startDate, endDate);
+
+        TencentAds tencentAds = clientFactory.getTencentAds(conf.getJobNumber(), Constant.MAIN_ORG_ACCOUNT_ID);
+        ReportDateRange dateRange = new ReportDateRange();
+        dateRange.setStartDate(startDate);
+        dateRange.setEndDate(endDate);
+        List<String> groupBy = Arrays.asList("dynamic_creative_id", "date");
+
+        // 分页查询 AdPlanCreative,条件:status=4, systemDelete='false'
+        int pageNum = 1;
+        int pageSize = 100;
+        while (true) {
+            Page<AdPlanCreative> page = adPlanCreativeService.page(
+                new Page<>(pageNum, pageSize),
+                new LambdaQueryWrapper<AdPlanCreative>()
+                    .eq(AdPlanCreative::getAdPlanConfId, conf.getId())
+                    .eq(AdPlanCreative::getStatus, 4)
+                    .eq(AdPlanCreative::getSystemDelete, "false")
+            );
+
+            List<AdPlanCreative> creativeList = page.getRecords();
+            if (creativeList.isEmpty()) {
+                break;
+            }
+
+            // 提取 creativeId 列表
+            List<Long> creativeIds = creativeList.stream()
+                .map(AdPlanCreative::getCreativeId)
+                .toList();
+
+            List<DailyReportsFilteringStruct> filtering = new ArrayList<>();
+            DailyReportsFilteringStruct struct = new DailyReportsFilteringStruct();
+            struct.setField("dynamic_creative_id");
+            struct.setOperator(FilterOperator.IN);
+            struct.setValues(creativeIds.stream().map(String::valueOf).toList());
+            filtering.add(struct);
+
+            DailyReportsGetResponseData response = tencentAds.dailyReports().dailyReportsGet(
+                    "REPORT_LEVEL_DYNAMIC_CREATIVE",
+                    dateRange,
+                    groupBy,
+                    SYNC_FIELDS,
+                    null,
+                    filtering,
+                    null,
+                    timeLine,
+                    1L,
+                    100L,
+                    Constant.MAIN_ORG_ACCOUNT_ID
+            );
+
+            if (response == null || response.getList() == null || response.getList().isEmpty()) {
+                pageNum++;
+                continue;
+            }
+
+            List<ReportStruct> list = response.getList();
+            if (TimeLine.REQUEST_TIME.getValue().equals(timeLine)) {
+                List<ReqDailyCreativeReport> entities = new ArrayList<>();
+                for (ReportStruct rs : list) {
+                    if (rs.getDynamicCreativeId() == null || rs.getDate() == null) {
+                        continue;
+                    }
+                    entities.add(toReqEntity(conf.getAccountGroupId(), rs));
+                }
+                if (!entities.isEmpty()) {
+                    reqMapper.batchUpsert(entities);
+                }
+            } else {
+                List<RepDailyCreativeReport> entities = new ArrayList<>();
+                for (ReportStruct rs : list) {
+                    if (rs.getDynamicCreativeId() == null || rs.getDate() == null) {
+                        continue;
+                    }
+                    entities.add(toRepEntity(conf.getAccountGroupId(), rs));
+                }
+                if (!entities.isEmpty()) {
+                    repMapper.batchUpsert(entities);
+                }
+            }
+
+            // 判断是否还有下一页
+            if (!page.hasNext()) {
+                break;
+            }
+            pageNum++;
+        }
+    }
+
+    /**
+     * 同步所有账户(定时任务调用)——通过 AccountGroupAccountRelationship 关联获取 groupId / groupName
+     *
+     * @param startDate 开始日期
+     * @param endDate   结束日期
+     * @param timeLine  时间口径
+     * @return 成功保存总行数
+     */
+    public void syncAllAccounts(String startDate, String endDate, String timeLine) {
+        // 获取所有广告计划配置
+        List<AdPlanConf> confList = adPlanConfService.list(
+            new LambdaQueryWrapper<AdPlanConf>()
+                .eq(AdPlanConf::getAdType, 2)
+                .in(AdPlanConf::getStatus, List.of(4,5))
+                .eq(AdPlanConf::getDeleted, 0));
+        log.info("查询到 {} 个广告计划配置", confList.size());
+
+        if (confList.isEmpty()) {
+            return;
+        }
+
+        // 使用 Semaphore 控制并发数为 10
+        Semaphore semaphore = new Semaphore(10);
+
+        // 使用虚拟线程池进行并发处理
+        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
+            for (AdPlanConf conf : confList) {
+                executor.submit(() -> {
+                    try {
+                        semaphore.acquire();
+                        syncReport(conf, startDate, endDate, timeLine);
+                    } catch (InterruptedException e) {
+                        log.error("获取信号量被中断", e);
+                        Thread.currentThread().interrupt();
+                    } catch (Exception e) {
+                        log.error("同步创意日报 {} 失败", conf.getId(), e);
+                    }  finally {
+                        semaphore.release();
+                    }
+                });
+            }
+            // 关闭线程池并等待所有任务完成
+            executor.shutdown();
+            boolean terminated = executor.awaitTermination(30, TimeUnit.MINUTES);
+            if (!terminated) {
+                log.warn("同步创意日报 任务未在指定时间内完成");
+            }
+        } catch (InterruptedException e) {
+            log.error("并发处理被中断", e);
+            Thread.currentThread().interrupt();
+        }
+
+        log.info("所有广告计划定向更新完成");
+
+    }
+
+    // ─── 查询方法 ─────────────────────────────────────────────────────────────
+
+    /**
+     * 分页查询日报表
+     *
+     * @param timeLine  时间口径(决定查哪张表)
+     * @param groupId   可选,账号组ID
+     * @param accountId 可选,广告账户ID
+     * @param startDate 可选,开始日期
+     * @param endDate   可选,结束日期
+     * @param pageNum   页码
+     * @param pageSize  每页大小
+     * @return 分页结果
+     */
+    public Page<? extends BaseDailyCreativeReport> listReports(
+            String timeLine, Long groupId, Long accountId, Long dynamicCreativeId,
+            String startDate, String endDate, long pageNum, long pageSize) {
+
+        if ("REPORTING_TIME".equals(timeLine)) {
+            LambdaQueryWrapper<RepDailyCreativeReport> wrapper = buildRepWrapper(groupId, accountId, dynamicCreativeId, startDate, endDate);
+            return repMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
+        } else {
+            LambdaQueryWrapper<ReqDailyCreativeReport> wrapper = buildReqWrapper(groupId, accountId, dynamicCreativeId, startDate, endDate);
+            return reqMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
+        }
+    }
+
+    private LambdaQueryWrapper<ReqDailyCreativeReport> buildReqWrapper(
+            Long groupId, Long accountId, Long dynamicCreativeId, String startDate, String endDate) {
+        LambdaQueryWrapper<ReqDailyCreativeReport> wrapper = new LambdaQueryWrapper<>();
+        if (groupId != null) {
+            wrapper.eq(ReqDailyCreativeReport::getGroupId, groupId);
+        }
+        if (accountId != null) {
+            wrapper.eq(ReqDailyCreativeReport::getAccountId, accountId);
+        }
+        if (dynamicCreativeId != null) {
+            wrapper.eq(ReqDailyCreativeReport::getDynamicCreativeId, dynamicCreativeId);
+        }
+        if (StringUtils.hasText(startDate)) {
+            wrapper.ge(ReqDailyCreativeReport::getDate, LocalDate.parse(startDate));
+        }
+        if (StringUtils.hasText(endDate)) {
+            wrapper.le(ReqDailyCreativeReport::getDate, LocalDate.parse(endDate));
+        }
+        wrapper.orderByDesc(ReqDailyCreativeReport::getDate);
+        return wrapper;
+    }
+
+    private LambdaQueryWrapper<RepDailyCreativeReport> buildRepWrapper(
+            Long groupId, Long accountId, Long dynamicCreativeId, String startDate, String endDate) {
+        LambdaQueryWrapper<RepDailyCreativeReport> wrapper = new LambdaQueryWrapper<>();
+        if (groupId != null) {
+            wrapper.eq(RepDailyCreativeReport::getGroupId, groupId);
+        }
+        if (accountId != null) {
+            wrapper.eq(RepDailyCreativeReport::getAccountId, accountId);
+        }
+        if (dynamicCreativeId != null) {
+            wrapper.eq(RepDailyCreativeReport::getDynamicCreativeId, dynamicCreativeId);
+        }
+        if (StringUtils.hasText(startDate)) {
+            wrapper.ge(RepDailyCreativeReport::getDate, LocalDate.parse(startDate));
+        }
+        if (StringUtils.hasText(endDate)) {
+            wrapper.le(RepDailyCreativeReport::getDate, LocalDate.parse(endDate));
+        }
+        wrapper.orderByDesc(RepDailyCreativeReport::getDate);
+        return wrapper;
+    }
+
+    // ─── 映射方法 ─────────────────────────────────────────────────────────────
+
+    private ReqDailyCreativeReport toReqEntity(Long groupId,  ReportStruct rs) {
+        ReqDailyCreativeReport e = new ReqDailyCreativeReport();
+        fillFields(e, groupId, rs);
+        return e;
+    }
+
+    private RepDailyCreativeReport toRepEntity(Long groupId, ReportStruct rs) {
+        RepDailyCreativeReport e = new RepDailyCreativeReport();
+        fillFields(e, groupId, rs);
+        return e;
+    }
+
+    private void fillFields(BaseDailyCreativeReport e,  Long groupId, ReportStruct rs) {
+        e.setAccountId(rs.getAccountId());
+        e.setGroupId(groupId);
+        e.setDynamicCreativeId(rs.getDynamicCreativeId());
+        e.setDynamicCreativeName(rs.getDynamicCreativeName());
+        e.setDate(LocalDate.parse(rs.getDate()));
+        // 基础
+        e.setViewCount(rs.getViewCount());
+        e.setViewUserCount(rs.getViewUserCount());
+        e.setAvgViewPerUser(d2b(rs.getAvgViewPerUser()));
+        e.setValidClickCount(rs.getValidClickCount());
+        e.setClickUserCount(rs.getClickUserCount());
+        e.setCpc(rs.getCpc());
+        e.setCtr(d2b(rs.getCtr()));
+        e.setValuableClickCount(rs.getValuableClickCount());
+        e.setValuableClickCost(rs.getValuableClickCost());
+        e.setValuableClickRate(d2b(rs.getValuableClickRate()));
+        // 花费
+        e.setCost(rs.getCost());
+        e.setAcquisitionCost(rs.getAcquisitionCost());
+        e.setThousandDisplayPrice(rs.getThousandDisplayPrice());
+        // 转化
+        e.setConversionsCount(rs.getConversionsCount());
+        e.setConversionsRate(d2b(rs.getConversionsRate()));
+        e.setConversionsCost(rs.getConversionsCost());
+        e.setDeepConversionsCount(rs.getDeepConversionsCount());
+        e.setDeepConversionsRate(d2b(rs.getDeepConversionsRate()));
+        e.setDeepConversionsCost(rs.getDeepConversionsCost());
+        e.setConversionsByDisplayCount(rs.getConversionsByDisplayCount());
+        e.setConversionsByDisplayRate(d2b(rs.getConversionsByDisplayRate()));
+        e.setConversionsByDisplayCost(rs.getConversionsByDisplayCost());
+        e.setConversionsByClickCount(rs.getConversionsByClickCount());
+        e.setConversionsByClickRate(d2b(rs.getConversionsByClickRate()));
+        e.setConversionsByClickCost(rs.getConversionsByClickCost());
+        e.setPreviewConversionsCount(rs.getPreviewConversionsCount());
+        e.setPreviewDeepConversionsCount(rs.getPreviewDeepConversionsCount());
+        // 视频
+        e.setVideoOuterPlayCount(rs.getVideoOuterPlayCount());
+        e.setVideoOuterPlayUserCount(rs.getVideoOuterPlayUserCount());
+        e.setAvgUserPlayCount(d2b(rs.getAvgUserPlayCount()));
+        e.setVideoOuterPlayTimeCount(d2b(rs.getVideoOuterPlayTimeCount()));
+        e.setVideoOuterPlayTimeAvgRate(d2b(rs.getVideoOuterPlayTimeAvgRate()));
+        e.setVideoOuterPlayRate(d2b(rs.getVideoOuterPlayRate()));
+        e.setVideoOuterPlayCost(rs.getVideoOuterPlayCost());
+        e.setVideoOuterPlay10Count(rs.getVideoOuterPlay10Count());
+        e.setVideoOuterPlay25Count(rs.getVideoOuterPlay25Count());
+        e.setVideoOuterPlay50Count(rs.getVideoOuterPlay50Count());
+        e.setVideoOuterPlay75Count(rs.getVideoOuterPlay75Count());
+        e.setVideoOuterPlay90Count(rs.getVideoOuterPlay90Count());
+        e.setVideoOuterPlay95Count(rs.getVideoOuterPlay95Count());
+        e.setVideoOuterPlay100Count(rs.getVideoOuterPlay100Count());
+        e.setVideoOuterPlay3sCount(rs.getVideoOuterPlay3sCount());
+        e.setVideoOuterPlay3sRate(d2b(rs.getVideoOuterPlay3sRate()));
+        e.setVideoOuterPlay5sCount(rs.getVideoOuterPlay5sCount());
+        e.setVideoOuterPlay7sCount(rs.getVideoOuterPlay7sCount());
+        // 互动
+        e.setReadCount(rs.getReadCount());
+        e.setReadCost(rs.getReadCost());
+        e.setCommentCount(rs.getCommentCount());
+        e.setCommentCost(rs.getCommentCost());
+        e.setPraiseCount(rs.getPraiseCount());
+        e.setPraiseCost(rs.getPraiseCost());
+        e.setForwardCount(rs.getForwardCount());
+        e.setForwardCost(rs.getForwardCost());
+        e.setNoInterestCount(rs.getNoInterestCount());
+        // 落地页
+        e.setPlatformPageViewCount(rs.getPlatformPageViewCount());
+        e.setPlatformPageViewRate(d2b(rs.getPlatformPageViewRate()));
+        e.setLanButtonClickCount(rs.getLanButtonClickCount());
+        e.setLanJumpButtonClickers(rs.getLanJumpButtonClickers());
+        e.setLanButtonClickCost(rs.getLanButtonClickCost());
+        e.setLanJumpButtonCtr(d2b(rs.getLanJumpButtonCtr()));
+        e.setLanJumpButtonClickCost(rs.getLanJumpButtonClickCost());
+        // 关键页面
+        e.setKeyPageViewCount(rs.getKeyPageViewCount());
+        e.setKeyPageUv(rs.getKeyPageUv());
+        // ROI/LTV - 注意:SDK字段名 incomeRoi124h 对应 API income_roi_1_24h
+        e.setIncomeVal1(rs.getIncomeVal1());
+        e.setIncomeRoi1(d2b(rs.getIncomeRoi1()));
+        e.setIncomeVal3(rs.getIncomeVal3());
+        e.setIncomeRoi3(d2b(rs.getIncomeRoi3()));
+        e.setIncomeVal7(rs.getIncomeVal7());
+        e.setIncomeRoi7(d2b(rs.getIncomeRoi7()));
+        e.setIncomeVal14(rs.getIncomeVal14());
+        e.setIncomeRoi14(d2b(rs.getIncomeRoi14()));
+        e.setIncomeVal24h(rs.getIncomeVal24h());
+        e.setIncomeRoi124h(d2b(rs.getIncomeRoi124h()));
+    }
+
+    /** Double → BigDecimal 安全转换 */
+    private BigDecimal d2b(Double d) {
+        return d == null ? null : BigDecimal.valueOf(d);
+    }
+}

+ 16 - 0
src/main/java/com/moka/gdtauto/service/RepDailyAdgroupReportService.java

@@ -0,0 +1,16 @@
+package com.moka.gdtauto.service;
+
+import com.moka.gdtauto.entity.RepDailyAdgroupReport;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 广告日报表(统计时间口径 REPORTING_TIME) 服务类
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+public interface RepDailyAdgroupReportService extends IService<RepDailyAdgroupReport> {
+
+}

+ 16 - 0
src/main/java/com/moka/gdtauto/service/ReqDailyAdgroupReportService.java

@@ -0,0 +1,16 @@
+package com.moka.gdtauto.service;
+
+import com.moka.gdtauto.entity.ReqDailyAdgroupReport;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 广告日报表(请求时间口径 REQUEST_TIME) 服务类
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+public interface ReqDailyAdgroupReportService extends IService<ReqDailyAdgroupReport> {
+
+}

+ 21 - 0
src/main/java/com/moka/gdtauto/service/impl/AdPlanServiceImpl.java

@@ -25,6 +25,7 @@ import com.tencent.ads.model.v3.AdgroupsUpdateRequest;
 import com.tencent.ads.model.v3.FilterOperator;
 import com.tencent.ads.model.v3.FilteringStruct;
 import com.tencent.ads.model.v3.SmartTargetingMode;
+import com.tencent.ads.model.v3.WriteTargetingSetting;
 import com.tencent.ads.v3.TencentAds;
 
 import lombok.RequiredArgsConstructor;
@@ -285,4 +286,24 @@ public class AdPlanServiceImpl extends ServiceImpl<AdPlanMapper, AdPlan> impleme
        .set(AdPlan::getFailReason, plan.getFailReason())
        .update();
     }
+
+    @Override
+    public void updateAdgroupTargeting(TencentAds tencentAds,AdPlanConf conf, AdPlan plan, WriteTargetingSetting targeting) throws Exception {
+        try {
+        AdgroupsUpdateRequest req = new AdgroupsUpdateRequest();
+        req.setAccountId(plan.getAccountId());
+        req.setAdgroupId(plan.getAdgroupId());
+        req.setTargeting(targeting);
+        req.setSmartTargetingMode(SmartTargetingMode.SMART_TARGETING_MANUAL);
+        tencentAds.adgroups().adgroupsUpdate(req);
+        plan.setFailReason("修改定向模版成功");
+       } catch (Exception e) {
+           log.error("[定时任务] 修改广告定向模版失败,ID: {},计划ID: {}",plan.getId(), plan.getAdgroupId(), e);
+           plan.setFailReason("修改定向模版失败:" + StrUtil.truncateError(e.getMessage()));
+       }
+       this.lambdaUpdate()
+       .eq(AdPlan::getId, plan.getId())
+       .set(AdPlan::getFailReason, plan.getFailReason())
+       .update();
+    }
 }

+ 20 - 0
src/main/java/com/moka/gdtauto/service/impl/RepDailyAdgroupReportServiceImp.java

@@ -0,0 +1,20 @@
+package com.moka.gdtauto.service.impl;
+
+import com.moka.gdtauto.entity.RepDailyAdgroupReport;
+import com.moka.gdtauto.mapper.RepDailyAdgroupReportMapper;
+import com.moka.gdtauto.service.RepDailyAdgroupReportService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 广告日报表(统计时间口径 REPORTING_TIME) 服务实现类
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+@Service
+public class RepDailyAdgroupReportServiceImp extends ServiceImpl<RepDailyAdgroupReportMapper, RepDailyAdgroupReport> implements RepDailyAdgroupReportService {
+
+}

+ 20 - 0
src/main/java/com/moka/gdtauto/service/impl/ReqDailyAdgroupReportServiceImp.java

@@ -0,0 +1,20 @@
+package com.moka.gdtauto.service.impl;
+
+import com.moka.gdtauto.entity.ReqDailyAdgroupReport;
+import com.moka.gdtauto.mapper.ReqDailyAdgroupReportMapper;
+import com.moka.gdtauto.service.ReqDailyAdgroupReportService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 广告日报表(请求时间口径 REQUEST_TIME) 服务实现类
+ * </p>
+ *
+ * @author mokamvp
+ * @since 2026-03-19
+ */
+@Service
+public class ReqDailyAdgroupReportServiceImp extends ServiceImpl<ReqDailyAdgroupReportMapper, ReqDailyAdgroupReport> implements ReqDailyAdgroupReportService {
+
+}

+ 16 - 16
src/main/java/com/moka/gdtauto/task/DailyReportSyncTask.java

@@ -1,16 +1,16 @@
 package com.moka.gdtauto.task;
 
-import com.moka.gdtauto.service.DailyReportService;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import org.springframework.scheduling.annotation.Scheduled;
+
+import com.moka.gdtauto.service.DailyCreativeReportService;
 import com.tencent.ads.model.v3.TimeLine;
 
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
 
 /**
  * 动态创意日报表定时同步任务
@@ -20,11 +20,11 @@ import java.time.format.DateTimeFormatter;
  * @since 2026-03-03
  */
 @Slf4j
-@Component
+// @Component
 @RequiredArgsConstructor
 public class DailyReportSyncTask {
 
-    private final DailyReportService dailyReportService;
+    private final DailyCreativeReportService dailyReportService;
 
     private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
 
@@ -40,8 +40,8 @@ public class DailyReportSyncTask {
         String today = LocalDate.now().format(FMT);
         log.info("[定时任务] 同步当日 REQUEST_TIME 日报表 date={}", today);
         try {
-            int total = dailyReportService.syncAllAccounts(today, today, TimeLine.REQUEST_TIME.getValue());
-            log.info("[定时任务] 当日 REQUEST_TIME 日报表同步完成 total={}", total);
+            dailyReportService.syncAllAccounts(today, today, TimeLine.REQUEST_TIME.getValue());
+            log.info("[定时任务] 当日 REQUEST_TIME 日报表同步完成");
         } catch (Exception e) {
             log.error("[定时任务] 当日 REQUEST_TIME 日报表同步异常", e);
         }
@@ -57,8 +57,8 @@ public class DailyReportSyncTask {
         String today = LocalDate.now().format(FMT);
         log.info("[定时任务] 同步当日 REPORTING_TIME 日报表 date={}", today);
         try {
-            int total = dailyReportService.syncAllAccounts(today, today, TimeLine.REPORTING_TIME.getValue());
-            log.info("[定时任务] 当日 REPORTING_TIME 日报表同步完成 total={}", total);
+            dailyReportService.syncAllAccounts(today, today, TimeLine.REPORTING_TIME.getValue());
+            log.info("[定时任务] 当日 REPORTING_TIME 日报表同步完成");
         } catch (Exception e) {
             log.error("[定时任务] 当日 REPORTING_TIME 日报表同步异常", e);
         }
@@ -76,8 +76,8 @@ public class DailyReportSyncTask {
         String yesterday = LocalDate.now().minusDays(1).format(FMT);
         log.info("[定时任务] 同步昨日 REQUEST_TIME 日报表 date={}", yesterday);
         try {
-            int total = dailyReportService.syncAllAccounts(yesterday, yesterday, TimeLine.REQUEST_TIME.getValue());
-            log.info("[定时任务] 昨日 REQUEST_TIME 日报表同步完成 total={}", total);
+            dailyReportService.syncAllAccounts(yesterday, yesterday, TimeLine.REQUEST_TIME.getValue());
+            log.info("[定时任务] 昨日 REQUEST_TIME 日报表同步完成");
         } catch (Exception e) {
             log.error("[定时任务] 昨日 REQUEST_TIME 日报表同步异常", e);
         }
@@ -93,8 +93,8 @@ public class DailyReportSyncTask {
         String yesterday = LocalDate.now().minusDays(1).format(FMT);
         log.info("[定时任务] 同步昨日 REPORTING_TIME 日报表 date={}", yesterday);
         try {
-            int total = dailyReportService.syncAllAccounts(yesterday, yesterday, TimeLine.REPORTING_TIME.getValue());
-            log.info("[定时任务] 昨日 REPORTING_TIME 日报表同步完成 total={}", total);
+            dailyReportService.syncAllAccounts(yesterday, yesterday, TimeLine.REPORTING_TIME.getValue());
+            log.info("[定时任务] 昨日 REPORTING_TIME 日报表同步完成");
         } catch (Exception e) {
             log.error("[定时任务] 昨日 REPORTING_TIME 日报表同步异常", e);
         }

+ 6 - 7
src/main/java/com/moka/gdtauto/util/TargetConfUtil.java

@@ -1,17 +1,16 @@
 package com.moka.gdtauto.util;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
-
-import com.tencent.ads.model.v3.ExcludedDay;
-import com.tencent.ads.model.v3.WriteTargetingSetting;
-import com.tencent.ads.model.v3.GeoLocations;
 import com.tencent.ads.model.v3.AgeStruct;
 import com.tencent.ads.model.v3.ExcludedConvertedAudience;
+import com.tencent.ads.model.v3.ExcludedDay;
 import com.tencent.ads.model.v3.ExcludedDimension;
+import com.tencent.ads.model.v3.GeoLocations;
+import com.tencent.ads.model.v3.WriteTargetingSetting;
 
 
 public class TargetConfUtil {
@@ -141,10 +140,10 @@ public class TargetConfUtil {
 
         // 排除自定义人群
         List<Long> excludedCustomAudience = new ArrayList<>();
-        excludedCustomAudience.add(44241932L);
-        excludedCustomAudience.add(44135417L);
+        excludedCustomAudience.add(44106830L);
         excludedCustomAudience.add(44107982L);
         excludedCustomAudience.add(43712084L);
+        excludedCustomAudience.add(44241932L);
         targeting.setExcludedCustomAudience(excludedCustomAudience);
 
         return targeting;

+ 198 - 0
src/main/resources/mapper/RepDailyAdgroupReportMapper.xml

@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.moka.gdtauto.mapper.RepDailyAdgroupReportMapper">
+<insert id="upsert" parameterType="com.moka.gdtauto.entity.RepDailyAdgroupReport">
+        INSERT INTO rep_daily_adgroup_report (
+            group_id, group_name, account_id, adgroup_id, adgroup_name, date,
+            view_count, view_user_count, avg_view_per_user,
+            valid_click_count, click_user_count, cpc, ctr,
+            valuable_click_count, valuable_click_cost, valuable_click_rate,
+            cost, acquisition_cost, thousand_display_price,
+            conversions_count, conversions_rate, conversions_cost,
+            deep_conversions_count, deep_conversions_rate, deep_conversions_cost,
+            conversions_by_display_count, conversions_by_display_rate, conversions_by_display_cost,
+            conversions_by_click_count, conversions_by_click_rate, conversions_by_click_cost,
+            preview_conversions_count, preview_deep_conversions_count,
+            video_outer_play_count, video_outer_play_user_count, avg_user_play_count,
+            video_outer_play_time_count, video_outer_play_time_avg_rate,
+            video_outer_play_rate, video_outer_play_cost,
+            video_outer_play10_count, video_outer_play25_count, video_outer_play50_count,
+            video_outer_play75_count, video_outer_play90_count, video_outer_play95_count,
+            video_outer_play100_count, video_outer_play3s_count, video_outer_play3s_rate,
+            video_outer_play5s_count, video_outer_play7s_count,
+            read_count, read_cost, comment_count, comment_cost,
+            praise_count, praise_cost, forward_count, forward_cost, no_interest_count,
+            live_stream_crt_click_cnt, click_image_count, click_head_count,
+            click_detail_count, click_poi_count, zone_header_click_count,
+            basic_info_client_count, account_info_click_count,
+            clk_account_living_status_pv, clk_accountinfo_weapp_pv,
+            clk_accountinfo_finder_pv, clk_accountinfo_biz_pv,
+            clk_account_info_producttab_pv, clk_account_info_productdetail_pv,
+            activity_info_click_count,
+            overall_leads_purchase_count, effective_leads_count, effective_cost,
+            effect_leads_purchase_count, effect_leads_purchase_cost,
+            platform_page_view_count, platform_page_view_rate,
+            lan_button_click_count, lan_jump_button_clickers, lan_button_click_cost,
+            lan_jump_button_ctr, lan_jump_button_click_cost,
+            key_page_view_count, key_page_view_by_display_count, key_page_view_by_click_count,
+            key_page_uv, key_page_view_cost, key_page_view_rate,
+            landing_commodity_detail_exp_pv,
+            app_commodity_page_view_by_display_count, app_commodity_page_view_by_click_count,
+            view_commodity_page_uv, web_commodity_page_view_rate, web_commodity_page_view_cost,
+            own_page_navigation_count, own_page_navi_cost,
+            platform_page_navigation_count, platform_page_navigation_cost,
+            platform_shop_navigation_count, platform_shop_navigation_cost,
+            active_page_views, active_page_viewers,
+            active_page_interaction_amount, active_page_interaction_users,
+            guide_to_follow_page_views, guide_to_follow_page_viewers,
+            guide_to_follow_page_interaction_amount, guide_to_follow_page_interaction_users,
+            platform_key_page_view_user_count,
+            page_consult_count, consult_uv_count, page_consult_rate, page_consult_cost,
+            consult_leave_info_users, consult_leave_info_cost,
+            potential_consult_count, effective_consult_count, tool_consult_count,
+            page_reservation_count, page_reservation_by_display_count, page_reservation_by_click_count,
+            reservation_uv, reservation_amount, page_reservation_cost, page_reservation_cost_with_people,
+            page_reservation_rate, page_reservation_roi,
+            biz_reservation_uv, biz_reservation_follow_rate,
+            external_form_reservation_count, potential_reserve_count,
+            reservation_check_uv, reservation_check_uv_cost, reservation_check_uv_rate,
+            effective_reserve_count, valid_leads_uv, try_out_intention_uv, ineffective_leads_uv,
+            coupon_get_pv, coupon_get_cost, coupon_get_rate,
+            platform_coupon_click_count, purchase_amount_with_coupon,
+            coupon_purchase_rate, purchase_amount_with_coupon_cost, coupon_usage_number,
+            page_phone_call_direct_count, page_phone_call_direct_rate, page_phone_call_direct_cost,
+            potential_phone_count, potential_customer_phone_uv,
+            effective_phone_count, valid_phone_uv,
+            income_val_1, income_roi_1, income_val_3, income_roi_3,
+            income_val_7, income_roi_7, income_val_14, income_roi_14,
+            income_val_24h, income_roi_1_24h
+        ) VALUES (
+            #{report.groupId}, #{report.groupName}, #{report.accountId}, #{report.adgroupId}, #{report.adgroupName}, #{report.date},
+            #{report.viewCount}, #{report.viewUserCount}, #{report.avgViewPerUser},
+            #{report.validClickCount}, #{report.clickUserCount}, #{report.cpc}, #{report.ctr},
+            #{report.valuableClickCount}, #{report.valuableClickCost}, #{report.valuableClickRate},
+            #{report.cost}, #{report.acquisitionCost}, #{report.thousandDisplayPrice},
+            #{report.conversionsCount}, #{report.conversionsRate}, #{report.conversionsCost},
+            #{report.deepConversionsCount}, #{report.deepConversionsRate}, #{report.deepConversionsCost},
+            #{report.conversionsByDisplayCount}, #{report.conversionsByDisplayRate}, #{report.conversionsByDisplayCost},
+            #{report.conversionsByClickCount}, #{report.conversionsByClickRate}, #{report.conversionsByClickCost},
+            #{report.previewConversionsCount}, #{report.previewDeepConversionsCount},
+            #{report.videoOuterPlayCount}, #{report.videoOuterPlayUserCount}, #{report.avgUserPlayCount},
+            #{report.videoOuterPlayTimeCount}, #{report.videoOuterPlayTimeAvgRate},
+            #{report.videoOuterPlayRate}, #{report.videoOuterPlayCost},
+            #{report.videoOuterPlay10Count}, #{report.videoOuterPlay25Count}, #{report.videoOuterPlay50Count},
+            #{report.videoOuterPlay75Count}, #{report.videoOuterPlay90Count}, #{report.videoOuterPlay95Count},
+            #{report.videoOuterPlay100Count}, #{report.videoOuterPlay3sCount}, #{report.videoOuterPlay3sRate},
+            #{report.videoOuterPlay5sCount}, #{report.videoOuterPlay7sCount},
+            #{report.readCount}, #{report.readCost}, #{report.commentCount}, #{report.commentCost},
+            #{report.praiseCount}, #{report.praiseCost}, #{report.forwardCount}, #{report.forwardCost}, #{report.noInterestCount},
+            #{report.liveStreamCrtClickCnt}, #{report.clickImageCount}, #{report.clickHeadCount},
+            #{report.clickDetailCount}, #{report.clickPoiCount}, #{report.zoneHeaderClickCount},
+            #{report.basicInfoClientCount}, #{report.accountInfoClickCount},
+            #{report.clkAccountLivingStatusPv}, #{report.clkAccountinfoWeappPv},
+            #{report.clkAccountinfoFinderPv}, #{report.clkAccountinfoBizPv},
+            #{report.clkAccountInfoProducttabPv}, #{report.clkAccountInfoProductdetailPv},
+            #{report.activityInfoClickCount},
+            #{report.overallLeadsPurchaseCount}, #{report.effectiveLeadsCount}, #{report.effectiveCost},
+            #{report.effectLeadsPurchaseCount}, #{report.effectLeadsPurchaseCost},
+            #{report.platformPageViewCount}, #{report.platformPageViewRate},
+            #{report.lanButtonClickCount}, #{report.lanJumpButtonClickers}, #{report.lanButtonClickCost},
+            #{report.lanJumpButtonCtr}, #{report.lanJumpButtonClickCost},
+            #{report.keyPageViewCount}, #{report.keyPageViewByDisplayCount}, #{report.keyPageViewByClickCount},
+            #{report.keyPageUv}, #{report.keyPageViewCost}, #{report.keyPageViewRate},
+            #{report.landingCommodityDetailExpPv},
+            #{report.appCommodityPageViewByDisplayCount}, #{report.appCommodityPageViewByClickCount},
+            #{report.viewCommodityPageUv}, #{report.webCommodityPageViewRate}, #{report.webCommodityPageViewCost},
+            #{report.ownPageNavigationCount}, #{report.ownPageNaviCost},
+            #{report.platformPageNavigationCount}, #{report.platformPageNavigationCost},
+            #{report.platformShopNavigationCount}, #{report.platformShopNavigationCost},
+            #{report.activePageViews}, #{report.activePageViewers},
+            #{report.activePageInteractionAmount}, #{report.activePageInteractionUsers},
+            #{report.guideToFollowPageViews}, #{report.guideToFollowPageViewers},
+            #{report.guideToFollowPageInteractionAmount}, #{report.guideToFollowPageInteractionUsers},
+            #{report.platformKeyPageViewUserCount},
+            #{report.pageConsultCount}, #{report.consultUvCount}, #{report.pageConsultRate}, #{report.pageConsultCost},
+            #{report.consultLeaveInfoUsers}, #{report.consultLeaveInfoCost},
+            #{report.potentialConsultCount}, #{report.effectiveConsultCount}, #{report.toolConsultCount},
+            #{report.pageReservationCount}, #{report.pageReservationByDisplayCount}, #{report.pageReservationByClickCount},
+            #{report.reservationUv}, #{report.reservationAmount}, #{report.pageReservationCost}, #{report.pageReservationCostWithPeople},
+            #{report.pageReservationRate}, #{report.pageReservationRoi},
+            #{report.bizReservationUv}, #{report.bizReservationFollowRate},
+            #{report.externalFormReservationCount}, #{report.potentialReserveCount},
+            #{report.reservationCheckUv}, #{report.reservationCheckUvCost}, #{report.reservationCheckUvRate},
+            #{report.effectiveReserveCount}, #{report.validLeadsUv}, #{report.tryOutIntentionUv}, #{report.ineffectiveLeadsUv},
+            #{report.couponGetPv}, #{report.couponGetCost}, #{report.couponGetRate},
+            #{report.platformCouponClickCount}, #{report.purchaseAmountWithCoupon},
+            #{report.couponPurchaseRate}, #{report.purchaseAmountWithCouponCost}, #{report.couponUsageNumber},
+            #{report.pagePhoneCallDirectCount}, #{report.pagePhoneCallDirectRate}, #{report.pagePhoneCallDirectCost},
+            #{report.potentialPhoneCount}, #{report.potentialCustomerPhoneUv},
+            #{report.effectivePhoneCount}, #{report.validPhoneUv},
+            #{report.incomeVal1}, #{report.incomeRoi1}, #{report.incomeVal3}, #{report.incomeRoi3},
+            #{report.incomeVal7}, #{report.incomeRoi7}, #{report.incomeVal14}, #{report.incomeRoi14},
+            #{report.incomeVal24h}, #{report.incomeRoi124h}
+        ) ON DUPLICATE KEY UPDATE
+            group_name = VALUES(group_name),
+            view_count = VALUES(view_count), view_user_count = VALUES(view_user_count), avg_view_per_user = VALUES(avg_view_per_user),
+            valid_click_count = VALUES(valid_click_count), click_user_count = VALUES(click_user_count), cpc = VALUES(cpc), ctr = VALUES(ctr),
+            valuable_click_count = VALUES(valuable_click_count), valuable_click_cost = VALUES(valuable_click_cost), valuable_click_rate = VALUES(valuable_click_rate),
+            cost = VALUES(cost), acquisition_cost = VALUES(acquisition_cost), thousand_display_price = VALUES(thousand_display_price),
+            conversions_count = VALUES(conversions_count), conversions_rate = VALUES(conversions_rate), conversions_cost = VALUES(conversions_cost),
+            deep_conversions_count = VALUES(deep_conversions_count), deep_conversions_rate = VALUES(deep_conversions_rate), deep_conversions_cost = VALUES(deep_conversions_cost),
+            conversions_by_display_count = VALUES(conversions_by_display_count), conversions_by_display_rate = VALUES(conversions_by_display_rate), conversions_by_display_cost = VALUES(conversions_by_display_cost),
+            conversions_by_click_count = VALUES(conversions_by_click_count), conversions_by_click_rate = VALUES(conversions_by_click_rate), conversions_by_click_cost = VALUES(conversions_by_click_cost),
+            preview_conversions_count = VALUES(preview_conversions_count), preview_deep_conversions_count = VALUES(preview_deep_conversions_count),
+            video_outer_play_count = VALUES(video_outer_play_count), video_outer_play_user_count = VALUES(video_outer_play_user_count), avg_user_play_count = VALUES(avg_user_play_count),
+            video_outer_play_time_count = VALUES(video_outer_play_time_count), video_outer_play_time_avg_rate = VALUES(video_outer_play_time_avg_rate),
+            video_outer_play_rate = VALUES(video_outer_play_rate), video_outer_play_cost = VALUES(video_outer_play_cost),
+            video_outer_play10_count = VALUES(video_outer_play10_count), video_outer_play25_count = VALUES(video_outer_play25_count), video_outer_play50_count = VALUES(video_outer_play50_count),
+            video_outer_play75_count = VALUES(video_outer_play75_count), video_outer_play90_count = VALUES(video_outer_play90_count), video_outer_play95_count = VALUES(video_outer_play95_count),
+            video_outer_play100_count = VALUES(video_outer_play100_count), video_outer_play3s_count = VALUES(video_outer_play3s_count), video_outer_play3s_rate = VALUES(video_outer_play3s_rate),
+            video_outer_play5s_count = VALUES(video_outer_play5s_count), video_outer_play7s_count = VALUES(video_outer_play7s_count),
+            read_count = VALUES(read_count), read_cost = VALUES(read_cost), comment_count = VALUES(comment_count), comment_cost = VALUES(comment_cost),
+            praise_count = VALUES(praise_count), praise_cost = VALUES(praise_cost), forward_count = VALUES(forward_count), forward_cost = VALUES(forward_cost), no_interest_count = VALUES(no_interest_count),
+            live_stream_crt_click_cnt = VALUES(live_stream_crt_click_cnt), click_image_count = VALUES(click_image_count), click_head_count = VALUES(click_head_count),
+            click_detail_count = VALUES(click_detail_count), click_poi_count = VALUES(click_poi_count), zone_header_click_count = VALUES(zone_header_click_count),
+            basic_info_client_count = VALUES(basic_info_client_count), account_info_click_count = VALUES(account_info_click_count),
+            clk_account_living_status_pv = VALUES(clk_account_living_status_pv), clk_accountinfo_weapp_pv = VALUES(clk_accountinfo_weapp_pv),
+            clk_accountinfo_finder_pv = VALUES(clk_accountinfo_finder_pv), clk_accountinfo_biz_pv = VALUES(clk_accountinfo_biz_pv),
+            clk_account_info_producttab_pv = VALUES(clk_account_info_producttab_pv), clk_account_info_productdetail_pv = VALUES(clk_account_info_productdetail_pv),
+            activity_info_click_count = VALUES(activity_info_click_count),
+            overall_leads_purchase_count = VALUES(overall_leads_purchase_count), effective_leads_count = VALUES(effective_leads_count), effective_cost = VALUES(effective_cost),
+            effect_leads_purchase_count = VALUES(effect_leads_purchase_count), effect_leads_purchase_cost = VALUES(effect_leads_purchase_cost),
+            platform_page_view_count = VALUES(platform_page_view_count), platform_page_view_rate = VALUES(platform_page_view_rate),
+            lan_button_click_count = VALUES(lan_button_click_count), lan_jump_button_clickers = VALUES(lan_jump_button_clickers), lan_button_click_cost = VALUES(lan_button_click_cost),
+            lan_jump_button_ctr = VALUES(lan_jump_button_ctr), lan_jump_button_click_cost = VALUES(lan_jump_button_click_cost),
+            key_page_view_count = VALUES(key_page_view_count), key_page_view_by_display_count = VALUES(key_page_view_by_display_count), key_page_view_by_click_count = VALUES(key_page_view_by_click_count),
+            key_page_uv = VALUES(key_page_uv), key_page_view_cost = VALUES(key_page_view_cost), key_page_view_rate = VALUES(key_page_view_rate),
+            landing_commodity_detail_exp_pv = VALUES(landing_commodity_detail_exp_pv),
+            app_commodity_page_view_by_display_count = VALUES(app_commodity_page_view_by_display_count), app_commodity_page_view_by_click_count = VALUES(app_commodity_page_view_by_click_count),
+            view_commodity_page_uv = VALUES(view_commodity_page_uv), web_commodity_page_view_rate = VALUES(web_commodity_page_view_rate), web_commodity_page_view_cost = VALUES(web_commodity_page_view_cost),
+            own_page_navigation_count = VALUES(own_page_navigation_count), own_page_navi_cost = VALUES(own_page_navi_cost),
+            platform_page_navigation_count = VALUES(platform_page_navigation_count), platform_page_navigation_cost = VALUES(platform_page_navigation_cost),
+            platform_shop_navigation_count = VALUES(platform_shop_navigation_count), platform_shop_navigation_cost = VALUES(platform_shop_navigation_cost),
+            active_page_views = VALUES(active_page_views), active_page_viewers = VALUES(active_page_viewers),
+            active_page_interaction_amount = VALUES(active_page_interaction_amount), active_page_interaction_users = VALUES(active_page_interaction_users),
+            guide_to_follow_page_views = VALUES(guide_to_follow_page_views), guide_to_follow_page_viewers = VALUES(guide_to_follow_page_viewers),
+            guide_to_follow_page_interaction_amount = VALUES(guide_to_follow_page_interaction_amount), guide_to_follow_page_interaction_users = VALUES(guide_to_follow_page_interaction_users),
+            platform_key_page_view_user_count = VALUES(platform_key_page_view_user_count),
+            page_consult_count = VALUES(page_consult_count), consult_uv_count = VALUES(consult_uv_count), page_consult_rate = VALUES(page_consult_rate), page_consult_cost = VALUES(page_consult_cost),
+            consult_leave_info_users = VALUES(consult_leave_info_users), consult_leave_info_cost = VALUES(consult_leave_info_cost),
+            potential_consult_count = VALUES(potential_consult_count), effective_consult_count = VALUES(effective_consult_count), tool_consult_count = VALUES(tool_consult_count),
+            page_reservation_count = VALUES(page_reservation_count), page_reservation_by_display_count = VALUES(page_reservation_by_display_count), page_reservation_by_click_count = VALUES(page_reservation_by_click_count),
+            reservation_uv = VALUES(reservation_uv), reservation_amount = VALUES(reservation_amount), page_reservation_cost = VALUES(page_reservation_cost), page_reservation_cost_with_people = VALUES(page_reservation_cost_with_people),
+            page_reservation_rate = VALUES(page_reservation_rate), page_reservation_roi = VALUES(page_reservation_roi),
+            biz_reservation_uv = VALUES(biz_reservation_uv), biz_reservation_follow_rate = VALUES(biz_reservation_follow_rate),
+            external_form_reservation_count = VALUES(external_form_reservation_count), potential_reserve_count = VALUES(potential_reserve_count),
+            reservation_check_uv = VALUES(reservation_check_uv), reservation_check_uv_cost = VALUES(reservation_check_uv_cost), reservation_check_uv_rate = VALUES(reservation_check_uv_rate),
+            effective_reserve_count = VALUES(effective_reserve_count), valid_leads_uv = VALUES(valid_leads_uv), try_out_intention_uv = VALUES(try_out_intention_uv), ineffective_leads_uv = VALUES(ineffective_leads_uv),
+            coupon_get_pv = VALUES(coupon_get_pv), coupon_get_cost = VALUES(coupon_get_cost), coupon_get_rate = VALUES(coupon_get_rate),
+            platform_coupon_click_count = VALUES(platform_coupon_click_count), purchase_amount_with_coupon = VALUES(purchase_amount_with_coupon),
+            coupon_purchase_rate = VALUES(coupon_purchase_rate), purchase_amount_with_coupon_cost = VALUES(purchase_amount_with_coupon_cost), coupon_usage_number = VALUES(coupon_usage_number),
+            page_phone_call_direct_count = VALUES(page_phone_call_direct_count), page_phone_call_direct_rate = VALUES(page_phone_call_direct_rate), page_phone_call_direct_cost = VALUES(page_phone_call_direct_cost),
+            potential_phone_count = VALUES(potential_phone_count), potential_customer_phone_uv = VALUES(potential_customer_phone_uv),
+            effective_phone_count = VALUES(effective_phone_count), valid_phone_uv = VALUES(valid_phone_uv),
+            income_val_1 = VALUES(income_val_1), income_roi_1 = VALUES(income_roi_1), income_val_3 = VALUES(income_val_3), income_roi_3 = VALUES(income_roi_3),
+            income_val_7 = VALUES(income_val_7), income_roi_7 = VALUES(income_roi_7), income_val_14 = VALUES(income_val_14), income_roi_14 = VALUES(income_roi_14),
+            income_val_24h = VALUES(income_val_24h), income_roi_1_24h = VALUES(income_roi_1_24h)
+    </insert>
+</mapper>

+ 202 - 2
src/main/resources/mapper/RepDailyCreativeReportMapper.xml

@@ -5,7 +5,7 @@
     <!-- 插入或更新(REPORTING_TIME 口径)唯一键: group_id + account_id + dynamic_creative_id + date -->
     <insert id="upsert" parameterType="com.moka.gdtauto.entity.RepDailyCreativeReport">
         INSERT INTO rep_daily_creative_report (
-            group_id, group_name, account_id, dynamic_creative_id, date,
+            group_id, group_name, account_id, dynamic_creative_id, dynamic_creative_name, date,
             view_count, view_user_count, avg_view_per_user,
             valid_click_count, click_user_count, cpc, ctr,
             valuable_click_count, valuable_click_cost, valuable_click_rate,
@@ -69,7 +69,7 @@
             income_val_7, income_roi_7, income_val_14, income_roi_14,
             income_val_24h, income_roi_1_24h
         ) VALUES (
-            #{report.groupId}, #{report.groupName}, #{report.accountId}, #{report.dynamicCreativeId}, #{report.date},
+            #{report.groupId}, #{report.groupName}, #{report.accountId}, #{report.dynamicCreativeId}, #{report.dynamicCreativeName}, #{report.date},
             #{report.viewCount}, #{report.viewUserCount}, #{report.avgViewPerUser},
             #{report.validClickCount}, #{report.clickUserCount}, #{report.cpc}, #{report.ctr},
             #{report.valuableClickCount}, #{report.valuableClickCost}, #{report.valuableClickRate},
@@ -198,4 +198,204 @@
             income_val_24h = VALUES(income_val_24h), income_roi_1_24h = VALUES(income_roi_1_24h)
     </insert>
 
+    <!-- 批量插入或更新(REPORTING_TIME 口径)-->
+    <insert id="batchUpsert" parameterType="java.util.List">
+        INSERT INTO rep_daily_creative_report (
+            group_id, group_name, account_id, dynamic_creative_id, dynamic_creative_name, date,
+            view_count, view_user_count, avg_view_per_user,
+            valid_click_count, click_user_count, cpc, ctr,
+            valuable_click_count, valuable_click_cost, valuable_click_rate,
+            cost, acquisition_cost, thousand_display_price,
+            conversions_count, conversions_rate, conversions_cost,
+            deep_conversions_count, deep_conversions_rate, deep_conversions_cost,
+            conversions_by_display_count, conversions_by_display_rate, conversions_by_display_cost,
+            conversions_by_click_count, conversions_by_click_rate, conversions_by_click_cost,
+            preview_conversions_count, preview_deep_conversions_count,
+            video_outer_play_count, video_outer_play_user_count, avg_user_play_count,
+            video_outer_play_time_count, video_outer_play_time_avg_rate,
+            video_outer_play_rate, video_outer_play_cost,
+            video_outer_play10_count, video_outer_play25_count, video_outer_play50_count,
+            video_outer_play75_count, video_outer_play90_count, video_outer_play95_count,
+            video_outer_play100_count, video_outer_play3s_count, video_outer_play3s_rate,
+            video_outer_play5s_count, video_outer_play7s_count,
+            read_count, read_cost, comment_count, comment_cost,
+            praise_count, praise_cost, forward_count, forward_cost, no_interest_count,
+            live_stream_crt_click_cnt, click_image_count, click_head_count,
+            click_detail_count, click_poi_count, zone_header_click_count,
+            basic_info_client_count, account_info_click_count,
+            clk_account_living_status_pv, clk_accountinfo_weapp_pv,
+            clk_accountinfo_finder_pv, clk_accountinfo_biz_pv,
+            clk_account_info_producttab_pv, clk_account_info_productdetail_pv,
+            activity_info_click_count,
+            overall_leads_purchase_count, effective_leads_count, effective_cost,
+            effect_leads_purchase_count, effect_leads_purchase_cost,
+            platform_page_view_count, platform_page_view_rate,
+            lan_button_click_count, lan_jump_button_clickers, lan_button_click_cost,
+            lan_jump_button_ctr, lan_jump_button_click_cost,
+            key_page_view_count, key_page_view_by_display_count, key_page_view_by_click_count,
+            key_page_uv, key_page_view_cost, key_page_view_rate,
+            landing_commodity_detail_exp_pv,
+            app_commodity_page_view_by_display_count, app_commodity_page_view_by_click_count,
+            view_commodity_page_uv, web_commodity_page_view_rate, web_commodity_page_view_cost,
+            own_page_navigation_count, own_page_navi_cost,
+            platform_page_navigation_count, platform_page_navigation_cost,
+            platform_shop_navigation_count, platform_shop_navigation_cost,
+            active_page_views, active_page_viewers,
+            active_page_interaction_amount, active_page_interaction_users,
+            guide_to_follow_page_views, guide_to_follow_page_viewers,
+            guide_to_follow_page_interaction_amount, guide_to_follow_page_interaction_users,
+            platform_key_page_view_user_count,
+            page_consult_count, consult_uv_count, page_consult_rate, page_consult_cost,
+            consult_leave_info_users, consult_leave_info_cost,
+            potential_consult_count, effective_consult_count, tool_consult_count,
+            page_reservation_count, page_reservation_by_display_count, page_reservation_by_click_count,
+            reservation_uv, reservation_amount, page_reservation_cost, page_reservation_cost_with_people,
+            page_reservation_rate, page_reservation_roi,
+            biz_reservation_uv, biz_reservation_follow_rate,
+            external_form_reservation_count, potential_reserve_count,
+            reservation_check_uv, reservation_check_uv_cost, reservation_check_uv_rate,
+            effective_reserve_count, valid_leads_uv, try_out_intention_uv, ineffective_leads_uv,
+            coupon_get_pv, coupon_get_cost, coupon_get_rate,
+            platform_coupon_click_count, purchase_amount_with_coupon,
+            coupon_purchase_rate, purchase_amount_with_coupon_cost, coupon_usage_number,
+            page_phone_call_direct_count, page_phone_call_direct_rate, page_phone_call_direct_cost,
+            potential_phone_count, potential_customer_phone_uv,
+            effective_phone_count, valid_phone_uv,
+            income_val_1, income_roi_1, income_val_3, income_roi_3,
+            income_val_7, income_roi_7, income_val_14, income_roi_14,
+            income_val_24h, income_roi_1_24h
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+                #{item.groupId}, #{item.groupName}, #{item.accountId}, #{item.dynamicCreativeId}, #{item.dynamicCreativeName}, #{item.date},
+                #{item.viewCount}, #{item.viewUserCount}, #{item.avgViewPerUser},
+                #{item.validClickCount}, #{item.clickUserCount}, #{item.cpc}, #{item.ctr},
+                #{item.valuableClickCount}, #{item.valuableClickCost}, #{item.valuableClickRate},
+                #{item.cost}, #{item.acquisitionCost}, #{item.thousandDisplayPrice},
+                #{item.conversionsCount}, #{item.conversionsRate}, #{item.conversionsCost},
+                #{item.deepConversionsCount}, #{item.deepConversionsRate}, #{item.deepConversionsCost},
+                #{item.conversionsByDisplayCount}, #{item.conversionsByDisplayRate}, #{item.conversionsByDisplayCost},
+                #{item.conversionsByClickCount}, #{item.conversionsByClickRate}, #{item.conversionsByClickCost},
+                #{item.previewConversionsCount}, #{item.previewDeepConversionsCount},
+                #{item.videoOuterPlayCount}, #{item.videoOuterPlayUserCount}, #{item.avgUserPlayCount},
+                #{item.videoOuterPlayTimeCount}, #{item.videoOuterPlayTimeAvgRate},
+                #{item.videoOuterPlayRate}, #{item.videoOuterPlayCost},
+                #{item.videoOuterPlay10Count}, #{item.videoOuterPlay25Count}, #{item.videoOuterPlay50Count},
+                #{item.videoOuterPlay75Count}, #{item.videoOuterPlay90Count}, #{item.videoOuterPlay95Count},
+                #{item.videoOuterPlay100Count}, #{item.videoOuterPlay3sCount}, #{item.videoOuterPlay3sRate},
+                #{item.videoOuterPlay5sCount}, #{item.videoOuterPlay7sCount},
+                #{item.readCount}, #{item.readCost}, #{item.commentCount}, #{item.commentCost},
+                #{item.praiseCount}, #{item.praiseCost}, #{item.forwardCount}, #{item.forwardCost}, #{item.noInterestCount},
+                #{item.liveStreamCrtClickCnt}, #{item.clickImageCount}, #{item.clickHeadCount},
+                #{item.clickDetailCount}, #{item.clickPoiCount}, #{item.zoneHeaderClickCount},
+                #{item.basicInfoClientCount}, #{item.accountInfoClickCount},
+                #{item.clkAccountLivingStatusPv}, #{item.clkAccountinfoWeappPv},
+                #{item.clkAccountinfoFinderPv}, #{item.clkAccountinfoBizPv},
+                #{item.clkAccountInfoProducttabPv}, #{item.clkAccountInfoProductdetailPv},
+                #{item.activityInfoClickCount},
+                #{item.overallLeadsPurchaseCount}, #{item.effectiveLeadsCount}, #{item.effectiveCost},
+                #{item.effectLeadsPurchaseCount}, #{item.effectLeadsPurchaseCost},
+                #{item.platformPageViewCount}, #{item.platformPageViewRate},
+                #{item.lanButtonClickCount}, #{item.lanJumpButtonClickers}, #{item.lanButtonClickCost},
+                #{item.lanJumpButtonCtr}, #{item.lanJumpButtonClickCost},
+                #{item.keyPageViewCount}, #{item.keyPageViewByDisplayCount}, #{item.keyPageViewByClickCount},
+                #{item.keyPageUv}, #{item.keyPageViewCost}, #{item.keyPageViewRate},
+                #{item.landingCommodityDetailExpPv},
+                #{item.appCommodityPageViewByDisplayCount}, #{item.appCommodityPageViewByClickCount},
+                #{item.viewCommodityPageUv}, #{item.webCommodityPageViewRate}, #{item.webCommodityPageViewCost},
+                #{item.ownPageNavigationCount}, #{item.ownPageNaviCost},
+                #{item.platformPageNavigationCount}, #{item.platformPageNavigationCost},
+                #{item.platformShopNavigationCount}, #{item.platformShopNavigationCost},
+                #{item.activePageViews}, #{item.activePageViewers},
+                #{item.activePageInteractionAmount}, #{item.activePageInteractionUsers},
+                #{item.guideToFollowPageViews}, #{item.guideToFollowPageViewers},
+                #{item.guideToFollowPageInteractionAmount}, #{item.guideToFollowPageInteractionUsers},
+                #{item.platformKeyPageViewUserCount},
+                #{item.pageConsultCount}, #{item.consultUvCount}, #{item.pageConsultRate}, #{item.pageConsultCost},
+                #{item.consultLeaveInfoUsers}, #{item.consultLeaveInfoCost},
+                #{item.potentialConsultCount}, #{item.effectiveConsultCount}, #{item.toolConsultCount},
+                #{item.pageReservationCount}, #{item.pageReservationByDisplayCount}, #{item.pageReservationByClickCount},
+                #{item.reservationUv}, #{item.reservationAmount}, #{item.pageReservationCost}, #{item.pageReservationCostWithPeople},
+                #{item.pageReservationRate}, #{item.pageReservationRoi},
+                #{item.bizReservationUv}, #{item.bizReservationFollowRate},
+                #{item.externalFormReservationCount}, #{item.potentialReserveCount},
+                #{item.reservationCheckUv}, #{item.reservationCheckUvCost}, #{item.reservationCheckUvRate},
+                #{item.effectiveReserveCount}, #{item.validLeadsUv}, #{item.tryOutIntentionUv}, #{item.ineffectiveLeadsUv},
+                #{item.couponGetPv}, #{item.couponGetCost}, #{item.couponGetRate},
+                #{item.platformCouponClickCount}, #{item.purchaseAmountWithCoupon},
+                #{item.couponPurchaseRate}, #{item.purchaseAmountWithCouponCost}, #{item.couponUsageNumber},
+                #{item.pagePhoneCallDirectCount}, #{item.pagePhoneCallDirectRate}, #{item.pagePhoneCallDirectCost},
+                #{item.potentialPhoneCount}, #{item.potentialCustomerPhoneUv},
+                #{item.effectivePhoneCount}, #{item.validPhoneUv},
+                #{item.incomeVal1}, #{item.incomeRoi1}, #{item.incomeVal3}, #{item.incomeRoi3},
+                #{item.incomeVal7}, #{item.incomeRoi7}, #{item.incomeVal14}, #{item.incomeRoi14},
+                #{item.incomeVal24h}, #{item.incomeRoi124h}
+            )
+        </foreach>
+        ON DUPLICATE KEY UPDATE
+            group_name = VALUES(group_name),
+            view_count = VALUES(view_count), view_user_count = VALUES(view_user_count), avg_view_per_user = VALUES(avg_view_per_user),
+            valid_click_count = VALUES(valid_click_count), click_user_count = VALUES(click_user_count), cpc = VALUES(cpc), ctr = VALUES(ctr),
+            valuable_click_count = VALUES(valuable_click_count), valuable_click_cost = VALUES(valuable_click_cost), valuable_click_rate = VALUES(valuable_click_rate),
+            cost = VALUES(cost), acquisition_cost = VALUES(acquisition_cost), thousand_display_price = VALUES(thousand_display_price),
+            conversions_count = VALUES(conversions_count), conversions_rate = VALUES(conversions_rate), conversions_cost = VALUES(conversions_cost),
+            deep_conversions_count = VALUES(deep_conversions_count), deep_conversions_rate = VALUES(deep_conversions_rate), deep_conversions_cost = VALUES(deep_conversions_cost),
+            conversions_by_display_count = VALUES(conversions_by_display_count), conversions_by_display_rate = VALUES(conversions_by_display_rate), conversions_by_display_cost = VALUES(conversions_by_display_cost),
+            conversions_by_click_count = VALUES(conversions_by_click_count), conversions_by_click_rate = VALUES(conversions_by_click_rate), conversions_by_click_cost = VALUES(conversions_by_click_cost),
+            preview_conversions_count = VALUES(preview_conversions_count), preview_deep_conversions_count = VALUES(preview_deep_conversions_count),
+            video_outer_play_count = VALUES(video_outer_play_count), video_outer_play_user_count = VALUES(video_outer_play_user_count), avg_user_play_count = VALUES(avg_user_play_count),
+            video_outer_play_time_count = VALUES(video_outer_play_time_count), video_outer_play_time_avg_rate = VALUES(video_outer_play_time_avg_rate),
+            video_outer_play_rate = VALUES(video_outer_play_rate), video_outer_play_cost = VALUES(video_outer_play_cost),
+            video_outer_play10_count = VALUES(video_outer_play10_count), video_outer_play25_count = VALUES(video_outer_play25_count), video_outer_play50_count = VALUES(video_outer_play50_count),
+            video_outer_play75_count = VALUES(video_outer_play75_count), video_outer_play90_count = VALUES(video_outer_play90_count), video_outer_play95_count = VALUES(video_outer_play95_count),
+            video_outer_play100_count = VALUES(video_outer_play100_count), video_outer_play3s_count = VALUES(video_outer_play3s_count), video_outer_play3s_rate = VALUES(video_outer_play3s_rate),
+            video_outer_play5s_count = VALUES(video_outer_play5s_count), video_outer_play7s_count = VALUES(video_outer_play7s_count),
+            read_count = VALUES(read_count), read_cost = VALUES(read_cost), comment_count = VALUES(comment_count), comment_cost = VALUES(comment_cost),
+            praise_count = VALUES(praise_count), praise_cost = VALUES(praise_cost), forward_count = VALUES(forward_count), forward_cost = VALUES(forward_cost), no_interest_count = VALUES(no_interest_count),
+            live_stream_crt_click_cnt = VALUES(live_stream_crt_click_cnt), click_image_count = VALUES(click_image_count), click_head_count = VALUES(click_head_count),
+            click_detail_count = VALUES(click_detail_count), click_poi_count = VALUES(click_poi_count), zone_header_click_count = VALUES(zone_header_click_count),
+            basic_info_client_count = VALUES(basic_info_client_count), account_info_click_count = VALUES(account_info_click_count),
+            clk_account_living_status_pv = VALUES(clk_account_living_status_pv), clk_accountinfo_weapp_pv = VALUES(clk_accountinfo_weapp_pv),
+            clk_accountinfo_finder_pv = VALUES(clk_accountinfo_finder_pv), clk_accountinfo_biz_pv = VALUES(clk_accountinfo_biz_pv),
+            clk_account_info_producttab_pv = VALUES(clk_account_info_producttab_pv), clk_account_info_productdetail_pv = VALUES(clk_account_info_productdetail_pv),
+            activity_info_click_count = VALUES(activity_info_click_count),
+            overall_leads_purchase_count = VALUES(overall_leads_purchase_count), effective_leads_count = VALUES(effective_leads_count), effective_cost = VALUES(effective_cost),
+            effect_leads_purchase_count = VALUES(effect_leads_purchase_count), effect_leads_purchase_cost = VALUES(effect_leads_purchase_cost),
+            platform_page_view_count = VALUES(platform_page_view_count), platform_page_view_rate = VALUES(platform_page_view_rate),
+            lan_button_click_count = VALUES(lan_button_click_count), lan_jump_button_clickers = VALUES(lan_jump_button_clickers), lan_button_click_cost = VALUES(lan_button_click_cost),
+            lan_jump_button_ctr = VALUES(lan_jump_button_ctr), lan_jump_button_click_cost = VALUES(lan_jump_button_click_cost),
+            key_page_view_count = VALUES(key_page_view_count), key_page_view_by_display_count = VALUES(key_page_view_by_display_count), key_page_view_by_click_count = VALUES(key_page_view_by_click_count),
+            key_page_uv = VALUES(key_page_uv), key_page_view_cost = VALUES(key_page_view_cost), key_page_view_rate = VALUES(key_page_view_rate),
+            landing_commodity_detail_exp_pv = VALUES(landing_commodity_detail_exp_pv),
+            app_commodity_page_view_by_display_count = VALUES(app_commodity_page_view_by_display_count), app_commodity_page_view_by_click_count = VALUES(app_commodity_page_view_by_click_count),
+            view_commodity_page_uv = VALUES(view_commodity_page_uv), web_commodity_page_view_rate = VALUES(web_commodity_page_view_rate), web_commodity_page_view_cost = VALUES(web_commodity_page_view_cost),
+            own_page_navigation_count = VALUES(own_page_navigation_count), own_page_navi_cost = VALUES(own_page_navi_cost),
+            platform_page_navigation_count = VALUES(platform_page_navigation_count), platform_page_navigation_cost = VALUES(platform_page_navigation_cost),
+            platform_shop_navigation_count = VALUES(platform_shop_navigation_count), platform_shop_navigation_cost = VALUES(platform_shop_navigation_cost),
+            active_page_views = VALUES(active_page_views), active_page_viewers = VALUES(active_page_viewers),
+            active_page_interaction_amount = VALUES(active_page_interaction_amount), active_page_interaction_users = VALUES(active_page_interaction_users),
+            guide_to_follow_page_views = VALUES(guide_to_follow_page_views), guide_to_follow_page_viewers = VALUES(guide_to_follow_page_viewers),
+            guide_to_follow_page_interaction_amount = VALUES(guide_to_follow_page_interaction_amount), guide_to_follow_page_interaction_users = VALUES(guide_to_follow_page_interaction_users),
+            platform_key_page_view_user_count = VALUES(platform_key_page_view_user_count),
+            page_consult_count = VALUES(page_consult_count), consult_uv_count = VALUES(consult_uv_count), page_consult_rate = VALUES(page_consult_rate), page_consult_cost = VALUES(page_consult_cost),
+            consult_leave_info_users = VALUES(consult_leave_info_users), consult_leave_info_cost = VALUES(consult_leave_info_cost),
+            potential_consult_count = VALUES(potential_consult_count), effective_consult_count = VALUES(effective_consult_count), tool_consult_count = VALUES(tool_consult_count),
+            page_reservation_count = VALUES(page_reservation_count), page_reservation_by_display_count = VALUES(page_reservation_by_display_count), page_reservation_by_click_count = VALUES(page_reservation_by_click_count),
+            reservation_uv = VALUES(reservation_uv), reservation_amount = VALUES(reservation_amount), page_reservation_cost = VALUES(page_reservation_cost), page_reservation_cost_with_people = VALUES(page_reservation_cost_with_people),
+            page_reservation_rate = VALUES(page_reservation_rate), page_reservation_roi = VALUES(page_reservation_roi),
+            biz_reservation_uv = VALUES(biz_reservation_uv), biz_reservation_follow_rate = VALUES(biz_reservation_follow_rate),
+            external_form_reservation_count = VALUES(external_form_reservation_count), potential_reserve_count = VALUES(potential_reserve_count),
+            reservation_check_uv = VALUES(reservation_check_uv), reservation_check_uv_cost = VALUES(reservation_check_uv_cost), reservation_check_uv_rate = VALUES(reservation_check_uv_rate),
+            effective_reserve_count = VALUES(effective_reserve_count), valid_leads_uv = VALUES(valid_leads_uv), try_out_intention_uv = VALUES(try_out_intention_uv), ineffective_leads_uv = VALUES(ineffective_leads_uv),
+            coupon_get_pv = VALUES(coupon_get_pv), coupon_get_cost = VALUES(coupon_get_cost), coupon_get_rate = VALUES(coupon_get_rate),
+            platform_coupon_click_count = VALUES(platform_coupon_click_count), purchase_amount_with_coupon = VALUES(purchase_amount_with_coupon),
+            coupon_purchase_rate = VALUES(coupon_purchase_rate), purchase_amount_with_coupon_cost = VALUES(purchase_amount_with_coupon_cost), coupon_usage_number = VALUES(coupon_usage_number),
+            page_phone_call_direct_count = VALUES(page_phone_call_direct_count), page_phone_call_direct_rate = VALUES(page_phone_call_direct_rate), page_phone_call_direct_cost = VALUES(page_phone_call_direct_cost),
+            potential_phone_count = VALUES(potential_phone_count), potential_customer_phone_uv = VALUES(potential_customer_phone_uv),
+            effective_phone_count = VALUES(effective_phone_count), valid_phone_uv = VALUES(valid_phone_uv),
+            income_val_1 = VALUES(income_val_1), income_roi_1 = VALUES(income_roi_1), income_val_3 = VALUES(income_val_3), income_roi_3 = VALUES(income_roi_3),
+            income_val_7 = VALUES(income_val_7), income_roi_7 = VALUES(income_roi_7), income_val_14 = VALUES(income_val_14), income_roi_14 = VALUES(income_roi_14),
+            income_val_24h = VALUES(income_val_24h), income_roi_1_24h = VALUES(income_roi_1_24h)
+    </insert>
+
 </mapper>

+ 198 - 0
src/main/resources/mapper/ReqDailyAdgroupReportMapper.xml

@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.moka.gdtauto.mapper.ReqDailyAdgroupReportMapper">
+<insert id="upsert" parameterType="com.moka.gdtauto.entity.ReqDailyAdgroupReport">
+        INSERT INTO req_daily_adgroup_report (
+            group_id, group_name, account_id, adgroup_id, adgroup_name, date,
+            view_count, view_user_count, avg_view_per_user,
+            valid_click_count, click_user_count, cpc, ctr,
+            valuable_click_count, valuable_click_cost, valuable_click_rate,
+            cost, acquisition_cost, thousand_display_price,
+            conversions_count, conversions_rate, conversions_cost,
+            deep_conversions_count, deep_conversions_rate, deep_conversions_cost,
+            conversions_by_display_count, conversions_by_display_rate, conversions_by_display_cost,
+            conversions_by_click_count, conversions_by_click_rate, conversions_by_click_cost,
+            preview_conversions_count, preview_deep_conversions_count,
+            video_outer_play_count, video_outer_play_user_count, avg_user_play_count,
+            video_outer_play_time_count, video_outer_play_time_avg_rate,
+            video_outer_play_rate, video_outer_play_cost,
+            video_outer_play10_count, video_outer_play25_count, video_outer_play50_count,
+            video_outer_play75_count, video_outer_play90_count, video_outer_play95_count,
+            video_outer_play100_count, video_outer_play3s_count, video_outer_play3s_rate,
+            video_outer_play5s_count, video_outer_play7s_count,
+            read_count, read_cost, comment_count, comment_cost,
+            praise_count, praise_cost, forward_count, forward_cost, no_interest_count,
+            live_stream_crt_click_cnt, click_image_count, click_head_count,
+            click_detail_count, click_poi_count, zone_header_click_count,
+            basic_info_client_count, account_info_click_count,
+            clk_account_living_status_pv, clk_accountinfo_weapp_pv,
+            clk_accountinfo_finder_pv, clk_accountinfo_biz_pv,
+            clk_account_info_producttab_pv, clk_account_info_productdetail_pv,
+            activity_info_click_count,
+            overall_leads_purchase_count, effective_leads_count, effective_cost,
+            effect_leads_purchase_count, effect_leads_purchase_cost,
+            platform_page_view_count, platform_page_view_rate,
+            lan_button_click_count, lan_jump_button_clickers, lan_button_click_cost,
+            lan_jump_button_ctr, lan_jump_button_click_cost,
+            key_page_view_count, key_page_view_by_display_count, key_page_view_by_click_count,
+            key_page_uv, key_page_view_cost, key_page_view_rate,
+            landing_commodity_detail_exp_pv,
+            app_commodity_page_view_by_display_count, app_commodity_page_view_by_click_count,
+            view_commodity_page_uv, web_commodity_page_view_rate, web_commodity_page_view_cost,
+            own_page_navigation_count, own_page_navi_cost,
+            platform_page_navigation_count, platform_page_navigation_cost,
+            platform_shop_navigation_count, platform_shop_navigation_cost,
+            active_page_views, active_page_viewers,
+            active_page_interaction_amount, active_page_interaction_users,
+            guide_to_follow_page_views, guide_to_follow_page_viewers,
+            guide_to_follow_page_interaction_amount, guide_to_follow_page_interaction_users,
+            platform_key_page_view_user_count,
+            page_consult_count, consult_uv_count, page_consult_rate, page_consult_cost,
+            consult_leave_info_users, consult_leave_info_cost,
+            potential_consult_count, effective_consult_count, tool_consult_count,
+            page_reservation_count, page_reservation_by_display_count, page_reservation_by_click_count,
+            reservation_uv, reservation_amount, page_reservation_cost, page_reservation_cost_with_people,
+            page_reservation_rate, page_reservation_roi,
+            biz_reservation_uv, biz_reservation_follow_rate,
+            external_form_reservation_count, potential_reserve_count,
+            reservation_check_uv, reservation_check_uv_cost, reservation_check_uv_rate,
+            effective_reserve_count, valid_leads_uv, try_out_intention_uv, ineffective_leads_uv,
+            coupon_get_pv, coupon_get_cost, coupon_get_rate,
+            platform_coupon_click_count, purchase_amount_with_coupon,
+            coupon_purchase_rate, purchase_amount_with_coupon_cost, coupon_usage_number,
+            page_phone_call_direct_count, page_phone_call_direct_rate, page_phone_call_direct_cost,
+            potential_phone_count, potential_customer_phone_uv,
+            effective_phone_count, valid_phone_uv,
+            income_val_1, income_roi_1, income_val_3, income_roi_3,
+            income_val_7, income_roi_7, income_val_14, income_roi_14,
+            income_val_24h, income_roi_1_24h
+        ) VALUES (
+            #{report.groupId}, #{report.groupName}, #{report.accountId}, #{report.adgroupId}, #{report.adgroupName}, #{report.date},
+            #{report.viewCount}, #{report.viewUserCount}, #{report.avgViewPerUser},
+            #{report.validClickCount}, #{report.clickUserCount}, #{report.cpc}, #{report.ctr},
+            #{report.valuableClickCount}, #{report.valuableClickCost}, #{report.valuableClickRate},
+            #{report.cost}, #{report.acquisitionCost}, #{report.thousandDisplayPrice},
+            #{report.conversionsCount}, #{report.conversionsRate}, #{report.conversionsCost},
+            #{report.deepConversionsCount}, #{report.deepConversionsRate}, #{report.deepConversionsCost},
+            #{report.conversionsByDisplayCount}, #{report.conversionsByDisplayRate}, #{report.conversionsByDisplayCost},
+            #{report.conversionsByClickCount}, #{report.conversionsByClickRate}, #{report.conversionsByClickCost},
+            #{report.previewConversionsCount}, #{report.previewDeepConversionsCount},
+            #{report.videoOuterPlayCount}, #{report.videoOuterPlayUserCount}, #{report.avgUserPlayCount},
+            #{report.videoOuterPlayTimeCount}, #{report.videoOuterPlayTimeAvgRate},
+            #{report.videoOuterPlayRate}, #{report.videoOuterPlayCost},
+            #{report.videoOuterPlay10Count}, #{report.videoOuterPlay25Count}, #{report.videoOuterPlay50Count},
+            #{report.videoOuterPlay75Count}, #{report.videoOuterPlay90Count}, #{report.videoOuterPlay95Count},
+            #{report.videoOuterPlay100Count}, #{report.videoOuterPlay3sCount}, #{report.videoOuterPlay3sRate},
+            #{report.videoOuterPlay5sCount}, #{report.videoOuterPlay7sCount},
+            #{report.readCount}, #{report.readCost}, #{report.commentCount}, #{report.commentCost},
+            #{report.praiseCount}, #{report.praiseCost}, #{report.forwardCount}, #{report.forwardCost}, #{report.noInterestCount},
+            #{report.liveStreamCrtClickCnt}, #{report.clickImageCount}, #{report.clickHeadCount},
+            #{report.clickDetailCount}, #{report.clickPoiCount}, #{report.zoneHeaderClickCount},
+            #{report.basicInfoClientCount}, #{report.accountInfoClickCount},
+            #{report.clkAccountLivingStatusPv}, #{report.clkAccountinfoWeappPv},
+            #{report.clkAccountinfoFinderPv}, #{report.clkAccountinfoBizPv},
+            #{report.clkAccountInfoProducttabPv}, #{report.clkAccountInfoProductdetailPv},
+            #{report.activityInfoClickCount},
+            #{report.overallLeadsPurchaseCount}, #{report.effectiveLeadsCount}, #{report.effectiveCost},
+            #{report.effectLeadsPurchaseCount}, #{report.effectLeadsPurchaseCost},
+            #{report.platformPageViewCount}, #{report.platformPageViewRate},
+            #{report.lanButtonClickCount}, #{report.lanJumpButtonClickers}, #{report.lanButtonClickCost},
+            #{report.lanJumpButtonCtr}, #{report.lanJumpButtonClickCost},
+            #{report.keyPageViewCount}, #{report.keyPageViewByDisplayCount}, #{report.keyPageViewByClickCount},
+            #{report.keyPageUv}, #{report.keyPageViewCost}, #{report.keyPageViewRate},
+            #{report.landingCommodityDetailExpPv},
+            #{report.appCommodityPageViewByDisplayCount}, #{report.appCommodityPageViewByClickCount},
+            #{report.viewCommodityPageUv}, #{report.webCommodityPageViewRate}, #{report.webCommodityPageViewCost},
+            #{report.ownPageNavigationCount}, #{report.ownPageNaviCost},
+            #{report.platformPageNavigationCount}, #{report.platformPageNavigationCost},
+            #{report.platformShopNavigationCount}, #{report.platformShopNavigationCost},
+            #{report.activePageViews}, #{report.activePageViewers},
+            #{report.activePageInteractionAmount}, #{report.activePageInteractionUsers},
+            #{report.guideToFollowPageViews}, #{report.guideToFollowPageViewers},
+            #{report.guideToFollowPageInteractionAmount}, #{report.guideToFollowPageInteractionUsers},
+            #{report.platformKeyPageViewUserCount},
+            #{report.pageConsultCount}, #{report.consultUvCount}, #{report.pageConsultRate}, #{report.pageConsultCost},
+            #{report.consultLeaveInfoUsers}, #{report.consultLeaveInfoCost},
+            #{report.potentialConsultCount}, #{report.effectiveConsultCount}, #{report.toolConsultCount},
+            #{report.pageReservationCount}, #{report.pageReservationByDisplayCount}, #{report.pageReservationByClickCount},
+            #{report.reservationUv}, #{report.reservationAmount}, #{report.pageReservationCost}, #{report.pageReservationCostWithPeople},
+            #{report.pageReservationRate}, #{report.pageReservationRoi},
+            #{report.bizReservationUv}, #{report.bizReservationFollowRate},
+            #{report.externalFormReservationCount}, #{report.potentialReserveCount},
+            #{report.reservationCheckUv}, #{report.reservationCheckUvCost}, #{report.reservationCheckUvRate},
+            #{report.effectiveReserveCount}, #{report.validLeadsUv}, #{report.tryOutIntentionUv}, #{report.ineffectiveLeadsUv},
+            #{report.couponGetPv}, #{report.couponGetCost}, #{report.couponGetRate},
+            #{report.platformCouponClickCount}, #{report.purchaseAmountWithCoupon},
+            #{report.couponPurchaseRate}, #{report.purchaseAmountWithCouponCost}, #{report.couponUsageNumber},
+            #{report.pagePhoneCallDirectCount}, #{report.pagePhoneCallDirectRate}, #{report.pagePhoneCallDirectCost},
+            #{report.potentialPhoneCount}, #{report.potentialCustomerPhoneUv},
+            #{report.effectivePhoneCount}, #{report.validPhoneUv},
+            #{report.incomeVal1}, #{report.incomeRoi1}, #{report.incomeVal3}, #{report.incomeRoi3},
+            #{report.incomeVal7}, #{report.incomeRoi7}, #{report.incomeVal14}, #{report.incomeRoi14},
+            #{report.incomeVal24h}, #{report.incomeRoi124h}
+        ) ON DUPLICATE KEY UPDATE
+            group_name = VALUES(group_name),
+            view_count = VALUES(view_count), view_user_count = VALUES(view_user_count), avg_view_per_user = VALUES(avg_view_per_user),
+            valid_click_count = VALUES(valid_click_count), click_user_count = VALUES(click_user_count), cpc = VALUES(cpc), ctr = VALUES(ctr),
+            valuable_click_count = VALUES(valuable_click_count), valuable_click_cost = VALUES(valuable_click_cost), valuable_click_rate = VALUES(valuable_click_rate),
+            cost = VALUES(cost), acquisition_cost = VALUES(acquisition_cost), thousand_display_price = VALUES(thousand_display_price),
+            conversions_count = VALUES(conversions_count), conversions_rate = VALUES(conversions_rate), conversions_cost = VALUES(conversions_cost),
+            deep_conversions_count = VALUES(deep_conversions_count), deep_conversions_rate = VALUES(deep_conversions_rate), deep_conversions_cost = VALUES(deep_conversions_cost),
+            conversions_by_display_count = VALUES(conversions_by_display_count), conversions_by_display_rate = VALUES(conversions_by_display_rate), conversions_by_display_cost = VALUES(conversions_by_display_cost),
+            conversions_by_click_count = VALUES(conversions_by_click_count), conversions_by_click_rate = VALUES(conversions_by_click_rate), conversions_by_click_cost = VALUES(conversions_by_click_cost),
+            preview_conversions_count = VALUES(preview_conversions_count), preview_deep_conversions_count = VALUES(preview_deep_conversions_count),
+            video_outer_play_count = VALUES(video_outer_play_count), video_outer_play_user_count = VALUES(video_outer_play_user_count), avg_user_play_count = VALUES(avg_user_play_count),
+            video_outer_play_time_count = VALUES(video_outer_play_time_count), video_outer_play_time_avg_rate = VALUES(video_outer_play_time_avg_rate),
+            video_outer_play_rate = VALUES(video_outer_play_rate), video_outer_play_cost = VALUES(video_outer_play_cost),
+            video_outer_play10_count = VALUES(video_outer_play10_count), video_outer_play25_count = VALUES(video_outer_play25_count), video_outer_play50_count = VALUES(video_outer_play50_count),
+            video_outer_play75_count = VALUES(video_outer_play75_count), video_outer_play90_count = VALUES(video_outer_play90_count), video_outer_play95_count = VALUES(video_outer_play95_count),
+            video_outer_play100_count = VALUES(video_outer_play100_count), video_outer_play3s_count = VALUES(video_outer_play3s_count), video_outer_play3s_rate = VALUES(video_outer_play3s_rate),
+            video_outer_play5s_count = VALUES(video_outer_play5s_count), video_outer_play7s_count = VALUES(video_outer_play7s_count),
+            read_count = VALUES(read_count), read_cost = VALUES(read_cost), comment_count = VALUES(comment_count), comment_cost = VALUES(comment_cost),
+            praise_count = VALUES(praise_count), praise_cost = VALUES(praise_cost), forward_count = VALUES(forward_count), forward_cost = VALUES(forward_cost), no_interest_count = VALUES(no_interest_count),
+            live_stream_crt_click_cnt = VALUES(live_stream_crt_click_cnt), click_image_count = VALUES(click_image_count), click_head_count = VALUES(click_head_count),
+            click_detail_count = VALUES(click_detail_count), click_poi_count = VALUES(click_poi_count), zone_header_click_count = VALUES(zone_header_click_count),
+            basic_info_client_count = VALUES(basic_info_client_count), account_info_click_count = VALUES(account_info_click_count),
+            clk_account_living_status_pv = VALUES(clk_account_living_status_pv), clk_accountinfo_weapp_pv = VALUES(clk_accountinfo_weapp_pv),
+            clk_accountinfo_finder_pv = VALUES(clk_accountinfo_finder_pv), clk_accountinfo_biz_pv = VALUES(clk_accountinfo_biz_pv),
+            clk_account_info_producttab_pv = VALUES(clk_account_info_producttab_pv), clk_account_info_productdetail_pv = VALUES(clk_account_info_productdetail_pv),
+            activity_info_click_count = VALUES(activity_info_click_count),
+            overall_leads_purchase_count = VALUES(overall_leads_purchase_count), effective_leads_count = VALUES(effective_leads_count), effective_cost = VALUES(effective_cost),
+            effect_leads_purchase_count = VALUES(effect_leads_purchase_count), effect_leads_purchase_cost = VALUES(effect_leads_purchase_cost),
+            platform_page_view_count = VALUES(platform_page_view_count), platform_page_view_rate = VALUES(platform_page_view_rate),
+            lan_button_click_count = VALUES(lan_button_click_count), lan_jump_button_clickers = VALUES(lan_jump_button_clickers), lan_button_click_cost = VALUES(lan_button_click_cost),
+            lan_jump_button_ctr = VALUES(lan_jump_button_ctr), lan_jump_button_click_cost = VALUES(lan_jump_button_click_cost),
+            key_page_view_count = VALUES(key_page_view_count), key_page_view_by_display_count = VALUES(key_page_view_by_display_count), key_page_view_by_click_count = VALUES(key_page_view_by_click_count),
+            key_page_uv = VALUES(key_page_uv), key_page_view_cost = VALUES(key_page_view_cost), key_page_view_rate = VALUES(key_page_view_rate),
+            landing_commodity_detail_exp_pv = VALUES(landing_commodity_detail_exp_pv),
+            app_commodity_page_view_by_display_count = VALUES(app_commodity_page_view_by_display_count), app_commodity_page_view_by_click_count = VALUES(app_commodity_page_view_by_click_count),
+            view_commodity_page_uv = VALUES(view_commodity_page_uv), web_commodity_page_view_rate = VALUES(web_commodity_page_view_rate), web_commodity_page_view_cost = VALUES(web_commodity_page_view_cost),
+            own_page_navigation_count = VALUES(own_page_navigation_count), own_page_navi_cost = VALUES(own_page_navi_cost),
+            platform_page_navigation_count = VALUES(platform_page_navigation_count), platform_page_navigation_cost = VALUES(platform_page_navigation_cost),
+            platform_shop_navigation_count = VALUES(platform_shop_navigation_count), platform_shop_navigation_cost = VALUES(platform_shop_navigation_cost),
+            active_page_views = VALUES(active_page_views), active_page_viewers = VALUES(active_page_viewers),
+            active_page_interaction_amount = VALUES(active_page_interaction_amount), active_page_interaction_users = VALUES(active_page_interaction_users),
+            guide_to_follow_page_views = VALUES(guide_to_follow_page_views), guide_to_follow_page_viewers = VALUES(guide_to_follow_page_viewers),
+            guide_to_follow_page_interaction_amount = VALUES(guide_to_follow_page_interaction_amount), guide_to_follow_page_interaction_users = VALUES(guide_to_follow_page_interaction_users),
+            platform_key_page_view_user_count = VALUES(platform_key_page_view_user_count),
+            page_consult_count = VALUES(page_consult_count), consult_uv_count = VALUES(consult_uv_count), page_consult_rate = VALUES(page_consult_rate), page_consult_cost = VALUES(page_consult_cost),
+            consult_leave_info_users = VALUES(consult_leave_info_users), consult_leave_info_cost = VALUES(consult_leave_info_cost),
+            potential_consult_count = VALUES(potential_consult_count), effective_consult_count = VALUES(effective_consult_count), tool_consult_count = VALUES(tool_consult_count),
+            page_reservation_count = VALUES(page_reservation_count), page_reservation_by_display_count = VALUES(page_reservation_by_display_count), page_reservation_by_click_count = VALUES(page_reservation_by_click_count),
+            reservation_uv = VALUES(reservation_uv), reservation_amount = VALUES(reservation_amount), page_reservation_cost = VALUES(page_reservation_cost), page_reservation_cost_with_people = VALUES(page_reservation_cost_with_people),
+            page_reservation_rate = VALUES(page_reservation_rate), page_reservation_roi = VALUES(page_reservation_roi),
+            biz_reservation_uv = VALUES(biz_reservation_uv), biz_reservation_follow_rate = VALUES(biz_reservation_follow_rate),
+            external_form_reservation_count = VALUES(external_form_reservation_count), potential_reserve_count = VALUES(potential_reserve_count),
+            reservation_check_uv = VALUES(reservation_check_uv), reservation_check_uv_cost = VALUES(reservation_check_uv_cost), reservation_check_uv_rate = VALUES(reservation_check_uv_rate),
+            effective_reserve_count = VALUES(effective_reserve_count), valid_leads_uv = VALUES(valid_leads_uv), try_out_intention_uv = VALUES(try_out_intention_uv), ineffective_leads_uv = VALUES(ineffective_leads_uv),
+            coupon_get_pv = VALUES(coupon_get_pv), coupon_get_cost = VALUES(coupon_get_cost), coupon_get_rate = VALUES(coupon_get_rate),
+            platform_coupon_click_count = VALUES(platform_coupon_click_count), purchase_amount_with_coupon = VALUES(purchase_amount_with_coupon),
+            coupon_purchase_rate = VALUES(coupon_purchase_rate), purchase_amount_with_coupon_cost = VALUES(purchase_amount_with_coupon_cost), coupon_usage_number = VALUES(coupon_usage_number),
+            page_phone_call_direct_count = VALUES(page_phone_call_direct_count), page_phone_call_direct_rate = VALUES(page_phone_call_direct_rate), page_phone_call_direct_cost = VALUES(page_phone_call_direct_cost),
+            potential_phone_count = VALUES(potential_phone_count), potential_customer_phone_uv = VALUES(potential_customer_phone_uv),
+            effective_phone_count = VALUES(effective_phone_count), valid_phone_uv = VALUES(valid_phone_uv),
+            income_val_1 = VALUES(income_val_1), income_roi_1 = VALUES(income_roi_1), income_val_3 = VALUES(income_val_3), income_roi_3 = VALUES(income_roi_3),
+            income_val_7 = VALUES(income_val_7), income_roi_7 = VALUES(income_roi_7), income_val_14 = VALUES(income_val_14), income_roi_14 = VALUES(income_roi_14),
+            income_val_24h = VALUES(income_val_24h), income_roi_1_24h = VALUES(income_roi_1_24h)
+    </insert>
+</mapper>

+ 202 - 2
src/main/resources/mapper/ReqDailyCreativeReportMapper.xml

@@ -5,7 +5,7 @@
     <!-- 插入或更新(REQUEST_TIME 口径)唯一键: group_id + account_id + dynamic_creative_id + date -->
     <insert id="upsert" parameterType="com.moka.gdtauto.entity.ReqDailyCreativeReport">
         INSERT INTO req_daily_creative_report (
-            group_id, group_name, account_id, dynamic_creative_id, date,
+            group_id, group_name, account_id, dynamic_creative_id, dynamic_creative_name, date,
             view_count, view_user_count, avg_view_per_user,
             valid_click_count, click_user_count, cpc, ctr,
             valuable_click_count, valuable_click_cost, valuable_click_rate,
@@ -69,7 +69,7 @@
             income_val_7, income_roi_7, income_val_14, income_roi_14,
             income_val_24h, income_roi_1_24h
         ) VALUES (
-            #{report.groupId}, #{report.groupName}, #{report.accountId}, #{report.dynamicCreativeId}, #{report.date},
+            #{report.groupId}, #{report.groupName}, #{report.accountId}, #{report.dynamicCreativeId}, #{report.dynamicCreativeName}, #{report.date},
             #{report.viewCount}, #{report.viewUserCount}, #{report.avgViewPerUser},
             #{report.validClickCount}, #{report.clickUserCount}, #{report.cpc}, #{report.ctr},
             #{report.valuableClickCount}, #{report.valuableClickCost}, #{report.valuableClickRate},
@@ -198,4 +198,204 @@
             income_val_24h = VALUES(income_val_24h), income_roi_1_24h = VALUES(income_roi_1_24h)
     </insert>
 
+    <!-- 批量插入或更新(REQUEST_TIME 口径)-->
+    <insert id="batchUpsert" parameterType="java.util.List">
+        INSERT INTO req_daily_creative_report (
+            group_id, group_name, account_id, dynamic_creative_id, dynamic_creative_name, date,
+            view_count, view_user_count, avg_view_per_user,
+            valid_click_count, click_user_count, cpc, ctr,
+            valuable_click_count, valuable_click_cost, valuable_click_rate,
+            cost, acquisition_cost, thousand_display_price,
+            conversions_count, conversions_rate, conversions_cost,
+            deep_conversions_count, deep_conversions_rate, deep_conversions_cost,
+            conversions_by_display_count, conversions_by_display_rate, conversions_by_display_cost,
+            conversions_by_click_count, conversions_by_click_rate, conversions_by_click_cost,
+            preview_conversions_count, preview_deep_conversions_count,
+            video_outer_play_count, video_outer_play_user_count, avg_user_play_count,
+            video_outer_play_time_count, video_outer_play_time_avg_rate,
+            video_outer_play_rate, video_outer_play_cost,
+            video_outer_play10_count, video_outer_play25_count, video_outer_play50_count,
+            video_outer_play75_count, video_outer_play90_count, video_outer_play95_count,
+            video_outer_play100_count, video_outer_play3s_count, video_outer_play3s_rate,
+            video_outer_play5s_count, video_outer_play7s_count,
+            read_count, read_cost, comment_count, comment_cost,
+            praise_count, praise_cost, forward_count, forward_cost, no_interest_count,
+            live_stream_crt_click_cnt, click_image_count, click_head_count,
+            click_detail_count, click_poi_count, zone_header_click_count,
+            basic_info_client_count, account_info_click_count,
+            clk_account_living_status_pv, clk_accountinfo_weapp_pv,
+            clk_accountinfo_finder_pv, clk_accountinfo_biz_pv,
+            clk_account_info_producttab_pv, clk_account_info_productdetail_pv,
+            activity_info_click_count,
+            overall_leads_purchase_count, effective_leads_count, effective_cost,
+            effect_leads_purchase_count, effect_leads_purchase_cost,
+            platform_page_view_count, platform_page_view_rate,
+            lan_button_click_count, lan_jump_button_clickers, lan_button_click_cost,
+            lan_jump_button_ctr, lan_jump_button_click_cost,
+            key_page_view_count, key_page_view_by_display_count, key_page_view_by_click_count,
+            key_page_uv, key_page_view_cost, key_page_view_rate,
+            landing_commodity_detail_exp_pv,
+            app_commodity_page_view_by_display_count, app_commodity_page_view_by_click_count,
+            view_commodity_page_uv, web_commodity_page_view_rate, web_commodity_page_view_cost,
+            own_page_navigation_count, own_page_navi_cost,
+            platform_page_navigation_count, platform_page_navigation_cost,
+            platform_shop_navigation_count, platform_shop_navigation_cost,
+            active_page_views, active_page_viewers,
+            active_page_interaction_amount, active_page_interaction_users,
+            guide_to_follow_page_views, guide_to_follow_page_viewers,
+            guide_to_follow_page_interaction_amount, guide_to_follow_page_interaction_users,
+            platform_key_page_view_user_count,
+            page_consult_count, consult_uv_count, page_consult_rate, page_consult_cost,
+            consult_leave_info_users, consult_leave_info_cost,
+            potential_consult_count, effective_consult_count, tool_consult_count,
+            page_reservation_count, page_reservation_by_display_count, page_reservation_by_click_count,
+            reservation_uv, reservation_amount, page_reservation_cost, page_reservation_cost_with_people,
+            page_reservation_rate, page_reservation_roi,
+            biz_reservation_uv, biz_reservation_follow_rate,
+            external_form_reservation_count, potential_reserve_count,
+            reservation_check_uv, reservation_check_uv_cost, reservation_check_uv_rate,
+            effective_reserve_count, valid_leads_uv, try_out_intention_uv, ineffective_leads_uv,
+            coupon_get_pv, coupon_get_cost, coupon_get_rate,
+            platform_coupon_click_count, purchase_amount_with_coupon,
+            coupon_purchase_rate, purchase_amount_with_coupon_cost, coupon_usage_number,
+            page_phone_call_direct_count, page_phone_call_direct_rate, page_phone_call_direct_cost,
+            potential_phone_count, potential_customer_phone_uv,
+            effective_phone_count, valid_phone_uv,
+            income_val_1, income_roi_1, income_val_3, income_roi_3,
+            income_val_7, income_roi_7, income_val_14, income_roi_14,
+            income_val_24h, income_roi_1_24h
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+                #{item.groupId}, #{item.groupName}, #{item.accountId}, #{item.dynamicCreativeId}, #{item.dynamicCreativeName}, #{item.date},
+                #{item.viewCount}, #{item.viewUserCount}, #{item.avgViewPerUser},
+                #{item.validClickCount}, #{item.clickUserCount}, #{item.cpc}, #{item.ctr},
+                #{item.valuableClickCount}, #{item.valuableClickCost}, #{item.valuableClickRate},
+                #{item.cost}, #{item.acquisitionCost}, #{item.thousandDisplayPrice},
+                #{item.conversionsCount}, #{item.conversionsRate}, #{item.conversionsCost},
+                #{item.deepConversionsCount}, #{item.deepConversionsRate}, #{item.deepConversionsCost},
+                #{item.conversionsByDisplayCount}, #{item.conversionsByDisplayRate}, #{item.conversionsByDisplayCost},
+                #{item.conversionsByClickCount}, #{item.conversionsByClickRate}, #{item.conversionsByClickCost},
+                #{item.previewConversionsCount}, #{item.previewDeepConversionsCount},
+                #{item.videoOuterPlayCount}, #{item.videoOuterPlayUserCount}, #{item.avgUserPlayCount},
+                #{item.videoOuterPlayTimeCount}, #{item.videoOuterPlayTimeAvgRate},
+                #{item.videoOuterPlayRate}, #{item.videoOuterPlayCost},
+                #{item.videoOuterPlay10Count}, #{item.videoOuterPlay25Count}, #{item.videoOuterPlay50Count},
+                #{item.videoOuterPlay75Count}, #{item.videoOuterPlay90Count}, #{item.videoOuterPlay95Count},
+                #{item.videoOuterPlay100Count}, #{item.videoOuterPlay3sCount}, #{item.videoOuterPlay3sRate},
+                #{item.videoOuterPlay5sCount}, #{item.videoOuterPlay7sCount},
+                #{item.readCount}, #{item.readCost}, #{item.commentCount}, #{item.commentCost},
+                #{item.praiseCount}, #{item.praiseCost}, #{item.forwardCount}, #{item.forwardCost}, #{item.noInterestCount},
+                #{item.liveStreamCrtClickCnt}, #{item.clickImageCount}, #{item.clickHeadCount},
+                #{item.clickDetailCount}, #{item.clickPoiCount}, #{item.zoneHeaderClickCount},
+                #{item.basicInfoClientCount}, #{item.accountInfoClickCount},
+                #{item.clkAccountLivingStatusPv}, #{item.clkAccountinfoWeappPv},
+                #{item.clkAccountinfoFinderPv}, #{item.clkAccountinfoBizPv},
+                #{item.clkAccountInfoProducttabPv}, #{item.clkAccountInfoProductdetailPv},
+                #{item.activityInfoClickCount},
+                #{item.overallLeadsPurchaseCount}, #{item.effectiveLeadsCount}, #{item.effectiveCost},
+                #{item.effectLeadsPurchaseCount}, #{item.effectLeadsPurchaseCost},
+                #{item.platformPageViewCount}, #{item.platformPageViewRate},
+                #{item.lanButtonClickCount}, #{item.lanJumpButtonClickers}, #{item.lanButtonClickCost},
+                #{item.lanJumpButtonCtr}, #{item.lanJumpButtonClickCost},
+                #{item.keyPageViewCount}, #{item.keyPageViewByDisplayCount}, #{item.keyPageViewByClickCount},
+                #{item.keyPageUv}, #{item.keyPageViewCost}, #{item.keyPageViewRate},
+                #{item.landingCommodityDetailExpPv},
+                #{item.appCommodityPageViewByDisplayCount}, #{item.appCommodityPageViewByClickCount},
+                #{item.viewCommodityPageUv}, #{item.webCommodityPageViewRate}, #{item.webCommodityPageViewCost},
+                #{item.ownPageNavigationCount}, #{item.ownPageNaviCost},
+                #{item.platformPageNavigationCount}, #{item.platformPageNavigationCost},
+                #{item.platformShopNavigationCount}, #{item.platformShopNavigationCost},
+                #{item.activePageViews}, #{item.activePageViewers},
+                #{item.activePageInteractionAmount}, #{item.activePageInteractionUsers},
+                #{item.guideToFollowPageViews}, #{item.guideToFollowPageViewers},
+                #{item.guideToFollowPageInteractionAmount}, #{item.guideToFollowPageInteractionUsers},
+                #{item.platformKeyPageViewUserCount},
+                #{item.pageConsultCount}, #{item.consultUvCount}, #{item.pageConsultRate}, #{item.pageConsultCost},
+                #{item.consultLeaveInfoUsers}, #{item.consultLeaveInfoCost},
+                #{item.potentialConsultCount}, #{item.effectiveConsultCount}, #{item.toolConsultCount},
+                #{item.pageReservationCount}, #{item.pageReservationByDisplayCount}, #{item.pageReservationByClickCount},
+                #{item.reservationUv}, #{item.reservationAmount}, #{item.pageReservationCost}, #{item.pageReservationCostWithPeople},
+                #{item.pageReservationRate}, #{item.pageReservationRoi},
+                #{item.bizReservationUv}, #{item.bizReservationFollowRate},
+                #{item.externalFormReservationCount}, #{item.potentialReserveCount},
+                #{item.reservationCheckUv}, #{item.reservationCheckUvCost}, #{item.reservationCheckUvRate},
+                #{item.effectiveReserveCount}, #{item.validLeadsUv}, #{item.tryOutIntentionUv}, #{item.ineffectiveLeadsUv},
+                #{item.couponGetPv}, #{item.couponGetCost}, #{item.couponGetRate},
+                #{item.platformCouponClickCount}, #{item.purchaseAmountWithCoupon},
+                #{item.couponPurchaseRate}, #{item.purchaseAmountWithCouponCost}, #{item.couponUsageNumber},
+                #{item.pagePhoneCallDirectCount}, #{item.pagePhoneCallDirectRate}, #{item.pagePhoneCallDirectCost},
+                #{item.potentialPhoneCount}, #{item.potentialCustomerPhoneUv},
+                #{item.effectivePhoneCount}, #{item.validPhoneUv},
+                #{item.incomeVal1}, #{item.incomeRoi1}, #{item.incomeVal3}, #{item.incomeRoi3},
+                #{item.incomeVal7}, #{item.incomeRoi7}, #{item.incomeVal14}, #{item.incomeRoi14},
+                #{item.incomeVal24h}, #{item.incomeRoi124h}
+            )
+        </foreach>
+        ON DUPLICATE KEY UPDATE
+            group_name = VALUES(group_name),
+            view_count = VALUES(view_count), view_user_count = VALUES(view_user_count), avg_view_per_user = VALUES(avg_view_per_user),
+            valid_click_count = VALUES(valid_click_count), click_user_count = VALUES(click_user_count), cpc = VALUES(cpc), ctr = VALUES(ctr),
+            valuable_click_count = VALUES(valuable_click_count), valuable_click_cost = VALUES(valuable_click_cost), valuable_click_rate = VALUES(valuable_click_rate),
+            cost = VALUES(cost), acquisition_cost = VALUES(acquisition_cost), thousand_display_price = VALUES(thousand_display_price),
+            conversions_count = VALUES(conversions_count), conversions_rate = VALUES(conversions_rate), conversions_cost = VALUES(conversions_cost),
+            deep_conversions_count = VALUES(deep_conversions_count), deep_conversions_rate = VALUES(deep_conversions_rate), deep_conversions_cost = VALUES(deep_conversions_cost),
+            conversions_by_display_count = VALUES(conversions_by_display_count), conversions_by_display_rate = VALUES(conversions_by_display_rate), conversions_by_display_cost = VALUES(conversions_by_display_cost),
+            conversions_by_click_count = VALUES(conversions_by_click_count), conversions_by_click_rate = VALUES(conversions_by_click_rate), conversions_by_click_cost = VALUES(conversions_by_click_cost),
+            preview_conversions_count = VALUES(preview_conversions_count), preview_deep_conversions_count = VALUES(preview_deep_conversions_count),
+            video_outer_play_count = VALUES(video_outer_play_count), video_outer_play_user_count = VALUES(video_outer_play_user_count), avg_user_play_count = VALUES(avg_user_play_count),
+            video_outer_play_time_count = VALUES(video_outer_play_time_count), video_outer_play_time_avg_rate = VALUES(video_outer_play_time_avg_rate),
+            video_outer_play_rate = VALUES(video_outer_play_rate), video_outer_play_cost = VALUES(video_outer_play_cost),
+            video_outer_play10_count = VALUES(video_outer_play10_count), video_outer_play25_count = VALUES(video_outer_play25_count), video_outer_play50_count = VALUES(video_outer_play50_count),
+            video_outer_play75_count = VALUES(video_outer_play75_count), video_outer_play90_count = VALUES(video_outer_play90_count), video_outer_play95_count = VALUES(video_outer_play95_count),
+            video_outer_play100_count = VALUES(video_outer_play100_count), video_outer_play3s_count = VALUES(video_outer_play3s_count), video_outer_play3s_rate = VALUES(video_outer_play3s_rate),
+            video_outer_play5s_count = VALUES(video_outer_play5s_count), video_outer_play7s_count = VALUES(video_outer_play7s_count),
+            read_count = VALUES(read_count), read_cost = VALUES(read_cost), comment_count = VALUES(comment_count), comment_cost = VALUES(comment_cost),
+            praise_count = VALUES(praise_count), praise_cost = VALUES(praise_cost), forward_count = VALUES(forward_count), forward_cost = VALUES(forward_cost), no_interest_count = VALUES(no_interest_count),
+            live_stream_crt_click_cnt = VALUES(live_stream_crt_click_cnt), click_image_count = VALUES(click_image_count), click_head_count = VALUES(click_head_count),
+            click_detail_count = VALUES(click_detail_count), click_poi_count = VALUES(click_poi_count), zone_header_click_count = VALUES(zone_header_click_count),
+            basic_info_client_count = VALUES(basic_info_client_count), account_info_click_count = VALUES(account_info_click_count),
+            clk_account_living_status_pv = VALUES(clk_account_living_status_pv), clk_accountinfo_weapp_pv = VALUES(clk_accountinfo_weapp_pv),
+            clk_accountinfo_finder_pv = VALUES(clk_accountinfo_finder_pv), clk_accountinfo_biz_pv = VALUES(clk_accountinfo_biz_pv),
+            clk_account_info_producttab_pv = VALUES(clk_account_info_producttab_pv), clk_account_info_productdetail_pv = VALUES(clk_account_info_productdetail_pv),
+            activity_info_click_count = VALUES(activity_info_click_count),
+            overall_leads_purchase_count = VALUES(overall_leads_purchase_count), effective_leads_count = VALUES(effective_leads_count), effective_cost = VALUES(effective_cost),
+            effect_leads_purchase_count = VALUES(effect_leads_purchase_count), effect_leads_purchase_cost = VALUES(effect_leads_purchase_cost),
+            platform_page_view_count = VALUES(platform_page_view_count), platform_page_view_rate = VALUES(platform_page_view_rate),
+            lan_button_click_count = VALUES(lan_button_click_count), lan_jump_button_clickers = VALUES(lan_jump_button_clickers), lan_button_click_cost = VALUES(lan_button_click_cost),
+            lan_jump_button_ctr = VALUES(lan_jump_button_ctr), lan_jump_button_click_cost = VALUES(lan_jump_button_click_cost),
+            key_page_view_count = VALUES(key_page_view_count), key_page_view_by_display_count = VALUES(key_page_view_by_display_count), key_page_view_by_click_count = VALUES(key_page_view_by_click_count),
+            key_page_uv = VALUES(key_page_uv), key_page_view_cost = VALUES(key_page_view_cost), key_page_view_rate = VALUES(key_page_view_rate),
+            landing_commodity_detail_exp_pv = VALUES(landing_commodity_detail_exp_pv),
+            app_commodity_page_view_by_display_count = VALUES(app_commodity_page_view_by_display_count), app_commodity_page_view_by_click_count = VALUES(app_commodity_page_view_by_click_count),
+            view_commodity_page_uv = VALUES(view_commodity_page_uv), web_commodity_page_view_rate = VALUES(web_commodity_page_view_rate), web_commodity_page_view_cost = VALUES(web_commodity_page_view_cost),
+            own_page_navigation_count = VALUES(own_page_navigation_count), own_page_navi_cost = VALUES(own_page_navi_cost),
+            platform_page_navigation_count = VALUES(platform_page_navigation_count), platform_page_navigation_cost = VALUES(platform_page_navigation_cost),
+            platform_shop_navigation_count = VALUES(platform_shop_navigation_count), platform_shop_navigation_cost = VALUES(platform_shop_navigation_cost),
+            active_page_views = VALUES(active_page_views), active_page_viewers = VALUES(active_page_viewers),
+            active_page_interaction_amount = VALUES(active_page_interaction_amount), active_page_interaction_users = VALUES(active_page_interaction_users),
+            guide_to_follow_page_views = VALUES(guide_to_follow_page_views), guide_to_follow_page_viewers = VALUES(guide_to_follow_page_viewers),
+            guide_to_follow_page_interaction_amount = VALUES(guide_to_follow_page_interaction_amount), guide_to_follow_page_interaction_users = VALUES(guide_to_follow_page_interaction_users),
+            platform_key_page_view_user_count = VALUES(platform_key_page_view_user_count),
+            page_consult_count = VALUES(page_consult_count), consult_uv_count = VALUES(consult_uv_count), page_consult_rate = VALUES(page_consult_rate), page_consult_cost = VALUES(page_consult_cost),
+            consult_leave_info_users = VALUES(consult_leave_info_users), consult_leave_info_cost = VALUES(consult_leave_info_cost),
+            potential_consult_count = VALUES(potential_consult_count), effective_consult_count = VALUES(effective_consult_count), tool_consult_count = VALUES(tool_consult_count),
+            page_reservation_count = VALUES(page_reservation_count), page_reservation_by_display_count = VALUES(page_reservation_by_display_count), page_reservation_by_click_count = VALUES(page_reservation_by_click_count),
+            reservation_uv = VALUES(reservation_uv), reservation_amount = VALUES(reservation_amount), page_reservation_cost = VALUES(page_reservation_cost), page_reservation_cost_with_people = VALUES(page_reservation_cost_with_people),
+            page_reservation_rate = VALUES(page_reservation_rate), page_reservation_roi = VALUES(page_reservation_roi),
+            biz_reservation_uv = VALUES(biz_reservation_uv), biz_reservation_follow_rate = VALUES(biz_reservation_follow_rate),
+            external_form_reservation_count = VALUES(external_form_reservation_count), potential_reserve_count = VALUES(potential_reserve_count),
+            reservation_check_uv = VALUES(reservation_check_uv), reservation_check_uv_cost = VALUES(reservation_check_uv_cost), reservation_check_uv_rate = VALUES(reservation_check_uv_rate),
+            effective_reserve_count = VALUES(effective_reserve_count), valid_leads_uv = VALUES(valid_leads_uv), try_out_intention_uv = VALUES(try_out_intention_uv), ineffective_leads_uv = VALUES(ineffective_leads_uv),
+            coupon_get_pv = VALUES(coupon_get_pv), coupon_get_cost = VALUES(coupon_get_cost), coupon_get_rate = VALUES(coupon_get_rate),
+            platform_coupon_click_count = VALUES(platform_coupon_click_count), purchase_amount_with_coupon = VALUES(purchase_amount_with_coupon),
+            coupon_purchase_rate = VALUES(coupon_purchase_rate), purchase_amount_with_coupon_cost = VALUES(purchase_amount_with_coupon_cost), coupon_usage_number = VALUES(coupon_usage_number),
+            page_phone_call_direct_count = VALUES(page_phone_call_direct_count), page_phone_call_direct_rate = VALUES(page_phone_call_direct_rate), page_phone_call_direct_cost = VALUES(page_phone_call_direct_cost),
+            potential_phone_count = VALUES(potential_phone_count), potential_customer_phone_uv = VALUES(potential_customer_phone_uv),
+            effective_phone_count = VALUES(effective_phone_count), valid_phone_uv = VALUES(valid_phone_uv),
+            income_val_1 = VALUES(income_val_1), income_roi_1 = VALUES(income_roi_1), income_val_3 = VALUES(income_val_3), income_roi_3 = VALUES(income_roi_3),
+            income_val_7 = VALUES(income_val_7), income_roi_7 = VALUES(income_roi_7), income_val_14 = VALUES(income_val_14), income_roi_14 = VALUES(income_roi_14),
+            income_val_24h = VALUES(income_val_24h), income_roi_1_24h = VALUES(income_roi_1_24h)
+    </insert>
+
 </mapper>

+ 13 - 0
src/test/java/com/moka/gdtauto/service/AdPlanDailyReportSyncTest.java

@@ -1,6 +1,8 @@
 package com.moka.gdtauto.service;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -9,6 +11,7 @@ import org.springframework.test.context.ActiveProfiles;
 
 import com.moka.gdtauto.GdtAutoApplication;
 import com.moka.gdtauto.task.AdPlanDailyReportSyncTask;
+import com.tencent.ads.model.v3.TimeLine;
 
 
 
@@ -24,6 +27,8 @@ public class AdPlanDailyReportSyncTest {
     private AdPlanDailyReportSyncTask adPlanDailyReportSyncTask;
     @Autowired
     private AdPlanDailyReportService adPlanDailyReportService;
+    @Autowired
+    private DailyCreativeReportService dailyCreativeReportService;
 
 
     @Test
@@ -37,4 +42,12 @@ public class AdPlanDailyReportSyncTest {
         LocalDateTime now = LocalDateTime.now();
         adPlanDailyReportService.syncRepDailyReport(29L, now, now);
     }
+
+
+    @Test
+    public void testSyncDailyCreativeReport() {
+        DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String today = LocalDate.now().format(FMT);
+        dailyCreativeReportService.syncAllAccounts(today, today, TimeLine.REQUEST_TIME.getValue());
+    }
 }

+ 133 - 0
src/test/java/com/moka/gdtauto/service/AdPlanServiceTest.java

@@ -0,0 +1,133 @@
+package com.moka.gdtauto.service;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.moka.gdtauto.GdtAutoApplication;
+import com.moka.gdtauto.client.TencentAdsApiClientFactory;
+import com.moka.gdtauto.common.Constant;
+import com.moka.gdtauto.entity.AdPlan;
+import com.moka.gdtauto.entity.AdPlanConf;
+import com.moka.gdtauto.util.TargetConfUtil;
+import com.tencent.ads.model.v3.WriteTargetingSetting;
+import com.tencent.ads.v3.TencentAds;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * mvn test -Dtest=AdPlanServiceTest#testUpdateTargetting -Dspring.profiles.active=test
+ */
+
+@Slf4j
+@SpringBootTest(classes = GdtAutoApplication.class)
+@ActiveProfiles("test")
+class AdPlanServiceTest {
+
+    @Autowired
+    private AdPlanService adPlanService;
+    @Autowired
+    private AdPlanConfService adPlanConfService;
+    @Autowired
+    private TencentAdsApiClientFactory clientFactory;
+
+    @Test
+    public void testUpdateTargetting() {
+        // 获取所有广告计划配置
+        List<AdPlanConf> confList = adPlanConfService.list(
+            new LambdaQueryWrapper<AdPlanConf>()
+                .in(AdPlanConf::getAccountGroupId, List.of(5,18))
+                .eq(AdPlanConf::getDeleted, 0));
+        log.info("查询到 {} 个广告计划配置", confList.size());
+
+        if (confList.isEmpty()) {
+            log.warn("没有可用的广告计划配置");
+            return;
+        }
+
+        // 使用 Semaphore 控制并发数为 10
+        Semaphore semaphore = new Semaphore(10);
+
+        // 使用虚拟线程池进行并发处理
+        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
+            for (AdPlanConf conf : confList) {
+                executor.submit(() -> {
+                    try {
+                        semaphore.acquire();
+                        processAdPlanConf(conf);
+                    } catch (InterruptedException e) {
+                        log.error("获取信号量被中断", e);
+                        Thread.currentThread().interrupt();
+                    } finally {
+                        semaphore.release();
+                    }
+                });
+            }
+            // 关闭线程池并等待所有任务完成
+            executor.shutdown();
+            boolean terminated = executor.awaitTermination(30, TimeUnit.MINUTES);
+            if (!terminated) {
+                log.warn("部分任务未在指定时间内完成");
+            }
+        } catch (InterruptedException e) {
+            log.error("并发处理被中断", e);
+            Thread.currentThread().interrupt();
+        }
+
+        log.info("所有广告计划定向更新完成");
+    }
+
+    /**
+     * 处理单个 AdPlanConf 下的所有 AdPlan
+     */
+    private void processAdPlanConf(AdPlanConf conf) {
+        try {
+            log.info("开始处理配置 ID: {}, 名称: {}", conf.getId(), conf.getName());
+            TencentAds tencentAds = clientFactory.getTencentAds("12329", Constant.MAIN_ORG_ACCOUNT_ID);
+            // 查询该配置下所有 adgroupId > 0 的广告计划
+            List<AdPlan> plans = adPlanService.lambdaQuery()
+                    .eq(AdPlan::getAdPlanConfId, conf.getId())
+                    .gt(AdPlan::getAdgroupId, 0)
+                    .eq(AdPlan::getDeleted, 0)
+                    .list();
+
+            if (plans.isEmpty()) {
+                log.info("配置 ID: {} 下没有有效的广告计划", conf.getId());
+                return;
+            }
+
+            log.info("配置 ID: {} 下找到 {} 个广告计划", conf.getId(), plans.size());
+
+            // 获取定向设置 (使用 targeting ID = 2)
+            WriteTargetingSetting targeting = TargetConfUtil.getTargetingSetting(2);
+            if (targeting == null) {
+                log.error("无法获取定向设置 ID=2");
+                return;
+            }
+
+            // 为每个计划更新定向
+            for (AdPlan plan : plans) {
+                try {
+                    adPlanService.updateAdgroupTargeting(tencentAds, conf, plan, targeting);
+                    log.info("更新定向成功 - 配置ID: {}, 计划ID: {}, adgroupId: {}",
+                            conf.getId(), plan.getId(), plan.getAdgroupId());
+                } catch (Exception e) {
+                    log.error("更新定向失败 - 配置ID: {}, 计划ID: {}, adgroupId: {}",
+                            conf.getId(), plan.getId(), plan.getAdgroupId(), e);
+                }
+            }
+
+            log.info("配置 ID: {} 处理完成", conf.getId());
+        } catch (Exception e) {
+            log.error("处理配置 ID: {} 时发生错误", conf.getId(), e);
+        }
+    }
+}

+ 0 - 75
src/test/java/com/moka/gdtauto/service/DailyReportTest.java

@@ -1,75 +0,0 @@
-package com.moka.gdtauto.service;
-
-import com.moka.gdtauto.GdtAutoApplication;
-import com.tencent.ads.model.v3.TimeLine;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.ActiveProfiles;
-
-/**
- * 腾讯广告 日报表同步入库测试
- * https://developers.e.qq.com/v3.0/docs/api/daily_reports/get
- *
- * mvn test -Dtest=DailyReportTest -Dspring.profiles.active=test
- *
- * @author moka
- * @since 2026-03-03
- */
-@SpringBootTest(classes = GdtAutoApplication.class)
-@ActiveProfiles("test")
-class DailyReportTest {
-
-    @Autowired
-    private DailyReportService dailyReportService;
-
-    private static final Long ORG_ACCOUNT_ID = 41644744L;
-    private static final Long TEST_ACCOUNT_ID = 69781948L;
-    private static final String TEST_JOB_NUMBER = "12458";
-    private static final Long TEST_GROUP_ID = 1L;
-    private static final String TEST_GROUP_NAME = "蒲栋良测试组";
-
-    @Test
-    @DisplayName("同步 REQUEST_TIME 口径日报表并入库")
-    void testSyncRequestTime() throws Exception {
-        System.out.println("\n========================================");
-        System.out.println("开始同步 REQUEST_TIME 日报表");
-        System.out.println("账户ID: " + TEST_ACCOUNT_ID);
-        System.out.println("========================================\n");
-
-        int saved = dailyReportService.syncReport(
-                TEST_JOB_NUMBER,
-                ORG_ACCOUNT_ID,
-                TEST_ACCOUNT_ID,
-                TEST_GROUP_ID,
-                TEST_GROUP_NAME,
-                "2026-02-20",
-                "2026-03-03",
-                TimeLine.REQUEST_TIME.getValue()
-        );
-        System.out.println("✅ REQUEST_TIME 同步完成,入库条数: " + saved);
-    }
-
-    @Test
-    @DisplayName("同步 REPORTING_TIME 口径日报表并入库")
-    void testSyncReportingTime() throws Exception {
-        System.out.println("\n========================================");
-        System.out.println("开始同步 REPORTING_TIME 日报表");
-        System.out.println("账户ID: " + TEST_ACCOUNT_ID);
-        System.out.println("========================================\n");
-
-        int saved = dailyReportService.syncReport(
-                TEST_JOB_NUMBER,
-                ORG_ACCOUNT_ID,
-                TEST_ACCOUNT_ID,
-                TEST_GROUP_ID,
-                TEST_GROUP_NAME,
-                "2026-02-20",
-                "2026-03-03",
-                TimeLine.REPORTING_TIME.getValue()
-        );
-        System.out.println("✅ REPORTING_TIME 同步完成,入库条数: " + saved);
-    }
-}