update code level

This commit is contained in:
lychang
2026-07-21 02:25:36 +08:00
parent 005688b58f
commit cff2eb2886
6 changed files with 80 additions and 67 deletions

View File

@@ -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
});
});
}

View File

@@ -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<AlbumMeta> {

View File

@@ -30,6 +30,8 @@ pub struct AlbumWithImages {
pub album: Album,
pub images: Vec<super::image::Image>,
pub image_count: i64,
pub tags: Vec<String>,
pub persons: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]

View File

@@ -79,10 +79,26 @@ pub async fn get_random_album(cache: web::Data<Arc<RwLock<AlbumsCache>>>) -> imp
HttpResponse::Ok().json(&c.albums[idx])
}
pub async fn get_album_detail(db: web::Data<Arc<Database>>, path: web::Path<String>) -> impl Responder {
pub async fn get_album_detail(
db: web::Data<Arc<Database>>,
search_db: web::Data<Arc<SearchDb>>,
path: web::Path<String>,
) -> 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<String> = 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<String> = 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)})),
}

View File

@@ -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<Arc<RwLock<PersonCache>>>) -> 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<Arc<Database>>,
search_db: web::Data<Arc<SearchDb>>,
cache: web::Data<Arc<RwLock<PersonCache>>>,
path: web::Path<String>,
) -> 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<String> = (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 {

View File

@@ -273,30 +273,11 @@ impl SearchDb {
})
}
/// 获取人物的所有相册
pub async fn get_person_albums(&self, person_id: i64) -> Vec<AlbumInfo> {
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<String> {
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 标签(用于详情页)