fix: 登录状态检查改为手动触发,避免自动请求不断弹出浏览器窗口

- useLoginStatus 默认 auto=false,不再挂载时自动请求
- Dashboard 登录状态卡片改为 "Click to check" 手动触发
- Login 页面初始显示 "Click Refresh to check" 提示
- Header 添加 Token 未配置警告横幅,引导用户去 Settings
This commit is contained in:
2026-03-01 14:51:17 +08:00
parent 31329905e2
commit f464333a53
4 changed files with 49 additions and 7 deletions
+18 -1
View File
@@ -1,12 +1,29 @@
import { useHealth } from '@/hooks/useHealth';
import { useAuth } from '@/context/AuthContext';
import { Badge } from '@/components/ui/Badge';
import { useNavigate } from 'react-router-dom';
export function Header() {
const { health } = useHealth(15_000);
const { token } = useAuth();
const navigate = useNavigate();
return (
<header className="h-14 bg-dark-card border-b border-dark-border flex items-center justify-between px-6 shrink-0">
<div />
<div>
{!token && (
<button
onClick={() => navigate('/settings')}
className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-dark-warning/15 border border-dark-warning/30 text-dark-warning text-xs font-medium hover:bg-dark-warning/25 transition-colors"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
<line x1="12" y1="9" x2="12" y2="13" /><line x1="12" y1="17" x2="12.01" y2="17" />
</svg>
Token Settings
</button>
)}
</div>
<div className="flex items-center gap-3">
{health && (
<Badge variant={health.healthy ? 'success' : 'danger'}>
+6 -3
View File
@@ -2,12 +2,14 @@ import { useState, useEffect, useCallback } from 'react';
import { getLoginStatus } from '@/api/endpoints';
import type { LoginStatus } from '@/api/types';
export function useLoginStatus(intervalMs = 0) {
export function useLoginStatus(options: { auto?: boolean; intervalMs?: number } = {}) {
const { auto = false, intervalMs = 0 } = options;
const [status, setStatus] = useState<LoginStatus | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [loading, setLoading] = useState(auto);
const refresh = useCallback(async () => {
setLoading(true);
try {
const res = await getLoginStatus();
if (res.success && res.data) {
@@ -24,12 +26,13 @@ export function useLoginStatus(intervalMs = 0) {
}, []);
useEffect(() => {
if (!auto) return;
void refresh();
if (intervalMs > 0) {
const id = setInterval(() => void refresh(), intervalMs);
return () => clearInterval(id);
}
}, [refresh, intervalMs]);
}, [refresh, auto, intervalMs]);
return { status, error, loading, refresh };
}
+7 -2
View File
@@ -9,7 +9,7 @@ import { useNavigate } from 'react-router-dom';
export function DashboardPage() {
const { health, loading: healthLoading, refresh: refreshHealth } = useHealth(10_000);
const { status: loginStatus, loading: loginLoading } = useLoginStatus();
const { status: loginStatus, loading: loginLoading, refresh: refreshLogin } = useLoginStatus();
const navigate = useNavigate();
return (
@@ -65,7 +65,12 @@ export function DashboardPage() {
)}
</div>
) : (
<Badge variant="warning">Unknown</Badge>
<button
onClick={() => void refreshLogin()}
className="text-xs text-dark-accent hover:underline"
>
Click to check
</button>
)}
</Card>
+18 -1
View File
@@ -1,15 +1,19 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { Spinner } from '@/components/ui/Spinner';
import { useLoginStatus } from '@/hooks/useLoginStatus';
import { useAuth } from '@/context/AuthContext';
import { useToast } from '@/context/ToastContext';
import { getLoginQRCode, deleteCookies, getLoginStatus } from '@/api/endpoints';
export function LoginPage() {
const { status, loading: statusLoading, refresh: refreshStatus } = useLoginStatus();
const { token } = useAuth();
const { toast } = useToast();
const navigate = useNavigate();
const [qrData, setQrData] = useState<string | null>(null);
const [qrLoading, setQrLoading] = useState(false);
@@ -107,6 +111,19 @@ export function LoginPage() {
<div className="max-w-2xl space-y-6">
<h1 className="text-2xl font-bold">Xiaohongshu Login</h1>
{!token && (
<Card className="border-dark-warning/30 bg-dark-warning/10">
<div className="flex items-center justify-between">
<p className="text-sm text-dark-warning">
Bearer Token API 401 Settings Token
</p>
<Button size="sm" variant="secondary" onClick={() => navigate('/settings')}>
Settings
</Button>
</div>
</Card>
)}
{/* Current Status */}
<Card>
<div className="flex items-center justify-between">
@@ -124,7 +141,7 @@ export function LoginPage() {
{status.username && <span className="text-sm">{status.username}</span>}
</div>
) : (
<Badge variant="danger">Unable to check</Badge>
<span className="text-sm text-dark-muted">Click Refresh to check login status</span>
)}
</div>
<div className="flex gap-2">