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

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

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

View File

@@ -1,6 +1,6 @@
import { useState, useEffect, useLayoutEffect, useRef, useCallback } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { ArrowLeft, ThumbsUp, Star, Pencil } from 'lucide-react';
import { ArrowLeft, ThumbsUp, Star, Pencil, Pin } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Spinner } from '@/components/ui/spinner';
@@ -162,6 +162,18 @@ export default function PostDetailPage() {
const authorInitial = post.user?.nickname?.[0] || '?';
const tags = post.tags?.split(/[,]/).map(t => t.trim()).filter(Boolean) ?? [];
const canEdit = user && (user.role === 'admin' || user.id === post.user_id);
const isAdmin = user?.role === 'admin';
const handlePin = async () => {
if (!post) return;
try {
const r = await api.adminPinPost(postId, !post.pinned);
setPost(p => p ? { ...p, pinned: r.pinned } : p);
notify.success(r.message);
} catch (e: unknown) {
notify.error(e instanceof Error ? e.message : '操作失败');
}
};
return (
<div className="page-wrap post-detail-page" ref={pageRef}>
@@ -217,6 +229,12 @@ export default function PostDetailPage() {
</Button>
)}
{isAdmin && (
<Button variant="outline" size="sm" onClick={handlePin}>
<Pin />
{post.pinned ? '取消置顶' : '置顶'}
</Button>
)}
</div>
</div>