- Implement knowledge base list, create, and detail pages - Add dialog provider and components for confirmation and alerts - Include knowledge card and grid view components - Enhance header with user menu and logout functionality - Implement knowledge operations hooks for CRUD operations
495 lines
16 KiB
TypeScript
495 lines
16 KiB
TypeScript
import React, { useState } from 'react';
|
||
import {
|
||
Box,
|
||
Typography,
|
||
Card,
|
||
CardContent,
|
||
Grid,
|
||
Button,
|
||
Table,
|
||
TableBody,
|
||
TableCell,
|
||
TableContainer,
|
||
TableHead,
|
||
TableRow,
|
||
Paper,
|
||
Chip,
|
||
LinearProgress,
|
||
Select,
|
||
MenuItem,
|
||
FormControl,
|
||
InputLabel,
|
||
} from '@mui/material';
|
||
import {
|
||
TrendingUp as TrendingUpIcon,
|
||
TrendingDown as TrendingDownIcon,
|
||
Assessment as AssessmentIcon,
|
||
Speed as SpeedIcon,
|
||
Error as ErrorIcon,
|
||
CheckCircle as CheckCircleIcon,
|
||
} from '@mui/icons-material';
|
||
import { styled } from '@mui/material/styles';
|
||
import KnowledgeGridView from '@/components/knowledge/KnowledgeGridView';
|
||
import UserDataDebug from '@/components/UserDataDebug';
|
||
import { useNavigate } from 'react-router-dom';
|
||
|
||
const PageContainer = styled(Box)(({ theme }) => ({
|
||
padding: '1.5rem',
|
||
backgroundColor: '#F8F9FA',
|
||
minHeight: 'calc(100vh - 60px)',
|
||
}));
|
||
|
||
const PageHeader = styled(Box)(({ theme }) => ({
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginBottom: '1.5rem',
|
||
}));
|
||
|
||
const MetricCard = styled(Card)(({ theme }) => ({
|
||
height: '100%',
|
||
border: '1px solid #E5E5E5',
|
||
transition: 'all 0.2s ease-in-out',
|
||
'&:hover': {
|
||
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||
},
|
||
}));
|
||
|
||
const MetricValue = styled(Typography)(({ theme }) => ({
|
||
fontSize: '2rem',
|
||
fontWeight: 700,
|
||
lineHeight: 1.2,
|
||
}));
|
||
|
||
const TrendIndicator = styled(Box)<{ trend: 'up' | 'down' }>(({ trend, theme }) => ({
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: '0.25rem',
|
||
color: trend === 'up' ? '#28A745' : '#DC3545',
|
||
fontSize: '0.875rem',
|
||
fontWeight: 500,
|
||
}));
|
||
|
||
const StatusChip = styled(Chip)<{ status: string }>(({ status, theme }) => ({
|
||
fontSize: '0.75rem',
|
||
height: '24px',
|
||
backgroundColor:
|
||
status === 'success' ? '#E8F5E8' :
|
||
status === 'warning' ? '#FFF3CD' :
|
||
status === 'error' ? '#F8D7DA' : '#F8F9FA',
|
||
color:
|
||
status === 'success' ? '#155724' :
|
||
status === 'warning' ? '#856404' :
|
||
status === 'error' ? '#721C24' : '#666',
|
||
}));
|
||
|
||
const mockMetrics = {
|
||
totalQueries: { value: 12847, trend: 'up', change: '+12.5%' },
|
||
avgResponseTime: { value: '2.3s', trend: 'down', change: '-8.2%' },
|
||
successRate: { value: '98.7%', trend: 'up', change: '+0.3%' },
|
||
activeUsers: { value: 1256, trend: 'up', change: '+5.7%' },
|
||
};
|
||
|
||
const mockRecentQueries = [
|
||
{
|
||
id: 1,
|
||
query: '如何配置RAG Pipeline的参数?',
|
||
user: 'user@example.com',
|
||
status: 'success',
|
||
responseTime: '1.8s',
|
||
timestamp: '2024-01-15 14:30:25',
|
||
knowledgeBase: '产品文档库',
|
||
},
|
||
{
|
||
id: 2,
|
||
query: '客服系统的常见问题有哪些?',
|
||
user: 'admin@company.com',
|
||
status: 'success',
|
||
responseTime: '2.1s',
|
||
timestamp: '2024-01-15 14:28:15',
|
||
knowledgeBase: '客服FAQ',
|
||
},
|
||
{
|
||
id: 3,
|
||
query: '法律合规要求的详细说明',
|
||
user: 'legal@company.com',
|
||
status: 'warning',
|
||
responseTime: '4.2s',
|
||
timestamp: '2024-01-15 14:25:10',
|
||
knowledgeBase: '法律合规',
|
||
},
|
||
{
|
||
id: 4,
|
||
query: '员工培训流程和要求',
|
||
user: 'hr@company.com',
|
||
status: 'error',
|
||
responseTime: 'N/A',
|
||
timestamp: '2024-01-15 14:22:45',
|
||
knowledgeBase: '培训资料',
|
||
},
|
||
];
|
||
|
||
const Dashboard: React.FC = () => {
|
||
const [timeRange, setTimeRange] = useState('24h');
|
||
const navigate = useNavigate();
|
||
|
||
// 模拟知识库数据
|
||
const mockKnowledgeBases = [
|
||
{
|
||
id: '1',
|
||
name: '产品文档库',
|
||
description: '包含所有产品相关的技术文档和用户手册',
|
||
status: '1',
|
||
doc_num: 156,
|
||
chunk_num: 1240,
|
||
size: 2400000000, // 2.4GB
|
||
update_date: '2024-01-15',
|
||
created_by: 'admin',
|
||
nickname: '管理员',
|
||
create_date: '2024-01-01',
|
||
create_time: 1704067200,
|
||
tenant_id: 'tenant1',
|
||
token_num: 50000,
|
||
parser_config: {},
|
||
parser_id: 'parser1',
|
||
pipeline_id: 'pipeline1',
|
||
pipeline_name: 'Default Pipeline',
|
||
pipeline_avatar: '',
|
||
permission: 'read',
|
||
similarity_threshold: 0.8,
|
||
update_time: 1705305600,
|
||
vector_similarity_weight: 0.7,
|
||
embd_id: 'embd1',
|
||
operator_permission: 1,
|
||
},
|
||
{
|
||
id: '2',
|
||
name: '客服FAQ',
|
||
description: '常见问题解答和客服对话记录',
|
||
status: '1',
|
||
doc_num: 89,
|
||
chunk_num: 670,
|
||
size: 1100000000, // 1.1GB
|
||
update_date: '2024-01-14',
|
||
created_by: 'support',
|
||
nickname: '客服团队',
|
||
create_date: '2024-01-02',
|
||
create_time: 1704153600,
|
||
tenant_id: 'tenant1',
|
||
token_num: 30000,
|
||
parser_config: {},
|
||
parser_id: 'parser1',
|
||
pipeline_id: 'pipeline1',
|
||
pipeline_name: 'Default Pipeline',
|
||
pipeline_avatar: '',
|
||
permission: 'read',
|
||
similarity_threshold: 0.8,
|
||
update_time: 1705219200,
|
||
vector_similarity_weight: 0.7,
|
||
embd_id: 'embd1',
|
||
operator_permission: 1,
|
||
},
|
||
{
|
||
id: '3',
|
||
name: '法律合规',
|
||
description: '法律条文、合规要求和相关政策文档',
|
||
status: '0',
|
||
doc_num: 234,
|
||
chunk_num: 1890,
|
||
size: 3700000000, // 3.7GB
|
||
update_date: '2024-01-13',
|
||
created_by: 'legal',
|
||
nickname: '法务部',
|
||
create_date: '2024-01-03',
|
||
create_time: 1704240000,
|
||
tenant_id: 'tenant1',
|
||
token_num: 75000,
|
||
parser_config: {},
|
||
parser_id: 'parser1',
|
||
pipeline_id: 'pipeline1',
|
||
pipeline_name: 'Default Pipeline',
|
||
pipeline_avatar: '',
|
||
permission: 'read',
|
||
similarity_threshold: 0.8,
|
||
update_time: 1705132800,
|
||
vector_similarity_weight: 0.7,
|
||
embd_id: 'embd1',
|
||
operator_permission: 1,
|
||
},
|
||
];
|
||
|
||
const handleSeeAllKnowledgeBases = () => {
|
||
navigate('/knowledge');
|
||
};
|
||
|
||
return (
|
||
<PageContainer>
|
||
<PageHeader>
|
||
<Typography variant="h4" fontWeight={600} color="#333">
|
||
运营监控
|
||
</Typography>
|
||
<FormControl size="small" sx={{ minWidth: 120 }}>
|
||
<InputLabel>时间范围</InputLabel>
|
||
<Select
|
||
value={timeRange}
|
||
onChange={(e) => setTimeRange(e.target.value)}
|
||
label="时间范围"
|
||
>
|
||
<MenuItem value="1h">最近1小时</MenuItem>
|
||
<MenuItem value="24h">最近24小时</MenuItem>
|
||
<MenuItem value="7d">最近7天</MenuItem>
|
||
<MenuItem value="30d">最近30天</MenuItem>
|
||
</Select>
|
||
</FormControl>
|
||
</PageHeader>
|
||
|
||
{/* 关键指标卡片 */}
|
||
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||
<Grid item xs={12} sm={6} md={3}>
|
||
<MetricCard>
|
||
<CardContent>
|
||
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||
<Box>
|
||
<Typography color="text.secondary" variant="body2">
|
||
总查询数
|
||
</Typography>
|
||
<MetricValue color="primary">
|
||
{mockMetrics.totalQueries.value.toLocaleString()}
|
||
</MetricValue>
|
||
<TrendIndicator trend={mockMetrics.totalQueries.trend}>
|
||
{mockMetrics.totalQueries.trend === 'up' ?
|
||
<TrendingUpIcon fontSize="small" /> :
|
||
<TrendingDownIcon fontSize="small" />
|
||
}
|
||
{mockMetrics.totalQueries.change}
|
||
</TrendIndicator>
|
||
</Box>
|
||
<AssessmentIcon color="primary" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||
</Box>
|
||
</CardContent>
|
||
</MetricCard>
|
||
</Grid>
|
||
|
||
<Grid item xs={12} sm={6} md={3}>
|
||
<MetricCard>
|
||
<CardContent>
|
||
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||
<Box>
|
||
<Typography color="text.secondary" variant="body2">
|
||
平均响应时间
|
||
</Typography>
|
||
<MetricValue color="warning.main">
|
||
{mockMetrics.avgResponseTime.value}
|
||
</MetricValue>
|
||
<TrendIndicator trend={mockMetrics.avgResponseTime.trend}>
|
||
{mockMetrics.avgResponseTime.trend === 'up' ?
|
||
<TrendingUpIcon fontSize="small" /> :
|
||
<TrendingDownIcon fontSize="small" />
|
||
}
|
||
{mockMetrics.avgResponseTime.change}
|
||
</TrendIndicator>
|
||
</Box>
|
||
<SpeedIcon color="warning" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||
</Box>
|
||
</CardContent>
|
||
</MetricCard>
|
||
</Grid>
|
||
|
||
<Grid item xs={12} sm={6} md={3}>
|
||
<MetricCard>
|
||
<CardContent>
|
||
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||
<Box>
|
||
<Typography color="text.secondary" variant="body2">
|
||
成功率
|
||
</Typography>
|
||
<MetricValue color="success.main">
|
||
{mockMetrics.successRate.value}
|
||
</MetricValue>
|
||
<TrendIndicator trend={mockMetrics.successRate.trend}>
|
||
{mockMetrics.successRate.trend === 'up' ?
|
||
<TrendingUpIcon fontSize="small" /> :
|
||
<TrendingDownIcon fontSize="small" />
|
||
}
|
||
{mockMetrics.successRate.change}
|
||
</TrendIndicator>
|
||
</Box>
|
||
<CheckCircleIcon color="success" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||
</Box>
|
||
</CardContent>
|
||
</MetricCard>
|
||
</Grid>
|
||
|
||
<Grid item xs={12} sm={6} md={3}>
|
||
<MetricCard>
|
||
<CardContent>
|
||
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||
<Box>
|
||
<Typography color="text.secondary" variant="body2">
|
||
活跃用户
|
||
</Typography>
|
||
<MetricValue color="info.main">
|
||
{mockMetrics.activeUsers.value.toLocaleString()}
|
||
</MetricValue>
|
||
<TrendIndicator trend={mockMetrics.activeUsers.trend}>
|
||
{mockMetrics.activeUsers.trend === 'up' ?
|
||
<TrendingUpIcon fontSize="small" /> :
|
||
<TrendingDownIcon fontSize="small" />
|
||
}
|
||
{mockMetrics.activeUsers.change}
|
||
</TrendIndicator>
|
||
</Box>
|
||
<AssessmentIcon color="info" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||
</Box>
|
||
</CardContent>
|
||
</MetricCard>
|
||
</Grid>
|
||
</Grid>
|
||
|
||
{/* 知识库概览 */}
|
||
<Card sx={{ border: '1px solid #E5E5E5', mb: 3 }}>
|
||
<CardContent>
|
||
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
||
<Typography variant="h6" fontWeight={600}>
|
||
知识库概览
|
||
</Typography>
|
||
<Button
|
||
variant="outlined"
|
||
size="small"
|
||
onClick={handleSeeAllKnowledgeBases}
|
||
>
|
||
查看全部
|
||
</Button>
|
||
</Box>
|
||
<KnowledgeGridView
|
||
knowledgeBases={mockKnowledgeBases}
|
||
maxItems={3}
|
||
showSeeAll={true}
|
||
onSeeAll={handleSeeAllKnowledgeBases}
|
||
/>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 系统状态 */}
|
||
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||
<Grid item xs={12} md={6}>
|
||
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||
<CardContent>
|
||
<Typography variant="h6" fontWeight={600} mb={2}>
|
||
系统状态
|
||
</Typography>
|
||
<Box mb={2}>
|
||
<Box display="flex" justifyContent="space-between" mb={1}>
|
||
<Typography variant="body2">CPU 使用率</Typography>
|
||
<Typography variant="body2" fontWeight={600}>45%</Typography>
|
||
</Box>
|
||
<LinearProgress variant="determinate" value={45} sx={{ height: 8, borderRadius: 4 }} />
|
||
</Box>
|
||
<Box mb={2}>
|
||
<Box display="flex" justifyContent="space-between" mb={1}>
|
||
<Typography variant="body2">内存使用率</Typography>
|
||
<Typography variant="body2" fontWeight={600}>67%</Typography>
|
||
</Box>
|
||
<LinearProgress variant="determinate" value={67} color="warning" sx={{ height: 8, borderRadius: 4 }} />
|
||
</Box>
|
||
<Box>
|
||
<Box display="flex" justifyContent="space-between" mb={1}>
|
||
<Typography variant="body2">存储使用率</Typography>
|
||
<Typography variant="body2" fontWeight={600}>23%</Typography>
|
||
</Box>
|
||
<LinearProgress variant="determinate" value={23} color="success" sx={{ height: 8, borderRadius: 4 }} />
|
||
</Box>
|
||
</CardContent>
|
||
</Card>
|
||
</Grid>
|
||
|
||
<Grid item xs={12} md={6}>
|
||
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||
<CardContent>
|
||
<Typography variant="h6" fontWeight={600} mb={2}>
|
||
知识库状态
|
||
</Typography>
|
||
<Box display="flex" flexDirection="column" gap={1}>
|
||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||
<Typography variant="body2">产品文档库</Typography>
|
||
<StatusChip status="success" label="正常" size="small" />
|
||
</Box>
|
||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||
<Typography variant="body2">客服FAQ</Typography>
|
||
<StatusChip status="success" label="正常" size="small" />
|
||
</Box>
|
||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||
<Typography variant="body2">法律合规</Typography>
|
||
<StatusChip status="warning" label="同步中" size="small" />
|
||
</Box>
|
||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||
<Typography variant="body2">培训资料</Typography>
|
||
<StatusChip status="error" label="错误" size="small" />
|
||
</Box>
|
||
</Box>
|
||
</CardContent>
|
||
</Card>
|
||
</Grid>
|
||
</Grid>
|
||
|
||
{/* 最近查询记录 */}
|
||
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||
<CardContent>
|
||
<Typography variant="h6" fontWeight={600} mb={2}>
|
||
最近查询记录
|
||
</Typography>
|
||
<TableContainer>
|
||
<Table>
|
||
<TableHead>
|
||
<TableRow>
|
||
<TableCell>查询内容</TableCell>
|
||
<TableCell>用户</TableCell>
|
||
<TableCell>知识库</TableCell>
|
||
<TableCell>状态</TableCell>
|
||
<TableCell>响应时间</TableCell>
|
||
<TableCell>时间</TableCell>
|
||
</TableRow>
|
||
</TableHead>
|
||
<TableBody>
|
||
{mockRecentQueries.map((query) => (
|
||
<TableRow key={query.id} hover>
|
||
<TableCell>
|
||
<Typography variant="body2" sx={{ maxWidth: '300px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||
{query.query}
|
||
</Typography>
|
||
</TableCell>
|
||
<TableCell>{query.user}</TableCell>
|
||
<TableCell>{query.knowledgeBase}</TableCell>
|
||
<TableCell>
|
||
<StatusChip status={query.status} label={
|
||
query.status === 'success' ? '成功' :
|
||
query.status === 'warning' ? '警告' : '失败'
|
||
} size="small" />
|
||
</TableCell>
|
||
<TableCell>{query.responseTime}</TableCell>
|
||
<TableCell>
|
||
<Typography variant="body2" color="text.secondary">
|
||
{query.timestamp}
|
||
</Typography>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</TableContainer>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 用户数据调试组件 - 仅在开发环境显示 */}
|
||
{process.env.NODE_ENV === 'development' && (
|
||
<Card sx={{ border: '1px solid #E5E5E5', mt: 3 }}>
|
||
<CardContent>
|
||
<UserDataDebug />
|
||
</CardContent>
|
||
</Card>
|
||
)}
|
||
</PageContainer>
|
||
);
|
||
};
|
||
|
||
export default Dashboard; |