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
+32 -10
View File
@@ -34,6 +34,7 @@ type ScanStatus struct {
Message string `json:"message"` // 简要说明
Started string `json:"started"` // 开始时间
Elapsed int64 `json:"elapsed"` // 已运行秒数
RootDir string `json:"rootDir"` // 本次扫描的根目录
Lines []string `json:"lines"` // 运行日志
}
@@ -44,6 +45,7 @@ type ScanService struct {
state ScanState
msg string
started time.Time
rootDir string
lines []string
}
@@ -52,20 +54,26 @@ func NewScanService(st *store.Store) *ScanService {
return &ScanService{store: st, state: ScanIdle}
}
// Start 启动一次扫描整理;已在运行时返回错误
func (s *ScanService) Start() error {
// Start 启动一次扫描整理;已在运行时返回错误。rootDir 为空时默认扫描当前运行目录。
func (s *ScanService) Start(rootDir string) error {
s.mu.Lock()
if s.state == ScanRunning {
s.mu.Unlock()
return errors.New("扫描整理正在运行中,请等待完成")
}
rootDir = resolveRootDir(rootDir)
if st, err := os.Stat(rootDir); err != nil || !st.IsDir() {
s.mu.Unlock()
return fmt.Errorf("扫描目录不存在或不可访问: %s", rootDir)
}
s.state = ScanRunning
s.msg = ""
s.started = time.Now()
s.rootDir = rootDir
s.lines = nil
s.mu.Unlock()
go s.run()
go s.run(rootDir)
return nil
}
@@ -82,12 +90,29 @@ func (s *ScanService) Status() ScanStatus {
Message: s.msg,
Started: s.started.Format("2006-01-02 15:04:05"),
Elapsed: elapsed,
RootDir: s.rootDir,
Lines: append([]string{}, s.lines...),
}
}
// resolveRootDir 解析扫描根目录:空值回退当前工作目录,并做绝对路径归一化
func resolveRootDir(dir string) string {
if strings.TrimSpace(dir) == "" {
wd, err := os.Getwd()
if err == nil {
return wd
}
return "."
}
abs, err := filepath.Abs(strings.TrimSpace(dir))
if err != nil {
return strings.TrimSpace(dir)
}
return abs
}
// run 后台执行:捕获 stdout 日志流式写入 lines,结束后更新状态
func (s *ScanService) run() {
func (s *ScanService) run(rootDir string) {
r, w, err := os.Pipe()
if err != nil {
s.finish(ScanError, "创建日志管道失败: "+err.Error())
@@ -112,7 +137,7 @@ func (s *ScanService) run() {
}
}()
scanErr := s.runScan()
scanErr := s.runScan(rootDir)
os.Stdout = oldStdout
_ = w.Close()
@@ -144,12 +169,9 @@ func sanitizeLine(line string) string {
}
// runScan 执行完整整理流程:扫描 → 过滤 → 释放解码器 → 归类 → 移动
func (s *ScanService) runScan() error {
rootDir, err := os.Getwd()
if err != nil {
return fmt.Errorf("获取当前路径异常: %v", err)
}
func (s *ScanService) runScan(rootDir string) error {
pickerDir := filepath.Join(rootDir, filepath.Base(rootDir)+"-picker")
fmt.Printf("=== 扫描根目录: %s \n", rootDir)
fmt.Printf("=== 整理输出目录(白名单): %s \n", pickerDir)
res, err := scanner.Scan(scanner.Options{