Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

dev_cs
caicai8 6 years ago
commit 5366784807

@ -497,17 +497,68 @@ class ExerciseQuestionsController < ApplicationController
ex_obj_score = @exercise_current_user.objective_score #全部客观题得分 ex_obj_score = @exercise_current_user.objective_score #全部客观题得分
ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分 ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分
ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分 ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分
if @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分, if @exercise_question.question_type == Exercise::MULTIPLE
if ex_answers.present? #学生有回答时 取学生的答题得分否则0分
answer_choice_array = []
ex_answers.each do |a|
answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置
end
user_answer_content = answer_choice_array.sort
standard_answer = @exercise_question.exercise_standard_answers.pluck(:exercise_choice_id).sort
if standard_answer.size == 1 # 老数据需要判断学生答题是否正确, 正确取原题得分否则是0分
standard_answer = standard_answer.first.to_s.split("").map(&:to_i).sort
if user_answer_content == standard_answer
ex_answer_old = @exercise_question.question_score
else
ex_answer_old = 0
end
else # 新多选题只需取第一条答题记录的得分
ex_answer_old = ex_answers.first.score > 0 ? ex_answers.first.score : 0
end
ex_answers.update_all(:score => @c_score) #所有的正确选项需重新更新
else
answer_option = {
:user_id => @user_id,
:exercise_question_id => @exercise_question.id,
:score => @c_score,
:answer_text => ""
}
ExerciseAnswer.create(answer_option)
ex_answer_old = 0
end
new_obj_score = ex_obj_score - ex_answer_old + @c_score
total_scores = new_obj_score + ex_subj_score
ex_scores = {
:objective_score => new_obj_score,
:score => total_scores
}
@exercise_current_user.update_attributes(ex_scores)
elsif @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分,
if ex_answers.exists?
ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和
each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数 each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数
new_obj_score = ex_obj_score - ex_answer_old + @c_score new_obj_score = ex_obj_score - ex_answer_old + @c_score
ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新
else #如果学生未答,则创建新的答题记录
answer_option = {
:user_id => @user_id,
:exercise_question_id => @exercise_question.id,
:score => @c_score,
:answer_text => ""
}
ExerciseAnswer.create(answer_option)
new_obj_score = ex_obj_score + @c_score
end
total_scores = new_obj_score + ex_subj_score total_scores = new_obj_score + ex_subj_score
ex_scores = { ex_scores = {
:objective_score => new_obj_score, :objective_score => new_obj_score,
:score => total_scores :score => total_scores
} }
@exercise_current_user.update_attributes(ex_scores) @exercise_current_user.update_attributes(ex_scores)
ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新
elsif @exercise_question.question_type == Exercise::SUBJECTIVE #当为主观题时 elsif @exercise_question.question_type == Exercise::SUBJECTIVE #当为主观题时
if ex_answers.exists? if ex_answers.exists?
ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0取0 ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0取0
@ -579,7 +630,7 @@ class ExerciseQuestionsController < ApplicationController
end end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception("没有权限") tip_exception(e.message)
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
end end
end end
@ -703,8 +754,8 @@ class ExerciseQuestionsController < ApplicationController
normal_status(-1,"用户不存在!") normal_status(-1,"用户不存在!")
elsif @c_score.blank? elsif @c_score.blank?
normal_status(-1,"分数不能为空!") normal_status(-1,"分数不能为空!")
elsif @exercise_question.question_type <= Exercise::JUDGMENT elsif @exercise_question.question_type == Exercise::SINGLE || @exercise_question.question_type == Exercise::JUDGMENT
normal_status(-1,"题/判断题不能调分!") normal_status(-1,"选题/判断题不能调分!")
elsif params[:comment].present? && params[:comment].length > 100 elsif params[:comment].present? && params[:comment].length > 100
normal_status(-1,"评语不能超过100个字符!") normal_status(-1,"评语不能超过100个字符!")
else else

@ -0,0 +1,10 @@
class ShixunListsController < ApplicationController
def index
@results = ShixunSearchService.call(search_params)
end
private
def search_params
params.permit(:keyword, :type, :page, :per_page, :order, :type, :status, :diff)
end
end

