import React, { useState, useEffect } from 'react'; import { Modal, Form, Radio, Spin, message, Cascader } from 'antd'; import type { CascaderProps } from 'antd'; import { question, textbook } from '../../../../api/index'; import { QuestionInput } from '../../../../compenents'; import { QChoice } from './choice'; import { QSelect } from './select'; import { QInput } from './input'; import { QJudge } from './judge'; import { QQa } from './qa'; import { QCap } from './cap'; import { useTranslation } from 'react-i18next'; // 级联选择器选项类型 interface CascaderOption { value: string | number; label: string; children?: CascaderOption[]; isLeaf?: boolean; loading?: boolean; } interface PropInterface { id: number; qid: number; open: boolean; onCancel: () => void; } export const QuestionsDetailUpdate: React.FC = ({ id, qid, open, onCancel }) => { const { t } = useTranslation(); const [form] = Form.useForm(); const [init, setInit] = useState(true); const [loading, setLoading] = useState(false); const [refresh, setRefresh] = useState(false); const [type, setType] = useState('1'); const [resourceUrl, setResourceUrl] = useState({}); const [cascaderOptions, setCascaderOptions] = useState([]); // 级联选择器选项 const [formParams, setFormParams] = useState({ v: 'v1', d: { content: null, remark: null, }, }); useEffect(() => { setInit(true); if (open && qid > 0) { getDetail(); } }, [form, open, id, qid]); const getDetail = async () => { try { // 1. 加载教材列表作为级联选择器第一级 const textbookRes = await textbook.getTextbookSelectListApi(); let options: CascaderOption[] = []; if (textbookRes.data && Array.isArray(textbookRes.data)) { options = textbookRes.data.map((item: any) => ({ value: item.id, label: item.title, isLeaf: false, })); setCascaderOptions(options); } // 2. 加载试题详情 const res: any = await question.questionDetail(qid); setResourceUrl(res.data.resource_url); const data = res.data.question; setType(String(data.type)); const params = JSON.parse(res.data.question.content); // 3. 处理知识点回显 let cascaderValue: (string | number)[][] = []; if (data.knowledge_code) { try { // 获取知识点详情(包含bookId) const knowledgeRes: any = await textbook.getKnowledgeByCodesApi(data.knowledge_code); if (knowledgeRes.data && Array.isArray(knowledgeRes.data) && knowledgeRes.data.length > 0) { // 获取所有需要预加载的教材ID(去重) const bookIds = [...new Set(knowledgeRes.data.map((k: any) => k.bookId))]; // 预加载每个教材的知识点列表到级联选项中 for (const bookId of bookIds) { const knowledgeListRes: any = await textbook.getKnowledgeListApi(bookId as number); const targetOption = options.find(opt => opt.value === bookId); if (targetOption && knowledgeListRes.data && Array.isArray(knowledgeListRes.data)) { targetOption.children = knowledgeListRes.data.map((item: any) => ({ value: item.knowledgeCode || item.knowledge_code, label: item.name, isLeaf: true, })); } } setCascaderOptions([...options]); // 构建级联选择器的值 [[bookId, knowledgeCode], ...] cascaderValue = knowledgeRes.data.map((k: any) => [k.bookId, k.knowledgeCode || k.knowledge_code]); } } catch (err) { console.error('加载知识点详情失败:', err); } } form.setFieldsValue({ level: data.level, type: String(data.type), content: params.d.content, remark: params.d.remark, knowledge_cascader: cascaderValue, }); setFormParams(params); setInit(false); } catch (err) { console.error('加载数据失败:', err); setInit(false); } }; // 级联选择器动态加载知识点 const loadKnowledgeData = (selectedOptions: CascaderOption[]) => { const targetOption = selectedOptions[selectedOptions.length - 1]; targetOption.loading = true; textbook.getKnowledgeListApi(targetOption.value as number).then((res: any) => { targetOption.loading = false; if (res.data && Array.isArray(res.data)) { targetOption.children = res.data.map((item: any) => ({ value: item.knowledgeCode || item.knowledge_code, label: item.name, isLeaf: true, })); } else { targetOption.children = []; } setCascaderOptions([...cascaderOptions]); }).catch((err) => { console.error('加载知识点失败:', err); targetOption.loading = false; targetOption.children = []; setCascaderOptions([...cascaderOptions]); }); }; const onFinish = (values: any) => { if (loading) { return; } const obj: any = formParams; if (!obj.d.content) { message.error(t('exam.question.detail.edit.text1')); return; } if (!obj.d.content.text) { message.error(t('exam.question.detail.edit.text2')); return; } if ((type === '2' || type === '1') && !obj.d.answer) { message.error(t('exam.question.detail.edit.text3')); return; } if (type === '2' || type === '1') { let isOk = true; for (const key in obj.d.options) { // 判断属性值是否为null if (obj.d.options[key] === null) { message.error( t('exam.question.detail.edit.text4') + key + t('exam.question.detail.edit.text5') ); isOk = false; break; } if ( obj.d.options[key] && !obj.d.options[key].text && obj.d.options[key].image.length === 0 && obj.d.options[key].audio.length === 0 && obj.d.options[key].video.length === 0 ) { message.error( t('exam.question.detail.edit.text4') + key + t('exam.question.detail.edit.text5') ); isOk = false; break; } } if (!isOk) { return; } } if (type === '2' && obj.d.answer && obj.d.answer.length === 0) { message.error(t('exam.question.detail.edit.text6')); return; } if (type === '3' && !obj.d.answer) { message.error(t('exam.question.detail.edit.text7')); return; } if (type === '3' && obj.d.answer && obj.d.answer.items && obj.d.answer.items.length === 0) { message.error(t('exam.question.detail.edit.text7')); return; } if (type === '3' && obj.d.answer && obj.d.answer.items && obj.d.answer.items.length > 0) { let isOk = true; obj.d.answer.items.map((item: any) => { if (item.items.length === 0) { isOk = false; } else { item.items.map((it: any) => { if (it === '') { isOk = false; } }); } }); if (!isOk) { message.error(t('exam.question.detail.edit.text8')); return; } } if (type === '4' && obj.d.answer === undefined) { message.error(t('exam.question.detail.edit.text9')); return; } if (type === '4' && obj.d.answer && obj.d.answer.length === 0) { message.error(t('exam.question.detail.edit.text3')); return; } if (type === '5' && !obj.d.answer) { message.error(t('exam.question.detail.edit.text10')); return; } if (type === '5' && obj.d.answer && obj.d.answer.length === 0) { message.error(t('exam.question.detail.edit.text10')); return; } if (type === '5' && obj.d.answer && obj.d.answer.length > 0) { let isOk = true; obj.d.answer.map((item: any) => { if (item.keywords.length === 0) { isOk = false; } else { item.keywords.map((it: any) => { if (it === '') { isOk = false; } }); } }); if (!isOk) { message.error(t('exam.question.detail.edit.text11')); return; } } if (type === '6' && !obj.d.children) { message.error(t('exam.question.detail.edit.text12')); return; } if (type === '6' && obj.d.children === '[]') { message.error(t('exam.question.detail.edit.text12')); return; } if (type === '6' && obj.d.children) { const result = JSON.parse(obj.d.children); let isOk = true; result.map((item: any) => { if (!item.raw.d.content) { isOk = false; } if (item.raw.d.content && !item.raw.d.content.text) { isOk = false; } if ((item.type === 1 || item.type === 2 || item.type === 3) && !item.raw.d.answer) { isOk = false; } if (item.type === 2 || item.type === 1) { for (const key in item.raw.d.options) { // 判断属性值是否为null if (item.raw.d.options[key] === null) { isOk = false; break; } if ( item.raw.d.options[key] && !item.raw.d.options[key].text && item.raw.d.options[key].image.length === 0 && item.raw.d.options[key].audio.length === 0 && item.raw.d.options[key].video.length === 0 ) { isOk = false; break; } } } if (item.type === 2 && item.raw.d.answer && item.raw.d.answer.length === 0) { isOk = false; } if ( item.type === 3 && item.raw.d.answer && item.raw.d.answer.items && item.raw.d.answer.items.length === 0 ) { isOk = false; } if ( item.type === 3 && item.raw.d.answer && item.raw.d.answer.items && item.raw.d.answer.items.length > 0 ) { item.raw.d.answer.items.map((item: any) => { if (item.items.length === 0) { isOk = false; } else { item.items.map((it: any) => { if (it === '') { isOk = false; } }); } }); } if (item.type === 4 && item.raw.d.answer === undefined) { isOk = false; } if (item.type === 4 && item.raw.d.answer && item.raw.d.answer.length === 0) { isOk = false; } if (item.type === 5 && !item.raw.d.answer) { isOk = false; } if (item.type === 5 && item.raw.d.answer && item.raw.d.answer.length === 0) { isOk = false; } if (item.type === 5 && item.raw.d.answer && item.raw.d.answer.length > 0) { item.raw.d.answer.map((item: any) => { if (item.keywords.length === 0) { isOk = false; } else { item.keywords.map((it: any) => { if (it === '') { isOk = false; } }); } }); } }); if (!isOk) { message.error(t('exam.question.detail.edit.text13')); return; } } const params = JSON.stringify(formParams); // 处理知识点:从级联选择器值中提取知识点编码(第二级的值) let knowledgeCode: string | undefined = undefined; if (values.knowledge_cascader && values.knowledge_cascader.length > 0) { const codes = values.knowledge_cascader .filter((item: any[]) => item && item.length === 2) .map((item: any[]) => item[1]); if (codes.length > 0) { knowledgeCode = codes.join(','); } } setLoading(true); question.questionUpdate(qid, id, params, values.level, Number(type), knowledgeCode).then((res: any) => { setLoading(false); message.success(t('commen.saveSuccess')); onCancel(); }); }; const onFinishFailed = (errorInfo: any) => { console.log('Failed:', errorInfo); }; const changeQuestionContent = ( text: string, image: number[], video: number[], audio: number[] ) => { const params = { text: text, image: image, video: video, audio: audio, }; const obj: any = { ...formParams }; obj.d.content = params; setFormParams(obj); form.setFieldsValue({ content: params, }); }; const changeQuestionRemark = ( text: string, image: number[], video: number[], audio: number[] ) => { const params = { text: text, image: image, video: video, audio: audio, }; const obj: any = { ...formParams }; obj.d.remark = params; setFormParams(obj); }; const change = (question: any, list: any) => { const obj = { ...formParams }; Object.assign(obj.d, question); setFormParams(obj); }; const choiceRender = (data: any) => { if (data.options && data.answer) { return { options: data.options, answer: data.answer, }; } else { return null; } }; const selectRender = (data: any) => { if (data.options && data.answer) { return { options: data.options, answer: data.answer, }; } else { return null; } }; const inputRender = (data: any) => { if (data.answer) { return { answer: data.answer, }; } else { return null; } }; const judgeRender = (data: any) => { if (data) { return { answer: data.answer, }; } else { return null; } }; const qaRender = (data: any) => { if (data.answer) { return { answer: data.answer, }; } else { return null; } }; const capRender = (data: any) => { if (data.children) { return { children: data.children, }; } else { return null; } }; return ( <> {open ? ( form.submit()} onCancel={() => onCancel()} maskClosable={false} okButtonProps={{ loading: loading }} > {init && (
)} {!init && ( <>
{t('exam.question.level1')} {t('exam.question.level2')} {t('exam.question.level3')} ['loadData']} multiple maxTagCount="responsive" placeholder="请选择教材和知识点(可多选)" style={{ width: '100%' }} showCheckedStrategy={Cascader.SHOW_CHILD} showSearch={{ filter: (inputValue: string, path: CascaderOption[]) => path.some( (option) => (option.label as string).toLowerCase().indexOf(inputValue.toLowerCase()) > -1 ), }} /> { changeQuestionContent(text, image, video, audio); }} > {type === '1' && ( change(question, list)} > )} {type === '2' && ( change(question, list)} > )} {type === '3' && ( change(question, list)} > )} {type === '4' && ( change(question, list)} > )} {type === '5' && ( change(question, list)} > )} {type === '6' && ( change(question, list)} > )} { changeQuestionRemark(text, image, video, audio); }} >
)}
) : null} ); };