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.

742 lines
40 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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, ProFormSelect, ProFormDateRangePicker } from '@ant-design/pro-form';
import ProCard from '@ant-design/pro-card';
import { Button, Checkbox, Col, Divider, Input, List, Menu, message, Radio, Row, Space, Typography } 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, queryRulesList, queryRulesPaper, saveQuestionTypeScore, autoPaperOfficial, queryPaperQuestionList, updateScore } from '../../service';
import { queryQuestionList, queryQuestionType } from '@/pages/questionbank/service';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import ProTable, { EditableProTable } from '@ant-design/pro-table';
//import { TableListPagination } from '@/pages/ListTableList2/data';
import { DiffOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
//import { TableListItem } from '../../components/QuestionSelector';
import ScoreSetter from '../../components/ScoreSetter';
import AutoSelector from '../components/AutoSelector';
import QuestionSelector from '../../components/QuestionSelector';
import { getSubjectInfo } from '@/pages/course/subject/service';
import { max } from 'lodash';
/** 选项序号 */
const labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'];
/** 题型序号 */
const numberType = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
export default () => {
const questionNumber = [1, 1, 1];
const params = useParams();
const formRef = useRef<ProFormInstance>();
const actionRef = useRef<ActionType>();
const setterRef = useRef();
const autoRef = useRef();
const [currentStep, setCurrentStep] = useState(0);
const [questionTypeValues, setQuestionTypeValues] = useState([]); // 题型数据[{count:0, score:0, score_harf:0}]
const [questionType, setQuestionType] = useState([]); // 题型
const [passScore, setPassScore] = useState(0)
const [rulesId, setRulesId] = useState(0); // 规则id, 保存新建的rules_id
const [subjectId, setSubjectId] = useState<number>(0); // 关联主题id
/** 自动组卷窗口 */
const [autoModalVisible, handleAutoModalVisible] = useState<boolean>(false);
/** 分值窗口 */
const [scoreModalVisible, handleScoreModalVisible] = useState<boolean>(false);
/** 试卷详情窗口 */
const [paperModalVisible, handlePaperModalVisible] = useState<boolean>(false);
const [paperInfo, setPaperInfo] = useState({})
/** 查看试卷 */
const { data: questions, run } = useRequest(async (params) => {
console.log('questions', questions)
return queryPaperQuestionList(params);
}, {
manual: true,
formatResult: (result) => {
return result?.question_list;
}
});
//
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]);
/** 列表项定义 */
const columns: ProColumns[] = [
{
title: '序号',
key: 'index',
valueType: 'indexBorder',
width: 48,
},
{
title: '考试名称',
dataIndex: 'rules_name',
valueType: 'text',
hideInTable: false,
hideInForm: false,
hideInSearch: true,
},
{
title: '试卷',
dataIndex: 'examination_time',
valueType: 'text',
sorter: false,
hideInTable: true,
hideInForm: true,
hideInSearch: true,
renderText: (val: string) => `${val}`,
},
{
title: '题型设置',
dataIndex: 'question_type',
valueType: 'text',
sorter: false,
hideInTable: false,
hideInForm: true,
hideInSearch: true,
render: (dom, record, index) => {
return <>
{record.question_type_count.map((item) => { return <span style={{ paddingRight: 15 }}>{`${item.type_name} ${item.count}`}</span> })}
</>
},
},
{
title: '关联主题',
dataIndex: 'subject_name',
valueType: 'text',
hideInTable: true,
hideInForm: true,
hideInSearch: true,
},
{
title: '题型设置',
dataIndex: 'question_type_count',
valueType: 'text',
hideInTable: true,
hideInForm: false,
hideInSearch: false,
request: async () => {
/*
const { data: Items } = await querySubjectList({});
// console.log(Items, ')))');
const sinfo = []
for (let i = 0; i < Items.list.length; i++) {
// console.log(Items.list[i], ">>>")
sinfo.push({ label: Items.list[i].subject_name, value: Items.list[i].subject_id })
}
console.log(sinfo, 'sinfo');
*/
return [];
},
},
{
title: '总分',
dataIndex: 'sum_score',
sorter: false,
valueType: 'text',
hideInSearch: true,
hideInForm: false,
renderText: (val: string) => `${val || '0'}`,
},
{
title: '通过线',
dataIndex: 'pass_score',
sorter: false,
valueType: 'text',
hideInSearch: true,
hideInForm: false,
renderText: (val: string) => `${val || '0'}`,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
width: 220,
render: (_dom: any, record: React.SetStateAction) => {
// console.log(record, 'record')
return [
<Button
type='link'
key="detail"
onClick={() => {
//console.log('entity', entity);
//setCurrentRow(record);
//
run({
paper_id: record?.paper_id,
}); // 获取试卷试题列表
handlePaperModalVisible(true); // 试卷详情
}}
style={{ fontSize: 14, padding: '0 2px 0 0' }}
>
</Button>,
<Button
type='link'
key="create"
onClick={async () => {
//history.push(`/examination/option/registration/${record.examination_id}`);
//setCurrentRow(record);
const _type_count: any[] = [];
record?.question_type_count.forEach((item: { count: any; }) => {
_type_count.push(item?.count || 0)
})
const { success } = await autoPaperOfficial(
{
paper_id: record?.paper_id,
rules_id: Number(params?.id || rulesId),
question_count: '50,50', // 当前数据库没保存,只能采用默认
question_type_count: _type_count?.toString()
}
)
if (success) {
message.success('试卷生成成功')
actionRef.current?.reload()
} else {
message.success('试卷生成失败')
}
}}
style={{ fontSize: 14, padding: '0 2px 0 0' }}
>
</Button>,
]
},
},
];
console.log(params, 'params');
let ruleData = {}
if (params?.id) {
//console.log(JSON.stringify(params), "878");
const { data } = useRequest(async () => {
const { bean } = await queryRulesView(params);
return { data: bean }
});
ruleData = data
}
console.log('ruleData',ruleData);
/** 获取题型 */
const { data: questionTypeData } = useRequest(() => {
return queryQuestionType();
}, {
formatResult: (result) => {
return result.list;
}
});
useEffect(() => {
setQuestionType(questionTypeData || []);
return () => {
/** 退出当前页面清空Map */
//parsingMap.clear();
}
}, [questionTypeData]);
return (
<PageContainer content={''} extraContent={''}>
<ProCard className={styles.examinationrules}>
<StepsForm<{
name: string;
}>
formRef={formRef}
onFinish={async () => {
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 }
}
console.log(fileds, 'fileds', params);
// return false
const { data } = await saveRules({
...fileds,
b_use: 0,
rules_type: 1,
start_time: fileds.dateRange[0],
end_time: fileds.dateRange[1]
});
setRulesId(data?.rules_id)
setSubjectId(fileds?.subject_id) // 设置当前关联主题
setCurrentStep(1)
return true;
}}
>
<Row gutter={24}>
<Col lg={24} md={24} sm={24}>
{ruleData && (
<>
<ProFormText
name="rules_name"
label="考试名称"
width="lg"
fieldProps={{
type: 'text',
allowClear: false,
width: 'large',
onInput: (e) => {
const val = `${e.currentTarget?.value}`;
if (val.length > 50) {
e.currentTarget.value = val.slice(0, 50)
}
}
//style:{width: '100%'}
}}
initialValue={ruleData.rules_name}
// tooltip="最长为 6 位汉字,需要与考生身份证一致"
placeholder="请输入名称"
rules={[{ required: true, message: '请输入考试名称' }]}
// value="锦书"
// disabled
/>
{/*主题一旦选择并提交将不支持修改 */}
<ProFormSelect
width="lg"
initialValue={ruleData.subject_id}
request={async () => {
return querySubjectList().then(({ data }) => {
console.log(data, 'querySubjectList')
return data.list.map((item) => {
return {
label: item.subject_name,
value: item.subject_id,
};
});
});
}}
rules={[{ required: true, message: '请选择主题' }]}
name="subject_id"
label="关联主题"
disabled={params?.id}
/>
<Row style={{ marginBottom: 24, marginTop: -7 }}>
<Col offset={8} style={{ color: '#bfbfbf' }}></Col>
</Row>
<ProFormText addonAfter={`分钟`} name="examination_time" label="考试时间"
initialValue={ruleData.examination_time}
rules={[{ required: true, message: '请输入考试时间' }]}
fieldProps={{
type: 'number',
min: 1,
allowClear: false,
width: 'large',
onInput: (e) => {
const val = `${e.currentTarget?.value}`;
console.log('val', val)
console.log('val.charAt(0)', val.charAt(0))
if (val.charAt(0) === '') {
console.log('vvv', val)
e.currentTarget.value = '0'
}
if (val.length > 3) {
e.currentTarget.value = val.slice(0, 3)
}
},
//style: {marginRight:3}
}}
// tooltip="限制考试时长的情况下,用户考试中离开,倒计时不会停止。"
/>
<Row style={{ marginBottom: 24, marginTop: -7 }}>
<Col offset={8} style={{ color: '#bfbfbf' }}></Col>
</Row>
{/*
<ProFormText name="paper_count" label="试卷数量"
width='lg'
initialValue={ruleData.paper_count}
rules={[{ required: true, message: '请输入试卷数量' }]}
fieldProps={{
type: 'number',
min: 1,
allowClear: false,
//width: 'large',
onInput: (e) => {
const val = `${e.currentTarget?.value}`;
console.log('val', val)
console.log('val.charAt(0)', val.charAt(0))
if (val.charAt(0) === '') {
console.log('vvv', val)
e.currentTarget.value = ''
}
if (val.length > 3) {
e.currentTarget.value = val.slice(0, 3)
}
},
//style:{width: '100%'}
}}
// tooltip="限制考试时长的情况下,用户考试中离开,倒计时不会停止。"
/>
<Row style={{ marginBottom: 24, marginTop: -7 }}>
<Col offset={8} style={{ color: '#bfbfbf' }}>试卷数量与学生重复考试次数一致</Col>
</Row>
*/}
{console.log('###', ruleData)}
<ProFormDateRangePicker width='lg' name="dateRange" label="试卷有效期" initialValue={(ruleData?.start_time && ruleData?.end_time) ? [ruleData?.start_time, ruleData?.end_time] : []} rules={[{ required: true, message: '请输试卷有效期' }]} />
<Row style={{ marginBottom: 24, marginTop: -7 }}>
<Col offset={8} style={{ color: '#bfbfbf' }}></Col>
</Row>
</>
)}
</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 || rulesId })
return true;
}}
>
<div style={{ margin: '0' }}>
<ProTable
page
headerTitle={false}
actionRef={actionRef}
rowKey="examination_id"
options={false}
search={false}
toolBarRender={() => (
<Space style={{ margin: -48 }} >
<Button
type="primary"
key="primary"
onClick={() => {
handleAutoModalVisible(true)
}}
style={{ marginRight: 5 }}
>
<PlusOutlined />
</Button>
<Button
type="primary"
key="primary"
onClick={async () => {
/** 获取试卷 */
const {question_type_score, question_list} = await queryRulesPaper(
{
rules_id: params?.id || rulesId,
page_number: 1,
page_size: 10
}
);
console.log('_data:', question_type_score)
setPassScore(question_list[0]?.pass_score)
//questionTypeValues?.map((item,idx)=>{return {...item, score:values[idx]?.score, score_harf:values[idx]?.score_harf}})
//setQuestionTypeValues() // 更新分值成功后设置组件分值
handleScoreModalVisible(true)
}}
>
<DiffOutlined />
</Button>
</Space>
)}
request={async (value) => {
console.log('queryRulesPaper::')
/** 获取试卷 */
const _data = await queryRulesPaper(
{
rules_id: params?.id || rulesId,
page_number: value.current,
page_size: value.pageSize
}
);
const _questionType = [];
const _questionTypeCountData = [];
_data.question_list[0]?.question_type_count.forEach((item) => {
_questionTypeCountData.push(item.count)
_questionType.push({ typeName: item.type_name, code: item.question_type })
})
console.log('_questionTypeCountData', _questionTypeCountData)
console.log('_data.question_type_score', _data.question_type_score)
if (_data?.question_type_score.length > 0) {
_data.question_type_score?.forEach((item, index) => {
_questionType[index] = { ..._questionType[index], count: _questionTypeCountData[index], score: item.score, score_harf: item.score_harf }
})
} else {
_questionTypeCountData?.forEach((item, index) => {
_questionType[index] = { ..._questionType[index], count: _questionTypeCountData[index], score: 0, score_harf: 0 }
})
}
// question_type_count
console.log('_questionType 1', _questionType)
setQuestionTypeValues(_questionType)
return {
current: _data?.pageNumber,
data: _data?.question_list,
pageSize: _data?.pageSize,
total: _data?.totalRow || 0,
};
}}
// dataSource={list}
columns={columns}
rowSelection={false}
/>
</div>
</StepsForm.StepForm>
<StepsForm.StepForm
name="time"
title="完成"
stepProps={{
description: false,
}}
onFinish={async () => {
console.log(formRef.current?.getFieldsValue());
// 跳转到指定路由
history.push('/examinationrules/attestation');
return true;
}}
>
<Row gutter={24}>
<Col lg={16} md={16} sm={16} offset={6}>
{currentStep === 2 && <ProDescriptions
layout='horizontal'
column={1}
//actionRef={actionRef}
title={false}
request={async () => {
const result = await queryRulesView({ id: rulesId })
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> {paperInfo?.question_type_count?.map(item => item.count)?.reduce((prev, curr) => prev + curr)} , {paperInfo?.sum_score || '-'} </span>
<span>{paperInfo?.question_type_count?.map(item => (<span style={{ paddingRight: 10 }}>{`${item?.type_name} ${item?.count} 道题 `}</span>))}</span>
<span>线 {paperInfo?.pass_score || '-'} </span>
</Space>
}} />
<ProDescriptions.Item dataIndex="paper_count" label="试卷数量" valueType="text" render={(dom, entity) => {
return <div stype={{ padding: 0 }}><span style={{ display: 'inline-block', width: 200 }}>{entity?.paper_count}</span> <span><ExclamationCircleOutlined /> </span></div>
}} />
<ProDescriptions.Item dataIndex="live_time" label="试卷有效期" valueType="text" render={(dom, entity) => {
return <div stype={{ padding: 0 }}><span style={{ display: 'inline-block', width: 200 }}>{/*entity?.start_time.substring(0,10)*/} {entity?.end_time.substring(0, 10)}</span> <span><ExclamationCircleOutlined /> </span></div>
}} />
</ProDescriptions>
}
</Col>
</Row>
</StepsForm.StepForm>
</StepsForm>
</ProCard>
<ModalForm
title="系统组卷 "
visible={autoModalVisible}
onVisibleChange={handleAutoModalVisible}
onFinish={async () => {
const values = autoRef.current?.getData();
console.log('系统组卷::::', values);
const { code, data: paper, msg } = await autoPaperOfficial({ rules_id: Number(params?.id || rulesId), subject_id: subjectId, paper_count: values?.paperCount, question_count: values?.questionCount.toString(), question_type_count: values?.questionTypeCount.toString() })
console.log('paper', paper)
// setUuidPaper(paper?.paper_uuid)
// message.success('提交成功');
actionRef.current?.reload()
handleAutoModalVisible(false)
return true;
}}
>
<AutoSelector ref={autoRef} questionType={questionType} rulesId={rulesId} subjectId={subjectId} />
</ModalForm>
<ModalForm
title={`批量设置分值`}
//
width="60%"
visible={scoreModalVisible}
onVisibleChange={handleScoreModalVisible}
onFinish={async () => {
const values = setterRef.current?.getData() // 获取题型分值数据
const passSocre = setterRef.current?.getValue() // 获取通过分数线
const sumCore = setterRef.current?.getSum() // 获取总分数
console.log('getSum()',sumCore)
if(passSocre > sumCore){
message.error('通过分数线不能大于总分,请修改通过分数线');
return false;
}
console.log('批量设置分值v::::', values);
const { code, data: paper, msg } = await saveQuestionTypeScore({ rules_id: Number(params?.id || rulesId), type_score: JSON.stringify(values) })
console.log('paper', paper)
// 总分及通过分
let _sumScore = 0;
values?.forEach((item: { score: number; }) => {
console.log('item--', item)
_sumScore += item?.score
})
console.log('_sumScore', _sumScore)
//return false;
console.log('passSocre', passSocre)
//console.log('sumScore',sumScore)
const { success } = await updateScore({ rules_id: Number(params?.id || rulesId), pass_socre: passSocre, sum_score: _sumScore })
//setSumScore(_sumScore)
// setUuidPaper(paper?.paper_uuid)
// message.success('提交成功');
actionRef.current?.reloadAndRest?.();
handleScoreModalVisible(false)
return true;
}}
>
<ScoreSetter ref={setterRef} questionTypeValues={questionTypeValues || false} passScore={passScore} />
</ModalForm>
<ModalForm
// title={`试卷详情`}
title={ruleData?.rules_name}
width="80%"
visible={paperModalVisible}
onVisibleChange={handlePaperModalVisible}
onFinish={async () => {
//alert(0)
//const values = setterRef.current?.getData()
//console.log('试卷详情::::', values);
//const {code, data: paper, msg} = await saveQuestionTypeScore({rules_id:Number(params?.id), type_score: JSON.stringify(values)})
//console.log('paper', paper)
// setUuidPaper(paper?.paper_uuid)
// message.success('提交成功');
handlePaperModalVisible(false)
return true;
}}
>
{questionTypeValues && questionTypeValues?.map((typeItem, index) => {
console.log('questionType:::', typeItem)
return <>
{questions?.length === 0 && <div></div>}
{/* 题型 */}
<div key={typeItem?.code} style={{ padding: 10, fontSize: 16 }}>{numberType[index]}. {typeItem?.typeName} ({typeItem?.count})</div>
{/* 试题列表 */}
<div style={{ padding: '0 10px 0 50px' }}>
{questions && questions.map((item, idx) => (
(typeItem?.code === item?.question_type) &&
<div style={{ border: 'none' }}>
<Typography style={{ marginBottom: 16, fontSize: 14, padding: '15px 15px 0 15px' }}>
{questionNumber[item?.question_type]++}. {typeItem?.typeName},{typeItem?.score}{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>
))}
</div>
</>
})}
</ModalForm>
</PageContainer>
);
};