任务1: 全局快捷键管理器 — useKeyboardShortcuts hook Ctrl+Tab/Shift+Tab标签切换, Ctrl+1~9跳转, F11全屏, Ctrl+Shift+N新建标签 任务2: 标签拖拽排序 — tabStore.moveTab + TabBar HTML5 DnD 不可变更新, 拖拽视觉反馈(opacity+指示线), 活跃标签底部accent-blue指示线 任务3: SFTP拖拽上传 + useSFTP调试清理 FileListPanel拖拽覆盖层(Upload图标+虚线边框), 5个调试函数→createLogger, disconnect()正确调用IPC, 删除mock data 任务4: SFTP右键菜单完善 — 重命名/复制路径/属性/权限 FilePropertiesDialog+ChmodDialog, sftpStat/sftpChmod IPC全栈实现 任务5-6: 侧边栏分组折叠动画 + 宽度可拖拽调整 Grid 0fr→1fr折叠动画, ChevronRight旋转, resize handle 180~400px, settings记忆 任务7: 响应式布局 + 视觉优化V1~V5 useMediaQuery hook, <800px侧边栏overlay模式, SFTP垂直堆叠, WelcomeView响应式grid 任务8: Loading/Skeleton骨架屏 Skeleton/SkeletonLine/SkeletonCircle/SkeletonBlock + FileListSkeleton/SessionTreeSkeleton/TabContentSkeleton 任务9: 空状态设计 EmptyState通用组件, SessionTree/FileListPanel/WelcomeView/SFTPView空状态引导 任务10: TerminalView组件拆分重构 711行→285行 useTerminalConnection(300行) + useTerminalSearch(123行) + TerminalOverlay(98行) + TerminalSearchBar(74行) 33 files changed, 2682 insertions(+), 872 deletions(-)
104 lines
5.5 KiB
TypeScript
104 lines
5.5 KiB
TypeScript
const { contextBridge, ipcRenderer } = require('electron')
|
|
|
|
// 暴露 API 到渲染进程
|
|
const api = {
|
|
// SSH 相关
|
|
sshConnect: (config: any) => ipcRenderer.invoke('ssh:connect', config),
|
|
sshDisconnect: (connectionId: string) => ipcRenderer.invoke('ssh:disconnect', connectionId),
|
|
sshExec: (connectionId: string, command: string) => ipcRenderer.invoke('ssh:exec', connectionId, command),
|
|
sshCreateShell: (connectionId: string, options?: any, shellId?: string) => ipcRenderer.invoke('ssh:createShell', connectionId, options, shellId),
|
|
sshShellWrite: (shellId: string, data: string | Uint8Array) => ipcRenderer.invoke('ssh:shellWrite', shellId, data),
|
|
sshShellResize: (shellId: string, cols: number, rows: number) => ipcRenderer.invoke('ssh:shellResize', shellId, cols, rows),
|
|
|
|
// 会话管理
|
|
sessionGetAll: () => ipcRenderer.invoke('session:getAll'),
|
|
sessionGetById: (id: string) => ipcRenderer.invoke('session:getById', id),
|
|
sessionCreate: (session: any) => ipcRenderer.invoke('session:create', session),
|
|
sessionUpdate: (id: string, updates: any) => ipcRenderer.invoke('session:update', id, updates),
|
|
sessionDelete: (id: string) => ipcRenderer.invoke('session:delete', id),
|
|
|
|
// SFTP
|
|
sftpConnect: (connectionId: string) => ipcRenderer.invoke('sftp:connect', connectionId),
|
|
sftpListDirectory: (sftpId: string, path: string) => ipcRenderer.invoke('sftp:listDirectory', sftpId, path),
|
|
sftpUpload: (sftpId: string, localPath: string, remotePath: string) => ipcRenderer.invoke('sftp:upload', sftpId, localPath, remotePath),
|
|
sftpDownload: (sftpId: string, remotePath: string, localPath: string) => ipcRenderer.invoke('sftp:download', sftpId, remotePath, localPath),
|
|
sftpRename: (sftpId: string, oldPath: string, newPath: string) => ipcRenderer.invoke('sftp:rename', sftpId, oldPath, newPath),
|
|
sftpDelete: (sftpId: string, path: string, isDirectory: boolean) => ipcRenderer.invoke('sftp:delete', sftpId, path, isDirectory),
|
|
sftpMkdir: (sftpId: string, path: string) => ipcRenderer.invoke('sftp:mkdir', sftpId, path),
|
|
sftpStat: (sftpId: string, filePath: string) => ipcRenderer.invoke('sftp:stat', sftpId, filePath),
|
|
sftpChmod: (sftpId: string, filePath: string, mode: number) => ipcRenderer.invoke('sftp:chmod', sftpId, filePath, mode),
|
|
|
|
// 端口转发
|
|
sshForwardLocal: (connectionId: string, localPort: number, remoteHost: string, remotePort: number) =>
|
|
ipcRenderer.invoke('ssh:forwardLocal', connectionId, localPort, remoteHost, remotePort),
|
|
sshForwardRemote: (connectionId: string, remotePort: number, localHost: string, localPort: number) =>
|
|
ipcRenderer.invoke('ssh:forwardRemote', connectionId, remotePort, localHost, localPort),
|
|
sshForwardDynamic: (connectionId: string, localPort: number) =>
|
|
ipcRenderer.invoke('ssh:forwardDynamic', connectionId, localPort),
|
|
|
|
// 设置
|
|
settingsGet: (key: string) => ipcRenderer.invoke('settings:get', key),
|
|
settingsSet: (key: string, value: any) => ipcRenderer.invoke('settings:set', key, value),
|
|
|
|
// 对话框
|
|
showSaveDialog: (options: any) => ipcRenderer.invoke('dialog:showSaveDialog', options),
|
|
showOpenDialog: (options: any) => ipcRenderer.invoke('dialog:showOpenDialog', options),
|
|
|
|
// 文件操作
|
|
readFile: (filePath: string) => ipcRenderer.invoke('file:read', filePath),
|
|
writeFile: (filePath: string, data: string) => ipcRenderer.invoke('file:write', filePath, data),
|
|
|
|
// 本地文件系统
|
|
getHomePath: () => ipcRenderer.invoke('local:getHome'),
|
|
getDownloadsPath: () => ipcRenderer.invoke('app:getDownloadsPath'),
|
|
localReadDir: (dirPath: string) => ipcRenderer.invoke('local:readDir', dirPath),
|
|
localGetStats: (filePath: string) => ipcRenderer.invoke('local:getStats', filePath),
|
|
localDelete: (filePath: string) => ipcRenderer.invoke('local:delete', filePath),
|
|
localRename: (oldPath: string, newPath: string) => ipcRenderer.invoke('local:rename', oldPath, newPath),
|
|
localMkdir: (dirPath: string) => ipcRenderer.invoke('local:mkdir', dirPath),
|
|
|
|
// Zmodem rz/sz
|
|
zmodemSend: (shellId: string) => ipcRenderer.invoke('zmodem:send', shellId),
|
|
zmodemReceive: (shellId: string) => ipcRenderer.invoke('zmodem:receive', shellId),
|
|
zmodemCancel: (sessionId: string) => ipcRenderer.invoke('zmodem:cancel', sessionId),
|
|
|
|
// Zmodem events
|
|
onZmodemProgress: (callback: (event: any, sessionId: string, progress: any) => void) => {
|
|
ipcRenderer.on('zmodem:progress', callback)
|
|
},
|
|
onZmodemComplete: (callback: (event: any, sessionId: string, result: any) => void) => {
|
|
ipcRenderer.on('zmodem:complete', callback)
|
|
},
|
|
|
|
// 应用信息
|
|
getVersion: () => ipcRenderer.invoke('app:getVersion'),
|
|
|
|
// 事件监听
|
|
onMenuNewSession: (callback: () => void) => {
|
|
ipcRenderer.on('menu-new-session', callback)
|
|
},
|
|
onMenuQuickConnect: (callback: () => void) => {
|
|
ipcRenderer.on('menu-quick-connect', callback)
|
|
},
|
|
onMenuImportSessions: (callback: () => void) => {
|
|
ipcRenderer.on('menu-import-sessions', callback)
|
|
},
|
|
onMenuExportSessions: (callback: () => void) => {
|
|
ipcRenderer.on('menu-export-sessions', callback)
|
|
},
|
|
onShellData: (callback: (event: any, connectionId: string, shellId: string, data: Buffer) => void) => {
|
|
ipcRenderer.on('ssh:shellData', callback)
|
|
},
|
|
onSFTPProgress: (callback: (event: any, sftpId: string, progress: any) => void) => {
|
|
ipcRenderer.on('sftp:progress', callback)
|
|
},
|
|
removeListener: (channel: string, callback: (...args: any[]) => void) => {
|
|
ipcRenderer.removeListener(channel, callback)
|
|
},
|
|
removeAllListeners: (channel: string) => {
|
|
ipcRenderer.removeAllListeners(channel)
|
|
}
|
|
}
|
|
|
|
contextBridge.exposeInMainWorld('electronAPI', api)
|