|
|
@@ -6,8 +6,10 @@
|
|
|
<div class="border-b border-gray-200 pb-4 mb-6">
|
|
|
<div class="flex items-center justify-between flex-wrap gap-4">
|
|
|
<h2 class="text-xl font-semibold text-gray-800 flex items-center gap-2">
|
|
|
- <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-blue-500" fill="none" viewBox="0 0 24 24"
|
|
|
+ stroke="currentColor">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
|
+ d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
|
</svg>
|
|
|
动态创意日报表
|
|
|
</h2>
|
|
|
@@ -54,121 +56,75 @@
|
|
|
<el-radio-button value="REPORTING_TIME">上报时间</el-radio-button>
|
|
|
</el-radio-group>
|
|
|
</div>
|
|
|
-<el-select
|
|
|
- v-model="queryForm.confId"
|
|
|
- placeholder="配置"
|
|
|
- clearable
|
|
|
- filterable
|
|
|
- style="width: 180px"
|
|
|
- @change="handleSearch"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="g in confOptions"
|
|
|
- :key="g.id"
|
|
|
- :label="g.name"
|
|
|
- :value="g.id"
|
|
|
- />
|
|
|
+ <el-select v-model="queryForm.confId" placeholder="配置" clearable filterable style="width: 180px"
|
|
|
+ @change="handleSearch">
|
|
|
+ <el-option v-for="g in confOptions" :key="g.id" :label="g.name" :value="g.id" />
|
|
|
</el-select>
|
|
|
- <el-select
|
|
|
- v-model="queryForm.groupId"
|
|
|
- placeholder="账号组筛选"
|
|
|
- clearable
|
|
|
- filterable
|
|
|
- style="width: 180px"
|
|
|
- @change="handleSearch"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="g in groupOptions"
|
|
|
- :key="g.id"
|
|
|
- :label="g.groupName"
|
|
|
- :value="g.id"
|
|
|
- />
|
|
|
+ <el-select v-model="queryForm.groupId" placeholder="账号组筛选" clearable filterable style="width: 180px"
|
|
|
+ @change="handleSearch">
|
|
|
+ <el-option v-for="g in groupOptions" :key="g.id" :label="g.groupName" :value="g.id" />
|
|
|
</el-select>
|
|
|
|
|
|
- <el-input
|
|
|
- v-model="queryForm.accountId"
|
|
|
- placeholder="账户ID"
|
|
|
- clearable
|
|
|
- style="width: 160px"
|
|
|
- @clear="handleSearch"
|
|
|
- />
|
|
|
- <el-input
|
|
|
- v-model="queryForm.adgroupId"
|
|
|
- placeholder="广告ID"
|
|
|
- clearable
|
|
|
- style="width: 180px"
|
|
|
- @clear="handleSearch"
|
|
|
- />
|
|
|
-
|
|
|
- <el-input
|
|
|
- v-model="queryForm.dynamicCreativeId"
|
|
|
- placeholder="动态创意ID"
|
|
|
- clearable
|
|
|
- style="width: 180px"
|
|
|
- @clear="handleSearch"
|
|
|
- />
|
|
|
-
|
|
|
- <el-date-picker
|
|
|
- v-model="queryDateRange"
|
|
|
- type="daterange"
|
|
|
- range-separator="~"
|
|
|
- start-placeholder="开始日期"
|
|
|
- end-placeholder="结束日期"
|
|
|
- format="YYYY-MM-DD"
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
- style="width: 240px"
|
|
|
- @change="handleSearch"
|
|
|
- />
|
|
|
+ <el-input v-model="queryForm.accountId" placeholder="账户ID" clearable style="width: 160px"
|
|
|
+ @clear="handleSearch" />
|
|
|
+ <el-input v-model="queryForm.adgroupId" placeholder="广告ID" clearable style="width: 180px"
|
|
|
+ @clear="handleSearch" />
|
|
|
+
|
|
|
+ <el-input v-model="queryForm.dynamicCreativeId" placeholder="动态创意ID" clearable style="width: 180px"
|
|
|
+ @clear="handleSearch" />
|
|
|
+
|
|
|
+ <el-date-picker v-model="queryDateRange" type="daterange" range-separator="~" start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" style="width: 240px"
|
|
|
+ @change="handleSearch" />
|
|
|
</div>
|
|
|
|
|
|
<!-- 第二行:按钮右对齐 -->
|
|
|
<div class="flex justify-end gap-2">
|
|
|
<el-button type="primary" @click="handleSearch">
|
|
|
- <el-icon><Search /></el-icon>
|
|
|
+ <el-icon>
|
|
|
+ <Search />
|
|
|
+ </el-icon>
|
|
|
查询
|
|
|
</el-button>
|
|
|
<el-button @click="handleReset">重置</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
+ <p>平均ROI:{{ formatRoi(avgRoi) }}</p>
|
|
|
+
|
|
|
<!-- 数据表格 -->
|
|
|
- <el-table
|
|
|
- :data="reportList"
|
|
|
- v-loading="loading"
|
|
|
- stripe
|
|
|
- border
|
|
|
- style="width: 100%"
|
|
|
- max-height="600"
|
|
|
- :default-sort="{ prop: 'cost', order: 'descending' }"
|
|
|
- @sort-change="handleSortChange"
|
|
|
- >
|
|
|
+ <el-table :data="reportList" v-loading="loading" stripe border style="width: 100%" max-height="600"
|
|
|
+ :default-sort="{ prop: 'cost', order: 'descending' }" @sort-change="handleSortChange">
|
|
|
<!-- yyyy-MM-dd -->
|
|
|
- <el-table-column prop="confId" label="配置ID" width="110" show-overflow-tooltip>
|
|
|
- <template #default="{ row }">{{ getConfName(row.confId) }}</template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="groupId" label="账号组ID" width="110" show-overflow-tooltip >
|
|
|
+ <el-table-column prop="confId" label="配置ID" width="110" show-overflow-tooltip>
|
|
|
+ <template #default="{ row }">{{ getConfName(row.confId) }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="groupId" label="账号组ID" width="110" show-overflow-tooltip>
|
|
|
<template #default="{ row }">{{ getGroupName(row.groupId) }}</template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="date" label="日期" width="110" sortable="custom">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="date" label="日期" width="110" sortable="custom">
|
|
|
<template #default="{ row }">{{ row.date.substring(0, 10) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="accountId" label="账户ID" width="110" >
|
|
|
+ <el-table-column prop="accountId" label="账户ID" width="110">
|
|
|
<template #default="{ row }">
|
|
|
- <el-button v-if="row.accountId > 0" type="primary" size="small" style="user-select: text;" link @click="goToTencentByAccountId(row)">
|
|
|
+ <el-button v-if="row.accountId > 0" type="primary" size="small" style="user-select: text;" link
|
|
|
+ @click="goToTencentByAccountId(row)">
|
|
|
{{ row.accountId }}
|
|
|
</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="adgroupId" label="广告ID" width="120" >
|
|
|
+ <el-table-column prop="adgroupId" label="广告ID" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <el-button v-if="row.adgroupId > 0" type="primary" size="small" style="user-select: text;" link @click="goToTencentByAdgroupId(row)">
|
|
|
+ <el-button v-if="row.adgroupId > 0" type="primary" size="small" style="user-select: text;" link
|
|
|
+ @click="goToTencentByAdgroupId(row)">
|
|
|
{{ row.adgroupId }}
|
|
|
</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="dynamicCreativeId" label="创意ID" width="120" >
|
|
|
+ <el-table-column prop="dynamicCreativeId" label="创意ID" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <el-button v-if="row.dynamicCreativeId > 0" type="primary" size="small" style="user-select: text;" link @click="goToTencentCreative(row)">
|
|
|
+ <el-button v-if="row.dynamicCreativeId > 0" type="primary" size="small" style="user-select: text;" link
|
|
|
+ @click="goToTencentCreative(row)">
|
|
|
{{ row.dynamicCreativeId }}
|
|
|
</el-button>
|
|
|
</template>
|
|
|
@@ -183,6 +139,9 @@
|
|
|
<el-table-column prop="validClickCount" label="有效点击" width="110" align="right" sortable="custom">
|
|
|
<template #default="{ row }">{{ formatInt(row.validClickCount) }}</template>
|
|
|
</el-table-column>
|
|
|
+ <el-table-column prop="cpc" label="点击均价" width="90" align="right">
|
|
|
+ <template #default="{ row }">{{ formatNum(row.cpc / 100) }}</template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="ctr" label="点击率" width="110" align="right" sortable="custom">
|
|
|
<template #default="{ row }">{{ formatPct(row.ctr) }}</template>
|
|
|
</el-table-column>
|
|
|
@@ -195,36 +154,33 @@
|
|
|
<el-table-column prop="incomeRoi1" label="1日ROI" width="110" align="right" sortable="custom">
|
|
|
<template #default="{ row }">{{ formatRoi(row.incomeRoi1) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="incomeRoi3" label="3日ROI" width="110" align="right" sortable="custom">
|
|
|
- <template #default="{ row }">{{ formatRoi(row.incomeRoi3) }}</template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="1日LTV" width="100" align="right">
|
|
|
- <template #default="{ row }">{{ formatNum(row.incomeVal1) }}</template>
|
|
|
+ <el-table-column label="1日变现" width="100" align="right">
|
|
|
+ <template #default="{ row }">{{ formatNum(row.incomeVal1 / 100) }}</template>
|
|
|
</el-table-column>
|
|
|
|
|
|
- <el-table-column prop="cpc" label="CPC" width="90" align="right">
|
|
|
- <template #default="{ row }">{{ formatNum(row.cpc) }}</template>
|
|
|
+ <el-table-column prop="incomeRoi3" label="3日ROI" width="110" align="right" sortable="custom">
|
|
|
+ <template #default="{ row }">{{ formatRoi(row.incomeRoi3) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="3日LTV" width="100" align="right">
|
|
|
- <template #default="{ row }">{{ formatNum(row.incomeVal3) }}</template>
|
|
|
+ <el-table-column label="3日变现" width="100" align="right">
|
|
|
+ <template #default="{ row }">{{ formatNum(row.incomeVal3 / 100) }}</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="7日ROI" width="90" align="right">
|
|
|
<template #default="{ row }">{{ formatRoi(row.incomeRoi7) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="7日LTV" width="100" align="right">
|
|
|
- <template #default="{ row }">{{ formatNum(row.incomeVal7) }}</template>
|
|
|
+ <el-table-column label="7日变现" width="100" align="right">
|
|
|
+ <template #default="{ row }">{{ formatNum(row.incomeVal7 / 100) }}</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="14日ROI" width="90" align="right">
|
|
|
<template #default="{ row }">{{ formatRoi(row.incomeRoi14) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="14日LTV" width="100" align="right">
|
|
|
- <template #default="{ row }">{{ formatNum(row.incomeVal14) }}</template>
|
|
|
+ <el-table-column label="14日变现" width="100" align="right">
|
|
|
+ <template #default="{ row }">{{ formatNum(row.incomeVal14 / 100) }}</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="24h ROI" width="100" align="right">
|
|
|
<template #default="{ row }">{{ formatRoi(row.incomeRoi124h) }}</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="24h LTV" width="100" align="right">
|
|
|
- <template #default="{ row }">{{ formatNum(row.incomeVal24h) }}</template>
|
|
|
+ <el-table-column label="24h变现" width="100" align="right">
|
|
|
+ <template #default="{ row }">{{ formatNum(row.incomeVal24h / 100) }}</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="videoOuterPlayCount" label="视频播放" width="100" align="right">
|
|
|
<template #default="{ row }">{{ formatInt(row.videoOuterPlayCount) }}</template>
|
|
|
@@ -236,15 +192,9 @@
|
|
|
|
|
|
<!-- 分页 -->
|
|
|
<div class="mt-6 flex justify-end">
|
|
|
- <el-pagination
|
|
|
- v-model:current-page="pagination.page"
|
|
|
- v-model:page-size="pagination.pageSize"
|
|
|
- :page-sizes="[20, 50, 100, 200]"
|
|
|
- :total="pagination.total"
|
|
|
- layout="total, sizes, prev, pager, next, jumper"
|
|
|
- @size-change="handleSizeChange"
|
|
|
- @current-change="handleCurrentChange"
|
|
|
- />
|
|
|
+ <el-pagination v-model:current-page="pagination.page" v-model:page-size="pagination.pageSize"
|
|
|
+ :page-sizes="[20, 50, 100, 200]" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -259,7 +209,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import { Refresh, Search } from '@element-plus/icons-vue'
|
|
|
import { useRoute } from 'vue-router'
|
|
|
-import { getDailyReportList } from '@/api/dailyCreativeReport'
|
|
|
+import { getDailyReportList, getAvgROI } from '@/api/dailyCreativeReport'
|
|
|
import { getAccountGroupListAll } from '@/api/accountGroup'
|
|
|
import dayjs from 'dayjs'
|
|
|
import { allForSelect } from '@/api/adPlanConf'
|
|
|
@@ -270,6 +220,8 @@ const route = useRoute()
|
|
|
const loading = ref(false)
|
|
|
const syncing = ref(false)
|
|
|
const reportList = ref([])
|
|
|
+const avgRoi = ref({})
|
|
|
+
|
|
|
const groupOptions = ref([])
|
|
|
const groupNameMap = ref({})
|
|
|
const getGroupName = (id) => groupNameMap.value[id] || ''
|
|
|
@@ -293,7 +245,7 @@ const queryForm = reactive({
|
|
|
const getDefaultDateRange = () => {
|
|
|
const end = new Date()
|
|
|
const start = new Date()
|
|
|
- start.setDate(start.getDate() - 7)
|
|
|
+ start.setDate(start.getDate())
|
|
|
const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
|
|
return [fmt(start), fmt(end)]
|
|
|
}
|
|
|
@@ -343,6 +295,13 @@ const loadList = async () => {
|
|
|
} else {
|
|
|
ElMessage.error(res.message || '查询失败')
|
|
|
}
|
|
|
+
|
|
|
+ const avgROIRes = await getAvgROI(params)
|
|
|
+ if (avgROIRes.success) {
|
|
|
+ avgRoi.value = avgROIRes.data
|
|
|
+ } else {
|
|
|
+ ElMessage.error(avgROIRes.message || '查询平均ROI失败')
|
|
|
+ }
|
|
|
} catch (err) {
|
|
|
console.error('查询日报表失败:', err)
|
|
|
ElMessage.error('查询失败')
|
|
|
@@ -352,7 +311,7 @@ const loadList = async () => {
|
|
|
}
|
|
|
|
|
|
|
|
|
-const goToTencentByAccountId = (row) => {
|
|
|
+const goToTencentByAccountId = (row) => {
|
|
|
const date = dayjs().format('YYYY-MM-DD')
|
|
|
window.open(`https://ad.qq.com/atlas/${row.accountId}/admanage/index?start_date=${date}&end_date=${date}&tab=adgroup&query={%22operation_status%22:[%22CALCULATE_STATUS_EXCLUDE_DEL%22],%22system_status%22:[]}`, '_blank')
|
|
|
}
|