Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Failing after 10s
- HTTP 层:安装 axios,创建 lib/api-client.ts 统一拦截器 - API 层:创建 33 个 api/*.ts 文件,所有页面迁移完成 - DataPages.tsx 拆分为 10 个独立文件 - message 导入统一为 App.useApp() - 新增 StaticAntdProvider 全局消息/通知 - 全局 HTTP 错误/成功提示(notification.error/success) - learning 路由 /learning → /learning/dashboard 修复选中 bug - 学习会话页面优化(移除 ID 列、加批量删除、后端排序) - 文档导入页面重构(知识库筛选、批量重新解析) - 删除旧 service 文件 10 个(admin-api、billing-api 等) - antd App 包裹根组件 Co-Authored-By: Claude <noreply@anthropic.com>
92 lines
4.2 KiB
TypeScript
92 lines
4.2 KiB
TypeScript
import { useState } from 'react'
|
||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||
import { Table, Tag, Typography, Button, App, Tabs, Input, Card, Space } from 'antd'
|
||
import { ReloadOutlined, SearchOutlined, ExperimentOutlined } from '@ant-design/icons'
|
||
import { knowledgeAPI, vectorAPI } from '@/api'
|
||
import { candidateStatusLabels } from '@/constants/labels'
|
||
import dayjs from 'dayjs'
|
||
|
||
const { Title, Text } = Typography
|
||
|
||
export default function KnowledgeOpsPage() {
|
||
const qc = useQueryClient()
|
||
const { message } = App.useApp()
|
||
const [sourceId, setSourceId] = useState('')
|
||
const [debugQuery, setDebugQuery] = useState('')
|
||
|
||
const { data: candidates } = useQuery({
|
||
queryKey: ['ops', 'candidates'],
|
||
queryFn: (): Promise<any> => knowledgeAPI.candidates(),
|
||
})
|
||
|
||
const { data: chunks } = useQuery({
|
||
queryKey: ['ops', 'chunks', sourceId],
|
||
queryFn: (): Promise<any> => knowledgeAPI.chunks(sourceId),
|
||
enabled: !!sourceId,
|
||
})
|
||
|
||
const handleDebugSearch = async () => {
|
||
if (!debugQuery) return
|
||
const res: any = await vectorAPI.debugSearch({ query: debugQuery })
|
||
message.info(JSON.stringify(res.data))
|
||
}
|
||
|
||
const candidateCols = [
|
||
{ title: '标题', dataIndex: 'title', width: 200, ellipsis: true },
|
||
{ title: '用户', dataIndex: 'userId', width: 120, ellipsis: true, render: (_: any, r: any) => r.userName || r.userId },
|
||
{ title: '状态', dataIndex: 'status', width: 80, render: (s: string) => <Tag color={s==='PENDING'?'gold':s==='ACCEPTED'?'green':'red'}>{candidateStatusLabels[s] || s}</Tag> },
|
||
{ title: '置信度', dataIndex: 'confidence', width: 80, align: 'center' as const, render: (v: any) => v ? `${(Number(v)*100).toFixed(0)}%` : '-' },
|
||
{ title: '难度', dataIndex: 'difficulty', width: 70 },
|
||
{ title: '时间', dataIndex: 'createdAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') },
|
||
]
|
||
|
||
const chunkCols = [
|
||
{ title: '#', dataIndex: 'chunkIndex', width: 50 },
|
||
{ title: '内容', dataIndex: 'content', ellipsis: true, render: (v: string) => <Text style={{ fontSize: 12 }}>{v?.slice(0, 150)}</Text> },
|
||
{ title: '页', dataIndex: 'pageNumber', width: 50 },
|
||
{ title: '章节', dataIndex: 'sectionTitle', width: 150, ellipsis: true },
|
||
{ title: 'Tokens', dataIndex: 'tokenCount', width: 70, align: 'center' as const },
|
||
{ title: 'Embedding', dataIndex: 'embeddingStatus', width: 80, render: (s: string) => <Tag color={s==='done'?'green':'default'}>{s}</Tag> },
|
||
]
|
||
|
||
return (
|
||
<div>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
|
||
<Title level={5} style={{ margin: 0 }}><ExperimentOutlined /> 知识运维</Title>
|
||
<Button icon={<ReloadOutlined />} onClick={() => qc.invalidateQueries({ queryKey: ['ops'] })}>刷新</Button>
|
||
</div>
|
||
|
||
<Tabs items={[
|
||
{
|
||
key: 'candidates', label: '候选巡检',
|
||
children: <Table dataSource={candidates || []} columns={candidateCols} rowKey="id" pagination={{ pageSize: 20 }} size="small" />,
|
||
},
|
||
{
|
||
key: 'chunks', label: 'Chunk 管理',
|
||
children: (
|
||
<>
|
||
<Space style={{ marginBottom: 16 }}>
|
||
<Input.Search placeholder="输入 Source ID" value={sourceId} onChange={e => setSourceId(e.target.value)} onSearch={v => setSourceId(v)} enterButton={<SearchOutlined />} style={{ width: 300 }} />
|
||
</Space>
|
||
{sourceId && <Table dataSource={chunks || []} columns={chunkCols} rowKey="id" pagination={{ pageSize: 20 }} size="small" />}
|
||
</>
|
||
),
|
||
},
|
||
{
|
||
key: 'rag-debug', label: 'RAG 调试',
|
||
children: (
|
||
<Card size="small" title="检索调试">
|
||
<Space>
|
||
<Input.Search placeholder="输入查询文本" value={debugQuery} onChange={e => setDebugQuery(e.target.value)} onSearch={handleDebugSearch} enterButton="检索" style={{ width: 400 }} />
|
||
</Space>
|
||
<div style={{ marginTop: 8 }}>
|
||
<Text type="secondary">输入查询文本后,将显示检索参数和结果(完整 RAG 管道在 M3 阶段完善)。</Text>
|
||
</div>
|
||
</Card>
|
||
),
|
||
},
|
||
]} />
|
||
</div>
|
||
)
|
||
}
|