import React, { useState, useEffect } from 'react'; import { Layout, Menu, Button, Table, Space, Form, Input, Select, message, Modal, Card, Spin, Row, Col, Breadcrumb, Avatar, Dropdown, ConfigProvider, theme, Typography, Switch, Badge, Image, Upload, Divider, Descriptions, Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer } from 'antd'; import { UploadOutlined, FileImageOutlined, FileExcelOutlined, FileWordOutlined, FilePdfOutlined, FileOutlined, } from '@ant-design/icons'; import { useQuery, } from '@tanstack/react-query'; import dayjs from 'dayjs'; import weekday from 'dayjs/plugin/weekday'; import localeData from 'dayjs/plugin/localeData'; import { uploadMinIOWithPolicy,uploadOSSWithPolicy } from '@d8d-appcontainer/api'; import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types'; import 'dayjs/locale/zh-cn'; import type { FileLibrary, FileCategory, KnowInfo } from '../share/types.ts'; import { AuditStatus,AuditStatusNameMap, OssType, } from '../share/types.ts'; import { getEnumOptions } from './utils.ts'; import { FileAPI, UserAPI, } from './api.ts'; // 配置 dayjs 插件 dayjs.extend(weekday); dayjs.extend(localeData); // 设置 dayjs 语言 dayjs.locale('zh-cn'); const { Title } = Typography; // 仪表盘页面 export const DashboardPage = () => { return (
仪表盘
); }; // 用户管理页面 export const UsersPage = () => { const [searchParams, setSearchParams] = useState({ page: 1, limit: 10, search: '' }); const [modalVisible, setModalVisible] = useState(false); const [modalTitle, setModalTitle] = useState(''); const [editingUser, setEditingUser] = useState(null); const [form] = Form.useForm(); const { data: usersData, isLoading, refetch } = useQuery({ queryKey: ['users', searchParams], queryFn: async () => { return await UserAPI.getUsers(searchParams); } }); const users = usersData?.data || []; const pagination = { current: searchParams.page, pageSize: searchParams.limit, total: usersData?.pagination?.total || 0 }; // 处理搜索 const handleSearch = (values: any) => { setSearchParams(prev => ({ ...prev, search: values.search || '', page: 1 })); }; // 处理分页变化 const handleTableChange = (newPagination: any) => { setSearchParams(prev => ({ ...prev, page: newPagination.current, limit: newPagination.pageSize })); }; // 打开创建用户模态框 const showCreateModal = () => { setModalTitle('创建用户'); setEditingUser(null); form.resetFields(); setModalVisible(true); }; // 打开编辑用户模态框 const showEditModal = (user: any) => { setModalTitle('编辑用户'); setEditingUser(user); form.setFieldsValue(user); setModalVisible(true); }; // 处理模态框确认 const handleModalOk = async () => { try { const values = await form.validateFields(); if (editingUser) { // 编辑用户 await UserAPI.updateUser(editingUser.id, values); message.success('用户更新成功'); } else { // 创建用户 await UserAPI.createUser(values); message.success('用户创建成功'); } setModalVisible(false); form.resetFields(); refetch(); // 刷新用户列表 } catch (error) { console.error('表单提交失败:', error); message.error('操作失败,请重试'); } }; // 处理删除用户 const handleDelete = async (id: number) => { try { await UserAPI.deleteUser(id); message.success('用户删除成功'); refetch(); // 刷新用户列表 } catch (error) { console.error('删除用户失败:', error); message.error('删除失败,请重试'); } }; const columns = [ { title: '用户名', dataIndex: 'username', key: 'username', }, { title: '昵称', dataIndex: 'nickname', key: 'nickname', }, { title: '邮箱', dataIndex: 'email', key: 'email', }, { title: '角色', dataIndex: 'role', key: 'role', render: (role: string) => ( {role === 'admin' ? '管理员' : '普通用户'} ), }, { title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (date: string) => dayjs(date).format('YYYY-MM-DD HH:mm:ss'), }, { title: '操作', key: 'action', render: (_: any, record: any) => ( handleDelete(record.id)} okText="确定" cancelText="取消" > ), }, ]; return (
用户管理
`共 ${total} 条记录` }} onChange={handleTableChange} /> {/* 创建/编辑用户模态框 */} { setModalVisible(false); form.resetFields(); }} width={600} >
{!editingUser && ( )}
); }; // 知识库管理页面组件 export const KnowInfoPage = () => { const [modalVisible, setModalVisible] = useState(false); const [formMode, setFormMode] = useState<'create' | 'edit'>('create'); const [editingId, setEditingId] = useState(null); const [form] = Form.useForm(); const [isLoading, setIsLoading] = useState(false); const [searchParams, setSearchParams] = useState({ title: '', category: '', page: 1, limit: 10, }); // 使用React Query获取知识库文章列表 const { data: articlesData, isLoading: isListLoading, refetch } = useQuery({ queryKey: ['articles', searchParams], queryFn: async () => { const { title, category, page, limit } = searchParams; const params = new URLSearchParams(); if (title) params.append('title', title); if (category) params.append('category', category); params.append('page', String(page)); params.append('limit', String(limit)); const response = await fetch(`/api/know-info?${params.toString()}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, }); if (!response.ok) { throw new Error('获取知识库文章列表失败'); } return await response.json(); } }); const articles = articlesData?.data || []; const pagination = articlesData?.pagination || { current: 1, pageSize: 10, total: 0 }; // 获取单个知识库文章 const fetchArticle = async (id: number) => { try { const response = await fetch(`/api/know-info/${id}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, }); if (!response.ok) { throw new Error('获取知识库文章详情失败'); } return await response.json(); } catch (error) { message.error('获取知识库文章详情失败'); return null; } }; // 处理表单提交 const handleSubmit = async (values: Partial) => { setIsLoading(true); try { const url = formMode === 'create' ? '/api/know-info' : `/api/know-info/${editingId}`; const method = formMode === 'create' ? 'POST' : 'PUT'; const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, body: JSON.stringify(values), }); if (!response.ok) { throw new Error(formMode === 'create' ? '创建知识库文章失败' : '更新知识库文章失败'); } message.success(formMode === 'create' ? '创建知识库文章成功' : '更新知识库文章成功'); setModalVisible(false); form.resetFields(); refetch(); } catch (error) { message.error((error as Error).message); } finally { setIsLoading(false); } }; // 处理编辑 const handleEdit = async (id: number) => { const article = await fetchArticle(id); if (article) { setFormMode('edit'); setEditingId(id); form.setFieldsValue(article); setModalVisible(true); } }; // 处理删除 const handleDelete = async (id: number) => { try { const response = await fetch(`/api/know-info/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, }); if (!response.ok) { throw new Error('删除知识库文章失败'); } message.success('删除知识库文章成功'); refetch(); } catch (error) { message.error((error as Error).message); } }; // 处理搜索 const handleSearch = (values: any) => { setSearchParams(prev => ({ ...prev, title: values.title || '', category: values.category || '', page: 1, })); }; // 处理分页 const handlePageChange = (page: number, pageSize?: number) => { setSearchParams(prev => ({ ...prev, page, limit: pageSize || prev.limit, })); }; // 处理添加 const handleAdd = () => { setFormMode('create'); setEditingId(null); form.resetFields(); setModalVisible(true); }; // 审核状态映射 const auditStatusOptions = getEnumOptions(AuditStatus, AuditStatusNameMap); // 表格列定义 const columns = [ { title: 'ID', dataIndex: 'id', key: 'id', width: 80, }, { title: '标题', dataIndex: 'title', key: 'title', }, { title: '分类', dataIndex: 'category', key: 'category', }, { title: '标签', dataIndex: 'tags', key: 'tags', render: (tags: string) => tags ? tags.split(',').map(tag => ( {tag} )) : null, }, { title: '作者', dataIndex: 'author', key: 'author', }, { title: '审核状态', dataIndex: 'audit_status', key: 'audit_status', render: (status: AuditStatus) => { let color = ''; let text = ''; switch(status) { case AuditStatus.PENDING: color = 'orange'; text = '待审核'; break; case AuditStatus.APPROVED: color = 'green'; text = '已通过'; break; case AuditStatus.REJECTED: color = 'red'; text = '已拒绝'; break; default: color = 'default'; text = '未知'; } return {text}; }, }, { title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (date: string) => new Date(date).toLocaleString(), }, { title: '操作', key: 'action', render: (_: any, record: KnowInfo) => ( handleDelete(record.id)} okText="确定" cancelText="取消" > ), }, ]; return (
form.submit()} onCancel={() => setModalVisible(false)} width={800} >
{/* 文件列表 */}
`共 ${total} 条记录` }} onChange={handleTableChange} />
{/* 上传文件弹窗 */} setUploadModalVisible(false)} footer={null} >
支持任意类型文件,单个文件不超过10MB
{/* 文件详情弹窗 */} setFileDetailModalVisible(false)} footer={[ , ]} width={700} > {currentFile && ( {currentFile.file_name} {currentFile.original_filename && ( {currentFile.original_filename} )} {currentFile.file_type} {currentFile.file_size < 1024 * 1024 ? `${(currentFile.file_size / 1024).toFixed(2)} KB` : `${(currentFile.file_size / 1024 / 1024).toFixed(2)} MB`} {currentFile.uploader_name} {dayjs(currentFile.created_at).format('YYYY-MM-DD HH:mm:ss')} {currentFile.category_id} {currentFile.download_count} {currentFile.tags?.split(',').map(tag => ( {tag} ))} {currentFile.description} {currentFile.file_type.startsWith('image/') && ( )} )} {/* 分类管理弹窗 */} { setCategoryModalVisible(false); categoryForm.resetFields(); setCurrentCategory(null); }} >
); };