import { useState, useEffect } from "react"; import { motion } from "framer-motion"; import { ArrowLeft, Play, Square, RotateCcw, ExternalLink, Download, AlertCircle, CheckCircle, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Toast, ToastContainer } from "@/components/ui/toast"; import { ccrApi, type CcrServiceStatus } from "@/lib/api"; import { open } from '@tauri-apps/plugin-shell'; interface CcrRouterManagerProps { onBack: () => void; } export function CcrRouterManager({ onBack }: CcrRouterManagerProps) { const [serviceStatus, setServiceStatus] = useState(null); const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState(false); const [toast, setToast] = useState<{ message: string; type: "success" | "error" | "info" } | null>(null); const [configPath, setConfigPath] = useState(""); useEffect(() => { loadServiceStatus(); loadConfigPath(); }, []); const loadServiceStatus = async () => { try { setLoading(true); const status = await ccrApi.getServiceStatus(); setServiceStatus(status); } catch (error) { console.error("Failed to load CCR service status:", error); setToast({ message: `加载CCR服务状态失败: ${error}`, type: "error" }); } finally { setLoading(false); } }; const loadConfigPath = async () => { try { const path = await ccrApi.getConfigPath(); setConfigPath(path); } catch (error) { console.error("Failed to get config path:", error); } }; const handleStartService = async () => { try { setActionLoading(true); const result = await ccrApi.startService(); setServiceStatus(result.status); setToast({ message: result.message, type: "success" }); } catch (error) { console.error("Failed to start CCR service:", error); setToast({ message: `启动CCR服务失败: ${error}`, type: "error" }); } finally { setActionLoading(false); } }; const handleStopService = async () => { try { setActionLoading(true); const result = await ccrApi.stopService(); setServiceStatus(result.status); setToast({ message: result.message, type: "success" }); } catch (error) { console.error("Failed to stop CCR service:", error); setToast({ message: `停止CCR服务失败: ${error}`, type: "error" }); } finally { setActionLoading(false); } }; const handleRestartService = async () => { try { setActionLoading(true); const result = await ccrApi.restartService(); setServiceStatus(result.status); setToast({ message: result.message, type: "success" }); } catch (error) { console.error("Failed to restart CCR service:", error); setToast({ message: `重启CCR服务失败: ${error}`, type: "error" }); } finally { setActionLoading(false); } }; const handleOpenUI = async () => { try { setActionLoading(true); // 如果服务未运行,先尝试启动 if (!serviceStatus?.is_running) { setToast({ message: "检测到服务未运行,正在启动...", type: "info" }); const startResult = await ccrApi.startService(); setServiceStatus(startResult.status); if (!startResult.status.is_running) { throw new Error("服务启动失败"); } // 等待服务完全启动 await new Promise(resolve => setTimeout(resolve, 3000)); } await ccrApi.openUI(); setToast({ message: "正在打开CCR UI...", type: "info" }); // 刷新服务状态 setTimeout(() => { loadServiceStatus(); }, 2000); } catch (error) { console.error("Failed to open CCR UI:", error); setToast({ message: `打开CCR UI失败: ${error}`, type: "error" }); } finally { setActionLoading(false); } }; const handleOpenInBrowser = async () => { try { // 如果服务未运行,先尝试启动 if (!serviceStatus?.is_running) { setActionLoading(true); setToast({ message: "检测到服务未运行,正在启动...", type: "info" }); const startResult = await ccrApi.startService(); setServiceStatus(startResult.status); if (!startResult.status.is_running) { throw new Error("服务启动失败"); } // 等待服务完全启动 await new Promise(resolve => setTimeout(resolve, 2000)); setActionLoading(false); } if (serviceStatus?.endpoint) { open(`${serviceStatus.endpoint}/ui/`); setToast({ message: "正在打开CCR管理界面...", type: "info" }); } } catch (error) { console.error("Failed to open CCR UI in browser:", error); setToast({ message: `打开管理界面失败: ${error}`, type: "error" }); setActionLoading(false); } }; const renderServiceStatus = () => { if (!serviceStatus) return null; const statusColor = serviceStatus.is_running ? "bg-green-500" : "bg-red-500"; const statusText = serviceStatus.is_running ? "运行中" : "已停止"; return (
{statusText} {serviceStatus.is_running && serviceStatus.port && ( 端口 {serviceStatus.port} )}
); }; const renderInstallationStatus = () => { if (!serviceStatus) return null; return (
{serviceStatus.has_ccr_binary ? ( <> 已安装 {serviceStatus.ccr_version && ( {serviceStatus.ccr_version} )} ) : ( <> 未安装 )}
); }; if (loading) { return (
); } return (
{/* Header */}

CCR 路由管理

管理 Claude Code Router 服务和配置

{/* Service Status Card */} 服务状态 CCR 路由服务当前状态和控制选项
安装状态: {renderInstallationStatus()}
服务状态: {renderServiceStatus()}
{serviceStatus?.endpoint && (
服务地址:
)} {serviceStatus?.process_id && (
进程 ID: {serviceStatus.process_id}
)} {configPath && (
配置文件: {configPath}
)}
{/* Control Panel */} 服务控制 启动、停止或重启 CCR 路由服务 {serviceStatus?.has_ccr_binary ? (
{!serviceStatus.is_running ? ( ) : ( )}
) : (

CCR 未安装

需要先安装 Claude Code Router 才能使用此功能

)}
{/* Information Card */} 关于 CCR 路由

Claude Code Router (CCR) 是一个强大的路由工具,允许您将 Claude Code 请求转发到不同的 LLM 提供商。

  • 支持多个 LLM 提供商(OpenRouter、DeepSeek、Gemini 等)
  • 智能路由规则,根据令牌数量和请求类型自动选择
  • Web UI 管理界面,方便配置和监控
  • 无需 Anthropic 账户即可使用 Claude Code
{/* Toast Container */} {toast && ( setToast(null)} /> )}
); }