From 86e43e3e6cf6e2c115e6347cd0abfbde66880e5e Mon Sep 17 00:00:00 2001 From: Zhukj <3262118957> Date: Sat, 6 Dec 2025 09:16:39 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=96=B0=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=8D=8E=E4=B8=BA=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/js/huaweiPay.js | 152 +++++++++++++++++++++++++++++ common/js/payCore.js | 28 ++++++ common/js/payUtils.js | 212 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 392 insertions(+) create mode 100644 common/js/huaweiPay.js create mode 100644 common/js/payCore.js create mode 100644 common/js/payUtils.js diff --git a/common/js/huaweiPay.js b/common/js/huaweiPay.js new file mode 100644 index 0000000..6941b30 --- /dev/null +++ b/common/js/huaweiPay.js @@ -0,0 +1,152 @@ +/** + * 华为支付核心工具类 + * 适配端:华为快应用(原生支付)、微信小程序(H5支付)、H5端(H5支付) + * 核心:统一封装支付调用逻辑,返回H5支付链接适配web-view组件 + */ + +/** + * 华为支付调用封装 + * @param {String} outTradeNo 前端生成的唯一订单号 + * @param {Number} amount 支付金额(单位:元,保留2位小数) + * @param {String} subject 订单标题 + * @param {String} payType 支付类型(默认huaweipay) + * @returns {Promise} 支付结果(含H5支付链接) + */ +export function invokeHuaweiPay(outTradeNo, amount, subject, payType = 'huaweipay') { + return new Promise(async (resolve, reject) => { + try { + // 1. 显示加载中提示 + uni.showLoading({ + title: '发起支付...' + }); + + // 2. 调用后端生成订单 + const orderRes = await uni.request({ + url: getApiUrl() + '/api/huawei/pay/createOrder', + method: 'POST', + data: { + out_trade_no: outTradeNo, + total_amount: amount, + subject: subject, + pay_type: payType + } + }); + + // 3. 校验后端返回结果 + if (orderRes.data.code !== 0) { + uni.hideLoading(); + reject(new Error(orderRes.data.msg || '生成支付订单失败')); + return; + } + + // 4. 区分运行端处理 + const systemInfo = uni.getSystemInfoSync(); + const accountInfo = uni.getAccountInfoSync(); + const isHuaweiQuickApp = systemInfo.platform === 'quickapp-huawei'; // 华为快应用 + const isWechatMini = accountInfo?.miniProgram?.appId?.includes('wx'); // 微信小程序 + const isH5 = systemInfo.platform === 'web' || !accountInfo?.miniProgram; // H5端 + + if (isHuaweiQuickApp) { + // 4.1 华为快应用:原生唤起支付控件 + // 注意:这里需要根据实际的华为快应用支付SDK调用 + try { + // 示例代码,实际需要根据华为快应用文档调整 + const huaweiPay = require('@service.pay.huawei'); + huaweiPay.pay({ + orderInfo: orderRes.data.data.orderInfo, + success: (payRes) => { + uni.hideLoading(); + resolve({ + code: 0, + msg: '华为支付控件唤起成功', + data: payRes + }); + }, + fail: (err) => { + uni.hideLoading(); + const errMsg = err.message || err.code || '未知错误'; + reject(new Error(`支付失败:${errMsg}`)); + } + }); + } catch (sdkError) { + // SDK不存在,降级到H5支付 + if (orderRes.data.data.payUrl) { + uni.hideLoading(); + resolve({ + code: 0, + msg: '跳转华为支付H5页面', + data: { payUrl: orderRes.data.data.payUrl } + }); + } else { + uni.hideLoading(); + reject(new Error('华为支付SDK不可用且无H5支付链接')); + } + } + } else if (isWechatMini || isH5) { + // 4.2 微信小程序/H5端:返回H5支付链接(适配web-view) + if (!orderRes.data.data.payUrl) { + uni.hideLoading(); + reject(new Error('未获取到华为支付H5跳转链接')); + return; + } + uni.hideLoading(); + resolve({ + code: 0, + msg: '跳转华为支付H5页面', + data: { payUrl: orderRes.data.data.payUrl } + }); + } else { + // 4.3 其他端:提示不支持 + uni.hideLoading(); + reject(new Error('当前环境暂不支持华为支付')); + } + } catch (err) { + uni.hideLoading(); + reject(new Error(`支付异常:${err.message || '网络请求失败'}`)); + } + }); +} + +/** + * 校验支付最终状态(统一适配所有支付方式) + * @param {String} outTradeNo 前端生成的订单号 + * @returns {Promise} 校验结果(包含订单实际支付状态) + */ +export function checkPayStatus(outTradeNo) { + return new Promise(async (resolve, reject) => { + try { + // 统一调用后端状态校验接口(适配所有支付类型) + const checkRes = await uni.request({ + url: getApiUrl() + '/api/pay/checkStatus', + method: 'POST', + data: { + out_trade_no: outTradeNo + } + }); + + resolve(checkRes.data); + } catch (err) { + reject(new Error(`校验支付状态失败:${err.message || '网络请求失败'}`)); + } + }); +} + +/** + * 获取API基础URL + */ +function getApiUrl() { + // 尝试获取配置的API地址 + try { + // #ifdef H5 + const config = require('@/common/js/config.js').default; + return config.baseUrl || ''; + // #endif + // #ifndef H5 + const config = require('@/common/js/config.js').default; + return config.baseUrl || ''; + // #endif + } catch (e) { + console.warn('获取API配置失败,使用空字符串'); + return ''; + } +} \ No newline at end of file diff --git a/common/js/payCore.js b/common/js/payCore.js new file mode 100644 index 0000000..9ec498b --- /dev/null +++ b/common/js/payCore.js @@ -0,0 +1,28 @@ +/** + * 全支付方式统一调用入口 + * 整合微信/支付宝/华为支付的所有方法,简化页面引入逻辑 + * 依赖:payUtils.js、huaweiPay.js(无需修改原文件) + */ + +// 1. 引入原工具类的所有方法(修正方法名) +import { + invokeWechatPay, // 微信支付(完整方法名) + invokeAlipay, // 支付宝支付(完整方法名) + checkPayStatus as payUtilsCheck // 微信/支付宝支付状态校验(完整方法名) +} from './payUtils.js'; + +import { + invokeHuaweiPay, // 华为支付(完整方法名) + checkPayStatus as huaweiCheck // 华为支付状态校验(完整方法名) +} from './huaweiPay.js'; + +// 2. 导出所有支付调用方法(修正方法名,和原方法一致) +export { + invokeWechatPay, + invokeAlipay, + invokeHuaweiPay +}; + +// 3. 导出统一的支付状态校验方法(两个工具类逻辑完全一致,任选其一即可) +export const checkPayStatus = payUtilsCheck; +// 若需使用华为支付工具类的校验逻辑,可替换为:export const checkPayStatus = huaweiCheck; \ No newline at end of file diff --git a/common/js/payUtils.js b/common/js/payUtils.js new file mode 100644 index 0000000..ddc7789 --- /dev/null +++ b/common/js/payUtils.js @@ -0,0 +1,212 @@ +/** + * 微信/支付宝支付工具类 + * 适配端:微信小程序(全支付方式)、华为快应用(全支付方式)、H5(全支付方式) + * 核心:统一封装支付调用逻辑,返回H5支付链接适配web-view组件 + */ + +/** + * 微信支付调用封装 + * @param {String} outTradeNo 前端生成的唯一订单号 + * @param {Number} amount 支付金额(单位:元,保留2位小数) + * @param {String} subject 订单标题 + * @returns {Promise} 支付结果(含H5支付链接) + */ +export function invokeWechatPay(outTradeNo, amount, subject) { + return new Promise(async (resolve, reject) => { + try { + // 1. 调用后端接口生成微信支付订单 + const orderRes = await uni.request({ + url: getApiUrl() + '/api/pay/wechat/createOrder', + method: 'POST', + data: { + out_trade_no: outTradeNo, + total_amount: amount, + subject: subject, + pay_type: 'wechatpay' + } + }); + + // 2. 校验后端返回结果 + if (orderRes.data.code !== 0) { + reject(new Error(orderRes.data.msg || '生成微信支付订单失败')); + return; + } + + // 3. 区分运行端处理 + const systemInfo = uni.getSystemInfoSync(); + const accountInfo = uni.getAccountInfoSync(); + const isWechatMini = accountInfo?.miniProgram?.appId?.includes('wx'); // 微信小程序 + const isHuaweiQuickApp = systemInfo.platform === 'quickapp-huawei'; // 华为快应用 + + if (isWechatMini) { + // 3.1 微信小程序:优先原生唤起,失败则返回H5链接 + if (orderRes.data.data.timeStamp && orderRes.data.data.paySign) { + uni.requestPayment({ + timeStamp: orderRes.data.data.timeStamp, + nonceStr: orderRes.data.data.nonceStr, + package: orderRes.data.data.package, + signType: 'MD5', + paySign: orderRes.data.data.paySign, + success: () => { + resolve({ + code: 0, + msg: '微信支付控件唤起成功', + data: {} + }); + }, + fail: (err) => { + // 原生唤起失败,返回H5链接适配web-view + if (orderRes.data.data.payUrl) { + resolve({ + code: 0, + msg: '原生支付失败,跳转H5支付', + data: { payUrl: orderRes.data.data.payUrl } + }); + } else { + reject(new Error(`微信支付失败:${err.errMsg || '无H5支付链接'}`)); + } + } + }); + } else if (orderRes.data.data.payUrl) { + // 无原生支付参数,直接返回H5链接 + resolve({ + code: 0, + msg: '跳转微信支付H5页面', + data: { payUrl: orderRes.data.data.payUrl } + }); + } else { + reject(new Error('缺少微信支付参数(原生/H5)')); + } + } else if (isHuaweiQuickApp) { + // 3.2 华为快应用:返回H5支付链接 + if (!orderRes.data.data.payUrl) { + reject(new Error('未获取到微信支付H5跳转链接')); + return; + } + resolve({ + code: 0, + msg: '跳转微信支付H5页面', + data: { payUrl: orderRes.data.data.payUrl } + }); + } else { + // 3.3 H5端:直接跳转 + if (!orderRes.data.data.payUrl) { + reject(new Error('未获取到微信支付跳转链接')); + return; + } + window.location.href = orderRes.data.data.payUrl; + resolve({ + code: 0, + msg: '跳转微信支付页面成功', + data: {} + }); + } + } catch (err) { + reject(new Error(`微信支付异常:${err.message || '网络请求失败'}`)); + } + }); +} + +/** + * 支付宝支付调用封装(全端支持,返回H5链接适配web-view) + * @param {String} outTradeNo 前端生成的唯一订单号 + * @param {Number} amount 支付金额(单位:元) + * @param {String} subject 订单标题 + * @returns {Promise} 支付结果(含H5支付链接) + */ +export function invokeAlipay(outTradeNo, amount, subject) { + return new Promise(async (resolve, reject) => { + try { + // 1. 调用后端接口生成支付宝支付订单 + const orderRes = await uni.request({ + url: getApiUrl() + '/api/pay/alipay/createOrder', + method: 'POST', + data: { + out_trade_no: outTradeNo, + total_amount: amount, + subject: subject, + pay_type: 'alipay' + } + }); + + // 2. 校验后端返回结果 + if (orderRes.data.code !== 0) { + reject(new Error(orderRes.data.msg || '生成支付宝支付订单失败')); + return; + } + + // 3. 区分运行端处理(全端返回H5链接) + const accountInfo = uni.getAccountInfoSync(); + const isWechatMini = accountInfo?.miniProgram?.appId?.includes('wx'); + const isHuaweiQuickApp = uni.getSystemInfoSync().platform === 'quickapp-huawei'; + + if (!orderRes.data.data.payUrl) { + reject(new Error('未获取到支付宝支付H5跳转链接')); + return; + } + + if (isWechatMini || isHuaweiQuickApp) { + // 3.1 微信小程序/华为快应用:返回H5链接(适配web-view) + resolve({ + code: 0, + msg: '跳转支付宝支付H5页面', + data: { payUrl: orderRes.data.data.payUrl } + }); + } else { + // 3.2 H5端:直接跳转 + window.location.href = orderRes.data.data.payUrl; + resolve({ + code: 0, + msg: '跳转支付宝支付页面成功', + data: {} + }); + } + } catch (err) { + reject(new Error(`支付宝支付异常:${err.message || '网络请求失败'}`)); + } + }); +} + +/** + * 统一支付状态校验(和huaweiPay.js的checkPayStatus对齐) + * @param {String} outTradeNo 前端生成的订单号 + * @returns {Promise} 校验结果(包含订单实际支付状态) + */ +export function checkPayStatus(outTradeNo) { + return new Promise(async (resolve, reject) => { + try { + // 统一调用后端状态校验接口(适配所有支付类型) + const checkRes = await uni.request({ + url: getApiUrl() + '/api/pay/checkStatus', // 和huaweiPay.js使用同一接口 + method: 'POST', + data: { + out_trade_no: outTradeNo + } + }); + + resolve(checkRes.data); + } catch (err) { + reject(new Error(`校验支付状态失败:${err.message || '网络请求失败'}`)); + } + }); +} + +/** + * 获取API基础URL + */ +function getApiUrl() { + // 尝试获取配置的API地址 + try { + // #ifdef H5 + const config = require('@/common/js/config.js').default; + return config.baseUrl || ''; + // #endif + // #ifndef H5 + const config = require('@/common/js/config.js').default; + return config.baseUrl || ''; + // #endif + } catch (e) { + console.warn('获取API配置失败,使用空字符串'); + return ''; + } +} \ No newline at end of file