feat: table组件替换

This commit is contained in:
rd
2025-09-04 18:05:16 +08:00
parent aaa8a320c8
commit 3f5249c731
42 changed files with 1816 additions and 1833 deletions

View File

@ -29,112 +29,110 @@
</div>
</div>
<a-table
<Table
ref="tableRef"
:data="dataSource"
row-key="id"
column-resizable
:row-selection="{
:dataSource="dataSource"
rowKey="id"
:rowSelection="{
type: 'checkbox',
showCheckedAll: true,
width: 48,
selectedRowKeys: selectedItems,
onChange: handleSelect,
}"
:selected-keys="selectedItems"
:pagination="false"
:scroll="{ x: '100%' }"
class="account-table w-100%"
bordered
@sorter-change="handleSorterChange"
@select="handleSelect"
@select-all="handleSelectAll"
:showSorterTooltip="false"
@change="(pagination, filters, sorter) => {
if (sorter && sorter.columnKey) {
handleSorterChange(sorter.columnKey, sorter.order === 'ascend' ? 'asc' : 'desc');
}
}"
>
<template #empty>
<Table.Column
v-for="column in tableColumns"
:key="column.dataIndex"
:dataIndex="column.dataIndex"
:fixed="column.fixed"
:width="column.width"
:minWidth="column.minWidth"
:sorter="column.sortable"
:align="column.align"
:ellipsis="true"
>
<template #title>
<div class="flex items-center">
<img v-if="column.dataIndex === 'ai_evaluate'" width="16" height="16" :src="icon5" class="mr-4px" />
<span class="cts mr-4px">{{ column.title }}</span>
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<template v-if="column.dataIndex === 'platform'" #customRender="{ record }">
{{ record.platform === 0 ? '抖音' : record.platform === 1 ? '小红书' : '-' }}
</template>
<template v-else-if="column.dataIndex === 'status'" #customRender="{ record }">
<div class="status-tag" :class="`status-tag-${record.status}`">
<span class="cts status-tag-text">{{
STATUS_LIST.find((item) => item.value === record.status)?.label
}}</span>
</div>
</template>
<template v-else-if="column.dataIndex === 'ai_evaluate'" #customRender="{ record }">
<div class="ai-evaluation-row flex">
<template v-if="record.ai_evaluate">
<img
width="16"
height="16"
:src="record.ai_evaluate?.status === 0 ? icon2 : record.ai_evaluate?.status === 1 ? icon3 : icon4"
class="mr-8px icon"
/>
<div>
<p class="cts">{{ `${record.ai_evaluate?.level} | ${record.ai_evaluate?.advise}` }}</p>
<p class="cts text-12px lh-20px !color-#939499">
{{ `ROI: ${record.roi}% CVR: ${record.conversion_rate}%` }}
</p>
</div>
</template>
<template v-else>
<p class="cts">-</p>
</template>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
<Button type="primary" ghost size="small" @click="handleDetail(record)">详情</Button>
</template>
<template v-else-if="column.isRateField" #customRender="{ record }">
<div class="flex items-center rate-row justify-end" :class="record[column.dataIndex] > 0 ? 'up' : 'down'">
<icon-arrow-up v-if="record[column.dataIndex] > 0" size="16" />
<icon-arrow-down v-else size="16" />
{{ formatTableField(column, record) }}
</div>
</template>
<template v-else-if="column.dataIndex === 'newest_work_title'" #customRender="{ record }">
<p class="cts cursor-pointer hover:!color-#6D4CFe">{{ record.newest_work_title }}</p>
<p class="cts text-12px lh-20px !color-#939499">
{{ exactFormatTime(record.newest_project_published_at) }}
</p>
</template>
<template v-else #customRender="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</Table.Column>
<template #emptyText>
<NoData />
</template>
<template #columns>
<a-table-column
v-for="column in tableColumns"
:key="column.dataIndex"
:data-index="column.dataIndex"
:fixed="column.fixed"
:width="column.width"
:min-width="column.minWidth"
:sortable="column.sortable"
:align="column.align"
ellipsis
tooltip
>
<template #title>
<div class="flex items-center">
<img v-if="column.dataIndex === 'ai_evaluate'" width="16" height="16" :src="icon5" class="mr-4px" />
<span class="cts mr-4px">{{ column.title }}</span>
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<template v-if="column.dataIndex === 'platform'" #cell="{ record }">
{{ record.platform === 0 ? '抖音' : record.platform === 1 ? '小红书' : '-' }}
</template>
<template v-else-if="column.dataIndex === 'status'" #cell="{ record }">
<div class="status-tag" :class="`status-tag-${record.status}`">
<span class="cts status-tag-text">{{
STATUS_LIST.find((item) => item.value === record.status)?.label
}}</span>
</div>
</template>
<template v-else-if="column.dataIndex === 'ai_evaluate'" #cell="{ record }">
<div class="ai-evaluation-row flex">
<template v-if="record.ai_evaluate">
<img
width="16"
height="16"
:src="record.ai_evaluate?.status === 0 ? icon2 : record.ai_evaluate?.status === 1 ? icon3 : icon4"
class="mr-8px icon"
/>
<div>
<p class="cts">{{ `${record.ai_evaluate?.level} | ${record.ai_evaluate?.advise}` }}</p>
<p class="cts text-12px lh-20px !color-#939499">
{{ `ROI: ${record.roi}% CVR: ${record.conversion_rate}%` }}
</p>
</div>
</template>
<template v-else>
<p class="cts">-</p>
</template>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
<Button type="primary" ghost size="small" @click="handleDetail(record)">详情</Button>
</template>
<template v-else-if="column.isRateField" #cell="{ record }">
<div class="flex items-center rate-row justify-end" :class="record[column.dataIndex] > 0 ? 'up' : 'down'">
<icon-arrow-up v-if="record[column.dataIndex] > 0" size="16" />
<icon-arrow-down v-else size="16" />
{{ formatTableField(column, record) }}
</div>
</template>
<template v-else-if="column.dataIndex === 'newest_work_title'" #cell="{ record }">
<p class="cts cursor-pointer hover:!color-#6D4CFe">{{ record.newest_work_title }}</p>
<p class="cts text-12px lh-20px !color-#939499">
{{ exactFormatTime(record.newest_project_published_at) }}
</p>
</template>
<template v-else #cell="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</a-table-column>
</template>
</a-table>
</Table>
<CustomTableColumnModal ref="modalRef" :type="CUSTOM_COLUMN_TYPE" @success="onCustomColumnSuccess" />
</template>
<script setup>
import { Checkbox, Button } from 'ant-design-vue';
import { Button, Checkbox, Table, Tooltip } from 'ant-design-vue';
import { ref, computed } from 'vue';
import { STATUS_LIST } from '@/views/property-marketing/put-account/components/status-select/constants';
import { formatTableField, exactFormatTime } from '@/utils/tools';

