基于 Vue 3 + TypeScript + WebDAV 的WEB文件管理器,作为 iHPC 门户的轻量交互式文件管理入口。
大文件提示:WebDAV 受单 TCP 流限制,适合小文件交互管理;GB~TB 级数据请使用 rsync / Globus / SFTP(详见 webdav README 的「定位与大数据传输」小节)。
- 浏览 — 网格/列表视图切换,路径面包屑导航,前进/后退/向上
- 搜索 — 支持当前目录搜索和递归搜索子目录
- 新建 — 创建目录和文件
- 重命名 — 单文件内联重命名(F2 或工具栏),多文件批量重命名(支持前缀/后缀模式)
- 剪切/复制/粘贴 — 支持跨目录操作,剪贴板持久化
- 删除 — 支持多选批量删除
- 上传 — 拖拽上传、文件夹上传(保留目录结构)
- 下载 — 单文件和批量下载
- 远程下载 — 直接从 URL 下载文件到当前目录
- 文件编辑 — Monaco 编辑器,支持语法高亮、主题切换、多语言自动检测
- 同时连接多个 WebDAV 服务器(NAS、私有云等)
- 快速切换空间
- 收藏夹(按空间隔离)
- 左侧边栏目录树,支持懒加载展开
- 与当前路径自动同步
- 支持拖拽文件/文件夹到目录树节点
- 双主题 — 深色/浅色,主题切换按钮位于工具栏右侧
- 响应式 — 侧边栏可折叠
- 右键菜单 — 完整的上下文操作(打开/编辑/剪切/复制/重命名/删除/收藏)
- 键盘快捷键 —
Delete删除、F2重命名、Ctrl+A全选、Ctrl+C/X/V复制/剪切/粘贴
cd ../webdav && make && ./bin/ihpc-webdav -listen :8080 -dev-dev 为开发模式(dev 认证 + 免沙箱),无需 root(macOS/Linux 通用)。后端监听 http://localhost:8080;浏览器首次访问会弹 Basic Auth 框,输入任意非空账号密码即可。
bun install && bun dev访问 http://localhost:5173,默认以 /dav/ 连接本地服务(同源 Basic Auth)。
bun run type-check && bun run build-only # 前端类型检查 + 构建
cd ../webdav && go test -race ./... # 后端单测(详见 webdav/README.md 测试命令清单)| 类别 | 技术 |
|---|---|
| 框架 | Vue 3 <script setup> Composition API |
| 状态管理 | Pinia(setup store 风格) |
| 文件操作 | webdav npm v5.x |
| 编辑器 | Monaco Editor |
| 构建 | Vite + Bun |
src/
├── main.ts # 入口,主题防闪烁初始化
├── App.vue # 根组件
├── assets/global.css # CSS 变量(双主题)、全局样式
├── stores/
│ ├── webdav.ts # 核心:WebDAV 客户端、文件操作、多空间管理
│ ├── ui.ts # UI 状态(视图/排序/侧边栏/主题)
│ └── favorites.ts # 收藏夹(按空间隔离)
├── views/
│ └── FileBrowser.vue # 顶层视图,组装所有组件,处理事件总线
├── components/
│ ├── AppIcon.vue # 统一 SVG 图标组件(40+ 图标,含 legacy emoji 映射)
│ ├── layout/
│ │ ├── AppToolbar.vue # 工具栏(新建/上传/远程下载/编辑/重命名/主题切换)
│ │ ├── AppBreadcrumb.vue # 路径面包屑 + 前进/后退/向上
│ │ ├── AppSearch.vue # 搜索框(支持递归搜索)
│ │ ├── AppSidebar.vue # 左侧边栏(空间/收藏/目录树)
│ │ ├── DirTree.vue # 目录树根组件(懒加载、路径同步)
│ │ ├── DirTreeNode.vue # 目录树节点(递归,async self-import)
│ │ └── SpaceManager.vue # 空间管理对话框
│ ├── file/
│ │ ├── FileGrid.vue # 网格视图
│ │ ├── FileList.vue # 列表视图(含列头排序)
│ │ ├── FileItem.vue # 单个文件项(双击打开/编辑、内联重命名)
│ │ └── FileContextMenu.vue # 右键菜单
│ └── dialogs/
│ ├── NewFolderDialog.vue
│ ├── NewFileDialog.vue
│ ├── DeleteConfirmDialog.vue
│ ├── UploadDialog.vue # 支持拖拽、文件夹上传
│ ├── ConnectServerDialog.vue # 添加/编辑 WebDAV 空间
│ ├── FileEditorDialog.vue # Monaco 编辑器
│ ├── RemoteDownloadDialog.vue
│ └── BatchRenameDialog.vue # 批量重命名(逐个/前缀后缀)
├── utils/
│ ├── fileUtils.ts # formatSize/formatDate/joinPath/dirname/isTextFile 等
│ ├── fileIcons.ts # 扩展名 → AppIcon 图标名映射
│ └── treeTypes.ts # TreeNode 接口
Vite 开发服务器通过 /dav 代理转发到 http://localhost:8080:
// vite.config.ts
proxy: {
'/dav': {
target: 'http://localhost:8080',
rewrite: (path) => path.replace(/^\/dav/, ''),
},
}webdav 库在解析 PROPFIND 响应的 <d:href> 时使用 pathPosix.relative(remoteBasePath, href) 计算文件名。当客户端以 /dav 前缀初始化而服务器返回无前缀的 href 时,会导致路径解析错误。
通过 detectServerBasePath() 自动解决:连接时以 remoteBasePath='/' 探测根目录,解析所有 href 的公共前缀作为 serverBasePath,然后重建客户端。
initClient() 在 store 创建时异步执行,返回值存为 _initPromise。所有文件操作(navigate、loadFiles、searchFiles、getSubDirs 等)均先 await _initPromise,确保客户端初始化完成后再发请求。
始终使用 joinPath(dav.currentPath, file.basename) 导航,不要直接用 file.filename。PROPFIND 返回的 filename 是服务端相对路径,不含 /dav 前缀,直接使用会绕过代理导致 404。
- 深色为默认,
<html data-theme="dark|light">切换 CSS 变量实现双主题 main.ts在createApp().mount()前设置主题,避免闪烁- Monaco 编辑器主题跟随应用主题(
dark→vs-dark,light→vs)
双击文件 → isTextFile(basename) ? 打开编辑器 : 浏览器新标签打开
双击目录 → 进入目录
| 键 | 存储 | 内容 |
|---|---|---|
dav_spaces |
localStorage | 空间列表(不含密码) |
dav_active_space |
localStorage | 当前激活空间 ID |
dav_favorites_v2 |
localStorage | 收藏夹(按空间隔离) |
theme |
localStorage | dark | light |
view_mode |
localStorage | grid | list |
sort_field/sort_order |
localStorage | 排序设置 |
show_hidden_files |
localStorage | 是否显示隐藏文件 |
| 快捷键 | 功能 |
|---|---|
Delete / Backspace |
删除选中项 |
F2 |
重命名(单选时内联,多选时弹批量对话框) |
Ctrl+A |
全选 |
Ctrl+C |
复制 |
Ctrl+X |
剪切 |
Ctrl+V |
粘贴 |