56 KiB
前端开发设计文档 — 自行招标流程
版本:V2.3
日期:2026-06-30
对应需求:3.7.4 自行招标流程(完整流程:发起节点至投标方终报)
URL 前缀说明:接口文档 V1.3 中定义的前缀为
/api,但当前后端实际服务前缀仍为/blade-zhaocai。因此前端实现统一使用/blade-zhaocai/bidding-self/...,待后端切换后再统一调整。
1. 需求概述
1.1 流程说明
自行招标流程包含15个前端页面,覆盖从发起至终报的完整流程:
| 页面 | 节点编号 | 节点名称 | 页面类型 | 说明 |
|---|---|---|---|---|
| 发起页面 | 3.7.4.1 | 招采发起人 | 表单填写 | 发起人填写招标信息,自动带出预招标数据 |
| 审批页面 | 3.7.4.2 | 招采负责人初审 | 表单编辑 | 招采负责人补充招标公告信息,上传文件 |
| 终审页面 | 3.7.4.3 | 总裁办负责人审批 | 审批节点 | 总裁办主任审核公告内容,终审通过 |
| 供应商报名页面 | 3.7.4.4 | 招采平台供应商报名入口 | 外部节点 | 供应商查看项目列表并报名 |
| 总裁办负责人审批页面(资质审核视图) | 3.7.4.5 | 供应商资质审核 | 审批节点 | 招采负责人审核供应商资质,由 final-approval.vue 根据 nodeName 切换展示 |
| 开标页面 | 3.7.4.6 | 开标 | 执行节点 | 招采负责人确认签到数量并开标 |
| 投标页面 | 3.7.4.6 | 投标 | 执行节点 | 供应商签到、上传投标文件、填写报价 |
| 唱标页面 | 3.7.4.7 | 唱标 | 展示节点 | 展示投标方报价信息,生成唱标记录表 |
| 专家签到页面 | 3.7.4.8 | 专家签到 | 交互节点 | 专家线上签到并电子签署文件 |
| 专家评标页面 | 3.7.4.9 | 专家评标 | 评审节点 | 专家对投标方进行评分 |
| 资格认定表审批页面 | 3.7.4.10 | 资格认定表审批 | 审批节点 | 招采负责人审核资格认定表 |
| 供应商报价页面 | 3.7.4.11/15 | 供应商多轮报价 | 报价节点 | 入围供应商进行多轮报价(含终报) |
| 出报价分页面 | 3.7.4.12 | 出报价分 | 计算节点 | 根据评分规则计算报价分 |
| 投票页面 | 3.7.4.13 | 投票页面 | 投票节点 | 业务部门进行投票选定入围供应商 |
| 确定入围供应商页面 | 3.7.4.14 | 确定入围供应商 | 确认节点 | 确认入围名单并通知供应商 |
说明:当前阶段已实现节点 3.7.4.1 和 3.7.4.2,后续节点(3.7.4.3-3.7.4.14)为待开发内容。
1.2 与接口文档的差异说明
重要:接口文档中的前端架构假设(TypeScript + Pinia +
views/bidding/self/pages/目录结构)与当前项目实际架构不符。本文档基于项目实际技术栈重新设计,并依据接口文档 V1.3 去除由第三方系统实现的“公众号/招采平台发布公告”模块(原 3.7.4.4),后续节点编号依次前移。
项目实际技术栈:
- Vue 3(Options API 为主流,Composition API 用于复杂交互页面)
- Element Plus(UI 组件库)
- Avue(CRUD 表格封装,但表单页面优先使用原生 Element Plus)
- Vuex(全局状态管理)
- Vite(构建工具)
- Pure JavaScript(无 TypeScript)
2. 文件结构设计
按项目现有模块规范,采用 扁平化目录结构:
src/
├── api/
│ └── bidding/
│ └── self.js # 自行招标流程 API 封装(全部45个接口)
├── views/
│ └── bidding/
│ ├── initiate.vue # 3.7.4.1 发起页面(招采发起人)
│ ├── approval.vue # 3.7.4.2 审批页面(招采负责人初审)
│ ├── final-approval.vue # 3.7.4.3 总裁办负责人审批
│ ├── registration.vue # 3.7.4.4 供应商报名
│ ├── qualification.vue # 3.7.4.5 资质审核
│ ├── bid.vue # 3.7.4.6 开标(招采负责人端)
│ ├── bid-supplier.vue # 3.7.4.6 投标(供应商端)
│ ├── opening.vue # 3.7.4.7 唱标
│ ├── expert-sign.vue # 3.7.4.8 专家签到
│ ├── evaluation.vue # 3.7.4.9 专家评标
│ ├── qualification-cert.vue # 3.7.4.10 资格认定表审批
│ ├── quote.vue # 3.7.4.11/15 供应商报价
│ ├── score.vue # 3.7.4.12 出报价分
│ ├── vote.vue # 3.7.4.13 投票
│ └── finalist.vue # 3.7.4.14 确定入围供应商
设计理由:
- 项目标准结构为
src/api/{module}/+src/views/{module}/,无需option层(非标准 CRUD 列表页)- 不创建
self/pages/子目录,保持与项目现有模块的目录风格一致- 无
PendingBidding.vue主容器(当前项目不存在该文件),各页面作为独立路由页面由流程引擎直接挂载
3. API 层设计(src/api/bidding/self.js)
3.1 设计原则
- 遵循项目现有 API 层模式:导出纯函数,返回
request({ url, method, params/data })Promise - 接口路径统一使用
/api前缀,与后端服务保持一致 - 统一处理请求参数和响应数据结构
3.2 接口清单(共42个接口)
3.2.1 基础接口(已实现)
| 序号 | 接口路径 | 方法 | 接口名称 |
|---|---|---|---|
| 1 | /blade-zhaocai/bidding-self/pre-project/{id} |
GET | 获取预招标项目信息 |
| 2 | /blade-zhaocai/bidding-self/draft |
POST | 保存招标发起草稿 |
| 3 | /blade-zhaocai/bidding-self/submit |
POST | 提交招标发起 |
| 4 | /blade-zhaocai/bidding-self/{id} |
GET | 获取招标发起详情 |
| 5 | /blade-zhaocai/bidding-self/{id}/update |
PUT | 更新招采负责人数据 |
| 6 | /blade-zhaocai/bidding-self/evaluation-principles |
GET | 获取评标原则列表 |
| 7 | /blade-zhaocai/bidding-self/upload |
POST | 文件上传 |
| 8 | /blade-zhaocai/bidding-self/organization-tree |
GET | 获取组织架构树 |
| 9 | /blade-zhaocai/bidding-self/user-dept-list |
GET | 获取用户部门列表 |
3.2.2 后续流程接口(待开发)
| 序号 | 接口路径 | 方法 | 接口名称 | 对应节点 |
|---|---|---|---|---|
| 10 | /blade-zhaocai/bidding-self/{id}/final-approval |
PUT | 更新总裁办负责人数据 | 3.7.4.3 |
| 11 | /blade-zhaocai/bidding-self/registration/list |
GET | 获取报名项目列表 | 3.7.4.4 |
| 12 | /blade-zhaocai/bidding-self/registration/submit |
POST | 提交报名 | 3.7.4.4 |
| 13 | /blade-zhaocai/bidding-self/registration/my |
GET | 获取我的报名 | 3.7.4.4 |
| 14 | /blade-zhaocai/bidding-self/qualification/list |
GET | 获取待审核供应商 | 3.7.4.5 |
| 15 | /blade-zhaocai/bidding-self/qualification/audit |
POST | 审核供应商资质 | 3.7.4.5 |
| 16 | /blade-zhaocai/bidding-self/qualification/batch |
POST | 批量审核 | 3.7.4.5 |
| 17 | /blade-zhaocai/bidding-self/bid/list |
GET | 获取待投标项目 | 3.7.4.6 |
| 18 | /blade-zhaocai/bidding-self/bid/sign |
POST | 开标签到 | 3.7.4.6 |
| 19 | /blade-zhaocai/bidding-self/bid/submit |
POST | 提交投标 | 3.7.4.6 |
| 20 | /blade-zhaocai/bidding-self/bid/opening |
POST | 开标 | 3.7.4.6 |
| 21 | /blade-zhaocai/bidding-self/bid/flow |
POST | 流标 | 3.7.4.6 |
| 22 | /blade-zhaocai/bidding-self/bid/sign-export |
GET | 导出签到表 | 3.7.4.6 |
| 23 | /blade-zhaocai/bidding-self/opening/list |
GET | 获取唱标列表 | 3.7.4.7 |
| 24 | /blade-zhaocai/bidding-self/opening/record |
POST | 生成唱标记录 | 3.7.4.7 |
| 25 | /blade-zhaocai/bidding-self/opening/complete |
POST | 唱标结束 | 3.7.4.7 |
| 26 | /blade-zhaocai/bidding-self/expert/sign |
POST | 专家签到 | 3.7.4.8 |
| 27 | /blade-zhaocai/bidding-self/expert/sign-file |
POST | 上传签署文件 | 3.7.4.8 |
| 28 | /blade-zhaocai/bidding-self/expert/audit |
POST | 审核签署文件 | 3.7.4.8 |
| 29 | /blade-zhaocai/bidding-self/evaluation/list |
GET | 获取待评标列表 | 3.7.4.9 |
| 30 | /blade-zhaocai/bidding-self/evaluation/detail |
GET | 获取投标方详情 | 3.7.4.9 |
| 31 | /blade-zhaocai/bidding-self/evaluation/score |
POST | 提交评分 | 3.7.4.9 |
| 32 | /blade-zhaocai/bidding-self/evaluation/cert |
POST | 生成资质认定表 | 3.7.4.9 |
| 33 | /blade-zhaocai/bidding-self/qualification-cert/audit |
POST | 审核资格认定表 | 3.7.4.10 |
| 34 | /blade-zhaocai/bidding-self/qualification-cert/notify |
POST | 发送淘汰通知 | 3.7.4.10 |
| 35 | /blade-zhaocai/bidding-self/quote/submit |
POST | 提交报价 | 3.7.4.11/15 |
| 36 | /blade-zhaocai/bidding-self/quote/history |
GET | 获取报价历史 | 3.7.4.11/15 |
| 37 | /blade-zhaocai/bidding-self/score/calculate |
POST | 计算报价分 | 3.7.4.12 |
| 38 | /blade-zhaocai/bidding-self/score/config |
GET | 获取评分配置 | 3.7.4.12 |
| 39 | /blade-zhaocai/bidding-self/vote/submit |
POST | 提交投票 | 3.7.4.13 |
| 40 | /blade-zhaocai/bidding-self/vote/result |
GET | 获取投票结果 | 3.7.4.13 |
| 41 | /blade-zhaocai/bidding-self/finalist/confirm |
POST | 确认入围 | 3.7.4.14 |
| 42 | /blade-zhaocai/bidding-self/finalist/notify |
POST | 通知入围供应商 | 3.7.4.14 |
3.3 API 函数定义
import request from '@/axios';
// ==================== 基础接口(3.7.4.1 - 3.7.4.2)====================
/**
* 获取当前用户的部门列表(含公司信息)
*/
export const getUserDeptList = () => {
return request({ url: '/blade-zhaocai/bidding-self/user-dept-list', method: 'get' });
};
/**
* 获取预招标项目信息
* @param {number} id - 预招标项目ID
*/
export const getPreProject = (id) => {
return request({ url: `/blade-zhaocai/bidding-self/pre-project/${id}`, method: 'get' });
};
/**
* 保存招标发起草稿
* @param {Object} data - BiddingSelfInitiateDTO
*/
export const saveDraft = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/draft', method: 'post', data });
};
/**
* 提交招标发起
* @param {Object} data - BiddingSelfInitiateDTO
*/
export const submitBidding = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/submit', method: 'post', data });
};
/**
* 获取招标发起详情
* @param {number} id - 发起主表ID
*/
export const getBiddingDetail = (id) => {
return request({ url: `/blade-zhaocai/bidding-self/${id}`, method: 'get' });
};
/**
* 更新招采负责人数据
* @param {number} id - 发起主表ID
* @param {Object} data - BiddingSelfUpdateDTO
*/
export const updateApproval = (id, data) => {
return request({ url: `/blade-zhaocai/bidding-self/${id}/update`, method: 'put', data });
};
/**
* 获取评标原则列表
*/
export const getEvaluationPrinciples = () => {
return request({ url: '/blade-zhaocai/bidding-self/evaluation-principles', method: 'get' });
};
/**
* 获取组织架构树
*/
export const getOrganizationTree = () => {
return request({ url: '/blade-zhaocai/bidding-self/organization-tree', method: 'get' });
};
// ==================== 3.7.4.3 总裁办负责人审批 ====================
/**
* 更新总裁办负责人数据
* @param {number} id - 发起主表ID
* @param {Object} data - BiddingSelfFinalApprovalDTO
*/
export const updateFinalApproval = (id, data) => {
return request({ url: `/blade-zhaocai/bidding-self/${id}/final-approval`, method: 'put', data });
};
// ==================== 3.7.4.4 供应商报名 ====================
/**
* 获取报名项目列表(通用)
* 供应商报名页面优先使用 getBiddingDetail(id) 按流程审批ID查询单个招标信息
*/
export const getRegistrationList = () => {
return request({ url: '/blade-zhaocai/bidding-self/registration/list', method: 'get' });
};
/**
* 提交报名
* @param {Object} data - BiddingSelfRegistrationDTO
*/
export const submitRegistration = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/registration/submit', method: 'post', data });
};
/**
* 获取我的报名
*/
export const getMyRegistration = () => {
return request({ url: '/blade-zhaocai/bidding-self/registration/my', method: 'get' });
};
// ==================== 3.7.4.5 资质审核 ====================
/**
* 获取待审核供应商
* @param {number} initiateId - 发起主表ID
*/
export const getQualificationList = (initiateId) => {
return request({ url: '/blade-zhaocai/bidding-self/qualification/list', method: 'get', params: { initiateId } });
};
/**
* 审核供应商资质
* @param {Object} data - BiddingSelfQualificationAuditDTO
*/
export const auditQualification = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/qualification/audit', method: 'post', data });
};
/**
* 批量审核供应商资质
* @param {Object} data - 批量审核数据
*/
export const batchAuditQualification = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/qualification/batch', method: 'post', data });
};
// ==================== 3.7.4.6 开标/投标 ====================
/**
* 获取待投标项目
*/
export const getBidList = () => {
return request({ url: '/blade-zhaocai/bidding-self/bid/list', method: 'get' });
};
/**
* 开标签到
* @param {Object} data - BiddingSelfBidSignDTO
*/
export const bidSign = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/bid/sign', method: 'post', data });
};
/**
* 提交投标
* @param {Object} data - BiddingSelfBidDTO
*/
export const submitBid = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/bid/submit', method: 'post', data });
};
/**
* 开标
* @param {Object} data - 开标数据
*/
export const bidOpening = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/bid/opening', method: 'post', data });
};
/**
* 流标
* @param {Object} data - 流标数据
*/
export const bidFlow = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/bid/flow', method: 'post', data });
};
/**
* 导出签到表
* @param {number} initiateId - 发起主表ID
*/
export const exportSignList = (initiateId) => {
return request({ url: '/blade-zhaocai/bidding-self/bid/sign-export', method: 'get', params: { initiateId } });
};
// ==================== 3.7.4.7 唱标 ====================
/**
* 获取唱标列表
* @param {number} initiateId - 发起主表ID
*/
export const getOpeningList = (initiateId) => {
return request({ url: '/blade-zhaocai/bidding-self/opening/list', method: 'get', params: { initiateId } });
};
/**
* 生成唱标记录
* @param {Object} data - BiddingSelfOpeningRecordDTO
*/
export const generateOpeningRecord = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/opening/record', method: 'post', data });
};
/**
* 唱标结束
* @param {Object} data - 唱标结束数据
*/
export const completeOpening = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/opening/complete', method: 'post', data });
};
// ==================== 3.7.4.8 专家签到 ====================
/**
* 专家签到
* @param {Object} data - 专家签到数据
*/
export const expertSign = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/expert/sign', method: 'post', data });
};
/**
* 上传签署文件
* @param {Object} data - 签署文件数据
*/
export const uploadSignFile = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/expert/sign-file', method: 'post', data });
};
/**
* 审核签署文件
* @param {Object} data - 审核数据
*/
export const auditSignFile = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/expert/audit', method: 'post', data });
};
// ==================== 3.7.4.9 专家评标 ====================
/**
* 获取待评标列表
* @param {number} initiateId - 发起主表ID
*/
export const getEvaluationList = (initiateId) => {
return request({ url: '/blade-zhaocai/bidding-self/evaluation/list', method: 'get', params: { initiateId } });
};
/**
* 获取投标方详情
* @param {number} supplierId - 供应商ID
*/
export const getEvaluationDetail = (supplierId) => {
return request({ url: '/blade-zhaocai/bidding-self/evaluation/detail', method: 'get', params: { supplierId } });
};
/**
* 提交评分
* @param {Object} data - BiddingSelfEvaluationDTO
*/
export const submitScore = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/evaluation/score', method: 'post', data });
};
/**
* 生成资质认定表
* @param {Object} data - 生成数据
*/
export const generateCert = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/evaluation/cert', method: 'post', data });
};
// ==================== 3.7.4.10 资格认定表审批 ====================
/**
* 审核资格认定表
* @param {Object} data - 审核数据
*/
export const auditQualificationCert = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/qualification-cert/audit', method: 'post', data });
};
/**
* 发送淘汰通知
* @param {Object} data - 通知数据
*/
export const sendEliminationNotify = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/qualification-cert/notify', method: 'post', data });
};
// ==================== 3.7.4.11/15 供应商报价 ====================
/**
* 提交报价
* @param {Object} data - BiddingSelfQuoteDTO
*/
export const submitQuote = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/quote/submit', method: 'post', data });
};
/**
* 获取报价历史
* @param {number} initiateId - 发起主表ID
* @param {number} supplierId - 供应商ID
*/
export const getQuoteHistory = (initiateId, supplierId) => {
return request({ url: '/blade-zhaocai/bidding-self/quote/history', method: 'get', params: { initiateId, supplierId } });
};
// ==================== 3.7.4.12 出报价分 ====================
/**
* 计算报价分
* @param {Object} data - BiddingSelfScoreCalculateDTO
*/
export const calculateScore = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/score/calculate', method: 'post', data });
};
/**
* 获取评分配置
* @param {number} initiateId - 发起主表ID
*/
export const getScoreConfig = (initiateId) => {
return request({ url: '/blade-zhaocai/bidding-self/score/config', method: 'get', params: { initiateId } });
};
// ==================== 3.7.4.13 投票 ====================
/**
* 提交投票
* @param {Object} data - BiddingSelfVoteDTO
*/
export const submitVote = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/vote/submit', method: 'post', data });
};
/**
* 获取投票结果
* @param {number} initiateId - 发起主表ID
*/
export const getVoteResult = (initiateId) => {
return request({ url: '/blade-zhaocai/bidding-self/vote/result', method: 'get', params: { initiateId } });
};
// ==================== 3.7.4.14 确定入围供应商 ====================
/**
* 确认入围
* @param {Object} data - BiddingSelfFinalistDTO
*/
export const confirmFinalist = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/finalist/confirm', method: 'post', data });
};
/**
* 通知入围供应商
* @param {Object} data - 通知数据
*/
export const notifyFinalist = (data) => {
return request({ url: '/blade-zhaocai/bidding-self/finalist/notify', method: 'post', data });
};
3.4 文件上传说明
文件上传 不单独封装 API 函数,直接使用 el-upload 组件的 action 属性指向 /blade-zhaocai/bidding-self/upload,由 axios 拦截器自动注入 token 和请求头。
4. 数据类型定义
4.1 基础数据类型(已有)
// BladeFile(附件对象)
// {
// name: string, // 文件名(存储名)
// url: string, // 文件访问URL
// size: number, // 文件大小(字节)
// originalName: string, // 原始文件名
// contentType: string, // 文件类型
// }
// SubjectItem(标的物)
// {
// seqNo: number, // 序号
// materialName: string, // 物料名称
// materialCode: string, // 物料编码
// specification: string, // 规格型号
// brand: string, // 品牌
// unit: string, // 计量单位
// referencePrice: number, // 参考价(不含税)
// estimatedQuantity: number, // 预计数量
// estimatedUseTime: string, // 预计使用时间
// amount: number, // 金额(元)
// contactPersonId: number, // 对接人ID
// contactPersonName: string, // 对接人姓名
// demandDesc: string, // 需求简介
// remark: string, // 备注
// }
// ExpertItem(评标专家)
// {
// expertId: number, // 专家ID
// expertName: string, // 专家姓名
// expertType: string, // 专家类型:appoint-指定 / random-随机
// }
// UserDeptItem(用户部门信息)
// {
// deptId: number, // 部门ID
// deptName: string, // 部门名称
// tenantId: number, // 公司ID(租户ID)
// tenantName: string, // 公司名称
// isDefault: boolean, // 是否默认部门
// }
4.2 新增数据类型
// BiddingSelfRegistration(供应商报名)
// {
// id: number, // 报名ID
// initiateId: number, // 发起主表ID
// supplierId: number, // 供应商ID
// supplierName: string, // 供应商名称
// contactName: string, // 联系人姓名
// contactPhone: string, // 联系人电话
// contactEmail: string, // 联系人邮箱
// qualificationFiles: string, // 资质文件(JSON BladeFile列表)
// otherFiles: string, // 其他资料(JSON BladeFile列表)
// status: string, // 状态:PENDING/APPROVED/REJECTED
// rejectReason: string, // 驳回原因
// }
// BiddingSelfQualification(资质审核)
// {
// id: number, // 审核ID
// initiateId: number, // 发起主表ID
// supplierId: number, // 供应商ID
// supplierName: string, // 供应商名称
// auditResult: string, // 审核结果:APPROVED/REJECTED
// rejectReason: string, // 未入围原因
// paymentStatus: string, // 付款状态:UNPAID/PAID
// paymentAmount: number, // 标书费用金额
// }
// BiddingSelfBid(投标/开标)
// {
// id: number, // 投标ID
// initiateId: number, // 发起主表ID
// supplierId: number, // 供应商ID
// signStatus: number, // 签到状态:0-未签到,1-已签到
// signTime: string, // 签到时间
// bidFiles: string, // 投标文件(JSON BladeFile列表)
// authorizationFile: string, // 授权书(JSON BladeFile)
// otherFiles: string, // 其他资料(JSON BladeFile列表)
// totalQuote: number, // 总报价(元)
// quoteDetails: string, // 报价明细(JSON)
// status: string, // 状态:PENDING/OPENED/FLOWED
// }
// BiddingSelfBidOpening(唱标记录)
// {
// id: number, // 唱标ID
// initiateId: number, // 发起主表ID
// supplierId: number, // 供应商ID
// supplierName: string, // 供应商名称
// totalQuote: number, // 投标总报价(元)
// taxRate: number, // 税率
// totalWithTax: number, // 含税总价
// totalWithoutTax: number, // 不含税总价
// taxCategory: string, // 税目
// deliveryPeriod: string, // 工期/交货期/质保期
// remarks: string, // 补充说明
// openingRecordFile: string, // 唱标记录表文件(JSON BladeFile)
// status: string, // 状态:PENDING/COMPLETED
// }
// BiddingSelfExpertSign(专家签到)
// {
// id: number, // 签到ID
// initiateId: number, // 发起主表ID
// expertId: number, // 专家ID
// expertName: string, // 专家姓名
// expertTitle: string, // 职称
// expertCategory: string, // 专业类别
// expertOrg: string, // 所属单位
// signStatus: number, // 签到状态:0-未签到,1-已签到
// signTime: string, // 签到时间
// signFiles: string, // 电子签署文件(JSON BladeFile列表)
// signStatusFile: string, // 签署状态:UNSIGNED/SIGNED/REJECTED
// }
// BiddingSelfEvaluation(专家评标)
// {
// id: number, // 评分ID
// initiateId: number, // 发起主表ID
// expertId: number, // 专家ID
// expertName: string, // 专家姓名
// supplierId: number, // 供应商ID
// supplierName: string, // 供应商名称
// qualificationScore: number, // 资质审查评分
// technicalScore: number, // 技术标准评分
// businessScore: number, // 商务标准评分
// priceScore: number, // 价格评分
// comprehensiveScore: number, // 综合评分
// evaluationOpinion: string, // 评审意见
// status: string, // 状态:PENDING/COMPLETED
// }
// BiddingSelfQuote(供应商报价)
// {
// id: number, // 报价ID
// initiateId: number, // 发起主表ID
// supplierId: number, // 供应商ID
// quoteRound: number, // 报价轮次:1-第一轮,2-第二轮,3-终报
// totalAmount: number, // 报价总金额(元)
// totalAmountUpper: string, // 总金额大写
// deliveryPeriod: string, // 服务/交货周期/质保期
// remarks: string, // 补充说明/优惠承诺
// quoteDetails: string, // 报价明细(JSON)
// quoteFiles: string, // 报价附件(JSON BladeFile列表)
// deadline: string, // 报价截止时间
// }
// BiddingSelfScore(报价分计算)
// {
// id: number, // 计算ID
// initiateId: number, // 发起主表ID
// scoreMethod: string, // 评分方式:LOW_PRICE/BASE_PRICE
// scoreWeight: number, // 价格分权重
// quoteRound: number, // 报价轮次
// scoreDetails: string, // 报价分明细(JSON)
// }
// ScoreResultItem(报价分结果项)
// {
// supplierName: string, // 供应商名称
// quote: number, // 报价(元)
// priceReduction: number, // 降价幅度
// lowestPrice: number, // 本轮最低价
// priceScore: number, // 价格分
// }
// BiddingSelfVote(投票)
// {
// id: number, // 投票ID
// initiateId: number, // 发起主表ID
// voterId: number, // 投票人ID
// voterName: string, // 投票人姓名
// voterRole: string, // 投票人角色:BUSINESS/PROCUREMENT/AUDIT
// voteRound: number, // 投票轮次
// voteType: string, // 投票类型:SINGLE/MULTIPLE
// voteResult: string, // 投票结果(JSON:供应商ID列表)
// personalOpinion: string, // 个人意见备注
// status: string, // 状态:PENDING/COMPLETED
// }
// VoteResultItem(投票结果项)
// {
// supplierId: number, // 供应商ID
// supplierName: string, // 供应商名称
// voteCount: number, // 得票数
// ranking: number, // 排名
// }
// BiddingSelfFinalist(入围供应商)
// {
// id: number, // 入围ID
// initiateId: number, // 发起主表ID
// supplierId: number, // 供应商ID
// supplierName: string, // 供应商名称
// ranking: number, // 排名
// comprehensiveScore: number, // 综合评分
// voteCount: number, // 得票数
// finalQuote: number, // 最终报价
// status: string, // 状态:CONFIRMED/REJECTED
// }
5. 页面设计
5.1 通用设计原则
| 项目 | 设计决策 | 理由 |
|---|---|---|
| API 风格 | Options API | 项目主流风格,与 90% 现有页面保持一致 |
| 容器组件 | basic-container |
全局注册组件,所有页面统一使用 |
| 表单组件 | Element Plus 原生表单 | 非标准 CRUD 列表,avue-crud 不适用复杂表单布局 |
| 表格组件 | el-table + el-table-column |
标的物列表需要自定义列和交互 |
| 状态管理 | 组件内部 data |
流程表单数据无需全局共享 |
| 时间处理 | dayjs(this.$dayjs) |
全局注入,统一时区处理 |
| 富文本编辑器 | avue-ueditor |
项目已集成,公告内容编辑使用 |
5.2 发起页面(src/views/bidding/initiate.vue)— 3.7.4.1
功能:招标发起人填写自行招标发起表单。页面数据根据预招标流程自动带出。
接口:
- 加载预招标数据:
GET /blade-zhaocai/bidding-self/pre-project/{preBiddingId} - 获取用户部门列表:
GET /blade-zhaocai/bidding-self/user-dept-list - 保存草稿:
POST /blade-zhaocai/bidding-self/draft - 提交:
POST /blade-zhaocai/bidding-self/submit
页面结构(从上到下):
-
发起人信息(自动带出,可编辑)
- 申请人:自动带出当前登录用户姓名,只读
- 申请时间:自动带出当前时间,只读
- 联系电话:自动带出当前用户电话,可修改,需验证手机号格式
- 所属部门:下拉框选择,调用
getUserDeptList获取部门列表,默认选中isDefault=true的项,选择后自动带出公司信息 - 所属公司:根据部门选择自动带出,只读
-
项目信息(表格形式,只读展示)
- 表格列:计划号、项目编号、项目名称、项目类型、预算金额、需求部门、需求公司、项目对接人
- 预算金额使用金额格式(保留两位小数)
-
标的物信息(列表形式,部分可编辑)
- 工具栏:添加明细按钮、清空明细按钮
- 表格列:序号、物料名称、物料编码、规格型号、品牌、计量单位、参考价、预计数量、预计使用时间、金额、对接人、需求简介、备注
- 序号自动生成(1开始)
- 物料名称必填,限制100字符
- 预计数量输入时,金额自动计算(参考价 × 数量)
- 对接人:点击选择,弹窗组织架构树
- 需求简介限制1000字符
-
投标要求(填写区)
- 报名开始/结束时间:时间控件,精确到时分秒
- 投标开始/结束时间:时间控件,精确到时分秒
- 投标方式:下拉选择(线上/线下)
- 开标时间:时间控件,精确到时分秒
- 校验:结束时间 > 开始时间
-
评标原则(选择区)
- 评标原则:下拉选择(调用
getEvaluationPrinciples) - 说明:自动带出,只读展示
- 评标原则:下拉选择(调用
-
评标小组(只读展示)
- 评标小组来源、评标小组人员列表
-
只读说明区(纯文本展示)
- 定标原则、合同签订说明、其他(没收投标保证金/严禁转包)
操作按钮:
- 取消:返回待招标库
- 保存草稿:调用
saveDraft - 提交:调用
submitBidding,提交成功后返回待招标库
提交校验:
- 所有必填字段已填写(包含
deptId必填) - 时间逻辑正确(结束时间 > 开始时间)
- 预计数量 > 0
- 联系电话格式正确
- 物料名称不为空且 <= 100字符
- 需求简介 <= 1000字符
防抖:保存草稿和提交按钮防抖 3 秒,提交期间按钮禁用
5.3 审批页面(src/views/bidding/approval.vue)— 3.7.4.2
功能:招采负责人对发起人提交的信息进行补充,填写招标公告核心信息并上传文件。
接口:
- 加载数据:
GET /blade-zhaocai/bidding-self/{id} - 保存数据:
PUT /blade-zhaocai/bidding-self/{id}/update - 文件上传:
POST /blade-zhaocai/bidding-self/upload
页面结构(从上到下):
-
上部:发起信息只读展示(默认展示,任何节点都显示)
- 显示发起页面填写的所有信息(发起人、项目、标的物、投标要求、评标原则、评标小组)
- 只读展示,不可编辑
-
中部:招标公告信息(根据节点名称控制可编辑性)
- 报名开始/结束时间:时间控件,精确到年月日时分,可修改
- 投标开始/结束时间:时间控件,精确到年月日时分,可修改
- 开标时间:时间控件,精确到年月日时分,可修改
- 投标方式:下拉选择(线上/线下),默认线上
- 投标地点:文本输入,选择线下时必填
- 投标联系方式:文本输入,格式:姓名、电话、邮箱
- 招标公告:文件上传,必填,支持 PDF/DOC/DOCX/JPG/PNG
-
下部:供应商资质审核视图(仅当
nodeName为供应商资质审核时展示)- 已报名供应商列表
- 审核弹窗
权限控制:
- 节点名称为"总裁办招采负责人审批"时允许编辑招标公告信息
- 节点名称为"供应商资质审核"时,在发起信息下方展示供应商资质审核视图
- 非目标节点时所有字段只读,仅显示"关闭"按钮
操作按钮:
- 取消/关闭:返回列表
- 暂存:保存当前编辑内容(不校验必填)
- 保存:校验后调用
updateApproval,保存业务数据 - 保存审核:在资质审核弹窗中保存当前审核结果
保存校验:
- 时间逻辑正确(结束时间 > 开始时间)
- 选择线下时,投标地点必填
- 招标公告文件必须上传
防抖:保存和暂存按钮防抖 3 秒,提交期间按钮禁用
注意:此页面不处理审批同意/驳回操作(由后续流程统一接口处理),仅保存业务数据(时间、地点、联系方式、附件信息)
5.4 总裁办负责人审批页面(src/views/bidding/final-approval.vue)— 3.7.4.3
功能:总裁办主任对招采负责人提交的信息进行审核。审核表单同上一节点页面,若有意见可在表单上填写意见。
接口:
- 加载数据:
GET /blade-zhaocai/bidding-self/{id} - 保存数据:
PUT /blade-zhaocai/bidding-self/{id}/final-approval - 文件上传:
POST /blade-zhaocai/bidding-self/upload
页面结构(从上到下):
-
上部:发起信息只读展示(默认展示,任何节点都显示)
- 显示发起页面和招采负责人填写的所有信息(发起人、项目等)
- 只读展示,不可编辑
-
中部:总裁办负责人填写区
- 审批意见:文本输入,可填写审核意见
- 附件:可上传补充文件
-
下部:供应商资质审核视图(仅当
nodeName为供应商资质审时展示)- 已报名供应商列表
- 审核弹窗
操作按钮:
- 取消:返回列表
- 暂存:保存当前编辑内容(不校验必填)
- 保存:调用
updateFinalApproval,保存业务数据
节点名称控制:
- 当流程引擎传入的
nodeName为供应商资质审时,在发起信息下方展示供应商资质审核视图,调用getQualificationList与auditQualification - 其他节点名称时,页面展示总裁办负责人审批视图
保存校验:
- 审批意见可为空(同意时无需填写)
- 驳回时需填写驳回原因
防抖:保存、暂存及审核提交按钮防抖 3 秒,提交期间按钮禁用
注意:此页面不处理审批同意/驳回操作(由后续流程统一接口处理),仅保存业务数据(审批意见、附件信息)
路由规则:
- 同意 → 供应商报名
- 驳回 → 退回总裁办招采负责人审批节点
5.5 供应商报名页面(src/views/bidding/registration.vue)— 3.7.4.4
功能:供应商通过招标公告中的报名网址进入系统,查看正在报名中的项目列表,选择项目进行报名。
路由参数:
- 供应商报名页面为外部入口页面,可通过流程引擎挂载或直接通过公告中的报名URL访问。
- 示例URL:
/bidding-self-registration/index
接口:
- 获取报名项目列表:
GET /blade-zhaocai/bidding-self/registration/list - 提交报名:
POST /blade-zhaocai/bidding-self/registration/submit - 获取我的报名:
GET /blade-zhaocai/bidding-self/registration/my - 文件上传:
POST /blade-zhaocai/bidding-self/upload
说明:
- 页面初始化时调用
getRegistrationList()获取正在报名中的项目列表,赋值给registrationList。 - 表格字段映射:
projectCode(项目编号)、projectName(项目名称)、projectType(项目类型)、registrationStartTime(报名开始时间)、registrationEndTime(报名结束时间)、bidOpeningTime(开标时间)。
页面结构(从上到下):
-
报名项目列表
- 表格列:项目编号、项目名称、项目类型、报名开始时间、报名结束时间、剩余报名时间(倒计时)、开标时间、操作(报名按钮)
- 业务规则:当前时间超过报名结束时间后,操作列不再展示“报名”按钮
-
报名弹窗
- 供应商名称:自动带出(根据登录账号)
- 联系人:输入,必填,限制50字符
- 联系电话:输入,必填,手机号格式
- 联系邮箱:输入,必填,邮箱格式
- 资质文件:文件上传(PDF/图片),必填,营业执照、资质证书等
- 其他资料:文件上传(PDF/图片),选填
-
我的报名(在"与您相关的项目"窗口查看)
- 表格列:招标方式、项目编号、开始投标时间、剩余投标时间(倒计时)、开标时间、操作(查看详情/修改报名)
操作按钮:
- 提交报名:提交报名信息
- 取消:关闭报名窗口
说明:弹窗中的联系人、联系电话、联系邮箱当前使用临时默认值(张三 / 13800138000 / supplier@example.com),后续将改为根据登录账号或供应商信息自动带出。
5.6 供应商资质审核页面(src/views/bidding/final-approval.vue)— 3.7.4.5
功能:在投标方报名完成后,审核投标方的相关资质,决定投标方是否入围。
实现说明:供应商资质审核逻辑已合并至
src/views/bidding/approval.vue与src/views/bidding/final-approval.vue。
approval.vue:当流程引擎传入的nodeName为供应商资质审核时,渲染资质审核视图。final-approval.vue:当流程引擎传入的nodeName为供应商资质审时,渲染资质审核视图。src/views/bidding/qualification.vue文件保留独立静态路由入口,但后续流程引擎统一使用approval.vue或final-approval.vue。
接口:
- 获取待审核供应商:
GET /blade-zhaocai/bidding-self/qualification/list?initiateId={id} - 审核供应商资质:
POST /blade-zhaocai/bidding-self/qualification/audit - 批量审核:
POST /blade-zhaocai/bidding-self/qualification/batch
页面结构(从上到下):
-
已报名供应商列表
- 表格列:投标方名称(可点击展开查看详情)、联系人、联系电话、报名状态、操作(审核按钮)
-
审核弹窗
- 供应商基本信息:自动带出(名称、联系人、联系方式)
- 资质文件:文件预览(支持预览和下载)
- 审核结果:下拉选择(入围/不入围)
- 未入围原因:文本输入,选择"不入围"时必填,限制500字符
操作按钮:
- 保存审核:保存当前审核结果
- 批量通过:批量选中供应商审核通过
- 批量驳回:批量选中供应商审核不通过
- 取消:返回列表
业务规则:
- 逐个审核供应商资质,可批量操作
- 选择"入围"后,系统自动向供应商发送收款信息(标书费用)
- 选择"不入围"时,必须填写未入围原因,系统通知供应商
- 审核通过后,供应商可进行付款购买标书
5.7 开标页面(src/views/bidding/bid.vue)— 3.7.4.6(招采负责人端)
功能:审核入围资质通过后,投标方在规定时间内进行报价投标。投标时间结束后,到达开标时间,进行开标操作。
接口:
- 获取待投标项目:
GET /blade-zhaocai/bidding-self/bid/list - 开标:
POST /blade-zhaocai/bidding-self/bid/opening - 流标:
POST /blade-zhaocai/bidding-self/bid/flow - 导出签到表:
GET /blade-zhaocai/bidding-self/bid/sign-export?initiateId={id}
页面结构(从上到下):
-
项目信息展示
- 项目编码、项目名称、投标开始时间、投标截止时间、开标时间、标的物明细
- 应签到/已签到:显示签到比例(如 5/8)
-
签到列表
- 表格列:投标方名称、签到时间、签到状态
- 支持导出签到表(Excel/PDF)
-
开标操作
- 到达开标时间后,如已报价投标方达到至少三家,则可以进行开标操作
- 开标时间到,现场宣布开标纪律,检查并先开启商务标,记录各投标人报价
-
流标操作(投标方不足三家时显示)
- 弹出流标公告通知窗口
- 编辑流标公告内容:公告标题、关键字、查看范围、是否置顶、招标简介
- 公告内容抓取招标内容自动生成,可手动编辑
5.8 投标页面(src/views/bidding/bid-supplier.vue)— 3.7.4.6(供应商端)
功能:供应商在开标前进行签到、上传投标文件、填写报价。
接口:
- 获取待投标项目:
GET /blade-zhaocai/bidding-self/bid/list - 开标签到:
POST /blade-zhaocai/bidding-self/bid/sign - 提交投标:
POST /blade-zhaocai/bidding-self/bid/submit - 文件上传:
POST /blade-zhaocai/bidding-self/upload
页面结构(从上到下):
-
项目信息展示(只读)
- 项目编码、项目名称、投标截止时间、开标时间、标的物明细
-
签到区
- 签到按钮:点击后调用
bidSign进行签到 - 签到状态显示
- 签到按钮:点击后调用
-
投标信息填写区
- 投标文件:文件上传(PDF),必填
- 授权书:文件上传(PDF),必填
- 其他资料:文件上传(PDF/图片),选填
- 报价明细:按标的物填写单价、数量,自动计算合价
- 总报价:自动汇总报价明细,只读
操作按钮:
- 保存草稿:保存投标信息,不提交
- 提交投标:提交投标文件和报价
- 取消:返回列表
5.9 唱标页面(src/views/bidding/opening.vue)— 3.7.4.7
功能:展示投标方报价信息,生成唱标记录表。
接口:
- 获取唱标列表:
GET /blade-zhaocai/bidding-self/opening/list?initiateId={id} - 生成唱标记录:
POST /blade-zhaocai/bidding-self/opening/record - 唱标结束:
POST /blade-zhaocai/bidding-self/opening/complete
页面结构(从上到下):
-
项目信息展示(只读)
-
唱标列表
- 表格列:投标方名称、投标总报价、税率、含税总价、不含税总价、税目、工期/交货期/质保期、补充说明
-
唱标记录操作
- 生成唱标记录表:调用
generateOpeningRecord,生成PDF文件 - 唱标结束:确认唱标结束,进入专家评标环节
- 生成唱标记录表:调用
操作按钮:
- 生成唱标记录表
- 唱标结束
- 返回列表
5.10 专家签到页面(src/views/bidding/expert-sign.vue)— 3.7.4.8
功能:专家线上签到并电子签署文件。
接口:
- 专家签到:
POST /blade-zhaocai/bidding-self/expert/sign - 上传签署文件:
POST /blade-zhaocai/bidding-self/expert/sign-file - 审核签署文件:
POST /blade-zhaocai/bidding-self/expert/audit
页面结构(从上到下):
-
项目信息展示(只读)
-
专家签到区
- 专家信息:姓名、职称、专业类别、所属单位
- 签到按钮:点击后签到
- 签到状态显示
-
电子签署区
- 签署文件:上传电子签署文件(PDF/图片)
- 签署状态:UNSIGNED/SIGNED/REJECTED
-
招采负责人审核区(仅招采负责人可见)
- 审核签署文件:通过/驳回
- 驳回原因:文本输入
操作按钮:
- 签到
- 上传签署文件
- 审核通过/驳回(招采负责人)
- 返回列表
5.11 专家评标页面(src/views/bidding/evaluation.vue)— 3.7.4.9
功能:专家对投标方进行评分。
接口:
- 获取待评标列表:
GET /blade-zhaocai/bidding-self/evaluation/list?initiateId={id} - 获取投标方详情:
GET /blade-zhaocai/bidding-self/evaluation/detail?initiateId={id}&supplierId={id} - 提交评分:
POST /blade-zhaocai/bidding-self/evaluation/score - 生成资质认定表:
POST /blade-zhaocai/bidding-self/evaluation/cert
页面结构(从上到下):
-
项目信息展示(只读)
-
待评标供应商列表
- 表格列:投标方名称、资质审查评分、技术标准评分、商务标准评分、价格评分、综合评分、操作(评分按钮)
-
评分弹窗
- 供应商基本信息:自动带出
- 投标文件:文件预览
- 资质审查评分:数字输入,0-100
- 技术标准评分:数字输入,0-100
- 商务标准评分:数字输入,0-100
- 价格评分:自动计算(根据报价)
- 综合评分:自动计算(加权汇总)
- 评审意见:文本输入,限制1000字符
-
生成资质认定表
- 所有专家评分完成后,生成资质认定表
操作按钮:
- 提交评分
- 生成资质认定表
- 返回列表
5.12 资格认定表审批页面(src/views/bidding/qualification-cert.vue)— 3.7.4.10
功能:招采负责人审核资格认定表,决定供应商是否入围。
接口:
- 审核资格认定表:
POST /blade-zhaocai/bidding-self/qualification-cert/audit - 发送淘汰通知:
POST /blade-zhaocai/bidding-self/qualification-cert/notify
页面结构(从上到下):
-
资格认定表展示
- 表格列:投标方名称、资质审查评分、技术标准评分、商务标准评分、价格评分、综合评分、排名
-
审核操作区
- 审核结果:通过/不通过
- 不通过原因:文本输入
-
淘汰通知
- 选择被淘汰供应商
- 发送淘汰通知
操作按钮:
- 审核通过
- 审核不通过
- 发送淘汰通知
- 返回列表
5.13 供应商报价页面(src/views/bidding/quote.vue)— 3.7.4.11/15
功能:入围供应商进行多轮报价(含终报)。
接口:
- 提交报价:
POST /blade-zhaocai/bidding-self/quote/submit - 获取报价历史:
GET /blade-zhaocai/bidding-self/quote/history?initiateId={id}&supplierId={id}
页面结构(从上到下):
-
项目信息展示(只读)
-
报价历史
- 表格列:报价轮次、报价总金额、报价时间、状态
-
当前报价区
- 报价总金额:金额输入,必填
- 总金额大写:自动转换
- 服务/交货周期/质保期:文本输入
- 补充说明/优惠承诺:文本输入
- 报价明细:按标的物填写单价、数量、小计
- 报价附件:文件上传(PDF/图片),选填
- 报价截止时间:只读展示
操作按钮:
- 提交报价
- 保存草稿
- 取消
5.14 出报价分页面(src/views/bidding/score.vue)— 3.7.4.12
功能:根据评分规则计算报价分。
接口:
- 计算报价分:
POST /blade-zhaocai/bidding-self/score/calculate - 获取评分配置:
GET /blade-zhaocai/bidding-self/score/config?initiateId={id}
页面结构(从上到下):
-
评分配置
- 评分方式:下拉选择(LOW_PRICE-低价优先/BASE_PRICE-基准价)
- 价格分权重:数字输入,0-100
- 报价轮次:数字输入
-
报价分明细
- 表格列:供应商名称、报价(元)、降价幅度、本轮最低价、价格分
-
计算公式展示
- 低价优先法:价格分 = (最低价 / 供应商报价) × 价格分权重
- 基准价法:价格分 = (基准价 / 供应商报价) × 价格分权重
操作按钮:
- 计算报价分
- 导出报价分表
- 返回列表
5.15 投票页面(src/views/bidding/vote.vue)— 3.7.4.13
功能:业务部门进行投票选定入围供应商。
接口:
- 提交投票:
POST /blade-zhaocai/bidding-self/vote/submit - 获取投票结果:
GET /blade-zhaocai/bidding-self/vote/result?initiateId={id}&voteRound={round}
页面结构(从上到下):
-
项目信息展示(只读)
-
投票区
- 投票轮次:数字输入
- 投票类型:单选/多选
- 供应商列表:表格展示,每行包含选择框
- 个人意见备注:文本输入
-
投票结果展示(投票完成后)
- 表格列:供应商名称、得票数、排名
操作按钮:
- 提交投票
- 查看投票结果
- 返回列表
5.16 确定入围供应商页面(src/views/bidding/finalist.vue)— 3.7.4.14
功能:确认入围名单并通知供应商。
接口:
- 确认入围:
POST /blade-zhaocai/bidding-self/finalist/confirm - 通知入围供应商:
POST /blade-zhaocai/bidding-self/finalist/notify
页面结构(从上到下):
-
入围供应商列表
- 表格列:供应商名称、排名、综合评分、得票数、最终报价
- 支持勾选确认入围
-
确认操作
- 确认入围:勾选后提交确认
- 发送入围通知:向入围供应商发送通知
操作按钮:
- 确认入围
- 发送入围通知
- 返回列表
6. 路由与流程引擎对接
6.1 路由设计
自行招标流程页面由 流程引擎动态挂载,不配置静态路由(除发起页面外可能需要独立路由)。流程引擎通过节点标识传递参数:
| 页面 | 接收参数 | 参数来源 |
|---|---|---|
| 发起页面 | preBiddingId |
待招标库跳转时传递 |
| 发起页面 | id(发起主表ID) |
草稿箱编辑时传递 |
| 审批页面 | id(发起主表ID) |
流程引擎 task 数据传递 |
| 审批页面 | nodeName(节点名称) |
流程引擎 task 数据传递,供应商资质审核 时切换为资质审核视图;总裁办招采负责人审批 时允许编辑招标公告信息 |
| 总裁办负责人审批页面 | id(发起主表ID) |
流程引擎 task 数据传递 |
| 总裁办负责人审批页面 | nodeName(节点名称) |
流程引擎 task 数据传递,供应商资质审 时切换为资质审核视图 |
| 其他页面 | id(发起主表ID) |
流程引擎 task 数据传递 |
6.2 页面挂载方式
流程引擎通过 <component :is="currentPage"> 动态切换,将业务 ID 作为 prop 传入:
// 流程引擎容器内(假设已有)
<template>
<component
:is="currentPage"
:node-data="nodeData"
@save="handleSave"
@submit="handleSubmit"
@cancel="handleCancel"
/>
</template>
本页面设计:所有页面作为独立组件,接收 nodeData prop 并 $emit 事件通知流程引擎。
6.3 静态路由(已配置)
// 自行招标发起
path: '/bidding-self-initiate/index'
// 自行招标审批
path: '/bidding-self-approval/index'
后续页面如需要独立访问入口,可继续扩展静态路由。
7. 时区与格式化
7.1 时间处理
- 所有时间展示使用
dayjs格式化(this.$dayjs全局注入) - 时间控件格式:
- 发起页:
YYYY-MM-DD HH:mm:ss - 审批页/终审页:
YYYY-MM-DD HH:mm - 供应商报名页:
YYYY-MM-DD HH:mm:ss
- 发起页:
- 提交时保持字符串格式,后端统一处理时区
- 倒计时显示:报名截止时间、投标截止时间等使用倒计时组件
// 示例:格式化显示
this.$dayjs(timeStr).format('YYYY-MM-DD HH:mm:ss');
// 倒计时
countdown(deadline) {
const now = this.$dayjs();
const end = this.$dayjs(deadline);
const diff = end.diff(now, 'second');
if (diff <= 0) return '已截止';
const days = Math.floor(diff / 86400);
const hours = Math.floor((diff % 86400) / 3600);
const minutes = Math.floor((diff % 3600) / 60);
return `${days}天${hours}小时${minutes}分钟`;
}
7.2 金额格式化
// 金额展示:千分位 + 两位小数
formatMoney(value) {
if (!value && value !== 0) return '-';
return '¥ ' + Number(value).toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
// 金额大写转换
formatMoneyUpper(value) {
// 使用现有工具或引入 num-to-zh-currency
}
8. 异常与边界处理
| 场景 | 处理策略 |
|---|---|
| 接口报错 | try/catch 捕获,ElMessage.error 提示错误信息 |
| 预招标 ID 无效 | 页面加载失败时提示并返回列表 |
| 提交校验失败 | 滚动到第一个错误字段,高亮提示 |
| 文件上传失败 | el-upload on-error 回调,提示上传失败 |
| 文件类型不符 | before-upload 校验文件类型和大小(≤50MB) |
| 文件数量超限 | el-upload limit 属性限制 5 个 |
| 网络超时 | axios 默认 30 秒超时,超时后提示重试 |
| 并发提交 | 按钮 loading 状态 + 防抖,防止重复提交 |
| 倒计时截止 | 报名/投标截止后,禁用相关操作按钮 |
| 权限不足 | 非目标节点时,表单只读,仅显示"关闭"按钮 |
9. 与接口文档的修正对照表
| 接口文档描述 | 实际项目修正 | 修正原因 |
|---|---|---|
| TypeScript + Pinia | Pure JavaScript + 组件内部状态 | 项目无 TS/Pinia,使用 Vuex 但流程表单无需全局状态 |
views/bidding/self/pages/ 目录 |
src/views/bidding/ + src/api/bidding/ |
遵循项目现有模块的扁平目录规范 |
PendingBidding.vue 主容器 |
不存在,由流程引擎直接挂载 | 当前项目中无该文件,无需创建容器 |
<component :is=""> 动态切换 |
由流程引擎实现,本页面仅提供子组件 | 保持页面职责单一 |
使用 el-upload 直接上传 |
保持使用,但利用 axios 拦截器自动注入 token | 无需手动设置 headers |
| 时间精确到秒(发起)+ 分(审批) | 发起页 YYYY-MM-DD HH:mm:ss,审批页 YYYY-MM-DD HH:mm |
与接口定义保持一致 |
接口路径 /blade-zhaocai/bidding-self/... |
/blade-zhaocai/bidding-self/... |
与后端实际服务前缀保持一致 |
| 15个独立页面 | 15个独立 .vue 文件 |
每个节点一个完整页面,不复用 |
10. 开发 checklist
10.1 已完成(V1.0)
- 创建
src/api/bidding/self.js— 基础 API 函数(9个) - 创建
src/views/bidding/initiate.vue— 发起页面 - 创建
src/views/bidding/approval.vue— 审批页面 - 发起人页面:表单校验、时间校验、金额自动计算、防抖处理
- 审批页面:文件上传/预览/删除、提交逻辑、时间校验
- 两页面:组织架构树弹窗选择对接人
- 发起人信息优化:所属部门下拉框,选择后自动带出公司信息
- 审批页面权限控制:根据节点名称判断编辑权限
10.2 待开发(V2.0)
- 扩展
src/api/bidding/self.js— 新增33个API函数(序号10-42) - 创建
src/views/bidding/final-approval.vue— 3.7.4.3 总裁办负责人审批 - 创建
src/views/bidding/registration.vue— 3.7.4.4 供应商报名 - 创建
src/views/bidding/qualification.vue— 3.7.4.5 资质审核 - 创建
src/views/bidding/bid.vue— 3.7.4.6 开标(招采负责人端) - 创建
src/views/bidding/bid-supplier.vue— 3.7.4.6 投标(供应商端) - 创建
src/views/bidding/opening.vue— 3.7.4.7 唱标 - 创建
src/views/bidding/expert-sign.vue— 3.7.4.8 专家签到 - 创建
src/views/bidding/evaluation.vue— 3.7.4.9 专家评标 - 创建
src/views/bidding/qualification-cert.vue— 3.7.4.10 资格认定表审批 - 创建
src/views/bidding/quote.vue— 3.7.4.11/15 供应商报价 - 创建
src/views/bidding/score.vue— 3.7.4.12 出报价分 - 创建
src/views/bidding/vote.vue— 3.7.4.13 投票 - 创建
src/views/bidding/finalist.vue— 3.7.4.14 确定入围供应商 - 联调:与后端42个接口逐一验证
- 测试:文件上传、表单校验、时间边界、并发提交、倒计时、权限控制
11. 变更记录
| 版本 | 日期 | 修改内容 | 修改人 |
|---|---|---|---|
| V1.0 | 2026-06-17 | 初始版本:发起页面 + 审批页面 | - |
| V1.1 | 2026-06-22 | 发起人信息优化:增加所属部门下拉框,选择后自动带出公司信息 | - |
| V1.2 | 2026-06-23 | 审批页面优化:权限控制、标题调整、投标地点位置调整、OSS上传、非必填 | - |
| V2.0 | 2026-06-24 | 完整流程设计:从2个节点扩展到15个完整节点,新增13个页面设计、36个API接口、12个数据类型 | - |
| V2.1 | 2026-06-30 | 供应商报名页面:超过报名结束时间隐藏“报名”按钮;弹窗联系人字段增加临时默认值;移除“保存草稿”按钮 | - |
| V2.2 | 2026-06-30 | 依据接口文档 V1.3 调整:去除第三方系统实现的“公众号/招采平台发布公告”模块(原 3.7.4.4),后续节点编号依次前移;接口前缀统一为 /api;接口总数由45调整为42;文件结构、API清单、数据类型、页面设计、开发 checklist 同步更新 |
- |
文档结束