优化
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();
|
||||
});
|
||||
|
@ -22,7 +22,7 @@
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
|
@ -22,7 +22,7 @@
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
|
@ -12,7 +12,14 @@
|
||||
<h3 class="text-lg font-semibold text-gray-800">下发变更通知信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form ref="leaveFormRef" :disabled="routeParams.type === 'view'" :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
|
@ -19,7 +19,14 @@
|
||||
<h3 class="text-lg font-semibold text-gray-800">变更图纸信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form ref="leaveFormRef" :disabled="routeParams.type === 'view'" :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="图纸文件" prop="fileId" class="mb-2 md:col-span-2">
|
||||
<file-upload :fileType="['pdf']" :fileSize="''" v-model="form.fileId" class="w-full"></file-upload>
|
||||
|
@ -19,23 +19,20 @@
|
||||
<h3 class="text-lg font-semibold text-gray-800">图纸评审</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-form ref="leaveFormRef" :disabled="routeParams.type === 'view'" :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<el-form-item label="图纸文件" v-for="value in form.fileVoList" :key="value.id" prop="fileId" class="mb-2 md:col-span-2">
|
||||
<el-input v-model="value.fileName" disabled placeholder="图纸名称" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
:disabled="routeParams.type === 'view' || form.auditStatus == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<el-form-item label="图纸文件" v-for="value in form.fileVoList" :key="value.id" prop="fileId" class="mb-2 md:col-span-2">
|
||||
<el-input v-model="value.fileName" disabled placeholder="图纸名称" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
|
@ -23,7 +23,7 @@
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
|
@ -23,7 +23,7 @@
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
|
@ -23,7 +23,7 @@
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
|
@ -22,7 +22,7 @@
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view'"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
|
Reference in New Issue
Block a user