feat: 登陆状态调整
This commit is contained in:
@@ -11,7 +11,8 @@
|
|||||||
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/Automotive.js)",
|
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/Automotive.js)",
|
||||||
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/CRM.js)",
|
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/CRM.js)",
|
||||||
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/SmartHome.js)",
|
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/SmartHome.js)",
|
||||||
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/Landing.js)"
|
"Bash(rm /Users/qiye/Desktop/jzqy/vf_react/src/views/Dashboard/Landing.js)",
|
||||||
|
"mcp__ide__getDiagnostics"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ export default function HomeNavbar() {
|
|||||||
error: error.message
|
error: error.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [isAuthenticated, user]); // 移除 getApiBase 依赖,因为它现在在组件外部
|
}, [isAuthenticated, user?.id]); // 只依赖 user.id,避免 user 对象变化导致无限循环
|
||||||
|
|
||||||
// 监听用户变化,重置检查标志(用户切换或退出登录时)
|
// 监听用户变化,重置检查标志(用户切换或退出登录时)
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -622,7 +622,7 @@ export default function HomeNavbar() {
|
|||||||
const timer = setTimeout(checkProfileCompleteness, 1000);
|
const timer = setTimeout(checkProfileCompleteness, 1000);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}
|
}
|
||||||
}, [isAuthenticated, user, checkProfileCompleteness]);
|
}, [isAuthenticated, user?.id, checkProfileCompleteness]); // 只依赖 user.id,避免无限循环
|
||||||
|
|
||||||
// 加载订阅信息
|
// 加载订阅信息
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ import {
|
|||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { logger } from '../../utils/logger';
|
import { logger } from '../../utils/logger';
|
||||||
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
import {
|
import {
|
||||||
FaWeixin,
|
FaWeixin,
|
||||||
FaGem,
|
FaGem,
|
||||||
FaStar,
|
|
||||||
FaCheck,
|
FaCheck,
|
||||||
FaQrcode,
|
FaQrcode,
|
||||||
FaClock,
|
FaClock,
|
||||||
@@ -38,6 +38,9 @@ import {
|
|||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
|
|
||||||
export default function SubscriptionContent() {
|
export default function SubscriptionContent() {
|
||||||
|
// Auth context
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
// Chakra color mode
|
// Chakra color mode
|
||||||
const textColor = useColorModeValue('gray.700', 'white');
|
const textColor = useColorModeValue('gray.700', 'white');
|
||||||
const borderColor = useColorModeValue('gray.200', 'gray.600');
|
const borderColor = useColorModeValue('gray.200', 'gray.600');
|
||||||
@@ -50,7 +53,6 @@ export default function SubscriptionContent() {
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
|
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
|
||||||
const [currentUser, setCurrentUser] = useState(null);
|
|
||||||
const [selectedPlan, setSelectedPlan] = useState(null);
|
const [selectedPlan, setSelectedPlan] = useState(null);
|
||||||
const [selectedCycle, setSelectedCycle] = useState('monthly');
|
const [selectedCycle, setSelectedCycle] = useState('monthly');
|
||||||
const [paymentOrder, setPaymentOrder] = useState(null);
|
const [paymentOrder, setPaymentOrder] = useState(null);
|
||||||
@@ -63,7 +65,7 @@ export default function SubscriptionContent() {
|
|||||||
// 加载订阅套餐数据
|
// 加载订阅套餐数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchSubscriptionPlans();
|
fetchSubscriptionPlans();
|
||||||
fetchCurrentUser();
|
// 不再需要 fetchCurrentUser(),直接使用 AuthContext 的 user
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 倒计时更新
|
// 倒计时更新
|
||||||
@@ -124,30 +126,8 @@ export default function SubscriptionContent() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchCurrentUser = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/auth/session', {
|
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
if (response.ok) {
|
|
||||||
const data = await response.json();
|
|
||||||
logger.debug('SubscriptionContent', '用户数据获取成功', { data });
|
|
||||||
if (data.success) {
|
|
||||||
setCurrentUser(data.user);
|
|
||||||
logger.debug('SubscriptionContent', '用户信息已更新', {
|
|
||||||
userId: data.user?.id,
|
|
||||||
subscriptionType: data.user?.subscription_type,
|
|
||||||
subscriptionStatus: data.user?.subscription_status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('SubscriptionContent', 'fetchCurrentUser', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubscribe = (plan) => {
|
const handleSubscribe = (plan) => {
|
||||||
if (!currentUser) {
|
if (!user) {
|
||||||
toast({
|
toast({
|
||||||
title: '请先登录',
|
title: '请先登录',
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
@@ -287,25 +267,9 @@ export default function SubscriptionContent() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRefreshUserStatus = async () => {
|
const handleRefreshUserStatus = () => {
|
||||||
try {
|
// 刷新页面以重新加载用户数据
|
||||||
await fetchCurrentUser();
|
window.location.reload();
|
||||||
toast({
|
|
||||||
title: '用户状态已刷新',
|
|
||||||
description: '订阅信息已更新',
|
|
||||||
status: 'success',
|
|
||||||
duration: 3000,
|
|
||||||
isClosable: true,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
toast({
|
|
||||||
title: '刷新失败',
|
|
||||||
description: '请稍后重试',
|
|
||||||
status: 'error',
|
|
||||||
duration: 3000,
|
|
||||||
isClosable: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleForceUpdatePayment = async () => {
|
const handleForceUpdatePayment = async () => {
|
||||||
@@ -459,7 +423,7 @@ export default function SubscriptionContent() {
|
|||||||
return (
|
return (
|
||||||
<VStack spacing={6} align="stretch" w="100%">
|
<VStack spacing={6} align="stretch" w="100%">
|
||||||
{/* 当前订阅状态 */}
|
{/* 当前订阅状态 */}
|
||||||
{currentUser && (
|
{user && (
|
||||||
<Box
|
<Box
|
||||||
p={6}
|
p={6}
|
||||||
borderRadius="xl"
|
borderRadius="xl"
|
||||||
@@ -487,8 +451,8 @@ export default function SubscriptionContent() {
|
|||||||
<HStack spacing={2} mb={2}>
|
<HStack spacing={2} mb={2}>
|
||||||
<Badge
|
<Badge
|
||||||
colorScheme={
|
colorScheme={
|
||||||
currentUser.subscription_type === 'max' ? 'purple' :
|
user.subscription_type === 'max' ? 'purple' :
|
||||||
currentUser.subscription_type === 'pro' ? 'blue' : 'gray'
|
user.subscription_type === 'pro' ? 'blue' : 'gray'
|
||||||
}
|
}
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
px={3}
|
px={3}
|
||||||
@@ -496,29 +460,30 @@ export default function SubscriptionContent() {
|
|||||||
borderRadius="full"
|
borderRadius="full"
|
||||||
fontSize="sm"
|
fontSize="sm"
|
||||||
>
|
>
|
||||||
{currentUser.subscription_type === 'free' ? '基础版' :
|
1SubscriptionContent {user.subscription_type}
|
||||||
currentUser.subscription_type === 'pro' ? 'Pro 专业版' : 'Max 旗舰版'}
|
{user.subscription_type === 'free' ? '基础版' :
|
||||||
|
user.subscription_type === 'pro' ? 'Pro 专业版' : 'Max 旗舰版'}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge
|
<Badge
|
||||||
colorScheme={currentUser.subscription_status === 'active' ? 'green' : 'red'}
|
colorScheme={user.subscription_status === 'active' ? 'green' : 'red'}
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
px={3}
|
px={3}
|
||||||
py={1}
|
py={1}
|
||||||
borderRadius="full"
|
borderRadius="full"
|
||||||
>
|
>
|
||||||
{currentUser.subscription_status === 'active' ? '已激活' : '未激活'}
|
{user.subscription_status === 'active' ? '已激活' : '未激活'}
|
||||||
</Badge>
|
</Badge>
|
||||||
</HStack>
|
</HStack>
|
||||||
{currentUser.subscription_end_date && (
|
{user.subscription_end_date && (
|
||||||
<Text fontSize="sm" color={secondaryText}>
|
<Text fontSize="sm" color={secondaryText}>
|
||||||
到期时间: {new Date(currentUser.subscription_end_date).toLocaleDateString('zh-CN')}
|
到期时间: {new Date(user.subscription_end_date).toLocaleDateString('zh-CN')}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{currentUser.subscription_status === 'active' && currentUser.subscription_type !== 'free' && (
|
{user.subscription_status === 'active' && user.subscription_type !== 'free' && (
|
||||||
<Icon
|
<Icon
|
||||||
as={currentUser.subscription_type === 'max' ? FaCrown : FaGem}
|
as={user.subscription_type === 'max' ? FaCrown : FaGem}
|
||||||
color={currentUser.subscription_type === 'max' ? 'purple.400' : 'blue.400'}
|
color={user.subscription_type === 'max' ? 'purple.400' : 'blue.400'}
|
||||||
boxSize={8}
|
boxSize={8}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -665,16 +630,16 @@ export default function SubscriptionContent() {
|
|||||||
variant="solid"
|
variant="solid"
|
||||||
onClick={() => handleSubscribe(plan)}
|
onClick={() => handleSubscribe(plan)}
|
||||||
isDisabled={
|
isDisabled={
|
||||||
currentUser?.subscription_type === plan.name &&
|
user?.subscription_type === plan.name &&
|
||||||
currentUser?.subscription_status === 'active'
|
user?.subscription_status === 'active'
|
||||||
}
|
}
|
||||||
_hover={{
|
_hover={{
|
||||||
transform: 'scale(1.02)',
|
transform: 'scale(1.02)',
|
||||||
}}
|
}}
|
||||||
transition="all 0.2s"
|
transition="all 0.2s"
|
||||||
>
|
>
|
||||||
{currentUser?.subscription_type === plan.name &&
|
{user?.subscription_type === plan.name &&
|
||||||
currentUser?.subscription_status === 'active'
|
user?.subscription_status === 'active'
|
||||||
? '✓ 已订阅'
|
? '✓ 已订阅'
|
||||||
: `选择 ${plan.display_name}`
|
: `选择 ${plan.display_name}`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,8 @@ export const useSubscription = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchSubscriptionInfo();
|
fetchSubscriptionInfo();
|
||||||
}, [isAuthenticated, user]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isAuthenticated, user?.id]); // 只依赖 user.id,避免 user 对象变化导致无限循环
|
||||||
|
|
||||||
// 获取订阅级别数值
|
// 获取订阅级别数值
|
||||||
const getSubscriptionLevel = (type = null) => {
|
const getSubscriptionLevel = (type = null) => {
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export default function CenterDashboard() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [user]);
|
}, [user?.id]); // 只依赖 user.id,避免无限循环
|
||||||
|
|
||||||
// 加载实时行情
|
// 加载实时行情
|
||||||
const loadRealtimeQuotes = useCallback(async () => {
|
const loadRealtimeQuotes = useCallback(async () => {
|
||||||
@@ -198,7 +198,7 @@ export default function CenterDashboard() {
|
|||||||
};
|
};
|
||||||
document.addEventListener('visibilitychange', onVis);
|
document.addEventListener('visibilitychange', onVis);
|
||||||
return () => document.removeEventListener('visibilitychange', onVis);
|
return () => document.removeEventListener('visibilitychange', onVis);
|
||||||
}, [user, location.pathname, loadData]);
|
}, [user?.id, location.pathname, loadData]); // 只依赖 user.id,避免无限循环
|
||||||
|
|
||||||
// 定时刷新实时行情(每分钟一次)
|
// 定时刷新实时行情(每分钟一次)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export default function HomePage() {
|
|||||||
nickname: user.nickname
|
nickname: user.nickname
|
||||||
} : null
|
} : null
|
||||||
});
|
});
|
||||||
}, [user, isAuthenticated, isLoading]);
|
}, [user?.id, isAuthenticated, isLoading]); // 只依赖 user.id,避免无限循环
|
||||||
|
|
||||||
// 统计数据动画
|
// 统计数据动画
|
||||||
const [stats, setStats] = useState({
|
const [stats, setStats] = useState({
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function HomePage() {
|
|||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
hasUser: !!user
|
hasUser: !!user
|
||||||
});
|
});
|
||||||
}, [user, isAuthenticated]);
|
}, [user?.id, isAuthenticated]); // 只依赖 user.id,避免无限循环
|
||||||
|
|
||||||
// 核心功能配置 - 5个主要功能
|
// 核心功能配置 - 5个主要功能
|
||||||
const coreFeatures = [
|
const coreFeatures = [
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default function TradingSimulation() {
|
|||||||
userId: user?.id,
|
userId: user?.id,
|
||||||
userName: user?.name
|
userName: user?.name
|
||||||
});
|
});
|
||||||
}, [isAuthenticated, user]);
|
}, [isAuthenticated, user?.id]); // 只依赖 user.id,避免无限循环
|
||||||
|
|
||||||
// 获取资产历史数据的 useEffect
|
// 获取资产历史数据的 useEffect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user