feat(table): add expandAll/collapseAll function close #333

This commit is contained in:
Vben 2021-03-21 21:51:50 +08:00
parent 6cda40f9b5
commit 399d2a0824
28 changed files with 289 additions and 274 deletions

View File

@ -3,6 +3,7 @@
### ✨ Features ### ✨ Features
- 路由新增 hideChildrenInMenu 配置。用于隐藏子菜单 - 路由新增 hideChildrenInMenu 配置。用于隐藏子菜单
- 树形表格内置展开/折叠全部函数
### ✨ Refactor ### ✨ Refactor

View File

@ -35,7 +35,7 @@
"@iconify/iconify": "^2.0.0-rc.6", "@iconify/iconify": "^2.0.0-rc.6",
"@vueuse/core": "^4.4.1", "@vueuse/core": "^4.4.1",
"@zxcvbn-ts/core": "^0.3.0", "@zxcvbn-ts/core": "^0.3.0",
"ant-design-vue": "2.0.1", "ant-design-vue": "2.1.0",
"apexcharts": "^3.26.0", "apexcharts": "^3.26.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",

View File

@ -1,15 +1,5 @@
<template> <template>
<div <div ref="wrapRef" :class="getWrapperClass">
ref="wrapRef"
:class="[
prefixCls,
$attrs.class,
{
[`${prefixCls}-form-container`]: getBindValues.useSearchForm,
[`${prefixCls}--inset`]: getBindValues.inset,
},
]"
>
<BasicForm <BasicForm
submitOnReset submitOnReset
v-bind="getFormProps" v-bind="getFormProps"
@ -32,9 +22,10 @@
v-show="getEmptyDataIsShowTable" v-show="getEmptyDataIsShowTable"
@change="handleTableChange" @change="handleTableChange"
> >
<template #[item]="data" v-for="item in Object.keys($slots)"> <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data"></slot> <slot :name="item" v-bind="data"></slot>
</template> </template>
<template #[`header-${column.dataIndex}`] v-for="column in columns" :key="column.dataIndex"> <template #[`header-${column.dataIndex}`] v-for="column in columns" :key="column.dataIndex">
<HeaderCell :column="column" /> <HeaderCell :column="column" />
</template> </template>
@ -47,8 +38,8 @@
import { defineComponent, ref, computed, unref } from 'vue'; import { defineComponent, ref, computed, unref } from 'vue';
import { Table } from 'ant-design-vue'; import { Table } from 'ant-design-vue';
import { BasicForm, useForm } from '/@/components/Form/index'; import { BasicForm, useForm } from '/@/components/Form/index';
import expandIcon from './components/ExpandIcon';
import { omit } from 'lodash-es'; import HeaderCell from './components/HeaderCell.vue';
import { usePagination } from './hooks/usePagination'; import { usePagination } from './hooks/usePagination';
import { useColumns } from './hooks/useColumns'; import { useColumns } from './hooks/useColumns';
@ -59,17 +50,16 @@
import { useCustomRow } from './hooks/useCustomRow'; import { useCustomRow } from './hooks/useCustomRow';
import { useTableStyle } from './hooks/useTableStyle'; import { useTableStyle } from './hooks/useTableStyle';
import { useTableHeader } from './hooks/useTableHeader'; import { useTableHeader } from './hooks/useTableHeader';
import { useTableExpand } from './hooks/useTableExpand';
import { createTableContext } from './hooks/useTableContext'; import { createTableContext } from './hooks/useTableContext';
import { useTableFooter } from './hooks/useTableFooter'; import { useTableFooter } from './hooks/useTableFooter';
import { useTableForm } from './hooks/useTableForm'; import { useTableForm } from './hooks/useTableForm';
import { useExpose } from '/@/hooks/core/useExpose'; import { useExpose } from '/@/hooks/core/useExpose';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { omit } from 'lodash-es';
import { basicProps } from './props'; import { basicProps } from './props';
import expandIcon from './components/ExpandIcon';
import HeaderCell from './components/HeaderCell.vue';
import './style/index.less';
export default defineComponent({ export default defineComponent({
components: { components: {
Table, Table,
@ -91,6 +81,7 @@
'edit-cancel', 'edit-cancel',
'edit-row-end', 'edit-row-end',
'edit-change', 'edit-change',
'expanded-rows-change',
], ],
setup(props, { attrs, emit, slots }) { setup(props, { attrs, emit, slots }) {
const tableElRef = ref<ComponentRef>(null); const tableElRef = ref<ComponentRef>(null);
@ -175,6 +166,8 @@
const { getRowClassName } = useTableStyle(getProps, prefixCls); const { getRowClassName } = useTableStyle(getProps, prefixCls);
const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);
const { getHeaderProps } = useTableHeader(getProps, slots); const { getHeaderProps } = useTableHeader(getProps, slots);
const { getFooterProps } = useTableFooter( const { getFooterProps } = useTableFooter(
@ -208,6 +201,7 @@
pagination: unref(getPaginationInfo), pagination: unref(getPaginationInfo),
dataSource: unref(getDataSourceRef), dataSource: unref(getDataSourceRef),
footer: unref(getFooterProps), footer: unref(getFooterProps),
...unref(getExpandOption),
}; };
if (slots.expandedRowRender) { if (slots.expandedRowRender) {
propsData = omit(propsData, 'scroll'); propsData = omit(propsData, 'scroll');
@ -218,6 +212,18 @@
return propsData; return propsData;
}); });
const getWrapperClass = computed(() => {
const values = unref(getBindValues);
return [
prefixCls,
attrs.class,
{
[`${prefixCls}-form-container`]: values.useSearchForm,
[`${prefixCls}--inset`]: values.inset,
},
];
});
const getEmptyDataIsShowTable = computed(() => { const getEmptyDataIsShowTable = computed(() => {
const { emptyDataIsShowTable, useSearchForm } = unref(getProps); const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
if (emptyDataIsShowTable || !useSearchForm) { if (emptyDataIsShowTable || !useSearchForm) {
@ -253,6 +259,8 @@
setShowPagination, setShowPagination,
getShowPagination, getShowPagination,
setCacheColumnsByField, setCacheColumnsByField,
expandAll,
collapseAll,
getSize: () => { getSize: () => {
return unref(getBindValues).size as SizeType; return unref(getBindValues).size as SizeType;
}, },
@ -278,9 +286,100 @@
getFormProps, getFormProps,
replaceFormSlotKey, replaceFormSlotKey,
getFormSlotKeys, getFormSlotKeys,
prefixCls, getWrapperClass,
columns: getViewColumns, columns: getViewColumns,
}; };
}, },
}); });
</script> </script>
<style lang="less">
@border-color: #cecece4d;
@prefix-cls: ~'@{namespace}-basic-table';
.@{prefix-cls} {
&-form-container {
padding: 16px;
.ant-form {
padding: 12px 10px 6px 10px;
margin-bottom: 16px;
background: #fff;
border-radius: 4px;
}
}
&-row__striped {
td {
background: #fafafa;
}
}
&--inset {
.ant-table-wrapper {
padding: 0;
}
}
.ant-tag {
margin-right: 0;
}
.ant-table-wrapper {
padding: 6px;
background: #fff;
border-radius: 2px;
.ant-table-title {
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;
}
.ant-table-tbody > tr.ant-table-row-selected td {
background: 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-body {
overflow-x: hidden !important;
overflow-y: scroll !important;
}
td {
padding: 12px 8px;
}
}
}
</style>

View File

@ -6,16 +6,15 @@
</span> </span>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, PropType } from 'vue'; import { defineComponent } from 'vue';
import { FormOutlined } from '@ant-design/icons-vue'; import { FormOutlined } from '@ant-design/icons-vue';
import { propTypes } from '/@/utils/propTypes';
export default defineComponent({ export default defineComponent({
name: 'EditTableHeaderIcon', name: 'EditTableHeaderIcon',
components: { FormOutlined }, components: { FormOutlined },
props: { props: {
title: { title: propTypes.string.def(''),
type: String as PropType<string>,
default: '',
},
}, },
}); });
</script> </script>

View File

@ -12,6 +12,7 @@
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue';
import BasicHelp from '/@/components/Basic/src/BasicHelp.vue'; import BasicHelp from '/@/components/Basic/src/BasicHelp.vue';
import EditTableHeaderCell from './EditTableHeaderIcon.vue'; import EditTableHeaderCell from './EditTableHeaderIcon.vue';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({ export default defineComponent({
name: 'TableHeaderCell', name: 'TableHeaderCell',
@ -27,17 +28,10 @@
}, },
setup(props) { setup(props) {
const { prefixCls } = useDesign('basic-table-header-cell'); const { prefixCls } = useDesign('basic-table-header-cell');
const getIsEdit = computed(() => {
return !!props.column?.edit;
});
const getTitle = computed(() => { const getIsEdit = computed(() => !!props.column?.edit);
return props.column?.customTitle; const getTitle = computed(() => props.column?.customTitle);
}); const getHelpMessage = computed(() => props.column?.helpMessage);
const getHelpMessage = computed(() => {
return props.column?.helpMessage;
});
return { prefixCls, getIsEdit, getTitle, getHelpMessage }; return { prefixCls, getIsEdit, getTitle, getHelpMessage };
}, },

View File

@ -19,17 +19,21 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, PropType, computed } from 'vue'; import { defineComponent, PropType, computed, toRaw } from 'vue';
import { MoreOutlined } from '@ant-design/icons-vue';
import Icon from '/@/components/Icon/index'; import Icon from '/@/components/Icon/index';
import { ActionItem, TableActionType } from '/@/components/Table'; import { ActionItem, TableActionType } from '/@/components/Table';
import { PopConfirmButton } from '/@/components/Button'; import { PopConfirmButton } from '/@/components/Button';
import { Divider } from 'ant-design-vue'; import { Divider } from 'ant-design-vue';
import { Dropdown } from '/@/components/Dropdown'; import { Dropdown } from '/@/components/Dropdown';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { MoreOutlined } from '@ant-design/icons-vue';
import { propTypes } from '/@/utils/propTypes';
import { useTableContext } from '../hooks/useTableContext'; import { useTableContext } from '../hooks/useTableContext';
import { propTypes } from '/@/utils/propTypes';
import { ACTION_COLUMN_FLAG } from '../const'; import { ACTION_COLUMN_FLAG } from '../const';
export default defineComponent({ export default defineComponent({
name: 'TableAction', name: 'TableAction',
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined }, components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined },
@ -52,26 +56,12 @@
table = useTableContext(); table = useTableContext();
} }
// const getSize = computed(() => {
// const size = table?.getSize?.();
// if (size === 'middle' || !size) {
// return;
// }
// if (size === 'default') {
// return 'large';
// }
// return size;
// });
const getActions = computed(() => { const getActions = computed(() => {
return (props.actions || []).map((action) => { return (toRaw(props.actions) || []).map((action) => {
const { popConfirm } = action; const { popConfirm } = action;
// const size = unref(getSize);
return { return {
type: 'link', type: 'link',
size: 'small', size: 'small',
// ...(size ? { size } : {}),
...action, ...action,
...(popConfirm || {}), ...(popConfirm || {}),
onConfirm: popConfirm?.confirm, onConfirm: popConfirm?.confirm,
@ -82,7 +72,7 @@
}); });
const getDropList = computed(() => { const getDropList = computed(() => {
return (props.dropDownActions || []).map((action, index) => { return (toRaw(props.dropDownActions) || []).map((action, index) => {
const { label } = action; const { label } = action;
return { return {
...action, ...action,

View File

@ -1,5 +1,6 @@
<template> <template>
<slot name="tableTitle" v-if="$slots.tableTitle"></slot> <slot name="tableTitle" v-if="$slots.tableTitle"></slot>
<TableTitle :helpMessage="titleHelpMessage" :title="title" v-if="!$slots.tableTitle && title" /> <TableTitle :helpMessage="titleHelpMessage" :title="title" v-if="!$slots.tableTitle && title" />
<div :class="`${prefixCls}__toolbar`"> <div :class="`${prefixCls}__toolbar`">
@ -11,19 +12,20 @@
<script lang="ts"> <script lang="ts">
import type { TableSetting } from '../types/table'; import type { TableSetting } from '../types/table';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { Divider } from 'ant-design-vue';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { Divider } from 'ant-design-vue';
import TableSettingComponent from './settings/index.vue';
import TableTitle from './TableTitle.vue';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import TableSettingComp from './settings/index.vue';
import TableTitle from './TableTitle.vue';
export default defineComponent({ export default defineComponent({
name: 'BasicTableHeader', name: 'BasicTableHeader',
components: { components: {
Divider, Divider,
TableTitle, TableTitle,
TableSetting: TableSettingComp, TableSetting: TableSettingComponent,
}, },
props: { props: {
title: { title: {

View File

@ -31,8 +31,8 @@
const getWrapStyle = computed( const getWrapStyle = computed(
(): CSSProperties => { (): CSSProperties => {
const { size } = props; const { size } = props;
const wh = `${size}px`; const s = `${size}px`;
return { height: wh, width: wh }; return { height: s, width: s };
} }
); );

View File

@ -83,18 +83,6 @@
return unref(ruleMessage) && unref(ruleVisible); return unref(ruleMessage) && unref(ruleVisible);
}); });
// const getSize = computed(() => {
// const size = table?.getSize?.();
// if (size === 'middle' || !size) {
// return;
// }
// if (size === 'default') {
// return 'large';
// }
// return size;
// });
const getIsCheckComp = computed(() => { const getIsCheckComp = computed(() => {
const component = unref(getComponent); const component = unref(getComponent);
return ['Checkbox', 'Switch'].includes(component); return ['Checkbox', 'Switch'].includes(component);

View File

@ -3,7 +3,6 @@
<template #title> <template #title>
<span>{{ t('component.table.settingColumn') }}</span> <span>{{ t('component.table.settingColumn') }}</span>
</template> </template>
<!-- :getPopupContainer="getPopupContainer" -->
<Popover <Popover
placement="bottomLeft" placement="bottomLeft"
trigger="click" trigger="click"

View File

@ -3,17 +3,18 @@
<template #title> <template #title>
<span>{{ t('component.table.settingFullScreen') }}</span> <span>{{ t('component.table.settingFullScreen') }}</span>
</template> </template>
<FullscreenOutlined @click="handleFullScreen" v-if="!isFullscreenRef" /> <FullscreenOutlined @click="toggleFullscreen" v-if="!isFullscreenRef" />
<FullscreenExitOutlined @click="handleFullScreen" v-else /> <FullscreenExitOutlined @click="toggleFullscreen" v-else />
</Tooltip> </Tooltip>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useTableContext } from '../../hooks/useTableContext';
import { Tooltip } from 'ant-design-vue'; import { Tooltip } from 'ant-design-vue';
import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons-vue'; import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons-vue';
import { useFullscreen } from '/@/hooks/web/useFullScreen'; import { useFullscreen } from '/@/hooks/web/useFullScreen';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { useTableContext } from '../../hooks/useTableContext';
export default defineComponent({ export default defineComponent({
name: 'FullScreenSetting', name: 'FullScreenSetting',
@ -26,15 +27,10 @@
setup() { setup() {
const table = useTableContext(); const table = useTableContext();
const { t } = useI18n(); const { t } = useI18n();
const { toggleFullscreen, isFullscreenRef } = useFullscreen(table.wrapRef); const { toggleFullscreen, isFullscreenRef } = useFullscreen(table.wrapRef);
function handleFullScreen() {
toggleFullscreen();
}
return { return {
handleFullScreen, toggleFullscreen,
isFullscreenRef, isFullscreenRef,
t, t,
}; };

View File

@ -8,10 +8,11 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useTableContext } from '../../hooks/useTableContext';
import { Tooltip } from 'ant-design-vue'; import { Tooltip } from 'ant-design-vue';
import { RedoOutlined } from '@ant-design/icons-vue'; import { RedoOutlined } from '@ant-design/icons-vue';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { useTableContext } from '../../hooks/useTableContext';
export default defineComponent({ export default defineComponent({
name: 'RedoSetting', name: 'RedoSetting',
@ -19,7 +20,6 @@
RedoOutlined, RedoOutlined,
Tooltip, Tooltip,
}, },
setup() { setup() {
const table = useTableContext(); const table = useTableContext();
const { t } = useI18n(); const { t } = useI18n();
@ -28,10 +28,7 @@
table.reload(); table.reload();
} }
return { return { redo, t };
redo,
t,
};
}, },
}); });
</script> </script>

View File

@ -23,14 +23,15 @@
</Tooltip> </Tooltip>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { SizeType } from '../../types/table';
import { defineComponent, ref } from 'vue'; import { defineComponent, ref } from 'vue';
import { useTableContext } from '../../hooks/useTableContext';
import { Tooltip, Dropdown, Menu } from 'ant-design-vue'; import { Tooltip, Dropdown, Menu } from 'ant-design-vue';
import { ColumnHeightOutlined } from '@ant-design/icons-vue'; import { ColumnHeightOutlined } from '@ant-design/icons-vue';
import { useI18n } from '/@/hooks/web/useI18n';
import { getPopupContainer } from '/@/utils';
import type { SizeType } from '../../types/table'; import { useI18n } from '/@/hooks/web/useI18n';
import { useTableContext } from '../../hooks/useTableContext';
import { getPopupContainer } from '/@/utils';
export default defineComponent({ export default defineComponent({
name: 'SizeSetting', name: 'SizeSetting',

View File

@ -7,13 +7,18 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, PropType, computed } from 'vue'; import type { PropType } from 'vue';
import type { TableSetting } from '../../types/table'; import type { TableSetting } from '../../types/table';
import { useI18n } from '/@/hooks/web/useI18n';
import { defineComponent, computed } from 'vue';
import ColumnSetting from './ColumnSetting.vue'; import ColumnSetting from './ColumnSetting.vue';
import SizeSetting from './SizeSetting.vue'; import SizeSetting from './SizeSetting.vue';
import RedoSetting from './RedoSetting.vue'; import RedoSetting from './RedoSetting.vue';
import FullScreenSetting from './FullScreenSetting.vue'; import FullScreenSetting from './FullScreenSetting.vue';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({ export default defineComponent({
name: 'TableSetting', name: 'TableSetting',
components: { components: {

View File

@ -6,22 +6,21 @@ const { pageSizeOptions, defaultPageSize, fetchSetting, defaultSortFn, defaultFi
export const ROW_KEY = 'key'; export const ROW_KEY = 'key';
// 可选的每页显示条数; // Optional display number per page;
export const PAGE_SIZE_OPTIONS = pageSizeOptions; export const PAGE_SIZE_OPTIONS = pageSizeOptions;
// 每页显示条数 // Number of items displayed per page
export const PAGE_SIZE = defaultPageSize; export const PAGE_SIZE = defaultPageSize;
// 通用接口字段设置 // Common interface field settings
export const FETCH_SETTING = fetchSetting; export const FETCH_SETTING = fetchSetting;
// 配置通用排序函数 // Configure general sort function
export const DEFAULT_SORT_FN = defaultSortFn; export const DEFAULT_SORT_FN = defaultSortFn;
export const DEFAULT_FILTER_FN = defaultFilterFn; export const DEFAULT_FILTER_FN = defaultFilterFn;
// 表格单元格默认布局 // Default layout of table cells
export const DEFAULT_ALIGN = 'center'; export const DEFAULT_ALIGN = 'center';
export const INDEX_COLUMN_FLAG = 'INDEX'; export const INDEX_COLUMN_FLAG = 'INDEX';
export const ACTION_COLUMN_FLAG = 'ACTION'; export const ACTION_COLUMN_FLAG = 'ACTION';

View File

@ -1,15 +1,18 @@
import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table'; import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
import type { PaginationProps } from '../types/pagination'; import type { PaginationProps } from '../types/pagination';
import { unref, ComputedRef, Ref, computed, watch, ref, toRaw } from 'vue'; import type { ComputedRef } from 'vue';
import { isBoolean, isArray, isString, isObject } from '/@/utils/is';
import { DEFAULT_ALIGN, PAGE_SIZE, INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG } from '../const'; import { unref, Ref, computed, watch, ref, toRaw } from 'vue';
import { useI18n } from '/@/hooks/web/useI18n';
import { isEqual, cloneDeep } from 'lodash-es';
import { isFunction } from '/@/utils/is';
import { formatToDate } from '/@/utils/dateUtil';
import { renderEditCell } from '../components/editable'; import { renderEditCell } from '../components/editable';
const { t } = useI18n(); import { useI18n } from '/@/hooks/web/useI18n';
import { isBoolean, isArray, isString, isObject, isFunction } from '/@/utils/is';
import { isEqual, cloneDeep } from 'lodash-es';
import { formatToDate } from '/@/utils/dateUtil';
import { DEFAULT_ALIGN, PAGE_SIZE, INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG } from '../const';
function handleItem(item: BasicColumn, ellipsis: boolean) { function handleItem(item: BasicColumn, ellipsis: boolean) {
const { key, dataIndex, children } = item; const { key, dataIndex, children } = item;
@ -43,6 +46,8 @@ function handleIndexColumn(
getPaginationRef: ComputedRef<boolean | PaginationProps>, getPaginationRef: ComputedRef<boolean | PaginationProps>,
columns: BasicColumn[] columns: BasicColumn[]
) { ) {
const { t } = useI18n();
const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef); const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef);
let pushIndexColumns = false; let pushIndexColumns = false;
@ -163,15 +168,6 @@ export function useColumns(
} }
); );
// watchEffect(() => {
// const columns = toRaw(unref(propsRef).columns);
// console.log('======================');
// console.log(111);
// console.log('======================');
// columnsRef.value = columns;
// cacheColumns = columns?.filter((item) => !item.flag) ?? [];
// });
function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) { function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
if (!dataIndex || !value) { if (!dataIndex || !value) {
return; return;

View File

@ -52,11 +52,6 @@ export function useDataSource(
}); });
const dataSourceRef = ref<Recordable[]>([]); const dataSourceRef = ref<Recordable[]>([]);
// watchEffect(() => {
// const { dataSource, api } = unref(propsRef);
// !api && dataSource && (dataSourceRef.value = dataSource);
// });
watchEffect(() => { watchEffect(() => {
tableData.value = unref(dataSourceRef); tableData.value = unref(dataSourceRef);
}); });

View File

@ -11,9 +11,7 @@ export function useLoading(props: ComputedRef<BasicTableProps>) {
} }
); );
const getLoading = computed(() => { const getLoading = computed(() => unref(loadingRef));
return unref(loadingRef);
});
function setLoading(loading: boolean) { function setLoading(loading: boolean) {
loadingRef.value = loading; loadingRef.value = loading;

View File

@ -25,11 +25,11 @@ function itemRender({ page, type, originalElement }: ItemRender) {
} }
export function usePagination(refProps: ComputedRef<BasicTableProps>) { export function usePagination(refProps: ComputedRef<BasicTableProps>) {
const configRef = ref<PaginationProps>({}); const { t } = useI18n();
const configRef = ref<PaginationProps>({});
const show = ref(true); const show = ref(true);
const { t } = useI18n();
const getPaginationInfo = computed((): PaginationProps | boolean => { const getPaginationInfo = computed((): PaginationProps | boolean => {
const { pagination } = unref(refProps); const { pagination } = unref(refProps);

View File

@ -1,12 +1,13 @@
import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table'; import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
import type { PaginationProps } from '../types/pagination'; import type { PaginationProps } from '../types/pagination';
import type { DynamicProps } from '/#/utils'; import type { DynamicProps } from '/#/utils';
import { getDynamicProps } from '/@/utils'; import type { FormActionType } from '/@/components/Form';
import type { WatchStopHandle } from 'vue';
import { getDynamicProps } from '/@/utils';
import { ref, onUnmounted, unref, watch, toRaw } from 'vue'; import { ref, onUnmounted, unref, watch, toRaw } from 'vue';
import { isProdMode } from '/@/utils/env'; import { isProdMode } from '/@/utils/env';
import { error } from '/@/utils/log'; import { error } from '/@/utils/log';
import type { FormActionType } from '/@/components/Form';
type Props = Partial<DynamicProps<BasicTableProps>>; type Props = Partial<DynamicProps<BasicTableProps>>;
@ -21,6 +22,8 @@ export function useTable(
const loadedRef = ref<Nullable<boolean>>(false); const loadedRef = ref<Nullable<boolean>>(false);
const formRef = ref<Nullable<UseTableMethod>>(null); const formRef = ref<Nullable<UseTableMethod>>(null);
let stopWatch: WatchStopHandle;
function register(instance: TableActionType, formInstance: UseTableMethod) { function register(instance: TableActionType, formInstance: UseTableMethod) {
isProdMode() && isProdMode() &&
onUnmounted(() => { onUnmounted(() => {
@ -28,15 +31,16 @@ export function useTable(
loadedRef.value = null; loadedRef.value = null;
}); });
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) { if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) return;
return;
}
tableRef.value = instance; tableRef.value = instance;
formRef.value = formInstance; formRef.value = formInstance;
tableProps && instance.setProps(getDynamicProps(tableProps)); tableProps && instance.setProps(getDynamicProps(tableProps));
loadedRef.value = true; loadedRef.value = true;
watch( stopWatch?.();
stopWatch = watch(
() => tableProps, () => tableProps,
() => { () => {
tableProps && instance.setProps(getDynamicProps(tableProps)); tableProps && instance.setProps(getDynamicProps(tableProps));
@ -128,6 +132,12 @@ export function useTable(
getShowPagination: () => { getShowPagination: () => {
return toRaw(getTableInstance().getShowPagination()); return toRaw(getTableInstance().getShowPagination());
}, },
expandAll: () => {
getTableInstance().expandAll();
},
collapseAll: () => {
getTableInstance().collapseAll();
},
}; };
return [register, methods]; return [register, methods];

View File

@ -0,0 +1,59 @@
import type { ComputedRef, Ref } from 'vue';
import type { BasicTableProps } from '../types/table';
import { computed, unref, ref, toRaw } from 'vue';
import { ROW_KEY } from '../const';
export function useTableExpand(
propsRef: ComputedRef<BasicTableProps>,
tableData: Ref<Recordable[]>,
emit: EmitType
) {
const expandedRowKeys = ref<string[]>([]);
const getAutoCreateKey = computed(() => {
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
});
const getRowKey = computed(() => {
const { rowKey } = unref(propsRef);
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
const getExpandOption = computed(() => {
const { isTreeTable } = unref(propsRef);
if (!isTreeTable) return {};
return {
expandedRowKeys: unref(expandedRowKeys),
onExpandedRowsChange: (keys: string[]) => {
expandedRowKeys.value = keys;
emit('expanded-rows-change', keys);
},
};
});
function expandAll() {
const keys = getAllKeys();
expandedRowKeys.value = keys;
}
function getAllKeys(data?: Recordable[]) {
const keys: string[] = [];
const { childrenColumnName } = unref(propsRef);
toRaw(data || unref(tableData)).forEach((item) => {
keys.push(item[unref(getRowKey) as string]);
const children = item[childrenColumnName || 'children'];
if (children?.length) {
keys.push(...getAllKeys(children));
}
});
return keys;
}
function collapseAll() {
expandedRowKeys.value = [];
}
return { getExpandOption, expandAll, collapseAll };
}

View File

@ -1,9 +1,11 @@
import type { ComputedRef, Slots } from 'vue'; import type { ComputedRef, Slots } from 'vue';
import type { BasicTableProps } from '../types/table'; import type { BasicTableProps } from '../types/table';
import { unref, computed, h } from 'vue'; import { unref, computed, h } from 'vue';
import { isString } from '/@/utils/is';
import TableHeader from '../components/TableHeader.vue'; import TableHeader from '../components/TableHeader.vue';
import { getSlot } from '../../../../utils/helper/tsxHelper';
import { isString } from '/@/utils/is';
import { getSlot } from '/@/utils/helper/tsxHelper';
export function useTableHeader(propsRef: ComputedRef<BasicTableProps>, slots: Slots) { export function useTableHeader(propsRef: ComputedRef<BasicTableProps>, slots: Slots) {
const getHeaderProps = computed( const getHeaderProps = computed(

View File

@ -1,5 +1,6 @@
import type { ComputedRef } from 'vue'; import type { ComputedRef } from 'vue';
import type { BasicTableProps, TableCustomRecord } from '../types/table'; import type { BasicTableProps, TableCustomRecord } from '../types/table';
import { unref } from 'vue'; import { unref } from 'vue';
import { isFunction } from '/@/utils/is'; import { isFunction } from '/@/utils/is';
export function useTableStyle(propsRef: ComputedRef<BasicTableProps>, prefixCls: string) { export function useTableStyle(propsRef: ComputedRef<BasicTableProps>, prefixCls: string) {

View File

@ -12,45 +12,32 @@ import type { FormProps } from '/@/components/Form';
import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING } from './const'; import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING } from './const';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
// 注释看 types/table
export const basicProps = { export const basicProps = {
clickToRowSelect: propTypes.bool.def(true), clickToRowSelect: propTypes.bool.def(true),
isTreeTable: propTypes.bool.def(false), isTreeTable: propTypes.bool.def(false),
tableSetting: propTypes.shape<TableSetting>({}),
tableSetting: {
type: Object as PropType<TableSetting>,
},
inset: propTypes.bool, inset: propTypes.bool,
sortFn: { sortFn: {
type: Function as PropType<(sortInfo: SorterResult) => any>, type: Function as PropType<(sortInfo: SorterResult) => any>,
default: DEFAULT_SORT_FN, default: DEFAULT_SORT_FN,
}, },
filterFn: { filterFn: {
type: Function as PropType<(data: Partial<Recordable<string[]>>) => any>, type: Function as PropType<(data: Partial<Recordable<string[]>>) => any>,
default: DEFAULT_FILTER_FN, default: DEFAULT_FILTER_FN,
}, },
showTableSetting: propTypes.bool, showTableSetting: propTypes.bool,
autoCreateKey: propTypes.bool.def(true), autoCreateKey: propTypes.bool.def(true),
striped: propTypes.bool.def(true), striped: propTypes.bool.def(true),
showSummary: propTypes.bool, showSummary: propTypes.bool,
summaryFunc: { summaryFunc: {
type: [Function, Array] as PropType<(...arg: any[]) => any[]>, type: [Function, Array] as PropType<(...arg: any[]) => any[]>,
default: null, default: null,
}, },
summaryData: { summaryData: {
type: Array as PropType<Recordable[]>, type: Array as PropType<Recordable[]>,
default: null, default: null,
}, },
indentSize: propTypes.number.def(24), indentSize: propTypes.number.def(24),
canColDrag: propTypes.bool.def(true), canColDrag: propTypes.bool.def(true),
api: { api: {
type: Function as PropType<(...arg: any[]) => Promise<any>>, type: Function as PropType<(...arg: any[]) => Promise<any>>,

View File

@ -1,107 +0,0 @@
@border-color: #cecece4d;
@prefix-cls: ~'@{namespace}-basic-table';
.@{prefix-cls} {
&-form-container {
padding: 16px;
.ant-form {
padding: 12px 10px 6px 10px;
margin-bottom: 16px;
background: #fff;
border-radius: 4px;
}
// .ant-table-wrapper {
// border-radius: 2px;
// }
}
&-row__striped {
td {
background: #fafafa;
}
}
&--inset {
.ant-table-wrapper {
padding: 0;
}
}
.ant-tag {
margin-right: 0;
}
.ant-table-wrapper {
padding: 6px;
background: #fff;
border-radius: 2px;
.ant-table-title {
padding: 0 0 8px 0 !important;
}
.ant-table.ant-table-bordered .ant-table-title {
border: none !important;
}
}
//
.ant-table {
width: 100%;
overflow-x: hidden;
// border: none;
&-title {
display: flex;
padding: 8px 6px;
border-bottom: none;
justify-content: space-between;
align-items: center;
}
// .ant-table-thead > tr > th,
// .ant-table-header {
// background: #f1f3f4;
// background-color: #f1f3f4 !important;
// }
.ant-table-tbody > tr.ant-table-row-selected td {
background: fade(@primary-color, 8%) !important;
}
}
// .ant-table-tbody > tr > td,
// .ant-table-tbody > tr > th,
// .ant-table-thead > tr > td,
// .ant-table-thead > tr > th {
// white-space: pre;
// }
.ant-pagination {
margin: 10px 0 0 0;
}
.ant-table-footer {
padding: 0;
.ant-table-wrapper {
padding: 0;
}
table {
border: none !important;
}
.ant-table-body {
overflow-x: hidden !important;
overflow-y: scroll !important;
}
td {
padding: 12px 8px;
}
}
}

View File

@ -87,6 +87,8 @@ export interface TableActionType {
reload: (opt?: FetchParams) => Promise<void>; reload: (opt?: FetchParams) => Promise<void>;
getSelectRows: <T = Recordable>() => T[]; getSelectRows: <T = Recordable>() => T[];
clearSelectedRowKeys: () => void; clearSelectedRowKeys: () => void;
expandAll: () => void;
collapseAll: () => void;
getSelectRowKeys: () => string[]; getSelectRowKeys: () => string[];
deleteSelectRowByKey: (key: string) => void; deleteSelectRowByKey: (key: string) => void;
setPagination: (info: Partial<PaginationProps>) => void; setPagination: (info: Partial<PaginationProps>) => void;
@ -208,7 +210,7 @@ export interface BasicTableProps<T = any> {
* @default 'children' * @default 'children'
* @type string | string[] * @type string | string[]
*/ */
childrenColumnName?: string | string[]; childrenColumnName?: string;
/** /**
* Override default table elements * Override default table elements

View File

@ -1,29 +1,31 @@
<template> <template>
<div class="p-4"> <div class="p-4">
<BasicTable <BasicTable @register="register">
:rowSelection="{ type: 'checkbox' }" <template #toolbar>
title="树形表格" <a-button type="primary" @click="expandAll">展开全部</a-button>
titleHelpMessage="树形组件不能和序列号列同时存在" <a-button type="primary" @click="collapseAll">折叠全部</a-button>
:columns="columns" </template>
:dataSource="data" </BasicTable>
rowKey="id"
:indentSize="20"
isTreeTable
/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { BasicTable } from '/@/components/Table'; import { BasicTable, useTable } from '/@/components/Table';
import { getBasicColumns, getTreeTableData } from './tableData'; import { getBasicColumns, getTreeTableData } from './tableData';
export default defineComponent({ export default defineComponent({
components: { BasicTable }, components: { BasicTable },
setup() { setup() {
return { const [register, { expandAll, collapseAll }] = useTable({
title: '树形表格',
isTreeTable: true,
rowSelection: { type: 'checkbox' },
titleHelpMessage: '树形组件不能和序列号列同时存在',
columns: getBasicColumns(), columns: getBasicColumns(),
data: getTreeTableData(), dataSource: getTreeTableData(),
}; rowKey: 'id',
});
return { register, expandAll, collapseAll };
}, },
}); });
</script> </script>

View File

@ -2180,10 +2180,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies: dependencies:
color-convert "^2.0.1" color-convert "^2.0.1"
ant-design-vue@2.0.1: ant-design-vue@2.1.0:
version "2.0.1" version "2.1.0"
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.0.1.tgz#3a5964523aac10fd2b16d84d651145cd2b65f1d5" resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.0.tgz#2489240f638f39874281e237544b857ebce52d18"
integrity sha512-CFIF+srTui4ZwdKPBXNoFA9/0fkSpypanQeOts0PAq1vEuMLxUoZHapDDn7wzsxZH3sYLF+mvMp8gYMRkaNn+w== integrity sha512-wzgwHRuwZrSvixccNlvas2gTWBkmfMrifbSsP+ga8VV6F0C6DdlimeFo+P99AxnVgpNVk8OUq9RVDQjb1UGk6g==
dependencies: dependencies:
"@ant-design-vue/use" "^0.0.1-0" "@ant-design-vue/use" "^0.0.1-0"
"@ant-design/icons-vue" "^6.0.0" "@ant-design/icons-vue" "^6.0.0"