1464 lines
56 KiB
Markdown
1464 lines
56 KiB
Markdown
# 前端开发设计文档 — 自行招标流程
|
||
|
||
**版本**: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 确定入围供应商
|
||
```
|
||
|
||
> **设计理由**:
|
||
> 1. 项目标准结构为 `src/api/{module}/` + `src/views/{module}/`,无需 `option` 层(非标准 CRUD 列表页)
|
||
> 2. 不创建 `self/pages/` 子目录,保持与项目现有模块的目录风格一致
|
||
> 3. 无 `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 函数定义
|
||
|
||
```javascript
|
||
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 基础数据类型(已有)
|
||
|
||
```javascript
|
||
// 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 新增数据类型
|
||
|
||
```javascript
|
||
// 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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 发起人信息(自动带出,可编辑)
|
||
- 申请人:自动带出当前登录用户姓名,只读
|
||
- 申请时间:自动带出当前时间,只读
|
||
- 联系电话:自动带出当前用户电话,可修改,需验证手机号格式
|
||
- 所属部门:下拉框选择,调用 `getUserDeptList` 获取部门列表,默认选中 `isDefault=true` 的项,选择后自动带出公司信息
|
||
- 所属公司:根据部门选择自动带出,只读
|
||
|
||
2. 项目信息(表格形式,只读展示)
|
||
- 表格列:计划号、项目编号、项目名称、项目类型、预算金额、需求部门、需求公司、项目对接人
|
||
- 预算金额使用金额格式(保留两位小数)
|
||
|
||
3. 标的物信息(列表形式,部分可编辑)
|
||
- 工具栏:添加明细按钮、清空明细按钮
|
||
- 表格列:序号、物料名称、物料编码、规格型号、品牌、计量单位、参考价、预计数量、预计使用时间、金额、对接人、需求简介、备注
|
||
- 序号自动生成(1开始)
|
||
- 物料名称必填,限制100字符
|
||
- 预计数量输入时,金额自动计算(参考价 × 数量)
|
||
- 对接人:点击选择,弹窗组织架构树
|
||
- 需求简介限制1000字符
|
||
|
||
4. 投标要求(填写区)
|
||
- 报名开始/结束时间:时间控件,精确到时分秒
|
||
- 投标开始/结束时间:时间控件,精确到时分秒
|
||
- 投标方式:下拉选择(线上/线下)
|
||
- 开标时间:时间控件,精确到时分秒
|
||
- 校验:结束时间 > 开始时间
|
||
|
||
5. 评标原则(选择区)
|
||
- 评标原则:下拉选择(调用 `getEvaluationPrinciples`)
|
||
- 说明:自动带出,只读展示
|
||
|
||
6. 评标小组(只读展示)
|
||
- 评标小组来源、评标小组人员列表
|
||
|
||
7. 只读说明区(纯文本展示)
|
||
- 定标原则、合同签订说明、其他(没收投标保证金/严禁转包)
|
||
|
||
**操作按钮**:
|
||
- 取消:返回待招标库
|
||
- 保存草稿:调用 `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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 上部:发起信息只读展示(默认展示,任何节点都显示)
|
||
- 显示发起页面填写的所有信息(发起人、项目、标的物、投标要求、评标原则、评标小组)
|
||
- 只读展示,不可编辑
|
||
|
||
2. 中部:招标公告信息(根据节点名称控制可编辑性)
|
||
- 报名开始/结束时间:时间控件,精确到年月日时分,可修改
|
||
- 投标开始/结束时间:时间控件,精确到年月日时分,可修改
|
||
- 开标时间:时间控件,精确到年月日时分,可修改
|
||
- 投标方式:下拉选择(线上/线下),默认线上
|
||
- 投标地点:文本输入,选择线下时必填
|
||
- 投标联系方式:文本输入,格式:姓名、电话、邮箱
|
||
- 招标公告:文件上传,必填,支持 PDF/DOC/DOCX/JPG/PNG
|
||
|
||
3. 下部:供应商资质审核视图(仅当 `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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 上部:发起信息只读展示(默认展示,任何节点都显示)
|
||
- 显示发起页面和招采负责人填写的所有信息(发起人、项目等)
|
||
- 只读展示,不可编辑
|
||
|
||
2. 中部:总裁办负责人填写区
|
||
- 审批意见:文本输入,可填写审核意见
|
||
- 附件:可上传补充文件
|
||
|
||
3. 下部:供应商资质审核视图(仅当 `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`(开标时间)。
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 报名项目列表
|
||
- 表格列:项目编号、项目名称、项目类型、报名开始时间、报名结束时间、剩余报名时间(倒计时)、开标时间、操作(报名按钮)
|
||
- 业务规则:当前时间超过报名结束时间后,操作列不再展示“报名”按钮
|
||
|
||
2. 报名弹窗
|
||
- 供应商名称:自动带出(根据登录账号)
|
||
- 联系人:输入,必填,限制50字符
|
||
- 联系电话:输入,必填,手机号格式
|
||
- 联系邮箱:输入,必填,邮箱格式
|
||
- 资质文件:文件上传(PDF/图片),必填,营业执照、资质证书等
|
||
- 其他资料:文件上传(PDF/图片),选填
|
||
|
||
3. 我的报名(在"与您相关的项目"窗口查看)
|
||
- 表格列:招标方式、项目编号、开始投标时间、剩余投标时间(倒计时)、开标时间、操作(查看详情/修改报名)
|
||
|
||
**操作按钮**:
|
||
- 提交报名:提交报名信息
|
||
- 取消:关闭报名窗口
|
||
|
||
> **说明**:弹窗中的联系人、联系电话、联系邮箱当前使用临时默认值(张三 / 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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 已报名供应商列表
|
||
- 表格列:投标方名称(可点击展开查看详情)、联系人、联系电话、报名状态、操作(审核按钮)
|
||
|
||
2. 审核弹窗
|
||
- 供应商基本信息:自动带出(名称、联系人、联系方式)
|
||
- 资质文件:文件预览(支持预览和下载)
|
||
- 审核结果:下拉选择(入围/不入围)
|
||
- 未入围原因:文本输入,选择"不入围"时必填,限制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}`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示
|
||
- 项目编码、项目名称、投标开始时间、投标截止时间、开标时间、标的物明细
|
||
- 应签到/已签到:显示签到比例(如 5/8)
|
||
|
||
2. 签到列表
|
||
- 表格列:投标方名称、签到时间、签到状态
|
||
- 支持导出签到表(Excel/PDF)
|
||
|
||
3. 开标操作
|
||
- 到达开标时间后,如已报价投标方达到至少三家,则可以进行开标操作
|
||
- 开标时间到,现场宣布开标纪律,检查并先开启商务标,记录各投标人报价
|
||
|
||
4. 流标操作(投标方不足三家时显示)
|
||
- 弹出流标公告通知窗口
|
||
- 编辑流标公告内容:公告标题、关键字、查看范围、是否置顶、招标简介
|
||
- 公告内容抓取招标内容自动生成,可手动编辑
|
||
|
||
---
|
||
|
||
### 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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示(只读)
|
||
- 项目编码、项目名称、投标截止时间、开标时间、标的物明细
|
||
|
||
2. 签到区
|
||
- 签到按钮:点击后调用 `bidSign` 进行签到
|
||
- 签到状态显示
|
||
|
||
3. 投标信息填写区
|
||
- 投标文件:文件上传(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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示(只读)
|
||
|
||
2. 唱标列表
|
||
- 表格列:投标方名称、投标总报价、税率、含税总价、不含税总价、税目、工期/交货期/质保期、补充说明
|
||
|
||
3. 唱标记录操作
|
||
- 生成唱标记录表:调用 `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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示(只读)
|
||
|
||
2. 专家签到区
|
||
- 专家信息:姓名、职称、专业类别、所属单位
|
||
- 签到按钮:点击后签到
|
||
- 签到状态显示
|
||
|
||
3. 电子签署区
|
||
- 签署文件:上传电子签署文件(PDF/图片)
|
||
- 签署状态:UNSIGNED/SIGNED/REJECTED
|
||
|
||
4. 招采负责人审核区(仅招采负责人可见)
|
||
- 审核签署文件:通过/驳回
|
||
- 驳回原因:文本输入
|
||
|
||
**操作按钮**:
|
||
- 签到
|
||
- 上传签署文件
|
||
- 审核通过/驳回(招采负责人)
|
||
- 返回列表
|
||
|
||
---
|
||
|
||
### 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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示(只读)
|
||
|
||
2. 待评标供应商列表
|
||
- 表格列:投标方名称、资质审查评分、技术标准评分、商务标准评分、价格评分、综合评分、操作(评分按钮)
|
||
|
||
3. 评分弹窗
|
||
- 供应商基本信息:自动带出
|
||
- 投标文件:文件预览
|
||
- 资质审查评分:数字输入,0-100
|
||
- 技术标准评分:数字输入,0-100
|
||
- 商务标准评分:数字输入,0-100
|
||
- 价格评分:自动计算(根据报价)
|
||
- 综合评分:自动计算(加权汇总)
|
||
- 评审意见:文本输入,限制1000字符
|
||
|
||
4. 生成资质认定表
|
||
- 所有专家评分完成后,生成资质认定表
|
||
|
||
**操作按钮**:
|
||
- 提交评分
|
||
- 生成资质认定表
|
||
- 返回列表
|
||
|
||
---
|
||
|
||
### 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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 资格认定表展示
|
||
- 表格列:投标方名称、资质审查评分、技术标准评分、商务标准评分、价格评分、综合评分、排名
|
||
|
||
2. 审核操作区
|
||
- 审核结果:通过/不通过
|
||
- 不通过原因:文本输入
|
||
|
||
3. 淘汰通知
|
||
- 选择被淘汰供应商
|
||
- 发送淘汰通知
|
||
|
||
**操作按钮**:
|
||
- 审核通过
|
||
- 审核不通过
|
||
- 发送淘汰通知
|
||
- 返回列表
|
||
|
||
---
|
||
|
||
### 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}`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示(只读)
|
||
|
||
2. 报价历史
|
||
- 表格列:报价轮次、报价总金额、报价时间、状态
|
||
|
||
3. 当前报价区
|
||
- 报价总金额:金额输入,必填
|
||
- 总金额大写:自动转换
|
||
- 服务/交货周期/质保期:文本输入
|
||
- 补充说明/优惠承诺:文本输入
|
||
- 报价明细:按标的物填写单价、数量、小计
|
||
- 报价附件:文件上传(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}`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 评分配置
|
||
- 评分方式:下拉选择(LOW_PRICE-低价优先/BASE_PRICE-基准价)
|
||
- 价格分权重:数字输入,0-100
|
||
- 报价轮次:数字输入
|
||
|
||
2. 报价分明细
|
||
- 表格列:供应商名称、报价(元)、降价幅度、本轮最低价、价格分
|
||
|
||
3. 计算公式展示
|
||
- 低价优先法:价格分 = (最低价 / 供应商报价) × 价格分权重
|
||
- 基准价法:价格分 = (基准价 / 供应商报价) × 价格分权重
|
||
|
||
**操作按钮**:
|
||
- 计算报价分
|
||
- 导出报价分表
|
||
- 返回列表
|
||
|
||
---
|
||
|
||
### 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}`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 项目信息展示(只读)
|
||
|
||
2. 投票区
|
||
- 投票轮次:数字输入
|
||
- 投票类型:单选/多选
|
||
- 供应商列表:表格展示,每行包含选择框
|
||
- 个人意见备注:文本输入
|
||
|
||
3. 投票结果展示(投票完成后)
|
||
- 表格列:供应商名称、得票数、排名
|
||
|
||
**操作按钮**:
|
||
- 提交投票
|
||
- 查看投票结果
|
||
- 返回列表
|
||
|
||
---
|
||
|
||
### 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`
|
||
|
||
**页面结构**(从上到下):
|
||
|
||
1. 入围供应商列表
|
||
- 表格列:供应商名称、排名、综合评分、得票数、最终报价
|
||
- 支持勾选确认入围
|
||
|
||
2. 确认操作
|
||
- 确认入围:勾选后提交确认
|
||
- 发送入围通知:向入围供应商发送通知
|
||
|
||
**操作按钮**:
|
||
- 确认入围
|
||
- 发送入围通知
|
||
- 返回列表
|
||
|
||
---
|
||
|
||
## 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 传入:
|
||
|
||
```javascript
|
||
// 流程引擎容器内(假设已有)
|
||
<template>
|
||
<component
|
||
:is="currentPage"
|
||
:node-data="nodeData"
|
||
@save="handleSave"
|
||
@submit="handleSubmit"
|
||
@cancel="handleCancel"
|
||
/>
|
||
</template>
|
||
```
|
||
|
||
**本页面设计**:所有页面作为独立组件,接收 `nodeData` prop 并 `$emit` 事件通知流程引擎。
|
||
|
||
### 6.3 静态路由(已配置)
|
||
|
||
```javascript
|
||
// 自行招标发起
|
||
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`
|
||
- 提交时保持字符串格式,后端统一处理时区
|
||
- 倒计时显示:报名截止时间、投标截止时间等使用倒计时组件
|
||
|
||
```javascript
|
||
// 示例:格式化显示
|
||
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 金额格式化
|
||
|
||
```javascript
|
||
// 金额展示:千分位 + 两位小数
|
||
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)
|
||
- [x] 创建 `src/api/bidding/self.js` — 基础 API 函数(9个)
|
||
- [x] 创建 `src/views/bidding/initiate.vue` — 发起页面
|
||
- [x] 创建 `src/views/bidding/approval.vue` — 审批页面
|
||
- [x] 发起人页面:表单校验、时间校验、金额自动计算、防抖处理
|
||
- [x] 审批页面:文件上传/预览/删除、提交逻辑、时间校验
|
||
- [x] 两页面:组织架构树弹窗选择对接人
|
||
- [x] 发起人信息优化:所属部门下拉框,选择后自动带出公司信息
|
||
- [x] 审批页面权限控制:根据节点名称判断编辑权限
|
||
|
||
### 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 同步更新 | - |
|
||
|
||
---
|
||
|
||
**文档结束** |