import React, { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { FiX, FiPlus, FiTrash2, FiServer, FiCheck, FiLoader, FiKey, FiEye, FiEyeOff, FiPlay, } from 'react-icons/fi'; const colors = [ '#58a6ff', '#3fb950', '#d29922', '#f85149', '#bc8cff', '#56d4dd', '#ffa657', '#ff7b72', '#d2a8ff', '#76e3ea', ]; function HostManager({ hosts, initialEditHost, onClose, onConnect, onUpdate }) { const [isEditing, setIsEditing] = useState(!!initialEditHost); const [editingHost, setEditingHost] = useState(initialEditHost || null); const [showPassword, setShowPassword] = useState(false); const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState(null); const [formData, setFormData] = useState({ name: '', host: '', port: 22, username: '', password: '', privateKey: '', groupName: '默认分组', color: '#58a6ff', description: '', }); // 初始化编辑状态 useEffect(() => { if (initialEditHost) { setEditingHost(initialEditHost); setIsEditing(true); } }, [initialEditHost]); useEffect(() => { if (editingHost) { setFormData({ name: editingHost.name || '', host: editingHost.host || '', port: editingHost.port || 22, username: editingHost.username || '', password: editingHost.password || '', privateKey: editingHost.private_key || '', groupName: editingHost.group_name || '默认分组', color: editingHost.color || '#58a6ff', description: editingHost.description || '', }); } }, [editingHost]); const resetForm = () => { setFormData({ name: '', host: '', port: 22, username: '', password: '', privateKey: '', groupName: '默认分组', color: '#58a6ff', description: '', }); setEditingHost(null); setIsEditing(false); setTestResult(null); }; const handleSubmit = async (e) => { e.preventDefault(); if (!window.electronAPI) return; try { if (editingHost) { await window.electronAPI.hosts.update(editingHost.id, formData); } else { await window.electronAPI.hosts.add(formData); } onUpdate(); resetForm(); } catch (error) { console.error('保存失败:', error); } }; const handleDelete = async (id) => { if (!window.electronAPI) return; if (window.confirm('确定要删除这个主机吗?')) { await window.electronAPI.hosts.delete(id); onUpdate(); } }; const handleTest = async () => { if (!window.electronAPI) return; setTesting(true); setTestResult(null); try { const result = await window.electronAPI.ssh.test({ host: formData.host, port: formData.port, username: formData.username, password: formData.password, privateKey: formData.privateKey, }); setTestResult(result); } catch (error) { setTestResult({ success: false, message: error.message }); } finally { setTesting(false); } }; return ( e.target === e.currentTarget && onClose()} > {/* 头部 */}

主机管理

{isEditing && ( {editingHost?.id ? '编辑中' : '新建'} )}
{/* 主机列表 */}
{hosts.map((host) => { const isSelected = editingHost?.id === host.id; return (
{ setEditingHost(host); setIsEditing(true); setTestResult(null); }} className={`group p-3 rounded-lg border transition-all cursor-pointer ${isSelected ? 'bg-shell-accent/10 border-shell-accent/50' : 'bg-shell-card/50 border-shell-border hover:border-shell-accent/30 hover:bg-shell-card' }`} >
{host.name}
{host.username}@{host.host}:{host.port}
); })} {hosts.length === 0 && (
暂无主机,点击上方按钮添加
)}
{/* 编辑表单 */}
{isEditing ? (
{/* 名称 */}
setFormData({ ...formData, name: e.target.value })} className="w-full px-4 py-2.5 bg-shell-bg border border-shell-border rounded-lg text-shell-text placeholder-shell-text-dim/50 focus:border-shell-accent focus:ring-1 focus:ring-shell-accent/50" placeholder="生产服务器" />
{/* 分组 */}
setFormData({ ...formData, groupName: e.target.value })} className="w-full px-4 py-2.5 bg-shell-bg border border-shell-border rounded-lg text-shell-text placeholder-shell-text-dim/50 focus:border-shell-accent focus:ring-1 focus:ring-shell-accent/50" placeholder="默认分组" />
{/* 主机 */}
setFormData({ ...formData, host: e.target.value })} className="w-full px-4 py-2.5 bg-shell-bg border border-shell-border rounded-lg text-shell-text placeholder-shell-text-dim/50 focus:border-shell-accent focus:ring-1 focus:ring-shell-accent/50" placeholder="192.168.1.100 或 example.com" />
{/* 端口 */}
setFormData({ ...formData, port: parseInt(e.target.value) || 22 })} className="w-full px-4 py-2.5 bg-shell-bg border border-shell-border rounded-lg text-shell-text placeholder-shell-text-dim/50 focus:border-shell-accent focus:ring-1 focus:ring-shell-accent/50" />
{/* 用户名 */}
setFormData({ ...formData, username: e.target.value })} className="w-full px-4 py-2.5 bg-shell-bg border border-shell-border rounded-lg text-shell-text placeholder-shell-text-dim/50 focus:border-shell-accent focus:ring-1 focus:ring-shell-accent/50" placeholder="root" />
{/* 密码 */}
setFormData({ ...formData, password: e.target.value })} className="w-full px-4 py-2.5 pr-12 bg-shell-bg border border-shell-border rounded-lg text-shell-text placeholder-shell-text-dim/50 focus:border-shell-accent focus:ring-1 focus:ring-shell-accent/50" placeholder="••••••••" />
{/* 私钥 */}