Browse Source

feat(BasicTable): asynchronous loading children node

main
刘凯 1 year ago
parent
commit
aa27b039e1
  1. 21
      src/components/Table/src/BasicTable.vue
  2. 37
      src/components/Table/src/components/ExpandIcon.vue
  3. 17
      src/components/Table/src/hooks/useDataSource.ts
  4. 4
      src/components/Table/src/props.ts
  5. 4
      src/components/Table/src/types/table.ts

21
src/components/Table/src/BasicTable.vue

@ -5,6 +5,7 @@ import { Table } from 'ant-design-vue'
import { omit } from 'lodash-es'
import type { BasicTableProps, ColumnChangeParam, InnerHandlers, SizeType, SlotBodyCellProps, TableActionType } from './types/table'
import HeaderCell from './components/HeaderCell.vue'
import ExpandIcon from './components/ExpandIcon.vue'
import { usePagination } from './hooks/usePagination'
import { useColumns } from './hooks/useColumns'
@ -64,7 +65,8 @@ const { prefixCls } = useDesign('basic-table')
const [registerForm, formActions] = useForm()
const getProps = computed(() => {
return { ...props, ...unref(innerPropsRef) } as BasicTableProps
// Because there are a lot of ts errors using BasicTableProps<T>, use any
return { ...props, ...unref(innerPropsRef) } as BasicTableProps<any>
})
const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false)
@ -109,6 +111,7 @@ const {
reload,
getAutoCreateKey,
updateTableData,
loadData,
} = useDataSource<T>(
getProps,
{
@ -315,19 +318,29 @@ emit('register', tableAction, formActions)
<!-- eslint-disable-next-line vue/no-extra-parens -->
<slot :name="item" v-bind="((data || {}) as SlotBodyCellProps<T>)" />
</template>
<template #headerCell="{ column }">
<slot name="headerCell" v-bind="{ column }">
<HeaderCell :column="column" />
</slot>
</template>
<!-- 增加对antdv3.x兼容 -->
<template #bodyCell="data">
<!-- eslint-disable-next-line vue/no-extra-parens -->
<slot name="bodyCell" v-bind="((data || {}) as SlotBodyCellProps<T>)" />
</template>
<!-- <template #[`header-${column.dataIndex}`] v-for="(column, index) in columns" :key="index"> -->
<!-- <HeaderCell :column="column" /> -->
<!-- </template> -->
<template #expandIcon="{ expanded, record, onExpand }">
<!-- if children is an array, render ExpandIcon -->
<ExpandIcon
:class="{ invisible: !record.children }"
:expanded="expanded"
:record="record"
:on-expand="onExpand"
:load-data="loadData"
/>
</template>
</Table>
</div>
</template>

37
src/components/Table/src/components/ExpandIcon.vue

@ -0,0 +1,37 @@
<script lang="ts" setup generic="T extends Recordable = Recordable">
import { ref } from 'vue'
import { LoadingOutlined } from '@ant-design/icons-vue'
const props = defineProps<{
expanded: boolean
record: T
onExpand: (record: any, e: MouseEvent) => void
loadData: (record: T & { children?: T[] }) => Promise<void>
}>()
const loading = ref(false)
function handleExpand(e: MouseEvent) {
loading.value = true
props.loadData(props.record)
.then(() => {
return props.onExpand(props.record, e)
})
.catch(() => {})
.finally(() => {
loading.value = false
})
}
</script>
<template>
<button
v-if="!loading"
class="ant-table-row-expand-icon"
:class="[`ant-table-row-expand-icon-${expanded ? 'expanded' : 'collapsed'}`]"
:aria-expanded="expanded"
@click="(e) => handleExpand(e)"
/>
<span v-else class="float-left mr-9px inline-block w-16px">
<LoadingOutlined />
</span>
</template>

17
src/components/Table/src/hooks/useDataSource.ts

@ -23,7 +23,7 @@ interface SearchState {
filterInfo: Record<string, string[]>
}
export function useDataSource<T extends Recordable = Recordable>(
propsRef: ComputedRef<BasicTableProps>,
propsRef: ComputedRef<BasicTableProps<T>>,
{
getPaginationInfo,
setPagination,
@ -176,7 +176,7 @@ export function useDataSource<T extends Recordable = Recordable>(
const row = data[i]
let targetKeyName: string = rowKeyName as string
if (isFunction(rowKeyName))
targetKeyName = rowKeyName(row)
targetKeyName = rowKeyName(row) as string
if (row[targetKeyName] === key)
return { index: i, data }
@ -348,6 +348,18 @@ export function useDataSource<T extends Recordable = Recordable>(
}
}
async function loadData(record: T & { children?: T[] }) {
const { load } = propsRef.value
if (!load || record.children?.length)
return
try {
const res = await load(record)
record.children = res
}
catch {}
}
function setTableData<T = Recordable>(values: T[]) {
dataSourceRef.value = values as Recordable[]
}
@ -385,5 +397,6 @@ export function useDataSource<T extends Recordable = Recordable>(
insertTableDataRecord,
findTableDataRecord,
handleTableChange,
loadData,
}
}

4
src/components/Table/src/props.ts

@ -52,6 +52,10 @@ export function defineTableProps<T>() {
>,
default: null,
},
load: {
type: Function as PropType<(record: T) => Promise<T[]>>,
default: null,
},
beforeFetch: {
type: Function as PropType<Fn>,
default: null,

4
src/components/Table/src/types/table.ts

@ -173,6 +173,10 @@ export interface BasicTableProps<T = Recordable<any>> {
* , `src/settings/componentSetting.ts > table > fetchSetting`
*/
api?: (...arg: any) => Promise<T[] | { records: T[], current?: number, size?: number, total?: number }>
/**
*
*/
load?: (record: T & { children?: T[] }) => Promise<T[]>
// 请求之前处理参数
beforeFetch?: Fn
// 自定义处理接口返回参数

Loading…
Cancel
Save