Merge branch 'dev_aliyun' into dev_cxt2

dev_cs
cxt 5 years ago
commit a1addf86e8

@ -458,7 +458,7 @@ class StudentWorksController < ApplicationController
@shixun = @homework.shixuns.take
# 提示: 这里如果includes outputs表的话 sum(:evaluate_count)会出现错误
@games = @work.myshixun.games.joins(:challenge).reorder("challenges.position asc") if @work.myshixun
@comment = @work.student_works_scores.shixun_comment.first
@comment = @work.shixun_work_comments.find_by(challenge_id: 0)
# 用户最大评测次数
if @games
@ -474,19 +474,37 @@ class StudentWorksController < ApplicationController
# 实训作品的评阅
def shixun_work_comment
tip_exception("评阅不能为空") if params[:comment].blank?
tip_exception("缺少is_hidden参数") if params[:is_hidden].blank? || ![1, 0].include?(params[:is_hidden])
comment = @work.student_works_scores.shixun_comment.first || StudentWorksScore.new(student_work_id: @work.id, user_id: current_user.id)
comment.comment = params[:comment]
comment.is_hidden = params[:is_hidden]
comment.save!
normal_status("评阅成功")
tip_exception("请至少输入一个评阅") if params[:comment].blank? && params[:hidden_comment].blank?
ActiveRecord::Base.transaction do
challenge = @homework.shixuns.first&.challenges.find_by(id: params[:challenge_id]) unless params[:challenge_id].blank?
if challenge.present?
comment = @work.shixun_work_comments.find_by(challenge_id: challenge.id) ||
ShixunWorkComment.new(student_work_id: @work.id, user_id: current_user.id, challenge_id: challenge.id)
else
comment = @work.shixun_work_comments.find_by(challenge_id: 0) ||
ShixunWorkComment.new(student_work_id: @work.id, user_id: current_user.id, challenge_id: 0)
end
comment.comment = params[:comment]
comment.hidden_comment = params[:hidden_comment]
comment.save!
normal_status("评阅成功")
end
end
# 删除实训作品评阅
def destroy_work_comment
@work.student_works_scores.shixun_comment.first.destroy! if @work.student_works_scores.shixun_comment.first.present?
normal_status("删除成功")
ActiveRecord::Base.transaction do
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
def export_shixun_work_report

@ -0,0 +1,5 @@
class ShixunWorkComment < ApplicationRecord
belongs_to :student_work
belongs_to :user
belongs_to :challenge, optional: true
end

@ -7,6 +7,7 @@ class StudentWork < ApplicationRecord
belongs_to :myshixun, optional: true
has_many :student_works_evaluation_distributions, dependent: :destroy
has_many :student_works_scores, dependent: :destroy
has_many :shixun_work_comments, dependent: :destroy
belongs_to :project, optional: true
# attachtype: 1正常提交的附件 7补交的附件

@ -36,6 +36,10 @@ if @shixun
challenge_score = @homework.challenge_score game.challenge_id
json.game_score_full challenge_score
json.game_score @work.work_challenge_score game, challenge_score
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
@ -54,8 +58,9 @@ if @shixun
json.passed_time @work.myshixun&.passed_time
# 评阅信息
json.work_comment @user_course_identity < Course::STUDENT || !@comment&.is_hidden ? @comment&.comment : nil
json.work_comment_hidden @comment&.is_hidden
json.work_comment @comment&.comment
json.work_comment_hidden @user_course_identity < Course::STUDENT ? @comment&.hidden_comment : nil
json.comment_id @comment&.id
# 图形统计
# 1 效率

@ -0,0 +1,13 @@
class CreateShixunWorkComments < ActiveRecord::Migration[5.2]
def change
create_table :shixun_work_comments do |t|
t.references :student_work, index: true, type: :integer
t.references :challenge, index: true, type: :integer, default: 0
t.references :user, index: true, type: :integer
t.text :comment
t.text :hidden_comment
t.timestamps
end
end
end

@ -0,0 +1,13 @@
class MigrateShixunWorkComment < ActiveRecord::Migration[5.2]
def change
StudentWorksScore.where(is_ultimate: 0, score: nil).where("created_at > '2019-09-04 00:00:00'").each do |work_score|
if work_score.student_work && work_score.student_work.homework_common&.shixuns
if work_score.is_hidden
ShixunWorkComment.create!(student_work_id: work_score.student_work_id, user_id: work_score.user_id, hidden_comment: work_score.comment)
else
ShixunWorkComment.create!(student_work_id: work_score.student_work_id, user_id: work_score.user_id, comment: work_score.comment)
end
end
end
end
end

