优化
This commit is contained in:
		| @ -8,7 +8,6 @@ | ||||
|         <el-button @click="disabledForm = false" class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="disabledForm"> | ||||
|           点击编辑 | ||||
|         </el-button> | ||||
|         <!-- ,带 <span class="text-red-300">*</span> 为必填项 --> | ||||
|       </div> | ||||
|       <!-- 表单内容区域 --> | ||||
|       <el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6"> | ||||
| @ -46,15 +45,23 @@ | ||||
|               class="flex-1 mr-3" | ||||
|             > | ||||
|               <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | ||||
|                 <!-- 设计人员专业选择(绑定重复校验) --> | ||||
|                 <el-select | ||||
|                   v-model="designer.userMajor" | ||||
|                   placeholder="请选择专业" | ||||
|                   class="transition-all duration-300 border-gray-300" | ||||
|                   :rules="{ required: true, message: '请选择专业', trigger: 'change' }" | ||||
|                   @change="() => checkDuplicate(designer, 'designers', index)" | ||||
|                 > | ||||
|                   <el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" /> | ||||
|                 </el-select> | ||||
|                 <el-select v-model="designer.userId" placeholder="请选择设计人员" class="transition-all duration-300 border-gray-300"> | ||||
|                 <!-- 设计人员选择(绑定重复校验) --> | ||||
|                 <el-select | ||||
|                   v-model="designer.userId" | ||||
|                   placeholder="请选择设计人员" | ||||
|                   class="transition-all duration-300 border-gray-300" | ||||
|                   @change="() => checkDuplicate(designer, 'designers', index)" | ||||
|                 > | ||||
|                   <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> | ||||
|                 </el-select> | ||||
|               </div> | ||||
| @ -97,15 +104,23 @@ | ||||
|               class="flex-1 mr-3" | ||||
|             > | ||||
|               <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | ||||
|                 <!-- 校审人员专业选择(绑定重复校验) --> | ||||
|                 <el-select | ||||
|                   v-model="reviewer.userMajor" | ||||
|                   placeholder="请选择专业" | ||||
|                   class="transition-all duration-300 border-gray-300" | ||||
|                   :rules="{ required: true, message: '请选择专业', trigger: 'change' }" | ||||
|                   @change="() => checkDuplicate(reviewer, 'reviewers', index)" | ||||
|                 > | ||||
|                   <el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" /> | ||||
|                 </el-select> | ||||
|                 <el-select v-model="reviewer.userId" placeholder="请选择校审人员" class="transition-all duration-300 border-gray-300"> | ||||
|                 <!-- 校审人员选择(绑定重复校验) --> | ||||
|                 <el-select | ||||
|                   v-model="reviewer.userId" | ||||
|                   placeholder="请选择校审人员" | ||||
|                   class="transition-all duration-300 border-gray-300" | ||||
|                   @change="() => checkDuplicate(reviewer, 'reviewers', index)" | ||||
|                 > | ||||
|                   <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> | ||||
|                 </el-select> | ||||
|               </div> | ||||
| @ -146,7 +161,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup name="PersonnelForm" lang="ts"> | ||||
| import { ref, reactive, computed, onMounted, toRefs } from 'vue'; | ||||
| import { ref, reactive, computed, onMounted, toRefs, watch, WatchStopHandle } from 'vue'; | ||||
| import { getCurrentInstance } from 'vue'; | ||||
| import type { ComponentInternalInstance } from 'vue'; | ||||
| import { useUserStoreHook } from '@/store/modules/user'; | ||||
| @ -184,11 +199,11 @@ const userList = ref([]); | ||||
| // 表单引用 | ||||
| const leaveFormRef = ref(); | ||||
| const disabledForm = ref(false); //控制提交按钮状态 | ||||
|  | ||||
| /** 查询当前部门的所有用户 */ | ||||
| const getDeptAllUser = async (deptId: any) => { | ||||
|   try { | ||||
|     const res = await systemUserList({ deptId }); | ||||
|     // 实际项目中使用接口返回的数据 | ||||
|     userList.value = res.rows; | ||||
|   } catch (error) { | ||||
|     ElMessage.error('获取用户列表失败'); | ||||
| @ -217,37 +232,20 @@ const designUser = async () => { | ||||
|       // 处理返回的数据,进行回显 | ||||
|       res.rows.forEach((item: any) => { | ||||
|         if (item.userType == 1) { | ||||
|           item.userType = 'designLeader'; | ||||
|           form.designLeader = item.userId; | ||||
|         } else if (item.userType == 2) { | ||||
|           item.userType = 'designer'; | ||||
|           form.designers.push({ | ||||
|             userId: item.userId, | ||||
|             userMajor: item.userMajor || null | ||||
|           }); | ||||
|         } else if (item.userType == 3) { | ||||
|           item.userType = 'reviewer'; | ||||
|         } | ||||
|         // 根据userType区分不同类型的人员 | ||||
|         switch (item.userType) { | ||||
|           case 'designLeader': | ||||
|           case 1: | ||||
|             form.designLeader = item.userId; | ||||
|             break; | ||||
|  | ||||
|           case 'designer': | ||||
|           case 2: | ||||
|             form.designers.push({ | ||||
|               userId: item.userId, | ||||
|               userMajor: item.userMajor || null | ||||
|             }); | ||||
|             break; | ||||
|  | ||||
|           case 'reviewer': | ||||
|           case 3: | ||||
|             form.reviewers.push({ | ||||
|               userId: item.userId, | ||||
|               userMajor: item.userMajor || null | ||||
|             }); | ||||
|             break; | ||||
|           form.reviewers.push({ | ||||
|             userId: item.userId, | ||||
|             userMajor: item.userMajor || null | ||||
|           }); | ||||
|         } | ||||
|       }); | ||||
|       // 如果没有设计人员或校审人员,添加一个空项 | ||||
|       // 补全默认空项 | ||||
|       if (form.designers.length === 0) { | ||||
|         form.designers.push({ userId: null, userMajor: null }); | ||||
|       } | ||||
| @ -261,7 +259,6 @@ const designUser = async () => { | ||||
|     } | ||||
|   } catch (error) { | ||||
|     ElMessage.error('获取配置数据失败'); | ||||
|     // 添加默认空项 | ||||
|     form.designers.push({ userId: null, userMajor: null }); | ||||
|     form.reviewers.push({ userId: null, userMajor: null }); | ||||
|   } finally { | ||||
| @ -272,7 +269,7 @@ const designUser = async () => { | ||||
| /** 添加人员 */ | ||||
| const addPerson = (type: 'designers' | 'reviewers') => { | ||||
|   form[type].push({ userId: null, userMajor: null }); | ||||
|   // 滚动到最后一个新增的元素 | ||||
|   // 滚动到最后一个新增元素 | ||||
|   setTimeout(() => { | ||||
|     const elements = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`); | ||||
|     if (elements.length > 0) { | ||||
| @ -290,48 +287,112 @@ const removePerson = (type: 'designers' | 'reviewers', index: number) => { | ||||
|   form[type].splice(index, 1); | ||||
| }; | ||||
|  | ||||
| /** 提交表单 */ | ||||
| // ===================== 核心修改:重复校验逻辑 ===================== | ||||
| /** | ||||
|  * 校验同一角色内(设计/校审)的「专业+人员」组合唯一性 | ||||
|  * @param current 当前操作的人员对象 | ||||
|  * @param role 角色类型(designers/reviewers) | ||||
|  * @param currentIndex 当前操作的索引 | ||||
|  */ | ||||
| const checkDuplicate = (current: { userId: number | null; userMajor: string | null }, role: 'designers' | 'reviewers', currentIndex: number) => { | ||||
|   // 未选完专业/人员时不校验 | ||||
|   if (!current.userId || !current.userMajor) return; | ||||
|  | ||||
|   // 只获取当前角色的所有人员(设计只查设计,校审只查校审) | ||||
|   const targetList = form[role]; | ||||
|   // 生成当前「专业+人员」唯一标识 | ||||
|   const currentKey = `${current.userMajor}-${current.userId}`; | ||||
|  | ||||
|   // 检查当前角色内是否有重复 | ||||
|   const duplicateItem = targetList.find((item, index) => { | ||||
|     // 排除当前操作项本身 | ||||
|     if (index === currentIndex) return false; | ||||
|     // 对比「专业+人员」组合 | ||||
|     return `${item.userMajor}-${item.userId}` === currentKey; | ||||
|   }); | ||||
|  | ||||
|   // 存在重复时提示并清空当前选择 | ||||
|   if (duplicateItem) { | ||||
|     ElMessage.warning(`当前「${getMajorLabel(current.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`); | ||||
|     // 清空当前项的选择 | ||||
|     current.userId = null; | ||||
|     current.userMajor = null; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** 辅助函数:通过专业值获取专业名称 */ | ||||
| const getMajorLabel = (majorValue: string | null) => { | ||||
|   if (!majorValue || !des_user_major.value) return ''; | ||||
|   const major = des_user_major.value.find((item: any) => item.value === majorValue); | ||||
|   return major ? major.label : majorValue; | ||||
| }; | ||||
|  | ||||
| /** 辅助函数:通过用户ID获取用户名 */ | ||||
| const getUserName = (userId: number | null) => { | ||||
|   if (!userId || !userList.value.length) return ''; | ||||
|   const user = userList.value.find((item: any) => item.userId === userId); | ||||
|   return user ? user.nickName : userId; | ||||
| }; | ||||
|  | ||||
| /** 提交表单(补充提交前重复校验) */ | ||||
| const submitForm = async () => { | ||||
|   if (!leaveFormRef.value) return; | ||||
|   try { | ||||
|     // 表单验证 | ||||
|     // 1. 先做基础表单验证 | ||||
|     await leaveFormRef.value.validate(); | ||||
|     // 构建提交数据 - 所有人员信息放在一个数组中 | ||||
|  | ||||
|     // 2. 提交前二次校验:确保当前角色内无重复(防止手动修改数据绕过实时校验) | ||||
|     let hasDuplicate = false; | ||||
|     // 校验设计人员 | ||||
|     const designKeys = form.designers.map((item) => `${item.userMajor}-${item.userId}`); | ||||
|     if (new Set(designKeys).size !== designKeys.length) { | ||||
|       hasDuplicate = true; | ||||
|       ElMessage.error('设计人员中存在重复的「专业+人员」组合,请检查'); | ||||
|     } | ||||
|     // 校验校审人员(不校验设计与校审之间) | ||||
|     if (!hasDuplicate) { | ||||
|       const reviewKeys = form.reviewers.map((item) => `${item.userMajor}-${item.userId}`); | ||||
|       if (new Set(reviewKeys).size !== reviewKeys.length) { | ||||
|         hasDuplicate = true; | ||||
|         ElMessage.error('校审人员中存在重复的「专业+人员」组合,请检查'); | ||||
|       } | ||||
|     } | ||||
|     // 有重复则终止提交 | ||||
|     if (hasDuplicate) return; | ||||
|  | ||||
|     // 3. 构建提交数据(原有逻辑不变) | ||||
|     const submitData = { | ||||
|       projectId: form.projectId, | ||||
|       personnel: [ | ||||
|         // 设计负责人 | ||||
|         { | ||||
|           userId: form.designLeader, | ||||
|           userType: 'designLeader', // 设计负责人类型标识 | ||||
|           userMajor: null // 负责人不需要专业 | ||||
|           userType: 'designLeader', | ||||
|           userMajor: null | ||||
|         }, | ||||
|         // 设计人员 | ||||
|         ...form.designers.map((designer) => ({ | ||||
|           userId: designer.userId, | ||||
|           userType: 'designer', // 设计人员类型标识 | ||||
|           userMajor: designer.userMajor // 包含专业信息 | ||||
|           userType: 'designer', | ||||
|           userMajor: designer.userMajor | ||||
|         })), | ||||
|         // 校审人员 | ||||
|         ...form.reviewers.map((reviewer) => ({ | ||||
|           userId: reviewer.userId, | ||||
|           userType: 'reviewer', // 校审人员类型标识 | ||||
|           userMajor: reviewer.userMajor // 包含专业信息 | ||||
|           userType: 'reviewer', | ||||
|           userMajor: reviewer.userMajor | ||||
|         })) | ||||
|       ] | ||||
|     }; | ||||
|  | ||||
|     // 数据处理 | ||||
|     // 数据处理(原有逻辑不变) | ||||
|     const arr = []; | ||||
|     userList.value.forEach((item) => { | ||||
|       submitData.personnel.forEach((item1) => { | ||||
|         if (item1.userId === item.userId) { | ||||
|           let userType = 1; // 默认为设计负责人 | ||||
|           if (item1.userType === 'designer') { | ||||
|             userType = 2; // 设计人员 | ||||
|           } else if (item1.userType === 'reviewer') { | ||||
|             userType = 3; // 校审人员 | ||||
|           } | ||||
|           let userType = 1; | ||||
|           if (item1.userType === 'designer') userType = 2; | ||||
|           else if (item1.userType === 'reviewer') userType = 3; | ||||
|           arr.push({ | ||||
|             userName: item.nickName, | ||||
|             projectId: submitData.projectId, | ||||
| @ -343,7 +404,8 @@ const submitForm = async () => { | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
|     // 提交到后端 | ||||
|     // 4. 提交到后端(原有逻辑不变) | ||||
|     const loading = ElLoading.service({ text: '提交中...', background: 'rgba(255,255,255,0.7)' }); | ||||
|     const res = await designUserAdd({ | ||||
|       list: arr, | ||||
|       projectId: currentProject.value?.id | ||||
| @ -357,7 +419,6 @@ const submitForm = async () => { | ||||
|   } catch (error) { | ||||
|     ElMessage.error('请完善表单信息后再提交'); | ||||
|   } finally { | ||||
|     // 关闭加载状态 | ||||
|     ElLoading.service().close(); | ||||
|   } | ||||
| }; | ||||
| @ -371,22 +432,22 @@ const resetForm = () => { | ||||
|     ElMessage.info('表单已重置'); | ||||
|   } | ||||
| }; | ||||
| //监听项目id刷新数据 | ||||
| const listeningProject = watch( | ||||
|  | ||||
| // 监听项目ID刷新数据 | ||||
| const listeningProject: WatchStopHandle = watch( | ||||
|   () => currentProject.value?.id, | ||||
|   (nid, oid) => { | ||||
|   () => { | ||||
|     getDeptAllUser(userStore.deptId).then(() => { | ||||
|       designUser(); | ||||
|     }); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| // 页面生命周期 | ||||
| onUnmounted(() => { | ||||
|   listeningProject(); | ||||
|   listeningProject(); // 修复原代码watchStopHandle调用问题 | ||||
| }); | ||||
| // 页面挂载时初始化数据 | ||||
| onMounted(() => { | ||||
|   // 先获取用户列表,再加载表单数据 | ||||
|   getDeptAllUser(userStore.deptId).then(() => { | ||||
|     designUser(); | ||||
|   }); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user