import { useCallback, useMemo, useState } from 'react' import type { TestConnectionResult } from '@/lib/config-api' import { AlertCircle, CheckCircle2, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Loader2, Pencil, Search, Trash2, XCircle, Zap } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Checkbox } from '@/components/ui/checkbox' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { ProviderCard } from './ProviderCard' import type { APIProvider } from './types' interface ProviderListProps { providers: APIProvider[] testingProviders: Set testResults: Map selectedProviders: Set onEdit: (provider: APIProvider, index: number) => void onDelete: (index: number) => void onTest: (name: string) => void onToggleSelect: (index: number) => void onToggleSelectAll: () => void } export function ProviderList({ providers, testingProviders, testResults, selectedProviders, onEdit, onDelete, onTest, onToggleSelect, onToggleSelectAll, }: ProviderListProps) { const [searchQuery, setSearchQuery] = useState('') const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(20) const [jumpToPage, setJumpToPage] = useState('') const filteredProviders = useMemo(() => { if (!searchQuery) return providers const query = searchQuery.toLowerCase() return providers.filter((provider) => ( provider.name.toLowerCase().includes(query) || provider.base_url.toLowerCase().includes(query) || provider.client_type.toLowerCase().includes(query) )) }, [providers, searchQuery]) const { totalPages, paginatedProviders } = useMemo(() => { const total = Math.ceil(filteredProviders.length / pageSize) const paginated = filteredProviders.slice( (page - 1) * pageSize, page * pageSize ) return { totalPages: total, paginatedProviders: paginated } }, [filteredProviders, page, pageSize]) const handleJumpToPage = useCallback(() => { const targetPage = parseInt(jumpToPage) if (targetPage >= 1 && targetPage <= totalPages) { setPage(targetPage) setJumpToPage('') } }, [jumpToPage, totalPages]) const renderTestStatus = (providerName: string) => { const isTesting = testingProviders.has(providerName) const result = testResults.get(providerName) if (isTesting) { return ( 测试中 ) } if (!result) { return ( 未测试 ) } if (result.network_ok) { if (result.api_key_valid === true) { return ( 正常 ) } else if (result.api_key_valid === false) { return ( Key无效 ) } else { return ( 可访问 ) } } else { return ( 离线 ) } } return ( <> {/* 搜索框 */}
setSearchQuery(e.target.value)} className="pl-9" />
{searchQuery && (

找到 {filteredProviders.length} 个结果

)}
{/* 移动端卡片视图 */}
{filteredProviders.length === 0 ? (
{searchQuery ? '未找到匹配的提供商' : '暂无提供商配置,点击"添加提供商"开始配置'}
) : ( paginatedProviders.map((provider, displayIndex) => { const actualIndex = providers.findIndex(p => p === provider) return ( ) }) )}
{/* 桌面端表格视图 */}
0} onCheckedChange={onToggleSelectAll} /> 状态 名称 基础URL 客户端类型 最大重试 超时(秒) 重试间隔(秒) 操作 {paginatedProviders.length === 0 ? ( {searchQuery ? '未找到匹配的提供商' : '暂无提供商配置,点击"添加提供商"开始配置'} ) : ( paginatedProviders.map((provider, displayIndex) => { const actualIndex = providers.findIndex(p => p === provider) return ( onToggleSelect(actualIndex)} /> {renderTestStatus(provider.name)} {provider.name} {provider.base_url} {provider.client_type} {provider.max_retry} {provider.timeout} {provider.retry_interval}
) }) )}
{/* 分页 */} {filteredProviders.length > 0 && (
显示 {(page - 1) * pageSize + 1} 到{' '} {Math.min(page * pageSize, filteredProviders.length)} 条,共 {filteredProviders.length} 条
setJumpToPage(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleJumpToPage()} placeholder={page.toString()} className="w-16 h-8 text-center" min={1} max={totalPages} />
)} ) }