Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Failing after 7s
M1-01 AI Gateway: - Tab-based layout: Overview, Routes CRUD, Provider toggle, Fallback logs M1-02 Vector: - New VectorAdmin page: collection stats, info panel, reindex trigger - Route /vector + menu entry under 系统运维 M1-03 Events: - Tab-based layout: Queue overview (with batch retry), Task statistics - Worker status panel, 16 task type configs table Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
83 lines
3.4 KiB
TypeScript
83 lines
3.4 KiB
TypeScript
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||
import { Card, Row, Col, Statistic, Button, Typography, Descriptions, App } from 'antd'
|
||
import { ReloadOutlined, DatabaseOutlined, NodeIndexOutlined } from '@ant-design/icons'
|
||
import { api } from '@/services/http-client'
|
||
|
||
const { Title } = Typography
|
||
|
||
export default function VectorAdminPage() {
|
||
const qc = useQueryClient()
|
||
const { message } = App.useApp()
|
||
|
||
const { data: coll, isLoading: collLoading } = useQuery({
|
||
queryKey: ['vector', 'collection'],
|
||
queryFn: (): Promise<any> => api.get('/admin-api/vector/collection'),
|
||
staleTime: 30_000,
|
||
})
|
||
|
||
const { data: count } = useQuery({
|
||
queryKey: ['vector', 'count'],
|
||
queryFn: (): Promise<any> => api.get('/admin-api/vector/count'),
|
||
staleTime: 30_000,
|
||
})
|
||
|
||
const handleReindex = async () => {
|
||
try {
|
||
await api.post('/admin-api/vector/reindex')
|
||
message.success('索引重建已提交')
|
||
qc.invalidateQueries({ queryKey: ['vector'] })
|
||
} catch {
|
||
message.error('操作失败')
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
|
||
<Title level={5} style={{ margin: 0 }}><DatabaseOutlined /> 向量检索</Title>
|
||
<Button icon={<ReloadOutlined />} onClick={() => qc.invalidateQueries({ queryKey: ['vector'] })}>刷新</Button>
|
||
</div>
|
||
|
||
<Row gutter={[16, 16]} style={{ marginBottom: 16 }}>
|
||
<Col span={6}>
|
||
<Card size="small"><Statistic title="向量总数" value={count?.count ?? 0} loading={collLoading} suffix="条" /></Card>
|
||
</Col>
|
||
<Col span={6}>
|
||
<Card size="small"><Statistic title="向量维度" value={coll?.vectorSize || 1024} /></Card>
|
||
</Col>
|
||
<Col span={6}>
|
||
<Card size="small"><Statistic title="距离度量" value={coll?.distance || 'Cosine'} /></Card>
|
||
</Col>
|
||
<Col span={6}>
|
||
<Card size="small"><Statistic title="状态" value={coll?.status || '-'} valueStyle={{ color: coll?.status === 'green' ? '#52c41a' : '#faad14' }} /></Card>
|
||
</Col>
|
||
</Row>
|
||
|
||
<Row gutter={[16, 16]}>
|
||
<Col span={16}>
|
||
<Card size="small" title="Collection 信息">
|
||
<Descriptions column={2} size="small" bordered>
|
||
<Descriptions.Item label="名称">{coll?.name || 'zhixi_chunks'}</Descriptions.Item>
|
||
<Descriptions.Item label="向量维度">{coll?.vectorSize || 1024}</Descriptions.Item>
|
||
<Descriptions.Item label="距离度量">{coll?.distance || 'Cosine'}</Descriptions.Item>
|
||
<Descriptions.Item label="向量总数">{count?.count ?? 0}</Descriptions.Item>
|
||
<Descriptions.Item label="索引算法">HNSW (m=16, ef_construct=100)</Descriptions.Item>
|
||
<Descriptions.Item label="Payload 索引">userId (keyword), knowledgeBaseId (keyword), deleted (bool)</Descriptions.Item>
|
||
</Descriptions>
|
||
</Card>
|
||
</Col>
|
||
<Col span={8}>
|
||
<Card size="small" title="索引操作">
|
||
<Button icon={<NodeIndexOutlined />} block onClick={handleReindex} style={{ marginBottom: 8 }}>
|
||
触发索引重建
|
||
</Button>
|
||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||
索引重建会通过任务队列异步执行,不影响线上检索。建议在低峰期操作。
|
||
</Typography.Text>
|
||
</Card>
|
||
</Col>
|
||
</Row>
|
||
</div>
|
||
)
|
||
}
|