From bcfd30664348986813aeb435cf7f18ea51c08e07 Mon Sep 17 00:00:00 2001 From: freefire Date: Mon, 31 Aug 2026 00:08:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AF=84=E8=AE=BA=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=94=B6=E8=BF=9B=E6=9B=B4=E5=A4=9A=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=EF=BC=8C=E5=87=8F=E5=B0=91=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E6=9D=82=E4=B9=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- frontend/src/components/CommentThreadList.tsx | 169 ++++++++++-------- frontend/src/styles/global.css | 7 + 2 files changed, 103 insertions(+), 73 deletions(-) diff --git a/frontend/src/components/CommentThreadList.tsx b/frontend/src/components/CommentThreadList.tsx index b751df5..95cccec 100644 --- a/frontend/src/components/CommentThreadList.tsx +++ b/frontend/src/components/CommentThreadList.tsx @@ -18,7 +18,6 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, - AlertDialogTrigger, } from '@/components/ui/alert-dialog'; import { Dialog, @@ -32,6 +31,8 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Button } from '@/components/ui/button'; @@ -144,6 +145,11 @@ function CommentItem({ && !!onApprove; const showEdited = !hidden && !!c.updated_at && isTimeDiffSignificant(c.created_at, c.updated_at); const canReport = !hidden && !isEditing && !isCommentAuthor(c, currentUser); + const showHistory = isAdmin && showEdited; + const showManageMenu = !hidden && !isEditing && ( + canApprove || canEdit || showHistory || canDelete || canReport + ); + const showManageGroup = canApprove || canEdit || showHistory || canDelete; const [editText, setEditText] = useState(c.content); const [saving, setSaving] = useState(false); const [deleting, setDeleting] = useState(false); @@ -152,6 +158,7 @@ function CommentItem({ const [liked, setLiked] = useState(!!c.liked); const [likeCount, setLikeCount] = useState(c.like_count ?? 0); const [revOpen, setRevOpen] = useState(false); + const [deleteOpen, setDeleteOpen] = useState(false); const [reportOpen, setReportOpen] = useState(false); const [reportReason, setReportReason] = useState('spam'); const [reportDetail, setReportDetail] = useState(''); @@ -333,24 +340,6 @@ function CommentItem({ {c.reply_target && ( @{commentNick(c.reply_target)} )} - {!hidden && !isEditing && canApprove && ( - - )} {!hidden && !isEditing && !!renderReplyBox && ( isReplying ? ( - )} {bountyAward?.open && bountyAward.canAward && c.user_id !== bountyAward.postAuthorId && c.status === 'published' && !hidden && ( - )} - {!hidden && !isEditing && canDelete && ( - - - - - - - 确定删除该评论? - - 将同时移入回收站其下所有回复,可在后台恢复或永久删除。 - - - - 取消 - { - setDeleting(true); - try { - await onDelete(c); - } finally { - setDeleting(false); - } - }} - > - 删除 - - - - - )} - {canReport && ( + {showManageMenu && ( - - - - 举报 - + + {showManageGroup && ( + <> + 管理 + {canApprove && ( + { + void (async () => { + setApproving(true); + try { + await onApprove?.(c); + } finally { + setApproving(false); + } + })(); + }} + > + + {approving ? '通过中…' : '通过审核'} + + )} + {canEdit && ( + onStartEdit(c)}> + + 编辑 + + )} + {showHistory && ( + setRevOpen(true)}> + + 编辑记录 + + )} + {canDelete && ( + setDeleteOpen(true)} + > + + 删除 + + )} + {canReport && } + + )} + {canReport && ( + + + 举报 + + )} )} + + + + 确定删除该评论? + + 将同时移入回收站其下所有回复,可在后台恢复或永久删除。 + + + + 取消 + { + e.preventDefault(); + void (async () => { + setDeleting(true); + try { + await onDelete(c); + setDeleteOpen(false); + } finally { + setDeleting(false); + } + })(); + }} + > + 删除 + + + + + {isAdmin && ( )} diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 68bdc11..f5bd65b 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -5017,6 +5017,13 @@ a.post-title:visited { background: color-mix(in srgb, hsl(var(--destructive)) 10%, transparent); } +/* 评论管理菜单(编辑 / 审核 / 删除 / 举报) */ +.comment-manage-menu { + min-width: 9.5rem; + max-height: 70vh; + overflow-y: auto; +} + .report-more-menu__item svg { width: 14px; height: 14px;