diff --git a/public/react/config/webpack.config.dev.js b/public/react/config/webpack.config.dev.js index 4e28af31f..d1092894a 100644 --- a/public/react/config/webpack.config.dev.js +++ b/public/react/config/webpack.config.dev.js @@ -30,7 +30,7 @@ const env = getClientEnvironment(publicUrl); module.exports = { // You may want 'eval' instead if you prefer to see the compiled output in DevTools. // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s - devtool: "cheap-module-eval-source-map", + //devtool: "cheap-module-eval-source-map", // 开启调试 //devtool: "source-map", // 开启调试 // These are the "entry points" to our application. diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css index 0b7f126be..7bda233fe 100644 --- a/public/react/public/css/edu-all.css +++ b/public/react/public/css/edu-all.css @@ -397,9 +397,9 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin- .task-colspan{min-width:25%;text-align: left;display: block;float: left;color: #999; } .colspan-grey{border-radius: 12px;background-color: #E6E6E6;padding: 3px 10px;color: #747A7F} /*新建任务*/ -.challenge_nav{padding: 40px 20px 0px 20px;border-bottom: 1px solid #eee;} -.challenge_nav li{width: auto;float: left;margin-right: 40px;position: relative} -.challenge_nav li.active:after{position: absolute;content: '';width: 50%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;} +.challenge_nav{padding: 20px 20px 0px 20px;border-bottom: 1px solid #eee;} +.challenge_nav li{width: auto;float: left;margin-right: 20px;position: relative} +.challenge_nav li.active:after{position: absolute;content: '';width: 76%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;} .challenge_nav li a{display: block;width: 100%;padding-bottom: 20px;} .add_choose_type{width: 60px;height: 20px;line-height: 19px;border-radius: 2px;background-color: #eaeaea;color: #999!important;display: block;float: left;text-align: center;margin-top: 4px;} diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js index 14981c363..f79301be0 100644 --- a/public/react/src/modules/tpm/TPMBanner.js +++ b/public/react/src/modules/tpm/TPMBanner.js @@ -130,16 +130,19 @@ class TPMBanner extends Component { if(this.props.status===0&&this.props.openknows===false){ if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 0 && this.props.identity < 5){ - if(shixunopenprocess===undefined||shixunopenprocess===false||shixunopenprocess===null){ - this.setState({ - openknow:true - }) - }else{ - this.setState({ - openknow:false - }) + if(this.props.user&&this.props.user.user_id){ + if(shixunopenprocess===undefined||shixunopenprocess===false||shixunopenprocess===null){ + this.setState({ + openknow:true + }) + }else{ + this.setState({ + openknow:false + }) + } } - } + } + }else{ this.setState({ openknow:false @@ -150,14 +153,16 @@ class TPMBanner extends Component { if(this.props.public===0&&this.props.status>1&&this.props.openknows===false){ if(this.props.shixunsDetails&&this.props.shixunsDetails.shixun_status === 2 && this.props.shixunsDetails&&this.props.shixunsDetails.public===0 && this.props.identity < 5){ - if(openopenpublictype===undefined||openopenpublictype===false||openopenpublictype===null){ - this.setState({ - openshowpublictype:true - }) - }else{ - this.setState({ - openshowpublictype:false - }) + if(this.props.user&&this.props.user.user_id) { + if (openopenpublictype === undefined || openopenpublictype === false || openopenpublictype === null) { + this.setState({ + openshowpublictype: true + }) + } else { + this.setState({ + openshowpublictype: false + }) + } } } }else{ diff --git a/public/react/src/modules/tpm/TPMIndex.js b/public/react/src/modules/tpm/TPMIndex.js index f7f73eabc..86d0e9637 100644 --- a/public/react/src/modules/tpm/TPMIndex.js +++ b/public/react/src/modules/tpm/TPMIndex.js @@ -87,6 +87,11 @@ const TPMchallengesnew = Loadable({ loader: () => import('./challengesnew/TPMchallengesnew'), loading: Loading, }) +//新建实训 +// const TPMchallengesnew = Loadable({ +// loader: () => import('./challengesnew/TpmTask/TpmTaskIndex'), +// loading: Loading, +// }) //新建tab2 const TPMevaluation = Loadable({ @@ -383,6 +388,7 @@ class TPMIndex extends Component { let url = window.location.href; let flag = url.indexOf("add_file")>-1; + return ( <div className="newMain clearfix"> {/*头部*/} diff --git a/public/react/src/modules/tpm/TPMIndexHOC.js b/public/react/src/modules/tpm/TPMIndexHOC.js index fe760f372..01d617c78 100644 --- a/public/react/src/modules/tpm/TPMIndexHOC.js +++ b/public/react/src/modules/tpm/TPMIndexHOC.js @@ -35,14 +35,14 @@ if (!window['indexHOCLoaded']) { // $('head').append($('<link rel="stylesheet" type="text/css" />') // .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`)); $('head').append($('<link rel="stylesheet" type="text/css" />') - .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?8`)); + .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?2020`)); $('head').append($('<link rel="stylesheet" type="text/css" />') - .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?8`)); + .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?2020`)); // index.html有加载 $('head').append($('<link rel="stylesheet" type="text/css" />') - .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?8`)); + .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?2020`)); // $('head').append($('<link rel="stylesheet" type="text/css" />') @@ -635,6 +635,18 @@ export function TPMIndexHOC(WrappedComponent) { } } + //跳转道描点的地方 + scrollToAnchor = (anchorName) => { + if (anchorName) { + // 找到锚点 + let anchorElement = document.getElementById(anchorName); + // 如果对应id的锚点存在,就跳转到锚点 + if (anchorElement) { + anchorElement.scrollIntoView(); + } + } + } + render() { let{Headertop,Footerdown, isRender, AccountProfiletype,AccountPhoneemailtype}=this.state; const common = { @@ -670,7 +682,8 @@ export function TPMIndexHOC(WrappedComponent) { hideGlobalLoading: this.hideGlobalLoading, yslslowCheckresults:this.yslslowCheckresults, yslslowCheckresultsNo:this.yslslowCheckresultsNo, - MdifHasAnchorJustScorll:this.MdifHasAnchorJustScorll + MdifHasAnchorJustScorll:this.MdifHasAnchorJustScorll, + scrollToAnchor:this.scrollToAnchor }; // console.log("this.props.mygetHelmetapi"); diff --git a/public/react/src/modules/tpm/challengesnew/TPManswer2.js b/public/react/src/modules/tpm/challengesnew/TPManswer2.js index dfdc58db4..596dcc910 100644 --- a/public/react/src/modules/tpm/challengesnew/TPManswer2.js +++ b/public/react/src/modules/tpm/challengesnew/TPManswer2.js @@ -1,48 +1,21 @@ import React, {Component} from 'react'; -import {Input, InputNumber, Select, Radio, Checkbox, Popconfirm, message, Modal, Tooltip} from 'antd'; +import {Input, InputNumber, Button, Tooltip} from 'antd'; import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; -// import "antd/dist/antd.css"; - -import { getImageUrl, toPath, getUrl } from 'educoder'; - import axios from 'axios'; -import './css/TPMchallengesnew.css'; - import TPMMDEditor from './TPMMDEditor'; +import Bottomsubmit from "../../modals/Bottomsubmit"; -let origin = getUrl(); - -let path = getUrl("/editormd/lib/") +import './css/TPMchallengesnew.css'; const $ = window.$; -let timeout; - -let currentValue; -const Option = Select.Option; -const RadioGroup = Radio.Group; - -// const testAnswers = [{ -// "id": 4337, -// "name": "解题思路1", -// "contents": "答案的解题思路1", -// "level": 1, -// "score": 25 -// }, -// { -// "id": 4338, -// "name": "解题思路2", -// "contents": "答案的解题思路2", -// "level": 2, -// "score": 25 -// }] export default class TPManswer extends Component { constructor(props) { super(props) @@ -94,7 +67,7 @@ export default class TPManswer extends Component { } } this.setState({ - answer:response.data.answer, + answer:response.data.answer, power: response.data.power, choice_url: newchoice_url, // 导航中的新建选择题url practice_url: newpractice_url, //string 导航中新建实践题url @@ -102,10 +75,11 @@ export default class TPManswer extends Component { position: response.data.position, //int 关卡位置,导航栏中的第几关 prev_challenge: newprev_challenge, next_challenge: next_challenge, + responsedata:response.data, }) if(response.data.power===false){ - this.props.showSnackbar("没有权限修改"); + this.props.showNotification("没有权限修改"); } // if(response.data.answer===undefined||response.data.answer===null){ // this.answerMD("", "answerMD"); @@ -133,7 +107,7 @@ export default class TPManswer extends Component { // this.refs.md0 const { answers } = this.state; const answersParams = answers.slice(0) - console.log(answersParams) + // console.log(answersParams) let isValidate = true; let totalScore = 0; answersParams.forEach( (item, index) => { @@ -147,10 +121,10 @@ export default class TPManswer extends Component { totalScore += item.score; delete item.id; if (!item.name) { - this.props.showSnackbar("请先填写参考答案名称"); + this.props.showNotification("请先填写参考答案名称"); isValidate = false; } else if (!mdContnet) { - this.props.showSnackbar("请先填写参考答案内容"); + this.props.showNotification("请先填写参考答案内容"); isValidate = false; } if (!isValidate) { @@ -161,7 +135,7 @@ export default class TPManswer extends Component { return; } if (answersParams.length != 0 && totalScore != 100) { - this.props.showSnackbar("请先保证占比和为100%"); + this.props.showNotification("请先保证占比和为100%"); return; } let id = this.props.match.params.shixunId; @@ -174,7 +148,7 @@ export default class TPManswer extends Component { ).then((response) => { if (response.data) { if (response.data.message) { - this.props.showSnackbar(response.data.message); + this.props.showNotification(response.data.message); } if (response.data.status == 1) { window.location.href=`/shixuns/${id}/challenges`; @@ -233,12 +207,16 @@ export default class TPManswer extends Component { } }) } + + gotocheckpoint=(url)=>{ + this.props.history.replace(url); + } render() { let { choice_url, practice_url, - go_back_url, + responsedata, position, task_pass_default, submit_url, @@ -256,60 +234,51 @@ export default class TPManswer extends Component { return ( <React.Fragment> <div className="educontent mt30 mb30 tpmAnswer"> - <div className="padding10-20 mb10 edu-back-white clearfix"> - <span className="fl ring-blue mr10 mt7"> - <img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/> - </span> - <span className="font-16 task-hide fl TPMtaskName">第{position}关</span> - <Link to={go_back_url === undefined ? "" : go_back_url} - className="color-grey-6 fr font-15 mt3">返回</Link> - - {prev_challenge === undefined ? "" : - <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> - } - - {next_challenge === undefined ? "" : - <a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a> - } - - <a href={practice_url === undefined ? "" : practice_url} - className="fr color-blue mr15 mt4" - style={{display:this.props.status===2||this.props.status===1?'none':'block'}} - data-tip-down="新增代码编辑类型的任务">+ 实践类型</a> - <a href={choice_url === undefined ? "" : choice_url} - className="fr color-blue mr15 mt4" - style={{display:this.props.status===2||this.props.status===1?'none':'block'}} - data-tip-down="新增选择题类型的任务">+ 选择题类型</a> - + <div className="TPMchallengesnewtitles edu-back-white clearfix borderbottomf4"> + <span className="font-16 task-hide fl TPMtaskName">第{position}关:{responsedata&&responsedata.st === 0 ?"实践题":responsedata&&responsedata.st === 1?"选择题":""}</span> + {this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<a href={practice_url === undefined ? "" : practice_url} className="fr ml15 mt13"> + <Button type="primary" className="edu-default-btn edu-greenback-btn " + >新增实践任务</Button></a>} + {this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<Link to={choice_url === undefined ? "" : choice_url} + className="fr ml15 mt13"> + <Button type="primary" + className="edu-default-btn edu-greenback-btn mr5" + >新增选择题任务</Button></Link>} + {next_challenge===undefined?"": + <Button type="primary" ghost onClick={()=>this.gotocheckpoint(next_challenge)} + className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13" + >下一关</Button> } + {prev_challenge===undefined?"": + <Button type="primary" ghost onClick={()=>this.gotocheckpoint(prev_challenge)} + className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13" + >上一关</Button>} </div> <div className="challenge_nav clearfix edu-back-white"> - <li> - <Link to={tab1url}>本关任务</Link> + <Link to={tab1url}>1、本关任务 </Link> </li> - + {tab2url === "" ? "":<li> > </li>} <li > - <Link to={tab2url}>评测设置</Link> + <Link to={tab2url} >2、评测设置</Link> </li> - + {tab3url === "" ? "":<li> > </li>} <li className="active"> - <Link to={tab3url}>参考答案</Link> + <Link to={tab3url} className={"color-blue"}> 3、参考答案</Link> </li> </div> <div className="edu-back-white mb10 clearfix"> <div className="padding30-20"> - <p className=" font-12" style={{ paddingBottom: '5px' - , color: '#666666'}}> - 可以将参考答案分级设置,让学员自行选择级别,每级查看后按照比例扣分值(学员已完成任务再查看,则不影响原因已获得的成绩) + <p className=" font-14" style={{ paddingBottom: '5px' + , color: '#333'}}> + 可以将参考答案分级设置,让学员自行选择级别,每级查看后按照比例扣分值(学员已完成任务再查看,则不影响学员已获得的成绩) </p> - <p className=" font-12 " - style={{ maxWidth: "782px" - , color: '#999999'}}> - 示例:级别1,扣减分值占比25%;级别2,扣减分值占比35%;级别3,扣减分值占比40%;则学员选择查看级别1的答案,将被扣减25%的分值; - 选择查看级别2的答案,将被扣减60%的分值;选择查看级别3的答案,将被扣减100%的分值。 + <p className=" font-14 mt15 " + style={{ color: '#888'}}> + <div>示例:级别1,扣减分值占比25%;级别2,扣减分值占比35%;级别3,扣减分值占比40%;</div> + <div className={"mt5 ml41"}>若学员选择查看级别1的答案,将被扣减25%的分值;选择查看级别2的答案,将被扣减60%的分值;选择查看级别3的答案,将被扣减100%的分值。</div> </p> <style>{` @@ -320,25 +289,31 @@ export default class TPManswer extends Component { { answers.map((answer, index) => { - return <div className="levelSection" id={`levelSection${index}`} style={{ clear: 'both' }}> + return <div className="levelSection mt30" id={`levelSection${index}`} style={{ clear: 'both' }}> <span className="mr4 color-orange pt10">*</span> - <p className="color-grey-6 font-16 mb30 mt10" style={{ display: "inline" }}>级别{index + 1}</p> + <p className="color-grey-6 font-16 mb30 mt10" style={{ display: "inline" }}>级别:{index + 1}</p> <Tooltip title="删除"> - <a className="fr sample_icon_remove mr30 mt8" onClick={()=>this.delanswers(index)}> - <i className="fa fa-times-circle color-grey-c font-16 fl" ></i> + <a className="fr sample_icon_remove mr10 mt8" onClick={()=>this.delanswers(index)}> + <i className={"iconfont icon-shanchu_Hover font-16 fl"}></i> </a> </Tooltip> - <div className=" color-grey-6 font-16" style={{ marginLeft: "9px", margin: '8px 9px'}}> + <div className=" color-grey-6 font-16 bortopeeetpm pt20 mt20" style={{ marginLeft: "9px", margin: '8px 9px'}}> <div className=" "> - <span>名称:</span> - <Input value={answer.name} onChange={(e) => this.onNameChange(e, index)}></Input> - - <span style={{ marginLeft: "20px"}} >扣减分值占比:</span> - <InputNumber className="score" step={1} min={1} max={100} defaultValue={answer.score} - onChange={(e) => this.onScoreChange(e, index)} ></InputNumber>% + <div className={"wind500height45"}> + <div className={"fl"} style={{'width':'240px'}}>名称:</div> + <div className={"fl"} style={{ marginLeft: "20px"}} >扣减分值占比:</div> + </div> + <div className={"wind500height45"}> + <Input value={answer.name} onChange={(e) => this.onNameChange(e, index)}></Input> + + + <InputNumber className="score" step={1} min={1} max={100} defaultValue={answer.score} + style={{ marginLeft: "32px"}} + onChange={(e) => this.onScoreChange(e, index)} ></InputNumber> % + </div> </div> <div className="mt10"> - <span>参考答案:</span> + <span>内容:</span> <TPMMDEditor ref={`md${index}`} mdID={index} initValue={answer.contents} onChange={(val) => this.answerOnChange(val, index)}></TPMMDEditor> </div> @@ -348,19 +323,28 @@ export default class TPManswer extends Component { } <div className="clearfix mt20" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}> - <a href={"javascript:void(0)"} className="defalutCancelbtn fl" onClick={this.addAnswer}>新增</a> + {/*<a href={"javascript:void(0)"} className="defalutCancelbtn fl" >新增参考答案</a>*/} + <Button type="primary" ghost className="edu-default-btn edu-greenback-btn mt20 mb20 newaddswermargin" onClick={this.addAnswer}>新增参考答案</Button> </div> </div> </div> - <div className="clearfix mt20" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}> - <a className="defalutSubmitbtn fl mr20" - onClick={this.challenge_answer_submit}>提交</a> - <a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a> - </div> </div> + + {this.props.identity>4||this.props.identity===undefined||power===false?"":<div className="clearfix mt20" > + {/*<a className="defalutSubmitbtn fl mr20" onClick={this.challenge_answer_submit}>提交</a>*/} + {/*/!*<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>*!/*/} + {/*<Link to={"/shixuns/" + shixunId + "/challenges"} className={"defalutCancelbtn fl"}>取消</Link>*/} + <Bottomsubmit url={"/shixuns/" + shixunId + "/challenges"} + bottomvalue={"提交"} + onSubmits={this.challenge_answer_submit} + {...this.props} + {...this.state} + loadings={false} + /> + </div>} </React.Fragment> ) } diff --git a/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js b/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js index f6bac13a5..70fb5d306 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js +++ b/public/react/src/modules/tpm/challengesnew/TPMchallengesnew.js @@ -1,35 +1,30 @@ import React, {Component} from 'react'; -import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd'; +import {Input, Select, Radio, Badge, message, Button} from 'antd'; -import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; - -// import "antd/dist/antd.css"; +import {Link} from "react-router-dom"; import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; +import Bottomsubmit from "../../modals/Bottomsubmit"; + import axios from 'axios'; import './css/TPMchallengesnew.css'; -import { getImageUrl, toPath } from 'educoder'; - -import {getUrl} from 'educoder'; - -let origin = getUrl(); - -let path = getUrl("/editormd/lib/") - const $ = window.$; -let timeout; - -let currentValue; - const Option = Select.Option; const RadioGroup = Radio.Group; +function isNulltpm( str ){ + if ( str == "" ) return true; + var regu = "^[ ]+$"; + var re = new RegExp(regu); + return re.test(str); +} + export default class TPMchallengesnew extends Component { constructor(props) { super(props) @@ -40,12 +35,12 @@ export default class TPMchallengesnew extends Component { go_back_url: undefined, task_pass_default: undefined, submit_url: undefined, - shixunCreatePracticeGroup: 1, + shixunCreatePracticeGroup: undefined, optionsums:[100,200], activetype:0, setopen: false, shixunCreatePractice: undefined, - onshixunsmarkvalue: 100, + onshixunsmarkvalue: undefined, shixunsskillvalue: undefined, shixunsskillvaluelist: [], tab2url: "", @@ -59,12 +54,13 @@ export default class TPMchallengesnew extends Component { editPracticesendtype:false, CreatePracticesendtype:false, exec_time:20, - shixunExec_timeType:false + shixunExec_timeType:false, + onshixunsmarkvaluetype:false, + shixunCreatePracticeGrouptype:false } } - - componentDidMount() { + getdatas=()=>{ let id = this.props.match.params.shixunId; let checkpointId=this.props.match.params.checkpointId; @@ -83,10 +79,11 @@ export default class TPMchallengesnew extends Component { task_pass_default: response.data.task_pass_default, submit_url: response.data.submit_url, checkpointId:checkpointId, - exercisememoMDRefval:response.data.task_pass_default + exercisememoMDRefval:response.data.task_pass_default, + responsedata:response.data }) - this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'') + this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'') }).catch((error) => { console.log(error) }); @@ -133,16 +130,18 @@ export default class TPMchallengesnew extends Component { onshixunsmarkvalue:response.data.score, shixunsskillvaluelist:response.data.tags, checkpointId:checkpointId, - exec_time:response.data.exec_time, tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2", tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3", - exercisememoMDRefval:response.data.task_pass + exercisememoMDRefval:response.data.task_pass, + responsedata:response.data }) + // exec_time:response.data.exec_time, if(response.data.power===false){ - this.props.showSnackbar("你没有权限修改"); + this.props.showNotification("你没有权限修改"); + } - this.exercisememoMDRef.current.setValue(response.data.task_pass||'') + this.exercisememoMDRef.current.setValue(response.data.task_pass||'') }).catch((error) => { console.log(error) }); @@ -150,8 +149,24 @@ export default class TPMchallengesnew extends Component { } } + componentDidUpdate=(prevProps, prevState)=>{ + if(prevProps!=this.props){ + this.getdatas() + } + } + componentDidMount() { + this.getdatas() + } onshixunCreatePracticeChange = (e) => { + if(e.target.value===undefined||e.target.value=== ""||e.target.value=== null){ + + }else{ + this.setState({ + shixunCreatePracticeGrouptype:false, + onshixunsmarkvaluetype:false + }) + } let optionsum; let onshixunsmark; if(e.target.value===1){ @@ -172,62 +187,134 @@ export default class TPMchallengesnew extends Component { } shixunCreatePractice = (e) => { + + if (e.target.value === undefined|| e.target.value== ""){ + + }else{ + this.setState({ + shixunCreatePracticetype:false + }) + } this.setState({ shixunCreatePractice: e.target.value }) + } CreatePracticesend = () => { - + const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); this.setState({ CreatePracticesendtype:true }) if(this.props.status===2){ - this.props.showSnackbar("该实训已经发布不能新建") + this.props.showNotification("该实训已经发布不能新建") this.setState({ CreatePracticesendtype:false }) return } let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,exec_time} = this.state; + + if (shixunCreatePractice === undefined||shixunCreatePractice=="") { this.setState({ - shixunCreatePracticetype: true + shixunCreatePracticetype: true, + CreatePracticesendtype:false }) - this.props.showSnackbar("任务名称为空") - $('html').animate({ + + $('html').animate({ scrollTop: 10 }, 1000); - this.setState({ - CreatePracticesendtype:false - }) return } + if (shixunCreatePractice.match(/^[ ]*$/)) { + this.props.showNotification("任务名称为空,请勿输入空格"); + this.setState({ + shixunCreatePracticetype: true, + CreatePracticesendtype:false + }) + $('html').animate({ + scrollTop: 10 + }, 1000); + return + } + + + if (exercise_editormdvalue === undefined||exercise_editormdvalue==""||exercise_editormdvalue===null) { + this.setState({ + tpmcourseMessageMDType:true, + CreatePracticesendtype:false + }) + this.props.scrollToAnchor("tpmcourseMessageMD"); + return + } + + if(isNulltpm(exercise_editormdvalue)){ + this.setState({ + tpmcourseMessageMDType:true, + CreatePracticesendtype:false + }) + this.props.scrollToAnchor("tpmcourseMessageMD"); + return + } + + + if(shixunCreatePracticeGroup===undefined){ + this.setState({ + shixunCreatePracticeGrouptype:true, + CreatePracticesendtype:false + }) + this.props.scrollToAnchor("shixunCreatePracticeGroupid"); + return + } + + if(onshixunsmarkvalue===undefined){ + this.setState({ + onshixunsmarkvaluetype:true, + CreatePracticesendtype:false + }) + this.props.scrollToAnchor("input_task_tag"); + return + } if (shixunsskillvaluelist.length === 0) { this.setState({ shixunsskillvaluelisttype: true, - CreatePracticesendtype:false + CreatePracticesendtype:false }) - this.props.showSnackbar("技能标签为空") + // this.props.showNotification("技能标签为空") + this.props.scrollToAnchor("input_task_tag"); return } - if(exec_time===null||exec_time===undefined||exec_time===""){ - this.setState({ - shixunExec_timeType:false - }) - return - } - const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); - let id = this.props.match.params.shixunId; + // if(exec_time===null||exec_time===undefined||exec_time === ""){ + // this.setState({ + // shixunExec_timeType:true, + // CreatePracticesendtype:false + // }) + // this.props.scrollToAnchor("exec_time"); + // return + // } + + // if (exec_time.match(/^[ ]*$/)) { + // this.props.showNotification("评测时限,请勿输入空格"); + // this.setState({ + // shixunExec_timeType:true, + // CreatePracticesendtype:false + // }) + // this.props.scrollToAnchor("exec_time"); + // return + // } + - let url = "/shixuns/" + id + "/challenges.json"; + let id = this.props.match.params.shixunId; + let url = "/shixuns/" + id + "/challenges.json"; + // exec_time:exec_time axios.post(url, { identifier:id, subject: shixunCreatePractice, @@ -236,12 +323,12 @@ export default class TPMchallengesnew extends Component { score: onshixunsmarkvalue, challenge_tag: shixunsskillvaluelist, st: 0, - exec_time:exec_time }).then((response) => { if (response.data.status === 1) { // $("html").animate({ scrollTop: 0 }) //window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/editcheckpoint?tab=2`; - window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`; + // window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`; + this.props.history.replace(`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`); // this.setState({ // setopen: true, // CreatePracticesendtype:false, @@ -250,7 +337,7 @@ export default class TPMchallengesnew extends Component { // }) } - // this.props.showSnackbar(response.data.messages); + // this.props.showNotification(response.data.messages); }).catch((error) => { console.log(error) }); @@ -287,6 +374,12 @@ export default class TPMchallengesnew extends Component { let list = shixunsskillvaluelist; list.push(shixunsskillvalue); + + if (list.length> 0) { + this.setState({ + shixunsskillvaluelisttype: false, + }) + } this.setState({ shixunsskillvaluelist: list, shixunsskillvalue: "" @@ -303,51 +396,103 @@ export default class TPMchallengesnew extends Component { } editPracticesend=()=>{ - this.setState({ editPracticesendtype:true }) - let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,checkpointId,exec_time} = this.state; - - const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); - let id = this.props.match.params.shixunId; - let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; + const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); if (shixunCreatePractice === undefined||shixunCreatePractice=="") { - // this.setState({ - // shixunCreatePracticetype: true - // }) - this.props.showSnackbar("任务名称为空") + this.setState({ + shixunCreatePracticetype: true, + editPracticesendtype:false + }) + // this.props.showNotification("任务名称为空") $('html').animate({ scrollTop: 10 }, 1000); + + return + } + + if (shixunCreatePractice.match(/^[ ]*$/)) { + this.props.showNotification("任务名称为空,请勿输入空格"); this.setState({ - editPracticesendtype:false + shixunCreatePracticetype: true, + editPracticesendtype:false }) + $('html').animate({ + scrollTop: 10 + }, 1000); return } - if (shixunsskillvaluelist.length === 0) { - // this.setState({ - // shixunsskillvaluelisttype: true - // }) - this.props.showSnackbar("技能标签为空") + if (exercise_editormdvalue === undefined||exercise_editormdvalue==""||exercise_editormdvalue===null) { this.setState({ - editPracticesendtype:false + tpmcourseMessageMDType:true, + editPracticesendtype:false }) + this.props.scrollToAnchor("tpmcourseMessageMD"); return } - if(exec_time===null||exec_time===undefined||exec_time===""){ + if(isNulltpm(exercise_editormdvalue)){ + this.setState({ + tpmcourseMessageMDType:true, + editPracticesendtype:false + }) + this.props.scrollToAnchor("tpmcourseMessageMD"); + this.props.showNotification("过关任务,请勿输入空格"); + return + } - this.setState({ - shixunExec_timeType:false - }) - return - } + if(shixunCreatePracticeGroup===undefined){ + this.setState({ + shixunCreatePracticeGrouptype:true, + editPracticesendtype:false + }) + this.props.scrollToAnchor("shixunCreatePracticeGroupid"); + return + } + if(onshixunsmarkvalue===undefined){ + this.setState({ + onshixunsmarkvaluetype:true, + editPracticesendtype:false + }) + this.props.scrollToAnchor("input_task_tag"); + return + } + + if (shixunsskillvaluelist.length === 0) { + this.setState({ + shixunsskillvaluelisttype: true, + editPracticesendtype:false, + }) + this.props.scrollToAnchor("input_task_tag"); + return + } + + // if(exec_time===null||exec_time===undefined||exec_time === ""){ + // this.setState({ + // shixunExec_timeType:true, + // editPracticesendtype:false + // }) + // this.props.scrollToAnchor("exec_time"); + // return + // } + + // if (exec_time.match(/^[ ]*$/)) { + // this.props.showNotification("评测时限,请勿输入空格"); + // this.setState({ + // shixunExec_timeType:true, + // editPracticesendtype:false + // }) + // this.props.scrollToAnchor("exec_time"); + // return + // } + // exec_time:exec_time axios.put(url, { tab:0, identifier:id, @@ -357,19 +502,19 @@ export default class TPMchallengesnew extends Component { task_pass: exercise_editormdvalue, difficulty: shixunCreatePracticeGroup, score: onshixunsmarkvalue, - exec_time:exec_time }, challenge_tag:shixunsskillvaluelist }).then((response) => { - this.props.showSnackbar(response.data.messages); + this.props.showNotification(response.data.messages); if (response.data.status === 1) { - window.location.href=`/shixuns/${id}/challenges/${checkpointId}/tab=2`; + // window.location.href=`/shixuns/${id}/challenges/${checkpointId}/tab=2`; this.setState({ setopen: true, editPracticesendtype:false, tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2", tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3", }) + this.props.history.replace(`/shixuns/${id}/challenges/${checkpointId}/tab=2`); // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2" } }).catch((error) => { @@ -396,12 +541,16 @@ export default class TPMchallengesnew extends Component { exec_time:e.target.value }) } + + gotocheckpoint=(url)=>{ + this.props.history.replace(url); + } render() { let shixuntype = this.props.match.params.type; - let {marktype, + let {responsedata, shixunCreatePracticetype, shixunsskillvaluelisttype, choice_url, practice_url, go_back_url, position, task_pass_default, submit_url, setopen,checkpointId,prev_challenge,next_challenge,power, shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvalue, shixunsskillvaluelist, tab2url, tab3url,optionsums, @@ -417,142 +566,146 @@ export default class TPMchallengesnew extends Component { }) } + // console.log(this.props) + // console.log(this.state) + //a console.log(shixunCreatePractice) + return ( <React.Fragment> <div className="educontent mt30 mb30"> - <div className="padding10-20 mb10 edu-back-white clearfix"> - <span className="fl ring-blue mr10 mt7"> - <img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/> - </span> - <span className="font-16 task-hide fl TPMtaskName">第{position}关</span> - - <Link to={go_back_url === undefined ? "" : go_back_url} - className="color-grey-6 fr font-15 mt3">返回</Link> - { next_challenge===undefined?"": - <a href={next_challenge}className="fr color-blue mr15 mt4">下一关</a> - } - { prev_challenge===undefined?"": - <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> - } - - - - - <a href={practice_url === undefined ? "" : practice_url} - className="fr color-blue mr15 mt4" - style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} - data-tip-down="新增代码编辑类型的任务">+ 实践类型</a> - - <a href={choice_url === undefined ? "" : choice_url} - className="fr color-blue mr15 mt4" - style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} - data-tip-down="新增选择题类型的任务">+ 选择题类型</a> - + <div className="TPMchallengesnewtitles edu-back-white clearfix borderbottomf4"> + <span className="font-16 task-hide fl TPMtaskName">第{position}关:{responsedata&&responsedata.st === 0 ?"实践题":responsedata&&responsedata.st === 1?"选择题":""}</span> + {this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<a href={practice_url === undefined ? "" : practice_url} className="fr ml15 mt13"> + <Button type="primary" className="edu-default-btn edu-greenback-btn " + >新增实践任务</Button></a>} + {this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<Link to={choice_url === undefined ? "" : choice_url} + className="fr ml15 mt13"> + <Button type="primary" + className="edu-default-btn edu-greenback-btn mr5" + >新增选择题任务</Button></Link>} + {next_challenge===undefined?"": + <Button type="primary" ghost onClick={()=>this.gotocheckpoint(next_challenge)} + className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13" + >下一关</Button> } + {prev_challenge===undefined?"": + <Button type="primary" ghost onClick={()=>this.gotocheckpoint(prev_challenge)} + className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13" + >上一关</Button>} </div> <div className="challenge_nav clearfix edu-back-white"> <li className="active"> - <a>本关任务</a> + <a className={"color-blue"}>1、本关任务 </a> </li> - + {tab2url === "" ? "":<li> > </li>} <li className=""> - {tab2url === "" ? <span>评测设置</span> : <Link to={tab2url}>评测设置</Link>} + {tab2url === "" ? <span></span> : <Link to={tab2url}>2、评测设置</Link>} </li> - + {tab3url === "" ? "":<li> > </li>} <li className=""> - {tab3url === "" ? <span>参考答案</span> : <Link to={tab3url}>参考答案</Link>} - + {tab3url === "" ? <span></span> : <Link to={tab3url}> 3、参考答案</Link>} </li> </div> - <div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb30">任务名称</p> - <div className="df"> - <span className="mr30 color-orange pt10">*</span> - <div className="flex1 mr20"> - <input type="text" - // className="input-100-45 greyInput" - className={shixunCreatePracticetype===true?"input-100-45 greyInpus wind100":"input-100-45 greyInput "} - maxLength="50" - name="challenge[subject]" - value={shixunCreatePractice} + <div className="edu-back-white clearfix"> + <div className="newpadding1020"> + <p className="color-grey-6 font-16 mb10"> <span className="mr5 color-red">*</span>名称</p> + <div> + <div className="flex1"> + <Input placeholder="请输入任务名称,最大限制60个字符;此信息将在实训发布后展示给学员,例:计算学生的课程成绩绩点" + maxLength="60" + className={shixunCreatePracticetype === true ? "bor-red":"newViewAfter"} onInput={this.shixunCreatePractice} - placeholder="请输入任务名称(此信息将提前展示给学员),例:计算学生的课程成绩绩点"/> + value={shixunCreatePractice} + addonAfter={`${String(!shixunCreatePractice? 0 : shixunCreatePractice.length)}/${60}`} + /> </div> - <div style={{width: '57px'}}> - <span - className={shixunCreatePracticetype === true ? "color-orange mt8 fl block" : "color-orange mt8 fl none"} - id="new_shixun_name"><i - className="fa fa-exclamation-circle mr3"></i>必填项</span> + <div> + <span className={shixunCreatePracticetype === true ? "color-red mt8 fl block" : "color-red mt8 fl none"} id="new_shixun_name">必填项:不能为空</span> </div> </div> </div> </div> - <div className="edu-back-white padding40-20 mb20"> + <div className="edu-back-white newpadding02020"> - <p className="color-grey-6 font-16 mb30">过关任务</p> + <p className="color-grey-6 font-16 mb10" id={"tpmcourseMessageMD"}><span className="mr5 color-red">*</span>过关任务</p> + <style> + { + ` + .markdown-body img { + max-width: 80%; + margin: 0 auto; + display: block; + width: auto; + height: auto; + max-height: 80%; + } + ` + } + </style> + <TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500} - <TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500} - watch={true} className="courseMessageMD" initValue={this.state.exercisememoMDRefval} height={700}></TPMMDEditor> + watch={true} className="courseMessageMD" initValue={this.state.exercisememoMDRefval} height={800}></TPMMDEditor> <p id="e_tip_Memochallengesnew" className="edu-txt-right color-grey-cd font-12"></p> <p id="e_tips_Memochallengesnew" className="edu-txt-right color-grey-cd font-12"></p> - </div> + {this.state.tpmcourseMessageMDType===true?<div className="color-red mt7 ml5 font-14" >必填项:不能为空</div>:""} + </div> - <div className="edu-back-white padding40-20 mb20"> - <p className="color-grey-6 font-16 mb30">难度系数</p> - <div className="clearfix mb40"> - <RadioGroup value={shixunCreatePracticeGroup} className="fl mr40" - disabled={this.props.status===2?true:false} - onChange={this.props.status===2?"":this.onshixunCreatePracticeChange}> + <div className="edu-back-white newpadding02020"> + <p className="color-grey-6 font-16 mb20"> + <span className="fl color-red mr5">*</span> + 难度系数: + <RadioGroup value={shixunCreatePracticeGroup} + className={"ml10"} + id={"shixunCreatePracticeGroupid"} + disabled={this.props.status===2?true:false} + onChange={this.props.status===2?"":this.onshixunCreatePracticeChange}> <Radio value={1}>简单</Radio> <Radio value={2}>中等</Radio> <Radio value={3}>困难</Radio> </RadioGroup> - - </div> - <p className="color-grey-6 font-16 mb30">奖励经验值</p> - <div className="clearfix" - // onMouseLeave={this.props.status===2?"":this.onshixunsmarkss} - > - <span className="fl mr30 color-orange pt10">*</span> - - <Select style={{width: 120}} className="winput-240-40 fl" + {this.state.shixunCreatePracticeGrouptype===true?<div className="color-red mt7 ml5 font-14" id="ex_value_notice"> + 必选项:不能为空</div>:""} + </p> + <p className="color-grey-6 font-16 mb10"> <span className="fl mr5 color-red">*</span> 奖励经验值:<span className={"color-grey-8 font-14"}> (如果学员答题正确,将获得相应的经验值;如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+100经验值、+100金币)</span></p> + <div className="clearfix"> + {this.state.onshixunsmarkvaluetype===true?<style> + { + ` + .ant-select-selection{ + border:1px solid red; + } + ` + } + </style>:""} + <Select style={{width: 252}} + className={"winput-240-40 ml3"} id="challenge_score" onChange={this.props.status===2?"":this.onshixunsmark} - // onMouseEnter={this.props.status===2?"":this.onshixunsmarks} disabled={this.props.status===2?true:false} - // open={marktype} value={onshixunsmarkvalue} getPopupContainer={triggerNode => triggerNode.parentNode} > {options} </Select> - - <p className="fl color-grey-9 font-12 ml20"> - 如果学员答题错误,则不能得到相应的经验值<br/> - 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币 - </p> - - <span className="color-orange mt7 fl ml20 none" id="ex_value_notice"><i - className="fa fa-exclamation-circle mr3"></i>必填项</span> + {this.state.onshixunsmarkvaluetype===true?<div className="color-red mt7 ml5" id="ex_value_notice"> + 必选项:不能为空</div>:""} </div> </div> - <div className="edu-back-white padding40-20 mb20"> - <p className="color-grey-6 font-16 mb30">技能标签</p> - <div className="clearfix df"> - <span className="mr30 color-orange pt10">*</span> + <div className="edu-back-white newpadding02020"> + <p className="color-grey-6 font-16 mb10"><span className="mr5 color-red">*</span>技能标签:<span className={"color-grey-8 font-14"}> (学员答题正确将获得技能,否则不能获得技能)</span></p> + <div className="clearfix"> <div className="flex1"> <Input type="text" - className="winput-240-40 fl mr20 winput-240-40s" + className={shixunsskillvaluelisttype === true ?"winput-240-40 fl mr20 winput-240-40s ml10 bor-red":"winput-240-40 fl mr20 winput-240-40s ml10"} id="input_task_tag" placeholder="添加标签" onInput={this.shixunsskill} @@ -560,54 +713,59 @@ export default class TPMchallengesnew extends Component { onPressEnter={this.clickshixunsskill} onBlur={this.clickshixunsskill} /> - {/*<a className="white-btn orange-btn fl mt1 use_scope-btn ml20 mt5 mr20"*/} - {/*onClick={this.clickshixunsskill}>+ 添加</a>*/} - <div className="ml15 color-grey-9 mt5">学员答题正确将获得技能,否则不能获得技能</div> + <div className="ml15 color-grey-9 pt5 font-14">(回车添加标签)</div> <div className="mt20 clearfix" id="task_tag_content"> - { shixunsskillvaluelist===undefined?"":shixunsskillvaluelist.length === 0 ? "" : shixunsskillvaluelist.map((itme, key) => { return ( - <li className="task_tag_span" key={key}><span>{itme}</span> - <a onClick={() => this.delshixunsskilllist(key)}>×</a> - </li> + <li key={key} className={"fl ml10 mr10"}> + <Badge className={"tpmpointer"} count={"x"} onClick={(key) => this.delshixunsskilllist(key)}> + <Button type="primary" ghost className={"Permanentban "}> + {itme} + </Button> + </Badge> + </li> ) }) } - - </div> </div> - <span - className={shixunsskillvaluelisttype === true ? "color-orange mt7 fl ml20 block" : " color-orange mt7 fl ml20 none"} - id="stage_name_notice"> - <i className="fa fa-exclamation-circle mr3"></i>必填项</span> + <div className={shixunsskillvaluelisttype === true ? "color-red ml10 mt5 block" : "none"} + id="stage_name_notice">必选项:不能为空</div> </div> </div> - <div className="edu-back-white padding40-20 mb20"> - <p className="color-grey-6 font-16 mb30">服务配置</p> - <div className="clearfix mb5"> - <span className="color-orange pt10 fl">*</span> - <label className="panel-form-label fl">评测时限(S):</label> - <div className="pr fl with80 status_con"> - <input value={this.state.exec_time} className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" onInput={this.setexec_time}/> - </div> - <span - className={this.state.shixunExec_timeType === true ? "color-orange mt8 fl block ml20" : "color-orange mt8 fl none"} - id="new_shixun_name"><i className="fa fa-exclamation-circle mr3"></i>必填项</span> - <div className="cl"></div> - </div> - </div> - - <div className="clearfix mt30" - style={{display:this.props.identity>4||this.props.identity===undefined?"none":'block'}} - > - {checkpointId===undefined?<a className="defalutSubmitbtn fl mr20" onClick={CreatePracticesendtype===true?"":this.CreatePracticesend}>提交</a>: - <a className="defalutSubmitbtn fl mr20" onClick={editPracticesendtype===true?"":this.editPracticesend}>提交</a>} - <a href={go_back_url === undefined ? "" : go_back_url} className="defalutCancelbtn fl">取消</a> - </div> + {/*<div className="edu-back-white newpadding02020">*/} + {/* <p className="color-grey-6 font-16 mb20"> <span className="color-orange mr5 fl">*</span> 服务配置:评测时限(S)</p>*/} + {/* <div className="clearfix mb5 ml10">*/} + {/* <div className="pr status_con" id={"exec_timeid"}>*/} + {/* /!*<label className="panel-form-label fl"></label>*!/*/} + {/* <input value={this.state.exec_time}*/} + {/* className={this.state.shixunExec_timeType === true ?"panel-box-sizing task-form-100 task-height-40 bor-red":"panel-box-sizing task-form-100 task-height-40" }*/} + {/* placeholder="请输入类别名称" onInput={this.setexec_time}/>*/} + {/* </div>*/} + {/* <div*/} + {/* className={this.state.shixunExec_timeType === true ? "color-red mt8 block ml5" : " none"}*/} + {/* id="new_shixun_name">必填项:不能为空</div>*/} + {/* </div>*/} + {/*</div>*/} + + </div> + {this.props.identity>4||this.props.identity===undefined?"":<div className="clearfix mt30" + // style={{display:this.props.identity>4||this.props.identity===undefined?"none":'block'}} + > + {/*{checkpointId===undefined?<a className="defalutSubmitbtn fl mr20" onClick={CreatePracticesendtype===true?"":this.CreatePracticesend}>提交</a>:*/} + {/*<a className="defalutSubmitbtn fl mr20" onClick={editPracticesendtype===true?"":this.editPracticesend}>提交</a>}*/} + {/*<a href={go_back_url === undefined ? "" : go_back_url} className="defalutCancelbtn fl">取消</a>*/} + {/*<Link to={go_back_url === undefined ? "" : go_back_url} className={"defalutCancelbtn fl"}>取消</Link>*/} + <Bottomsubmit url={go_back_url === undefined ? "" : go_back_url} + {...this.props} + {...this.state} + bottomvalue={"提交"} + onSubmits={checkpointId===undefined?()=>this.CreatePracticesend():()=>this.editPracticesend()} + loadings={CreatePracticesendtype===true?true:editPracticesendtype===true?true:false}/> + </div>} </React.Fragment> ) } diff --git a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js index 34eb1a075..7ff0942cc 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js +++ b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js @@ -1,97 +1,32 @@ import React, {Component} from 'react'; -import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Button,Icon,Tooltip} from 'antd'; +import {Input, Select, Radio, Checkbox, Modal,Button,Tooltip} from 'antd'; -import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; - -// import "antd/dist/antd.css"; +import { Link} from "react-router-dom"; import axios from 'axios'; -import { getImageUrl, toPath } from 'educoder'; - -import './css/TPMchallengesnew.css'; +import Bottomsubmit from "../../modals/Bottomsubmit"; -import {getUrl} from 'educoder'; +import { getImageUrl } from 'educoder'; -let origin = getUrl(); - -let path = getUrl("/editormd/lib/") +import './css/TPMchallengesnew.css'; const $ = window.$; -let timeout; - -let currentValue; - const Option = Select.Option; const RadioGroup = Radio.Group; const { TextArea } = Input; -function create_editorMD(id, width, high, placeholder, imageUrl, callback) { - var editorName = window.editormd(id, { - width: width, - height: high, - path: path, // "/editormd/lib/" - - syncScrolling: "single", - tex: true, - tocm: true, - emoji: true, - taskList: true, - codeFold: true, - searchReplace: true, - htmlDecode: "style,script,iframe", - sequenceDiagram: true, - autoFocus: false, - toolbarIcons: function () { - // Or return editormd.toolbarModes[name]; // full, simple, mini - // Using "||" set icons align right. - return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] - }, - toolbarCustomIcons: { - testIcon: "<a type=\"inline\" class=\"latex\" ><div class='zbg'></div></a>", - testIcon1: "<a type=\"latex\" class=\"latex\" ><div class='zbg_latex'></div></a>" - }, - //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 - saveHTMLToTextarea: true, - // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 - dialogMaskOpacity: 0.6, - placeholder: placeholder, - imageUpload: true, - imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], - imageUploadURL: imageUrl,//url - onload: function () { - // this.previewing(); - $("#" + id + " [type=\"latex\"]").bind("click", function () { - editorName.cm.replaceSelection("```latex"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("```"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line - 1, 0); - }); - - $("#" + id + " [type=\"inline\"]").bind("click", function () { - editorName.cm.replaceSelection("`$$$$`"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); - editorName.cm.focus(); - }); - $("[type=\"inline\"]").attr("title", "行内公式"); - $("[type=\"latex\"]").attr("title", "多行公式"); - - window.md_elocalStorage(editorName, `exercise__${id}`, "Memochallengesnew"); - - callback && callback() - } - }); - return editorName; +function isNulltpm( str ){ + if ( str == "" ) return true; + var regu = "^[ ]+$"; + var re = new RegExp(regu); + return re.test(str); } - export default class TPMevaluation extends Component { constructor(props) { super(props) @@ -127,39 +62,11 @@ export default class TPMevaluation extends Component { scorevalue:false, markvalue:true, scoretype:undefined, - web_route:null + web_route:null, + exec_time:undefined } } - - exerciseMD(initValue, id) { - - this.contentChanged = false; - const placeholder = ""; -// amp; -// 编辑时要传memoId - const imageUrl = `/api/attachments.json`; -// 创建editorMd - - const exercise_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => { - setTimeout(() => { - exercise_editormd.resize() - exercise_editormd.cm && exercise_editormd.cm.refresh() - }, 500) - - if (initValue != undefined) { - exercise_editormd.setValue(initValue) - } - exercise_editormd.cm.on("change", (_cm, changeObj) => { - console.log('....contentChanged') - this.contentChanged = true; - }) - }); - this.exercise_editormd = exercise_editormd; - window.exercise_editormd = exercise_editormd; - - } - componentDidMount() { let id = this.props.match.params.shixunId; let checkpointId=this.props.match.params.checkpointId; @@ -193,8 +100,7 @@ export default class TPMevaluation extends Component { let newevaluationlist=[] if(response.data.test_sets.length===0){ let newlist=[ - {hidden:0,input:"",output:"",score:50}, - {hidden:0,input:"",output:"",score:50} + {hidden:0,input:"",output:"",score:100}, ] newevaluationlist=newlist }else{ @@ -219,18 +125,16 @@ export default class TPMevaluation extends Component { scorevalue:response.data.test_set_score, markvalue:response.data.test_set_average, web_route:response.data.web_route, - has_web_route:response.data.has_web_route + has_web_route:response.data.has_web_route, + responsedata:response.data, + exec_time:response.data.exec_time, }) this.evaluationoninputvalueonload(); if(response.data.power===false){ - this.props.showSnackbar("你没有权限修改"); - } - if(response.data.answer===undefined){ - this.answerMD("", "answerMD"); - }else{ - this.answerMD(response.data.answer, "answerMD"); + this.props.showNotification("你没有权限修改"); } + }).catch((error) => { console.log(error) }); @@ -249,7 +153,7 @@ export default class TPMevaluation extends Component { addevaluationon=()=>{ let {evaluationlist,markvalue}=this.state; let newevaluationlist=evaluationlist; - newevaluationlist.push({hidden:0,input:"",output:"",score:0}); + newevaluationlist.push({hidden:0,input:"",output:"",score:0,match_rule:"full"}); newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue); this.setevaluationlist(newevaluationlist); } @@ -379,34 +283,6 @@ export default class TPMevaluation extends Component { } - - - - - // delesavegetfilepath=(value)=>{ - // let {selectpatharr} = this.state - // let newarr =selectpatharr; - // let newselectpath=""; - // for(var i=0; i<newarr.length;i++){ - // if(newarr[i]===value){ - // - // newarr.splice(i,1); - // console.log(newarr) - // console.log(value) - // } - // } - // - // - // - // - // for(var z=0; z<newarr.length;z++){ - // newselectpath=newselectpath+newarr[z]+ ";" - // } - // this.setState({ - // selectpatharr:newarr, - // selectpath: newselectpath - // }) - // } savegetfilepath=(value)=>{ let {selectpath,saveshixunfilepath,pathtype} = this.state @@ -438,30 +314,6 @@ export default class TPMevaluation extends Component { }) } - // let newarr =selectpatharr; - // let arrtype=false; - // let arrsum=0; - // let newselectpath=""; - // newarr.push(value) - // if(newarr.length>1&&arrtype===false){ - // for(var i=0; i<newarr.length;i++){ - // if(newarr[i]===value){ - // arrsum=arrsum+1; - // if(arrsum===2){ - // newarr.splice(i,1); - // arrtype=true; - // } - // } - // } - // } - - // for(var z=0; z<newarr.length;z++){ - // newselectpath=newselectpath+newarr[z]+ ";" - // } - - - - } evaluationenter=()=>{ @@ -505,12 +357,6 @@ export default class TPMevaluation extends Component { }else{ newtype=1; } - // newevaluationlist[key].is_public=newtype; - // for(var i=0; i<newevaluationlist.length; i++){ - // if(i===key){ - // - // } - // } newevaluationlist[key].hidden=newtype; this.setState({ @@ -597,7 +443,7 @@ export default class TPMevaluation extends Component { $('textarea[autoHeight]').autoHeight(); } submitarbitrationevaluation=()=>{ - let{evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue,web_route}=this.state; + let{exec_time,evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue,web_route}=this.state; let newscorevalue; @@ -610,7 +456,7 @@ export default class TPMevaluation extends Component { let sum=0; for(var i=0; i<evaluationlist.length; i++){ if(evaluationlist[i].score>100){ - this.props.showSnackbar("测试集的评分占比不能大于100"); + this.props.showNotification("测试集的评分占比不能大于100"); this.setState({ scoretype:i }) @@ -620,36 +466,52 @@ export default class TPMevaluation extends Component { } if(sum>100||sum<100){ - this.props.showSnackbar("测试集的评分占比之和必须等于100"); + this.props.showNotification("测试集的评分占比之和必须等于100"); return } } + + + if(exec_time===null||exec_time===undefined||exec_time === ""){ + this.setState({ + shixunExec_timeType:true, + }) + this.props.scrollToAnchor("exec_timeid"); + return + } + + if (isNulltpm(exec_time)) { + this.props.showNotification("评测时长,请勿输入空格"); + this.setState({ + shixunExec_timeType:true, + }) + this.props.scrollToAnchor("exec_timeid"); + return + } + if(shixunfilepath===undefined||shixunfilepath===""||shixunfilepath===null){ - this.props.showSnackbar("学员任务文件路径为空"); + // this.props.showSnackbar("学员任务文件路径为空"); this.setState({ StudentTaskPapers:true }) - $('html').animate({ - scrollTop: 120 - }, 1000); + this.props.scrollToAnchor("Studenttaskfile"); return } if(shixunfilepathplay===undefined||shixunfilepathplay===""||shixunfilepathplay===null){ - this.props.showSnackbar("评测执行文件路径为空"); + // this.props.showSnackbar("评测执行文件路径为空"); this.setState({ StudentTaskDocs:true }) - $('html').animate({ - scrollTop: 130 - }, 1000); + this.props.scrollToAnchor("Benchmarkexecutable"); return } if(evaluationlist.length===0){ this.props.showSnackbar("测试集不能为空"); + this.props.scrollToAnchor("Thetestset"); return } let id = this.props.match.params.shixunId; @@ -664,7 +526,8 @@ export default class TPMevaluation extends Component { picture_path:pathoptionvalue===-1?undefined:shixunfilepicturepath===undefined?null:shixunfilepicturepath, test_set_score:newscorevalue, test_set_average:markvalue, - web_route:web_route===null?undefined:web_route + web_route:web_route===null?undefined:web_route, + exec_time:exec_time } axios.put(url,{ tab:1, @@ -672,7 +535,7 @@ export default class TPMevaluation extends Component { test_set:evaluationlist } ).then((response) => { - this.props.showSnackbar(response.data.messages); + this.props.showNotification(response.data.messages); window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=3`; // if(response.data.status===1){ // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3" @@ -681,16 +544,7 @@ export default class TPMevaluation extends Component { console.log(error) }); } - handpathoptionvalues=()=>{ - this.setState({ - handpathopt:true - }) - } - handpathoptionvaluess=()=>{ - this.setState({ - handpathopt:false - }) - } + saveselectpath=(e)=>{ this.setState({ @@ -768,6 +622,24 @@ export default class TPMevaluation extends Component { web_route:e.target.value }) } + + gotocheckpoint=(url)=>{ + this.props.history.replace(url); + } + + setexec_time=(e)=>{ + if(e.target.value===null||e.target.value===undefined||e.target.value === ""||e.target.value.match(/^[ ]*$/)){ + + }else{ + this.setState({ + shixunExec_timeType:false, + }) + } + this.setState({ + exec_time:e.target.value + }) + } + render() { let { @@ -799,7 +671,8 @@ export default class TPMevaluation extends Component { scorevalue, markvalue, scoretype, - has_web_route + has_web_route, + responsedata } = this.state; let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint"; @@ -812,64 +685,115 @@ export default class TPMevaluation extends Component { lineHeight: '30px', marginLeft: '20px', }; + return ( <React.Fragment> <div className="educontent mt30 mb30"> - <div className="padding10-20 mb10 edu-back-white clearfix"> - <span className="fl ring-blue mr10 mt7"> - <img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/> - </span> - <span className="font-16 task-hide fl TPMtaskName">第{position}关</span> - <Link to={go_back_url === undefined ? "" : go_back_url} - className="color-grey-6 fr font-15 mt3">返回</Link> - - {prev_challenge === undefined ? "" : - <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> - } - - {next_challenge === undefined ? "" : - <a href={next_challenge} className="fr color-blue mr15 mt4">下一关</a> - } - - <a href={practice_url === undefined ? "" : practice_url} - className="fr color-blue mr15 mt4" - style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1? "none":'block'}} - data-tip-down="新增代码编辑类型的任务">+ 实践类型</a> - <a href={choice_url === undefined ? "" : choice_url} - className="fr color-blue mr15 mt4" - style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} - data-tip-down="新增选择题类型的任务">+ 选择题类型</a> - + <div className="TPMchallengesnewtitles edu-back-white clearfix borderbottomf4"> + <span className="font-16 task-hide fl TPMtaskName">第{position}关:{responsedata&&responsedata.st === 0 ?"实践题":responsedata&&responsedata.st === 1?"选择题":""}</span> + {this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<a href={practice_url === undefined ? "" : practice_url} className="fr ml15 mt13"> + <Button type="primary" className="edu-default-btn edu-greenback-btn " + >新增实践任务</Button></a>} + {this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"":<Link to={choice_url === undefined ? "" : choice_url} + className="fr ml15 mt13"> + <Button type="primary" + className="edu-default-btn edu-greenback-btn mr5" + >新增选择题任务</Button></Link>} + {next_challenge===undefined?"": + <Button type="primary" ghost onClick={()=>this.gotocheckpoint(next_challenge)} + className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13" + >下一关</Button> } + {prev_challenge===undefined?"": + <Button type="primary" ghost onClick={()=>this.gotocheckpoint(prev_challenge)} + className="edu-default-btn edu-greenback-btn mr5 fr ml15 mt13" + >上一关</Button>} </div> <div className="challenge_nav clearfix edu-back-white"> - <li> - <Link to={tab1url}>本关任务</Link> + <Link to={tab1url}>1、本关任务 </Link> </li> - + {tab2url === "" ? "":<li> > </li>} <li className="active"> - <Link to={tab2url}>评测设置</Link> + <Link to={tab2url} className={"color-blue"}>2、评测设置</Link> </li> - + {tab3url === "" ? "":<li> > </li>} <li className=""> - <Link to={tab3url}>参考答案</Link> + <Link to={tab3url}> 3、参考答案</Link> </li> </div> - <p className="color-orange-tip font-12 padding20"> - 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到 - <a href={"/shixuns/" + shixunId + "/repository"} className="color-bule-tip decoration" target="_blank">版本库</a> + <p className="color-orange-tip font-14 padding10 edu-back-white text-centers"> + <div className={"bor25510211"}> + 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到 + <a href={"/shixuns/" + shixunId + "/repository"} className="color-bule-tip decoration" target="_blank">版本库</a> + </div> </p> + <div className="edu-back-white newpadding02020" id={"exec_timeid"} > + <p className="color-grey-6 font-16 mb20"> <span className="color-red mr5 fl">*</span> 评测时长限制<span className={"color-grey-8 font-14"}>(程序评测运行时间限制时长,单位:秒)</span></p> + <div className="clearfix mb5"> + <div className="pr status_con" style={{'width':'233px'}}> + <Input value={this.state.exec_time} + className={this.state.shixunExec_timeType === true ?"panel-box-sizing task-form-100 task-height-40 bor-red":"panel-box-sizing task-form-100 task-height-40" } + placeholder="请输入评测时长" onInput={this.setexec_time}/> + </div> + <div + className={this.state.shixunExec_timeType === true ? "color-red mt8 block ml5" : " none"} + id="new_shixun_name">必填项:不能为空</div> + </div> + </div> - <div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">学员任务文件</p> - <div className="df"> - <span className="mr30 color-orange pt10">*</span> - <div className="flex1 mr20"> - <input type="text" className="input-100-45 greyInput change" id="shixun_file_path" + + <div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10"> + <p className="color-grey-6 font-16 mb20"><span className="color-red mr5 fl">*</span> 评测效果展现方式<span className={"color-grey-8 font-14"}>(学员评测本关任务时,查看效果页上需要展现的文件类型)</span></p> + <div className="pr"> + <Select className="winput-240-40" + value={pathoptionvalue} + onChange={this.handpathoptionvalue}> + <Option value={-1}>无</Option> + <Option value={1}>图片</Option> + <Option value={2}>apk/exe</Option> + <Option value={3}>txt</Option> + <Option value={4}>html</Option> + <Option value={5}>mp3</Option> + <Option value={6}>mp4</Option> + </Select> + <a className="ml10" onClick={()=>this.showrepositoryurltip(1)}><img src={getImageUrl("images/educoder/problem.png")}/></a> + <div className="invite-tip clearfix repository_url_tippostion" style={{display:showrepositoryurltiptype===true?"block":"none"}} id="repository_url_tip" + > + <span className="top-black-trangleft"></span> + <div className="padding20 invitecontent clearfix"> + <p className="font-12 edu-txt-left"> + 图片:处理或输出图片类型的任务,请选填此项<br/> + 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果<br/><br/> + apk/exe:写可执行文件的任务,请选填此项<br/> + 可以通过设置学员答案文件路径,展示二维码以供扫码下载<br/><br/> + txt:输出txt文档类型的任务,请选填此项<br/> + 可以通过学员答案文件路径设置,展示txt文件内容<br/><br/> + html:web类型的任务,请选填此项<br/> + 可以通过Web路由设置,展示html效果预览页<br/><br/> + mp3/mp4:mp3/mp4文件类型的任务,请选填此项<br/> + 可以通过学员答案文件路径设置,展示mp3/mp4文件内容<br/><br/> + </p></div> + <p className="inviteTipbtn with100"><a onClick={()=>this.showrepositoryurltip(2)} + >知道了</a> + </p> + </div> + </div> + </div> + </div> + + + <div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10" id={"Studenttaskfile"}> + <p className="color-grey-6 font-16 mb20"><span className="color-red mr5 fl">*</span> 学员任务文件<span className={"color-grey-8 font-14"}>(该文件将直接显示给学生,需要学生在其中填写代码)</span></p> + <div> + <div className="flex1"> + <input type="text" + className={StudentTaskPapers===true?"input-100-45 greyInput change bor-red":"input-100-45 greyInput change"} + id="shixun_file_path" name="challenge[path]" autoComplete="off" placeholder="请选择版本库中的代码文件。例: src/step1/HelloWorld.java" value={shixunfilepath} @@ -877,15 +801,16 @@ export default class TPMevaluation extends Component { onInput={(e)=>this.updatepath(e,"shixunfilepath",1)} onClick={(e)=>this.getfilepath(e,"shixunfilepath",1)} /> - <p className="color-grey-9 mt15">该文件将直接显示给学生,需要学生在其中填写代码</p> </div> - <div style={{width: '57px'}}> - <span className={StudentTaskPapers===true?"color-orange mt8 fl":"color-orange mt8 fl none"} id="student_task_name"><i - className="fa fa-exclamation-circle mr3"></i>必填项</span> + <div> + <span className={StudentTaskPapers===true?"color-red mt8 fl":" none"} id="student_task_name"> 必选项:不能为空</span> </div> </div> </div> </div> + + + <Modal keyboard={false} title="文件路径" @@ -914,9 +839,6 @@ export default class TPMevaluation extends Component { {path+item.name}</a>:<a data-remote="true"> <i className="iconfont icon-zuoye color-blue mr2"></i> <span onClick={()=>this.savegetfilepath(path+item.name,item.type)}>{path+item.name}</span> - {/*<Tooltip placement="bottom" title={"点击删除下方所选文件路径"}>*/} - {/*<Icon className={"fr mt4"} type="close-circle" onClick={()=>this.delesavegetfilepath(path+item.name)}/>*/} - {/*</Tooltip>*/} </a> } </div> @@ -942,13 +864,12 @@ export default class TPMevaluation extends Component { </div> </Modal> - <div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">评测执行文件</p> - <div className="df"> - <span className="mr30 color-orange pt10">*</span> - <div className="flex1 mr20"> - <input type="text" className="input-100-45 greyInput" id="shixun_file_path_play" + <div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10" id={"Benchmarkexecutable"}> + <p className="color-grey-6 font-16 mb20"><span className="color-red mr5 fl">*</span>评测执行文件<span className={"color-grey-8 font-14"}>(若执行平台脚本,请输入学员任务文件路径;若使用自己设计的脚本测试学生代码,请输入设计的脚本文件路径)</span></p> + <div> + <div className="flex1"> + <input type="text" className={StudentTaskDocs===true?"bor-red input-100-45 greyInput":"input-100-45 greyInput"} id="shixun_file_path_play" name="challenge[exec_path]" autoComplete="off" placeholder="请选择版本库中的代码文件。例:src/step1/HelloWorldTest.java" value={shixunfilepathplay} @@ -956,59 +877,19 @@ export default class TPMevaluation extends Component { onInput={(e)=>this.updatepath(e,"shixunfilepathplay",1)} onClick={(e)=>this.getfilepath(e,"shixunfilepathplay",1)} /> - <p className="color-grey-9 mt15">该文件由平台执行,用来测试平台学员代码是否正确</p> - </div> - <div style={{width: '57px'}}> - <span className={StudentTaskDocs===true?"color-orange mt8 fl":"color-orange mt8 fl none"} id="student_task_name"><i - className="fa fa-exclamation-circle mr3"></i>必填项</span> </div> - </div> - </div> - </div> - - - <div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">效果展现方式</p> - <div className="pr"> - <Select className="winput-240-40" - value={pathoptionvalue} - onChange={this.handpathoptionvalue}> - <Option value={-1}>请选择效果展现方式</Option> - <Option value={1}>图片</Option> - <Option value={2}>apk/exe</Option> - <Option value={3}>txt</Option> - <Option value={4}>html</Option> - <Option value={5}>mp3</Option> - <Option value={6}>mp4</Option> - </Select> - <a className="ml10" onClick={()=>this.showrepositoryurltip(1)}><img src={getImageUrl("images/educoder/problem.png")}/></a> - <div className="invite-tip clearfix repository_url_tippostion" style={{display:showrepositoryurltiptype===true?"block":"none"}} id="repository_url_tip" - > - <span className="top-black-trangleft"></span> - <div className="padding20 invitecontent clearfix"> - <p className="font-12 edu-txt-left"> - 图片:处理或输出图片类型的任务,请选填此项<br/> - 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果<br/><br/> - apk/exe:写可执行文件的任务,请选填此项<br/> - 可以通过设置学员答案文件路径,展示二维码以供扫码下载<br/><br/> - txt:输出txt文档类型的任务,请选填此项<br/> - 可以通过学员答案文件路径设置,展示txt文件内容<br/><br/> - html:web类型的任务,请选填此项<br/> - 可以通过Web路由设置,展示html效果预览页 - </p></div> - <p className="inviteTipbtn with100"><a onClick={()=>this.showrepositoryurltip(2)} - >知道了</a> - </p> + <div> + <span className={StudentTaskDocs===true?"color-red mt8 fl":"none"} id="student_task_name"> + 必选项:不能为空 + </span> </div> </div> - <p className="color-grey-9 mt15">该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型</p> </div> </div> - {pathoptionvalue===4&&web_route!=null||pathoptionvalue===4&&has_web_route===true?<div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">Web路由</p> + {pathoptionvalue===4&&web_route!=null||pathoptionvalue===4&&has_web_route===true?<div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10"> + <p className="color-grey-6 font-16 mb20">Web路由<span className={"color-grey-8 font-14"}>(请注意将服务器程序的端口号映射到8080端口)</span></p> <div className="df"> <div className="flex1 mr20"> <input type="text" className="input-100-45 change" autoComplete="off" @@ -1021,9 +902,9 @@ export default class TPMevaluation extends Component { </div> </div>:""} - {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?<div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">待处理文件路径</p> + {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?<div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10"> + <p className="color-grey-6 font-16 mb20">待处理文件路径<span className={"color-grey-8 font-14"}>(该路径下的文件将在学员评测本关任务时,作为原始文件显示在查看效果页,供学员参考;请注意与程序文件所在文件夹分开)</span></p> <div className="df"> <div className="flex1 mr20"> <input type="text" className="input-100-45" autoComplete="off" @@ -1033,9 +914,6 @@ export default class TPMevaluation extends Component { onInput={(e)=>this.updatepath(e,"shixunfileexpectpicturepath",2)} onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath",2)} /> - <p className="color-grey-9 mt15"> - 该路径下的文件将在学员评测本关任务时,作为原始文件显示在查看效果页,供学员参考;任务为文件处理时请指定该路径,并注意与程序文件所在文件夹分开。 - </p> </div> <div></div> </div> @@ -1043,9 +921,9 @@ export default class TPMevaluation extends Component { </div>:""} - {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6? <div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">标准答案文件路径</p> + {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6? <div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10"> + <p className="color-grey-6 font-16 mb20">标准答案文件路径<span className={"color-grey-8 font-14"}>(该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考;请注意与程序文件所在文件夹分开)</span></p> <div className="df"> <div className="flex1 mr20"> <input type="text" className="input-100-45" autoComplete="off" @@ -1055,9 +933,6 @@ export default class TPMevaluation extends Component { onInput={(e)=>this.updatepath(e,"shixunfilestandardpicturepath",2)} onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath",2)} /> - <p className="color-grey-9 mt15"> - 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考;任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开。 - </p> </div> <div></div> </div> @@ -1065,9 +940,9 @@ export default class TPMevaluation extends Component { </div>:""} - {pathoptionvalue===-1?"":<div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> - <p className="color-grey-6 font-16 mb20">学员答案文件路径</p> + {pathoptionvalue===-1?"":<div className="edu-back-white clearfix"> + <div className="padding1020tpms mb10"> + <p className="color-grey-6 font-16 mb20">学员答案文件路径<span className={"color-grey-8 font-14"}>(学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认;请注意与程序文件所在文件夹分开)</span></p> <div className="df"> <div className="flex1 mr20"> <input type="text" className="input-100-45 change" autoComplete="off" @@ -1076,9 +951,6 @@ export default class TPMevaluation extends Component { onInput={(e)=>this.updatepath(e,"shixunfilepicturepath",2)} onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath",2)} placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例:src/step1/outputfiles"/> - <p className="color-grey-9 mt15"> - 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认;任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开。 - </p> </div> <div></div> </div> @@ -1086,10 +958,10 @@ export default class TPMevaluation extends Component { </div>} - <div className="edu-back-white mb10 clearfix"> - <div className="padding40-20"> + <div className="edu-back-white clearfix" id={"Thetestset"}> + <div className="padding1020tpms mb20"> {/*<p className="color-grey-6 font-16">测试集</p>*/} - <p className="color-grey-6 font-16">测试集和系统评分规则</p> + <p className="color-grey-6 font-16 height40pxtpm borbottomeeetpm">测试集和系统评分规则</p> <p className="color-grey-9 mt20" style={{width:'100%',height:'60px'}} > @@ -1132,9 +1004,9 @@ export default class TPMevaluation extends Component { {evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{ return( - <div className="test_array_item mt30" key={key}> + <div className="test_array_item mt30 borbottomeeetpm pb20" key={key}> <p className="clearfix pr mb20"> - <span className="fl mt5 mr10 color-orange">*</span> + <span className="fl mr10 color-red">*</span> <span className="color-blue font-16 fl" name="sample_inputs_label">组{key+1}</span> <span className="fl ml20 color-grey-6"> {/*checked={item.is_public===1?false:true}*/} @@ -1143,19 +1015,19 @@ export default class TPMevaluation extends Component { style={{width: '25%',display:scorevalue===true?'inline-block':'none'}} onInput={(e)=>this.editpercentage(e,key)} value={item.score} /> - <span className="mr15" + <span className="mr15 ml10" style={{display:scorevalue===true?'inline-block':'none'}} >%</span> - <Checkbox onChange={()=>this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏</Checkbox> + <Checkbox onChange={()=>this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏<span className={"color-grey-8 font-14"}>(选中则对学员隐藏本测试集内容)</span></Checkbox> </span> <Tooltip placement="bottom" title={"删除"}> - <a className="fr del_array sample_icon_remove mr30" style={{display:key===0?"none":"block"}} + <div className="fr sample_icon_remove " style={{display:key===0?"none":"block"}} onClick={()=>this.del_test_array(key)}> - <i className="fa fa-times-circle color-grey-c font-16 fl"></i> - </a> + <i className={"iconfont icon-shanchu_Hover font-16 fl"}></i> + </div> </Tooltip> </p> <TextArea className="textareavalue mb15" name="test_set[input][]" @@ -1174,11 +1046,11 @@ export default class TPMevaluation extends Component { rows={5} onInput={(e)=>this.evaluationoninputvalue(e,key,"yq")} ></TextArea> - <div className="clearfix lineh-30"> + <div className="clearfix lineh-30 mt20"> <span className="fl mr10 color-grey-6">匹配规则:</span> <RadioGroup className="fl" value={item.match_rule} onChange={(e)=>this.changeEvaluationRule(e,key)}> - <Radio value='full'>完全匹配</Radio> - <Radio value='last'>末尾匹配</Radio> + <Radio value='full'>完全匹配<span className={"color-grey-8 font-14"}>(实际输出与预期输出完全相同)</span></Radio> + <Radio value='last'>末尾匹配<span className={"color-grey-8 font-14"}>(实际输出的末尾内容与预期输出完全相同)</span></Radio> </RadioGroup> </div> </div> @@ -1189,23 +1061,28 @@ export default class TPMevaluation extends Component { </div> <p className="clearfix" onClick={this.addevaluationon}> - <a className="fl edu-default-btn edu-greyline-btn mt20 mb20 sample_icon_add"> - 新增测试集 - </a> + <Button type="primary" ghost className="edu-default-btn edu-greenback-btn mt20 mb20">新增测试集</Button> </p> - <p className="color-grey-9">温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测</p> + + <p className="color-grey-9">温馨提示:公开测试集和隐藏测试集结合使用,可以降低作弊的几率;隐藏测试集,在“提交评测”时也将被系统自动检测</p> </div> </div> </div> - - <div className="clearfix mt30" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}> - <a className="defalutSubmitbtn fl mr20" onClick={this.submitarbitrationevaluation}>提交</a> - <a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a> - </div> - - </div> + + {this.props.identity>4||this.props.identity===undefined||power===false?"":<div className="clearfix mt30"> + {/*<a className="defalutSubmitbtn fl mr20" onClick={this.submitarbitrationevaluation}>提交</a>*/} + {/*/!*<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>*!/*/} + {/*<Link to={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</Link>*/} + <Bottomsubmit url={"/shixuns/" + shixunId + "/challenges"} + bottomvalue={"提交"} + onSubmits={this.submitarbitrationevaluation} + {...this.props} + {...this.state} + loadings={false} + /> + </div>} </React.Fragment> ) } diff --git a/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js b/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js index d0e6f98bd..5e90c1f3d 100644 --- a/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js +++ b/public/react/src/modules/tpm/challengesnew/TpmQuestionEdit.js @@ -212,9 +212,9 @@ export default class TpmQuestionEdit extends Component { <div className="clearfix mt30" style={{display:this.props.identity>4||this.props.identity===undefined||this.props.power===false?"none":"block"}}> <a className="defalutSubmitbtn fl mr20" onClick={()=>this.props.answer_subit()}>提交</a> - <a href={this.props.go_back_url} - className="defalutCancelbtn fl">取消</a> - + {/*<a href={this.props.go_back_url}*/} + {/* className="defalutCancelbtn fl">取消</a>*/} + <Link to={this.props.go_back_url} className="defalutCancelbtn fl">取消</Link> <a onClick={()=>this.delecbtns()} className="delectshixuncdbtn fr">删除</a> </div> diff --git a/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js b/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js index 614842ab8..c4008f89c 100644 --- a/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js +++ b/public/react/src/modules/tpm/challengesnew/TpmQuestionMain.js @@ -69,9 +69,9 @@ export default class TpmQuestionMain extends Component { style={{display: this.props.identity > 4 || this.props.identity === undefined || this.props.power === false ? "none" : "block"}}> <a className="defalutSubmitbtn fl mr20" onClick={this.props.sumittype === true ? "" : this.props.clickquestionsumit}>提交</a> - <a href={this.props.go_back_url} - className="defalutCancelbtn fl">取消</a> - + {/*<a href={this.props.go_back_url}*/} + {/* className="defalutCancelbtn fl">取消</a>*/} + <Link to={this.props.go_back_url} className="defalutCancelbtn fl">取消</Link> </div> </div> diff --git a/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js b/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js index 861c4f879..c808fea61 100644 --- a/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js +++ b/public/react/src/modules/tpm/challengesnew/TpmQuestionNew.js @@ -205,8 +205,10 @@ export default class TpmQuestionNew extends Component { <div className="clearfix mt30" style={{display:this.props.identity>4||this.props.identity===undefined||this.props.power===false?"none":"block"}}> <a className="defalutSubmitbtn fl mr20" onClick={this.props.answer_subit}>提交</a> - <a href={this.props.go_back_url} - className="defalutCancelbtn fl">取消</a> + <Link to={this.props.go_back_url} + className="defalutCancelbtn fl">取消</Link> + {/*<a href={this.props.go_back_url}*/} + {/* className="defalutCancelbtn fl">取消</a>*/} </div> </div> diff --git a/public/react/src/modules/tpm/challengesnew/TpmTask/TpmTaskIndex.js b/public/react/src/modules/tpm/challengesnew/TpmTask/TpmTaskIndex.js new file mode 100644 index 000000000..5a64daf9e --- /dev/null +++ b/public/react/src/modules/tpm/challengesnew/TpmTask/TpmTaskIndex.js @@ -0,0 +1,55 @@ +import React, {Component} from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import Loadable from 'react-loadable'; + +import Loading from "../../../../Loading"; + +import Bottomsubmit from "../../../modals/Bottomsubmit"; + + +const TPMchallengestask = Loadable({ + loader: () => import('../../challengesnew/TPMchallengesnew'), + loading: Loading, +}) + +export default class TpmTaskIndex extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + + + componentDidMount() { + + } + + + render() { + // console.log(a.indexOf("vnc")) + // console.log(b.indexOf("vnc")) + + return ( + + <div> + <Switch {...this.props}> + {/*新建关卡*/} + <Route path="/shixuns/:shixunId/challenges/new" render={ + (props) => (<TPMchallengestask {...this.props} {...props} {...this.state}/>) + }></Route> + + {/*编辑关卡*/} + <Route path="/shixuns/:shixunId/challenges/:checkpointId/editcheckpoint" render={ + (props) => (<TPMchallengestask {...this.props} {...props} {...this.state} />) + }></Route> + </Switch> + </div> + + ); + } +} + + diff --git a/public/react/src/modules/tpm/challengesnew/css/TPMchallengesnew.css b/public/react/src/modules/tpm/challengesnew/css/TPMchallengesnew.css index 37a65ef97..a65c3b7fa 100644 --- a/public/react/src/modules/tpm/challengesnew/css/TPMchallengesnew.css +++ b/public/react/src/modules/tpm/challengesnew/css/TPMchallengesnew.css @@ -266,4 +266,66 @@ a{ height: 32px; line-height: 20px; font-family: "微软雅黑","宋体"; +} + +.borderbottomf4{ + border-bottom:1px solid #F4F4F4; +} + +.TPMchallengesnewtitles{ + height: 76px; + line-height: 56px; + padding: 10px 20px; +} + +.newpadding1020{ + padding: 20px 20px 20px; + box-sizing: border-box; +} +.newpadding02020{ + padding: 0px 20px 20px; +} +.mb10 { + margin-bottom: 10px !important; +} + +.tpmpointer{ + cursor: pointer; +} +.text-centers{text-align:center} +.bor25510211{ + width: 1180px; + height: 34px; + border: 1px solid rgba(255,102,1,1); + line-height: 34px; +} + +.padding1020tpms{ + padding: 10px 20px; + box-sizing: border-box; +} + +.bortopeeetpm{ + border-top: 1px solid #eee; +} + +.borbottomeeetpm { + border-bottom: 1px solid #eee; +} + +.height40pxtpm{ + height:40px +} + +.ml41{ + margin-left: 41px; +} + +.wind500height45{ + width: 500px; + height: 45px; +} + +.newaddswermargin{ + margin: 0 auto; } \ No newline at end of file diff --git a/public/react/src/modules/tpm/challengesnew/TPManswer.js b/public/react/src/modules/tpm/challengesnew/old/TPManswer.js similarity index 98% rename from public/react/src/modules/tpm/challengesnew/TPManswer.js rename to public/react/src/modules/tpm/challengesnew/old/TPManswer.js index 9187e09b0..7d090c607 100644 --- a/public/react/src/modules/tpm/challengesnew/TPManswer.js +++ b/public/react/src/modules/tpm/challengesnew/old/TPManswer.js @@ -10,7 +10,7 @@ import { getImageUrl, toPath, getUrl } from 'educoder'; import axios from 'axios'; -import './css/TPMchallengesnew.css'; +import '../css/TPMchallengesnew.css'; let origin = getUrl(); @@ -355,7 +355,8 @@ export default class TPManswer extends Component { <div className="clearfix mt20" style={{display:this.props.identity>4||this.props.identity===undefined||power===false?"none":"block"}}> <a className="defalutSubmitbtn fl mr20" onClick={this.challenge_answer_submit}>提交</a> - <a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a> + {/*<a href={"/shixuns/" + shixunId + "/challenges"} className="defalutCancelbtn fl">取消</a>*/} + <Link to={"/shixuns/" + shixunId + "/challenges"} className={"defalutCancelbtn fl"}>取消</Link> </div> </div> </React.Fragment> diff --git a/public/react/src/modules/tpm/challengesnew/old/TPMchallengesnew.js b/public/react/src/modules/tpm/challengesnew/old/TPMchallengesnew.js new file mode 100644 index 000000000..6dfc04eef --- /dev/null +++ b/public/react/src/modules/tpm/challengesnew/old/TPMchallengesnew.js @@ -0,0 +1,617 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +// import "antd/dist/antd.css"; + +import TPMMDEditor from '../TPMMDEditor'; + +import axios from 'axios'; + +import '../css/TPMchallengesnew.css'; + +import { getImageUrl, toPath } from 'educoder'; + +import {getUrl} from 'educoder'; + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + +export default class TPMchallengesnew extends Component { + constructor(props) { + super(props) + this.exercisememoMDRef=React.createRef(); + this.state = { + choice_url: undefined, + practice_url: undefined, + go_back_url: undefined, + task_pass_default: undefined, + submit_url: undefined, + shixunCreatePracticeGroup: 1, + optionsums:[100,200], + activetype:0, + setopen: false, + shixunCreatePractice: undefined, + onshixunsmarkvalue: 100, + shixunsskillvalue: undefined, + shixunsskillvaluelist: [], + tab2url: "", + tab3url: "", + prev_challenge:undefined, + next_challenge:undefined, + power: false, + shixunCreatePracticetype: false, + shixunsskillvaluelisttype: false, + marktype:false, + editPracticesendtype:false, + CreatePracticesendtype:false, + exec_time:20, + shixunExec_timeType:false + } + } + + + componentDidMount() { + let id = this.props.match.params.shixunId; + let checkpointId=this.props.match.params.checkpointId; + + let newchoice_url= "/shixuns/"+id+"/challenges/newquestion"; + let newpractice_url= "/shixuns/"+id+"/challenges/new"; + let newgo_back_url="/shixuns/"+id+"/challenges" + if(checkpointId===undefined){ + //新建模式 + let url = "/shixuns/" + id + "/challenges/new.json" + axios.get(url).then((response) => { + this.setState({ + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + position: response.data.position, + task_pass_default: response.data.task_pass_default, + submit_url: response.data.submit_url, + checkpointId:checkpointId, + exercisememoMDRefval:response.data.task_pass_default + }) + + this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'') + }).catch((error) => { + console.log(error) + }); + }else{ + //编辑模式 + let url="/shixuns/"+id+"/challenges/"+checkpointId+".json?tab=0"; + axios.get(url).then((response) => { + + let optionsum; + if(response.data.difficulty===1){ + optionsum=[100,200]; + }else if(response.data.difficulty===2){ + optionsum=[300,400,500,600]; + }else if(response.data.difficulty===3){ + optionsum=[700,800,900,1000] + } + let newprev_challenge=response.data.prev_challenge; + let next_challenge=response.data.next_challenge; + if (newprev_challenge != undefined) { + if(newprev_challenge.st===0){ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint"; + }else{ + newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion"; + } + } + if (next_challenge != undefined) { + if(next_challenge.st===0){ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint"; + }else{ + next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion"; + } + } + this.setState({ + power: response.data.power, + prev_challenge:newprev_challenge, + next_challenge:next_challenge, + choice_url: newchoice_url, + practice_url: newpractice_url, + go_back_url: newgo_back_url, + shixunCreatePractice:response.data.subject, + position:response.data.position, + shixunCreatePracticeGroup:response.data.difficulty, + optionsums:optionsum, + onshixunsmarkvalue:response.data.score, + shixunsskillvaluelist:response.data.tags, + checkpointId:checkpointId, + exec_time:response.data.exec_time, + tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2", + tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3", + exercisememoMDRefval:response.data.task_pass + }) + if(response.data.power===false){ + this.props.showSnackbar("你没有权限修改"); + } + + this.exercisememoMDRef.current.setValue(response.data.task_pass||'') + }).catch((error) => { + console.log(error) + }); + + } + + } + + onshixunCreatePracticeChange = (e) => { + let optionsum; + let onshixunsmark; + if(e.target.value===1){ + optionsum=[100,200]; + onshixunsmark=100; + }else if(e.target.value===2){ + optionsum=[300,400,500,600]; + onshixunsmark=300; + }else if(e.target.value===3){ + optionsum=[700,800,900,1000] + onshixunsmark=700; + } + this.setState({ + shixunCreatePracticeGroup: e.target.value, + optionsums:optionsum, + onshixunsmarkvalue:onshixunsmark + }) + } + + shixunCreatePractice = (e) => { + this.setState({ + shixunCreatePractice: e.target.value + }) + } + + CreatePracticesend = () => { + + + this.setState({ + CreatePracticesendtype:true + }) + + if(this.props.status===2){ + this.props.showSnackbar("该实训已经发布不能新建") + this.setState({ + CreatePracticesendtype:false + }) + return + } + let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,exec_time} = this.state; + if (shixunCreatePractice === undefined||shixunCreatePractice=="") { + this.setState({ + shixunCreatePracticetype: true + }) + this.props.showSnackbar("任务名称为空") + $('html').animate({ + scrollTop: 10 + }, 1000); + + this.setState({ + CreatePracticesendtype:false + }) + return + } + + if (shixunsskillvaluelist.length === 0) { + this.setState({ + shixunsskillvaluelisttype: true, + CreatePracticesendtype:false + }) + this.props.showSnackbar("技能标签为空") + return + } + if(exec_time===null||exec_time===undefined||exec_time===""){ + + this.setState({ + shixunExec_timeType:false + }) + return + } + + const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); + let id = this.props.match.params.shixunId; + + let url = "/shixuns/" + id + "/challenges.json"; + + axios.post(url, { + identifier:id, + subject: shixunCreatePractice, + task_pass: exercise_editormdvalue, + difficulty: shixunCreatePracticeGroup, + score: onshixunsmarkvalue, + challenge_tag: shixunsskillvaluelist, + st: 0, + exec_time:exec_time + }).then((response) => { + if (response.data.status === 1) { + // $("html").animate({ scrollTop: 0 }) + //window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/editcheckpoint?tab=2`; + window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/tab=2`; + // this.setState({ + // setopen: true, + // CreatePracticesendtype:false, + // tab2url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2", + // tab3url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3", + // }) + + } + // this.props.showSnackbar(response.data.messages); + }).catch((error) => { + console.log(error) + }); + + + + } + + onshixunsmark = (value) => { + this.setState({ + onshixunsmarkvalue: value + }) + } + + shixunsskill = (e) => { + this.setState({ + shixunsskillvalue: e.target.value + }) + } + + clickshixunsskill = () => { + + let {shixunsskillvalue, shixunsskillvaluelist} = this.state; + if (shixunsskillvalue === "") { + return + } else if (shixunsskillvalue === undefined) { + return + } + + if(shixunsskillvalue == "" || shixunsskillvalue == undefined || shixunsskillvalue == null || (shixunsskillvalue.length>0 && shixunsskillvalue.trim().length == 0)){ + message.error("输入为空,不能保存!"); + return + } + + let list = shixunsskillvaluelist; + list.push(shixunsskillvalue); + this.setState({ + shixunsskillvaluelist: list, + shixunsskillvalue: "" + }) + } + + delshixunsskilllist = (key) => { + let {shixunsskillvaluelist} = this.state; + let newshixunsskillvaluelist = shixunsskillvaluelist; + newshixunsskillvaluelist.splice(key, 1); + this.setState({ + shixunsskillvaluelist: newshixunsskillvaluelist + }) + } + + editPracticesend=()=>{ + + this.setState({ + editPracticesendtype:true + }) + + let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,checkpointId,exec_time} = this.state; + + const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim(); + + let id = this.props.match.params.shixunId; + + let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json"; + + if (shixunCreatePractice === undefined||shixunCreatePractice=="") { + // this.setState({ + // shixunCreatePracticetype: true + // }) + this.props.showSnackbar("任务名称为空") + $('html').animate({ + scrollTop: 10 + }, 1000); + this.setState({ + editPracticesendtype:false + }) + return + } + + if (shixunsskillvaluelist.length === 0) { + // this.setState({ + // shixunsskillvaluelisttype: true + // }) + this.props.showSnackbar("技能标签为空") + this.setState({ + editPracticesendtype:false + }) + return + } + + if(exec_time===null||exec_time===undefined||exec_time===""){ + + this.setState({ + shixunExec_timeType:false + }) + return + } + axios.put(url, { + tab:0, + identifier:id, + id:checkpointId, + challenge:{ + subject: shixunCreatePractice, + task_pass: exercise_editormdvalue, + difficulty: shixunCreatePracticeGroup, + score: onshixunsmarkvalue, + exec_time:exec_time + }, + challenge_tag:shixunsskillvaluelist + }).then((response) => { + this.props.showSnackbar(response.data.messages); + if (response.data.status === 1) { + window.location.href=`/shixuns/${id}/challenges/${checkpointId}/tab=2`; + this.setState({ + setopen: true, + editPracticesendtype:false, + tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2", + tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3", + }) + // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2" + } + }).catch((error) => { + console.log(error) + }); + + + } + + onshixunsmarks=()=> { + this.setState({ + marktype:true + }) + } + + onshixunsmarkss=()=> { + this.setState({ + marktype:false + }) + } + + setexec_time=(e)=>{ + this.setState({ + exec_time:e.target.value + }) + } + render() { + + let shixuntype = this.props.match.params.type; + + + let {marktype, + shixunCreatePracticetype, shixunsskillvaluelisttype, + choice_url, practice_url, go_back_url, position, task_pass_default, submit_url, setopen,checkpointId,prev_challenge,next_challenge,power, + shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvalue, shixunsskillvaluelist, tab2url, tab3url,optionsums, + CreatePracticesendtype,editPracticesendtype + } = this.state; + + let options; + if(optionsums!=undefined){ + options = optionsums.map((d, k) => { + return ( + <Option key={d} id={k}>{d}</Option> + ) + }) + } + + return ( + <React.Fragment> + <div className="educontent mt30 mb30"> + <div className="padding10-20 mb10 edu-back-white clearfix"> + <span className="fl ring-blue mr10 mt7"> + <img src={getImageUrl("images/educoder/icon/code.svg")} data-tip-down="实训任务" className="fl mt2 ml2"/> + </span> + <span className="font-16 task-hide fl TPMtaskName">第{position}关</span> + + <Link to={go_back_url === undefined ? "" : go_back_url} + className="color-grey-6 fr font-15 mt3">返回</Link> + { next_challenge===undefined?"": + <a href={next_challenge}className="fr color-blue mr15 mt4">下一关</a> + } + { prev_challenge===undefined?"": + <a href={prev_challenge} className="fr color-blue mr15 mt4">上一关</a> + } + + + + + <a href={practice_url === undefined ? "" : practice_url} + className="fr color-blue mr15 mt4" + style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} + data-tip-down="新增代码编辑类型的任务">+ 实践类型</a> + + <a href={choice_url === undefined ? "" : choice_url} + className="fr color-blue mr15 mt4" + style={{display:this.props.identity>4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}} + data-tip-down="新增选择题类型的任务">+ 选择题类型</a> + + </div> + + <div className="challenge_nav clearfix edu-back-white"> + + <li className="active"> + <a>本关任务</a> + </li> + + <li className=""> + {tab2url === "" ? <span>评测设置</span> : <Link to={tab2url}>评测设置</Link>} + </li> + + <li className=""> + {tab3url === "" ? <span>参考答案</span> : <Link to={tab3url}>参考答案</Link>} + + </li> + </div> + + <div className="edu-back-white mb10 clearfix"> + <div className="padding40-20"> + <p className="color-grey-6 font-16 mb30">任务名称</p> + <div className="df"> + <span className="mr30 color-orange pt10">*</span> + <div className="flex1 mr20"> + <input type="text" + // className="input-100-45 greyInput" + className={shixunCreatePracticetype===true?"input-100-45 greyInpus wind100":"input-100-45 greyInput "} + maxLength="50" + name="challenge[subject]" + value={shixunCreatePractice} + onInput={this.shixunCreatePractice} + placeholder="请输入任务名称(此信息将提前展示给学员),例:计算学生的课程成绩绩点"/> + </div> + <div style={{width: '57px'}}> + <span + className={shixunCreatePracticetype === true ? "color-orange mt8 fl block" : "color-orange mt8 fl none"} + id="new_shixun_name"><i + className="fa fa-exclamation-circle mr3"></i>必填项</span> + </div> + </div> + </div> + </div> + + + <div className="edu-back-white padding40-20 mb20"> + + <p className="color-grey-6 font-16 mb30">过关任务</p> + + <TPMMDEditor ref={this.exercisememoMDRef} placeholder="请输入选择题的题干内容" mdID={'exercisememoMD'} refreshTimeout={1500} + watch={true} className="courseMessageMD" initValue={this.state.exercisememoMDRefval} height={700}></TPMMDEditor> + + <p id="e_tip_Memochallengesnew" className="edu-txt-right color-grey-cd font-12"></p> + <p id="e_tips_Memochallengesnew" className="edu-txt-right color-grey-cd font-12"></p> + </div> + + + <div className="edu-back-white padding40-20 mb20"> + <p className="color-grey-6 font-16 mb30">难度系数</p> + <div className="clearfix mb40"> + + <RadioGroup value={shixunCreatePracticeGroup} className="fl mr40" + disabled={this.props.status===2?true:false} + onChange={this.props.status===2?"":this.onshixunCreatePracticeChange}> + <Radio value={1}>简单</Radio> + <Radio value={2}>中等</Radio> + <Radio value={3}>困难</Radio> + </RadioGroup> + + </div> + <p className="color-grey-6 font-16 mb30">奖励经验值</p> + <div className="clearfix" + // onMouseLeave={this.props.status===2?"":this.onshixunsmarkss} + > + <span className="fl mr30 color-orange pt10">*</span> + + <Select style={{width: 120}} className="winput-240-40 fl" + id="challenge_score" + onChange={this.props.status===2?"":this.onshixunsmark} + // onMouseEnter={this.props.status===2?"":this.onshixunsmarks} + disabled={this.props.status===2?true:false} + // open={marktype} + value={onshixunsmarkvalue} + getPopupContainer={triggerNode => triggerNode.parentNode} + > + {options} + </Select> + + <p className="fl color-grey-9 font-12 ml20"> + 如果学员答题错误,则不能得到相应的经验值<br/> + 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币 + </p> + + <span className="color-orange mt7 fl ml20 none" id="ex_value_notice"><i + className="fa fa-exclamation-circle mr3"></i>必填项</span> + </div> + </div> + + + <div className="edu-back-white padding40-20 mb20"> + <p className="color-grey-6 font-16 mb30">技能标签</p> + <div className="clearfix df"> + <span className="mr30 color-orange pt10">*</span> + <div className="flex1"> + <Input type="text" + className="winput-240-40 fl mr20 winput-240-40s" + id="input_task_tag" + placeholder="添加标签" + onInput={this.shixunsskill} + value={shixunsskillvalue} + onPressEnter={this.clickshixunsskill} + onBlur={this.clickshixunsskill} + /> + {/*<a className="white-btn orange-btn fl mt1 use_scope-btn ml20 mt5 mr20"*/} + {/*onClick={this.clickshixunsskill}>+ 添加</a>*/} + <div className="ml15 color-grey-9 mt5">学员答题正确将获得技能,否则不能获得技能</div> + <div className="mt20 clearfix" id="task_tag_content"> + + { + shixunsskillvaluelist===undefined?"":shixunsskillvaluelist.length === 0 ? "" : shixunsskillvaluelist.map((itme, key) => { + return ( + <li className="task_tag_span" key={key}><span>{itme}</span> + <a onClick={() => this.delshixunsskilllist(key)}>×</a> + </li> + ) + }) + } + + + </div> + </div> + <span + className={shixunsskillvaluelisttype === true ? "color-orange mt7 fl ml20 block" : " color-orange mt7 fl ml20 none"} + id="stage_name_notice"> + <i className="fa fa-exclamation-circle mr3"></i>必填项</span> + </div> + </div> + + <div className="edu-back-white padding40-20 mb20"> + <p className="color-grey-6 font-16 mb30">服务配置</p> + <div className="clearfix mb5"> + <span className="color-orange pt10 fl">*</span> + <label className="panel-form-label fl">评测时限(S):</label> + <div className="pr fl with80 status_con"> + <input value={this.state.exec_time} className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" onInput={this.setexec_time}/> + </div> + <span + className={this.state.shixunExec_timeType === true ? "color-orange mt8 fl block ml20" : "color-orange mt8 fl none"} + id="new_shixun_name"><i className="fa fa-exclamation-circle mr3"></i>必填项</span> + <div className="cl"></div> + </div> + </div> + + <div className="clearfix mt30" + style={{display:this.props.identity>4||this.props.identity===undefined?"none":'block'}} + > + {checkpointId===undefined?<a className="defalutSubmitbtn fl mr20" onClick={CreatePracticesendtype===true?"":this.CreatePracticesend}>提交</a>: + <a className="defalutSubmitbtn fl mr20" onClick={editPracticesendtype===true?"":this.editPracticesend}>提交</a>} + {/*<a href={go_back_url === undefined ? "" : go_back_url} className="defalutCancelbtn fl">取消</a>*/} + <Link to={go_back_url === undefined ? "" : go_back_url} className={"defalutCancelbtn fl"}>取消</Link> + </div> + </div> + </React.Fragment> + ) + } +} + + diff --git a/public/stylesheets/educoder/edu-all.css b/public/stylesheets/educoder/edu-all.css index 154be61be..4b663de87 100644 --- a/public/stylesheets/educoder/edu-all.css +++ b/public/stylesheets/educoder/edu-all.css @@ -401,9 +401,9 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin- .task-colspan{min-width:25%;text-align: left;display: block;float: left;color: #999; } .colspan-grey{border-radius: 12px;background-color: #E6E6E6;padding: 3px 10px;color: #747A7F} /*新建任务*/ -.challenge_nav{padding: 40px 20px 0px 20px;border-bottom: 1px solid #eee;} -.challenge_nav li{width: auto;float: left;margin-right: 40px;position: relative} -.challenge_nav li.active:after{position: absolute;content: '';width: 50%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;} +.challenge_nav{padding: 20px 20px 0px 20px;border-bottom: 1px solid #eee;} +.challenge_nav li{width: auto;float: left;margin-right: 20px;position: relative} +.challenge_nav li.active:after{position: absolute;content: '';width:76%;background-color: #4CACFF;height: 3px;border-radius: 2px;left: 25%;bottom: 0px;} .challenge_nav li a{display: block;width: 100%;padding-bottom: 20px;} .add_choose_type{width: 60px;height: 20px;line-height: 19px;border-radius: 2px;background-color: #eaeaea;color: #999!important;display: block;float: left;text-align: center;margin-top: 4px;}