import { useState, useEffect, useCallback } from 'react' import { reportsApi, type ReportListItem, type ReportDetail, type ReportQueryParams, type ReportStatus, type ReportTargetType } from '@/api' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { Checkbox } from '@/components/ui/checkbox' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { PaginationNavigator } from '@/components/ui/pagination' import { Textarea } from '@/components/ui/textarea' import { Label } from '@/components/ui/label' import { Search, RefreshCw, Eye, Check, X, Loader2, Flag, FileText, MessageSquare, Mail, } from 'lucide-react' import { format } from 'date-fns' import type { PaginatedResponse } from '@/types' // 状态颜色映射 const statusColors: Record = { pending: 'bg-yellow-500', processing: 'bg-blue-500', resolved: 'bg-green-500', rejected: 'bg-gray-500', } // 状态文本映射 const statusText: Record = { pending: '待处理', processing: '处理中', resolved: '已确认', rejected: '已驳回', } // 目标类型图标 const targetTypeIcons: Record = { post: , comment: , message: , } // 目标类型文本 const targetTypeText: Record = { post: '帖子', comment: '评论', message: '消息', } // 举报原因文本 const reasonText: Record = { spam: '垃圾广告', inappropriate: '违规内容', harassment: '辱骂/攻击', misinformation: '虚假信息', other: '其他', } export default function Reports() { // 状态 const [reports, setReports] = useState([]) const [loading, setLoading] = useState(true) const [total, setTotal] = useState(0) const [page, setPage] = useState(1) const [pageSize] = useState(10) const [keyword, setKeyword] = useState('') const [statusFilter, setStatusFilter] = useState('all') const [typeFilter, setTypeFilter] = useState('all') // 批量选择 const [selectedIds, setSelectedIds] = useState([]) const [isAllSelected, setIsAllSelected] = useState(false) // 详情对话框 const [detailOpen, setDetailOpen] = useState(false) const [selectedReport, setSelectedReport] = useState(null) const [detailLoading, setDetailLoading] = useState(false) // 处理对话框 const [handleOpen, setHandleOpen] = useState(false) const [handleReport, setHandleReport] = useState(null) const [handleAction, setHandleAction] = useState<'approve' | 'reject'>('approve') const [handleResult, setHandleResult] = useState('') const [handleLoading, setHandleLoading] = useState(false) // 批量操作加载状态 const [batchLoading, setBatchLoading] = useState(false) // 加载举报列表 const loadReports = useCallback(async () => { setLoading(true) try { const params: ReportQueryParams = { page, page_size: pageSize, keyword: keyword || undefined, status: statusFilter !== 'all' ? (statusFilter as ReportStatus) : undefined, target_type: typeFilter !== 'all' ? (typeFilter as ReportTargetType) : undefined, } const response = await reportsApi.getReports(params) const data = response.data.data as PaginatedResponse setReports(data.list || []) setTotal(data.total || 0) } catch (error) { console.error('Failed to load reports:', error) } finally { setLoading(false) setSelectedIds([]) setIsAllSelected(false) } }, [page, pageSize, keyword, statusFilter, typeFilter]) useEffect(() => { loadReports() }, [loadReports]) // 处理搜索 const handleSearch = () => { setPage(1) loadReports() } // 处理刷新 const handleRefresh = () => { loadReports() } // 全选/取消全选 const handleSelectAll = (checked: boolean) => { if (checked) { setSelectedIds(reports.map(r => r.id)) setIsAllSelected(true) } else { setSelectedIds([]) setIsAllSelected(false) } } // 单选 const handleSelect = (id: string, checked: boolean) => { if (checked) { setSelectedIds([...selectedIds, id]) } else { setSelectedIds(selectedIds.filter(i => i !== id)) } setIsAllSelected(checked && selectedIds.length === reports.length - 1) } // 查看详情 const handleViewDetail = async (report: ReportListItem) => { setDetailLoading(true) setDetailOpen(true) try { const response = await reportsApi.getReportById(report.id) setSelectedReport(response.data) } catch (error) { console.error('Failed to load report detail:', error) setDetailOpen(false) } finally { setDetailLoading(false) } } // 打开处理对话框 const openHandleDialog = (report: ReportListItem) => { setHandleReport(report) setHandleAction('approve') setHandleResult('') setHandleOpen(true) } // 提交处理 const submitHandle = async () => { if (!handleReport) return setHandleLoading(true) try { await reportsApi.handleReport(handleReport.id, { action: handleAction, result: handleResult || undefined, }) setHandleOpen(false) loadReports() } catch (error) { console.error('Failed to handle report:', error) } finally { setHandleLoading(false) } } // 批量处理 const handleBatchAction = async (action: 'approve' | 'reject') => { if (selectedIds.length === 0) return setBatchLoading(true) try { await reportsApi.batchHandle({ ids: selectedIds, action, }) loadReports() } catch (error) { console.error('Failed to batch handle:', error) } finally { setBatchLoading(false) } } return (
{/* 标题 */}

举报管理

处理用户举报的帖子、评论和消息

{/* 筛选卡片 */} 筛选条件
setKeyword(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} />
{/* 举报列表 */}
举报列表 共 {total} 条记录
{selectedIds.length > 0 && (
)}
举报人 目标类型 举报原因 状态 举报时间 操作 {loading ? ( 加载中... ) : reports.length === 0 ? ( 暂无举报记录 ) : ( reports.map((report) => ( handleSelect(report.id, !!checked)} />
{report.reporter?.nickname?.[0] || '?'} {report.reporter?.nickname || '未知用户'}
{targetTypeIcons[report.target_type]} {targetTypeText[report.target_type]}
{reasonText[report.reason] || report.reason} {report.description && (

{report.description}

)}
{statusText[report.status]} {format(new Date(report.created_at), 'yyyy-MM-dd HH:mm')}
{report.status === 'pending' && ( )}
)) )}
{/* 详情对话框 */} 举报详情 {detailLoading ? (
) : selectedReport ? (
{selectedReport.reporter?.nickname?.[0]} {selectedReport.reporter?.nickname}

{format(new Date(selectedReport.created_at), 'yyyy-MM-dd HH:mm:ss')}

{targetTypeText[selectedReport.target_type]}

{statusText[selectedReport.status]}

{reasonText[selectedReport.reason] || selectedReport.reason}

{selectedReport.description && (

{selectedReport.description}

)}
{selectedReport.target_content && ( 被举报内容 {selectedReport.target_content.title && (

{selectedReport.target_content.title}

)}

{selectedReport.target_content.content}

{selectedReport.target_content.images && selectedReport.target_content.images.length > 0 && (
{selectedReport.target_content.images.map((img, i) => ( ))}
)}
)} {selectedReport.handler && (
{selectedReport.handler.nickname?.[0]} {selectedReport.handler.nickname} {selectedReport.handled_at && ( {format(new Date(selectedReport.handled_at), 'yyyy-MM-dd HH:mm')} )}
)} {selectedReport.result && (

{selectedReport.result}

)}
) : null}
{/* 处理对话框 */} 处理举报 请选择处理方式