'use client'; import {useEffect, useMemo, useState} from 'react'; import {Copy} from 'lucide-react'; import {toast} from 'sonner'; import {Button} from '@/components/ui/button'; import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@/components/ui/card'; import {Input} from '@/components/ui/input'; import {Label} from '@/components/ui/label'; import type {NodeItem} from '@/lib/services/openflare'; import { buildRelayDockerInstallCommand, buildRelayInstallCommand, buildTunnelDockerInstallCommand, buildTunnelInstallCommand, getServerUrl, } from './node-utils'; type InstallVariant = 'relay' | 'tunnel'; const variantMeta: Record< InstallVariant, { title: string; description: string; tokenLabel: string; scriptLabel: string; dockerLabel: string; } > = { relay: { title: '中继部署命令', description: '使用 Discovery Token 将 frps 中继节点接入控制端。', tokenLabel: 'Discovery Token', scriptLabel: '一键脚本部署 (Linux / macOS)', dockerLabel: 'Docker 容器部署', }, tunnel: { title: '隧道部署命令', description: '使用 Tunnel Token 将 openflared 客户端接入控制端。', tokenLabel: 'Tunnel Token', scriptLabel: '一键脚本部署 (Linux / macOS)', dockerLabel: 'Docker 容器部署', }, }; export function InstallCommand({ node, variant, }: { node: NodeItem; variant: InstallVariant; }) { const [serverUrl, setServerUrl] = useState(''); const meta = variantMeta[variant]; useEffect(() => { if (typeof window !== 'undefined' && !serverUrl) { setServerUrl(window.location.origin); } }, [serverUrl]); const normalizedServerUrl = getServerUrl(serverUrl); const scriptCommand = useMemo(() => { if (!normalizedServerUrl || !node.access_token) { return ''; } return variant === 'relay' ? buildRelayInstallCommand(normalizedServerUrl, node.access_token) : buildTunnelInstallCommand(normalizedServerUrl, node.access_token); }, [normalizedServerUrl, node.access_token, variant]); const dockerCommand = useMemo(() => { if (!normalizedServerUrl || !node.access_token) { return ''; } return variant === 'relay' ? buildRelayDockerInstallCommand(normalizedServerUrl, node.access_token) : buildTunnelDockerInstallCommand(normalizedServerUrl, node.access_token); }, [normalizedServerUrl, node.access_token, variant]); const handleCopy = async (value: string, message: string) => { try { await navigator.clipboard.writeText(value); toast.success(message); } catch { toast.error('复制失败,请手动选择命令文本。'); } }; return (
{meta.title} {meta.description}
{scriptCommand ? ( ) : null} {dockerCommand ? ( ) : null}

Node ID

{node.node_id}

{meta.tokenLabel}

{node.access_token || '暂无'}

setServerUrl(event.target.value)} placeholder="https://openflare.example.com" />

部署脚本和容器将使用此地址连接 OpenFlare 控制端。

{!node.access_token ? (

节点尚未生成接入 Token,请稍后刷新。

) : !normalizedServerUrl ? (

请填写有效的 Server URL 以生成部署命令。

) : ( <>

{meta.scriptLabel}

                {scriptCommand}
              

{meta.dockerLabel}

                {dockerCommand}
              
)}
); }