瀏覽代碼

✨ feat(pushReport): 增加pushReport页面

dodo hold 1 年之前
父節點
當前提交
f0ebb68fdd

+ 60 - 0
src/api/dataReport.ts

@@ -0,0 +1,60 @@
+import axios from 'axios';
+import type { ListRes, FormRes } from './base';
+
+export interface PushDataReportRecord {
+    id: number;
+    report_date: Date;
+    is_settlement: boolean;
+    type: number;
+    sub_type: number;
+    platform: number;
+    platform_name: string;
+    distribution: number;
+    req_count: number;
+    dp_transition_succ_count: number;
+    transition_succ_count: number;
+    expose_count: number;
+    expose_user_count: number;
+    click_count: number;
+    click_user_count: number;
+    app_open_count: number;
+    app_open_user_count: number;
+    order_count: number;
+    order_user_count: number;
+    gmv: number;
+    income: number;
+    request_id: string;
+    create_time: Date;
+    update_time: Date;
+    status: number;
+    last_push_time?: Date;
+}
+
+export interface PushDataReportParams {
+    current: number;
+    pageSize: number;
+    type?: number;
+    platform?: number;
+    status?: number;
+    is_settlement?: number;
+    report_date?: string;
+    sort?: string;
+    order?: string;
+    getTotal: boolean;
+}
+
+export interface PushDataReportRes extends ListRes {
+    list: PushDataReportRecord[];
+}
+
+export function queryReportList(data: PushDataReportParams) {
+    return axios.post<PushDataReportRes>('/api/dataReport/list', data);
+}
+
+export function saveReport(data: Partial<PushDataReportRecord>) {
+    return axios.post<FormRes>('/api/dataReport/save', data);
+}
+
+export function pushReport(id: number) {
+    return axios.post<FormRes>('/api/dataReport/push', { id });
+} 

+ 251 - 0
src/constants/platform.js

@@ -0,0 +1,251 @@
+/**
+ * 平台类型枚举
+ */
+export const PlatformEnum = {
+    // 未知
+    Unknown: 0,
+    // 淘宝
+    Taobao: 1,
+    // 抖音
+    Douyin: 2,
+    // 天猫
+    Tmall: 4,
+    // 百度网盘
+    BaiduNetdisk: 7,
+    // 腾讯会议
+    TencentMeeting: 8,
+    // 拼多多
+    Pinduoduo: 9,
+    // 拼多多H5
+    PinduoduoH5: 10,
+    // 支付宝
+    Alipay: 11,
+    // 快手
+    Kuaishou: 12,
+    // 京东
+    JD: 13,
+    // 安居客
+    Anjuke: 27,
+    // 抖音商城
+    DouyinMall: 28,
+    // 番茄畅听音乐版
+    FanqieMusic: 29,
+    // 唯品会
+    Vipshop: 30,
+    // 京东金融
+    JDFinance: 32,
+    // 爱奇艺极速版
+    IqiyiLite: 33,
+    // 安逸花
+    Anyihua: 34,
+    // 同程旅行
+    TongchengTravel: 35,
+    // 河马剧场
+    HemaTheater: 36,
+    // BOSS直聘
+    BossZhipin: 37,
+    // 喜马拉雅
+    Ximalaya: 38,
+    // QQ浏览器
+    QQBrowser: 39,
+    // 咪咕视频
+    MiguVideo: 40,
+    // 飞猪旅行
+    Fliggy: 41,
+    // 途虎养车
+    Tuhu: 42,
+    // 桔多多
+    Juduoduo: 43,
+    // Keep
+    Keep: 44,
+    // 百度文库
+    BaiduWenku: 45,
+    // TT语音
+    TTVoice: 46,
+    // 通义
+    Tongyi: 47,
+    // 起点读书
+    Qidian: 48,
+    // 搜狐新闻
+    SohuNews: 49,
+    // YY
+    YY: 50,
+    // 腾讯新闻
+    TencentNews: 52,
+    // 网易云音乐
+    NetEaseMusic: 53,
+    // QQ音乐
+    QQMusic: 54,
+    // 酷狗音乐
+    KugouMusic: 55,
+    // 全民K歌
+    QuanminKge: 56,
+    // 识货
+    Shihuo: 57,
+    // 酷我音乐
+    KuwoMusic: 58,
+    // 微博
+    Weibo: 59,
+    // 转转
+    Zhuanzhuan: 60,
+    // 快手极速版
+    KuaishouLite: 61,
+    // 抖音极速版
+    DouyinLite: 62,
+    // 百度极速版
+    BaiduLite: 63,
+    // 搜狐视频
+    SohuVideo: 64,
+    // 酷安
+    Coolapk: 65,
+    // 好看视频
+    HaokanVideo: 66,
+    // 大众点评
+    Dianping: 67,
+    // 虎牙直播
+    Huya: 68,
+    // 番茄免费小说
+    FanqieNovel: 101,
+    // 红果免费短剧
+    HongguoDrama: 102,
+    // 阿里巴巴
+    Alibaba: 103,
+    // 百度
+    Baidu: 104,
+    // 番茄畅听
+    FanqieAudio: 105,
+    // 小红书
+    Xiaohongshu: 106,
+    // 美团
+    Meituan: 107,
+    // 西瓜视频
+    XiguaVideo: 108,
+    // 抖音火山版
+    DouyinHuoshan: 109,
+    // 饿了么
+    Eleme: 110,
+    // 优酷视频
+    Youku: 111,
+    // 今日头条
+    Toutiao: 112,
+    // 得物
+    Dewu: 113,
+    // 七猫免费小说
+    QimaoNovel: 114,
+    // 夸克
+    Quark: 115,
+    // 悟空浏览器
+    WukongBrowser: 116,
+    // 豆包
+    Doubao: 117,
+    // 懂车帝
+    Dongchedi: 118,
+    // 腾讯视频
+    TencentVideo: 119,
+    // 哔哩哔哩
+    Bilibili: 120,
+    // 头条搜索极速版
+    ToutiaoSearchLite: 121,
+    // 爱奇艺
+    Iqiyi: 122,
+    // 闲鱼
+    Xianyu: 123,
+    // 携程旅行
+    Ctrip: 124,
+    // Soul
+    Soul: 125,
+    // UC浏览器
+    UCBrowser: 126
+};
+
+/**
+ * 平台类型列表 (用于下拉选择)
+ */
+export const platformList = [
+    { label: '淘宝', value: PlatformEnum.Taobao },
+    { label: '抖音', value: PlatformEnum.Douyin },
+    { label: '天猫', value: PlatformEnum.Tmall },
+    { label: '百度网盘', value: PlatformEnum.BaiduNetdisk },
+    { label: '腾讯会议', value: PlatformEnum.TencentMeeting },
+    { label: '拼多多', value: PlatformEnum.Pinduoduo },
+    { label: '拼多多H5', value: PlatformEnum.PinduoduoH5 },
+    { label: '支付宝', value: PlatformEnum.Alipay },
+    { label: '快手', value: PlatformEnum.Kuaishou },
+    { label: '京东', value: PlatformEnum.JD },
+    { label: '安居客', value: PlatformEnum.Anjuke },
+    { label: '抖音商城', value: PlatformEnum.DouyinMall },
+    { label: '番茄畅听音乐版', value: PlatformEnum.FanqieMusic },
+    { label: '唯品会', value: PlatformEnum.Vipshop },
+    { label: '京东金融', value: PlatformEnum.JDFinance },
+    { label: '爱奇艺极速版', value: PlatformEnum.IqiyiLite },
+    { label: '安逸花', value: PlatformEnum.Anyihua },
+    { label: '同程旅行', value: PlatformEnum.TongchengTravel },
+    { label: '河马剧场', value: PlatformEnum.HemaTheater },
+    { label: 'BOSS直聘', value: PlatformEnum.BossZhipin },
+    { label: '喜马拉雅', value: PlatformEnum.Ximalaya },
+    { label: 'QQ浏览器', value: PlatformEnum.QQBrowser },
+    { label: '咪咕视频', value: PlatformEnum.MiguVideo },
+    { label: '飞猪旅行', value: PlatformEnum.Fliggy },
+    { label: '途虎养车', value: PlatformEnum.Tuhu },
+    { label: '桔多多', value: PlatformEnum.Juduoduo },
+    { label: 'Keep', value: PlatformEnum.Keep },
+    { label: '百度文库', value: PlatformEnum.BaiduWenku },
+    { label: 'TT语音', value: PlatformEnum.TTVoice },
+    { label: '通义', value: PlatformEnum.Tongyi },
+    { label: '起点读书', value: PlatformEnum.Qidian },
+    { label: '搜狐新闻', value: PlatformEnum.SohuNews },
+    { label: 'YY', value: PlatformEnum.YY },
+    { label: '腾讯新闻', value: PlatformEnum.TencentNews },
+    { label: '网易云音乐', value: PlatformEnum.NetEaseMusic },
+    { label: 'QQ音乐', value: PlatformEnum.QQMusic },
+    { label: '酷狗音乐', value: PlatformEnum.KugouMusic },
+    { label: '全民K歌', value: PlatformEnum.QuanminKge },
+    { label: '识货', value: PlatformEnum.Shihuo },
+    { label: '酷我音乐', value: PlatformEnum.KuwoMusic },
+    { label: '微博', value: PlatformEnum.Weibo },
+    { label: '转转', value: PlatformEnum.Zhuanzhuan },
+    { label: '快手极速版', value: PlatformEnum.KuaishouLite },
+    { label: '抖音极速版', value: PlatformEnum.DouyinLite },
+    { label: '百度极速版', value: PlatformEnum.BaiduLite },
+    { label: '搜狐视频', value: PlatformEnum.SohuVideo },
+    { label: '酷安', value: PlatformEnum.Coolapk },
+    { label: '好看视频', value: PlatformEnum.HaokanVideo },
+    { label: '大众点评', value: PlatformEnum.Dianping },
+    { label: '虎牙直播', value: PlatformEnum.Huya },
+    { label: '番茄免费小说', value: PlatformEnum.FanqieNovel },
+    { label: '红果免费短剧', value: PlatformEnum.HongguoDrama },
+    { label: '阿里巴巴', value: PlatformEnum.Alibaba },
+    { label: '百度', value: PlatformEnum.Baidu },
+    { label: '番茄畅听', value: PlatformEnum.FanqieAudio },
+    { label: '小红书', value: PlatformEnum.Xiaohongshu },
+    { label: '美团', value: PlatformEnum.Meituan },
+    { label: '西瓜视频', value: PlatformEnum.XiguaVideo },
+    { label: '抖音火山版', value: PlatformEnum.DouyinHuoshan },
+    { label: '饿了么', value: PlatformEnum.Eleme },
+    { label: '优酷视频', value: PlatformEnum.Youku },
+    { label: '今日头条', value: PlatformEnum.Toutiao },
+    { label: '得物', value: PlatformEnum.Dewu },
+    { label: '七猫免费小说', value: PlatformEnum.QimaoNovel },
+    { label: '夸克', value: PlatformEnum.Quark },
+    { label: '悟空浏览器', value: PlatformEnum.WukongBrowser },
+    { label: '豆包', value: PlatformEnum.Doubao },
+    { label: '懂车帝', value: PlatformEnum.Dongchedi },
+    { label: '腾讯视频', value: PlatformEnum.TencentVideo },
+    { label: '哔哩哔哩', value: PlatformEnum.Bilibili },
+    { label: '头条搜索极速版', value: PlatformEnum.ToutiaoSearchLite },
+    { label: '爱奇艺', value: PlatformEnum.Iqiyi },
+    { label: '闲鱼', value: PlatformEnum.Xianyu },
+    { label: '携程旅行', value: PlatformEnum.Ctrip },
+    { label: 'Soul', value: PlatformEnum.Soul },
+    { label: 'UC浏览器', value: PlatformEnum.UCBrowser }
+];
+
+/**
+ * 根据平台ID获取平台名称
+ * @param {number} id 平台ID
+ * @returns {string} 平台名称
+ */
+export function getPlatformNameById(id) {
+    const platform = platformList.find(item => item.value === id);
+    return platform ? platform.label : `未知(${id})`;
+} 

