创作中心模块包含首页展示、个人中心、帖子审核。

“首页展示”支持广告轮播展示、推广帖子优先展示、分页显示所有帖子、导航栏便捷标签筛选帖子、全局标题模糊搜索帖子、点击帖子“查看更多”进入帖子详情页。帖子详情页展示帖子封面图片、作者时间、详细内容(可以插入种子链接对种子进行介绍与推广)等基本信息、对帖子点赞收藏举报评论回复、查看相关推荐帖子。相关推荐会推荐当前帖子作者的其他帖子(最多推荐5篇),还会推荐具有相似标签的其他帖子,两者总共最多推荐9篇帖子。

“个人中心”包含“我的中心”和“我的收藏”。
“我的中心”中可以管理已经成功发布的帖子(编辑、删除帖子),还可以发布新帖子。发布新帖子时除了填写帖子基本信息以外,帖子标签支持下拉多项选择,用户还可以选择帖子推广项目并进行支付。设置了多种推广项目,包含广告轮播推广、帖子置顶展示、限时优先展示、分类页首条展示。系统后台执行自动定时任务,每小时对帖子的推广时效性进行检查,如超出推广时限,则取消帖子的推广显示特权。用户点击发布帖子后帖子处于待审核状态,需要管理员审核通过才能正常发布在首页展示页面。编辑帖子时用户可以追加帖子推广,但如果帖子处于推广状态,则禁止修改推广项目。
“我的收藏”中可以便捷查看所有已收藏的帖子。

“帖子审核”包含“帖子发布管理”和“帖子举报管理”。“帖子审核”板块具有权限管理,只有管理员界面能够进入。
“帖子发布管理”对所有待审核帖子进行处理,支持预览待审核帖子详细内容,批准通过和拒绝通过选项。
“帖子举报管理”对所有用户的举报请求进行人工审核,如果举报内容属实,则将帖子下架处理,如果举报内容不属实,驳回举报请求。所有举报请求的处理结果均留存显示,方便后续再次审查。

