转运任务支付功能设计方案(最终版)
本方案针对转运任务的"总额一次性支付"场景:总额=成交价+附加费用汇总,支持现金、挂帐、微信、支付宝四种方式。微信/支付宝由"独立支付模块"生成二维码与回调,我方系统仅对接该支付模块。
一、最终确认点
- 结算金额必须与总金额一致(总金额=成交价+附加费用汇总)。
- 挂帐支付仅记录备注即可。
- 附加费用类型由后台字典维护(字典类型:task_additional_fee_type)。
- 微信、支付宝由独立支付模块生成支付二维码与查询结果,不直接集成商户号逻辑。
- 结算入口在 APP 的任务详情页和任务列表卡片上都要有。
- 后台 ruoyi-ui 只展示支付信息与附加费用明细,不允许修改。
- 只展示"有效支付"(最近一条已支付成功的记录)。
- 交易单号 outTradeNo 格式:{taskCode}-{timestampMillis},timestamp 使用毫秒级时间戳。
- 回调路径 callbackUrl 在创建二维码时由我方传入,必须为绝对地址(含域名与路径)。
- 金额校验:我方发起支付前强校验 settlementAmount==totalAmount;支付模块也进行金额二次校验。
二、总体流程
- APP 在任务列表与任务详情增加"结算"入口,跳转结算页。
- 结算页拉取成交价与附加费用列表,允许新增/删除附加费用,实时计算总金额。
- 选择支付方式并发起支付:
- 现金、挂帐:后端直接标记已支付。
- 微信、支付宝:后端调用"支付模块创建二维码",返回 codeUrl 与过期时间给前端展示;前端轮询我方"支付状态接口"。
- 支付成功后,APP 自动提示并展示"支付成功"状态;禁用后续修改。
- ruoyi-ui 在任务明细页只读展示支付信息与附加费用明细。
三、数据模型
支付与附加费独立建表,避免污染任务主表:
sys_task_additional_fee(附加费用明细)
- 字段:id, task_id, fee_type(字典), fee_name, unit_amount, quantity, total_amount, remark, created_by, created_time
sys_task_payment(任务支付记录)
- 字段:id, task_id, total_amount, settlement_amount(必须==total_amount), payment_method("CASH""ON_ACCOUNT""WECHAT""ALIPAY"), pay_status("UNPAID""PENDING""PAID""FAILED""REFUNDED"), pay_time, out_trade_no, trade_no, code_url, qr_expire_time, provider("WECHAT""ALIPAY"), payment_ref_id(支付模块返回唯一标识), callback_url, remark, created_by, created_time, update_time
成交价来源
- SysTaskEmergency.transferPrice
- 总金额=transferPrice + sum(sys_task_additional_fee.total_amount)
有效支付
- 同一任务展示最近一条 pay_status="PAID"的记录;若不存在则显示"未支付"
四、字典与配置
字典类型:task_additional_fee_type
- 1:等待费
- 2:担架
- 3:居家ICU
- 4:医疗设备
配置项
- payment.module.url:支付模块服务地址(默认:http://localhost:8081/pay)
- payment.callback.base-url:回调基础URL(默认:http://localhost:8080)
五、与支付模块的对接契约
创建二维码(支付模块)
- 接口:POST /pay/qrcode/create
- 入参:outTradeNo, amount, provider("WECHAT""ALIPAY"), subject, attach(如 taskId/taskCode), callbackUrl(绝对地址)
- 出参:paymentRefId, codeUrl, expireTime
查询支付状态(支付模块)
- 接口:GET /pay/status?paymentRefId=xxx 或 GET /pay/status?outTradeNo=xxx
- 出参:status("PENDING""PAID""FAILED""CLOSED"), tradeNo, payTime
回调(支付模块 → 我方)
- 接口:POST {callbackUrl}
- 体内字段:outTradeNo, tradeNo, amount, status=PAID, sign 等;我方验签后更新为 PAID
订单号规范
- outTradeNo:TASK-{taskCode}-{timestampMillis}
- subject:"转运任务结算({taskCode})"
六、我方后端接口(APP 用)
GET /task/payment/info
- 入参:taskId
- 出参:transferPrice, additionalFees[], additionalAmount, totalAmount, latestPayment(如有), paymentMethods["CASH""ON_ACCOUNT""WECHAT""ALIPAY"]
POST /task/additional-fee/add
- 入参:taskId, feeType, feeName, unitAmount, quantity, remark
- 出参:additionalAmount, totalAmount
POST /task/additional-fee/remove
- 入参:taskId, feeId
- 出参:additionalAmount, totalAmount
POST /task/payment/create
- 入参:taskId, paymentMethod, settlementAmount(必须==totalAmount), remark
- 行为:
- CASH/ON_ACCOUNT:直接创建支付记录并置为 PAID
- WECHAT/ALIPAY:生成 outTradeNo(taskCode-毫秒时间戳)、计算 amount、准备 subject/attach/callbackUrl;调用支付模块创建二维码;保存 paymentRefId、codeUrl、expireTime,置为 PENDING 返回
- 出参:paymentId, payStatus, codeUrl(仅微信/支付宝), qrExpireTime
GET /task/payment/status
- 入参:taskId 或 paymentId
- 行为:根据 paymentRefId 或 outTradeNo 调用支付模块查询;若返回 PAID,我方更新 sys_task_payment 为 PAID 并返回最新状态
- 出参:payStatus, tradeNo, payTime
POST /payment/callback/{provider}
七、APP 前端改造
入口
- 任务列表卡片与任务详情页均增加"结算"按钮(详情页遵循既有按钮显示规则:仅完成/取消状态隐藏)
结算页(settlement.vue)
- 初始化:调用 /task/payment/info 拉取成交价、附加费列表与汇总
- 附加费用:新增/删除使用对应接口,费用类型来自字典;刷新汇总
- 支付:
- 现金/挂帐:调用 /task/payment/create,成功后提示"支付成功"
- 微信/支付宝:调用 /task/payment/create 获取 codeUrl 与 qrExpireTime;展示二维码并每 2~3 秒轮询 /task/payment/status,直到 PAID 或超时
- 校验:settlementAmount 必须等于 totalAmount;二维码过期提示重新生成
- 成功后:禁用附加费用与支付操作;可返回任务详情
八、ruoyi-ui 后台展示(只读)
任务明细页新增"支付信息"区块
- 展示:支付方式、结算金额、总金额、支付状态、交易号、支付时间
- 附加费用明细列表与汇总
- 若有历史支付记录,仅展示最近一次 PAID;不提供编辑或重试入口
九、权限与安全
- APP 鉴权:JWT;仅任务归属成员(创建人、执行人、调度角色)可结算
- 数据权限:延续现有部门/分公司隔离规则
- 回调安全:callbackUrl 验签(签名算法由支付模块确定),可加源 IP 白名单
- 金额一致性:前后端双重校验;二维码创建后金额锁定,变更附加费需重新发起支付
十、边界处理
- 二维码过期:提示并允许重新创建;旧支付记录置为 FAILED/CLOSED
- 轮询与回调竞态:以我方后端支付状态为准(回调或查询更新)
- 退款/撤销:本期不实现;如后续需要,增加 REFUNDED 状态与退款接口
十一、验收标准
- APP:附加费用维护与总额计算正确;四种支付流程通畅;扫码支付成功后自动提示与禁用修改
- 后台:准确展示支付信息与附加费用明细;只显示有效支付
- 后端:支付与附加费落库正确;回调与轮询均能准确更新支付状态;金额校验严格生效
十二、实现文件清单
数据库
- sql/task_payment_tables.sql
实体类
- SysTaskAdditionalFee.java
- SysTaskPayment.java
- TaskPaymentInfoVO.java
- TaskPaymentCreateVO.java
- TaskPaymentResultVO.java
Mapper
- SysTaskAdditionalFeeMapper.java / SysTaskAdditionalFeeMapper.xml
- SysTaskPaymentMapper.java / SysTaskPaymentMapper.xml
Service
- ISysTaskPaymentService.java / SysTaskPaymentServiceImpl.java
- IPaymentModuleService.java / PaymentModuleServiceImpl.java
Controller
- SysTaskPaymentController.java
- PaymentCallbackController.java
前端(待实现)
- app/pages/task/settlement.vue(改造)
- app/api/payment.js(新增)
- ruoyi-ui/src/views/task/detail.vue(增加支付信息展示)