统一 React 管理后台,修复评论换行与帖子置顶

- /admin/* 全部由 React SPA 渲染,替代旧版 HTML 后台页面
- 新增仪表盘、帖子/评论/用户管理、系统设置与 JSON API
- 帖子详情页支持管理员置顶;评论换行显示修复

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
freefire
2026-06-15 23:06:44 +08:00
parent 9230f7272d
commit d0555de28e
63 changed files with 1289 additions and 284 deletions

View File

@@ -33,7 +33,7 @@ export default function BoardGrid({ boards, loading = false, selectedId = 0, onS
</p>
{user?.role === 'admin' && (
<div style={{ textAlign: 'center', marginTop: 12 }}>
<Button onClick={() => nav('/boards')}>
<Button onClick={() => nav('/admin/boards')}>
<Plus />
</Button>

View File

@@ -8,12 +8,11 @@ interface Props {
/** 渲染评论正文(支持正文内 @ 高亮) */
export default function CommentContent({ content, onMentionClick }: Props) {
return (
<div className="floor-body">
<span
dangerouslySetInnerHTML={{
__html: highlightMentions(content, onMentionClick),
}}
/>
</div>
<div
className="floor-body"
dangerouslySetInnerHTML={{
__html: highlightMentions(content, onMentionClick),
}}
/>
);
}

View File

@@ -50,7 +50,7 @@ export default function FeedHeader({ boardId, keyword, boards, stats, postTotal
<Button size="sm" onClick={() => nav('/login')}></Button>
)}
{!authLoading && user?.role === 'admin' && (
<Button size="sm" variant="outline" onClick={() => nav('/boards')}>
<Button size="sm" variant="outline" onClick={() => nav('/admin/boards')}>
<Settings />
</Button>

View File

@@ -1,10 +1,9 @@
import {
Home, Settings, Star, LayoutDashboard,
Home, Star, LayoutDashboard,
} from 'lucide-react';
import { useNavigate, useLocation } from 'react-router-dom';
import type { Board } from '../api/types';
import { useAuth } from '../hooks/useAuth';
import { openAdminDashboard } from '../utils/admin';
import { cn } from '@/lib/utils';
// 内容页不参与左侧栏高亮(非 feed 浏览上下文)
@@ -17,7 +16,7 @@ export function isNeutralSidebarRoute(pathname: string): boolean {
function resolveMenuKey(pathname: string, activeBoard: number): string | null {
if (isNeutralSidebarRoute(pathname)) return null;
if (pathname.startsWith('/favorites')) return 'favorites';
if (pathname.startsWith('/boards')) return 'boards';
if (pathname.startsWith('/admin')) return 'admin';
return activeBoard === 0 ? 'all' : String(activeBoard);
}
@@ -77,8 +76,7 @@ export default function Sidebar({ boards, activeBoard, onSelectBoard }: Props) {
<>
<div className="sidebar-section" style={{ marginTop: 8 }}></div>
<nav className="sidebar-nav">
{navItem('boards', '管理板块', <Settings />, () => nav('/boards'))}
{navItem('admin', '系统后台', <LayoutDashboard />, openAdminDashboard)}
{navItem('admin', '管理后台', <LayoutDashboard />, () => nav('/admin/dashboard'))}
</nav>
</>
)}