feat: 刷题页面
This commit is contained in:
438
src/views/upload-questions/components/option-input-box/index.jsx
Normal file
438
src/views/upload-questions/components/option-input-box/index.jsx
Normal file
@@ -0,0 +1,438 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, message, Tooltip, Select } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { debounce } from '@utils';
|
||||
import { optionLetter } from '../../constant';
|
||||
import KindEditor from '../kind-editor';
|
||||
import './index.less';
|
||||
const { TextArea } = Input;
|
||||
const { Option } = Select;
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
||||
// 判断题
|
||||
const judgeList = [
|
||||
{
|
||||
label: '错误',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '正确',
|
||||
value: 1,
|
||||
},
|
||||
];
|
||||
const optionLetterLength = 7; // ABCD的长度
|
||||
const showDeleteLength = 3; // 展示删除icon的最短长度
|
||||
export default class OptionInputBox extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
optionList: [
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 4,
|
||||
},
|
||||
], // 选项列表
|
||||
currentActiveList: [], // 当前选中的项
|
||||
scoreValue: '', // 分数
|
||||
subjectAnalysis: '', //试题解析
|
||||
};
|
||||
}
|
||||
|
||||
kindEditor = KindEditor | null;
|
||||
subjectAnswer = ''; // 选项内容
|
||||
|
||||
/**
|
||||
* 新增/删除
|
||||
* @param {*} len
|
||||
* @param {*} type add-新增 / del-删除
|
||||
* @returns
|
||||
*/
|
||||
onChangeAddOption = (len, type) => () => {
|
||||
let { optionList, currentActiveList } = this.state;
|
||||
let list = [];
|
||||
// 新增
|
||||
if (type === 'add') {
|
||||
if (len === optionLetterLength) {
|
||||
return;
|
||||
}
|
||||
optionList.push({ label: defalutLabel, value: optionLetter[len].value });
|
||||
} else {
|
||||
// 删除
|
||||
currentActiveList = [];
|
||||
optionList.splice(len, 1);
|
||||
// 重新初始化ABCD对应的id
|
||||
list = optionList.map((item, index) => {
|
||||
return {
|
||||
label: item.label,
|
||||
value: optionLetter[index].value,
|
||||
};
|
||||
});
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
optionList: type === 'add' ? optionList : list,
|
||||
currentActiveList,
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 确认/取消 编辑框
|
||||
* @param {*} index
|
||||
* @param {*} type submit/cancel
|
||||
* @returns
|
||||
*/
|
||||
onChangeOptEditor = (index, type) => () => {
|
||||
let { optionList } = this.state;
|
||||
this.kindEditor && this.kindEditor.onClear();
|
||||
if (type === 'submit') {
|
||||
_.set(
|
||||
optionList,
|
||||
[index, 'label'],
|
||||
!!this.subjectAnswer ? this.subjectAnswer : defalutLabel
|
||||
);
|
||||
}
|
||||
_.set(optionList, [index, 'isShowEditor'], false);
|
||||
this.subjectAnswer = '';
|
||||
this.setState(
|
||||
{
|
||||
optionList,
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展开 编辑项
|
||||
* @param {*} index
|
||||
* @returns
|
||||
*/
|
||||
onChangeShowEditor = (index) =>
|
||||
debounce(() => {
|
||||
let { optionList } = this.state;
|
||||
if (optionList.filter((item) => item.isShowEditor).length > 0) {
|
||||
return message.info('请先确认正在编辑的选项内容');
|
||||
}
|
||||
_.set(optionList, [index, 'isShowEditor'], true);
|
||||
this.setState(
|
||||
{
|
||||
optionList,
|
||||
},
|
||||
() => {
|
||||
this.kindEditor && this.kindEditor.onCashBack();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* 富文本编辑器
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeEditor = (index) => (e) => {
|
||||
this.subjectAnswer = e;
|
||||
};
|
||||
|
||||
/**
|
||||
* 正确选项
|
||||
* @param {*} value
|
||||
*/
|
||||
onChangeSelect = (value) => {
|
||||
const { isMultiple } = this.props;
|
||||
let str = value;
|
||||
if (!isMultiple) {
|
||||
// 单选,格式化成数组
|
||||
str = [value];
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
currentActiveList: str,
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 本题分值
|
||||
*/
|
||||
onChangeScore = (e) => {
|
||||
this.setState(
|
||||
{
|
||||
scoreValue: e.target.value.trim(),
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 试题解析
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectAnalysis = (e) => {
|
||||
this.setState(
|
||||
{
|
||||
subjectAnalysis: e.target.value.trim(),
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 清空
|
||||
*/
|
||||
handleClearOption = () => {
|
||||
this.subjectAnswer = ''; // 选项内容
|
||||
this.setState({
|
||||
optionList: [
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 4,
|
||||
},
|
||||
], // 选项列表
|
||||
currentActiveList: [], // 当前选中的项
|
||||
scoreValue: '', // 分数
|
||||
subjectAnalysis: '', //试题解析
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 向父组件传值
|
||||
*/
|
||||
handleChangeOption = () => {
|
||||
let { currentActiveList, scoreValue, subjectAnalysis, optionList } = this.state;
|
||||
const { isJudge } = this.props;
|
||||
let activeList = [];
|
||||
if (!isJudge) {
|
||||
// 单选/多选
|
||||
activeList = optionList.map((item) => {
|
||||
let flag = 0;
|
||||
if (currentActiveList.includes(item.value)) {
|
||||
flag = 1;
|
||||
}
|
||||
return {
|
||||
optionType: item.value,
|
||||
optionContent: item.label,
|
||||
isCorrect: flag,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// 判断
|
||||
activeList = currentActiveList;
|
||||
}
|
||||
console.log('向父组件传值', activeList, scoreValue, subjectAnalysis);
|
||||
// this.props.handleChangeOption(activeList, scoreValue, subjectAnalysis);
|
||||
this.props.handleChangeOption(activeList, 1, subjectAnalysis);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectAnalysis } = this.state;
|
||||
const { isJudge } = this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
{!isJudge && this.renderOption()}
|
||||
{this.renderOptionBtn()}
|
||||
<div className="option-input-container">
|
||||
<div className="option-input-title">试题解析:</div>
|
||||
<TextArea
|
||||
placeholder="试题解析(非必填 限500字)"
|
||||
value={subjectAnalysis}
|
||||
style={{ height: 48, width: '100%' }}
|
||||
maxLength={500}
|
||||
autoSize={{ minRows: 3, maxRows: 4 }}
|
||||
onChange={(e) => this.onChangeSubjectAnalysis(e)}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选项模块
|
||||
* @returns
|
||||
*/
|
||||
renderOption = () => {
|
||||
const { optionList } = this.state;
|
||||
let listLen = optionList.length;
|
||||
return (
|
||||
<Fragment>
|
||||
{optionList.length > 0 &&
|
||||
optionList.map((item, index) => {
|
||||
const isShowTip = item.label === defalutLabel;
|
||||
return (
|
||||
<div
|
||||
className="option-input-container"
|
||||
style={{ flexDirection: 'column' }}
|
||||
key={`option_input_${index}`}>
|
||||
<div className="option-input-main">
|
||||
<div className="option-input-title-option">
|
||||
{optionLetter[item.value - 1].label}
|
||||
</div>
|
||||
<div
|
||||
className="option-input-item"
|
||||
key={`option_id_${item.value}`}>
|
||||
<Tooltip
|
||||
title="点击可输入该选项内容"
|
||||
onClick={this.onChangeShowEditor(index)}>
|
||||
<div
|
||||
className="option-input-item-header"
|
||||
style={
|
||||
isShowTip
|
||||
? {
|
||||
color: 'rgba(51,51,51,0.3)',
|
||||
}
|
||||
: {
|
||||
color: 'rgba(51,51,51,0.9)',
|
||||
}
|
||||
}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.label,
|
||||
}}></div>
|
||||
</Tooltip>
|
||||
<div className="option-input-item-delete">
|
||||
{listLen > showDeleteLength && (
|
||||
<Tooltip
|
||||
title="删除选项"
|
||||
onClick={this.onChangeAddOption(index, 'del')}>
|
||||
<img
|
||||
className="option-input-item-delete-icon"
|
||||
src="https://img14.360buyimg.com/imagetools/jfs/t1/212738/17/4123/399/618dd36bEd53475f5/38e899e92bbd5d5e.png"
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{item.isShowEditor && (
|
||||
<div
|
||||
key={`option_editor_${index}`}
|
||||
className="option-input-main"
|
||||
style={{ marginTop: 19 }}>
|
||||
<div className="option-input-editor">
|
||||
<KindEditor
|
||||
ref={(ref) => {
|
||||
this.kindEditor = ref;
|
||||
}}
|
||||
bodyHeight={145}
|
||||
borderRadius={12}
|
||||
onChange={this.onChangeEditor(index)}
|
||||
cashBackText={isShowTip ? '' : item.label}
|
||||
/>
|
||||
<div className="option-input-editor-btns">
|
||||
<Tooltip title="取消后内容将不会更新到选项框内">
|
||||
<div
|
||||
className="option-input-editor-btn"
|
||||
onClick={this.onChangeOptEditor(
|
||||
index,
|
||||
'cancel'
|
||||
)}>
|
||||
取消
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip title="确定后内容将会更新到选项框内">
|
||||
<div
|
||||
className="option-input-editor-btn option-input-editor-submit-btn"
|
||||
onClick={this.onChangeOptEditor(
|
||||
index,
|
||||
'submit'
|
||||
)}>
|
||||
确定
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选项模块-操作按钮
|
||||
* @returns
|
||||
*/
|
||||
renderOptionBtn = () => {
|
||||
const { optionList, scoreValue, currentActiveList } = this.state;
|
||||
const { isMultiple, isJudge } = this.props;
|
||||
let listLen = optionList.length;
|
||||
return (
|
||||
<div className="option-input-container">
|
||||
<div className="option-input-title option-input-title-required">题目操作:</div>
|
||||
<div style={{ display: 'flex', width: '100%' }}>
|
||||
{!isJudge && (
|
||||
<div
|
||||
className="option-input-option-btn"
|
||||
onClick={this.onChangeAddOption(listLen, 'add')}>
|
||||
添加选项
|
||||
</div>
|
||||
)}
|
||||
<div className="option-input-option-btn option-input-option-input">
|
||||
正确选项
|
||||
<Select
|
||||
mode={isMultiple && 'multiple'}
|
||||
defaultActiveFirstOption={false}
|
||||
value={currentActiveList}
|
||||
placeholder="请选择"
|
||||
style={{ minWidth: isMultiple ? '64px' : '68px', marginLeft: 4 }}
|
||||
onChange={this.onChangeSelect}>
|
||||
{isJudge
|
||||
? judgeList.map((item, index) => {
|
||||
return (
|
||||
<Option
|
||||
key={`option_select_${item.value}`}
|
||||
value={item.value}>
|
||||
{item.label}
|
||||
</Option>
|
||||
);
|
||||
})
|
||||
: optionList.map((item, index) => {
|
||||
return (
|
||||
<Option
|
||||
key={`option_select_${item.value}`}
|
||||
value={item.value}>
|
||||
{optionLetter[index].label}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user