更新
This commit is contained in:
@@ -208,13 +208,109 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 部门参与人选择(部门负责人审核时显示) -->
|
||||
<el-card v-if="showRepresentorSection" shadow="never" class="representor-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon><User /></el-icon>
|
||||
部门参与人
|
||||
</span>
|
||||
<el-tag v-if="applyData.representorTeacherNo" type="success">已设置</el-tag>
|
||||
<el-tag v-else type="warning">待设置</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form label-width="120px">
|
||||
<el-form-item label="选择方式">
|
||||
<el-radio-group v-model="representorSelectMode" :disabled="isViewMode">
|
||||
<el-radio label="designate">指定一人</el-radio>
|
||||
<el-radio label="random">随机抽取</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 指定一人 -->
|
||||
<el-form-item v-if="representorSelectMode === 'designate'" label="选择参与人">
|
||||
<el-select
|
||||
v-model="selectedRepresentor"
|
||||
placeholder="请选择参与人"
|
||||
filterable
|
||||
:disabled="isViewMode"
|
||||
style="width: 300px"
|
||||
>
|
||||
<el-option
|
||||
v-for="member in deptMembers"
|
||||
:key="member.teacherNo"
|
||||
:label="`${member.realName} (${member.teacherNo})`"
|
||||
:value="member.teacherNo"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 随机抽取 -->
|
||||
<el-form-item v-if="representorSelectMode === 'random'" label="选择候选人">
|
||||
<el-select
|
||||
v-model="randomCandidates"
|
||||
placeholder="请选择参与随机抽取的人员(可多选)"
|
||||
multiple
|
||||
filterable
|
||||
:disabled="isViewMode"
|
||||
style="width: 400px"
|
||||
>
|
||||
<el-option
|
||||
v-for="member in deptMembers"
|
||||
:key="member.teacherNo"
|
||||
:label="`${member.realName} (${member.teacherNo})`"
|
||||
:value="member.teacherNo"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="randomSelectLoading"
|
||||
:disabled="randomCandidates.length < 2 || isViewMode"
|
||||
style="margin-left: 12px"
|
||||
@click="handleRandomSelect"
|
||||
>
|
||||
随机抽取
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 已选中的参与人 -->
|
||||
<el-form-item v-if="currentRepresentor" label="已选中参与人">
|
||||
<el-tag type="success" size="large">
|
||||
{{ currentRepresentor.realName }} ({{ currentRepresentor.teacherNo }})
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 参与人身份 -->
|
||||
<el-form-item label="参与人身份" required>
|
||||
<el-radio-group v-model="representorType" :disabled="isViewMode">
|
||||
<el-radio label="purchase_rep">采购代表</el-radio>
|
||||
<el-radio label="judge">评委</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="saveRepresentorLoading"
|
||||
:disabled="!canSaveRepresentor || isViewMode"
|
||||
@click="handleSaveRepresentor"
|
||||
>
|
||||
保存参与人信息
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BidFileAudit">
|
||||
import { ref, reactive, computed, onMounted, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Document, FolderOpened, Upload, Link, Guide } from '@element-plus/icons-vue';
|
||||
import { Document, FolderOpened, Upload, Link, Guide, User } from '@element-plus/icons-vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Session } from '/@/utils/storage';
|
||||
import { useUserInfo } from '/@/stores/userInfo';
|
||||
@@ -232,6 +328,7 @@ import {
|
||||
} from '/@/api/purchase/bidfile';
|
||||
import { getRequirementFiles } from '/@/api/purchase/purchasingfiles';
|
||||
import { currElTabIsSave } from '/@/api/order/order-key-vue';
|
||||
import { getDeptMembers, saveRepresentor, randomSelectRepresentor } from '/@/api/purchase/purchasingrequisition';
|
||||
|
||||
// ==================== Props & Emits ====================
|
||||
|
||||
@@ -252,7 +349,8 @@ const currentUserRoleCodes = computed(() => userStore.userInfos.roleCodes || [])
|
||||
const ROLE_LABEL_MAP: Record<string, string> = {
|
||||
PURCHASE_AGENT: '招标代理',
|
||||
PURCHASE_ASSET: '资产管理处',
|
||||
PURCHASE_DEPT_APPLY: '部门负责人',
|
||||
PURCHASE_DEPT_APPLY: '部门经办人',
|
||||
PURCHASE_DEPT_AUDIT: '部门负责人',
|
||||
PURCHASE_FILE_AUDIT: '内审部门',
|
||||
PURCHASE_CENTER: '采购中心',
|
||||
};
|
||||
@@ -295,6 +393,7 @@ const isViewMode = computed(() => {
|
||||
const isAgent = computed(() => currentUserRoleCodes.value.includes('PURCHASE_AGENT'));
|
||||
const isAsset = computed(() => currentUserRoleCodes.value.includes('PURCHASE_ASSET'));
|
||||
const isDeptApply = computed(() => currentUserRoleCodes.value.includes('PURCHASE_DEPT_APPLY'));
|
||||
const isDeptAudit = computed(() => currentUserRoleCodes.value.includes('PURCHASE_DEPT_AUDIT'));
|
||||
const isFileAudit = computed(() => currentUserRoleCodes.value.includes('PURCHASE_FILE_AUDIT'));
|
||||
|
||||
// 是否显示上传区域
|
||||
@@ -311,6 +410,12 @@ const showFlowTargetSection = computed(() => {
|
||||
return isAsset.value && isFlowEmbed.value;
|
||||
});
|
||||
|
||||
// 是否显示部门参与人选择区域(仅部门负责人在审核时显示)
|
||||
const showRepresentorSection = computed(() => {
|
||||
if (isViewMode.value) return false;
|
||||
return isDeptAudit.value && isFlowEmbed.value;
|
||||
});
|
||||
|
||||
// 采购申请数据
|
||||
const applyData = ref<any>({});
|
||||
const purchaseTypeLabel = computed(() => {
|
||||
@@ -351,6 +456,24 @@ const uploadRules = {
|
||||
// 流转去向(资产管理处审核时使用)
|
||||
const flowTarget = ref<string>('');
|
||||
|
||||
// 部门参与人选择相关(部门负责人审核时使用)
|
||||
const representorSelectMode = ref<'designate' | 'random'>('designate');
|
||||
const deptMembers = ref<any[]>([]);
|
||||
const deptMembersLoading = ref(false);
|
||||
const selectedRepresentor = ref<string>('');
|
||||
const randomCandidates = ref<string[]>([]);
|
||||
const currentRepresentor = ref<any>(null);
|
||||
const representorType = ref<string>('purchase_rep');
|
||||
const saveRepresentorLoading = ref(false);
|
||||
const randomSelectLoading = ref(false);
|
||||
|
||||
const canSaveRepresentor = computed(() => {
|
||||
if (representorSelectMode.value === 'designate') {
|
||||
return !!selectedRepresentor.value;
|
||||
}
|
||||
return !!currentRepresentor.value;
|
||||
});
|
||||
|
||||
// ==================== 计算属性 ====================
|
||||
|
||||
const BID_FILE_TYPE = '130';
|
||||
@@ -634,6 +757,93 @@ const registerFlowCallbacks = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 部门参与人选择 ====================
|
||||
|
||||
const loadDeptMembers = async () => {
|
||||
if (!showRepresentorSection.value) return;
|
||||
|
||||
try {
|
||||
deptMembersLoading.value = true;
|
||||
const res = await getDeptMembers();
|
||||
if (res.code === 0 && res.data) {
|
||||
deptMembers.value = res.data;
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.msg || '加载部门人员失败');
|
||||
} finally {
|
||||
deptMembersLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleRandomSelect = async () => {
|
||||
if (randomCandidates.value.length < 2) {
|
||||
ElMessage.warning('请至少选择2名候选人');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
randomSelectLoading.value = true;
|
||||
const res = await randomSelectRepresentor(
|
||||
effectivePurchaseId.value,
|
||||
randomCandidates.value.join(',')
|
||||
);
|
||||
if (res.code === 0 && res.data) {
|
||||
currentRepresentor.value = res.data;
|
||||
ElMessage.success(`随机抽取成功:${res.data.realName}`);
|
||||
} else {
|
||||
ElMessage.error(res.msg || '随机抽取失败');
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.msg || '随机抽取失败');
|
||||
} finally {
|
||||
randomSelectLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveRepresentor = async () => {
|
||||
if (!canSaveRepresentor.value) {
|
||||
ElMessage.warning('请先选择参与人');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!representorType.value) {
|
||||
ElMessage.warning('请选择参与人身份');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saveRepresentorLoading.value = true;
|
||||
let res: any;
|
||||
|
||||
if (representorSelectMode.value === 'designate') {
|
||||
res = await saveRepresentor(
|
||||
Number(effectivePurchaseId.value),
|
||||
selectedRepresentor.value,
|
||||
undefined,
|
||||
representorType.value
|
||||
);
|
||||
} else {
|
||||
res = await saveRepresentor(
|
||||
Number(effectivePurchaseId.value),
|
||||
currentRepresentor.value?.teacherNo,
|
||||
randomCandidates.value.join(','),
|
||||
representorType.value
|
||||
);
|
||||
}
|
||||
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('保存参与人信息成功');
|
||||
await loadApplyData();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败');
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.msg || '保存失败');
|
||||
} finally {
|
||||
saveRepresentorLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 生命周期 ====================
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -642,6 +852,9 @@ onMounted(async () => {
|
||||
if (isAgent.value) {
|
||||
await loadRequirementFiles();
|
||||
}
|
||||
if (showRepresentorSection.value) {
|
||||
await loadDeptMembers();
|
||||
}
|
||||
registerFlowCallbacks();
|
||||
});
|
||||
|
||||
@@ -654,6 +867,9 @@ watch(
|
||||
if (isAgent.value) {
|
||||
await loadRequirementFiles();
|
||||
}
|
||||
if (showRepresentorSection.value) {
|
||||
await loadDeptMembers();
|
||||
}
|
||||
registerFlowCallbacks();
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user