feat: Library 批量注册 + PeopleView 修复 + 国际化
Library: - 添加 checkbox 和鼠标框选功能 - Unregistered 卡片添加快速注册按钮 - 状态标签移至左下方,人脸图标移至左侧中间 - Deep Scan 改为 unregister -> register -> process - 完整国际化(日语、繁体中文、英语) PeopleView: - 修复卡片不显示问题(使用 get_file_traces API) - 移除对 identity_id 字段的依赖 其他: - 添加日语语言包 - 添加 useDragSelect composable - 新增文档:Face Bbox Null Bug Report
This commit is contained in:
@@ -24,6 +24,16 @@ CREATE TABLE IF NOT EXISTS bookmarks (
|
||||
created_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS video_marks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
file_uuid TEXT NOT NULL,
|
||||
tag TEXT NOT NULL,
|
||||
start_frame INTEGER NOT NULL,
|
||||
end_frame INTEGER,
|
||||
note TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS app_users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
@@ -36,6 +46,7 @@ CREATE TABLE IF NOT EXISTS app_users (
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_search_history_sort ON search_history(pinned DESC, updated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_bookmarks_created ON bookmarks(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_video_marks_file ON video_marks(file_uuid);
|
||||
";
|
||||
|
||||
static DB_CONN: Mutex<Option<Connection>> = Mutex::new(None);
|
||||
@@ -281,6 +292,75 @@ pub fn delete_bookmark(id: i64) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct VideoMark {
|
||||
pub id: i64,
|
||||
pub file_uuid: String,
|
||||
pub tag: String,
|
||||
pub start_frame: i64,
|
||||
pub end_frame: Option<i64>,
|
||||
pub note: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
pub fn get_video_marks(file_uuid: String) -> Result<Vec<VideoMark>, String> {
|
||||
let conn = get_conn()?;
|
||||
let mut stmt = conn
|
||||
.prepare("SELECT id, file_uuid, tag, start_frame, end_frame, note, created_at FROM video_marks WHERE file_uuid = ?1 ORDER BY start_frame ASC")
|
||||
.map_err(|e| format!("Prepare error: {}", e))?;
|
||||
let items = stmt
|
||||
.query_map([file_uuid], |row| {
|
||||
Ok(VideoMark {
|
||||
id: row.get(0)?,
|
||||
file_uuid: row.get(1)?,
|
||||
tag: row.get(2)?,
|
||||
start_frame: row.get(3)?,
|
||||
end_frame: row.get(4)?,
|
||||
note: row.get(5)?,
|
||||
created_at: row.get(6)?,
|
||||
})
|
||||
})
|
||||
.map_err(|e| format!("Query error: {}", e))?
|
||||
.filter_map(|r| r.ok())
|
||||
.collect();
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
pub fn save_video_mark(
|
||||
file_uuid: String,
|
||||
tag: String,
|
||||
start_frame: i64,
|
||||
end_frame: Option<i64>,
|
||||
note: Option<String>,
|
||||
) -> Result<VideoMark, String> {
|
||||
let conn = get_conn()?;
|
||||
conn.execute(
|
||||
"INSERT INTO video_marks (file_uuid, tag, start_frame, end_frame, note) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
rusqlite::params![file_uuid, tag, start_frame, end_frame, note],
|
||||
)
|
||||
.map_err(|e| format!("Insert error: {}", e))?;
|
||||
let id = conn.last_insert_rowid();
|
||||
Ok(VideoMark {
|
||||
id,
|
||||
file_uuid,
|
||||
tag,
|
||||
start_frame,
|
||||
end_frame,
|
||||
note,
|
||||
created_at: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
pub fn delete_video_mark(id: i64) -> Result<(), String> {
|
||||
let conn = get_conn()?;
|
||||
conn.execute("DELETE FROM video_marks WHERE id = ?1", [id])
|
||||
.map_err(|e| format!("Delete error: {}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_user(username: &str, password: &str) -> Result<Option<User>, String> {
|
||||
let conn = get_conn()?;
|
||||
let mut stmt = conn
|
||||
|
||||
Reference in New Issue
Block a user