import React, { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { Table, Button, Space, Modal, Form, Input, Select, message, Popconfirm, Tag, Card, Radio, Divider, } from 'antd' import { PlusOutlined, EditOutlined, DeleteOutlined, ArrowLeftOutlined, MinusCircleOutlined, } from '@ant-design/icons' import * as questionApi from '../api/question' import type { Question } from '../types/question' import styles from './QuestionManagement.module.less' const { Option } = Select const { TextArea } = Input // 题型配置 const questionTypes = [ { key: 'multiple-choice', label: '单选题' }, { key: 'multiple-selection', label: '多选题' }, { key: 'true-false', label: '判断题' }, { key: 'fill-in-blank', label: '填空题' }, { key: 'short-answer', label: '简答题' }, ] const QuestionManagement: React.FC = () => { const navigate = useNavigate() const [questions, setQuestions] = useState([]) const [loading, setLoading] = useState(false) const [modalVisible, setModalVisible] = useState(false) const [editingQuestion, setEditingQuestion] = useState(null) const [form] = Form.useForm() // 筛选和搜索状态 const [selectedType, setSelectedType] = useState('') const [searchText, setSearchText] = useState('') // 加载题目列表 const loadQuestions = async () => { setLoading(true) try { const params: any = {} if (selectedType) { params.type = selectedType } if (searchText) { params.search = searchText } const res = await questionApi.getQuestions(params) if (res.success && res.data) { setQuestions(res.data) } } catch (error) { message.error('加载题目失败') } finally { setLoading(false) } } useEffect(() => { loadQuestions() }, [selectedType, searchText]) // 打开新建/编辑弹窗 const handleOpenModal = (question?: Question) => { if (question) { setEditingQuestion(question) // 直接使用后端返回的答案数据 let answerValue: any = question.answer // 解析选项(单选题和多选题) let optionsValue: Array<{ key: string; value: string }> = [] if (question.options && question.options.length > 0 && (question.type === 'multiple-choice' || question.type === 'multiple-selection')) { optionsValue = question.options.map(opt => ({ key: opt.key, value: opt.value, })) } // 设置表单值 form.setFieldsValue({ type: question.type, content: question.content, answer: answerValue, options: optionsValue, }) } else { setEditingQuestion(null) form.resetFields() // 新建时设置默认值 form.setFieldsValue({ type: 'multiple-choice', options: [{ key: 'A', value: '' }, { key: 'B', value: '' }], }) } setModalVisible(true) } // 关闭弹窗 const handleCloseModal = () => { setModalVisible(false) setEditingQuestion(null) form.resetFields() } // 保存题目 const handleSave = async () => { try { const values = await form.validateFields() // 解析答案 let answer: any if (values.type === 'true-false') { answer = values.answer } else if (values.type === 'multiple-choice') { answer = values.answer } else if (values.type === 'multiple-selection') { // 多选题答案是数组 answer = values.answer } else if (values.type === 'fill-in-blank') { // 填空题答案是数组 answer = values.answer } else if (values.type === 'short-answer') { answer = values.answer } else { answer = values.answer } // 解析选项(仅选择题和多选题需要) let options: Record | undefined if (values.options && (values.type === 'multiple-choice' || values.type === 'multiple-selection')) { // 将数组格式转换为对象格式 { "A": "选项A", "B": "选项B" } options = values.options.reduce((acc: Record, opt: any) => { if (opt && opt.key && opt.value) { acc[opt.key] = opt.value } return acc }, {}) } // 构建请求数据 const data = { type: values.type, type_name: '', // 不再使用分类字段 question: values.content, answer: answer, options: options, } if (editingQuestion) { // 更新 await questionApi.updateQuestion(editingQuestion.id, data) message.success('更新成功') } else { // 创建 await questionApi.createQuestion(data) message.success('创建成功') } handleCloseModal() loadQuestions() } catch (error) { console.error('保存失败:', error) message.error('保存失败') } } // 删除题目 const handleDelete = async (id: number) => { try { await questionApi.deleteQuestion(id) message.success('删除成功') loadQuestions() } catch (error) { message.error('删除失败') } } // 表格列定义 const columns = [ { title: '题目编号', dataIndex: 'question_id', key: 'question_id', width: 100, }, { title: '题型', dataIndex: 'type', key: 'type', width: 120, render: (type: string) => { const typeConfig = questionTypes.find(t => t.key === type) const colorMap: Record = { 'multiple-choice': 'blue', 'multiple-selection': 'green', 'true-false': 'orange', 'fill-in-blank': 'purple', 'short-answer': 'magenta', } return {typeConfig?.label || type} }, }, { title: '题目内容', dataIndex: 'content', key: 'content', ellipsis: true, }, { title: '操作', key: 'action', width: 150, render: (_: any, record: Question) => ( handleDelete(record.id)} okText="确定" cancelText="取消" > ), }, ] // 根据题型动态渲染表单项 const renderFormByType = () => { const type = form.getFieldValue('type') switch (type) { case 'true-false': return ( 正确 错误 ) case 'multiple-choice': return ( <> { if (!options || options.length < 2) { return Promise.reject(new Error('至少需要2个选项')) } }, }, ]} > {(fields, { add, remove }, { errors }) => ( <> {fields.map((field) => ( {fields.length > 2 && ( remove(field.name)} /> )} ))} )} ) case 'multiple-selection': return ( <> { if (!options || options.length < 2) { return Promise.reject(new Error('至少需要2个选项')) } }, }, ]} > {(fields, { add, remove }, { errors }) => ( <> {fields.map((field) => ( {fields.length > 2 && ( remove(field.name)} /> )} ))} )} {fields.length > 1 && ( remove(field.name)} /> )} ))} )} ) case 'short-answer': return (