feat: 实现文件浏览器功能

- 添加 /api/files 路由支持目录浏览和文件读取
- 支持 list、read、stat、tree 四个端点
- 安全路径检查防止目录遍历攻击
- 创建 FileBrowser React 组件
- 支持目录导航、文件预览、隐藏文件切换
- 在 Web UI 中添加可切换的文件浏览面板
This commit is contained in:
2025-12-12 11:55:11 +08:00
parent da1773b950
commit 6438ecf2a6
6 changed files with 719 additions and 7 deletions
+67
View File
@@ -94,3 +94,70 @@ export function createWebSocket(sessionId: string): WebSocket {
const host = window.location.host;
return new WebSocket(`${protocol}//${host}/api/ws/${sessionId}`);
}
// Files
export interface FileInfo {
name: string;
path: string;
type: 'file' | 'directory';
size: number;
modified: string;
extension?: string;
}
export interface FileListResponse {
success: boolean;
data: {
path: string;
absolutePath: string;
parent: string | null;
files: FileInfo[];
};
}
export interface FileReadResponse {
success: boolean;
data: {
path: string;
name: string;
type: string;
size: number;
modified: string;
content: string;
encoding: 'utf-8' | 'base64';
};
}
export interface FileTreeNode {
name: string;
path: string;
type: 'file' | 'directory';
children?: FileTreeNode[];
}
export interface FileTreeResponse {
success: boolean;
data: {
path: string;
tree: FileTreeNode[];
};
}
export async function getWorkingDirectory(): Promise<{ success: boolean; data: { workingDirectory: string; separator: string } }> {
return request('GET', '/files');
}
export async function listFiles(path: string = '.', showHidden: boolean = false): Promise<FileListResponse> {
const params = new URLSearchParams({ path });
if (showHidden) params.set('hidden', 'true');
return request('GET', `/files/list?${params}`);
}
export async function readFile(path: string): Promise<FileReadResponse> {
return request('GET', `/files/read?path=${encodeURIComponent(path)}`);
}
export async function getFileTree(path: string = '.', depth: number = 3): Promise<FileTreeResponse> {
const params = new URLSearchParams({ path, depth: String(depth) });
return request('GET', `/files/tree?${params}`);
}