feat: 添加mock数据,给导航添加选中标识
This commit is contained in:
@@ -446,10 +446,10 @@ export default function AuthFormContent() {
|
||||
<AlertDialogOverlay>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader fontSize="lg" fontWeight="bold">完善个人信息</AlertDialogHeader>
|
||||
<AlertDialogBody>您已成功注册!是否前往个人中心设置昵称和其他信息?</AlertDialogBody>
|
||||
<AlertDialogBody>您已成功注册!是否前往个人资料设置昵称和其他信息?</AlertDialogBody>
|
||||
<AlertDialogFooter>
|
||||
<Button ref={cancelRef} onClick={() => { setShowNicknamePrompt(false); handleLoginSuccess({ phone: currentPhone }); }}>稍后再说</Button>
|
||||
<Button colorScheme="green" onClick={() => { setShowNicknamePrompt(false); handleLoginSuccess({ phone: currentPhone }); setTimeout(() => { navigate('/admin/profile'); }, 300); }} ml={3}>去设置</Button>
|
||||
<Button colorScheme="green" onClick={() => { setShowNicknamePrompt(false); handleLoginSuccess({ phone: currentPhone }); setTimeout(() => { navigate('/home/profile'); }, 300); }} ml={3}>去设置</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogOverlay>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { FormControl, FormErrorMessage, HStack, Input, Button } from "@chakra-ui/react";
|
||||
import { FormControl, FormErrorMessage, HStack, Input, Button, Spinner } from "@chakra-ui/react";
|
||||
|
||||
/**
|
||||
* 通用验证码输入组件
|
||||
@@ -30,6 +30,17 @@ export default function VerificationCodeInput({
|
||||
}
|
||||
};
|
||||
|
||||
// 计算按钮显示的文本(避免在 JSX 中使用条件渲染)
|
||||
const getButtonText = () => {
|
||||
if (isSending) {
|
||||
return "发送中";
|
||||
}
|
||||
if (countdown > 0) {
|
||||
return countdownText(countdown);
|
||||
}
|
||||
return buttonText;
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl isRequired={isRequired} isInvalid={!!error}>
|
||||
<HStack>
|
||||
@@ -41,13 +52,14 @@ export default function VerificationCodeInput({
|
||||
maxLength={6}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
colorScheme={colorScheme}
|
||||
onClick={handleSendCode}
|
||||
isDisabled={countdown > 0 || isLoading}
|
||||
isLoading={isSending}
|
||||
isDisabled={countdown > 0 || isLoading || isSending}
|
||||
minW="120px"
|
||||
leftIcon={isSending ? <Spinner size="sm" /> : undefined}
|
||||
>
|
||||
{countdown > 0 ? countdownText(countdown) : buttonText}
|
||||
{getButtonText()}
|
||||
</Button>
|
||||
</HStack>
|
||||
<FormErrorMessage>{error}</FormErrorMessage>
|
||||
|
||||
@@ -17,10 +17,25 @@ class ErrorBoundary extends React.Component {
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
// 开发环境:不拦截错误,让 React DevTools 显示完整堆栈
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return { hasError: false };
|
||||
}
|
||||
// 生产环境:拦截错误,显示友好界面
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
// 开发环境:打印错误到控制台,但不显示错误边界
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error('🔴 ErrorBoundary 捕获到错误(开发模式,不拦截):');
|
||||
console.error('错误:', error);
|
||||
console.error('错误信息:', errorInfo);
|
||||
// 不更新 state,让错误继续抛出
|
||||
return;
|
||||
}
|
||||
|
||||
// 生产环境:保存错误信息到 state
|
||||
this.setState({
|
||||
error: error,
|
||||
errorInfo: errorInfo
|
||||
@@ -28,6 +43,12 @@ class ErrorBoundary extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
// 开发环境:直接渲染子组件,不显示错误边界
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return this.props.children;
|
||||
}
|
||||
|
||||
// 生产环境:如果有错误,显示错误边界
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<Container maxW="lg" py={20}>
|
||||
@@ -57,7 +78,7 @@ class ErrorBoundary extends React.Component {
|
||||
<Box fontWeight="bold" mb={2}>错误详情:</Box>
|
||||
<Box as="pre" whiteSpace="pre-wrap">
|
||||
{this.state.error && this.state.error.toString()}
|
||||
{this.state.errorInfo.componentStack}
|
||||
{this.state.errorInfo && this.state.errorInfo.componentStack}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -238,6 +238,9 @@ const NavItems = ({ isAuthenticated, user }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 计算 API 基础地址(移到组件外部,避免每次 render 重新创建)
|
||||
const getApiBase = () => (process.env.NODE_ENV === 'production' ? '' : (process.env.REACT_APP_API_URL || 'http://49.232.185.254:5001'));
|
||||
|
||||
export default function HomeNavbar() {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const navigate = useNavigate();
|
||||
@@ -269,6 +272,10 @@ export default function HomeNavbar() {
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await logout();
|
||||
// 重置资料完整性检查标志
|
||||
hasCheckedCompleteness.current = false;
|
||||
setProfileCompleteness(null);
|
||||
setShowCompletenessAlert(false);
|
||||
// logout函数已经包含了跳转逻辑,这里不需要额外处理
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
@@ -293,13 +300,13 @@ export default function HomeNavbar() {
|
||||
const [profileCompleteness, setProfileCompleteness] = useState(null);
|
||||
const [showCompletenessAlert, setShowCompletenessAlert] = useState(false);
|
||||
|
||||
// 计算 API 基础地址(与 Center.js 一致的策略)
|
||||
const getApiBase = () => (process.env.NODE_ENV === 'production' ? '' : (process.env.REACT_APP_API_URL || 'http://49.232.185.254:5001'));
|
||||
// 添加标志位:追踪是否已经检查过资料完整性(避免重复请求)
|
||||
const hasCheckedCompleteness = React.useRef(false);
|
||||
|
||||
const loadWatchlistQuotes = useCallback(async () => {
|
||||
try {
|
||||
setWatchlistLoading(true);
|
||||
const base = getApiBase();
|
||||
const base = getApiBase(); // 使用外部函数
|
||||
const resp = await fetch(base + '/api/account/watchlist/realtime', {
|
||||
credentials: 'include',
|
||||
cache: 'no-store',
|
||||
@@ -321,7 +328,7 @@ export default function HomeNavbar() {
|
||||
} finally {
|
||||
setWatchlistLoading(false);
|
||||
}
|
||||
}, []);
|
||||
}, []); // getApiBase 是外部函数,不需要作为依赖
|
||||
|
||||
const loadFollowingEvents = useCallback(async () => {
|
||||
try {
|
||||
@@ -369,7 +376,7 @@ export default function HomeNavbar() {
|
||||
} finally {
|
||||
setEventsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
}, []); // getApiBase 是外部函数,不需要作为依赖
|
||||
|
||||
// 从自选股移除
|
||||
const handleRemoveFromWatchlist = useCallback(async (stockCode) => {
|
||||
@@ -399,7 +406,7 @@ export default function HomeNavbar() {
|
||||
} catch (e) {
|
||||
toast({ title: '网络错误,移除失败', status: 'error', duration: 2000 });
|
||||
}
|
||||
}, [getApiBase, toast, WATCHLIST_PAGE_SIZE]);
|
||||
}, [toast]); // WATCHLIST_PAGE_SIZE 是常量,getApiBase 是外部函数,不需要作为依赖
|
||||
|
||||
// 取消关注事件
|
||||
const handleUnfollowEvent = useCallback(async (eventId) => {
|
||||
@@ -424,13 +431,20 @@ export default function HomeNavbar() {
|
||||
} catch (e) {
|
||||
toast({ title: '网络错误,操作失败', status: 'error', duration: 2000 });
|
||||
}
|
||||
}, [getApiBase, toast, EVENTS_PAGE_SIZE]);
|
||||
}, [toast]); // EVENTS_PAGE_SIZE 是常量,getApiBase 是外部函数,不需要作为依赖
|
||||
|
||||
// 检查用户资料完整性
|
||||
const checkProfileCompleteness = useCallback(async () => {
|
||||
if (!isAuthenticated || !user) return;
|
||||
|
||||
// 如果已经检查过,跳过(避免重复请求)
|
||||
if (hasCheckedCompleteness.current) {
|
||||
console.log('[Profile] 已检查过资料完整性,跳过重复请求');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[Profile] 开始检查资料完整性...');
|
||||
const base = getApiBase();
|
||||
const resp = await fetch(base + '/api/account/profile-completeness', {
|
||||
credentials: 'include'
|
||||
@@ -442,12 +456,25 @@ export default function HomeNavbar() {
|
||||
setProfileCompleteness(data.data);
|
||||
// 只有微信用户且资料不完整时才显示提醒
|
||||
setShowCompletenessAlert(data.data.needsAttention);
|
||||
// 标记为已检查
|
||||
hasCheckedCompleteness.current = true;
|
||||
console.log('[Profile] 资料完整性检查完成:', data.data);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('检查资料完整性失败:', error);
|
||||
}
|
||||
}, [isAuthenticated, user, getApiBase]);
|
||||
}, [isAuthenticated, user]); // 移除 getApiBase 依赖,因为它现在在组件外部
|
||||
|
||||
// 监听用户变化,重置检查标志(用户切换或退出登录时)
|
||||
React.useEffect(() => {
|
||||
if (!isAuthenticated || !user) {
|
||||
// 用户退出登录,重置标志
|
||||
hasCheckedCompleteness.current = false;
|
||||
setProfileCompleteness(null);
|
||||
setShowCompletenessAlert(false);
|
||||
}
|
||||
}, [isAuthenticated, user?.id]); // 监听用户 ID 变化
|
||||
|
||||
// 用户登录后检查资料完整性
|
||||
React.useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user