采购更新

This commit is contained in:
吴红兵
2026-03-01 11:22:54 +08:00
parent f5df8200aa
commit 3bfa9889c4
5 changed files with 611 additions and 19 deletions

View File

@@ -90,6 +90,18 @@ export function assignAgent(applyId: number | string, mode: 'random' | 'designat
});
}
/**
* 发送招标代理:将采购项目发送给已分配的招标代理
* @param applyId 采购申请ID
*/
export function sendToAgent(applyId: number | string) {
return request({
url: '/purchase/purchasingapply/sendToAgent',
method: 'post',
data: { id: Number(applyId) }
});
}
/**
* 修改采购申请
* @param obj 对象数据
@@ -226,3 +238,74 @@ export function getFileApplyTemplateDownloadUrl(id: string | number) {
return `/purchase/purchasingapply/export-file-apply-template?id=${encodeURIComponent(String(id))}`;
}
// ==================== 招标代理专用接口 ====================
/**
* 招标代理获取待处理列表
* @param params 分页参数
*/
export function getAgentPendingList(params?: any) {
return request({
url: '/purchase/purchasingdoc/agent/list',
method: 'get',
params
});
}
/**
* 招标代理获取采购需求文件列表
* @param applyId 采购申请ID
*/
export function getAgentRequirementFiles(applyId: number | string) {
return request({
url: `/purchase/purchasingdoc/agent/requirement/${applyId}`,
method: 'get'
});
}
/**
* 招标代理获取项目详情(仅返回采购编号和项目名称)
* @param applyId 采购申请ID
*/
export function getAgentApplyDetail(applyId: number | string) {
return request({
url: `/purchase/purchasingdoc/agent/detail/${applyId}`,
method: 'get'
});
}
/**
* 招标代理上传采购文件
* @param data 文件数据
*/
export function uploadAgentDoc(data: any) {
return request({
url: '/purchase/purchasingdoc/upload',
method: 'post',
data
});
}
/**
* 招标代理重新上传采购文件
* @param data 文件数据
*/
export function reuploadAgentDoc(data: any) {
return request({
url: '/purchase/purchasingdoc/reupload',
method: 'post',
data
});
}
/**
* 获取采购文件列表
* @param applyId 采购申请ID
*/
export function getDocList(applyId: number | string) {
return request({
url: `/purchase/purchasingdoc/list/${applyId}`,
method: 'get'
});
}

View File

