Initial commit

This commit is contained in:
2025-10-11 11:55:25 +08:00
parent 467dad8449
commit 8107dee8d3
2879 changed files with 610575 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
// src/hooks/useSubscription.js
import { useState, useEffect } from 'react';
import { useAuth } from '../contexts/AuthContext';
// 订阅级别映射
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) {
console.log('📋 从用户对象获取订阅信息:', user.subscription_type);
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调用失败回退到用户对象中的信息
console.log('📋 API失败使用用户对象中的订阅信息');
setSubscriptionInfo({
type: user.subscription_type || 'free',
status: 'active',
is_active: true,
days_left: user.subscription_days_left || 0
});
}
} catch (error) {
console.error('获取订阅信息失败:', error);
// 发生错误时,回退到用户对象中的信息
setSubscriptionInfo({
type: user.subscription_type || 'free',
status: 'active',
is_active: true,
days_left: user.subscription_days_left || 0
});
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchSubscriptionInfo();
}, [isAuthenticated, user]);
// 获取订阅级别数值
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') {
console.log(`🔓 Max用户直接解锁功能: ${featureName}`);
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
};
};