feat: v0.3.0 版本 - SSH终端、SFTP、端口转发功能实现

核心功能:
- SSH终端: 密码/密钥认证、XTerm.js终端、多主题配色、IP高亮
- SFTP管理: 双栏文件管理、上传下载、传输队列
- 端口转发: 本地/远程转发、SOCKS5动态代理、规则管理

架构改进:
- 拆分大型组件 (SFTPView/TabBar/Sidebar)
- 添加统一日志和错误处理
- 修复React严格模式下的终端黑屏问题

UI更新:
- 新增端口转发视图
- 更新UI预览文档
- 左侧栏右键菜单支持SFTP快捷打开
This commit is contained in:
Logan.Li committed 2026-04-06 01:20:47 +08:00
1 parent cf1c054381
commit 484d850abd
105 files changed
+25330 -64

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
import { create } from 'zustand'
import { createLogger } from '../utils/logger'
const logger = createLogger('SettingsStore')
export interface AppSettings {
// 常规
restoreOnStart: boolean
autoSave: boolean
showNotifications: boolean
// 外观
theme: 'dark' | 'light' | 'system'
language: 'zh-CN' | 'en-US'
// 终端
fontFamily: string
fontSize: number
terminalTheme: 'dracula' | 'monokai' | 'solarized' | 'one-dark'
// SSH
keepAlive: boolean
defaultPort: number
timeout: number
// 专业连接管理
maxConnections: number
maxBackgroundConnections: number
idleTimeoutMs: number
suspendTimeoutMs: number
enableSnapshots: boolean
autoReconnect: boolean
// 安全
encryptPasswords: boolean
lockOnSleep: boolean
}
const defaultSettings: AppSettings = {
restoreOnStart: true,
autoSave: true,
showNotifications: false,
theme: 'dark',
language: 'zh-CN',
fontFamily: 'JetBrains Mono',
fontSize: 14,
terminalTheme: 'dracula',
keepAlive: true,
defaultPort: 22,
timeout: 30,
// 专业连接管理默认值
maxConnections: 10,
maxBackgroundConnections: 5,
idleTimeoutMs: 5 * 60 * 1000, // 5 分钟
suspendTimeoutMs: 30 * 60 * 1000, // 30 分钟
enableSnapshots: true,
autoReconnect: true,
encryptPasswords: true,
lockOnSleep: false,
}
interface SettingsState {
settings: AppSettings
isLoaded: boolean
setSetting: <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => Promise<void>
loadSettings: () => Promise<void>
saveSettings: (settings: Partial<AppSettings>) => Promise<void>
}
export const useSettingsStore = create<SettingsState>((set, get) => ({
settings: defaultSettings,
isLoaded: false,
loadSettings: async () => {
try {
const result = await window.electronAPI?.settingsGet('app-settings')
if (result?.success && result.value) {
set({ settings: { ...defaultSettings, ...result.value }, isLoaded: true })
} else {
set({ isLoaded: true })
}
} catch (error) {
logger.error('Failed to load settings:', error)
set({ isLoaded: true })
}
},
setSetting: async (key, value) => {
const newSettings = { ...get().settings, [key]: value }
set({ settings: newSettings })
await window.electronAPI?.settingsSet('app-settings', newSettings)
},
saveSettings: async (newSettings) => {
const merged = { ...get().settings, ...newSettings }
set({ settings: merged })
await window.electronAPI?.settingsSet('app-settings', merged)
},
}))