支付模块说明
本文档描述
src/modules/pay与收银台、UTS 插件的实际行为,便于团队内分享或复制到博客/文档站。路径均以本仓库为准。
文档路径:docs/payment-module.md
目录
- 1. 概述
- 2. 能力矩阵
- 3. 架构与目录
- 4. 核心流程
- 5.
usePayment与页面职责 - 6. 收银台页面
cashier/index.vue - 7. 业务错误码与表现层处理
- 8. 支付渠道
payChannel与 APP 策略解析 - 9. 原生插件与鸿蒙
- 10. 扩展与维护
- 11. 常见问题
- 12. 相关文件索引
1. 概述
本模块采用策略模式:PaymentManager 单例按运行端注册 IPayStrategy,统一入口 pay();与 uni.requestPayment 相关的逻辑集中在 NativePayStrategy 子类中;APP 端还存在拉起小程序、支付宝深链(连连)、**企业网银(仅拉配置)**等非单一 requestPayment 路径。
设计要点:
- 业务接口失败时由 HTTP 层统一 Toast,同时将
errorCode透传到PaymentResult,供收银台等页面做跳转/刷新。 - 支持开发者彩蛋中的假支付(不拉真实 submit-pay、不调 SDK 的独立线路)。
- 订单维度支持单笔与合并支付(
orderNoList: string[])。
2. 能力矩阵
| 运行端 | 微信支付 | 支付宝支付 | 企业网银 | 说明 |
|---|---|---|---|---|
微信小程序 (MP-WEIXIN) | ✅ uni.requestPayment(payInfo) | - | ✅ 仅拉 submit-pay 配置,页面展示复制链接 | 策略在 PaymentManager.initStrategies 中注册 |
APP (APP-PLUS / APP-HARMONY) | ✅ 拉起微信小程序支付 | ✅ 默认拉起支付宝小程序;payChannel === LL_PAY 时走 HTTPS payUrl → alipays:// 深链 | ✅ 同左 | 微信固定 AppWxMiniProgramPay;支付宝按渠道在 AppAliMiniProgramPay 与 AppAlipayScanPay 间切换 |
支付宝小程序 (MP-ALIPAY) | - | ⚠️ | ⚠️ | getAppType() 会返回 ALI_MINI,但当前 initStrategies 未注册对应策略;若需支持需在 PaymentManager 中补充并引入 NativePayStrategy 实现 |
| H5 | 🚫 | 🚫 | 🚫 | getAppType() 返回 null,不初始化策略 |
说明: native-pay.ts 中仍保留 AppWxNativePay / AppAlipayNativePay(uni.requestPayment + payUrl)等类,但当前 PaymentManager 未注册,APP 实际走的是小程序拉起与连连深链方案。
3. 架构与目录
3.1 文件结构
src/modules/pay/
├── index.ts # PaymentManager 单例、懒初始化、策略注册、resolvePayStrategy
├── types.ts # PayPlatform / PayPlatformEnum / PAY_CHANNEL / 错误码常量 / PaymentParams / PaymentResult
├── pay-strategy.ts # PayStrategy 基类:getPaymentConfig、wrapUniPayment、假支付、handleError
└── strategies/
├── native-pay.ts # NativePayStrategy;WxMiniProgramPay;(另有未注册的 APP 原生支付类)
├── app-mini-program-pay.ts # AppWxMiniProgramPay、AppAliMiniProgramPay(拉起小程序)
├── app-alipay-scan-pay.ts # AppAlipayScanPay(连连 payUrl + alipays 深链)
└── enterprise-bank-pay.ts # EnterpriseBankPayStrategy(不调 SDK)
src/hooks/usePayment.ts # 页面侧:loading、pay、checkIsPayable、availablePlatforms
src/pages-sub/pages/order/cashier/index.vue # 收银台 UI、轮询、企业网银、路由与来源处理
src/uni_modules/app-miniprogram-launcher/ # UTS:APP 端拉起微信/支付宝小程序
src/uni_modules/harmony-native-kit/ # UTS:鸿蒙 openOuterUrl(外链 / scheme)
3.2 继承与分工(简化)
IPayStrategy
└── PayStrategy(抽象:buildPaymentConfigRequest、getPaymentConfig、假支付、wrapUniPayment)
├── NativePayStrategy(模板:getConfig → buildUniPaymentOptions → requestPayment)
│ └── WxMiniProgramPay
├── AppWxMiniProgramPay / AppAliMiniProgramPay(launchMiniProgram)
├── AppAlipayScanPay(openAlipaySchemeUrl)
└── EnterpriseBankPayStrategy(仅返回 paymentConfig)
3.3 分层调用
页面(收银台 / 订单列表…)
→ usePayment.pay / checkIsPayable
→ paymentManager.pay / isPayable
→ 具体 IPayStrategy
→ API:submit-pay、is-payable、query payment result 等
4. 核心流程
4.1 原生小程序支付(微信)
WxMiniProgramPay.pay():
- 若开启假支付 →
fakeSubmitPayment,直接成功。 - 否则
submitPayRequest,取model.payInfo,组装uni.requestPayment(provider: 'wxpay',timeStamp/nonceStr/package/signType/paySign)。
4.2 APP 微信支付
AppWxMiniProgramPay:submit-pay 得到 payUrl 作为小程序 path,调用 launchMiniProgram({ type: 'wechat', userName, appId, path, miniProgramType })。成功时返回 { success: true, errorCode: 'APP_LAUNCH_SUCCESS', paymentConfig },由收银台在 onShow 后轮询支付结果。
iOS APP-PLUS: 使用项目内 launch-miniprogram(plus.share);Android / 鸿蒙: 使用 app-miniprogram-launcher UTS 插件。
4.3 APP 支付宝支付
- 通联等渠道(非连连):
AppAliMiniProgramPay,将payUrl编码进支付宝小程序path(含thirdPartSchema回跳等),launchMiniProgram({ type: 'alipay', alipayAppId, path })。成功码同为APP_LAUNCH_SUCCESS,收银台同样可轮询。 - 连连
LL_PAY:AppAlipayScanPay,将payUrl(须为http(s))拼为alipays://platformapi/startapp?saId=10000007&qrcode=+ URL,再调起支付宝客户端。- APP-PLUS:
plus.runtime.openURL(错误码-3视为未安装支付宝)。 - APP-HARMONY:
openOuterUrl(schemeUrl)(harmony-native-kit)。
- APP-PLUS:
4.4 企业网银
EnterpriseBankPayStrategy 只请求 submit-pay,返回 { success: true, errorCode: 'ENTERPRISE_BANK_SUCCESS', paymentConfig }。收银台根据 expireTime 计算倒计时,展示 payUrl 供用户复制到 PC 浏览器;到期可再次 handlePayment 刷新配置。
4.5 假支付
PayStrategy.runFakePaymentIfEnabled:读取开发者选项 fakePayment,走 fakeSubmitPayment,不调用真实 submit-pay 的完整调款链路(与真实支付配置拉取分离)。
5. usePayment 与页面职责
文件: src/hooks/usePayment.ts
5.1 usePayment(options?)
| 项 | 说明 |
|---|---|
options.onSuccess / onError / onFinally | 支付结束回调;pay() 内根据 result.success 分发 |
返回 loading | pay() 执行期间为 true |
返回 availablePlatforms | paymentManager.getAvailablePlatforms(),与当前包编译平台有关 |
返回 isPlatformAvailable(platform) | 是否已注册该 PayPlatform |
返回 pay(params) | 转调 paymentManager.pay |
返回 checkIsPayable(params) | 见下 |
5.2 checkIsPayable(跳转收银台前)
参数类型 CheckIsPayableParams(与历史文档差异:使用 orderNoList,不是单个 orderNo):
| 字段 | 说明 |
|---|---|
orderNoList | 订单号数组(必填) |
amount | 金额(必填) |
closeCurrentPage | 默认 false;确认订单页建议 true,用 redirectTo 进收银台 |
source | 来源标识,会带到收银台 URL:order-list / order-detail / confirm-order 等 |
platform | 可选;传入则收银台默认勾选对应支付方式 |
onOrderStatusChanged | 当 errorCode 属于「订单状态变更」类时,延迟约 1.5s 回调(用于刷新列表/详情) |
onNeedRedirect | 当 errorCode 属于「需跳转订单列表」类时,延迟约 1.5s 回调 |
逻辑: 调用 paymentManager.isPayable({ orderNoList })(即 getIsPayable 接口)。succeed === true 则拼接
/pages-sub/pages/order/cashier/index?orderNoList=...&amount=...&source=...&platform=... 并 navigateTo / redirectTo。
5.3 pay(params) 的 PaymentParams
(定义见 types.ts)
platform: PayPlatform('wxpay' | 'alipay' | 'enterprise-bank')orderNoList: string[]amount?: numberpayChannel?: PayChannel | string(收银台从getBuyerCashier的payChannel传入,供 APP 解析支付宝策略)
6. 收银台页面 cashier/index.vue
6.1 路由参数
| 参数 | 说明 |
|---|---|
orderNoList | 逗号分隔;页面内 split(',') 得到数组(合并支付为多笔) |
amount | 应付总额 |
source | 来源;影响返回与成功后的导航 |
platform | 可选;可为后端支付方式编码 100/110/120 或 PayPlatform 枚举值,解析后仅展示该支付方式 |
6.2 支付方式列表
- 优先使用
getBuyerCashier返回的payMethodList,映射PayMethodMap(100→微信,110→支付宝,120→企业网银)。 - 微信小程序端仅展示微信 + 企业网银(即使后端返回支付宝也会过滤掉)。
- APP / 鸿蒙:后端列表为空时回退为
availablePlatforms(微信、支付宝、企业网银由PaymentManager注册决定)。
6.3 确认支付 handlePayment
清除轮询定时器后调用 pay({ platform, orderNoList, amount, payChannel: cashierInfo?.payChannel })。
6.4 成功回调分支(onSuccess)
| 情况 | 行为 |
|---|---|
errorCode 为 APP_LAUNCH_SUCCESS | 写入 paymentConfig,shouldPollOnShow = true,用户从支付宝/微信返回后在 onShow 里每 2 秒轮询,最多 30 秒;成功则 payResultSuccessRedirect |
errorCode 为 ENTERPRISE_BANK_SUCCESS | 写入 paymentConfig 并计算 expireDurationMs,展示复制地址 UI,不展示底部确认支付按钮 |
| 其他成功 | navigateToPayResult({ status: 'success' }) |
轮询使用 getPaymentResultSafe,payStatus:130 成功、140 失败、170 关闭等(见页面内常量)。
6.5 失败回调(onError)
- 有
errorCode:调用handlePayErrorRedirect,将REDIRECT_TO_ORDER_LIST_CODES与ORDER_STATUS_CHANGED_CODES合并判断,命中则约 3s 后跳转订单列表。 - 无
errorCode:视为用户取消或网络等 →navigateToPayResult({ status: 'error' })。 - 微信小程序 +
source === 'app-share'+ 用户取消(USER_CANCEL):wx.exitMiniProgram()回到 APP。
6.6 其他交互
- 导航栏返回:
source === 'app-share'时同样exitMiniProgram。 - 微信场景值 1036: App 打开小程序收银台等场景;页面会执行
handleAppLaunchWechatCashier(改标题、默认选微信等,与产品配置联动)。
7. 业务错误码与表现层处理
定义位置:src/modules/pay/types.ts。
7.1 ORDER_STATUS_CHANGED_CODES(订单状态变更 → 宜刷新)
含例如:BU-APP-013、BU-APP-021、BU-APP-022(具体以源码为准)。
- 在
checkIsPayable中:触发onOrderStatusChanged(延迟 ~1.5s)。 - 在 收银台
handlePayErrorRedirect中:与下列组合判断,延迟 ~3s 跳转订单列表。
7.2 REDIRECT_TO_ORDER_LIST_CODES(宜回列表)
含例如:BU-APP-016、BU-APP-027、BU-APP-018、BU-APP-019、BU-APP-020、BU-APP-028、BU-APP-029 等(不包含上一节的变更码,但收银台会把两类合并用于跳转)。
- 在
checkIsPayable中:触发onNeedRedirect(延迟 ~1.5s)。
7.3 用户取消
PaymentErrorCodes.USER_CANCEL:wrapUniPayment 在 errMsg 含 cancel 时写入,便于小程序 app-share 场景关闭小程序。
8. 支付渠道 payChannel 与 APP 策略解析
types.ts 中 PAY_CHANNEL:
ALLINPAY:通联收银宝ALLIN_PAY_YST:通联云商通LL_PAY:连连支付
PaymentManager.resolvePayStrategy(APP):
- 微信: 始终
AppWxMiniProgramPay。 - 支付宝:
params.payChannel === PAY_CHANNEL.LL_PAY→AppAlipayScanPay;否则 →AppAliMiniProgramPay。
小程序跳转的 userName / appId / miniProgramType / 支付宝 pagePath 等由 app-mini-launch-config(支付模块侧配置)按 payChannel 区分,此处不展开。
9. 原生插件与鸿蒙
9.1 app-miniprogram-launcher
- 作用: 在 Android / iOS / HarmonyOS 上统一调用
launchMiniProgram(options)打开微信或支付宝小程序。 - Harmony: 支持微信;不支持支付宝小程序(插件 README 明确说明)。
- 调用约定: 策略内使用
await Promise.resolve(launchMiniProgram(...)),兼容同步与异步返回值。 - 更完整的配置说明、错误码、manifest 示例: 见
src/uni_modules/app-miniprogram-launcher/readme.md。
9.2 harmony-native-kit
- 作用:
openOuterUrl(url: string): Promise<void>,鸿蒙侧用系统能力打开外链;支付里用于打开alipays://...深链。 - 类型:
src/uni_modules/harmony-native-kit/index.d.ts。
10. 扩展与维护
10.1 新增一种 APP 支付宝形态
在 resolvePayStrategy 增加 payChannel 分支,并实现新的 IPayStrategy(或复用 PayStrategy / NativePayStrategy)。
10.2 恢复 APP uni.requestPayment 原生微信/支付宝
在 PaymentManager.initStrategies 的 AppType.APP 分支中,将 PayPlatform.WECHAT / ALIPAY 改为 new AppWxNativePay() / new AppAlipayNativePay()(需确认后端 payUrl 与客户端 manifest 能力一致)。
10.3 支持支付宝小程序包
为 AppType.ALI_MINI 增加 #ifdef MP-ALIPAY 分支,注册 NativePayStrategy 子类(参考 WxMiniProgramPay 实现支付宝 provider: 'alipay' 与 orderInfo)。
10.4 新增支付方式枚举
在 types.ts 增加 PayPlatform / PayPlatformEnum / PayMethodMap / 名称图标颜色,并在对应端的 initStrategies 注册策略。
11. 常见问题
Q:为什么 APP 不直接用 uni.requestPayment?
A:当前产品策略是拉起小程序或连连深链;仓库中仍保留原生类便于切换。
Q:合并支付如何传参?
A:全程使用 orderNoList;路由里用逗号拼接多个订单号。
Q:REDIRECT_TO_ORDER_LIST_CODES 是否包含订单状态变更码?
A:类型定义上互不包含;收银台错误跳转时会把两类合并判断。checkIsPayable 则分别触发 onNeedRedirect 与 onOrderStatusChanged。
Q:假支付如何开?
A:开发者彩蛋页 fakePayment 开关;开启后走 fakeSubmitPayment,不调真实调起。
Q:鸿蒙上支付宝小程序?
A:isSupportLaunch('alipay') 为 false,当前应依赖连连深链或其它非支付宝小程序路径。
12. 相关文件索引
| 用途 | 路径 |
|---|---|
| 支付管理器 | src/modules/pay/index.ts |
| 类型与常量 | src/modules/pay/types.ts |
| 页面 Hook | src/hooks/usePayment.ts |
| 收银台 | src/pages-sub/pages/order/cashier/index.vue |
| 支付 API | src/api/pay/ |
| 小程序拉起插件 | src/uni_modules/app-miniprogram-launcher/ |
| 鸿蒙外链 | src/uni_modules/harmony-native-kit/ |
更新记录(摘要)
- 当前版本(文档同步代码): APP 微信/支付宝以拉起小程序为主,连连支付宝走
AppAlipayScanPay;微信小程序支持企业网银;PaymentParams使用orderNoList;PayPlatformEnum为100/110/120。