feat: M0-09 admin files page
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Has been cancelled

This commit is contained in:
WangDL 2026-05-23 09:44:58 +08:00
parent 38cc2ff74c
commit 5d6b803f66
2 changed files with 46 additions and 1 deletions

View File

@ -81,7 +81,7 @@ function App() {
<Route path="knowledge/bases" element={<Suspense fallback={<PageLoading />}><KnowledgeBasesPage /></Suspense>} /> <Route path="knowledge/bases" element={<Suspense fallback={<PageLoading />}><KnowledgeBasesPage /></Suspense>} />
<Route path="knowledge/sources" element={<Placeholder title="知识源列表" />} /> <Route path="knowledge/sources" element={<Placeholder title="知识源列表" />} />
<Route path="imports" element={<Placeholder title="文档导入" />} /> <Route path="imports" element={<Placeholder title="文档导入" />} />
<Route path="files" element={<Placeholder title="文件与 COS" />} /> <Route path="files" element={<Suspense fallback={<PageLoading />}><FilesAdminPage /></Suspense>} />
<Route <Route
path="settings" path="settings"
element={ element={

45
src/pages/FilesAdmin.tsx Normal file
View File

@ -0,0 +1,45 @@
import { useState } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { Table, Button, Typography, App, Tag } from 'antd'
import { ReloadOutlined, DeleteOutlined, FileOutlined } from '@ant-design/icons'
import { api } from '@/services/http-client'
import dayjs from 'dayjs'
const { Title, Text } = Typography
export default function FilesAdminPage() {
const { modal, message } = App.useApp()
const qc = useQueryClient()
const [page, setPage] = useState(1)
const { data, isLoading } = useQuery({
queryKey: ['admin-files', page],
queryFn: (): Promise<any> => api.get(`/admin-api/files?page=${page}&limit=20`),
})
const handleDelete = (file: any) => modal.confirm({
title: '删除文件', content: `确定删除 ${file.filename}`, okType: 'danger',
onOk: async () => { await api.delete(`/admin-api/files/${file.id}`); message.success('已删除'); qc.invalidateQueries({ queryKey: ['admin-files'] }) },
})
const cols = [
{ title: '文件名', dataIndex: 'filename', width: 200, ellipsis: true },
{ title: '用户', width: 120, render: (_:any, r:any) => r.user?.nickname || r.user?.email || '-' },
{ title: '类型', dataIndex: 'mimeType', width: 100, ellipsis: true },
{ title: '大小', dataIndex: 'sizeBytes', width: 80, render: (v: number) => v ? (v / 1024).toFixed(1) + 'KB' : '-' },
{ title: '用途', dataIndex: 'purpose', width: 80, render: (v: string) => <Tag>{v || '-'}</Tag> },
{ title: '上传时间', dataIndex: 'createdAt', width: 150, render: (d: string) => dayjs(d).format('MM-DD HH:mm') },
{ title: '操作', width: 80, render: (_:any, r:any) => <Button type="link" size="small" danger icon={<DeleteOutlined />} onClick={() => handleDelete(r)} /> },
]
return (
<div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
<Title level={5} style={{ margin: 0 }}><FileOutlined /> </Title>
<Button icon={<ReloadOutlined />} onClick={() => qc.invalidateQueries({ queryKey: ['admin-files'] })}></Button>
</div>
<Table dataSource={data?.items || []} columns={cols} rowKey="id" loading={isLoading}
pagination={{ current: page, pageSize: 20, total: data?.total || 0, onChange: setPage, showTotal: (t: number) => `${t}` }} />
</div>
)
}