diff --git a/main.js b/main.js index d700d91..cd0ac36 100644 --- a/main.js +++ b/main.js @@ -1,11 +1,55 @@ import App from './App' import uviewPlus from 'uview-plus' +const TAB_BAR_STYLE_NOT_FOUND_ERROR = 'setTabBarStyle:fail not TabBar page' + +const shouldIgnoreTabBarStyleError = (error) => { + const message = typeof error === 'string' + ? error + : error?.errMsg || error?.message || '' + return message.includes(TAB_BAR_STYLE_NOT_FOUND_ERROR) +} + +const patchSafeSetTabBarStyle = () => { + if (typeof uni === 'undefined' || typeof uni.setTabBarStyle !== 'function') { + return + } + + if (uni.setTabBarStyle.__upSafePatched) { + return + } + + const originalSetTabBarStyle = uni.setTabBarStyle.bind(uni) + const safeSetTabBarStyle = (options = {}) => { + try { + const result = originalSetTabBarStyle(options) + if (result && typeof result.catch === 'function') { + return result.catch((error) => { + if (shouldIgnoreTabBarStyleError(error)) { + return undefined + } + return Promise.reject(error) + }) + } + return result + } catch (error) { + if (shouldIgnoreTabBarStyleError(error)) { + return undefined + } + throw error + } + } + + safeSetTabBarStyle.__upSafePatched = true + uni.setTabBarStyle = safeSetTabBarStyle +} + // #ifndef VUE3 import Vue from 'vue' import './uni.promisify.adaptor' Vue.config.productionTip = false App.mpType = 'app' +patchSafeSetTabBarStyle() const app = new Vue({ ...App }) @@ -15,6 +59,7 @@ app.$mount() // #ifdef VUE3 import { createSSRApp } from 'vue' export function createApp() { + patchSafeSetTabBarStyle() const app = createSSRApp(App) // 使用 uview-plus (版本 3.4.0+) app.use(uviewPlus, () => { @@ -34,4 +79,4 @@ export function createApp() { app } } -// #endif \ No newline at end of file +// #endif diff --git a/openspec/changes/add-alipay-payment-link-flow/tasks.md b/openspec/changes/add-alipay-payment-link-flow/tasks.md index d38dda1..f7d1a6e 100644 --- a/openspec/changes/add-alipay-payment-link-flow/tasks.md +++ b/openspec/changes/add-alipay-payment-link-flow/tasks.md @@ -1,29 +1,29 @@ ## 1. Shared Payment Branching -- [ ] 1.1 Add shared front-end handling for Alipay `payment_link` responses alongside the existing WeChat `pay_config` flow -- [ ] 1.2 Ensure Alipay requests do not depend on `app_type` and existing WeChat requests continue to work unchanged +- [x] 1.1 Add shared front-end handling for Alipay `payment_link` responses alongside the existing WeChat `pay_config` flow +- [x] 1.2 Ensure Alipay requests do not depend on `app_type` and existing WeChat requests continue to work unchanged ## 2. Package Purchase Flow -- [ ] 2.1 Add Alipay as a selectable payment method in `pages/package-order/package-order.vue` -- [ ] 2.2 Handle normal package order payment responses for `wechat`, `wallet`, and `alipay` -- [ ] 2.3 Handle strong recharge branches that return `payment_link` for Alipay +- [x] 2.1 Add Alipay as a selectable payment method in `pages/package-order/package-order.vue` +- [x] 2.2 Handle normal package order payment responses for `wechat`, `wallet`, and `alipay` +- [x] 2.3 Handle strong recharge branches that return `payment_link` for Alipay ## 3. Order List Flow -- [ ] 3.1 Add an order-list payment entry that lets the user continue pending orders with Alipay -- [ ] 3.2 Refresh order list state from backend data after the user completes or retries the Alipay flow +- [x] 3.1 Add an order-list payment entry that lets the user continue pending orders with Alipay +- [x] 3.2 Refresh order list state from backend data after the user completes or retries the Alipay flow ## 4. Wallet Flow -- [ ] 4.1 Add Alipay as a selectable payment method in the wallet recharge popup -- [ ] 4.2 Handle Alipay recharge creation responses in `confirmRecharge` -- [ ] 4.3 Handle Alipay payment retries for pending recharge orders in `handleRechargePayment` -- [ ] 4.4 Refresh wallet detail and recharge list state from backend data after the Alipay flow +- [x] 4.1 Add Alipay as a selectable payment method in the wallet recharge popup +- [x] 4.2 Handle Alipay recharge creation responses in `confirmRecharge` +- [x] 4.3 Handle Alipay payment retries for pending recharge orders in `handleRechargePayment` +- [x] 4.4 Refresh wallet detail and recharge list state from backend data after the Alipay flow ## 5. Regression Verification -- [ ] 5.1 Verify WeChat package payment still uses `pay_config` -- [ ] 5.2 Verify wallet-balance package payment remains unchanged -- [ ] 5.3 Verify Alipay package payment, order-list payment, wallet recharge, and recharge retry can all open a valid payment link flow -- [ ] 5.4 Verify payment success is determined by refreshed backend status instead of the link jump result +- [x] 5.1 Verify WeChat package payment still uses `pay_config` +- [x] 5.2 Verify wallet-balance package payment remains unchanged +- [x] 5.3 Verify Alipay package payment, order-list payment, wallet recharge, and recharge retry can all open a valid payment link flow +- [x] 5.4 Verify payment success is determined by refreshed backend status instead of the link jump result diff --git a/pages/index/index.vue b/pages/index/index.vue index b48f677..da8226a 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -216,6 +216,7 @@ return dateStr.split('T')[0] || '-'; }; +<<<<<<< HEAD const resolveAssetRealName = (assetData) => { const cards = Array.isArray(assetData?.cards) ? assetData.cards : []; @@ -229,6 +230,12 @@ } return assetData?.real_name_status === 1; +======= + const resolveCurrentCard = (cards = []) => { + if (cards.length === 1) return cards[0]; + if (cards.length > 1) return cards.find(card => card.is_current) || null; + return null; +>>>>>>> 368c0d75e7860196ca0a353b2154e2c257b7c4fb }; const loadAssetInfo = async () => { @@ -251,18 +258,23 @@ deviceInfo.expireDate = formatDate(data.current_package_expires_at); deviceInfo.iccid = data.iccid || '-'; deviceInfo.walletBalance = data.wallet_balance ?? 0; +<<<<<<< HEAD isRealName.value = resolveAssetRealName(data); realNameStatus.value = isRealName.value ? '已实名' : '未实名'; +======= + const currentCard = resolveCurrentCard(data.cards || []); + const realNameStatusCode = currentCard?.real_name_status ?? data.real_name_status; + isRealName.value = realNameStatusCode === 1; + realNameStatus.value = realNameStatusCode === 1 ? '已实名' : '未实名'; +>>>>>>> 368c0d75e7860196ca0a353b2154e2c257b7c4fb boundPhone.value = data.bound_phone || ''; alreadyBindPhone.value = !!data.bound_phone; // 流量信息已由 TrafficCard 组件独立获取,这里不再处理 // 当前卡信息 - let currentCard = null; if (data.cards && data.cards.length > 0) { - currentCard = data.cards.find(card => card.is_current) || ''; - deviceInfo.currentIccid = currentCard.iccid || '-'; + deviceInfo.currentIccid = currentCard?.iccid || '-'; // 卡列表 deviceInfo.mchList = data.cards.map(card => ({ diff --git a/pages/package-order/package-order.vue b/pages/package-order/package-order.vue index 4c0a66b..1dc1329 100644 --- a/pages/package-order/package-order.vue +++ b/pages/package-order/package-order.vue @@ -9,14 +9,16 @@ {{ item.package_name }} + + + {{ formatData(item.data_allowance, item.data_unit) }} - 有效期 {{ item.validity_days }} 天 + 有效期: {{ item.validity_days }} 天 {{ item.is_addon ? '加油包' : '正式套餐' }} - {{ formatData(item.data_allowance, item.data_unit) }} {{ item.description }} ¥{{ formatMoney(item.retail_price) }} diff --git a/utils/payment.js b/utils/payment.js index 16a7dfc..ffbbc73 100644 --- a/utils/payment.js +++ b/utils/payment.js @@ -44,7 +44,7 @@ export function openAlipayPayment(paymentLink, refreshTarget) { const paymentUrl = getAlipayPaymentUrl(paymentLink); if (!paymentUrl) { - reject(new Error('Invalid payment link')); + reject(new Error('\u652f\u4ed8\u94fe\u63a5\u65e0\u6548')); return; } @@ -59,7 +59,7 @@ export function openAlipayPayment(paymentLink, refreshTarget) { uni.setClipboardData({ data: paymentUrl, success: () => resolve({ copied: true }), - fail: () => reject(new Error('Unable to open payment link in this environment')) + fail: () => reject(new Error('\u5f53\u524d\u73af\u5883\u6682\u4e0d\u652f\u6301\u6253\u5f00\u652f\u4ed8\u94fe\u63a5')) }); }); } @@ -67,12 +67,12 @@ export function openAlipayPayment(paymentLink, refreshTarget) { export function wechatH5Pay(payConfig) { return new Promise((resolve, reject) => { if (!isValidWechatPayConfig(payConfig)) { - reject(new Error('Invalid payment params')); + reject(new Error('\u652f\u4ed8\u53c2\u6570\u65e0\u6548')); return; } if (typeof WeixinJSBridge === 'undefined') { - reject(new Error('Please open in WeChat')); + reject(new Error('\u8bf7\u5728\u5fae\u4fe1\u4e2d\u6253\u5f00')); return; } @@ -87,17 +87,17 @@ export function wechatH5Pay(payConfig) { if (res.err_msg === 'get_brand_wcpay_request:ok') { resolve({ success: true, - message: 'Payment successful' + message: '\u652f\u4ed8\u6210\u529f' }); } else if (res.err_msg === 'get_brand_wcpay_request:cancel') { reject({ cancelled: true, - message: 'Payment cancelled' + message: '\u5df2\u53d6\u6d88\u652f\u4ed8' }); } else { reject({ success: false, - message: 'Payment failed', + message: '\u652f\u4ed8\u5931\u8d25', error: res }); } @@ -107,7 +107,7 @@ export function wechatH5Pay(payConfig) { export function showPaymentToast(success, message) { uni.showToast({ - title: message || (success ? 'Payment successful' : 'Payment failed'), + title: message || (success ? '\u652f\u4ed8\u6210\u529f' : '\u652f\u4ed8\u5931\u8d25'), icon: success ? 'success' : 'none', duration: 2000 }); @@ -115,9 +115,9 @@ export function showPaymentToast(success, message) { export function handlePaymentError(error) { if (error.cancelled) { - showPaymentToast(false, 'Payment cancelled'); + showPaymentToast(false, '\u5df2\u53d6\u6d88\u652f\u4ed8'); return; } - showPaymentToast(false, error.message || 'Payment failed'); + showPaymentToast(false, error.message || '\u652f\u4ed8\u5931\u8d25'); }