import React from 'react'; import { Tabs, Form, Tag, InputNumber, Radio, Row, Col, Checkbox, Icon, Input, Button, List, Cascader, Switch } from 'antd'; import './index.less'; import DragList from '@src/components/DragList'; import Editor from '@src/components/Editor'; import Page from '@src/containers/Page'; import Block from '@src/components/Block'; import Select from '@src/components/Select'; import { getMap, formatFormError, formatTreeData, generateSearch } from '@src/services/Tools'; import { asyncSMessage, asyncGet } from '@src/services/AsyncTools'; import { QuestionType, QuestionDifficult, QuestionStyleType, QuestionRadioDirection } from '../../../../Constant'; import QuestionNoList from '../../../components/QuestionNoList'; import { System } from '../../../stores/system'; import { Question } from '../../../stores/question'; import { Examination } from '../../../stores/examination'; import { Exercise } from '../../../stores/exercise'; const QuestionStyleTypeMap = getMap(QuestionStyleType, 'value', 'label'); const DifficultScoreMap = { verbal: { easy: [{ label: 6, value: 6 }, { label: 7.6, value: 7.6 }, { label: 9.2, value: 9.2 }, { label: 10.8, value: 10.8 }, { label: 12.4, value: 12.4 }], medium: [{ label: 14, value: 14 }, { label: 15.6, value: 15.6 }, { label: 17.2, value: 17.2 }, { label: 18.8, value: 18.8 }, { label: 20.4, value: 20.4 }], hard: [{ label: 22, value: 22 }, { label: 23.6, value: 23.6 }, { label: 25.2, value: 25.2 }, { label: 26.8, value: 26.8 }, { label: 28.4, value: 28.4 }], }, quant: { easy: [{ label: 12, value: 12 }, { label: 13.5, value: 13.5 }], medium: [{ label: 15, value: 15 }, { label: 16.5, value: 16.5 }, { label: 18, value: 18 }, { label: 19.5, value: 19.5 }, { label: 21, value: 21 }], hard: [{ label: 22.5, value: 22.5 }, { label: 24, value: 24 }, { label: 25.5, value: 25.5 }, { label: 27, value: 27 }, { label: 28.5, value: 28.5 }], }, }; export default class extends Page { constructor(props) { super(props); this.placeList = []; this.placeSetting = null; this.uuid = []; this.examinationStructMap = {}; this.exerciseStructMap = {}; this.questionTypeToSubject = {}; } init() { Promise.all([ Exercise.allStruct().then(result => { result = result.filter(row => row.isExamination); this.exerciseStructMap = getMap(result, 'id'); result.forEach((row) => { if (row.level !== 2) return; const subject = this.exerciseStructMap[row.parentId]; this.questionTypeToSubject[row.extend] = subject.extend; }); return { value: 'exercise', key: 'exercise', label: '练习', title: '练习', children: formatTreeData(result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; }), 'id', 'title', 'parentId') }; }), Examination.allStruct().then(result => { this.examinationStructMap = getMap(result, 'id'); return { value: 'examination', key: 'examination', label: '模考', title: '模考', children: formatTreeData(result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; }), 'id', 'title', 'parentId') }; }), ]).then(result => { this.setState({ moduleStructData: result }); }); } initData() { const { id } = this.params; const { form } = this.props; let handler; if (id) { handler = Question.get({ id }).then(result => { result.content = result.content || { questions: [], steps: [] }; result.keyword = result.keyword ? result.keyword.filter(row => row) : []; return result; }); } else { handler = Promise.resolve({ content: { number: 1, type: 'single', typeset: 'one', questions: [], steps: [], table: {} } }); } handler.then(result => { this.uuid[0] = -1; let type = result.content.type || 'single'; if (type === 'inline') type = 'single'; result.content.questions.forEach((row, index) => { const keys = []; this.uuid[index] = 0; if (row.select && row.select.length > 0) { for (; this.uuid[index] < row.select.length; this.uuid[index] += 1) { keys.push(this.uuid[index]); form.getFieldDecorator(`content.questions[${index}].select[${this.uuid[index]}]`); form.getFieldDecorator(`content.questions[${index}].direction`); form.getFieldDecorator(`content.questions[${index}].first`); form.getFieldDecorator(`content.questions[${index}].second`); form.getFieldDecorator(`content.questions[${index}].description`); if (type === 'double') { form.getFieldDecorator(`answer.questions[${index}].${type}[${this.uuid[index]}][0]`); form.getFieldDecorator(`answer.questions[${index}].${type}[${this.uuid[index]}][1]`); } else { form.getFieldDecorator(`answer.questions[${index}].${type}[${this.uuid[index]}]`); } } } form.getFieldDecorator(`content.questions[${index}].keys`); row.keys = keys; return row; }); (result.content.steps || []).forEach((row, index) => { form.getFieldDecorator(`content.steps[${index}].title`); form.getFieldDecorator(`content.steps[${index}].stem`); }); const { row, col } = result.content.table; for (let i = 0; i < col; i += 1) { form.getFieldDecorator(`content.table.header[${i}]`); for (let j = 0; j < row; j += 1) { // console.log(`content.table.data[${j}][${i}]`); form.getFieldDecorator(`content.table.data[${j}][${i}]`); } } form.getFieldDecorator('content.step'); form.getFieldDecorator('content.number'); form.getFieldDecorator('content.table.row'); form.getFieldDecorator('content.table.col'); form.getFieldDecorator('stem'); form.getFieldDecorator('difficult'); form.getFieldDecorator('difficultScore'); form.getFieldDecorator('questionType'); form.getFieldDecorator('place'); form.getFieldDecorator('id'); form.getFieldDecorator('questionNoIds'); form.getFieldDecorator('relationQuestion'); form.setFieldsValue(result); return result; }) .then((result) => { this.refreshPlace(result.questionType); this.refreshDifficultScore(result.questionType, result.difficult); this.setState({ associationContentQuestionNos: [], realtionQuestionNos: [] }); if (result.questionNoIds && result.questionNoIds.length > 0) { Question.listNo({ ids: result.questionNoIds }).then(list => { this.setState({ questionNos: list }); return list; }).then(rr => { // 阅读关联题目: 只有一个id if (rr.length === 1 && rr[0].relationQuestion && rr[0].relationQuestion.length > 0) { form.getFieldDecorator('rcType'); form.setFieldsValue({ rcType: true }); this.bindRelationQuestion(rr[0].relationQuestion); } else { this.bindRelationQuestion(); } return null; }); } else { this.bindRelationQuestion(); } this.bindAssociationContent(result.associationContent); return null; }); } refreshPlace(type) { let handler = null; if (this.placeSetting) { handler = Promise.resolve(this.placeSetting); } else { handler = System.getPlace(); } handler.then(result => { this.placeSetting = result; this.placeList = result[type] || []; this.setState({ placeList: this.placeList }); }); } refreshDifficultScore(questionType, difficult) { const subject = this.questionTypeToSubject[questionType]; const difficultScore = (DifficultScoreMap[subject] || {})[difficult] || []; this.setState({ difficultScore }); } addNo() { const { form } = this.props; form.validateFields(['moduleStruct', 'questionNo'], (err) => { if (!err) { const data = form.getFieldsValue(['id', 'moduleStruct', 'questionNo']); data.moduleStruct = data.moduleStruct.map(row => row); data.module = data.moduleStruct.shift(); const node = data.moduleStruct[data.moduleStruct.length - 1]; let nodeString; switch (data.module) { case 'exercise': nodeString = this.exerciseStructMap[node].titleZh; break; case 'examination': nodeString = this.examinationStructMap[node].titleZh; break; default: } data.questionId = data.id || 0; delete data.id; data.no = data.questionNo; data.title = `${nodeString}-${data.no}`; delete data.questionNo; Question.addNo(data).then((result) => { const { questionNos = [] } = this.state; questionNos.push(result); this.setState({ questionNos }); form.setFieldsValue({ moduleStruct: [], questionNo: '', questionNoIds: questionNos.map(row => row.id) }); asyncSMessage('保存成功'); }).catch((e) => { if (e.result) form.setFields(formatFormError(data, e.result)); }); } }); } removeNo(noId) { let { questionNos } = this.state; questionNos = questionNos.filter(row => row.id !== noId); Question.delNo({ id: noId }).then(() => { this.setState({ questionNos }); }); } changeType(type) { const { getFieldValue, setFieldsValue, getFieldDecorator } = this.props.form; const number = getFieldValue('content.number'); // const keys = []; this.uuid = []; for (let index = 0; index < Number(number); index += 1) { this.uuid[index] = 0; switch (type) { case 'double': getFieldDecorator(`content.questions[${index}].direction`); setFieldsValue({ [`content.questions[${index}].direction`]: 'landscape' }); break; default: } } } removeQuestion(index, k) { const { form } = this.props; const keys = form.getFieldValue(`content.questions[${index}].keys`); if (keys.length === 1) { return; } form.setFieldsValue({ [`content.questions[${index}].keys`]: keys.filter(key => key !== k), }); } addQuestion(index) { const { form } = this.props; const keys = form.getFieldValue(`content.questions[${index}].keys`) || []; if (!this.uuid[index]) { this.uuid[index] = 1; } else { this.uuid[index] += 1; } const nextKeys = keys.concat(this.uuid[index]); form.setFieldsValue({ [`content.questions[${index}].keys`]: nextKeys, }); } orderQuestion(index, oldIndex, newIndex) { const { form } = this.props; const keys = form.getFieldValue(`content.questions[${index}].keys`) || []; const tmp = keys[oldIndex]; keys[oldIndex] = keys[newIndex]; keys[newIndex] = tmp; form.setFieldsValue({ [`content.questions[${index}].keys`]: keys, }); } changeQuestion(index, k, value) { const { form } = this.props; let answer = form.getFieldValue(`answer.questions[${index}].single`) || []; answer = answer.map(() => !value); answer[k] = !!value; form.setFieldsValue({ [`answer.questions[${index}].single`]: answer }); } changeDouble(index, k, o, value) { const { form } = this.props; const direction = form.getFieldValue(`content.questions[${index}].direction`); let answer = form.getFieldValue(`answer.questions[${index}].double`) || []; switch (direction) { case 'landscape': answer[k] = answer[k].map(() => !value); if (o >= 0) { answer[k][o] = !!value; } break; case 'portrait': answer = answer.map((row) => { row[o] = !value; return row; }); if (o >= 0) { answer[k][o] = !!value; } break; default: } form.setFieldsValue({ [`answer.questions[${index}].double`]: answer }); } submit() { const { form } = this.props; const fields = ['id', 'questionType', 'place', 'difficult', 'difficultScore', 'content', 'answer', 'stem', 'keyword', 'questionNoIds', 'officialContent', 'qxContent', 'associationContent']; form.validateFields(fields, (err) => { if (!err) { const data = form.getFieldsValue(fields); let handler; data.associationContent = this.state.associationContentQuestionNos.map(row => row.id); data.stem = data.stem || ''; data.description = (data.stem || '').replace(/<[^>]+>/g, ''); data.qxContent = data.qxContent || ''; data.officialContent = data.officialContent || ''; data.content = data.content || {}; data.content.questions = (data.content.questions || []).map(row => { delete row.keys; row.select = (row.select || []).filter(r => r); return row; }); data.answer = data.answer || {}; data.answer.questions = (data.answer.questions || []).map(row => { if (row.single) row.single = row.single.filter(r => r); if (row.double) row.double = row.double.filter(r => r); return row; }); data.relationQuestion = this.state.realtionQuestionNos.map(row => row.id); if (!data.id) { handler = Question.add(data); } else { handler = Question.edit(data); } handler.then((result) => { asyncSMessage('保存成功'); if (data.id) { linkTo(`/subject/question/${data.id}`); } else { linkTo(`/subject/question/${result.id}`); } }).catch((e) => { if (e.result) form.setFields(formatFormError(data, e.result)); }); } }); } searchStem() { const { form } = this.props; const content = (form.getFieldValue('stem') || '').replace(/<[^>]+>/g, ''); Question.searchStem({ content }) .then(result => { if (result.list.length > 0) { asyncGet(() => import('../../../components/SimilarQuestionNo'), { title: '找到可匹配题目', questionNos: result.list, modal: true }, (questionNo) => { this.inited = false; linkTo(`/subject/question/${questionNo.questionId}`); return Promise.resolve(); }); } else { asyncSMessage('无可匹配题目', 'warn'); } }); } bindAssociationContent(associationContent) { generateSearch('associationContent', { mode: 'multiple' }, this, (search) => { return this.searchQuestion(search); }, (row) => { return { title: row.title, value: row.id, }; }, associationContent, null); if (associationContent) this.listQuestion(associationContent, 'ids', 'associationContentQuestionNos'); } bindRelationQuestion(relationQuestion) { generateSearch('relationQuestion', { mode: 'multiple' }, this, (search) => { return this.searchQuestion(search); }, (row) => { return { title: row.title, value: row.id, }; }, relationQuestion, null); if (relationQuestion) this.listQuestion(relationQuestion, 'ids', 'realtionQuestionNos'); } listQuestion(values, field, targetField) { if (!values || values.length === 0) { this.setState({ [targetField]: [] }); return; } this.setState({ [`${targetField}Loading`]: true }); Question.listNo({ [field]: values }).then(result => { const map = getMap(result, 'id'); const questionNos = values.map(row => map[row]).filter(row => row); this.setState({ [targetField]: questionNos, [`${targetField}Loading`]: false }); }); } searchQuestion(params) { return Question.searchNo(params); } renderBase() { const { getFieldDecorator } = this.props.form; return <Block flex> <h1>题干信息</h1> <Form> {getFieldDecorator('id')(<input hidden />)} {getFieldDecorator('stem', { })( <Editor modules={{ toolbar: { container: [ ['image', 'table', 'select'], [{ header: '1' }, { header: '2' }], ['bold', 'underline', 'blockquote'], [{ color: ['red', 'green', 'blue', 'orange', 'violet', '#d0d1d2', 'black'] }], [{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }], ], handlers: { table: (quill) => { const range = quill.getSelection(true); quill.insertText(range.index, '#table#'); }, select: (quill) => { const range = quill.getSelection(true); quill.insertText(range.index, '#select#'); }, }, }, }} placeholder='请输入内容' onUpload={(file) => System.uploadImage(file)} />, )} <Button style={{ marginBottom: '10px', marginTop: '10px' }} onClick={() => { this.searchStem(); }}>查询相似</Button> <Row> <Col span={12}> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='递进层次'> {getFieldDecorator('content.step', { normalize: (value, preValue) => { if (value === undefined || value === '' || value === null) return preValue; if (Math.abs(value - preValue) > 1) return preValue; return value; }, })( <InputNumber defaultValue={0} min={1} max={10} placeholder='输入数量' />, )} </Form.Item> </Col> <Col span={12}> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='折叠表格'> <Col span={1}>行</Col> <Col span={9} offset={1}> {getFieldDecorator('content.table.row')( <InputNumber placeholder='行' defaultValue={0} precision={0} min={0} />, )} </Col> <Col span={1} offset={1}>列</Col> <Col span={9} offset={1}> {getFieldDecorator('content.table.col')( <InputNumber placeholder='列' defaultValue={0} precision={0} min={0} />, )} </Col> </Form.Item> </Col> </Row> {this.renderTable()} </Form> </Block>; } renderTable() { const { getFieldDecorator, getFieldValue } = this.props.form; const row = Number(getFieldValue('content.table.row')); const col = Number(getFieldValue('content.table.col')); const table = []; if (row === 0 || col === 0) return table; const span = 100 / col; const colums = []; for (let i = 0; i < col; i += 1) { colums.push(<div style={{ width: `${span}%` }} className='table-col'>{getFieldDecorator(`content.table.header[${i}]`)(<Input size='small' />)}</div>); } table.push(<Row style={{ width: '100%' }} className='table-header' gutter={10}>{colums}</Row>); for (let index = 0; index < row; index += 1) { const cols = []; for (let i = 0; i < col; i += 1) { cols.push(<div style={{ width: `${span}%` }} className='table-col'>{getFieldDecorator(`content.table.data[${index}][${i}]`)(<Input size='small' />)}</div>); } table.push(<Row style={{ width: '100%' }} gutter={10}>{cols}</Row>); } return table; } renderStep() { const { getFieldDecorator, getFieldValue } = this.props.form; const number = getFieldValue('content.step'); const result = []; for (let index = 0; index < Number(number); index += 1) { result.push(<Block flex> <h1>递进层次 {index + 1}</h1> <Form> <Form.Item> {getFieldDecorator(`content.steps[${index}].title`, { rules: [ { required: true, message: '请输入标题' }, ], })( <Input placeholder='请输入标题' />, )} </Form.Item> <Form.Item> {getFieldDecorator(`content.steps[${index}].stem`, { })( <Editor placeholder='请输入内容' />, )} </Form.Item> </Form> </Block>); } return result; } renderIdentity() { const { questionNos = [] } = this.state; const { getFieldDecorator } = this.props.form; return <Block flex> <h1>题目身份</h1> <Form> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 17 }} label='请输入题目id'> {getFieldDecorator('questionNoIds', { rules: [{ required: true, message: '添加关联题目ID', }], })(<input hidden />)} {questionNos.map((no, index) => { return <Tag key={index} closable onClose={() => { this.removeNo(no.id); }}> {no.title} </Tag>; })} <Row> <Col span={14}> <Form.Item> {getFieldDecorator('moduleStruct', { rules: [{ required: true, message: '选择题目编号关系', }], })(<Cascader fieldNames={{ label: 'title', value: 'value', children: 'children' }} onClick={(value) => { this.setState({ moduleStruct: value }); }} placeholder='选择' options={this.state.moduleStructData} />)} </Form.Item> </Col> <Col span={4} offset={1}> <Form.Item> {getFieldDecorator('questionNo', { rules: [{ required: true, message: '输入编号', }], })(<InputNumber placeholder='题目id' onClick={(value) => { this.setState({ questionNo: value }); }} />)} </Form.Item> </Col> <Col span={4} offset={1}> <Button size='small' onClick={() => { this.addNo(); }}><Icon type='plus' /></Button> </Col> </Row> </Form.Item> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label={'关键词'}> {getFieldDecorator('keyword')( <Select mode='tags' maxTagCount={200} notFoundContent={null} placeholder='输入多个关键词, 逗号分隔' tokenSeparators={[',', ',']} />, )} </Form.Item> </Form> </Block>; } renderAttr() { const { getFieldDecorator, getFieldValue, setFieldsValue } = this.props.form; // const { questionNos = [] } = this.state; const isRc = getFieldValue('questionType') === 'rc'; const rcType = getFieldValue('rcType') || false; return <Block flex> <h1>题目属性</h1> <Form> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'> {getFieldDecorator('questionType', { rules: [ { required: true, message: '请选择题型' }, ], })( <Select select={QuestionType} placeholder='请选择题型' onChange={(v) => { this.refreshPlace(v); this.refreshDifficultScore(v, getFieldValue('difficult')); }} />, )} </Form.Item> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='考点'> {getFieldDecorator('place', { rules: [ { required: true, message: '请选择考点' }, ], })( <Select select={this.state.placeList} placeholder='请选择考点' />, )} </Form.Item> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='难度'> {getFieldDecorator('difficult', { rules: [ { required: true, message: '请选择难度' }, ], })( <Select select={QuestionDifficult} placeholder='请选择难度' onChange={(v) => { this.refreshDifficultScore(getFieldValue('questionType'), v); }} />, )} </Form.Item> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='难度分'> {getFieldDecorator('difficultScore', { rules: [ { required: true, message: '请选择难度分' }, ], })( <Select select={this.state.difficultScore} placeholder='请选择难度分' />, )} </Form.Item> {/* 阅读题,并且只有一个id才能关联 */} {isRc && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='阅读题模式' > {getFieldDecorator('rcType', { valuePropName: 'checked', })( <Switch checkedChildren='on' unCheckedChildren='off' />, )} </Form.Item>} {rcType && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='关联题目'> {getFieldDecorator('relationQuestion', { rules: [{ required: true, message: '请输入关联题目', }], })( <Select mode='multiple' maxTagCount={200} notFoundContent={null} placeholder='输入题目id, 逗号分隔' tokenSeparators={[',', ',']} {...this.state.relationQuestion} onChange={(values) => { this.listQuestion(values, 'ids', 'relationQuestionNos'); // this.setState({ relationQuestion: values }); }} />, )} <QuestionNoList type='inline' loading={this.state.relationQuestionNosLoading} questionNos={this.state.relationQuestionNos} onChange={(nos) => { getFieldDecorator('relationQuestion'); setFieldsValue({ relationQuestion: nos.map(row => row.id) }); this.setState({ relationQuestionNos: nos }); }} render={(row, dragClass, close) => { return <Tag className={dragClass} closable onClose={() => { close(); }}> {row.title} </Tag>; }} /> </Form.Item>} </Form> </Block>; } renderStyle() { const { getFieldDecorator } = this.props.form; return <Block flex> <h1>题目样式</h1> <Form> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='选项类型'> {getFieldDecorator('content.type', { rules: [ { required: true, message: '请选择类型' }, ], })( <Select select={QuestionStyleType} placeholder='请选择类型' onChange={(type) => { this.changeType(type); }} />, )} </Form.Item> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目数量'> {getFieldDecorator('content.number', { normalize: (value, preValue) => { if (value === undefined || value === '' || value === null) return preValue; if (Math.abs(value - preValue) > 1) return preValue; return value; }, })( <InputNumber defaultValue={1} min={1} max={10} placeholder='请输入数量' />, )} </Form.Item> <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='排版方式'> {getFieldDecorator('content.typeset')( <Radio.Group defaultValue='one'> <Radio value='one'>单排</Radio> <Radio value='two'>双排</Radio> </Radio.Group>, )} </Form.Item> </Form> </Block>; } renderSelect() { const { getFieldDecorator, getFieldValue } = this.props.form; const number = getFieldValue('content.number'); const type = getFieldValue('content.type'); const result = []; let handler = null; switch (type) { case 'single': handler = (index) => this.renderSelectSingle(index); break; case 'double': handler = (index) => this.renderSelectDouble(index); break; case 'inline': handler = (index) => this.renderSelectInline(index); break; default: } for (let index = 0; index < Number(number); index += 1) { result.push(<Block flex className={type}> <h1>选项信息({QuestionStyleTypeMap[type]})</h1> <Form> {type !== 'inline' && ( <Form.Item> {getFieldDecorator(`content.questions[${index}].description`, { })( <Editor placeholder='选项问题说明' />, )} </Form.Item> )} {handler(index)} </Form> </Block>); } return result; } renderSelectSingle(index) { const { getFieldDecorator, getFieldValue } = this.props.form; getFieldDecorator(`content.questions[${index}].keys`); const keys = getFieldValue(`content.questions[${index}].keys`) || []; return [ <DragList loading={false} dataSource={keys || []} handle={'.icon'} onMove={(oldIndex, newIndex) => { this.orderQuestion(index, oldIndex, newIndex); }} renderItem={(k) => ( <List.Item actions={[<Icon type='bars' className='icon' />]}> <Row key={k} style={{ width: '100%' }}> <Col span={1}> {getFieldDecorator(`answer.questions[${index}].single[${k}]`, { valuePropName: 'checked', })( <Checkbox onChange={(e) => { this.changeQuestion(index, k, e.target.checked); }} />, )} </Col> <Col span={23}> <Form.Item key={k} hidden > {getFieldDecorator(`content.questions[${index}].select[${k}]`, { rules: [{ required: true, whitespace: true, message: '请填写选项信息', }], })( <Input />, )} {keys.length > 1 ? ( <Icon type='minus-circle-o' disabled={keys.length === 1} onClick={() => this.removeQuestion(index, k)} /> ) : null} </Form.Item> </Col> </Row> </List.Item> )} />, <Form.Item> <Button type='dashed' onClick={() => this.addQuestion(index)} > <Icon type='plus' /> 新增 </Button> </Form.Item>, ]; } renderSelectDouble(index) { const { getFieldDecorator, getFieldValue } = this.props.form; getFieldDecorator(`content.questions[${index}].keys`); const keys = getFieldValue(`content.questions[${index}].keys`) || []; return [ <Form.Item className='no-validate' labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='单选方向'> {getFieldDecorator(`content.questions[${index}].direction`)( <Select select={QuestionRadioDirection} placeholder='请选择方向' onChange={(value) => { keys.forEach((k) => this.changeDouble(index, k, -1, value)); }} />, )} </Form.Item>, <List.Item actions={[<Icon type='bars' style={{ display: 'none' }} className='icon' />]}><Row style={{ width: '100%' }}> <Col span={4}> {getFieldDecorator(`content.questions[${index}].first`)( <Input placeholder='选项一' />, )} </Col> <Col span={4} offset={1}> {getFieldDecorator(`content.questions[${index}].second`)( <Input placeholder='选项二' />, )} </Col> </Row></List.Item>, <DragList loading={false} dataSource={keys.map(key => { return { key, }; }) || []} rowKey={'key'} handle={'.icon'} onMove={(oldIndex, newIndex) => { this.orderQuestion(index, oldIndex, newIndex); }} renderItem={({ key }) => { return <List.Item actions={[<Icon type='bars' className='icon' />]}> <Row style={{ width: '100%' }}> <Col span={4}> {getFieldDecorator(`answer.questions[${index}].double[${key}][0]`, { valuePropName: 'checked', })( <Checkbox onChange={(e) => { this.changeDouble(index, key, 0, e.target.checked); }} />, )} </Col> <Col span={4} offset={1}> {getFieldDecorator(`answer.questions[${index}].double[${key}][1]`, { valuePropName: 'checked', })( <Checkbox onChange={(e) => { this.changeDouble(index, key, 1, e.target.checked); }} />, )} </Col> <Col span={14} offset={1}> <Form.Item key={key} hidden > {getFieldDecorator(`content.questions[${index}].select[${key}]`, { rules: [{ required: true, whitespace: true, message: '请填写选项信息', }], })( <Input />, )} {keys.length > 1 ? ( <Icon type='minus-circle-o' disabled={keys.length === 1} onClick={() => this.removeQuestion(index, key)} /> ) : null} </Form.Item> </Col> </Row> </List.Item>; }} />, <Form.Item> <Button type='dashed' onClick={() => this.addQuestion(index)} > <Icon type='plus' /> 新增 </Button> </Form.Item>, ]; } renderSelectInline(index) { return this.renderSelectSingle(index); } renderOffical() { const { getFieldDecorator } = this.props.form; return <Block flex> <Form> <Form.Item label='官方解析'> {getFieldDecorator('officialContent', { })( <Editor placeholder='输入内容' />, )} </Form.Item> </Form> </Block>; } renderQX() { const { getFieldDecorator } = this.props.form; return <Block flex> <Form> <Form.Item label='千行解析'> {getFieldDecorator('qxContent', { })( <Editor placeholder='输入内容' />, )} </Form.Item> </Form> </Block>; } renderAssociation() { const { getFieldDecorator, setFieldsValue } = this.props.form; return <Block flex> <h1>题源联想</h1> <Form> <Form.Item> {getFieldDecorator('associationContent')( <Select mode='multiple' maxTagCount={200} notFoundContent={null} placeholder='输入题目id, 逗号分隔' tokenSeparators={[',', ',']} {...this.state.associationContent} onChange={(values) => { this.listQuestion(values, 'ids', 'associationContentQuestionNos'); // this.setState({ associationContent: values }); }} />, )} </Form.Item> <QuestionNoList loading={this.state.associationContentQuestionNosLoading} questionNos={this.state.associationContentQuestionNos} onChange={(nos) => { getFieldDecorator('associationContent'); setFieldsValue({ associationContent: nos.map(row => row.id) }); this.setState({ associationContentQuestionNos: nos }); }} /> </Form> </Block>; } renderTab() { return <Tabs activeKey='base' onChange={(tab) => { switch (tab) { case 'sentence': linkTo('/subject/sentence/question'); break; case 'textbook': linkTo('/subject/textbook/question'); break; default: } }}> <Tabs.TabPane key='base' tab='考试题型' /> <Tabs.TabPane key='sentence' tab='长难句' /> <Tabs.TabPane key='textbook' tab='数学机经' /> </Tabs>; } renderView() { return <div flex > {this.renderTab()} {this.renderBase()} {this.renderStep()} {this.renderIdentity()} {this.renderAttr()} {this.renderStyle()} {this.renderSelect()} {this.renderOffical()} {this.renderQX()} {this.renderAssociation()} <Row type="flex" justify="center"> <Col> <Button type="primary" onClick={() => { this.submit(); }}>保存</Button> </Col> </Row> </div>; } }