feat(vip): 实现VIP服务权限控制和食物识别功能限制
- 添加VIP服务权限检查hook,支持免费使用次数限制 - 为食物识别功能添加登录验证和VIP权限检查 - 优化RevenueCat用户标识同步逻辑 - 修复会员购买状态检查的类型安全问题 - 为营养成分分析添加登录验证
This commit is contained in:
@@ -72,6 +72,23 @@ const DEFAULT_PLANS: MembershipPlan[] = [
|
||||
},
|
||||
];
|
||||
|
||||
// RevenueCat 在 JS SDK 中以 string[] 返回 activeSubscriptions,但保持健壮性以防类型变化
|
||||
const getActiveSubscriptionIds = (customerInfo: CustomerInfo): string[] => {
|
||||
const activeSubscriptions = customerInfo.activeSubscriptions as unknown;
|
||||
|
||||
if (Array.isArray(activeSubscriptions)) {
|
||||
return activeSubscriptions;
|
||||
}
|
||||
|
||||
if (activeSubscriptions && typeof activeSubscriptions === 'object') {
|
||||
return Object.values(activeSubscriptions as Record<string, string>).filter(
|
||||
(value): value is string => typeof value === 'string'
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// 权限类型枚举
|
||||
type PermissionType = 'exclusive' | 'limited' | 'unlimited';
|
||||
|
||||
@@ -356,10 +373,11 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
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 = Object.keys(customerInfo.activeSubscriptions).length > 0;
|
||||
const hasActiveSubscriptions = activeSubscriptionIds.length > 0;
|
||||
|
||||
if (hasActiveEntitlements || hasNonSubscriptionTransactions || hasActiveSubscriptions) {
|
||||
capturePurchaseEvent('success', '监听到购买状态变化', {
|
||||
@@ -368,7 +386,7 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
hasActiveSubscriptions,
|
||||
activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length,
|
||||
nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length,
|
||||
activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length,
|
||||
activeSubscriptionsCount: activeSubscriptionIds.length,
|
||||
modalVisible: visible
|
||||
});
|
||||
|
||||
@@ -424,10 +442,12 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
log.info('获取用户购买信息', { customerInfo });
|
||||
|
||||
// 记录详细的购买状态日志
|
||||
const activeSubscriptionIds = getActiveSubscriptionIds(customerInfo);
|
||||
|
||||
captureMessageWithContext('获取用户购买信息成功', {
|
||||
activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length,
|
||||
nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length,
|
||||
activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length,
|
||||
activeSubscriptionsCount: activeSubscriptionIds.length,
|
||||
originalAppUserId: customerInfo.originalAppUserId,
|
||||
firstSeen: customerInfo.firstSeen,
|
||||
originalPurchaseDate: customerInfo.originalPurchaseDate,
|
||||
@@ -451,7 +471,7 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
});
|
||||
|
||||
// 检查订阅
|
||||
Object.keys(customerInfo.activeSubscriptions).forEach(productId => {
|
||||
activeSubscriptionIds.forEach(productId => {
|
||||
activePurchasedProductIds.push(productId);
|
||||
log.debug(`激活的订阅: ${productId}`);
|
||||
});
|
||||
@@ -517,7 +537,7 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
captureMessageWithContext('用户没有激活的购买记录', {
|
||||
hasEntitlements: Object.keys(customerInfo.entitlements.active).length > 0,
|
||||
hasNonSubscriptions: customerInfo.nonSubscriptionTransactions.length > 0,
|
||||
hasActiveSubscriptions: Object.keys(customerInfo.activeSubscriptions).length > 0
|
||||
hasActiveSubscriptions: activeSubscriptionIds.length > 0
|
||||
});
|
||||
log.info('用户没有激活的购买记录,使用默认选择逻辑');
|
||||
setSelectedProduct(availableProducts[0] ?? null);
|
||||
@@ -611,13 +631,14 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
|
||||
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: Object.keys(customerInfo.activeSubscriptions).length
|
||||
activeSubscriptionsCount: activeSubscriptionIds.length
|
||||
});
|
||||
|
||||
// 购买成功后,监听器会自动处理后续逻辑(刷新用户信息、关闭弹窗等)
|
||||
@@ -687,10 +708,11 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
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: Object.keys(customerInfo.activeSubscriptions).length,
|
||||
activeSubscriptionsCount: activeSubscriptionIds.length,
|
||||
managementUrl: customerInfo.managementURL,
|
||||
originalAppUserId: customerInfo.originalAppUserId
|
||||
});
|
||||
@@ -698,7 +720,7 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
// 检查是否有有效的购买记录
|
||||
const hasActiveEntitlements = Object.keys(customerInfo.entitlements.active).length > 0;
|
||||
const hasNonSubscriptionTransactions = customerInfo.nonSubscriptionTransactions.length > 0;
|
||||
const hasActiveSubscriptions = Object.keys(customerInfo.activeSubscriptions).length > 0;
|
||||
const hasActiveSubscriptions = activeSubscriptionIds.length > 0;
|
||||
|
||||
if (hasActiveEntitlements || hasNonSubscriptionTransactions || hasActiveSubscriptions) {
|
||||
// 检查具体的购买内容
|
||||
@@ -716,7 +738,7 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
});
|
||||
|
||||
// 检查订阅
|
||||
Object.keys(customerInfo.activeSubscriptions).forEach(productId => {
|
||||
activeSubscriptionIds.forEach(productId => {
|
||||
restoredProducts.push(productId);
|
||||
});
|
||||
|
||||
@@ -787,7 +809,7 @@ export function MembershipModal({ visible, onClose, onPurchaseSuccess }: Members
|
||||
hasActiveSubscriptions,
|
||||
activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length,
|
||||
nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length,
|
||||
activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length
|
||||
activeSubscriptionsCount: activeSubscriptionIds.length
|
||||
});
|
||||
GlobalToast.show({
|
||||
message: '没有找到购买记录',
|
||||
|
||||
Reference in New Issue
Block a user