| | |
| | | <view class="payment-methods"> |
| | | <text class="method-title">选择支付方式</text> |
| | | |
| | | <view class="method-item" @tap="selectPayment('wechat')"> |
| | | <view v-if="isIosApp" class="method-item" @tap="selectPayment('appleiap')"> |
| | | <view class="method-left"> |
| | | <image class="pay-icon" src="/static/image/vip/weixinPay.png" mode="aspectFit"></image> |
| | | <text class="method-name">微信支付</text> |
| | | <view class="pay-icon pay-icon--apple">A</view> |
| | | <text class="method-name">App Store 支付</text> |
| | | </view> |
| | | <view class="method-radio"> |
| | | <image class="radio-img" :src="selectedPaymentMethod === 'wechat' ? '/static/image/vip/check.png' : '/static/image/vip/uncheck.png'" mode="aspectFit"></image> |
| | | <image class="radio-img" :src="selectedPaymentMethod === 'appleiap' ? '/static/image/vip/check.png' : '/static/image/vip/uncheck.png'" mode="aspectFit"></image> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="method-item" @tap="selectPayment('alipay')"> |
| | | <view class="method-left"> |
| | | <image class="pay-icon" src="/static/image/vip/aliPay.png" mode="aspectFit"></image> |
| | | <text class="method-name">支付宝支付</text> |
| | | <template v-else> |
| | | <view class="method-item" @tap="selectPayment('wechat')"> |
| | | <view class="method-left"> |
| | | <image class="pay-icon" src="/static/image/vip/weixinPay.png" mode="aspectFit"></image> |
| | | <text class="method-name">微信支付</text> |
| | | </view> |
| | | <view class="method-radio"> |
| | | <image class="radio-img" :src="selectedPaymentMethod === 'wechat' ? '/static/image/vip/check.png' : '/static/image/vip/uncheck.png'" mode="aspectFit"></image> |
| | | </view> |
| | | </view> |
| | | <view class="method-radio"> |
| | | <image class="radio-img" :src="selectedPaymentMethod === 'alipay' ? '/static/image/vip/check.png' : '/static/image/vip/uncheck.png'" mode="aspectFit"></image> |
| | | |
| | | <view class="method-item" @tap="selectPayment('alipay')"> |
| | | <view class="method-left"> |
| | | <image class="pay-icon" src="/static/image/vip/aliPay.png" mode="aspectFit"></image> |
| | | <text class="method-name">支付宝支付</text> |
| | | </view> |
| | | <view class="method-radio"> |
| | | <image class="radio-img" :src="selectedPaymentMethod === 'alipay' ? '/static/image/vip/check.png' : '/static/image/vip/uncheck.png'" mode="aspectFit"></image> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | </view> |
| | | |
| | | <view class="popup-footer"> |
| | |
| | | import { computed, ref } from 'vue' |
| | | import { onLoad, onShow } from '@dcloudio/uni-app' |
| | | import { getMemberOpenPage, purchaseMember } from './service' |
| | | import { requestAppleIapPayment, isIosAppRuntime } from '@/utils/appleIap.js' |
| | | import { resolveCurrentAppUserId } from '@/utils/app-user.js' |
| | | |
| | | type PaymentMethod = 'wechat' | 'alipay' |
| | | type PaymentMethod = 'wechat' | 'alipay' | 'appleiap' |
| | | |
| | | type PurchaseMemberType = 'MONTH_CARD' | 'QUARTER_CARD' |
| | | |
| | |
| | | title: string |
| | | price: number | string | null |
| | | days: number | null |
| | | appleProductId?: string |
| | | productId?: string |
| | | iosProductId?: string |
| | | } |
| | | |
| | | interface MemberBenefitItem { |
| | |
| | | } |
| | | |
| | | interface AppUserInfo { |
| | | id?: number | null |
| | | nickname?: string |
| | | phone?: string |
| | | avatar?: string |
| | |
| | | const statusBarHeight = ref(20) |
| | | const currentPlan = ref('') |
| | | const showPaymentPopup = ref(false) |
| | | const selectedPaymentMethod = ref<PaymentMethod>('alipay') |
| | | const isIosApp = isIosAppRuntime() |
| | | const selectedPaymentMethod = ref<PaymentMethod>(isIosApp ? 'appleiap' : 'alipay') |
| | | const purchaseSubmitting = ref(false) |
| | | const memberOpenPage = ref<MemberOpenPageData>(createDefaultMemberOpenPage()) |
| | | const appUserInfo = ref<AppUserInfo>(createDefaultAppUserInfo()) |
| | |
| | | }) |
| | | return |
| | | } |
| | | if (isIosApp) { |
| | | selectedPaymentMethod.value = 'appleiap' |
| | | } |
| | | showPaymentPopup.value = true |
| | | } |
| | | |
| | |
| | | } |
| | | purchaseSubmitting.value = true |
| | | try { |
| | | if (selectedPaymentMethod.value === 'appleiap') { |
| | | const response = await submitAppleIapMemberPurchase(memberType) |
| | | if (response?.code !== 0 || !response.data) { |
| | | return |
| | | } |
| | | applyPurchaseResult(response.data) |
| | | showPaymentPopup.value = false |
| | | uni.showToast({ |
| | | title: '开通成功', |
| | | icon: 'none', |
| | | }) |
| | | return |
| | | } |
| | | const response = await purchaseMember({ |
| | | memberType, |
| | | paymentMethod: selectedPaymentMethod.value === 'wechat' ? 'WECHAT' : 'ALIPAY', |
| | |
| | | } finally { |
| | | purchaseSubmitting.value = false |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 拉起苹果内购后,将交易凭证回传会员购买接口完成验单。 |
| | | */ |
| | | async function submitAppleIapMemberPurchase(memberType: PurchaseMemberType) { |
| | | const appleProductId = resolveMemberAppleProductId(selectedPlan.value) |
| | | if (!appleProductId) { |
| | | uni.showToast({ |
| | | title: '当前套餐未配置苹果内购商品', |
| | | icon: 'none', |
| | | }) |
| | | return null |
| | | } |
| | | const iapResult = await requestAppleIapPayment({ |
| | | productId: appleProductId, |
| | | username: resolveAppleIapUsername(), |
| | | }) |
| | | if (!normalizeOptionalText(iapResult?.transactionReceipt)) { |
| | | uni.showToast({ |
| | | title: '苹果内购凭证缺失', |
| | | icon: 'none', |
| | | }) |
| | | return null |
| | | } |
| | | return purchaseMember({ |
| | | memberType, |
| | | paymentMethod: 'APPLE_IAP', |
| | | appleProductId, |
| | | transactionReceipt: iapResult.transactionReceipt, |
| | | transactionIdentifier: iapResult.transactionIdentifier, |
| | | }) |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | uni.setStorageSync('appUserInfo', nextUserInfo) |
| | | syncCachedUserInfo() |
| | | } |
| | | |
| | | function resolveMemberAppleProductId(plan?: MemberOpenPackage | null) { |
| | | if (!plan) { |
| | | return '' |
| | | } |
| | | return normalizeOptionalText(plan.appleProductId || plan.productId || plan.iosProductId) |
| | | } |
| | | |
| | | function resolveAppleIapUsername() { |
| | | const userId = resolveCurrentAppUserId() |
| | | if (userId > 0) { |
| | | return String(userId) |
| | | } |
| | | return normalizeOptionalText(appUserInfo.value.phone) || 'guest' |
| | | } |
| | | |
| | | /** |
| | |
| | | width: 100rpx; |
| | | height: 68.57rpx; |
| | | } |
| | | |
| | | .pay-icon--apple { |
| | | width: 68rpx; |
| | | height: 68rpx; |
| | | border-radius: 16rpx; |
| | | background: #111111; |
| | | color: #ffffff; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 34rpx; |
| | | font-weight: 600; |
| | | } |
| | | } |
| | | |
| | | .method-name { |