diff --git a/apps/web/src/pages/health/ArticleManageList.tsx b/apps/web/src/pages/health/ArticleManageList.tsx index d776020..6048404 100644 --- a/apps/web/src/pages/health/ArticleManageList.tsx +++ b/apps/web/src/pages/health/ArticleManageList.tsx @@ -1,10 +1,11 @@ -import { useState, useEffect, useMemo } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useState, useEffect, useMemo, useCallback } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; import { Table, Button, Space, Input, + InputNumber, Select, Tag, Tabs, @@ -26,13 +27,20 @@ import { import { articleApi, articleCategoryApi, + articleTagApi, type ArticleListItem, type ArticleStatus, type ArticleTagItem, + type ArticleCategory, + type CreateCategoryReq, + type UpdateCategoryReq, + type CreateTagReq, } from '../../api/health/articles'; +import { handleApiError } from '../../api/client'; import { AuthButton } from '../../components/AuthButton'; import { PageContainer } from '../../components/PageContainer'; import { usePaginatedData } from '../../hooks/usePaginatedData'; +import { useThemeMode } from '../../hooks/useThemeMode'; import { formatDateTime } from '../../utils/format'; // --- 常量 --- @@ -66,12 +74,21 @@ const DEFAULT_FILTERS: ArticleFilters = { category_id: '', }; +const PAGE_TABS = [ + { key: 'articles', label: '文章' }, + { key: 'categories', label: '分类管理' }, + { key: 'tags', label: '标签管理' }, +]; + export default function ArticleManageList() { const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); + const activePageTab = searchParams.get('tab') || 'articles'; const [categories, setCategories] = useState<{ id: string; name: string }[]>([]); const [rejectModalOpen, setRejectModalOpen] = useState(false); const [rejectingArticle, setRejectingArticle] = useState(null); const [rejectForm] = Form.useForm(); + const isDark = useThemeMode(); // ---- 分页数据 Hook ---- const { @@ -96,15 +113,12 @@ export default function ArticleManageList() { { 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, version: number) => { try { await articleApi.delete(id, version); @@ -240,8 +254,6 @@ export default function ArticleManageList() { ); - // ---- 列定义 ---- - const columns = useMemo(() => [ { title: '标题', @@ -353,74 +365,211 @@ export default function ArticleManageList() { }, ], [navigate, renderActions]); + // ---- 分类管理内联 ---- + const [catList, setCatList] = useState([]); + const [catLoading, setCatLoading] = useState(false); + const [catModalOpen, setCatModalOpen] = useState(false); + const [catEditing, setCatEditing] = useState(null); + const [catForm] = Form.useForm(); + + const fetchCategories = useCallback(async () => { + setCatLoading(true); + try { + const result = await articleCategoryApi.list(); + setCatList(result); + } catch { + message.error('加载分类列表失败'); + } finally { + setCatLoading(false); + } + }, []); + + useEffect(() => { + if (activePageTab === 'categories') fetchCategories(); + }, [activePageTab, fetchCategories]); + + const catParentOptions = catList + .filter((c) => !catEditing || c.id !== catEditing.id) + .map((c) => ({ label: c.name, value: c.id })); + + const catColumns = useMemo(() => [ + { title: '分类名称', dataIndex: 'name', key: 'name', render: (v: string) => {v} }, + { title: '别名', dataIndex: 'slug', key: 'slug', width: 180, render: (v?: string) => v || '-' }, + { title: '父分类', dataIndex: 'parent_name', key: 'parent_name', width: 140, + render: (_v: string | undefined, record: ArticleCategory) => { + if (!record.parent_id) return '-'; + return catList.find((c) => c.id === record.parent_id)?.name || record.parent_id; + }, + }, + { title: '排序', dataIndex: 'sort_order', key: 'sort_order', width: 80, render: (v: number) => v ?? 0 }, + { title: '描述', dataIndex: 'description', key: 'description', ellipsis: true, render: (v?: string) => v || '-' }, + { title: '操作', key: 'actions', width: 120, + render: (_: unknown, record: ArticleCategory) => ( + + + + + + + + +
+ +
+ + + + + +
+ +
+ 三级折叠 +
+ 侧边栏 +
+
+ + + +
+ + +
+
+ + + +