| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- <script lang="ts" setup generic="T">
- import type { TableInstance, TableProps } from 'element-plus'
- import { FilterPayload, SortField, SortOrder, TableContextKey } from './token'
- interface Props extends /* @vue-ignore */ Partial<Omit<TableProps<T>, 'data'>> {
- data: T[]
- loading: boolean
- handleQuery?: (payload?: FilterPayload) => void
- sortingFields?: SortField[]
- sortFn?: (prop: string, order: SortOrder | null) => void
- customClass?: boolean
- showBorder?: boolean
- }
- const props = defineProps<Props>()
- const emits = defineEmits<{
- 'update:sortingFields': [fields: SortField[]]
- }>()
- const attrs = useAttrs()
- const tableRef = ref<TableInstance>()
- const defaultOptions: Partial<Props> = {
- size: 'default',
- stripe: true,
- border: true,
- highlightCurrentRow: true,
- showOverflowTooltip: true,
- scrollbarAlwaysOn: true,
- showBorder: false,
- customClass: false,
- tooltipOptions: {
- popperClass: 'max-w-120'
- }
- }
- const bindProps = computed(() => {
- const { data, sortingFields, ...otherProps } = props
- return {
- ...defaultOptions,
- ...attrs,
- ...otherProps,
- data: data || []
- }
- })
- const handleDefaultSort = (prop: string, order: SortOrder | null) => {
- const newFields = [...(props.sortingFields || [])]
- const idx = newFields.findIndex((f) => f.field === prop)
- if (order === null) {
- if (idx > -1) {
- newFields.splice(idx, 1)
- }
- } else {
- if (idx > -1) {
- newFields[idx] = { ...newFields[idx], order }
- } else {
- newFields.push({ field: prop, order })
- }
- }
- emits('update:sortingFields', newFields)
- props.handleQuery?.()
- }
- const safeSortingFields = computed(() => props.sortingFields || [])
- const safeData = computed(() => props.data || [])
- const safeLoading = computed(() => props.loading)
- provide(TableContextKey, {
- onQuery: (payload) => props.handleQuery?.(payload),
- onSort: (prop, order) => {
- if (props.sortFn) {
- props.sortFn(prop, order)
- } else {
- handleDefaultSort(prop, order)
- }
- },
- // 关键:传递响应式的 data 和 sortingFields
- data: safeData,
- sortingFields: safeSortingFields,
- loading: safeLoading
- })
- defineExpose({
- elTableRef: tableRef
- })
- </script>
- <template>
- <el-table
- ref="tableRef"
- v-loading="loading"
- :class="{ 'zm-table': !customClass, 'show-border': showBorder }"
- v-bind="bindProps"
- :data="data"
- >
- <template v-for="(_, name) in $slots" #[name]="slotData">
- <slot :name="name" v-bind="slotData || {}"></slot>
- </template>
- </el-table>
- </template>
- <style>
- .zm-table {
- border-radius: 8px;
- &::before,
- &::after {
- display: none;
- }
- .el-table__inner-wrapper {
- &::before,
- &::after {
- display: none;
- }
- }
- .el-table__border-left-patch {
- display: none;
- }
- .el-table__cell {
- height: 52px;
- &:last-child {
- border-right: none !important;
- }
- }
- .el-table__header {
- border-bottom-right-radius: 8px;
- border-bottom-left-radius: 8px;
- .el-table__cell {
- background: var(--el-fill-color-light) !important;
- &:last-child {
- .cell {
- border-right: none;
- }
- }
- &:first-child {
- border-bottom-left-radius: 8px;
- }
- &:last-child {
- border-bottom-right-radius: 8px;
- }
- }
- }
- .el-table__body-wrapper {
- .el-table__cell {
- &:last-child {
- border-top-right-radius: 8px;
- border-bottom-right-radius: 8px;
- }
- &:first-child {
- border-bottom-left-radius: 8px;
- border-top-left-radius: 8px;
- }
- }
- }
- }
- .zm-table:not(.show-border) {
- .el-table__cell {
- border: none !important;
- }
- .el-table__header {
- .el-table__cell {
- .cell {
- border-right: var(--el-table-border);
- border-color: var(--el-table-header-text-color);
- }
- &:last-child {
- .cell {
- border-right: none;
- }
- }
- }
- }
- .el-table__row {
- &:last-child {
- .el-table__cell {
- border-bottom: none;
- }
- }
- }
- }
- </style>
|