Files
hzdyjs/web/src/views/xg/xgss/xsssgly/components/ScopeDialog.vue
T

441 lines
14 KiB
Vue

<template>
<el-dialog title="分配管理范围" v-model="dialogVisible" width="500px" append-to-body>
<el-form ref="formRef" :model="form" label-width="100px">
<el-form-item label="管理员姓名">
<span>{{ admin?.name }}</span>
</el-form-item>
<el-form-item label="管理范围" prop="scope">
<!-- 校区类型使用原有的多选下拉框 -->
<el-select
v-if="type === 'campus'"
v-model="form.scope"
placeholder="请选择管理范围"
style="width: 100%"
clearable
filterable
multiple
collapse-tags
default-expand-all
collapse-tags-tooltip
>
<el-option v-for="item in scopeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<!-- 宿舍区类型使用树形选择器 -->
<el-tree-select
v-else-if="type === 'area'"
v-model="form.scope"
placeholder="请选择宿舍区"
style="width: 100%"
clearable
filterable
multiple
collapse-tags
collapse-tags-tooltip
default-expand-all
:data="treeData"
:props="{
children: 'children',
label: 'label',
disabled: 'disabled',
value: 'id'
}"
check-strictly
/>
<!-- 宿舍楼类型使用新的树形选择器 -->
<el-tree-select
v-else-if="type === 'building'"
v-model="form.scope"
placeholder="请选择宿舍楼"
style="width: 100%"
clearable
filterable
multiple
collapse-tags
collapse-tags-tooltip
default-expand-all
:data="buildingTreeData"
:props="{
children: 'children',
label: 'label',
disabled: 'disabled',
value: 'id'
}"
check-strictly
/>
<!-- 其他类型保持原有的单选下拉框 -->
<el-select v-else v-model="form.scope" placeholder="请选择管理范围" style="width: 100%" clearable filterable>
<el-option v-for="item in scopeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, computed, watch, onMounted } from 'vue';
import { listDormCampus } from '@/api/xg/xgss/xqxx/dormCampus';
import { getAreaTree } from '@/api/xg/xgss/ssqxx/dormArea';
import { getBuildingTree } from '@/api/xg/xgss/sslxx/dormBuilding';
import type { TreeSelectVo } from '@/api/xg/xgss/ssqxx/dormArea/types';
import type { BuildingTreeSelectVo } from '@/api/xg/xgss/sslxx/dormBuilding/types';
export default defineComponent({
name: 'ScopeDialog',
props: {
modelValue: {
type: Boolean,
default: false
},
admin: {
type: Object,
default: () => ({})
},
type: {
type: String,
default: ''
}
},
emits: ['update:modelValue', 'submit'],
setup(props, { emit }) {
const dialogVisible = computed({
get: () => props.modelValue,
set: (val) => {
emit('update:modelValue', val);
}
});
// 判断是否为校区类型的计算属性
const isCampusType = computed(() => props.type === 'campus');
// 判断是否为宿舍区类型的计算属性
const isAreaType = computed(() => props.type === 'area');
// 判断是否为宿舍楼类型的计算属性
const isBuildingType = computed(() => props.type === 'building');
const formRef = ref();
const form = reactive({
scope: isCampusType.value || isAreaType.value || isBuildingType.value ? [] : ''
});
// 下拉选项数据
const scopeOptions = ref<any[]>([]);
// 宿舍区树形数据
const treeData = ref<TreeSelectVo[]>([]);
// 宿舍楼树形数据
const buildingTreeData = ref<BuildingTreeSelectVo[]>([]);
// 标记是否完成数据加载的状态
const dataLoaded = ref(false);
// 处理scope字符串为数组的辅助函数(校区使用)
const parseScopeString = (scopeString: string) => {
if (!scopeString) return [];
// 尝试按逗号分隔并提取ID (假设格式为: "东校区,西校区")
return scopeString
.split(',')
.map((item) => {
// 在校区选项中查找匹配的校区名称
const option = scopeOptions.value.find((opt) => opt.label === item.trim());
return option ? option.value : null;
})
.filter((id) => id !== null); // 过滤掉未找到的项
};
// 处理宿舍区scope字符串为数组的辅助函数
const parseAreaScopeString = (scopeString: string) => {
if (!scopeString) return [];
// 尝试按逗号分隔宿舍区名称
const areaNames = scopeString.split(',').map((item) => item.trim());
// 在树形数据中查找匹配的宿舍区ID
const findAreaIds = (nodes: TreeSelectVo[]): number[] => {
if (!nodes || nodes.length === 0) return [];
let result: number[] = [];
for (const node of nodes) {
// 如果节点标签匹配任何一个宿舍区名称,添加该节点ID
if (areaNames.includes(node.label)) {
result.push(node.id);
}
// 如果有子节点,递归查找
if (node.children && node.children.length > 0) {
result = [...result, ...findAreaIds(node.children)];
}
}
return result;
};
return findAreaIds(treeData.value);
};
// 处理宿舍楼scope字符串为数组的辅助函数
const parseBuildingScopeString = (scopeString: string) => {
if (!scopeString) return [];
// 尝试按逗号分隔宿舍楼名称
const buildingNames = scopeString.split(',').map((item) => item.trim());
// 在树形数据中查找匹配的宿舍楼ID
const findBuildingIds = (nodes: BuildingTreeSelectVo[]): number[] => {
if (!nodes || nodes.length === 0) return [];
let result: number[] = [];
for (const node of nodes) {
// 如果是宿舍楼节点,且名称匹配,添加该节点ID
if (node.nodeType === 'building' && buildingNames.includes(node.label)) {
result.push(node.id);
}
// 如果有子节点,递归查找
if (node.children && node.children.length > 0) {
result = [...result, ...findBuildingIds(node.children)];
}
}
return result;
};
return findBuildingIds(buildingTreeData.value);
};
// 根据类型加载选项
const loadScopeOptions = async () => {
dataLoaded.value = false;
if (isCampusType.value) {
// 调用API获取校区列表
try {
const res = await listDormCampus();
// 适配el-select格式
console.log('校区数据加载成功:', res);
scopeOptions.value = (res.rows || []).map((item: any) => ({
value: item.id,
label: item.campusName
}));
// 校区支持多选,初始化为数组
form.scope = Array.isArray(form.scope) ? form.scope : [];
dataLoaded.value = true;
// 数据加载完成后,处理当前管理员的scope
handleAdminScope();
} catch (error) {
console.error('加载校区数据失败:', error);
dataLoaded.value = true;
}
} else if (isAreaType.value) {
// 宿舍区类型时加载树形数据
try {
const res = await getAreaTree();
if (res && res.data) {
treeData.value = res.data;
console.log('宿舍区树形数据加载成功:', treeData.value);
}
// 宿舍区使用树形选择,支持多选
form.scope = Array.isArray(form.scope) ? form.scope : [];
dataLoaded.value = true;
// 数据加载完成后,处理当前管理员的scope
handleAdminScope();
} catch (error) {
console.error('加载树形数据失败:', error);
dataLoaded.value = true;
}
} else if (isBuildingType.value) {
// 宿舍楼类型时加载树形数据
try {
const res = await getBuildingTree();
if (res && res.data) {
buildingTreeData.value = res.data;
console.log('宿舍楼树形数据加载成功:', buildingTreeData.value);
}
// 宿舍楼使用树形选择,支持多选
form.scope = Array.isArray(form.scope) ? form.scope : [];
dataLoaded.value = true;
// 数据加载完成后,处理当前管理员的scope
handleAdminScope();
} catch (error) {
console.error('加载宿舍楼树形数据失败:', error);
dataLoaded.value = true;
}
} else if (props.type === 'building') {
// 这段代码已被上面的isBuildingType.value条件替代,保留此处以兼容旧代码
// 将在下一次重构时移除
dataLoaded.value = true;
// 数据加载完成后,处理当前管理员的scope
handleAdminScope();
} else {
scopeOptions.value = [];
dataLoaded.value = true;
// 数据加载完成后,处理当前管理员的scope
handleAdminScope();
}
};
// 创建单独的函数处理admin的scope,确保在数据加载完成后执行
const handleAdminScope = () => {
const admin = props.admin;
if (!admin || !dataLoaded.value) return;
// 根据类型决定如何设置scope值
if (isCampusType.value) {
// 校区类型 - 支持多选
if (admin.scope) {
// 判断scope的类型
if (Array.isArray(admin.scope)) {
// 如果已经是数组,直接使用
form.scope = admin.scope;
} else if (typeof admin.scope === 'string') {
// 如果是字符串,需要解析
form.scope = parseScopeString(admin.scope);
} else {
// 其他情况,初始化为空数组
form.scope = [];
}
console.log('校区管理员回显数据:', form.scope);
} else {
form.scope = [];
}
} else if (isAreaType.value) {
// 宿舍区类型 - 支持多选
if (admin.scope) {
if (Array.isArray(admin.scope)) {
// 如果已经是数组,直接使用
form.scope = admin.scope;
} else if (typeof admin.scope === 'string') {
// 如果是字符串,需要解析为树形选择器所需的ID数组
form.scope = parseAreaScopeString(admin.scope);
} else {
form.scope = [];
}
console.log('宿舍区管理员回显数据:', form.scope);
} else {
form.scope = [];
}
} else if (isBuildingType.value) {
// 宿舍楼类型 - 支持多选
if (admin.scope) {
if (Array.isArray(admin.scope)) {
// 如果已经是数组,直接使用
form.scope = admin.scope;
} else if (typeof admin.scope === 'string') {
// 如果是字符串,需要解析为树形选择器所需的ID数组
form.scope = parseBuildingScopeString(admin.scope);
} else {
form.scope = [];
}
console.log('宿舍楼管理员回显数据:', form.scope);
} else {
form.scope = [];
}
} else {
// 其他类型 - 单选
form.scope = admin.scope || '';
}
};
// 监听type变化,动态加载选项
watch(
() => props.type,
() => {
loadScopeOptions();
},
{ immediate: true }
);
// 监听对话框可见性,确保每次打开时都重新加载数据
watch(
() => dialogVisible.value,
(newVal) => {
if (newVal) {
// 对话框打开时,确保重新加载数据
loadScopeOptions();
}
}
);
// 监听admin变化
watch(
() => props.admin,
() => {
// 如果数据已加载完成,则立即处理admin的scope
if (dataLoaded.value) {
handleAdminScope();
}
// 否则,会在loadScopeOptions完成后自动调用handleAdminScope
},
{ deep: true }
);
const submitForm = () => {
// 将form.scope转换为API所需的格式
let result;
if (Array.isArray(form.scope)) {
// 对于多选,发送选中的ID数组
result = {
sourceIds: form.scope
};
} else {
// 对于单选,将字符串ID包装在数组中
result = {
sourceIds: form.scope ? [form.scope] : []
};
}
emit('submit', result);
dialogVisible.value = false;
};
// 在对话框打开时,重置数据状态,防止旧数据影响新的显示
watch(
() => dialogVisible.value,
(newVal) => {
if (newVal) {
// 对话框打开时,先清空数据,确保重新加载
scopeOptions.value = [];
treeData.value = [];
buildingTreeData.value = [];
dataLoaded.value = false;
// 根据类型设置默认值
if (isCampusType.value || isAreaType.value || isBuildingType.value) {
form.scope = [];
} else {
form.scope = '';
}
// 然后加载新数据
loadScopeOptions();
}
}
);
return {
dialogVisible,
form,
formRef,
scopeOptions,
treeData,
buildingTreeData,
submitForm,
isCampusType,
type: computed(() => props.type)
};
}
});
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>