feat: 增加 Web 管理界面,扫描整理改为页面点击触发

- main.go 改为 Web 服务入口(Gin + 内嵌前端 dist + 自动打开浏览器)
- internal/service: 新增扫描整理后台任务,支持状态机与实时日志捕获
- internal/api: 新增统一响应、媒体列表/统计、扫描开始/状态接口
- internal/store: 追加 ListMedia/CountMedia/Stats 查询,MediaInfo 补 JSON tag
- internal/config: application.properties 配置加载(端口/数据库/自动开浏览器)
- frontend: Vue2 + ElementUI + Vite 工程,含扫描整理/统计看板/媒体库三页
- build.sh 整合前端构建,输出单一 kenaito-media-picker.exe
This commit is contained in:
2025-04-21 21:08:02 +08:00
parent 767b093b45
commit e053b378fb
29 changed files with 3684 additions and 104 deletions
+43 -1
View File
@@ -1,7 +1,10 @@
// Package classify 提供纯函数的分辨率归类规则,不依赖任何状态。
package classify
import "strings"
import (
"fmt"
"strings"
)
// Orientation 画面方向
type Orientation int
@@ -72,3 +75,42 @@ func longEdge(w, h int) int {
}
return h
}
// ResLabel 返回分辨率档位标签(标准后缀 / 1K~19K / 普通 / 原图),无有效尺寸时返回空串。
// 供媒体库统计与筛选使用,图片/视频统一以"原图"作为超档标签。
func ResLabel(width, height int) string {
if width <= 0 || height <= 0 {
return ""
}
if suffix := matchStandard(width, height); suffix != "" {
return suffix
}
return levelName(longEdge(width, height), "原图")
}
// ResRange 解析分辨率档位标签,返回 (长边下限 minLong, 长边上限 maxLong(不含), 精确宽 exactW, 精确高 exactH)。
// minLong<0 表示未知标签;maxLong 为 -1 表示无上限;exactW/exactH 非零时表示标准分辨率精确匹配。
// 供数据层构造 SQL 过滤条件,规则与归类逻辑保持一致。
func ResRange(label string) (minLong, maxLong, exactW, exactH int) {
if label == "" {
return -1, -1, 0, 0
}
for _, r := range standardResolutions {
if r.suffix == label {
return 0, 0, r.width, r.height
}
}
if label == "普通" {
return 0, bucketStep, 0, 0
}
if label == "原图" {
return (maxLevel + 1) * bucketStep, -1, 0, 0
}
if len(label) > 1 && label[len(label)-1] == 'K' {
var level int
if _, err := fmt.Sscanf(label, "%dK", &level); err == nil && level >= 1 && level <= maxLevel {
return level * bucketStep, (level + 1) * bucketStep, 0, 0
}
}
return -1, -1, 0, 0
}