设计出图

This commit is contained in:
2025-08-18 20:02:07 +08:00
parent 12e80c57d3
commit 9e2cf9c73a
5 changed files with 573 additions and 610 deletions

View File

@ -49,7 +49,7 @@
@click.stop @click.stop
> >
<li <li
style="margin-bottom: 10px" style="margin-top: 10px;"
v-for="(file, index) in fileList" v-for="(file, index) in fileList"
:key="file.uid" :key="file.uid"
class="el-upload-list__item ele-upload-list__item-content" class="el-upload-list__item ele-upload-list__item-content"

View File

@ -13,134 +13,212 @@
<el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6"> <el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6">
<!-- 设计负责人 --> <!-- 设计负责人 -->
<div class="fonts"> <div class="fonts">
<el-form-item label="设计负责人" prop="designLeader" class="mb-4"> <el-row>
<el-select <el-col :span="8"
v-model="form.designLeader" ><el-form-item label="设计负责人" prop="designLeader" class="mb-4">
placeholder="请选择设计负责人"
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
</div>
<!-- 设计人员 -->
<div class="border border-gray-200 rounded-lg p-5 transition-all duration-300 hover:shadow-md bg-gray-50">
<div class="flex justify-between items-center mb-5">
<h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-user mr-2 text-blue-500"></i>设计人员</h3>
<el-button
type="primary"
size="small"
@click="addPerson('designers')"
class="transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600"
>
<i class="el-icon-plus mr-1"></i>新增设计人员
</el-button>
</div>
<div v-for="(designer, index) in form.designers" :key="index" class="flex items-center mb-4 animate-fadeIn">
<el-form-item
:prop="`designers.${index}.userId`"
:rules="{ required: true, message: '请选择设计人员', trigger: 'change' }"
class="flex-1 mr-3"
>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 设计人员专业选择绑定重复校验 -->
<el-select <el-select
v-model="designer.userMajor" v-model="form.designLeader"
placeholder="请选择专业" placeholder="请选择设计负责人"
class="transition-all duration-300 border-gray-300" class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
: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"
@change="() => checkDuplicate(designer, 'designers', index)"
> >
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select> </el-select>
</div> </el-form-item>
</el-form-item> </el-col>
<el-button </el-row>
type="danger"
size="small"
@click="removePerson('designers', index)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="form.designers.length <= 1"
>
<el-icon :size="16">
<Delete />
</el-icon>
</el-button>
</div>
<div v-if="form.designers.length === 0" class="text-gray-500 text-center py-4 bg-gray-100 rounded-lg border border-dashed border-gray-200">
暂无设计人员请点击"新增设计人员"添加
</div>
</div> </div>
<!-- 校审人员 --> <!-- 专业人员配置专业 + 设计人员 + 校审人员 横向排列 -->
<div class="border border-gray-200 rounded-lg p-5 transition-all duration-300 hover:shadow-md bg-gray-50"> <div class="border border-gray-200 rounded-lg p-5 transition-all duration-300 hover:shadow-md bg-gray-50">
<div class="flex justify-between items-center mb-5"> <div class="flex justify-between items-center mb-5">
<h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-check-circle mr-2 text-green-500"></i>校审人员</h3> <h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-users mr-2 text-blue-500"></i>专业人员配置</h3>
<el-button <div class="flex gap-3">
type="primary" <!-- 新增专业按钮 -->
size="small" <el-button type="primary" size="small" :disabled="disabledForm" @click="addMajor">
@click="addPerson('reviewers')" <i class="el-icon-plus mr-1"></i>新增专业
class="transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600" </el-button>
> </div>
<i class="el-icon-plus mr-1"></i>新增校审人员
</el-button>
</div> </div>
<div v-for="(reviewer, index) in form.reviewers" :key="index" class="flex items-center mb-4 animate-fadeIn"> <!-- 表头 -->
<el-form-item <el-row :gutter="20" class="mb-3 font-medium text-gray-700">
:prop="`reviewers.${index}.userId`" <el-col :span="6" :xs="24" :sm="8">专业</el-col>
:rules="{ required: true, message: '请选择校审人员', trigger: 'change' }" <el-col :span="9" :xs="24" :sm="8">设计人员可多选</el-col>
class="flex-1 mr-3" <el-col :span="9" :xs="24" :sm="8">校审人员可多选</el-col>
> </el-row>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 校审人员专业选择绑定重复校验 --> <!-- 分割线 -->
<el-select <el-divider class="my-4" />
v-model="reviewer.userMajor"
placeholder="请选择专业" <!-- 专业配置行专业+ 设计人员+ 校审人员 横向排列 -->
class="transition-all duration-300 border-gray-300" <div
v-for="(majorConfig, configIndex) in combinedConfigs"
:key="configIndex"
style="background: aliceblue; border-radius: 10px"
class="mb-5 animate-fadeIn"
>
<el-row :gutter="20" class="items-top">
<!-- 左侧专业选择 -->
<el-col :span="6" :xs="24" :sm="8" class="mb-4 sm:mb-0" style="margin-top: 8px">
<el-form-item
:prop="`designers.${configIndex}.userMajor`"
:rules="{ required: true, message: '请选择专业', trigger: 'change' }" :rules="{ required: true, message: '请选择专业', trigger: 'change' }"
@change="() => checkDuplicate(reviewer, 'reviewers', index)" class="mb-0"
label-width="80px"
label="专业"
> >
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" /> <!-- 专业选择下拉框 -->
</el-select> <el-select
<!-- 校审人员选择绑定重复校验 --> v-model="form.designers[configIndex].userMajor"
<el-select placeholder="请选择专业"
v-model="reviewer.userId" class="w-full transition-all duration-300 border-gray-300"
placeholder="请选择校审人员" @change="(val) => handleMajorChange(val, configIndex)"
class="transition-all duration-300 border-gray-300" >
@change="() => checkDuplicate(reviewer, 'reviewers', index)" <!-- 临时添加调试显示 -->
<template v-if="des_user_major && des_user_major.length > 0">
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
</template>
<template v-else>
<el-option label="无专业数据" value="" disabled />
</template>
</el-select>
</el-form-item>
</el-col>
<!-- 中间设计人员 -->
<el-col :span="9" :xs="24" :sm="8" class="mb-4 sm:mb-0">
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-blue-200 py-0 sm:py-2">
<!-- 设计人员列表 -->
<div class="space-y-3">
<div v-for="(person, personIndex) in majorConfig.designPersons" :key="personIndex" class="flex items-center">
<el-form-item
:prop="`designers.${configIndex}.persons.${personIndex}.userId`"
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
class="flex-1 mr-3 mb-0"
label="设计人员"
label-width="80px"
>
<el-select
v-model="person.userId"
placeholder="请选择设计人员"
class="w-full transition-all duration-300 border-gray-300"
@change="() => checkDuplicate(person, 'designers', configIndex, personIndex)"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<div>
<el-button
type="danger"
size="small"
@click="removePerson('designers', configIndex, personIndex)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="majorConfig.designPersons.length <= 1 || disabledForm"
>
<el-icon :size="16">
<Delete />
</el-icon>
</el-button>
<el-button
type="success"
size="small"
@click="addPerson('designers', configIndex)"
class="transition-all duration-300 transform hover:scale-105"
:disabled="!majorConfig.userMajor || disabledForm"
>
<el-icon :size="16">
<Plus />
</el-icon>
</el-button>
</div>
</div>
</div>
<!-- 空状态提示 -->
<div
v-if="majorConfig.designPersons.length == 0"
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
>
暂无设计人员请点击"添加设计人员"
</div>
</div>
</el-col>
<!-- 右侧校审人员 -->
<el-col :span="9" :xs="24" :sm="8">
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-green-200 py-0 sm:py-2">
<!-- 校审人员列表 -->
<div class="space-y-3">
<div v-for="(person, personIndex) in majorConfig.reviewPersons" :key="personIndex" class="flex items-center">
<el-form-item
:prop="`reviewers.${configIndex}.persons.${personIndex}.userId`"
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
class="flex-1 mr-3 mb-0"
label="校审人员"
label-width="80px"
>
<el-select
v-model="person.userId"
placeholder="请选择校审人员"
class="w-full transition-all duration-300 border-gray-300"
@change="() => checkDuplicate(person, 'reviewers', configIndex, personIndex)"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<div>
<el-button
type="danger"
size="small"
@click="removePerson('reviewers', configIndex, personIndex)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="majorConfig.reviewPersons.length <= 1 || disabledForm"
>
<el-icon :size="16">
<Delete />
</el-icon>
</el-button>
<el-button
type="success"
size="small"
@click="addPerson('reviewers', configIndex)"
class="transition-all duration-300 transform hover:scale-105"
:disabled="!majorConfig.userMajor || disabledForm"
>
<el-icon :size="16">
<Plus />
</el-icon>
</el-button>
</div>
</div>
</div>
<!-- 空状态提示 -->
<div
v-if="majorConfig.reviewPersons.length == 0"
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
>
暂无校审人员请点击"添加校审人员"
</div>
</div>
</el-col>
</el-row>
<!-- 删除专业配置行 -->
<el-row class="mt-2">
<el-col :span="24" class="text-right pr-4">
<el-button
type="text"
class="text-red-500 hover:text-red-700 transition-colors"
@click="removeMajor(configIndex)"
:disabled="combinedConfigs.length <= 1 || disabledForm"
> >
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> <i class="el-icon-delete mr-1"></i>删除专业
</el-select> </el-button>
</div> </el-col>
</el-form-item> </el-row>
<el-button
type="danger"
size="small"
@click="removePerson('reviewers', index)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="form.reviewers.length <= 1"
>
<el-icon :size="16">
<Delete />
</el-icon>
</el-button>
</div>
<div v-if="form.reviewers.length === 0" class="text-gray-500 text-center py-4 bg-gray-100 rounded-lg border border-dashed border-gray-200">
暂无校审人员请点击"新增校审人员"添加
</div> </div>
</div> </div>
<!-- 提交按钮区域 --> <!-- 提交按钮区域 -->
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100"> <div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100">
<el-button <el-button
@ -149,10 +227,16 @@
v-hasPermi="['design:user:batch']" v-hasPermi="['design:user:batch']"
@click="submitForm" @click="submitForm"
class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium" class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium"
:disabled="disabledForm"
> >
<i class="el-icon-check mr-2"></i>确认提交 <i class="el-icon-check mr-2"></i>确认提交
</el-button> </el-button>
<el-button size="large" @click="resetForm" class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium"> <el-button
size="large"
@click="resetForm"
class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium"
:disabled="disabledForm"
>
<i class="el-icon-refresh mr-2"></i>重置 <i class="el-icon-refresh mr-2"></i>重置
</el-button> </el-button>
</div> </div>
@ -167,7 +251,7 @@ import { getCurrentInstance } from 'vue';
import type { ComponentInternalInstance } from 'vue'; import type { ComponentInternalInstance } from 'vue';
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from '@/store/modules/user';
import { ElMessage, ElLoading } from 'element-plus'; 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'; import { designUserAdd, designUserList, systemUserList } from '@/api/design/appointment';
// 获取当前实例 // 获取当前实例
@ -176,17 +260,43 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStoreHook(); const userStore = useUserStoreHook();
// 从 store 中获取当前选中的项目 // 从 store 中获取当前选中的项目
const currentProject = computed(() => userStore.selectedProject); const currentProject = computed(() => userStore.selectedProject);
// 专业字典数据 // 专业字典数据 - 增加默认空数组避免undefined
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major')); const { des_user_major = ref([]) } = toRefs<any>(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({ const form = reactive({
projectId: currentProject.value?.id, projectId: currentProject.value?.id,
designLeader: null, // 设计负责人 designLeader: null, // 设计负责人
// 设计人员列表包含用户ID和专业 designers: [] as MajorGroup[], // 设计人员:按专业分组,每组含多个人员
designers: [] as Array<{ userId: number | null; userMajor: string | null }>, reviewers: [] as MajorGroup[] // 校审人员:按专业分组,每组含多个人员
// 校审人员列表包含用户ID和专业 });
reviewers: [] as Array<{ userId: number | null; userMajor: string | null }>
// 组合配置用于视图展示(专业+设计人员+校审人员)
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 { try {
const res = await designUserList({ projectId: currentProject.value?.id }); const res = await designUserList({ projectId: currentProject.value?.id });
if (res.code == 200 && res.rows) { // 清空现有数据
// 清空现有数据 form.designLeader = null;
form.designLeader = null; form.designers = [];
form.designers = []; form.reviewers = [];
form.reviewers = [];
if (res.rows.length > 0) { if (res.code == 200 && res.rows && res.rows.length > 0) {
disabledForm.value = true; disabledForm.value = true;
} // 1. 分类整理数据(按用户类型)
// 处理返回的数据,进行回显 const designLeader = res.rows.find((item) => item.userType == 1);
res.rows.forEach((item: any) => { const designerItems = res.rows.filter((item) => item.userType == 2);
if (item.userType == 1) { const reviewerItems = res.rows.filter((item) => item.userType == 3);
form.designLeader = item.userId;
} else if (item.userType == 2) { // 2. 回显设计负责人
form.designers.push({ if (designLeader) form.designLeader = designLeader.userId;
userId: item.userId,
userMajor: item.userMajor || null // 3. 回显设计人员(按专业分组)
}); form.designers = groupPersonByMajor(designerItems);
} else if (item.userType == 3) { // 4. 回显校审人员(按专业分组)
form.reviewers.push({ form.reviewers = groupPersonByMajor(reviewerItems);
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 });
} }
// 补全默认空项至少1个专业分组每组至少1个人员
if (form.designers.length == 0) form.designers.push(createEmptyMajorGroup());
if (form.reviewers.length == 0) form.reviewers.push(createEmptyMajorGroup());
} catch (error) { } catch (error) {
ElMessage.error('获取配置数据失败'); ElMessage.error('获取配置数据失败');
form.designers.push({ userId: null, userMajor: null }); // 异常时初始化默认空项
form.reviewers.push({ userId: null, userMajor: null }); form.designers = [createEmptyMajorGroup()];
form.reviewers = [createEmptyMajorGroup()];
} finally { } finally {
loading.close(); loading.close();
} }
}; };
/** 添加人员 */ /** 辅助函数创建空的专业分组含1个空人员 */
const addPerson = (type: 'designers' | 'reviewers') => { const createEmptyMajorGroup = (): MajorGroup => ({
form[type].push({ userId: null, userMajor: null }); userMajor: null,
// 滚动到最后一个新增元素 persons: [{ userId: null }]
});
/** 辅助函数:按专业分组整理人员数据(用于回显) */
const groupPersonByMajor = (items: any[]): MajorGroup[] => {
const groupMap: Record<string, MajorGroup> = {};
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(() => { setTimeout(() => {
const elements = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`); const groups = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .animate-fadeIn`);
if (elements.length > 0) { if (groups.length > 0) {
elements[elements.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' }); groups[groups.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
} }
}, 100); }, 100);
}; };
/** 移除人员 */ /** 删除专业配置行 */
const removePerson = (type: 'designers' | 'reviewers', index: number) => { const removeMajor = (configIndex: number) => {
if (form[type].length <= 1) { if (form.designers.length <= 1) {
ElMessage.warning('至少保留一个人员'); ElMessage.warning('至少保留一个专业配置');
return; 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) => { const checkDuplicate = (current: { userId: number | null }, role: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
// 未选完专业/人员时不校验 console.log(`校验触发 - 角色: ${role}, 专业索引: ${configIndex}, 人员索引: ${personIndex}, 人员ID: ${current.userId}`);
if (!current.userId || !current.userMajor) return; 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;
// 检查当前角色内是否有重复 // 1. 检查当前专业配置行内是否有重复人员
const duplicateItem = targetList.find((item, index) => { duplicateItem = currentGroup.persons.find((item, idx) => {
// 排除当前操作项本身 return idx !== personIndex && item.userId == current.userId;
if (index === currentIndex) return false; });
// 对比「专业+人员」组合 if (duplicateItem) {
return `${item.userMajor}-${item.userId}` === currentKey; 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) { if (duplicateItem) {
ElMessage.warning(`当前${getMajorLabel(current.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`); ElMessage.warning(`${getMajorLabel(currentGroup.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`);
// 清空当前项的选择
current.userId = null; current.userId = null;
current.userMajor = null;
} }
}; };
/** 辅助函数:通过专业值获取专业名称 */ /** 辅助函数:通过专业值获取专业名称 */
const getMajorLabel = (majorValue: string | null) => { const getMajorLabel = (majorValue: string | null) => {
if (!majorValue || !des_user_major.value) return ''; 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; return major ? major.label : majorValue;
}; };
/** 辅助函数通过用户ID获取用户名 */ /** 辅助函数通过用户ID获取用户名 */
const getUserName = (userId: number | null) => { const getUserName = (userId: number | null) => {
if (!userId || !userList.value.length) return ''; 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; return user ? user.nickName : userId;
}; };
/** 提交表单(补充提交前重复校验 */ /** 提交表单(保持原有数据结构 */
const submitForm = async () => { const submitForm = async () => {
if (!leaveFormRef.value) return; if (!leaveFormRef.value) return;
try { try {
// 1. 先做基础表单验证 // 1. 基础表单验证
await leaveFormRef.value.validate(); await leaveFormRef.value.validate();
// 2. 提交前二次校验:确保当前角色内无重复(防止手动修改数据绕过实时校验) // 2. 提交前二次校验:「专业+人员」组合唯一性
let hasDuplicate = false; 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}`); collectKeys(form.designers, '设计人员');
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; if (hasDuplicate) return;
// 3. 构建提交数据(原有逻辑不变 // 清空临时数组,校验校审人员(不校验设计与校审之间
allKeys.length = 0;
collectKeys(form.reviewers, '校审人员');
if (hasDuplicate) return;
// 3. 构建提交数据(适配后端原有数据格式)
const submitData = { const submitData = {
projectId: form.projectId, projectId: form.projectId,
personnel: [ personnel: [
@ -371,29 +550,33 @@ const submitForm = async () => {
userType: 'designLeader', userType: 'designLeader',
userMajor: null userMajor: null
}, },
// 设计人员 // 设计人员:展开专业分组,每个人员单独作为一条数据
...form.designers.map((designer) => ({ ...form.designers.flatMap((group) =>
userId: designer.userId, group.persons.map((person) => ({
userType: 'designer', userId: person.userId,
userMajor: designer.userMajor userType: 'designer',
})), userMajor: group.userMajor
// 校审人员 }))
...form.reviewers.map((reviewer) => ({ ),
userId: reviewer.userId, // 校审人员:展开专业分组,每个人员单独作为一条数据
userType: 'reviewer', ...form.reviewers.flatMap((group) =>
userMajor: reviewer.userMajor group.persons.map((person) => ({
})) userId: person.userId,
userType: 'reviewer',
userMajor: group.userMajor
}))
)
] ]
}; };
// 数据处理(原有逻辑不变) // 4. 数据处理(保持原有逻辑不变)
const arr = []; const arr = [];
userList.value.forEach((item) => { userList.value.forEach((item) => {
submitData.personnel.forEach((item1) => { submitData.personnel.forEach((item1) => {
if (item1.userId === item.userId) { if (item1.userId == item.userId) {
let userType = 1; let userType = 1;
if (item1.userType === 'designer') userType = 2; if (item1.userType == 'designer') userType = 2;
else if (item1.userType === 'reviewer') userType = 3; else if (item1.userType == 'reviewer') userType = 3;
arr.push({ arr.push({
userName: item.nickName, userName: item.nickName,
projectId: submitData.projectId, 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 loading = ElLoading.service({ text: '提交中...', background: 'rgba(255,255,255,0.7)' });
const res = await designUserAdd({ const res = await designUserAdd({
list: arr, list: arr,
projectId: currentProject.value?.id projectId: currentProject.value?.id
}); });
if (res.code === 200) { if (res.code == 200) {
disabledForm.value = true; disabledForm.value = true;
ElMessage.success('提交成功'); ElMessage.success('提交成功');
} else { } else {
@ -424,12 +607,13 @@ const submitForm = async () => {
} }
}; };
/** 重置表单 */ /** 重置表单(适配新数据结构) */
const resetForm = () => { const resetForm = () => {
if (leaveFormRef.value) { if (leaveFormRef.value) {
leaveFormRef.value.resetFields(); leaveFormRef.value.resetFields();
form.designers = [{ userId: null, userMajor: null }]; // 重置为默认空状态1个专业分组每组1个空人员
form.reviewers = [{ userId: null, userMajor: null }]; form.designers = [createEmptyMajorGroup()];
form.reviewers = [createEmptyMajorGroup()];
ElMessage.info('表单已重置'); ElMessage.info('表单已重置');
} }
}; };
@ -446,7 +630,7 @@ const listeningProject: WatchStopHandle = watch(
// 页面生命周期 // 页面生命周期
onUnmounted(() => { onUnmounted(() => {
listeningProject(); // 修复原代码watchStopHandle调用问题 listeningProject();
}); });
onMounted(() => { onMounted(() => {
getDeptAllUser(userStore.deptId).then(() => { getDeptAllUser(userStore.deptId).then(() => {
@ -455,16 +639,19 @@ onMounted(() => {
}); });
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.appWidth { .appWidth {
width: 50vw; width: 70vw;
max-width: 1200px; max-width: 1600px;
.el-select__wrapper { .el-select__wrapper {
width: 16vw !important; width: 100% !important;
} }
.el-button--small { .el-button--small {
margin-bottom: 10px; margin-bottom: 0;
} }
.fonts { .fonts {
.el-form-item--default .el-form-item__label { .el-form-item--default .el-form-item__label {
font-size: 18px !important; font-size: 18px !important;
@ -499,7 +686,6 @@ onMounted(() => {
&__label { &__label {
font-weight: 500; font-weight: 500;
color: #4e5969; color: #4e5969;
padding: 0 0 8px 0;
} }
&__content { &__content {
@ -539,6 +725,21 @@ onMounted(() => {
} }
} }
&--success {
background-color: #67c23a;
border-color: #67c23a;
&:hover {
background-color: #85ce61;
border-color: #85ce61;
}
&:disabled {
background-color: #b3e099;
border-color: #b3e099;
}
}
&--danger { &--danger {
background-color: #f56c6c; background-color: #f56c6c;
border-color: #f56c6c; border-color: #f56c6c;
@ -554,6 +755,15 @@ onMounted(() => {
cursor: not-allowed; cursor: not-allowed;
} }
} }
&--text {
color: #f56c6c;
&:hover {
color: #f78989;
background-color: rgba(245, 108, 108, 0.05);
}
}
} }
// 响应式网格布局 // 响应式网格布局
@ -573,7 +783,7 @@ onMounted(() => {
gap: 1rem; gap: 1rem;
} }
// 适配小屏幕 // 适配小屏幕小于768px时垂直排列
@media (max-width: 768px) { @media (max-width: 768px) {
.appWidth { .appWidth {
width: 95vw; width: 95vw;
@ -586,5 +796,10 @@ onMounted(() => {
::v-deep .el-form-item__label { ::v-deep .el-form-item__label {
width: 100px; width: 100px;
} }
// 小屏幕下各列上下间距
::v-deep .el-col-xs-24 + .el-col-xs-24 {
margin-top: 12px;
}
} }
</style> </style>

View File

@ -1,321 +0,0 @@
<template>
<div class="p-2 bg-gray-50" style="padding: 20px;">
<!-- <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="文件名称" prop="fileName">
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="原文件名" prop="originalName">
<el-input v-model="queryParams.originalName" placeholder="请输入原文件名" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="是否最新" prop="newest">
<el-select v-model="queryParams.newest" placeholder="请选择" clearable>
<el-option label="是" :value="1" />
<el-option label="否" :value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition> -->
<div class="drawing">
<div class="file-category">
<span style="color: #757575; display: inline-block; margin-bottom: 15px">卷册目录</span>
<div
v-for="(item, i) of volumeCatalogList"
:key="i"
:class="{ active: currentActive === i }"
@click="handleClick(item, i)"
class="category-item"
>
<el-icon :size="20" class="folder-icon">
<Folder />
</el-icon>
<span class="folder-name">
{{ item.volumeNumber }}
</span>
</div>
</div>
<div class="boxs">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<DrawingTable
:drawingList="drawingList"
:loading="loading"
:drawing_file_type="drawing_file_type"
:wf_business_status="wf_business_status"
@selection-change="handleSelectionChange"
@view="handleView"
@update="handleUpdate"
@delete="handleDelete"
@view-info="handleViewInfo"
@cancel-process-apply="handleCancelProcessApply"
/>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
</div>
</div>
</div>
</template>
<script setup name="Drawing" lang="ts">
import { listDrawing, delDrawing } from '@/api/design/drawing';
import { DrawingVO } from '@/api/design/drawing/types';
import { useUserStoreHook } from '@/store/modules/user';
import { LeaveVO } from '@/api/workflow/leave/types';
import { cancelProcessApply } from '@/api/workflow/instance';
import DrawingTable from './DrawingTable.vue';
import { listVolumeCatalog } from '@/api/design/volumeCatalog';
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { drawing_file_type, wf_business_status } = toRefs<any>(proxy?.useDict('drawing_file_type', 'wf_business_status'));
console.log(drawing_file_type);
// 当前激活项的索引
const currentActive = ref(0);
const volumeCatalogList = ref([]);
const drawingList = ref<DrawingVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const activeName = ref('1');
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
fileName: undefined,
fileSuffix: undefined,
fileStatus: undefined,
originalName: undefined,
newest: undefined,
volumeCatalogId: undefined, //卷册目录id
params: {}
}
});
const { queryParams } = toRefs(data);
/** 查询图纸管理列表 */
const getList = async () => {
loading.value = true;
const res = await listDrawing(queryParams.value);
drawingList.value = res.rows;
total.value = res.total;
loading.value = false;
};
// 点击事件处理函数
const handleClick = (item, index) => {
console.log(item);
currentActive.value = index;
queryParams.value.volumeCatalogId = item.design;
getList();
};
/** 查询卷册目录列表 */
const getlistVolume = async () => {
const res = await listVolumeCatalog({ projectId: currentProject.value?.id });
volumeCatalogList.value = res.rows;
if (res.rows.length) {
queryParams.value.volumeCatalogId = res.rows[0].id;
getList();
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: DrawingVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 修改按钮操作 */
const handleUpdate = async (row?: DrawingVO) => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
path: `/design-management/drawing/indexEdit`,
query: {
id: row.id,
type: 'update'
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: DrawingVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除图纸管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delDrawing(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
const handleView = (row) => {
var url = row.file.url;
window.open(url, '_blank');
};
/** 查看按钮操作 */
const handleViewInfo = (row?: LeaveVO) => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
path: `/design-management/drawing/indexEdit`,
query: {
id: row.id,
type: 'view'
}
});
};
/** 撤销按钮操作 */
const handleCancelProcessApply = async (id: string) => {
await proxy?.$modal.confirm('是否确认撤销当前单据?');
loading.value = true;
const data = {
businessId: id,
message: '申请人撤销流程!'
};
await cancelProcessApply(data).finally(() => (loading.value = false));
await getList();
proxy?.$modal.msgSuccess('撤销成功');
};
onMounted(() => {
getlistVolume();
});
//监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
getlistVolume();
}
);
onUnmounted(() => {
listeningProject();
});
</script>
<style lang="scss">
.drawing {
display: flex;
.el-tabs__header {
height: 90vh !important;
}
.file-category {
width: 200px;
display: flex;
flex-direction: column;
background-color: #f7f7f79e;
padding: 10px;
border-radius: 6px;
margin-right: 10px;
height: 84vh;
}
.file-category > div {
cursor: pointer;
padding: 8px 12px;
margin-bottom: 4px;
border-radius: 4px;
display: flex;
white-space: nowrap;
transition: all 0.2s ease;
> span {
margin-left: 6px;
}
}
.file-category {
width: 200px;
display: flex;
flex-direction: column;
background-color: #f7f7f79e;
padding: 10px;
border-radius: 8px;
margin-right: 10px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
// 分类项样式优化
.category-item {
cursor: pointer;
padding: 10px 12px;
margin-bottom: 4px;
border-radius: 6px;
display: inline-flex;
align-items: center; /* 垂直居中对齐 */
white-space: nowrap;
transition: all 0.25s ease;
font-size: 14px;
color: #334155;
line-height: 1; /* 确保行高一致 */
&:hover {
background-color: #f1f5f9;
transform: translateX(2px);
}
}
// 图标样式
.folder-icon {
color: #94a3b8;
transition: color 0.25s ease;
}
// 文件夹名称样式
.folder-name {
margin-left: 8px; /* 增加图标与文字间距 */
overflow: hidden;
text-overflow: ellipsis;
max-width: calc(100% - 30px); /* 限制最大宽度,防止溢出 */
}
// 活跃状态样式
.category-item.active {
background-color: #eff6ff;
color: #2563eb;
font-weight: 500;
.folder-icon {
color: #2563eb;
}
}
.boxs {
width: calc(100% - 220px);
}
}
</style>

View File

@ -44,6 +44,7 @@
target="_blank" target="_blank"
:type="scope.row.status == '1' ? 'primary' : 'info'" :type="scope.row.status == '1' ? 'primary' : 'info'"
:underline="false" :underline="false"
@click="handleBookFile(scope.row)"
> >
{{ scope.row.fileName }} {{ scope.row.fileName }}
</el-link> </el-link>
@ -207,6 +208,9 @@ const handleDownload = (row: any) => {
getCheck(row); getCheck(row);
proxy?.$download.oss(row.fileId); proxy?.$download.oss(row.fileId);
}; };
const handleBookFile = (row: any) => {
getCheck(row);
};
// 调用查阅接口 // 调用查阅接口
const getCheck = async (row) => { const getCheck = async (row) => {
volumeFileViewer({ volumeFileId: row.fileId }); volumeFileViewer({ volumeFileId: row.fileId });

View File

@ -25,7 +25,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:volumeCatalog:add']">新增</el-button> <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:volumeCatalog:add']">新增</el-button>
</el-col> </el-col>
<!-- <el-col :span="1.5"> <el-col :span="1.5">
<file-upload <file-upload
v-model="form.file" v-model="form.file"
isImportInfo isImportInfo
@ -41,7 +41,7 @@
> >
<el-button type="warning" plain icon="Upload">导入</el-button> <el-button type="warning" plain icon="Upload">导入</el-button>
</file-upload> </file-upload>
</el-col> --> </el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
</template> </template>
@ -94,7 +94,7 @@
v-hasPermi="['design:volumeFile:add']" v-hasPermi="['design:volumeFile:add']"
>上传图纸</el-button >上传图纸</el-button
> >
<el-button <!-- <el-button
link link
type="primary" type="primary"
icon="edit" icon="edit"
@ -112,7 +112,7 @@
v-if="scope.row.auditType == 'back' || scope.row.auditStatus == 'termination'" v-if="scope.row.auditType == 'back' || scope.row.auditStatus == 'termination'"
@click="handleViewHistory(scope.row)" @click="handleViewHistory(scope.row)"
>查看单据</el-button >查看单据</el-button
> > -->
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -159,53 +159,98 @@
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog draggable title="上传图纸卷册文件" v-model="uploadVisible" width="500px" append-to-body> <el-dialog draggable title="上传图纸文件" v-model="uploadVisible" width="500px" append-to-body>
<el-form :model="uploadForm" label-width="80px" :inline="false"> <el-form :model="uploadForm" label-width="80px" :inline="false">
<el-form-item label="上传文件" prop="fileId"> <el-form-item label="蓝图" prop="type">
<file-upload :fileType="['pdf']" :fileSize="''" v-model="uploadForm.fileId"></file-upload> <el-select v-model="uploadForm.type" placeholder="请选择图纸类型"
><el-option label="过程图纸" value="1" /><el-option label="蓝图" value="3"
/></el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item v-if="uploadForm.type == '3'" label="蓝图" prop="fileIds">
<el-button type="primary" @click="onSubmit" :loading="buttonLoading">确定</el-button> <file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.fileIds"></file-upload>
<el-button @click="uploadVisible = false">取消</el-button> </el-form-item>
<el-form-item v-if="uploadForm.type == '1'" label="过程图纸" prop="cancellationIds">
<file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.cancellationIds"></file-upload>
</el-form-item> </el-form-item>
</el-form> </el-form>
<span style="font-size: 12px; color: #999999">注意:请上传pdf格式文件</span>
<div style="display: flex; justify-content: flex-end">
<el-button type="primary" @click="onSubmit" :loading="buttonLoading">确定</el-button>
<el-button @click="uploadVisible = false">取消</el-button>
</div>
</el-dialog> </el-dialog>
<!-- 查看文件列表 --> <!-- 查看文件列表 -->
<el-dialog draggable title="文件列表" v-model="viewVisible" width="45%"> <el-dialog draggable title="文件列表" v-model="viewVisible" width="45%">
<el-table v-if="fileList.length > 0" :data="fileList" style="width: 100%" border> <el-tabs type="border-card" v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-table-column prop="fileName" label="文件" align="center"> <el-tab-pane label="蓝图" name="first"
<template #default="scope"> ><el-table :data="fileList" style="width: 100%" border>
<el-link <el-table-column prop="fileName" label="文件" align="center">
:key="scope.row.fileId" <template #default="scope">
:href="scope.row.fileUrl" <el-link
target="_blank" :key="scope.row.fileId"
:type="scope.row.status == '1' ? 'primary' : 'info'" :href="scope.row.fileUrl"
:underline="false" target="_blank"
> :type="scope.row.status == '1' ? 'primary' : 'info'"
{{ scope.row.fileName }} :underline="false"
</el-link> >
</template> {{ scope.row.fileName }}
</el-table-column> </el-link>
<el-table-column prop="size" label="是否变更" align="center" width="120"> </template>
<template #default="scope"> </el-table-column>
<el-tag :type="scope.row.type == 1 ? 'success' : 'info'">{{ scope.row.type == 1 ? '否' : '是' }}</el-tag> <el-table-column prop="size" label="是否变更" align="center" width="120">
</template> <template #default="scope">
</el-table-column> <el-tag :type="scope.row.type == 1 ? 'success' : 'info'">{{ scope.row.type == 1 ? '否' : '是' }}</el-tag>
<el-table-column prop="size" label="状态" width="120" align="center"> </template>
<template #default="scope"> </el-table-column>
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">{{ scope.row.status == 1 ? '使用中' : '已作废' }}</el-tag> <el-table-column prop="size" label="状态" width="120" align="center">
</template> <template #default="scope">
</el-table-column> <el-tag :type="scope.row.status == 1 ? 'success' : 'info'">{{ scope.row.status == 1 ? '使用中' : '已作废' }}</el-tag>
<el-table-column label="操作" width="170" align="center"> </template>
<template #default="scope"> </el-table-column>
<el-button type="danger" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button> <el-table-column label="操作" width="170" align="center">
</template> <template #default="scope">
</el-table-column> <el-button type="danger" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button>
</el-table> </template>
<div v-else class="empty-list text-center">暂无文件</div> </el-table-column>
</el-table></el-tab-pane
>
<el-tab-pane label="过程图纸 " name="second"
><el-table :data="fileList" style="width: 100%" border>
<el-table-column prop="fileName" label="文件" align="center">
<template #default="scope">
<el-link
:key="scope.row.fileId"
:href="scope.row.fileUrl"
target="_blank"
:type="scope.row.status == '1' ? 'primary' : 'info'"
:underline="false"
>
{{ scope.row.fileName }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="size" label="是否变更" align="center" width="120">
<template #default="scope">
<el-tag :type="scope.row.type == 1 ? 'success' : 'info'">{{ scope.row.type == 1 ? '否' : '是' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="size" label="状态" width="120" align="center">
<template #default="scope">
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">{{ scope.row.status == 1 ? '使用中' : '已作废' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="170" align="center">
<template #default="scope">
<el-button type="primary" v-if="activeName === 'second'" @click="handleAuditInfo(scope.row)">审核过程图纸</el-button>
<el-button type="danger" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button>
</template>
</el-table-column>
</el-table></el-tab-pane
>
</el-tabs>
<template #footer> <template #footer>
<span> <span>
<el-button type="primary" @click="viewVisible = false">关闭</el-button> <el-button type="danger" @click="viewVisible = false">关闭</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -242,6 +287,7 @@ const ids = ref<Array<string | number>>([]);
const histroyRef = ref<InstanceType<typeof histroy>>(); const histroyRef = ref<InstanceType<typeof histroy>>();
const single = ref(true); const single = ref(true);
const multiple = ref(true); const multiple = ref(true);
const activeName = ref('first');
const total = ref(0); const total = ref(0);
const dialogHistory = ref(false); const dialogHistory = ref(false);
// 获取用户 store // 获取用户 store
@ -259,9 +305,11 @@ const dialog = reactive<DialogOption>({
const uploadForm = reactive({ const uploadForm = reactive({
userIds: [], userIds: [],
volumeCatalogId: undefined, volumeCatalogId: undefined,
fileId: undefined, fileIds: undefined,
cancellationIds: undefined,
explainText: '', explainText: '',
fileList: [], fileList: [],
type: '1',
cancellationIds: [] // 用于存储已作废的文件ID cancellationIds: [] // 用于存储已作废的文件ID
}); });
const examineForm = ref({ const examineForm = ref({
@ -419,10 +467,12 @@ const handleUpload = async (row?: any) => {
const resetUploadForm = () => { const resetUploadForm = () => {
uploadForm.userIds = []; uploadForm.userIds = [];
uploadForm.volumeCatalogId = undefined; uploadForm.volumeCatalogId = undefined;
uploadForm.fileId = undefined; uploadForm.fileIds = undefined;
uploadForm.cancellationIds = undefined;
uploadForm.explainText = ''; uploadForm.explainText = '';
uploadForm.fileList = []; uploadForm.fileList = [];
uploadForm.cancellationIds = []; // 重置作废文件ID列表 uploadForm.type = '1';
uploadForm.cancellationIds = [];
}; };
/** 提交按钮 */ /** 提交按钮 */
@ -449,10 +499,19 @@ const handleDownload = (row: any) => {
/** 上传文件提交 */ /** 上传文件提交 */
const onSubmit = async () => { const onSubmit = async () => {
buttonLoading.value = true; 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 = { let obj = {
volumeCatalogId: uploadForm.volumeCatalogId, volumeCatalogId: uploadForm.volumeCatalogId,
fileIds: uploadForm.fileId.split(','), fileIds: fileIds,
explainText: '' cancellationIds: cancellationIds,
type: uploadForm.type
}; };
try { try {
await uploadVolumeFile(obj); await uploadVolumeFile(obj);
@ -511,7 +570,13 @@ const handleUpdate = async (row?: VolumeCatalogVO) => {
dialog.visible = true; dialog.visible = true;
dialog.title = '修改设计出图计划'; dialog.title = '修改设计出图计划';
}; };
// 过程图纸
const handleClick = () => {
//
};
const handleAuditInfo = (row) => {
// 审核图纸
};
onMounted(() => { onMounted(() => {
getUserAppList(); getUserAppList();
getList(); getList();