import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Table, Button, Space, Input, Select, Tag, Tabs, Popconfirm, message, Modal, Form, } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, SendOutlined, CheckOutlined, CloseOutlined, RollbackOutlined, EyeOutlined, } from '@ant-design/icons'; import { articleApi, articleCategoryApi, type ArticleListItem, type ArticleStatus, type ArticleTagItem, } from '../../api/health/articles'; import { AuthButton } from '../../components/AuthButton'; import { PageContainer } from '../../components/PageContainer'; import { usePaginatedData } from '../../hooks/usePaginatedData'; import { formatDateTime } from '../../utils/format'; // --- 常量 --- const STATUS_TABS: { key: string; label: string }[] = [ { key: '', label: '全部' }, { key: 'draft', label: '草稿' }, { key: 'pending_review', label: '待审核' }, { key: 'published', label: '已发布' }, { key: 'rejected', label: '已拒绝' }, ]; const STATUS_CONFIG: Record = { draft: { label: '草稿', color: 'default' }, pending_review: { label: '待审核', color: 'processing' }, published: { label: '已发布', color: 'success' }, rejected: { label: '已拒绝', color: 'error' }, }; // --- 筛选器 --- interface ArticleFilters { keyword: string; status: string; category_id: string; } const DEFAULT_FILTERS: ArticleFilters = { keyword: '', status: '', category_id: '', }; export default function ArticleManageList() { const navigate = useNavigate(); const [categories, setCategories] = useState<{ id: string; name: string }[]>([]); const [rejectModalOpen, setRejectModalOpen] = useState(false); const [rejectingArticle, setRejectingArticle] = useState(null); const [rejectForm] = Form.useForm(); // ---- 分页数据 Hook ---- const { data, total, page, loading, filters, setFilters, refresh, } = usePaginatedData( async (p, pageSize, f) => { const result = await articleApi.list({ page: p, page_size: pageSize, status: (f.status || undefined) as ArticleStatus | undefined, category_id: f.category_id || undefined, keyword: f.keyword || undefined, }); return result; }, { pageSize: 20, defaultFilters: { ...DEFAULT_FILTERS } }, ); // ---- 分类列表 ---- useEffect(() => { articleCategoryApi.list() .then((cats) => setCategories(cats.map((c) => ({ id: c.id, name: c.name })))) .catch(() => {}); }, []); // ---- 操作 ---- const handleDelete = async (id: string) => { try { await articleApi.delete(id); message.success('文章已删除'); refresh(); } catch { message.error('删除失败'); } }; const handleSubmit = async (record: ArticleListItem) => { try { await articleApi.submit(record.id, record.version); message.success('已提交审核'); refresh(); } catch { message.error('提交审核失败'); } }; const handleApprove = async (record: ArticleListItem) => { try { await articleApi.approve(record.id, record.version); message.success('审核通过,文章已发布'); refresh(); } catch { message.error('审核操作失败'); } }; const openRejectModal = (record: ArticleListItem) => { setRejectingArticle(record); rejectForm.resetFields(); setRejectModalOpen(true); }; const handleReject = async (values: { review_note: string }) => { if (!rejectingArticle) return; try { await articleApi.reject(rejectingArticle.id, rejectingArticle.version, values.review_note); message.success('已拒绝文章'); setRejectModalOpen(false); refresh(); } catch { message.error('拒绝操作失败'); } }; const handleUnpublish = async (record: ArticleListItem) => { try { await articleApi.unpublish(record.id, record.version); message.success('文章已撤回为草稿'); refresh(); } catch { message.error('撤回操作失败'); } }; const renderActions = (record: ArticleListItem) => ( {record.status === 'draft' && ( <> )} {record.status === 'pending_review' && ( <> )} {record.status === 'published' && ( )} {(record.status === 'draft' || record.status === 'rejected') && ( handleDelete(record.id)} >