You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11 KiB
11 KiB
直接支付页面功能说明
页面概述
页面路径: /payment/direct-payment?payment_type=direct
组件文件: src/views/payment/DirectPayment.vue (包装组件)
实际组件: src/views/payment/CreatePayment.vue (核心组件)
直接支付页面用于创建无需审批流程的支付申请,适用于水电费、工会经费、人员工资等常规支付场景。
功能流程
步骤概览
直接支付页面采用三步向导式流程:
- 步骤0:选择支付分类 - 通过思维导图选择支付分类
- 步骤1:填写表单信息 - 填写金额和模板配置的字段
- 步骤2:发起主流程 - 发起主审批流程(如果有配置)或确认提交
详细功能说明
步骤0:选择支付分类
功能描述
- 使用 D3.js 渲染思维导图(树状图)展示支付分类层级结构
- 用户点击叶子节点选择支付分类
- 选择后自动进入下一步
数据加载
- API:
GET /budget/payment-categories(树形结构) - 参数:
payment_type=direct(筛选直接支付分类)
关键逻辑
// 判断是否为直接支付
const isDirectPayment = computed(() => {
return route.path === '/payment/direct-payment' ||
paymentType.value === 'direct'
})
步骤1:填写表单信息
1.1 支付金额
功能特性:
- 必填字段,支持小数点后2位
- 直接支付模式下显示金额大写(如:壹万贰仟叁佰元整)
- 支持金额限制条件验证(
amount_limit_conditions) - 直接支付模式下隐藏数字输入框的增减按钮
金额限制条件:
- 支持多种比较操作:
lt(小于)、lte(小于等于)、gt(大于)、gte(大于等于) - 可配置多个条件,所有条件需同时满足(AND逻辑)
- 实时验证并显示提示信息
数据字段:
formData.amount // 支付金额(Number类型)
1.2 合同关联(可选)
触发条件:
- 支付分类配置了
need_contract: true - 仅直接支付模式显示
功能特性:
- 点击"选择合同"按钮打开合同选择器
- 显示已选择合同的详细信息:
- 合同名称
- 合同总额
- 已支付次数
- 已支付金额
- 剩余金额(闭口合同显示)
- 支持重新选择和清除
合同验证:
- 开口合同:不允许用于直接支付,提示用户使用非直接支付
- 闭口合同:验证本次支付金额不能超过合同剩余金额
数据字段:
selectedContract.value // 选中的合同对象
contractRemainingAmount // 合同剩余金额(计算属性)
1.3 动态模板字段
根据支付分类配置的模板元素动态渲染表单字段。
支持的字段类型:
-
审批流程 (
approval_flow)- 非主审批流程:下拉选择OA模型
- 主审批流程:在步骤2中通过iframe处理
-
会议纪要 (
meeting_minutes)- 使用专用组件
MeetingMinutesField - 支持会议信息录入
- 使用专用组件
-
勾选清单 (
checklist)- 多选复选框
- 未勾选项需填写备注说明
- 支持自定义选项和备注验证
-
明细表格 (
detail_table)- 动态添加/删除行
- 支持多种字段类型:
- 文本 (
text) - 数字 (
number) - 日期 (
date) - 多行文本 (
textarea) - 部门选择 (
department) - 用户选择 (
user)
- 文本 (
-
表单元素 (
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
数据字段:
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
上传成功处理:
{
name: "文件名",
url: "文件URL",
uid: "唯一标识"
}
步骤2:发起主流程
功能描述
- 所有支付类型(包括直接支付)都会进入此步骤
- 如果支付分类配置了主审批流程,显示OA流程创建iframe
- 如果未配置主审批流程,显示提示信息,用户可直接提交
主审批流程处理
情况1:配置了主审批流程
- 显示主审批流程信息
- 加载OA流程创建iframe
- 用户需要在OA页面完成流程创建
- 流程创建成功后,通过postMessage返回flow_id
- 提交时会验证是否已创建流程
情况2:未配置主审批流程
- 显示提示:"当前分类未配置主审批流程"
- 用户可以直接点击"提交"按钮完成提交
- 提交时
oa_flow_id为null
数据字段
mainApprovalFlow.value // 主审批流程配置对象
oaFlowId.value // OA流程ID(从postMessage接收)
数据提交流程
提交前验证
-
表单验证
- 必填字段检查
- 金额格式验证
- 明细表格行数据验证
- 勾选清单备注验证
-
金额限制条件验证
- 检查是否满足分类配置的金额限制条件
-
合同验证(如需要)
- 合同类型验证(开口合同不允许)
- 支付金额不能超过合同剩余金额
-
主审批流程验证
- 如果配置了主审批流程,检查是否已创建OA流程
- 如果未配置主审批流程,允许直接提交
提交数据构建
直接支付数据结构
{
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时必填)
}
完整提交示例
// 直接支付 + 关联合同
{
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)
提交后处理
-
成功响应
- 显示成功提示:"申请付款提交成功"
- 跳转到支付查询页面:
/payment/payment-query
-
失败处理
- 显示错误提示
- 保持当前页面,允许用户修改后重新提交
关键计算属性和方法
金额大写转换
const amountUppercase = computed(() => {
if (!isDirectPayment.value) return ''
const n = Number(formData.amount)
if (!Number.isFinite(n) || n <= 0) return ''
return toChineseMoneyUppercase(n) // 转换为中文大写
})
合同剩余金额
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
})
金额限制条件验证
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
↓
提交成功 → 跳转到支付查询页面
注意事项
-
直接支付 vs 非直接支付
- 直接支付和非直接支付都支持主审批流程
- 如果分类配置了主审批流程,两种类型都需要在步骤2中创建OA流程
- 如果分类未配置主审批流程,
oa_flow_id为null,可直接提交
-
合同关联
- 只有分类配置了
need_contract: true才显示合同选择 - 开口合同不能用于直接支付
- 闭口合同的支付金额不能超过剩余金额
- 只有分类配置了
-
字段显示条件
- 字段的显示/隐藏基于金额条件动态控制
- 条件支持合同总金额和本次支付金额两种比较
-
文件上传
- 文件上传是异步的,上传成功后才会保存到
formData.fields - 支持多文件上传,但单个文件大小不能超过10MB
- 文件上传是异步的,上传成功后才会保存到
-
明细表格
- 支持动态添加/删除行
- 每行的字段类型可以不同
- 支持部门、用户等关联字段
相关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
更新日志
- 支持直接支付模式
- 支持合同关联
- 支持金额限制条件
- 支持字段显示条件
- 支持多种模板字段类型
- 支持文件上传
- 支持明细表格
- 支持勾选清单