WholeProcessPlatform/frontend/src/views/DataQueryMenuModule/components/conventionalHydropower/BasicData/CustomColumnModal.vue

298 lines
7.2 KiB
Vue
Raw Normal View History

<template>
<a-modal
:open="visible"
title="自定义数据列"
:width="1280"
:style="{ maxWidth: '80vw' }"
:footer="null"
@cancel="handleClose"
:destroyOnClose="true"
class="custom-column-modal"
>
<div class="custom-column-content">
<div
v-for="(group, idx) in groupedColumns"
:key="idx"
class="column-group"
>
<!-- 分组标题行 -->
<div class="group-header">
<span class="group-title">{{ group.name }}</span>
<div class="group-actions">
<a-checkbox
:checked="isGroupAllSelected(group)"
:indeterminate="isGroupIndeterminate(group)"
:disabled="isGroupAllDisabled(group)"
@change="e => handleGroupSelectAll(group, e.target.checked)"
>
全选
</a-checkbox>
<a-checkbox
:disabled="isGroupAllDisabled(group)"
@change="() => handleGroupSelectInverse(group)"
>
反选
</a-checkbox>
</div>
</div>
<!-- 子项列表 -->
<div class="group-items">
<a-checkbox
v-for="item in group.children"
:key="item.filed"
:checked="tempSelectedKeys.includes(item.filed)"
:disabled="item.disabled"
@change="e => handleItemChange(item, e.target.checked)"
>
{{ item.name }}
</a-checkbox>
</div>
</div>
</div>
<div class="modal-footer">
<a-button @click="handleClose">取消</a-button>
<a-button type="primary" @click="handleConfirm">确定</a-button>
</div>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { BasicColumns } from '@/components/MapModal/column.config';
interface ColumnItem {
name: string;
filed: string;
disabled?: boolean;
}
interface ColumnGroup {
name: string;
children: ColumnItem[];
}
interface Props {
visible: boolean;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void;
(e: 'confirm', keys: string[]): void;
}>();
const groupedColumns = ref<ColumnGroup[]>([]);
const tempSelectedKeys = ref<string[]>([]);
// 根据 BasicColumns 构建分组结构
const buildGroupedColumns = () => {
const groups: ColumnGroup[] = [];
let currentGroup: ColumnGroup | null = null;
for (const col of BasicColumns) {
if (!col.name && !col.filed) continue;
if (col.visible === false && col.name) {
currentGroup = {
name: col.name,
children: []
};
groups.push(currentGroup);
} else if (col.name && col.filed) {
if (!currentGroup) {
currentGroup = {
name: '基础信息',
children: []
};
groups.push(currentGroup);
}
const isStationName = col.filed === 'ennm';
currentGroup.children.push({
name: col.name,
filed: col.filed,
disabled: isStationName
});
}
}
return groups;
};
// 始终勾选的 filed电站名称
const STATION_NAME_FILED = 'ennm';
// 初始化选中状态(所有非禁用的都默认选中 + 电站名称始终选中)
const initSelectedKeys = () => {
const allKeys: string[] = [STATION_NAME_FILED];
for (const group of groupedColumns.value) {
for (const child of group.children) {
if (!child.disabled && child.filed !== STATION_NAME_FILED) {
allKeys.push(child.filed);
}
}
}
tempSelectedKeys.value = [...allKeys];
};
// 判断分组是否全选
const isGroupAllSelected = (group: ColumnGroup) => {
const selectable = group.children.filter(child => !child.disabled);
if (selectable.length === 0) return false;
return selectable.every(child =>
tempSelectedKeys.value.includes(child.filed)
);
};
// 判断分组是否半选
const isGroupIndeterminate = (group: ColumnGroup) => {
const selectable = group.children.filter(child => !child.disabled);
if (selectable.length === 0) return false;
const selectedCount = selectable.filter(child =>
tempSelectedKeys.value.includes(child.filed)
).length;
return selectedCount > 0 && selectedCount < selectable.length;
};
// 判断分组是否所有项都被禁用
const isGroupAllDisabled = (group: ColumnGroup) => {
return group.children.every(child => child.disabled);
};
// 全选 / 取消全选
const handleGroupSelectAll = (group: ColumnGroup, checked: boolean) => {
const selectableFiled = group.children
.filter(child => !child.disabled)
.map(child => child.filed);
if (checked) {
for (const filed of selectableFiled) {
if (!tempSelectedKeys.value.includes(filed)) {
tempSelectedKeys.value.push(filed);
}
}
} else {
const filedSet = new Set(selectableFiled);
tempSelectedKeys.value = tempSelectedKeys.value.filter(
filed => !filedSet.has(filed)
);
}
};
// 反选
const handleGroupSelectInverse = (group: ColumnGroup) => {
for (const child of group.children) {
if (child.disabled) continue;
const index = tempSelectedKeys.value.indexOf(child.filed);
if (index > -1) {
tempSelectedKeys.value.splice(index, 1);
} else {
tempSelectedKeys.value.push(child.filed);
}
}
};
// 单个项变化
const handleItemChange = (item: ColumnItem, checked: boolean) => {
if (checked) {
if (!tempSelectedKeys.value.includes(item.filed)) {
tempSelectedKeys.value.push(item.filed);
}
} else {
tempSelectedKeys.value = tempSelectedKeys.value.filter(
filed => filed !== item.filed
);
}
};
const handleClose = () => {
emit('update:visible', false);
};
const handleConfirm = () => {
// 确保电站名称始终在结果中
const keys = [...new Set([STATION_NAME_FILED, ...tempSelectedKeys.value])];
emit('confirm', keys);
emit('update:visible', false);
};
watch(
() => props.visible,
newVal => {
if (newVal) {
groupedColumns.value = buildGroupedColumns();
initSelectedKeys();
}
}
);
</script>
<style lang="scss" scoped>
.custom-column-modal {
:deep(.ant-modal-header) {
background-color: #005294;
.ant-modal-title {
color: #fff;
font-weight: 600;
}
}
.custom-column-content {
max-height: 500px;
overflow-y: auto;
padding: 8px 0;
.column-group {
margin-bottom: 16px;
border: 1px solid #e8e8e8;
border-radius: 4px;
padding: 12px;
.group-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
margin-bottom: 8px;
.group-title {
font-weight: 600;
font-size: 14px;
color: #333;
}
.group-actions {
display: flex;
gap: 12px;
:deep(.ant-checkbox-wrapper) {
margin-right: 0;
}
}
}
.group-items {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
:deep(.ant-checkbox-wrapper) {
margin: 0;
font-size: 13px;
}
}
}
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
}
}
</style>