2025-11-18 13:32:46 +08:00
|
|
|
|
import React, { useState, useEffect } from 'react';
|
2025-11-29 22:31:42 +08:00
|
|
|
|
import { Modal, Form, Radio, Spin, message, Cascader } from 'antd';
|
|
|
|
|
|
import type { CascaderProps } from 'antd';
|
|
|
|
|
|
import { question, textbook } from '../../../../api/index';
|
2025-11-18 13:32:46 +08:00
|
|
|
|
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';
|
|
|
|
|
|
|
2025-11-29 22:31:42 +08:00
|
|
|
|
// 级联选择器选项类型
|
|
|
|
|
|
interface CascaderOption {
|
|
|
|
|
|
value: string | number;
|
|
|
|
|
|
label: string;
|
|
|
|
|
|
children?: CascaderOption[];
|
|
|
|
|
|
isLeaf?: boolean;
|
|
|
|
|
|
loading?: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 13:32:46 +08:00
|
|
|
|
interface PropInterface {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
qid: number;
|
|
|
|
|
|
open: boolean;
|
|
|
|
|
|
onCancel: () => void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const QuestionsDetailUpdate: React.FC<PropInterface> = ({ 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<ResourceUrlModel>({});
|
2025-11-29 22:31:42 +08:00
|
|
|
|
const [cascaderOptions, setCascaderOptions] = useState<CascaderOption[]>([]); // 级联选择器选项
|
2025-11-18 13:32:46 +08:00
|
|
|
|
const [formParams, setFormParams] = useState({
|
|
|
|
|
|
v: 'v1',
|
|
|
|
|
|
d: {
|
|
|
|
|
|
content: null,
|
|
|
|
|
|
remark: null,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
setInit(true);
|
|
|
|
|
|
if (open && qid > 0) {
|
|
|
|
|
|
getDetail();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [form, open, id, qid]);
|
|
|
|
|
|
|
2025-11-29 22:31:42 +08:00
|
|
|
|
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);
|
2025-11-18 13:32:46 +08:00
|
|
|
|
setResourceUrl(res.data.resource_url);
|
|
|
|
|
|
const data = res.data.question;
|
|
|
|
|
|
setType(String(data.type));
|
|
|
|
|
|
const params = JSON.parse(res.data.question.content);
|
2025-11-29 22:31:42 +08:00
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 13:32:46 +08:00
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
|
level: data.level,
|
|
|
|
|
|
type: String(data.type),
|
|
|
|
|
|
content: params.d.content,
|
|
|
|
|
|
remark: params.d.remark,
|
2025-11-29 22:31:42 +08:00
|
|
|
|
knowledge_cascader: cascaderValue,
|
2025-11-18 13:32:46 +08:00
|
|
|
|
});
|
|
|
|
|
|
setFormParams(params);
|
|
|
|
|
|
setInit(false);
|
2025-11-29 22:31:42 +08:00
|
|
|
|
} 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]);
|
2025-11-18 13:32:46 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2025-11-29 22:31:42 +08:00
|
|
|
|
// 处理知识点:从级联选择器值中提取知识点编码(第二级的值)
|
|
|
|
|
|
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(',');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-18 13:32:46 +08:00
|
|
|
|
setLoading(true);
|
2025-11-29 22:31:42 +08:00
|
|
|
|
question.questionUpdate(qid, id, params, values.level, Number(type), knowledgeCode).then((res: any) => {
|
2025-11-18 13:32:46 +08:00
|
|
|
|
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 ? (
|
|
|
|
|
|
<Modal
|
|
|
|
|
|
title={t('exam.question.detail.update')}
|
|
|
|
|
|
centered
|
|
|
|
|
|
forceRender
|
|
|
|
|
|
open={true}
|
|
|
|
|
|
width={1000}
|
|
|
|
|
|
onOk={() => form.submit()}
|
|
|
|
|
|
onCancel={() => onCancel()}
|
|
|
|
|
|
maskClosable={false}
|
|
|
|
|
|
okButtonProps={{ loading: loading }}
|
|
|
|
|
|
>
|
|
|
|
|
|
{init && (
|
|
|
|
|
|
<div className="float-left text-center mt-30">
|
|
|
|
|
|
<Spin></Spin>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{!init && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<div className="exam-tabs"></div>
|
|
|
|
|
|
<div className="float-left mt-10">
|
|
|
|
|
|
<Form
|
|
|
|
|
|
form={form}
|
|
|
|
|
|
name="question-detail-create"
|
|
|
|
|
|
labelCol={{ span: 2 }}
|
|
|
|
|
|
wrapperCol={{ span: 22 }}
|
|
|
|
|
|
initialValues={{ remember: true }}
|
|
|
|
|
|
onFinish={onFinish}
|
|
|
|
|
|
onFinishFailed={onFinishFailed}
|
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={t('exam.question.detail.edit.level')}
|
|
|
|
|
|
name="level"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: t('exam.question.detail.edit.levelPlaceholder'),
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Radio.Group>
|
|
|
|
|
|
<Radio value={1}>{t('exam.question.level1')}</Radio>
|
|
|
|
|
|
<Radio value={2} style={{ marginLeft: 8 }}>
|
|
|
|
|
|
{t('exam.question.level2')}
|
|
|
|
|
|
</Radio>
|
|
|
|
|
|
<Radio value={3} style={{ marginLeft: 8 }}>
|
|
|
|
|
|
{t('exam.question.level3')}
|
|
|
|
|
|
</Radio>
|
|
|
|
|
|
</Radio.Group>
|
|
|
|
|
|
</Form.Item>
|
2025-11-29 22:31:42 +08:00
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="关联知识点"
|
|
|
|
|
|
name="knowledge_cascader"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Cascader
|
|
|
|
|
|
options={cascaderOptions}
|
|
|
|
|
|
loadData={loadKnowledgeData as CascaderProps<CascaderOption>['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
|
|
|
|
|
|
),
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
2025-11-18 13:32:46 +08:00
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={t('exam.question.detail.edit.name')}
|
|
|
|
|
|
name="content"
|
|
|
|
|
|
labelCol={{ style: { marginTop: 4, marginLeft: 28 } }}
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: t('exam.question.detail.edit.namePlaceholder'),
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<QuestionInput
|
|
|
|
|
|
defautValue={formParams.d.content}
|
|
|
|
|
|
resourceUrl={resourceUrl}
|
|
|
|
|
|
height={40}
|
|
|
|
|
|
placeholder={t('exam.question.questionPlaceholder')}
|
|
|
|
|
|
setContent={(text, image, video, audio) => {
|
|
|
|
|
|
changeQuestionContent(text, image, video, audio);
|
|
|
|
|
|
}}
|
|
|
|
|
|
></QuestionInput>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
{type === '1' && (
|
|
|
|
|
|
<QChoice
|
|
|
|
|
|
question={choiceRender(formParams.d)}
|
|
|
|
|
|
resourceUrl={resourceUrl}
|
|
|
|
|
|
index={null}
|
|
|
|
|
|
onChange={(question: any, list: any) => change(question, list)}
|
|
|
|
|
|
></QChoice>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{type === '2' && (
|
|
|
|
|
|
<QSelect
|
|
|
|
|
|
question={selectRender(formParams.d)}
|
|
|
|
|
|
index={null}
|
|
|
|
|
|
resourceUrl={resourceUrl}
|
|
|
|
|
|
onChange={(question: any, list: any) => change(question, list)}
|
|
|
|
|
|
></QSelect>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{type === '3' && (
|
|
|
|
|
|
<QInput
|
|
|
|
|
|
question={inputRender(formParams.d)}
|
|
|
|
|
|
index={null}
|
|
|
|
|
|
onChange={(question: any, list: any) => change(question, list)}
|
|
|
|
|
|
></QInput>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{type === '4' && (
|
|
|
|
|
|
<QJudge
|
|
|
|
|
|
question={judgeRender(formParams.d)}
|
|
|
|
|
|
index={null}
|
|
|
|
|
|
onChange={(question: any, list: any) => change(question, list)}
|
|
|
|
|
|
></QJudge>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{type === '5' && (
|
|
|
|
|
|
<QQa
|
|
|
|
|
|
question={qaRender(formParams.d)}
|
|
|
|
|
|
index={null}
|
|
|
|
|
|
onChange={(question: any, list: any) => change(question, list)}
|
|
|
|
|
|
></QQa>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{type === '6' && (
|
|
|
|
|
|
<QCap
|
|
|
|
|
|
question={capRender(formParams.d)}
|
|
|
|
|
|
resourceUrl={resourceUrl}
|
|
|
|
|
|
index={null}
|
|
|
|
|
|
onChange={(question: any, list: any) => change(question, list)}
|
|
|
|
|
|
></QCap>
|
|
|
|
|
|
)}
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={t('exam.question.detail.edit.remark')}
|
|
|
|
|
|
name="remark"
|
|
|
|
|
|
labelCol={{ style: { marginTop: 4, marginLeft: 39 } }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<QuestionInput
|
|
|
|
|
|
defautValue={formParams.d.remark}
|
|
|
|
|
|
resourceUrl={resourceUrl}
|
|
|
|
|
|
height={120}
|
|
|
|
|
|
placeholder={t('exam.question.questionPlaceholder4')}
|
|
|
|
|
|
setContent={(text, image, video, audio) => {
|
|
|
|
|
|
changeQuestionRemark(text, image, video, audio);
|
|
|
|
|
|
}}
|
|
|
|
|
|
></QuestionInput>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Modal>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|