CET-vue-3.0/src/components/Table/src/BasicTable.vue

557 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div ref="wrapRef" :class="getWrapperClass">
<BasicForm
submitOnReset
v-bind="getFormProps"
v-if="getBindValues.useSearchForm"
:tableAction="tableAction"
@register="registerForm"
@submit="handleSearchInfoChange"
@advanced-change="redoHeight"
>
<template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</BasicForm>
<!-- antd v3 升级兼容,阻止数据的收集,防止控制台报错 -->
<!-- https://antdv.com/docs/vue/migration-v3-cn -->
<a-form-item-rest>
<Table ref="tableElRef" v-bind="getBindValues" :rowClassName="getRowClassName" v-show="getEmptyDataIsShowTable" @resizeColumn="handleResizeColumn" @change="handleTableChange">
<!-- antd的原生插槽直接传递 -->
<template #[item]="data" v-for="item in slotNamesGroup.native" :key="item">
<slot :name="item" v-bind="data || {}"></slot>
</template>
<template #headerCell="{ column }">
<!-- update-begin--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题 -->
<CustomSelectHeader v-if="isCustomSelection(column)" v-bind="selectHeaderProps"/>
<HeaderCell v-else :column="column" />
<!-- update-end--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题 -->
</template>
<!-- 增加对antdv3.x兼容 -->
<template #bodyCell="data">
<!-- update-begin--author:liaozhiyang---date:220230717---for【issues-179】antd3 一些警告以及报错(针对表格) -->
<!-- update-begin--author:liusq---date:20230921---for【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
<template v-if="data.column?.slotsBak?.customRender">
<!-- update-end--author:liusq---date:20230921---for【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
<slot :name="data.column.slotsBak.customRender" v-bind="data || {}"></slot>
</template>
<template v-else>
<slot name="bodyCell" v-bind="data || {}"></slot>
</template>
<!-- update-begin--author:liaozhiyang---date:22030717---for【issues-179】antd3 一些警告以及报错(针对表格) -->
</template>
</Table>
</a-form-item-rest>
</div>
</template>
<script lang="ts">
import type { BasicTableProps, TableActionType, SizeType, ColumnChangeParam, BasicColumn } from './types/table';
import { defineComponent, ref, computed, unref, toRaw, inject, watchEffect, watch, onUnmounted, onMounted } from 'vue';
import { Table } from 'ant-design-vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { PageWrapperFixedHeightKey } from '/@/components/Page/injectionKey';
import CustomSelectHeader from './components/CustomSelectHeader.vue'
import expandIcon from './components/ExpandIcon';
import HeaderCell from './components/HeaderCell.vue';
import { InnerHandlers } from './types/table';
import { usePagination } from './hooks/usePagination';
import { useColumns } from './hooks/useColumns';
import { useDataSource } from './hooks/useDataSource';
import { useLoading } from './hooks/useLoading';
import { useRowSelection } from './hooks/useRowSelection';
import { useTableScroll } from './hooks/useTableScroll';
import { useCustomRow } from './hooks/useCustomRow';
import { useTableStyle } from './hooks/useTableStyle';
import { useTableHeader } from './hooks/useTableHeader';
import { useTableExpand } from './hooks/useTableExpand';
import { createTableContext } from './hooks/useTableContext';
import { useTableFooter } from './hooks/useTableFooter';
import { useTableForm } from './hooks/useTableForm';
import { useDesign } from '/@/hooks/web/useDesign';
import { useCustomSelection } from "./hooks/useCustomSelection";
import { omit } from 'lodash-es';
import { basicProps } from './props';
import { isFunction } from '/@/utils/is';
import { warn } from '/@/utils/log';
export default defineComponent({
components: {
Table,
BasicForm,
HeaderCell,
CustomSelectHeader,
},
props: basicProps,
emits: [
'fetch-success',
'fetch-error',
'selection-change',
'register',
'row-click',
'row-dbClick',
'row-contextmenu',
'row-mouseenter',
'row-mouseleave',
'edit-end',
'edit-cancel',
'edit-row-end',
'edit-change',
'expanded-rows-change',
'change',
'columns-change',
'table-redo',
],
setup(props, { attrs, emit, slots, expose }) {
const tableElRef = ref(null);
const tableData = ref<Recordable[]>([]);
const wrapRef = ref(null);
const innerPropsRef = ref<Partial<BasicTableProps>>();
const { prefixCls } = useDesign('basic-table');
const [registerForm, formActions] = useForm();
const getProps = computed(() => {
return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
});
const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
watchEffect(() => {
unref(isFixedHeightPage) &&
props.canResize &&
warn("'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)");
});
const { getLoading, setLoading } = useLoading(getProps);
const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } = usePagination(getProps);
// update-begin--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
// const { getRowSelection, getRowSelectionRef, getSelectRows, clearSelectedRowKeys, getSelectRowKeys, deleteSelectRowByKey, setSelectedRowKeys } =
// useRowSelection(getProps, tableData, emit);
// 子级列名
const childrenColumnName = computed(() => getProps.value.childrenColumnName || 'children');
// 自定义选择列
const {
getRowSelection,
getSelectRows,
getSelectRowKeys,
setSelectedRowKeys,
getRowSelectionRef,
selectHeaderProps,
isCustomSelection,
handleCustomSelectColumn,
clearSelectedRowKeys,
deleteSelectRowByKey,
getExpandIconColumnIndex,
} = useCustomSelection(
getProps,
emit,
wrapRef,
getPaginationInfo,
tableData,
childrenColumnName
)
// update-end--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
const {
handleTableChange: onTableChange,
getDataSourceRef,
getDataSource,
getRawDataSource,
setTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
fetch,
getRowKey,
reload,
getAutoCreateKey,
updateTableData,
} = useDataSource(
getProps,
{
tableData,
getPaginationInfo,
setLoading,
setPagination,
validate: formActions.validate,
clearSelectedRowKeys,
},
emit
);
function handleTableChange(...args) {
onTableChange.call(undefined, ...args);
emit('change', ...args);
// 解决通过useTable注册onChange时不起作用的问题
const { onChange } = unref(getProps);
onChange && isFunction(onChange) && onChange.call(undefined, ...args);
}
const { getViewColumns, getColumns, setCacheColumnsByField, setColumns, getColumnsRef, getCacheColumns } = useColumns(
getProps,
getPaginationInfo,
// update-begin--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
handleCustomSelectColumn,
// update-end--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
);
const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef, getColumnsRef, getRowSelectionRef, getDataSourceRef);
const { customRow } = useCustomRow(getProps, {
setSelectedRowKeys,
getSelectRowKeys,
clearSelectedRowKeys,
getAutoCreateKey,
emit,
});
const { getRowClassName } = useTableStyle(getProps, prefixCls);
const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);
const handlers: InnerHandlers = {
onColumnsChange: (data: ColumnChangeParam[]) => {
emit('columns-change', data);
// support useTable
unref(getProps).onColumnsChange?.(data);
},
};
const { getHeaderProps } = useTableHeader(getProps, slots, handlers);
const { getFooterProps } = useTableFooter(getProps, slots, getScrollRef, tableElRef, getDataSourceRef);
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } = useTableForm(getProps, slots, fetch, getLoading);
const getBindValues = computed(() => {
const dataSource = unref(getDataSourceRef);
let propsData: Recordable = {
// ...(dataSource.length === 0 ? { getPopupContainer: () => document.body } : {}),
...attrs,
customRow,
//树列表展开使用AntDesignVue默认的加减图标 author:scott date:20210914
//expandIcon: slots.expandIcon ? null : expandIcon(),
...unref(getProps),
...unref(getHeaderProps),
scroll: unref(getScrollRef),
loading: unref(getLoading),
tableLayout: 'fixed',
rowSelection: unref(getRowSelectionRef),
rowKey: unref(getRowKey),
columns: toRaw(unref(getViewColumns)),
pagination: toRaw(unref(getPaginationInfo)),
dataSource,
footer: unref(getFooterProps),
...unref(getExpandOption),
// 【QQYUN-5837】动态计算 expandIconColumnIndex
expandIconColumnIndex: getExpandIconColumnIndex.value,
};
//update-begin---author:wangshuai ---date:20230214 for[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
//额外的展开行存在插槽时会将滚动移除掉,注释掉
/*if (slots.expandedRowRender) {
propsData = omit(propsData, 'scroll');
}*/
//update-end---author:wangshuai ---date:20230214 for[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
// update-begin--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
// 自定义选择列,需要去掉原生的
delete propsData.rowSelection
// update-end--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
// update-begin--author:liaozhiyang---date:20230919---for【QQYUN-6387】展开写法去掉报错
!propsData.isTreeTable && delete propsData.expandIconColumnIndex;
propsData.expandedRowKeys === null && delete propsData.expandedRowKeys;
// update-end--author:liaozhiyang---date:20230919---for【QQYUN-6387】展开写法去掉报错
propsData = omit(propsData, ['class', 'onChange']);
return propsData;
});
// 统一设置表格列宽度
const getMaxColumnWidth = computed(() => {
const values = unref(getBindValues);
return values.maxColumnWidth > 0 ? values.maxColumnWidth + 'px' : null;
});
const getWrapperClass = computed(() => {
const values = unref(getBindValues);
return [
prefixCls,
attrs.class,
{
[`${prefixCls}-form-container`]: values.useSearchForm,
[`${prefixCls}--inset`]: values.inset,
[`${prefixCls}-col-max-width`]: getMaxColumnWidth.value != null,
// 是否显示表尾合计
[`${prefixCls}--show-summary`]: values.showSummary,
},
];
});
const getEmptyDataIsShowTable = computed(() => {
const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
if (emptyDataIsShowTable || !useSearchForm) {
return true;
}
return !!unref(getDataSourceRef).length;
});
function setProps(props: Partial<BasicTableProps>) {
innerPropsRef.value = { ...unref(innerPropsRef), ...props };
}
const tableAction: TableActionType = {
reload,
getSelectRows,
clearSelectedRowKeys,
getSelectRowKeys,
deleteSelectRowByKey,
setPagination,
setTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
redoHeight,
setSelectedRowKeys,
setColumns,
setLoading,
getDataSource,
getRawDataSource,
setProps,
getRowSelection,
getPaginationRef: getPagination,
getColumns,
getCacheColumns,
emit,
updateTableData,
setShowPagination,
getShowPagination,
setCacheColumnsByField,
expandAll,
collapseAll,
getSize: () => {
return unref(getBindValues).size as SizeType;
},
};
createTableContext({ ...tableAction, wrapRef, getBindValues });
// update-begin--author:sunjianlei---date:220230718---for【issues/179】兼容新老slots写法移除控制台警告
// 获取分组之后的slot名称
const slotNamesGroup = computed<{
// AntTable原生插槽
native: string[];
// 列自定义插槽
custom: string[];
}>(() => {
const native: string[] = [];
const custom: string[] = [];
const columns = unref<Recordable[]>(getViewColumns) as BasicColumn[];
const allCustomRender = columns.map<string>((column) => column.slotsBak?.customRender);
for (const name of Object.keys(slots)) {
// 过滤特殊的插槽
if (['bodyCell'].includes(name)) {
continue;
}
if (allCustomRender.includes(name)) {
custom.push(name);
} else {
native.push(name);
}
}
return { native, custom };
});
// update-end--author:sunjianlei---date:220230718---for【issues/179】兼容新老slots写法移除控制台警告
expose(tableAction);
emit('register', tableAction, formActions);
return {
tableElRef,
getBindValues,
getLoading,
registerForm,
handleSearchInfoChange,
getEmptyDataIsShowTable,
handleTableChange,
getRowClassName,
wrapRef,
tableAction,
redoHeight,
handleResizeColumn: (w, col) => {
col.width = w;
},
getFormProps: getFormProps as any,
replaceFormSlotKey,
getFormSlotKeys,
getWrapperClass,
getMaxColumnWidth,
columns: getViewColumns,
// update-begin--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
selectHeaderProps,
isCustomSelection,
// update-end--author:sunjianlei---date:220230630---for【QQYUN-5571】自封装选择列解决数据行选择卡顿问题
slotNamesGroup,
};
},
});
</script>
<style lang="less">
@border-color: #cecece4d;
@prefix-cls: ~'@{namespace}-basic-table';
[data-theme='dark'] {
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
.ant-table-tbody > tr.ant-table-row-selected td {
background-color: #262626;
}
.@{prefix-cls} {
//表格选择工具栏样式
.alert {
background-color: #323232;
border-color: #424242;
}
}
}
.@{prefix-cls} {
max-width: 100%;
&-row__striped {
td {
background-color: @app-content-background;
}
}
&-form-container {
padding: 10px;
.ant-form {
padding: 12px 10px 6px 10px;
margin-bottom: 8px;
background-color: @component-background;
border-radius: 2px;
}
}
.ant-tag {
margin-right: 0;
}
//update-begin-author:liusq---date:20230517--for: [issues/526]RangePicker 设置预设范围按钮样式问题---
.ant-picker-preset {
.ant-tag {
margin-right: 8px !important;
}
}
//update-end-author:liusq---date:20230517--for: [issues/526]RangePicker 设置预设范围按钮样式问题---
.ant-table-wrapper {
padding: 6px;
background-color: @component-background;
border-radius: 2px;
.ant-table-title {
min-height: 40px;
padding: 0 0 8px 0 !important;
}
.ant-table.ant-table-bordered .ant-table-title {
border: none !important;
}
}
.ant-table {
width: 100%;
overflow-x: hidden;
&-title {
display: flex;
padding: 8px 6px;
border-bottom: none;
justify-content: space-between;
align-items: center;
}
//定义行颜色
.trcolor {
background-color: rgba(255, 192, 203, 0.31);
color: red;
}
//.ant-table-tbody > tr.ant-table-row-selected td {
//background-color: fade(@primary-color, 8%) !important;
//}
}
.ant-pagination {
margin: 10px 0 0 0;
}
.ant-table-footer {
padding: 0;
.ant-table-wrapper {
padding: 0;
}
table {
border: none !important;
}
.ant-table-content {
overflow-x: hidden !important;
// overflow-y: scroll !important;
}
td {
padding: 12px 8px;
}
}
//表格选择工具栏样式
.alert {
height: 38px;
background-color: #e6f7ff;
border-color: #91d5ff;
}
&--inset {
.ant-table-wrapper {
padding: 0;
}
}
// ------ 统一设置表格列最大宽度 ------
&-col-max-width {
.ant-table-thead tr th,
.ant-table-tbody tr td {
max-width: v-bind(getMaxColumnWidth);
}
}
// ------ 统一设置表格列最大宽度 ------
// update-begin--author:sunjianlei---date:220230718---for【issues/622】修复表尾合计错位的问题
&--show-summary {
.ant-table > .ant-table-footer {
padding: 12px 0 0;
}
.ant-table.ant-table-bordered > .ant-table-footer {
border: 0;
}
}
// update-end--author:sunjianlei---date:220230718---for【issues/622】修复表尾合计错位的问题
}
</style>