feat: Add Table component and add useTable hook
This commit is contained in:
parent
b271e13227
commit
17e8e7cda9
|
@ -2,6 +2,7 @@ import Table from './src/Table.vue'
|
|||
|
||||
export interface TableExpose {
|
||||
setProps: (props: Recordable) => void
|
||||
setColumn: (columnProps: TableSetPropsType[]) => void
|
||||
}
|
||||
|
||||
export { Table }
|
||||
|
|
|
@ -5,6 +5,7 @@ import { propTypes } from '@/utils/propTypes'
|
|||
import { setIndex } from './helper'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
import type { TableProps } from './types'
|
||||
import { set } from 'lodash-es'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Table',
|
||||
|
@ -20,6 +21,8 @@ export default defineComponent({
|
|||
type: Array as PropType<TableColumn[]>,
|
||||
default: () => []
|
||||
},
|
||||
// 展开行
|
||||
expand: propTypes.bool.def(false),
|
||||
// 是否展示分页
|
||||
pagination: {
|
||||
type: Object as PropType<Pagination>,
|
||||
|
@ -73,8 +76,22 @@ export default defineComponent({
|
|||
outsideProps.value = props
|
||||
}
|
||||
|
||||
const setColumn = (columnProps: TableSetPropsType[], columnsChildren?: TableColumn[]) => {
|
||||
const { columns } = unref(getProps)
|
||||
for (const v of columnsChildren || columns) {
|
||||
for (const item of columnProps) {
|
||||
if (v.field === item.field) {
|
||||
set(v, item.path, item.value)
|
||||
} else if (v.children?.length) {
|
||||
setColumn(columnProps, v.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expose({
|
||||
setProps
|
||||
setProps,
|
||||
setColumn
|
||||
})
|
||||
|
||||
const pagination = computed(() => {
|
||||
|
@ -129,21 +146,73 @@ export default defineComponent({
|
|||
})
|
||||
|
||||
const renderTableSelection = () => {
|
||||
const { selection, reserveSelection, align, headerAlign } = unref(getProps)
|
||||
// 渲染多选
|
||||
return unref(getProps).selection ? (
|
||||
return selection ? (
|
||||
<ElTableColumn
|
||||
type="selection"
|
||||
reserveSelection={unref(getProps).reserveSelection}
|
||||
align={unref(getProps).align}
|
||||
headerAlign={unref(getProps).headerAlign}
|
||||
reserveSelection={reserveSelection}
|
||||
align={align}
|
||||
headerAlign={headerAlign}
|
||||
width="50"
|
||||
></ElTableColumn>
|
||||
) : undefined
|
||||
}
|
||||
|
||||
const rnderTableColumn = (columns: TableColumn[]) => {
|
||||
return [renderTableSelection()].concat(
|
||||
columns.map((v) => {
|
||||
const renderTableExpand = () => {
|
||||
const { align, headerAlign } = unref(getProps)
|
||||
// 渲染展开行
|
||||
return unref(getProps).expand ? (
|
||||
<ElTableColumn type="expand" align={align} headerAlign={headerAlign}>
|
||||
{{
|
||||
// @ts-ignore
|
||||
default: (data: TableSlotDefault) => getSlot(slots, 'expand', data)
|
||||
}}
|
||||
</ElTableColumn>
|
||||
) : undefined
|
||||
}
|
||||
|
||||
const rnderTreeTableColumn = (columnsChildren: TableColumn[]) => {
|
||||
const { align, headerAlign, showOverflowTooltip } = unref(getProps)
|
||||
return columnsChildren.map((v) => {
|
||||
const props = { ...v }
|
||||
if (props.children) delete props.children
|
||||
return (
|
||||
<ElTableColumn
|
||||
showOverflowTooltip={showOverflowTooltip}
|
||||
align={align}
|
||||
headerAlign={headerAlign}
|
||||
{...props}
|
||||
prop={v.field}
|
||||
>
|
||||
{{
|
||||
default: (data: TableSlotDefault) =>
|
||||
v.children && v.children.length
|
||||
? rnderTableColumn(v.children)
|
||||
: // @ts-ignore
|
||||
getSlot(slots, v.field, data) ||
|
||||
v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
|
||||
data.row[v.field],
|
||||
// @ts-ignore
|
||||
header: getSlot(slots, `${v.field}-header`)
|
||||
}}
|
||||
</ElTableColumn>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const rnderTableColumn = (columnsChildren?: TableColumn[]) => {
|
||||
const {
|
||||
columns,
|
||||
reserveIndex,
|
||||
pageSize,
|
||||
currentPage,
|
||||
align,
|
||||
headerAlign,
|
||||
showOverflowTooltip
|
||||
} = unref(getProps)
|
||||
return [...[renderTableExpand()], ...[renderTableSelection()]].concat(
|
||||
(columnsChildren || columns).map((v) => {
|
||||
// 自定生成序号
|
||||
if (v.type === 'index') {
|
||||
return (
|
||||
|
@ -152,35 +221,33 @@ export default defineComponent({
|
|||
index={
|
||||
v.index
|
||||
? v.index
|
||||
: (index) =>
|
||||
setIndex(
|
||||
unref(getProps).reserveIndex,
|
||||
index,
|
||||
unref(getProps).pageSize,
|
||||
unref(getProps).currentPage
|
||||
)
|
||||
: (index) => setIndex(reserveIndex, index, pageSize, currentPage)
|
||||
}
|
||||
align={v.align || unref(getProps).align}
|
||||
headerAlign={v.headerAlign || unref(getProps).headerAlign}
|
||||
align={v.align || align}
|
||||
headerAlign={v.headerAlign || headerAlign}
|
||||
label={v.label}
|
||||
width="100px"
|
||||
></ElTableColumn>
|
||||
)
|
||||
} else {
|
||||
const props = { ...v }
|
||||
if (props.children) delete props.children
|
||||
return (
|
||||
<ElTableColumn
|
||||
showOverflowTooltip={unref(getProps).showOverflowTooltip}
|
||||
align={unref(getProps).align}
|
||||
headerAlign={unref(getProps).headerAlign}
|
||||
{...v}
|
||||
showOverflowTooltip={showOverflowTooltip}
|
||||
align={align}
|
||||
headerAlign={headerAlign}
|
||||
{...props}
|
||||
prop={v.field}
|
||||
>
|
||||
{{
|
||||
default: (data: TableSlotDefault) =>
|
||||
// @ts-ignore
|
||||
getSlot(slots, v.field, data) ||
|
||||
v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
|
||||
data.row[v.field],
|
||||
v.children && v.children.length
|
||||
? rnderTreeTableColumn(v.children)
|
||||
: // @ts-ignore
|
||||
getSlot(slots, v.field, data) ||
|
||||
v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
|
||||
data.row[v.field],
|
||||
// @ts-ignore
|
||||
header: getSlot(slots, `${v.field}-header`)
|
||||
}}
|
||||
|
@ -201,7 +268,7 @@ export default defineComponent({
|
|||
v-loading={unref(getProps).loading}
|
||||
>
|
||||
{{
|
||||
default: () => rnderTableColumn(unref(getProps).columns),
|
||||
default: () => rnderTableColumn(),
|
||||
// @ts-ignore
|
||||
append: () => getSlot(slots, 'append')
|
||||
}}
|
||||
|
|
|
@ -20,4 +20,5 @@ export type TableProps = {
|
|||
// 表头对齐方式
|
||||
headerAlign?: 'left' | 'center' | 'right'
|
||||
data?: Recordable
|
||||
expand?: boolean
|
||||
} & Recordable
|
||||
|
|
|
@ -12,6 +12,7 @@ interface UseTableConfig<T, L> {
|
|||
list: string
|
||||
total?: string
|
||||
}
|
||||
props?: TableProps
|
||||
}
|
||||
|
||||
interface TableObject<K, L> {
|
||||
|
@ -88,7 +89,11 @@ export const useTable = <T, K, L extends AxiosConfig = AxiosConfig>(
|
|||
return table
|
||||
}
|
||||
|
||||
const methods = {
|
||||
const methods: {
|
||||
setProps: (props: Recordable) => void
|
||||
getList: () => Promise<void>
|
||||
setColumn: (columnProps: TableSetPropsType[]) => void
|
||||
} = {
|
||||
getList: async () => {
|
||||
tableObject.loading = true
|
||||
const res = await config
|
||||
|
@ -105,11 +110,18 @@ export const useTable = <T, K, L extends AxiosConfig = AxiosConfig>(
|
|||
setProps: async (props: TableProps = {}) => {
|
||||
const table = await getTable()
|
||||
table?.setProps(props)
|
||||
},
|
||||
setColumn: async (columnProps: TableSetPropsType[]) => {
|
||||
const table = await getTable()
|
||||
table?.setColumn(columnProps)
|
||||
}
|
||||
}
|
||||
|
||||
config?.props && methods.setProps(config.props)
|
||||
|
||||
return {
|
||||
register,
|
||||
elTableRef,
|
||||
tableObject,
|
||||
methods
|
||||
}
|
||||
|
|
|
@ -324,9 +324,11 @@ export default {
|
|||
pagination: 'pagination',
|
||||
reserveIndex: 'Reserve index',
|
||||
restoreIndex: 'Restore index',
|
||||
showSelections: 'show selections',
|
||||
hiddenSelections: 'restore selections',
|
||||
showExpandedRows: 'show expanded rows',
|
||||
hiddenExpandedRows: 'hidden expanded rows'
|
||||
showSelections: 'Show selections',
|
||||
hiddenSelections: 'Restore selections',
|
||||
showExpandedRows: 'Show expanded rows',
|
||||
hiddenExpandedRows: 'Hidden expanded rows',
|
||||
changeTitle: 'Change title',
|
||||
header: 'Header'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -324,6 +324,8 @@ export default {
|
|||
showSelections: '显示多选',
|
||||
hiddenSelections: '隐藏多选',
|
||||
showExpandedRows: '显示展开行',
|
||||
hiddenExpandedRows: '隐藏展开行'
|
||||
hiddenExpandedRows: '隐藏展开行',
|
||||
changeTitle: '修改标题',
|
||||
header: '头部'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
|||
meta: {
|
||||
title: 'UseTable'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'ref-table',
|
||||
component: () => import('@/views/Components/Table/RefTable.vue'),
|
||||
name: 'RefTable',
|
||||
meta: {
|
||||
title: 'RefTable'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Table, TableExpose } from '@/components/Table'
|
||||
import { getTableListApi } from '@/api/table'
|
||||
import { TableData } from '@/api/table/types'
|
||||
import { ref, h, reactive, unref } from 'vue'
|
||||
import { ElTag, ElButton } from 'element-plus'
|
||||
import { useTable } from '@/hooks/web/useTable'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const columns = reactive<TableColumn[]>([
|
||||
{
|
||||
field: 'index',
|
||||
label: t('tableDemo.index'),
|
||||
type: 'index'
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
label: t('tableDemo.header'),
|
||||
children: [
|
||||
{
|
||||
field: 'title',
|
||||
label: t('tableDemo.title')
|
||||
},
|
||||
{
|
||||
field: 'author',
|
||||
label: t('tableDemo.author')
|
||||
},
|
||||
{
|
||||
field: 'display_time',
|
||||
label: t('tableDemo.displayTime')
|
||||
},
|
||||
{
|
||||
field: 'importance',
|
||||
label: t('tableDemo.importance'),
|
||||
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{
|
||||
type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
|
||||
},
|
||||
() =>
|
||||
cellValue === 1
|
||||
? t('tableDemo.important')
|
||||
: cellValue === 2
|
||||
? t('tableDemo.good')
|
||||
: t('tableDemo.commonly')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'pageviews',
|
||||
label: t('tableDemo.pageviews')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
label: t('tableDemo.action')
|
||||
}
|
||||
])
|
||||
|
||||
const { register, tableObject, methods } = useTable<
|
||||
{
|
||||
total: number
|
||||
list: TableData[]
|
||||
},
|
||||
TableData
|
||||
>({
|
||||
getListApi: getTableListApi,
|
||||
response: {
|
||||
list: 'list',
|
||||
total: 'total'
|
||||
},
|
||||
props: {
|
||||
columns
|
||||
}
|
||||
})
|
||||
|
||||
const { getList } = methods
|
||||
|
||||
getList()
|
||||
|
||||
const tableRef = ref<TableExpose>()
|
||||
|
||||
const acitonFn = (data: TableSlotDefault) => {
|
||||
console.log(data)
|
||||
}
|
||||
|
||||
const paginationObj = ref<Pagination>()
|
||||
|
||||
const showPagination = (show: boolean) => {
|
||||
if (show) {
|
||||
paginationObj.value = {
|
||||
total: tableObject.total
|
||||
}
|
||||
} else {
|
||||
paginationObj.value = undefined
|
||||
}
|
||||
}
|
||||
|
||||
const reserveIndex = (custom: boolean) => {
|
||||
unref(tableRef)?.setProps({
|
||||
reserveIndex: custom
|
||||
})
|
||||
}
|
||||
|
||||
const showSelections = (show: boolean) => {
|
||||
unref(tableRef)?.setProps({
|
||||
selection: show
|
||||
})
|
||||
}
|
||||
|
||||
const index = ref(1)
|
||||
|
||||
const changeTitle = () => {
|
||||
unref(tableRef)?.setColumn([
|
||||
{
|
||||
field: 'title',
|
||||
path: 'label',
|
||||
value: `${t('tableDemo.title')}${unref(index)}`
|
||||
}
|
||||
])
|
||||
index.value++
|
||||
}
|
||||
|
||||
const showExpandedRows = (show: boolean) => {
|
||||
unref(tableRef)?.setProps({
|
||||
expand: show
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContentWrap :title="`RefTable ${t('tableDemo.operate')}`">
|
||||
<ElButton @click="showPagination(true)">
|
||||
{{ t('tableDemo.show') }} {{ t('tableDemo.pagination') }}
|
||||
</ElButton>
|
||||
<ElButton @click="showPagination(false)">
|
||||
{{ t('tableDemo.hidden') }} {{ t('tableDemo.pagination') }}
|
||||
</ElButton>
|
||||
|
||||
<ElButton @click="reserveIndex(true)">{{ t('tableDemo.reserveIndex') }}</ElButton>
|
||||
<ElButton @click="reserveIndex(false)">{{ t('tableDemo.restoreIndex') }}</ElButton>
|
||||
|
||||
<ElButton @click="showSelections(true)">{{ t('tableDemo.showSelections') }}</ElButton>
|
||||
<ElButton @click="showSelections(false)">{{ t('tableDemo.hiddenSelections') }}</ElButton>
|
||||
|
||||
<ElButton @click="changeTitle">{{ t('tableDemo.changeTitle') }}</ElButton>
|
||||
|
||||
<ElButton @click="showExpandedRows(true)">{{ t('tableDemo.showExpandedRows') }}</ElButton>
|
||||
<ElButton @click="showExpandedRows(false)">{{ t('tableDemo.hiddenExpandedRows') }}</ElButton>
|
||||
</ContentWrap>
|
||||
<ContentWrap :title="`RefTable ${t('tableDemo.example')}`">
|
||||
<Table
|
||||
ref="tableRef"
|
||||
v-model:pageSize="tableObject.pageSize"
|
||||
v-model:currentPage="tableObject.currentPage"
|
||||
:data="tableObject.tableList"
|
||||
:loading="tableObject.loading"
|
||||
:pagination="paginationObj"
|
||||
@register="register"
|
||||
>
|
||||
<template #action="data">
|
||||
<ElButton type="primary" @click="acitonFn(data as TableSlotDefault)">
|
||||
{{ t('tableDemo.action') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
|
||||
<template #expand="data">
|
||||
<div class="ml-30px">
|
||||
<div>{{ t('tableDemo.title') }}:{{ data.row.title }}</div>
|
||||
<div>{{ t('tableDemo.author') }}:{{ data.row.author }}</div>
|
||||
<div>{{ t('tableDemo.displayTime') }}:{{ data.row.display_time }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
</ContentWrap>
|
||||
</template>
|
|
@ -4,7 +4,7 @@ import { useI18n } from '@/hooks/web/useI18n'
|
|||
import { Table } from '@/components/Table'
|
||||
import { getTableListApi } from '@/api/table'
|
||||
import { TableData } from '@/api/table/types'
|
||||
import { ref, h } from 'vue'
|
||||
import { ref, h, reactive, unref } from 'vue'
|
||||
import { ElTag, ElButton } from 'element-plus'
|
||||
import { useTable } from '@/hooks/web/useTable'
|
||||
|
||||
|
@ -28,51 +28,57 @@ getList()
|
|||
|
||||
const { t } = useI18n()
|
||||
|
||||
const columns: TableColumn[] = [
|
||||
const columns = reactive<TableColumn[]>([
|
||||
{
|
||||
field: 'index',
|
||||
label: t('tableDemo.index'),
|
||||
type: 'index'
|
||||
},
|
||||
{
|
||||
field: 'title',
|
||||
label: t('tableDemo.title')
|
||||
},
|
||||
{
|
||||
field: 'author',
|
||||
label: t('tableDemo.author')
|
||||
},
|
||||
{
|
||||
field: 'display_time',
|
||||
label: t('tableDemo.displayTime')
|
||||
},
|
||||
{
|
||||
field: 'importance',
|
||||
label: t('tableDemo.importance'),
|
||||
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{
|
||||
type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
|
||||
},
|
||||
() =>
|
||||
cellValue === 1
|
||||
? t('tableDemo.important')
|
||||
: cellValue === 2
|
||||
? t('tableDemo.good')
|
||||
: t('tableDemo.commonly')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'pageviews',
|
||||
label: t('tableDemo.pageviews')
|
||||
field: 'content',
|
||||
label: t('tableDemo.header'),
|
||||
children: [
|
||||
{
|
||||
field: 'title',
|
||||
label: t('tableDemo.title')
|
||||
},
|
||||
{
|
||||
field: 'author',
|
||||
label: t('tableDemo.author')
|
||||
},
|
||||
{
|
||||
field: 'display_time',
|
||||
label: t('tableDemo.displayTime')
|
||||
},
|
||||
{
|
||||
field: 'importance',
|
||||
label: t('tableDemo.importance'),
|
||||
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{
|
||||
type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
|
||||
},
|
||||
() =>
|
||||
cellValue === 1
|
||||
? t('tableDemo.important')
|
||||
: cellValue === 2
|
||||
? t('tableDemo.good')
|
||||
: t('tableDemo.commonly')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'pageviews',
|
||||
label: t('tableDemo.pageviews')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
label: t('tableDemo.action')
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
const acitonFn = (data: TableSlotDefault) => {
|
||||
console.log(data)
|
||||
|
@ -103,6 +109,27 @@ const showSelections = (show: boolean) => {
|
|||
selection: show
|
||||
})
|
||||
}
|
||||
|
||||
const index = ref(1)
|
||||
|
||||
const changeTitle = () => {
|
||||
const { setColumn } = methods
|
||||
setColumn([
|
||||
{
|
||||
field: 'title',
|
||||
path: 'label',
|
||||
value: `${t('tableDemo.title')}${unref(index)}`
|
||||
}
|
||||
])
|
||||
index.value++
|
||||
}
|
||||
|
||||
const showExpandedRows = (show: boolean) => {
|
||||
const { setProps } = methods
|
||||
setProps({
|
||||
expand: show
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -120,8 +147,10 @@ const showSelections = (show: boolean) => {
|
|||
<ElButton @click="showSelections(true)">{{ t('tableDemo.showSelections') }}</ElButton>
|
||||
<ElButton @click="showSelections(false)">{{ t('tableDemo.hiddenSelections') }}</ElButton>
|
||||
|
||||
<ElButton @click="showSelections(true)">{{ t('tableDemo.showExpandedRows') }}</ElButton>
|
||||
<ElButton @click="showSelections(false)">{{ t('tableDemo.hiddenExpandedRows') }}</ElButton>
|
||||
<ElButton @click="changeTitle">{{ t('tableDemo.changeTitle') }}</ElButton>
|
||||
|
||||
<ElButton @click="showExpandedRows(true)">{{ t('tableDemo.showExpandedRows') }}</ElButton>
|
||||
<ElButton @click="showExpandedRows(false)">{{ t('tableDemo.hiddenExpandedRows') }}</ElButton>
|
||||
</ContentWrap>
|
||||
<ContentWrap :title="`UseTable ${t('tableDemo.example')}`">
|
||||
<Table
|
||||
|
@ -138,6 +167,14 @@ const showSelections = (show: boolean) => {
|
|||
{{ t('tableDemo.action') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
|
||||
<template #expand="data">
|
||||
<div class="ml-30px">
|
||||
<div>{{ t('tableDemo.title') }}:{{ data.row.title }}</div>
|
||||
<div>{{ t('tableDemo.author') }}:{{ data.row.author }}</div>
|
||||
<div>{{ t('tableDemo.displayTime') }}:{{ data.row.display_time }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
declare type TableColumn = {
|
||||
field: string
|
||||
label?: string
|
||||
children?: TableColumn[]
|
||||
} & Recordable
|
||||
|
||||
declare type TableSlotDefault = {
|
||||
|
@ -27,3 +28,9 @@ declare interface Pagination {
|
|||
disabled?: boolean
|
||||
hideOnSinglePage?: boolean
|
||||
}
|
||||
|
||||
declare interface TableSetPropsType {
|
||||
field: string
|
||||
path: string
|
||||
value: any
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue