mirror of
https://github.com/vbenjs/vben-admin-thin-next.git
synced 2025-01-23 09:40:22 +08:00
wip(table): perf table
This commit is contained in:
parent
a305e59124
commit
3549043f37
@ -12,10 +12,13 @@
|
||||
- form: 新增远程下拉`ApiSelect`及示例
|
||||
- form: 新增`autoFocusFirstItem`配置。用于配置是否聚焦表单第一个输入框
|
||||
- useForm: 支持动态改变参数。可以传入`Ref`类型与`Computed`类型进行动态更改
|
||||
- table: 新增`clickToRowSelect`属性。用于控制点击行是否选中勾选狂
|
||||
- table: 监听行点击事件
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
- 优化`modal`与`drawer`滚动条组件
|
||||
- table: 移除 `isTreeTable`属性
|
||||
|
||||
### 🎫 Chores
|
||||
|
||||
|
@ -225,6 +225,10 @@
|
||||
padding: 16px !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
> .scrollbar > .scrollbar__bar.is-horizontal {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
||||
if (el) {
|
||||
await nextTick();
|
||||
const icon = unref(getIconRef);
|
||||
|
||||
if (!icon) return;
|
||||
const svg = Iconify.renderSVG(icon, {});
|
||||
|
||||
if (svg) {
|
||||
@ -74,7 +74,7 @@
|
||||
}
|
||||
);
|
||||
|
||||
watch(() => props.icon, update, { flush: 'post' });
|
||||
// watch(() => props.icon, update, { flush: 'post' });
|
||||
|
||||
onMounted(update);
|
||||
|
||||
|
@ -40,6 +40,10 @@
|
||||
|
||||
.ant-modal-body {
|
||||
padding: 0;
|
||||
|
||||
> .scrollbar > .scrollbar__bar.is-horizontal {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-large {
|
||||
|
@ -11,7 +11,7 @@
|
||||
:submitOnReset="true"
|
||||
v-bind="getFormProps"
|
||||
v-if="getBindValues.useSearchForm"
|
||||
:submitButtonOptions="{ loading }"
|
||||
:submitButtonOptions="{ loading: getLoading }"
|
||||
:tableAction="tableAction"
|
||||
@register="registerForm"
|
||||
@submit="handleSearchInfoChange"
|
||||
@ -35,18 +35,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type {
|
||||
BasicTableProps,
|
||||
FetchParams,
|
||||
GetColumnsParams,
|
||||
TableActionType,
|
||||
SizeType,
|
||||
SorterResult,
|
||||
TableCustomRecord,
|
||||
} from './types/table';
|
||||
import type { BasicTableProps, TableActionType, SizeType, SorterResult } from './types/table';
|
||||
import { PaginationProps } from './types/pagination';
|
||||
|
||||
import { defineComponent, ref, computed, unref, watch, nextTick, toRaw } from 'vue';
|
||||
import { defineComponent, ref, computed, unref, watch, nextTick } from 'vue';
|
||||
import { Table } from 'ant-design-vue';
|
||||
import renderTitle from './components/renderTitle';
|
||||
import renderFooter from './components/renderFooter';
|
||||
@ -64,51 +56,64 @@
|
||||
import { useRowSelection } from './hooks/useRowSelection';
|
||||
import { useTableScroll } from './hooks/useTableScroll';
|
||||
import { provideTable } from './hooks/useProvinceTable';
|
||||
import { useCustomRow } from './hooks/useCustomRow';
|
||||
import { useTableStyle } from './hooks/useTableStyle';
|
||||
|
||||
import { useEventListener } from '/@/hooks/event/useEventListener';
|
||||
import { basicProps } from './props';
|
||||
import { ROW_KEY } from './const';
|
||||
import { useExpose } from '/@/hooks/core/useExpose';
|
||||
|
||||
import './style/index.less';
|
||||
export default defineComponent({
|
||||
props: basicProps,
|
||||
components: { Table, BasicForm },
|
||||
emits: ['fetch-success', 'fetch-error', 'selection-change', 'register'],
|
||||
emits: [
|
||||
'fetch-success',
|
||||
'fetch-error',
|
||||
'selection-change',
|
||||
'register',
|
||||
'row-click',
|
||||
'row-dbClick',
|
||||
'row-contextmenu',
|
||||
'row-mouseenter',
|
||||
'row-mouseleave',
|
||||
],
|
||||
setup(props, { attrs, emit, slots }) {
|
||||
const tableElRef = ref<ComponentRef>(null);
|
||||
|
||||
const wrapRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const innerPropsRef = ref<Partial<BasicTableProps>>();
|
||||
|
||||
const [registerForm, { getFieldsValue }] = useForm();
|
||||
|
||||
const getMergeProps = computed(() => {
|
||||
return {
|
||||
...props,
|
||||
...unref(innerPropsRef),
|
||||
} as BasicTableProps;
|
||||
const getProps = computed(() => {
|
||||
return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
|
||||
});
|
||||
|
||||
// const getProps = computed(
|
||||
// (): FormProps => {
|
||||
// return deepMerge(toRaw(props), unref(innerPropsRef));
|
||||
// }
|
||||
// );
|
||||
|
||||
const { loadingRef } = useLoading(getMergeProps);
|
||||
const { getPaginationRef, setPagination } = usePagination(getMergeProps);
|
||||
const { getColumnsRef, setColumns } = useColumns(getMergeProps, getPaginationRef);
|
||||
const { getDataSourceRef, setTableData, fetch, getAutoCreateKey } = useDataSource(
|
||||
getMergeProps,
|
||||
const { getLoading, setLoading } = useLoading(getProps);
|
||||
const { getPaginationInfo, getPagination, setPagination } = usePagination(getProps);
|
||||
const { getColumnsRef, getColumns, setColumns } = useColumns(getProps, getPaginationInfo);
|
||||
const {
|
||||
getDataSourceRef,
|
||||
getDataSource,
|
||||
setTableData,
|
||||
fetch,
|
||||
getRowKey,
|
||||
reload,
|
||||
getAutoCreateKey,
|
||||
} = useDataSource(
|
||||
getProps,
|
||||
{
|
||||
getPaginationRef,
|
||||
loadingRef,
|
||||
getPaginationInfo,
|
||||
setLoading,
|
||||
setPagination,
|
||||
getFieldsValue,
|
||||
},
|
||||
emit
|
||||
);
|
||||
|
||||
const { getScrollRef, redoHeight } = useTableScroll(getMergeProps, tableElRef);
|
||||
const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef);
|
||||
|
||||
const {
|
||||
getRowSelectionRef,
|
||||
getSelectRows,
|
||||
@ -116,55 +121,58 @@
|
||||
getSelectRowKeys,
|
||||
deleteSelectRowByKey,
|
||||
setSelectedRowKeys,
|
||||
} = useRowSelection(getMergeProps, emit);
|
||||
} = useRowSelection(getProps, emit);
|
||||
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey } = unref(getMergeProps);
|
||||
|
||||
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
|
||||
const { customRow } = useCustomRow(getProps, {
|
||||
setSelectedRowKeys,
|
||||
getSelectRowKeys,
|
||||
clearSelectedRowKeys,
|
||||
getAutoCreateKey,
|
||||
emit,
|
||||
});
|
||||
|
||||
const { getRowClassName } = useTableStyle(getProps);
|
||||
|
||||
const getTitleProps = computed(
|
||||
(): Recordable => {
|
||||
const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(getProps);
|
||||
const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting;
|
||||
if (hideTitle && !isString(title)) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
title: hideTitle
|
||||
? null
|
||||
: renderTitle.bind(
|
||||
null,
|
||||
title,
|
||||
titleHelpMessage,
|
||||
slots,
|
||||
showTableSetting,
|
||||
tableSetting
|
||||
),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const getBindValues = computed(() => {
|
||||
const { title, titleHelpMessage, showSummary, showTableSetting, tableSetting } = unref(
|
||||
getMergeProps
|
||||
);
|
||||
const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting;
|
||||
const titleData: Recordable =
|
||||
hideTitle && !isString(title)
|
||||
? {}
|
||||
: {
|
||||
title: hideTitle
|
||||
? null
|
||||
: renderTitle.bind(
|
||||
null,
|
||||
title,
|
||||
titleHelpMessage,
|
||||
slots,
|
||||
showTableSetting,
|
||||
tableSetting
|
||||
),
|
||||
};
|
||||
const pagination = unref(getPaginationRef);
|
||||
const rowSelection = unref(getRowSelectionRef);
|
||||
const scroll = unref(getScrollRef);
|
||||
const loading = unref(loadingRef);
|
||||
const rowKey = unref(getRowKey);
|
||||
const columns = unref(getColumnsRef);
|
||||
const dataSource = unref(getDataSourceRef);
|
||||
let propsData = {
|
||||
const { showSummary } = unref(getProps);
|
||||
|
||||
let propsData: Recordable = {
|
||||
size: 'middle',
|
||||
...(slots.expandedRowRender ? { expandIcon: renderExpandIcon() } : {}),
|
||||
...attrs,
|
||||
...unref(getMergeProps),
|
||||
...titleData,
|
||||
scroll,
|
||||
loading,
|
||||
customRow,
|
||||
...unref(getProps),
|
||||
...unref(getTitleProps),
|
||||
scroll: unref(getScrollRef),
|
||||
loading: unref(getLoading),
|
||||
tableLayout: 'fixed',
|
||||
rowSelection,
|
||||
rowKey,
|
||||
columns,
|
||||
pagination,
|
||||
dataSource,
|
||||
rowSelection: unref(getRowSelectionRef),
|
||||
rowKey: unref(getRowKey),
|
||||
columns: unref(getColumnsRef),
|
||||
pagination: unref(getPaginationInfo),
|
||||
dataSource: unref(getDataSourceRef),
|
||||
};
|
||||
if (slots.expandedRowRender) {
|
||||
propsData = omit(propsData, 'scroll');
|
||||
@ -173,7 +181,7 @@
|
||||
propsData.footer = renderFooter.bind(null, {
|
||||
scroll: scroll as any,
|
||||
columnsRef: getColumnsRef,
|
||||
summaryFunc: unref(getMergeProps).summaryFunc,
|
||||
summaryFunc: unref(getProps).summaryFunc,
|
||||
dataSourceRef: getDataSourceRef,
|
||||
rowSelectionRef: getRowSelectionRef,
|
||||
});
|
||||
@ -182,17 +190,17 @@
|
||||
});
|
||||
|
||||
const getFormProps = computed(() => {
|
||||
const { formConfig } = unref(getBindValues);
|
||||
const formProps: FormProps = {
|
||||
const { formConfig } = unref(getProps);
|
||||
const formProps: Partial<FormProps> = {
|
||||
showAdvancedButton: true,
|
||||
...(formConfig as FormProps),
|
||||
...formConfig,
|
||||
compact: true,
|
||||
};
|
||||
return formProps;
|
||||
});
|
||||
|
||||
const getEmptyDataIsShowTable = computed(() => {
|
||||
const { emptyDataIsShowTable, useSearchForm } = unref(getMergeProps);
|
||||
const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
|
||||
if (emptyDataIsShowTable || !useSearchForm) {
|
||||
return true;
|
||||
}
|
||||
@ -207,17 +215,8 @@
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function getRowClassName(record: TableCustomRecord, index: number) {
|
||||
const { striped, rowClassName } = unref(getMergeProps);
|
||||
if (!striped) return;
|
||||
if (rowClassName && isFunction(rowClassName)) {
|
||||
return rowClassName(record);
|
||||
}
|
||||
return (index || 0) % 2 === 1 ? 'basic-table-row__striped' : '';
|
||||
}
|
||||
|
||||
function handleSearchInfoChange(info: any) {
|
||||
const { handleSearchInfoFn } = unref(getMergeProps);
|
||||
const { handleSearchInfoFn } = unref(getProps);
|
||||
if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) {
|
||||
info = handleSearchInfoFn(info) || info;
|
||||
}
|
||||
@ -230,7 +229,7 @@
|
||||
filters: Partial<Recordable<string[]>>,
|
||||
sorter: SorterResult
|
||||
) {
|
||||
const { clearSelectOnPageChange, sortFn } = unref(getMergeProps);
|
||||
const { clearSelectOnPageChange, sortFn } = unref(getProps);
|
||||
if (clearSelectOnPageChange) {
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
@ -245,7 +244,7 @@
|
||||
}
|
||||
|
||||
function handleSummary() {
|
||||
if (unref(getMergeProps).showSummary) {
|
||||
if (unref(getProps).showSummary) {
|
||||
nextTick(() => {
|
||||
const tableEl = unref(tableElRef);
|
||||
if (!tableEl) return;
|
||||
@ -273,9 +272,7 @@
|
||||
}
|
||||
|
||||
const tableAction: TableActionType = {
|
||||
reload: async (opt?: FetchParams) => {
|
||||
await fetch(opt);
|
||||
},
|
||||
reload,
|
||||
getSelectRows,
|
||||
clearSelectedRowKeys,
|
||||
getSelectRowKeys,
|
||||
@ -285,27 +282,11 @@
|
||||
redoHeight,
|
||||
setSelectedRowKeys,
|
||||
setColumns,
|
||||
getPaginationRef: () => {
|
||||
return unref(getPaginationRef);
|
||||
},
|
||||
getColumns: (opt?: GetColumnsParams) => {
|
||||
const { ignoreIndex, ignoreAction } = opt || {};
|
||||
let columns = toRaw(unref(getColumnsRef));
|
||||
if (ignoreIndex) {
|
||||
columns = columns.filter((item) => item.flag !== 'INDEX');
|
||||
}
|
||||
if (ignoreAction) {
|
||||
columns = columns.filter((item) => item.flag !== 'ACTION');
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
getDataSource: () => {
|
||||
return unref(getDataSourceRef);
|
||||
},
|
||||
setLoading: (loading: boolean) => {
|
||||
loadingRef.value = loading;
|
||||
},
|
||||
setLoading,
|
||||
getDataSource,
|
||||
setProps,
|
||||
getPaginationRef: getPagination,
|
||||
getColumns,
|
||||
getSize: () => {
|
||||
return unref(getBindValues).size as SizeType;
|
||||
},
|
||||
@ -323,7 +304,7 @@
|
||||
return {
|
||||
tableElRef,
|
||||
getBindValues,
|
||||
loading: loadingRef,
|
||||
getLoading,
|
||||
registerForm,
|
||||
handleSearchInfoChange,
|
||||
getFormProps,
|
||||
|
@ -31,3 +31,9 @@ export function DEFAULT_SORT_FN(sortInfo: SorterResult) {
|
||||
order,
|
||||
};
|
||||
}
|
||||
|
||||
// 表格单元格默认布局
|
||||
export const DEFAULT_ALIGN = 'center';
|
||||
|
||||
export const INDEX_COLUMN_FLAG = 'INDEX';
|
||||
export const ACTION_COLUMN_FLAG = 'ACTION';
|
||||
|
@ -1,113 +1,133 @@
|
||||
import { BasicColumn, BasicTableProps } from '../types/table';
|
||||
import { BasicColumn, BasicTableProps, GetColumnsParams } from '../types/table';
|
||||
import { PaginationProps } from '../types/pagination';
|
||||
import { unref, ComputedRef, Ref, computed, watchEffect, ref, toRaw } from 'vue';
|
||||
import { isBoolean, isArray, isObject } from '/@/utils/is';
|
||||
import { PAGE_SIZE } from '../const';
|
||||
import { useProps } from './useProps';
|
||||
import { DEFAULT_ALIGN, PAGE_SIZE, INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG } from '../const';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
export function useColumns(
|
||||
refProps: ComputedRef<BasicTableProps>,
|
||||
getPaginationRef: ComputedRef<false | PaginationProps>
|
||||
|
||||
function handleItem(item: BasicColumn, ellipsis: boolean) {
|
||||
const { key, dataIndex, children } = item;
|
||||
item.align = item.align || DEFAULT_ALIGN;
|
||||
if (ellipsis) {
|
||||
if (!key) {
|
||||
item.key = dataIndex;
|
||||
}
|
||||
if (!isBoolean(item.ellipsis)) {
|
||||
Object.assign(item, {
|
||||
ellipsis,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (children && children.length) {
|
||||
handleChildren(children, !!ellipsis);
|
||||
}
|
||||
}
|
||||
|
||||
function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean) {
|
||||
if (!children) return;
|
||||
children.forEach((item) => {
|
||||
const { children } = item;
|
||||
handleItem(item, ellipsis);
|
||||
handleChildren(children, ellipsis);
|
||||
});
|
||||
}
|
||||
|
||||
function handleIndexColumn(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
getPaginationRef: ComputedRef<boolean | PaginationProps>,
|
||||
columns: BasicColumn[]
|
||||
) {
|
||||
const { showIndexColumn, indexColumnProps, ellipsis } = unref(propsRef);
|
||||
|
||||
let pushIndexColumns = false;
|
||||
columns.forEach((item) => {
|
||||
const { children } = item;
|
||||
handleItem(item, !!ellipsis);
|
||||
const isTreeTable = children && children.length;
|
||||
|
||||
const indIndex = columns.findIndex((column) => column.flag === INDEX_COLUMN_FLAG);
|
||||
|
||||
if (showIndexColumn && !isTreeTable) {
|
||||
pushIndexColumns = indIndex === -1;
|
||||
} else if (!showIndexColumn && !isTreeTable && indIndex !== -1) {
|
||||
columns.splice(indIndex, 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (!pushIndexColumns) return;
|
||||
|
||||
const isFixedLeft = columns.some((item) => item.fixed === 'left');
|
||||
|
||||
columns.unshift({
|
||||
flag: INDEX_COLUMN_FLAG,
|
||||
width: 50,
|
||||
title: t('component.table.index'),
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
const getPagination = unref(getPaginationRef);
|
||||
if (isBoolean(getPagination)) {
|
||||
return `${index + 1}`;
|
||||
}
|
||||
const { current = 1, pageSize = PAGE_SIZE } = getPagination;
|
||||
const currentIndex = (current - 1) * pageSize + index + 1;
|
||||
return currentIndex;
|
||||
},
|
||||
...(isFixedLeft
|
||||
? {
|
||||
fixed: 'left',
|
||||
}
|
||||
: {}),
|
||||
...indexColumnProps,
|
||||
});
|
||||
}
|
||||
|
||||
function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
|
||||
const { actionColumn } = unref(propsRef);
|
||||
if (!actionColumn) return;
|
||||
|
||||
const hasIndex = columns.findIndex((column) => column.flag === ACTION_COLUMN_FLAG);
|
||||
if (hasIndex === -1) {
|
||||
columns.push({
|
||||
...columns[hasIndex],
|
||||
fixed: 'right',
|
||||
...actionColumn,
|
||||
flag: ACTION_COLUMN_FLAG,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function useColumns(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
getPaginationRef: ComputedRef<boolean | PaginationProps>
|
||||
) {
|
||||
const { propsRef } = useProps(refProps);
|
||||
const columnsRef = (ref(unref(propsRef).columns) as unknown) as Ref<BasicColumn[]>;
|
||||
const cacheColumnsRef = (ref(unref(propsRef).columns) as unknown) as Ref<BasicColumn[]>;
|
||||
let cacheColumns = unref(propsRef).columns;
|
||||
|
||||
const getColumnsRef = computed(() => {
|
||||
const props = unref(propsRef);
|
||||
const { showIndexColumn, indexColumnProps, ellipsis, actionColumn, isTreeTable } = props;
|
||||
|
||||
const columns = unref(columnsRef);
|
||||
if (!columns) {
|
||||
return [];
|
||||
}
|
||||
let pushIndexColumns = false;
|
||||
columns.forEach((item) => {
|
||||
const { children } = item;
|
||||
handleItem(item, !!ellipsis);
|
||||
|
||||
handleChildren(children, !!ellipsis);
|
||||
handleIndexColumn(propsRef, getPaginationRef, columns);
|
||||
handleActionColumn(propsRef, columns);
|
||||
|
||||
const indIndex = columns.findIndex((column) => column.flag === 'INDEX');
|
||||
if (showIndexColumn && !isTreeTable) {
|
||||
pushIndexColumns = indIndex === -1;
|
||||
} else if (!showIndexColumn && !isTreeTable && indIndex !== -1) {
|
||||
columns.splice(indIndex, 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (pushIndexColumns) {
|
||||
const isFixedLeft = columns.some((item) => item.fixed === 'left');
|
||||
|
||||
columns.unshift({
|
||||
flag: 'INDEX',
|
||||
width: 50,
|
||||
title: t('component.table.index'),
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
const getPagination = unref(getPaginationRef);
|
||||
if (isBoolean(getPagination)) {
|
||||
return `${index + 1}`;
|
||||
}
|
||||
const { current = 1, pageSize = PAGE_SIZE } = getPagination;
|
||||
const currentIndex = (current - 1) * pageSize + index + 1;
|
||||
return currentIndex;
|
||||
},
|
||||
...(isFixedLeft
|
||||
? {
|
||||
fixed: 'left',
|
||||
}
|
||||
: {}),
|
||||
...indexColumnProps,
|
||||
});
|
||||
}
|
||||
if (actionColumn) {
|
||||
const hasIndex = columns.findIndex((column) => column.flag === 'ACTION');
|
||||
if (hasIndex === -1) {
|
||||
columns.push({
|
||||
...columns[hasIndex],
|
||||
fixed: 'right',
|
||||
...actionColumn,
|
||||
flag: 'ACTION',
|
||||
});
|
||||
}
|
||||
}
|
||||
return columns;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
const columns = toRaw(unref(propsRef).columns);
|
||||
columnsRef.value = columns;
|
||||
cacheColumnsRef.value = columns;
|
||||
cacheColumns = columns;
|
||||
});
|
||||
|
||||
function handleItem(item: BasicColumn, ellipsis: boolean) {
|
||||
const { key, dataIndex } = item;
|
||||
item.align = item.align || 'center';
|
||||
if (ellipsis) {
|
||||
if (!key) {
|
||||
item.key = dataIndex;
|
||||
}
|
||||
if (!isBoolean(item.ellipsis)) {
|
||||
Object.assign(item, {
|
||||
ellipsis,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean) {
|
||||
if (!children) return;
|
||||
children.forEach((item) => {
|
||||
const { children } = item;
|
||||
handleItem(item, ellipsis);
|
||||
handleChildren(children, ellipsis);
|
||||
});
|
||||
}
|
||||
|
||||
function setColumns(columns: BasicColumn[] | string[]) {
|
||||
/**
|
||||
* set columns
|
||||
* @param columns key|column
|
||||
*/
|
||||
function setColumns(columns: Partial<BasicColumn>[] | string[]) {
|
||||
if (!isArray(columns)) return;
|
||||
|
||||
if (columns.length <= 0) {
|
||||
@ -116,15 +136,30 @@ export function useColumns(
|
||||
}
|
||||
|
||||
const firstColumn = columns[0];
|
||||
|
||||
if (isObject(firstColumn)) {
|
||||
columnsRef.value = columns as any;
|
||||
columnsRef.value = columns as BasicColumn[];
|
||||
} else {
|
||||
const newColumns = unref(cacheColumnsRef).filter((item) =>
|
||||
(columns as string[]).includes(`${item.key}`! || item.dataIndex!)
|
||||
const newColumns = cacheColumns.filter(
|
||||
(item) =>
|
||||
(item.dataIndex || `${item.key}`) &&
|
||||
(columns as string[]).includes(`${item.key}`! || item.dataIndex!)
|
||||
);
|
||||
columnsRef.value = newColumns;
|
||||
}
|
||||
}
|
||||
|
||||
return { getColumnsRef, setColumns };
|
||||
function getColumns(opt?: GetColumnsParams) {
|
||||
const { ignoreIndex, ignoreAction } = opt || {};
|
||||
let columns = toRaw(unref(getColumnsRef));
|
||||
if (ignoreIndex) {
|
||||
columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG);
|
||||
}
|
||||
if (ignoreAction) {
|
||||
columns = columns.filter((item) => item.flag !== ACTION_COLUMN_FLAG);
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
return { getColumnsRef, getColumns, setColumns };
|
||||
}
|
||||
|
90
src/components/Table/src/hooks/useCustomRow.ts
Normal file
90
src/components/Table/src/hooks/useCustomRow.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import type { ComputedRef } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import { unref } from 'vue';
|
||||
import { ROW_KEY } from '../const';
|
||||
import { isString, isFunction } from '/@/utils/is';
|
||||
|
||||
interface Options {
|
||||
setSelectedRowKeys: (keys: string[]) => void;
|
||||
getSelectRowKeys: () => string[];
|
||||
clearSelectedRowKeys: () => void;
|
||||
emit: EmitType;
|
||||
getAutoCreateKey: ComputedRef<boolean | undefined>;
|
||||
}
|
||||
|
||||
function getKey(
|
||||
record: Recordable,
|
||||
rowKey: string | ((record: Record<string, any>) => string) | undefined,
|
||||
autoCreateKey?: boolean
|
||||
) {
|
||||
if (!rowKey || autoCreateKey) {
|
||||
return record[ROW_KEY];
|
||||
}
|
||||
if (isString(rowKey)) {
|
||||
return record[rowKey];
|
||||
}
|
||||
if (isFunction(rowKey)) {
|
||||
return record[rowKey(record)];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function useCustomRow(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
{ setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options
|
||||
) {
|
||||
const customRow = (record: Recordable, index: number) => {
|
||||
return {
|
||||
onClick: (e: Event) => {
|
||||
emit('row-click', record, index, e);
|
||||
e?.stopPropagation();
|
||||
const { rowSelection, rowKey, clickToRowSelect } = unref(propsRef);
|
||||
if (!rowSelection || !clickToRowSelect) return;
|
||||
const keys = getSelectRowKeys();
|
||||
const key = getKey(record, rowKey, unref(getAutoCreateKey));
|
||||
if (!key) return;
|
||||
|
||||
const isCheckbox = rowSelection.type === 'checkbox';
|
||||
|
||||
if (isCheckbox) {
|
||||
if (!keys.includes(key)) {
|
||||
setSelectedRowKeys([...keys, key]);
|
||||
return;
|
||||
}
|
||||
const keyIndex = keys.findIndex((item) => item === key);
|
||||
keys.splice(keyIndex, 1);
|
||||
setSelectedRowKeys(keys);
|
||||
return;
|
||||
}
|
||||
|
||||
const isRadio = rowSelection.type === 'radio';
|
||||
if (isRadio) {
|
||||
if (!keys.includes(key)) {
|
||||
if (keys.length) {
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
setSelectedRowKeys([key]);
|
||||
return;
|
||||
}
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
},
|
||||
onDblclick: (event: Event) => {
|
||||
emit('row-dbClick', record, index, event);
|
||||
},
|
||||
onContextmenu: (event: Event) => {
|
||||
emit('row-contextmenu', record, index, event);
|
||||
},
|
||||
onMouseenter: (event: Event) => {
|
||||
emit('row-mouseenter', record, index, event);
|
||||
},
|
||||
onMouseleave: (event: Event) => {
|
||||
emit('row-mouseleave', record, index, event);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
customRow,
|
||||
};
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import type { BasicTableProps, FetchParams } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
|
||||
import { watch, ref, unref, ComputedRef, computed, onMounted, Ref } from 'vue';
|
||||
import { ref, unref, ComputedRef, computed, onMounted, watchEffect } from 'vue';
|
||||
|
||||
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
|
||||
|
||||
@ -9,39 +9,28 @@ import { buildUUID } from '/@/utils/uuid';
|
||||
import { isFunction, isBoolean } from '/@/utils/is';
|
||||
import { get } from 'lodash-es';
|
||||
|
||||
import { useProps } from './useProps';
|
||||
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
|
||||
|
||||
import { FETCH_SETTING, ROW_KEY } from '../const';
|
||||
interface ActionType {
|
||||
getPaginationRef: ComputedRef<false | PaginationProps>;
|
||||
getPaginationInfo: ComputedRef<boolean | PaginationProps>;
|
||||
setPagination: (info: Partial<PaginationProps>) => void;
|
||||
loadingRef: Ref<boolean | undefined>;
|
||||
getFieldsValue: () => {
|
||||
[field: string]: any;
|
||||
};
|
||||
setLoading: (loading: boolean) => void;
|
||||
getFieldsValue: () => Recordable;
|
||||
}
|
||||
export function useDataSource(
|
||||
refProps: ComputedRef<BasicTableProps>,
|
||||
{ getPaginationRef, setPagination, loadingRef, getFieldsValue }: ActionType,
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
{ getPaginationInfo, setPagination, setLoading, getFieldsValue }: ActionType,
|
||||
emit: EmitType
|
||||
) {
|
||||
const { propsRef } = useProps(refProps);
|
||||
const dataSourceRef = ref<Recordable[]>([]);
|
||||
|
||||
const dataSourceRef = ref<any[]>([]);
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).dataSource,
|
||||
(data: any[]) => {
|
||||
const { api } = unref(propsRef);
|
||||
!api && (dataSourceRef.value = data);
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
watchEffect(() => {
|
||||
const { dataSource, api } = unref(propsRef);
|
||||
!api && dataSource && (dataSourceRef.value = dataSource);
|
||||
});
|
||||
|
||||
function setTableKey(items: any[]) {
|
||||
if (!items || !Array.isArray(items)) {
|
||||
return;
|
||||
}
|
||||
if (!items || !Array.isArray(items)) return;
|
||||
items.forEach((item) => {
|
||||
if (!item[ROW_KEY]) {
|
||||
item[ROW_KEY] = buildUUID();
|
||||
@ -51,10 +40,16 @@ export function useDataSource(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const getAutoCreateKey = computed(() => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
});
|
||||
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey } = unref(propsRef);
|
||||
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
|
||||
});
|
||||
|
||||
const getDataSourceRef = computed(() => {
|
||||
const dataSource = unref(dataSourceRef);
|
||||
if (!dataSource || dataSource.length === 0) {
|
||||
@ -86,20 +81,20 @@ export function useDataSource(
|
||||
);
|
||||
if (!api || !isFunction(api)) return;
|
||||
try {
|
||||
loadingRef.value = true;
|
||||
setLoading(true);
|
||||
const { pageField, sizeField, listField, totalField } = fetchSetting || FETCH_SETTING;
|
||||
let pageParams: any = {};
|
||||
|
||||
const { current, pageSize } = unref(getPaginationRef) as PaginationProps;
|
||||
|
||||
if (isBoolean(getPaginationRef)) {
|
||||
let pageParams: Recordable = {};
|
||||
|
||||
const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps;
|
||||
|
||||
if (isBoolean(getPaginationInfo)) {
|
||||
pageParams = {};
|
||||
} else {
|
||||
pageParams[pageField] = (opt && opt.page) || current;
|
||||
pageParams[sizeField] = pageSize;
|
||||
}
|
||||
|
||||
let params: any = {
|
||||
let params: Recordable = {
|
||||
...pageParams,
|
||||
...(useSearchForm ? getFieldsValue() : {}),
|
||||
...searchInfo,
|
||||
@ -112,18 +107,21 @@ export function useDataSource(
|
||||
}
|
||||
|
||||
const res = await api(params);
|
||||
let resultItems: any[] = get(res, listField);
|
||||
const resultTotal: number = get(res, totalField);
|
||||
|
||||
|
||||
const isArrayResult = Array.isArray(res);
|
||||
|
||||
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
|
||||
const resultTotal: number = isArrayResult ? 0 : get(res, totalField);
|
||||
|
||||
// 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
|
||||
var currentTotalPage = Math.ceil(resultTotal / pageSize);
|
||||
const currentTotalPage = Math.ceil(resultTotal / pageSize);
|
||||
if (current > currentTotalPage) {
|
||||
setPagination({
|
||||
current: currentTotalPage,
|
||||
});
|
||||
fetch(opt);
|
||||
setPagination({
|
||||
current: currentTotalPage,
|
||||
});
|
||||
fetch(opt);
|
||||
}
|
||||
|
||||
|
||||
if (afterFetch && isFunction(afterFetch)) {
|
||||
resultItems = afterFetch(resultItems) || resultItems;
|
||||
}
|
||||
@ -147,20 +145,35 @@ export function useDataSource(
|
||||
total: 0,
|
||||
});
|
||||
} finally {
|
||||
loadingRef.value = false;
|
||||
// setSearchFormLoading(false);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function setTableData(values: any[]) {
|
||||
function setTableData<T = Recordable>(values: T[]) {
|
||||
dataSourceRef.value = values;
|
||||
}
|
||||
|
||||
function getDataSource<T = Recordable>() {
|
||||
return getDataSourceRef.value as T[];
|
||||
}
|
||||
|
||||
async function reload(opt?: FetchParams) {
|
||||
await fetch(opt);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 转异步任务
|
||||
useTimeoutFn(() => {
|
||||
unref(propsRef).immediate && fetch();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
return { getDataSourceRef, setTableData, getAutoCreateKey, fetch: fetch };
|
||||
return {
|
||||
getDataSourceRef,
|
||||
getDataSource,
|
||||
getRowKey,
|
||||
setTableData,
|
||||
getAutoCreateKey,
|
||||
fetch,
|
||||
reload,
|
||||
};
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
import { watch, ref, ComputedRef, unref } from 'vue';
|
||||
import { BasicTableProps } from '../types/table';
|
||||
import { useProps } from './useProps';
|
||||
export function useLoading(refProps: ComputedRef<BasicTableProps>) {
|
||||
const { propsRef } = useProps(refProps);
|
||||
import { ref, ComputedRef, unref, computed, watchEffect } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
|
||||
const loadingRef = ref(unref(propsRef).loading);
|
||||
watch(
|
||||
() => unref(propsRef).loading,
|
||||
(v: boolean) => {
|
||||
loadingRef.value = v;
|
||||
}
|
||||
);
|
||||
return { loadingRef };
|
||||
export function useLoading(props: ComputedRef<BasicTableProps>) {
|
||||
const loadingRef = ref(unref(props).loading);
|
||||
|
||||
watchEffect(() => {
|
||||
loadingRef.value = unref(props).loading;
|
||||
});
|
||||
|
||||
const getLoading = computed(() => {
|
||||
return unref(loadingRef);
|
||||
});
|
||||
|
||||
function setLoading(loading: boolean) {
|
||||
loadingRef.value = loading;
|
||||
}
|
||||
|
||||
return { getLoading, setLoading };
|
||||
}
|
||||
|
@ -7,16 +7,30 @@ import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||
import { isBoolean } from '/@/utils/is';
|
||||
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '../const';
|
||||
import { useProps } from './useProps';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
interface ItemRender {
|
||||
page: number;
|
||||
type: 'page' | 'prev' | 'next';
|
||||
originalElement: any;
|
||||
}
|
||||
|
||||
function itemRender({ page, type, originalElement }: ItemRender) {
|
||||
if (type === 'prev') {
|
||||
return page === 0 ? null : <LeftOutlined />;
|
||||
} else if (type === 'next') {
|
||||
return page === 1 ? null : <RightOutlined />;
|
||||
}
|
||||
return originalElement;
|
||||
}
|
||||
|
||||
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||
const configRef = ref<PaginationProps>({});
|
||||
const { propsRef } = useProps(refProps);
|
||||
|
||||
const getPaginationRef = computed((): PaginationProps | false => {
|
||||
const { pagination } = unref(propsRef);
|
||||
const { t } = useI18n();
|
||||
const getPaginationInfo = computed((): PaginationProps | boolean => {
|
||||
const { pagination } = unref(refProps);
|
||||
|
||||
if (isBoolean(pagination) && !pagination) {
|
||||
return false;
|
||||
}
|
||||
@ -28,20 +42,7 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||
showTotal: (total) => t('component.table.total', { total }),
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: PAGE_SIZE_OPTIONS,
|
||||
itemRender: ({ page, type, originalElement }) => {
|
||||
if (type === 'prev') {
|
||||
if (page === 0) {
|
||||
return null;
|
||||
}
|
||||
return <LeftOutlined />;
|
||||
} else if (type === 'next') {
|
||||
if (page === 1) {
|
||||
return null;
|
||||
}
|
||||
return <RightOutlined />;
|
||||
}
|
||||
return originalElement;
|
||||
},
|
||||
itemRender: itemRender,
|
||||
showQuickJumper: true,
|
||||
...(isBoolean(pagination) ? {} : pagination),
|
||||
...unref(configRef),
|
||||
@ -49,10 +50,15 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||
});
|
||||
|
||||
function setPagination(info: Partial<PaginationProps>) {
|
||||
const paginationInfo = unref(getPaginationInfo);
|
||||
configRef.value = {
|
||||
...unref(getPaginationRef),
|
||||
...(!isBoolean(paginationInfo) ? paginationInfo : {}),
|
||||
...info,
|
||||
};
|
||||
}
|
||||
return { getPaginationRef, setPagination };
|
||||
|
||||
function getPagination() {
|
||||
return unref(getPaginationInfo);
|
||||
}
|
||||
return { getPagination, getPaginationInfo, setPagination };
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
import { Ref, ref, watch, unref } from 'vue';
|
||||
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @Date: 2020-05-12 13:20:37
|
||||
*/
|
||||
export function useProps(props: Readonly<Ref<BasicTableProps>>) {
|
||||
const propsRef = (ref<BasicTableProps>(unref(props)) as unknown) as Ref<BasicTableProps>;
|
||||
watch(
|
||||
() => props.value,
|
||||
(v) => {
|
||||
propsRef.value = unref(v);
|
||||
},
|
||||
{
|
||||
immediate: false,
|
||||
}
|
||||
);
|
||||
return { propsRef };
|
||||
}
|
@ -1,17 +1,14 @@
|
||||
import type { BasicTableProps, TableRowSelection } from '../types/table';
|
||||
|
||||
import { computed, ref, unref, ComputedRef } from 'vue';
|
||||
import { useProps } from './useProps';
|
||||
|
||||
/* eslint-disable */
|
||||
export function useRowSelection(refProps: ComputedRef<BasicTableProps>, emit: EmitType) {
|
||||
const { propsRef } = useProps(refProps);
|
||||
|
||||
export function useRowSelection(propsRef: ComputedRef<BasicTableProps>, emit: EmitType) {
|
||||
const selectedRowKeysRef = ref<string[]>([]);
|
||||
const selectedRowRef = ref<any[]>([]);
|
||||
const selectedRowRef = ref<Recordable[]>([]);
|
||||
|
||||
const getRowSelectionRef = computed((): TableRowSelection | null => {
|
||||
const rowSelection = unref(propsRef).rowSelection;
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (!rowSelection) {
|
||||
return null;
|
||||
}
|
||||
@ -46,11 +43,14 @@ export function useRowSelection(refProps: ComputedRef<BasicTableProps>, emit: Em
|
||||
unref(selectedRowKeysRef).splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectRowKeys() {
|
||||
return unref(selectedRowKeysRef);
|
||||
}
|
||||
function getSelectRows() {
|
||||
return unref(selectedRowRef);
|
||||
|
||||
function getSelectRows<T = Recordable>() {
|
||||
// const ret = toRaw(unref(selectedRowRef)).map((item) => toRaw(item));
|
||||
return unref(selectedRowRef) as T[];
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -14,10 +14,11 @@ export function useTable(
|
||||
const loadedRef = ref<Nullable<boolean>>(false);
|
||||
|
||||
function register(instance: TableActionType) {
|
||||
onUnmounted(() => {
|
||||
tableRef.value = null;
|
||||
loadedRef.value = null;
|
||||
});
|
||||
isProdMode() &&
|
||||
onUnmounted(() => {
|
||||
tableRef.value = null;
|
||||
loadedRef.value = null;
|
||||
});
|
||||
|
||||
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) {
|
||||
return;
|
||||
|
@ -1,57 +1,63 @@
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import { computed, Ref, onMounted, unref, ref, nextTick, ComputedRef, watch } from 'vue';
|
||||
import type { Ref, ComputedRef } from 'vue';
|
||||
import { computed, unref, ref, nextTick, watchEffect } from 'vue';
|
||||
|
||||
import { getViewportOffset } from '/@/utils/domUtils';
|
||||
import { isBoolean } from '/@/utils/is';
|
||||
|
||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
||||
import { useProps } from './useProps';
|
||||
import { useModalContext } from '/@/components/Modal';
|
||||
|
||||
export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRef: Ref<any>) {
|
||||
const { propsRef } = useProps(refProps);
|
||||
|
||||
const tableHeightRef: Ref<number | null> = ref(null);
|
||||
export function useTableScroll(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
tableElRef: Ref<ComponentRef>
|
||||
) {
|
||||
const tableHeightRef: Ref<Nullable<number>> = ref(null);
|
||||
|
||||
const modalFn = useModalContext();
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).canResize,
|
||||
() => {
|
||||
redoHeight();
|
||||
}
|
||||
);
|
||||
const getCanResize = computed(() => {
|
||||
const { canResize, scroll } = unref(propsRef);
|
||||
return canResize && !(scroll || {}).y;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
redoHeight();
|
||||
});
|
||||
|
||||
function redoHeight() {
|
||||
const { canResize } = unref(propsRef);
|
||||
|
||||
if (!canResize) return;
|
||||
calcTableHeight();
|
||||
if (unref(getCanResize)) {
|
||||
nextTick(() => {
|
||||
calcTableHeight();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// No need to repeat queries
|
||||
let paginationEl: HTMLElement | null;
|
||||
let footerEl: HTMLElement | null;
|
||||
|
||||
async function calcTableHeight() {
|
||||
const { canResize, resizeHeightOffset, pagination, maxHeight } = unref(propsRef);
|
||||
if (!canResize) return;
|
||||
const { resizeHeightOffset, pagination, maxHeight } = unref(propsRef);
|
||||
if (!unref(getCanResize)) return;
|
||||
|
||||
await nextTick();
|
||||
const table = unref(tableElRef) as any;
|
||||
const table = unref(tableElRef);
|
||||
if (!table) return;
|
||||
|
||||
const tableEl: Element = table.$el;
|
||||
if (!tableEl) return;
|
||||
|
||||
const headEl = tableEl.querySelector('.ant-table-thead ');
|
||||
if (!headEl) return;
|
||||
|
||||
// 表格距离底部高度
|
||||
// Table height from bottom
|
||||
const { bottomIncludeBody } = getViewportOffset(headEl);
|
||||
// 表格高度+距离底部高度-自定义偏移量
|
||||
// Table height from bottom height-custom offset
|
||||
|
||||
const paddingHeight = 32;
|
||||
const borderHeight = 2 * 2;
|
||||
// 分页器高度
|
||||
|
||||
// Pager height
|
||||
let paginationHeight = 2;
|
||||
if (!isBoolean(pagination)) {
|
||||
if (!paginationEl) {
|
||||
@ -61,7 +67,7 @@ export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRe
|
||||
const offsetHeight = paginationEl.offsetHeight;
|
||||
paginationHeight += offsetHeight || 0;
|
||||
} else {
|
||||
// TODO 先固定24
|
||||
// TODO First fix 24
|
||||
paginationHeight += 24;
|
||||
}
|
||||
}
|
||||
@ -75,11 +81,13 @@ export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRe
|
||||
footerHeight += offsetHeight || 0;
|
||||
}
|
||||
}
|
||||
|
||||
let headerHeight = 0;
|
||||
if (headEl) {
|
||||
headerHeight = (headEl as HTMLElement).offsetHeight;
|
||||
}
|
||||
tableHeightRef.value =
|
||||
|
||||
const height =
|
||||
bottomIncludeBody -
|
||||
(resizeHeightOffset || 0) -
|
||||
paddingHeight -
|
||||
@ -89,27 +97,14 @@ export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRe
|
||||
headerHeight;
|
||||
|
||||
setTimeout(() => {
|
||||
tableHeightRef.value =
|
||||
tableHeightRef.value! > maxHeight! ? (maxHeight as number) : tableHeightRef.value;
|
||||
// 解决表格放modal内的时候,modal自适应高度计算问题
|
||||
tableHeightRef.value = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
|
||||
// Solve the problem of modal adaptive height calculation when the form is placed in the modal
|
||||
modalFn?.redoModalHeight?.();
|
||||
}, 16);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
const getCanResize = computed(() => {
|
||||
const { canResize, scroll } = unref(propsRef);
|
||||
return canResize && !(scroll || {}).y;
|
||||
});
|
||||
|
||||
useWindowSizeFn(calcTableHeight, 100);
|
||||
|
||||
onMounted(() => {
|
||||
if (unref(getCanResize)) {
|
||||
nextTick(() => {
|
||||
calcTableHeight();
|
||||
});
|
||||
}
|
||||
});
|
||||
const getScrollRef = computed(() => {
|
||||
const tableHeight = unref(tableHeightRef);
|
||||
const { canResize, scroll } = unref(propsRef);
|
||||
@ -121,5 +116,6 @@ export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRe
|
||||
...scroll,
|
||||
};
|
||||
});
|
||||
|
||||
return { getScrollRef, redoHeight };
|
||||
}
|
||||
|
18
src/components/Table/src/hooks/useTableStyle.ts
Normal file
18
src/components/Table/src/hooks/useTableStyle.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import type { ComputedRef } from 'vue';
|
||||
import type { BasicTableProps, TableCustomRecord } from '../types/table';
|
||||
import { unref } from 'vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
export function useTableStyle(propsRef: ComputedRef<BasicTableProps>) {
|
||||
function getRowClassName(record: TableCustomRecord, index: number) {
|
||||
const { striped, rowClassName } = unref(propsRef);
|
||||
if (!striped) return;
|
||||
if (rowClassName && isFunction(rowClassName)) {
|
||||
return rowClassName(record);
|
||||
}
|
||||
return (index || 0) % 2 === 1 ? 'basic-table-row__striped' : '';
|
||||
}
|
||||
|
||||
return {
|
||||
getRowClassName,
|
||||
};
|
||||
}
|
@ -14,6 +14,7 @@ import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
// 注释看 types/table
|
||||
export const basicProps = {
|
||||
clickToRowSelect: propTypes.bool.def(true),
|
||||
tableSetting: {
|
||||
type: Object as PropType<TableSetting>,
|
||||
},
|
||||
@ -34,7 +35,6 @@ export const basicProps = {
|
||||
},
|
||||
|
||||
canColDrag: propTypes.bool.def(true),
|
||||
isTreeTable: propTypes.bool,
|
||||
api: {
|
||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||
default: null,
|
||||
|
@ -167,20 +167,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ant-radio {
|
||||
&-inner {
|
||||
border-color: @text-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-checkbox {
|
||||
&:not(.ant-checkbox-checked) {
|
||||
.ant-checkbox-inner {
|
||||
border-color: @text-color-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-bordered .ant-table-thead > tr:not(:last-child) > th,
|
||||
.ant-table-tbody > tr > td {
|
||||
word-break: break-word;
|
||||
|
@ -124,6 +124,8 @@ export interface TableSetting {
|
||||
}
|
||||
|
||||
export interface BasicTableProps<T = any> {
|
||||
// 点击行选中
|
||||
clickToRowSelect?: boolean;
|
||||
// 自定义排序方法
|
||||
sortFn?: (sortInfo: SorterResult) => any;
|
||||
// 取消表格的默认padding
|
||||
@ -141,8 +143,6 @@ export interface BasicTableProps<T = any> {
|
||||
showSummary?: boolean;
|
||||
// 是否可拖拽列
|
||||
canColDrag?: boolean;
|
||||
// 是否树表
|
||||
isTreeTable?: boolean;
|
||||
// 接口请求对象
|
||||
api?: (...arg: any) => Promise<any>;
|
||||
// 请求之前处理参数
|
||||
@ -158,7 +158,7 @@ export interface BasicTableProps<T = any> {
|
||||
// 在开起搜索表单的时候,如果没有数据是否显示表格
|
||||
emptyDataIsShowTable?: boolean;
|
||||
// 额外的请求参数
|
||||
searchInfo?: any;
|
||||
searchInfo?: Recordable;
|
||||
// 使用搜索表单
|
||||
useSearchForm?: boolean;
|
||||
// 表单配置
|
||||
@ -180,9 +180,9 @@ export interface BasicTableProps<T = any> {
|
||||
// 在分页改变的时候清空选项
|
||||
clearSelectOnPageChange?: boolean;
|
||||
//
|
||||
rowKey?: string | ((record: any) => string);
|
||||
rowKey?: string | ((record: Recordable) => string);
|
||||
// 数据
|
||||
dataSource?: any[];
|
||||
dataSource?: Recordable[];
|
||||
// 标题右侧提示
|
||||
titleHelpMessage?: string | string[];
|
||||
// 表格滚动最大高度
|
||||
|
@ -9,7 +9,8 @@
|
||||
:loading="loading"
|
||||
:striped="striped"
|
||||
:bordered="border"
|
||||
:pagination="{ pageSize: 20 }"
|
||||
showTableSetting
|
||||
:pagination="pagination"
|
||||
>
|
||||
<template #toolbar>
|
||||
<a-button type="primary" @click="toggleCanResize">
|
||||
@ -38,6 +39,7 @@
|
||||
const loading = ref(false);
|
||||
const striped = ref(true);
|
||||
const border = ref(true);
|
||||
const pagination = ref<any>(false);
|
||||
function toggleCanResize() {
|
||||
canResize.value = !canResize.value;
|
||||
}
|
||||
@ -48,6 +50,7 @@
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
pagination.value = { pageSize: 20 };
|
||||
}, 3000);
|
||||
}
|
||||
function toggleBorder() {
|
||||
@ -64,6 +67,7 @@
|
||||
toggleCanResize,
|
||||
toggleLoading,
|
||||
toggleBorder,
|
||||
pagination,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -74,10 +74,10 @@
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
});
|
||||
function handleDelete(record: any) {
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
}
|
||||
function handleOpen(record: any) {
|
||||
function handleOpen(record: Recordable) {
|
||||
console.log('点击了启用', record);
|
||||
}
|
||||
return {
|
||||
|
@ -2,7 +2,6 @@
|
||||
<div class="p-4">
|
||||
<BasicTable
|
||||
:rowSelection="{ type: 'checkbox' }"
|
||||
:isTreeTable="true"
|
||||
title="树形表格"
|
||||
titleHelpMessage="树形组件不能和序列号列同时存在"
|
||||
:columns="columns"
|
||||
|
@ -44,12 +44,13 @@
|
||||
clearSelectedRowKeys,
|
||||
},
|
||||
] = useTable({
|
||||
canResize: false,
|
||||
canResize: true,
|
||||
title: 'useTable示例',
|
||||
titleHelpMessage: '使用useTable调用表格内方法',
|
||||
api: demoListApi,
|
||||
columns: getBasicColumns(),
|
||||
rowKey: 'id',
|
||||
showTableSetting: true,
|
||||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
|
@ -5,13 +5,13 @@ export function getBasicColumns(): BasicColumn[] {
|
||||
return [
|
||||
{
|
||||
title: 'ID',
|
||||
width: 150,
|
||||
dataIndex: 'id',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
width: 120,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '地址',
|
||||
@ -20,14 +20,16 @@ export function getBasicColumns(): BasicColumn[] {
|
||||
{
|
||||
title: '编号',
|
||||
dataIndex: 'no',
|
||||
width: 80,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
width: 120,
|
||||
dataIndex: 'beginTime',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
width: 120,
|
||||
sorter: true,
|
||||
dataIndex: 'endTime',
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user