From d98b959a80c6b58f15e854b2c2d60df57e1039d2 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Fri, 27 Mar 2020 10:58:20 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=AF=95=E5=8D=B7?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/examination_banks_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/examination_banks_controller.rb b/app/controllers/examination_banks_controller.rb index 4cb25aa29..96cab6b7f 100644 --- a/app/controllers/examination_banks_controller.rb +++ b/app/controllers/examination_banks_controller.rb @@ -52,7 +52,7 @@ class ExaminationBanksController < ApplicationController end def destroy - tip_exception(403, "无权限") unless current_user.admin? || @item.user == current_user + tip_exception(403, "无权限") unless current_user.admin? || @exam.user == current_user ActiveRecord::Base.transaction do ApplyAction.where(container_type: "ExaminationBank", container_id: @exam.id).destroy_all @exam.destroy! From b46e7f0887018ad52424e90c5ef5108dd970c5ce Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Fri, 27 Mar 2020 11:27:42 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/exercises_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index b96ab0d4b..9c8947fdb 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -137,7 +137,7 @@ class ExercisesController < ApplicationController :course_id => @course.id, :time => -1, :exercise_status => 1, - :is_md => params[:md] + :is_md => params[:is_md] } @exercise = Exercise.create!(exercise_options) end From 424e54b5b6d4a5c2e1fe55b98216c959a69ac3c7 Mon Sep 17 00:00:00 2001 From: harry Date: Fri, 27 Mar 2020 13:22:56 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E8=AF=95=E5=8D=B7=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/components/custom-editor/index.jsx | 0 .../common/components/markdown/DMDEditor.js | 60 ++-- .../src/common/quillForEditor/ImageBlot.js | 26 +- .../react/src/common/quillForEditor/index.js | 277 +++++++---------- .../courses/exercise/ExerciseNewCommon.js | 11 +- .../exercise/exercise-new-form/index.jsx | 8 +- .../exercise/exercise-new-form/index.scss | 8 +- .../courses/exercise/new/ShixunEditor.js | 19 +- .../courses/exercise/new/SingleEditor.js | 283 +++++++----------- 9 files changed, 256 insertions(+), 436 deletions(-) create mode 100644 public/react/src/common/components/custom-editor/index.jsx diff --git a/public/react/src/common/components/custom-editor/index.jsx b/public/react/src/common/components/custom-editor/index.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/public/react/src/common/components/markdown/DMDEditor.js b/public/react/src/common/components/markdown/DMDEditor.js index 7091adf00..c109e956c 100644 --- a/public/react/src/common/components/markdown/DMDEditor.js +++ b/public/react/src/common/components/markdown/DMDEditor.js @@ -1,74 +1,58 @@ -import React,{ Component } from "react"; +import React, { Component } from "react"; import TPMMDEditor from '../../../modules/tpm/challengesnew/TPMMDEditor' -import {markdownToHTML} from 'educoder' +import { markdownToHTML } from 'educoder' import './DMDEditor.css' // 需要父组件通过toShowMode、toMDMode 来控制,一次只能打开一个DMDEditor -class DMDEditor extends Component{ - constructor(props){ +class DMDEditor extends Component { + constructor(props) { super(props); this.mdRef = React.createRef() - this.state={ - mdMode: false, - // value: this.props.initValue + this.state = { + mdMode: false, } } - componentDidUpdate(prevProps, prevState) { - - } - componentDidMount() { - // if(this.props.initValue != this.mdRef.current.getValue()) { - // this.mdRef.current.setValue(this.props.initValue) - // } - } - - + toMDMode = () => { - this.setState({mdMode: true}, () => { - this.mdRef.current.resize() - this.mdRef.current.setValue(this.props.initValue) + this.setState({ mdMode: true }, () => { + this.mdRef.current.resize() + this.mdRef.current.setValue(this.props.initValue) }) - this.props.toMDMode(this) + this.props.toMDMode(this) } toShowMode = () => { - this.setState({mdMode: false}) + this.setState({ mdMode: false }) this.props.toShowMode && this.props.toShowMode(this) } onCMBlur = () => { - this.toShowMode() + this.toShowMode() } onChange = (val) => { - // this.setState({ value: val }) this.props.onChange(val) if (this.state.showError == true) { - this.setState({showError: false}) + this.setState({ showError: false }) } } showError = () => { this.mdRef.current.showError() - this.setState({showError: true}) + this.setState({ showError: true }) } - render(){ + render() { const { mdMode, showError } = this.state; const { initValue } = this.props; let _style = {} if (showError) { - _style.border = '1px solid red' + _style.border = '1px solid red' } - _style = Object.assign(_style, {display: mdMode == true ? 'none' : '', color: initValue? '': '#999', alignItems: 'center', wordBreak: 'break-all'}) - return( + _style = Object.assign(_style, { display: mdMode == true ? 'none' : '', color: initValue ? '' : '#999', alignItems: 'center', wordBreak: 'break-all' }) + return ( -
- {/* - onCMBlur={this.onCMBlur} */} { - // value.onClick && value.onClick(value.url); - // } + if (value.onclick) { + node.addEventListener('click', () => { + value.onClick(value.url) + }) + } return node; } diff --git a/public/react/src/common/quillForEditor/index.js b/public/react/src/common/quillForEditor/index.js index 7f0e56e86..d5376fb46 100644 --- a/public/react/src/common/quillForEditor/index.js +++ b/public/react/src/common/quillForEditor/index.js @@ -1,30 +1,24 @@ -/* - * @Description: quill 编辑器 - * @Author: tangjiang - * @Github: - * @Date: 2019-12-18 08:49:30 - * @LastEditors : tangjiang - * @LastEditTime : 2020-02-05 11:23:03 - */ -import './index.scss'; -import 'quill/dist/quill.core.css'; // 核心样式 -import 'quill/dist/quill.snow.css'; // 有工具栏 -import 'quill/dist/quill.bubble.css'; // 无工具栏 -import 'katex/dist/katex.min.css'; // katex 表达式样式 +import './index.scss' +import 'quill/dist/quill.core.css' // 核心样式 +import 'quill/dist/quill.snow.css' // 有工具栏 +import 'quill/dist/quill.bubble.css' // 无工具栏 +import 'katex/dist/katex.min.css' // katex 表达式样式 import './font.css' -import React, { useState, useRef, useEffect } from 'react'; -import Quill from 'quill'; -import katex from 'katex'; -import deepEqual from './deepEqual.js' -import { fetchUploadImage } from '../../services/ojService.js'; +import React, { useState, useRef, useEffect } from 'react' +import Quill from 'quill' +import katex from 'katex' + +import { fetchUploadImage } from '../../services/ojService.js' import { getImageUrl } from 'educoder' -import ImageBlot from './ImageBlot'; -import FillBlot from './FillBlot'; +import ImageBlot from './ImageBlot' +import FillBlot from './FillBlot' import LinkBlot from './link-blot' -var Size = Quill.import('attributors/style/size'); -Size.whitelist = ['14px', '16px', '18px', '20px', false]; -var fonts = ['Microsoft-YaHei', 'SimSun', 'SimHei', 'KaiTi', 'FangSong']; -var Font = Quill.import('formats/font'); + +let Size = Quill.import('attributors/style/size') +Size.whitelist = ['14px', '16px', '18px', '20px', false] +let fonts = ['Microsoft-YaHei', 'SimSun', 'SimHei', 'KaiTi', 'FangSong'] +let Font = Quill.import('formats/font') + Font.whitelist = fonts; //将字体加入到白名单 window.Quill = Quill; window.katex = katex; @@ -32,14 +26,12 @@ Quill.register(ImageBlot); Quill.register(Size); Quill.register(LinkBlot); Quill.register(Font, true); -// Quill.register({'modules/toolbar': Toolbar}); + Quill.register({ 'formats/fill': FillBlot -}); -// Quill.register(Color); +}) - -function QuillForEditor({ +export default ({ placeholder, readOnly, autoFocus = false, @@ -52,41 +44,23 @@ function QuillForEditor({ onContentChange, addFill, // 点击填空成功的回调 deleteFill // 删除填空,返回删除的下标 -}) { - // toolbar 默认值 - const defaultConfig = [ +}) => { + const defaultToolBarOptions = [ 'bold', 'italic', 'underline', - { size: ['14px', '16px', '18px', '20px'] }, - { align: [] }, { list: 'ordered' }, { list: 'bullet' }, // 列表 + { align: [] }, { list: 'ordered' }, { list: 'bullet' }, { script: 'sub' }, { script: 'super' }, { 'color': [] }, { 'background': [] }, { 'font': [] }, - { header: [1, 2, 3, 4, 5, false] }, - 'blockquote', 'code-block', - 'link', 'image', 'video', + 'blockquote', 'link', 'image', 'video', 'formula', 'clean' - ]; - - const editorRef = useRef(null); + ] + const editorRef = useRef(null) // quill 实例 - const [quill, setQuill] = useState(null); - const [selection, setSelection] = useState(null); - const [fillCount, setFillCount] = useState(0); - const [quillCtx, setQuillCtx] = useState({}); - - // 文本内容变化时 - const handleOnChange = content => { - onContentChange && onContentChange(content, quill); - }; - - const renderOptions = options || defaultConfig; + const [quill, setQuill] = useState(null) + const [fillCount, setFillCount] = useState(0) const bindings = { - tab: { - key: 9, - handler: function () { } - }, backspace: { key: 'Backspace', /** @@ -97,186 +71,139 @@ function QuillForEditor({ * @param {*} context 上下文 */ handler: function (range, context) { - /** - * index: 删除元素的位置 - * length: 删除元素的个数 - */ - const { index, length } = range; - const _start = length === 0 ? index - 1 : index; - const _length = length || 1; - let delCtx = this.quill.getText(_start, _length); // 删除的元素 + const { index, length } = range + const _start = length === 0 ? index - 1 : index + const _length = length || 1 + let delCtx = this.quill.getText(_start, _length) const reg = /▁/g; - const delArrs = delCtx.match(reg); + const delArrs = delCtx.match(reg) if (delArrs) { - const r = window.confirm('确定要删除吗?'); + const r = window.confirm('确定要删除吗?') if (r) { - let leaveCtx; // 获取删除元素之前的内容 + let leaveCtx = this.quill.getText(0, index) // 获取删除元素之前的内容 if (length === 0) { - leaveCtx = this.quill.getText(0, index - 1); - } else { - leaveCtx = this.quill.getText(0, index); + leaveCtx = this.quill.getText(0, index - 1) } - const leaveArrs = leaveCtx.match(reg); - const leaveLen = (leaveArrs || []).length; - let delIndexs = []; + const leaveArrs = leaveCtx.match(reg) + const leaveLen = (leaveArrs || []).length + let delIndexs = [] // 获取删除元素的下标 delArrs.forEach((item, i) => { - leaveLen === 0 ? delIndexs.push(i) : delIndexs.push(leaveLen + i); + leaveLen === 0 ? delIndexs.push(i) : delIndexs.push(leaveLen + i) }); - deleteFill && deleteFill(delIndexs); // 调用删除回调, 返回删除的元素下标[] + deleteFill && deleteFill(delIndexs) // 调用删除回调, 返回删除的元素下标[] return true } else { - return false; + return false } } - return true; + return true } } - }; - // quill 配置信息 + } const quillOption = { modules: { - toolbar: renderOptions, + toolbar: options || defaultToolBarOptions, keyboard: { bindings: bindings } - // toolbar: { - // container: renderOptions - // } }, readOnly, placeholder, theme: readOnly ? 'bubble' : 'snow', - }; + } useEffect(() => { - - const quillNode = document.createElement('div'); - editorRef.current.appendChild(quillNode); - const _quill = new Quill(editorRef.current, quillOption); - - setQuill(_quill); + const quillInstance = new Quill(editorRef.current, quillOption) + setQuill(quillInstance) // 处理图片上传功能 - _quill.getModule('toolbar').addHandler('image', (e) => { - const input = document.createElement('input'); - input.setAttribute('type', 'file'); - input.setAttribute('accept', 'image/*'); - input.click(); - + quillInstance.getModule('toolbar').addHandler('image', (e) => { + const input = document.createElement('input') + input.setAttribute('type', 'file') + input.setAttribute('accept', 'image/*') + input.click() input.onchange = async (e) => { - const file = input.files[0]; // 获取文件信息 - const formData = new FormData(); - formData.append('file', file); + const file = input.files[0] // 获取文件信息 + const formData = new FormData() + formData.append('file', file) + + const range = quillInstance.getSelection(true) + let fileUrl = '' // 保存上传成功后图片的url - const range = _quill.getSelection(true); - let fileUrl = ''; // 保存上传成功后图片的url - // 上传文件 - const result = await fetchUploadImage(formData); + const result = await fetchUploadImage(formData) // 获取上传图片的url if (result.data && result.data.id) { - fileUrl = getImageUrl(`api/attachments/${result.data.id}`); + fileUrl = getImageUrl(`api/attachments/${result.data.id}`) } - // 根据id获取文件路径 - const { width, height } = imgAttrs; - // console.log('上传图片的url:', fileUrl); + const { width, height } = imgAttrs if (fileUrl) { - _quill.insertEmbed(range.index, 'image', { + let imgOption = { url: fileUrl, alt: '图片信息', - onClick: showUploadImage, width, height - }); + } + if (showUploadImage) { + imgOption.onClick = showUploadImage + } + quillInstance.insertEmbed(range.index, 'image', imgOption) } } - }); + }) // 处理填空 - _quill.getModule('toolbar').addHandler('fill', (e) => { - // alert(1111); + quillInstance.getModule('toolbar').addHandler('fill', (e) => { setFillCount(fillCount + 1); - const range = _quill.getSelection(true); - _quill.insertText(range.index, '▁'); + const range = quillInstance.getSelection(true); + quillInstance.insertText(range.index, '▁'); addFill && addFill(); // 调用添加回调 - }); - }, []); + }) + }, []) - // 设置值 useEffect(() => { - if (!quill) return - - const previous = quill.getContents() - - if (value && value.hasOwnProperty('ops')) { - // console.log(value.ops); - try { - const ops = value.ops || []; - ops.forEach((item, i) => { - if (item.insert['image']) { - item.insert['image'] = Object.assign({}, item.insert['image'], { style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url) }); - } - }); - }catch (e) { - - } - } - - const current = value - if (!deepEqual(previous, current)) { - setSelection(quill.getSelection()) - if (typeof value === 'string' && value) { - // debugger - quill.clipboard.dangerouslyPasteHTML(value, 'api'); - if (autoFocus) { - quill.focus(); - } else { - quill.blur(); - } - } else { + if (quill) { + if (value && value.hasOwnProperty('ops')) { quill.setContents(value) - if (autoFocus) quill.focus(); + } else { + quill.pasteHTML(value) } } - }, [quill, value, setQuill, autoFocus]); + }, [quill, value]) - // 清除选择区域 useEffect(() => { - if (quill && selection) { - quill.setSelection(selection) - setSelection(null) + if (quill) { + quill.root.dataset.placeholder = placeholder; } - }, [quill, selection, setSelection]); + }, [quill, placeholder]) - // 设置placeholder值 useEffect(() => { - if (!quill || !quill.root) return; - quill.root.dataset.placeholder = placeholder; - }, [quill, placeholder]); + if (quill) { + autoFocus ? quill.focus() : quill.blur() + } + }, [quill, autoFocus]) - // 处理内容变化 useEffect(() => { - if (!quill) return; - if (typeof handleOnChange !== 'function') return; - let handler; - quill.on( - 'text-change', - (handler = (delta, oldDelta, source) => { - const _ctx = quill.getContents(); - setQuillCtx(_ctx); - handleOnChange(quill.getContents()); // getContents: 检索编辑器内容 - }) - ); - return () => { - quill.off('text-change', handler); + if (quill && onContentChange) { + function onChangeHandler() { + let html = editorRef.current.children[0].innerHTML + let text = quill.getText() + if (html === '


') html = '' + if (onContentChange) { + onContentChange(quill.getContents(), quill, html, text) + } + } + quill.on('text-change', onChangeHandler) + return () => { + quill.off('text-change', onChangeHandler) + } } - }, [quill, handleOnChange]); + }, [quill, onContentChange]) // 返回结果 return (
- ); + ) } -export default QuillForEditor; diff --git a/public/react/src/modules/courses/exercise/ExerciseNewCommon.js b/public/react/src/modules/courses/exercise/ExerciseNewCommon.js index 677a09f8f..7bf8eeb0c 100644 --- a/public/react/src/modules/courses/exercise/ExerciseNewCommon.js +++ b/public/react/src/modules/courses/exercise/ExerciseNewCommon.js @@ -75,12 +75,8 @@ class ExerciseNewCommon extends Component { axios.get(url) .then((response) => { if (response.data.exercise) { - const { exercise, ...others } = response.data - exercise.exercise_name = exercise.exercise_name || exercise.name - exercise.exercise_description = exercise.exercise_description || exercise.description this.setState({ - ...exercise, - ...others, + ...response.data, editMode: false }) this.props.initData && this.props.initData(response.data) @@ -397,6 +393,7 @@ class ExerciseNewCommon extends Component { getAddQuestionUrl: this.getAddQuestionUrl, getEditQuestionUrl: this.getEditQuestionUrl, exercise_url: this.props.exercise_url, + is_md } console.log(this.props) console.log(this.state) @@ -422,10 +419,10 @@ class ExerciseNewCommon extends Component { `} - {!this.state.editMode &&
+ {!this.state.editMode &&
diff --git a/public/react/src/modules/courses/exercise/exercise-new-form/index.jsx b/public/react/src/modules/courses/exercise/exercise-new-form/index.jsx index 00b9aec90..1cbb0e676 100644 --- a/public/react/src/modules/courses/exercise/exercise-new-form/index.jsx +++ b/public/react/src/modules/courses/exercise/exercise-new-form/index.jsx @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import { Input, Form, Radio } from 'antd' +import { Input, Form, Radio, Button } from 'antd' import './index.scss' import { QuillForEditor } from 'educoder' import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor' @@ -90,8 +90,10 @@ export default ({ exercise_name = '', exercise_description, is_md, onSaveHandler - 保存 - {isEdit && 取消} +
+ + +
diff --git a/public/react/src/modules/courses/exercise/exercise-new-form/index.scss b/public/react/src/modules/courses/exercise/exercise-new-form/index.scss index e5188d2ff..987655d1e 100644 --- a/public/react/src/modules/courses/exercise/exercise-new-form/index.scss +++ b/public/react/src/modules/courses/exercise/exercise-new-form/index.scss @@ -12,12 +12,8 @@ width: 70px; } - .defalutCancelbtn { - height: '30px'; - width: '70px'; - font-size: '14px'; - line-height: '30px'; - margin-right: '16px'; + .btn-group { + text-align: right; } .editor-tip { diff --git a/public/react/src/modules/courses/exercise/new/ShixunEditor.js b/public/react/src/modules/courses/exercise/new/ShixunEditor.js index 6457d256b..130bb78f8 100644 --- a/public/react/src/modules/courses/exercise/new/ShixunEditor.js +++ b/public/react/src/modules/courses/exercise/new/ShixunEditor.js @@ -1,20 +1,12 @@ import React,{ Component } from "react"; -import { - Form, Input, InputNumber, Switch, Radio, - Slider, Button, Upload, Icon, Rate, Checkbox, message, - Row, Col, Select, Modal, Tooltip -} from 'antd'; +import { Input, InputNumber, Select, Modal } from 'antd'; import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor'; import axios from 'axios' import update from 'immutability-helper' import { qNameArray } from './common' -import {getUrl, ActionBtn, DMDEditor} from 'educoder'; -const { TextArea } = Input; -const confirm = Modal.confirm; -const $ = window.$ -const { Option } = Select; +import { ActionBtn} from 'educoder'; class ShixunEditor extends Component{ constructor(props){ @@ -91,18 +83,12 @@ class ShixunEditor extends Component{ const {question_title, question_scores, question_type, shixun_name } = this.state; const { question_id_to_insert_after, question_id , shixun_id } = this.props - // TODO check - - // if(!question_title) { - // this.props.showNotification('请先输入实训题完成要求'); return; - // } for(let _i = 0; _i < question_scores.length; _i++) { if (!question_scores[_i] || question_scores[_i] == '0') { this.props.showNotification(`第${_i+1}题的分值:必须大于0`); return; } } - /** { "question_title":"社会主义核心价值观是?.", @@ -250,7 +236,6 @@ class ShixunEditor extends Component{ this.setState({shixun_name: e.target.value})} style={{ marginBottom: '10px'}} > - {/*
{shixun_name}
*/} this.setState({ question_title: val})} noStorage={true} diff --git a/public/react/src/modules/courses/exercise/new/SingleEditor.js b/public/react/src/modules/courses/exercise/new/SingleEditor.js index 8585e0a82..ebd2787ba 100644 --- a/public/react/src/modules/courses/exercise/new/SingleEditor.js +++ b/public/react/src/modules/courses/exercise/new/SingleEditor.js @@ -1,28 +1,19 @@ -import React,{ Component } from "react"; +import React, { Component } from "react"; -import { - Form, Input, InputNumber, Switch, Radio, - Slider, Button, Upload, Icon, Rate, Checkbox, message, - Row, Col, Select, Modal, Tooltip -} from 'antd'; +import { InputNumber, Tooltip } from 'antd'; import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor'; import axios from 'axios' import update from 'immutability-helper' -import {getUrl, ActionBtn, DMDEditor, ConditionToolTip} from 'educoder'; +import { ActionBtn, DMDEditor, ConditionToolTip } from 'educoder'; import QuillForEditor from "../../../../common/quillForEditor"; -const { TextArea } = Input; -const confirm = Modal.confirm; -const $ = window.$ -const { Option } = Select; - const tagArray = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ] -class SingleEditor extends Component{ - constructor(props){ +class SingleEditor extends Component { + constructor(props) { super(props); /** choice_id: 32076 @@ -30,7 +21,7 @@ class SingleEditor extends Component{ choice_text: "1" standard_boolean: true */ - const {question_choices} = this.props; + const { question_choices } = this.props; let _standard_answers = undefined; let _question_choices = undefined; if (question_choices) { @@ -48,7 +39,6 @@ class SingleEditor extends Component{ question_title: this.props.question_title || '', question_type: this.props.question_type || 0, question_score: this.props.question_score || this.props.init_question_score, - choice_editor: 'md', quill_question_title: '', quill_default_title: '' } @@ -60,25 +50,25 @@ class SingleEditor extends Component{ this.setState({ question_choices, standard_answers }) } deleteOption = (index) => { - let {question_choices}=this.state; - if(question_choices[index]===""){ + let { question_choices } = this.state; + if (question_choices[index] === "") { // repeat code this.toMDMode(null) this.setState( (prevState) => ({ - question_choices : update(prevState.question_choices, {$splice: [[index, 1]]}), - standard_answers : update(prevState.standard_answers, {$splice: [[index, 1]]}) + question_choices: update(prevState.question_choices, { $splice: [[index, 1]] }), + standard_answers: update(prevState.standard_answers, { $splice: [[index, 1]] }) }) ) - }else{ + } else { this.props.confirm({ content: `确认要删除这个选项吗?`, onOk: () => { this.toMDMode(null) this.setState( (prevState) => ({ - question_choices : update(prevState.question_choices, {$splice: [[index, 1]]}), - standard_answers : update(prevState.standard_answers, {$splice: [[index, 1]]}) + question_choices: update(prevState.question_choices, { $splice: [[index, 1]] }), + standard_answers: update(prevState.standard_answers, { $splice: [[index, 1]] }) }) ) } @@ -86,11 +76,11 @@ class SingleEditor extends Component{ } } onSave = () => { - const {question_title, question_score, question_type, question_choices, standard_answers } = this.state; + const { question_title, question_score, question_choices, standard_answers } = this.state; const { question_id_to_insert_after, question_id } = this.props // TODO check - const answerArray = standard_answers.map((item, index) => { return item == true ? index+1 : -1 }).filter(item => item != -1); - if(!question_title) { + const answerArray = standard_answers.map((item, index) => { return item == true ? index + 1 : -1 }).filter(item => item != -1); + if (!question_title) { this.refs['titleEditor'].showError() this.props.showNotification('题目:不能为空'); return; @@ -100,18 +90,18 @@ class SingleEditor extends Component{ const intScore = parseFloat(question_score) if (intScore == 0) { this.props.showNotification('分值:必须大于0'); return; - } else if(!question_score || intScore == NaN) { + } else if (!question_score || intScore == NaN) { this.props.showNotification('分值:不能为空'); return; } - if(!answerArray || answerArray.length == 0) { + if (!answerArray || answerArray.length == 0) { this.props.showNotification('请先点击选择本选择题的正确选项'); return; } - if(!question_title) { + if (!question_title) { this.refs['titleEditor'].showError() this.props.showNotification('题目:不能为空'); return; } - for(let i = 0; i < question_choices.length; i++) { + for (let i = 0; i < question_choices.length; i++) { if (!question_choices[i]) { this.refs[`optionEditor${i}`].showError() this.props.showNotification(`请先输入 ${tagArray[i]} 选项的内容`); return; @@ -138,14 +128,14 @@ class SingleEditor extends Component{ }).then((response) => { if (response.data.status == 0) { this.props.addSuccess() - }else if(response.data.status == 3){ + } else if (response.data.status == 3) { // 已发布试卷编辑保存 - this.props.changeScore(question_id,answerArray); + this.props.changeScore(question_id, answerArray); } }) - .catch(function (error) { - console.log(error); - }); + .catch(function (error) { + console.log(error); + }); } else { const url = this.props.getAddQuestionUrl(); @@ -174,13 +164,7 @@ class SingleEditor extends Component{ - componentDidMount = () => { - - } onOptionClick = (index) => { - // if (this.props.exerciseIsPublish) { - // return; - // } let standard_answers = this.state.standard_answers.slice(0) standard_answers[index] = !standard_answers[index] this.setState({ standard_answers }) @@ -206,24 +190,6 @@ class SingleEditor extends Component{ this.mdReactObject = that; } - toShowMode = () => { - - } - - // 切换编辑器 - handleChangeEditor = (e) => { - const {quill_question_title} = this.state; - const value = e.target.value - if (value === 'quill') { - const _val = quill_question_title ? JSON.parse(quill_question_title) : ''; - this.setState({ - quill_default_title: _val - }) - } - this.setState({ - choice_editor: value - }); - } // quill编辑器内容变化时调用此接口 handleCtxChange = (ctx) => { @@ -235,37 +201,19 @@ class SingleEditor extends Component{ } render() { - let { question_title, question_score, question_type, question_choices, standard_answers, choice_editor, quill_default_title } = this.state; - let { question_id, index, exerciseIsPublish, - // question_title, - // question_type, - // question_score, - isNew } = this.props; - - // const { getFieldDecorator } = this.props.form; - - const isAdmin = this.props.isAdmin() - const courseId=this.props.match.params.coursesId; - const isEdit = !!this.props.question_id + let { question_title, question_score, question_choices, standard_answers, quill_default_title } = this.state; + let { index, exerciseIsPublish, is_md } = this.props; const qNumber = `question_${index}`; - // TODO show模式 isNew为false isEdit为false - - // [true, false, true] -> [0, 2] - const answerTagArray = standard_answers.map((item, index) => { return item == true ? tagArray[index] : -1 }).filter(item => item != -1); - console.log("xuanzheshijuan"); - console.log(answerTagArray); - console.log(!exerciseIsPublish); - return( -
- -

- {/* {!question_id ? '新建' : '编辑'} */} - 选择题 - (客观题,由系统自动评分,请设置标准答案) - {/* */} - {/*

- 切换编辑器: - - MD - Quill - -
*/} -

- - {choice_editor === 'md' - ? this.setState({ question_title: val})} - ref="titleEditor" - > - - : - } - - {question_choices.map( (item, index) => { - const bg = standard_answers[index] ? 'check-option-bg' : '' - return
- {/* 点击设置答案 */} - {/* TODO 加了tooltip后,会丢失掉span的class */} - {/* */} - this.onOptionClick(index)} style={{flex: '0 0 38px'}}> - -
{tagArray[index]}
-
-
- {/*
*/} -
- this.onOptionContentChange(value, index)} - initValue={item} - > -
- {exerciseIsPublish || index===0? - - : - this.deleteOption(index)}> - } - { !exerciseIsPublish && - this.addOption()} - style={{float: 'right', visibility: index == question_choices.length - 1 ? '' : 'hidden', marginTop: '2px'}} - > - } - -
- }) } +

+ 选择题 + (客观题,由系统自动评分,请设置标准答案) +

+ + {is_md ? this.setState({ question_title: val })} + ref="titleEditor" + > + + : + } -
- {'温馨提示:点击选项输入框可设置答案;选中的选项即为正确答案,选择多个答案即为多选题'} - { answerTagArray && !!answerTagArray.length ? - - {answerTagArray.join(' ')} - 标准答案: - - : - "" - } + {question_choices.map((item, index) => { + const bg = standard_answers[index] ? 'check-option-bg' : '' + return
+ {/* 点击设置答案 */} + this.onOptionClick(index)} style={{ flex: '0 0 38px' }}> + +
{tagArray[index]}
+
+
+
+ this.onOptionContentChange(value, index)} + initValue={item} + >
+ {exerciseIsPublish || index === 0 ? + + : + this.deleteOption(index)}> + } + {!exerciseIsPublish && + this.addOption()} + style={{ float: 'right', visibility: index == question_choices.length - 1 ? '' : 'hidden', marginTop: '2px' }} + > + } + +
+ })} + +
+ {'温馨提示:点击选项输入框可设置答案;选中的选项即为正确答案,选择多个答案即为多选题'} + {answerTagArray && !!answerTagArray.length ? + + {answerTagArray.join(' ')} + 标准答案: + + : + "" + } +
-
- 分值: -  分 +
+ 分值: +  分 - 取消 - 保存 - - -
+ 取消 + 保存 +
- ) - } + +
+ ) + } } // RouteHOC() export default (SingleEditor); From 1507701d3cddc25e3592367e2ba1b4028e3dff1d Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Fri, 27 Mar 2020 14:32:00 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/examination_banks_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/examination_banks_controller.rb b/app/controllers/examination_banks_controller.rb index 96cab6b7f..59b2876fe 100644 --- a/app/controllers/examination_banks_controller.rb +++ b/app/controllers/examination_banks_controller.rb @@ -3,7 +3,7 @@ class ExaminationBanksController < ApplicationController before_action :require_login before_action :certi_identity_auth, only: [:create, :edit, :update, :destroy, :set_public, :revoke_item, :cancel_items] before_action :find_exam, except: [:index, :create, :cancel_items] - before_action :edit_auth, only: [:update, :set_public, :revoke_item, :cancel_items] + before_action :edit_auth, only: [:update, :set_public, :revoke_item] before_action :identity_auth, only: [:index] def index