import { CustomNodeForm } from "./custom-node-form"; import { ActionForm } from "@/components/action-form"; import { buttonVariants } from "@/components/ui/button"; import { CopyButton } from "@/components/copy-button"; import { FilterList } from "@/components/filter-list"; import { Input } from "@/components/ui/input"; import { SubmitButton } from "@/components/submit-button"; import { getRequestOrigin } from "@/lib/request-origin"; import { formatLocalDateTime } from "@/lib/datetime"; import { buildNodeHy2Config } from "@/lib/subscription"; import { buildNodeAuthUrl, buildTrafficStatsUrl, getNodeProxyName, listNodes, } from "@/lib/store"; import { createNodeAction, updateAnyTLSNodeAction, deleteNodeAction, updateNodeAction, } from "./actions"; function getNodePills(node: { enabled: number; node_type: "hy2" | "custom" | "anytls"; last_error_message: string | null; last_sync_ok_at: string | null; }) { return [ { label: node.enabled ? "已启用" : "已禁用", className: `status-pill ${node.enabled ? "status-pill--ok" : "status-pill--off"}`, }, node.node_type === "custom" ? { label: "自定义 YAML", className: "status-pill status-pill--ink" } : node.node_type === "anytls" && (!node.last_sync_ok_at || Date.parse(node.last_sync_ok_at) < new Date().getTime() - 90_000) ? { label: "心跳超时", className: "status-pill status-pill--danger" } : node.last_error_message ? { label: "同步异常", className: "status-pill status-pill--danger" } : { label: "同步正常", className: "status-pill status-pill--sage" }, ]; } export default async function NodesPage() { const [nodes, origin] = await Promise.all([listNodes(), getRequestOrigin()]); return (
节点

节点管理

证书托管 / 自动安装节点
启用 {nodes.filter((node) => node.enabled).length} 总数 {nodes.length}

新增 HY2 节点

展开
创建节点

新增自定义订阅节点

节点列表

{nodes.length} 个节点
节点 状态 对外地址 trafficStats 在线/流 最近同步 操作 } items={nodes.map((node) => { const isCustom = node.node_type === "custom"; const isAnyTLS = node.node_type === "anytls"; const proxyName = getNodeProxyName(node); const authUrl = buildNodeAuthUrl( node.slug, node.auth_token, origin, ); const suggestedTrafficStatsUrl = buildTrafficStatsUrl( node.server_host, node.traffic_stats_listen, ); return { id: node.id, text: `${node.name} ${node.slug} ${node.server_host} ${proxyName} ${isCustom ? "自定义 YAML custom" : isAnyTLS ? "AnyTLS sing-box TCP" : "HY2"}`, status: node.enabled ? "enabled" : "disabled", content: (
{node.name} /{node.slug} {getNodePills(node).map((pill) => ( {pill.label} ))} {isCustom ? proxyName : `${node.server_host}:${node.server_port}`} {isCustom ? "自定义订阅节点" : `${isAnyTLS ? "AnyTLS TCP" : "HY2 UDP"} ${node.hy2_listen}`} {isCustom ? "不轮询" : isAnyTLS ? "节点主动上报" : node.traffic_stats_url} {isCustom ? "仅订阅" : isAnyTLS ? "管理接口仅本机" : node.traffic_stats_listen} {isCustom ? "—" : `${isAnyTLS ? "—" : node.last_online_users} / ${node.last_stream_count}`} {isCustom ? "无流量统计" : "用户 / 流"} {isCustom ? "—" : formatLocalDateTime(node.last_sync_ok_at)} {!isCustom && node.last_error_at ? ( 错误 {formatLocalDateTime(node.last_error_at)} ) : null} 编辑 收起
{isCustom ? ( ) : isAnyTLS ? ( <>

AnyTLS / sing-box · 每用户独立凭据,约 15 秒同步。用户增删、密码、到期或额度变更会更新配置并重启 sing-box,现有连接会断开。连续失联约 90 秒后停止代理。在线用户数暂不提供,流数量来自本机接口。

{!node.last_sync_ok_at || Date.parse(node.last_sync_ok_at) < new Date().getTime() - 90_000 ? "节点未连接或心跳已超时" : "节点心跳正常"}{" "} · SNI:{node.sni}

保存节点 ) : ( <>
鉴权 URL
{authUrl}
自动推导 trafficStats {suggestedTrafficStatsUrl}
保存节点
查看 hy2 config.yaml
{buildNodeHy2Config(node, origin)}
下载 hy2 config.yaml
{node.last_error_message ? (

{node.last_error_message}

) : null} )}
删除节点
), }; })} />
); }