// src/hooks/useSubscription.js import { useState, useEffect, useRef } from 'react'; import { useAuth } from '../contexts/AuthContext'; import { logger } from '../utils/logger'; // 订阅级别映射 const SUBSCRIPTION_LEVELS = { free: 0, pro: 1, max: 2 }; // 功能权限映射 const FEATURE_REQUIREMENTS = { 'related_stocks': 'pro', // 相关标的 'related_concepts': 'pro', // 相关概念 'transmission_chain': 'max', // 事件传导链分析 'historical_events_full': 'pro', // 历史事件对比(完整版) 'concept_html_detail': 'pro', // 概念HTML具体内容 'concept_stats_panel': 'pro', // 概念统计中心 'concept_related_stocks': 'pro', // 概念相关股票 'concept_timeline': 'max', // 概念历史时间轴 'hot_stocks': 'pro' // 热门个股 }; export const useSubscription = () => { const { user, isAuthenticated } = useAuth(); const [subscriptionInfo, setSubscriptionInfo] = useState({ type: 'free', status: 'active', is_active: true, days_left: 0 }); const [loading, setLoading] = useState(false); // 获取订阅信息 const fetchSubscriptionInfo = async () => { if (!isAuthenticated || !user) { setSubscriptionInfo({ type: 'free', status: 'active', is_active: true, days_left: 0 }); return; } // 首先检查用户对象中是否已经包含订阅信息 if (user.subscription_type) { logger.debug('useSubscription', '从用户对象获取订阅信息', { subscriptionType: user.subscription_type, daysLeft: user.subscription_days_left }); setSubscriptionInfo({ type: user.subscription_type, status: 'active', is_active: true, days_left: user.subscription_days_left || 0 }); return; } try { setLoading(true); const response = await fetch('/api/subscription/info', { method: 'GET', credentials: 'include', headers: { 'Content-Type': 'application/json', } }); if (response.ok) { const data = await response.json(); if (data.success) { setSubscriptionInfo(data.data); } } else { // 如果API调用失败,回退到用户对象中的信息 logger.warn('useSubscription', 'API调用失败,使用用户对象订阅信息', { status: response.status, fallbackType: user.subscription_type || 'free' }); setSubscriptionInfo({ type: user.subscription_type || 'free', status: 'active', is_active: true, days_left: user.subscription_days_left || 0 }); } } catch (error) { logger.error('useSubscription', 'fetchSubscriptionInfo', error, { userId: user?.id }); // 发生错误时,回退到用户对象中的信息 setSubscriptionInfo({ type: user.subscription_type || 'free', status: 'active', is_active: true, days_left: user.subscription_days_left || 0 }); } finally { setLoading(false); } }; // ⚡ 提取 userId 为独立变量,避免 user 对象引用变化导致无限循环 const userId = user?.id; const prevUserIdRef = useRef(userId); const prevIsAuthenticatedRef = useRef(isAuthenticated); useEffect(() => { // ⚡ 只在 userId 或 isAuthenticated 真正变化时才请求 const userIdChanged = prevUserIdRef.current !== userId; const authChanged = prevIsAuthenticatedRef.current !== isAuthenticated; if (userIdChanged || authChanged) { logger.debug('useSubscription', 'fetchSubscriptionInfo 触发', { userIdChanged, authChanged, prevUserId: prevUserIdRef.current, currentUserId: userId, prevAuth: prevIsAuthenticatedRef.current, currentAuth: isAuthenticated }); prevUserIdRef.current = userId; prevIsAuthenticatedRef.current = isAuthenticated; fetchSubscriptionInfo(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isAuthenticated, userId]); // 使用 userId 原始值,而不是 user?.id 表达式 // 获取订阅级别数值 const getSubscriptionLevel = (type = null) => { const subType = (type || subscriptionInfo.type || 'free').toLowerCase(); return SUBSCRIPTION_LEVELS[subType] || 0; }; // 检查是否有指定功能的权限 const hasFeatureAccess = (featureName) => { // 临时调试:如果用户对象中有max权限,直接解锁所有功能 if (user?.subscription_type === 'max') { logger.debug('useSubscription', 'Max用户解锁功能', { featureName, userId: user?.id }); return true; } if (!subscriptionInfo.is_active) { return false; } const requiredLevel = FEATURE_REQUIREMENTS[featureName]; if (!requiredLevel) { return true; // 如果功能不需要特定权限,默认允许 } const currentLevel = getSubscriptionLevel(); const requiredLevelNum = getSubscriptionLevel(requiredLevel); return currentLevel >= requiredLevelNum; }; // 检查是否达到指定订阅级别 const hasSubscriptionLevel = (requiredLevel) => { if (!subscriptionInfo.is_active) { return false; } const currentLevel = getSubscriptionLevel(); const requiredLevelNum = getSubscriptionLevel(requiredLevel); return currentLevel >= requiredLevelNum; }; // 获取功能所需的订阅级别 const getRequiredLevel = (featureName) => { return FEATURE_REQUIREMENTS[featureName] || 'free'; }; // 获取订阅状态文本 const getSubscriptionStatusText = () => { const type = subscriptionInfo.type || 'free'; switch (type.toLowerCase()) { case 'free': return '免费版'; case 'pro': return 'Pro版'; case 'max': return 'Max版'; default: return '未知'; } }; // 获取升级建议 const getUpgradeRecommendation = (featureName) => { const requiredLevel = getRequiredLevel(featureName); const currentType = subscriptionInfo.type || 'free'; if (hasFeatureAccess(featureName)) { return null; } return { current: currentType, required: requiredLevel, message: `此功能需要${requiredLevel === 'pro' ? 'Pro版' : 'Max版'}订阅` }; }; return { subscriptionInfo, loading, hasFeatureAccess, hasSubscriptionLevel, getRequiredLevel, getSubscriptionStatusText, getUpgradeRecommendation, refreshSubscription: fetchSubscriptionInfo }; };