Files
sshclient/ui/host_dialog.py
T
Hermes a57dbc0252 feat: SSHClient v1.0.0 - PyQt5 + paramiko 跨平台 SSH 客户端
功能:
- 多主机管理 (增删改查, 密码/私钥双认证, 导入导出)
- 远程终端 (命令执行 + 常用命令快捷栏 + 超时控制)
- SFTP 文件浏览 (上传/下载带进度, 新建/删除/重命名)
- 实时监控 (CPU/内存/磁盘/网络, 1-10秒可调刷新)
- AI Agent (OpenAI 兼容 API, 5 工具自动调用: 命令/指标/列文件/读文件/上传)

技术栈: PyQt5 + paramiko + psutil + requests + PyInstaller
打包: build_windows.bat / build.sh 一键产出 ~57MB 单文件 exe
测试: core 6/6 + UI 3/3 + E2E 6/6 全部通过
2026-07-28 21:01:31 +08:00

110 lines
3.9 KiB
Python

"""
主机新增/编辑对话框
"""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QSpinBox,
QPushButton, QDialogButtonBox, QFileDialog, QMessageBox, QCheckBox,
QGroupBox, QTabWidget, QWidget, QTextEdit,
)
class HostDialog(QDialog):
def __init__(self, parent=None, current: dict = None):
super().__init__(parent)
self.current = current or {}
title = "编辑主机" if current else "新增主机"
self.setWindowTitle(title)
self.resize(480, 380)
self._build()
self._load()
def _build(self):
v = QVBoxLayout(self)
form = QFormLayout()
self.name_edit = QLineEdit()
self.name_edit.setPlaceholderText("给这台主机起个名字(用于显示)")
form.addRow("名称:", self.name_edit)
self.host_edit = QLineEdit()
self.host_edit.setPlaceholderText("192.168.1.1 或 example.com")
form.addRow("主机/IP:", self.host_edit)
self.port_spin = QSpinBox()
self.port_spin.setRange(1, 65535)
self.port_spin.setValue(22)
form.addRow("端口:", self.port_spin)
self.user_edit = QLineEdit()
self.user_edit.setPlaceholderText("root")
form.addRow("用户名:", self.user_edit)
self.pwd_edit = QLineEdit()
self.pwd_edit.setEchoMode(QLineEdit.Password)
self.pwd_edit.setPlaceholderText("密码(密钥无密码可留空)")
form.addRow("密码:", self.pwd_edit)
# 私钥
key_row = QHBoxLayout()
self.key_edit = QLineEdit()
self.key_edit.setPlaceholderText("可选,例如 C:/Users/xxx/.ssh/id_rsa")
self.btn_browse = QPushButton("浏览...")
self.btn_browse.clicked.connect(self._browse_key)
key_row.addWidget(self.key_edit, 1)
key_row.addWidget(self.btn_browse)
form.addRow("私钥文件:", key_row)
self.show_pwd = QCheckBox("显示密码")
self.show_pwd.toggled.connect(
lambda c: self.pwd_edit.setEchoMode(QLineEdit.Normal if c else QLineEdit.Password))
form.addRow("", self.show_pwd)
self.notes_edit = QTextEdit()
self.notes_edit.setMaximumHeight(60)
self.notes_edit.setPlaceholderText("备注(仅本地保存)")
form.addRow("备注:", self.notes_edit)
v.addLayout(form)
bb = QDialogButtonBox()
bb.addButton(QDialogButtonBox.Save).clicked.connect(self._save)
bb.addButton(QDialogButtonBox.Cancel).clicked.connect(self.reject)
v.addWidget(bb)
def _browse_key(self):
path, _ = QFileDialog.getOpenFileName(
self, "选择私钥文件", "", "所有文件 (*)")
if path:
self.key_edit.setText(path)
def _load(self):
c = self.current
self.name_edit.setText(c.get("name", ""))
self.host_edit.setText(c.get("host", ""))
self.port_spin.setValue(int(c.get("port", 22)))
self.user_edit.setText(c.get("username", ""))
self.pwd_edit.setText(c.get("password", ""))
self.key_edit.setText(c.get("key_path", ""))
self.notes_edit.setPlainText(c.get("notes", ""))
def _save(self):
host = self.host_edit.text().strip()
user = self.user_edit.text().strip()
if not host or not user:
QMessageBox.warning(self, "校验失败", "主机和用户名不能为空")
return
self.accept()
def get_value(self) -> dict:
return {
"name": self.name_edit.text().strip() or self.host_edit.text().strip(),
"host": self.host_edit.text().strip(),
"port": self.port_spin.value(),
"username": self.user_edit.text().strip(),
"password": self.pwd_edit.text(),
"key_path": self.key_edit.text().strip(),
"notes": self.notes_edit.toPlainText().strip(),
}