import { useState, useEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; const STATUS_LABELS = { open: '待处理', in_progress: '处理中', closed: '已关闭' }; const STATUS_COLORS = { open: { color: '#f59e0b', bg: '#fffbeb' }, in_progress: { color: '#3b82f6', bg: '#eff6ff' }, closed: { color: '#10b981', bg: '#ecfdf5' } }; const TYPE_LABELS = { bug: '🐛 Bug 报告', feature: '💡 功能建议', other: '📌 其他' }; export default function IssueDetail() { const { id } = useParams(); const { user } = useAuth(); const navigate = useNavigate(); const [issue, setIssue] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); // 回复表单 const [replyContent, setReplyContent] = useState(''); const [replying, setReplying] = useState(false); const [replyMsg, setReplyMsg] = useState(''); useEffect(() => { if (!user) { navigate('/login'); return; } fetchIssue(); }, [user, id, navigate]); const fetchIssue = async () => { try { const token = localStorage.getItem('token'); const res = await fetch(`/api/issues/${id}`, { headers: { Authorization: `Bearer ${token}` } }); const data = await res.json(); if (!res.ok) throw new Error(data.detail || '获取失败'); setIssue(data.issue); } catch (err) { setError(err.message); } finally { setLoading(false); } }; const handleReply = async (e) => { e.preventDefault(); if (!replyContent.trim()) return; setReplying(true); setReplyMsg(''); try { const token = localStorage.getItem('token'); const res = await fetch(`/api/issues/${id}/reply`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify({ content: replyContent.trim() }) }); const data = await res.json(); if (!res.ok) throw new Error(data.detail || '回复失败'); setReplyContent(''); setReplyMsg('回复成功'); fetchIssue(); } catch (err) { setReplyMsg(err.message); } finally { setReplying(false); } }; if (!user) return null; if (loading) { return
加载中...
; } if (error) { return (
{error}
← 返回反馈列表
); } if (!issue) return null; return (
← 返回反馈列表 {/* Issue 主体 */}

{issue.title}

{STATUS_LABELS[issue.status] || issue.status}
{TYPE_LABELS[issue.type] || issue.type} 提交者: {issue.username} {new Date(issue.created_at).toLocaleString('zh-CN')}

问题描述

{issue.description}

{/* 附带的 Markdown 用例 */} {issue.markdown_sample && (

📎 附带的 Markdown 用例

{issue.markdown_sample}
)}
{/* 回复列表 */}

💬 回复 ({issue.replies?.length || 0})

{(!issue.replies || issue.replies.length === 0) ? (

暂无回复

) : (
{issue.replies.map(reply => (
{reply.author === 'admin' ? '🔧 管理员' : reply.author} {new Date(reply.created_at).toLocaleString('zh-CN')}

{reply.content}

))}
)} {/* 回复表单 */} {issue.status !== 'closed' && ( <>