设计出图
This commit is contained in:
@ -49,7 +49,7 @@
|
||||
@click.stop
|
||||
>
|
||||
<li
|
||||
style="margin-bottom: 10px"
|
||||
style="margin-top: 10px;"
|
||||
v-for="(file, index) in fileList"
|
||||
:key="file.uid"
|
||||
class="el-upload-list__item ele-upload-list__item-content"
|
||||
|
@ -13,134 +13,212 @@
|
||||
<el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6">
|
||||
<!-- 设计负责人 -->
|
||||
<div class="fonts">
|
||||
<el-form-item label="设计负责人" prop="designLeader" class="mb-4">
|
||||
<el-select
|
||||
v-model="form.designLeader"
|
||||
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-row>
|
||||
<el-col :span="8"
|
||||
><el-form-item label="设计负责人" prop="designLeader" class="mb-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"
|
||||
@change="() => checkDuplicate(designer, 'designers', index)"
|
||||
v-model="form.designLeader"
|
||||
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>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-button
|
||||
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>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</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-check-circle mr-2 text-green-500"></i>校审人员</h3>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="addPerson('reviewers')"
|
||||
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>
|
||||
<h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-users mr-2 text-blue-500"></i>专业人员配置</h3>
|
||||
<div class="flex gap-3">
|
||||
<!-- 新增专业按钮 -->
|
||||
<el-button type="primary" size="small" :disabled="disabledForm" @click="addMajor">
|
||||
<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
|
||||
:prop="`reviewers.${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
|
||||
v-model="reviewer.userMajor"
|
||||
placeholder="请选择专业"
|
||||
class="transition-all duration-300 border-gray-300"
|
||||
<!-- 表头 -->
|
||||
<el-row :gutter="20" class="mb-3 font-medium text-gray-700">
|
||||
<el-col :span="6" :xs="24" :sm="8">专业</el-col>
|
||||
<el-col :span="9" :xs="24" :sm="8">设计人员(可多选)</el-col>
|
||||
<el-col :span="9" :xs="24" :sm="8">校审人员(可多选)</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<el-divider class="my-4" />
|
||||
|
||||
<!-- 专业配置行:专业(左)+ 设计人员(中)+ 校审人员(右) 横向排列 -->
|
||||
<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' }"
|
||||
@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="reviewer.userId"
|
||||
placeholder="请选择校审人员"
|
||||
class="transition-all duration-300 border-gray-300"
|
||||
@change="() => checkDuplicate(reviewer, 'reviewers', index)"
|
||||
<!-- 专业选择下拉框 -->
|
||||
<el-select
|
||||
v-model="form.designers[configIndex].userMajor"
|
||||
placeholder="请选择专业"
|
||||
class="w-full transition-all duration-300 border-gray-300"
|
||||
@change="(val) => handleMajorChange(val, configIndex)"
|
||||
>
|
||||
<!-- 临时添加调试显示 -->
|
||||
<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" />
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<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">
|
||||
暂无校审人员,请点击"新增校审人员"添加
|
||||
<i class="el-icon-delete mr-1"></i>删除专业
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提交按钮区域 -->
|
||||
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100">
|
||||
<el-button
|
||||
@ -149,10 +227,16 @@
|
||||
v-hasPermi="['design:user:batch']"
|
||||
@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"
|
||||
:disabled="disabledForm"
|
||||
>
|
||||
<i class="el-icon-check mr-2"></i>确认提交
|
||||
</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>重置
|
||||
</el-button>
|
||||
</div>
|
||||
@ -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<any>(proxy?.useDict('des_user_major'));
|
||||
// 专业字典数据 - 增加默认空数组避免undefined
|
||||
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({
|
||||
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<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(() => {
|
||||
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(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.appWidth {
|
||||
width: 50vw;
|
||||
max-width: 1200px;
|
||||
width: 70vw;
|
||||
max-width: 1600px;
|
||||
|
||||
.el-select__wrapper {
|
||||
width: 16vw !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.el-button--small {
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.fonts {
|
||||
.el-form-item--default .el-form-item__label {
|
||||
font-size: 18px !important;
|
||||
@ -499,7 +686,6 @@ onMounted(() => {
|
||||
&__label {
|
||||
font-weight: 500;
|
||||
color: #4e5969;
|
||||
padding: 0 0 8px 0;
|
||||
}
|
||||
|
||||
&__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 {
|
||||
background-color: #f56c6c;
|
||||
border-color: #f56c6c;
|
||||
@ -554,6 +755,15 @@ onMounted(() => {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&--text {
|
||||
color: #f56c6c;
|
||||
|
||||
&:hover {
|
||||
color: #f78989;
|
||||
background-color: rgba(245, 108, 108, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式网格布局
|
||||
@ -573,7 +783,7 @@ onMounted(() => {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
// 适配小屏幕
|
||||
// 适配小屏幕(小于768px时,垂直排列)
|
||||
@media (max-width: 768px) {
|
||||
.appWidth {
|
||||
width: 95vw;
|
||||
@ -586,5 +796,10 @@ onMounted(() => {
|
||||
::v-deep .el-form-item__label {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
// 小屏幕下各列上下间距
|
||||
::v-deep .el-col-xs-24 + .el-col-xs-24 {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -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>
|
@ -44,6 +44,7 @@
|
||||
target="_blank"
|
||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||
:underline="false"
|
||||
@click="handleBookFile(scope.row)"
|
||||
>
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
@ -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 });
|
||||
|
@ -25,7 +25,7 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:volumeCatalog:add']">新增</el-button>
|
||||
</el-col>
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-col :span="1.5">
|
||||
<file-upload
|
||||
v-model="form.file"
|
||||
isImportInfo
|
||||
@ -41,7 +41,7 @@
|
||||
>
|
||||
<el-button type="warning" plain icon="Upload">导入</el-button>
|
||||
</file-upload>
|
||||
</el-col> -->
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
@ -94,7 +94,7 @@
|
||||
v-hasPermi="['design:volumeFile:add']"
|
||||
>上传图纸</el-button
|
||||
>
|
||||
<el-button
|
||||
<!-- <el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="edit"
|
||||
@ -112,7 +112,7 @@
|
||||
v-if="scope.row.auditType == 'back' || scope.row.auditStatus == 'termination'"
|
||||
@click="handleViewHistory(scope.row)"
|
||||
>查看单据</el-button
|
||||
>
|
||||
> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -159,53 +159,98 @@
|
||||
</div>
|
||||
</template>
|
||||
</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-item label="上传文件" prop="fileId">
|
||||
<file-upload :fileType="['pdf']" :fileSize="''" v-model="uploadForm.fileId"></file-upload>
|
||||
<el-form-item label="蓝图" prop="type">
|
||||
<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-button type="primary" @click="onSubmit" :loading="buttonLoading">确定</el-button>
|
||||
<el-button @click="uploadVisible = false">取消</el-button>
|
||||
<el-form-item v-if="uploadForm.type == '3'" label="蓝图" prop="fileIds">
|
||||
<file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.fileIds"></file-upload>
|
||||
</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>
|
||||
<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 draggable title="文件列表" v-model="viewVisible" width="45%">
|
||||
<el-table v-if="fileList.length > 0" :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="danger" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-else class="empty-list text-center">暂无文件</div>
|
||||
<el-tabs type="border-card" v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="蓝图" name="first"
|
||||
><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="danger" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button>
|
||||
</template>
|
||||
</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>
|
||||
<span>
|
||||
<el-button type="primary" @click="viewVisible = false">关闭</el-button>
|
||||
<el-button type="danger" @click="viewVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -242,6 +287,7 @@ const ids = ref<Array<string | number>>([]);
|
||||
const histroyRef = ref<InstanceType<typeof histroy>>();
|
||||
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<DialogOption>({
|
||||
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();
|
||||
|
Reference in New Issue
Block a user