@ -1,6 +1,7 @@
class ShixunsController < ApplicationController class ShixunsController < ApplicationController
include ShixunsHelper include ShixunsHelper
include ApplicationHelper include ApplicationHelper
include ElasticsearchAble
before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list, before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list,
:discusses, :collaborators, :fork_list, :propaedeutics] :discusses, :collaborators, :fork_list, :propaedeutics]
@ -131,8 +132,16 @@ class ShixunsController < ApplicationController
offset = (page.to_i - 1) * (limit.to_i) offset = (page.to_i - 1) * (limit.to_i)
order = params[:order] || "desc" order = params[:order] || "desc"
## 搜索关键字创建者、实训名称、院校名称 ## 搜索关键字创建者、实训名称、院校名称
keyword = params[:search].blank? ? "*" : params[:search] keyword = params[:keyword].to_s.strip.presence || '*'
@shixuns = Shixun.search keyword, where: {id: @shixuns.pluck(:id)}, order: {"myshixuns_count" => order}, limit: limit, offset: offset
model_options = {
index_name: [Shixun],
model_includes: Shixun.searchable_includes
}
model_options.merge(where: { id: @shixuns.pluck(:id) }).merge(order: {"myshixuns_count" => order}).merge(limit: limit, offset: offset)
model_options.merge(default_options)
@shixuns = Searchkick.search(keyword, model_options)
# @shixuns = Shixun.search keyword, where: {id: @shixuns.pluck(:id)}, order: {"myshixuns_count" => order}, limit: limit, offset: offset
@total_count = @shixuns.total_count @total_count = @shixuns.total_count
end end

@ -51,13 +51,12 @@ module Searchable::Shixun
visits_count: visits, visits_count: visits,
challenges_count: challenges_count, challenges_count: challenges_count,
study_count: myshixuns_count, study_count: myshixuns_count,
description: description
} }
end end
module ClassMethods module ClassMethods
def searchable_includes def searchable_includes
{ user: { user_extension: :school } } [ :shixun_info, user: { user_extension: :school } ]
end end
end end
end end

@ -28,9 +28,11 @@ module ElasticsearchAble
end end
def body_options def body_options
{ hash = {}
min_score: EduSetting.get('es_min_score') || 10
} hash[:min_score] = (EduSetting.get('es_min_score') || 10) if keyword != '*'
hash
end end
def per_page def per_page

@ -0,0 +1,56 @@
class ShixunSearchService < ApplicationService
include ElasticsearchAble
attr_reader :params
def initialize(params)
@params = params
end
def call
# 全部实训/我的实训
type = params[:type] || "all"
# 状态:已发布/未发布
status = params[:status] || "all"
# 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭)
if type == "mine"
@shixuns = User.current.shixuns.none_closed
else
if User.current.admin? || User.current.business?
@shixuns = Shixun.none_closed.where(hidden: 0)
else
none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
@shixuns = Shixun.where.not(id: none_shixun_ids).none_closed.where(hidden: 0)
end
end
unless status == "all"
@shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1])
end
## 筛选 难度
if params[:diff].present? && params[:diff].to_i != 0
@shixuns = @shixuns.where(trainee: params[:diff])
end
Shixun.search(keyword, search_options)
end
private
def search_options
model_options = {
includes: Shixun.searchable_includes
}
model_options.merge!(where: { id: @shixuns.pluck(:id) })
model_options.merge!(order: {"myshixuns_count" => sort_str})
model_options.merge!(default_options)
model_options
end
def sort_str
params[:order] || "desc"
end
end

@ -1,4 +1,4 @@
# json.shixun_list @shixuns do |shixun| # json.shixun_lists @shixuns do |shixun|
# json.shixun_identifier shixun.identifier # json.shixun_identifier shixun.identifier
# json.name shixun.name # json.name shixun.name
# json.creator shixun.user&.full_name # json.creator shixun.user&.full_name

@ -0,0 +1,23 @@
json.shixuns_count @results.total_count
json.shixun_list do
json.array! @results.with_highlights(multiple: true) do |obj, highlights|
puts obj
json.merge! obj.to_searchable_json
json.challenge_names obj.challenges.pluck(:subject)
# 去除开头标点符号
reg = /^[,。?:;‘’!“”—……、]/
highlights[:description]&.first&.sub!(reg, '')
highlights[:content]&.first&.sub!(reg, '')
json.title highlights.delete(:name)&.join('...') || obj.searchable_title
json.description highlights[:description]&.join('...') || obj.description
json.content highlights
json.level level_to_s(obj.trainee)
json.subjects obj.subjects.uniq do |subject|
json.(subject, :id, :name)
end
end
end

@ -10,7 +10,7 @@ json.shixun_list do
# json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('<br/>') # json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('<br/>')
json.content highlights json.content highlights
json.level level_to_s(obj.trainee) json.level level_to_s(obj.trainee)
json.subjects obj.subjects do |subject| json.subjects obj.subjects.uniq do |subject|
json.(subject, :id, :name) json.(subject, :id, :name)
end end
end end

@ -174,7 +174,10 @@ Rails.application.routes.draw do
end end
end end
resources :shixun_lists
resources :shixuns, param: :identifier do resources :shixuns, param: :identifier do
collection do collection do
get :menus get :menus
get :get_recommend_shixuns get :get_recommend_shixuns
@ -182,7 +185,7 @@ Rails.application.routes.draw do
get :get_mirror_script get :get_mirror_script
post :apply_shixun_mirror post :apply_shixun_mirror
get :download_file get :download_file
get :shixun_list get :shixun_lists
end end
member do member do

Binary file not shown.

