You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

603 lines
32 KiB

import React, { useEffect, useRef, useState } from 'react';
import { history, useParams, useRequest } from 'umi';
import type { ProFormInstance } from '@ant-design/pro-form';
import { ModalForm } from '@ant-design/pro-form';
import { ProFormRadio } from '@ant-design/pro-form';
import ProForm, {
StepsForm,
ProFormText,
ProFormDatePicker,
ProFormSelect,
ProFormTextArea,
ProFormCheckbox,
ProFormDateRangePicker,
} from '@ant-design/pro-form';
import ProCard from '@ant-design/pro-card';
import { Button, Checkbox, Col, Divider, Dropdown, Form, Input, List, Menu, message, Modal, Radio, Row, Space, Table, Typography, Upload } from 'antd';
import { PageContainer } from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import styles from './index.less'
import { saveRules, querySubjectList, queryRulesView, queryTempQuestionList, saveQuestionTypeScore, queryRulesPaper, updateScore } from '../../service';
import { queryCourseView } from '@/pages/course/option/service';
import { queryQuestionList, queryQuestionById, queryQuestionType } from '@/pages/questionbank/service';
import { PlusOutlined, DownOutlined, DeleteOutlined, DownloadOutlined, UploadOutlined, EyeInvisibleOutlined, EyeOutlined, EditOutlined, ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import ProList from '@ant-design/pro-list';
import { autoPaper, manualPaper, updatePaper } from '../service';
import ProTable, { EditableProTable } from '@ant-design/pro-table';
import QuestionSelector from '../../components/QuestionSelector';
import ScoreSetter from '../../components/ScoreSetter';
import AutoSelector from '../components/AutoSelector';
import { ConsoleMessage } from 'puppeteer-core';
import { getSubjectInfo } from '@/pages/course/subject/service';
import { forEach } from 'lodash';
/**
* 保存选题
*
* @param values
*/
const handleAppend = async (rules_id: number, rows: any[]) => {
const hide = message.loading('正在添加');
try {
const questions: { question_id: any; }[] = [];
rows?.forEach((item) => {
questions.push({ question_id: item?.id })
})
const _data = await manualPaper({
question_count: questions?.length || 0,
questions: JSON.stringify(questions),
rules_id: Number(rules_id)
});
hide();
message.success('添加成功');
return _data;
} catch (error) {
hide();
message.error('添加失败请重试!');
return false;
}
};
/**
* 保存选题试卷
*
* @param values
*/
const handleUpdatePaper = async (rules_id: number, paper_uuid: number, paper_id: number) => {
const hide = message.loading('正在保存');
try {
const _data = {
rules_id: Number(rules_id),
paper_uuid: paper_uuid,
paper_id: paper_id
}
if (paper_id === 0) {
delete _data.paper_id;
}
await updatePaper(_data);
hide();
message.success('保存成功');
return true;
} catch (error) {
hide();
message.error('保存失败请重试!');
return false;
}
};
const labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
// 模拟考试规则维护
export default () => {
const [selectorModalVisible, handleSelectorModalVisible] = useState<boolean>(false);
const [scoreModalVisible, handleScoreModalVisible] = useState<boolean>(false);
const [autoModalVisible, handleAutoModalVisible] = useState<boolean>(false);
const [subjectId, setSubjectId] = useState<number>(0); // 关联主题id
const [subjectName, setSubjectName] = useState(''); // 关联主题name
const [questionTypeValues, setQuestionTypeValues] = useState([]); // 题型数据[{count:0, score:0, score_harf:0}]
const [uuidPaper, setUuidPaper] = useState<number>(0);
const [createType, setCreateType] = useState<number>(1); // 组卷类型
const [rulesName, setRulesName] = useState<string>(''); // 组卷类型
const [sumScore, setSumScore] = useState<number>(0); // 总分
const [passScore, setPassScore] = useState<number>(0); // 通过分数线
const [typeQuestionCount, setTypeQuestionCount] = useState([0, 0, 0]); // 临时卷 各题型数量
const [rulesId, setRulesId] = useState(0); // 规则id, 保存新建的rules_id
const formRef = useRef<ProFormInstance>();
const selectorRef = useRef();
const setterRef = useRef();
const autoRef = useRef();
const [currentStep, setCurrentStep] = useState(0);
const params = useParams();
const [questionType, setQuestionType] = useState([]); // 题型
const [scoreValues, setScoreValues] = useState([]); // 分值 [{"question_type": "0","score": "3","score_harf": "0"},]
const [paperInfo, setPaperInfo] = useState({})
/** 获取题型 */
const { data: questionTypeData } = useRequest(() => {
return queryQuestionType();
}, {
formatResult: (result) => {
return result.list;
}
});
useEffect(() => {
setQuestionType(questionTypeData || []);
return () => {
/** 退出当前页面清空Map */
//parsingMap.clear();
}
}, [questionTypeData]);
/** 组卷,查询试题临时表(当前选题列表) */
const { data: questions, run } = useRequest(async (params) => {
console.log('questions', questions)
const _data = await queryTempQuestionList(params);
return _data;
}, {
manual: true,
formatResult: (result) => {
return result?.table_List;
}
});
/** 从临时表中计算各题型数量 */
useEffect(() => {
const _data = [0, 0, 0]; // 当前仅支持 单选 / 多选 / 判断 的顺序
console.log('questions-info', questions)
questions?.forEach((item) => {
_data[Number(item?.question_type)] += 1
})
setTypeQuestionCount(_data);
return () => {
/** 退出当前页面清空Map */
//parsingMap.clear();
}
}, [questions]);
//
const { data: paperData, run: runPaper } = useRequest(async (params) => {
console.log('paperData', paperData)
/**
* rules_id: params?.id,
page_number: value.current,
page_size: value.pageSize
*/
return queryRulesPaper(params);
}, {
manual: true,
formatResult: (result) => {
return result?.question_list;
}
});
useEffect(() => {
console.log('paperData2', paperData)
if (paperData?.length > 0) {
console.log('paperData[0]', paperData[0])
setPaperInfo(paperData[0])
}
console.log('PaperInfo', paperInfo)
}, [paperData]);
console.log(params, 'params');
let ruleData = {}
//
if (params?.id) {
//console.log(JSON.stringify(params), "878");
const { data } = useRequest(async () => {
return queryRulesView(params);
}, {
formatResult: (result) => {
return result?.bean;
}
});
ruleData = data
}
console.log(ruleData, 'ruleData');
return (
<PageContainer content={''} extraContent={''}>
<ProCard className={styles.examinationrules}>
<StepsForm<{
name: string;
}>
formRef={formRef}
onFinish={async (e) => {
message.success('提交成功');
}}
formProps={{
layout: "horizontal",
labelCol: { span: 8 },
wrapperCol: { span: 12 },
validateMessages: {
required: '此项为必填项',
},
}}
>
<StepsForm.StepForm<{
name: string;
}>
name="base"
title="模拟考试基本信息"
stepProps={{
description: false,
}}
onFinish={async (fileds) => {
if (params?.id) {
fileds = { ...fileds, id: (params.id || rulesId) }
}
const { data } = await saveRules({
...fileds,
b_use: 0,
rules_type: 0,
});
setRulesId(data?.rules_id) // 保存规则id
//run({paper_uuid:1}); // 获取当前选题列表
// console.log('模拟考试基本信息', fileds)
setSubjectId(fileds?.subject_id) // 设置当前关联主题
setRulesName(fileds?.rules_name) // 设置模拟考试规则名称
console.log('fileds', fileds)
console.log('formRef', formRef.current?.getFieldValue(''))
// await waitTime(2000);
setCurrentStep(1) // 设置步骤号
return true;
}}
>
<Row gutter={24}>
<Col lg={24} md={24} sm={24}>
{ruleData && (
<>
<ProFormText
name="rules_name"
label="考试名称"
width="md"
initialValue={ruleData?.rules_name}
// tooltip="最长为 6 位汉字,需要与考生身份证一致"
placeholder="请输入名称"
rules={[
{ required: true, message: '请输入考试名称' },
{
pattern: /^[^\s]*$/,
message: '禁止输入空格'
}
]}
// value="锦书"
// disabled
/>
<ProFormSelect
width="md"
initialValue={ruleData?.subject_id}
request={async () => {
return querySubjectList().then(({ data }) => {
console.log(data, 'querySubjectList')
return data.list.map((item) => {
if (item?.subject_id === ruleData?.subject_id) {
setSubjectName(item?.subject_name) // 设置关联主题名称
console.log('label::', item?.subject_name)
}
return {
label: item?.subject_name,
value: item?.subject_id,
};
});
});
}}
onChange={(value) => {
console.log('on change', value)
}}
rules={[{ required: true, message: '请选择主题' }]}
name="subject_id"
label="关联主题"
/>
<ProFormText addonAfter={`分钟`} name="examination_time" label="考试时长"
width="md"
initialValue={ruleData?.examination_time}
rules={[
{
required: true,
message: '请输入考试时长'
},
{
pattern: /^[^\s]*$/,
message: '禁止输入空格'
}]}
tooltip="单位(分钟)" />
</>
)}
</Col>
</Row>
</StepsForm.StepForm>
<StepsForm.StepForm<{
checkbox: string;
}>
name="object"
title="组卷"
stepProps={{
description: false,
}}
onFinish={async () => {
console.log(formRef.current?.getFieldsValue());
setCurrentStep(2) // 设置步骤号
runPaper({ rules_id: params?.id })
return true;
}}
>
<div style={{ margin: '0' }}>
<Typography style={{ padding: 24, fontSize: 24, textAlign: 'center' }}>{rulesName}</Typography>
{/** 一旦录入另一项将禁用,清空组卷后可选另一项 */}
<Radio.Group size='large' value={createType} onChange={(e) => {
setCreateType(Number(e?.target?.value))
console.log('value', e?.target?.value)
//handleAutoModalVisible(true); // 显示系统组卷窗口
}} style={{ marginBottom: 16, }}>
<Radio.Button value={1} style={{ width: 200, textAlign: 'center' }}></Radio.Button>
<Radio.Button value={2} style={{ width: 200, textAlign: 'center' }}></Radio.Button>
</Radio.Group>
<Divider style={{ margin: '6px 0', opacity: 0.5 }} />
<Row>
<Col span={18} style={{ background: '#ffffff', padding: 0 }}>
<ProCard
title=""
extra={false}
split='vertical'
bordered
headerBordered
>
<Space direction="vertical" style={{ width: '100%', padding: '24px 48px' }}>
{questions && questions.map((item, idx) => (
item &&
<div style={{ border: 'none' }}>
<Typography style={{ marginBottom: 16, fontSize: 14, padding: '15px 15px 0 15px' }}>
{idx + 1}. {item?.question_stem}
</Typography>
{(item?.question_type === 0) && // 单选题
<div style={{ padding: '0 15px 15px 15px' }}>
{item?.answers && item?.answers.map((anster, k) => (
<div value={k} checked style={{ width: '100%', padding: 5, fontSize: 14 }}>
{anster?.is_true === '0' && <span style={{ color: '#1890ff', border: '1px solid #1890ff', display: 'inline-block', width: 16, height: 16, textAlign: 'center', borderRadius: '50%', fontSize: 12, lineHeight: '12px', marginRight: 10 }}>{labels[k]} </span>}
{anster?.is_true === '1' && <span style={{ color: '#ffffff', border: '1px solid #1890ff', display: 'inline-block', width: 16, height: 16, textAlign: 'center', borderRadius: '50%', fontSize: 12, lineHeight: '12px', marginRight: 10, backgroundColor: '#1890ff' }}>{labels[k]} </span>}
<span style={{ display: 'inline-block' }}>{anster?.answer}</span>
</div>
))}
</div>
}
{(item?.question_type === 1) && // 多选题
<div style={{ padding: '0 15px 15px 15px' }}>
{item?.answers && item?.answers.map((anster, k) => (
<div value={k} checked style={{ width: '100%', padding: 5, fontSize: 14 }}>
{anster?.is_true === '0' && <span style={{ color: '#1890ff', border: '1px solid #1890ff', display: 'inline-block', width: 16, height: 16, textAlign: 'center', borderRadius: '50%', fontSize: 12, lineHeight: '12px', marginRight: 10 }}>{labels[k]} </span>}
{anster?.is_true === '1' && <span style={{ color: '#ffffff', border: '1px solid #1890ff', display: 'inline-block', width: 16, height: 16, textAlign: 'center', borderRadius: '50%', fontSize: 12, lineHeight: '12px', marginRight: 10, backgroundColor: '#1890ff' }}>{labels[k]} </span>}
<span style={{ display: 'inline-block' }}>{anster?.answer}</span>
</div>
))}
</div>
}
{(item?.question_type === 2) && // 判断选题
<div style={{ padding: '0 15px 15px 15px' }}>
{item?.answers && item?.answers.map((anster, k) => (
<div value={k} checked style={{ width: '100%', padding: 5, fontSize: 14 }}>
{anster?.is_true === '0' && <span style={{ color: '#1890ff', border: '1px solid #1890ff', display: 'inline-block', width: 16, height: 16, textAlign: 'center', borderRadius: '50%', fontSize: 12, lineHeight: '12px', marginRight: 10 }}>{labels[k]} </span>}
{anster?.is_true === '1' && <span style={{ color: '#ffffff', border: '1px solid #1890ff', display: 'inline-block', width: 16, height: 16, textAlign: 'center', borderRadius: '50%', fontSize: 12, lineHeight: '12px', marginRight: 10, backgroundColor: '#1890ff' }}>{labels[k]} </span>}
<span style={{ display: 'inline-block' }}>{anster?.answer}</span>
</div>
))}
</div>
}
<div style={{ height: 'auto', backgroundColor: '#f0f0f0', textAlign: 'right', padding: 5, opacity: 0.5 }}>
<Button><ArrowUpOutlined /></Button> <Button><ArrowDownOutlined /></Button> <Button><DeleteOutlined /></Button>
</div>
</div>
))}
</Space>
</ProCard>
</Col>
<Col span={6} style={{ paddingLeft: 24 }}>
<div style={{ background: '#ffffff', padding: 24 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<strong></strong>
<Typography> {'-'} {'-'} </Typography>
<Divider style={{ margin: '6px 0', opacity: 0.5 }} />
<Space direction="vertical">
{questionType.map((item) => {
return <Typography>{item?.name} {typeQuestionCount[Number(item.code)]} {'-'} </Typography>
}
)}
</Space>
<Divider style={{ margin: '6px 0', opacity: 0.5 }} />
<Button size="large" block onClick={() => {
console.log('createType', createType)
if (createType === 1) {
console.log('11:', createType)
handleSelectorModalVisible(true)
} else {
console.log('22:', createType)
handleAutoModalVisible(true); // 显示系统组卷窗口(true)
}
}}></Button>
<Button size="large" block onClick={() => {
/**
* 设置分值前需要题型数据
* [{count: 0, score: 0, score_harf: 0},{count: 0, score: 0, score_harf: 0},{count: 0, score: 0, score_harf: 0}]
*/
//
const _data = []
typeQuestionCount?.forEach((item) => {
_data.push({ count: item, score: 0, score_harf: 0 })
})
setQuestionTypeValues(_data)
console.log('typeQuestionCount', typeQuestionCount);
handleScoreModalVisible(true)
}}></Button>
<Button size="large" type="primary" block onClick={async () => {
console.log('uuidPaper::', uuidPaper)
console.log('rules_id::', params?.id)
const paper_id = paper_id ? paper_id : 0;
await handleUpdatePaper(params?.id || rulesId, uuidPaper, paper_id)
}}></Button>
</Space>
</div>
</Col>
</Row>
</div>
</StepsForm.StepForm>
<StepsForm.StepForm
name="time"
title="完成"
stepProps={{
description: false,
}}
onFinish={async () => {
console.log(formRef.current?.getFieldsValue());
// 跳转到指定路由
history.push('/examinationrules/normal');
return true;
}}
>
<Row gutter={24}>
<Col lg={12} md={12} sm={12} offset={8}>
{currentStep === 2 && <ProDescriptions
layout='horizontal'
column={1}
//actionRef={actionRef}
title={false}
request={async () => {
const result = await queryRulesView(params)
console.log('queryRulesView', result)
const subjectInfo = await getSubjectInfo({ subject_id: result.bean.subject_id })
console.log('subjectInfo', subjectInfo)
return { data: { ...result.bean, subject_name: subjectInfo.data.subject_name } };
}}
extra={false}
>
<ProDescriptions.Item dataIndex="id" hideInDescriptions />
<ProDescriptions.Item dataIndex="rules_name" label="考试名称" valueType="text" />
<ProDescriptions.Item dataIndex="subject_name" label="关联主题" valueType="text" />
<ProDescriptions.Item dataIndex="examination_time" label="考试时长" valueType="text" renderText={(text) => (`${text} 分钟`)} />
<ProDescriptions.Item dataIndex="grade" label="试卷信息" valueType="text" render={() => {
{/** 需要从试卷 或 临时试卷 中读取 需要处理 */ }
return <Space direction="vertical">
<span> 0 , {paperInfo?.sum_score} </span>
<span>: 0 : 0 : 0 </span>
<span>线 {paperInfo?.pass_score} </span>
</Space>
}} />
</ProDescriptions>
}
</Col>
</Row>
</StepsForm.StepForm>
</StepsForm>
</ProCard>
<ModalForm
title={`手动组卷`}
width="60%"
visible={selectorModalVisible}
onVisibleChange={handleSelectorModalVisible}
onFinish={async (values) => {
console.log('v::::', values.name);
const rows = selectorRef?.current?.getSelectedRows()
console.log('rows::::', rows);
const { code, data: paper, msg } = await handleAppend(Number(params?.id || rulesId), rows)
console.log('paper', paper)
setUuidPaper(paper?.paper_uuid)
console.log('paper_uuid', paper?.paper_uuid)
run({
paper_uuid: paper?.paper_uuid,
page_size: 1000,
page_number: 1
}); // 获取当前选题列表
// message.success('提交成功');
handleSelectorModalVisible(false)
return true;
}}
>
{selectorModalVisible && <QuestionSelector ref={selectorRef} />}
</ModalForm>
<ModalForm
title={`系统组卷`}
//
width="60%"
visible={autoModalVisible}
onVisibleChange={handleAutoModalVisible}
onFinish={async () => {
// 需要处理
//console.log('111')
//const values = autoRef?.current?.getData()
//console.log('2222')
//const {code, data: paper, msg} = await autoPaper({rules_id: Number(params?.id), auto_param: JSON.stringify(values)})
//console.log('paper', paper)
//setUuidPaper(paper?.paper_uuid)
// message.success('提交成功');
handleAutoModalVisible(false)
return true;
}}
>
{autoModalVisible && <AutoSelector ref={autoRef} subjectId={subjectId} questionType={questionType} />}
</ModalForm>
<ModalForm
title={`批量设置分值`}
//
width="60%"
visible={scoreModalVisible}
onVisibleChange={handleScoreModalVisible}
onFinish={async () => {
console.log('typeQuestionCount', typeQuestionCount)
const values = setterRef.current?.getData() // 获取题型分值数据
const passSocre = setterRef.current?.getValue() // 获取通过分数线
console.log('批量设置分值v::::2', values);
// 题型分数
const { code, data: paper, msg } = await saveQuestionTypeScore({ rules_id: Number(params?.id || rulesId), type_score: JSON.stringify(values) })
// 总分及通过分
let _sumScore = 0;
values?.forEach((item) => {
console.log('item--', item)
_sumScore += item?.score
})
//console.log('_sumScore', _sumScore)
//console.log('passScore',passScore)
console.log('sumScore', sumScore)
const { success } = await updateScore({ rules_id: Number(params?.id || rulesId), pass_socre: passSocre, sum_score: _sumScore })
setSumScore(_sumScore)
console.log('paper', paper)
// setUuidPaper(paper?.paper_uuid)
// message.success('提交成功');
handleScoreModalVisible(false)
return true;
}}
>
<ScoreSetter ref={setterRef} questionTypeValues={questionTypeValues || false} />
</ModalForm>
</PageContainer>
);
};