wip: Table改版中
This commit is contained in:
parent
f8ffbd1e61
commit
002d03a0ad
|
@ -1,7 +1,7 @@
|
|||
import request from '@/config/axios'
|
||||
import type { TableData } from './types'
|
||||
|
||||
export const getTableListApi = (params: any): Promise<IResponse> => {
|
||||
export const getTableListApi = (params: any) => {
|
||||
return request.get({ url: '/example/list', params })
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ export type {
|
|||
FormProps,
|
||||
PlaceholderModel,
|
||||
InputPasswordComponentProps,
|
||||
CheckboxButtonComponentProps
|
||||
TreeSelectComponentProps
|
||||
} from './src/types'
|
||||
|
||||
export interface FormExpose {
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<script lang="tsx">
|
||||
import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue'
|
||||
import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'
|
||||
import {
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElRow,
|
||||
ElCol,
|
||||
FormRules,
|
||||
ComponentSize
|
||||
// FormItemProp
|
||||
} from 'element-plus'
|
||||
import { componentMap } from './helper/componentMap'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
|
@ -47,7 +55,7 @@ export default defineComponent({
|
|||
isCol: propTypes.bool.def(true),
|
||||
// 表单数据对象
|
||||
model: {
|
||||
type: Object as PropType<Recordable>,
|
||||
type: Object as PropType<any>,
|
||||
default: () => ({})
|
||||
},
|
||||
// 是否自动设置placeholder
|
||||
|
@ -55,7 +63,30 @@ export default defineComponent({
|
|||
// 是否自定义内容
|
||||
isCustom: propTypes.bool.def(false),
|
||||
// 表单label宽度
|
||||
labelWidth: propTypes.oneOfType([String, Number]).def('auto')
|
||||
labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
|
||||
rules: {
|
||||
type: Object as PropType<FormRules>,
|
||||
default: () => ({})
|
||||
},
|
||||
labelPosition: propTypes.oneOf(['left', 'right', 'top']).def('right'),
|
||||
labelSuffix: propTypes.string.def(''),
|
||||
hideRequiredAsterisk: propTypes.bool.def(false),
|
||||
requireAsteriskPosition: propTypes.oneOf(['left', 'right']).def('left'),
|
||||
showMessage: propTypes.bool.def(true),
|
||||
inlineMessage: propTypes.bool.def(false),
|
||||
statusIcon: propTypes.bool.def(false),
|
||||
validateOnRuleChange: propTypes.bool.def(true),
|
||||
size: {
|
||||
type: String as PropType<ComponentSize>,
|
||||
default: 'small'
|
||||
},
|
||||
disabled: propTypes.bool.def(false),
|
||||
scrollToError: propTypes.bool.def(false),
|
||||
scrollToErrorOffset: propTypes.oneOfType([Boolean, Object]).def(undefined)
|
||||
// onValidate: {
|
||||
// type: Function as PropType<(prop: FormItemProp, isValid: boolean, message: string) => void>,
|
||||
// default: () => {}
|
||||
// }
|
||||
},
|
||||
emits: ['register'],
|
||||
setup(props, { slots, expose, emit }) {
|
||||
|
@ -93,6 +124,7 @@ export default defineComponent({
|
|||
|
||||
const setProps = (props: FormProps = {}) => {
|
||||
mergeProps.value = Object.assign(unref(mergeProps), props)
|
||||
// @ts-ignore
|
||||
outsideProps.value = props
|
||||
}
|
||||
|
||||
|
@ -336,7 +368,7 @@ export default defineComponent({
|
|||
delete props[key]
|
||||
}
|
||||
}
|
||||
return props
|
||||
return props as FormProps
|
||||
}
|
||||
|
||||
return () => (
|
||||
|
|
|
@ -17,8 +17,7 @@ import {
|
|||
DatePickerProps,
|
||||
FormItemProps as ElFormItemProps,
|
||||
FormProps as ElFormProps,
|
||||
TextareaProps,
|
||||
CheckboxButtonProps
|
||||
ISelectProps
|
||||
} from 'element-plus'
|
||||
import { IEditorConfig } from '@wangeditor/editor'
|
||||
import { CSSProperties } from 'vue'
|
||||
|
@ -121,55 +120,7 @@ export interface SelectOption {
|
|||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface SelectComponentProps {
|
||||
multiple?: boolean
|
||||
disabled?: boolean
|
||||
valueKey?: string
|
||||
size?: ComponentSize
|
||||
clearable?: boolean
|
||||
collapseTags?: boolean
|
||||
collapseTagsTooltip?: number
|
||||
multipleLimit?: number
|
||||
name?: string
|
||||
effect?: string
|
||||
autocomplete?: string
|
||||
placeholder?: string
|
||||
filterable?: boolean
|
||||
allowCreate?: boolean
|
||||
filterMethod?: (query: string, item: any) => boolean
|
||||
remote?: boolean
|
||||
remoteMethod?: (query: string) => void
|
||||
remoteShowSuffix?: boolean
|
||||
loading?: boolean
|
||||
loadingText?: string
|
||||
noMatchText?: string
|
||||
noDataText?: string
|
||||
popperClass?: string
|
||||
reserveKeyword?: boolean
|
||||
defaultFirstOption?: boolean
|
||||
popperAppendToBody?: boolean
|
||||
teleported?: boolean
|
||||
persistent?: boolean
|
||||
automaticDropdown?: boolean
|
||||
clearIcon?: string | JSX.Element | null
|
||||
fitInputWidth?: boolean
|
||||
suffixIcon?: string | JSX.Element | null
|
||||
tagType?: 'success' | 'info' | 'warning' | 'danger'
|
||||
validateEvent?: boolean
|
||||
placement?:
|
||||
| 'top'
|
||||
| 'top-start'
|
||||
| 'top-end'
|
||||
| 'bottom'
|
||||
| 'bottom-start'
|
||||
| 'bottom-end'
|
||||
| 'left'
|
||||
| 'left-start'
|
||||
| 'left-end'
|
||||
| 'right'
|
||||
| 'right-start'
|
||||
| 'right-end'
|
||||
maxCollapseTags?: number
|
||||
export interface SelectComponentProps extends Omit<Partial<ISelectProps>, 'options'> {
|
||||
/**
|
||||
* 数据源的字段别名
|
||||
*/
|
||||
|
@ -400,25 +351,6 @@ export interface CheckboxGroupComponentProps extends Partial<CheckboxGroupProps>
|
|||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface CheckboxButtonComponentProps extends Partial<CheckboxButtonProps> {
|
||||
options?: CheckboxOption[]
|
||||
/**
|
||||
* 数据源的字段别名
|
||||
*/
|
||||
props?: {
|
||||
label?: string
|
||||
value?: string
|
||||
disabled?: string
|
||||
}
|
||||
on?: {
|
||||
change?: (value: string | number | boolean) => void
|
||||
}
|
||||
slots?: {
|
||||
default?: (...args: any[]) => JSX.Element[] | null
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface DividerComponentProps extends Partial<DividerProps> {
|
||||
on?: {
|
||||
change?: (value: number) => void
|
||||
|
@ -573,6 +505,70 @@ export interface FormItemProps extends Partial<ElFormItemProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export interface TreeSelectComponentProps
|
||||
extends Omit<Partial<SelectComponentProps>, 'props' | 'on' | 'slots'> {
|
||||
data?: any[]
|
||||
emptyText?: string
|
||||
nodeKey?: string
|
||||
props?: {
|
||||
children?: string
|
||||
label?: string | ((...args: any[]) => string)
|
||||
disabled?: string | ((...args: any[]) => string)
|
||||
isLeaf?: string | ((...args: any[]) => string)
|
||||
class?: string | ((...args: any[]) => string)
|
||||
}
|
||||
renderAfterExpand?: boolean
|
||||
load?: (...args: any[]) => Promise<any>
|
||||
renderContent?: (...args: any[]) => JSX.Element | null
|
||||
highlightCurrent?: boolean
|
||||
defaultExpandAll?: boolean
|
||||
expandOnClickNode?: boolean
|
||||
checkOnClickNode?: boolean
|
||||
autoExpandParent?: boolean
|
||||
defaultExpandedKeys?: any[]
|
||||
showCheckbox?: boolean
|
||||
checkStrictly?: boolean
|
||||
defaultCheckedKeys?: any[]
|
||||
currentNodeKey?: string | number
|
||||
filterNodeMethod?: (...args: any[]) => boolean
|
||||
accordion?: boolean
|
||||
indent?: number
|
||||
icon?: string | ((...args: any[]) => JSX.Element | null)
|
||||
lazy?: boolean
|
||||
draggable?: boolean
|
||||
allowDrag?: (...args: any[]) => boolean
|
||||
allowDrop?: (...args: any[]) => boolean
|
||||
on?: {
|
||||
change?: (value: string | number | boolean | Object) => void
|
||||
visibleChange?: (visible: boolean) => void
|
||||
removeTag?: (tag: any) => void
|
||||
clear?: () => void
|
||||
blur?: (event: FocusEvent) => void
|
||||
focus?: (event: FocusEvent) => void
|
||||
nodeClick?: (...args: any[]) => void
|
||||
nodeContextMenu?: (...args: any[]) => void
|
||||
checkChange?: (...args: any[]) => void
|
||||
check?: (...args: any[]) => void
|
||||
currentChange?: (...args: any[]) => void
|
||||
nodeExpand?: (...args: any[]) => void
|
||||
nodeCollapse?: (...args: any[]) => void
|
||||
nodeDragStart?: (...args: any[]) => void
|
||||
nodeDragEnter?: (...args: any[]) => void
|
||||
nodeDragLeave?: (...args: any[]) => void
|
||||
nodeDragOver?: (...args: any[]) => void
|
||||
nodeDragEnd?: (...args: any[]) => void
|
||||
nodeDrop?: (...args: any[]) => void
|
||||
}
|
||||
slots?: {
|
||||
default?: (...args: any[]) => JSX.Element | null
|
||||
optionGroupDefault?: (item: SelectOption) => JSX.Element
|
||||
optionDefault?: (option: SelectOption) => JSX.Element | null
|
||||
prefix?: (...args: any[]) => JSX.Element | null
|
||||
empty?: (...args: any[]) => JSX.Element | null
|
||||
}
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
export interface FormSchema {
|
||||
/**
|
||||
* 唯一标识
|
||||
|
@ -610,7 +606,7 @@ export interface FormSchema {
|
|||
| DateTimePickerComponentProps
|
||||
| TimePickerComponentProps
|
||||
| InputPasswordComponentProps
|
||||
| CheckboxButtonComponentProps
|
||||
| TreeSelectComponentProps
|
||||
|
||||
/**
|
||||
* formItem组件属性,具体可以查看element-plus文档
|
||||
|
|
|
@ -112,6 +112,7 @@ const getProps = computed(() => {
|
|||
|
||||
const setProps = (props: SearchProps = {}) => {
|
||||
mergeProps.value = Object.assign(unref(mergeProps), props)
|
||||
// @ts-ignore
|
||||
outsideProps.value = props
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<script lang="tsx">
|
||||
import { ElTable, ElTableColumn, ElPagination } from 'element-plus'
|
||||
import { ElTable, ElTableColumn, ElPagination, ComponentSize, ElTooltipProps } from 'element-plus'
|
||||
import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { setIndex } from './helper'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
import type { TableProps, TableColumn, TableSlotDefault, Pagination, TableSetProps } from './types'
|
||||
import type { TableProps, TableColumn, Pagination, TableSetProps } from './types'
|
||||
import { set } from 'lodash-es'
|
||||
import { CSSProperties } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Table',
|
||||
|
@ -45,10 +45,137 @@ export default defineComponent({
|
|||
data: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
height: propTypes.oneOfType([Number, String]),
|
||||
maxHeight: propTypes.oneOfType([Number, String]),
|
||||
stripe: propTypes.bool.def(false),
|
||||
border: propTypes.bool.def(false),
|
||||
size: {
|
||||
type: String as PropType<ComponentSize>,
|
||||
validator: (v: ComponentSize) => ['medium', 'small', 'mini'].includes(v)
|
||||
},
|
||||
fit: propTypes.bool.def(true),
|
||||
showHeader: propTypes.bool.def(true),
|
||||
highlightCurrentRow: propTypes.bool.def(false),
|
||||
currentRowKey: propTypes.oneOfType([Number, String]),
|
||||
// row-class-name, 类型为 (row: Recordable, rowIndex: number) => string | string
|
||||
rowClassName: {
|
||||
type: [Function, String] as PropType<(row: Recordable, rowIndex: number) => string | string>,
|
||||
default: ''
|
||||
},
|
||||
rowStyle: {
|
||||
type: [Function, Object] as PropType<
|
||||
(row: Recordable, rowIndex: number) => Recordable | CSSProperties
|
||||
>,
|
||||
default: () => undefined
|
||||
},
|
||||
cellClassName: {
|
||||
type: [Function, String] as PropType<
|
||||
(row: Recordable, column: any, rowIndex: number) => string | string
|
||||
>,
|
||||
default: ''
|
||||
},
|
||||
cellStyle: {
|
||||
type: [Function, Object] as PropType<
|
||||
(row: Recordable, column: any, rowIndex: number) => Recordable | CSSProperties
|
||||
>,
|
||||
default: () => undefined
|
||||
},
|
||||
headerRowClassName: {
|
||||
type: [Function, String] as PropType<(row: Recordable, rowIndex: number) => string | string>,
|
||||
default: ''
|
||||
},
|
||||
headerRowStyle: {
|
||||
type: [Function, Object] as PropType<
|
||||
(row: Recordable, rowIndex: number) => Recordable | CSSProperties
|
||||
>,
|
||||
default: () => undefined
|
||||
},
|
||||
headerCellClassName: {
|
||||
type: [Function, String] as PropType<
|
||||
(row: Recordable, column: any, rowIndex: number) => string | string
|
||||
>,
|
||||
default: ''
|
||||
},
|
||||
headerCellStyle: {
|
||||
type: [Function, Object] as PropType<
|
||||
(row: Recordable, column: any, rowIndex: number) => Recordable | CSSProperties
|
||||
>,
|
||||
default: () => undefined
|
||||
},
|
||||
rowKey: {
|
||||
type: [Function, String] as PropType<(row: Recordable) => string | string>,
|
||||
default: () => 'id'
|
||||
},
|
||||
emptyText: propTypes.string.def('No Data'),
|
||||
defaultExpandAll: propTypes.bool.def(false),
|
||||
expandRowKeys: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => []
|
||||
},
|
||||
defaultSort: {
|
||||
type: Object as PropType<{ prop: string; order: string }>,
|
||||
default: () => ({})
|
||||
},
|
||||
tooltipEffect: {
|
||||
type: String as PropType<'dark' | 'light'>,
|
||||
default: 'dark'
|
||||
},
|
||||
tooltipOptions: {
|
||||
type: Object as PropType<
|
||||
Pick<
|
||||
ElTooltipProps,
|
||||
| 'effect'
|
||||
| 'enterable'
|
||||
| 'hideAfter'
|
||||
| 'offset'
|
||||
| 'placement'
|
||||
| 'popperClass'
|
||||
| 'popperOptions'
|
||||
| 'showAfter'
|
||||
| 'showArrow'
|
||||
>
|
||||
>,
|
||||
default: () => ({
|
||||
enterable: true,
|
||||
placement: 'top',
|
||||
showArrow: true,
|
||||
hideAfter: 200,
|
||||
popperOptions: { strategy: 'fixed' }
|
||||
})
|
||||
},
|
||||
showSummary: propTypes.bool.def(false),
|
||||
sumText: propTypes.string.def('Sum'),
|
||||
summaryMethod: {
|
||||
type: Function as PropType<(param: { columns: any[]; data: any[] }) => any[]>,
|
||||
default: () => undefined
|
||||
},
|
||||
spanMethod: {
|
||||
type: Function as PropType<
|
||||
(param: { row: any; column: any; rowIndex: number; columnIndex: number }) => any[]
|
||||
>,
|
||||
default: () => undefined
|
||||
},
|
||||
selectOnIndeterminate: propTypes.bool.def(true),
|
||||
indent: propTypes.number.def(16),
|
||||
lazy: propTypes.bool.def(false),
|
||||
load: {
|
||||
type: Function as PropType<(row: Recordable, treeNode: any, resolve: Function) => void>,
|
||||
default: () => undefined
|
||||
},
|
||||
treeProps: {
|
||||
type: Object as PropType<{ hasChildren: string; children: string; label: string }>,
|
||||
default: () => ({ hasChildren: 'hasChildren', children: 'children', label: 'label' })
|
||||
},
|
||||
tableLayout: {
|
||||
type: String as PropType<'auto' | 'fixed'>,
|
||||
default: 'fixed'
|
||||
},
|
||||
scrollbarAlwaysOn: propTypes.bool.def(false),
|
||||
flexible: propTypes.bool.def(false)
|
||||
},
|
||||
emits: ['update:pageSize', 'update:currentPage', 'register'],
|
||||
setup(props, { attrs, slots, emit, expose }) {
|
||||
setup(props, { attrs, emit, expose }) {
|
||||
const elTableRef = ref<ComponentRef<typeof ElTable>>()
|
||||
|
||||
// 注册
|
||||
|
@ -74,7 +201,7 @@ export default defineComponent({
|
|||
|
||||
const setProps = (props: TableProps = {}) => {
|
||||
mergeProps.value = Object.assign(unref(mergeProps), props)
|
||||
outsideProps.value = props
|
||||
outsideProps.value = { ...props } as any
|
||||
}
|
||||
|
||||
const setColumn = (columnProps: TableSetProps[], columnsChildren?: TableColumn[]) => {
|
||||
|
@ -186,6 +313,22 @@ export default defineComponent({
|
|||
return columnsChildren.map((v) => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (props?.slots?.header) {
|
||||
slots['header'] = (...args: any[]) => props.slots.header(args)
|
||||
}
|
||||
|
||||
return (
|
||||
<ElTableColumn
|
||||
showOverflowTooltip={showOverflowTooltip}
|
||||
|
@ -194,17 +337,7 @@ export default defineComponent({
|
|||
{...props}
|
||||
prop={v.field}
|
||||
>
|
||||
{{
|
||||
default: (data: TableSlotDefault) =>
|
||||
v.children && v.children.length
|
||||
? renderTableColumn(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`)
|
||||
}}
|
||||
{slots}
|
||||
</ElTableColumn>
|
||||
)
|
||||
})
|
||||
|
@ -241,6 +374,22 @@ export default defineComponent({
|
|||
} 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (props?.slots?.header) {
|
||||
slots['header'] = (...args: any[]) => props.slots.header(args)
|
||||
}
|
||||
|
||||
return (
|
||||
<ElTableColumn
|
||||
showOverflowTooltip={showOverflowTooltip}
|
||||
|
@ -249,17 +398,7 @@ export default defineComponent({
|
|||
{...props}
|
||||
prop={v.field}
|
||||
>
|
||||
{{
|
||||
default: (data: TableSlotDefault) =>
|
||||
v.children && v.children.length
|
||||
? renderTreeTableColumn(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`) || v.label
|
||||
}}
|
||||
{slots}
|
||||
</ElTableColumn>
|
||||
)
|
||||
}
|
||||
|
@ -270,16 +409,13 @@ export default defineComponent({
|
|||
return () => (
|
||||
<div v-loading={unref(getProps).loading}>
|
||||
<ElTable
|
||||
// @ts-ignore
|
||||
ref={elTableRef}
|
||||
data={unref(getProps).data}
|
||||
onSelection-change={selectionChange}
|
||||
{...unref(getBindValue)}
|
||||
>
|
||||
{{
|
||||
default: () => renderTableColumn(),
|
||||
// @ts-ignore
|
||||
append: () => getSlot(slots, 'append')
|
||||
default: () => renderTableColumn()
|
||||
}}
|
||||
</ElTable>
|
||||
{unref(getProps).pagination ? (
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { TableProps as ElTableProps } from 'element-plus'
|
||||
export interface TableColumn {
|
||||
field: string
|
||||
label?: string
|
||||
children?: TableColumn[]
|
||||
slots?: {
|
||||
defalut?: (...args: any[]) => JSX.Element | null
|
||||
default?: (...args: any[]) => JSX.Element | JSX.Element[] | null
|
||||
header?: (...args: any[]) => JSX.Element | null
|
||||
}
|
||||
index?: number | ((index: number) => number)
|
||||
|
@ -65,7 +66,7 @@ export interface TableSetProps {
|
|||
value: any
|
||||
}
|
||||
|
||||
export interface TableProps {
|
||||
export interface TableProps extends Omit<Partial<ElTableProps<any[]>>, 'data'> {
|
||||
pageSize?: number
|
||||
currentPage?: number
|
||||
// 是否多选
|
||||
|
@ -87,6 +88,4 @@ export interface TableProps {
|
|||
// 表头对齐方式
|
||||
headerAlign?: 'left' | 'center' | 'right'
|
||||
data?: Recordable
|
||||
expand?: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Table, TableExpose, TableProps, TableSetProps } from '@/components/Table'
|
||||
import { ElTable, ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { ref, reactive, watch, computed, unref, nextTick } from 'vue'
|
||||
import { ref, reactive, watch, computed, unref, nextTick, onMounted } from 'vue'
|
||||
import { get } from 'lodash-es'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
|
@ -13,17 +13,28 @@ interface TableResponse<T = any> {
|
|||
pageSize: number
|
||||
}
|
||||
|
||||
interface UseTableConfig<T = any> {
|
||||
getListApi: (option: any) => Promise<IResponse<TableResponse<T>>>
|
||||
delListApi?: (option: any) => Promise<IResponse>
|
||||
// 返回数据格式配置
|
||||
response: {
|
||||
list: string
|
||||
interface UseTableConfig {
|
||||
// 是否初始化请求一次
|
||||
immediate?: boolean
|
||||
// 获取数据字段映射
|
||||
props?: {
|
||||
list?: string
|
||||
total?: string
|
||||
}
|
||||
fetchDataApi: () => Promise<{
|
||||
list: any[]
|
||||
total: number
|
||||
}>
|
||||
// getListApi: (option: any) => Promise<IResponse<TableResponse<T>>>
|
||||
// delListApi?: (option: any) => Promise<IResponse>
|
||||
// 返回数据格式配置
|
||||
// response: {
|
||||
// list: string
|
||||
// total?: string
|
||||
// }
|
||||
// 默认传递的参数
|
||||
defaultParams?: Recordable
|
||||
props?: TableProps
|
||||
// defaultParams?: Recordable
|
||||
// props?: TableProps
|
||||
}
|
||||
|
||||
interface TableObject<T = any> {
|
||||
|
@ -36,8 +47,16 @@ interface TableObject<T = any> {
|
|||
currentRow: Nullable<T>
|
||||
}
|
||||
|
||||
export const useTable = <T = any>(config?: UseTableConfig<T>) => {
|
||||
const tableObject = reactive<TableObject<T>>({
|
||||
export const useTable = (config: UseTableConfig) => {
|
||||
const { immediate = true } = config
|
||||
|
||||
const loading = ref(false)
|
||||
const pageIndex = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
const dataList = ref<any[]>([])
|
||||
|
||||
const tableObject = reactive<TableObject>({
|
||||
// 页数
|
||||
pageSize: 10,
|
||||
// 当前页
|
||||
|
@ -48,7 +67,7 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
|
|||
list: [],
|
||||
// AxiosConfig 配置
|
||||
params: {
|
||||
...(config?.defaultParams || {})
|
||||
// ...(config?.defaultParams || {})
|
||||
},
|
||||
// 加载中
|
||||
loading: true,
|
||||
|
@ -64,25 +83,31 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
|
|||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => tableObject.currentPage,
|
||||
() => {
|
||||
// watch(
|
||||
// () => tableObject.currentPage,
|
||||
// () => {
|
||||
// methods.getList()
|
||||
// }
|
||||
// )
|
||||
|
||||
// watch(
|
||||
// () => tableObject.pageSize,
|
||||
// () => {
|
||||
// // 当前页不为1时,修改页数后会导致多次调用getList方法
|
||||
// if (tableObject.currentPage === 1) {
|
||||
// methods.getList()
|
||||
// } else {
|
||||
// tableObject.currentPage = 1
|
||||
// methods.getList()
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
onMounted(() => {
|
||||
if (immediate) {
|
||||
methods.getList()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => tableObject.pageSize,
|
||||
() => {
|
||||
// 当前页不为1时,修改页数后会导致多次调用getList方法
|
||||
if (tableObject.currentPage === 1) {
|
||||
methods.getList()
|
||||
} else {
|
||||
tableObject.currentPage = 1
|
||||
methods.getList()
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// Table实例
|
||||
const tableRef = ref<typeof Table & TableExpose>()
|
||||
|
@ -104,91 +129,108 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
|
|||
return table
|
||||
}
|
||||
|
||||
const delData = async (ids: string[] | number[]) => {
|
||||
const res = await (config?.delListApi && config?.delListApi(ids))
|
||||
if (res) {
|
||||
ElMessage.success(t('common.delSuccess'))
|
||||
// const delData = async (ids: string[] | number[]) => {
|
||||
// const res = await (config?.delListApi && config?.delListApi(ids))
|
||||
// if (res) {
|
||||
// ElMessage.success(t('common.delSuccess'))
|
||||
|
||||
// 计算出临界点
|
||||
const currentPage =
|
||||
tableObject.total % tableObject.pageSize === ids.length || tableObject.pageSize === 1
|
||||
? tableObject.currentPage > 1
|
||||
? tableObject.currentPage - 1
|
||||
: tableObject.currentPage
|
||||
: tableObject.currentPage
|
||||
// // 计算出临界点
|
||||
// const currentPage =
|
||||
// tableObject.total % tableObject.pageSize === ids.length || tableObject.pageSize === 1
|
||||
// ? tableObject.currentPage > 1
|
||||
// ? tableObject.currentPage - 1
|
||||
// : tableObject.currentPage
|
||||
// : tableObject.currentPage
|
||||
|
||||
tableObject.currentPage = currentPage
|
||||
methods.getList()
|
||||
}
|
||||
}
|
||||
// tableObject.currentPage = currentPage
|
||||
// methods.getList()
|
||||
// }
|
||||
// }
|
||||
|
||||
const methods = {
|
||||
getList: async () => {
|
||||
tableObject.loading = true
|
||||
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
|
||||
}
|
||||
},
|
||||
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()
|
||||
if (multiple) {
|
||||
if (!tableRef?.selections.length) {
|
||||
ElMessage.warning(t('common.delNoData'))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!tableObject.currentRow) {
|
||||
ElMessage.warning(t('common.delNoData'))
|
||||
return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await config?.fetchDataApi()
|
||||
console.log('fetchDataApi res', res)
|
||||
if (res) {
|
||||
dataList.value = res.list
|
||||
total.value = res.total
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('fetchDataApi error')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
if (message) {
|
||||
ElMessageBox.confirm(t('common.delMessage'), t('common.delWarning'), {
|
||||
confirmButtonText: t('common.delOk'),
|
||||
cancelButtonText: t('common.delCancel'),
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
await delData(ids)
|
||||
})
|
||||
} else {
|
||||
await delData(ids)
|
||||
}
|
||||
// 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
|
||||
// }
|
||||
}
|
||||
// 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()
|
||||
// if (multiple) {
|
||||
// if (!tableRef?.selections.length) {
|
||||
// ElMessage.warning(t('common.delNoData'))
|
||||
// return
|
||||
// }
|
||||
// } else {
|
||||
// if (!tableObject.currentRow) {
|
||||
// ElMessage.warning(t('common.delNoData'))
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// if (message) {
|
||||
// ElMessageBox.confirm(t('common.delMessage'), t('common.delWarning'), {
|
||||
// confirmButtonText: t('common.delOk'),
|
||||
// cancelButtonText: t('common.delCancel'),
|
||||
// type: 'warning'
|
||||
// }).then(async () => {
|
||||
// await delData(ids)
|
||||
// })
|
||||
// } else {
|
||||
// await delData(ids)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
config?.props && methods.setProps(config.props)
|
||||
|
||||
return {
|
||||
register,
|
||||
tableRegister: register,
|
||||
elTableRef,
|
||||
tableObject,
|
||||
methods
|
||||
methods,
|
||||
tableState: {
|
||||
pageIndex,
|
||||
pageSize,
|
||||
total,
|
||||
dataList,
|
||||
loading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,15 +176,15 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
|||
meta: {
|
||||
title: t('router.defaultTable')
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'use-table',
|
||||
component: () => import('@/views/Components/Table/UseTableDemo.vue'),
|
||||
name: 'UseTable',
|
||||
meta: {
|
||||
title: 'UseTable'
|
||||
}
|
||||
}
|
||||
// {
|
||||
// path: 'use-table',
|
||||
// component: () => import('@/views/Components/Table/UseTableDemo.vue'),
|
||||
// name: 'UseTable',
|
||||
// meta: {
|
||||
// title: 'UseTable'
|
||||
// }
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="tsx">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Table, TableColumn, TableSlotDefault } from '@/components/Table'
|
||||
|
@ -52,7 +52,16 @@ const columns: TableColumn[] = [
|
|||
},
|
||||
{
|
||||
field: 'action',
|
||||
label: t('tableDemo.action')
|
||||
label: t('tableDemo.action'),
|
||||
slots: {
|
||||
default: (data) => {
|
||||
return (
|
||||
<ElButton type="primary" onClick={() => actionFn(data)}>
|
||||
{t('tableDemo.action')}
|
||||
</ElButton>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -90,12 +99,6 @@ const actionFn = (data: TableSlotDefault) => {
|
|||
:data="tableDataList"
|
||||
:loading="loading"
|
||||
:defaultSort="{ prop: 'display_time', order: 'descending' }"
|
||||
>
|
||||
<template #action="data">
|
||||
<ElButton type="primary" @click="actionFn(data as TableSlotDefault)">
|
||||
{{ t('tableDemo.action') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
</Table>
|
||||
/>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
|
|
@ -1,41 +1,52 @@
|
|||
<script setup lang="ts">
|
||||
<script setup lang="tsx">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Table } from '@/components/Table'
|
||||
import { Table, Pagination, TableColumn, TableSlotDefault } 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'
|
||||
import { Pagination, TableColumn, TableSlotDefault } from '@/types/table'
|
||||
|
||||
const { register, tableObject, methods, elTableRef } = useTable<TableData>({
|
||||
getListApi: getTableListApi,
|
||||
response: {
|
||||
list: 'list',
|
||||
total: 'total'
|
||||
const { tableRegister, tableObject, methods, elTableRef, tableState } = useTable({
|
||||
fetchDataApi: async () => {
|
||||
const { pageIndex, pageSize } = tableState
|
||||
const res = await getTableListApi({
|
||||
pageIndex: unref(pageIndex),
|
||||
pageSize: unref(pageSize)
|
||||
})
|
||||
return {
|
||||
list: res.data.list,
|
||||
total: res.data.total
|
||||
}
|
||||
}
|
||||
// getListApi: getTableListApi,
|
||||
// response: {
|
||||
// list: 'list',
|
||||
// total: 'total'
|
||||
// }
|
||||
})
|
||||
const { loading, dataList, total, pageIndex, pageSize } = tableState
|
||||
|
||||
const { getList } = methods
|
||||
// const { getList } = methods
|
||||
|
||||
getList()
|
||||
// getList()
|
||||
|
||||
const {
|
||||
register: register2,
|
||||
tableObject: tableObject2,
|
||||
methods: methods2
|
||||
} = useTable<TableData>({
|
||||
getListApi: getTableListApi,
|
||||
response: {
|
||||
list: 'list',
|
||||
total: 'total'
|
||||
}
|
||||
})
|
||||
// const {
|
||||
// register: register2,
|
||||
// tableObject: tableObject2,
|
||||
// methods: methods2
|
||||
// } = useTable<TableData>({
|
||||
// getListApi: getTableListApi,
|
||||
// response: {
|
||||
// list: 'list',
|
||||
// total: 'total'
|
||||
// }
|
||||
// })
|
||||
|
||||
const { getList: getList2 } = methods2
|
||||
// const { getList: getList2 } = methods2
|
||||
|
||||
getList2()
|
||||
// getList2()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
@ -65,17 +76,14 @@ const columns = reactive<TableColumn[]>([
|
|||
field: 'importance',
|
||||
label: t('tableDemo.importance'),
|
||||
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{
|
||||
type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
|
||||
},
|
||||
() =>
|
||||
cellValue === 1
|
||||
return (
|
||||
<ElTag type={cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'}>
|
||||
{cellValue === 1
|
||||
? t('tableDemo.important')
|
||||
: cellValue === 2
|
||||
? t('tableDemo.good')
|
||||
: t('tableDemo.commonly')
|
||||
: t('tableDemo.commonly')}
|
||||
</ElTag>
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -87,7 +95,16 @@ const columns = reactive<TableColumn[]>([
|
|||
},
|
||||
{
|
||||
field: 'action',
|
||||
label: t('tableDemo.action')
|
||||
label: t('tableDemo.action'),
|
||||
slots: {
|
||||
default: (data) => {
|
||||
return (
|
||||
<ElButton type="primary" onClick={() => actionFn(data)}>
|
||||
{t('tableDemo.action')}
|
||||
</ElButton>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -171,20 +188,14 @@ const selectAllNone = () => {
|
|||
</ContentWrap>
|
||||
<ContentWrap :title="`UseTable ${t('tableDemo.example')}`">
|
||||
<Table
|
||||
v-model:pageSize="tableObject.pageSize"
|
||||
v-model:currentPage="tableObject.currentPage"
|
||||
v-model:pageSize="pageSize"
|
||||
v-model:currentPage="pageIndex"
|
||||
:columns="columns"
|
||||
:data="tableObject.tableList"
|
||||
:loading="tableObject.loading"
|
||||
:data="dataList"
|
||||
:loading="loading"
|
||||
:pagination="paginationObj"
|
||||
@register="register"
|
||||
@register="tableRegister"
|
||||
>
|
||||
<template #action="data">
|
||||
<ElButton type="primary" @click="actionFn(data as TableSlotDefault)">
|
||||
{{ t('tableDemo.action') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
|
||||
<template #expand="data">
|
||||
<div class="ml-30px">
|
||||
<div>{{ t('tableDemo.title') }}:{{ data.row.title }}</div>
|
||||
|
@ -195,7 +206,7 @@ const selectAllNone = () => {
|
|||
</Table>
|
||||
</ContentWrap>
|
||||
|
||||
<ContentWrap :title="`UseTable 2 ${t('tableDemo.example')}`">
|
||||
<!-- <ContentWrap :title="`UseTable 2 ${t('tableDemo.example')}`">
|
||||
<Table
|
||||
v-model:pageSize="tableObject2.pageSize"
|
||||
v-model:currentPage="tableObject2.currentPage"
|
||||
|
@ -219,5 +230,5 @@ const selectAllNone = () => {
|
|||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
</ContentWrap>
|
||||
</ContentWrap> -->
|
||||
</template>
|
||||
|
|
Loading…
Reference in New Issue