|
|
@@ -5,18 +5,70 @@
|
|
|
<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="isCampusType"
|
|
|
+ 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>
|
|
|
@@ -31,6 +83,10 @@
|
|
|
<script lang="ts">
|
|
|
import { defineComponent, ref, reactive, computed, watch, onMounted } from 'vue';
|
|
|
import { listDormCampus } from '@/api/xqxx/dormCampus';
|
|
|
+import { getAreaTree } from '@/api/ssqxx/dormArea';
|
|
|
+import { getBuildingTree } from '@/api/sslxx/dormBuilding';
|
|
|
+import type { TreeSelectVo } from '@/api/ssqxx/dormArea/types';
|
|
|
+import type { BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types';
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'ScopeDialog',
|
|
|
@@ -59,47 +115,231 @@ export default defineComponent({
|
|
|
|
|
|
// 判断是否为校区类型的计算属性
|
|
|
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 ? [] : ''
|
|
|
+ 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获取校区列表
|
|
|
- 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 : [];
|
|
|
- } else if (props.type === 'area') {
|
|
|
- scopeOptions.value = [
|
|
|
- { value: '1号宿舍区', label: '1号宿舍区' },
|
|
|
- { value: '2号宿舍区', label: '2号宿舍区' },
|
|
|
- { value: '3号宿舍区', label: '3号宿舍区' }
|
|
|
- ];
|
|
|
- // 非校区为单选,初始化为字符串
|
|
|
- form.scope = Array.isArray(form.scope) ? '' : form.scope;
|
|
|
+ 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') {
|
|
|
- scopeOptions.value = [
|
|
|
- { value: '1号楼', label: '1号楼' },
|
|
|
- { value: '2号楼', label: '2号楼' },
|
|
|
- { value: '3号楼', label: '3号楼' },
|
|
|
- { value: '4号楼', label: '4号楼' }
|
|
|
- ];
|
|
|
- // 非校区为单选,初始化为字符串
|
|
|
- form.scope = Array.isArray(form.scope) ? '' : form.scope;
|
|
|
+ // 这段代码已被上面的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 || '';
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -112,35 +352,82 @@ export default defineComponent({
|
|
|
{ immediate: true }
|
|
|
);
|
|
|
|
|
|
+ // 监听对话框可见性,确保每次打开时都重新加载数据
|
|
|
watch(
|
|
|
- () => props.admin,
|
|
|
+ () => dialogVisible.value,
|
|
|
(newVal) => {
|
|
|
- if (newVal && newVal.scope) {
|
|
|
- // 根据类型决定如何设置scope值
|
|
|
- if (isCampusType.value) {
|
|
|
- // 校区支持多选,确保scope是数组
|
|
|
- form.scope = Array.isArray(newVal.scope) ? newVal.scope : [newVal.scope];
|
|
|
- } else {
|
|
|
- // 其他类型是单选
|
|
|
- form.scope = newVal.scope;
|
|
|
- }
|
|
|
+ if (newVal) {
|
|
|
+ // 对话框打开时,确保重新加载数据
|
|
|
+ loadScopeOptions();
|
|
|
}
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 监听admin变化
|
|
|
+ watch(
|
|
|
+ () => props.admin,
|
|
|
+ () => {
|
|
|
+ // 如果数据已加载完成,则立即处理admin的scope
|
|
|
+ if (dataLoaded.value) {
|
|
|
+ handleAdminScope();
|
|
|
+ }
|
|
|
+ // 否则,会在loadScopeOptions完成后自动调用handleAdminScope
|
|
|
},
|
|
|
- { deep: true, immediate: true }
|
|
|
+ { deep: true }
|
|
|
);
|
|
|
|
|
|
const submitForm = () => {
|
|
|
- emit('submit', form.scope);
|
|
|
+ // 将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
|
|
|
+ isCampusType,
|
|
|
+ type: computed(() => props.type)
|
|
|
};
|
|
|
}
|
|
|
});
|