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

@ -152,7 +152,7 @@ const props = defineProps({
},
rowSelection: {
type: Array,
default: () => [],
default: () => {},
},
selectedRowKeys: {
type: Array,
@ -175,6 +175,7 @@ const handleTableChange = (pagination, filters, sorter) => {
const rowSelection = {
selectedRowKeys: computed(() => props.selectedRowKeys),
onSelect: (record, selected, selectedRows, nativeEvent) => {
console.log(selectedRows, record);
emits(
'select',
selectedRows.map((row) => row.id),

View File

@ -1,5 +1,5 @@
export const INITIAL_FORM = {
audit_status: '',
audit_status: undefined,
sort_column: undefined,
sort_order: undefined,
};

View File

@ -1,6 +1,5 @@
<script lang="jsx">
import { Button, Modal, Tooltip } from 'ant-design-vue';
import { Table, TableColumn, Pagination } from '@arco-design/web-vue';
import { Button, Modal, Tooltip, Table, Pagination } from 'ant-design-vue';
import CommonSelect from '@/components/common-select';
import TextOverTips from '@/components/text-over-tips';
import ShareModal from '@/views/material-center/components/finished-products/manuscript/components/share-manuscript-modal/share-modal';
@ -112,10 +111,12 @@ export default {
const onShare = () => {
shareModalRef.value?.open(selectedRowKeys.value);
};
const handleSorterChange = (column, order) => {
query.value.sort_column = column;
query.value.sort_order = order === 'ascend' ? 'asc' : 'desc';
reload();
const handleSorterChange = (pagination, filters, sorter) => {
if (sorter && !Array.isArray(sorter) && sorter.columnKey) {
query.value.sort_column = sorter.columnKey;
query.value.sort_order = sorter.order === 'ascend' ? 'asc' : 'desc';
reload();
}
};
const getStatusInfo = (audit_status) => {
return CHECK_STATUS.find((v) => v.id === audit_status) ?? {};
@ -163,109 +164,100 @@ export default {
</div>
<Table
ref={tableRef}
data={dataSource.value}
row-key="id"
column-resizable
row-selection={rowSelection.value}
selected-keys={selectedRowKeys.value}
dataSource={dataSource.value}
rowKey="id"
rowSelection={{
selectedRowKeys: selectedRowKeys.value,
onChange: (keys, rows) => handleSelect(keys, rows),
onSelectAll: (selected, rows, changeRows) => handleSelectAll(selected, rows, changeRows),
}}
pagination={false}
scroll={{ x: '100%', y: '100%' }}
class="overflow-hidden"
bordered
onSorterChange={handleSorterChange}
onSelect={handleSelect}
onSelectAll={handleSelectAll}
showSorterTooltip={false}
onChange={handleSorterChange}
v-slots={{
empty: () => <NoData />,
columns: () => (
<>
{TABLE_COLUMNS.map((column) => (
<TableColumn
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
v-slots={{
title: () => (
<div class="flex items-center">
<span class="cts mr-4px bold color-#211F24">{column.title}</span>
{column.tooltip && (
<Tooltip title={column.tooltip} placement="top">
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
</Tooltip>
)}
</div>
),
cell: ({ record }) => {
if (column.dataIndex === 'audit_status') {
return (
<div
class="flex items-center w-fit h-24px px-8px rounded-2px"
style={{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }}
>
<span class="cts s1 bold" style={{ color: getStatusInfo(record.audit_status).color }}>
{getStatusInfo(record.audit_status).name}
</span>
</div>
);
} else if (column.dataIndex === 'title') {
return <TextOverTips context={record.title} />;
} else if (column.dataIndex === 'type') {
return (
<div class="flex items-center">
<img
src={record.type === EnumManuscriptType.Image ? icon2 : icon3}
width="16"
height="16"
class="mr-4px"
/>
<span
class={`cts !text-14px !lh-22px ${
record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'
}`}
>
{record.type === EnumManuscriptType.Image ? '图文' : '视频'}
</span>
</div>
);
} else if (column.dataIndex === 'last_modified_at') {
return (
<span class="cts num">
{exactFormatTime(
record.last_modified_at,
'YYYY-MM-DD HH:mm:ss',
'YYYY-MM-DD HH:mm:ss',
)}
</span>
);
} else {
return formatTableField(column, record, true);
}
},
}}
/>
))}
</>
),
emptyText: () => <NoData />,
}}
/>
>
{TABLE_COLUMNS.map((column) => (
<Table.Column
key={column.dataIndex}
dataIndex={column.dataIndex}
fixed={column.fixed}
width={column.width}
minWidth={column.minWidth}
sorter={column.sortable}
align={column.align}
ellipsis
title={() => (
<div class="flex items-center">
<span class="cts mr-4px bold color-#211F24">{column.title}</span>
{column.tooltip && (
<Tooltip title={column.tooltip} placement="top">
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
</Tooltip>
)}
</div>
)}
customRender={({ record }) => {
if (column.dataIndex === 'audit_status') {
return (
<div
class="flex items-center w-fit h-24px px-8px rounded-2px"
style={{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }}
>
<span class="cts s1 bold" style={{ color: getStatusInfo(record.audit_status).color }}>
{getStatusInfo(record.audit_status).name}
</span>
</div>
);
} else if (column.dataIndex === 'title') {
return <TextOverTips context={record.title} class="!text-12px" />;
} else if (column.dataIndex === 'type') {
return (
<div class="flex items-center">
<img
src={record.type === EnumManuscriptType.Image ? icon2 : icon3}
width="16"
height="16"
class="mr-4px"
/>
<span
class={`cts !text-14px !lh-22px ${
record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'
}`}
>
{record.type === EnumManuscriptType.Image ? '图文' : '视频'}
</span>
</div>
);
} else if (column.dataIndex === 'last_modified_at') {
return (
<span class="cts num">
{exactFormatTime(record.last_modified_at, 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss')}
</span>
);
} else {
return formatTableField(column, record, true);
}
}}
/>
))}
</Table>
{pageInfo.value.total > 0 && (
<div class="flex justify-end mt-16px">
<Pagination
total={pageInfo.value.total}
size="mini"
show-total
show-jumper
show-page-size
size="small"
showTotal={(total, range) => `${total} 条记录`}
showQuickJumper
showSizeChanger
current={pageInfo.value.page}
page-size={pageInfo.value.page_size}
pageSize={pageInfo.value.page_size}
onChange={onPageChange}
onPageSizeChange={onPageSizeChange}
onShowSizeChange={onPageSizeChange}
/>
</div>
)}

View File

@ -23,44 +23,31 @@
display: flex;
flex-direction: column;
overflow: hidden;
.arco-scrollbar-track {
.ant-scrollbar-track {
display: none !important;
}
.arco-table {
.arco-table-container {
.arco-table-element {
thead {
.arco-table-tr {
.arco-table-th {
.arco-table-cell {
padding: 10px 16px !important;
}
}
}
}
tbody {
.arco-table-tr {
.arco-table-td {
.arco-table-cell {
padding: 6px 16px;
.arco-table-cell-content,
.arco-table-td-content {
font-size: 12px;
line-height: 20px;
}
}
}
}
.ant-table {
.ant-table-thead {
.ant-table-cell {
padding: 10px 16px !important;
}
}
.ant-table-body {
.ant-table-cell {
padding: 6px 16px;
.ant-table-cell-content {
font-size: 12px;
line-height: 20px;
}
}
}
}
.arco-pagination {
.arco-pagination-total,
.arco-pagination-jumper-prepend {
.ant-pagination {
.ant-pagination-total-text,
.ant-pagination-options-quick-jumper {
font-size: 14px;
}
.arco-pagination-jumper-prepend {
.ant-pagination-options-quick-jumper {
font-family: $font-family-regular;
}
}

View File

@ -2,7 +2,7 @@ export const INITIAL_QUERY = {
title: '',
// project_ids: [],
uid: '',
audit_status: '',
audit_status: undefined,
created_at: [],
sort_column: undefined,
sort_order: undefined,
@ -11,13 +11,13 @@ export const INITIAL_QUERY = {
export enum EnumCheckStatus {
All = '',
Wait = 1,
Checking = 2,
Checking = 2,
Passed = 3,
}
export enum EnumManuscriptType {
All = '',
Image = 0,
Video = 1,
Video = 1,
}
export const CHECK_STATUS = [
@ -25,19 +25,19 @@ export const CHECK_STATUS = [
name: '待审核',
id: EnumCheckStatus.Wait,
backgroundColor: '#F2F3F5',
color: '#3C4043'
color: '#3C4043',
},
{
name: '审核中',
id: EnumCheckStatus.Checking,
backgroundColor: '#FFF7E5',
color: '#FFAE00'
color: '#FFAE00',
},
{
name: '已通过',
id: EnumCheckStatus.Passed,
backgroundColor: '#EBF7F2',
color: '#25C883'
color: '#25C883',
},
];
export const MANUSCRIPT_TYPE = [
@ -53,4 +53,4 @@ export const MANUSCRIPT_TYPE = [
label: '视频',
value: EnumManuscriptType.Video,
},
]
];

View File

@ -27,7 +27,7 @@
</template>
<script lang="jsx" setup>
import { defineComponent } from 'vue';
import { Button } from '@arco-design/web-vue';
import { Button, Pagination } from '@arco-design/web-vue';
import FilterBlock from './components/filter-block';
import ManuscriptTable from './components/manuscript-table';
import DeleteManuscriptModal from './components/manuscript-table/delete-manuscript-modal.vue';

View File

@ -1,90 +1,85 @@
<template>
<a-table
<Table
ref="tableRef"
:data="dataSource"
row-key="id"
column-resizable
:dataSource="dataSource"
rowKey="id"
:pagination="false"
:scroll="{ x: '100%' }"
class="flex-1 manuscript-table w-100%"
bordered
:row-selection="rowSelection"
:selected-row-keys="selectedRowKeys"
@sorter-change="handleSorterChange"
@select="(selectedKeys, rowKeyValue, record) => emits('select', selectedKeys, rowKeyValue, record)"
@select-all="(check) => emits('selectAll', check)"
:rowSelection="rowSelection"
:showSorterTooltip="false"
@change="handleTableChange"
>
<template #empty>
<template #emptyText>
<NoData text="暂无文件" />
</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">
<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>
<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">
<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 === 'name'" #customRender="{ record }">
<div class="flex items-center">
<HoverImagePreview :src="record.cover">
<Image :width="64" :height="64" :src="record.cover" class="!rounded-8px mr-16px" :preview="false">
<template #error>
<img :src="icon4" class="w-full h-full" />
</template>
</Image>
</HoverImagePreview>
<div class="flex-1 flex flex-col overflow-hidden">
<TextOverTips :context="record.name" :line="1" class="cts mb-4px regular" />
<TextOverTips :context="`序号:${record.uid}`" :line="1" class="cts !color-#737478 regular" />
</div>
</template>
<template v-if="column.dataIndex === 'name'" #cell="{ record }">
<div class="flex items-center">
<HoverImagePreview :src="record.cover">
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-8px mr-16px" fit="cover">
<template #error>
<img :src="icon4" class="w-full h-full" />
</template>
</a-image>
</HoverImagePreview>
<div class="flex-1 flex flex-col overflow-hidden">
<TextOverTips :context="record.name" :line="1" class="cts mb-4px regular" />
<TextOverTips :context="`序号:${record.uid}`" :line="1" class="cts !color-#737478 regular" />
</div>
</div>
</template>
<template v-else-if="column.dataIndex === 'type'" #cell="{ record }">
{{ TABS_LIST.find((item) => item.value === record.type)?.label ?? '-' }}
</template>
<template v-else-if="column.dataIndex === 'size'" #cell="{ record }">
<span class="cts num">{{ formatFileSize(record.size) }}</span>
</template>
<template v-else-if="column.dataIndex === 'origin'" #cell="{ record }">
{{ ORIGIN_LIST.find((item) => item.value === record.origin)?.label ?? '-' }}
</template>
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #cell="{ record }">
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
</template>
<template #cell="{ record }" v-else-if="['created_at'].includes(column.dataIndex)">
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
</template>
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
<div class="flex items-center">
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
<Button type="primary" ghost size="small" @click="onDownload(record)">下载</Button>
</div>
</template>
<template v-else #cell="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</a-table-column>
</template>
</a-table>
</div>
</template>
<template v-else-if="column.dataIndex === 'type'" #customRender="{ record }">
{{ TABS_LIST.find((item) => item.value === record.type)?.label ?? '-' }}
</template>
<template v-else-if="column.dataIndex === 'size'" #customRender="{ record }">
<span class="cts num">{{ formatFileSize(record.size) }}</span>
</template>
<template v-else-if="column.dataIndex === 'origin'" #customRender="{ record }">
{{ ORIGIN_LIST.find((item) => item.value === record.origin)?.label ?? '-' }}
</template>
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #customRender="{ record }">
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
</template>
<template #customRender="{ record }" v-else-if="['created_at'].includes(column.dataIndex)">
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
</template>
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
<div class="flex items-center">
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
<Button type="primary" ghost size="small" @click="onDownload(record)">下载</Button>
</div>
</template>
<template v-else #customRender="{ record }">
{{ formatTableField(column, record, true) }}
</template>
</Column>
</Table>
</template>
<script setup>
import { ref } from 'vue';
import { Button, Tooltip } from 'ant-design-vue';
import { ref, computed } from 'vue';
import { Button, Tooltip, Table, Image } from 'ant-design-vue';
const { Column } = Table;
import { formatTableField, exactFormatTime, formatFileSize, downloadByUrl } from '@/utils/tools';
import { slsWithCatch } from '@/utils/stroage.ts';
import { TABS_LIST, ORIGIN_LIST } from '../../constants';
@ -122,8 +117,20 @@ const props = defineProps({
const tableRef = ref(null);
const handleSorterChange = (column, order) => {
emits('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
const handleTableChange = (pagination, filters, sorter) => {
if (sorter && sorter.field) {
emits('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
}
};
const rowSelection = {
selectedRowKeys: computed(() => props.selectedRowKeys),
onSelect: (record, selected, selectedRows, nativeEvent) => {
emits('select', selectedRows.map(row => row.id), record.id, record);
},
onSelectAll: (selected, selectedRows, changeRows) => {
emits('selectAll', selected);
},
};
const onDelete = (item) => {
emits('delete', item);