235 lines
6.0 KiB
Vue
235 lines
6.0 KiB
Vue
<script setup lang="ts">
|
|
import { reactive, watch, onMounted, PropType, nextTick } from 'vue';
|
|
import { Container, Draggable } from 'vue3-smooth-dnd';
|
|
import useI18n from '@/hooks/useI18n';
|
|
import { dbGetJSON, dbSetJSON } from '@/utils/cache-db-utils';
|
|
import { CACHE_DB_TABLE_DND } from '@/constants/cache-keys-constants';
|
|
const { t, currentLocale } = useI18n();
|
|
|
|
const emit = defineEmits(['update:columns-dnd']);
|
|
const props = defineProps({
|
|
/**
|
|
* 表格字段列非响应式数据,必传
|
|
*
|
|
* v-model:columns-dnd取变更的数据
|
|
*/
|
|
columns: {
|
|
type: Array<any>,
|
|
required: true,
|
|
},
|
|
/**
|
|
* 按钮类型
|
|
* text 图标
|
|
* ghost 图标按钮带文字
|
|
*/
|
|
type: {
|
|
type: String as PropType<'text' | 'ghost'>,
|
|
default: 'text',
|
|
},
|
|
/**
|
|
* 缓存列变更数据标识,不传则不缓存
|
|
*/
|
|
cacheId: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
});
|
|
|
|
/**表格字段列 */
|
|
const tableColumns = reactive(props.columns);
|
|
|
|
/**表格字段列勾选状态 */
|
|
const state = reactive<{
|
|
indeterminate: boolean;
|
|
/**是否全选 */
|
|
checkAll: boolean;
|
|
/**字段标题列表 */
|
|
columnsTitleList: string[];
|
|
}>({
|
|
indeterminate: false,
|
|
checkAll: true,
|
|
columnsTitleList: [],
|
|
});
|
|
|
|
/**表格字段列全选操作 */
|
|
function fnTableColumnsCheckAllChange(e: any) {
|
|
const checked = e.target.checked;
|
|
state.indeterminate = false;
|
|
state.columnsTitleList = checked
|
|
? tableColumns.map(s => `${s.title as string}`)
|
|
: [];
|
|
}
|
|
|
|
/**表格字段列拖拽操作 */
|
|
function fnTableColumnsDrop(dropResult: any) {
|
|
const { removedIndex, addedIndex, payload } = dropResult;
|
|
if (removedIndex === null || addedIndex === null) {
|
|
return;
|
|
}
|
|
let itemToAdd = payload;
|
|
itemToAdd = tableColumns.splice(removedIndex, 1)[0];
|
|
tableColumns.splice(addedIndex, 0, itemToAdd);
|
|
fnUpdateColumns();
|
|
}
|
|
|
|
/**表格字段列固定操作 */
|
|
function fnTableColumnsFixed(row: Record<string, any>) {
|
|
if (row.fixed === undefined) {
|
|
return;
|
|
}
|
|
const optTitle = t('common.operate');
|
|
if (row.title === optTitle) {
|
|
const optFixed = row.fixed === 'right';
|
|
row.fixed = optFixed ? false : 'right';
|
|
} else {
|
|
row.fixed = !row.fixed;
|
|
}
|
|
fnUpdateColumns();
|
|
}
|
|
|
|
/**表格字段列勾选字段变化 */
|
|
function fnUpdateColumns() {
|
|
let list = tableColumns.filter(s =>
|
|
state.columnsTitleList.includes(`${s.title}`)
|
|
);
|
|
// 取消全选时留第一个
|
|
if (list.length === 0) {
|
|
list = [tableColumns[0]];
|
|
}
|
|
|
|
if (props.cacheId) {
|
|
// 存入数据
|
|
dbSetJSON(
|
|
CACHE_DB_TABLE_DND,
|
|
`${props.cacheId}#${currentLocale.value}`,
|
|
list
|
|
);
|
|
}
|
|
nextTick(() => {
|
|
emit('update:columns-dnd', list);
|
|
});
|
|
}
|
|
|
|
/**表格字段列勾选监听 */
|
|
watch(
|
|
() => state.columnsTitleList,
|
|
val => {
|
|
const len = val.length;
|
|
state.indeterminate = !!len && len < tableColumns.length;
|
|
state.checkAll = len === tableColumns.length;
|
|
fnUpdateColumns();
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
if (props.cacheId) {
|
|
// 读取数据后响应
|
|
dbGetJSON(CACHE_DB_TABLE_DND, `${props.cacheId}#${currentLocale.value}`)
|
|
.then(data => {
|
|
if (data) {
|
|
const titleList: string[] = [];
|
|
for (const item of data) {
|
|
titleList.push(`${item.title}`);
|
|
// 固定标记还原
|
|
if (item.fixed !== undefined) {
|
|
const fixedItem = tableColumns.find(s => s.title === item.title);
|
|
if (fixedItem) {
|
|
fixedItem.fixed = item.fixed;
|
|
}
|
|
}
|
|
}
|
|
state.columnsTitleList = titleList;
|
|
} else {
|
|
state.columnsTitleList = tableColumns.map(s => `${s.title}`);
|
|
}
|
|
})
|
|
.finally(() => {
|
|
fnUpdateColumns();
|
|
});
|
|
} else {
|
|
state.columnsTitleList = tableColumns.map(s => `${s.title}`);
|
|
fnUpdateColumns();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<a-tooltip>
|
|
<template #title>
|
|
{{ t('common.columnSetText') }}
|
|
</template>
|
|
<a-popover trigger="click" placement="bottomRight">
|
|
<template #title>
|
|
<div class="table-column-setting-title">
|
|
<a-checkbox
|
|
v-model:checked="state.checkAll"
|
|
:indeterminate="state.indeterminate"
|
|
@change="fnTableColumnsCheckAllChange"
|
|
>
|
|
{{ t('common.columnSetTitle') }}
|
|
</a-checkbox>
|
|
</div>
|
|
</template>
|
|
<template #content>
|
|
<a-checkbox-group
|
|
v-model:value="state.columnsTitleList"
|
|
style="width: 100%; max-height: 450px; overflow-y: auto"
|
|
>
|
|
<Container orientation="vertical" @drop="fnTableColumnsDrop">
|
|
<Draggable v-for="c in tableColumns" :key="c.title">
|
|
<div class="table-column-setting-list-item">
|
|
<HolderOutlined class="anticon" />
|
|
<a-checkbox :value="c.title">
|
|
{{ c.title }}
|
|
</a-checkbox>
|
|
<a-button
|
|
v-if="c.fixed !== undefined"
|
|
size="small"
|
|
:title="c.fixed ? `Fixed ${c.fixed} side` : ''"
|
|
:type="c.fixed ? 'primary' : 'dashed'"
|
|
@click="fnTableColumnsFixed(c)"
|
|
>
|
|
<template #icon><FlagOutlined /></template>
|
|
</a-button>
|
|
</div>
|
|
</Draggable>
|
|
</Container>
|
|
</a-checkbox-group>
|
|
</template>
|
|
<a-button :type="props.type" size="small">
|
|
<template #icon><TableOutlined /></template>
|
|
<span v-if="props.type === 'ghost'">
|
|
{{ t('common.columnSetText') }}
|
|
</span>
|
|
</a-button>
|
|
</a-popover>
|
|
</a-tooltip>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.table-column-setting-title {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 32px;
|
|
margin-left: 4px;
|
|
}
|
|
|
|
.table-column-setting-list-item {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
padding: 4px;
|
|
}
|
|
|
|
.table-column-setting-list-item > .anticon {
|
|
padding-right: 8px;
|
|
cursor: move;
|
|
}
|
|
|
|
.table-column-setting-list-item .ant-checkbox-wrapper {
|
|
flex: 1;
|
|
margin: 0;
|
|
}
|
|
</style>
|