diff --git a/src/modules/extensions/builtin/user-center/routes/agent.tsx b/src/modules/extensions/builtin/user-center/routes/agent.tsx index 3242174..6278698 100644 --- a/src/modules/extensions/builtin/user-center/routes/agent.tsx +++ b/src/modules/extensions/builtin/user-center/routes/agent.tsx @@ -1,12 +1,14 @@ 'use client' -import { useMemo } from 'react' +import { useEffect, useMemo, useState } from 'react' import useSWR from 'swr' import { Server, MapPin, Plus, ExternalLink, RefreshCw } from 'lucide-react' import Breadcrumbs from '@/app/panel/components/Breadcrumbs' import { useLanguage } from '@i18n/LanguageProvider' import { translations } from '@i18n/translations' +import { useUserStore } from '@lib/userStore' +import { getSandboxNodeBinding } from '../lib/sandboxNodeBinding' interface VlessNode { name: string @@ -57,8 +59,43 @@ async function fetcher(url: string): Promise { export default function UserCenterAgentRoute() { const { language } = useLanguage() const t = translations[language].userCenter + const user = useUserStore((state) => state.user) const { data: nodes, error, isLoading, mutate } = useSWR('/api/agent-server/v1/nodes', fetcher) const visibleNodes = useMemo(() => (nodes ?? []).filter(isDisplayableNode), [nodes]) + const [boundNode, setBoundNode] = useState(null) + const normalizedEmail = user?.email?.toLowerCase() ?? '' + const isGuestSandboxReadOnly = Boolean( + user?.isReadOnly && (normalizedEmail === 'sandbox@svc.plus' || normalizedEmail === 'demo@svc.plus'), + ) + + useEffect(() => { + if (!isGuestSandboxReadOnly) { + setBoundNode(null) + return + } + const binding = getSandboxNodeBinding() + if (!binding) { + setBoundNode(null) + return + } + setBoundNode({ + name: binding.name || 'Sandbox Node', + address: binding.address, + port: 443, + transport: 'tcp', + security: 'tls', + }) + }, [isGuestSandboxReadOnly]) + + const effectiveNodes = useMemo(() => { + if (visibleNodes.length > 0) { + return visibleNodes + } + if (isGuestSandboxReadOnly && boundNode) { + return [boundNode] + } + return [] + }, [boundNode, isGuestSandboxReadOnly, visibleNodes]) const groupedNodes = useMemo(() => { const groups: Record = { @@ -68,9 +105,9 @@ export default function UserCenterAgentRoute() { Other: [], } - if (!visibleNodes.length) return groups + if (!effectiveNodes.length) return groups - visibleNodes.forEach((node) => { + effectiveNodes.forEach((node) => { const name = node.name.toLowerCase() if (name.includes('hk')) groups.HK.push(node) else if (name.includes('jp')) groups.JP.push(node) @@ -79,7 +116,7 @@ export default function UserCenterAgentRoute() { }) return groups - }, [visibleNodes]) + }, [effectiveNodes]) return (
@@ -115,7 +152,7 @@ export default function UserCenterAgentRoute() {
- {error && ( + {error && !(isGuestSandboxReadOnly && boundNode) && (
{language === 'zh' ? `节点列表加载失败:${error.message}` @@ -172,7 +209,7 @@ export default function UserCenterAgentRoute() { ) ))} - {!isLoading && visibleNodes.length === 0 && ( + {!isLoading && effectiveNodes.length === 0 && (