|
@@ -6,7 +6,7 @@
|
|
|
<Popover
|
|
|
placement="bottomLeft"
|
|
|
trigger="click"
|
|
|
- @open-change="handleVisibleChange"
|
|
|
+ @open-change="onOpenChange"
|
|
|
:overlayClassName="`${prefixCls}__column-list`"
|
|
|
:getPopupContainer="getPopupContainer"
|
|
|
>
|
|
@@ -14,25 +14,25 @@
|
|
|
<div :class="`${prefixCls}__popover-title`">
|
|
|
<Checkbox
|
|
|
:indeterminate="indeterminate"
|
|
|
- v-model:checked="state.checkAll"
|
|
|
- @change="onCheckAllChange"
|
|
|
+ v-model:checked="isColumnAllSelected"
|
|
|
+ @change="onColumnAllSelectChange"
|
|
|
>
|
|
|
{{ t('component.table.settingColumnShow') }}
|
|
|
</Checkbox>
|
|
|
|
|
|
- <Checkbox v-model:checked="checkIndex" @change="handleIndexCheckChange">
|
|
|
+ <Checkbox v-model:checked="isIndexColumnShow" @change="onIndexColumnShowChange">
|
|
|
{{ t('component.table.settingIndexColumnShow') }}
|
|
|
</Checkbox>
|
|
|
-
|
|
|
+ <!-- 设置了 rowSelection 才出现 -->
|
|
|
<Checkbox
|
|
|
- v-model:checked="checkSelect"
|
|
|
- @change="handleSelectCheckChange"
|
|
|
- :disabled="!defaultRowSelection"
|
|
|
+ v-model:checked="isRowSelectionShow"
|
|
|
+ @change="onRowSelectionShowChange"
|
|
|
+ v-if="defaultIsRowSelectionShow"
|
|
|
>
|
|
|
{{ t('component.table.settingSelectColumnShow') }}
|
|
|
</Checkbox>
|
|
|
|
|
|
- <a-button size="small" type="link" @click="reset">
|
|
|
+ <a-button size="small" type="link" @click="onReset">
|
|
|
{{ t('common.resetText') }}
|
|
|
</a-button>
|
|
|
</div>
|
|
@@ -40,12 +40,12 @@
|
|
|
|
|
|
<template #content>
|
|
|
<ScrollContainer>
|
|
|
- <Checkbox.Group v-model:value="state.checkedList" @change="onChange" ref="columnListRef">
|
|
|
- <template v-for="item in plainOptions" :key="item.value">
|
|
|
- <div :class="`${prefixCls}__check-item`" v-if="!('ifShow' in item && !item.ifShow)">
|
|
|
+ <Checkbox.Group v-model:value="columnCheckedOptions" ref="columnOptionsRef">
|
|
|
+ <template v-for="opt in columnOptions" :key="opt.value">
|
|
|
+ <div :class="`${prefixCls}__check-item`" :data-no="opt.value">
|
|
|
<DragOutlined class="table-column-drag-icon" />
|
|
|
- <Checkbox :value="item.value">
|
|
|
- {{ item.label }}
|
|
|
+ <Checkbox :value="opt.value">
|
|
|
+ {{ opt.label }}
|
|
|
</Checkbox>
|
|
|
|
|
|
<Tooltip
|
|
@@ -61,11 +61,11 @@
|
|
|
:class="[
|
|
|
`${prefixCls}__fixed-left`,
|
|
|
{
|
|
|
- active: item.fixed === 'left',
|
|
|
- disabled: !state.checkedList.includes(item.value),
|
|
|
+ active: opt.fixed === 'left',
|
|
|
+ disabled: opt.value ? !columnCheckedOptions.includes(opt.value) : true,
|
|
|
},
|
|
|
]"
|
|
|
- @click="handleColumnFixed(item, 'left')"
|
|
|
+ @click="onColumnFixedChange(opt, 'left')"
|
|
|
/>
|
|
|
</Tooltip>
|
|
|
<Divider type="vertical" />
|
|
@@ -82,11 +82,11 @@
|
|
|
:class="[
|
|
|
`${prefixCls}__fixed-right`,
|
|
|
{
|
|
|
- active: item.fixed === 'right',
|
|
|
- disabled: !state.checkedList.includes(item.value),
|
|
|
+ active: opt.fixed === 'right',
|
|
|
+ disabled: opt.value ? !columnCheckedOptions.includes(opt.value) : true,
|
|
|
},
|
|
|
]"
|
|
|
- @click="handleColumnFixed(item, 'right')"
|
|
|
+ @click="onColumnFixedChange(opt, 'right')"
|
|
|
/>
|
|
|
</Tooltip>
|
|
|
</div>
|
|
@@ -99,302 +99,515 @@
|
|
|
</Tooltip>
|
|
|
</template>
|
|
|
<script lang="ts" setup>
|
|
|
- import type { BasicColumn, BasicTableProps, ColumnChangeParam } from '../../types/table';
|
|
|
- import { ref, reactive, watchEffect, nextTick, unref, computed, useAttrs } from 'vue';
|
|
|
+ import type { BasicColumn, ColumnOptionsType, ColumnChangeParam } from '../../types/table';
|
|
|
+ import { ref, nextTick, unref, computed, useAttrs, watch, onMounted } from 'vue';
|
|
|
import { Tooltip, Popover, Checkbox, Divider } from 'ant-design-vue';
|
|
|
- import type {
|
|
|
- CheckboxChangeEvent,
|
|
|
- CheckboxValueType,
|
|
|
- } from 'ant-design-vue/lib/checkbox/interface';
|
|
|
+ import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
|
|
|
import { SettingOutlined, DragOutlined } from '@ant-design/icons-vue';
|
|
|
import Icon from '@/components/Icon/Icon.vue';
|
|
|
import { ScrollContainer } from '@/components/Container';
|
|
|
import { useI18n } from '@/hooks/web/useI18n';
|
|
|
import { useTableContext } from '../../hooks/useTableContext';
|
|
|
import { useDesign } from '@/hooks/web/useDesign';
|
|
|
- // import { useSortable } from '@/hooks/web/useSortable';
|
|
|
import { isFunction, isNil } from '@/utils/is';
|
|
|
import { getPopupContainer as getParentContainer } from '@/utils';
|
|
|
- import { cloneDeep, omit } from 'lodash-es';
|
|
|
+ import { cloneDeep } from 'lodash-es';
|
|
|
import Sortablejs from 'sortablejs';
|
|
|
import type Sortable from 'sortablejs';
|
|
|
|
|
|
- interface State {
|
|
|
- checkAll: boolean;
|
|
|
- isInit?: boolean;
|
|
|
- checkedList: string[];
|
|
|
- defaultCheckList: string[];
|
|
|
- }
|
|
|
+ // 列表设置缓存
|
|
|
+ import { useTableSettingStore } from '@/store/modules/tableSetting';
|
|
|
+ import { useRoute } from 'vue-router';
|
|
|
+ import { TableRowSelection } from '@/components/Table/src/types/table';
|
|
|
|
|
|
- interface Options {
|
|
|
- label: string;
|
|
|
- value: string;
|
|
|
- fixed?: boolean | 'left' | 'right';
|
|
|
- }
|
|
|
+ const tableSettingStore = useTableSettingStore();
|
|
|
|
|
|
defineOptions({ name: 'ColumnSetting' });
|
|
|
-
|
|
|
const emit = defineEmits(['columns-change']);
|
|
|
|
|
|
- const attrs = useAttrs();
|
|
|
- const { t } = useI18n();
|
|
|
- const table = useTableContext();
|
|
|
-
|
|
|
- const defaultRowSelection = omit(table.getRowSelection(), 'selectedRowKeys');
|
|
|
- let inited = false;
|
|
|
- // 是否当前的setColumns触发的
|
|
|
- let isSetColumnsFromThis = false;
|
|
|
- // 是否当前组件触发的setProps
|
|
|
- let isSetPropsFromThis = false;
|
|
|
-
|
|
|
- const cachePlainOptions = ref<Options[]>([]);
|
|
|
- const plainOptions = ref<Options[] | any>([]);
|
|
|
+ const route = useRoute();
|
|
|
|
|
|
- const plainSortOptions = ref<Options[]>([]);
|
|
|
+ const { t } = useI18n();
|
|
|
+ const { prefixCls } = useDesign('basic-column-setting');
|
|
|
|
|
|
- const columnListRef = ref(null);
|
|
|
+ const attrs = useAttrs();
|
|
|
+ const table = useTableContext();
|
|
|
|
|
|
- const state = reactive<State>({
|
|
|
- checkAll: true,
|
|
|
- checkedList: [],
|
|
|
- defaultCheckList: [],
|
|
|
+ const getPopupContainer = () => {
|
|
|
+ return isFunction(attrs.getPopupContainer) ? attrs.getPopupContainer() : getParentContainer();
|
|
|
+ };
|
|
|
+
|
|
|
+ // 是否已经从缓存恢复
|
|
|
+ let isRestored = false;
|
|
|
+ let isInnerChange = false;
|
|
|
+
|
|
|
+ // 列可选项
|
|
|
+ const columnOptions = ref<ColumnOptionsType[]>([]);
|
|
|
+ const columnOptionsRef = ref(null);
|
|
|
+ // 已选列
|
|
|
+ const columnCheckedOptions = ref<string[]>([]);
|
|
|
+ // 已选变化
|
|
|
+ watch(columnCheckedOptions, () => {
|
|
|
+ // 恢复缓存后生效
|
|
|
+ if (isRestored) {
|
|
|
+ // 显示
|
|
|
+ columnOptions.value
|
|
|
+ .filter((o) => columnCheckedOptions.value.includes(o.value))
|
|
|
+ .forEach((o) => {
|
|
|
+ o.column.defaultHidden = false;
|
|
|
+ });
|
|
|
+ // 隐藏
|
|
|
+ columnOptions.value
|
|
|
+ .filter((o) => !columnCheckedOptions.value.includes(o.value))
|
|
|
+ .forEach((o) => {
|
|
|
+ o.column.defaultHidden = true;
|
|
|
+ o.fixed = undefined;
|
|
|
+ });
|
|
|
+ // 从 列可选项 更新 全选状态
|
|
|
+ isColumnAllSelectedUpdate();
|
|
|
+
|
|
|
+ // 列表列更新
|
|
|
+ tableColumnsUpdate();
|
|
|
+ // 更新列缓存
|
|
|
+ columnOptionsSave();
|
|
|
+ }
|
|
|
});
|
|
|
- /** 缓存初始化props */
|
|
|
- let cacheTableProps: Partial<BasicTableProps<any>> = {};
|
|
|
- const checkIndex = ref(false);
|
|
|
- const checkSelect = ref(false);
|
|
|
|
|
|
- const { prefixCls } = useDesign('basic-column-setting');
|
|
|
+ // 全选
|
|
|
+ const isColumnAllSelected = ref<boolean>(false);
|
|
|
+ const onColumnAllSelectChange = () => {
|
|
|
+ if (columnCheckedOptions.value.length < columnOptions.value.length) {
|
|
|
+ columnCheckedOptions.value = columnOptions.value.map((o) => o.value);
|
|
|
+ } else {
|
|
|
+ columnCheckedOptions.value = [];
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- const getValues = computed(() => {
|
|
|
- return unref(table?.getBindValues) || {};
|
|
|
+ // 半选状态
|
|
|
+ const indeterminate = computed(() => {
|
|
|
+ return (
|
|
|
+ columnCheckedOptions.value.length > 0 &&
|
|
|
+ columnCheckedOptions.value.length < columnOptions.value.length
|
|
|
+ );
|
|
|
});
|
|
|
|
|
|
- watchEffect(() => {
|
|
|
- const columns = table.getColumns();
|
|
|
- setTimeout(() => {
|
|
|
- if (isSetColumnsFromThis) {
|
|
|
- isSetColumnsFromThis = false;
|
|
|
- } else if (columns.length) {
|
|
|
- init();
|
|
|
+ // 是否显示序号列
|
|
|
+ const isIndexColumnShow = ref<boolean>(false);
|
|
|
+ // 序号列更新
|
|
|
+ const onIndexColumnShowChange = (e: CheckboxChangeEvent) => {
|
|
|
+ // 更新 showIndexColumn
|
|
|
+ showIndexColumnUpdate(e.target.checked);
|
|
|
+ // 更新 showIndexColumn 缓存
|
|
|
+ tableSettingStore.setShowIndexColumn(e.target.checked);
|
|
|
+ // 从无到有需要处理
|
|
|
+ if (e.target.checked) {
|
|
|
+ const columns = cloneDeep(table?.getColumns());
|
|
|
+ const idx = columns.findIndex((o) => o.flag === 'INDEX');
|
|
|
+ // 找到序号列
|
|
|
+ if (idx > -1) {
|
|
|
+ const cache = columns[idx];
|
|
|
+ // 强制左fix
|
|
|
+ cache.fixed = 'left';
|
|
|
+ // 强制移动到 第一/选择列后
|
|
|
+ columns.splice(idx, 1);
|
|
|
+ columns.splice(0, 0, cache);
|
|
|
+ // 设置列表列
|
|
|
+ tableColumnsSet(columns);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 是否显示选择列
|
|
|
+ const isRowSelectionShow = ref<boolean>(false);
|
|
|
+ // 选择列更新
|
|
|
+ const onRowSelectionShowChange = (e: CheckboxChangeEvent) => {
|
|
|
+ // 更新 showRowSelection
|
|
|
+ showRowSelectionUpdate(e.target.checked);
|
|
|
+ // 更新 showRowSelection 缓存
|
|
|
+ tableSettingStore.setShowRowSelection(e.target.checked);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 更新列缓存
|
|
|
+ const columnOptionsSave = () => {
|
|
|
+ if (typeof route.name === 'string') {
|
|
|
+ // 按路由 name 作为缓存的key(若一个路由内存在多个表格,需自行调整缓存key来源)
|
|
|
+ tableSettingStore.setColumns(route.name, columnOptions.value);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 重置
|
|
|
+ const onReset = () => {
|
|
|
+ // 重置默认值
|
|
|
+ isIndexColumnShow.value = defaultIsIndexColumnShow;
|
|
|
+ // 序号列更新
|
|
|
+ onIndexColumnShowChange({
|
|
|
+ target: { checked: defaultIsIndexColumnShow },
|
|
|
+ } as CheckboxChangeEvent);
|
|
|
+ // 重置默认值
|
|
|
+ isRowSelectionShow.value = defaultIsRowSelectionShow;
|
|
|
+ // 选择列更新
|
|
|
+ onRowSelectionShowChange({
|
|
|
+ target: { checked: defaultIsRowSelectionShow },
|
|
|
+ } as CheckboxChangeEvent);
|
|
|
+ // 重置默认值
|
|
|
+ columnOptions.value = cloneDeep(defaultColumnOptions);
|
|
|
+ // 重置排序
|
|
|
+ sortableOrder = defaultSortableOrder;
|
|
|
+ // 排序
|
|
|
+ sortable?.sort(defaultSortableOrder);
|
|
|
+ // 更新表单状态
|
|
|
+ formUpdate();
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置列的 fixed
|
|
|
+ const onColumnFixedChange = (opt: ColumnOptionsType, type: 'left' | 'right') => {
|
|
|
+ if (type === 'left') {
|
|
|
+ if (!opt.fixed || opt.fixed === 'right') {
|
|
|
+ opt.fixed = 'left';
|
|
|
+ } else {
|
|
|
+ opt.fixed = undefined;
|
|
|
+ }
|
|
|
+ } else if (type === 'right') {
|
|
|
+ if (!opt.fixed || opt.fixed === 'left') {
|
|
|
+ opt.fixed = 'right';
|
|
|
+ } else {
|
|
|
+ opt.fixed = undefined;
|
|
|
}
|
|
|
- }, 0);
|
|
|
- });
|
|
|
-
|
|
|
- watchEffect(() => {
|
|
|
- const values = unref(getValues);
|
|
|
- if (isSetPropsFromThis) {
|
|
|
- isSetPropsFromThis = false;
|
|
|
- } else {
|
|
|
- cacheTableProps = cloneDeep(values);
|
|
|
}
|
|
|
- checkIndex.value = !!values.showIndexColumn;
|
|
|
- checkSelect.value = !!values.rowSelection;
|
|
|
- });
|
|
|
|
|
|
- function getColumns() {
|
|
|
- const ret: Options[] = [];
|
|
|
- table.getColumns({ ignoreIndex: true, ignoreAction: true }).forEach((item) => {
|
|
|
- ret.push({
|
|
|
- label: (item.title as string) || (item.customTitle as string),
|
|
|
- value: (item.dataIndex || item.title) as string,
|
|
|
- ...item,
|
|
|
- });
|
|
|
- });
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ // 列表列更新
|
|
|
+ tableColumnsUpdate();
|
|
|
+ // 更新列缓存
|
|
|
+ columnOptionsSave();
|
|
|
+ };
|
|
|
|
|
|
- async function init(isReset = false) {
|
|
|
+ // 沿用逻辑
|
|
|
+ const sortableFix = async () => {
|
|
|
// Sortablejs存在bug,不知道在哪个步骤中会向el append了一个childNode,因此这里先清空childNode
|
|
|
// 有可能复现上述问题的操作:拖拽一个元素,快速的上下移动,最后放到最后的位置中松手
|
|
|
- plainOptions.value = [];
|
|
|
- const columnListEl = unref(columnListRef);
|
|
|
- if (columnListEl && (columnListEl as any).$el) {
|
|
|
- const el = (columnListEl as any).$el as Element;
|
|
|
+ if (columnOptionsRef.value) {
|
|
|
+ const el = (columnOptionsRef.value as InstanceType<typeof Checkbox.Group>).$el;
|
|
|
Array.from(el.children).forEach((item) => el.removeChild(item));
|
|
|
}
|
|
|
await nextTick();
|
|
|
- const columns = isReset ? cloneDeep(cachePlainOptions.value) : getColumns();
|
|
|
-
|
|
|
- const checkList = table
|
|
|
- .getColumns({ ignoreAction: true, ignoreIndex: true })
|
|
|
- .map((item) => {
|
|
|
- if (item.defaultHidden) {
|
|
|
- return '';
|
|
|
+ };
|
|
|
+
|
|
|
+ // 列是否显示逻辑
|
|
|
+ const columnIfShow = (column?: Partial<Omit<BasicColumn, 'children'>>) => {
|
|
|
+ if (column) {
|
|
|
+ if ('ifShow' in column) {
|
|
|
+ if (typeof column.ifShow === 'boolean') {
|
|
|
+ return column.ifShow;
|
|
|
+ } else if (column.ifShow) {
|
|
|
+ return column.ifShow(column);
|
|
|
}
|
|
|
- return item.dataIndex || item.title;
|
|
|
- })
|
|
|
- .filter(Boolean) as string[];
|
|
|
- plainOptions.value = columns;
|
|
|
- plainSortOptions.value = columns;
|
|
|
- // 更新缓存配置
|
|
|
- table.setCacheColumns?.(columns);
|
|
|
- !isReset && (cachePlainOptions.value = cloneDeep(columns));
|
|
|
- state.defaultCheckList = checkList;
|
|
|
- state.checkedList = checkList;
|
|
|
- // 是否列展示全选
|
|
|
- state.checkAll = checkList.length === columns.length;
|
|
|
- inited = false;
|
|
|
- handleVisibleChange();
|
|
|
- }
|
|
|
-
|
|
|
- // checkAll change
|
|
|
- function onCheckAllChange(e: CheckboxChangeEvent) {
|
|
|
- const checkList = plainSortOptions.value.map((item) => item.value);
|
|
|
- plainSortOptions.value.forEach(
|
|
|
- (item) => ((item as BasicColumn).defaultHidden = !e.target.checked),
|
|
|
- );
|
|
|
- if (e.target.checked) {
|
|
|
- state.checkedList = checkList;
|
|
|
- setColumns(checkList);
|
|
|
- } else {
|
|
|
- state.checkedList = [];
|
|
|
- setColumns([]);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- const indeterminate = computed(() => {
|
|
|
- const len = plainOptions.value.length;
|
|
|
- let checkedLen = state.checkedList.length;
|
|
|
- // unref(checkIndex) && checkedLen--;
|
|
|
- return checkedLen > 0 && checkedLen < len;
|
|
|
- });
|
|
|
-
|
|
|
- // Trigger when check/uncheck a column
|
|
|
- function onChange(checkedList: CheckboxValueType[]) {
|
|
|
- const len = plainSortOptions.value.length;
|
|
|
- state.checkAll = checkedList.length === len;
|
|
|
- const sortList = unref(plainSortOptions).map((item) => item.value);
|
|
|
- checkedList.sort((prev, next) => {
|
|
|
- return sortList.indexOf(String(prev)) - sortList.indexOf(String(next));
|
|
|
- });
|
|
|
- unref(plainSortOptions).forEach((item) => {
|
|
|
- (item as BasicColumn).defaultHidden = !checkedList.includes(item.value);
|
|
|
- });
|
|
|
- setColumns(checkedList as string[]);
|
|
|
- }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
|
|
|
+ // sortable 实例
|
|
|
let sortable: Sortable;
|
|
|
+ // 排序
|
|
|
let sortableOrder: string[] = [];
|
|
|
- // reset columns
|
|
|
- function reset() {
|
|
|
- setColumns(cachePlainOptions.value);
|
|
|
- init(true);
|
|
|
- checkIndex.value = !!cacheTableProps.showIndexColumn;
|
|
|
- checkSelect.value = !!cacheTableProps.rowSelection;
|
|
|
- table.setProps({
|
|
|
- showIndexColumn: checkIndex.value,
|
|
|
- rowSelection: checkSelect.value ? defaultRowSelection : undefined,
|
|
|
- });
|
|
|
- sortable.sort(sortableOrder);
|
|
|
- }
|
|
|
|
|
|
- // Open the pop-up window for drag and drop initialization
|
|
|
- function handleVisibleChange() {
|
|
|
- if (inited) return;
|
|
|
- nextTick(() => {
|
|
|
- const columnListEl = unref(columnListRef);
|
|
|
- if (!columnListEl) return;
|
|
|
- const el = (columnListEl as any).$el;
|
|
|
- if (!el) return;
|
|
|
- // Drag and drop sort
|
|
|
+ // 获取数据列
|
|
|
+ const getTableColumns = () => {
|
|
|
+ return table
|
|
|
+ .getColumns({ ignoreIndex: true, ignoreAction: true })
|
|
|
+ .filter((col) => columnIfShow(col));
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置列表列
|
|
|
+ const tableColumnsSet = (columns: BasicColumn[]) => {
|
|
|
+ isInnerChange = true;
|
|
|
+ table?.setColumns(columns);
|
|
|
+
|
|
|
+ // 沿用逻辑
|
|
|
+ const columnChangeParams: ColumnChangeParam[] = columns.map((col) => ({
|
|
|
+ dataIndex: col.dataIndex ? col.dataIndex.toString() : '',
|
|
|
+ fixed: col.fixed,
|
|
|
+ visible: !col.defaultHidden,
|
|
|
+ }));
|
|
|
+ emit('columns-change', columnChangeParams);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 列表列更新
|
|
|
+ const tableColumnsUpdate = () => {
|
|
|
+ // 考虑了所有列
|
|
|
+ const columns = cloneDeep(table.getColumns());
|
|
|
+
|
|
|
+ // 从左 fixed 最一列开始排序
|
|
|
+ let count = columns.filter((o) => o.fixed === 'left' || o.fixed === true).length;
|
|
|
+
|
|
|
+ // 按 columnOptions 的排序 调整 table.getColumns() 的顺序和值
|
|
|
+ for (const opt of columnOptions.value) {
|
|
|
+ const colIdx = columns.findIndex((o) => o.dataIndex === opt.value);
|
|
|
+ //
|
|
|
+ if (colIdx > -1) {
|
|
|
+ const target = columns[colIdx];
|
|
|
+ target.defaultHidden = opt.column?.defaultHidden;
|
|
|
+ target.fixed = opt.fixed;
|
|
|
+ columns.splice(colIdx, 1);
|
|
|
+ columns.splice(count++, 0, target); // 递增插入
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置列表列
|
|
|
+ tableColumnsSet(columns);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 打开浮窗
|
|
|
+ const onOpenChange = async () => {
|
|
|
+ await nextTick();
|
|
|
+
|
|
|
+ if (columnOptionsRef.value) {
|
|
|
+ // 注册排序实例
|
|
|
+ const el = (columnOptionsRef.value as InstanceType<typeof Checkbox.Group>).$el;
|
|
|
sortable = Sortablejs.create(unref(el), {
|
|
|
animation: 500,
|
|
|
delay: 400,
|
|
|
delayOnTouchOnly: true,
|
|
|
handle: '.table-column-drag-icon ',
|
|
|
+ dataIdAttr: 'data-no',
|
|
|
onEnd: (evt) => {
|
|
|
const { oldIndex, newIndex } = evt;
|
|
|
if (isNil(oldIndex) || isNil(newIndex) || oldIndex === newIndex) {
|
|
|
return;
|
|
|
}
|
|
|
- // Sort column
|
|
|
- const columns = cloneDeep(plainSortOptions.value);
|
|
|
|
|
|
+ const options = cloneDeep(columnOptions.value);
|
|
|
+
|
|
|
+ // 排序
|
|
|
if (oldIndex > newIndex) {
|
|
|
- columns.splice(newIndex, 0, columns[oldIndex]);
|
|
|
- columns.splice(oldIndex + 1, 1);
|
|
|
+ options.splice(newIndex, 0, options[oldIndex]);
|
|
|
+ options.splice(oldIndex + 1, 1);
|
|
|
} else {
|
|
|
- columns.splice(newIndex + 1, 0, columns[oldIndex]);
|
|
|
- columns.splice(oldIndex, 1);
|
|
|
+ options.splice(newIndex + 1, 0, options[oldIndex]);
|
|
|
+ options.splice(oldIndex, 1);
|
|
|
}
|
|
|
|
|
|
- plainSortOptions.value = columns;
|
|
|
- setColumns(columns.filter((item) => state.checkedList.includes(item.value)));
|
|
|
+ // 更新 列可选项
|
|
|
+ columnOptions.value = options;
|
|
|
+
|
|
|
+ // 列表列更新
|
|
|
+ tableColumnsUpdate();
|
|
|
+ // 更新列缓存
|
|
|
+ columnOptionsSave();
|
|
|
},
|
|
|
});
|
|
|
- // 记录原始order 序列
|
|
|
- sortableOrder = sortable.toArray();
|
|
|
- inited = true;
|
|
|
- });
|
|
|
- }
|
|
|
|
|
|
- // Control whether the serial number column is displayed
|
|
|
- function handleIndexCheckChange(e: CheckboxChangeEvent) {
|
|
|
- isSetPropsFromThis = true;
|
|
|
- isSetColumnsFromThis = true;
|
|
|
+ // 从缓存恢复
|
|
|
+ sortable.sort(sortableOrder);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // remove消失的列、push新出现的列
|
|
|
+ const diff = () => {
|
|
|
+ if (typeof route.name === 'string') {
|
|
|
+ let cache = tableSettingStore.getColumns(route.name);
|
|
|
+ if (cache) {
|
|
|
+ // value、label是否一致
|
|
|
+ if (
|
|
|
+ JSON.stringify(columnOptions.value.map((o) => ({ value: o.value, label: o.label }))) !==
|
|
|
+ JSON.stringify(cache.map((o) => ({ value: o.value, label: o.label })))
|
|
|
+ ) {
|
|
|
+ const map = columnOptions.value.reduce((map, item) => {
|
|
|
+ map[item.value] = item.label;
|
|
|
+ return map;
|
|
|
+ }, {});
|
|
|
+ if (Array.isArray(cache)) {
|
|
|
+ // remove消失的列
|
|
|
+ cache = cache.filter((o) => map[o.value]);
|
|
|
+ // 更新label
|
|
|
+ cache.forEach((o) => {
|
|
|
+ o.label = map[o.value];
|
|
|
+ });
|
|
|
+ const cacheKeys = cache.map((o) => o.value);
|
|
|
+ // push新出现的列
|
|
|
+ cache = cache.concat(columnOptions.value.filter((o) => !cacheKeys.includes(o.value)));
|
|
|
+ // 更新缓存
|
|
|
+ tableSettingStore.setColumns(route.name, cache);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 从缓存恢复
|
|
|
+ const restore = () => {
|
|
|
+ // 设置过才恢复
|
|
|
+ if (typeof tableSettingStore.getShowIndexColumn === 'boolean') {
|
|
|
+ isIndexColumnShow.value = tableSettingStore.getShowIndexColumn;
|
|
|
+ }
|
|
|
+ if (typeof tableSettingStore.getShowRowSelection === 'boolean') {
|
|
|
+ isRowSelectionShow.value = defaultIsRowSelectionShow && tableSettingStore.getShowRowSelection;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 序号列更新
|
|
|
+ onIndexColumnShowChange({
|
|
|
+ target: { checked: isIndexColumnShow.value },
|
|
|
+ } as CheckboxChangeEvent);
|
|
|
+ // 选择列更新
|
|
|
+ onRowSelectionShowChange({
|
|
|
+ target: { checked: isRowSelectionShow.value },
|
|
|
+ } as CheckboxChangeEvent);
|
|
|
+
|
|
|
+ if (typeof route.name === 'string') {
|
|
|
+ const cache = tableSettingStore.getColumns(route.name);
|
|
|
+ // 设置过才恢复
|
|
|
+ if (Array.isArray(cache)) {
|
|
|
+ columnOptions.value = cache;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 从 列可选项 更新 已选列
|
|
|
+ const columnCheckedOptionsUpdate = () => {
|
|
|
+ columnCheckedOptions.value = columnOptions.value
|
|
|
+ .filter((o) => !o.column?.defaultHidden)
|
|
|
+ .map((o) => o.value);
|
|
|
+ };
|
|
|
+ // 从 列可选项 更新 全选状态
|
|
|
+ const isColumnAllSelectedUpdate = () => {
|
|
|
+ isColumnAllSelected.value = columnOptions.value.length === columnCheckedOptions.value.length;
|
|
|
+ };
|
|
|
+ // 从 列可选项 更新 排序
|
|
|
+ const sortableOrderUpdateByOptions = (options: ColumnOptionsType[]) => {
|
|
|
+ sortableOrder = options.map((o) => o.value);
|
|
|
+ };
|
|
|
+ // 更新 showIndexColumn
|
|
|
+ const showIndexColumnUpdate = (showIndexColumn) => {
|
|
|
+ isInnerChange = true;
|
|
|
table.setProps({
|
|
|
- showIndexColumn: e.target.checked,
|
|
|
+ showIndexColumn,
|
|
|
});
|
|
|
- }
|
|
|
-
|
|
|
- // Control whether the check box is displayed
|
|
|
- function handleSelectCheckChange(e: CheckboxChangeEvent) {
|
|
|
- isSetPropsFromThis = true;
|
|
|
- isSetColumnsFromThis = true;
|
|
|
+ };
|
|
|
+ // 更新 rowSelection
|
|
|
+ const showRowSelectionUpdate = (showRowSelection) => {
|
|
|
+ isInnerChange = true;
|
|
|
table.setProps({
|
|
|
- rowSelection: e.target.checked ? defaultRowSelection : undefined,
|
|
|
+ rowSelection: showRowSelection
|
|
|
+ ? {
|
|
|
+ ...defaultRowSelection,
|
|
|
+ fixed: true,
|
|
|
+ }
|
|
|
+ : undefined,
|
|
|
});
|
|
|
- }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 更新表单状态
|
|
|
+ const formUpdate = () => {
|
|
|
+ // 从 列可选项 更新 已选列
|
|
|
+ columnCheckedOptionsUpdate();
|
|
|
+
|
|
|
+ // 从 列可选项 更新 全选状态
|
|
|
+ isColumnAllSelectedUpdate();
|
|
|
+
|
|
|
+ // 从 列可选项 更新 排序
|
|
|
+ sortableOrderUpdateByOptions(columnOptions.value);
|
|
|
+
|
|
|
+ // 更新 showIndexColumn
|
|
|
+ showIndexColumnUpdate(isIndexColumnShow.value);
|
|
|
+
|
|
|
+ // 更新 showRowSelection
|
|
|
+ showRowSelectionUpdate(isRowSelectionShow.value);
|
|
|
+
|
|
|
+ // 列表列更新
|
|
|
+ tableColumnsUpdate();
|
|
|
+ };
|
|
|
+
|
|
|
+ // 默认值
|
|
|
+ let defaultIsIndexColumnShow: boolean = false;
|
|
|
+ let defaultIsRowSelectionShow: boolean = false;
|
|
|
+ let defaultRowSelection: TableRowSelection<Recordable<any>>;
|
|
|
+ let defaultColumnOptions: ColumnOptionsType[] = [];
|
|
|
+ let defaultSortableOrder: string[] = [];
|
|
|
+
|
|
|
+ const init = async () => {
|
|
|
+ if (!isRestored) {
|
|
|
+ await sortableFix();
|
|
|
+
|
|
|
+ // 获取数据列
|
|
|
+ const columns = getTableColumns();
|
|
|
+
|
|
|
+ // 沿用逻辑
|
|
|
+ table.setCacheColumns?.(columns);
|
|
|
+
|
|
|
+ // 生成 默认值
|
|
|
+ const options: ColumnOptionsType[] = [];
|
|
|
+ for (const col of columns) {
|
|
|
+ // 只缓存 string 类型的列
|
|
|
+ options.push({
|
|
|
+ label:
|
|
|
+ typeof col.title === 'string'
|
|
|
+ ? col.title
|
|
|
+ : col.customTitle === 'string'
|
|
|
+ ? col.customTitle
|
|
|
+ : '',
|
|
|
+ value:
|
|
|
+ typeof col.dataIndex === 'string'
|
|
|
+ ? col.dataIndex
|
|
|
+ : col.title === 'string'
|
|
|
+ ? col.title
|
|
|
+ : '',
|
|
|
+ column: {
|
|
|
+ defaultHidden: col.defaultHidden,
|
|
|
+ },
|
|
|
+ fixed: col.fixed,
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
- function handleColumnFixed(item: BasicColumn, fixed?: 'left' | 'right') {
|
|
|
- if (!state.checkedList.includes(item.dataIndex as string)) return;
|
|
|
+ // 默认值 缓存,浮窗出现的时候使用
|
|
|
+ defaultSortableOrder = options.map((o) => o.value);
|
|
|
|
|
|
- const columns = getColumns().filter((c: BasicColumn) =>
|
|
|
- state.checkedList.includes(c.dataIndex as string),
|
|
|
- ) as BasicColumn[];
|
|
|
- const isFixed = item.fixed === fixed ? false : fixed;
|
|
|
- const index = columns.findIndex((col) => col.dataIndex === item.dataIndex);
|
|
|
- if (index !== -1) {
|
|
|
- columns[index].fixed = isFixed;
|
|
|
- }
|
|
|
- item.fixed = isFixed;
|
|
|
+ // 默认值 缓存
|
|
|
+ defaultIsIndexColumnShow = table.getBindValues.value.showIndexColumn || false;
|
|
|
+ defaultRowSelection = table.getRowSelection();
|
|
|
+ defaultIsRowSelectionShow = !!defaultRowSelection; // 设置了 rowSelection 才出现
|
|
|
+ defaultColumnOptions = options;
|
|
|
|
|
|
- if (isFixed && !item.width) {
|
|
|
- item.width = 100;
|
|
|
- }
|
|
|
- updateSortOption(item);
|
|
|
- table.setCacheColumnsByField?.(item.dataIndex as string, { fixed: isFixed });
|
|
|
- setColumns(columns);
|
|
|
- }
|
|
|
+ // 默认值 赋值
|
|
|
+ isIndexColumnShow.value = defaultIsIndexColumnShow;
|
|
|
+ isRowSelectionShow.value = defaultIsRowSelectionShow;
|
|
|
+ columnOptions.value = cloneDeep(options);
|
|
|
|
|
|
- function setColumns(columns: BasicColumn[] | string[]) {
|
|
|
- isSetPropsFromThis = true;
|
|
|
- isSetColumnsFromThis = true;
|
|
|
- table.setColumns(columns);
|
|
|
- const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
|
|
|
- const visible =
|
|
|
- columns.findIndex(
|
|
|
- (c: BasicColumn | string) =>
|
|
|
- c === col.value || (typeof c !== 'string' && c.dataIndex === col.value),
|
|
|
- ) !== -1;
|
|
|
- return { dataIndex: col.value, fixed: col.fixed, visible };
|
|
|
- });
|
|
|
+ // remove消失的列、push新出现的列
|
|
|
+ diff();
|
|
|
|
|
|
- emit('columns-change', data);
|
|
|
- }
|
|
|
+ // 从缓存恢复
|
|
|
+ restore();
|
|
|
|
|
|
- function getPopupContainer() {
|
|
|
- return isFunction(attrs.getPopupContainer) ? attrs.getPopupContainer() : getParentContainer();
|
|
|
- }
|
|
|
+ // 更新表单状态
|
|
|
+ formUpdate();
|
|
|
+
|
|
|
+ isRestored = true;
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- function updateSortOption(column: BasicColumn) {
|
|
|
- plainSortOptions.value.forEach((item) => {
|
|
|
- if (item.value === column.dataIndex) {
|
|
|
- Object.assign(item, column);
|
|
|
+ // 初始化
|
|
|
+ init();
|
|
|
+
|
|
|
+ // 外部列改变
|
|
|
+ const getColumns = computed(() => {
|
|
|
+ return table?.getColumns();
|
|
|
+ });
|
|
|
+ const getValues = computed(() => {
|
|
|
+ return table?.getBindValues;
|
|
|
+ });
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ watch([getColumns, getValues], () => {
|
|
|
+ if (!isInnerChange) {
|
|
|
+ isRestored = false;
|
|
|
+ console.log('onMounted isRestored');
|
|
|
+ init();
|
|
|
+ } else {
|
|
|
+ isInnerChange = false;
|
|
|
}
|
|
|
});
|
|
|
- }
|
|
|
+ });
|
|
|
</script>
|
|
|
<style lang="less">
|
|
|
@prefix-cls: ~'@{namespace}-basic-column-setting';
|