/* eslint-disable react-hooks/exhaustive-deps */ import CustomCheckBox from '@/components/ui/CheckBox'; import { USER_AGREEMENT_URL } from '@/constants/Agree'; import { useAppDispatch } from '@/hooks/redux'; import { useI18n } from '@/hooks/useI18n'; import { MEMBERSHIP_PLAN_META, extractMembershipProductsFromOfferings, getActiveSubscriptionIds, getPlanMetaById, resolvePlanDisplayName, type MembershipPlanType, } from '@/services/membership'; import { fetchMembershipData } from '@/store/membershipSlice'; import { log, logger } from '@/utils/logger'; import { captureMessage, captureMessageWithContext, capturePurchaseEvent, captureUserAction } from '@/utils/sentry.utils'; import { Toast as GlobalToast } from '@/utils/toast.utils'; import { Ionicons } from '@expo/vector-icons'; import { captureException } from '@sentry/react-native'; import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect'; import { LinearGradient } from 'expo-linear-gradient'; import React, { useEffect, useRef, useState } from 'react'; import { ActivityIndicator, Alert, Dimensions, Linking, Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import Purchases, { CustomerInfo, PurchasesStoreProduct } from 'react-native-purchases'; const { height } = Dimensions.get('window'); interface MembershipModalProps { visible: boolean; onClose?: () => void; onPurchaseSuccess?: () => void; } // RevenueCat 在 JS SDK 中以 string[] 返回 activeSubscriptions,但保持健壮性以防类型变化 // 权限类型枚举 type PermissionType = 'exclusive' | 'limited' | 'unlimited'; // 权限配置接口 interface PermissionConfig { type: PermissionType; text: string; vipText?: string; // VIP用户的特殊文案,可选 } // 权益对比项接口 interface BenefitItem { title: string; description?: string; // 功能描述,可选 vip: PermissionConfig; regular: PermissionConfig; } const PLAN_STYLE_CONFIG: Record = { lifetime: { gradient: ['#FFF1DD', '#FFE8FA'] as const, accent: '#7B2CBF', }, quarterly: { gradient: ['#E5EAFE', '#F4E8FF'] as const, accent: '#5B5BE6', }, weekly: { gradient: ['#FFF6E5', '#FFE7CC'] as const, accent: '#FF9500', }, }; // 根据权限类型获取对应的图标 const getPermissionIcon = (type: PermissionType, isVip: boolean) => { switch (type) { case 'exclusive': return isVip ? ( ) : ( ); case 'limited': return isVip ? ( ) : ( ); case 'unlimited': return ( ); default: return ; } }; export function MembershipModal({ visible, onClose, onPurchaseSuccess }: MembershipModalProps) { const { t } = useI18n(); const dispatch = useAppDispatch(); const [selectedProduct, setSelectedProduct] = useState(null); const [loading, setLoading] = useState(false); const [restoring, setRestoring] = useState(false); // const { user } = useAuth() // const { refreshUserInfo } = useAuth(); const [products, setProducts] = useState([]); // 协议同意状态 - 只需要一个状态 const [agreementAccepted, setAgreementAccepted] = useState(false); // 保存监听器引用,用于移除监听器 const purchaseListenerRef = useRef<((customerInfo: CustomerInfo) => void) | null>(null); // 权益对比配置 - Move inside component to use t function const benefitComparison: BenefitItem[] = [ { title: t('membershipModal.benefits.items.aiCalories.title'), description: t('membershipModal.benefits.items.aiCalories.description'), vip: { type: 'unlimited', text: t('membershipModal.benefits.permissions.unlimited'), vipText: t('membershipModal.benefits.permissions.unlimited') }, regular: { type: 'limited', text: t('membershipModal.benefits.permissions.limited'), vipText: t('membershipModal.benefits.permissions.dailyLimit', { count: 3 }) } }, { title: t('membershipModal.benefits.items.aiNutrition.title'), description: t('membershipModal.benefits.items.aiNutrition.description'), vip: { type: 'unlimited', text: t('membershipModal.benefits.permissions.unlimited'), vipText: t('membershipModal.benefits.permissions.unlimited') }, regular: { type: 'limited', text: t('membershipModal.benefits.permissions.limited'), vipText: t('membershipModal.benefits.permissions.dailyLimit', { count: 5 }) } }, { title: t('membershipModal.benefits.items.healthReminder.title'), description: t('membershipModal.benefits.items.healthReminder.description'), vip: { type: 'unlimited', text: t('membershipModal.benefits.permissions.fullSupport'), vipText: t('membershipModal.benefits.permissions.smartReminder') }, regular: { type: 'unlimited', text: t('membershipModal.benefits.permissions.basicSupport'), vipText: t('membershipModal.benefits.permissions.basicSupport') } }, { title: t('membershipModal.benefits.items.aiMedication.title'), description: t('membershipModal.benefits.items.aiMedication.description'), vip: { type: 'exclusive', text: t('membershipModal.benefits.permissions.fullAnalysis'), vipText: t('membershipModal.benefits.permissions.fullAnalysis') }, regular: { type: 'exclusive', text: t('membershipModal.benefits.permissions.notSupported'), vipText: t('membershipModal.benefits.permissions.notSupported') } }, { title: t('membershipModal.benefits.items.customChallenge.title'), description: t('membershipModal.benefits.items.customChallenge.description'), vip: { type: 'exclusive', text: t('membershipModal.benefits.permissions.createUnlimited'), vipText: t('membershipModal.benefits.permissions.createUnlimited') }, regular: { type: 'exclusive', text: t('membershipModal.benefits.permissions.notSupported'), vipText: t('membershipModal.benefits.permissions.notSupported') } }, ]; // 根据选中的产品生成tips内容 const getTipsContent = (product: PurchasesStoreProduct | null): string => { if (!product) return ''; const plan = MEMBERSHIP_PLAN_META.find(item => item.id === product.identifier); if (!plan) { return ''; } switch (plan.type) { case 'lifetime': return t('membershipModal.plans.lifetime.subtitle'); case 'quarterly': return t('membershipModal.plans.quarterly.subtitle'); case 'weekly': return t('membershipModal.plans.weekly.subtitle'); default: return ''; } }; // useEffect(() => { // if (user) { // captureMessage('用户已登录,开始初始化 Purchases'); // initPurchases(); // } // }, [user]); // 初始化只需要执行一次 // 单独的 useEffect 来处理购买监听器,依赖 visible 状态 useEffect(() => { if (visible) { setupPurchaseListener(); setAgreementAccepted(false); initPurchases(); } else { removePurchaseListener(); setProducts([]); setSelectedProduct(null); setAgreementAccepted(false); setLoading(false); setRestoring(false); } // 组件卸载时确保移除监听器 return () => { removePurchaseListener(); log.info('MembershipModal 购买监听器已清理'); }; }, [visible]); // 依赖 visible 状态 const initPurchases = async () => { capturePurchaseEvent('init', '开始获取会员产品套餐'); try { const offerings = await Purchases.getOfferings(); log.info('获取产品套餐', { offerings }); logger.info('获取产品套餐成功', { currentOffering: offerings.current?.identifier || null, availablePackagesCount: offerings.current?.availablePackages.length || 0, allOfferingsCount: Object.keys(offerings.all).length, }); const productsToUse = extractMembershipProductsFromOfferings(offerings); if (productsToUse.length === 0) { log.warn('没有找到可用的产品套餐', { hasCurrentOffering: offerings.current !== null, packagesLength: offerings.current?.availablePackages.length || 0, }); logger.info('没有找到可用的产品套餐', { hasCurrentOffering: offerings.current !== null, packagesLength: offerings.current?.availablePackages.length || 0, }); setProducts([]); setSelectedProduct(null); return; } log.info('productsToUse', productsToUse) setProducts(productsToUse); // 获取产品后,检查用户的购买记录并自动选中对应套餐 await checkAndSelectActivePlan(productsToUse); // 确保始终有一个选中的产品 setSelectedProduct(current => { // 如果已经有选中的产品,保持不变 if (current) return current; // 否则选择第一个可用产品 return productsToUse[0] ?? null; }); } catch (e: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: e?.message || '未知错误', code: e?.code || null, name: e?.name || 'Error', // 只包含基本的错误信息,避免可能的循环引用 }; log.error('获取产品套餐失败', { error: errorData }); captureException(e); capturePurchaseEvent('error', '获取产品套餐失败', errorData); // 设置空状态,避免界面卡在加载状态 setProducts([]); setSelectedProduct(null); } }; // 添加购买状态监听器 const setupPurchaseListener = () => { log.info('设置购买监听器', { visible }); // 如果已经有监听器,先移除 if (purchaseListenerRef.current) { removePurchaseListener(); } // 创建监听器函数 const listener = (customerInfo: CustomerInfo) => { log.info('购买状态变化监听器触发', { customerInfo, visible }); const activeSubscriptionIds = getActiveSubscriptionIds(customerInfo); // 检查是否有有效的购买记录 const hasActiveEntitlements = Object.keys(customerInfo.entitlements.active).length > 0; const hasNonSubscriptionTransactions = customerInfo.nonSubscriptionTransactions.length > 0; const hasActiveSubscriptions = activeSubscriptionIds.length > 0; if (hasActiveEntitlements || hasNonSubscriptionTransactions || hasActiveSubscriptions) { capturePurchaseEvent('success', '监听到购买状态变化', { hasActiveEntitlements, hasNonSubscriptionTransactions, hasActiveSubscriptions, activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: activeSubscriptionIds.length, modalVisible: visible }); log.info('检测到购买成功,准备刷新用户信息并关闭弹窗'); // 延迟一点时间,确保购买流程完全完成 setTimeout(async () => { void dispatch(fetchMembershipData()); // 刷新用户信息 // await refreshUserInfo(); // 调用购买成功回调 onPurchaseSuccess?.(); // 关闭弹窗 onClose?.(); // 显示成功提示 GlobalToast.show({ message: t('membershipModal.success.purchase'), }); }, 1000); } }; // 保存监听器引用 purchaseListenerRef.current = listener; // 添加监听器 Purchases.addCustomerInfoUpdateListener(listener); log.info('购买监听器已添加'); }; // 移除购买状态监听器 const removePurchaseListener = () => { if (purchaseListenerRef.current) { log.info('移除购买监听器'); Purchases.removeCustomerInfoUpdateListener(purchaseListenerRef.current); purchaseListenerRef.current = null; log.info('购买监听器已移除'); } }; // 检查用户的购买记录并自动选中对应套餐 const checkAndSelectActivePlan = async (availableProducts: PurchasesStoreProduct[]) => { try { captureUserAction('开始检查用户购买记录'); // 获取用户的购买信息 const customerInfo = await Purchases.getCustomerInfo(); log.info('获取用户购买信息', { customerInfo }); // 记录详细的购买状态日志 const activeSubscriptionIds = getActiveSubscriptionIds(customerInfo); captureMessageWithContext('获取用户购买信息成功', { activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: activeSubscriptionIds.length, originalAppUserId: customerInfo.originalAppUserId, firstSeen: customerInfo.firstSeen, originalPurchaseDate: customerInfo.originalPurchaseDate, latestExpirationDate: customerInfo.latestExpirationDate }); // 查找激活的产品ID let activePurchasedProductIds: string[] = []; // 检查权益 Object.keys(customerInfo.entitlements.active).forEach(key => { const entitlement = customerInfo.entitlements.active[key]; activePurchasedProductIds.push(entitlement.productIdentifier); log.debug(`激活的权益: ${key}, 产品ID: ${entitlement.productIdentifier}`); }); // 检查非订阅购买(如终身会员) customerInfo.nonSubscriptionTransactions.forEach(transaction => { activePurchasedProductIds.push(transaction.productIdentifier); log.debug(`非订阅购买: ${transaction.productIdentifier}, 购买时间: ${transaction.purchaseDate}`); }); // 检查订阅 activeSubscriptionIds.forEach(productId => { activePurchasedProductIds.push(productId); log.debug(`激活的订阅: ${productId}`); }); // 去重 activePurchasedProductIds = [...new Set(activePurchasedProductIds)]; captureMessageWithContext('用户激活的产品列表', { activePurchasedProductIds, activePurchasedProductCount: activePurchasedProductIds.length }); if (activePurchasedProductIds.length > 0) { // 尝试在可用产品中找到匹配的产品 let selectedProduct: PurchasesStoreProduct | null = null; // 优先级:终身会员 > 季度会员 > 周会员 const priorityOrder = MEMBERSHIP_PLAN_META.map(plan => plan.id); // 按照优先级查找 for (const priorityProductId of priorityOrder) { if (activePurchasedProductIds.includes(priorityProductId)) { selectedProduct = availableProducts.find(product => product.identifier === priorityProductId) || null; if (selectedProduct) { log.info(`找到优先级最高的激活产品: ${priorityProductId}`); break; } } } // 如果按优先级没找到,尝试找到任何匹配的产品 if (!selectedProduct) { for (const productId of activePurchasedProductIds) { selectedProduct = availableProducts.find(product => product.identifier === productId) || null; if (selectedProduct) { log.info(`找到匹配的激活产品: ${productId}`); break; } } } if (selectedProduct) { setSelectedProduct(selectedProduct); captureMessageWithContext('自动选中用户已购买的套餐', { selectedProductId: selectedProduct.identifier, selectedProductTitle: selectedProduct.title, selectedProductPrice: selectedProduct.price, allActivePurchasedProductIds: activePurchasedProductIds }); } else { captureMessageWithContext('未找到匹配的可用产品', { activePurchasedProductIds, availableProductIds: availableProducts.map(p => p.identifier) }); log.warn('用户有激活的购买记录,但没有找到匹配的可用产品', { activePurchasedProductIds, availableProductIds: availableProducts.map(p => p.identifier) }); } } else { captureMessageWithContext('用户没有激活的购买记录', { hasEntitlements: Object.keys(customerInfo.entitlements.active).length > 0, hasNonSubscriptions: customerInfo.nonSubscriptionTransactions.length > 0, hasActiveSubscriptions: activeSubscriptionIds.length > 0 }); log.info('用户没有激活的购买记录,使用默认选择逻辑'); setSelectedProduct(availableProducts[0] ?? null); } } catch (error: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: error?.message || '未知错误', code: error?.code || null, name: error?.name || 'Error', }; log.error('检查用户购买记录失败', { error: errorData }); captureException(error); captureMessageWithContext('检查用户购买记录失败', errorData); } }; const handlePurchase = async () => { // 添加调试日志 log.info('handlePurchase 被调用', { loading, productsLength: products.length, selectedProductId: selectedProduct?.identifier, selectedProductTitle: selectedProduct?.title, agreementAccepted }); // 验证是否已同意协议 if (!agreementAccepted) { Alert.alert( t('membershipModal.agreements.alert.title'), t('membershipModal.agreements.alert.message'), [ { text: t('membershipModal.agreements.alert.confirm'), style: 'default', } ] ); return; } // 如果没有选中的产品但有可用产品,自动选择第一个 if (!selectedProduct && products.length > 0) { log.info('自动选择第一个可用产品', { firstProductId: products[0]?.identifier, firstProductTitle: products[0]?.title }); setSelectedProduct(products[0]); return; // 返回让用户确认选择后再点击 } // 验证是否选择了产品 if (!selectedProduct) { Alert.alert( t('membershipModal.errors.selectPlan'), '', [ { text: t('membershipModal.agreements.alert.confirm'), style: 'default', } ] ); return; } // 防止重复点击 if (loading) { return; } try { // 设置加载状态 setLoading(true); // 记录购买开始事件 capturePurchaseEvent('init', `开始购买: ${selectedProduct.identifier}`, { productIdentifier: selectedProduct.identifier, productTitle: selectedProduct.title, productPrice: selectedProduct.price }); // 执行购买 const { customerInfo, productIdentifier } = await Purchases.purchaseStoreProduct(selectedProduct); log.info('购买成功', { customerInfo, productIdentifier }); const activeSubscriptionIds = getActiveSubscriptionIds(customerInfo); // 记录购买成功事件 capturePurchaseEvent('success', `购买成功: ${productIdentifier}`, { productIdentifier, hasActiveEntitlements: Object.keys(customerInfo.entitlements.active).length > 0, activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: activeSubscriptionIds.length }); // 购买成功后,监听器会自动处理后续逻辑(刷新用户信息、关闭弹窗等) log.info('购买流程完成,等待监听器处理后续逻辑'); } catch (error: any) { captureException(error); // 记录购买失败事件 capturePurchaseEvent('error', `购买失败: ${error.message || '未知错误'}`, { errorCode: error.code || null, errorMessage: error.message || '未知错误', productIdentifier: selectedProduct.identifier }); // 处理不同类型的购买错误 if (error.userCancelled || error.code === Purchases.PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) { // 用户取消购买 GlobalToast.show({ message: t('membershipModal.errors.purchaseCancelled'), }); } else if (error.code === Purchases.PURCHASES_ERROR_CODE.PRODUCT_ALREADY_PURCHASED_ERROR) { // 商品已拥有 GlobalToast.show({ message: t('membershipModal.errors.alreadyPurchased'), }); } else if (error.code === Purchases.PURCHASES_ERROR_CODE.NETWORK_ERROR) { // 网络错误 GlobalToast.show({ message: t('membershipModal.errors.networkError'), }); } else if (error.code === Purchases.PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR) { // 支付待处理 GlobalToast.show({ message: t('membershipModal.errors.paymentPending'), }); } else if (error.code === Purchases.PURCHASES_ERROR_CODE.INVALID_CREDENTIALS_ERROR) { // 凭据无效 GlobalToast.show({ message: t('membershipModal.errors.invalidCredentials'), }); } else { // 其他错误 GlobalToast.show({ message: t('membershipModal.errors.purchaseFailed'), }); } } finally { // 确保在所有情况下都重置加载状态 setLoading(false); log.info('购买流程结束,加载状态已重置'); } }; const handleRestore = async () => { // 防止重复点击 if (restoring || loading) { return; } try { setRestoring(true); captureUserAction('开始恢复购买'); // 恢复购买 const customerInfo = await Purchases.restorePurchases(); log.info('恢复购买结果', { customerInfo }); const activeSubscriptionIds = getActiveSubscriptionIds(customerInfo); captureMessageWithContext('恢复购买结果', { activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: activeSubscriptionIds.length, managementUrl: customerInfo.managementURL, originalAppUserId: customerInfo.originalAppUserId }); // 检查是否有有效的购买记录 const hasActiveEntitlements = Object.keys(customerInfo.entitlements.active).length > 0; const hasNonSubscriptionTransactions = customerInfo.nonSubscriptionTransactions.length > 0; const hasActiveSubscriptions = activeSubscriptionIds.length > 0; if (hasActiveEntitlements || hasNonSubscriptionTransactions || hasActiveSubscriptions) { // 检查具体的购买内容 let restoredProducts: string[] = []; // 检查权益 Object.keys(customerInfo.entitlements.active).forEach(key => { const entitlement = customerInfo.entitlements.active[key]; restoredProducts.push(entitlement.productIdentifier); }); // 检查非订阅购买(如终身会员) customerInfo.nonSubscriptionTransactions.forEach(transaction => { restoredProducts.push(transaction.productIdentifier); }); // 检查订阅 activeSubscriptionIds.forEach(productId => { restoredProducts.push(productId); }); log.info('恢复的产品', { restoredProducts }); capturePurchaseEvent('restore', '恢复购买成功', { restoredProducts, restoredProductsCount: restoredProducts.length }); void dispatch(fetchMembershipData()); try { // 调用后台服务接口进行票据匹配 captureUserAction('开始调用后台恢复购买接口'); // const restoreResponse = await UserApi.restorePurchase({ // customerInfo: { // originalAppUserId: customerInfo.originalAppUserId, // activeEntitlements: customerInfo.entitlements.active, // nonSubscriptionTransactions: customerInfo.nonSubscriptionTransactions, // activeSubscriptions: customerInfo.activeSubscriptions, // restoredProducts // } // }); // log.debug('后台恢复购买响应', { restoreResponse }); // captureMessageWithContext('后台恢复购买成功', { // responseData: restoreResponse, // restoredProductsCount: restoredProducts.length // }); // 刷新用户信息 // await refreshUserInfo(); // 调用购买成功回调 onPurchaseSuccess?.(); // 关闭弹窗 onClose?.(); GlobalToast.show({ message: t('membershipModal.errors.restoreSuccess'), }); } catch (apiError: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: apiError?.message || '未知错误', code: apiError?.code || null, name: apiError?.name || 'Error', restoredProductsCount: restoredProducts.length }; log.error('后台恢复购买接口调用失败', { error: errorData }); captureException(apiError); captureMessageWithContext('后台恢复购买接口失败', errorData); // 即使后台接口失败,也显示恢复成功(因为 RevenueCat 已经确认有购买记录) // 但不关闭弹窗,让用户知道可能需要重试 GlobalToast.show({ message: t('membershipModal.errors.restorePartialFailed'), }); } } else { capturePurchaseEvent('restore', '没有找到购买记录', { hasActiveEntitlements, hasNonSubscriptionTransactions, hasActiveSubscriptions, activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: activeSubscriptionIds.length }); GlobalToast.show({ message: t('membershipModal.errors.noPurchasesFound'), }); } } catch (error: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: error?.message || '未知错误', code: error?.code || null, name: error?.name || 'Error', }; log.error('恢复购买失败', { error: errorData }); captureException(error); // 记录恢复购买失败事件 capturePurchaseEvent('error', `恢复购买失败: ${errorData.message}`, errorData); // 处理特定的恢复购买错误 if (error.userCancelled || error.code === Purchases.PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) { GlobalToast.show({ message: t('membershipModal.errors.restoreCancelled'), }); } else if (error.code === Purchases.PURCHASES_ERROR_CODE.NETWORK_ERROR) { GlobalToast.show({ message: t('membershipModal.errors.networkError'), }); } else if (error.code === Purchases.PURCHASES_ERROR_CODE.INVALID_CREDENTIALS_ERROR) { GlobalToast.show({ message: t('membershipModal.errors.invalidCredentials'), }); } else { GlobalToast.show({ message: t('membershipModal.errors.restoreFailed'), }); } } finally { // 确保在所有情况下都重置恢复状态 setRestoring(false); log.info('恢复购买流程结束,恢复状态已重置'); } }; const renderPlanCard = (product: PurchasesStoreProduct) => { const planMeta = getPlanMetaById(product.identifier); const isSelected = selectedProduct === product; // 优先使用翻译的标题,如果找不到 meta 则回退到产品标题 let displayTitle = product.title; let displaySubtitle = planMeta?.subtitle ?? ''; if (planMeta) { displayTitle = t(`membershipModal.plans.${planMeta.type}.title`); displaySubtitle = t(`membershipModal.plans.${planMeta.type}.subtitle`); } else { // 如果没有 meta,尝试使用 resolvePlanDisplayName (虽然这里主要依赖 meta) displayTitle = resolvePlanDisplayName(product, planMeta); } const priceLabel = product.priceString || ''; const styleConfig = planMeta ? PLAN_STYLE_CONFIG[planMeta.type] : undefined; return ( !loading && product && setSelectedProduct(product)} disabled={loading} activeOpacity={loading ? 1 : 0.8} accessible={true} accessibilityLabel={`${displayTitle} ${priceLabel}`} accessibilityHint={loading ? t('membershipModal.loading.purchase') : t('membershipModal.actions.selectPlan', { plan: displayTitle })} accessibilityState={{ disabled: loading, selected: isSelected }} > {planMeta?.tag && ( {t('membershipModal.plans.tag')} )} {displayTitle} {priceLabel || '--'} {planMeta?.originalPrice && ( {planMeta.originalPrice} )} {displaySubtitle} ); }; return ( {/* 半透明背景 */} {/* 悬浮返回按钮 - 移到 ScrollView 外部以确保始终在最上层 */} {isLiquidGlassAvailable() ? ( ) : ( )} {t('membershipModal.sectionTitle.plans')} {t('membershipModal.sectionTitle.plansSubtitle')} {products.length === 0 ? ( {t('membershipModal.errors.noProducts')} ) : ( <> {products.map(renderPlanCard)} {selectedProduct && ( {getTipsContent(selectedProduct)} )} )} {t('membershipModal.benefits.title')} {t('membershipModal.benefits.subtitle')} {t('membershipModal.benefits.table.benefit')} {t('membershipModal.benefits.table.vip')} {t('membershipModal.benefits.table.regular')} {benefitComparison.map((row, index) => ( {row.title} {row.description && ( {row.description} )} {/* VIP 权限列 */} {getPermissionIcon(row.vip.type, true)} {row.vip.vipText || row.vip.text} {/* 普通用户权限列 */} {getPermissionIcon(row.regular.type, false)} {row.regular.vipText || row.regular.text} ))} {t('membershipModal.agreements.prefix')} { Linking.openURL(USER_AGREEMENT_URL); captureMessage('click user agreement'); }} > {t('membershipModal.agreements.userAgreement')} | { captureMessage('click membership agreement'); }} > {t('membershipModal.agreements.membershipAgreement')} | { captureMessage('click auto renewal agreement'); }} > {t('membershipModal.agreements.autoRenewalAgreement')} {restoring ? ( {t('membershipModal.actions.restoring')} ) : ( {t('membershipModal.actions.restore')} )} {/* 悬浮购买按钮 */} {isLiquidGlassAvailable() ? ( {loading ? ( {t('membershipModal.actions.processing')} ) : ( {t('membershipModal.actions.subscribe')} )} ) : ( {loading ? ( {t('membershipModal.actions.processing')} ) : ( {t('membershipModal.actions.subscribe')} )} )} ); } const styles = StyleSheet.create({ overlay: { flex: 1, justifyContent: 'flex-end', }, backdrop: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0, 0, 0, 0.35)', }, modalContainer: { height: height * 0.92, backgroundColor: '#F5F6FA', borderTopLeftRadius: 28, borderTopRightRadius: 28, overflow: 'hidden', }, modalContent: { flex: 1, }, modalContentContainer: { paddingHorizontal: 20, paddingBottom: 100, // 增加底部内边距,避免内容被悬浮按钮遮挡 paddingTop: 16, }, floatingBackButton: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, floatingBackButtonContainer: { position: 'absolute', top: 20, left: 20, zIndex: 10, // 确保按钮在最上层 }, fallbackBackButton: { backgroundColor: 'rgba(255, 255, 255, 0.9)', }, sectionCard: { backgroundColor: '#FFFFFF', borderRadius: 20, paddingHorizontal: 20, paddingVertical: 18, marginBottom: 20, shadowColor: '#1C1C1E', shadowOpacity: 0.06, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 2, }, sectionTitleRow: { flexDirection: 'row', alignItems: 'center', }, sectionTitleBadge: { width: 28, height: 28, borderRadius: 14, alignItems: 'center', justifyContent: 'center', backgroundColor: '#F4EFFD', marginRight: 8, }, sectionTitle: { fontSize: 18, fontWeight: '700', color: '#2B2B2E', fontFamily: 'AliBold', }, sectionSubtitle: { fontSize: 13, color: '#6B6B73', marginTop: 6, marginBottom: 16, fontFamily: 'AliRegular', }, configurationNotice: { borderRadius: 16, padding: 16, backgroundColor: '#FFF4E5', }, configurationText: { fontSize: 14, color: '#B86A04', textAlign: 'center', lineHeight: 20, fontFamily: 'AliRegular', }, plansContainer: { flexDirection: 'row', justifyContent: 'space-between', }, planCardWrapper: { flex: 1, marginHorizontal: 4, borderRadius: 18, overflow: 'hidden', borderWidth: 1, borderColor: 'rgba(123,44,191,0.08)', }, planCardWrapperSelected: { borderColor: '#7B2CBF', shadowColor: '#7B2CBF', shadowOpacity: 0.18, shadowRadius: 16, shadowOffset: { width: 0, height: 8 }, elevation: 4, }, planCardGradient: { flex: 1, paddingHorizontal: 16, paddingVertical: 18, minHeight: 170, justifyContent: 'space-between', }, planTag: { alignSelf: 'flex-start', backgroundColor: '#2F2F36', borderRadius: 14, paddingHorizontal: 6, paddingVertical: 6, marginBottom: 12, }, planTagText: { color: '#FFFFFF', fontSize: 10, fontWeight: '600', fontFamily: 'AliBold', }, planCardTitle: { fontSize: 16, fontWeight: '700', color: '#241F1F', fontFamily: 'AliBold', }, planCardPrice: { fontSize: 14, fontWeight: '700', marginTop: 12, fontFamily: 'AliBold', }, planCardOriginalPrice: { fontSize: 13, color: '#8E8EA1', textDecorationLine: 'line-through', marginTop: 2, fontFamily: 'AliRegular', }, planCardDescription: { fontSize: 12, color: '#6C6C77', lineHeight: 17, fontFamily: 'AliRegular', }, planCardTopSection: { flex: 1, justifyContent: 'flex-start', }, planCardMiddleSection: { flex: 1, justifyContent: 'center', alignItems: 'flex-start', }, planCardBottomSection: { flex: 1, justifyContent: 'flex-end', }, tipsContainer: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#FEF4E6', borderRadius: 14, paddingHorizontal: 12, paddingVertical: 10, marginTop: 16, }, tipsText: { flex: 1, fontSize: 12, color: '#9B6200', marginLeft: 6, lineHeight: 16, fontFamily: 'AliRegular', }, comparisonTable: { borderRadius: 16, overflow: 'hidden', borderWidth: 1, borderColor: '#ECECF3', }, tableRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 14, paddingHorizontal: 16, backgroundColor: '#FFFFFF', }, tableHeader: { backgroundColor: '#F8F8FF', }, tableHeaderText: { fontSize: 12, fontWeight: '600', color: '#575764', textTransform: 'uppercase', letterSpacing: 0.4, fontFamily: 'AliBold', }, tableCellText: { fontSize: 13, color: '#3E3E44', fontFamily: 'AliRegular', }, tableTitleCell: { flex: 1.5, justifyContent: 'center', }, tableVipCell: { flex: 0.8, alignItems: 'center', justifyContent: 'center', }, tableNormalCell: { flex: 0.8, alignItems: 'center', justifyContent: 'center', }, tableRowAlt: { backgroundColor: '#FBFBFF', }, bottomSection: { backgroundColor: '#FFFFFF', borderRadius: 20, paddingHorizontal: 20, paddingVertical: 20, marginBottom: 10, shadowColor: '#1C1C1E', shadowOpacity: 0.04, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 1, }, purchaseButton: { borderRadius: 28, height: 64, justifyContent: 'center', alignItems: 'center', overflow: 'hidden', }, purchaseButtonContent: { flex: 1, width: '100%', justifyContent: 'center', alignItems: 'center', }, floatingPurchaseContainer: { position: 'absolute', bottom: 34, // 底部安全区域 left: 20, right: 20, }, fallbackPurchaseButton: { backgroundColor: '#151515', }, disabledButton: { backgroundColor: '#C6C6C8', }, purchaseButtonText: { color: '#FFFFFF', fontSize: 18, fontWeight: '700', fontFamily: 'AliBold', }, loadingContainer: { flexDirection: 'row', alignItems: 'center', }, loadingSpinner: { marginRight: 8, }, agreementContainer: { flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'center', marginBottom: 20, paddingHorizontal: 4, }, checkboxWrapper: { marginTop: 2, // Align with text line-height marginRight: 8, }, agreementText: { flex: 1, fontSize: 11, lineHeight: 16, color: '#666672', fontFamily: 'AliRegular', }, agreementLink: { fontSize: 11, color: '#E91E63', fontWeight: '500', textDecorationLine: 'underline', fontFamily: 'AliBold', }, agreementSeparator: { fontSize: 11, color: '#A0A0B0', }, restoreButton: { alignSelf: 'center', paddingVertical: 6, }, restoreButtonText: { color: '#6F6F7A', fontSize: 12, fontWeight: '500', fontFamily: 'AliBold', }, disabledRestoreButton: { opacity: 0.5, }, restoreButtonContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, restoreButtonLoader: { marginRight: 8, }, disabledPlanCard: { opacity: 0.5, }, // 新增样式:权限相关 tableDescriptionText: { fontSize: 11, color: '#8E8E93', marginTop: 2, lineHeight: 14, fontFamily: 'AliRegular', }, permissionContainer: { alignItems: 'center', justifyContent: 'center', flexDirection: 'column', paddingVertical: 4, }, permissionText: { fontSize: 10, color: '#6B6B73', marginTop: 4, textAlign: 'center', lineHeight: 12, fontFamily: 'AliRegular', }, });