feat: V1 - DAG编排/告警系统/Agent循环/知识库RAG/Webhook + 审核管理富上下文修复

This commit is contained in:
2026-08-13 00:47:23 +08:00
parent d3ca2bb7d0
commit 6aa8b635d7
+134
View File
@@ -0,0 +1,134 @@
import { useState, useEffect, useCallback } from 'react';
import {
Card, Table, Button, Modal, Form, Input, Tag, Space, message,
Empty, Typography, Input as SearchInput,
} from 'antd';
import {
PlusOutlined, DeleteOutlined, SearchOutlined, BookOutlined,
} from '@ant-design/icons';
import { knowledgeApi } from '@/api';
import type { KnowledgeDoc, KnowledgeSearchResult } from '@/types';
const { TextArea } = Input;
const { Text } = Typography;
export default function KnowledgeBase() {
const [docs, setDocs] = useState<KnowledgeDoc[]>([]);
const [loading, setLoading] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const [form] = Form.useForm();
const [searchQuery, setSearchQuery] = useState('');
const [searchResults, setSearchResults] = useState<KnowledgeSearchResult[] | null>(null);
const loadData = useCallback(() => {
setLoading(true);
knowledgeApi.list().then(setDocs).catch(() => {}).finally(() => setLoading(false));
}, []);
useEffect(() => { loadData(); }, [loadData]);
const handleCreate = async () => {
try {
const values = await form.validateFields();
await knowledgeApi.create(values);
message.success('文档创建成功');
setModalOpen(false);
form.resetFields();
loadData();
} catch (err: any) {
if (err?.errorFields) return;
message.error('创建失败');
}
};
const handleDelete = async (id: number) => {
try {
await knowledgeApi.delete(id);
message.success('已删除');
loadData();
} catch { message.error('删除失败'); }
};
const handleSearch = async () => {
if (!searchQuery.trim()) { setSearchResults(null); return; }
try {
const results = await knowledgeApi.search(searchQuery);
setSearchResults(results);
} catch { message.error('搜索失败'); }
};
const columns = [
{ title: '标题', dataIndex: 'title', key: 'title', render: (t: string) => <Text strong>{t}</Text> },
{ title: '类型', dataIndex: 'doc_type', key: 'doc_type', width: 80, render: (t: string) => <Tag>{t}</Tag> },
{
title: '标签', dataIndex: 'tags', key: 'tags', width: 200,
render: (tags: string) => tags ? tags.split(',').map((t, i) => <Tag key={i} color="blue">{t.trim()}</Tag>) : '-',
},
{
title: '内容预览', dataIndex: 'content', key: 'content',
render: (c: string) => <Text type="secondary" ellipsis style={{ maxWidth: 300 }}>{c?.slice(0, 80)}...</Text>,
},
{
title: '操作', key: 'action', width: 80,
render: (_: any, r: KnowledgeDoc) => (
<Button size="small" danger icon={<DeleteOutlined />} onClick={() => handleDelete(r.id)} />
),
},
];
return (
<div>
<Card
title={<Space><BookOutlined /> </Space>}
extra={<Button type="primary" icon={<PlusOutlined />} onClick={() => { form.resetFields(); setModalOpen(true); }}></Button>}
>
<SearchInput.Group compact style={{ marginBottom: 16 }}>
<SearchInput
style={{ width: 'calc(100% - 100px)' }}
placeholder="搜索知识库..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onPressEnter={handleSearch}
prefix={<SearchOutlined />}
/>
<Button type="primary" onClick={handleSearch} style={{ width: 100 }}></Button>
</SearchInput.Group>
{searchResults !== null ? (
<div>
<div style={{ marginBottom: 8 }}>
<Text type="secondary"> ({searchResults.length} ) </Text>
<Button type="link" size="small" onClick={() => { setSearchResults(null); setSearchQuery(''); }}></Button>
</div>
{searchResults.length === 0 ? (
<Empty description="未找到匹配文档" />
) : (
searchResults.map((r) => (
<Card key={r.id} size="small" style={{ marginBottom: 8 }}>
<Space direction="vertical" size={4} style={{ width: '100%' }}>
<Space>
<Text strong>{r.title}</Text>
<Tag color="gold">: {r.score}</Tag>
</Space>
<Text type="secondary">{r.content?.slice(0, 200)}</Text>
</Space>
</Card>
))
)}
</div>
) : (
<Table columns={columns} dataSource={docs} rowKey="id" loading={loading} pagination={{ pageSize: 10 }} />
)}
</Card>
<Modal title="添加知识文档" open={modalOpen} onOk={handleCreate} onCancel={() => setModalOpen(false)} width={600} okText="保存" cancelText="取消">
<Form form={form} layout="vertical">
<Form.Item name="title" label="标题" rules={[{ required: true }]}><Input placeholder="文档标题" /></Form.Item>
<Form.Item name="content" label="内容" rules={[{ required: true }]}><TextArea rows={6} placeholder="文档内容..." /></Form.Item>
<Form.Item name="tags" label="标签"><Input placeholder="用逗号分隔,如: API,文档" /></Form.Item>
<Form.Item name="doc_type" label="类型" initialValue="text"><Input /></Form.Item>
</Form>
</Modal>
</div>
);
}