diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index 9e37571b1..39401d079 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -494,7 +494,15 @@ class StudentWorksController < ApplicationController # 删除实训作品评阅 def destroy_work_comment ActiveRecord::Base.transaction do - @work.shixun_work_comments.find_by!(id: params[:comment_id]).destroy_all + tip_exception("visible_comment参数有误") if params[:visible_comment].nil? + + comment = @work.shixun_work_comments.find_by!(id: params[:comment_id]) + params[:visible_comment] ? comment.comment = nil : comment.hidden_comment = nil + if comment.comment.nil? && comment.hidden_comment.nil? + comment.destroy! + else + comment.save! + end normal_status("删除成功") end end diff --git a/app/views/student_works/shixun_work_report.json.jbuilder b/app/views/student_works/shixun_work_report.json.jbuilder index e8e3af057..e63cc2c13 100644 --- a/app/views/student_works/shixun_work_report.json.jbuilder +++ b/app/views/student_works/shixun_work_report.json.jbuilder @@ -39,6 +39,7 @@ if @shixun challenge_comment = @work.shixun_work_comments.find_by(challenge_id: game.challenge_id) json.challenge_comment challenge_comment&.comment json.challenge_comment_hidden challenge_comment&.hidden_comment + json.comment_id challenge_comment&.id end end @@ -59,6 +60,7 @@ if @shixun # 评阅信息 json.work_comment @comment&.comment json.work_comment_hidden @user_course_identity < Course::STUDENT ? @comment&.hidden_comment : nil + json.comment_id @comment&.id # 图形统计 # 1: 效率 diff --git a/public/react/src/modules/tpm/TPMIndex.js b/public/react/src/modules/tpm/TPMIndex.js index 00a88cd21..67779af8d 100644 --- a/public/react/src/modules/tpm/TPMIndex.js +++ b/public/react/src/modules/tpm/TPMIndex.js @@ -190,6 +190,8 @@ class TPMIndex extends Component { identity: response.data.identity, propaedeutics:response.data.propaedeutics, status: response.data.shixun_status, + secret_repository: response.data.secret_repository, + }); } }).catch((error) => { @@ -285,6 +287,10 @@ class TPMIndex extends Component { (props) => () }> + () + }> ( () }> + () + }> + {/* */} + {/* */} { loadingContent ? : { this.fetchRepo() @@ -72,7 +78,8 @@ class TPMRepositoryComponent extends Component { let id = this.props.match.params.shixunId; let url = `/shixuns/${id}/file_content.json`; axios.post(url, { - path: path + path: path, + secret_repository: this.props.secret_repository_tab }).then((response) => { trace_collapse('repository res: ', response) @@ -138,7 +145,7 @@ class TPMRepositoryComponent extends Component { const path = urlNewPathArray.join('/') let id = this.props.match.params.shixunId; - let url = `/shixuns/${id}/repository.json`; + let url = `/shixuns/${id}/${this.props.secret_repository_tab ? 'secret_repository' : 'repository'}.json`; // this.props.setLoadingContent(true) axios.post(url, { path: path ? path : '' diff --git a/public/react/src/modules/tpm/TPMsettings/TPMsettings.js b/public/react/src/modules/tpm/TPMsettings/TPMsettings.js index a8917fd02..5e27cb41c 100644 --- a/public/react/src/modules/tpm/TPMsettings/TPMsettings.js +++ b/public/react/src/modules/tpm/TPMsettings/TPMsettings.js @@ -353,6 +353,8 @@ export default class TPMsettings extends Component { test_set_permission: response.data.shixun.test_set_permission, hide_code: response.data.shixun.hide_code, code_hidden: response.data.shixun.code_hidden, + is_secret_repository: response.data.shixun.is_secret_repository, + init_is_secret_repository: response.data.shixun.is_secret_repository, forbid_copy: response.data.shixun.forbid_copy, vnc: response.data.shixun.vnc, vnc_evaluate: response.data.shixun.vnc_evaluate, @@ -439,20 +441,52 @@ export default class TPMsettings extends Component { SelectshixunCommand=(e)=>{ // console.log( e.target.value) - this.setState({ - webssh: e.target.value, - }); - if(e.target.value===2){ - this.setState({ - SelectTheCommandtype: true, - multi_webssh:false - }); - }else{ - this.setState({ - SelectTheCommandtype: false, - multi_webssh:false - }); - } + const webssh = e.target.value + if (webssh == 2) { + this.setState({ + webssh: webssh, + SelectTheCommandtype: true, + multi_webssh:false + }); + } else { + if (this.state.init_is_secret_repository && !this.state.vnc) { + this.confirmDeleteSecretRepo({ + onOk: () => { + this.setState({ + webssh: webssh, + SelectTheCommandtype: false, + multi_webssh:false + }); + } + }) + } else { + if (!this.state.vnc) { + this.setState({ + is_secret_repository: false, + }) + } + this.setState({ + webssh: webssh, + SelectTheCommandtype: false, + multi_webssh:false + }); + } + } + + // this.setState({ + // webssh: webssh, + // }); + // if(webssh===2){ + // this.setState({ + // SelectTheCommandtype: true, + // multi_webssh:false + // }); + // }else{ + // this.setState({ + // SelectTheCommandtype: false, + // multi_webssh:false + // }); + // } } SelectOpenpublic=(e)=>{ @@ -525,6 +559,35 @@ export default class TPMsettings extends Component { }); } + confirmDeleteSecretRepo = ({title, onOk}) => { + confirm({ + title: title ||
+
已创建的私密版本库及其内容,将在“保存”时被删除。
+
是否确认取消勾选?
+
, + okText: '确定', + cancelText: '取消', + onOk: () => { + this.setState({ is_secret_repository: false }) + onOk && onOk() + }, + onCancel() { + }, + }); + } + is_secret_repository = (e) => { + const checked = e.target.checked + if (!checked) { + if (this.state.init_is_secret_repository) { + this.confirmDeleteSecretRepo({ + }) + } else { + this.setState({ is_secret_repository: false }) + } + } else { + this.setState({ is_secret_repository: true }) + } + } forbid_copy = (e) => { let sum = "" if (e.target.checked === false) { @@ -550,11 +613,34 @@ export default class TPMsettings extends Component { // } else if (e.target.checked === true) { // sum = 1 // } - this.setState({ - vnc: e.target.checked, - vnc_evaluate: false, - }); - + const vnc = e.target.checked; + if (!vnc) { + if (this.state.init_is_secret_repository && this.state.webssh != 2) { + this.confirmDeleteSecretRepo({ + onOk: () => { + this.setState({ + vnc: e.target.checked, + vnc_evaluate: false, + }); + } + }) + } else { + if (this.state.webssh != 2) { + this.setState({ + is_secret_repository: false + }) + } + this.setState({ + vnc: e.target.checked, + vnc_evaluate: false, + }); + } + } else { + this.setState({ + vnc: e.target.checked, + vnc_evaluate: false, + }); + } } shixunsname = (e) => { // let {shixunsstatus}=this.state; @@ -782,7 +868,7 @@ export default class TPMsettings extends Component { let { name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate, evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh, - opening_time,shixunmemoMDvalue,shixun_service_configlist + opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository } = this.state; let newshixun_service_configlist = shixun_service_configlist.map(v => { @@ -886,6 +972,7 @@ export default class TPMsettings extends Component { let Url = `/shixuns/` + id + `.json`; let data = { shixun:{ + name: name, webssh: webssh, use_scope: use_scope, @@ -906,6 +993,7 @@ export default class TPMsettings extends Component { description: description_editormd, evaluate_script: evaluate_script_editormd, }, + is_secret_repository: is_secret_repository, main_type: choice_main_type, small_type: choice_small_type, scope_partment: scope_partment, @@ -1460,6 +1548,7 @@ export default class TPMsettings extends Component { name, settingsData, webssh, + is_secret_repository, use_scope, shixunsID, can_copy, @@ -2199,6 +2288,15 @@ export default class TPMsettings extends Component { + { (vnc || webssh == 2) &&
+ 私密版本库: + + + + +
} +
禁用复制粘贴: @@ -2239,7 +2337,7 @@ export default class TPMsettings extends Component { VNC图形化评测: - +
:""} diff --git a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js index 491751b6a..dd074fc0d 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js +++ b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js @@ -240,6 +240,7 @@ export default class TPMevaluation extends Component { this.setState({ evaluationlist:newevaluationlist }) + console.log(newevaluationlist) } @@ -539,6 +540,14 @@ export default class TPMevaluation extends Component { this.setevaluationlist(newevaluationlist); } + // 修改测试集的匹配规则 + changeEvaluationRule=(e,key)=>{ + let {evaluationlist}=this.state; + let newevaluationlist=evaluationlist; + newevaluationlist[key].match_rule=e.target.value + this.setevaluationlist(newevaluationlist); + } + evaluationoninputvalue=(e,key,type)=>{ $.fn.autoHeight = function(){ function autoHeight(elem){ @@ -1159,6 +1168,13 @@ export default class TPMevaluation extends Component { autoHeight="true" onInput={(e)=>this.evaluationoninputvalue(e,key,"yq")} > +
+ 匹配规则: + this.changeEvaluationRule(e,key)}> + 完全匹配 + 末尾匹配 + +
) })} diff --git a/public/react/src/modules/tpm/component/TPMNav.js b/public/react/src/modules/tpm/component/TPMNav.js index 1683c59a0..ce74be13b 100644 --- a/public/react/src/modules/tpm/component/TPMNav.js +++ b/public/react/src/modules/tpm/component/TPMNav.js @@ -5,7 +5,7 @@ import { BrowserRouter as Router, Route, Link } from "react-router-dom"; class TPMNav extends Component { render() { - const { user, match, shixun } = this.props; + const { user, match, shixun, secret_repository } = this.props; let isAdminOrCreator = false; if (user) { isAdminOrCreator = user.admin || user.manager @@ -30,7 +30,10 @@ class TPMNav extends Component { 4||this.props.identity===undefined ? "none" : 'block'}} - className={`${match.url.indexOf('repository') != -1 ? 'active' : ''} fl mr40`}>版本库 + className={`${match.url.indexOf('/repository') != -1 ? 'active' : ''} fl mr40`}>版本库 + {secret_repository && 4||this.props.identity===undefined ? "none" : 'block'}} + className={`${match.url.indexOf('secret_repository') != -1 ? 'active' : ''} fl mr40`}>私密版本库} 合作者 diff --git a/public/react/src/modules/tpm/component/modal/RepositoryChooseModal.js b/public/react/src/modules/tpm/component/modal/RepositoryChooseModal.js new file mode 100644 index 000000000..58839f334 --- /dev/null +++ b/public/react/src/modules/tpm/component/modal/RepositoryChooseModal.js @@ -0,0 +1,153 @@ +import React, { useState, useEffect, memo } from 'react'; +import axios from 'axios' +import { Modal, Input } from 'antd'; + +function RepositoryChooseModal(props) { + const [trees, setTrees] = useState([]) + const [path, setPath] = useState('') + const [pathArray, setPathArray] = useState([{val: "根目录/", path: ""}]) + const [modalVisible, setModalVisible] = useState(true) + + useEffect(() => { + repository('') + }, []) + function onOk() { + + } + function onCancel() { + + } + /** + 点nav 会传入key + 点item 会传入 newPath + + item => name, type type tree/leaf + */ + const repository=(item, key, newPath)=>{ + let newPathArray = [] // + // + if (key) { + for(var i=0; i<=key; i++){ + newPathArray.push(pathArray[i]) + } + } else if (item) { + newPathArray = pathArray.slice(0) + newPathArray.push({val: item.name, path: pathArray[pathArray.length - 1] + "/" + item.name}) + } + + const path = item || key ? newPathArray[newPathArray.length - 1] : '' + + let id = props.match.params.shixunId; + let url ="/shixuns/"+id+"/repository.json"; + axios.post(url,{ + path: path + }).then((response) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + setTrees(response.data.trees) + setPath(path) + pathArray(newPathArray) + } + + }).catch((error) => { + console.log(error) + }); + } + const savegetfilepath=(value)=>{ + const state = {} + let {selectpath,saveshixunfilepath,pathtype} = state + + if(pathtype===1){ + let newselectpath; + + if(saveshixunfilepath==="shixunfilepathplay"){ + newselectpath=value + }else{ + const type = selectpath.split(';'); + let types=false; + for(var i=0; i{ + + } + function sendgetfilepath() { + + } + return ( + +
+
+ +
+ + saveselectpath(e)} + value={path}/> +
+ + onOk()}>确定 + onCancel()}>取消 +
+
+
+ ) + +} + +export default RepositoryChooseModal \ No newline at end of file diff --git a/public/react/src/modules/tpm/shixunchild/Repository/Repository.js b/public/react/src/modules/tpm/shixunchild/Repository/Repository.js index a62151126..58379b1e8 100644 --- a/public/react/src/modules/tpm/shixunchild/Repository/Repository.js +++ b/public/react/src/modules/tpm/shixunchild/Repository/Repository.js @@ -15,7 +15,7 @@ import { trace, trace_collapse ,getImageUrl, toPath} from "educoder"; import RepositoryDirectories from './RepositoryDirectories' import { ActionBtn , NoneData } from 'educoder' - +import RepositoryCombinePath from './RepositoryCombinePath' const $ = window.$; // 点击按钮复制功能 @@ -85,10 +85,13 @@ class Repository extends Component { className=" guideBtn" >Git使用指南 { this.props.current_user && (this.props.current_user.admin ==true || (TPMRightSectionData && TPMRightSectionData.creator && TPMRightSectionData.creator.login == this.props.current_user.login)) ? - +添加文件:"" + !this.props.secret_repository_tab && + +添加文件 + :"" } +
+ {this.props.secret_repository_tab && + + } + @@ -181,7 +188,7 @@ class Repository extends Component { {commits===undefined?"":commits[0].time} :{commits===undefined?"":commits[0].title} - 提交记录 diff --git a/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCodeEditor.js b/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCodeEditor.js index bd7c8355b..51f6e35f2 100644 --- a/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCodeEditor.js +++ b/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCodeEditor.js @@ -121,6 +121,7 @@ class RepositoryCodeEditor extends Component { const path = pathArray.join('/') this.setState({ codeSaving: true }) axios.post(url, { + secret_repository: this.props.secret_repository_tab, content: this.extend_editor.getValue(), // type: forTest === true ? 1 : 0, path: path diff --git a/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCombinePath.js b/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCombinePath.js new file mode 100644 index 000000000..aba008e20 --- /dev/null +++ b/public/react/src/modules/tpm/shixunchild/Repository/RepositoryCombinePath.js @@ -0,0 +1,82 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import { trace_collapse, WordsBtn } from 'educoder' + +import { message, Input } from 'antd'; + + +const $ = window.$; + + +class RepositoryCombinePath extends Component { + constructor(props) { + super(props) + this.state = { + value: this.props.secret_dir_path || '', + isEdit: false, + } + } + + onSave = () => { + const { shixunId, pathArray } = this.props; + const url = `/shixuns/${shixunId}/set_secret_dir.json` + + this.setState({ codeSaving: true }) + axios.post(url, { + secret_dir_path: this.state.value + } + ).then((response) => { + if (response.data) { + message.success('保存成功'); + this.setState({isEdit: false}) + } + }) + } + onChange = (e) => { + const { value } = e.target; + this.setState({ value }) + } + onEdit = () => { + this.setState({isEdit: true}, () => { + window.$('.combinePathEditRow input')[0].focus() + }); + } + render() { + const { fileContent, match, saveCode } = this.props; + const { isEdit, value } = this.state; + return ( + +
+ + 第一版本库合并路径: + + {!isEdit && 修改} + {isEdit && 保存} +
+ + + ); + } +} +export default RepositoryCombinePath; diff --git a/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js b/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js index d0499a76c..663c5fcf3 100644 --- a/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js +++ b/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js @@ -34,7 +34,9 @@ class TPMRepositoryCommits extends Component { let id = this.props.match.params.shixunId; let collaborators=`/shixuns/`+id+`/commits.json`; - axios.post(collaborators).then((response)=> { + axios.post(collaborators, { + secret_repository: this.props.secret_repository_tab + }).then((response)=> { if(response.status===200){ this.setState({