Merge remote-tracking branch 'origin/feature/v1.3_营销资产中台' into feature/v1.3_营销资产中台

# Conflicts:
#	src/api/all/propertyMarketing.ts
This commit is contained in:
林志军
2025-07-07 21:39:53 +08:00
30 changed files with 257 additions and 161 deletions

View File

@ -20,7 +20,7 @@ export const TABLE_COLUMNS = [
{
title: '运营人员',
dataIndex: 'operator_ame',
prop: 'operator_ame',
prop: 'operator',
width: 180,
},
{
@ -73,8 +73,8 @@ export const TABLE_COLUMNS = [
},
// {
// title: '账户余额',
// dataIndex: 'balance',
// prop: 'balance',
// dataIndex: 'balance_amount',
// prop: 'balance_amount',
// width: 180,
// tooltip: '当前账户剩余的可用余额,用于后续广告投放。',
// prefix: '¥',
@ -83,23 +83,23 @@ export const TABLE_COLUMNS = [
// sortDirections: ['ascend', 'descend'],
// },
// },
// {
// title: 'AI评价',
// dataIndex: 'ai_evaluate',
// prop: 'ai_evaluate',
// width: 260,
// },
// {
// title: '投资回报率',
// dataIndex: 'roi',
// prop: 'roi',
// width: 180,
// tooltip: '投入产出比ROI等于收益 ÷ 投入,反映投放带来的商业价值。',
// align: 'right',
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
{
title: 'AI评价',
dataIndex: 'ai_evaluate',
prop: 'ai_evaluate',
width: 260,
},
{
title: '投资回报率',
dataIndex: 'roi',
prop: 'roi',
width: 180,
tooltip: '投入产出比ROI等于收益 ÷ 投入,反映投放带来的商业价值。',
align: 'right',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
// {
// title: '投资回报率环比',
// dataIndex: 'roi_chain',
@ -114,7 +114,7 @@ export const TABLE_COLUMNS = [
// },
// },
{
title: '展示',
title: '展示',
dataIndex: 'show_number',
prop: 'show_number',
width: 180,
@ -124,21 +124,21 @@ export const TABLE_COLUMNS = [
sortDirections: ['ascend', 'descend'],
},
},
// {
// title: '展示量环比',
// dataIndex: 'view_number_chain',
// prop: 'view_number_chain',
// width: 180,
// tooltip: '展示量与上一周期的变化百分比,反映广告曝光趋势。',
// align: 'right',
// suffix: '%',
// isRateField: true,
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
{
title: '点击量',
title: '展示数环比',
dataIndex: 'show_number_chain',
prop: 'show_number_chain',
width: 180,
tooltip: '展示数与上一周期的变化百分比,反映广告曝光趋势。',
align: 'right',
suffix: '%',
isRateField: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '点击数',
dataIndex: 'click_number',
prop: 'click_number',
width: 180,
@ -148,19 +148,19 @@ export const TABLE_COLUMNS = [
sortDirections: ['ascend', 'descend'],
},
},
// {
// title: '点击环比',
// dataIndex: 'click_number_chain',
// prop: 'click_number_chain',
// width: 180,
// tooltip: '当前周期点击相较上一周期的变化百分比。',
// align: 'right',
// suffix: '%',
// isRateField: true,
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
{
title: '点击环比',
dataIndex: 'click_number_chain',
prop: 'click_number_chain',
width: 180,
tooltip: '当前周期点击相较上一周期的变化百分比。',
align: 'right',
suffix: '%',
isRateField: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '点击率',
dataIndex: 'click_rate',
@ -172,19 +172,19 @@ export const TABLE_COLUMNS = [
sortDirections: ['ascend', 'descend'],
},
},
// {
// title: '点击率环比',
// dataIndex: 'click_rate_chain',
// prop: 'click_rate_chain',
// width: 180,
// tooltip: '当前 CTR 相较上一周期的变化百分比,评估广告表现是否优化。',
// align: 'right',
// suffix: '%',
// isRateField: true,
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
{
title: '点击率环比',
dataIndex: 'click_rate_chain',
prop: 'click_rate_chain',
width: 180,
tooltip: '当前 CTR 相较上一周期的变化百分比,评估广告表现是否优化。',
align: 'right',
suffix: '%',
isRateField: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '平均点击成本',
dataIndex: 'avg_click_cost',
@ -197,7 +197,7 @@ export const TABLE_COLUMNS = [
},
},
{
title: '千次展费用',
title: '千次展费用',
dataIndex: 'thousand_show_cost',
prop: 'thousand_show_cost',
width: 180,
@ -296,14 +296,4 @@ export const TABLE_COLUMNS = [
// prop: 'newest_work_title',
// width: 260,
// },
// {
// title: '投放回报率',
// dataIndex: 'roi_chain1',
// prop: 'roi_chain1',
// width: 180,
// align: 'right',
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
];

View File

@ -33,6 +33,7 @@
ref="tableRef"
:data="dataSource"
row-key="id"
column-resizable
:row-selection="{
type: 'checkbox',
showCheckedAll: true,

View File

@ -48,7 +48,7 @@
<a-range-picker
v-model="query.data_time"
size="medium"
allow-clear
:allow-clear="false"
format="YYYY-MM-DD"
class="w-100%"
@change="handleSearch"

View File

@ -31,6 +31,7 @@
</a-button>
</div>
<a-table
column-resizable
:columns="columns"
:data="list"
row-key="id"

View File

@ -34,7 +34,7 @@ export const TABLE_COLUMNS = [
{
title: '运营人员',
dataIndex: 'operator_name',
prop: 'operator_name',
prop: 'operator',
width: 180,
},
{
@ -51,8 +51,8 @@ export const TABLE_COLUMNS = [
},
// {
// title: '账户余额',
// dataIndex: 'balance',
// prop: 'balance',
// dataIndex: 'balance_amount',
// prop: 'balance_amount',
// width: 180,
// tooltip: '当前投流计划剩余可用预算,用于后续广告持续投放。',
// prefix: '¥',
@ -61,25 +61,25 @@ export const TABLE_COLUMNS = [
// sortDirections: ['ascend', 'descend'],
// },
// },
// {
// title: 'AI评价',
// dataIndex: 'ai_evaluate',
// prop: 'ai_evaluate',
// width: 260,
// },
// {
// title: '投资回报率',
// dataIndex: 'roi',
// prop: 'roi',
// width: 180,
// tooltip: '投入产出比ROI= 收益 ÷ 投入,用于衡量该计划的经济效益。',
// align: 'right',
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
{
title: '展示量',
title: 'AI评价',
dataIndex: 'ai_evaluate',
prop: 'ai_evaluate',
width: 260,
},
{
title: '投资回报率',
dataIndex: 'roi',
prop: 'roi',
width: 180,
tooltip: '投入产出比ROI= 收益 ÷ 投入,用于衡量该计划的经济效益。',
align: 'right',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '展示数',
dataIndex: 'show_number',
prop: 'show_number',
width: 180,
@ -90,7 +90,7 @@ export const TABLE_COLUMNS = [
},
},
{
title: '点击',
title: '点击',
dataIndex: 'click_number',
prop: 'click_number',
width: 180,
@ -111,19 +111,19 @@ export const TABLE_COLUMNS = [
sortDirections: ['ascend', 'descend'],
},
},
// {
// title: '点击率环比',
// dataIndex: 'click_rate_chain',
// prop: 'click_rate_chain',
// width: 180,
// tooltip: '当前 CTR 与上一周期对比的变化百分比,用于追踪广告吸引力趋势。',
// align: 'right',
// suffix: '%',
// isRateField: true,
// sortable: {
// sortDirections: ['ascend', 'descend'],
// },
// },
{
title: '点击率环比',
dataIndex: 'click_rate_chain',
prop: 'click_rate_chain',
width: 180,
tooltip: '当前 CTR 与上一周期对比的变化百分比,用于追踪广告吸引力趋势。',
align: 'right',
suffix: '%',
isRateField: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '平均点击成本',
dataIndex: 'avg_click_cost',
@ -136,7 +136,7 @@ export const TABLE_COLUMNS = [
},
},
{
title: '千次展费用',
title: '千次展费用',
dataIndex: 'thousand_show_cost',
prop: 'thousand_show_cost',
width: 180,

View File

@ -31,6 +31,7 @@
<a-table
ref="tableRef"
column-resizable
:data="dataSource"
row-key="id"
:row-selection="{

View File

@ -22,7 +22,7 @@
v-model:query="query"
:isAccountTab="isAccountTab"
@onSearch="getData"
@onReset="handleReset"
@onReset="init"
/>
</div>
<div
@ -84,6 +84,19 @@ const pageInfo = ref(cloneDeep(INITIAL_PAGE_INFO));
const isAccountTab = computed(() => activeTab.value === '1');
const init = () => {
query.value = cloneDeep(INITIAL_QUERY);
dataSource.value = [];
pageInfo.value = cloneDeep(INITIAL_PAGE_INFO);
selectedRowKeys.value = [];
accountTableRef.value?.resetTable();
const data_time = [dayjs().format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')];
query.value.data_time = data_time;
getData();
};
const getData = async () => {
const _fn = isAccountTab.value ? getPlacementAccountData : getPlacementAccountDataList;
const { page, page_size } = pageInfo.value;
@ -113,14 +126,6 @@ const reload = () => {
getData();
};
const handleReset = () => {
pageInfo.value = cloneDeep(INITIAL_PAGE_INFO);
selectedRowKeys.value = [];
accountTableRef.value?.resetTable();
query.value = cloneDeep(INITIAL_QUERY);
reload();
};
const handleSorterChange = (column, order) => {
query.value.column = column;
query.value.order = order;
@ -132,8 +137,7 @@ const handleSelectionChange = (selectedRows) => {
const handleTabClick = (key) => {
activeTab.value = key;
dataSource.value = [];
handleReset();
init();
};
const handleExport = () => {
@ -153,7 +157,7 @@ const handleOpenGroupModal = () => {
};
onMounted(() => {
getData();
init();
});
</script>

View File

@ -119,14 +119,14 @@
<a-input v-model="form.balance_amount" placeholder="请输入..." size="large" disabled />
</a-form-item>
</template>
<a-form-item label="同步项目数据" field="is_sync">
<a-form-item label="同步项目数据" field="is_sync_project">
<template #label>
<span class="label">同步项目数据</span>
<a-tooltip content="同步项目数据后,账户数据将同步到项目中">
<icon-question-circle size="14" class="ml-4px color-#737478" />
</a-tooltip>
</template>
<a-switch v-model="form.is_sync" size="medium" :checked-value="1" :un-checked-value="0" />
<a-switch v-model="form.is_sync_project" size="medium" :checked-value="1" :un-checked-value="0" />
</a-form-item>
</template>
</a-form>
@ -173,7 +173,7 @@ const INITIAL_FORM = {
operator_name: '',
holder_name: '',
platform: 0,
is_sync: 0,
is_sync_project: 0,
};
const visible = ref(false);

View File

@ -16,9 +16,9 @@
<div class="flex items-center mb-20px">
<img :src="icon1" width="16" height="16" class="mr-16px" />
<p class="s2">
检测到该账户最后更新日期为{{ exactFormatTime(lastSyncedAt, 'MM-DD', 'YYYY-MM-DD') }}已有{{
dayjs().diff(dayjs(lastSyncedAt * 1000), 'day')
}}未同步最新数据
检测到该账户最后更新日期为{{ exactFormatTime(lastSyncedAt, 'MMDD日HH:mm', 'YYYYMMDD日 HH:mm') }}已有{{
getDaysDiffText(lastSyncedAt)
}}未同步最新数据
</p>
</div>
<a-radio-group v-model="syncType" class="ml-32px">
@ -65,14 +65,18 @@
import dayjs from 'dayjs';
import { defineExpose, ref, computed, defineEmits } from 'vue';
import { exactFormatTime } from '@/utils/tools';
import { putPlacementAccountsAuthorized, getPlacementAccountsAuthorizedStatus } from '@/api/all/propertyMarketing';
import {
putPlacementAccountsAuthorized,
getPlacementAccountsAuthorizedStatus,
postPlacementAccountsSync,
} from '@/api/all/propertyMarketing';
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
import icon2 from '@/assets/img/media-account/icon-feedback-success.png';
import icon3 from '@/assets/img/media-account/icon-feedback-fail.png';
const emits = defineEmits(['update']);
const INITIAL_SYNC_TYPE = 'sync';
const visible = ref(false);
const isLoading = ref(false);
const isCompleted = ref(false);
@ -81,9 +85,10 @@ const formRef = ref(null);
const failReason = ref('');
const progress = ref(0);
const id = ref('');
const lastSyncedAt = ref(null);
const syncType = ref('sync'); // sync no_sync
const lastSyncedAt = ref(null); // 上次同步时间戳
const showSyncTip = ref(false);
const syncType = ref(INITIAL_SYNC_TYPE); // sync no_sync
const INITIAL_FORM = {
account: '',
@ -111,6 +116,15 @@ const confirmBtnText = computed(() => {
return isSuccess.value ? '继续添加' : '重试';
});
const getDaysDiffText = (lastSyncedAt) => {
if (!lastSyncedAt) return '0天';
const daysDiff = dayjs().diff(dayjs(lastSyncedAt * 1000), 'day');
if (daysDiff === 0) return '不到1天';
return `${daysDiff}`;
};
const open = (accountId, last_synced_at = null) => {
id.value = accountId;
lastSyncedAt.value = last_synced_at;
@ -129,7 +143,7 @@ const close = () => {
progress.value = 0;
id.value = '';
lastSyncedAt.value = null;
syncType.value = 'sync';
syncType.value = INITIAL_SYNC_TYPE;
showSyncTip.value = false;
clearFakeProgressTimer();
clearStatusPollingTimer();
@ -206,8 +220,8 @@ const clearFakeProgressTimer = () => {
}
};
const handleOk = () => {
if (lastSyncedAt.value) {
const handleSyncData = () => {
if (!showSyncTip.value) {
formRef.value.validate(async (errors) => {
if (!errors) {
showSyncTip.value = true;
@ -216,6 +230,23 @@ const handleOk = () => {
return;
}
if (syncType.value === INITIAL_SYNC_TYPE) {
postPlacementAccountsSync(id.value).then((res) => {
if (res.code === 200) {
close();
}
});
} else {
close();
}
};
const handleOk = () => {
if (lastSyncedAt.value && lastSyncedAt.value < dayjs().startOf('day').valueOf()) {
handleSyncData();
return;
}
if (isCompleted.value) {
if (isSuccess.value) {
emits('update');