|
|
# 直接支付页面功能说明
|
|
|
|
|
|
## 页面概述
|
|
|
|
|
|
**页面路径**: `/payment/direct-payment?payment_type=direct`
|
|
|
**组件文件**: `src/views/payment/DirectPayment.vue` (包装组件)
|
|
|
**实际组件**: `src/views/payment/CreatePayment.vue` (核心组件)
|
|
|
|
|
|
直接支付页面用于创建无需审批流程的支付申请,适用于水电费、工会经费、人员工资等常规支付场景。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 功能流程
|
|
|
|
|
|
### 步骤概览
|
|
|
|
|
|
直接支付页面采用**三步向导式**流程:
|
|
|
|
|
|
1. **步骤0:选择支付分类** - 通过思维导图选择支付分类
|
|
|
2. **步骤1:填写表单信息** - 填写金额和模板配置的字段
|
|
|
3. **步骤2:发起主流程** - 发起主审批流程(如果有配置)或确认提交
|
|
|
|
|
|
---
|
|
|
|
|
|
## 详细功能说明
|
|
|
|
|
|
### 步骤0:选择支付分类
|
|
|
|
|
|
#### 功能描述
|
|
|
- 使用 D3.js 渲染思维导图(树状图)展示支付分类层级结构
|
|
|
- 用户点击叶子节点选择支付分类
|
|
|
- 选择后自动进入下一步
|
|
|
|
|
|
#### 数据加载
|
|
|
- **API**: `GET /budget/payment-categories` (树形结构)
|
|
|
- **参数**: `payment_type=direct` (筛选直接支付分类)
|
|
|
|
|
|
#### 关键逻辑
|
|
|
```javascript
|
|
|
// 判断是否为直接支付
|
|
|
const isDirectPayment = computed(() => {
|
|
|
return route.path === '/payment/direct-payment' ||
|
|
|
paymentType.value === 'direct'
|
|
|
})
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
### 步骤1:填写表单信息
|
|
|
|
|
|
#### 1.1 支付金额
|
|
|
|
|
|
**功能特性**:
|
|
|
- 必填字段,支持小数点后2位
|
|
|
- 直接支付模式下显示**金额大写**(如:壹万贰仟叁佰元整)
|
|
|
- 支持金额限制条件验证(`amount_limit_conditions`)
|
|
|
- 直接支付模式下隐藏数字输入框的增减按钮
|
|
|
|
|
|
**金额限制条件**:
|
|
|
- 支持多种比较操作:`lt`(小于)、`lte`(小于等于)、`gt`(大于)、`gte`(大于等于)
|
|
|
- 可配置多个条件,所有条件需同时满足(AND逻辑)
|
|
|
- 实时验证并显示提示信息
|
|
|
|
|
|
**数据字段**:
|
|
|
```javascript
|
|
|
formData.amount // 支付金额(Number类型)
|
|
|
```
|
|
|
|
|
|
#### 1.2 合同关联(可选)
|
|
|
|
|
|
**触发条件**:
|
|
|
- 支付分类配置了 `need_contract: true`
|
|
|
- 仅直接支付模式显示
|
|
|
|
|
|
**功能特性**:
|
|
|
- 点击"选择合同"按钮打开合同选择器
|
|
|
- 显示已选择合同的详细信息:
|
|
|
- 合同名称
|
|
|
- 合同总额
|
|
|
- 已支付次数
|
|
|
- 已支付金额
|
|
|
- 剩余金额(闭口合同显示)
|
|
|
- 支持重新选择和清除
|
|
|
|
|
|
**合同验证**:
|
|
|
- **开口合同**:不允许用于直接支付,提示用户使用非直接支付
|
|
|
- **闭口合同**:验证本次支付金额不能超过合同剩余金额
|
|
|
|
|
|
**数据字段**:
|
|
|
```javascript
|
|
|
selectedContract.value // 选中的合同对象
|
|
|
contractRemainingAmount // 合同剩余金额(计算属性)
|
|
|
```
|
|
|
|
|
|
#### 1.3 动态模板字段
|
|
|
|
|
|
根据支付分类配置的模板元素动态渲染表单字段。
|
|
|
|
|
|
**支持的字段类型**:
|
|
|
|
|
|
1. **审批流程** (`approval_flow`)
|
|
|
- 非主审批流程:下拉选择OA模型
|
|
|
- 主审批流程:在步骤2中通过iframe处理
|
|
|
|
|
|
2. **会议纪要** (`meeting_minutes`)
|
|
|
- 使用专用组件 `MeetingMinutesField`
|
|
|
- 支持会议信息录入
|
|
|
|
|
|
3. **勾选清单** (`checklist`)
|
|
|
- 多选复选框
|
|
|
- 未勾选项需填写备注说明
|
|
|
- 支持自定义选项和备注验证
|
|
|
|
|
|
4. **明细表格** (`detail_table`)
|
|
|
- 动态添加/删除行
|
|
|
- 支持多种字段类型:
|
|
|
- 文本 (`text`)
|
|
|
- 数字 (`number`)
|
|
|
- 日期 (`date`)
|
|
|
- 多行文本 (`textarea`)
|
|
|
- 部门选择 (`department`)
|
|
|
- 用户选择 (`user`)
|
|
|
|
|
|
5. **表单元素** (`form_element`)
|
|
|
- 单行文本 (`single_line_text`)
|
|
|
- 多行文本 (`multi_line_text`)
|
|
|
- 附件上传 (`attachment`)
|
|
|
- 支持多文件上传(最多10个)
|
|
|
- 文件大小限制:10MB
|
|
|
- 支持格式:JPG/PNG/PDF/DOC/DOCX/XLS/XLSX
|
|
|
|
|
|
**字段显示条件**:
|
|
|
- 支持基于金额的显示条件(`display_conditions`)
|
|
|
- 可配置基于 `contract_total_amount`(合同总金额)或 `current_payment_amount`(本次支付金额)的条件
|
|
|
- 支持比较操作:`lt`、`lte`、`gt`、`gte`、`eq`
|
|
|
|
|
|
**数据字段**:
|
|
|
```javascript
|
|
|
formData.fields = {
|
|
|
[elementId]: value, // 字段值
|
|
|
[elementId]: [file1, file2], // 附件类型为数组
|
|
|
[elementId]: [{field1: value1, field2: value2}], // 明细表格为对象数组
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 1.4 文件上传
|
|
|
|
|
|
**上传配置**:
|
|
|
- **接口**: `POST /api/upload-file`
|
|
|
- **请求头**: `Authorization: Bearer {token}`
|
|
|
- **文件限制**:
|
|
|
- 大小:≤ 10MB
|
|
|
- 格式:JPG/PNG/PDF/DOC/DOCX/XLS/XLSX
|
|
|
|
|
|
**上传成功处理**:
|
|
|
```javascript
|
|
|
{
|
|
|
name: "文件名",
|
|
|
url: "文件URL",
|
|
|
uid: "唯一标识"
|
|
|
}
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
### 步骤2:发起主流程
|
|
|
|
|
|
#### 功能描述
|
|
|
- 所有支付类型(包括直接支付)都会进入此步骤
|
|
|
- 如果支付分类配置了主审批流程,显示OA流程创建iframe
|
|
|
- 如果未配置主审批流程,显示提示信息,用户可直接提交
|
|
|
|
|
|
#### 主审批流程处理
|
|
|
|
|
|
**情况1:配置了主审批流程**
|
|
|
- 显示主审批流程信息
|
|
|
- 加载OA流程创建iframe
|
|
|
- 用户需要在OA页面完成流程创建
|
|
|
- 流程创建成功后,通过postMessage返回flow_id
|
|
|
- 提交时会验证是否已创建流程
|
|
|
|
|
|
**情况2:未配置主审批流程**
|
|
|
- 显示提示:"当前分类未配置主审批流程"
|
|
|
- 用户可以直接点击"提交"按钮完成提交
|
|
|
- 提交时`oa_flow_id`为`null`
|
|
|
|
|
|
#### 数据字段
|
|
|
```javascript
|
|
|
mainApprovalFlow.value // 主审批流程配置对象
|
|
|
oaFlowId.value // OA流程ID(从postMessage接收)
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 数据提交流程
|
|
|
|
|
|
### 提交前验证
|
|
|
|
|
|
1. **表单验证**
|
|
|
- 必填字段检查
|
|
|
- 金额格式验证
|
|
|
- 明细表格行数据验证
|
|
|
- 勾选清单备注验证
|
|
|
|
|
|
2. **金额限制条件验证**
|
|
|
- 检查是否满足分类配置的金额限制条件
|
|
|
|
|
|
3. **合同验证**(如需要)
|
|
|
- 合同类型验证(开口合同不允许)
|
|
|
- 支付金额不能超过合同剩余金额
|
|
|
|
|
|
4. **主审批流程验证**
|
|
|
- 如果配置了主审批流程,检查是否已创建OA流程
|
|
|
- 如果未配置主审批流程,允许直接提交
|
|
|
|
|
|
### 提交数据构建
|
|
|
|
|
|
#### 直接支付数据结构
|
|
|
|
|
|
```javascript
|
|
|
{
|
|
|
payment_category_id: Number, // 支付分类ID
|
|
|
amount: Number, // 支付金额
|
|
|
fields: Object, // 模板字段数据
|
|
|
oa_flow_id: Number | null, // OA流程ID(直接支付通常为null)
|
|
|
// Step2:后端已切换 1 Payment = 1 明细,直接写 Payment 级字段(不再传 details)
|
|
|
contract_id: Number | null, // 关联合同ID(need_contract=true时必填)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 完整提交示例
|
|
|
|
|
|
```javascript
|
|
|
// 直接支付 + 关联合同
|
|
|
{
|
|
|
payment_category_id: 123,
|
|
|
amount: 50000.00,
|
|
|
fields: {
|
|
|
456: "备注信息",
|
|
|
789: [
|
|
|
{name: "文件1.pdf", url: "/uploads/xxx.pdf", uid: "xxx"}
|
|
|
],
|
|
|
101: [
|
|
|
{field1: "值1", field2: "值2"}
|
|
|
]
|
|
|
},
|
|
|
oa_flow_id: null,
|
|
|
contract_id: 999
|
|
|
}
|
|
|
|
|
|
// 直接支付 + 未关联合同
|
|
|
{
|
|
|
payment_category_id: 123,
|
|
|
amount: 50000.00,
|
|
|
fields: {
|
|
|
456: "备注信息"
|
|
|
},
|
|
|
oa_flow_id: null,
|
|
|
contract_id: null
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### API调用
|
|
|
|
|
|
**接口**: `POST /budget/payments`
|
|
|
**API方法**: `paymentAPI.create(paymentData)`
|
|
|
|
|
|
### 提交后处理
|
|
|
|
|
|
1. **成功响应**
|
|
|
- 显示成功提示:"申请付款提交成功"
|
|
|
- 跳转到支付查询页面:`/payment/payment-query`
|
|
|
|
|
|
2. **失败处理**
|
|
|
- 显示错误提示
|
|
|
- 保持当前页面,允许用户修改后重新提交
|
|
|
|
|
|
---
|
|
|
|
|
|
## 关键计算属性和方法
|
|
|
|
|
|
### 金额大写转换
|
|
|
```javascript
|
|
|
const amountUppercase = computed(() => {
|
|
|
if (!isDirectPayment.value) return ''
|
|
|
const n = Number(formData.amount)
|
|
|
if (!Number.isFinite(n) || n <= 0) return ''
|
|
|
return toChineseMoneyUppercase(n) // 转换为中文大写
|
|
|
})
|
|
|
```
|
|
|
|
|
|
### 合同剩余金额
|
|
|
```javascript
|
|
|
const contractRemainingAmount = computed(() => {
|
|
|
if (!selectedContract.value || selectedContract.value.amount_type !== 'fixed') {
|
|
|
return 0
|
|
|
}
|
|
|
const total = Number(selectedContract.value.amount_total) || 0
|
|
|
const paid = Number(selectedContract.value.payment_stats?.paid_amount) || 0
|
|
|
return total - paid
|
|
|
})
|
|
|
```
|
|
|
|
|
|
### 金额限制条件验证
|
|
|
```javascript
|
|
|
const amountLimitValidation = computed(() => {
|
|
|
// 验证逻辑
|
|
|
// 返回 { valid: boolean, message: string }
|
|
|
})
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 路由参数
|
|
|
|
|
|
### 支持的查询参数
|
|
|
|
|
|
- `payment_type=direct` - 支付类型(必填,用于区分直接/非直接支付)
|
|
|
- `category_id` - 预选分类ID(可选,直接进入指定分类)
|
|
|
- `step` - 步骤编号(可选,直接进入指定步骤)
|
|
|
|
|
|
### 路由监听
|
|
|
|
|
|
页面会监听路由参数变化,自动:
|
|
|
- 确保 `payment_type=direct` 参数存在
|
|
|
- 根据 `category_id` 预选分类
|
|
|
- 根据 `step` 跳转到指定步骤
|
|
|
|
|
|
---
|
|
|
|
|
|
## 数据流图
|
|
|
|
|
|
```
|
|
|
用户访问页面
|
|
|
↓
|
|
|
加载支付分类树(payment_type=direct)
|
|
|
↓
|
|
|
步骤0:选择支付分类
|
|
|
↓
|
|
|
加载分类详情和模板元素
|
|
|
↓
|
|
|
步骤1:填写表单信息
|
|
|
├─ 填写支付金额
|
|
|
├─ 选择合同(如需要)
|
|
|
└─ 填写模板字段
|
|
|
↓
|
|
|
验证表单数据
|
|
|
↓
|
|
|
步骤2:发起主流程
|
|
|
├─ 如果配置了主审批流程
|
|
|
│ ├─ 显示OA流程创建iframe
|
|
|
│ └─ 等待用户创建流程
|
|
|
└─ 如果未配置主审批流程
|
|
|
└─ 显示提示信息
|
|
|
↓
|
|
|
验证主审批流程(如需要)
|
|
|
↓
|
|
|
构建提交数据
|
|
|
↓
|
|
|
调用 API: POST /budget/payments
|
|
|
↓
|
|
|
提交成功 → 跳转到支付查询页面
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 注意事项
|
|
|
|
|
|
1. **直接支付 vs 非直接支付**
|
|
|
- 直接支付和非直接支付都支持主审批流程
|
|
|
- 如果分类配置了主审批流程,两种类型都需要在步骤2中创建OA流程
|
|
|
- 如果分类未配置主审批流程,`oa_flow_id` 为 `null`,可直接提交
|
|
|
|
|
|
2. **合同关联**
|
|
|
- 只有分类配置了 `need_contract: true` 才显示合同选择
|
|
|
- 开口合同不能用于直接支付
|
|
|
- 闭口合同的支付金额不能超过剩余金额
|
|
|
|
|
|
3. **字段显示条件**
|
|
|
- 字段的显示/隐藏基于金额条件动态控制
|
|
|
- 条件支持合同总金额和本次支付金额两种比较
|
|
|
|
|
|
4. **文件上传**
|
|
|
- 文件上传是异步的,上传成功后才会保存到 `formData.fields`
|
|
|
- 支持多文件上传,但单个文件大小不能超过10MB
|
|
|
|
|
|
5. **明细表格**
|
|
|
- 支持动态添加/删除行
|
|
|
- 每行的字段类型可以不同
|
|
|
- 支持部门、用户等关联字段
|
|
|
|
|
|
---
|
|
|
|
|
|
## 相关API接口
|
|
|
|
|
|
| 接口 | 方法 | 说明 |
|
|
|
|------|------|------|
|
|
|
| `/budget/payment-categories` | GET | 获取支付分类树 |
|
|
|
| `/budget/payment-categories/{id}` | GET | 获取分类详情 |
|
|
|
| `/budget/payment-template-elements` | GET | 获取模板元素列表 |
|
|
|
| `/budget/payment-template-elements/oa-models` | GET | 获取OA模型列表 |
|
|
|
| `/api/upload-file` | POST | 文件上传 |
|
|
|
| `/budget/payments` | POST | 创建支付流程 |
|
|
|
| `/budget/contracts` | GET | 获取合同列表(合同选择器) |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 相关文件
|
|
|
|
|
|
- **组件文件**: `src/views/payment/CreatePayment.vue`
|
|
|
- **包装组件**: `src/views/payment/DirectPayment.vue`
|
|
|
- **API定义**: `src/utils/api.js`
|
|
|
- **路由配置**: `src/router/index.js`
|
|
|
|
|
|
---
|
|
|
|
|
|
## 更新日志
|
|
|
|
|
|
- 支持直接支付模式
|
|
|
- 支持合同关联
|
|
|
- 支持金额限制条件
|
|
|
- 支持字段显示条件
|
|
|
- 支持多种模板字段类型
|
|
|
- 支持文件上传
|
|
|
- 支持明细表格
|
|
|
- 支持勾选清单
|
|
|
|