fix: 登录状态检查改为手动触发,避免自动请求不断弹出浏览器窗口
- useLoginStatus 默认 auto=false,不再挂载时自动请求 - Dashboard 登录状态卡片改为 "Click to check" 手动触发 - Login 页面初始显示 "Click Refresh to check" 提示 - Header 添加 Token 未配置警告横幅,引导用户去 Settings
This commit is contained in:
@@ -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'}>
|
||||||
|
|||||||
@@ -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 };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user