2025-10-11 17:18:40 +08:00
|
|
|
|
import React, { useState, useCallback } from 'react';
|
2025-10-09 17:23:15 +08:00
|
|
|
|
import {
|
|
|
|
|
|
Box,
|
|
|
|
|
|
Typography,
|
|
|
|
|
|
TextField,
|
2025-10-11 17:18:40 +08:00
|
|
|
|
Select,
|
|
|
|
|
|
MenuItem,
|
|
|
|
|
|
FormControl,
|
|
|
|
|
|
InputLabel,
|
|
|
|
|
|
Button,
|
2025-10-09 17:23:15 +08:00
|
|
|
|
InputAdornment,
|
2025-10-11 17:18:40 +08:00
|
|
|
|
Pagination,
|
|
|
|
|
|
Stack,
|
|
|
|
|
|
CircularProgress,
|
2025-10-09 17:23:15 +08:00
|
|
|
|
} from '@mui/material';
|
|
|
|
|
|
import {
|
|
|
|
|
|
Search as SearchIcon,
|
|
|
|
|
|
Add as AddIcon,
|
2025-10-11 17:18:40 +08:00
|
|
|
|
Refresh as RefreshIcon,
|
2025-10-09 17:23:15 +08:00
|
|
|
|
} from '@mui/icons-material';
|
2025-10-11 17:18:40 +08:00
|
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
|
|
import { useKnowledgeList } from '@/hooks/knowledge_hooks';
|
|
|
|
|
|
import KnowledgeGridView from '@/components/KnowledgeGridView';
|
|
|
|
|
|
import type { IKnowledge } from '@/interfaces/database/knowledge';
|
2025-10-09 17:23:15 +08:00
|
|
|
|
|
|
|
|
|
|
const KnowledgeBaseList: React.FC = () => {
|
2025-10-11 17:18:40 +08:00
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
|
|
|
|
|
|
|
// 搜索和筛选状态
|
2025-10-09 17:23:15 +08:00
|
|
|
|
const [searchTerm, setSearchTerm] = useState('');
|
2025-10-11 17:18:40 +08:00
|
|
|
|
const [teamFilter, setTeamFilter] = useState('all');
|
|
|
|
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
|
|
|
|
const pageSize = 12; // 每页显示12个知识库
|
|
|
|
|
|
|
|
|
|
|
|
// 使用knowledge_hooks获取数据
|
|
|
|
|
|
const {
|
|
|
|
|
|
knowledgeBases,
|
|
|
|
|
|
loading,
|
|
|
|
|
|
error,
|
|
|
|
|
|
refresh,
|
|
|
|
|
|
} = useKnowledgeList({
|
|
|
|
|
|
keywords: searchTerm,
|
|
|
|
|
|
page: currentPage,
|
|
|
|
|
|
page_size: pageSize,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 处理搜索
|
|
|
|
|
|
const handleSearch = useCallback((value: string) => {
|
|
|
|
|
|
setSearchTerm(value);
|
|
|
|
|
|
setCurrentPage(1); // 搜索时重置到第一页
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理团队筛选
|
|
|
|
|
|
const handleTeamFilterChange = useCallback((value: string) => {
|
|
|
|
|
|
setTeamFilter(value);
|
|
|
|
|
|
setCurrentPage(1); // 筛选时重置到第一页
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理分页变化
|
|
|
|
|
|
const handlePageChange = useCallback((_: React.ChangeEvent<unknown>, page: number) => {
|
|
|
|
|
|
setCurrentPage(page);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理刷新
|
|
|
|
|
|
const handleRefresh = useCallback(() => {
|
|
|
|
|
|
refresh();
|
|
|
|
|
|
}, [refresh]);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理创建知识库
|
|
|
|
|
|
const handleCreateKnowledge = useCallback(() => {
|
|
|
|
|
|
navigate('/knowledge/create');
|
|
|
|
|
|
}, [navigate]);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理编辑知识库
|
|
|
|
|
|
const handleEditKnowledge = useCallback((kb: IKnowledge) => {
|
|
|
|
|
|
navigate(`/knowledge/${kb.id}/edit`);
|
|
|
|
|
|
}, [navigate]);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理查看知识库详情
|
|
|
|
|
|
const handleViewKnowledge = useCallback((kb: IKnowledge) => {
|
|
|
|
|
|
navigate(`/knowledge/${kb.id}`);
|
|
|
|
|
|
}, [navigate]);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理删除知识库
|
|
|
|
|
|
const handleDeleteKnowledge = useCallback((kb: IKnowledge) => {
|
|
|
|
|
|
// TODO: 实现删除逻辑
|
|
|
|
|
|
console.log('删除知识库:', kb.id);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// 根据团队筛选过滤知识库
|
|
|
|
|
|
const filteredKnowledgeBases = React.useMemo(() => {
|
|
|
|
|
|
if (!knowledgeBases) return [];
|
|
|
|
|
|
|
|
|
|
|
|
if (teamFilter === 'all') {
|
|
|
|
|
|
return knowledgeBases;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return knowledgeBases.filter(kb => {
|
|
|
|
|
|
if (teamFilter === 'me') return kb.permission === 'me';
|
|
|
|
|
|
if (teamFilter === 'team') return kb.permission === 'team';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
});
|
|
|
|
|
|
}, [knowledgeBases, teamFilter]);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算总页数
|
|
|
|
|
|
const totalPages = Math.ceil((knowledgeBases?.length || 0) / pageSize);
|
2025-10-09 17:23:15 +08:00
|
|
|
|
|
|
|
|
|
|
return (
|
2025-10-11 17:18:40 +08:00
|
|
|
|
<Box sx={{ p: 3 }}>
|
|
|
|
|
|
{/* 页面标题 */}
|
|
|
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
|
|
|
|
|
<Typography variant="h4" fontWeight={600}>
|
2025-10-09 17:23:15 +08:00
|
|
|
|
知识库管理
|
|
|
|
|
|
</Typography>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
variant="contained"
|
|
|
|
|
|
startIcon={<AddIcon />}
|
2025-10-11 17:18:40 +08:00
|
|
|
|
onClick={handleCreateKnowledge}
|
|
|
|
|
|
sx={{ borderRadius: 2 }}
|
2025-10-09 17:23:15 +08:00
|
|
|
|
>
|
|
|
|
|
|
新建知识库
|
|
|
|
|
|
</Button>
|
2025-10-11 17:18:40 +08:00
|
|
|
|
</Box>
|
2025-10-09 17:23:15 +08:00
|
|
|
|
|
2025-10-11 17:18:40 +08:00
|
|
|
|
{/* 搜索和筛选区域 */}
|
|
|
|
|
|
<Box sx={{ display: 'flex', gap: 2, mb: 3, alignItems: 'center' }}>
|
2025-10-09 17:23:15 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
placeholder="搜索知识库..."
|
|
|
|
|
|
value={searchTerm}
|
2025-10-11 17:18:40 +08:00
|
|
|
|
onChange={(e) => handleSearch(e.target.value)}
|
|
|
|
|
|
sx={{ flex: 1, maxWidth: 400 }}
|
2025-10-09 17:23:15 +08:00
|
|
|
|
InputProps={{
|
|
|
|
|
|
startAdornment: (
|
|
|
|
|
|
<InputAdornment position="start">
|
2025-10-11 17:18:40 +08:00
|
|
|
|
<SearchIcon />
|
2025-10-09 17:23:15 +08:00
|
|
|
|
</InputAdornment>
|
|
|
|
|
|
),
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2025-10-11 17:18:40 +08:00
|
|
|
|
|
|
|
|
|
|
<FormControl sx={{ minWidth: 120 }}>
|
|
|
|
|
|
<InputLabel>团队筛选</InputLabel>
|
|
|
|
|
|
<Select
|
|
|
|
|
|
value={teamFilter}
|
|
|
|
|
|
label="团队筛选"
|
|
|
|
|
|
onChange={(e) => handleTeamFilterChange(e.target.value)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<MenuItem value="all">全部</MenuItem>
|
|
|
|
|
|
<MenuItem value="me">我的</MenuItem>
|
|
|
|
|
|
<MenuItem value="team">团队</MenuItem>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
</FormControl>
|
2025-10-09 17:23:15 +08:00
|
|
|
|
|
2025-10-11 17:18:40 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
variant="outlined"
|
|
|
|
|
|
startIcon={<RefreshIcon />}
|
|
|
|
|
|
onClick={handleRefresh}
|
|
|
|
|
|
disabled={loading}
|
|
|
|
|
|
>
|
|
|
|
|
|
刷新
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 错误提示 */}
|
|
|
|
|
|
{error && (
|
|
|
|
|
|
<Box sx={{ mb: 3, p: 2, bgcolor: 'error.light', borderRadius: 1 }}>
|
|
|
|
|
|
<Typography color="error">
|
|
|
|
|
|
加载知识库列表失败: {error}
|
|
|
|
|
|
</Typography>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 加载状态 */}
|
|
|
|
|
|
{loading && (
|
|
|
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
|
|
|
|
|
|
<CircularProgress />
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 知识库列表 */}
|
|
|
|
|
|
{!loading && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<KnowledgeGridView
|
|
|
|
|
|
knowledgeBases={filteredKnowledgeBases}
|
|
|
|
|
|
onEdit={handleEditKnowledge}
|
|
|
|
|
|
onDelete={handleDeleteKnowledge}
|
|
|
|
|
|
onView={handleViewKnowledge}
|
|
|
|
|
|
loading={loading}
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 分页组件 */}
|
|
|
|
|
|
{totalPages > 1 && (
|
|
|
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 4 }}>
|
|
|
|
|
|
<Stack spacing={2}>
|
|
|
|
|
|
<Pagination
|
|
|
|
|
|
count={totalPages}
|
|
|
|
|
|
page={currentPage}
|
|
|
|
|
|
onChange={handlePageChange}
|
|
|
|
|
|
color="primary"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
showFirstButton
|
|
|
|
|
|
showLastButton
|
|
|
|
|
|
/>
|
|
|
|
|
|
<Typography variant="body2" color="text.secondary" textAlign="center">
|
|
|
|
|
|
共 {knowledgeBases?.length || 0} 个知识库,第 {currentPage} 页,共 {totalPages} 页
|
2025-10-09 17:23:15 +08:00
|
|
|
|
</Typography>
|
2025-10-11 17:18:40 +08:00
|
|
|
|
</Stack>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 空状态 */}
|
|
|
|
|
|
{!loading && filteredKnowledgeBases.length === 0 && !error && (
|
|
|
|
|
|
<Box sx={{ textAlign: 'center', py: 8 }}>
|
|
|
|
|
|
<Typography variant="h6" color="text.secondary" gutterBottom>
|
|
|
|
|
|
{searchTerm || teamFilter !== 'all' ? '没有找到匹配的知识库' : '暂无知识库'}
|
|
|
|
|
|
</Typography>
|
|
|
|
|
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
|
|
|
|
|
{searchTerm || teamFilter !== 'all'
|
|
|
|
|
|
? '尝试调整搜索条件或筛选器'
|
|
|
|
|
|
: '创建您的第一个知识库开始使用'
|
|
|
|
|
|
}
|
|
|
|
|
|
</Typography>
|
|
|
|
|
|
{(!searchTerm && teamFilter === 'all') && (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
variant="contained"
|
|
|
|
|
|
startIcon={<AddIcon />}
|
|
|
|
|
|
onClick={handleCreateKnowledge}
|
|
|
|
|
|
>
|
|
|
|
|
|
新建知识库
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Box>
|
2025-10-09 17:23:15 +08:00
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default KnowledgeBaseList;
|