+ 251 - 0
src/constants/pushPlatform.js

@@ -0,0 +1,251 @@
+/**
+ * 平台类型枚举
+ */
+export const PlatformEnum = {
+    // 未知
+    Unknown: 0,
+    // 淘宝
+    Taobao: 1,
+    // 抖音
+    Douyin: 2,
+    // 天猫
+    Tmall: 4,
+    // 百度网盘
+    BaiduNetdisk: 7,
+    // 腾讯会议
+    TencentMeeting: 8,
+    // 拼多多
+    Pinduoduo: 9,
+    // 拼多多H5
+    PinduoduoH5: 10,
+    // 支付宝
+    Alipay: 11,
+    // 快手
+    Kuaishou: 12,
+    // 京东
+    JD: 13,
+    // 安居客
+    Anjuke: 27,
+    // 抖音商城
+    DouyinMall: 28,
+    // 番茄畅听音乐版
+    FanqieMusic: 29,
+    // 唯品会
+    Vipshop: 30,
+    // 京东金融
+    JDFinance: 32,
+    // 爱奇艺极速版
+    IqiyiLite: 33,
+    // 安逸花
+    Anyihua: 34,
+    // 同程旅行
+    TongchengTravel: 35,
+    // 河马剧场
+    HemaTheater: 36,
+    // BOSS直聘
+    BossZhipin: 37,
+    // 喜马拉雅
+    Ximalaya: 38,
+    // QQ浏览器
+    QQBrowser: 39,
+    // 咪咕视频
+    MiguVideo: 40,
+    // 飞猪旅行
+    Fliggy: 41,
+    // 途虎养车
+    Tuhu: 42,
+    // 桔多多
+    Juduoduo: 43,
+    // Keep
+    Keep: 44,
+    // 百度文库
+    BaiduWenku: 45,
+    // TT语音
+    TTVoice: 46,
+    // 通义
+    Tongyi: 47,
+    // 起点读书
+    Qidian: 48,
+    // 搜狐新闻
+    SohuNews: 49,
+    // YY
+    YY: 50,
+    // 腾讯新闻
+    TencentNews: 52,
+    // 网易云音乐
+    NetEaseMusic: 53,
+    // QQ音乐
+    QQMusic: 54,
+    // 酷狗音乐
+    KugouMusic: 55,
+    // 全民K歌
+    QuanminKge: 56,
+    // 识货
+    Shihuo: 57,
+    // 酷我音乐
+    KuwoMusic: 58,
+    // 微博
+    Weibo: 59,
+    // 转转
+    Zhuanzhuan: 60,
+    // 快手极速版
+    KuaishouLite: 61,
+    // 抖音极速版
+    DouyinLite: 62,
+    // 百度极速版
+    BaiduLite: 63,
+    // 搜狐视频
+    SohuVideo: 64,
+    // 酷安
+    Coolapk: 65,
+    // 好看视频
+    HaokanVideo: 66,
+    // 大众点评
+    Dianping: 67,
+    // 虎牙直播
+    Huya: 68,
+    // 番茄免费小说
+    FanqieNovel: 101,
+    // 红果免费短剧
+    HongguoDrama: 102,
+    // 阿里巴巴
+    Alibaba: 103,
+    // 百度
+    Baidu: 104,
+    // 番茄畅听
+    FanqieAudio: 105,
+    // 小红书
+    Xiaohongshu: 106,
+    // 美团
+    Meituan: 107,
+    // 西瓜视频
+    XiguaVideo: 108,
+    // 抖音火山版
+    DouyinHuoshan: 109,
+    // 饿了么
+    Eleme: 110,
+    // 优酷视频
+    Youku: 111,
+    // 今日头条
+    Toutiao: 112,
+    // 得物
+    Dewu: 113,
+    // 七猫免费小说
+    QimaoNovel: 114,
+    // 夸克
+    Quark: 115,
+    // 悟空浏览器
+    WukongBrowser: 116,
+    // 豆包
+    Doubao: 117,
+    // 懂车帝
+    Dongchedi: 118,
+    // 腾讯视频
+    TencentVideo: 119,
+    // 哔哩哔哩
+    Bilibili: 120,
+    // 头条搜索极速版
+    ToutiaoSearchLite: 121,
+    // 爱奇艺
+    Iqiyi: 122,
+    // 闲鱼
+    Xianyu: 123,
+    // 携程旅行
+    Ctrip: 124,
+    // Soul
+    Soul: 125,
+    // UC浏览器
+    UCBrowser: 126
+};
+
+/**
+ * 平台类型列表 (用于下拉选择)
+ */
+export const platformList = [
+    { label: '淘宝(1)', value: PlatformEnum.Taobao },
+    { label: '抖音(2)', value: PlatformEnum.Douyin },
+    { label: '天猫(3)', value: PlatformEnum.Tmall },
+    { label: '百度网盘(4)', value: PlatformEnum.BaiduNetdisk },
+    { label: '腾讯会议(5)', value: PlatformEnum.TencentMeeting },
+    { label: '拼多多(6)', value: PlatformEnum.Pinduoduo },
+    { label: '拼多多H5(7)', value: PlatformEnum.PinduoduoH5 },
+    { label: '支付宝(8)', value: PlatformEnum.Alipay },
+    { label: '快手(9)', value: PlatformEnum.Kuaishou },
+    { label: '京东(10)', value: PlatformEnum.JD },
+    { label: '安居客(11)', value: PlatformEnum.Anjuke },
+    { label: '抖音商城(12)', value: PlatformEnum.DouyinMall },
+    { label: '番茄畅听音乐版(13)', value: PlatformEnum.FanqieMusic },
+    { label: '唯品会(14)', value: PlatformEnum.Vipshop },
+    { label: '京东金融(15)', value: PlatformEnum.JDFinance },
+    { label: '爱奇艺极速版(16)', value: PlatformEnum.IqiyiLite },
+    { label: '安逸花(17)', value: PlatformEnum.Anyihua },
+    { label: '同程旅行(18)', value: PlatformEnum.TongchengTravel },
+    { label: '河马剧场(19)', value: PlatformEnum.HemaTheater },
+    { label: 'BOSS直聘(20)', value: PlatformEnum.BossZhipin },
+    { label: '喜马拉雅(21)', value: PlatformEnum.Ximalaya },
+    { label: 'QQ浏览器(22)', value: PlatformEnum.QQBrowser },
+    { label: '咪咕视频(23)', value: PlatformEnum.MiguVideo },
+    { label: '飞猪旅行(24)', value: PlatformEnum.Fliggy },
+    { label: '途虎养车(25)', value: PlatformEnum.Tuhu },
+    { label: '桔多多(26)', value: PlatformEnum.Juduoduo },
+    { label: 'Keep(27)', value: PlatformEnum.Keep },
+    { label: '百度文库(28)', value: PlatformEnum.BaiduWenku },
+    { label: 'TT语音(29)', value: PlatformEnum.TTVoice },
+    { label: '通义(30)', value: PlatformEnum.Tongyi },
+    { label: '起点读书(31)', value: PlatformEnum.Qidian },
+    { label: '搜狐新闻(32)', value: PlatformEnum.SohuNews },
+    { label: 'YY(33)', value: PlatformEnum.YY },
+    { label: '腾讯新闻(34)', value: PlatformEnum.TencentNews },
+    { label: '网易云音乐(35)', value: PlatformEnum.NetEaseMusic },
+    { label: 'QQ音乐(36)', value: PlatformEnum.QQMusic },
+    { label: '酷狗音乐(37)', value: PlatformEnum.KugouMusic },
+    { label: '全民K歌(38)', value: PlatformEnum.QuanminKge },
+    { label: '识货(39)', value: PlatformEnum.Shihuo },
+    { label: '酷我音乐(40)', value: PlatformEnum.KuwoMusic },
+    { label: '微博(41)', value: PlatformEnum.Weibo },
+    { label: '转转(42)', value: PlatformEnum.Zhuanzhuan },
+    { label: '快手极速版(43)', value: PlatformEnum.KuaishouLite },
+    { label: '抖音极速版(44)', value: PlatformEnum.DouyinLite },
+    { label: '百度极速版(45)', value: PlatformEnum.BaiduLite },
+    { label: '搜狐视频(46)', value: PlatformEnum.SohuVideo },
+    { label: '酷安(65)', value: PlatformEnum.Coolapk },
+    { label: '好看视频(66)', value: PlatformEnum.HaokanVideo },
+    { label: '大众点评(67)', value: PlatformEnum.Dianping },
+    { label: '虎牙直播(68)', value: PlatformEnum.Huya },
+    { label: '番茄免费小说(101)', value: PlatformEnum.FanqieNovel },
+    { label: '红果免费短剧(102)', value: PlatformEnum.HongguoDrama },
+    { label: '阿里巴巴(103)', value: PlatformEnum.Alibaba },
+    { label: '百度(104)', value: PlatformEnum.Baidu },
+    { label: '番茄畅听(105)', value: PlatformEnum.FanqieAudio },
+    { label: '小红书(106)', value: PlatformEnum.Xiaohongshu },
+    { label: '美团(107)', value: PlatformEnum.Meituan },
+    { label: '西瓜视频(108)', value: PlatformEnum.XiguaVideo },
+    { label: '抖音火山版(109)', value: PlatformEnum.DouyinHuoshan },
+    { label: '饿了么(110)', value: PlatformEnum.Eleme },
+    { label: '优酷视频(111)', value: PlatformEnum.Youku },
+    { label: '今日头条(112)', value: PlatformEnum.Toutiao },
+    { label: '得物(113)', value: PlatformEnum.Dewu },
+    { label: '七猫免费小说(114)', value: PlatformEnum.QimaoNovel },
+    { label: '夸克(115)', value: PlatformEnum.Quark },
+    { label: '悟空浏览器(116)', value: PlatformEnum.WukongBrowser },
+    { label: '豆包(117)', value: PlatformEnum.Doubao },
+    { label: '懂车帝(118)', value: PlatformEnum.Dongchedi },
+    { label: '腾讯视频(119)', value: PlatformEnum.TencentVideo },
+    { label: '哔哩哔哩(120)', value: PlatformEnum.Bilibili },
+    { label: '头条搜索极速版(121)', value: PlatformEnum.ToutiaoSearchLite },
+    { label: '爱奇艺(122)', value: PlatformEnum.Iqiyi },
+    { label: '闲鱼(123)', value: PlatformEnum.Xianyu },
+    { label: '携程旅行(124)', value: PlatformEnum.Ctrip },
+    { label: 'Soul(125)', value: PlatformEnum.Soul },
+    { label: 'UC浏览器(126)', value: PlatformEnum.UCBrowser }
+];
+
+/**
+ * 根据平台ID获取平台名称
+ * @param {number} id 平台ID
+ * @returns {string} 平台名称
+ */
+export function getPlatformNameById(id) {
+    const platform = platformList.find(item => item.value === id);
+    return platform ? platform.label : `未知(${id})`;
+} 

