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

@ -28,127 +28,122 @@
</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,
onSelect: handleSelect,
onSelectAll: handleSelectAll,
}"
:selected-keys="selectedItems"
:pagination="false"
:scroll="{ x: '100%' }"
class="account-table w-100% flex-1"
bordered
@sorter-change="handleSorterChange"
@select="handleSelect"
@select-all="handleSelectAll"
:showSorterTooltip="false"
@change="handleTableChange"
>
<template #empty>
<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" position="top">
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
</Tooltip>
</div>
</template>
<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'" #cell="{ record }">
<img :src="getMediaAccountPlatformLogo(record.platform)" width="20" height="20" class="rounded-4px" />
</template>
<template v-else-if="column.dataIndex === 'status'" #cell="{ record }">
<StatusBox :item="record" class="w-fit h-28px" />
</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">
{{
`观看: ${record[`${getPropPrefix(dateType)}view_rate`]}% 点赞: ${
record[`${getPropPrefix(dateType)}like_rate`]
}%`
}}
</p>
</div>
</template>
<template v-else>
<p class="cts">-</p>
</template>
</div>
</template>
<template v-else-if="column.dataIndex === 'like_collect_number'" #cell="{ record }">
{{
formatNumberShow({
value: `${record[`${getPropPrefix(dateType)}like_number`] ?? 0} + ${
record[`${getPropPrefix(dateType)}collect_number`] ?? 0
}`,
showExactValue: true,
})
}}
</template>
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
<Button type="outline" size="small" @click="handleDetail(record)">详情</Button>
</template>
<template v-if="column.dataIndex === 'platform'" #customRender="{ record }">
<img :src="getMediaAccountPlatformLogo(record.platform)" width="20" height="20" class="rounded-4px" />
</template>
<template v-else-if="column.dataIndex === 'status'" #customRender="{ record }">
<StatusBox :item="record" class="w-fit h-28px" />
</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">
{{
`观看: ${record[`${getPropPrefix(dateType)}view_rate`]}% 点赞: ${
record[`${getPropPrefix(dateType)}like_rate`]
}%`
}}
</p>
</div>
</template>
<template v-else>
<p class="cts">-</p>
</template>
</div>
</template>
<template v-else-if="column.dataIndex === 'like_collect_number'" #customRender="{ record }">
{{
formatNumberShow({
value: `${record[`${getPropPrefix(dateType)}like_number`] ?? 0} + ${
record[`${getPropPrefix(dateType)}collect_number`] ?? 0
}`,
showExactValue: true,
})
}}
</template>
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
<Button type="outline" 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_work_published_at) }}
</p>
</template>
<template v-else-if="column.dataIndex === 'second_new_work_title'" #cell="{ record }">
<p class="cts cursor-pointer hover:!color-#6D4CFE">{{ record.second_new_work_title }}</p>
<p class="cts text-12px lh-20px !color-#939499">
{{ exactFormatTime(record.second_new_work_published_at) }}
</p>
</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_work_published_at) }}
</p>
</template>
<template v-else-if="column.dataIndex === 'second_new_work_title'" #customRender="{ record }">
<p class="cts cursor-pointer hover:!color-#6D4CFE">{{ record.second_new_work_title }}</p>
<p class="cts text-12px lh-20px !color-#939499">
{{ exactFormatTime(record.second_new_work_published_at) }}
</p>
</template>
<template v-else #cell="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</a-table-column>
<a-table-column data-index="operation" fixed="right" width="100" title="操作">
<template #cell="{ record }">
<Button type="outline" size="small" @click="handleDetail(record)">详情</Button>
</template>
</a-table-column>
</template>
</a-table>
<template v-else #customRender="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</Column>
<Column dataIndex="operation" fixed="right" :width="100" title="操作">
<template #customRender="{ record }">
<Button type="outline" size="small" @click="handleDetail(record)">详情</Button>
</template>
</Column>
</Table>
<CustomTableColumnModal
ref="customTableColumnModalRef"
@ -161,7 +156,8 @@
<script setup>
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import { Checkbox, Button, Tooltip } from 'ant-design-vue';
import { Checkbox, Button, Tooltip, Table } from 'ant-design-vue';
const { Column } = Table;
import { getCustomColumns } from '@/api/all/common';
import StatusBox from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
@ -220,30 +216,34 @@ const tableColumns = computed(() => {
return _result;
});
const handleSelectAll = (checked) => {
if (checked) {
selectedItems.value = props.dataSource.map((item) => item.id);
} else {
selectedItems.value = [];
}
emit('selectionChange', checked ? selectedItems.value : []);
};
const handleDetail = (record) => {
router.push(`/media-account/detail/${record.id}?type=${dateType.value}`);
};
// 处理排序变化
const handleSorterChange = (column, order) => {
console.log(column, order);
emit('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
// 处理表格变化
const handleTableChange = (pagination, filters, sorter) => {
if (sorter && sorter.field) {
emit('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
}
};
const handleSelect = (selectedRowKeys, selectedRows) => {
selectedItems.value = selectedRowKeys;
const handleSelect = (record, selected, selectedRows, nativeEvent) => {
selectedItems.value = selectedRows.map(row => row.id);
emit('selectionChange', selectedRows);
};
const handleSelectAll = (selected, selectedRows, changeRows) => {
if (selected) {
selectedItems.value = props.dataSource.map((item) => item.id);
emit('selectionChange', props.dataSource);
} else {
selectedItems.value = [];
emit('selectionChange', []);
}
};
const handleExport = () => {
emit('export');
};

View File

@ -45,54 +45,50 @@
<template #default>重置</template>
</Button>
</div>
<a-table
:data="dataSource"
row-key="id"
<Table
:dataSource="dataSource"
rowKey="id"
:pagination="false"
:scroll="{ x: '100%' }"
class="w-100%"
bordered
column-resizable
:showSorterTooltip="false"
>
<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 }">
<template v-if="column.dataIndex === 'published_at'">
{{ exactFormatTime(record.published_at) }}
</template>
<template v-else-if="column.dataIndex === 'exposure_number'">
{{ formatNumberShow({ value: record.view_number * 10, showExactValue: true }) }}
</template>
<template v-else>
{{ formatTableField(column, record, true) }}
</template>
</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 }">
<template v-if="column.dataIndex === 'published_at'">
{{ exactFormatTime(record.published_at) }}
</template>
<template v-else-if="column.dataIndex === 'exposure_number'">
{{ formatNumberShow({ value: record.view_number * 10, showExactValue: true }) }}
</template>
<template v-else>
{{ formatTableField(column, record, true) }}
</template>
</template>
</a-table-column>
</template>
</a-table>
</Table>
<div v-if="pageInfo.total > 0" class="pagination-row mb-24px">
<a-pagination
:total="pageInfo.total"
@ -110,7 +106,7 @@
</template>
<script setup>
import { Button, Input, Tooltip } from 'ant-design-vue';
import { Button, Input, Tooltip, Table } from 'ant-design-vue';
import { TABLE_COLUMNS, INITIAL_QUERY, INITIAL_PAGE_INFO } from './constants';
import { useRoute } from 'vue-router';
import { formatTableField, exactFormatTime, formatNumberShow } from '@/utils/tools';

View File

@ -53,7 +53,7 @@
</template>
<template v-else-if="column.dataIndex === 'group_id'">
<div class="flex items-center w-100%">
<CommonSelect v-model="record.group_id" :options="groupOptions" :multiple="false" />
<CommonSelect v-model="record.group_id" :options="groupOptions" :multiple="false" class="w-full" />
</div>
</template>
</template>

View File

@ -47,31 +47,29 @@
<!-- 分别编辑 -->
<template v-if="editType === 'each'">
<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 }">
<span>{{ record.name || '-' }}</span>
</template>
</a-table-column>
<a-table-column title="选择标签" data-index="tags">
<template #cell="{ record, rowIndex }">
<div class="flex items-center w-100%">
<Select
v-model:value="record.tags"
:options="tagOptions"
mode="tags"
placeholder="请输入标签,回车键可直接添加..."
:max-tag-count="5"
style="width: 90%"
@search="(val) => handleCreateTag(val, rowIndex)"
/>
<span class="tag-count ml-8px">{{ record.tags.length }}/5</span>
</div>
</template>
</a-table-column>
</template>
</a-table>
<Table :dataSource="accountTagList" :pagination="false" rowKey="id" class="w-100%">
<Table.Column title="账号名称" dataIndex="name" :width="200">
<template #customRender="{ record }">
<span>{{ record.name || '-' }}</span>
</template>
</Table.Column>
<Table.Column title="选择标签" dataIndex="tags">
<template #customRender="{ record, index }">
<div class="flex items-center w-100%">
<Select
v-model:value="record.tags"
:options="tagOptions"
mode="tags"
placeholder="请输入标签,回车键可直接添加..."
:max-tag-count="5"
class="!w-full"
@search="(val) => handleCreateTag(val, index)"
/>
<span class="tag-count ml-8px">{{ record.tags.length }}/5</span>
</div>
</template>
</Table.Column>
</Table>
</template>
</Form>
<template #footer>
@ -83,7 +81,7 @@
<script setup>
import { ref, reactive } from 'vue';
import { Button, Modal, Form, FormItem,Tooltip, RadioGroup, Radio, Select } from 'ant-design-vue';
import { Button, Form, FormItem, Modal, Radio, RadioGroup, Select, Table, Tooltip } from 'ant-design-vue';
import { fetchAccountTags, batchPutTag } from '@/api/all/propertyMarketing';
import icon1 from '@/assets/img/icon-question.png';

View File

@ -32,18 +32,46 @@
</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="(pagination, filters, sorter) => {
if (sorter && sorter.columnKey) {
handleSorterChange(sorter.columnKey, sorter.order);
}
}"
>
<template #empty>
<Table.Column title="分组名称" dataIndex="name" />
<Table.Column title="创建人" dataIndex="creator">
<template #customRender="{ record }">
{{ record.creator?.name || '-' }}
</template>
</Table.Column>
<Table.Column
title="创建日期"
dataIndex="created_at"
:width="160"
key="created_at"
:sorter="true"
>
<template #customRender="{ record }">
{{ exactFormatTime(record.created_at) }}
</template>
</Table.Column>
<Table.Column title="操作" :align="'center'" :width="120">
<template #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>
</Table.Column>
<template #emptyText>
<NoData>
<span class="s1 mb-16px">暂无分组</span>
<Button type="primary" class="mb-16px" size="middle" @click="openAdd"
@ -54,13 +82,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" size="small" @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"
@ -82,7 +104,7 @@
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { Button, Modal, Input, Space } from 'ant-design-vue';
import { Button, Input, Modal, Space, Table } from 'ant-design-vue';
import { getAccountGroup } from '@/api/all/propertyMarketing';
import { exactFormatTime } from '@/utils/tools';
@ -117,24 +139,7 @@ const loading = ref(false);
const query = ref(cloneDeep(INITIAL_QUERY));
const pageInfo = ref(cloneDeep(INITIAL_PAGE_INFO));
const columns = [
{ title: '分组名称', dataIndex: 'name' },
{
title: '创建人',
dataIndex: 'creator',
render: ({ record }) => record.creator?.name || '-',
},
{
title: '创建日期',
dataIndex: 'created_at',
width: 160,
render: ({ record }) => exactFormatTime(record.created_at),
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{ title: '操作', slotName: 'action', align: 'center', width: 120 },
];
function open() {
visible.value = true;