fix(admin): 评论管理页多项修复

- 修复默认头像无法显示:AdminComment 添加 avatar_url 字段
- 修复状态标签换行:移除 w-20 固定宽度,添加 whitespace-nowrap
- 操作按钮添加 cursor-pointer
- 已处于该状态的评论隐藏对应操作按钮
- 修复操作后页面不自动刷新:将 restart() 移到异步块内
This commit is contained in:
xfy 2026-06-11 16:10:42 +08:00
parent b55409d421
commit 569eec5bf8
3 changed files with 37 additions and 21 deletions

View File

@ -39,6 +39,7 @@ pub fn row_to_public_comment(row: &tokio_postgres::Row) -> PublicComment {
#[cfg(feature = "server")] #[cfg(feature = "server")]
pub fn row_to_admin_comment(row: &tokio_postgres::Row) -> AdminComment { pub fn row_to_admin_comment(row: &tokio_postgres::Row) -> AdminComment {
let status_str: String = row.get("status"); let status_str: String = row.get("status");
let email: String = row.get("author_email");
AdminComment { AdminComment {
id: row.get("id"), id: row.get("id"),
@ -48,8 +49,9 @@ pub fn row_to_admin_comment(row: &tokio_postgres::Row) -> AdminComment {
parent_id: row.get("parent_id"), parent_id: row.get("parent_id"),
depth: row.get("depth"), depth: row.get("depth"),
author_name: row.get("author_name"), author_name: row.get("author_name"),
author_email: row.get("author_email"), author_email: email.clone(),
author_url: row.get("author_url"), author_url: row.get("author_url"),
avatar_url: gravatar_url(&email),
content_md: row.get("content_md"), content_md: row.get("content_md"),
status: CommentStatus::from_str(&status_str), status: CommentStatus::from_str(&status_str),
created_at: row.get("created_at"), created_at: row.get("created_at"),

View File

@ -77,6 +77,7 @@ pub struct AdminComment {
pub author_name: String, pub author_name: String,
pub author_email: String, pub author_email: String,
pub author_url: Option<String>, pub author_url: Option<String>,
pub avatar_url: String,
pub content_md: String, pub content_md: String,
pub status: CommentStatus, pub status: CommentStatus,
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,

View File

@ -167,7 +167,7 @@ pub fn AdminCommentsPage(page: i32) -> Element {
th { class: "px-4 py-3 font-medium", "作者" } th { class: "px-4 py-3 font-medium", "作者" }
th { class: "px-4 py-3 font-medium", "内容" } th { class: "px-4 py-3 font-medium", "内容" }
th { class: "px-4 py-3 font-medium", "文章" } th { class: "px-4 py-3 font-medium", "文章" }
th { class: "px-4 py-3 font-medium w-20 text-center", "状态" } th { class: "px-4 py-3 font-medium text-center", "状态" }
th { class: "px-4 py-3 font-medium w-28", "日期" } th { class: "px-4 py-3 font-medium w-28", "日期" }
th { class: "px-4 py-3 font-medium w-32 text-right", "操作" } th { class: "px-4 py-3 font-medium w-32 text-right", "操作" }
} }
@ -187,26 +187,29 @@ pub fn AdminCommentsPage(page: i32) -> Element {
} }
}, },
on_approve: { on_approve: {
let mut comments_res = comments_res;
let id = comment.id; let id = comment.id;
move |_| { move |_| {
spawn(async move { spawn(async move {
let _ = approve_comment(id).await; let _ = approve_comment(id).await;
});
comments_res.restart(); comments_res.restart();
});
} }
}, },
on_spam: { on_spam: {
let mut comments_res = comments_res;
let id = comment.id; let id = comment.id;
move |_| { move |_| {
spawn(async move { spawn(async move {
let _ = spam_comment(id).await; let _ = spam_comment(id).await;
});
comments_res.restart(); comments_res.restart();
});
} }
}, },
on_trash: { on_trash: {
#[allow(unused_variables)] #[allow(unused_variables)]
let id = comment.id; let mut comments_res = comments_res;
let _id = comment.id;
move |_| { move |_| {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
{ {
@ -214,11 +217,11 @@ pub fn AdminCommentsPage(page: i32) -> Element {
.and_then(|w| w.confirm_with_message("确定要删除这条评论吗?").ok()) .and_then(|w| w.confirm_with_message("确定要删除这条评论吗?").ok())
.unwrap_or(false) .unwrap_or(false)
{ {
let id = id; let id = _id;
spawn(async move { spawn(async move {
let _ = trash_comment(id).await; let _ = trash_comment(id).await;
});
comments_res.restart(); comments_res.restart();
});
} }
} }
} }
@ -296,7 +299,11 @@ fn CommentRow(
} }
td { class: "px-4 py-3", td { class: "px-4 py-3",
div { class: "flex items-center gap-2", div { class: "flex items-center gap-2",
div { class: "w-8 h-8 rounded-full bg-gray-200 dark:bg-[#444] flex-shrink-0" } img {
class: "w-8 h-8 rounded-full flex-shrink-0",
src: "{comment.avatar_url}",
alt: "{comment.author_name}",
}
div { class: "min-w-0", div { class: "min-w-0",
div { class: "text-sm font-medium text-gray-900 dark:text-[#dadadb] truncate", div { class: "text-sm font-medium text-gray-900 dark:text-[#dadadb] truncate",
"{comment.author_name}" "{comment.author_name}"
@ -320,7 +327,7 @@ fn CommentRow(
} }
} }
td { class: "px-4 py-3 text-center", td { class: "px-4 py-3 text-center",
span { class: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {badge_class}", span { class: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium whitespace-nowrap {badge_class}",
"{status_label}" "{status_label}"
} }
} }
@ -329,18 +336,23 @@ fn CommentRow(
} }
td { class: "px-4 py-3 text-right", td { class: "px-4 py-3 text-right",
div { class: "flex justify-end gap-2", div { class: "flex justify-end gap-2",
if !matches!(comment.status, CommentStatus::Approved) {
button { button {
class: "text-xs text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-300 transition-colors", class: "text-xs text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-300 transition-colors cursor-pointer",
onclick: move |_| on_approve.call(()), onclick: move |_| on_approve.call(()),
"通过" "通过"
} }
}
if !matches!(comment.status, CommentStatus::Spam) {
button { button {
class: "text-xs text-amber-600 hover:text-amber-800 dark:text-amber-400 dark:hover:text-amber-300 transition-colors", class: "text-xs text-amber-600 hover:text-amber-800 dark:text-amber-400 dark:hover:text-amber-300 transition-colors cursor-pointer",
onclick: move |_| on_spam.call(()), onclick: move |_| on_spam.call(()),
"垃圾" "垃圾"
} }
}
if !matches!(comment.status, CommentStatus::Trash) {
button { button {
class: "text-xs text-red-500 hover:text-red-700 dark:hover:text-red-300 transition-colors", class: "text-xs text-red-500 hover:text-red-700 dark:hover:text-red-300 transition-colors cursor-pointer",
onclick: move |_| on_trash.call(()), onclick: move |_| on_trash.call(()),
"删除" "删除"
} }
@ -349,6 +361,7 @@ fn CommentRow(
} }
} }
} }
}
#[component] #[component]
fn CommentsPagination(current_page: i32, total: i64) -> Element { fn CommentsPagination(current_page: i32, total: i64) -> Element {