编辑 | blame | 历史 | 原始文档

转运任务支付功能设计方案(最终版)

本方案针对转运任务的"总额一次性支付"场景:总额=成交价+附加费用汇总,支持现金、挂帐、微信、支付宝四种方式。微信/支付宝由"独立支付模块"生成二维码与回调,我方系统仅对接该支付模块。

一、最终确认点

  • 结算金额必须与总金额一致(总金额=成交价+附加费用汇总)。
  • 挂帐支付仅记录备注即可。
  • 附加费用类型由后台字典维护(字典类型:task_additional_fee_type)。
  • 微信、支付宝由独立支付模块生成支付二维码与查询结果,不直接集成商户号逻辑。
  • 结算入口在 APP 的任务详情页和任务列表卡片上都要有。
  • 后台 ruoyi-ui 只展示支付信息与附加费用明细,不允许修改。
  • 只展示"有效支付"(最近一条已支付成功的记录)。
  • 交易单号 outTradeNo 格式:{taskCode}-{timestampMillis},timestamp 使用毫秒级时间戳。
  • 回调路径 callbackUrl 在创建二维码时由我方传入,必须为绝对地址(含域名与路径)。
  • 金额校验:我方发起支付前强校验 settlementAmount==totalAmount;支付模块也进行金额二次校验。

二、总体流程

  1. APP 在任务列表与任务详情增加"结算"入口,跳转结算页。
  2. 结算页拉取成交价与附加费用列表,允许新增/删除附加费用,实时计算总金额。
  3. 选择支付方式并发起支付:
  • 现金、挂帐:后端直接标记已支付。
  • 微信、支付宝:后端调用"支付模块创建二维码",返回 codeUrl 与过期时间给前端展示;前端轮询我方"支付状态接口"。
  1. 支付成功后,APP 自动提示并展示"支付成功"状态;禁用后续修改。
  2. 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}

  • 支付模块回调接口,验签后更新支付状态为 PAID

七、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(增加支付信息展示)