import { useState, useEffect } from 'react'
import { Card, Upload, Table, Button, Space, Select, Popconfirm, message, Tag } from 'antd'
import { InboxOutlined, DeleteOutlined, ReloadOutlined } from '@ant-design/icons'
import useAuthStore from '../../stores/authStore'
import knowledgeService from '../../services/knowledgeService'
const { Dragger } = Upload
// source_type 枚举值(固定五类,不写死但供 Select 用)
const SOURCE_TYPE_OPTIONS = [
{ label: '全部类型', value: '' },
{ label: '杂志文章', value: 'military_report' },
{ label: '节目文稿', value: 'manuscript' },
{ label: '报题单', value: 'baoti' },
]
// source_type 中文标签
const SOURCE_TYPE_LABEL = {
military_report: '杂志文章',
manuscript: '节目文稿',
baoti: '报题单',
manual: '其他',
}
export default function KnowledgeBase() {
const { user } = useAuthStore()
const [items, setItems] = useState([])
const [sources, setSources] = useState([])
const [loading, setLoading] = useState(false)
const [uploading, setUploading] = useState(false)
const [sourceTypeFilter, setSourceTypeFilter] = useState('')
const [sourceDetailFilter, setSourceDetailFilter] = useState('')
const fetchItems = async () => {
setLoading(true)
try {
const data = await knowledgeService.listItems(sourceTypeFilter || null)
setItems(data)
} catch {
message.error('加载知识库失败')
} finally {
setLoading(false)
}
}
const fetchSources = async () => {
try {
const data = await knowledgeService.listSources()
setSources(data.map(s => ({ label: s.source, value: s.source })))
} catch {
// ignore
}
}
useEffect(() => {
fetchItems()
fetchSources()
}, [sourceTypeFilter])
// 上传
const handleUpload = async (file) => {
if (!file.name.endsWith('.md')) {
message.warning('仅支持 .md 文件')
return false
}
setUploading(true)
try {
const result = await knowledgeService.uploadFiles([file])
const { uploaded, errors } = result
if (uploaded.length > 0) {
message.success(`成功入库 ${uploaded.length} 篇`)
fetchItems()
fetchSources()
}
if (errors.length > 0) {
errors.forEach(e => message.error(`${e.file}: ${e.error}`))
}
} catch {
message.error('上传失败')
} finally {
setUploading(false)
}
return false // 阻止默认上传行为
}
// 删除
const handleDelete = async (id) => {
try {
await knowledgeService.deleteItem(id)
message.success('删除成功')
fetchItems()
fetchSources()
} catch {
message.error('删除失败')
}
}
// 列表筛选后过滤 source_detail
const displayedItems = sourceDetailFilter
? items.filter(i => i.source_detail === sourceDetailFilter)
: items
const columns = [
{
title: '标题',
dataIndex: 'title',
key: 'title',
render: (text, record) => (
{text}
),
},
{
title: '作者',
dataIndex: 'author',
key: 'author',
render: (val) => val || null, // 无则不显示
},
{
title: '播出/发表时间',
dataIndex: 'publish_date',
key: 'publish_date',
render: (val) => val || null, // 无则不显示
},
{
title: '出处',
dataIndex: 'source_detail',
key: 'source_detail',
render: (val) => val || '-',
},
{
title: '类型',
dataIndex: 'source_type',
key: 'source_type',
render: (val) => (
上传 md 笔记 · 语义检索 · 报题参考
{uploading ? '正在上传并生成向量…' : '点击或拖拽 .md 文件上传'}
支持批量上传,系统自动解析 yaml frontmatter 并生成语义向量