feat: 添加标签管理模态框

This commit is contained in:
Baobhan Sith
2025-05-11 11:20:26 +08:00
parent 1eb1efde72
commit 598df938bf
40 changed files with 634 additions and 170 deletions
@@ -54,7 +54,7 @@ interface ActiveUpload {
bytesWritten: number;
stream: WriteStream;
sessionId: string; // Link back to the session for cleanup
relativePath?: string; // +++ 新增:存储相对路径 +++
relativePath?: string;
}
export class SftpService {
@@ -646,7 +646,7 @@ export class SftpService {
}
}
// +++ 新增:复制文件或目录 +++
// +++ 复制文件或目录 +++
async copy(sessionId: string, sources: string[], destinationDir: string, requestId: string): Promise<void> {
const state = this.clientStates.get(sessionId);
if (!state || !state.sftp) {
@@ -720,7 +720,7 @@ export class SftpService {
}
}
// +++ 新增:移动文件或目录 +++
// +++ 移动文件或目录 +++
async move(sessionId: string, sources: string[], destinationDir: string, requestId: string): Promise<void> {
const state = this.clientStates.get(sessionId);
if (!state || !state.sftp) {
@@ -803,7 +803,7 @@ export class SftpService {
}
}
// +++ 新增:辅助方法 - 复制文件 +++
// +++ 辅助方法 - 复制文件 +++
private copyFile(sftp: SFTPWrapper, sourcePath: string, destPath: string): Promise<void> {
return new Promise((resolve, reject) => {
const readStream = sftp.createReadStream(sourcePath);
@@ -833,7 +833,7 @@ export class SftpService {
});
}
// +++ 新增:辅助方法 - 递归复制目录 +++
// +++ 辅助方法 - 递归复制目录 +++
private async copyDirectoryRecursive(sftp: SFTPWrapper, sourcePath: string, destPath: string): Promise<void> {
try {
// Create destination directory
@@ -861,7 +861,7 @@ export class SftpService {
}
}
// +++ 新增:辅助方法 - 获取 Stats (Promise wrapper) +++
// +++ 辅助方法 - 获取 Stats (Promise wrapper) +++
private getStats(sftp: SFTPWrapper, path: string): Promise<Stats> {
return new Promise((resolve, reject) => {
sftp.lstat(path, (err, stats) => {
@@ -951,7 +951,7 @@ export class SftpService {
}
}
// +++ 新增:辅助方法 - 列出目录内容 (Promise wrapper) +++
// +++ 辅助方法 - 列出目录内容 (Promise wrapper) +++
private listDirectory(sftp: SFTPWrapper, path: string): Promise<SftpDirEntry[]> { // 使用本地接口 SftpDirEntry
return new Promise((resolve, reject) => {
sftp.readdir(path, (err, list) => { // list 的类型现在是 SftpDirEntry[]
@@ -964,7 +964,7 @@ export class SftpService {
});
}
// +++ 新增:辅助方法 - 执行重命名 (Promise wrapper) +++
// +++ 辅助方法 - 执行重命名 (Promise wrapper) +++
private performRename(sftp: SFTPWrapper, oldPath: string, newPath: string): Promise<void> {
return new Promise((resolve, reject) => {
sftp.rename(oldPath, newPath, (err) => {
@@ -977,7 +977,7 @@ export class SftpService {
});
}
// +++ 新增:辅助方法 - 格式化 Stats 为 FileListItem +++
// +++ 辅助方法 - 格式化 Stats 为 FileListItem +++
private formatStatsToFileListItem(itemPath: string, stats: Stats): any {
return {
filename: pathModule.basename(itemPath),
@@ -75,3 +75,23 @@ export const updateTag = async (id: number, name: string): Promise<TagData | nul
export const deleteTag = async (id: number): Promise<boolean> => {
return TagRepository.deleteTag(id);
};
/**
* 更新标签与连接的关联关系
*/
export const updateTagConnections = async (tagId: number, connectionIds: number[]): Promise<void> => {
// 在服务层可以添加额外的业务逻辑,例如验证 tagId 和 connectionIds 的有效性
// 例如,检查标签是否存在,连接 ID 是否都存在于数据库中等。
// 此处为简化,直接调用 repository 方法。
// 确保 connectionIds 是一个数组,即使是空数组
const idsToUpdate = Array.isArray(connectionIds) ? connectionIds : [];
try {
await TagRepository.updateTagConnections(tagId, idsToUpdate);
} catch (error: any) {
// 服务层可以进一步处理或包装错误
console.error(`Service: 更新标签 ${tagId} 的连接关联时发生错误:`, error.message);
throw new Error(`服务层更新标签连接关联失败: ${error.message}`);
}
};