feat(scan): 添加自定义扫描目录选择功能

- 在扫描页面添加目录输入框和选择按钮
- 实现文件系统浏览器,支持Windows盘符和目录浏览
- 添加扫描目录参数传递到后端服务
- 显示当前扫描目录路径信息
- 修复前端空数组访问错误
- 更新文档说明扫描功能变化
This commit is contained in:
2025-04-24 21:05:00 +08:00
parent e053b378fb
commit 14056ba7b9
13 changed files with 460 additions and 135 deletions
+88
View File
@@ -0,0 +1,88 @@
// Package api 提供服务器文件系统浏览接口,供前端目录选择器使用(只列出目录,不列文件)。
package api
import (
"net/http"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"github.com/gin-gonic/gin"
)
// FsController 服务器文件系统浏览控制器
type FsController struct{}
// NewFsController 创建文件系统浏览控制器
func NewFsController() *FsController {
return &FsController{}
}
// FsListResult 目录浏览结果
type FsListResult struct {
Current string `json:"current"` // 当前目录绝对路径;盘符层为空
Parent string `json:"parent"` // 父目录;根/盘符层时等于 Current
Drives []string `json:"drives"` // Windows 盘符列表(非 Windows 为空)
Dirs []FsDir `json:"dirs"` // 子目录列表(不含文件)
}
// FsDir 子目录项
type FsDir struct {
Name string `json:"name"`
Path string `json:"path"`
}
// List GET /api/fs/list?dir= 列出指定目录的子目录(不含文件);
// dir 为空时返回 Windows 盘符列表或 Unix 根目录。
func (c *FsController) List(ctx *gin.Context) {
dir := strings.TrimSpace(ctx.Query("dir"))
if dir == "" {
if runtime.GOOS == "windows" {
Success(ctx, FsListResult{Drives: listLogicalDrives()})
return
}
dir = string(os.PathSeparator)
}
abs, err := filepath.Abs(dir)
if err != nil {
Error(ctx, http.StatusBadRequest, "路径解析失败: "+err.Error())
return
}
st, err := os.Stat(abs)
if err != nil || !st.IsDir() {
Error(ctx, http.StatusBadRequest, "目录不存在或不可访问: "+abs)
return
}
entries, err := os.ReadDir(abs)
if err != nil {
Error(ctx, http.StatusBadRequest, "读取目录失败: "+err.Error())
return
}
parent := filepath.Dir(abs)
if parent == abs {
parent = abs
}
dirs := make([]FsDir, 0, len(entries))
for _, e := range entries {
if !e.IsDir() {
continue
}
dirs = append(dirs, FsDir{Name: e.Name(), Path: filepath.Join(abs, e.Name())})
}
sort.Slice(dirs, func(i, j int) bool {
return strings.ToLower(dirs[i].Name) < strings.ToLower(dirs[j].Name)
})
Success(ctx, FsListResult{
Current: abs,
Parent: parent,
Drives: nil,
Dirs: dirs,
})
}