Files
beaver_project/app-instance/frontend/components/AuthGuard.tsx
steven_li 8aeb97a5fc feat(app): 移除内置agents并添加CORS支持和技能上传优化
移除了agents/registry.json中的所有内置agents配置,将agents数组清空。
为web应用添加了CORS中间件支持,允许指定的前端地址跨域访问。
重构了技能上传功能,增加了LLM重写机制,自动规范化上传的技能格式。
新增了工具名称提取逻辑,从技能正文中自动识别Required Tools段落。
更新了技能学习候选者和草稿的载荷结构,添加评估报告统计信息。
修改了意图路由技能的说明,改进任务状态管理逻辑。
2026-06-12 13:25:20 +08:00

116 lines
3.0 KiB
TypeScript

'use client';
import { useEffect } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { buildAuthPortalUrl } from '@/lib/auth-portal';
import { AUTH_CLEARED_EVENT, clearTokens, getMe, isLoggedIn } from '@/lib/api';
import { pickAppText } from '@/lib/i18n/core';
import { useAppI18n } from '@/lib/i18n/provider';
import { useChatStore } from '@/lib/store';
export default function AuthGuard({
children,
minHeightClassName = 'min-h-[calc(100vh-3.5rem)]',
}: {
children: React.ReactNode;
minHeightClassName?: string;
}) {
const { locale } = useAppI18n();
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const user = useChatStore((s) => s.user);
const setUser = useChatStore((s) => s.setUser);
const setIsAuthLoading = useChatStore((s) => s.setIsAuthLoading);
const isAuthLoading = useChatStore((s) => s.isAuthLoading);
useEffect(() => {
let cancelled = false;
const init = async () => {
if (!isLoggedIn()) {
setUser(null);
if (!cancelled) {
setIsAuthLoading(false);
}
return;
}
if (useChatStore.getState().user) {
if (!cancelled) {
setIsAuthLoading(false);
}
return;
}
setIsAuthLoading(true);
try {
const me = await getMe();
if (cancelled) return;
setUser(me);
} catch {
clearTokens();
if (cancelled) return;
setUser(null);
} finally {
if (!cancelled) {
setIsAuthLoading(false);
}
}
};
init();
return () => {
cancelled = true;
};
}, [setIsAuthLoading, setUser]);
useEffect(() => {
const handleAuthCleared = () => {
setUser(null);
setIsAuthLoading(false);
};
window.addEventListener(AUTH_CLEARED_EVENT, handleAuthCleared);
return () => {
window.removeEventListener(AUTH_CLEARED_EVENT, handleAuthCleared);
};
}, [setIsAuthLoading, setUser]);
useEffect(() => {
if (isAuthLoading) {
return;
}
const isPublicRoute = pathname === '/login' || pathname === '/register';
const loggedIn = isLoggedIn();
if (!loggedIn && !isPublicRoute) {
const search = searchParams?.toString();
const nextPath = search ? `${pathname}?${search}` : pathname;
window.location.replace(buildAuthPortalUrl('/login', nextPath));
return;
}
if (loggedIn && user && isPublicRoute) {
router.replace('/');
}
}, [isAuthLoading, pathname, router, searchParams, user]);
if (isAuthLoading) {
return (
<div className={`flex ${minHeightClassName} items-center justify-center`}>
<div className="text-muted-foreground">{pickAppText(locale, '加载中...', 'Loading...')}</div>
</div>
);
}
const isPublicRoute = pathname === '/login' || pathname === '/register';
if (!isPublicRoute && (!isLoggedIn() || !user)) {
return null;
}
return <>{children}</>;
}