@@ -93,16 +93,16 @@
</el-col>
<el-col :span="8" class="mb12" >
<el-form-item label="采购方式" prop="purchaseType" :required="!isEntrustCenterChannel">
<el-select
v-model="dataForm.purchaseType"
placeholder="请选择采购方式"
<el-select
v-model="dataForm.purchaseType"
placeholder="请选择采购方式"
clearable
:disabled="(isFlowEmbed && isPurchaseCenter) ? false : (isDeptSelfMallLocked || isAutoSelectPurchaseType || isEntrustCenterChannel)"
style="width: 100%">
<el-option
v-for="item in purchaseTypeDeptList"
:key="item.value"
:label="item.label"
<el-option
v-for="item in purchaseTypeDeptOptions"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
<div
@@ -215,7 +215,7 @@
</el-col>
<el-col :span="8" class="mb12" >
<el-form-item label="采购方式" prop="purchaseType" :required="!isDeptPurchase">
<el-select v-model="dataForm.purchaseType" placeholder="请选择采购方式" clearable :disabled="(isFlowEmbed && isPurchaseCenter) ? false : (isAutoSelectPurchaseTypeUnion || flowFieldDisabled('purchaseType'))" style="width: 100%">
<el-select v-model="dataForm.purchaseType" placeholder="请选择采购方式" clearable :disabled="(isFlowEmbed && isPurchaseCenter) ? false : (isAutoSelectPurchaseTypeUnion || flowFieldDisabled('purchaseType') || !isPurchaseCenter)" style="width: 100%">
<el-option v-for="item in purchaseTypeUnionList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@@ -640,6 +640,8 @@ const fundSourceList = ref<any[]>([]);
const isCentralizedList = ref<any[]>([]);
const isSpecialList = ref<any[]>([]);
const purchaseTypeDeptList = ref<any[]>([]);
/** 部门采购方式字典(委托采购中心采购时使用) */
const purchaseTypeDeptDelegationList = ref<any[]>([]);
const purchaseModeSchoolList = ref<any[]>([]);
const purchaseTypeUnionList = ref<any[]>([]);
const businessDeptList = ref<any[]>([]);
@@ -974,12 +976,6 @@ const isAutoSelectPurchaseTypeUnion = computed(() => {
watch(
[() => dataForm.categoryCode, () => dataForm.budget, () => isDeptPurchase.value, () => isFlowEmbed.value, () => dataForm.purchaseChannel, () => isPurchaseCenter.value],
() => {
// 学校统一采购申请阶段:采购方式隐藏,由审批环节采购中心补充,此处不自动写入且清空已有值
if (!isDeptPurchase.value && !isFlowEmbed.value) {
dataForm.purchaseType = '';
return;
}
// 部门自行采购 & 采购途径为”委托采购中心采购”且为新增申请阶段:采购方式隐藏且不设置
// 注意:查看模式和编辑模式不清空已有的采购方式
if (isDeptPurchase.value && isEntrustCenterChannel.value && !isFlowEmbed.value && !isViewMode.value && !isEditMode.value) {
@@ -1219,10 +1215,10 @@ async function loadDetail(applyId: string | number) {
budget: detail.budget != null ? Number(detail.budget) : null,
isCentralized: detail.isCentralized != null ? String(detail.isCentralized) : '',
isSpecial: detail.isSpecial != null ? String(detail.isSpecial) : '',
purchaseMode: detail.purchaseMode ?? '',
purchaseType: detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER ? '' : (detail.purchaseType ?? ''),
purchaseMode: detail.purchaseMode != null ? String(detail.purchaseMode) : '',
purchaseType: detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER ? '' : (detail.purchaseType != null ? String(detail.purchaseType) : (detail.purchaseTypeUnion != null ? String(detail.purchaseTypeUnion) : '')),
purchaseChannel: (detail as any).purchaseChannel ?? (detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER ? PURCHASE_CHANNEL.ENTRUST_CENTER : ''),
purchaseTypeUnion: detail.purchaseTypeUnion ?? '',
purchaseTypeUnion: detail.purchaseTypeUnion != null ? String(detail.purchaseTypeUnion) : '',
categoryCode: detail.categoryCode ?? '',
remark: detail.remark ?? '',
status: detail.status ?? '',
@@ -1480,7 +1476,7 @@ const getIsSpecialDict = async () => {
}
};
// 获取部门采购方式字典(过滤掉委托采购中心采购”,由采购途径字段控制)
// 获取部门采购方式字典(过滤掉委托采购中心采购”,由采购途径字段控制)
const getPurchaseTypeDeptDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_DEPT');
@@ -1498,6 +1494,30 @@ const getPurchaseTypeDeptDict = async () => {
}
};
// 获取部门采购方式字典(委托采购中心采购时使用)
const getPurchaseTypeDeptDelegationDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_DEPT_DELEGATION');
purchaseTypeDeptDelegationList.value = res.data && Array.isArray(res.data)
? res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code,
}))
: [];
} catch (err) {
purchaseTypeDeptDelegationList.value = [];
}
};
/** 部门采购方式下拉选项:根据采购途径动态切换字典 */
const purchaseTypeDeptOptions = computed(() => {
if (isEntrustCenterChannel.value) {
return purchaseTypeDeptDelegationList.value;
}
return purchaseTypeDeptList.value;
});
// 获取学校采购形式字典
const getPurchaseModeSchoolDict = async () => {
try {
@@ -1946,6 +1966,7 @@ onMounted(async () => {
getIsCentralizedDict(),
getIsSpecialDict(),
getPurchaseTypeDeptDict(),
getPurchaseTypeDeptDelegationDict(),
getPurchaseModeSchoolDict(),
getPurchaseTypeUnionDict(),
getBusinessDeptListData(),

View File

@@ -0,0 +1,288 @@
<template>
<el-dialog
v-model="visible"
:title="'处理项目 - ' + (projectInfo.purchaseNo || '')"
width="900px"
:close-on-click-modal="false"
destroy-on-close
class="agent-doc-dialog">
<el-tabs v-model="activeTab" type="border-card">
<!-- Tab 1: 项目基本信息 -->
<el-tab-pane label="项目信息" name="info">
<el-descriptions :column="2" border>
<el-descriptions-item label="采购编号">{{ projectInfo.purchaseNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="项目名称">{{ projectInfo.projectName || '-' }}</el-descriptions-item>
<el-descriptions-item label="文件状态">
<el-tag :type="getStatusType(projectInfo.status)">{{ getStatusLabel(projectInfo.status) }}</el-tag>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- Tab 2: 采购需求文件 -->
<el-tab-pane label="采购需求文件" name="requirement">
<el-table :data="requirementFiles" v-loading="requirementLoading" stripe>
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="fileName" label="文件名称" min-width="200" show-overflow-tooltip />
<el-table-column label="操作" width="120" align="center">
<template #default="scope">
<el-button type="primary" link icon="Download" @click="handleDownload(scope.row)">下载</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-if="!requirementLoading && requirementFiles.length === 0" description="暂无采购需求文件" />
</el-tab-pane>
<!-- Tab 3: 上传招标文件 -->
<el-tab-pane label="上传招标文件" name="upload">
<div class="upload-section">
<el-alert type="info" :closable="false" class="mb-4">
<template #title>
<span>当前状态<el-tag :type="getStatusType(projectInfo.status)" size="small">{{ getStatusLabel(projectInfo.status) }}</el-tag></span>
</template>
</el-alert>
<!-- 文件上传 -->
<el-upload
ref="uploadRef"
:action="uploadAction"
:headers="uploadHeaders"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:before-upload="beforeUpload"
:file-list="fileList"
:auto-upload="false"
:limit="1"
accept=".doc,.docx,.pdf"
class="upload-demo">
<el-button type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">支持 .doc, .docx, .pdf 格式文件大小不超过 50MB</div>
</template>
</el-upload>
<el-button
type="success"
:loading="uploadSubmitting"
:disabled="fileList.length === 0 || !canUpload"
@click="handleUploadSubmit"
class="mt-4">
{{ projectInfo.status === 'RETURNED' ? '重新上传招标文件' : '上传招标文件' }}
</el-button>
<el-alert v-if="!canUpload" type="warning" :closable="false" class="mt-4">
<template #title>
<span v-if="projectInfo.status === 'ASSET_REVIEWING'">文件审核中请等待审核结果</span>
<span v-else-if="projectInfo.status === 'DEPT_REVIEWING'">文件审核中请等待审核结果</span>
<span v-else-if="projectInfo.status === 'AUDIT_REVIEWING'">文件审核中请等待审核结果</span>
<span v-else-if="projectInfo.status === 'ASSET_CONFIRMING'">文件审核中请等待确认</span>
<span v-else-if="projectInfo.status === 'COMPLETED'">文件审核已完成</span>
<span v-else>当前状态不允许上传</span>
</template>
</el-alert>
</div>
</el-tab-pane>
</el-tabs>
<template #footer>
<el-button @click="handleClose">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="AgentDocDialog">
import { ref, computed } from 'vue'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import { getAgentRequirementFiles, getAgentApplyDetail, uploadAgentDoc, reuploadAgentDoc, getDocList } from '/@/api/finance/purchasingrequisition'
import type { UploadInstance, UploadProps, UploadUserFile } from 'element-plus'
const emit = defineEmits(['refresh'])
const visible = ref(false)
const activeTab = ref('info')
const projectInfo = ref<any>({})
const requirementFiles = ref<any[]>([])
const requirementLoading = ref(false)
const uploadSubmitting = ref(false)
const uploadRef = ref<UploadInstance>()
const fileList = ref<UploadUserFile[]>([])
// 上传配置
const uploadAction = computed(() => {
const baseUrl = import.meta.env.VITE_API_URL || ''
return `${baseUrl}/admin/sys-file/upload`
})
const uploadHeaders = computed(() => {
const token = Session.getToken()
return {
Authorization: `Bearer ${token}`,
'TENANT-ID': Session.getTenant() || '1'
}
})
// 是否可以上传
const canUpload = computed(() => {
const status = projectInfo.value.status
return status === 'PENDING_UPLOAD' || status === 'RETURNED'
})
const open = async (row: any) => {
projectInfo.value = { ...row }
visible.value = true
activeTab.value = 'info'
fileList.value = []
await loadProjectDetail()
await loadRequirementFiles()
}
const loadProjectDetail = async () => {
try {
const res = await getAgentApplyDetail(projectInfo.value.applyId)
if (res?.data) {
projectInfo.value = { ...projectInfo.value, ...res.data }
}
} catch (e: any) {
console.error('加载项目详情失败', e)
}
}
const loadRequirementFiles = async () => {
requirementLoading.value = true
try {
const res = await getAgentRequirementFiles(projectInfo.value.applyId)
requirementFiles.value = res?.data || []
} catch (e: any) {
requirementFiles.value = []
} finally {
requirementLoading.value = false
}
}
const handleDownload = (row: any) => {
// TODO: 实现下载功能
const downloadUrl = `/purchase/purchasingdoc/download/${row.id}`
window.open(downloadUrl, '_blank')
}
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
const allowedTypes = ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/pdf']
const allowedExtensions = ['.doc', '.docx', '.pdf']
const fileExt = rawFile.name.substring(rawFile.name.lastIndexOf('.')).toLowerCase()
if (!allowedTypes.includes(rawFile.type) && !allowedExtensions.includes(fileExt)) {
useMessage().error('只能上传 .doc, .docx, .pdf 格式的文件')
return false
}
if (rawFile.size / 1024 / 1024 > 50) {
useMessage().error('文件大小不能超过 50MB')
return false
}
return true
}
const handleUploadSuccess: UploadProps['onSuccess'] = (response: any, uploadFile: any) => {
if (response?.code === 0 || response?.code === 200) {
const fileUrl = response.data?.url || response.data?.fileUrl || response.data?.filePath
const fileName = uploadFile.name
submitUpload(fileName, fileUrl)
} else {
useMessage().error(response?.msg || '上传失败')
uploadSubmitting.value = false
}
}
const handleUploadError: UploadProps['onError'] = (error: any) => {
useMessage().error('文件上传失败:' + (error?.message || '未知错误'))
uploadSubmitting.value = false
}
const submitUpload = async (fileName: string, filePath: string) => {
try {
const data = {
applyId: projectInfo.value.applyId,
fileName,
filePath
}
if (projectInfo.value.status === 'RETURNED') {
await reuploadAgentDoc(data)
} else {
await uploadAgentDoc(data)
}
useMessage().success('招标文件上传成功')
emit('refresh')
await loadProjectDetail()
fileList.value = []
} catch (e: any) {
useMessage().error(e?.msg || '上传失败')
} finally {
uploadSubmitting.value = false
}
}
const handleUploadSubmit = async () => {
if (fileList.value.length === 0) {
useMessage().warning('请先选择文件')
return
}
uploadSubmitting.value = true
uploadRef.value?.submit()
}
const handleClose = () => {
visible.value = false
}
const getStatusType = (status: string) => {
const typeMap: Record<string, string> = {
'PENDING_UPLOAD': 'info',
'ASSET_REVIEWING': 'warning',
'DEPT_REVIEWING': 'warning',
'AUDIT_REVIEWING': 'warning',
'ASSET_CONFIRMING': 'primary',
'COMPLETED': 'success',
'RETURNED': 'danger'
}
return typeMap[status] || 'info'
}
const getStatusLabel = (status: string) => {
const labelMap: Record<string, string> = {
'PENDING_UPLOAD': '待上传',
'ASSET_REVIEWING': '资产管理处审核中',
'DEPT_REVIEWING': '需求部门审核中',
'AUDIT_REVIEWING': '内审部门审核中',
'ASSET_CONFIRMING': '资产管理处确认中',
'COMPLETED': '已完成',
'RETURNED': '已退回'
}
return labelMap[status] || '-'
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.agent-doc-dialog {
:deep(.el-dialog__body) {
padding: 16px 20px;
}
}
.upload-section {
padding: 16px 0;
}
.mb-4 {
margin-bottom: 16px;
}
.mt-4 {
margin-top: 16px;
}
</style>

View File

@@ -0,0 +1,166 @@
<template>
<div class="modern-page-container">
<div class="page-wrapper">
<!-- 搜索表单卡片 -->
<el-card v-show="showSearch" class="search-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Search /></el-icon>
筛选条件
</span>
</div>
</template>
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
<el-form-item label="采购编号" prop="purchaseNo">
<el-input
v-model="state.queryForm.purchaseNo"
placeholder="请输入采购编号"
clearable
style="width: 200px" />
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input
v-model="state.queryForm.projectName"
placeholder="请输入项目名称"
clearable
style="width: 200px" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button icon="Refresh" @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 内容卡片 -->
<el-card class="content-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><DocumentCopy /></el-icon>
招标代理工作台
</span>
<div class="header-actions">
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
</div>
</div>
</template>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
v-loading="state.loading"
stripe
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
class="modern-table">
<el-table-column type="index" label="序号" width="70" align="center">
<template #header>
<el-icon><List /></el-icon>
</template>
</el-table-column>
<el-table-column prop="purchaseNo" label="采购编号" min-width="140" show-overflow-tooltip />
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="status" label="文件状态" width="140" align="center">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ getStatusLabel(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="120">
<template #default="scope">
<el-button type="primary" link icon="View" @click="handleView(scope.row)">
处理
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-if="state.pagination && state.pagination.total && state.pagination.total > 0"
:total="state.pagination.total"
:current="state.pagination.current"
:size="state.pagination.size"
@sizeChange="sizeChangeHandle"
@currentChange="currentChangeHandle"
/>
</el-card>
</div>
<!-- 处理弹窗 -->
<AgentDocDialog ref="agentDocDialogRef" @refresh="getDataList" />
</div>
</template>
<script setup lang="ts" name="PurchasingAgentDoc">
import { ref, reactive, defineAsyncComponent, onMounted } from 'vue'
import { BasicTableProps, useTable } from "/@/hooks/table";
import { useMessage } from "/@/hooks/message";
import { getAgentPendingList } from "/@/api/finance/purchasingrequisition";
import { Search, DocumentCopy, List } from '@element-plus/icons-vue'
// 引入组件
const AgentDocDialog = defineAsyncComponent(() => import('./AgentDocDialog.vue'));
const agentDocDialogRef = ref()
const searchFormRef = ref()
const showSearch = ref(true)
const state: BasicTableProps = reactive<BasicTableProps>({
pageList: getAgentPendingList,
queryForm: {
purchaseNo: '',
projectName: '',
},
createdIsNeed: true
});
const { getDataList, tableStyle, sizeChangeHandle, currentChangeHandle } = useTable(state);
const handleReset = () => {
searchFormRef.value?.resetFields();
getDataList();
};
const getStatusType = (status: string) => {
const typeMap: Record<string, string> = {
'PENDING_UPLOAD': 'info',
'ASSET_REVIEWING': 'warning',
'DEPT_REVIEWING': 'warning',
'AUDIT_REVIEWING': 'warning',
'ASSET_CONFIRMING': 'primary',
'COMPLETED': 'success',
'RETURNED': 'danger'
};
return typeMap[status] || 'info';
};
const getStatusLabel = (status: string) => {
const labelMap: Record<string, string> = {
'PENDING_UPLOAD': '待上传',
'ASSET_REVIEWING': '资产管理处审核中',
'DEPT_REVIEWING': '需求部门审核中',
'AUDIT_REVIEWING': '内审部门审核中',
'ASSET_CONFIRMING': '资产管理处确认中',
'COMPLETED': '已完成',
'RETURNED': '已退回'
};
return labelMap[status] || '-';
};
const handleView = (row: any) => {
agentDocDialogRef.value?.open(row);
};
onMounted(() => {
// 页面加载时的初始化逻辑
});
</script>
<style scoped lang="scss">
@import '/@/assets/styles/modern-page.scss';
</style>

View File

@@ -38,6 +38,10 @@
<el-form-item v-if="agentMode === 'random'">
<el-button type="primary" :loading="assignAgentSubmitting" :disabled="!!assignedAgentName" @click="handleAssignAgentRandom">随机分配</el-button>
</el-form-item>
<!-- 发送招标代理按钮 -->
<el-form-item v-if="canSendToAgent">
<el-button type="success" :loading="sendToAgentSubmitting" @click="handleSendToAgent">发送招标代理</el-button>
</el-form-item>
</template>
<!-- 仅部门审核角色显示采购代表相关 -->
@@ -71,7 +75,7 @@
<script setup lang="ts" name="PurchasingImplement">
import { ref, computed, onMounted, watch, onUnmounted } from 'vue'
import { useRoute } from 'vue-router'
import { getDeptMembers, getObj, assignAgent } from '/@/api/finance/purchasingrequisition'
import { getDeptMembers, getObj, assignAgent, sendToAgent } from '/@/api/finance/purchasingrequisition'
import { getPage as getAgentPage } from '/@/api/finance/purchaseagent'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
@@ -129,6 +133,7 @@ const agentListLoading = ref(false)
const assignAgentSubmitting = ref(false)
const rollingAgentName = ref<string>('')
const assignedAgentName = ref<string>('')
const sendToAgentSubmitting = ref(false)
let rollInterval: ReturnType<typeof setInterval> | null = null
/** 是否可以分配代理:委托代理采购 且 (学校统一采购 或 部门自行采购且委托采购中心采购) */
@@ -140,6 +145,16 @@ const canAssignAgent = computed(() => {
return row.purchaseMode === '2' || (row.purchaseMode === '0' && row.purchaseType === '4')
})
/** 是否可以发送招标代理:委托代理采购 且 已分配代理 且 未发送 */
const canSendToAgent = computed(() => {
// 自行组织采购不需要发送
if (implementType.value !== '2') return false
const row = applyRow.value
if (!row) return false
// 已分配代理 且 未发送
return !!row.agentId && row.agentSent !== '1'
})
const loadAgentList = async () => {
if (!canAssignAgent.value) return
agentListLoading.value = true
@@ -233,6 +248,25 @@ const handleAssignAgentDesignated = async () => {
}
}
/** 发送招标代理 */
const handleSendToAgent = async () => {
const id = applyRow.value?.id ?? applyId.value
if (!id) {
useMessage().warning('无法获取申请单ID')
return
}
sendToAgentSubmitting.value = true
try {
await sendToAgent(Number(id))
useMessage().success('已发送招标代理')
await loadData()
} catch (e: any) {
useMessage().error(e?.msg || '发送招标代理失败')
} finally {
sendToAgentSubmitting.value = false
}
}
const isInIframe = () => typeof window !== 'undefined' && window.self !== window.top
const postMessage = (type: string, payload?: any) => {