Change-Id: If822351183e9d55a5a56ff5cf1e13b313fdbe231
diff --git a/src/pages/PostReview/ReportManagement.tsx b/src/pages/PostReview/ReportManagement.tsx
new file mode 100644
index 0000000..f5c0e99
--- /dev/null
+++ b/src/pages/PostReview/ReportManagement.tsx
@@ -0,0 +1,325 @@
+import React, { useState, useEffect } from 'react';
+import { 
+  Card, 
+  Table, 
+  Button, 
+  Modal, 
+  Tag, 
+  Space, 
+  message, 
+  Typography,
+  Input
+} from 'antd';
+import { 
+  EyeOutlined, 
+  CheckOutlined, 
+  CloseOutlined
+} from '@ant-design/icons';
+import { getReportList, handleReport } from '@/services/post';
+import styles from './index.module.css';
+
+const { Title, Paragraph } = Typography;
+const { TextArea } = Input;
+
+interface ReportInfo {
+  reportId: number;
+  postId: number;
+  postTitle: string;
+  reportUserId: number;
+  reportUserName: string;
+  reportReason: string;
+  status: string;
+  handleResult?: string;
+  handleTime?: string;
+  handleBy?: string;
+  createTime: string;
+}
+
+const ReportManagement: React.FC = () => {
+  const [reports, setReports] = useState<ReportInfo[]>([]);
+  const [loading, setLoading] = useState(false);
+  const [detailModalVisible, setDetailModalVisible] = useState(false);
+  const [handleModalVisible, setHandleModalVisible] = useState(false);
+  const [currentReport, setCurrentReport] = useState<ReportInfo | null>(null);
+  const [currentAction, setCurrentAction] = useState<'approve' | 'reject' | null>(null);
+  const [handleReason, setHandleReason] = useState('');
+
+  useEffect(() => {
+    fetchReports();
+  }, []);
+
+  const fetchReports = async () => {
+    setLoading(true);
+    try {
+      const response = await getReportList({ 
+        pageNum: 1, 
+        pageSize: 100
+      });
+      
+      if (response.code === 200) {
+        setReports(response.rows || []);
+      } else {
+        message.error(response.msg || '获取举报列表失败');
+      }
+    } catch (error) {
+      message.error('获取举报列表失败');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleReportAction = async (report: ReportInfo, action: 'approve' | 'reject') => {
+    setCurrentReport(report);
+    setCurrentAction(action);
+    setHandleReason('');
+    setHandleModalVisible(true);
+  };
+
+  const submitHandle = async () => {
+    if (!currentReport || !currentAction) return;
+
+    try {
+      const response = await handleReport(
+        currentReport.reportId, 
+        currentAction, 
+        currentReport.postId,
+        handleReason
+      );
+
+      if (response.code === 200) {
+        message.success(currentAction === 'approve' ? '举报处理成功,帖子已下架' : '举报已驳回');
+        fetchReports();
+      } else {
+        message.error(response.msg || '处理失败');
+      }
+    } catch (error) {
+      message.error('处理失败');
+    }
+    
+    setHandleModalVisible(false);
+    setCurrentReport(null);
+    setCurrentAction(null);
+    setHandleReason('');
+  };
+
+  const showDetail = (report: ReportInfo) => {
+    setCurrentReport(report);
+    setDetailModalVisible(true);
+  };
+
+  const columns = [
+    {
+      title: '举报帖子',
+      dataIndex: 'postTitle',
+      key: 'postTitle',
+      width: 180,
+      render: (text: string, record: ReportInfo) => (
+        <a onClick={() => showDetail(record)} style={{ color: '#1890ff' }}>
+          {text}
+        </a>
+      ),
+    },
+    {
+      title: '举报人',
+      dataIndex: 'reportUserName',
+      key: 'reportUserName',
+      width: 100,
+    },
+    {
+      title: '举报时间',
+      dataIndex: 'createTime',
+      key: 'createTime',
+      width: 140,
+    },
+    {
+      title: '举报理由',
+      dataIndex: 'reportReason',
+      key: 'reportReason',
+      width: 150,
+      ellipsis: true,
+      render: (text: string) => (
+        <span title={text}>{text}</span>
+      ),
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      key: 'status',
+      width: 80,
+      render: (status: string) => {
+        const statusMap: Record<string, { color: string; text: string }> = {
+          '0': { color: 'orange', text: '待处理' },
+          '1': { color: 'green', text: '已处理' },
+          '2': { color: 'red', text: '已驳回' }
+        };
+        const statusInfo = statusMap[status] || { color: 'gray', text: '未知' };
+        return <Tag color={statusInfo.color}>{statusInfo.text}</Tag>;
+      },
+    },
+    {
+      title: '操作',
+      key: 'action',
+      width: 300,
+      fixed: 'right' as const,
+      render: (text: any, record: ReportInfo) => (
+        <Space size="small">
+          <Button 
+            type="link" 
+            icon={<EyeOutlined />} 
+            onClick={() => showDetail(record)}
+            size="small"
+          >
+            查看
+          </Button>
+          {record.status === '0' && (
+            <>
+              <Button 
+                type="link" 
+                icon={<CheckOutlined />} 
+                style={{ color: 'green' }}
+                onClick={() => handleReportAction(record, 'approve')}
+                size="small"
+              >
+                确认下架
+              </Button>
+              <Button 
+                type="link" 
+                danger 
+                icon={<CloseOutlined />}
+                onClick={() => handleReportAction(record, 'reject')}
+                size="small"
+              >
+                驳回举报
+              </Button>
+            </>
+          )}
+        </Space>
+      ),
+    },
+  ];
+
+  return (
+    <div className={styles.postReviewContainer}>
+      <Card title="帖子举报管理">
+        <Table
+          columns={columns}
+          dataSource={reports}
+          loading={loading}
+          rowKey="reportId"
+          scroll={{ x: 880 }}
+          pagination={{
+            pageSize: 10,
+            showTotal: (total) => `共 ${total} 条记录`,
+            showSizeChanger: true,
+            showQuickJumper: true,
+          }}
+        />
+      </Card>
+
+      {/* 举报详情弹窗 */}
+      <Modal
+        title="举报详情"
+        open={detailModalVisible}
+        onCancel={() => {
+          setDetailModalVisible(false);
+          setCurrentReport(null);
+        }}
+        footer={null}
+        width={600}
+      >
+        {currentReport && (
+          <div>
+            <div style={{ marginBottom: 16 }}>
+              <strong>举报帖子:</strong>{currentReport.postTitle}
+            </div>
+            <div style={{ marginBottom: 16 }}>
+              <strong>举报人:</strong>{currentReport.reportUserName}
+            </div>
+            <div style={{ marginBottom: 16 }}>
+              <strong>举报时间:</strong>{currentReport.createTime}
+            </div>
+            <div style={{ marginBottom: 16 }}>
+              <strong>举报理由:</strong>
+              <Paragraph>{currentReport.reportReason}</Paragraph>
+            </div>
+            {currentReport.status !== '0' && (
+              <>
+                <div style={{ marginBottom: 16 }}>
+                  <strong>处理结果:</strong>{currentReport.handleResult}
+                </div>
+                <div style={{ marginBottom: 16 }}>
+                  <strong>处理时间:</strong>{currentReport.handleTime}
+                </div>
+                <div style={{ marginBottom: 16 }}>
+                  <strong>处理人:</strong>{currentReport.handleBy}
+                </div>
+              </>
+            )}
+            {currentReport.status === '0' && (
+              <div style={{ marginTop: 16 }}>
+                <Space>
+                  <Button 
+                    type="primary" 
+                    icon={<CheckOutlined />}
+                    onClick={() => {
+                      handleReportAction(currentReport, 'approve');
+                      setDetailModalVisible(false);
+                    }}
+                  >
+                    确认下架
+                  </Button>
+                  <Button 
+                    danger 
+                    icon={<CloseOutlined />}
+                    onClick={() => {
+                      handleReportAction(currentReport, 'reject');
+                      setDetailModalVisible(false);
+                    }}
+                  >
+                    驳回举报
+                  </Button>
+                </Space>
+              </div>
+            )}
+          </div>
+        )}
+      </Modal>
+
+      {/* 处理举报弹窗 */}
+      <Modal
+        title={currentAction === 'approve' ? '确认下架帖子' : '驳回举报'}
+        open={handleModalVisible}
+        onOk={submitHandle}
+        onCancel={() => {
+          setHandleModalVisible(false);
+          setCurrentReport(null);
+          setCurrentAction(null);
+          setHandleReason('');
+        }}
+        okText="确定"
+        cancelText="取消"
+      >
+        <div style={{ marginBottom: 16 }}>
+          <strong>帖子:</strong>{currentReport?.postTitle}
+        </div>
+        <div>
+          <strong>
+            {currentAction === 'approve' ? '下架理由' : '驳回理由'}
+            (可选):
+          </strong>
+          <TextArea
+            value={handleReason}
+            onChange={(e) => setHandleReason(e.target.value)}
+            placeholder={
+              currentAction === 'approve' ? '请输入下架理由...' : '请输入驳回理由...'
+            }
+            rows={4}
+            style={{ marginTop: 8 }}
+          />
+        </div>
+      </Modal>
+    </div>
+  );
+};
+
+export default ReportManagement; 
\ No newline at end of file