import { useState, useEffect } from 'react' import { Table, Button, Form, Input, Modal, message, Space, Popconfirm, } from 'antd' import { PlusOutlined, EditOutlined, DeleteOutlined, ReloadOutlined, EyeOutlined } from '@ant-design/icons' import type { ColumnsType } from 'antd/es/table' import type { Material } from '@/types/question' import { MaterialType } from '@/types/question' import { searchMaterials, createMaterial, updateMaterial, deleteMaterial } from '@/api/question' import { DEFAULT_PAGE_SIZE } from '@/constants' import dayjs from 'dayjs' import RichTextEditor from '@/components/RichTextEditor/RichTextEditor' const MaterialList = () => { const [loading, setLoading] = useState(false) const [dataSource, setDataSource] = useState([]) const [total, setTotal] = useState(0) const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE) const [query, setQuery] = useState('') const [modalVisible, setModalVisible] = useState(false) const [previewVisible, setPreviewVisible] = useState(false) const [editingRecord, setEditingRecord] = useState(null) const [previewContent, setPreviewContent] = useState('') const [form] = Form.useForm() // 获取列表数据 const fetchData = async () => { setLoading(true) try { const res = await searchMaterials({ query, type: MaterialType.OBJECTIVE, page, pageSize, }) if (res.data.code === 200) { const list = res.data.data.list || [] const total = res.data.data.total || 0 setDataSource(list) setTotal(total) } } catch (error: any) { console.error('获取材料列表错误:', error) setDataSource([]) setTotal(0) if (error.response?.status >= 500 || !error.response) { message.error('服务器错误,请稍后重试') } } finally { setLoading(false) } } useEffect(() => { fetchData() }, [page, pageSize, query]) // 监听 Modal 打开,设置表单初始值 useEffect(() => { if (modalVisible && editingRecord) { console.log('编辑材料数据:', editingRecord) form.setFieldsValue({ name: editingRecord.name || '', content: editingRecord.content || '', }) } }, [modalVisible, editingRecord, form]) // 打开新增/编辑弹窗 const handleOpenModal = (record?: Material) => { if (record) { setEditingRecord(record) } else { setEditingRecord(null) form.resetFields() form.setFieldsValue({ name: '', content: '', }) } setModalVisible(true) } // 预览材料内容 const handlePreview = (record: Material) => { setPreviewContent(record.content) setPreviewVisible(true) } // 提交表单 const handleSubmit = async () => { try { const values = await form.validateFields() const formData = { type: MaterialType.OBJECTIVE, name: values.name || '', content: values.content || '', } if (editingRecord) { // 编辑 await updateMaterial({ ...editingRecord, ...formData }) message.success('编辑材料成功') } else { // 新增 await createMaterial(formData) message.success('新增材料成功') } setModalVisible(false) setEditingRecord(null) form.resetFields() fetchData() } catch (error: any) { const errorMsg = error?.message || '操作失败' message.error(errorMsg) } } // 删除材料 const handleDelete = async (id: string) => { try { await deleteMaterial(id) message.success('删除成功') fetchData() } catch (error: any) { const errorMsg = error?.message || '删除失败' message.error(errorMsg) } } // 搜索 const handleSearch = (value: string) => { setQuery(value) setPage(1) } const columns: ColumnsType = [ { title: '材料名称', dataIndex: 'name', key: 'name', width: 200, ellipsis: true, render: (name: string) => name || 未命名, }, { title: '材料内容', dataIndex: 'content', key: 'content', width: 400, ellipsis: true, render: (content: string) => { // 移除 HTML 标签,只显示纯文本 const textContent = content .replace(/]*>/gi, '[图片]') .replace(/<[^>]+>/g, '') .replace(/\n/g, ' ') .trim() return textContent || 无内容 }, }, { title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', width: 180, render: (timestamp: number) => { if (!timestamp) return '-' return dayjs(timestamp * 1000).format('YYYY-MM-DD HH:mm') }, }, { title: '更新时间', dataIndex: 'updatedAt', key: 'updatedAt', width: 180, render: (timestamp: number) => { if (!timestamp) return '-' return dayjs(timestamp * 1000).format('YYYY-MM-DD HH:mm') }, }, { title: '操作', key: 'action', width: 200, fixed: 'right', render: (_, record) => ( handleDelete(record.id)} okText="确定" cancelText="取消" > ), }, ] return (
{/* 页面标题 */}

客观题管理 - 材料管理

管理客观题材料,材料可用于题目中
`共 ${total} 个材料`, onChange: (page, pageSize) => { setPage(page) setPageSize(pageSize) }, }} /> {/* 新增/编辑弹窗 */} { setModalVisible(false) setEditingRecord(null) form.resetFields() }} width={900} okText="确定" cancelText="取消" >
{/* 预览弹窗 */} setPreviewVisible(false)} footer={[ , ]} width={900} >
{ let html = previewContent || '' if (!html) return '' // react-quill 生成的 HTML 已经是完整的格式,直接使用 // 只需要确保图片标签有正确的样式 return html.replace( /]*)>/gi, (match, attrs) => { if (!attrs.includes('style=')) { return `` } return match } ) })() }} />
) } export default MaterialList