diff --git a/mock/role/index.ts b/mock/role/index.ts
index 72022c6..477806b 100644
--- a/mock/role/index.ts
+++ b/mock/role/index.ts
@@ -142,6 +142,14 @@ const adminList = [
title: 'UseTable'
}
},
+ {
+ path: 'tree-table',
+ component: 'views/Components/Table/TreeTable',
+ name: 'TreeTable',
+ meta: {
+ title: 'TreeTable'
+ }
+ },
{
path: 'ref-table',
component: 'views/Components/Table/RefTable',
@@ -481,6 +489,7 @@ const testList: string[] = [
'/components/table',
'/components/table/default-table',
'/components/table/use-table',
+ '/components/table/tree-table',
'/components/table/ref-table',
'/components/editor-demo',
'/components/editor-demo/editor',
diff --git a/mock/table/index.ts b/mock/table/index.ts
index ca8512d..267b835 100644
--- a/mock/table/index.ts
+++ b/mock/table/index.ts
@@ -12,7 +12,7 @@ const count = 100
const baseContent =
'
I am testing data, I am testing data.

'
-let List: {
+interface ListProps {
id: string
author: string
title: string
@@ -20,7 +20,20 @@ let List: {
importance: number
display_time: string
pageviews: number
-}[] = []
+}
+
+interface TreeListProps {
+ id: string
+ author: string
+ title: string
+ content: string
+ importance: number
+ display_time: string
+ pageviews: number
+ children: TreeListProps[]
+}
+
+let List: ListProps[] = []
for (let i = 0; i < count; i++) {
List.push(
@@ -38,7 +51,114 @@ for (let i = 0; i < count; i++) {
)
}
+const treeList: TreeListProps[] = []
+
+for (let i = 0; i < count; i++) {
+ treeList.push(
+ Mock.mock({
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)',
+ children: [
+ {
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)',
+ children: [
+ {
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)'
+ },
+ {
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)'
+ }
+ ]
+ },
+ {
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)'
+ },
+ {
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)'
+ },
+ {
+ id: toAnyString(),
+ // timestamp: +Mock.Random.date('T'),
+ author: '@first',
+ title: '@title(5, 10)',
+ content: baseContent,
+ importance: '@integer(1, 3)',
+ display_time: '@datetime',
+ pageviews: '@integer(300, 5000)'
+ }
+ ]
+ // image_uri
+ })
+ )
+}
+
export default [
+ // 树形列表接口
+ {
+ url: '/example/treeList',
+ method: 'get',
+ timeout,
+ response: ({ query }) => {
+ const { title, pageIndex, pageSize } = query
+ const mockList = treeList.filter((item) => {
+ if (title && item.title.indexOf(title) < 0) return false
+ return true
+ })
+ const pageList = mockList.filter(
+ (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
+ )
+ return {
+ data: {
+ code: code,
+ data: {
+ total: mockList.length,
+ list: pageList
+ }
+ }
+ }
+ }
+ },
// 列表接口
{
url: '/example/list',
diff --git a/src/api/table/index.ts b/src/api/table/index.ts
index 36b3af9..c3b6d06 100644
--- a/src/api/table/index.ts
+++ b/src/api/table/index.ts
@@ -5,6 +5,10 @@ export const getTableListApi = (params: any) => {
return request.get({ url: '/example/list', params })
}
+export const getTreeTableListApi = (params: any) => {
+ return request.get({ url: '/example/treeList', params })
+}
+
export const saveTableApi = (data: Partial): Promise => {
return request.post({ url: '/example/save', data })
}
diff --git a/src/components/Table/index.ts b/src/components/Table/index.ts
index 224d32d..1799596 100644
--- a/src/components/Table/index.ts
+++ b/src/components/Table/index.ts
@@ -1,6 +1,6 @@
import Table from './src/Table.vue'
import { ElTable } from 'element-plus'
-import { TableSetProps } from './src/types'
+import { TableColumn, TableSetProps } from './src/types'
export type {
TableColumn,
@@ -13,6 +13,8 @@ export type {
export interface TableExpose {
setProps: (props: Recordable) => void
setColumn: (columnProps: TableSetProps[]) => void
+ addColumn: (column: TableColumn, index?: number) => void
+ delColumn: (field: string) => void
selections: Recordable[]
elTableRef: ComponentRef
}
diff --git a/src/components/Table/src/Table.vue b/src/components/Table/src/Table.vue
index bfa0ae9..757fe9e 100644
--- a/src/components/Table/src/Table.vue
+++ b/src/components/Table/src/Table.vue
@@ -6,14 +6,13 @@ import { setIndex } from './helper'
import type { TableProps, TableColumn, Pagination, TableSetProps } from './types'
import { set } from 'lodash-es'
import { CSSProperties } from 'vue'
+import { getSlot } from '@/utils/tsxHelper'
export default defineComponent({
name: 'Table',
props: {
pageSize: propTypes.number.def(10),
currentPage: propTypes.number.def(1),
- // 是否多选
- selection: propTypes.bool.def(true),
// 是否所有的超出隐藏,优先级低于schema中的showOverflowTooltip,
showOverflowTooltip: propTypes.bool.def(true),
// 表头
@@ -49,7 +48,7 @@ export default defineComponent({
height: propTypes.oneOfType([Number, String]),
maxHeight: propTypes.oneOfType([Number, String]),
stripe: propTypes.bool.def(false),
- border: propTypes.bool.def(false),
+ border: propTypes.bool.def(true),
size: {
type: String as PropType,
validator: (v: ComponentSize) => ['medium', 'small', 'mini'].includes(v)
@@ -103,10 +102,7 @@ export default defineComponent({
>,
default: () => undefined
},
- rowKey: {
- type: [Function, String] as PropType<(row: Recordable) => string | string>,
- default: () => 'id'
- },
+ rowKey: propTypes.string.def('id'),
emptyText: propTypes.string.def('No Data'),
defaultExpandAll: propTypes.bool.def(false),
expandRowKeys: {
@@ -164,7 +160,7 @@ export default defineComponent({
default: () => undefined
},
treeProps: {
- type: Object as PropType<{ hasChildren: string; children: string; label: string }>,
+ type: Object as PropType<{ hasChildren?: string; children?: string; label?: string }>,
default: () => ({ hasChildren: 'hasChildren', children: 'children', label: 'label' })
},
tableLayout: {
@@ -175,7 +171,7 @@ export default defineComponent({
flexible: propTypes.bool.def(false)
},
emits: ['update:pageSize', 'update:currentPage', 'register'],
- setup(props, { attrs, emit, expose }) {
+ setup(props, { attrs, emit, slots, expose }) {
const elTableRef = ref>()
// 注册
@@ -217,6 +213,23 @@ export default defineComponent({
}
}
+ const addColumn = (column: TableColumn, index?: number) => {
+ const { columns } = unref(getProps)
+ if (index) {
+ columns.splice(index, 0, column)
+ } else {
+ columns.push(column)
+ }
+ }
+
+ const delColumn = (field: string) => {
+ const { columns } = unref(getProps)
+ const index = columns.findIndex((item) => item.field === field)
+ if (index > -1) {
+ columns.splice(index, 1)
+ }
+ }
+
const selections = ref([])
const selectionChange = (selection: Recordable[]) => {
@@ -226,6 +239,8 @@ export default defineComponent({
expose({
setProps,
setColumn,
+ delColumn,
+ addColumn,
selections,
elTableRef
})
@@ -275,42 +290,17 @@ export default defineComponent({
)
const getBindValue = computed(() => {
- const bindValue: Recordable = { ...attrs, ...props }
+ const bindValue: Recordable = { ...attrs, ...unref(getProps) }
delete bindValue.columns
delete bindValue.data
+ console.log(bindValue)
return bindValue
})
- const renderTableSelection = () => {
- const { selection, reserveSelection, align, headerAlign } = unref(getProps)
- // 渲染多选
- return selection ? (
-
- ) : undefined
- }
-
- // const renderTableExpand = () => {
- // const { align, headerAlign, expand } = unref(getProps)
- // // 渲染展开行
- // return expand ? (
- //
- // {{
- // // @ts-ignore
- // default: (data: TableSlotDefault) => getSlot(slots, 'expand', data)
- // }}
- //
- // ) : undefined
- // }
-
const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
const { align, headerAlign, showOverflowTooltip } = unref(getProps)
return columnsChildren.map((v) => {
+ if (v.hidden) return null
const props = { ...v } as any
if (props.children) delete props.children
@@ -318,11 +308,13 @@ export default defineComponent({
const slots = {
default: (...args: any[]) => {
- if (props?.slots?.default) {
- return slots.default(args)
- } else if (children && children.length) {
- return renderTreeTableColumn(children)
- }
+ const data = args[0]
+ return children && children.length
+ ? renderTreeTableColumn(children)
+ : props?.slots?.default
+ ? props.slots.default(args)
+ : v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
+ data.row[v.field]
}
}
if (props?.slots?.header) {
@@ -351,59 +343,69 @@ export default defineComponent({
currentPage,
align,
headerAlign,
- showOverflowTooltip
+ showOverflowTooltip,
+ reserveSelection
} = unref(getProps)
- return [renderTableSelection()].concat(
- (columnsChildren || columns).map((v) => {
- // 自定生成序号
- if (v.type === 'index') {
- return (
- setIndex(reserveIndex, index, pageSize, currentPage)
- }
- align={v.align || align}
- headerAlign={v.headerAlign || headerAlign}
- label={v.label}
- width="65px"
- >
- )
- } else {
- const props = { ...v } as any
- if (props.children) delete props.children
- const children = v.children
-
- const slots = {
- default: (...args: any[]) => {
- if (props?.slots?.default) {
- return slots.default(args)
- } else if (children && children.length) {
- return renderTreeTableColumn(children)
- }
+ return (columnsChildren || columns).map((v) => {
+ if (v.hidden) return null
+ if (v.type === 'index') {
+ return (
+ setIndex(reserveIndex, index, pageSize, currentPage)
}
- }
- if (props?.slots?.header) {
- slots['header'] = (...args: any[]) => props.slots.header(args)
- }
+ align={v.align || align}
+ headerAlign={v.headerAlign || headerAlign}
+ label={v.label}
+ width="65px"
+ >
+ )
+ } else if (v.type === 'selection') {
+ return (
+
+ )
+ } else {
+ const props = { ...v } as any
+ if (props.children) delete props.children
- return (
-
- {slots}
-
- )
+ const children = v.children
+
+ const slots = {
+ default: (...args: any[]) => {
+ const data = args[0]
+ return children && children.length
+ ? renderTreeTableColumn(children)
+ : props?.slots?.default
+ ? props.slots.default(args)
+ : v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
+ data.row[v.field]
+ }
}
- })
- )
+ if (props?.slots?.header) {
+ slots['header'] = (...args: any[]) => props.slots.header(args)
+ }
+
+ return (
+
+ {slots}
+
+ )
+ }
+ })
}
return () => (
@@ -415,7 +417,9 @@ export default defineComponent({
{...unref(getBindValue)}
>
{{
- default: () => renderTableColumn()
+ default: () => renderTableColumn(),
+ empty: () => getSlot(slots, 'empty') || props.emptyText,
+ append: () => getSlot(slots, 'append')
}}
{unref(getProps).pagination ? (
diff --git a/src/components/Table/src/types/index.ts b/src/components/Table/src/types/index.ts
index 0799cff..173eb86 100644
--- a/src/components/Table/src/types/index.ts
+++ b/src/components/Table/src/types/index.ts
@@ -2,6 +2,11 @@ import { TableProps as ElTableProps } from 'element-plus'
export interface TableColumn {
field: string
label?: string
+ type?: string
+ /**
+ * 是否隐藏
+ */
+ hidden?: boolean
children?: TableColumn[]
slots?: {
default?: (...args: any[]) => JSX.Element | JSX.Element[] | null
@@ -69,8 +74,6 @@ export interface TableSetProps {
export interface TableProps extends Omit>, 'data'> {
pageSize?: number
currentPage?: number
- // 是否多选
- selection?: boolean
// 是否所有的超出隐藏,优先级低于schema中的showOverflowTooltip,
showOverflowTooltip?: boolean
// 表头
diff --git a/src/hooks/web/useForm.ts b/src/hooks/web/useForm.ts
index ef5a906..3846210 100644
--- a/src/hooks/web/useForm.ts
+++ b/src/hooks/web/useForm.ts
@@ -32,7 +32,7 @@ export const useForm = () => {
const methods = {
/**
* @description 设置form组件的props
- * @param field FormItem的field
+ * @param props form组件的props
*/
setProps: async (props: FormProps = {}) => {
const form = await getForm()
diff --git a/src/hooks/web/useTable.ts b/src/hooks/web/useTable.ts
index b81f45a..e1fa3f9 100644
--- a/src/hooks/web/useTable.ts
+++ b/src/hooks/web/useTable.ts
@@ -1,107 +1,46 @@
-import { Table, TableExpose, TableProps, TableSetProps } from '@/components/Table'
-import { ElTable, ElMessageBox, ElMessage } from 'element-plus'
-import { ref, reactive, watch, computed, unref, nextTick, onMounted } from 'vue'
-import { get } from 'lodash-es'
-import { useI18n } from '@/hooks/web/useI18n'
-
-const { t } = useI18n()
-
-interface TableResponse {
- total: number
- list: T[]
- pageNumber: number
- pageSize: number
-}
+import { Table, TableExpose, TableProps, TableSetProps, TableColumn } from '@/components/Table'
+import { ElTable } from 'element-plus'
+import { ref, watch, unref, nextTick, onMounted } from 'vue'
interface UseTableConfig {
- // 是否初始化请求一次
+ /**
+ * 是否初始化的时候请求一次
+ */
immediate?: boolean
- // 获取数据字段映射
- props?: {
- list?: string
- total?: string
- }
fetchDataApi: () => Promise<{
list: any[]
total: number
}>
- // getListApi: (option: any) => Promise>>
- // delListApi?: (option: any) => Promise
- // 返回数据格式配置
- // response: {
- // list: string
- // total?: string
- // }
- // 默认传递的参数
- // defaultParams?: Recordable
- // props?: TableProps
-}
-
-interface TableObject {
- pageSize: number
- currentPage: number
- total: number
- list: T[]
- params: any
- loading: boolean
- currentRow: Nullable
}
export const useTable = (config: UseTableConfig) => {
const { immediate = true } = config
const loading = ref(false)
- const pageIndex = ref(1)
+ const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0)
const dataList = ref([])
- const tableObject = reactive({
- // 页数
- pageSize: 10,
- // 当前页
- currentPage: 1,
- // 总条数
- total: 10,
- // 表格数据
- list: [],
- // AxiosConfig 配置
- params: {
- // ...(config?.defaultParams || {})
- },
- // 加载中
- loading: true,
- // 当前行的数据
- currentRow: null
- })
-
- const paramsObj = computed(() => {
- return {
- ...tableObject.params,
- pageSize: tableObject.pageSize,
- pageIndex: tableObject.currentPage
+ watch(
+ () => currentPage.value,
+ () => {
+ methods.getList()
}
- })
+ )
- // watch(
- // () => tableObject.currentPage,
- // () => {
- // methods.getList()
- // }
- // )
-
- // watch(
- // () => tableObject.pageSize,
- // () => {
- // // 当前页不为1时,修改页数后会导致多次调用getList方法
- // if (tableObject.currentPage === 1) {
- // methods.getList()
- // } else {
- // tableObject.currentPage = 1
- // methods.getList()
- // }
- // }
- // )
+ watch(
+ () => pageSize.value,
+ () => {
+ // 当前页不为1时,修改页数后会导致多次调用getList方法
+ if (unref(currentPage) === 1) {
+ methods.getList()
+ } else {
+ currentPage.value = 1
+ methods.getList()
+ }
+ }
+ )
onMounted(() => {
if (immediate) {
@@ -148,6 +87,9 @@ export const useTable = (config: UseTableConfig) => {
// }
const methods = {
+ /**
+ * 获取表单数据
+ */
getList: async () => {
loading.value = true
try {
@@ -162,36 +104,62 @@ export const useTable = (config: UseTableConfig) => {
} finally {
loading.value = false
}
- // const res = await config?.getListApi(unref(paramsObj)).finally(() => {
- // tableObject.loading = false
- // })
- // if (res) {
- // tableObject.list = get(res.data || {}, config?.response.list as string)
- // tableObject.total = get(res.data || {}, config?.response?.total as string) || 0
- // }
+ },
+
+ /**
+ * @description 设置table组件的props
+ * @param props table组件的props
+ */
+ setProps: async (props: TableProps = {}) => {
+ const table = await getTable()
+ table?.setProps(props)
+ },
+
+ /**
+ * @description 设置column
+ * @param columnProps 需要设置的列
+ */
+ setColumn: async (columnProps: TableSetProps[]) => {
+ const table = await getTable()
+ table?.setColumn(columnProps)
+ },
+
+ /**
+ * @description 新增column
+ * @param tableColumn 需要新增数据
+ * @param index 在哪里新增
+ */
+ addColumn: async (tableColumn: TableColumn, index?: number) => {
+ const table = await getTable()
+ table?.addColumn(tableColumn, index)
+ },
+
+ /**
+ * @description 删除column
+ * @param field 删除哪个数据
+ */
+ delColumn: async (field: string) => {
+ const table = await getTable()
+ table?.delColumn(field)
+ },
+
+ /**
+ * @description 获取全选数据
+ * @returns
+ */
+ getSelections: async () => {
+ const table = await getTable()
+ return table?.selections || []
+ },
+
+ /**
+ * @description 获取ElTable组件的实例
+ * @returns ElTable instance
+ */
+ getElTableExpose: async () => {
+ await getTable()
+ return unref(elTableRef)
}
- // setProps: async (props: TableProps = {}) => {
- // const table = await getTable()
- // table?.setProps(props)
- // },
- // setColumn: async (columnProps: TableSetProps[]) => {
- // const table = await getTable()
- // table?.setColumn(columnProps)
- // },
- // getSelections: async () => {
- // const table = await getTable()
- // return (table?.selections || []) as T[]
- // },
- // // 与Search组件结合
- // setSearchParams: (data: Recordable) => {
- // tableObject.currentPage = 1
- // tableObject.params = Object.assign(tableObject.params, {
- // pageSize: tableObject.pageSize,
- // pageIndex: tableObject.currentPage,
- // ...data
- // })
- // methods.getList()
- // },
// // 删除数据
// delList: async (ids: string[] | number[], multiple: boolean, message = true) => {
// const tableRef = await getTable()
@@ -222,11 +190,9 @@ export const useTable = (config: UseTableConfig) => {
return {
tableRegister: register,
- elTableRef,
- tableObject,
- methods,
+ tableMethods: methods,
tableState: {
- pageIndex,
+ currentPage,
pageSize,
total,
dataList,
diff --git a/src/locales/en.ts b/src/locales/en.ts
index 4f2b13f..51eb882 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -417,7 +417,11 @@ export default {
hiddenExpandedRows: 'Hidden expanded rows',
changeTitle: 'Change title',
header: 'Header',
- selectAllNone: 'Select all / none'
+ selectAllNone: 'Select all / none',
+ delOrAddAction: 'Delete or add action',
+ showOrHiddenStripe: 'Show or hidden stripe',
+ showOrHiddenBorder: 'Show or hidden border',
+ fixedHeaderOrAuto: 'Fixed header or auto'
},
richText: {
richText: 'Rich text',
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index e8f4fb0..494da9f 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -412,7 +412,11 @@ export default {
hiddenExpandedRows: '隐藏展开行',
changeTitle: '修改标题',
header: '头部',
- selectAllNone: '全选/全不选'
+ selectAllNone: '全选/全不选',
+ delOrAddAction: '删除/添加操作列',
+ showOrHiddenStripe: '显示/隐藏斑马纹',
+ showOrHiddenBorder: '显示/隐藏边框',
+ fixedHeaderOrAuto: '固定头部/自动'
},
richText: {
richText: '富文本',
diff --git a/src/router/index.ts b/src/router/index.ts
index 2c998df..7f55b3f 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -184,6 +184,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
meta: {
title: 'UseTable'
}
+ },
+ {
+ path: 'tree-table',
+ component: () => import('@/views/Components/Table/TreeTable.vue'),
+ name: 'TreeTable',
+ meta: {
+ title: 'TreeTable'
+ }
}
]
},
diff --git a/src/views/Components/Table/TreeTable.vue b/src/views/Components/Table/TreeTable.vue
new file mode 100644
index 0000000..dfb1293
--- /dev/null
+++ b/src/views/Components/Table/TreeTable.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Components/Table/UseTableDemo.vue b/src/views/Components/Table/UseTableDemo.vue
index 42d67d6..7575d21 100644
--- a/src/views/Components/Table/UseTableDemo.vue
+++ b/src/views/Components/Table/UseTableDemo.vue
@@ -1,18 +1,17 @@
-
+
{{ t('tableDemo.show') }} {{ t('tableDemo.pagination') }}
@@ -185,50 +230,34 @@ const selectAllNone = () => {
{{ t('tableDemo.hiddenExpandedRows') }}
{{ t('tableDemo.selectAllNone') }}
+
+ {{ t('tableDemo.delOrAddAction') }}
+
+ {{ t('tableDemo.showOrHiddenStripe') }}
+
+ {{ t('tableDemo.fixedHeaderOrAuto') }}
-
-
-
{{ t('tableDemo.title') }}:{{ data.row.title }}
-
{{ t('tableDemo.author') }}:{{ data.row.author }}
-
{{ t('tableDemo.displayTime') }}:{{ data.row.display_time }}
-
-
-
+ />
-
-
+
+