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 { useHealth } from '@/hooks/useHealth';
import { useAuth } from '@/context/AuthContext';
import { Badge } from '@/components/ui/Badge'; import { Badge } from '@/components/ui/Badge';
import { useNavigate } from 'react-router-dom';
export function Header() { export function Header() {
const { health } = useHealth(15_000); const { health } = useHealth(15_000);
const { token } = useAuth();
const navigate = useNavigate();
return ( return (
<header className="h-14 bg-dark-card border-b border-dark-border flex items-center justify-between px-6 shrink-0"> <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"> <div className="flex items-center gap-3">
{health && ( {health && (
<Badge variant={health.healthy ? 'success' : 'danger'}> <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 { getLoginStatus } from '@/api/endpoints';
import type { LoginStatus } from '@/api/types'; 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 [status, setStatus] = useState<LoginStatus | null>(null);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(auto);
const refresh = useCallback(async () => { const refresh = useCallback(async () => {
setLoading(true);
try { try {
const res = await getLoginStatus(); const res = await getLoginStatus();
if (res.success && res.data) { if (res.success && res.data) {
@@ -24,12 +26,13 @@ export function useLoginStatus(intervalMs = 0) {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!auto) return;
void refresh(); void refresh();
if (intervalMs > 0) { if (intervalMs > 0) {
const id = setInterval(() => void refresh(), intervalMs); const id = setInterval(() => void refresh(), intervalMs);
return () => clearInterval(id); return () => clearInterval(id);
} }
}, [refresh, intervalMs]); }, [refresh, auto, intervalMs]);
return { status, error, loading, refresh }; return { status, error, loading, refresh };
} }
+7 -2
View File
@@ -9,7 +9,7 @@ import { useNavigate } from 'react-router-dom';
export function DashboardPage() { export function DashboardPage() {
const { health, loading: healthLoading, refresh: refreshHealth } = useHealth(10_000); 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(); const navigate = useNavigate();
return ( return (
@@ -65,7 +65,12 @@ export function DashboardPage() {
)} )}
</div> </div>
) : ( ) : (
<Badge variant="warning">Unknown</Badge> <button
onClick={() => void refreshLogin()}
className="text-xs text-dark-accent hover:underline"
>
Click to check
</button>
)} )}
</Card> </Card>
+18 -1
View File
@@ -1,15 +1,19 @@
import { useState, useEffect, useCallback, useRef } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card } from '@/components/ui/Card'; import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button'; import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge'; import { Badge } from '@/components/ui/Badge';
import { Spinner } from '@/components/ui/Spinner'; import { Spinner } from '@/components/ui/Spinner';
import { useLoginStatus } from '@/hooks/useLoginStatus'; import { useLoginStatus } from '@/hooks/useLoginStatus';
import { useAuth } from '@/context/AuthContext';
import { useToast } from '@/context/ToastContext'; import { useToast } from '@/context/ToastContext';
import { getLoginQRCode, deleteCookies, getLoginStatus } from '@/api/endpoints'; import { getLoginQRCode, deleteCookies, getLoginStatus } from '@/api/endpoints';
export function LoginPage() { export function LoginPage() {
const { status, loading: statusLoading, refresh: refreshStatus } = useLoginStatus(); const { status, loading: statusLoading, refresh: refreshStatus } = useLoginStatus();
const { token } = useAuth();
const { toast } = useToast(); const { toast } = useToast();
const navigate = useNavigate();
const [qrData, setQrData] = useState<string | null>(null); const [qrData, setQrData] = useState<string | null>(null);
const [qrLoading, setQrLoading] = useState(false); const [qrLoading, setQrLoading] = useState(false);
@@ -107,6 +111,19 @@ export function LoginPage() {
<div className="max-w-2xl space-y-6"> <div className="max-w-2xl space-y-6">
<h1 className="text-2xl font-bold">Xiaohongshu Login</h1> <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 */} {/* Current Status */}
<Card> <Card>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@@ -124,7 +141,7 @@ export function LoginPage() {
{status.username && <span className="text-sm">{status.username}</span>} {status.username && <span className="text-sm">{status.username}</span>}
</div> </div>
) : ( ) : (
<Badge variant="danger">Unable to check</Badge> <span className="text-sm text-dark-muted">Click Refresh to check login status</span>
)} )}
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">