@ -218,7 +218,7 @@ function _initSider() {
})
}
$(function() {
loadHeader();
// loadHeader();
_initSider();
$(window).scroll(function() {
@ -436,86 +436,86 @@ function editormd_to_html(id, callback) {
}
function loadHeader() {
//头部导航条的----------显示搜索框
$("#search-open").on("click", function(e) {
$(this).hide();
// $("#header-nav").animate({opacity:"0"},1000);
$(".posi-search").show()
// .animate({opacity:"1"},1000);
$("#header-nav").css("z-index", "2");
$(".posi-search").css("z-index", "3");
// $(".search-input").val(""); // 不清空
$(".search-input").focus();
$(".search-all .search-content").hide();
e.stopPropagation();
//阻止冒泡
});
$(".search-input").on("click", function(e) {
e.stopPropagation();
//阻止冒泡
});
//搜索框输入内容
$(".search-input").on("input", function(e) {
if ($(".search-input").val() == "") {
$(".search-all .search-content").hide();
} else {
$(".search-all .search-content").show();
}
e.stopPropagation();
//阻止冒泡
});
//搜索
$("#header_keyword_search").on("click", header_search);
$("input[name='search_keyword']").on("keydown", function(event) {
var code;
if (!event) {
event = window.event;
//针对ie浏览器
code = event.keyCode;
} else {
code = event.keyCode;
}
if (code == 13) {
header_search();
return false;
}
});
$(".search-clear").click(function(e) {
e.stopPropagation();
});
//切换搜索条件
$("#searchkey li").click(function(e) {
var key = $($(this).children("a")[0]).html();
switch (key) {
case '实训':
$("#search_type").val('1');
break;
case '课堂':
$("#search_type").val('2');
break;
case '用户':
$("#search_type").val('3');
break;
}
$("#searchkey").siblings(".searchkey").html(key);
// $("#searchkey").hide();
e.stopPropagation();
//阻止冒泡
});
//切换选择导航条
$("#header-nav li").click(function() {
$("#header-nav li").removeClass("active");
$(this).addClass("active");
});
//点击页面其它(与搜索框无关的地方)都会将搜索框隐藏,所以与搜索框有关的地方需要阻止冒泡
$("body").on("click", function() {
closeSearch();
});
$(".search_history").on("click", function() {
$("input[name='search_keyword']").val($(this).html());
header_search();
});
// //头部导航条的----------显示搜索框
// $("#search-open").on("click", function(e) {
// $(this).hide();
// // $("#header-nav").animate({opacity:"0"},1000);
// $(".posi-search").show()
// // .animate({opacity:"1"},1000);
// $("#header-nav").css("z-index", "2");
// $(".posi-search").css("z-index", "3");
// // $(".search-input").val(""); // 不清空
// $(".search-input").focus();
// $(".search-all .search-content").hide();
// e.stopPropagation();
// //阻止冒泡
// });
// $(".search-input").on("click", function(e) {
// e.stopPropagation();
// //阻止冒泡
// });
// //搜索框输入内容
// $(".search-input").on("input", function(e) {
// if ($(".search-input").val() == "") {
// $(".search-all .search-content").hide();
// } else {
// $(".search-all .search-content").show();
// }
// e.stopPropagation();
// //阻止冒泡
// });
// //搜索
// $("#header_keyword_search").on("click", header_search);
// $("input[name='search_keyword']").on("keydown", function(event) {
// var code;
// if (!event) {
// event = window.event;
// //针对ie浏览器
// code = event.keyCode;
// } else {
// code = event.keyCode;
// }
// if (code == 13) {
// header_search();
// return false;
// }
// });
// $(".search-clear").click(function(e) {
// e.stopPropagation();
// });
// //切换搜索条件
// $("#searchkey li").click(function(e) {
// var key = $($(this).children("a")[0]).html();
// switch (key) {
// case '实训':
// $("#search_type").val('1');
// break;
// case '课堂':
// $("#search_type").val('2');
// break;
// case '用户':
// $("#search_type").val('3');
// break;
// }
// $("#searchkey").siblings(".searchkey").html(key);
// // $("#searchkey").hide();
// e.stopPropagation();
// //阻止冒泡
// });
// //切换选择导航条
// $("#header-nav li").click(function() {
// $("#header-nav li").removeClass("active");
// $(this).addClass("active");
// });
// //点击页面其它(与搜索框无关的地方)都会将搜索框隐藏,所以与搜索框有关的地方需要阻止冒泡
// $("body").on("click", function() {
// closeSearch();
// });
//
// $(".search_history").on("click", function() {
// $("input[name='search_keyword']").val($(this).html());
// header_search();
// });
}
function header_search() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

@ -22,6 +22,8 @@
-->
<title>EduCoder</title>
<script type="text/javascript">
window.__testImageUrl = "https://pre-newweb.educoder.net/react/build/images/share_logo_icon.jpg"
window.__isR = true;
// 不支持ie9 ie10
if (

@ -327,11 +327,11 @@ class App extends Component {
wx.ready(function () {
console.log('wx is ready')
var shareData = {
title: 'EduCoder',
desc: '创新源于实践',
title: 'EduCoder - 首页',
desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台提供企业级工程实训以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动将传统的知识传授和时兴的工程实战一体化。',
link: currentUrl,
imgUrl: window.__testImageUrl
|| (currentUrl.endsWith('/') ? currentUrl : currentUrl + '/') + 'images/educoder/index/subject/subject15.jpg'
|| (currentUrl.endsWith('/') ? currentUrl : currentUrl + '/') + 'react/build/images/share_logo_icon.jpg'
};
wx.onMenuShareAppMessage(shareData);//分享给好友

@ -20,6 +20,8 @@ export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, ap
downloadFile, sortDirections } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForSinglePath, configShareForSingleShixun } from './util/ShareUtil'
export { isDev as isDev, isMobile } from './Env'
export { toStore as toStore, fromStore as fromStore } from './Store'

@ -0,0 +1,79 @@
const host = window.location.host
const wx = window.wx
function share(shareData) {
wx.onMenuShareAppMessage(shareData);//分享给好友
wx.onMenuShareTimeline(shareData);//分享到朋友圈
wx.onMenuShareQQ(shareData);//分享给手机QQ
wx.onMenuShareWeibo(shareData);//分享腾讯微博
wx.onMenuShareQZone(shareData);//分享到QQ空间
}
/**
实践课程 平台提供涵盖基础入门案例实践和创新应用的完整实训项目体系通过由浅入深的实训路径帮助学生快速提升实战能力
实训项目 覆盖不同专业的IT实验和实训每周更新无需配置本机实验环境随时随地开启企业级真实实训
翻转课堂 自动评测实训任务支持技能统计提供教学活动分析报告减轻教师和助教的辅导压力免去作业发布和批改的困扰实时了解学生学习情况全面提升教师施教效率和水平
单个课程和实训 获取课程/实训的简介 该课程或者实训展示的缩略图
*/
export function configShareForIndex () {
var shareData = {
title: 'EduCoder - 首页',
desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台提供企业级工程实训以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动将传统的知识传授和时兴的工程实战一体化。',
link: host,
imgUrl: window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};
share(shareData)
}
export function configShareForPaths () {
var shareData = {
title: 'EduCoder - 实践课程',
desc: '平台提供涵盖基础入门、案例实践和创新应用的完整实训项目体系,通过由浅入深的实训路径,帮助学生快速提升实战能力。',
link: `${host}/paths`,
imgUrl: window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};
share(shareData)
}
export function configShareForShixuns () {
var shareData = {
title: 'EduCoder - 实训项目',
desc: '覆盖不同专业的IT实验和实训每周更新无需配置本机实验环境随时随地开启企业级真实实训。',
link: `${host}/shixuns`,
imgUrl: window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};
share(shareData)
}
export function configShareForCourses () {
var shareData = {
title: 'EduCoder - 翻转课堂',
desc: '自动评测实训任务,支持技能统计,提供教学活动分析报告,减轻教师和助教的辅导压力,免去作业发布和批改的困扰,实时了解学生学习情况,全面提升教师施教效率和水平。',
link: `${host}/courses`,
imgUrl: window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};
share(shareData)
}
// detail
export function configShareForSinglePath (title, desc, path, imgUrl) {
var shareData = {
title: title,
desc: desc,
link: `${host}/${path}`,
imgUrl: imgUrl || window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};
share(shareData)
}
export function configShareForSingleShixun (title, desc, path, imgUrl) {
var shareData = {
title: title,
desc: desc,
link: `${host}/${path}`,
imgUrl: imgUrl || window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};
share(shareData)
}

@ -9,10 +9,11 @@ class AppraiseModal extends Component{
this.state={
group_ids:[],
fileList:[],
textareaval:undefined,
Inputsval:undefined,
valuetype:0,
textareavaltype:false
textareavaltype:false,
comment:undefined,
hidden_comment:undefined
}
}
@ -25,32 +26,40 @@ class AppraiseModal extends Component{
}
onChanges=(e)=>{
this.setState({
valuetype:e.target.value
comment=(e)=>{
this.setState({
comment:e.target.value
})
}
settextarea=(e)=>{
hidden_comment=(e)=>{
this.setState({
textareaval:e.target.value
hidden_comment:e.target.value
})
}
Saves=()=>{
let{textareaval,valuetype}=this.state;
let{textareaval,valuetype,comment,hidden_comment}=this.state;
let commenttype=comment===undefined||comment===null||comment==="";
let hidden_commenttype=hidden_comment===undefined||hidden_comment===null||hidden_comment==="";
if(textareaval===undefined||textareaval===null||textareaval===""){
if(commenttype===true&&hidden_commenttype===true){
this.setState({
textareavaltype:true
})
return
}
//comment 是 text 可见的评阅内容
// hidden_comment 是 text 不可见的评阅内容
// challenge_id 否 int 关卡id关卡评阅才需传关卡id
let url=`/student_works/${this.props.match.params.homeworkid}/shixun_work_comment.json`
axios.post(url, {
comment:textareaval,
is_hidden:valuetype
hidden_comment:valuetype
}).then((response) => {
if(response.data.status===0){
this.props.showNotification(response.data.message)
@ -64,15 +73,41 @@ class AppraiseModal extends Component{
}
render(){
let {textareaval,Inputsval,textareavaltype,Inputsvaltype}=this.state;
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
let {textareavaltype,comment,hidden_comment}=this.state;
return(
<div>
<style>
{
`
@media (max-width: 2000px) {
.WordNumberTextarea{
height: 130px !important;
}
}
@media (max-width: 1350px) {
.HomeworkModal{
top:10px !important;
}
.WordNumberTextarea{
height: 80px !important;
}
}
@media (max-width: 1250px) {
.HomeworkModal{
top:0px !important;
}
.WordNumberTextarea{
height: 40px !important;
}
}
`
}
</style>
<Modal
keyboard={false}
className={"HomeworkModal"}
@ -91,12 +126,9 @@ class AppraiseModal extends Component{
padding: 0px 15px 15px 15px;
}
.font{
width: 48px;
height: 16px;
font-size: 16px;
font-weight: 400;
color: rgba(5,16,26,1);
line-height: 16px;
font-size: 14px;
font-weight: 400;
color: rgba(5,16,26,1);
}
.newfont{
height: 16px;
@ -110,25 +142,31 @@ class AppraiseModal extends Component{
}
</style>
<div className="clearfix">
<p className={"font mt10 mb10"}>
权限
<p className={"font mt10 mb10 ml10"}>
可见:(学生可查看老师的评阅内容
</p>
<Radio.Group onChange={this.onChanges} value={this.state.valuetype}>
<Radio value={0} style={radioStyle} className={"newfont"}>可见 (学生查看老师的评阅内容</Radio>
<Radio value={1} style={radioStyle} className={"newfont"}>不可见 (仅对课堂老师可见</Radio>
</Radio.Group>
{/*<Radio.Group onChange={this.onChanges} value={this.state.valuetype}>*/}
{/*<Radio value={0} style={radioStyle} className={"newfont"}>可见 (学生查看老师的评阅内容)</Radio>*/}
{/*<Radio value={1} style={radioStyle} className={"newfont"}>不可见 (仅对课堂老师可见)</Radio>*/}
{/*</Radio.Group>*/}
<WordNumberTextarea
placeholder={"请填写评阅内容"}
onInput={(e)=>this.comment(e)}
value={comment}
maxlength={500}
/>
<p className={"font mt10 mb20"}>
内容
<p className={"font mt10 mb10 ml10"}>
不可见:(仅对课堂老师可见
</p>
<WordNumberTextarea
placeholder={"请填写评阅内容"}
onInput={(e)=>this.settextarea(e)}
value={textareaval}
onInput={(e)=>this.hidden_comment(e)}
value={hidden_comment}
maxlength={500}
/>
<li style={{height:"20px",lineHeight:"20px"}} className={textareavaltype===true?"color-red mt20 mb10":"none"}><span>评阅内容为空</span></li>
<li style={{height:"20px",lineHeight:"20px"}} className={textareavaltype===true?"color-red mt20 mb10":"none"}><span>评阅内容至少有一个不为空</span></li>
</div>
<div className={textareavaltype===false?"mt20 clearfix edu-txt-center":"clearfix edu-txt-center"}>

@ -157,6 +157,42 @@ class Ecerciseallbackagain extends Component{
console.log()
return(
<div>
<style>
{
`
@media (max-width: 2000px) {
.newupload_select_box{
height: 265px !important;
}
}
@media (max-width: 1350px) {
.HomeworkModal{
top:10px !important;
}
.newupload_select_box{
height: 220px !important;
}
}
@media (max-width: 1250px) {
.HomeworkModal{
top:0px !important;
}
.newupload_select_box{
height: 150px !important;
}
}
.eerxisbox:hover {
background: #e4eaf6;
}
.upload_select_box li:hover {
background:transparent;
}
`
}
</style>
<Modal
className={"HomeworkModal"}
title={this.props.modalname}
@ -169,11 +205,12 @@ class Ecerciseallbackagain extends Component{
<div className="task-popup-content">
<style>{`
.greybackHead{
padding:0px 30px;
}
.fontlefts{text-align: left;}
`}</style>
.greybackHead{
padding:0px 30px;
}
.fontlefts{text-align: left;}
`}</style>
<div className="clearfix edu-txt-center mb10" style={{color:"#333333",fontSize: '15px'}}>学生将得到一次重新答题的机会现有的答题情况将被清空</div>
<ul className="clearfix edu-txt-center ml35">
<li className="fl paddingleft22 fontlefts" style={{width:'160px'}}>姓名</li>
@ -182,7 +219,7 @@ class Ecerciseallbackagain extends Component{
</ul>
{datalist===undefined?"":
<ul className="upload_select_box fl clearfix mt10 mb10" style={{"overflow-y":"auto",height: "319px"}}
<ul className="upload_select_box fl clearfix mt10 mb10 newupload_select_box" style={{"overflow-y":"auto"}}
id="search_not_members_list"
onScroll={this.contentViewScroll}
>
@ -190,7 +227,7 @@ class Ecerciseallbackagain extends Component{
{ datalist.map((item,key)=>{
return(
<div className="clearfix edu-txt-center lineh-40" key={key}>
<div className="clearfix edu-txt-center lineh-40 eerxisbox" key={key}>
<li className="fl" style={{width: '158px'}}>
<Checkbox
className="fl task-hide edu-txt-left"
@ -198,8 +235,12 @@ class Ecerciseallbackagain extends Component{
value={item.user_id}
key={item.user_id}
>
<label style={{"textAlign": "left", "color": "#05101A"}}
className="task-hide color-grey-name" title="frerere">{item.user_name}</label>
<a style={{"textAlign": "left"}}
className="task-hide color-grey-name"
href={`/users/${item.user_id}/courses`}
target={'_blank'}
title={item.user_name}
>{item.user_name}</a>
</Checkbox>
</li>
<li className="fl" style={{width: '150px'}}>
@ -220,7 +261,7 @@ class Ecerciseallbackagain extends Component{
<Checkbox checked={onChangetype} onChange={this.onChange}>{onChangetype===true?"清除":"全选"}</Checkbox>
</div>
<div className="clearfix mt30 edu-txt-center mb10">
<div className="clearfix edu-txt-center">
<a className="task-btn color-white mr30" onClick={this.issCancel}>取消</a>
<a className="task-btn task-btn-orange" onClick={this.isSave}>确认</a>
</div>

@ -155,19 +155,20 @@ class ShixunWorkReport extends Component {
})
}
showAppraiseModal=(sum)=>{
// if(sum===undefined){
// this.setState({
// showAppraiseModaltype:true,
// })
// }else{
// this.setState({
// showAppraiseModaltype:true,
// work_comment:undefined,
// work_type:0,
// })
//
// }
showAppraiseModal=(type,id)=>{
if(type==="child"){
this.setState({
showAppraisetype:type,
challenge_id:id
})
}else{
this.setState({
showAppraisetype:type,
challenge_id:undefined
})
}
let{work_comment,work_comment_hidden}=this.state;
this.setState({
showAppraiseModaltype:true,
@ -253,6 +254,9 @@ class ShixunWorkReport extends Component {
modalSave={this.state.modalSave}
modalCancel={this.state.modalCancel}
></Modals>
{showAppraiseModaltype===true?<AppraiseModal
{...this.props}
{...this.state}
@ -299,7 +303,7 @@ class ShixunWorkReport extends Component {
{/*>评阅</a> : ""}*/}
{this.props.isAdmin() ?<a
className=" color-blue font-14 fr ml20 mt15"
onClick={()=>this.showAppraiseModal(1)}
onClick={()=>this.showAppraiseModal("main")}
>评阅</a>:""}
</div>
{/*{work_comment===null||work_comment===undefined?"评阅":"编辑评阅"}*/}
@ -421,6 +425,7 @@ class ShixunWorkReport extends Component {
jumptopic={this.jumptopic}
getdatalist={()=>this.getdatalist()}
setupdalist={(challenge_score,overall_appraisal,work_score)=>this.setupdalist(challenge_score,overall_appraisal,work_score)}
showAppraiseModal={(type,id)=>this.showAppraiseModal(type,id)}
/>
</div>
@ -483,7 +488,7 @@ class ShixunWorkReport extends Component {
>删除</a>:""}
{this.props&&this.props.isAdminOrTeacher()===true?<a className="color-blue font-14 fr"
onClick={()=>this.showAppraiseModal()}
onClick={()=>this.showAppraiseModal("main")}
>编辑</a>:""}
</div>

@ -273,7 +273,7 @@ class ShixunWorkModal extends Component{
</div>
:
<ul className="upload_select_box fl clearfix mt10 mb10" tyle={{"overflow-y":"auto"}}id="search_not_members_list"
<ul className="upload_select_box fl clearfix mt10 mb10" style={{"overflow-y":"auto"}} id="search_not_members_list"
onScroll={this.contentViewScroll}
>
@ -286,7 +286,7 @@ class ShixunWorkModal extends Component{
group_list&&group_list.length===0?"":group_list.map((item,key)=>{
return(
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}>
<li className="fl task-hide" style={{width: '240px'}}>
<li className="fl task-hide" style={{width: '240px',paddingLeft: '10px'}}>
<Checkbox
className="fl task-hide edu-txt-left"
name="shixun_homework[]"
@ -294,7 +294,7 @@ class ShixunWorkModal extends Component{
key={item=== undefined?"":item.id}
>
<label style={{"textAlign": "left", "color": "#05101A"}}
className="task-hide color-grey-name" title="frerere">{item===undefined?"":item.name}</label>
className="task-hide color-grey-name" title={item===undefined?"":item.name}>{item===undefined?"":item.name}</label>
</Checkbox>
</li>
<li className="fl" style={{width: '100px'}}>

@ -29,7 +29,9 @@ class OfficialAcademicTranscript extends Component {
elapsedtime:item.time_consuming,
empvalue:{myself:item.myself_experience,experience:item.experience},
game_scores:{game_score:item.game_score,game_score_full:item.game_score_full},
challenge_id:{id:item.challenge_id}
challenge_id:{id:item.challenge_id},
challenge_comment: item.challenge_comment,
challenge_comment_hidden: item.challenge_comment_hidden,
// adjustmentminute:asdasd
})
})
@ -196,6 +198,20 @@ class OfficialAcademicTranscript extends Component {
// min={0} max={record.game_scores.game_score_full}
/></a>
{/*<a style={{textAlign: "center"}} className="color-blue font-14 mr20">查看</a>*/}
</span>
),
},{
title: '操作',
key: 'operation',
dataIndex: 'operation',
render: (text, record) => (
<span>
{console.log(record)}
<a
className=" color-blue font-14 fr mr22"
onClick={()=>this.props.showAppraiseModal("child",record.challenge_id.id,record.challenge_comment,record.challenge_comment_hidden)}
>评阅</a>
</span>
),
}];
@ -210,6 +226,13 @@ class OfficialAcademicTranscript extends Component {
}
}
)
columns.some((item,key)=> {
if (item.title === "操作") {
columns.splice(key, 1)
return true
}
}
)
}
return (
<div>
@ -276,6 +299,9 @@ class OfficialAcademicTranscript extends Component {
.linhe15{
line-height: 15px;
}
.mr22{
margin-right: 22px;
}
`}
</style>
{datas===undefined?"":<Table

@ -10,9 +10,8 @@
resize:none; /*禁止拉伸*/
border: none; /*去掉默认边框*/
width: 100%;
height:150px;
height:130px;
border:none;
padding: 10px;
display: block;
}
@ -26,12 +25,9 @@
height: auto;
border: 1px solid rgba(234,234,234,1);
border-radius: 0.125rem;
margin: 0.31rem;
padding: 0.19rem;
margin: 10px 10px 0px 10px;
padding: 10px 10px 5px 10px;
backgroud:rgba(234,234,234,1);
padding-bottom: 10px;
padding-right: 10px;
}
.WordNumberTextarea-count {
display: inline-block;

@ -31,8 +31,22 @@ class MainContent extends Component {
onResizeButtonClick = () => {
// console.log('onResizeButtonClick')
}
onRunCodeTest = () => {
const vncContainer = this.refs['vncContainer']
if (vncContainer) {
vncContainer.showCodeEvaluate && vncContainer.showCodeEvaluate()
}
this.props.onRunCodeTest();
}
hideCodeEvaluate = () => {
const vncContainer = this.refs['vncContainer']
if (vncContainer) {
vncContainer.onBottomDrawerClose && vncContainer.onBottomDrawerClose()
}
}
render() {
const { challenge, output_sets, onRunCodeTest, latest_output, record, st, readRepoTimeout,
const onRunCodeTest = this.onRunCodeTest
const { challenge, output_sets, latest_output, record, st, readRepoTimeout,
onTestSetHeaderClick, loading, codeLoading, shixun, vnc_url} = this.props
// if (output_sets && output_sets.test_sets) {
@ -97,11 +111,23 @@ class MainContent extends Component {
{ showIframeContent && vnc_url ?
<CodeRepositoryViewContainer { ...this.props } isOnlyContainer={true}>
<VNCContainer
ref="vncContainer"
vnc_url={vnc_url}
{...this.props}
codeEvaluate={
<div id="games_valuation_contents">
<CodeEvaluateView output_sets={output_sets} latest_output={latest_output}
record={record} onTestSetHeaderClick={onTestSetHeaderClick}
{...this.props} inDrawer={true}
hideCodeEvaluate={this.hideCodeEvaluate}
></CodeEvaluateView>
</div>
}
></VNCContainer>
<div id="actionView" className="-layout-h -center -bg-grey-90 -grey-20 -bg-darkblack" style={{height:'48px'}}>
<ActionView onRunCodeTest={onRunCodeTest} {...this.props}></ActionView>
<ActionView {...this.props}
onRunCodeTest={onRunCodeTest}
></ActionView>
</div>
</CodeRepositoryViewContainer>
:
@ -158,7 +184,7 @@ class MainContent extends Component {
</div>
<div id="actionView" className="-layout-h -center -bg-grey-90 -grey-20 -bg-darkblack" style={{height:'48px'}}>
<ActionView onRunCodeTest={onRunCodeTest} {...this.props}></ActionView>
<ActionView {...this.props} onRunCodeTest={onRunCodeTest}></ActionView>
</div>
</React.Fragment>

@ -10,6 +10,8 @@ import RepoTree from './component/repo/RepoTree'
import TPIMonaco from './component/monaco/TPIMonaco'
import notEditablePathImg from '../../images/tpi/notEditablePath.png'
import { Drawer } from "antd";
import './VNC.css'
const $ = window.$;
const firstDrawerWidth = 260;
@ -103,6 +105,16 @@ class VNCContainer extends Component {
}
}
}
onBottomDrawerClose = () => {
this.setState({ bottomDrawer: false })
}
swtichBottomDrawer = () => {
this.setState({ bottomDrawer: !this.state.bottomDrawer })
}
showCodeEvaluate = () => {
this.setState({ bottomDrawer: true })
}
/*
selectedKeys={fileTreeSelectedKeys}
onSelect={onTreeSelect}
@ -125,6 +137,23 @@ class VNCContainer extends Component {
secondDrawerClassName="codeInDrawer"
>
<style>{`
/* 评测结果 */
.codeEvaluateDrawer #game_test_set_results {
height: 198px;
}
.codeEvaluateDrawer .ant-drawer-body {
padding: 0px;
}
.codeEvaluateFloatButton {
bottom: 180px !important;
left: unset;
right: 0px;
top: unset;
}
.codeEvaluateFloatButton .text {
left: 10px;
}
.vncDrawer .ant-drawer-body {
padding: 0px;
}
@ -173,10 +202,36 @@ class VNCContainer extends Component {
></RepoTree>
</SecondDrawer>
<FloatButton></FloatButton>
{/* <FloatButton></FloatButton> */}
<VNCDisplay
{...this.props}
></VNCDisplay>
>
<Drawer
mask={true}
title=""
width={firstDrawerWidth}
// closable={false}
onClose={this.onBottomDrawerClose}
visible={this.state.bottomDrawer}
className={'codeEvaluateDrawer'}
placement="bottom"
getContainer={false}
style={{ position: 'absolute', bottom: '25px', zIndex: 1 }}
afterVisibleChange={(visible) => {
if (visible) {
const canvas = $('.vncDisply canvas')[0]
canvas && canvas.focus()
}
}}
>
{ this.props.codeEvaluate }
</Drawer>
<FloatButton onClick={this.swtichBottomDrawer}
className="codeEvaluateFloatButton"
>测试集</FloatButton>
</VNCDisplay>
</React.Fragment>

@ -165,7 +165,10 @@ class VNCDisplay extends Component {
<div id="status">Loading</div>
<div id="sendCtrlAltDelButton">Send CtrlAltDel</div>
</div>
<div id="screen"></div>
<div id="screen">
</div>
{this.props.children}
</div>
);
}

@ -8,10 +8,10 @@ class FloatButton extends Component {
}
render() {
const { challenge, vnc_url, children } = this.props
const { challenge, vnc_url, children, className } = this.props
return (
<div className="float_button" onClick={this.props.onClick}>
<div className={`float_button ${className}` } onClick={this.props.onClick}>
<style>{`
`}</style>

@ -127,4 +127,11 @@
height: 10px;
margin: 5px 0;
float: right;
}
.-task-ces-info .inputTitle {
line-height: 16px;
}
.-task-ces-info .inputTitle .input{
white-space: pre-wrap;
}

@ -227,7 +227,12 @@ class CodeEvaluateView extends Component {
<div className="clearfix df inputTitle">
<span className="fl fb color-grey">测试输入</span>
<div className="fl color-blue" style={{flex:1}} dangerouslySetInnerHTML={{__html: item.input.replace(/\r\n/g,"</br>")}}></div>
<div className="fl color-blue input" style={{flex:1}}
// dangerouslySetInnerHTML={{__html: (item.input.replace(/\r\n/g,"</br>"))}}
>
{item.input}
</div>
</div>
</div>
@ -307,14 +312,21 @@ class CodeEvaluateView extends Component {
<a href="javascript:void(0);" className="tab_type tab_color">测试结果</a>
</li>
<Tooltip id="tooltip-icon-expand" title={ evaluateViewExpanded ? "收起" : "展开"}>
{this.props.inDrawer ? <Tooltip id="tooltip-icon-expand" title={ "收起" }>
{/*TODO 按钮大小改造css*/}
{/* icon-guanbi */}
<a className="iconButton fr mr15 mt4" onClick={this.props.hideCodeEvaluate} id="extend_and_zoom" >
<i className={ "font-18 iconfont icon-guanbi" }></i>
</a>
</Tooltip> : <Tooltip id="tooltip-icon-expand" title={ evaluateViewExpanded ? "" : ""}>
{/*TODO 按钮大小改造css*/}
<a className="iconButton fr mr15" onClick={this.onEvaluateViewExpand} id="extend_and_zoom" >
<i className={ evaluateViewExpanded ? "font-18 iconfont icon-shousuo" : "iconfont icon-zhankai font-18" }></i>
</a>
</Tooltip>
</Tooltip>}
<div className="cl"></div>
</ul>

@ -518,7 +518,7 @@ class DetailCardsEditAndAdd extends Component{
style={{"width":"298px"}}
name="shixun_homework[]"
>
<label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title="frerere">{item.shixun_name}</label>
<label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title={item.shixun_name}>{item.shixun_name}</label>
</Checkbox>
</li>
<li className="fl with30 edu-txt-left task-hide paddingl5">{item.school_users}</li>

@ -554,7 +554,7 @@ class DetailCardsEditAndEdit extends Component{
style={{"width":"298px"}}
name="shixun_homework[]"
>
<label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title="frerere">{item.shixun_name}</label>
<label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title={item.shixun_name}>{item.shixun_name}</label>
</Checkbox>
</li>
<li className="fl with30 edu-txt-left task-hide paddingl5">{item.school_users}</li>

@ -459,8 +459,8 @@ class PathDetailIndex extends Component{
this.props.checkIfLogin()===false?"":progress === undefined ? "" : progress === null ? "" :
<div className="edu-back-white myProgress padding40-20 mb10">
<p className="mb20">
<span className="font-16 mr10">我的进展</span>
<Tooltip placement="bottom" title="获得经验值/总经验值">
<span className="font-16 mr10">关卡数</span>
<Tooltip placement="bottom" title="已通过关卡数/总关卡数">
<span className="color-green" >{progress.my_score} / {progress.all_score}</span>
</Tooltip>
</p>

@ -76,8 +76,7 @@
-o-transition: all 1s;
width: 100%;
position: absolute;
top: -50%;
margin-top: 67.5px;
top: -17.5px;
}
.squareCard .squareImg img:hover{
transform: scale(1.05);

@ -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) => {
@ -300,6 +302,11 @@ class TPMIndex extends Component {
(props) => (<TPMRepositoryComponent {...this.props} {...this.state} {...props}
/>)
}></Route>
<Route path="/shixuns/:shixunId/secret_repository" render={
(props) => (<TPMRepositoryComponent {...this.props} {...this.state} {...props} secret_repository_tab={true}
/>)
}></Route>
{/* <Route exact path="/shixuns/:shixunId/propaedeutics" component={TPMPropaedeuticsComponent}></Route> */}
<Route exact path="/shixuns/:shixunId/propaedeutics" render={

@ -11,6 +11,8 @@ import Repository from './shixunchild/Repository/Repository'
import TPMRightSection from './component/TPMRightSection'
import TPMNav from './component/TPMNav'
import RepositoryChooseModal from './component/modal/RepositoryChooseModal'
class TPMRepository extends Component {
constructor(props) {
super(props)
@ -34,6 +36,7 @@ class TPMRepository extends Component {
shixun={shixun}
{...this.props}
></TPMNav>
{/* <RepositoryChooseModal {...this.props}></RepositoryChooseModal> */}
{ loadingContent ?
<CircularProgress size={40} thickness={3} style={{ marginLeft: 'auto', marginRight: 'auto', marginTop: '200px', display: 'block' }}/> :
<Repository

@ -30,6 +30,12 @@ class TPMRepositoryComponent extends Component {
isContentWidth100: this._isFileInPathArray(pathArray)
}
}
componentDidUpdate(prevProps, prevState) {
if (this.props.secret_repository_tab != prevProps.secret_repository_tab) {
this.fetchRepo()
}
}
componentDidMount = () => {
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 : ''

@ -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 || <div>
<div>已创建的私密版本库及其内容将在保存时被删除</div>
<div>是否确认取消勾选</div>
</div>,
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 {
</span>
</div>
{ (vnc || webssh == 2) && <div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>私密版本库:</span>
<span className="fl mt5">
<Checkbox checked={is_secret_repository === undefined ? false : is_secret_repository}
onChange={this.is_secret_repository}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则启用私密版本库学员页面不能查看该版本库目录</label>
</span>
</div>}
<div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>禁用复制粘贴:</span>
<span className="fl mt5">
@ -2239,7 +2337,7 @@ export default class TPMsettings extends Component {
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>VNC图形化评测:</span>
<span className="fl mt5 ml5">
<Checkbox checked={vnc_evaluate === undefined ? false : vnc_evaluate} onChange={this.shixun_vnc_evaluate}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则在VNC图形化实训中给学员开启评测</label>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则在学员的VNC图形化页面中开启评测功能</label>
</span>
</div>:""}

@ -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")}
></textarea>
<div className="clearfix lineh-30">
<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>
</RadioGroup>
</div>
</div>
)
})}

@ -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 {
<Link to={`/shixuns/${shixunId}/repository`}
style={{display: this.props.identity >4||this.props.identity===undefined ? "none" : 'block'}}
className={`${match.url.indexOf('repository') != -1 ? 'active' : ''} fl mr40`}>版本库</Link>
className={`${match.url.indexOf('/repository') != -1 ? 'active' : ''} fl mr40`}>版本库</Link>
{secret_repository && <Link to={`/shixuns/${shixunId}/secret_repository`}
style={{display: this.props.identity >4||this.props.identity===undefined ? "none" : 'block'}}
className={`${match.url.indexOf('secret_repository') != -1 ? 'active' : ''} fl mr40`}>私密版本库</Link>}
<Link to={`/shixuns/${shixunId}/collaborators`}
className={`${match.url.indexOf('collaborators') != -1 ? 'active' : ''} fl mr40`}>合作者</Link>

@ -121,7 +121,7 @@ class TPMRightSection extends Component {
<div className="padding20 edu-back-white mb10 mt10" style={{
display: TPMRightSectionData === undefined?"none":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "none" : "block"
}}>
<p className="mb20 font-16 clearfix">相关实践课程</p>
<p className="mb20 font-16 clearfix">所属课程</p>
<div className="recommend-list" >
{
TPMRightSectionData===undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.map((i,k)=>{
@ -164,7 +164,7 @@ class TPMRightSection extends Component {
<div className="padding20 edu-back-white"
style={{
display:
TPMRightSectionData === undefined?"none":TPMRightSectionData.recommands===undefined?"none":TPMRightSectionData.recommands.length === 0 ? "none" : "block"
TPMRightSectionData === undefined?"none":TPMRightSectionData.recommands===undefined?"none":TPMRightSectionData.recommands.length === 0 ||TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "none" : "block"
}}
>
<p className="mb20 font-16 clearfix">推荐实训</p>

@ -0,0 +1,148 @@
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 = this.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)=>{
let {selectpath,saveshixunfilepath,pathtype} = this.state
if(pathtype===1){
let newselectpath;
if(saveshixunfilepath==="shixunfilepathplay"){
newselectpath=value
}else{
const type = selectpath.split('');
let types=false;
for(var i=0; i<type.length; i++){
if(type[i]===value){
types=true
return
}
}
if(types===false){
newselectpath=selectpath+value+ ""
}else{
newselectpath=selectpath
}
}
this.setState({
// selectpatharr:newarr,
selectpath: newselectpath,
})
}
const goblakepath=(path,key)=>{
}
}
return (
<Modal
keyboard={false}
title="文件路径"
visible={modalVisible}
closable={false}
footer={false}
>
<div className="task_popup_con">
<div className="newupload_conbox clearfix">
<ul id="directory_file">
{/*文件导航*/}
{
pathArray.length===0?"":pathArray.map((item,key)=>{
return(
<a className="f14 fb" onClick={()=>goblakepath(item.path,key,item)}>{item.val}</a>
)
})
}
{/*文件*/}
{trees === undefined || trees === null ? "" : trees.map((item, key) => {
return(
<li className="entry" key={key}>
<div className="filename_no_report hidden">{
item.type==="tree"?<a onClick={()=>sendgetfilepath(item.name,item.type,path+item.name)} data-remote="true">
<i className="iconfont icon-wenjianjia color-blue mr2"></i>
{path+item.name}</a>:<a data-remote="true">
<i className="iconfont icon-zuoye color-blue mr2"></i>
<span onClick={()=>savegetfilepath(path+item.name,item.type)}>{path+item.name}</span>
</a>
}
</div>
</li>
)
})}
</ul>
<div className="clearfix mt20">
<label className="fl mt5 directory_filepath">选中的文件路径</label>
<Input id="points_tusi" placeholder="选中的文件路径" className="fl input-60-40"
style={{width:"400px"}}
onInput={(e)=>this.saveselectpath(e)}
value={path}/>
</div>
<a className="task-btn task-btn-orange fr"
style={{marginTop: '20px',marginLeft:'20px'}} id="add_path" onClick={()=>onOk()}>确定</a>
<a className="pop_close task-btn mb10 fr"
style={{marginTop: '20px'}} id="back_page" onClick={()=>onCancel()}>取消</a>
</div>
</div>
</Modal>
)
}
export default RepositoryChooseModal

@ -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使用指南</a>
{
this.props.current_user && (this.props.current_user.admin ==true || (TPMRightSectionData && TPMRightSectionData.creator && TPMRightSectionData.creator.login == this.props.current_user.login)) ?
<ActionBtn style="orangeLine" className="ml20" to={`/shixuns/${match.params.shixunId}/repository/add_file`}>+添加文件</ActionBtn>:""
!this.props.secret_repository_tab &&
<ActionBtn style="orangeLine" className="ml20" to={`/shixuns/${match.params.shixunId}/repository/add_file`}>+添加文件</ActionBtn>
:""
}
<div className="fr font-12 color-grey-9 pr">
<label className="fl mt2">网址克隆</label>
<input type="text" id="copy_rep_content" className="fl url-input mt2"
@ -155,6 +158,10 @@ class Repository extends Component {
</div>
</div>
{this.props.secret_repository_tab && <RepositoryCombinePath {...this.props}>
</RepositoryCombinePath>}
</div>
</div>

@ -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

@ -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 (
<div className="df combinePathEditRow">
<style>{`
.combinePathEditRow {
margin: 4px 0;
}
.combinePathEditRow input {
flex: 0 0 300px;
border: none;
}
.combinePathEditRow .wordsBtn {
margin-left: 24px;
}
`}</style>
<span>第一版本库合并路径</span>
<Input disabled={!isEdit} value={value} onChange={this.onChange}></Input>
{!isEdit && <WordsBtn className="wordsBtn" onClick={this.onEdit} style="blue">修改</WordsBtn>}
{isEdit && <WordsBtn className="wordsBtn" onClick={this.onSave} style="blue">保存</WordsBtn>}
</div>
);
}
}
export default RepositoryCombinePath;

@ -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({

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe ShixunWorkComment, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
Loading…
Cancel
Save