diff --git a/src/App.tsx b/src/App.tsx index 1566270..9ffdda4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import PageLoading from './components/PageLoading' import AdminLayout from './layouts/AdminLayout' const Login = lazy(() => import('./pages/Login')) +const KnowledgeBasesPage = lazy(() => import('./pages/KnowledgeBases')) const BillingPage = lazy(() => import('./pages/Billing')) const GiteaEmbed = lazy(() => import('./pages/GiteaEmbed')) const ServersPage = lazy(() => import("./pages/Servers")) @@ -82,6 +83,10 @@ function App() { } /> + }>} + /> }>} diff --git a/src/config/menu.tsx b/src/config/menu.tsx index 00d5842..def6a02 100644 --- a/src/config/menu.tsx +++ b/src/config/menu.tsx @@ -44,6 +44,7 @@ export const adminMenuItems: AdminMenuItem[] = [ { path: '/imports', name: '文档导入', icon: }, { path: '/files', name: '文件与 COS', icon: }, { path: '/settings', name: '系统配置', icon: , requiredRole: 'ADMIN' }, + { path: '/knowledge/bases', name: '知识库列表', icon: }, { path: '/billing', name: 'API 用量', icon: , requiredRole: 'SUPER_ADMIN' }, { path: '/git', name: '代码仓库', icon: }, { path: '/servers', name: '服务器运维', icon: , requiredRole: 'SUPER_ADMIN' }, diff --git a/src/layouts/AdminLayout.tsx b/src/layouts/AdminLayout.tsx index f9ff39c..4defd0f 100644 --- a/src/layouts/AdminLayout.tsx +++ b/src/layouts/AdminLayout.tsx @@ -20,6 +20,7 @@ const breadcrumbMap: Record = { '/imports': '文档导入', '/files': '文件与 COS', '/settings': '系统配置', + '/knowledge/bases': '知识库列表', '/billing': 'API 用量', '/git': '代码仓库', '/servers': '服务器运维', diff --git a/src/pages/KnowledgeBases.tsx b/src/pages/KnowledgeBases.tsx new file mode 100644 index 0000000..ba07305 --- /dev/null +++ b/src/pages/KnowledgeBases.tsx @@ -0,0 +1,57 @@ +import { useState } from 'react' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { Table, Tag, Typography, Button, Space, App, Input } from 'antd' +import { ReloadOutlined, EyeOutlined, DeleteOutlined } from '@ant-design/icons' +import { getKnowledgeBases, deleteKnowledgeBase, type KnowledgeBase } from '@/services/knowledge-api' +import dayjs from 'dayjs' + +const { Title, Text } = Typography + +function KBPage() { + const { modal, message } = App.useApp() + const qc = useQueryClient() + const [page, setPage] = useState(1) + const [pageSize, setPageSize] = useState(20) + + const { data, isLoading } = useQuery({ + queryKey: ['knowledge-bases', page, pageSize], + queryFn: () => getKnowledgeBases(page, pageSize), + }) + + const handleDelete = (kb: KnowledgeBase) => modal.confirm({ + title: '删除知识库', content: `确定删除「${kb.title}」?`, okType: 'danger', + onOk: async () => { await deleteKnowledgeBase(kb.id); qc.invalidateQueries({ queryKey: ['knowledge-bases'] }); message.success('已删除') }, + }) + + const columns = [ + { title: '名称', dataIndex: 'title', ellipsis: true, render: (t: string, r: KnowledgeBase) => message.info(`ID: ${r.id}`)}>{t} }, + { title: '用户', dataIndex: ['user', 'nickname'], width: 120, render: (_: any, r: KnowledgeBase) => r.user?.nickname || r.user?.email || '-' }, + { title: '知识点', dataIndex: 'itemCount', width: 80, align: 'center' as const }, + { title: '状态', dataIndex: 'status', width: 80, render: (s: string) => {s} }, + { title: '创建时间', dataIndex: 'createdAt', width: 160, render: (d: string) => dayjs(d).format('YYYY-MM-DD HH:mm') }, + { + title: '操作', width: 100, + render: (_: any, r: KnowledgeBase) => ( + + + + + `共 ${t} 条`, onChange: (p, ps) => { setPage(p); setPageSize(ps) } }} + /> + + ) +} + +export default function KnowledgeBasesPage() { return } diff --git a/src/services/knowledge-api.ts b/src/services/knowledge-api.ts new file mode 100644 index 0000000..3ec0e5c --- /dev/null +++ b/src/services/knowledge-api.ts @@ -0,0 +1,15 @@ +import { api } from './http-client' + +export interface KnowledgeBase { + id: string; title: string; description: string | null; status: string; itemCount: number; + user?: { nickname: string | null; email: string }; + createdAt: string; updatedAt: string; + sources?: any[]; _count?: { items: number }; +} + +export function getKnowledgeBases(page = 1, limit = 20): Promise<{ items: KnowledgeBase[]; total: number; page: number; limit: number; totalPages: number }> { + return api.get(`/admin-api/knowledge-bases?page=${page}&limit=${limit}`) +} + +export function getKnowledgeBase(id: string): Promise { return api.get(`/admin-api/knowledge-bases/${id}`) } +export function deleteKnowledgeBase(id: string): Promise { return api.delete(`/admin-api/knowledge-bases/${id}`) }