@ -326,6 +326,20 @@ class App extends Component {
}); });
wx.ready(function () { wx.ready(function () {
console.log('wx is ready') console.log('wx is ready')
// var shareData = {
// title: 'EduCoder - 首页',
// desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台提供企业级工程实训以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动将传统的知识传授和时兴的工程实战一体化。',
// link: currentUrl,
// imgUrl: window.__testImageUrl
// || (currentUrl.endsWith('/') ? currentUrl : currentUrl + '/') + 'react/build/images/share_logo_icon.jpg'
// };
// wx.onMenuShareAppMessage(shareData);//分享给好友
// wx.onMenuShareTimeline(shareData);//分享到朋友圈
// wx.onMenuShareQQ(shareData);//分享给手机QQ
// wx.onMenuShareWeibo(shareData);//分享腾讯微博
// wx.onMenuShareQZone(shareData);//分享到QQ空间
configShareForIndex('/') configShareForIndex('/')
}); });
wx.error(function (res) { wx.error(function (res) {

@ -1,4 +1,4 @@
const host = window.location.host const host = window.location.protocol + '//' + window.location.host
const wx = window.wx const wx = window.wx
function share(shareData) { function share(shareData) {
try { try {

@ -174,7 +174,7 @@ class TPIContextProvider extends Component {
} }
let testPath = '' let testPath = ''
if (window.location.port == 3007) { if (window.location.port == 3007) {
testPath = 'http://pre-newweb.educoder.net' testPath = 'http://test-newweb.educoder.net'
} }
// var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time` // var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time`
var url = `${testPath}/api/tasks/${ game.identifier }/cost_time` var url = `${testPath}/api/tasks/${ game.identifier }/cost_time`
@ -268,12 +268,14 @@ pop_box_new(htmlvalue, 480, 182);
}); });
} }
onPathChange(index) { onPathChange(index, callback) {
let { challenge } = this.state; let { challenge } = this.state;
// challenge = Object.assign({}, challenge) // challenge = Object.assign({}, challenge)
// challenge.pathIndex = index; // challenge.pathIndex = index;
this.setState({ this.setState({
challenge: update(challenge, {pathIndex: { $set: index }}), challenge: update(challenge, {pathIndex: { $set: index }}),
}, () => {
callback && callback()
}) })
// TODO load new path content // TODO load new path content
} }

@ -305,7 +305,7 @@ class CoursesIndex extends Component{
//Do your stuff here //Do your stuff here
}); });
} }
//更新左边课堂导航
updataleftNav=()=>{ updataleftNav=()=>{
let query=this.props.location.pathname let query=this.props.location.pathname
let {isaloadtype}=this.state; let {isaloadtype}=this.state;

@ -29,11 +29,13 @@ class Elearning extends Component{
userlogin:"", userlogin:"",
isRender:false, isRender:false,
subject_id:0, subject_id:0,
myupdataleftNavs:this.myupdataleftNav
} }
} }
componentDidMount() { componentDidMount() {
// 记得删除退出课堂 // 记得删除退出课堂
// console.log("在线学习");
// console.log("获取到数据"); // console.log("获取到数据");
// console.log(this.props); // console.log(this.props);
this.getdata(); this.getdata();
@ -289,6 +291,9 @@ class Elearning extends Component{
}) })
}; };
myupdataleftNav=()=>{
this.props.updataleftNavfun();
}
render(){ render(){
console.log("Elearning++++++++"); console.log("Elearning++++++++");
// console.log(this.props.Chapterupdate); // console.log(this.props.Chapterupdate);

@ -210,7 +210,7 @@ class YslDetailCards extends Component{
//取消 //确认
updatapathCardsedit=()=>{ updatapathCardsedit=()=>{
this.setState({ this.setState({
idsum:undefined, idsum:undefined,
@ -219,9 +219,10 @@ class YslDetailCards extends Component{
editbuttomtypeadd:false editbuttomtypeadd:false
}) })
this.props.getPathCardsList(); this.props.getPathCardsList();
this.props.myupdataleftNavs();
// this.props.updatadetailInfoLists(); // this.props.updatadetailInfoLists();
}; };
//确认 //取消
editeditbuttomtypecanle=()=>{ editeditbuttomtypecanle=()=>{
this.setState({ this.setState({
editbuttomtype:true, editbuttomtype:true,
@ -300,6 +301,7 @@ class YslDetailCards extends Component{
this.updatapathCardsedit() this.updatapathCardsedit()
this.props.showNotification(`删除成功`); this.props.showNotification(`删除成功`);
this.props.myupdataleftNavs();
}else { }else {
this.props.showNotification(`删除失败`); this.props.showNotification(`删除失败`);
} }

@ -502,9 +502,9 @@ class ShixunHomework extends Component{
// }).then((result)=>{ // }).then((result)=>{
// if(result.status===200){ // if(result.status===200){
// //
// let shixun_list=result.data.shixun_list; // let shixun_lists=result.data.shixun_lists;
// for(var i=0; i<shixun_list.length;i++){ // for(var i=0; i<shixun_lists.length;i++){
// newshixunmodallists.push(shixun_list[i]) // newshixunmodallists.push(shixun_lists[i])
// } // }
// this.setState({ // this.setState({
// shixunmodal:true, // shixunmodal:true,
@ -540,9 +540,9 @@ class ShixunHomework extends Component{
// }).then((result)=>{ // }).then((result)=>{
// if(result.status===200){ // if(result.status===200){
// //
// let shixun_list=result.data.subject_list; // let shixun_lists=result.data.subject_list;
// for(var i=0; i<shixun_list.length;i++){ // for(var i=0; i<shixun_lists.length;i++){
// newshixunmodallists.push(shixun_list[i]) // newshixunmodallists.push(shixun_lists[i])
// } // }
// this.setState({ // this.setState({
// shixunpath:true, // shixunpath:true,
@ -1037,7 +1037,7 @@ class ShixunHomework extends Component{
{/*<span className="font-18 fl color-dark-21">{datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:datas&&datas.category_name+" 作业列表"}</span>*/} {/*<span className="font-18 fl color-dark-21">{datas&&datas.category_name===undefined||datas&&datas.category_name===null?datas&&datas.main_category_name:datas&&datas.category_name+" 作业列表"}</span>*/}
<span className="font-18 fl color-dark-21">实训作业</span> <span className="font-18 fl color-dark-21">实训作业</span>
<li className="fr"> <li className="fr">
{datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isClassManagement()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null? {datas===undefined?"":datas.homeworks && datas.homeworks.length>1?this.props.isAdminOrCreator()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null?
<span> <span>
<WordsBtn style="blue" className={"mr30 font-16"}> <WordsBtn style="blue" className={"mr30 font-16"}>
<Link className="color4CACFF" to={`/courses/${this.props.match.params.coursesId}/ordering/shixun_homework/${main_id&&main_id}`}>调整排序</Link> <Link className="color4CACFF" to={`/courses/${this.props.match.params.coursesId}/ordering/shixun_homework/${main_id&&main_id}`}>调整排序</Link>

@ -207,12 +207,13 @@ class MainContentContainer extends Component {
if (newProps.game && newProps.st === 0) { if (newProps.game && newProps.st === 0) {
if (!this.props || !this.props.game if (!this.props || !this.props.game
|| ( newProps.game.identifier !== this.props.game.identifier ) ) { || ( newProps.game.identifier !== this.props.game.identifier ) ) {
setTimeout(this.fetchRepositoryCode( newProps), 1500);
} else if ( this.props.challenge.pathIndex != newProps.challenge.pathIndex
&& newProps.challenge.pathIndex !== -1) { // 切换到只读文件
// pathIndex切换
setTimeout(this.fetchRepositoryCode( newProps), 1500); setTimeout(this.fetchRepositoryCode( newProps), 1500);
} }
// else if ( this.props.challenge.pathIndex != newProps.challenge.pathIndex
// && newProps.challenge.pathIndex !== -1) { // 切换到只读文件
// pathIndex切换
// setTimeout(this.fetchRepositoryCode( newProps), 1500);
// }
} }
if (newProps.myshixun) { if (newProps.myshixun) {
var stageId = newProps.match.params.stageId; var stageId = newProps.match.params.stageId;
@ -231,7 +232,11 @@ class MainContentContainer extends Component {
// 切换关卡时,停止轮训 // 切换关卡时,停止轮训
this.oldGameIdentifier = prevProps.game.identifier; this.oldGameIdentifier = prevProps.game.identifier;
this.doFileUpdateRequestOnCodeMirrorBlur(prevProps) this.doFileUpdateRequestOnCodeMirrorBlur(prevProps)
} else if (challenge && (challenge.pathIndex || prevProps.challenge.pathIndex) && challenge.pathIndex != prevProps.challenge.pathIndex) { }
// else if (this.props.shixun && this.props.shixun.code_edit_permission && this.state.currentPath != prevState.currentPath) {
// this.doFileUpdateRequestOnCodeMirrorBlur(prevProps)
// }
else if (challenge && (challenge.pathIndex || prevProps.challenge.pathIndex) && challenge.pathIndex != prevProps.challenge.pathIndex) {
this.doFileUpdateRequestOnCodeMirrorBlur(prevProps) this.doFileUpdateRequestOnCodeMirrorBlur(prevProps)
} }
@ -253,6 +258,9 @@ class MainContentContainer extends Component {
this.setState({ codeLoading: false }); this.setState({ codeLoading: false });
return; return;
} }
if (type && arg_path) {
this.doFileUpdateRequestOnCodeMirrorBlur(this.props)
}
const stageId = game.identifier const stageId = game.identifier
let path; let path;
let isEditablePath = false; let isEditablePath = false;
@ -383,9 +391,16 @@ class MainContentContainer extends Component {
// var fileUpdatePromise = this.doFileUpdateRequest(true) // var fileUpdatePromise = this.doFileUpdateRequest(true)
// }); // });
// } // }
window.addEventListener("beforeunload", this.beforeunload);
} }
componentWillUnmount() { componentWillUnmount() {
// window.$(window).off( "unload" ) // window.$(window).off( "unload" )
window.removeEventListener("beforeunload", this.beforeunload);
}
beforeunload = () => {
this.doFileUpdateRequestOnCodeMirrorBlur()
} }
@ -535,7 +550,9 @@ class MainContentContainer extends Component {
this.oldRepositoryCode = codeContent; this.oldRepositoryCode = codeContent;
let argPath; let argPath;
if (challenge.pathIndex === -1) { // 当前是只读文件 if (this.props.shixun && this.props.shixun.code_edit_permission == true) {
argPath = this.state.currentPath
} else if (challenge.pathIndex === -1) { // 当前是只读文件
argPath = challenge.multiPath === true ? challenge.path[0] : challenge.path argPath = challenge.multiPath === true ? challenge.path[0] : challenge.path
} else { } else {
argPath = challenge.multiPath === true ? challenge.path[challenge.pathIndex] : challenge.path argPath = challenge.multiPath === true ? challenge.path[challenge.pathIndex] : challenge.path
@ -624,6 +641,11 @@ class MainContentContainer extends Component {
gameBuilding: false gameBuilding: false
}) })
} }
onPathChange = (index, isDropDown) => {
this.props.onPathChange(index, () => {
isDropDown && this.fetchRepositoryCode()
})
}
onRunCodeTest() { onRunCodeTest() {
// tipContent(0, 100, 30, 360, 1) // tipContent(0, 100, 30, 360, 1)
// return; // for test // return; // for test
@ -634,7 +656,7 @@ class MainContentContainer extends Component {
showDialog({ showDialog({
contentText: '需要先切回可编辑的文件才可评测,确认要现在切换吗?', contentText: '需要先切回可编辑的文件才可评测,确认要现在切换吗?',
callback: () => { callback: () => {
onPathChange(0) this.onPathChange(0, true)
handleGdialogClose(); handleGdialogClose();
} }
}) })
@ -957,7 +979,9 @@ class MainContentContainer extends Component {
onRepositoryCodeUpdate={this.onRepositoryCodeUpdate} onRunCodeTest={this.onRunCodeTest} onRepositoryCodeUpdate={this.onRepositoryCodeUpdate} onRunCodeTest={this.onRunCodeTest}
codemirrorDidMount={this.codemirrorDidMount} fetchRepositoryCode={this.fetchRepositoryCode} codemirrorDidMount={this.codemirrorDidMount} fetchRepositoryCode={this.fetchRepositoryCode}
showResetCodeDialog={this.showResetCodeDialog} showResetPassedCodeDialog={this.showResetPassedCodeDialog} showResetCodeDialog={this.showResetCodeDialog} showResetPassedCodeDialog={this.showResetPassedCodeDialog}
doFileUpdateRequestOnCodeMirrorBlur={this.doFileUpdateRequestOnCodeMirrorBlur} ></MainContent> doFileUpdateRequestOnCodeMirrorBlur={this.doFileUpdateRequestOnCodeMirrorBlur}
onPathChange={this.onPathChange}
></MainContent>
</React.Fragment> </React.Fragment>
); );

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import axios from 'axios' import axios from 'axios'
import { Spin } from 'antd' import { Spin, Icon } from 'antd'
import ClipboardJS from 'clipboard' import ClipboardJS from 'clipboard'
import VNCDisplay from './VNCDisplay' import VNCDisplay from './VNCDisplay'
@ -22,7 +22,9 @@ class VNCContainer extends Component {
this.state = { this.state = {
fileTreeSelectedKeys: [], fileTreeSelectedKeys: [],
repositoryCode: '', repositoryCode: '',
displayKey: 1 displayKey: 1,
vnc_reseting: false,
} }
} }
componentDidMount() { componentDidMount() {
@ -116,6 +118,7 @@ class VNCContainer extends Component {
this.setState({ bottomDrawer: true }) this.setState({ bottomDrawer: true })
} }
onResetVNC = () => { onResetVNC = () => {
if (this.state.vnc_reseting) return;
// 桌面系统将恢复到初始状态,您在系统中创建的数据可能会丢失 // 桌面系统将恢复到初始状态,您在系统中创建的数据可能会丢失
// 请确保您的数据已保存(如:版本库代码已推送到服务器) // 请确保您的数据已保存(如:版本库代码已推送到服务器)
// 是否确认重置? // 是否确认重置?
@ -127,13 +130,15 @@ class VNCContainer extends Component {
</div>, </div>,
onOk: () => { onOk: () => {
const url = `/tasks/${this.props.game.identifier}/reset_vnc_link.json` const url = `/tasks/${this.props.game.identifier}/reset_vnc_link.json`
this.setState({ vnc_reseting: true })
axios.get(url, { axios.get(url, {
}).then((response) => { }).then((response) => {
if (response.data.data && response.data.data.vnc_url) { if (response.data.data && response.data.data.vnc_url) {
// reset // reset
this.setState({ this.setState({
displayKey: this.state.displayKey + 1, displayKey: this.state.displayKey + 1,
vnc_url: response.data.data.vnc_url vnc_url: response.data.data.vnc_url,
vnc_reseting: false
}) })
} else { } else {
} }
@ -141,7 +146,7 @@ class VNCContainer extends Component {
}).catch(error =>{ }).catch(error =>{
console.log(error) console.log(error)
this.setState({ readingCodeLoading: false }); this.setState({ vnc_reseting: false });
this.props.showSnackbar(`服务端异常,请联系管理员!`); this.props.showSnackbar(`服务端异常,请联系管理员!`);
}) })
@ -270,15 +275,23 @@ class VNCContainer extends Component {
></RepoTree> ></RepoTree>
</SecondDrawer> </SecondDrawer>
<FloatButton className="resetVNC" onClick={this.onResetVNC}> <FloatButton className="resetVNC" onClick={this.onResetVNC}>
<i className="iconfont icon-zhongzhi2 font-16 "></i> {/* <i className="iconfont icon-zhongzhi2 font-16 "></i> */}
{this.state.vnc_reseting ? <Icon type="loading" style={{verticalAlign: 'sub'}} />
: <i className="iconfont icon-zhongzhi2 font-16 "></i>}
<span>重置桌面系统</span> <span>重置桌面系统</span>
</FloatButton> </FloatButton>
{/* <Spin tip="..." spinning={this.state.vnc_reseting}>
</Spin> */}
<VNCDisplay <VNCDisplay
{...this.props} {...this.props}
key={this.state.displayKey} key={this.state.displayKey}
vnc_url={this.state.vnc_url || this.props.vnc_url} vnc_url={this.state.vnc_url || this.props.vnc_url}
> >
<Spin tip="加载中..." spinning={this.state.vnc_reseting}>
</Spin>
<Drawer <Drawer
mask={true} mask={true}
title="" title=""

@ -222,7 +222,7 @@ class TPIMonaco extends Component {
// https://github.com/Microsoft/monaco-editor/issues/539 // https://github.com/Microsoft/monaco-editor/issues/539
window.monaco.editor.setModelLanguage(editor_monaco.getModel(), lang) window.monaco.editor.setModelLanguage(editor_monaco.getModel(), lang)
} else if (prevProps.isEditablePath != this.props.isEditablePath) { } else if (prevProps.isEditablePath != this.props.isEditablePath) {
if (this.props.isEditablePath) { if (this.props.isEditablePath || this.props.shixun && this.props.shixun.code_edit_permission == true) {
editor_monaco.updateOptions({readOnly: false}) editor_monaco.updateOptions({readOnly: false})
} else { } else {
editor_monaco.updateOptions({readOnly: true}) editor_monaco.updateOptions({readOnly: true})
@ -271,7 +271,7 @@ class TPIMonaco extends Component {
const lang = getLanguageByMirrorName(this.props.mirror_name); const lang = getLanguageByMirrorName(this.props.mirror_name);
const editor = window.monaco.editor.create(document.getElementById('extend-challenge-file-edit'), { const editor = window.monaco.editor.create(document.getElementById('extend-challenge-file-edit'), {
value: value, value: value,
readOnly: !this.props.isEditablePath, readOnly: !this.props.isEditablePath && this.props.shixun && this.props.shixun.code_edit_permission != true,
// 属性说明 // 属性说明
// http://testeduplus2.educoder.net/react/build/static/node_modules/_monaco-editor@0.15.6@monaco-editor/esm/vs/editor/common/config/commonEditorConfig.js // http://testeduplus2.educoder.net/react/build/static/node_modules/_monaco-editor@0.15.6@monaco-editor/esm/vs/editor/common/config/commonEditorConfig.js
// https://github.com/Microsoft/monaco-editor/issues/29 // https://github.com/Microsoft/monaco-editor/issues/29

@ -157,13 +157,13 @@ class CodeRepositoryView extends Component {
} }
onPathChange(index) { onPathChange(index, isDropDown) {
const { challenge, onPathChange, doFileUpdateRequestOnCodeMirrorBlur } = this.props; const { challenge, onPathChange, doFileUpdateRequestOnCodeMirrorBlur } = this.props;
if (challenge.pathIndex !== index) { if (challenge.pathIndex !== index) {
// 切换时保存文件 // 切换时保存文件
// doFileUpdateRequestOnCodeMirrorBlur(true) // doFileUpdateRequestOnCodeMirrorBlur(true)
onPathChange(index) onPathChange(index, isDropDown)
} }
} }
@ -174,7 +174,7 @@ class CodeRepositoryView extends Component {
const pathArray = path.forEach ? path : [path] const pathArray = path.forEach ? path : [path]
pathArray.forEach( (item, index) => { pathArray.forEach( (item, index) => {
domArray.push( domArray.push(
<p key={index} className={classNames({'blue-line': pathIndex == index})} onClick={ () => this.onPathChange(index) } > <p key={index} className={classNames({'blue-line': pathIndex == index})} onClick={ () => this.onPathChange(index, true) } >
{item} {item}
</p> ) </p> )
}) })
@ -501,7 +501,8 @@ class CodeRepositoryView extends Component {
</Tooltip> </Tooltip>
} */} } */}
<div className="codemirrorBackground" <div className="codemirrorBackground"
style={{ backgroundImage: `url('${notEditablePathImg}')`, display: (isEditablePath ? 'none' : 'block') }}></div> style={{ backgroundImage: `url('${notEditablePathImg}')`
, display: (isEditablePath || this.props.shixun && this.props.shixun.code_edit_permission ? 'none' : 'block') }}></div>
{/*<textarea className = "" id="extend-challenge-file-edit" name="content">{repositoryCode}</textarea>*/} {/*<textarea className = "" id="extend-challenge-file-edit" name="content">{repositoryCode}</textarea>*/}
{/* cm monaco 切换 */} {/* cm monaco 切换 */}
{/* <TPICodeMirror {...this.props} ></TPICodeMirror> */} {/* <TPICodeMirror {...this.props} ></TPICodeMirror> */}

@ -231,12 +231,14 @@ class CodeRepositoryViewContainer extends Component {
const { fetchRepositoryCode, onPathChange, showSnackbar, challenge } = this.props; const { fetchRepositoryCode, onPathChange, showSnackbar, challenge } = this.props;
const nodePath = info.node.props.eventKey; const nodePath = info.node.props.eventKey;
let isCurrentFile = false;
// 设置pathIndex为-1那么代码文件下拉可以切回可编辑的文件 // 设置pathIndex为-1那么代码文件下拉可以切回可编辑的文件
if (!challenge.multiPath) { // 单path任务 多path任务 path是数组 if (!challenge.multiPath) { // 单path任务 多path任务 path是数组
if (challenge.path.trim() == nodePath.trim()) { if (challenge.path.trim() == nodePath.trim()) {
if (challenge.pathIndex === 0) { if (challenge.pathIndex === 0) {
showSnackbar(`当前编辑文件已经是${nodePath}`) showSnackbar(`当前编辑文件已经是${nodePath}`)
} else { } else {
fetchRepositoryCode(null, nodePath, 1);
onPathChange(0) onPathChange(0)
} }
return; return;
@ -244,7 +246,7 @@ class CodeRepositoryViewContainer extends Component {
onPathChange(-1) onPathChange(-1)
} }
} else { } else {
let isCurrentFile = false;
let cur_index = -1; let cur_index = -1;
if (challenge.path && challenge.path.forEach) { if (challenge.path && challenge.path.forEach) {
challenge.path.forEach((item, index) => { challenge.path.forEach((item, index) => {

@ -123,10 +123,11 @@ class DetailCardsEditAndAdd extends Component{
//点击新建阶段 //点击新建阶段
addStage=()=>{ addStage=()=>{
this.props.editeditbuttomtypes();
this.setState({ this.setState({
editPanel:true editPanel:true
}) })
this.props.editeditbuttomtypes();
} }
//取消新建阶段 //取消新建阶段
@ -294,13 +295,12 @@ class DetailCardsEditAndAdd extends Component{
shixun_id:shixuns_listeditlist shixun_id:shixuns_listeditlist
}).then((response) => { }).then((response) => {
// window.location.href = "/paths/" + response.data.subject_id // window.location.href = "/paths/" + response.data.subject_id
this.props.getPathCardsLists();
this.cancelAddState(); this.cancelAddState();
this.setState({ this.setState({
stage_nametype:false, stage_nametype:false,
descriptiontype:false descriptiontype:false
}) })
this.props.getPathCardsLists();
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
}); });

@ -202,48 +202,40 @@ export function TPMIndexHOC(WrappedComponent) {
NORMAL = 6 # 普通用户 NORMAL = 6 # 普通用户
Anonymous = 7 # 普未登录 Anonymous = 7 # 普未登录
*/ */
//超管 //超管0
isSuperAdmin = () => { isSuperAdmin = () => {
// return false // return false
return this.state.coursedata&&this.state.coursedata.course_identity === 0 return this.state.coursedata&&this.state.coursedata.course_identity === 0
} }
// 课堂管理等 //超管、运维0-1
isClassManagement = () => { isClassManagement = () => {
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity < 2 return this.state.coursedata&&this.state.coursedata.course_identity < 2
} }
//老师等 //超管、运维、课堂管理0-2
isAdminOrCreator = () => { isAdminOrCreator = () => {
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity < 3 return this.state.coursedata&&this.state.coursedata.course_identity < 3
} }
// 助教等 //超管、运维、课堂管理、老师0-3
isAdminOrTeacher = () => { isAdminOrTeacher = () => {
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity < 4 return this.state.coursedata&&this.state.coursedata.course_identity < 4
} }
// 老师、管理员等 // 超管、运维、课堂管理、老师、助教0-4
isAdmin = () => { isAdmin = () => {
// return false
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity < 5 return this.state.coursedata&&this.state.coursedata.course_identity < 5
} }
// 学生 // 学生5
isStudent = () => { isStudent = () => {
// return true
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity === 5 return this.state.coursedata&&this.state.coursedata.course_identity === 5
} }
// 超管、运维、课堂管理、老师、助教、学生0-5
isAdminOrStudent = () => { isAdminOrStudent = () => {
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity <= 5 return this.state.coursedata&&this.state.coursedata.course_identity <= 5
} }
// 非课堂成员 // 游客未登录/非课堂成员6>
isNotMember = () => { isNotMember = () => {
// return this.state.coursedata&&this.state.coursedata.course_identity >= 0 &&
return this.state.coursedata&&this.state.coursedata.course_identity >= 6 return this.state.coursedata&&this.state.coursedata.course_identity >= 6
} }
//课堂是否已结束
isCourseEnd = () => { isCourseEnd = () => {
return this.state.current_user ? this.state.current_user.course_is_end : false return this.state.current_user ? this.state.current_user.course_is_end : false
} }

@ -220,6 +220,7 @@ export default class TPMsettings extends Component {
can_copy: undefined, can_copy: undefined,
task_pass: undefined, task_pass: undefined,
test_set_permission: undefined, test_set_permission: undefined,
code_edit_permission: undefined,
hide_code: undefined, hide_code: undefined,
code_hidden: undefined, code_hidden: undefined,
forbid_copy: undefined, forbid_copy: undefined,
@ -352,6 +353,7 @@ export default class TPMsettings extends Component {
task_pass: response.data.shixun.task_pass, task_pass: response.data.shixun.task_pass,
test_set_permission: response.data.shixun.test_set_permission, test_set_permission: response.data.shixun.test_set_permission,
hide_code: response.data.shixun.hide_code, hide_code: response.data.shixun.hide_code,
code_edit_permission: response.data.shixun.code_edit_permission,
code_hidden: response.data.shixun.code_hidden, code_hidden: response.data.shixun.code_hidden,
is_secret_repository: response.data.shixun.is_secret_repository, is_secret_repository: response.data.shixun.is_secret_repository,
init_is_secret_repository: response.data.shixun.is_secret_repository, init_is_secret_repository: response.data.shixun.is_secret_repository,
@ -546,7 +548,11 @@ export default class TPMsettings extends Component {
}); });
} }
code_edit_permission = (e) => {
this.setState({
code_edit_permission: e.target.checked
})
}
code_hidden=(e)=>{ code_hidden=(e)=>{
let sum = "" let sum = ""
if (e.target.checked === false) { if (e.target.checked === false) {
@ -869,7 +875,7 @@ export default class TPMsettings extends Component {
let { let {
name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate, 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, 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, is_secret_repository opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository, code_edit_permission
} = this.state; } = this.state;
let newshixun_service_configlist = shixun_service_configlist.map(v => { let newshixun_service_configlist = shixun_service_configlist.map(v => {
@ -982,6 +988,7 @@ export default class TPMsettings extends Component {
vnc_evaluate: vnc_evaluate===null?undefined:vnc_evaluate, vnc_evaluate: vnc_evaluate===null?undefined:vnc_evaluate,
test_set_permission: test_set_permission, test_set_permission: test_set_permission,
code_hidden: code_hidden, code_hidden: code_hidden,
code_edit_permission: code_edit_permission,
trainee: trainee, trainee: trainee,
task_pass: task_pass, task_pass: task_pass,
hide_code: hide_code, hide_code: hide_code,
@ -1563,6 +1570,7 @@ export default class TPMsettings extends Component {
test_set_permission, test_set_permission,
hide_code, hide_code,
forbid_copy, forbid_copy,
code_edit_permission,
code_hidden, code_hidden,
vnc, vnc,
vnc_evaluate, vnc_evaluate,
@ -2274,6 +2282,15 @@ export default class TPMsettings extends Component {
</span> </span>
</div> </div>
{!code_hidden && !hide_code && <div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>代码开放修改:</span>
<span className="fl mt5">
<Checkbox checked={code_edit_permission === undefined ? false : code_edit_permission}
onChange={this.code_edit_permission}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则学员可以修改版本库目录中的任意文件内容</label>
</span>
</div>}
<div className="clearfix mt20 ml30"> <div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>隐藏代码窗口:</span> <span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>隐藏代码窗口:</span>
<span className="fl mt5"> <span className="fl mt5">

Loading…
Cancel
Save