diff --git a/src/components/FileUpload/index.vue b/src/components/FileUpload/index.vue index 2d278c1..a871113 100644 --- a/src/components/FileUpload/index.vue +++ b/src/components/FileUpload/index.vue @@ -49,7 +49,7 @@ @click.stop >
  • - - - - - -
    - - -
    -
    -

    设计人员

    - - 新增设计人员 - -
    - -
    - -
    - + + - - - - -
    -
    - - - - - -
    -
    - 暂无设计人员,请点击"新增设计人员"添加 -
    + + +
    - +
    -

    校审人员

    - - 新增校审人员 - +

    专业人员配置

    +
    + + + 新增专业 + +
    -
    - -
    - - + + 专业 + 设计人员(可多选) + 校审人员(可多选) + + + + + + +
    + + + + - - - - + + + + + + + + + + +
    + +
    +
    + + + + + +
    + + + + + + + + + + +
    +
    +
    + + +
    + 暂无设计人员,请点击"添加设计人员" +
    +
    +
    + + + +
    + +
    +
    + + + + + +
    + + + + + + + + + + +
    +
    +
    + + +
    + 暂无校审人员,请点击"添加校审人员" +
    +
    +
    +
    + + + + - - -
    - - - - - - -
    -
    - 暂无校审人员,请点击"新增校审人员"添加 + 删除专业 + + +
    +
    确认提交 - + 重置
    @@ -167,7 +251,7 @@ import { getCurrentInstance } from 'vue'; import type { ComponentInternalInstance } from 'vue'; import { useUserStoreHook } from '@/store/modules/user'; import { ElMessage, ElLoading } from 'element-plus'; -import { Delete } from '@element-plus/icons-vue'; +import { Delete, Plus } from '@element-plus/icons-vue'; // 修复:添加Plus图标导入 import { designUserAdd, designUserList, systemUserList } from '@/api/design/appointment'; // 获取当前实例 @@ -176,17 +260,43 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance; const userStore = useUserStoreHook(); // 从 store 中获取当前选中的项目 const currentProject = computed(() => userStore.selectedProject); -// 专业字典数据 -const { des_user_major } = toRefs(proxy?.useDict('des_user_major')); +// 专业字典数据 - 增加默认空数组避免undefined +const { des_user_major = ref([]) } = toRefs(proxy?.useDict('des_user_major') || {}); -// 表单数据 +// 调试:打印专业数据 +onMounted(() => { + console.log('专业数据:', des_user_major.value); +}); + +// 表单数据:保持原有数据结构不变 +interface MajorGroup { + userMajor: string | null; // 专业 + persons: Array<{ userId: number | null }>; // 该专业下的多个人员 +} const form = reactive({ projectId: currentProject.value?.id, designLeader: null, // 设计负责人 - // 设计人员列表(包含用户ID和专业) - designers: [] as Array<{ userId: number | null; userMajor: string | null }>, - // 校审人员列表(包含用户ID和专业) - reviewers: [] as Array<{ userId: number | null; userMajor: string | null }> + designers: [] as MajorGroup[], // 设计人员:按专业分组,每组含多个人员 + reviewers: [] as MajorGroup[] // 校审人员:按专业分组,每组含多个人员 +}); + +// 组合配置用于视图展示(专业+设计人员+校审人员) +const combinedConfigs = computed(() => { + // 确保designers和reviewers数组长度一致 + const maxLength = Math.max(form.designers.length, form.reviewers.length); + while (form.designers.length < maxLength) { + form.designers.push(createEmptyMajorGroup()); + } + while (form.reviewers.length < maxLength) { + form.reviewers.push(createEmptyMajorGroup()); + } + + // 组合数据用于视图展示 + return form.designers.map((designerGroup, index) => ({ + userMajor: designerGroup.userMajor, + designPersons: designerGroup.persons, + reviewPersons: form.reviewers[index].persons + })); }); // 表单验证规则 @@ -222,146 +332,215 @@ const designUser = async () => { }); try { const res = await designUserList({ projectId: currentProject.value?.id }); - if (res.code == 200 && res.rows) { - // 清空现有数据 - form.designLeader = null; - form.designers = []; - form.reviewers = []; - if (res.rows.length > 0) { - disabledForm.value = true; - } - // 处理返回的数据,进行回显 - res.rows.forEach((item: any) => { - if (item.userType == 1) { - form.designLeader = item.userId; - } else if (item.userType == 2) { - form.designers.push({ - userId: item.userId, - userMajor: item.userMajor || null - }); - } else if (item.userType == 3) { - form.reviewers.push({ - userId: item.userId, - userMajor: item.userMajor || null - }); - } - }); - // 补全默认空项 - if (form.designers.length === 0) { - form.designers.push({ userId: null, userMajor: null }); - } - if (form.reviewers.length === 0) { - form.reviewers.push({ userId: null, userMajor: null }); - } - } else { - // 添加默认空项 - form.designers.push({ userId: null, userMajor: null }); - form.reviewers.push({ userId: null, userMajor: null }); + // 清空现有数据 + form.designLeader = null; + form.designers = []; + form.reviewers = []; + + if (res.code == 200 && res.rows && res.rows.length > 0) { + disabledForm.value = true; + // 1. 分类整理数据(按用户类型) + const designLeader = res.rows.find((item) => item.userType == 1); + const designerItems = res.rows.filter((item) => item.userType == 2); + const reviewerItems = res.rows.filter((item) => item.userType == 3); + + // 2. 回显设计负责人 + if (designLeader) form.designLeader = designLeader.userId; + + // 3. 回显设计人员(按专业分组) + form.designers = groupPersonByMajor(designerItems); + // 4. 回显校审人员(按专业分组) + form.reviewers = groupPersonByMajor(reviewerItems); } + + // 补全默认空项(至少1个专业分组,每组至少1个人员) + if (form.designers.length == 0) form.designers.push(createEmptyMajorGroup()); + if (form.reviewers.length == 0) form.reviewers.push(createEmptyMajorGroup()); } catch (error) { ElMessage.error('获取配置数据失败'); - form.designers.push({ userId: null, userMajor: null }); - form.reviewers.push({ userId: null, userMajor: null }); + // 异常时初始化默认空项 + form.designers = [createEmptyMajorGroup()]; + form.reviewers = [createEmptyMajorGroup()]; } finally { loading.close(); } }; -/** 添加人员 */ -const addPerson = (type: 'designers' | 'reviewers') => { - form[type].push({ userId: null, userMajor: null }); - // 滚动到最后一个新增元素 +/** 辅助函数:创建空的专业分组(含1个空人员) */ +const createEmptyMajorGroup = (): MajorGroup => ({ + userMajor: null, + persons: [{ userId: null }] +}); + +/** 辅助函数:按专业分组整理人员数据(用于回显) */ +const groupPersonByMajor = (items: any[]): MajorGroup[] => { + const groupMap: Record = {}; + items.forEach((item) => { + const major = item.userMajor || '未分类'; + // 不存在该专业分组则创建 + if (!groupMap[major]) { + groupMap[major] = { userMajor: item.userMajor, persons: [] }; + } + // 添加当前人员到专业分组 + groupMap[major].persons.push({ userId: item.userId }); + }); + // 处理空分组(确保每组至少1个人员) + Object.values(groupMap).forEach((group) => { + if (group.persons.length == 0) group.persons.push({ userId: null }); + }); + return Object.values(groupMap); +}; + +/** 新增专业配置行 */ +const addMajor = () => { + form.designers.push(createEmptyMajorGroup()); + form.reviewers.push(createEmptyMajorGroup()); + + // 滚动到新增的专业配置行 setTimeout(() => { - const elements = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`); - if (elements.length > 0) { - elements[elements.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + const groups = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .animate-fadeIn`); + if (groups.length > 0) { + groups[groups.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } }, 100); }; -/** 移除人员 */ -const removePerson = (type: 'designers' | 'reviewers', index: number) => { - if (form[type].length <= 1) { - ElMessage.warning('至少保留一个人员'); +/** 删除专业配置行 */ +const removeMajor = (configIndex: number) => { + if (form.designers.length <= 1) { + ElMessage.warning('至少保留一个专业配置'); return; } - form[type].splice(index, 1); + form.designers.splice(configIndex, 1); + form.reviewers.splice(configIndex, 1); }; -// ===================== 核心修改:重复校验逻辑 ===================== +/** 给指定专业配置行添加人员 */ +const addPerson = (type: 'designers' | 'reviewers', configIndex: number) => { + form[type][configIndex].persons.push({ userId: null }); + + // 滚动到新增的人员选择框 + setTimeout(() => { + const personSelects = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`); + if (personSelects.length > 0) { + personSelects[personSelects.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } + }, 100); +}; + +/** 从指定专业配置行删除人员 */ +const removePerson = (type: 'designers' | 'reviewers', configIndex: number, personIndex: number) => { + const targetGroup = form[type][configIndex]; + if (targetGroup.persons.length <= 1) { + ElMessage.warning(`该专业至少保留一个${type == 'designers' ? '设计' : '校审'}人员`); + return; + } + targetGroup.persons.splice(personIndex, 1); +}; + +/** 专业变更时:清空当前专业下的人员(避免专业与人员不匹配) */ +const handleMajorChange = (newMajor: string, configIndex: number) => { + // 直接修改原始数据源,确保响应式生效 + form.designers[configIndex].userMajor = newMajor; + form.reviewers[configIndex].userMajor = newMajor; + form.designers[configIndex].persons = [{ userId: null }]; + form.reviewers[configIndex].persons = [{ userId: null }]; + // ElMessage.info(`已重置「${getMajorLabel(newMajor)}」专业下的人员,请重新选择`); +}; + +// ========== 核心:重复校验逻辑 ========== /** * 校验同一角色内(设计/校审)的「专业+人员」组合唯一性 - * @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 checkDuplicate = (current: { userId: number | null }, role: 'designers' | 'reviewers', configIndex: number, personIndex: number) => { + console.log(`校验触发 - 角色: ${role}, 专业索引: ${configIndex}, 人员索引: ${personIndex}, 人员ID: ${current.userId}`); + console.log(form); + + const currentGroup = form[role][configIndex]; + // 未选专业/人员时不校验 + if (!currentGroup.userMajor || !current.userId) return; - // 只获取当前角色的所有人员(设计只查设计,校审只查校审) - const targetList = form[role]; // 生成当前「专业+人员」唯一标识 - const currentKey = `${current.userMajor}-${current.userId}`; + const currentKey = `${currentGroup.userMajor}-${current.userId}`; + let duplicateItem = null; - // 检查当前角色内是否有重复 - const duplicateItem = targetList.find((item, index) => { - // 排除当前操作项本身 - if (index === currentIndex) return false; - // 对比「专业+人员」组合 - return `${item.userMajor}-${item.userId}` === currentKey; + // 1. 检查当前专业配置行内是否有重复人员 + duplicateItem = currentGroup.persons.find((item, idx) => { + return idx !== personIndex && item.userId == current.userId; + }); + if (duplicateItem) { + ElMessage.warning(`当前专业下「${getUserName(current.userId)}」已存在,请重新选择`); + current.userId = null; + return; + } + + // 2. 检查同一角色内其他专业配置行是否有重复(专业+人员唯一) + form[role].forEach((group, gIdx) => { + if (gIdx == configIndex) return; // 跳过当前配置行 + group.persons.forEach((item) => { + if (`${group.userMajor}-${item.userId}` == currentKey) { + duplicateItem = item; + } + }); }); - // 存在重复时提示并清空当前选择 if (duplicateItem) { - ElMessage.warning(`当前「${getMajorLabel(current.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`); - // 清空当前项的选择 + ElMessage.warning(`「${getMajorLabel(currentGroup.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); + 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); + const user = userList.value.find((item: any) => item.userId == userId); return user ? user.nickName : userId; }; -/** 提交表单(补充提交前重复校验) */ +/** 提交表单(保持原有数据结构) */ const submitForm = async () => { if (!leaveFormRef.value) return; try { - // 1. 先做基础表单验证 + // 1. 基础表单验证 await leaveFormRef.value.validate(); - // 2. 提交前二次校验:确保当前角色内无重复(防止手动修改数据绕过实时校验) + // 2. 提交前二次校验:「专业+人员」组合唯一性 let hasDuplicate = false; + const allKeys: string[] = []; + + // 收集所有「专业+人员」组合(设计+校审分开校验) + const collectKeys = (roleGroups: MajorGroup[], roleName: string) => { + roleGroups.forEach((group) => { + if (!group.userMajor) return; + group.persons.forEach((person) => { + if (!person.userId) return; + const key = `${group.userMajor}-${person.userId}`; + if (allKeys.includes(key)) { + hasDuplicate = true; + ElMessage.error(`${roleName}中存在重复的「专业+人员」组合,请检查`); + } + allKeys.push(key); + }); + }); + }; + // 校验设计人员 - 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('校审人员中存在重复的「专业+人员」组合,请检查'); - } - } - // 有重复则终止提交 + collectKeys(form.designers, '设计人员'); if (hasDuplicate) return; - // 3. 构建提交数据(原有逻辑不变) + // 清空临时数组,校验校审人员(不校验设计与校审之间) + allKeys.length = 0; + collectKeys(form.reviewers, '校审人员'); + if (hasDuplicate) return; + + // 3. 构建提交数据(适配后端原有数据格式) const submitData = { projectId: form.projectId, personnel: [ @@ -371,29 +550,33 @@ const submitForm = async () => { userType: 'designLeader', userMajor: null }, - // 设计人员 - ...form.designers.map((designer) => ({ - userId: designer.userId, - userType: 'designer', - userMajor: designer.userMajor - })), - // 校审人员 - ...form.reviewers.map((reviewer) => ({ - userId: reviewer.userId, - userType: 'reviewer', - userMajor: reviewer.userMajor - })) + // 设计人员:展开专业分组,每个人员单独作为一条数据 + ...form.designers.flatMap((group) => + group.persons.map((person) => ({ + userId: person.userId, + userType: 'designer', + userMajor: group.userMajor + })) + ), + // 校审人员:展开专业分组,每个人员单独作为一条数据 + ...form.reviewers.flatMap((group) => + group.persons.map((person) => ({ + userId: person.userId, + userType: 'reviewer', + userMajor: group.userMajor + })) + ) ] }; - // 数据处理(原有逻辑不变) + // 4. 数据处理(保持原有逻辑不变) const arr = []; userList.value.forEach((item) => { submitData.personnel.forEach((item1) => { - if (item1.userId === item.userId) { + if (item1.userId == item.userId) { let userType = 1; - if (item1.userType === 'designer') userType = 2; - else if (item1.userType === 'reviewer') userType = 3; + if (item1.userType == 'designer') userType = 2; + else if (item1.userType == 'reviewer') userType = 3; arr.push({ userName: item.nickName, projectId: submitData.projectId, @@ -405,13 +588,13 @@ const submitForm = async () => { }); }); - // 4. 提交到后端(原有逻辑不变) + // 5. 提交到后端(保持原有逻辑不变) const loading = ElLoading.service({ text: '提交中...', background: 'rgba(255,255,255,0.7)' }); const res = await designUserAdd({ list: arr, projectId: currentProject.value?.id }); - if (res.code === 200) { + if (res.code == 200) { disabledForm.value = true; ElMessage.success('提交成功'); } else { @@ -424,12 +607,13 @@ const submitForm = async () => { } }; -/** 重置表单 */ +/** 重置表单(适配新数据结构) */ const resetForm = () => { if (leaveFormRef.value) { leaveFormRef.value.resetFields(); - form.designers = [{ userId: null, userMajor: null }]; - form.reviewers = [{ userId: null, userMajor: null }]; + // 重置为默认空状态(1个专业分组,每组1个空人员) + form.designers = [createEmptyMajorGroup()]; + form.reviewers = [createEmptyMajorGroup()]; ElMessage.info('表单已重置'); } }; @@ -446,7 +630,7 @@ const listeningProject: WatchStopHandle = watch( // 页面生命周期 onUnmounted(() => { - listeningProject(); // 修复原代码watchStopHandle调用问题 + listeningProject(); }); onMounted(() => { getDeptAllUser(userStore.deptId).then(() => { @@ -455,16 +639,19 @@ onMounted(() => { }); - diff --git a/src/views/design/drawing/index copy.vue b/src/views/design/drawing/index copy.vue deleted file mode 100644 index e7b87c9..0000000 --- a/src/views/design/drawing/index copy.vue +++ /dev/null @@ -1,321 +0,0 @@ - - - - diff --git a/src/views/design/drawing/index.vue b/src/views/design/drawing/index.vue index 6c352b0..c05d284 100644 --- a/src/views/design/drawing/index.vue +++ b/src/views/design/drawing/index.vue @@ -44,6 +44,7 @@ target="_blank" :type="scope.row.status == '1' ? 'primary' : 'info'" :underline="false" + @click="handleBookFile(scope.row)" > {{ scope.row.fileName }} @@ -207,6 +208,9 @@ const handleDownload = (row: any) => { getCheck(row); proxy?.$download.oss(row.fileId); }; +const handleBookFile = (row: any) => { + getCheck(row); +}; // 调用查阅接口 const getCheck = async (row) => { volumeFileViewer({ volumeFileId: row.fileId }); diff --git a/src/views/design/volumeCatalog/index.vue b/src/views/design/volumeCatalog/index.vue index 7f989ee..bb72e43 100644 --- a/src/views/design/volumeCatalog/index.vue +++ b/src/views/design/volumeCatalog/index.vue @@ -25,7 +25,7 @@ 新增 - + @@ -94,7 +94,7 @@ v-hasPermi="['design:volumeFile:add']" >上传图纸 - 查看单据 + > --> @@ -159,53 +159,98 @@
    - + - - + + - - 确定 - 取消 + + + + + + 注意:请上传pdf格式文件 +
    + 确定 + 取消 +
    - - - - - - - - - - - - - - -
    暂无文件
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @@ -242,6 +287,7 @@ const ids = ref>([]); const histroyRef = ref>(); const single = ref(true); const multiple = ref(true); +const activeName = ref('first'); const total = ref(0); const dialogHistory = ref(false); // 获取用户 store @@ -259,9 +305,11 @@ const dialog = reactive({ const uploadForm = reactive({ userIds: [], volumeCatalogId: undefined, - fileId: undefined, + fileIds: undefined, + cancellationIds: undefined, explainText: '', fileList: [], + type: '1', cancellationIds: [] // 用于存储已作废的文件ID }); const examineForm = ref({ @@ -419,10 +467,12 @@ const handleUpload = async (row?: any) => { const resetUploadForm = () => { uploadForm.userIds = []; uploadForm.volumeCatalogId = undefined; - uploadForm.fileId = undefined; + uploadForm.fileIds = undefined; + uploadForm.cancellationIds = undefined; uploadForm.explainText = ''; uploadForm.fileList = []; - uploadForm.cancellationIds = []; // 重置作废文件ID列表 + uploadForm.type = '1'; + uploadForm.cancellationIds = []; }; /** 提交按钮 */ @@ -449,10 +499,19 @@ const handleDownload = (row: any) => { /** 上传文件提交 */ const onSubmit = async () => { buttonLoading.value = true; + let cancellationIds = []; + let fileIds = []; + if (uploadForm.cancellationIds && uploadForm.cancellationIds.length > 0) { + cancellationIds = uploadForm.cancellationIds.split(','); + } + if (uploadForm.fileIds && uploadForm.fileIds.length > 0) { + fileIds = uploadForm.fileIds.split(','); + } let obj = { volumeCatalogId: uploadForm.volumeCatalogId, - fileIds: uploadForm.fileId.split(','), - explainText: '' + fileIds: fileIds, + cancellationIds: cancellationIds, + type: uploadForm.type }; try { await uploadVolumeFile(obj); @@ -511,7 +570,13 @@ const handleUpdate = async (row?: VolumeCatalogVO) => { dialog.visible = true; dialog.title = '修改设计出图计划'; }; - +// 过程图纸 +const handleClick = () => { + // +}; +const handleAuditInfo = (row) => { + // 审核图纸 +}; onMounted(() => { getUserAppList(); getList();