mirror of
https://github.com/vbenjs/gf-vben-admin.git
synced 2025-02-02 19:08:40 +08:00
feat(table): add expandAll/collapseAll function close #333
This commit is contained in:
parent
b2a1951fd0
commit
391da9ec28
@ -3,6 +3,7 @@
|
||||
### ✨ Features
|
||||
|
||||
- 路由新增 hideChildrenInMenu 配置。用于隐藏子菜单
|
||||
- 树形表格内置展开/折叠全部函数
|
||||
|
||||
### ✨ Refactor
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
"@iconify/iconify": "^2.0.0-rc.6",
|
||||
"@vueuse/core": "^4.4.1",
|
||||
"@zxcvbn-ts/core": "^0.3.0",
|
||||
"ant-design-vue": "2.0.1",
|
||||
"ant-design-vue": "2.1.0",
|
||||
"apexcharts": "^3.26.0",
|
||||
"axios": "^0.21.1",
|
||||
"crypto-js": "^4.0.0",
|
||||
|
@ -1,15 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
ref="wrapRef"
|
||||
:class="[
|
||||
prefixCls,
|
||||
$attrs.class,
|
||||
{
|
||||
[`${prefixCls}-form-container`]: getBindValues.useSearchForm,
|
||||
[`${prefixCls}--inset`]: getBindValues.inset,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div ref="wrapRef" :class="getWrapperClass">
|
||||
<BasicForm
|
||||
submitOnReset
|
||||
v-bind="getFormProps"
|
||||
@ -32,9 +22,10 @@
|
||||
v-show="getEmptyDataIsShowTable"
|
||||
@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>
|
||||
</template>
|
||||
|
||||
<template #[`header-${column.dataIndex}`] v-for="column in columns" :key="column.dataIndex">
|
||||
<HeaderCell :column="column" />
|
||||
</template>
|
||||
@ -47,8 +38,8 @@
|
||||
import { defineComponent, ref, computed, unref } from 'vue';
|
||||
import { Table } from 'ant-design-vue';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
|
||||
import { omit } from 'lodash-es';
|
||||
import expandIcon from './components/ExpandIcon';
|
||||
import HeaderCell from './components/HeaderCell.vue';
|
||||
|
||||
import { usePagination } from './hooks/usePagination';
|
||||
import { useColumns } from './hooks/useColumns';
|
||||
@ -59,17 +50,16 @@
|
||||
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 { useExpose } from '/@/hooks/core/useExpose';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { omit } from 'lodash-es';
|
||||
import { basicProps } from './props';
|
||||
import expandIcon from './components/ExpandIcon';
|
||||
import HeaderCell from './components/HeaderCell.vue';
|
||||
|
||||
import './style/index.less';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Table,
|
||||
@ -91,6 +81,7 @@
|
||||
'edit-cancel',
|
||||
'edit-row-end',
|
||||
'edit-change',
|
||||
'expanded-rows-change',
|
||||
],
|
||||
setup(props, { attrs, emit, slots }) {
|
||||
const tableElRef = ref<ComponentRef>(null);
|
||||
@ -175,6 +166,8 @@
|
||||
|
||||
const { getRowClassName } = useTableStyle(getProps, prefixCls);
|
||||
|
||||
const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);
|
||||
|
||||
const { getHeaderProps } = useTableHeader(getProps, slots);
|
||||
|
||||
const { getFooterProps } = useTableFooter(
|
||||
@ -208,6 +201,7 @@
|
||||
pagination: unref(getPaginationInfo),
|
||||
dataSource: unref(getDataSourceRef),
|
||||
footer: unref(getFooterProps),
|
||||
...unref(getExpandOption),
|
||||
};
|
||||
if (slots.expandedRowRender) {
|
||||
propsData = omit(propsData, 'scroll');
|
||||
@ -218,6 +212,18 @@
|
||||
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 { emptyDataIsShowTable, useSearchForm } = unref(getProps);
|
||||
if (emptyDataIsShowTable || !useSearchForm) {
|
||||
@ -253,6 +259,8 @@
|
||||
setShowPagination,
|
||||
getShowPagination,
|
||||
setCacheColumnsByField,
|
||||
expandAll,
|
||||
collapseAll,
|
||||
getSize: () => {
|
||||
return unref(getBindValues).size as SizeType;
|
||||
},
|
||||
@ -278,9 +286,100 @@
|
||||
getFormProps,
|
||||
replaceFormSlotKey,
|
||||
getFormSlotKeys,
|
||||
prefixCls,
|
||||
getWrapperClass,
|
||||
columns: getViewColumns,
|
||||
};
|
||||
},
|
||||
});
|
||||
</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>
|
||||
|
@ -6,16 +6,15 @@
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { FormOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
export default defineComponent({
|
||||
name: 'EditTableHeaderIcon',
|
||||
components: { FormOutlined },
|
||||
props: {
|
||||
title: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
title: propTypes.string.def(''),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -12,6 +12,7 @@
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import BasicHelp from '/@/components/Basic/src/BasicHelp.vue';
|
||||
import EditTableHeaderCell from './EditTableHeaderIcon.vue';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
export default defineComponent({
|
||||
name: 'TableHeaderCell',
|
||||
@ -27,17 +28,10 @@
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('basic-table-header-cell');
|
||||
const getIsEdit = computed(() => {
|
||||
return !!props.column?.edit;
|
||||
});
|
||||
|
||||
const getTitle = computed(() => {
|
||||
return props.column?.customTitle;
|
||||
});
|
||||
|
||||
const getHelpMessage = computed(() => {
|
||||
return props.column?.helpMessage;
|
||||
});
|
||||
const getIsEdit = computed(() => !!props.column?.edit);
|
||||
const getTitle = computed(() => props.column?.customTitle);
|
||||
const getHelpMessage = computed(() => props.column?.helpMessage);
|
||||
|
||||
return { prefixCls, getIsEdit, getTitle, getHelpMessage };
|
||||
},
|
||||
|
@ -19,17 +19,21 @@
|
||||
</div>
|
||||
</template>
|
||||
<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 { ActionItem, TableActionType } from '/@/components/Table';
|
||||
import { PopConfirmButton } from '/@/components/Button';
|
||||
import { Divider } from 'ant-design-vue';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { MoreOutlined } from '@ant-design/icons-vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useTableContext } from '../hooks/useTableContext';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { ACTION_COLUMN_FLAG } from '../const';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableAction',
|
||||
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined },
|
||||
@ -52,26 +56,12 @@
|
||||
table = useTableContext();
|
||||
}
|
||||
|
||||
// const getSize = computed(() => {
|
||||
// const size = table?.getSize?.();
|
||||
// if (size === 'middle' || !size) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (size === 'default') {
|
||||
// return 'large';
|
||||
// }
|
||||
// return size;
|
||||
// });
|
||||
|
||||
const getActions = computed(() => {
|
||||
return (props.actions || []).map((action) => {
|
||||
return (toRaw(props.actions) || []).map((action) => {
|
||||
const { popConfirm } = action;
|
||||
// const size = unref(getSize);
|
||||
return {
|
||||
type: 'link',
|
||||
size: 'small',
|
||||
// ...(size ? { size } : {}),
|
||||
...action,
|
||||
...(popConfirm || {}),
|
||||
onConfirm: popConfirm?.confirm,
|
||||
@ -82,7 +72,7 @@
|
||||
});
|
||||
|
||||
const getDropList = computed(() => {
|
||||
return (props.dropDownActions || []).map((action, index) => {
|
||||
return (toRaw(props.dropDownActions) || []).map((action, index) => {
|
||||
const { label } = action;
|
||||
return {
|
||||
...action,
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<slot name="tableTitle" v-if="$slots.tableTitle"></slot>
|
||||
|
||||
<TableTitle :helpMessage="titleHelpMessage" :title="title" v-if="!$slots.tableTitle && title" />
|
||||
|
||||
<div :class="`${prefixCls}__toolbar`">
|
||||
@ -11,19 +12,20 @@
|
||||
<script lang="ts">
|
||||
import type { TableSetting } from '../types/table';
|
||||
import type { PropType } from 'vue';
|
||||
import { Divider } from 'ant-design-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 TableSettingComp from './settings/index.vue';
|
||||
import TableTitle from './TableTitle.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicTableHeader',
|
||||
components: {
|
||||
Divider,
|
||||
TableTitle,
|
||||
TableSetting: TableSettingComp,
|
||||
TableSetting: TableSettingComponent,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
|
@ -31,8 +31,8 @@
|
||||
const getWrapStyle = computed(
|
||||
(): CSSProperties => {
|
||||
const { size } = props;
|
||||
const wh = `${size}px`;
|
||||
return { height: wh, width: wh };
|
||||
const s = `${size}px`;
|
||||
return { height: s, width: s };
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -83,18 +83,6 @@
|
||||
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 component = unref(getComponent);
|
||||
return ['Checkbox', 'Switch'].includes(component);
|
||||
|
@ -3,7 +3,6 @@
|
||||
<template #title>
|
||||
<span>{{ t('component.table.settingColumn') }}</span>
|
||||
</template>
|
||||
<!-- :getPopupContainer="getPopupContainer" -->
|
||||
<Popover
|
||||
placement="bottomLeft"
|
||||
trigger="click"
|
||||
|
@ -3,17 +3,18 @@
|
||||
<template #title>
|
||||
<span>{{ t('component.table.settingFullScreen') }}</span>
|
||||
</template>
|
||||
<FullscreenOutlined @click="handleFullScreen" v-if="!isFullscreenRef" />
|
||||
<FullscreenExitOutlined @click="handleFullScreen" v-else />
|
||||
<FullscreenOutlined @click="toggleFullscreen" v-if="!isFullscreenRef" />
|
||||
<FullscreenExitOutlined @click="toggleFullscreen" v-else />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { useFullscreen } from '/@/hooks/web/useFullScreen';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FullScreenSetting',
|
||||
@ -26,15 +27,10 @@
|
||||
setup() {
|
||||
const table = useTableContext();
|
||||
const { t } = useI18n();
|
||||
|
||||
const { toggleFullscreen, isFullscreenRef } = useFullscreen(table.wrapRef);
|
||||
|
||||
function handleFullScreen() {
|
||||
toggleFullscreen();
|
||||
}
|
||||
|
||||
return {
|
||||
handleFullScreen,
|
||||
toggleFullscreen,
|
||||
isFullscreenRef,
|
||||
t,
|
||||
};
|
||||
|
@ -8,10 +8,11 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { RedoOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RedoSetting',
|
||||
@ -19,7 +20,6 @@
|
||||
RedoOutlined,
|
||||
Tooltip,
|
||||
},
|
||||
|
||||
setup() {
|
||||
const table = useTableContext();
|
||||
const { t } = useI18n();
|
||||
@ -28,10 +28,7 @@
|
||||
table.reload();
|
||||
}
|
||||
|
||||
return {
|
||||
redo,
|
||||
t,
|
||||
};
|
||||
return { redo, t };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -23,14 +23,15 @@
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { SizeType } from '../../types/table';
|
||||
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import { Tooltip, Dropdown, Menu } from 'ant-design-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({
|
||||
name: 'SizeSetting',
|
||||
|
@ -7,13 +7,18 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
import type { PropType } from 'vue';
|
||||
import type { TableSetting } from '../../types/table';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
import { defineComponent, computed } from 'vue';
|
||||
|
||||
import ColumnSetting from './ColumnSetting.vue';
|
||||
import SizeSetting from './SizeSetting.vue';
|
||||
import RedoSetting from './RedoSetting.vue';
|
||||
import FullScreenSetting from './FullScreenSetting.vue';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableSetting',
|
||||
components: {
|
||||
|
@ -6,22 +6,21 @@ const { pageSizeOptions, defaultPageSize, fetchSetting, defaultSortFn, defaultFi
|
||||
|
||||
export const ROW_KEY = 'key';
|
||||
|
||||
// 可选的每页显示条数;
|
||||
// Optional display number per page;
|
||||
export const PAGE_SIZE_OPTIONS = pageSizeOptions;
|
||||
|
||||
// 每页显示条数
|
||||
// Number of items displayed per page
|
||||
export const PAGE_SIZE = defaultPageSize;
|
||||
|
||||
// 通用接口字段设置
|
||||
// Common interface field settings
|
||||
export const FETCH_SETTING = fetchSetting;
|
||||
|
||||
// 配置通用排序函数
|
||||
// Configure general sort function
|
||||
export const DEFAULT_SORT_FN = defaultSortFn;
|
||||
|
||||
export const DEFAULT_FILTER_FN = defaultFilterFn;
|
||||
|
||||
// 表格单元格默认布局
|
||||
// Default layout of table cells
|
||||
export const DEFAULT_ALIGN = 'center';
|
||||
|
||||
export const INDEX_COLUMN_FLAG = 'INDEX';
|
||||
export const ACTION_COLUMN_FLAG = 'ACTION';
|
||||
|
@ -1,15 +1,18 @@
|
||||
import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
import { unref, ComputedRef, Ref, computed, watch, ref, toRaw } from 'vue';
|
||||
import { isBoolean, isArray, isString, isObject } from '/@/utils/is';
|
||||
import { DEFAULT_ALIGN, PAGE_SIZE, INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG } from '../const';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { isEqual, cloneDeep } from 'lodash-es';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { formatToDate } from '/@/utils/dateUtil';
|
||||
import type { ComputedRef } from 'vue';
|
||||
|
||||
import { unref, Ref, computed, watch, ref, toRaw } from 'vue';
|
||||
|
||||
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) {
|
||||
const { key, dataIndex, children } = item;
|
||||
@ -43,6 +46,8 @@ function handleIndexColumn(
|
||||
getPaginationRef: ComputedRef<boolean | PaginationProps>,
|
||||
columns: BasicColumn[]
|
||||
) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef);
|
||||
|
||||
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>) {
|
||||
if (!dataIndex || !value) {
|
||||
return;
|
||||
|
@ -52,11 +52,6 @@ export function useDataSource(
|
||||
});
|
||||
const dataSourceRef = ref<Recordable[]>([]);
|
||||
|
||||
// watchEffect(() => {
|
||||
// const { dataSource, api } = unref(propsRef);
|
||||
// !api && dataSource && (dataSourceRef.value = dataSource);
|
||||
// });
|
||||
|
||||
watchEffect(() => {
|
||||
tableData.value = unref(dataSourceRef);
|
||||
});
|
||||
|
@ -11,9 +11,7 @@ export function useLoading(props: ComputedRef<BasicTableProps>) {
|
||||
}
|
||||
);
|
||||
|
||||
const getLoading = computed(() => {
|
||||
return unref(loadingRef);
|
||||
});
|
||||
const getLoading = computed(() => unref(loadingRef));
|
||||
|
||||
function setLoading(loading: boolean) {
|
||||
loadingRef.value = loading;
|
||||
|
@ -25,11 +25,11 @@ function itemRender({ page, type, originalElement }: ItemRender) {
|
||||
}
|
||||
|
||||
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||
const configRef = ref<PaginationProps>({});
|
||||
const { t } = useI18n();
|
||||
|
||||
const configRef = ref<PaginationProps>({});
|
||||
const show = ref(true);
|
||||
|
||||
const { t } = useI18n();
|
||||
const getPaginationInfo = computed((): PaginationProps | boolean => {
|
||||
const { pagination } = unref(refProps);
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
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 { isProdMode } from '/@/utils/env';
|
||||
import { error } from '/@/utils/log';
|
||||
import type { FormActionType } from '/@/components/Form';
|
||||
|
||||
type Props = Partial<DynamicProps<BasicTableProps>>;
|
||||
|
||||
@ -21,6 +22,8 @@ export function useTable(
|
||||
const loadedRef = ref<Nullable<boolean>>(false);
|
||||
const formRef = ref<Nullable<UseTableMethod>>(null);
|
||||
|
||||
let stopWatch: WatchStopHandle;
|
||||
|
||||
function register(instance: TableActionType, formInstance: UseTableMethod) {
|
||||
isProdMode() &&
|
||||
onUnmounted(() => {
|
||||
@ -28,15 +31,16 @@ export function useTable(
|
||||
loadedRef.value = null;
|
||||
});
|
||||
|
||||
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) {
|
||||
return;
|
||||
}
|
||||
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) return;
|
||||
|
||||
tableRef.value = instance;
|
||||
formRef.value = formInstance;
|
||||
tableProps && instance.setProps(getDynamicProps(tableProps));
|
||||
loadedRef.value = true;
|
||||
|
||||
watch(
|
||||
stopWatch?.();
|
||||
|
||||
stopWatch = watch(
|
||||
() => tableProps,
|
||||
() => {
|
||||
tableProps && instance.setProps(getDynamicProps(tableProps));
|
||||
@ -128,6 +132,12 @@ export function useTable(
|
||||
getShowPagination: () => {
|
||||
return toRaw(getTableInstance().getShowPagination());
|
||||
},
|
||||
expandAll: () => {
|
||||
getTableInstance().expandAll();
|
||||
},
|
||||
collapseAll: () => {
|
||||
getTableInstance().collapseAll();
|
||||
},
|
||||
};
|
||||
|
||||
return [register, methods];
|
||||
|
59
src/components/Table/src/hooks/useTableExpand.ts
Normal file
59
src/components/Table/src/hooks/useTableExpand.ts
Normal 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 };
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
import type { ComputedRef, Slots } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
|
||||
import { unref, computed, h } from 'vue';
|
||||
import { isString } from '/@/utils/is';
|
||||
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) {
|
||||
const getHeaderProps = computed(
|
||||
|
@ -1,5 +1,6 @@
|
||||
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>, prefixCls: string) {
|
||||
|
@ -12,45 +12,32 @@ import type { FormProps } from '/@/components/Form';
|
||||
import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING } from './const';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
// 注释看 types/table
|
||||
export const basicProps = {
|
||||
clickToRowSelect: propTypes.bool.def(true),
|
||||
|
||||
isTreeTable: propTypes.bool.def(false),
|
||||
|
||||
tableSetting: {
|
||||
type: Object as PropType<TableSetting>,
|
||||
},
|
||||
|
||||
tableSetting: propTypes.shape<TableSetting>({}),
|
||||
inset: propTypes.bool,
|
||||
|
||||
sortFn: {
|
||||
type: Function as PropType<(sortInfo: SorterResult) => any>,
|
||||
default: DEFAULT_SORT_FN,
|
||||
},
|
||||
|
||||
filterFn: {
|
||||
type: Function as PropType<(data: Partial<Recordable<string[]>>) => any>,
|
||||
default: DEFAULT_FILTER_FN,
|
||||
},
|
||||
|
||||
showTableSetting: propTypes.bool,
|
||||
autoCreateKey: propTypes.bool.def(true),
|
||||
striped: propTypes.bool.def(true),
|
||||
showSummary: propTypes.bool,
|
||||
|
||||
summaryFunc: {
|
||||
type: [Function, Array] as PropType<(...arg: any[]) => any[]>,
|
||||
default: null,
|
||||
},
|
||||
|
||||
summaryData: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
default: null,
|
||||
},
|
||||
|
||||
indentSize: propTypes.number.def(24),
|
||||
|
||||
canColDrag: propTypes.bool.def(true),
|
||||
api: {
|
||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -87,6 +87,8 @@ export interface TableActionType {
|
||||
reload: (opt?: FetchParams) => Promise<void>;
|
||||
getSelectRows: <T = Recordable>() => T[];
|
||||
clearSelectedRowKeys: () => void;
|
||||
expandAll: () => void;
|
||||
collapseAll: () => void;
|
||||
getSelectRowKeys: () => string[];
|
||||
deleteSelectRowByKey: (key: string) => void;
|
||||
setPagination: (info: Partial<PaginationProps>) => void;
|
||||
@ -208,7 +210,7 @@ export interface BasicTableProps<T = any> {
|
||||
* @default 'children'
|
||||
* @type string | string[]
|
||||
*/
|
||||
childrenColumnName?: string | string[];
|
||||
childrenColumnName?: string;
|
||||
|
||||
/**
|
||||
* Override default table elements
|
||||
|
@ -1,29 +1,31 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<BasicTable
|
||||
:rowSelection="{ type: 'checkbox' }"
|
||||
title="树形表格"
|
||||
titleHelpMessage="树形组件不能和序列号列同时存在"
|
||||
:columns="columns"
|
||||
:dataSource="data"
|
||||
rowKey="id"
|
||||
:indentSize="20"
|
||||
isTreeTable
|
||||
/>
|
||||
<BasicTable @register="register">
|
||||
<template #toolbar>
|
||||
<a-button type="primary" @click="expandAll">展开全部</a-button>
|
||||
<a-button type="primary" @click="collapseAll">折叠全部</a-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicTable } from '/@/components/Table';
|
||||
import { BasicTable, useTable } from '/@/components/Table';
|
||||
import { getBasicColumns, getTreeTableData } from './tableData';
|
||||
|
||||
export default defineComponent({
|
||||
components: { BasicTable },
|
||||
setup() {
|
||||
return {
|
||||
const [register, { expandAll, collapseAll }] = useTable({
|
||||
title: '树形表格',
|
||||
isTreeTable: true,
|
||||
rowSelection: { type: 'checkbox' },
|
||||
titleHelpMessage: '树形组件不能和序列号列同时存在',
|
||||
columns: getBasicColumns(),
|
||||
data: getTreeTableData(),
|
||||
};
|
||||
dataSource: getTreeTableData(),
|
||||
rowKey: 'id',
|
||||
});
|
||||
return { register, expandAll, collapseAll };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -2180,10 +2180,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
ant-design-vue@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.0.1.tgz#3a5964523aac10fd2b16d84d651145cd2b65f1d5"
|
||||
integrity sha512-CFIF+srTui4ZwdKPBXNoFA9/0fkSpypanQeOts0PAq1vEuMLxUoZHapDDn7wzsxZH3sYLF+mvMp8gYMRkaNn+w==
|
||||
ant-design-vue@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.0.tgz#2489240f638f39874281e237544b857ebce52d18"
|
||||
integrity sha512-wzgwHRuwZrSvixccNlvas2gTWBkmfMrifbSsP+ga8VV6F0C6DdlimeFo+P99AxnVgpNVk8OUq9RVDQjb1UGk6g==
|
||||
dependencies:
|
||||
"@ant-design-vue/use" "^0.0.1-0"
|
||||
"@ant-design/icons-vue" "^6.0.0"
|
||||
|
Loading…
Reference in New Issue
Block a user