修复: 粘贴图失效与SFTP串台回退等一批问题
粘贴图根修(Ctrl+V直读系统剪贴板,不再依赖不可靠的paste事件)/SFTP串台双刀(拨号期禁回退本机+盘符路径自动回根)/PDF导出目录设置与文案带落盘路径/性能批(连接保存下载防重/md渲染防抖+预热/hljs按需加载/审计锁外置/快捷方式解析超时/webview-watch可停)/前端62类型错清零(含keyPath蛇形字段炸弹)/目录图标字段错位修复
This commit is contained in:
@@ -24,16 +24,29 @@ export class SftpTransport implements FsTransport {
|
||||
}
|
||||
|
||||
async connect(): Promise<string> {
|
||||
const result = await SftpConnect({
|
||||
host: this.profile.host,
|
||||
port: this.profile.port || 22,
|
||||
username: this.profile.username || 'root',
|
||||
password: this.profile.password || '',
|
||||
key_path: this.profile.keyPath || '',
|
||||
key_passphrase: '',
|
||||
// 前端反馈层 9s 超时:后端连接继续由既有逻辑管理(不主动断),
|
||||
// 仅避免 UI 在网络不可达时无限挂起,用户能立刻拿到失败反馈
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
const timeout = new Promise<never>((_, reject) => {
|
||||
timer = setTimeout(() => reject(new Error('连接超时,请检查网络')), 9000)
|
||||
})
|
||||
this.connID = result
|
||||
return result
|
||||
try {
|
||||
const result = await Promise.race([
|
||||
SftpConnect({
|
||||
host: this.profile.host,
|
||||
port: this.profile.port || 22,
|
||||
username: this.profile.username || 'root',
|
||||
password: this.profile.password || '',
|
||||
key_path: this.profile.keyPath || '',
|
||||
key_passphrase: '',
|
||||
}),
|
||||
timeout,
|
||||
])
|
||||
this.connID = result
|
||||
return result
|
||||
} finally {
|
||||
if (timer) clearTimeout(timer)
|
||||
}
|
||||
}
|
||||
|
||||
async isAlive(): Promise<boolean> {
|
||||
@@ -56,23 +69,34 @@ export class SftpTransport implements FsTransport {
|
||||
return this.connID
|
||||
}
|
||||
|
||||
/** 远程路径守卫:本机盘符路径串入 SFTP(tab 恢复/面板状态错位)会在服务器端报 No such file */
|
||||
private assertRemotePath(path: string): void {
|
||||
if (/^[A-Za-z]:[\\/]/.test(path)) {
|
||||
throw new Error(`本机路径不可用于远程操作: ${path}`)
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 文件列表与信息 ======
|
||||
|
||||
async listDir(path: string): Promise<FileItem[]> {
|
||||
this.assertRemotePath(path)
|
||||
return transformFileList(await SftpListDir(this.requireConn(), path))
|
||||
}
|
||||
|
||||
async getFileInfo(path: string): Promise<Record<string, any>> {
|
||||
this.assertRemotePath(path)
|
||||
return SftpGetFileInfo(this.requireConn(), path)
|
||||
}
|
||||
|
||||
// ====== 文件读写 ======
|
||||
|
||||
async readFile(path: string): Promise<string> {
|
||||
this.assertRemotePath(path)
|
||||
return SftpReadFile(this.requireConn(), path)
|
||||
}
|
||||
|
||||
async writeFile(path: string, content: string): Promise<void> {
|
||||
this.assertRemotePath(path)
|
||||
await SftpWriteFile({
|
||||
session_id: this.requireConn(),
|
||||
path,
|
||||
@@ -82,24 +106,30 @@ export class SftpTransport implements FsTransport {
|
||||
|
||||
async saveBase64File(path: string, content: string): Promise<void> {
|
||||
if (!content) throw new Error('无效的 base64 内容')
|
||||
this.assertRemotePath(path)
|
||||
await SftpWriteBase64File(this.requireConn(), path, content)
|
||||
}
|
||||
|
||||
// ====== 文件操作 ======
|
||||
|
||||
async createFile(dirPath: string, filename: string): Promise<FileOperationResult> {
|
||||
this.assertRemotePath(dirPath)
|
||||
return SftpCreateFile(this.requireConn(), joinPath(dirPath, filename))
|
||||
}
|
||||
|
||||
async createDir(parentPath: string, dirname: string): Promise<FileOperationResult> {
|
||||
this.assertRemotePath(parentPath)
|
||||
return SftpCreateDir(this.requireConn(), joinPath(parentPath, dirname))
|
||||
}
|
||||
|
||||
async deletePath(path: string): Promise<FileOperationResult> {
|
||||
this.assertRemotePath(path)
|
||||
return SftpDeletePath(this.requireConn(), path)
|
||||
}
|
||||
|
||||
async renamePath(oldPath: string, newPath: string): Promise<FileOperationResult> {
|
||||
this.assertRemotePath(oldPath)
|
||||
this.assertRemotePath(newPath)
|
||||
return SftpRenamePath({
|
||||
session_id: this.requireConn(),
|
||||
old_path: oldPath,
|
||||
@@ -121,11 +151,13 @@ export class SftpTransport implements FsTransport {
|
||||
|
||||
/** 下载远程文件/目录到用户指定目录(流式无上限,重名自动副本),返回本地落地路径 */
|
||||
async downloadToFile(remotePath: string, localDstDir: string): Promise<string> {
|
||||
this.assertRemotePath(remotePath)
|
||||
return SftpDownloadToFile(this.requireConn(), remotePath, localDstDir)
|
||||
}
|
||||
|
||||
/** 上传本地文件/目录到远程目录(流式,目录递归) */
|
||||
async uploadFromFile(localPath: string, remoteDir: string): Promise<void> {
|
||||
this.assertRemotePath(remoteDir)
|
||||
await SftpUploadFromFile(this.requireConn(), localPath, remoteDir)
|
||||
}
|
||||
|
||||
@@ -190,11 +222,13 @@ export class SftpTransport implements FsTransport {
|
||||
|
||||
/** 下载远程文件到本地临时目录用于预览(缓存由 Go 后端管理) */
|
||||
async downloadForPreview(remotePath: string): Promise<string> {
|
||||
this.assertRemotePath(remotePath)
|
||||
return SftpDownloadToTemp(this.requireConn(), remotePath)
|
||||
}
|
||||
|
||||
/** 下载 HTML 及其网站资源到临时目录用于预览 */
|
||||
async downloadSiteForPreview(remotePath: string): Promise<string> {
|
||||
this.assertRemotePath(remotePath)
|
||||
return SftpDownloadSiteForPreview(this.requireConn(), remotePath)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user