feat: knowledge base list page for admin
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Failing after 6s
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Failing after 6s
This commit is contained in:
parent
d8a70b4562
commit
c5ddce4216
@ -10,6 +10,7 @@ import PageLoading from './components/PageLoading'
|
|||||||
import AdminLayout from './layouts/AdminLayout'
|
import AdminLayout from './layouts/AdminLayout'
|
||||||
|
|
||||||
const Login = lazy(() => import('./pages/Login'))
|
const Login = lazy(() => import('./pages/Login'))
|
||||||
|
const KnowledgeBasesPage = lazy(() => import('./pages/KnowledgeBases'))
|
||||||
const BillingPage = lazy(() => import('./pages/Billing'))
|
const BillingPage = lazy(() => import('./pages/Billing'))
|
||||||
const GiteaEmbed = lazy(() => import('./pages/GiteaEmbed'))
|
const GiteaEmbed = lazy(() => import('./pages/GiteaEmbed'))
|
||||||
const ServersPage = lazy(() => import("./pages/Servers"))
|
const ServersPage = lazy(() => import("./pages/Servers"))
|
||||||
@ -82,6 +83,10 @@ function App() {
|
|||||||
</PermissionGuard>
|
</PermissionGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="knowledge/bases"
|
||||||
|
element={<Suspense fallback={<PageLoading />}><KnowledgeBasesPage /></Suspense>}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="billing"
|
path="billing"
|
||||||
element={<PermissionGuard requiredRole="SUPER_ADMIN"><Suspense fallback={<PageLoading />}><BillingPage /></Suspense></PermissionGuard>}
|
element={<PermissionGuard requiredRole="SUPER_ADMIN"><Suspense fallback={<PageLoading />}><BillingPage /></Suspense></PermissionGuard>}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ export const adminMenuItems: AdminMenuItem[] = [
|
|||||||
{ path: '/imports', name: '文档导入', icon: <ImportOutlined /> },
|
{ path: '/imports', name: '文档导入', icon: <ImportOutlined /> },
|
||||||
{ path: '/files', name: '文件与 COS', icon: <FileOutlined /> },
|
{ path: '/files', name: '文件与 COS', icon: <FileOutlined /> },
|
||||||
{ path: '/settings', name: '系统配置', icon: <SettingOutlined />, requiredRole: 'ADMIN' },
|
{ path: '/settings', name: '系统配置', icon: <SettingOutlined />, requiredRole: 'ADMIN' },
|
||||||
|
{ path: '/knowledge/bases', name: '知识库列表', icon: <BookOutlined /> },
|
||||||
{ path: '/billing', name: 'API 用量', icon: <DollarOutlined />, requiredRole: 'SUPER_ADMIN' },
|
{ path: '/billing', name: 'API 用量', icon: <DollarOutlined />, requiredRole: 'SUPER_ADMIN' },
|
||||||
{ path: '/git', name: '代码仓库', icon: <CodeOutlined /> },
|
{ path: '/git', name: '代码仓库', icon: <CodeOutlined /> },
|
||||||
{ path: '/servers', name: '服务器运维', icon: <CloudServerOutlined />, requiredRole: 'SUPER_ADMIN' },
|
{ path: '/servers', name: '服务器运维', icon: <CloudServerOutlined />, requiredRole: 'SUPER_ADMIN' },
|
||||||
|
|||||||
@ -20,6 +20,7 @@ const breadcrumbMap: Record<string, string> = {
|
|||||||
'/imports': '文档导入',
|
'/imports': '文档导入',
|
||||||
'/files': '文件与 COS',
|
'/files': '文件与 COS',
|
||||||
'/settings': '系统配置',
|
'/settings': '系统配置',
|
||||||
|
'/knowledge/bases': '知识库列表',
|
||||||
'/billing': 'API 用量',
|
'/billing': 'API 用量',
|
||||||
'/git': '代码仓库',
|
'/git': '代码仓库',
|
||||||
'/servers': '服务器运维',
|
'/servers': '服务器运维',
|
||||||
|
|||||||
57
src/pages/KnowledgeBases.tsx
Normal file
57
src/pages/KnowledgeBases.tsx
Normal file
@ -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) => <a onClick={() => message.info(`ID: ${r.id}`)}>{t}</a> },
|
||||||
|
{ 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) => <Tag color={s === 'active' ? 'green' : 'default'}>{s}</Tag> },
|
||||||
|
{ title: '创建时间', dataIndex: 'createdAt', width: 160, render: (d: string) => dayjs(d).format('YYYY-MM-DD HH:mm') },
|
||||||
|
{
|
||||||
|
title: '操作', width: 100,
|
||||||
|
render: (_: any, r: KnowledgeBase) => (
|
||||||
|
<Space>
|
||||||
|
<Button type="link" size="small" icon={<EyeOutlined />}>详情</Button>
|
||||||
|
<Button type="link" size="small" danger icon={<DeleteOutlined />} onClick={() => handleDelete(r)} />
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
|
||||||
|
<Title level={5} style={{ margin: 0 }}>知识库列表</Title>
|
||||||
|
<Button icon={<ReloadOutlined />} onClick={() => qc.invalidateQueries({ queryKey: ['knowledge-bases'] })}>刷新</Button>
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
dataSource={data?.items || []} columns={columns} rowKey="id" loading={isLoading}
|
||||||
|
pagination={{ current: page, pageSize, total: data?.total || 0, showSizeChanger: true, showTotal: t => `共 ${t} 条`, onChange: (p, ps) => { setPage(p); setPageSize(ps) } }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function KnowledgeBasesPage() { return <App><KBPage /></App> }
|
||||||
15
src/services/knowledge-api.ts
Normal file
15
src/services/knowledge-api.ts
Normal file
@ -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<KnowledgeBase> { return api.get(`/admin-api/knowledge-bases/${id}`) }
|
||||||
|
export function deleteKnowledgeBase(id: string): Promise<void> { return api.delete(`/admin-api/knowledge-bases/${id}`) }
|
||||||
Loading…
x
Reference in New Issue
Block a user