441 lines
14 KiB
Vue
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>
|