View File

@ -31,18 +31,39 @@
<template #default>添加新分组</template>
</Button>
</div>
<a-table
column-resizable
:columns="columns"
:data="list"
row-key="id"
<Table
:dataSource="list"
rowKey="id"
:loading="loading"
:scroll="{ y: 500 }"
class="h-500px"
:pagination="false"
@sorter-change="handleSorterChange"
:showSorterTooltip="false"
@change="handleTableChange"
>
<template #empty>
<Column
v-for="column in columns"
:key="column.dataIndex"
:title="column.title"
:dataIndex="column.dataIndex"
:width="column.width"
:align="column.align"
:sortable="column.sortable"
>
<template v-if="column.slotName === 'action'" #customRender="{ record }">
<div class="flex items-center">
<img :src="icon1" width="16" height="16" class="mr-8px cursor-pointer" @click="openDelete(record)" />
<Button type="primary" size="small" @click="openEdit(record)">编辑</Button>
</div>
</template>
<template v-else-if="column.dataIndex === 'creator'" #customRender="{ record }">
{{ record.creator?.name || '-' }}
</template>
<template v-else-if="column.dataIndex === 'created_at'" #customRender="{ record }">
{{ exactFormatTime(record.created_at) }}
</template>
</Column>
<template #emptyText>
<NoData>
<span class="s1 mb-16px">暂无分组</span>
<Button type="primary" class="mb-16px" size="medium" @click="openAdd"
@ -53,13 +74,7 @@
</Button>
</NoData>
</template>
<template #action="{ record }">
<div class="flex items-center">
<img :src="icon1" width="16" height="16" class="mr-8px cursor-pointer" @click="openDelete(record)" />
<Button type="primary" @click="openEdit(record)">编辑</Button>
</div>
</template>
</a-table>
</Table>
<div v-if="pageInfo.total > 0" class="pagination-row flex justify-end">
<a-pagination
:total="pageInfo.total"
@ -81,9 +96,10 @@
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { Button, Modal, Input, Space } from 'ant-design-vue';
import { Button, Modal, Input, Space, Table } from 'ant-design-vue';
import { getPlacementAccountProjectGroups } from '@/api/all/propertyMarketing';
import { exactFormatTime } from '@/utils/tools';
const { Column } = Table;
import AddGroup from './add-group.vue';
import DeleteGroup from './delete-group.vue';
@ -159,9 +175,9 @@ function openDelete(record) {
deleteGroupRef.value.open(record);
}
const handleSorterChange = (column, order) => {
query.value.sort_column = column;
query.value.sort_order = order === 'ascend' ? 'asc' : 'desc';
const handleTableChange = (pagination, filters, sorter) => {
query.value.sort_column = sorter.field;
query.value.sort_order = sorter.order === 'ascend' ? 'asc' : 'desc';
getData();
};
async function getData() {

View File

@ -29,62 +29,55 @@
</div>
</div>
<a-table
<Table
ref="tableRef"
column-resizable
:data="dataSource"
row-key="id"
:row-selection="{
:dataSource="dataSource"
rowKey="id"
:rowSelection="{
type: 'checkbox',
showCheckedAll: true,
width: 48,
selectedRowKeys: selectedItems,
onChange: handleSelect,
onSelectAll: handleSelectAll,
}"
:selected-keys="selectedItems"
:pagination="false"
:scroll="{ x: '100%' }"
class="plan-table w-100%"
bordered
@sorter-change="handleSorterChange"
@select="handleSelect"
@select-all="handleSelectAll"
:showSorterTooltip="false"
@change="handleTableChange"
>
<template #empty>
<NoData />
</template>
<template #columns>
<a-table-column
v-for="column in tableColumns"
:key="column.dataIndex"
:data-index="column.dataIndex"
:fixed="column.fixed"
:width="column.width"
:min-width="column.minWidth"
:sortable="column.sortable"
:align="column.align"
ellipsis
tooltip
>
<template #title>
<div class="flex items-center">
<img v-if="column.dataIndex === 'ai_evaluate'" width="16" height="16" :src="icon5" class="mr-4px" />
<span class="cts mr-4px">{{ column.title }}</span>
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<template v-if="column.dataIndex === 'platform'" #cell="{ record }">
<Table.Column
v-for="column in tableColumns"
:key="column.dataIndex"
:dataIndex="column.dataIndex"
:fixed="column.fixed"
:width="column.width"
:minWidth="column.minWidth"
:sortable="column.sortable"
:align="column.align"
:ellipsis="true"
>
<template #title>
<div class="flex items-center">
<img v-if="column.dataIndex === 'ai_evaluate'" width="16" height="16" :src="icon5" class="mr-4px" />
<span class="cts mr-4px">{{ column.title }}</span>
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<template #customRender="{ record }">
<template v-if="column.dataIndex === 'platform'">
{{ record.platform === 0 ? '抖音' : record.platform === 1 ? '小红书' : '-' }}
</template>
<template v-else-if="column.dataIndex === 'status'" #cell="{ record }">
<template v-else-if="column.dataIndex === 'status'">
<div class="status-tag" :class="`status-tag-${record.status}`">
<span class="cts status-tag-text">{{
STATUS_LIST.find((item) => item.value === record.status)?.label
}}</span>
</div>
</template>
<template v-else-if="column.dataIndex === 'ai_evaluate'" #cell="{ record }">
<template v-else-if="column.dataIndex === 'ai_evaluate'">
<div class="ai-evaluation-row flex">
<template v-if="record.ai_evaluate">
<img
@ -105,41 +98,40 @@
</template>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
<template v-else-if="column.dataIndex === 'operation'">
<Button type="primary" ghost size="small" @click="handleDetail(record)">详情</Button>
</template>
<template v-else-if="column.isRateField" #cell="{ record }">
<template v-else-if="column.isRateField">
<div class="flex items-center rate-row justify-end" :class="record[column.dataIndex] > 0 ? 'up' : 'down'">
<icon-arrow-up v-if="record[column.dataIndex] > 0" size="16" />
<icon-arrow-down v-else size="16" />
{{ formatTableField(column, record) }}
</div>
</template>
<!-- <template v-else-if="['like_chain1', 'like_chain4'].includes(column.dataIndex)" #cell="{ record }">
<p class="cts cursor-pointer hover:!color-#6D4CFE">打工人的环游世界旅行计划国内版</p>
<p class="cts text-12px lh-20px !color-#939499">2025-06-18</p>
</template> -->
<template v-else #cell="{ record }">
<template v-else>
{{ formatTableField(column, record, true) }}
</template>
</a-table-column>
</template>
</Table.Column>
<template #emptyText>
<NoData />
</template>
</a-table>
</Table>
<CustomTableColumnModal ref="modalRef" :type="CUSTOM_COLUMN_TYPE" @success="onCustomColumnSuccess" />
</template>
<script setup>
import { Checkbox, Button } from 'ant-design-vue';
import { ref, computed } from 'vue';
import { Checkbox, Button, Table } from 'ant-design-vue';
import { ref, computed, onMounted } from 'vue';
import { cloneDeep, union } from 'lodash-es';
import { STATUS_LIST } from '@/views/property-marketing/put-account/components/status-select/constants';
import { formatTableField } from '@/utils/tools';
import { TABLE_COLUMNS } from './constants';
import { useRouter } from 'vue-router';
import CustomTableColumnModal from '@/components/custom-table-column-modal';
import { getCustomColumns } from '@/api/all/common';
const { Column } = Table;
import icon1 from '@/assets/img/media-account/icon-custom.png';
import icon2 from '@/assets/img/media-account/icon-warn.png';
@ -172,22 +164,11 @@ const indeterminate = computed(
() => selectedItems.value.length > 0 && selectedItems.value.length < props.dataSource.length,
);
const handleSelectAll = (checked) => {
if (checked) {
selectedItems.value = props.dataSource.map((item) => item.id);
} else {
selectedItems.value = [];
// 处理表格变化(排序、分页等)
const handleTableChange = (pagination, filters, sorter) => {
if (sorter && sorter.field) {
emit('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
}
emit('selectionChange', checked ? selectedItems.value : []);
};
const handleDetail = (record) => {
router.push(`/media-account/detail/${record.id}`);
};
// 处理排序变化
const handleSorterChange = (column, order) => {
emit('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
};
const handleSelect = (selectedRowKeys, selectedRows) => {
@ -195,6 +176,19 @@ const handleSelect = (selectedRowKeys, selectedRows) => {
emit('selectionChange', selectedRows);
};
const handleSelectAll = (selected, selectedRows, changeRows) => {
if (selected) {
selectedItems.value = props.dataSource.map((item) => item.id);
} else {
selectedItems.value = [];
}
emit('selectionChange', selected ? selectedRows : []);
};
const handleDetail = (record) => {
router.push(`/media-account/detail/${record.id}`);
};
const handleExport = () => {
emit('export');
};

View File

@ -7,17 +7,15 @@
<div class="filter-wrap bg-#fff rounded-8px mb-16px">
<Tabs v-model:activeKey="activeTab" @change="handleTabClick" size="large">
<TabPane key="1" tab="账户"></TabPane>
<TabPane key="2" tab="计划">
<template v-if="!isAccountTab" #tab>
计划
<Button type="primary" ghost class="mr-12px flex items-center" @click="handleOpenGroupModal">
<template #icon>
<img :src="icon2" width="16" height="16" class="mr-8px" />
</template>
<template #default>分组管理</template>
</Button>
</template>
</TabPane>
<TabPane key="2" tab="计划"> </TabPane>
<template v-if="!isAccountTab" #rightExtra>
<Button type="primary" ghost class="mr-12px flex items-center" @click="handleOpenGroupModal">
<template #icon>
<img :src="icon2" width="16" height="16" class="mr-8px" />
</template>
<template #default>分组管理</template>
</Button>
</template>
</Tabs>
<FilterBlock
ref="filterBlockRef"

View File

@ -42,51 +42,46 @@
</div>
</div>
<a-table
<Table
ref="tableRef"
:data="dataSource"
column-resizable
:row-selection="rowSelection"
:row-key="ROW_KEY"
:dataSource="dataSource"
:rowSelection="rowSelection"
:rowKey="ROW_KEY"
:pagination="false"
:scroll="{ x: '100%', y: '100%' }"
class="w-100% flex-1 overflow-hidden"
:selected-keys="selectedRowKeys"
bordered
@select="handleSelect"
@select-all="handleSelectAll"
:showSorterTooltip="false"
@change="(pagination, filters, sorter) => {}"
>
<template #empty>
<Table.Column
v-for="column in TABLE_COLUMNS"
:key="column.dataIndex"
:dataIndex="column.dataIndex"
:fixed="column.fixed"
:width="column.width"
:minWidth="column.minWidth"
:sortable="column.sortable"
:align="column.align"
:ellipsis="true"
>
<template #title>
<div class="flex items-center">
<span class="cts mr-4px">{{ column.title }}</span>
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<template #customRender="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</Table.Column>
<template #emptyText>
<NoData />
</template>
<template #columns>
<a-table-column
v-for="column in TABLE_COLUMNS"
:key="column.dataIndex"
:data-index="column.dataIndex"
:fixed="column.fixed"
:width="column.width"
:min-width="column.minWidth"
:sortable="column.sortable"
:align="column.align"
ellipsis
tooltip
>
<template #title>
<div class="flex items-center">
<span class="cts mr-4px">{{ column.title }}</span>
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<template #cell="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</a-table-column>
</template>
</a-table>
</Table>
<div v-if="pageInfo.total > 0" class="flex justify-end mt-16px">
<a-pagination
:total="pageInfo.total"
@ -115,12 +110,11 @@
</template>
<script setup>
import { Button, Input, Tooltip } from 'ant-design-vue';
import { Button, Input, Modal, Table, Tooltip } from 'ant-design-vue';
import { INITIAL_FORM, INITIAL_PAGE_INFO, TABLE_COLUMNS } from './constants';
import { formatTableField } from '@/utils/tools';
import { postSubAccount, postAddSubAccount } from '@/api/all/propertyMarketing';
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
import { Modal } from 'ant-design-vue';
const emits = defineEmits('confirm');
const update = inject('update');

View File

@ -1,73 +1,74 @@
<template>
<view>
<a-table class="account-table" :columns="columns" :data="listData" :pagination="false">
<template #platform="{ record }">
<span class="mr-8px" v-if="record.platform.length > 0" v-for="(item, index) in record.platform">
<img :src="PLATFORM_LIST?.[item]?.icon" width="15" height="15" />
<span class="label ml-5px">{{ PLATFORM_LIST?.[item]?.label }}</span>
</span>
</template>
<template #operation="{ record }">
<Space size="medium">
<Table class="account-table" :dataSource="listData" :pagination="false" :showSorterTooltip="false" @change="(pagination, filters, sorter) => {}">
<Table.Column
title="生成日期"
dataIndex="created_at"
:width="60"
:minWidth="60"
/>
<Table.Column
title="账号"
dataIndex="account"
:width="120"
:minWidth="120"
/>
<Table.Column
:width="180"
:minWidth="180"
title="计划"
dataIndex="plan"
/>
<Table.Column
title="平台"
:width="120"
:minWidth="120"
>
<template #customRender="{ record }">
<template v-if="record.platform.length > 0">
<span class="mr-8px" v-for="(item, index) in record.platform" :key="index">
<img :src="PLATFORM_LIST?.[item]?.icon" width="15" height="15" />
<span class="label ml-5px">{{ PLATFORM_LIST?.[item]?.label }}</span>
</span>
</template>
</template>
</Table.Column>
<Table.Column
title="操作"
dataIndex="operation"
:width="60"
:minWidth="60"
>
<template #customRender="{ record }">
<Space>
<a-popconfirm
content="确定删除吗?"
type="warning"
ok-text="确认删除"
cancel-text="取消"
@ok="deleteData(record.id)"
>
<icon-delete></icon-delete>
</a-popconfirm>
<Space>
<a-popconfirm
content="确定删除吗?"
type="warning"
ok-text="确认删除"
cancel-text="取消"
@ok="deleteData(record.id)"
>
<icon-delete></icon-delete>
</a-popconfirm>
</Space>
<Space>
<Button type="primary" ghost @click="downLoad(record.file_url)" class="operation-btn">下载</Button>
<Button type="primary" ghost @click="goDetail(record.id)" class="operation-btn">详情</Button>
</Space>
</Space>
<Space>
<Button type="primary" ghost @click="downLoad(record.file_url)" class="operation-btn">下载</Button>
<Button type="primary" ghost @click="goDetail(record.id)" class="operation-btn">详情</Button>
</Space>
</Space>
</template>
</a-table>
</template>
</Table.Column>
</Table>
</view>
</template>
<script setup lang="ts">
import { Button, Space } from 'ant-design-vue';
import { Button, Space, Table } from 'ant-design-vue';
import { IconDelete } from '@arco-design/web-vue/es/icon';
import { PLATFORM_LIST } from '@/utils/platform';
import { Message } from '@arco-design/web-vue';
const columns = [
{
title: '生成日期',
dataIndex: 'created_at',
width: 60,
minWidth: 60,
},
{
title: '账号',
dataIndex: 'account',
width: 120,
minWidth: 120,
},
{
width: 180,
minWidth: 180,
title: '计划',
dataIndex: 'plan',
},
{
title: '平台',
width: 120,
minWidth: 120,
slotName: 'platform',
},
{
title: '操作',
dataIndex: 'operation',
slotName: 'operation',
width: 60,
minWidth: 60,
},
];
// hotTranslation.vue
import { useRouter } from 'vue-router';
import { deleteHistorylog } from '@/api/all/propertyMarketing';

View File

@ -1,98 +1,144 @@
<template>
<view class="table-data">
<a-table
<Table
class="account-table"
:columns="columns"
:data="listData"
:dataSource="listData"
:pagination="false"
@sorter-change="handleSorterChange"
:showSorterTooltip="false"
@change="(pagination, filters, sorter) => {
if (sorter && !Array.isArray(sorter) && sorter.columnKey) {
handleSorterChange(sorter.columnKey, sorter.order);
}
}"
>
<template #total_use_amount_label>
<Space>
<span>本周总消耗</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>当前周内所有投流账户的累计广告花费反映整体投放规模</p>
<Table.Column
title="账户名称"
dataIndex="account_name"
:width="60"
:minWidth="60"
/>
<Table.Column
:width="180"
:minWidth="180"
title="计划名称"
dataIndex="name"
/>
<Table.Column
title="平台"
dataIndex="platform"
:width="120"
:minWidth="120"
>
<template #customRender="{ record }">
<div class="field-row">
<img :src="PLATFORM_LIST.find((v) => v.value === record.platform)?.icon" width="15" height="15" />
<span class="label ml-5px">{{ PLATFORM_LIST.find((v) => v.value === record.platform)?.label }}</span>
</div>
</template>
</Table.Column>
<Table.Column
:width="120"
:minWidth="120"
key="total_use_amount"
:sorter="true"
dataIndex="total_use_amount"
>
<template #title>
<Space>
<span>本周总消耗</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>当前周内所有投流账户的累计广告花费反映整体投放规模</p>
</template>
</a-popover>
</Space>
</template>
<template #customRender="{ record }">
<Space>{{ record.total_use_amount }}</Space>
</template>
</Table.Column>
<Table.Column
:width="120"
:minWidth="120"
key="pre_total_use_amount_chain"
:sorter="true"
dataIndex="pre_total_use_amount_chain"
>
<template #title>
<Space>
<span>本周总消耗环比</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>本周消耗金额与上周对比的变化百分比用于衡量预算投放趋势</p>
</template>
</a-popover>
</Space>
</template>
<template #customRender="{ record }">
<a-statistic
:value="record.pre_total_use_amount_chain * 100"
:value-style="{
color: record.pre_total_use_amount_chain > 0 ? '#F64B31' : '#25C883',
fontStyle: 'normal',
fontSize: '14px',
}"
>
<template #prefix>
<icon-arrow-rise v-if="record.pre_total_use_amount_chain > 0" />
<icon-arrow-down v-else />
</template>
</a-popover>
</Space>
</template>
<template #pre_total_use_amount_chain_title>
<Space>
<span>本周总消耗环比</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>本周消耗金额与上周对比的变化百分比用于衡量预算投放趋势</p>
</template>
</a-popover>
</Space>
</template>
<template #roi>
<Space>
<span>ROI</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>投资回报率ROI= 收益 ÷ 投入成本反映整体投流账户的收益效率</p>
</template>
</a-popover>
</Space>
</template>
<template #ctr>
<Space>
<span>CTR</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>点击率CTR= 点击量 ÷ 展示量是衡量广告素材吸引力的关键指标</p>
</template>
</a-popover>
</Space>
</template>
<template #platform="{ record }">
<div class="field-row">
<img :src="PLATFORM_LIST.find((v) => v.value === record.platform)?.icon" width="15" height="15" />
<span class="label ml-5px">{{ PLATFORM_LIST.find((v) => v.value === record.platform)?.label }}</span>
</div>
</template>
<template #total_use_amount="{ record }">
<Space>{{ record.total_use_amount }}</Space>
</template>
<template #total_use_amoun2="{ record }">
<div class="field-row">
<img :src="PLATFORM_LIST.find((v) => v.value === record.platform)?.icon" width="15" height="15" />
<span class="label ml-5px">{{ PLATFORM_LIST.find((v) => v.value === record.platform)?.label }}</span>
</div>
</template>
<template #pre_total_use_amount_chain="{ record }">
<a-statistic
:value="record.pre_total_use_amount_chain * 100"
:value-style="{
color: record.pre_total_use_amount_chain > 0 ? '#F64B31' : '#25C883',
fontStyle: 'normal',
fontSize: '14px',
}"
>
<template #prefix>
<icon-arrow-rise v-if="record.pre_total_use_amount_chain > 0" />
<icon-arrow-down v-else />
</template>
<template #suffix>%</template>
</a-statistic>
</template>
<template #clickRate="{ record }">
<span>{{ `${record.click_rate}%` }}</span>
</template>
</a-table>
<template #suffix>%</template>
</a-statistic>
</template>
</Table.Column>
<Table.Column
dataIndex="roi"
:width="120"
:minWidth="120"
key="roi"
:sorter="true"
>
<template #title>
<Space>
<span>ROI</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>投资回报率ROI= 收益 ÷ 投入成本,反映整体投流账户的收益效率。</p>
</template>
</a-popover>
</Space>
</template>
</Table.Column>
<Table.Column
dataIndex="click_rate"
:width="120"
:minWidth="120"
key="click_rate"
:sorter="true"
>
<template #title>
<Space>
<span>CTR</span>
<a-popover position="tl">
<icon-question-circle />
<template #content>
<p>点击率CTR= 点击量 ÷ 展示量,是衡量广告素材吸引力的关键指标。</p>
</template>
</a-popover>
</Space>
</template>
<template #customRender="{ record }">
<span>{{ `${record.click_rate}%` }}</span>
</template>
</Table.Column>
</Table>
</view>
</template>
<script setup lang="ts">
import { Space } from "ant-design-vue"
import { Space, Table } from "ant-design-vue"
import { PLATFORM_LIST } from '@/utils/platform';
const props = defineProps({
@ -109,69 +155,6 @@ const emit = defineEmits(['updateQuery']);
const handleSorterChange = (column, order) => {
emit('updateQuery', { column, order });
};
const columns = [
{
title: '账户名称',
dataIndex: 'account_name',
width: 60,
minWidth: 60,
},
{
width: 180,
minWidth: 180,
title: '计划名称',
dataIndex: 'name',
},
{
title: '平台',
dataIndex: 'platform',
width: 120,
minWidth: 120,
slotName: 'platform',
},
{
title: '本周总消耗',
titleSlotName: 'total_use_amount_label',
dataIndex: 'total_use_amount',
slotName: 'total_use_amount',
width: 120,
minWidth: 120,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '本周总消耗环比',
titleSlotName: 'pre_total_use_amount_chain_title',
dataIndex: 'pre_total_use_amount_chain',
width: 120,
minWidth: 120,
slotName: 'pre_total_use_amount_chain',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
titleSlotName: 'roi',
dataIndex: 'roi',
width: 120,
minWidth: 120,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
titleSlotName: 'ctr',
dataIndex: 'click_rate',
width: 120,
minWidth: 120,
slotName: 'clickRate',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
];
</script>
<style lang="scss"></style>