fix: 待审通知实时回填审核态并重构消息页体验

This commit is contained in:
2026-09-02 01:39:27 +08:00
parent 2e9c42a34c
commit 1c0f7ede55
18 changed files with 1458 additions and 463 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useEffect, useRef, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { Search, Lock, LockOpen, MessageSquareOff, Trash2, RotateCcw } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -32,6 +32,8 @@ function formatAdminTime(iso: string) {
export default function AdminPostsPage() {
const nav = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const focusId = Number(searchParams.get('id') || 0) || 0;
const { ready } = useAdminGuard();
const [tab, setTab] = useState<Tab>('pending');
const [posts, setPosts] = useState<PostItem[]>([]);
@@ -42,6 +44,9 @@ export default function AdminPostsPage() {
const [pendingCount, setPendingCount] = useState(0);
const [keyword, setKeyword] = useState('');
const [search, setSearch] = useState('');
const [highlightId, setHighlightId] = useState<number | null>(focusId > 0 ? focusId : null);
const focusTriedRef = useRef(false);
const highlightTimer = useRef<ReturnType<typeof setTimeout>>();
const loadActive = (p = page, kw = search, status = tab === 'pending' ? 'pending' : 'all') => {
setLoading(true);
@@ -92,6 +97,43 @@ export default function AdminPostsPage() {
// eslint-disable-next-line react-hooks/exhaustive-deps -- 仅随 tab/search/ready 刷新
}, [ready, search, tab]);
// 从通知深链 ?id= 定位并高亮
useEffect(() => {
if (!ready || loading || focusId <= 0 || focusTriedRef.current) return;
if (tab === 'trash') return;
const found = posts.find((p) => p.id === focusId);
if (found) {
focusTriedRef.current = true;
setHighlightId(focusId);
requestAnimationFrame(() => {
document.getElementById(`admin-post-row-${focusId}`)?.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
});
clearTimeout(highlightTimer.current);
highlightTimer.current = setTimeout(() => setHighlightId(null), 2800);
const next = new URLSearchParams(searchParams);
next.delete('id');
setSearchParams(next, { replace: true });
return;
}
if (tab === 'pending') {
setTab('active');
return;
}
focusTriedRef.current = true;
notify.warning('该帖子可能已审核或不在当前列表');
const next = new URLSearchParams(searchParams);
next.delete('id');
setSearchParams(next, { replace: true });
}, [ready, loading, posts, focusId, tab, searchParams, setSearchParams]);
useEffect(() => () => clearTimeout(highlightTimer.current), []);
const switchTab = (next: Tab) => {
if (next === tab) return;
setTab(next);
@@ -352,7 +394,11 @@ export default function AdminPostsPage() {
{posts.map(p => {
const edited = p.updated_at && isTimeDiffSignificant(p.created_at, p.updated_at);
return (
<tr key={p.id}>
<tr
key={p.id}
id={`admin-post-row-${p.id}`}
className={cn(highlightId === p.id && 'admin-row-highlight')}
>
<td>{p.id}</td>
<td className="max-w-[200px] truncate">
<button type="button" className="admin-text-link" onClick={() => nav(`/post/${p.id}`)}>