+ 3 - 0
src/locale/zh-CN/taoke.ts

@@ -9,6 +9,9 @@ export default {
   'menu.apiAccount.list': '授权账号',
 
   
+  'menu.pushReport': '数据回传',
+  'menu.pushReport.list': '数据回传列表',
+
 
   'menu.jd': '京东联盟',
   'menu.jd.updateCookies': '更新 JD Cookies',

+ 10 - 0
src/router/routes/modules/settings.ts

@@ -32,6 +32,16 @@ const SETTINGS: AppRouteRecordRaw = {
         roles: ['*'],
       },
     },
+    {
+      path: 'push_report',
+      name: 'pushReport',
+      component: () => import('@/views/site/pushReport.vue'),
+      meta: {
+        locale: 'menu.pushReport',
+        requiresAuth: true,
+        roles: ['*'],
+      },
+    },
     {
       path: 'apiAccount',
       name: 'apiAccount',

+ 1099 - 0
src/views/site/pushReport.vue

@@ -0,0 +1,1099 @@
+<template>
+    <div class="container">
+        <Breadcrumb :items="['menu.pushReport', 'menu.pushReport.list']" />
+        <a-card class="general-card" :title="$t('menu.pushReport.list')">
+            <a-row>
+                <a-col :flex="1">
+                    <a-form :model="formModel" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
+                        label-align="left">
+                        <a-row :gutter="16">
+                            <a-col :span="6">
+                                <a-form-item field="type" label="投放场景">
+                                    <a-select v-model="formModel.type" :options="typeOptions" placeholder="请选择投放场景"
+                                        @change="onTypeOrDateChange" />
+                                </a-form-item>
+                            </a-col>
+                            <a-col :span="6">
+                                <a-form-item field="report_date" label="报告日期">
+                                    <a-date-picker v-model="formModel.report_date" style="width: 100%;"
+                                        value-format="YYYY-MM-DD" @change="onTypeOrDateChange" />
+                                </a-form-item>
+                            </a-col>
+                            <a-col :span="6">
+                                <a-form-item field="platform" label="平台">
+                                    <div class="filter-with-clear">
+                                        <a-select v-model="formModel.platform" :options="platformOptions"
+                                            placeholder="请选择平台" allow-search :filter-option="filterPlatformOption"
+                                            @change="onTypeOrDateChange" style="width: 100%;">
+                                        </a-select>
+                                        <a-button v-if="formModel.platform" type="text" class="clear-btn"
+                                            @click="clearPlatform">
+                                            <icon-close />
+                                        </a-button>
+                                    </div>
+                                </a-form-item>
+                            </a-col>
+                            <a-col :span="6">
+                                <a-form-item field="status" label="推送状态">
+                                    <a-select v-model="formModel.status" :options="statusOptions" placeholder="请选择推送状态"
+                                        @change="onTypeOrDateChange">
+                                    </a-select>
+                                </a-form-item>
+                            </a-col>
+                        </a-row>
+                        <a-row :gutter="16">
+                            <a-col :span="6">
+                                <a-form-item field="is_settlement" label="结算状态">
+                                    <a-select v-model="formModel.is_settlement" :options="settlementOptions"
+                                        placeholder="请选择结算状态" @change="onTypeOrDateChange">
+                                    </a-select>
+                                </a-form-item>
+                            </a-col>
+                        </a-row>
+                    </a-form>
+                </a-col>
+                <a-divider style="height: 38px" direction="vertical" />
+                <a-col :flex="'86px'" style="text-align: right">
+                    <a-space direction="vertical" :size="18">
+                        <a-button type="primary" @click="search">
+                            <template #icon>
+                                <icon-search />
+                            </template>
+                            {{ $t('searchTable.form.search') }}
+                        </a-button>
+                    </a-space>
+                </a-col>
+            </a-row>
+            <a-divider style="margin-top: 0" />
+            <a-row style="margin-bottom: 16px">
+                <a-col :span="12">
+                    <a-space>
+                        <a-button type="primary" @click="onAdd">
+                            <template #icon>
+                                <icon-plus />
+                            </template>
+                            新增数据
+                        </a-button>
+                    </a-space>
+                </a-col>
+                <a-col :span="12" style="
+                        display: flex;
+                        align-items: center;
+                        justify-content: end;
+                    ">
+                    <a-tooltip :content="$t('searchTable.actions.refresh')">
+                        <div class="action-icon" @click="search"><icon-refresh size="18" /></div>
+                    </a-tooltip>
+                    <a-dropdown @select="handleSelectDensity">
+                        <a-tooltip :content="$t('searchTable.actions.density')">
+                            <div class="action-icon"><icon-line-height size="18" /></div>
+                        </a-tooltip>
+                        <template #content>
+                            <a-doption v-for="item in densityList" :key="item.value" :value="item.value"
+                                :class="{ active: item.value === size }">
+                                <span>{{ item.name }}</span>
+                            </a-doption>
+                        </template>
+                    </a-dropdown>
+                    <a-tooltip :content="$t('searchTable.actions.columnSetting')">
+                        <a-popover trigger="click" position="bl" @popup-visible-change="popupVisibleChange">
+                            <div class="action-icon"><icon-settings size="18" /></div>
+                            <template #content>
+                                <div id="tableSetting">
+                                    <div v-for="(item, index) in showColumns" :key="item.dataIndex" class="setting">
+                                        <div style="
+                                                margin-right: 4px;
+                                                cursor: move;
+                                            ">
+                                            <icon-drag-arrow />
+                                        </div>
+                                        <div>
+                                            <a-checkbox v-model="item.checked" @change="
+                                                handleChange(
+                                                    $event,
+                                                    item as TableColumnData,
+                                                    index
+                                                )
+                                                ">
+                                            </a-checkbox>
+                                        </div>
+                                        <div class="title">
+                                            {{
+                                                item.title === '#'
+                                                    ? '序列号'
+                                                    : item.title
+                                            }}
+                                        </div>
+                                    </div>
+                                </div>
+                            </template>
+                        </a-popover>
+                    </a-tooltip>
+                </a-col>
+            </a-row>
+
+            <a-table row-key="id" :loading="loading" :pagination="pagination"
+                :columns="(cloneColumns as TableColumnData[])" :data="renderData" :bordered="{ headerCell: true }"
+                :size="size" @page-change="onPageChange" :scroll="{ x: 1700, y: tableHeight }">
+                <template #index="{ record }">
+                    {{ record.id }}
+                </template>
+                <template #type="{ record }">
+                    <div>{{ getTypeName(record.type) }}</div>
+
+                    <a-typography-text type="secondary">{{ getSubTypeName(record.sub_type) }}
+                    </a-typography-text>
+
+                </template>
+                <template #date="{ record }">
+                    {{ dayjs(record.report_date).format('YYYY-MM-DD') }}
+                </template>
+                <template #platform="{ record }">
+                    {{ getPlatformNameById(record.platform) }}
+                </template>
+                <template #status="{ record }">
+                    <div>
+                        <a-tag :color="getStatusColor(record.status)" bordered>
+                            {{ record.status === 1 ? '已推送' : getStatusText(record.status, record.last_push_time) }}
+                        </a-tag>
+                        <div class="status-extra-info" v-if="record.last_push_time || record.request_id">
+                            <div v-if="record.request_id" class="text-ellipsis">
+                                <span class="text-gray">标识: </span>
+                                {{ record.request_id }}
+                            </div>
+                        </div>
+                    </div>
+                </template>
+                <template #time="{ record }">
+                    <div style="color:gray;">
+                        <div>添加:{{ dayjs(record.create_time).format('MM-DD HH:mm') }}</div>
+                        <div>更新:{{ dayjs(record.update_time).format('MM-DD HH:mm') }}</div>
+                        <div v-if="record.last_push_time">推送:{{ dayjs(record.last_push_time).format('MM-DD HH:mm') }}
+                        </div>
+                    </div>
+                </template>
+                <template #request_metrics="{ record }">
+                    <div>请求量: <template v-if="record.req_count == 0">-</template><a-tag v-else color="green">{{ record.req_count }}</a-tag></div>
+                    <div>DP转链: <template v-if="record.dp_transition_succ_count == 0">-</template><a-tag v-else color="green">{{ record.dp_transition_succ_count }}</a-tag></div>
+                    <div>商业转链: <template v-if="record.transition_succ_count == 0">-</template><a-tag v-else color="green">{{ record.transition_succ_count }}</a-tag></div>
+                </template>
+                <template #expose_metrics="{ record }">
+                    <div>曝光PV: <template v-if="record.expose_count == 0">-</template><a-tag v-else color="green">{{ record.expose_count }}</a-tag></div>
+                    <div>曝光UV: <template v-if="record.expose_user_count == 0">-</template><a-tag v-else color="green">{{ record.expose_user_count }}</a-tag></div>
+                </template>
+                <template #click_metrics="{ record }">
+                    <div>点击PV: <template v-if="record.click_count == 0">-</template><a-tag v-else color="green">{{ record.click_count }}</a-tag></div>
+                    <div>点击UV: <template v-if="record.click_user_count == 0">-</template><a-tag v-else color="green">{{ record.click_user_count }}</a-tag></div>
+                </template>
+                <template #app_metrics="{ record }">
+                    <div>唤端PV: <template v-if="record.app_open_count == 0">-</template><a-tag v-else color="green">{{ record.app_open_count }}</a-tag></div>
+                    <div>唤端UV: <template v-if="record.app_open_user_count == 0">-</template><a-tag v-else color="green">{{ record.app_open_user_count }}</a-tag></div>
+                </template>
+                <template #order_metrics="{ record }">
+                    <div>订单PV: <template v-if="record.order_count == 0">-</template><a-tag v-else color="green">{{ record.order_count }}</a-tag></div>
+                    <div>订单UV: <template v-if="record.order_user_count == 0">-</template><a-tag v-else color="green">{{ record.order_user_count }}</a-tag></div>
+                </template>
+                <template #income_metrics="{ record }">
+                    <div>GMV: <template v-if="record.gmv == 0">-</template><a-tag v-else color="green">{{ record.gmv }}元</a-tag></div>
+                    <div>预估收入: <template v-if="record.income == 0">-</template><a-tag v-else color="green">{{ record.income }}元</a-tag></div>
+                </template>
+                <template #settlement="{ record }">
+                    <a-tag :color="record.is_settlement ? 'green' : 'orange'" bordered>
+                        {{ record.is_settlement ? '已结算' : '未结算' }}
+                    </a-tag>
+                </template>
+                <template #command="{ record }">
+                    <a-space>
+                        <a-button type="primary" @click="onEdit(record)">
+                            更新数据
+                        </a-button>
+                        <a-button status="success" @click="onPush(record)">
+                            推送数据
+                        </a-button>
+                    </a-space>
+                </template>
+            </a-table>
+        </a-card>
+
+        <a-modal v-model:visible="visible" :title="isEdit ? '修改数据' : '新建数据'" @ok="handleSubmit" @cancel="handleCancel"
+            width="800px">
+            <a-form :model="editForm" layout="vertical">
+                <a-row :gutter="24">
+                    <a-col :span="12">
+                        <a-form-item label="报告日期" required>
+                            <a-date-picker v-model="editForm.report_date" style="width: 100%;" value-format="YYYY-MM-DD"
+                                format="YYYY-MM-DD" show-time-default-value="00:00:00" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-item label="是否结算" required>
+                            <a-switch v-model="editForm.is_settlement" :checked-value="true" :unchecked-value="false"
+                                checked-text="已结算" unchecked-text="未结算" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-item label="投放场景" required>
+                            <a-select v-model="editForm.type" :options="typeOptions" placeholder="请选择投放场景" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-item label="子场景" required>
+                            <a-select v-model="editForm.sub_type" :options="subTypeOptions" placeholder="请选择子场景"
+                                allow-create allow-search />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="8">
+                        <a-form-item label="请求量" required>
+                            <a-input-number v-model="editForm.req_count" placeholder="请输入请求量" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="8">
+                        <a-form-item label="DP转链成功数" required>
+                            <a-input-number v-model="editForm.dp_transition_succ_count" placeholder="请输入DP转链成功数"
+                                :min="0" style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="8">
+                        <a-form-item label="商业转链成功数" required>
+                            <a-input-number v-model="editForm.transition_succ_count" placeholder="请输入商业转链成功数" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="曝光PV" required>
+                            <a-input-number v-model="editForm.expose_count" placeholder="请输入曝光PV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="曝光UV" required>
+                            <a-input-number v-model="editForm.expose_user_count" placeholder="请输入曝光UV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="点击PV" required>
+                            <a-input-number v-model="editForm.click_count" placeholder="请输入点击PV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="点击UV" required>
+                            <a-input-number v-model="editForm.click_user_count" placeholder="请输入点击UV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="唤端PV" required>
+                            <a-input-number v-model="editForm.app_open_count" placeholder="请输入唤端PV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="唤端UV" required>
+                            <a-input-number v-model="editForm.app_open_user_count" placeholder="请输入唤端UV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="订单PV" required>
+                            <a-input-number v-model="editForm.order_count" placeholder="请输入订单PV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="6">
+                        <a-form-item label="订单UV" required>
+                            <a-input-number v-model="editForm.order_user_count" placeholder="请输入订单UV" :min="0"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-item label="GMV(元)" required>
+                            <a-input-number v-model="editForm.gmv" placeholder="请输入GMV" :min="0" :precision="2"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-item label="预估收入(元)" required>
+                            <a-input-number v-model="editForm.income" placeholder="请输入预估收入" :min="0" :precision="2"
+                                style="width: 100%;" />
+                        </a-form-item>
+                    </a-col>
+                    <a-col :span="12">
+                        <a-form-item label="平台" required>
+                            <a-select v-model="editForm.platform" :options="platformOptions" placeholder="请选择平台"
+                                allow-search :filter-option="filterPlatformOption" />
+                        </a-form-item>
+                    </a-col>
+                </a-row>
+            </a-form>
+        </a-modal>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { useRouter } from 'vue-router';
+import { computed, ref, reactive, watch, nextTick, onMounted, onUnmounted } from 'vue';
+import { useI18n } from 'vue-i18n';
+import dayjs from 'dayjs';
+import useLoading from '@/hooks/loading';
+import { Pagination } from '@/types/global';
+import { Modal, Message } from '@arco-design/web-vue';
+import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
+import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
+import cloneDeep from 'lodash/cloneDeep';
+import Sortable from 'sortablejs';
+import {
+    PushDataReportParams, PushDataReportRecord, queryReportList, saveReport, pushReport
+} from '@/api/dataReport';
+import { platformList, getPlatformNameById } from '@/constants/pushPlatform';
+
+type SizeProps = 'mini' | 'small' | 'medium' | 'large';
+type Column = TableColumnData & { checked?: true };
+
+const generateFormModel = () => {
+    return {
+        type: '',
+        platform: '',
+        status: -1,
+        is_settlement: -1,
+        report_date: dayjs().format('YYYY-MM-DD'),
+        sort: 'id',
+        order: 'descending',
+    };
+};
+
+const router = useRouter();
+const { loading, setLoading } = useLoading(true);
+const { t } = useI18n();
+const renderData = ref<PushDataReportRecord[]>([]);
+const formModel = ref(generateFormModel());
+const cloneColumns = ref<Column[]>([]);
+const showColumns = ref<Column[]>([]);
+
+const size = ref<SizeProps>('small');
+
+const basePagination: Pagination = {
+    current: 1,
+    pageSize: 50,
+};
+const pagination = reactive({
+    ...basePagination,
+});
+
+const typeOptions = computed<SelectOptionData[]>(() => [
+    {
+        label: '全部',
+        value: '',
+    },
+    {
+        label: '口令',
+        value: 1,
+    },
+    {
+        label: 'SDK优惠券',
+        value: 2,
+    },
+    {
+        label: '应用建议卡',
+        value: 3,
+    },
+    {
+        label: '侧边栏',
+        value: 7,
+    },
+    {
+        label: '搜同款',
+        value: 10,
+    },
+]);
+
+const densityList = computed(() => [
+    {
+        name: t('searchTable.size.mini'),
+        value: 'mini',
+    },
+    {
+        name: t('searchTable.size.small'),
+        value: 'small',
+    },
+    {
+        name: t('searchTable.size.medium'),
+        value: 'medium',
+    },
+    {
+        name: t('searchTable.size.large'),
+        value: 'large',
+    },
+]);
+
+// 推送状态选项
+const statusOptions = computed<SelectOptionData[]>(() => [
+    {
+        label: '全部状态',
+        value: -1,
+    },
+    {
+        label: '未推送',
+        value: 0,
+    },
+    {
+        label: '已推送',
+        value: 1,
+    },
+    {
+        label: '推送失败',
+        value: 2,
+    },
+]);
+
+// 结算状态选项
+const settlementOptions = computed<SelectOptionData[]>(() => [
+    {
+        label: '全部状态',
+        value: -1,
+    },
+    {
+        label: '已结算',
+        value: 1,
+    },
+    {
+        label: '未结算',
+        value: 0,
+    },
+]);
+
+// 获取投放场景名称
+const getTypeName = (type: number) => {
+    switch (type) {
+        case 1:
+            return '口令';
+        case 2:
+            return 'SDK优惠券';
+        case 3:
+            return '应用建议卡';
+        case 7:
+            return '侧边栏';
+        case 10:
+            return '搜同款';
+        default:
+            return `未知(${type})`;
+    }
+};
+
+// 获取子场景名称
+const getSubTypeName = (subType: number) => {
+    switch (subType) {
+        case 100000:
+            return '口令';
+        case 100001:
+            return '应用内优惠券';
+        case 300001:
+            return '应用建议卡';
+        case 700001:
+            return '侧边栏';
+        case 1000001:
+            return '搜同款拍一拍';
+        case 1000002:
+            return '搜同款相册';
+        case 1000003:
+            return '搜同款助力栏';
+        case 1000004:
+            return '搜同款默认';
+        case 1000005:
+            return '搜同款识屏';
+        case 1000006:
+            return '搜同款小布CUI拍一拍';
+        case 1000007:
+            return '搜同款小布CUI客户端';
+        default:
+            return `未知(${subType})`;
+    }
+};
+
+// 子场景选项,根据当前选择的type动态生成
+const subTypeOptions = computed(() => {
+    const baseOptions: SelectOptionData[] = [];
+
+    switch (editForm.value.type) {
+        case 1:
+            baseOptions.push({ label: '口令', value: 100000 });
+            break;
+        case 3:
+            baseOptions.push({ label: '应用建议卡', value: 300001 });
+            break;
+        case 7:
+            baseOptions.push({ label: '侧边栏', value: 700001 });
+            break;
+        case 10:
+            baseOptions.push(
+                { label: '搜同款拍一拍', value: 1000001 },
+                { label: '搜同款相册', value: 1000002 },
+                { label: '搜同款助力栏', value: 1000003 },
+                { label: '搜同款默认', value: 1000004 },
+                { label: '搜同款识屏', value: 1000005 },
+                { label: '搜同款小布CUI拍一拍', value: 1000006 },
+                { label: '搜同款小布CUI客户端', value: 1000007 }
+            );
+            break;
+        default:
+            // 默认不提供选项,允许用户自定义添加
+            break;
+    }
+
+    return baseOptions;
+});
+
+const columns = computed<TableColumnData[]>(() => [
+    {
+        title: '#',
+        dataIndex: 'index',
+        slotName: 'index',
+        width: 80,
+        fixed: 'left',
+    },
+    {
+        title: '报告日期',
+        slotName: 'date',
+        width: 120,
+    },
+    {
+        title: '投放场景',
+        slotName: 'type',
+        width: 150,
+    },
+    {
+        title: '平台',
+        slotName: 'platform',
+        width: 200,
+    },
+    {
+        title: '推送状态',
+        slotName: 'status',
+        width: 200,
+    },
+    {
+        title: '请求量/转链数',
+        slotName: 'request_metrics',
+        width: 170,
+    },
+    {
+        title: '曝光',
+        slotName: 'expose_metrics',
+        width: 170,
+    },
+    {
+        title: '点击',
+        slotName: 'click_metrics',
+        width: 170,
+    },
+    {
+        title: '唤端',
+        slotName: 'app_metrics',
+        width: 170,
+    },
+    {
+        title: '订单',
+        slotName: 'order_metrics',
+        width: 170,
+    },
+    {
+        title: '收益',
+        slotName: 'income_metrics',
+        width: 200,
+    },
+    {
+        title: '时间',
+        slotName: 'time',
+        width: 180,
+    },
+    {
+        title: '结算状态',
+        slotName: 'settlement',
+        width: 100,
+    },
+    {
+        title: '操作',
+        slotName: 'command',
+        width: 180,
+        fixed: 'right',
+    },
+]);
+
+const fetchData = async (
+    params: PushDataReportParams = {
+        current: 1,
+        pageSize: 50,
+        sort: 'report_date',
+        order: 'descending',
+        getTotal: true,
+        report_date: dayjs().format('YYYY-MM-DD'),
+    },
+    tryPreviousDay = true
+) => {
+    setLoading(true);
+    try {
+        const { data } = await queryReportList(params);
+        if (!data) return;
+
+        renderData.value = data.list;
+        pagination.current = data.page;
+        pagination.total = data.count;
+
+        // Recalculate table height after data is loaded
+        nextTick(() => {
+            calculateTableHeight();
+        });
+
+        if (tryPreviousDay && data.list.length === 0 && !params.type && params.report_date === dayjs().format('YYYY-MM-DD')) {
+            const prevDay = dayjs().subtract(1, 'day').format('YYYY-MM-DD');
+            formModel.value.report_date = prevDay;
+            fetchData({
+                ...params,
+                report_date: prevDay
+            }, false);
+            Message.info(`当天无数据,已自动加载 ${prevDay} 的数据`);
+        }
+    } catch (err) {
+        console.log(err);
+    } finally {
+        setLoading(false);
+    }
+};
+
+const search = () => {
+    const statusNumber = Number(formModel.value.status);
+    const isSettlementValue = formModel.value.is_settlement;
+
+    fetchData({
+        ...basePagination,
+        ...formModel.value,
+        type: formModel.value.type ? Number(formModel.value.type) : undefined,
+        platform: formModel.value.platform ? Number(formModel.value.platform) : undefined,
+        status: statusNumber,
+        is_settlement: isSettlementValue,
+        getTotal: true,
+    } as PushDataReportParams);
+};
+
+const onPageChange = (current: number) => {
+    const statusNumber = Number(formModel.value.status);
+    const isSettlementValue = Number(formModel.value.is_settlement);
+
+    fetchData({
+        ...basePagination,
+        current,
+        type: formModel.value.type ? Number(formModel.value.type) : undefined,
+        platform: formModel.value.platform ? Number(formModel.value.platform) : undefined,
+        status: statusNumber,
+        is_settlement: isSettlementValue,
+        report_date: formModel.value.report_date,
+        getTotal: true,
+    });
+};
+
+const visible = ref(false);
+const isEdit = ref(false);
+const editForm = ref<Partial<PushDataReportRecord>>({
+    report_date: new Date(),
+    is_settlement: false,
+    type: 3,
+    sub_type: 300001,
+    platform: 1,
+    distribution: 0,
+    req_count: 0,
+    dp_transition_succ_count: 0,
+    transition_succ_count: 0,
+    expose_count: 0,
+    expose_user_count: 0,
+    click_count: 0,
+    click_user_count: 0,
+    app_open_count: 0,
+    app_open_user_count: 0,
+    order_count: 0,
+    order_user_count: 0,
+    gmv: 0,
+    income: 0,
+    request_id: '',
+});
+
+const onEdit = (current: PushDataReportRecord) => {
+    console.log('Editing record:', current);
+    isEdit.value = true;
+
+    // 处理日期,确保它是正确的格式
+    let formattedDate = current.report_date;
+    if (typeof current.report_date === 'string') {
+        formattedDate = new Date(current.report_date);
+    }
+
+    // 确保所有数值字段都是数字类型
+    const ensureNumber = (value: any) => {
+        return value !== undefined && value !== null ? Number(value) : 0;
+    };
+
+    editForm.value = {
+        id: current.id,
+        report_date: formattedDate,
+        is_settlement: Boolean(current.is_settlement),
+        type: ensureNumber(current.type),
+        sub_type: ensureNumber(current.sub_type),
+        platform: ensureNumber(current.platform || 1),
+        platform_name: current.platform_name || getPlatformNameById(ensureNumber(current.platform || 1)),
+        distribution: ensureNumber(current.distribution || 0),
+        req_count: ensureNumber(current.req_count),
+        dp_transition_succ_count: ensureNumber(current.dp_transition_succ_count),
+        transition_succ_count: ensureNumber(current.transition_succ_count),
+        expose_count: ensureNumber(current.expose_count),
+        expose_user_count: ensureNumber(current.expose_user_count),
+        click_count: ensureNumber(current.click_count),
+        click_user_count: ensureNumber(current.click_user_count),
+        app_open_count: ensureNumber(current.app_open_count),
+        app_open_user_count: ensureNumber(current.app_open_user_count),
+        order_count: ensureNumber(current.order_count),
+        order_user_count: ensureNumber(current.order_user_count),
+        gmv: ensureNumber(current.gmv),
+        income: ensureNumber(current.income),
+        request_id: current.request_id || '',
+        status: ensureNumber(current.status),
+        last_push_time: current.last_push_time,
+    };
+
+    // 确保子场景与投放场景匹配
+    nextTick(() => {
+        // 在DOM更新后检查子场景是否与投放场景匹配
+        if (editForm.value.type !== undefined) {
+            const { type } = editForm.value;
+            // 根据类型设置对应的默认子场景值
+            if (type === 1 && editForm.value.sub_type !== 100000) {
+                editForm.value.sub_type = 100000;
+            } else if (type === 3 && editForm.value.sub_type !== 300001) {
+                editForm.value.sub_type = 300001;
+            } else if (type === 7 && editForm.value.sub_type !== 700001) {
+                editForm.value.sub_type = 700001;
+            } else if (type === 10 && !([1000001, 1000002, 1000003, 1000004, 1000005, 1000006, 1000007].includes(editForm.value.sub_type as number))) {
+                editForm.value.sub_type = 1000001;
+            }
+        }
+    });
+
+    console.log('Edit form populated:', editForm.value);
+    visible.value = true;
+};
+
+const onAdd = () => {
+    isEdit.value = false;
+    const initialPlatform = 1; // 默认淘宝
+    editForm.value = {
+        report_date: new Date(),
+        is_settlement: false,
+        type: 3,
+        sub_type: 300001,
+        platform: initialPlatform,
+        platform_name: getPlatformNameById(initialPlatform),
+        distribution: 0,
+        req_count: 0,
+        dp_transition_succ_count: 0,
+        transition_succ_count: 0,
+        expose_count: 0,
+        expose_user_count: 0,
+        click_count: 0,
+        click_user_count: 0,
+        app_open_count: 0,
+        app_open_user_count: 0,
+        order_count: 0,
+        order_user_count: 0,
+        gmv: 0,
+        income: 0,
+        request_id: '',
+    };
+    visible.value = true;
+};
+
+const onPush = async (record: PushDataReportRecord) => {
+    try {
+        const response = await pushReport(record.id);
+        if (response.data.success) {
+            Message.success(response.data.msg || '推送数据成功');
+            // 推送成功后刷新当前数据
+            search();
+        } else {
+            Message.error(response.data.msg || '推送数据失败');
+        }
+    } catch (error) {
+        Message.error('请求失败');
+    }
+};
+
+// 初始加载数据
+fetchData();
+
+const handleSelectDensity = (
+    val: string | number | Record<string, any> | undefined,
+) => {
+    size.value = val as SizeProps;
+};
+
+const handleChange = (
+    checked: boolean | (string | boolean | number)[],
+    column: Column,
+    index: number
+) => {
+    if (!checked) {
+        cloneColumns.value = showColumns.value.filter(
+            (item) => item.dataIndex !== column.dataIndex
+        );
+    } else {
+        cloneColumns.value.splice(index, 0, column);
+    }
+};
+
+const exchangeArray = <T extends Array<any>>(
+    array: T,
+    beforeIdx: number,
+    newIdx: number,
+    isDeep = false
+): T => {
+    const newArray = isDeep ? cloneDeep(array) : array;
+    if (beforeIdx > -1 && newIdx > -1) {
+        // 先替换后面的,然后拿到替换的结果替换前面的
+        newArray.splice(
+            beforeIdx,
+            1,
+            newArray.splice(newIdx, 1, newArray[beforeIdx]).pop()
+        );
+    }
+    return newArray;
+};
+
+const popupVisibleChange = (val: boolean) => {
+    if (val) {
+        nextTick(() => {
+            const el = document.getElementById(
+                'tableSetting'
+            ) as HTMLElement;
+            const sortable = new Sortable(el, {
+                onEnd(e: any) {
+                    const { oldIndex, newIndex } = e;
+                    exchangeArray(cloneColumns.value, oldIndex, newIndex);
+                    exchangeArray(showColumns.value, oldIndex, newIndex);
+                },
+            });
+        });
+    }
+};
+
+const handleSubmit = async () => {
+    try {
+        // 使用统一的saveReport接口
+        const response = await saveReport(editForm.value);
+
+        if (response.data.success) {
+            Message.success(response.data.msg || '操作成功');
+            visible.value = false;
+            search(); // 重新加载当前筛选条件下的数据
+        } else {
+            Message.error(response.data.msg || '操作失败');
+        }
+    } catch (error) {
+        Message.error('请求失败');
+    }
+};
+
+const handleCancel = () => {
+    visible.value = false;
+};
+
+watch(
+    () => columns.value,
+    (val) => {
+        cloneColumns.value = cloneDeep(val);
+        cloneColumns.value.forEach((item) => {
+            item.checked = true;
+        });
+        showColumns.value = cloneDeep(cloneColumns.value);
+    },
+    { deep: true, immediate: true }
+);
+
+// 当切换type时,更新子场景值
+watch(
+    () => editForm.value.type,
+    (newType) => {
+        if (newType === 1) {
+            editForm.value.sub_type = 100000;
+        } else if (newType === 3) {
+            editForm.value.sub_type = 300001;
+        } else if (newType === 7) {
+            editForm.value.sub_type = 700001;
+        } else if (newType === 10) {
+            editForm.value.sub_type = 1000001;
+        }
+    }
+);
+
+// 添加自动加载数据的方法
+const onTypeOrDateChange = () => {
+    search();
+};
+
+const getStatusText = (status: number, lastPushTime?: Date) => {
+    switch (status) {
+        case 0:
+            return '未推送';
+        case 1:
+            if (lastPushTime) {
+                return `${dayjs(lastPushTime).format('MM-DD HH:mm')} 已推送`;
+            }
+            return '已推送';
+        case 2:
+            return '推送中';
+        case -1:
+            return '推送失败';
+        default:
+            return `未知(${status})`;
+    }
+};
+
+const getStatusColor = (status: number) => {
+    switch (status) {
+        case 0:
+            return 'gray';
+        case 1:
+            return 'green';
+        case 2:
+            return 'blue';
+        case -1:
+            return 'red';
+        default:
+            return '';
+    }
+};
+
+// 使用导入的platformList
+const platformOptions = computed<SelectOptionData[]>(() => platformList);
+
+// 监听platform变化,自动更新platform_name
+watch(
+    () => editForm.value.platform,
+    (newPlatform) => {
+        if (newPlatform !== undefined) {
+            editForm.value.platform_name = getPlatformNameById(newPlatform);
+        }
+    }
+);
+
+// Add this before the platformOptions declaration
+const filterPlatformOption = (inputValue: string, option: SelectOptionData) => {
+    return option.label.toLowerCase().includes(inputValue.toLowerCase()) ||
+        String(option.value).includes(inputValue);
+};
+
+const clearPlatform = () => {
+    formModel.value.platform = '';
+    search(); // Trigger search after clearing
+};
+
+// Add table height calculation
+const tableHeight = ref(0);
+
+onMounted(() => {
+    calculateTableHeight();
+    window.addEventListener('resize', calculateTableHeight);
+});
+
+// Cleanup the event listener when component is unmounted
+onUnmounted(() => {
+    window.removeEventListener('resize', calculateTableHeight);
+});
+
+const calculateTableHeight = () => {
+    // Get viewport height
+    const vh = window.innerHeight;
+    // Get search form height dynamically
+    const searchArea = document.querySelector('.general-card')?.querySelector('form')?.parentElement?.parentElement;
+    const searchHeight = searchArea ? searchArea.offsetHeight + 32 : 160; // 32px for margins
+
+    // Subtract header(64px), breadcrumb(40px), padding(40px), search area, table header(56px), pagination(56px)
+    tableHeight.value = vh - searchHeight - 380;
+};
+</script>
+
+<script lang="ts">
+export default {
+    name: 'PushReport',
+};
+</script>
+
+<style scoped lang="less">
+.container {
+    padding: 0 20px 20px 20px;
+}
+
+:deep(.general-card) {
+    height: 100%;
+}
+
+.action-icon {
+    margin-left: 12px;
+    cursor: pointer;
+}
+
+.active {
+    color: #0960bd;
+    background-color: #e3f4fc;
+}
+
+.setting {
+    display: flex;
+    align-items: center;
+    width: 200px;
+
+    .title {
+        margin-left: 12px;
+        cursor: pointer;
+    }
+}
+
+.status-extra-info {
+    font-size: 12px;
+    margin-top: 4px;
+    max-width: 160px;
+}
+
+.text-ellipsis {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.text-gray {
+    color: #86909c;
+}
+
+.filter-with-clear {
+    position: relative;
+    width: 100%;
+
+    .clear-btn {
+        position: absolute;
+        right: 32px;
+        top: 50%;
+        transform: translateY(-50%);
+        color: #86909c;
+        z-index: 2;
+        height: 20px;
+        width: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        padding: 0;
+        margin-right: 4px;
+
+        &:hover {
+            color: #165DFF;
+        }
+    }
+}
+</style>