2e14873f2d
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
import { fetchReports, processReport } from '../api/client';
|
||
|
||
export function ReportsPage() {
|
||
const [reports, setReports] = useState<Awaited<ReturnType<typeof fetchReports>>['reports']>([]);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
const load = async () => {
|
||
try {
|
||
const data = await fetchReports();
|
||
setReports(data.reports);
|
||
} catch (err) {
|
||
setError(err instanceof Error ? err.message : '加载失败');
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
void load();
|
||
}, []);
|
||
|
||
return (
|
||
<div className="grid">
|
||
{error ? <p className="alert">{error}</p> : null}
|
||
{reports.map((report) => (
|
||
<div key={report.id} className="card">
|
||
<h3>
|
||
{report.target_type} · {report.reason}
|
||
{report.target_report_count > 3 ? (
|
||
<span className="alert"> · 高频举报 ({report.target_report_count})</span>
|
||
) : null}
|
||
</h3>
|
||
<p>{report.detail || '无补充说明'}</p>
|
||
<p style={{ color: '#68716c', fontSize: 12 }}>目标 ID:{report.target_id}</p>
|
||
<div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
|
||
<button
|
||
type="button"
|
||
className="btn danger"
|
||
onClick={() =>
|
||
void processReport(report.id, 'hide_post', 'hide from report queue').then(load)
|
||
}
|
||
>
|
||
隐藏内容
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="btn secondary"
|
||
onClick={() => void processReport(report.id, 'dismiss').then(load)}
|
||
>
|
||
驳回举报
|
||
</button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|