From cff2eb28867671bafc2b210626ee08ea60d51cb8 Mon Sep 17 00:00:00 2001 From: lychang <632945494@qq.com> Date: Tue, 21 Jul 2026 02:25:36 +0800 Subject: [PATCH] update code level --- assets/js/album.js | 51 ++++++++++++----------------------------- src/db/album.rs | 2 +- src/models/album.rs | 2 ++ src/routes/album.rs | 20 ++++++++++++++-- src/routes/person.rs | 43 ++++++++++++++++++++++++++++++---- src/search_db/search.rs | 29 ++++------------------- 6 files changed, 80 insertions(+), 67 deletions(-) diff --git a/assets/js/album.js b/assets/js/album.js index 684d3c2..ceba37a 100644 --- a/assets/js/album.js +++ b/assets/js/album.js @@ -323,47 +323,26 @@ function updateAlbumMeta() { let chips = []; - // 添加人名标签 - if (currentAlbum.person_name_cleaned) { - chips.push({ - text: currentAlbum.person_name_cleaned, - type: 'person', - category: 'person', - query: currentAlbum.person_name_cleaned + // 添加人名标签(从 search.db 返回的 persons 数组) + if (currentAlbum.persons && Array.isArray(currentAlbum.persons)) { + currentAlbum.persons.forEach(name => { + chips.push({ + text: name, + type: 'person', + category: 'person', + query: name + }); }); } - // 添加标签(支持多种格式) - if (currentAlbum.tags) { - let tagList = []; - try { - const parsed = JSON.parse(currentAlbum.tags); - if (Array.isArray(parsed)) { - parsed.forEach(item => { - if (Array.isArray(item)) { - tagList.push({ text: item[0], category: item[1] || 'default' }); - } else if (typeof item === 'string') { - tagList.push({ text: item, category: getTagCategory(item) }); - } else if (item.tag || item.name) { - const t = item.tag || item.name; - const c = item.category || item.type || getTagCategory(t); - tagList.push({ text: t, category: c }); - } - }); - } - } catch (e) { - currentAlbum.tags.split(',').forEach(tag => { - const t = tag.trim(); - if (t) tagList.push({ text: t, category: getTagCategory(t) }); - }); - } - - tagList.forEach(t => { + // 添加标签(从 search.db 返回的 tags 数组) + if (currentAlbum.tags && Array.isArray(currentAlbum.tags)) { + currentAlbum.tags.forEach(tag => { chips.push({ - text: t.text, + text: tag, type: 'tag', - category: t.category, - query: t.text + category: getTagCategory(tag), + query: tag }); }); } diff --git a/src/db/album.rs b/src/db/album.rs index 975e646..c1363fd 100644 --- a/src/db/album.rs +++ b/src/db/album.rs @@ -165,7 +165,7 @@ impl Database { }); } - Ok(Some(AlbumWithImages { album, images: images.clone(), image_count: images.len() as i64 })) + Ok(Some(AlbumWithImages { album, images: images.clone(), image_count: images.len() as i64, tags: vec![], persons: vec![] })) } pub async fn get_all_albums_full(&self) -> Vec { diff --git a/src/models/album.rs b/src/models/album.rs index 24c697b..9b9309c 100644 --- a/src/models/album.rs +++ b/src/models/album.rs @@ -30,6 +30,8 @@ pub struct AlbumWithImages { pub album: Album, pub images: Vec, pub image_count: i64, + pub tags: Vec, + pub persons: Vec, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/routes/album.rs b/src/routes/album.rs index 6524c9e..6dad693 100644 --- a/src/routes/album.rs +++ b/src/routes/album.rs @@ -79,10 +79,26 @@ pub async fn get_random_album(cache: web::Data>>) -> imp HttpResponse::Ok().json(&c.albums[idx]) } -pub async fn get_album_detail(db: web::Data>, path: web::Path) -> impl Responder { +pub async fn get_album_detail( + db: web::Data>, + search_db: web::Data>, + path: web::Path, +) -> impl Responder { let id = match Uuid::parse_str(&path.into_inner()) { Ok(id) => id, Err(_) => return HttpResponse::BadRequest().json(serde_json::json!({"error": "无效ID"})) }; + let id_str = id.to_string(); match db.get_album_with_images(id).await { - Ok(Some(album)) => HttpResponse::Ok().json(album), + Ok(Some(mut album)) => { + // 从 search.db 查询该相册的 tags 和 persons + let tag_rows: Vec = sqlx::query_scalar( + r#"SELECT t.name FROM album_tags at JOIN tags t ON at.tag_id = t.id WHERE at.album_id = ?"# + ).bind(&id_str).fetch_all(&search_db.pool).await.unwrap_or_default(); + let person_rows: Vec = sqlx::query_scalar( + r#"SELECT p.name FROM album_persons ap JOIN persons p ON ap.person_id = p.id WHERE ap.album_id = ?"# + ).bind(&id_str).fetch_all(&search_db.pool).await.unwrap_or_default(); + album.tags = tag_rows; + album.persons = person_rows; + HttpResponse::Ok().json(album) + } Ok(None) => HttpResponse::NotFound().json(serde_json::json!({"error": "相册不存在"})), Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({"error": format!("{}", e)})), } diff --git a/src/routes/person.rs b/src/routes/person.rs index 7d12a67..4957736 100644 --- a/src/routes/person.rs +++ b/src/routes/person.rs @@ -1,10 +1,13 @@ use crate::cache::PersonCache; +use crate::db::Database; use crate::search_db::SearchDb; use crate::models::*; use actix_web::{HttpResponse, Responder, web}; +use sqlx::Row; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; +use uuid::Uuid; /// GET /api/people — 从内存缓存获取所有人名列表 pub async fn get_people(cache: web::Data>>) -> impl Responder { @@ -35,21 +38,53 @@ pub async fn search_people( }) } -/// GET /api/people/{name} — 从 search.db 查找人物详情(缓存查人物信息,search.db 查相册列表) +/// GET /api/people/{name} — 查找人物详情 +/// 人物基本信息从内存缓存获取,相册列表从 imager.db 查询 pub async fn get_person_detail( + db: web::Data>, search_db: web::Data>, cache: web::Data>>, path: web::Path, ) -> impl Responder { let name = path.into_inner(); let c = cache.read().await; - // 在内存缓存中查找人物 let found = c.search(&name); let p = found.into_iter().find(|p| p.name.to_lowercase() == name.to_lowercase()); match p { Some(p) => { - // 相册列表从 search.db 获取 - let albums = search_db.get_person_albums(p.id).await; + // 从 search.db 获取相册 ID 列表 + let album_ids = search_db.get_person_album_ids(p.id).await; + // 从 imager.db 查询相册详情 + let albums = if album_ids.is_empty() { + Vec::new() + } else { + let placeholders: Vec = (0..album_ids.len()).map(|_| "?".to_string()).collect(); + let sql = format!( + "SELECT id, title, document, description, cover_image_id, image_count, created_at \ + FROM albums WHERE id IN ({}) ORDER BY created_at DESC", + placeholders.join(", ") + ); + let mut query = sqlx::query(&sql); + for id in &album_ids { + query = query.bind(id); + } + query.fetch_all(&db.pool).await.unwrap_or_default() + .iter().map(|r| { + let id_str: String = r.get("id"); + AlbumInfo { + id: Uuid::parse_str(&id_str).unwrap_or_else(|_| Uuid::nil()), + title: r.get("title"), + document: r.get("document"), + description: r.get("description"), + cover_image_id: r.get("cover_image_id"), + image_count: r.get("image_count"), + created_at: r.get("created_at"), + tags: vec![], + persons: vec![], + } + }).collect() + }; + HttpResponse::Ok().json(PersonWithAlbums { album_count: albums.len(), person: Person { diff --git a/src/search_db/search.rs b/src/search_db/search.rs index 7c2a46e..c5d0307 100644 --- a/src/search_db/search.rs +++ b/src/search_db/search.rs @@ -273,30 +273,11 @@ impl SearchDb { }) } - /// 获取人物的所有相册 - pub async fn get_person_albums(&self, person_id: i64) -> Vec { - let rows = sqlx::query( - r#"SELECT a.id, a.title, a.cover_image_id, a.image_count, a.created_at - FROM albums a - JOIN album_persons ap ON a.id = ap.album_id - WHERE ap.person_id = ? - ORDER BY a.created_at DESC"# - ).bind(person_id).fetch_all(&self.pool).await.unwrap_or_default(); - - rows.iter().map(|r| { - let id_str: String = r.get("id"); - AlbumInfo { - id: Uuid::parse_str(&id_str).unwrap_or_else(|_| Uuid::nil()), - title: r.get("title"), - document: String::new(), - description: None, - cover_image_id: r.get("cover_image_id"), - image_count: r.get("image_count"), - created_at: r.get("created_at"), - tags: vec![], - persons: vec![], - } - }).collect() + /// 获取人物的所有相册 ID(从 search.db 的 album_persons 关联表查询) + pub async fn get_person_album_ids(&self, person_id: i64) -> Vec { + sqlx::query_scalar::<_, String>( + "SELECT album_id FROM album_persons WHERE person_id = ?" + ).bind(person_id).fetch_all(&self.pool).await.unwrap_or_default() } /// 获取人物的 top 标签(用于详情页)