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

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ coverage
*.local
*.js.map
*.js
CURSOR_RULES.md
/cypress/videos/
/cypress/screenshots/

View File

@ -6,9 +6,8 @@
"dev": "vite",
"build": "run-p build-only",
"build:test": "vite build --mode test && tar -czvf dist-test.tar.gz dist",
"build:production": "vite build --mode production && tar -czvf dist.tar.gz dist",
"build:prod": "vite build --mode production && tar -czvf dist.tar.gz dist",
"build-only": "vite build -- mode development",
"test": "vite build --mode test",
"type-check": "vue-tsc --noEmit",
"prepare": "husky install"
},

View File

@ -285,7 +285,6 @@ export const getPlacementAccountsTrend = (params = {}) => {
return Http.get(`/v1/placement-accounts/trend`, params);
};
// 投放账号计划数据-趋势
export const getPlacementAccountProjectsTrend = (params = {}) => {
return Http.get(`/v1/placement-account-projects/trend`, params);
@ -293,7 +292,7 @@ export const getPlacementAccountProjectsTrend = (params = {}) => {
// 投放指南查询
export const getPlacementGuide = (params: {}) => {
return Http.get(`/v1/placement-account-projects/getGuideList`,params);
return Http.get(`/v1/placement-account-projects/getGuideList`, params);
};
//查询投放指南历史
export const getPlacementGuideHistory = (params: {}) => {
@ -323,4 +322,9 @@ export const getPlacementAccountsList = (params = {}) => {
return Http.get('/v1/placement-accounts/list', params);
};
// 投放账号-同步数据
export const postPlacementAccountsSync = (id: string) => {
return Http.post(`/v1/placement-accounts/${id}/sync-data`);
};

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M11.4165 8.97559C12.8259 8.97562 13.969 10.118 13.9693 11.5273L13.9556 11.7891C13.9073 12.2634 13.7275 12.6982 13.4556 13.0596L14.0542 13.6582C14.2495 13.8535 14.2495 14.17 14.0542 14.3652C13.8589 14.5603 13.5424 14.5604 13.3472 14.3652L12.7085 13.7256C12.3292 13.949 11.8886 14.0801 11.4165 14.0801L11.1558 14.0664C9.86908 13.9356 8.86497 12.8485 8.86477 11.5273C8.86501 10.1182 10.0073 8.97583 11.4165 8.97559ZM8.74074 3.80469C8.74092 4.35682 9.18857 4.80469 9.74074 4.80469L11.8862 4.80469V7.85937C11.7712 7.84857 11.6545 7.84278 11.5366 7.84277C9.49559 7.84277 7.84035 9.49802 7.84035 11.5391C7.84042 12.5835 8.27458 13.5262 8.97121 14.1982H2.79934C2.24716 14.1981 1.79934 13.7504 1.79934 13.1982L1.79934 2.48828C1.79934 1.93608 2.24716 1.48841 2.79934 1.48828L8.74074 1.48828V3.80469ZM11.4165 9.97559C10.5596 9.97583 9.86501 10.6704 9.86477 11.5273C9.86498 12.3843 10.5596 13.0798 11.4165 13.0801C12.2736 13.08 12.969 12.3844 12.9693 11.5273C12.969 10.6703 12.2736 9.97562 11.4165 9.97559ZM3.48879 6.35156C3.37847 6.35156 3.28882 6.44051 3.28859 6.55078V7.0498C3.28868 7.16018 3.37839 7.25 3.48879 7.25L7.14211 7.25C7.25238 7.24984 7.34221 7.16009 7.3423 7.0498V6.55078C7.34208 6.44061 7.25229 6.35172 7.14211 6.35156L3.48879 6.35156ZM3.48879 4.04395C3.37837 4.04395 3.28866 4.13374 3.28859 4.24414V4.74316C3.28884 4.85341 3.37848 4.94238 3.48879 4.94238H7.14211C7.25228 4.94222 7.34206 4.85332 7.3423 4.74316V4.24414C7.34223 4.13384 7.25239 4.0441 7.14211 4.04395H3.48879ZM11.978 3.91895L10.0474 3.91895C9.77124 3.91895 9.54738 3.69509 9.54738 3.41895V1.48828L11.978 3.91895Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M10.0492 9.03058C12.2731 9.03059 14.0867 10.8117 14.1273 13.0352C14.1439 13.9477 13.4092 14.6964 12.4966 14.6966L3.50042 14.6966C2.59261 14.6965 1.86034 13.9541 1.87254 13.0463C1.90255 10.8197 3.71631 9.03058 5.94319 9.03058H10.0492ZM7.87154 1.30322C9.93387 1.30328 11.6061 2.88101 11.6064 4.8269C11.6064 6.773 9.93402 8.35146 7.87154 8.35151C5.809 8.35151 4.1367 6.77303 4.1367 4.8269C4.13695 2.88097 5.80916 1.30322 7.87154 1.30322Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 571 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M13.434 6.4018C13.7387 6.4018 13.9863 6.64936 13.9863 6.95409L13.9863 13.4136C13.9863 13.9214 13.5744 14.333 13.0667 14.3332L2.94324 14.3332C2.4355 14.333 2.02367 13.9214 2.02367 13.4136L2.02367 6.95409C2.02367 6.64938 2.27125 6.40182 2.57595 6.4018L13.434 6.4018ZM3.6482 9.82418C3.49585 9.8242 3.3725 9.94752 3.3725 10.0999L3.3725 12.6521C3.37274 12.8042 3.496 12.9277 3.6482 12.9278H5.6948C5.84701 12.9278 5.97025 12.8042 5.97049 12.6521L5.97049 10.0999C5.97049 9.94751 5.84716 9.82418 5.6948 9.82418H3.6482ZM7.55192 5.66362L2.38198 5.66362C2.1291 5.66334 1.95132 5.41309 2.03444 5.1742L3.04113 2.28345C3.16976 1.9142 3.51856 1.66682 3.90952 1.6665L7.55192 1.6665L7.55192 5.66362ZM12.0537 1.6665C12.4421 1.66658 12.7886 1.91054 12.9194 2.27626L13.9549 5.1715C14.0405 5.41104 13.8626 5.66357 13.6082 5.66362L8.44276 5.66362V1.6665L12.0537 1.6665Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 984 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M2.97785 10.8532C3.06071 10.71 3.24367 10.6612 3.38703 10.7438L6.48859 12.5348C6.63203 12.6176 6.68168 12.8005 6.59894 12.944L5.44757 14.9371C5.34178 15.1204 5.08511 15.1398 4.95343 14.9743L3.88214 13.6256C3.83419 13.5653 3.76511 13.5259 3.68878 13.5153L2.04816 13.2897C1.83724 13.2606 1.72302 13.0269 1.82941 12.8424L2.97785 10.8532ZM12.6126 10.7438C12.7561 10.661 12.9399 10.7097 13.0228 10.8532L14.1712 12.8424C14.2775 13.0269 14.1625 13.2607 13.9515 13.2897L12.3118 13.5153C12.2353 13.5258 12.1655 13.5651 12.1175 13.6256L11.0472 14.9743C10.9155 15.14 10.6579 15.1205 10.5521 14.9371L9.40167 12.944C9.31889 12.8006 9.36778 12.6177 9.51105 12.5348L12.6126 10.7438ZM7.55304 0.954723C7.82985 0.795119 8.17083 0.794962 8.44757 0.954723L12.7542 3.44105C13.0311 3.60091 13.2015 3.89674 13.2015 4.21644L13.2015 9.1891C13.2015 9.50881 13.0311 9.80462 12.7542 9.96449L8.44757 12.4508C8.17085 12.6105 7.82982 12.6104 7.55304 12.4508L3.2464 9.96449C2.96951 9.80462 2.79816 9.50883 2.79816 9.1891L2.79816 4.21644C2.79817 3.89673 2.96952 3.60091 3.2464 3.44105L7.55304 0.954723ZM10.8304 4.61488C10.5246 4.42717 10.1247 4.52313 9.93683 4.82875L8.0921 7.8307L6.04914 4.80433L5.96417 4.70375C5.74823 4.49246 5.406 4.45398 5.14582 4.62953C4.88559 4.80537 4.79393 5.1373 4.90949 5.41664L4.97101 5.53285L7.58039 9.39418C7.70405 9.57726 7.91224 9.6851 8.13312 9.68031C8.35384 9.67538 8.55762 9.5589 8.67316 9.37074L11.0443 5.50843C11.2316 5.20262 11.136 4.80263 10.8304 4.61488Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -87,7 +87,30 @@ export default defineComponent({
// 跳过没有 name 的菜单项,防止 key 报错
if (!element?.name) return;
const icon = element?.meta?.icon ? () => h(element?.meta?.icon as object) : null;
// const icon element?.meta?.icon
const icon = element?.meta?.icon
? (() => {
if (typeof element.meta.icon === 'string') {
return h(
'svg',
{
style: {
width: '16px',
height: '16px',
},
},
[
h('use', {
'xlink:href': element.meta.icon,
}),
],
);
} else {
// 如果是对象,按原来的方式渲染
return h(element.meta.icon as object);
}
})()
: null;
if (element.children && element.children.length > 0) {
nodes.push(
<a-sub-menu

View File

@ -2,10 +2,14 @@
* 资产营销平台
*/
import { IconBookmark } from '@arco-design/web-vue/es/icon';
import type { AppRouteRecordRaw } from '../types';
import { MENU_GROUP_IDS } from '@/router/constants';
import IconRepository from '@/assets/svg/icon-repository.svg';
import IconMediaAccount from '@/assets/svg/icon-mediaAccount.svg';
import IconPutAccount from '@/assets/svg/icon-putAccount.svg';
import IconIntelligentSolution from '@/assets/svg/icon-intelligentSolution.svg';
const COMPONENTS: AppRouteRecordRaw[] = [
{
path: '/repository',
@ -13,7 +17,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
redirect: 'repository/brandMaterials',
meta: {
locale: '品牌资产管理',
icon: IconBookmark,
icon: IconRepository,
requiresAuth: true,
roles: ['*'],
requiresSidebar: true,
@ -39,7 +43,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
redirect: 'media-account/accountManagement',
meta: {
locale: '账号资源中心',
icon: IconBookmark,
icon: IconMediaAccount,
requiresAuth: true,
roles: ['*'],
requiresSidebar: true,
@ -87,7 +91,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
redirect: 'put-account/accountManagement',
meta: {
locale: '投放资源中心',
icon: IconBookmark,
icon: IconPutAccount,
requiresAuth: true,
roles: ['*'],
requiresSidebar: true,
@ -154,7 +158,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
redirect: 'intelligent-solution/businessAnalysisReport',
meta: {
locale: '智能方案管理',
icon: IconBookmark,
icon: IconIntelligentSolution,
requiresAuth: true,
roles: ['*'],
requiresSidebar: true,

View File

@ -4,7 +4,7 @@ declare module 'vue-router' {
interface RouteMeta {
roles?: string[]; // Controls roles that have access to the page
requiresAuth?: boolean; // Whether login is required to access the current page (every route must declare)
icon?: RouteComponent; // The icon show in the side menu
icon?: RouteComponent | string; // The icon show in the side menu
locale?: string; // The locale name show in side menu and breadcrumb
needNavigate?: boolean; // if set true, the breadcrumb will support navigate
hideInMenu?: boolean; // If true, it is not displayed in the side menu

View File

@ -5,7 +5,7 @@
<!-- 关键词热度榜 -->
<a-space
direction="vertical"
class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid w-100% py-0 px-20px mb-24px"
class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid w-100% py-0 px-20px mb-20px"
>
<div class="title-row">
<span class="title mr-4px">关键词热度榜</span>

View File

@ -3,8 +3,8 @@
<!-- 头部 -->
<a-space
direction="vertical"
class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid"
style="background-color: #fff; width: 100%; padding: 24px; margin: 24px 0; color: #737478; font-size: 14px"
class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid mb-20px"
style="background-color: #fff; width: 100%; padding: 24px; color: #737478; font-size: 14px"
>
<a-space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
<span style="flex-shrink: 0; line-height: 28px" class="mr-32px">行业大类</span>

View File

@ -1,6 +1,6 @@
<template>
<div class="container">
<div class="flex arco-row-justify-space-between flex-center">
<div class="flex arco-row-justify-space-between">
<img class="avatar" :src="props.product.image" :alt="props.product.name" />
<a-tag v-if="props.product.status === Status.Enable" class="status status-enable">已开通</a-tag>
<a-tag v-if="props.product.status === Status.Disable" class="status status-disable">未开通</a-tag>
@ -21,7 +21,7 @@
{{ props.product.desc }}
</p>
</div>
<div class="footer flex arco-row-justify-start flex-center">
<div class="footer flex arco-row-justify-start">
<a-button
v-if="props.product.status === Status.Enable || props.product.status === Status.ON_TRIAL"
class="primary-button"

View File

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

View File

@ -28,7 +28,7 @@
:disabled="option.is_require === ENUM_STATUS.NO"
@change="(checked) => onCheckChange(checked, option)"
>
{{ option.label }}
{{ localFields.find((item) => item.prop === option.value)?.title }}
</a-checkbox>
</div>
</div>
@ -77,7 +77,7 @@ import { ref, defineExpose } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';
import { getCustomColumns, updateCustomColumns } from '@/api/all/common';
import { getPropPrefix } from '@/views/property-marketing/media-account/account-dashboard/constants';
import { getPropPrefix, getDefaultColumns } from '@/views/property-marketing/media-account/account-dashboard/constants';
import icon1 from './img/icon-lock.png';
@ -106,9 +106,13 @@ const dataSource = ref([]);
const checkColumns = ref([]); // 选中字段
const allColumns = ref([]); // 所有字段
const requiredGroupNames = ref([]); // 必选分组名称
const localFields = ref([]);
const open = () => {
initData();
localFields.value = getDefaultColumns(props.dateType);
visible.value = true;
};
@ -118,6 +122,7 @@ const close = () => {
dataSource.value = [];
checkColumns.value = [];
allColumns.value = [];
localFields.value = [];
requiredGroupNames.value = [];
};
@ -150,8 +155,8 @@ const isCheck = (option) => {
return checkColumns.value.includes(option.value);
};
const getCheckColumnLabel = (value) => {
const column = allColumns.value.find((column) => column.value === value);
return column?.label;
const column = localFields.value.find((column) => column.prop === value);
return column?.title;
};
const isRequiredColumn = (value) => {
const column = allColumns.value.find((column) => column.value === value);

View File

@ -72,7 +72,7 @@ export const getDefaultColumns = (type = 'week') => {
fixed: 'left',
},
{
title: '项目分组',
title: '账号分组',
dataIndex: 'group.name',
prop: 'group',
width: 180,
@ -111,7 +111,7 @@ export const getDefaultColumns = (type = 'week') => {
{
title: '总赞藏数',
dataIndex: 'like_collect_number',
prop: 'like_collect_number',
prop: 'like_number',
width: 180,
tooltip: '账号所有内容获得的点赞数与收藏数总和,用于衡量历史内容的整体吸引力与认可度。',
align: 'right',
@ -222,6 +222,17 @@ export const getDefaultColumns = (type = 'week') => {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '次新作品收藏数',
dataIndex: 'second_new_work_collect_number',
prop: 'second_new_work_collect_number',
width: 180,
tooltip: '次新作品内容的收藏数',
align: 'right',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '次新作品评论数',
dataIndex: 'second_new_work_comment_number',

View File

@ -49,7 +49,15 @@
<template #default>重置</template>
</a-button>
</div>
<a-table :data="dataSource" row-key="id" :pagination="false" :scroll="{ x: '100%' }" class="w-100%" bordered>
<a-table
:data="dataSource"
row-key="id"
:pagination="false"
:scroll="{ x: '100%' }"
class="w-100%"
bordered
column-resizable
>
<template #empty>
<NoData />
</template>

View File

@ -37,7 +37,7 @@
<!-- 分别编辑 -->
<template v-if="editType === 'each'">
<a-table :data="accountGroupList" :pagination="false" row-key="id" class="w-100%">
<a-table :data="accountGroupList" :pagination="false" row-key="id" class="w-100%" column-resizable>
<template #columns>
<a-table-column title="账号名称" data-index="name" width="200">
<template #cell="{ record }">

View File

@ -47,7 +47,7 @@
<!-- 分别编辑 -->
<template v-if="editType === 'each'">
<a-table :data="accountTagList" :pagination="false" row-key="id" class="w-100%">
<a-table :data="accountTagList" :pagination="false" row-key="id" class="w-100%" column-resizable>
<template #columns>
<a-table-column title="账号名称" data-index="name" width="200">
<template #cell="{ record }">

View File

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

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');

View File

@ -40,8 +40,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
// 目标地址
target: 'http://192.168.40.3/api',
// target: 'https://lingjiapi.lvfunai.com/api',
target: 'https://lingjiapi.lvfunai.com/api',
},
},
},