From be4aafa6fd5542f56b62a9fba07f50d62faa2b76 Mon Sep 17 00:00:00 2001 From: jacobxu666 Date: Thu, 24 Sep 2026 21:31:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=A6=96=E6=AC=A1=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E6=94=AF=E4=BB=98=E6=97=A0=E5=8F=8D=E5=BA=94?= =?UTF-8?q?=E2=80=94=E2=80=94upsdk=20=E5=BC=82=E6=AD=A5=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E6=9C=AA=E5=B0=B1=E7=BB=AA=E5=8D=B3=E5=94=A4=E8=B5=B7=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=B0=B1=E7=BB=AA=20Promise=20=E7=AD=89?= =?UTF-8?q?=E5=BE=85(9s=E8=B6=85=E6=97=B6)=E5=90=8E=E5=86=8D=20pluginReady?= =?UTF-8?q?=EF=BC=9B=E5=AE=B9=E5=99=A8=E5=88=A4=E5=AE=9A=E5=8E=BB=20SDK=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E5=8F=AA=E8=AE=A4=20UA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- common/petrolVoucher.js | 7 ++-- pages/petrol/orderConfirm.vue | 77 +++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/common/petrolVoucher.js b/common/petrolVoucher.js index adc3a94..33f267c 100644 --- a/common/petrolVoucher.js +++ b/common/petrolVoucher.js @@ -22,12 +22,11 @@ export const VOUCHER_USE_FLOW = [ '支付差额可选:油卡 / 现金等' ] -// xuchao: 云闪付容器判定。UA 特征 + window.upsdk 双判,真机实测后定稿(方案文档 §8 挂账项); -// 若实测 UA 关键字不符,只需调整下方正则。 +// xuchao: 云闪付容器判定只看 UA——不能掺 window.upsdk 是否已加载(SDK 是异步注入的, +// 首屏点击时可能还没 load 完,会把云闪付内首点误判为站外)。UA 关键字真机实测后定稿。 export function isUnionPayApp() { if (typeof navigator === 'undefined' || !navigator.userAgent) return false - if (!/unionpay|upsdk|云闪付/i.test(navigator.userAgent)) return false - return typeof window !== 'undefined' && !!window.upsdk + return /unionpay|upsdk|云闪付/i.test(navigator.userAgent) } // xuchao: open-api/hhService/voucher/* 为双层壳:外层 errcode,内层 data.code 才是业务码 diff --git a/pages/petrol/orderConfirm.vue b/pages/petrol/orderConfirm.vue index d656d1d..9741d61 100644 --- a/pages/petrol/orderConfirm.vue +++ b/pages/petrol/orderConfirm.vue @@ -86,16 +86,25 @@ export default { this.initFromServer() }, methods: { - // xuchao: upsdk 运行时注入。不能依赖 index.html 静态标签——HBuilderX 命令行构建的 H5 模板 - // 不受项目根 index.html 控制(产物会丢标签),与人脸 SDK 同款动态加载兜底。 - loadUpSdk() { - if (typeof window !== 'undefined' && window.upsdk) return - if (typeof document === 'undefined') return - if (document.querySelector('script[data-upsdk]')) return - const s = document.createElement('script') - s.src = 'https://open.95516.com/s/open/js/upsdk.js' - s.setAttribute('data-upsdk', '1') - document.head.appendChild(s) + // xuchao: upsdk 运行时注入并返回就绪 Promise(同一加载只发起一次;超时/失败 resolve(false))。 + // 不能依赖 index.html 静态标签——HBuilderX 命令行构建的 H5 模板不吃根 index.html(会丢标签)。 + loadUpSdk(timeout = 9000) { + if (typeof window === 'undefined' || typeof document === 'undefined') return Promise.resolve(false) + if (window.upsdk) return Promise.resolve(true) + if (this._upSdkPromise) return this._upSdkPromise + const loading = new Promise(resolve => { + let done = false + const finish = v => { if (!done) { done = true; resolve(v) } } + const s = document.createElement('script') + s.src = 'https://open.95516.com/s/open/js/upsdk.js' + s.setAttribute('data-upsdk', '1') + s.onload = () => finish(!!window.upsdk) + s.onerror = () => finish(false) + document.head.appendChild(s) + setTimeout(() => finish(!!window.upsdk), timeout) + }) + this._upSdkPromise = loading + return loading }, // xuchao: 价格展示以服务端 latest 为准(测试期 0.01);已有待支付单自动续用;已发券直接跳券详情 initFromServer() { @@ -143,33 +152,29 @@ export default { uni.showToast({ title: (err && err.message) || '操作失败,请稍后再试', icon: 'none' }) }) }, - // xuchao: 云闪付控件唤起,交互与湘工惠商城一致(xghmall ordersure.vue:195-229 同型) - launchUnionPay(tn) { - this.loadUpSdk() - const tryPay = (retries) => { - if (typeof window !== 'undefined' && window.upsdk) { - window.upsdk.pluginReady(() => { - window.upsdk.pay({ - tn: tn, - success: () => { - uni.redirectTo({ url: '/pages/petrol/voucherDetail?orderNo=' + this.orderNo }) - }, - fail: () => { - this.submitting = false - uni.showToast({ title: '支付未完成,可在门店页继续支付', icon: 'none' }) - } - }) - }) - // 控件无异步结果时兜底:3 秒后恢复按钮(支付成功路径以回跳/轮询为准) - setTimeout(() => { this.submitting = false }, 3000) - } else if (retries > 0) { - setTimeout(() => tryPay(retries - 1), 500) - } else { - this.submitting = false - uni.showToast({ title: '支付组件加载失败,请在云闪付内重进页面', icon: 'none' }) - } + // xuchao: 云闪付控件唤起。先等 SDK 就绪(修复首点无反应:脚本异步加载未完成时 + // 旧逻辑只重试 4 秒且静默;就绪判定收敛到 loadUpSdk 的 Promise)。 + async launchUnionPay(tn) { + const ready = await this.loadUpSdk() + if (!ready) { + this.submitting = false + uni.showToast({ title: '支付组件加载失败,请稍后重试', icon: 'none' }) + return } - tryPay(8) // SDK 注入后最多等 4 秒 + window.upsdk.pluginReady(() => { + window.upsdk.pay({ + tn: tn, + success: () => { + uni.redirectTo({ url: '/pages/petrol/voucherDetail?orderNo=' + this.orderNo }) + }, + fail: () => { + this.submitting = false + uni.showToast({ title: '支付未完成,可在门店页继续支付', icon: 'none' }) + } + }) + }) + // 控件无异步结果时兜底:3 秒后恢复按钮(支付成功路径以回跳/轮询为准) + setTimeout(() => { this.submitting = false }, 3000) }, goBack() { const pages = getCurrentPages()