Merge branch 'dev_jupyter' of http://bdgit.educoder.net/Hjqreturn/educoder into dev_jupyter

chromesetting
guange 5 years ago
commit 53f3edba6a

@ -1318,7 +1318,7 @@ class CoursesController < ApplicationController
@c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc") @c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
set_export_cookies set_export_cookies
member_to_xlsx(@course, @all_members, @c_homeworks, @c_exercises, @c_tasks) member_to_xlsx(@course, @all_members.includes(user: :user_extension), @c_homeworks, @c_exercises, @c_tasks)
filename_ = "#{current_user.real_name}_#{@course.name}_总成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}" filename_ = "#{current_user.real_name}_#{@course.name}_总成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx", render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx",
locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays, locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,

@ -3,7 +3,7 @@ class GamesController < ApplicationController
before_action :find_game, except: [:jupyter] before_action :find_game, except: [:jupyter]
before_action :find_shixun, only: [:show, :answer, :rep_content, :choose_build, :game_build, :game_status] before_action :find_shixun, only: [:show, :answer, :rep_content, :choose_build, :game_build, :game_status]
before_action :allowed before_action :allowed, except: [:jupyter]
#require 'iconv' #require 'iconv'
@ -95,6 +95,9 @@ class GamesController < ApplicationController
def jupyter def jupyter
# Jupyter没有challenge # Jupyter没有challenge
@myshixun = Myshixun.find_by_identifier params[:identifier] @myshixun = Myshixun.find_by_identifier params[:identifier]
unless current_user.id == @myshixun.user_id || current_user.admin_or_business?
raise Educoder::TipException.new(403, "..")
end
@shixun = @myshixun.shixun @shixun = @myshixun.shixun
# 判断tpm是否修改了 # 判断tpm是否修改了
begin begin

@ -1,4 +1,3 @@
require 'net/http'
class JupytersController < ApplicationController class JupytersController < ApplicationController
include JupyterService include JupyterService
@ -6,8 +5,8 @@ class JupytersController < ApplicationController
before_action :shixun, only: [:open, :open1, :test, :save] before_action :shixun, only: [:open, :open1, :test, :save]
def save_with_tpi def save_with_tpi
game = Game.find_by(identifier: params[:identifier]) myshixun = Myshixun.find_by(identifier: params[:identifier])
jupyter_save_with_game(game, params[:jupyter_port]) jupyter_save_with_game(myshixun, params[:jupyter_port])
render json: {status: 0} render json: {status: 0}
end end
@ -18,9 +17,9 @@ class JupytersController < ApplicationController
end end
def get_info_with_tpi def get_info_with_tpi
game = Game.find_by(identifier: params[:identifier]) myshixun = Myshixun.find_by(identifier: params[:identifier])
url = jupyter_url_with_game(game) url = jupyter_url_with_game(myshixun)
port = jupyter_port_with_game(game) port = jupyter_port_with_game(myshixun)
render json: {status: 0, url: url, port: port} render json: {status: 0, url: url, port: port}
end end
@ -32,89 +31,4 @@ class JupytersController < ApplicationController
end end
private
def open
#打开tpm - juypter接口
shixun = @shixun
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/get"
tpiID = "tpm#{shixun.id}"
params = {tpiID: tpiID, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
logger.info "test_juypter: uri->#{uri}, params->#{params}"
res = uri_post uri, params
logger.info "test_juypter: #{res}"
render plain: "https://#{res['port']}.jupyter.educoder.net/notebooks/data/workspace/myshixun_#{tpiID}/01.ipynb"
end
def open1
## 打开tpi
game = Game.find(2170158)
shixun = game.myshixun.shixun
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/get"
tpiID = game.myshixun.id
params = {tpiID: tpiID, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
res = uri_post uri, params
logger.info "test_juypter: #{res}"
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级99")
end
repo_save_path = game.myshixun.repo_save_path
render plain: "https://#{res['port']}.jupyter.educoder.net/notebooks/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb"
end
def test
render plain: 'test'
end
def save()
# 保存01.ipy
author_name = current_user.real_name
author_email = current_user.git_mail
message = "User submitted"
#https://47526.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_570461/f2ef5p798r20191210163135/01.ipynb?download=true
src_url = URI("https://47519.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_tpm3575/01.ipynb?download=true")
response = Net::HTTP.get_response(src_url)
if response.code.to_i != 200
raise("获取文件内容失败:#{response.code}")
end
content = response.body
c = GitService.update_file(repo_path: @shixun.repo_path,
file_path: "01.ipynb",
message: message,
content: content,
author_name: author_name,
author_email: author_email)
render plain: 'save: #{c.size}'
end
private
def shixun
@shixun = Shixun.find(3575)
end
end end

@ -716,7 +716,7 @@ class ShixunsController < ApplicationController
project_fork(@myshixun, @repo_path, current_user.login) project_fork(@myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path) rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
uri = "#{cloud_bridge}/bridge/game/openGameInstance" uri = "#{cloud_bridge}/bridge/game/openGameInstance"
params = {tpiID: "#{myshixun.id}", tpmGitURL: rep_url, tpiRepoName: myshixun.repo_name.split("/").last} params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
interface_post uri, params, 83, "实训云平台繁忙繁忙等级83" interface_post uri, params, 83, "实训云平台繁忙繁忙等级83"
end end
end end

@ -529,8 +529,8 @@ class StudentWorksController < ApplicationController
@echart_data = student_efficiency(@homework, @work) @echart_data = student_efficiency(@homework, @work)
@myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id } @myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id }
@myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id } @myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id }
filename_ = "#{@use&.student_id}_#{@use&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" filename_ = "#{@use&.student_id}_#{@use&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf"
filename = Base64.urlsafe_encode64(filename_.strip) filename = filename_.strip.tr("+/", "-_")
stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css) stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css)
if params[:export].present? && params[:export] if params[:export].present? && params[:export]
normal_status(0,"正在下载中") normal_status(0,"正在下载中")

@ -22,21 +22,21 @@ module ExportHelper
end end
end end
shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user) shixun_homeworks = shixun_homeworks&.includes(:score_student_works)
common_homeworks = homeworks.search_homework_type(1) #全部普通作业 common_homeworks = homeworks.search_homework_type(1) #全部普通作业
common_titles = common_homeworks.pluck(:name)+ ["总得分"] common_titles = common_homeworks.pluck(:name)+ ["总得分"]
common_homeworks = common_homeworks&.includes(score_student_works: :user) common_homeworks = common_homeworks&.includes(:score_student_works)
group_homeworks = homeworks.search_homework_type(3) #全部分组作业 group_homeworks = homeworks.search_homework_type(3) #全部分组作业
group_titles = group_homeworks.pluck(:name)+ ["总得分"] group_titles = group_homeworks.pluck(:name)+ ["总得分"]
group_homeworks = group_homeworks&.includes(score_student_works: :user) group_homeworks = group_homeworks&.includes(:score_student_works)
task_titles = tasks.pluck(:name) + ["总得分"] task_titles = tasks.pluck(:name) + ["总得分"]
tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user) tasks = tasks&.includes(:score_graduation_works)
exercise_titles = exercises.pluck(:exercise_name) + ["总得分"] exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user) exercises = exercises&.includes(:score_exercise_users)
total_user_score_array = [] #学生总成绩集合 total_user_score_array = [] #学生总成绩集合
@ -168,7 +168,7 @@ module ExportHelper
#实训作业 #实训作业
shixun_homeworks.each_with_index do |s,index| shixun_homeworks.each_with_index do |s,index|
all_student_works = s.score_student_works.select{|work| all_user_ids.include?(work.user_id)} #该实训题的全部用户回答 all_student_works = s.score_student_works.where(user_id: all_user_ids) #该实训题的全部用户回答
title_no = index.to_i + 1 title_no = index.to_i + 1
student_work_to_xlsx(all_student_works,s) student_work_to_xlsx(all_student_works,s)
shixun_work_display_name = format_sheet_name (title_no.to_s + "." + s.name).strip.first(30) shixun_work_display_name = format_sheet_name (title_no.to_s + "." + s.name).strip.first(30)
@ -178,7 +178,7 @@ module ExportHelper
#普通作业 #普通作业
common_homeworks.each_with_index do |c,index| common_homeworks.each_with_index do |c,index|
all_student_works = c.score_student_works.select{|work| all_user_ids.include?(work.user_id)} #当前用户的对该作业的回答 all_student_works = c.score_student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + index.to_i + 1 title_no = count_1 + index.to_i + 1
student_work_to_xlsx(all_student_works,c) student_work_to_xlsx(all_student_works,c)
@ -190,7 +190,7 @@ module ExportHelper
#分组作业 #分组作业
group_homeworks.each_with_index do |c,index| group_homeworks.each_with_index do |c,index|
all_student_works = c.score_student_works.select{|work| all_user_ids.include?(work.user_id)} #当前用户的对该作业的回答 all_student_works = c.score_student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + index.to_i + 1 title_no = count_1 + count_2 + index.to_i + 1
student_work_to_xlsx(all_student_works,c) student_work_to_xlsx(all_student_works,c)
work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30) work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30)
@ -200,7 +200,7 @@ module ExportHelper
#毕设任务 #毕设任务
tasks.each_with_index do |c,index| tasks.each_with_index do |c,index|
all_student_works = c.score_graduation_works.select{|work| all_user_ids.include?(work.user_id)} #当前用户的对该作业的回答 all_student_works = c.score_graduation_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + count_3 + index.to_i + 1 title_no = count_1 + count_2 + count_3 + index.to_i + 1
graduation_work_to_xlsx(all_student_works,c,current_user) graduation_work_to_xlsx(all_student_works,c,current_user)
work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30) work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30)
@ -210,7 +210,7 @@ module ExportHelper
#试卷的导出 #试卷的导出
exercises.each_with_index do |c,index| exercises.each_with_index do |c,index|
all_student_works = c.score_exercise_users.select{|work| all_user_ids.include?(work.user_id)} #当前用户的对该作业的回答 all_student_works = c.score_exercise_users.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1 title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1
get_export_users(c,course,all_student_works) get_export_users(c,course,all_student_works)
work_name = format_sheet_name (title_no.to_s + "." + c.exercise_name).strip.first(30) work_name = format_sheet_name (title_no.to_s + "." + c.exercise_name).strip.first(30)

@ -36,15 +36,15 @@ module JupyterService
end end
def _open_game_jupyter(game) def _open_game_jupyter(myshixun)
## 打开tpi ## 打开tpi
shixun = game.myshixun.shixun shixun = myshixun.shixun
if shixun.is_jupyter? if shixun.is_jupyter?
shixun_tomcat = edu_setting('cloud_bridge') shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/get" uri = "#{shixun_tomcat}/bridge/jupyter/get"
tpiID = game.myshixun.id tpiID = myshixun.id
params = {tpiID: tpiID, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"} params = {tpiID: tpiID, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
res = uri_post uri, params res = uri_post uri, params
@ -56,20 +56,20 @@ module JupyterService
@game_jupyter_port = res['port'] @game_jupyter_port = res['port']
repo_save_path = game.myshixun.repo_save_path repo_save_path = myshixun.repo_save_path
"https://#{res['port']}.jupyter.educoder.net/notebooks/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb" "https://#{res['port']}.jupyter.educoder.net/notebooks/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb"
end end
end end
def jupyter_url_with_game(game) def jupyter_url_with_game(myshixun)
_open_game_jupyter(game) _open_game_jupyter(myshixun)
end end
def jupyter_port_with_game(game) def jupyter_port_with_game(myshixun)
if @game_jupyter_port.to_i <=0 if @game_jupyter_port.to_i <=0
_open_game_jupyter(shixun) _open_game_jupyter(myshixun)
end end
@game_jupyter_port @game_jupyter_port
end end
@ -82,11 +82,11 @@ module JupyterService
tpiID = "tpm#{shixun.id}" tpiID = "tpm#{shixun.id}"
#https://47526.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_570461/f2ef5p798r20191210163135/01.ipynb?download=true #https://47526.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_570461/f2ef5p798r20191210163135/01.ipynb?download=true
src_url = URI("https://#{jupyter_port}.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/01.ipynb?download=true") src_url = "https://#{jupyter_port}.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/01.ipynb?download=true"
response = Net::HTTP.get_response(src_url) response = Faraday.get(src_url)
if response.code.to_i != 200 if response.status.to_i != 200
raise("获取文件内容失败:#{response.code}") raise("获取文件内容失败:#{response.status}")
end end
content = response.body content = response.body
@ -101,25 +101,25 @@ module JupyterService
return c.size return c.size
end end
def jupyter_save_with_game(game,jupyter_port) def jupyter_save_with_game(myshixun,jupyter_port)
author_name = current_user.real_name author_name = current_user.real_name
author_email = current_user.git_mail author_email = current_user.git_mail
message = "User submitted" message = "User submitted"
tpiID = game.myshixun.id tpiID = myshixun.id
repo_save_path = game.myshixun.repo_save_path repo_save_path = myshixun.repo_save_path
src_url = URI("https://#{jupyter_port}.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb?download=true") src_url = "https://#{jupyter_port}.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb?download=true"
response = Net::HTTP.get_response(src_url) response = Faraday.get(src_url)
if response.code.to_i != 200 if response.status.to_i != 200
raise("获取文件内容失败:#{response.code}") raise("获取文件内容失败:#{response.status}")
end end
content = response.body content = response.body
c = GitService.update_file(repo_path: game.myshixun.repo_path, c = GitService.update_file(repo_path: myshixun.repo_path,
file_path: "01.ipynb", file_path: "01.ipynb",
message: message, message: message,
content: content, content: content,

@ -327,7 +327,7 @@ module.exports = {
}, },
compress: { compress: {
drop_debugger: true, drop_debugger: true,
drop_console: false drop_console: true
} }
} }
}), }),

@ -615,6 +615,15 @@ class App extends Component {
<Route path="/shixuns/new" component={Newshixuns}> <Route path="/shixuns/new" component={Newshixuns}>
</Route> </Route>
{/* jupyter */}
<Route path="/tasks/:identifier/jupyter/"
render={
(props) => {
return (<JupyterTPI {...this.props} {...props} {...this.state}/>)
}
}
/>
<Route path="/tasks/:stageId" component={IndexWrapperComponent}/> <Route path="/tasks/:stageId" component={IndexWrapperComponent}/>
<Route path="/shixuns/:shixunId" component={TPMIndexComponent}> <Route path="/shixuns/:shixunId" component={TPMIndexComponent}>
@ -702,10 +711,6 @@ class App extends Component {
(props) => (<Developer {...this.props} {...props} {...this.state} />) (props) => (<Developer {...this.props} {...props} {...this.state} />)
}/> }/>
<Route path="/jupytertpi"
component={JupyterTPI}
/>
<Route exact path="/" <Route exact path="/"
// component={ShixunsHome} // component={ShixunsHome}
render={ render={

@ -4,12 +4,12 @@
* @Github: * @Github:
* @Date: 2019-12-10 09:03:48 * @Date: 2019-12-10 09:03:48
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-10 09:05:41 * @LastEditTime: 2019-12-12 10:53:47
*/ */
import { Icon } from 'antd'; import { Icon } from 'antd';
const MyIcon = Icon.createFromIconfontCN({ const MyIcon = Icon.createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_1535266_ss6796i6f6j.js' scriptUrl: '//at.alicdn.com/t/font_1535266_i4ilpm93kp.js'
}); });
export default MyIcon; export default MyIcon;

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

@ -539,26 +539,26 @@ class NewShixunModel extends Component{
className="fl task-hide edu-txt-left mt3" className="fl task-hide edu-txt-left mt3"
name="shixun_homework[]" name="shixun_homework[]"
></Checkbox> ></Checkbox>
{
this.props.type==='shixuns'?
(
item.is_jupyter===true?
<div className="myysljupyter fl ml15 mt3 intermediatecenter">
<p className="myysljupytertest">
Jupyter
</p>
</div>
:""
)
:""
}
<a target="_blank" href={this.props.type==='shixuns'?`/shixuns/${item.identifier}/challenges`:`/paths/${item.id}`} className="ml15 fl font-16 color-dark maxwidth1100" <a target="_blank" href={this.props.type==='shixuns'?`/shixuns/${item.identifier}/challenges`:`/paths/${item.id}`} className="ml15 fl font-16 color-dark maxwidth1100"
dangerouslySetInnerHTML={{__html: item.title}} dangerouslySetInnerHTML={{__html: item.title}}
> >
</a> </a>
{/*{*/}
{/* this.props.type==='shixuns'?*/}
{/* (*/}
{/* item.is_jupyter===true?*/}
<div className="myysljupyter fl ml20 mt3 intermediatecenter">
<p className="myysljupytertest">
Jupyter
</p>
</div>
{/* :""*/}
{/* )*/}
{/* :""*/}
{/*}*/}
<div className="cl"></div> <div className="cl"></div>
<style> <style>
{ {

@ -386,16 +386,19 @@
margin: 0 auto; margin: 0 auto;
} }
.myysljupyter{ .myysljupyter{
width:48px; width:54px;
height:22px; height:24px;
background:#FF6802; text-align: center;
border-radius:2px 10px 10px 2px; border-radius:5px;
border:1px solid #FF6802;
margin-top: 4px;
} }
.myysljupytertest{ .myysljupytertest{
width:39px; width:54px;
height:16px; height:16px;
line-height:16px;
font-size:12px; font-size:12px;
color:#FFFFFF; color:#FF6802;
line-height:16px; line-height:16px;
} }
.intermediatecenter{ .intermediatecenter{

@ -1,11 +1,14 @@
.banner-wrap{ .banner-wrap{
width: 100%; width: 100%;
height: 300px; height: 300px;
background-image: url(/static/media/path.e39ba7de.png); // background-image: url(/static/media/path.e39ba7de.png);
background-color: #000a4f; // background: #000a4f url(../../images/oj//oj_banner.jpg) none center;
/* background-size: cover; */ // background-color: #000a4f;
background-position: center; // /* background-size: cover; */
background-repeat: no-repeat; // background-position: center;
// background-repeat: no-repeat;
background: rgb(0, 1, 35) url(../../images/oj/oj_banner.jpg) no-repeat center;
background-size: cover;
} }
.developer-list{ .developer-list{

@ -334,6 +334,33 @@ class ShixunsHome extends Component {
.square-Item:nth-child(4n+0) { .square-Item:nth-child(4n+0) {
margin-right: 25px; margin-right: 25px;
} }
.tag-org{
position: absolute;
left: 0px;
top: 20px;
}
.tag-org-name{
width:66px;
height:28px;
background:#FF6802;
width:66px;
height:28px;
border-radius:0px 20px 20px 0px;
}
.tag-org-name-test{
width:45px;
height:23px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
margin-right: 6px;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
` `
} }
</style> </style>
@ -345,7 +372,13 @@ class ShixunsHome extends Component {
<span className="tag-name"> {item.tag_name}</span> <span className="tag-name"> {item.tag_name}</span>
{/*<img style={{display:item.tag_name===null?"none":'block'}} src={require(`./tag2.png`)}/>*/} {/*<img style={{display:item.tag_name===null?"none":'block'}} src={require(`./tag2.png`)}/>*/}
</div> </div>
{
item.is_jupyter===true?
<div className="tag-org">
<p className="tag-org-name intermediatecenter"> <span className="tag-org-name-test">Jupyter</span></p>
{/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/}
</div>
:""}
<div className={item.power === false ? "closeSquare" : "none"}> <div className={item.power === false ? "closeSquare" : "none"}>
<img src={getImageUrl("images/educoder/icon/lockclose.svg")} <img src={getImageUrl("images/educoder/icon/lockclose.svg")}
className="mt80 mb25"/> className="mt80 mb25"/>

@ -10,7 +10,8 @@ class Bottomsubmit extends Component {
} }
cannelfun=()=>{ cannelfun=()=>{
window.location.href=this.props.url // window.location.href=
this.props.history.replace(this.props.url);
} }

@ -748,7 +748,8 @@ class TPMBanner extends Component {
</li> </li>
</ul> </ul>
{
this.props.is_jupyter===false?
<div className="pr fl" id="commentsStar" onMouseOver={() => this.showonMouseOver()} <div className="pr fl" id="commentsStar" onMouseOver={() => this.showonMouseOver()}
onMouseOut={() => this.hideonMouseOut()}> onMouseOut={() => this.hideonMouseOut()}>
<div className={"color-grey-c ml15"} style={{color: "#Fff", textAlign: "center"}}>学员评分</div> <div className={"color-grey-c ml15"} style={{color: "#Fff", textAlign: "center"}}>学员评分</div>
@ -824,6 +825,9 @@ class TPMBanner extends Component {
</div> </div>
</div> </div>
:""
}
{ {
startbtn === false && shixunsDetails.shixun_status != -1 ? startbtn === false && shixunsDetails.shixun_status != -1 ?

@ -16,7 +16,6 @@ class TPMDataset extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
datas: [0, 1, 2, 3, 4, 5],
value: undefined, value: undefined,
columns: [ columns: [
{ {
@ -80,10 +79,15 @@ class TPMDataset extends Component {
datalist:[], datalist:[],
data_sets_count:0, data_sets_count:0,
selectedRowKeysdata:[], selectedRowKeysdata:[],
loadingstate:false,
checked: false,
} }
} }
componentDidMount() { componentDidMount() {
this.setState({
loadingstate:true,
})
this.getdatas() this.getdatas()
} }
@ -98,18 +102,20 @@ class TPMDataset extends Component {
datas.push(i); datas.push(i);
} }
this.setState({ this.setState({
selectedRowKeysdata:mydata, selectedRowKeysdata:mydata,
selectedRowKeys: datas, selectedRowKeys: datas,
checked:true,
}) })
// console.log(mydata); // console.log(mydata);
// console.log(datas); // console.log(datas);
} else { } else {
this.setState({ this.setState({
selectedRowKeysdata:[],
selectedRowKeys: [], selectedRowKeys: [],
checked:false,
}) })
} }
} }
@ -143,11 +149,26 @@ class TPMDataset extends Component {
collaboratorList: response.data, collaboratorList: response.data,
data_sets_count:response.data.data_sets_count, data_sets_count:response.data.data_sets_count,
datalist:datalists, datalist:datalists,
selectedRowKeysdata:[],
selectedRowKeys: [],
checked:false,
}); });
} }
} }
setTimeout(() => {
this.setState({
loadingstate:false,
})
}, 500)
}).catch((error)=>{ }).catch((error)=>{
setTimeout(() => {
this.setState({
loadingstate:false,
})
}, 500)
console.log(error) console.log(error)
}); });
@ -181,34 +202,39 @@ class TPMDataset extends Component {
collaboratorList: response.data, collaboratorList: response.data,
data_sets_count:response.data.data_sets_count, data_sets_count:response.data.data_sets_count,
datalist:datalists, datalist:datalists,
selectedRowKeysdata:[],
selectedRowKeys: [],
checked:false,
}); });
} }
} }
setTimeout(() => {
this.setState({
loadingstate:false,
})
}, 500)
}).catch((error)=>{ }).catch((error)=>{
setTimeout(() => {
this.setState({
loadingstate:false,
})
}, 500)
console.log(error) console.log(error)
}); });
} }
showModal = (id, status) => {
};
handleOk = (id, editid) => {
};
handleCancel = (e) => {
};
paginationonChanges = (pageNumber) => { paginationonChanges = (pageNumber) => {
// //console.log('Page: '); // //console.log('Page: ');
this.setState({ this.setState({
page: pageNumber, page: pageNumber,
loadingstate:true,
}) })
this.getdatastwo(pageNumber,10); this.getdatastwo(pageNumber,10);
} }
onSelectChange = (selectedRowKeys, selectedRows) => { onSelectChange = (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
this.setState( this.setState(
@ -237,27 +263,37 @@ class TPMDataset extends Component {
// 附件相关 START // 附件相关 START
handleChange = (info) => { handleChange = (info) => {
debugger
if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
let {fileList} = this.state; let {fileList} = this.state;
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
console.log("handleChange1"); console.log("handleChange1fileLists");
// if(fileList.length===0){ // if(fileList.length===0){
let fileLists = info.fileList; let fileLists = info.fileList;
// console.log(fileLists);
this.setState({ this.setState({
// fileList:appendFileSizeToUploadFileAll(fileList), // fileList:appendFileSizeToUploadFileAll(fileList),
fileList: fileLists, fileList: fileLists,
deleteisnot: false deleteisnot: false
}); });
}
if(info.file.status === 'done'){
//done 成功就会调用这个方法
this.getdatas(); this.getdatas();
// } // this.props.showNotification(`上传文件成功`);
}else if(info.file.status === 'removed'){
// this.props.showNotification(`上传文件失败`);
}else if(info.file.status === 'uploading'){
// this.props.showNotification(`正在上传文件中`);
} }
} }
} }
onAttachmentRemove = (file) => { onAttachmentRemove = (file) => {
debugger // debugger
if(!file.percent || file.percent == 100){ if(!file.percent || file.percent == 100){
confirm({ confirm({
title: '确定要删除这个附件吗?', title: '确定要删除这个附件吗?',
@ -278,18 +314,32 @@ class TPMDataset extends Component {
} }
deleteRemovedata(){ deleteRemovedata(){
debugger
console.log("删除"); if(this.state.selectedRowKeysdata===undefined || this.state.selectedRowKeysdata===null ||this.state.selectedRowKeysdata.length===0){
console.log(this.state.selectedRowKeysdata);
this.props.showNotification(`请选择要删除的文件`);
return
}
confirm({
title: '确定要删除文件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
const url = `/attachments/destroy_files.json`; const url = `/attachments/destroy_files.json`;
axios.delete(url, { axios.delete(url,
{ params: {
id:this.state.selectedRowKeysdata, id:this.state.selectedRowKeysdata,
}) }}
)
.then((response) => { .then((response) => {
if (response.data) { if (response.data) {
const { status } = response.data; const { status } = response.data;
if (status == 0) { if (status == 0) {
this.props.showNotification(`删除成功`); this.props.showNotification(`删除成功`);
this.getdatas() this.getdatas()
} }
} }
@ -297,9 +347,15 @@ class TPMDataset extends Component {
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
}); });
},
onCancel() {
console.log('Cancel');
},
});
} }
deleteAttachment = (file) => { deleteAttachment = (file) => {
console.log(file); // console.log(file);
let id=file.response ==undefined ? file.id : file.response.id let id=file.response ==undefined ? file.id : file.response.id
const url = `/attachements/destroy_files.json` const url = `/attachements/destroy_files.json`
axios.delete(url, { axios.delete(url, {
@ -333,7 +389,7 @@ class TPMDataset extends Component {
render() { render() {
const {tpmLoading, shixun, user, match} = this.props; const {tpmLoading, shixun, user, match} = this.props;
const {columns, datas, page, limit, selectedRowKeys,mylistansum,fileList,datalist,data_sets_count} = this.state; const {columns, page, limit, selectedRowKeys,mylistansum,fileList,datalist,data_sets_count,loadingstate} = this.state;
const rowSelection = { const rowSelection = {
selectedRowKeys, selectedRowKeys,
onChange: this.onSelectChange, onChange: this.onSelectChange,
@ -359,7 +415,7 @@ class TPMDataset extends Component {
onChange: this.handleChange, onChange: this.handleChange,
onRemove: this.onAttachmentRemove, onRemove: this.onAttachmentRemove,
beforeUpload: (file, fileList) => { beforeUpload: (file, fileList) => {
debugger
if (this.state.fileList.length >= 1) { if (this.state.fileList.length >= 1) {
return false return false
} }
@ -372,7 +428,6 @@ class TPMDataset extends Component {
message: '提示', message: '提示',
description: description:
'文件大小必须小于50MB', '文件大小必须小于50MB',
} }
) )
} }
@ -386,8 +441,6 @@ class TPMDataset extends Component {
file:file file:file
}) })
} }
console.log("handleChange2");
return isLt150M; return isLt150M;
}, },
} }
@ -407,9 +460,14 @@ class TPMDataset extends Component {
<div className="padding20 edu-back-white mt20 " style={{minHeight: '463px'}}> <div className="padding20 edu-back-white mt20 " style={{minHeight: '463px'}}>
<div className="sortinxdirection"> <div className="sortinxdirection">
{
data_sets_count>0?
<div className="tpmwidth"> <div className="tpmwidth">
<Checkbox onChange={this.mysonChange}>全选</Checkbox> <Checkbox checked={this.state.checked} onChange={this.mysonChange}>全选</Checkbox>
</div> </div>
:""
}
<div className="tpmwidth xaxisreverseorder"> <div className="tpmwidth xaxisreverseorder">
<style> <style>
{ {
@ -507,6 +565,8 @@ class TPMDataset extends Component {
className="mysjysltable4" className="mysjysltable4"
rowSelection={rowSelection} rowSelection={rowSelection}
rowClassName={this.rowClassName} rowClassName={this.rowClassName}
loading={loadingstate}
/> />
</div> </div>
} }

@ -20,9 +20,9 @@ import TPMRepositoryComponent from './TPMRepositoryComponent';
import TPMRepositoryCommits from './shixunchild/Repository/TPMRepositoryCommits'; import TPMRepositoryCommits from './shixunchild/Repository/TPMRepositoryCommits';
//import TPMsettings from './TPMsettings/TPMsettings'; import TPMsettings from './TPMsettings/TPMsettings';
import TPMsettings from './TPMsettings/oldTPMsettings'; //import TPMsettings from './TPMsettings/oldTPMsettings';
import TPMChallengeComponent from './TPMChallengeContainer'; import TPMChallengeComponent from './TPMChallengeContainer';
import TPMPropaedeuticsComponent from './TPMPropaedeuticsComponent'; import TPMPropaedeuticsComponent from './TPMPropaedeuticsComponent';
@ -153,7 +153,7 @@ class TPMIndex extends Component {
componentDidMount = () => { componentDidMount = () => {
let id = this.props.match.params.shixunId; let id = this.props.match.params.shixunId;
console.log('props', this.props); // console.log('props', this.props);
// let collaborators = `/shixuns/` + id + `/propaedeutics.json`; // let collaborators = `/shixuns/` + id + `/propaedeutics.json`;
// //
// axios.get(collaborators).then((response) => { // axios.get(collaborators).then((response) => {
@ -288,6 +288,7 @@ class TPMIndex extends Component {
<TPMBanner <TPMBanner
{...this.props} {...this.props}
{...this.state} {...this.state}
is_jupyter={this.state. is_jupyter}
></TPMBanner> ></TPMBanner>
} }
{/*筛选*/} {/*筛选*/}

@ -1,9 +1,15 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import MonacoEditor from 'react-monaco-editor';
//MonacoDiffEditor 对比模式 //MonacoDiffEditor 对比模式
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip} from 'antd'; import {
Badge,
Select,
Radio,
Checkbox,
Modal,
DatePicker,
Button,
} from 'antd';
// import "antd/dist/antd.css"; // import "antd/dist/antd.css";
@ -17,10 +23,7 @@ import './css/TPMsettings.css';
import {getImageUrl, toPath, getUrl, appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder'; import {getImageUrl, toPath, getUrl, appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
import {handleDateStrings} from "./oldTPMsettings"; import {handleDateStrings} from "./oldTPMsettings";
import Bottomsubmit from "../../modals/Bottomsubmit";
let origin = getUrl();
let path = getUrl("/editormd/lib/")
const $ = window.$; const $ = window.$;
@ -40,6 +43,7 @@ function range(start, end) {
} }
return result; return result;
} }
function disabledDateTime() { function disabledDateTime() {
return { return {
// disabledHours: () => range(0, 24).splice(4, 20), // disabledHours: () => range(0, 24).splice(4, 20),
@ -57,46 +61,210 @@ export default class Shixuninformation extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
can_copy:false,
use_scope:0,
opening_time:null,
opentime:false,
oldscope_partment:[],
scope_partment:[]
}
}
componentDidMount() {
if (this.props.data) {
this.setState({
can_copy: this.props.data && this.props.data.shixun.can_copy === undefined ? false :this.props.data.shixun.can_copy,
use_scope:this.props.data && this.props.data.shixun.use_scope,
opening_time: this.props.data && this.props.data.shixun.opening_time,
opentime:!this.props.data && this.props.data.shixun.opening_time?false:true,
oldscope_partment:this.props.data&&this.props.data.shixun.scope_partment,
})
}
let departmentsUrl = `/shixuns/departments.json`;
axios.get(departmentsUrl).then((response) => {
if (response.status === 200) {
if (response.data.message === undefined) {
this.setState({
departmentslist: response.data.shools_name
});
}
}
}).catch((error) => {
console.log(error)
});
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.data != this.props.data) {
if (this.props.data) {
this.setState({
can_copy: this.props.data && this.props.data.shixun.can_copy === undefined ? false :this.props.data.shixun.can_copy,
use_scope:this.props.data && this.props.data.shixun.use_scope,
opening_time: this.props.data && this.props.data.shixun.opening_time,
opentime:!this.props.data && this.props.data.shixun.opening_time?false:true,
oldscope_partment:this.props.data&&this.props.data.shixun.scope_partment,
})
} }
} }
}
onChangeTimePicker = (value, dateString) => { onChangeTimePicker = (value, dateString) => {
this.setState({ this.setState({
opening_time: dateString=== ""?"":moment(handleDateStrings(dateString)) opening_time: dateString === "" ? "" :handleDateStrings(dateString)
})
}
onSubmits = () => {
let {can_copy,use_scope,scope_partment,opening_time }=this.state;
let id = this.props.match.params.shixunId;
let url=`/shixuns/${id}/update_permission_setting.json`;
axios.post(url,
{
scope_partment:scope_partment,
shixun:{
can_copy: can_copy,
use_scope:use_scope,
opening_time:opening_time
}
}
).then((response) => {
if(response.data.status===-1){
}else{
this.props.getdatas()
this.props.showNotification("保存成功")
}
}).catch((error) => {
console.log(error)
})
}
CheckboxonChange=(e)=>{
this.setState({
can_copy:e.target.checked
})
}
SelectOpenpublic=(e)=>{
this.setState({
use_scope: e.target.value
});
}
shixunScopeInput = (e) => {
let {scope_partment,oldscope_partment} = this.state;
let datalist = scope_partment;
if (datalist===undefined) {
datalist=[]
}
datalist.push(e)
let scopetype=false;
scope_partment.map((item,key)=>{
if(item===e){
scopetype=true
}
}) })
oldscope_partment.map((item,key)=>{
if(item===e){
scopetype=true
}
})
if(scopetype===false){
this.setState({
scope_partment: datalist
});
}else{
this.props.showNotification("请勿指定相同的单位")
} }
}
shixunsfetch = (value, callback) => {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
currentValue = value;
function fake() {
let departmentsUrl = `/shixuns/departments.json?q=` + currentValue;
axios.get(departmentsUrl).then((response) => {
callback(response.data.shools_name);
}).catch((error) => {
console.log(error)
});
}
timeout = setTimeout(fake, 300);
}
shixunHandleSearch = (value) => {
this.shixunsfetch(value, departmentslist => this.setState({departmentslist}));
}
deleteScopeInput = (key) => {
let {scope_partment} = this.state;
let datalist = scope_partment;
datalist.splice(key, 1);
this.setState({
scope_partment: datalist
});
}
setopentime=(e)=>{
this.setState({
opentime:e.target.checked
})
}
render() { render() {
let {can_copy}=this.state;
let options;
if (this.props.departmentslist != undefined) { let options;
options = this.props.departmentslist.map((d, k) => { if (this.state.departmentslist != undefined) {
options = this.state.departmentslist.map((d, k) => {
return ( return (
<Option key={d} id={k}>{d}</Option> <Option key={d} id={k}>{d}</Option>
) )
}) })
} }
const dateFormat = 'YYYY-MM-DD HH:mm';
return ( return (
<div className="educontent mb50 edu-back-white padding10-20"> <div>
<div className="clearfix ml30"> <div className="educontent mb200 edu-back-white padding10-20 pdb30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>复制:</span> <div className="clearfix ml40">
<span className="fl mt5"> <span className="color-grey-6 mt5 fl font-16 ml20" style={{minWidth: '45px'}}>复制:</span>
<Checkbox checked={this.props.data&&this.props.data.shixun.can_copy === undefined ? false : this.props.data&&this.props.data.shixun.can_copy} onChange={this.props.data&&this.props.data.shixun.can_copy}></Checkbox> <span className="fl mt8 ml13">
<label style={{top:'6px'}} className="color-grey-9 ml10">(勾选则允许已认证的教师复制该实训)</label> <Checkbox
checked={this.state.can_copy}
onChange={this.CheckboxonChange}></Checkbox>
<label style={{top: '6px'}} className="color-grey-9 ml10">选中则允许已职业认证的教师复制该实训</label>
</span> </span>
</div> </div>
<div className="edu-back-white mb10 padding40-20" style={{display:this.props.identity===1?"block":this.props.data&&this.props.data.shixun.status===2&&this.props.data&&this.props.data.shixun.use_scope===0||this.props.data&&this.props.data.shixun.status===1&&this.props.data&&this.props.data.shixun.use_scope===0?"none":"block"}}> <div className="edu-back-white mb10 ml30 mt20">
<p className="color-grey-6 font-16 mb30">公开程度</p> {this.props.data && this.props.data.shixun.use_scope === 0 &&this.props.data && this.props.data.shixun.status === 2?"": <div>
<RadioGroup onChange={this.SelectOpenpublic} value={this.props.data&&this.props.data.use_scope}> <span className="color-grey-6 mt5 fl font-16" style={{minWidth: '45px'}}>公开程度:</span>
<Radio className="radioStyle" value={0}><span>对所有公开</span> <span className="color-grey-9">()</span></Radio> <span className="fl mt8 ml20">
<Radio className="radioStyle" value={1}><span>对指定单位公开</span> <span className="color-grey-9">()</span></Radio> <RadioGroup onChange={this.SelectOpenpublic} value={this.state.use_scope}>
<Radio className="radioStyle" value={0}><span>对所有单位公开</span> <span
className="color-grey-9">实训发布后所有用户可见</span></Radio>
<Radio className="radioStyle" value={1}><span>对指定单位公开</span> <span
className="color-grey-9">实训发布后仅对下方指定单位的用户可见</span></Radio>
</RadioGroup> </RadioGroup>
<div className="clearfix none" id="unit-all" style={{display: this.props.scopetype === false ? 'none' : 'block'}}> <div className="clearfix" id="unit-all"
style={{display:this.state.use_scope === 0 ? 'none' : 'block'}}>
<div className="fl ml25"> <div className="fl ml25">
<div className="fl" id="unit-input-part" style={{width: '100%'}}> <div className="fl" id="unit-input-part" style={{width: '100%'}}>
<div id="person-unit" className="fl pr mr10"> <div id="person-unit" className="fl pr mr10">
@ -107,6 +275,7 @@ export default class Shixuninformation extends Component {
onChange={(value) => this.shixunScopeInput(value)} onChange={(value) => this.shixunScopeInput(value)}
onSearch={this.shixunHandleSearch} onSearch={this.shixunHandleSearch}
showSearch showSearch
value={this.state.scope_partment}
defaultActiveFirstOption={false} defaultActiveFirstOption={false}
showArrow={false} showArrow={false}
filterOption={false} filterOption={false}
@ -116,22 +285,33 @@ export default class Shixuninformation extends Component {
{options} {options}
</Select> </Select>
</div> </div>
<span className="color-grey-9">(搜索并选中添加单位名称)</span> <span className="color-grey-9 openrenyuan">请通过搜索并选中单位名称进行添加</span>
</div> </div>
</div> </div>
<div style={{width: '100%'}}> <div style={{width: '100%'}}>
<div className="mt20 clearfix" id="task_tag_content"> <div className="mt20 clearfix" id="task_tag_content">
{ {
this.props.scope_partment===undefined?"":this.props.scope_partment.map((item,key)=>{ this.state.oldscope_partment.map((item,key)=>{
return (
<li key={key} className={"fl mr20"}>
<Button type="primary" ghost className={"Permanentban "}>
{item}
</Button>
</li>
)
})
}
{
this.state.scope_partment === undefined ? "" : this.state.scope_partment.map((item, key) => {
return ( return (
<li className="task_tag_span" key={key}><span>{item}</span> <li key={key} className={"fl mr20"}>
<a style={{ color: 'rgba(0,0,0,.25)' }} <Badge count={"x"} onClick={(key) => this.deleteScopeInput(key)}>
onClick={(key)=>this.deleteScopeInput(key)} <Button type="primary" ghost className={"Permanentban "}>
> {item}
{this.props.identity===1?"x":this.state.status===2&&this.props.scope_partment===this.props.scope_partments||this.state.status===1&&this.props.scope_partment===this.props.scope_partments?"":"×"} </Button>
</a> </Badge>
</li> </li>
) )
}) })
@ -140,15 +320,28 @@ export default class Shixuninformation extends Component {
</div> </div>
<span className={this.props.scope_partmenttype===true?"color-orange ml20 fl":"color-orange ml20 fl none"} id="public_unit_notice"> <span
className={this.props.scope_partmenttype === true ? "color-orange ml20 fl" : "color-orange ml20 fl none"}
id="public_unit_notice">
<i className="fa fa-exclamation-circle mr3"></i> <i className="fa fa-exclamation-circle mr3"></i>
请选择需要公开的单位 请选择需要公开的单位
</span> </span>
</div>
</div>
<div className="clearfix mt20 ml30"> </span>
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>开启时间:</span> </div>}
<span className="fl mt5">
<div className="clearfix mt20">
<span className="color-grey-6 mt5 fl font-16" style={{minWidth: '45px'}}>开启时间:</span>
<span className="fl mt8 ml20">
<Checkbox
checked={this.state.opentime=== undefined ? false : this.state.opentime}
onChange={this.setopentime}></Checkbox>
<label style={{top: '6px'}} className="color-grey-9 ml10">选中则学员在指定的开启时间后才能开启学习不选中则学员在实训发布后能立即开启学习</label>
<div className={"both"}></div>
{this.state.opentime===false?"":<div className="mt20 ml25">
<DatePicker <DatePicker
showToday={false} showToday={false}
showTime={{format: 'HH:mm'}} showTime={{format: 'HH:mm'}}
@ -157,19 +350,22 @@ export default class Shixuninformation extends Component {
locale={locale} locale={locale}
disabledTime={disabledDateTime} disabledTime={disabledDateTime}
disabledDate={disabledDate} disabledDate={disabledDate}
placeholder="请选择开启时间" placeholder="请输入开启时间"
value={this.props.shixun.opening_time===null||this.props.shixun.opening_time===""?"":moment(this.props.shixun.opening_time, dateFormat)} value={this.state.opening_time === null ||this.state.opening_time === "" ? "" : moment(this.state.opening_time, dateFormat)}
onChange={this.onChangeTimePicker} onChange={this.onChangeTimePicker}
dropdownClassName="hideDisable" dropdownClassName="hideDisable"
/> />
<label style={{top:'6px'}} className="color-grey-9 ml10" >为空则学员在实训发布后能随时开启实训挑战否则学员在开启时间后才能开启实训挑战</label> </div>}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</div> {this.props.identity < 5 ?
<Bottomsubmit {...this.props} {...this.state} url={`/shixuns/${this.props.match.params.shixunId}/challenges`}
onSubmits={this.onSubmits}/> : ""}
</div> </div>
); );
} }

@ -5,19 +5,12 @@ import MonacoEditor from 'react-monaco-editor';
import { import {
Input, Input,
Select, Select,
Radio,
Checkbox, Checkbox,
Popconfirm,
message,
Modal, Modal,
Icon, Icon,
DatePicker,
Breadcrumb,
Upload, Upload,
Button, Button,
notification,
Tooltip, Tooltip,
Tabs,
Form Form
} from 'antd'; } from 'antd';
@ -42,13 +35,16 @@ class Shixuninformation extends Component {
this.state = { this.state = {
NAME_COUNT: 60, NAME_COUNT: 60,
shixunmemoMDvalue: "", shixunmemoMDvalue: "",
language: "java",
testscripttiptype: false, testscripttiptype: false,
shixunName: '', shixunName: '',
trainee: undefined, trainee: undefined,
choice_small_type: [], choice_small_type: [],
simichecked: false, simichecked: false,
Executivetyoe: false,
Executiveordervalue: "",
Compilecommandvalue: "",
shixun_service_configs: undefined,
fileList:[]
} }
} }
@ -67,10 +63,47 @@ class Shixuninformation extends Component {
choice_standard_scripts: this.props.data.shixun.choice_standard_scripts, choice_standard_scripts: this.props.data.shixun.choice_standard_scripts,
shixunmemoMDvalue: this.props.data.shixun.evaluate_script, shixunmemoMDvalue: this.props.data.shixun.evaluate_script,
simichecked: this.props.data.shixun.is_secret_repository, simichecked: this.props.data.shixun.is_secret_repository,
shixun_service_configs: this.props.data.shixun.shixun_service_configs,
standard_scripts:this.props.data.shixun.standard_scripts,
shixun_service_configlist:this.props.data.shixun.shixun_service_configs,
})
if(this.props.data.shixun.choice_standard_scripts===null){
this.setState({
choice_standard_scripts:{id: this.props.data.shixun.standard_scripts[0].id, value: ""},
choice_standard_scriptssum:this.props.data.shixun.standard_scripts[0].id
})
this.props.form.setFieldsValue({
selectscripts:this.props.data.shixun.standard_scripts[0].id
})
this.get_mirror_script(this.props.data.shixun.standard_scripts[0].id)
}
let newlist = ""
this.props.data.shixun.choice_small_type.map((item, key) => {
this.props.data.shixun.small_type.map((i,k)=>{
if (item===i.id) {
newlist = newlist + `${i.description}`
}
})
})
this.setState({
subvalues: newlist
})
this.props.data.shixun.main_type.map((item,key)=>{
if(item.id===this.props.data.shixun.choice_main_type){
this.setState({
mainvalues:item.description,
})
}
}) })
this.props.form.setFieldsValue({ this.props.form.setFieldsValue({
name: this.props.data.shixun.name, name: this.props.data.shixun.name,
trainee: this.props.data.shixun.trainee,
selectleft: this.props.data.shixun.choice_main_type,
selectright:this.props.data.shixun.choice_small_type,
}) })
this.contentMdRef.current.setValue(this.props.data.shixun.description); this.contentMdRef.current.setValue(this.props.data.shixun.description);
} }
@ -202,15 +235,8 @@ class Shixuninformation extends Component {
fileList: [] fileList: []
}) })
} }
this.props.showNotification("提交成功")
notification.open(
{
message: '提示',
description:
'提交成功!',
}
)
this.sendhideModaly() this.sendhideModaly()
} }
@ -223,13 +249,123 @@ class Shixuninformation extends Component {
} }
bigClass = (value) => { setlanguage = (e) => {
this.setState({
language: e.target.value
})
if (e.target.value) {
this.setState({
languagewritetype: false
})
}
}
setruntime = (e) => {
this.setState({
runtime: e.target.value
})
if (e.target.value) {
this.setState({
systemenvironmenttype: false
})
}
}
setrun_method = (e) => {
this.setState({
run_method: e.target.value
})
if (e.target.value) {
this.setState({
testcoderunmodetype: false
})
}
}
// 附件相关 START
handleChange = (info) => {
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
let {fileList} = this.state;
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
console.log("handleChange1");
// if(fileList.length===0){
let fileLists = info.fileList;
this.setState({
// fileList:appendFileSizeToUploadFileAll(fileList),
fileList: fileLists,
deleteisnot: false
});
// }
}
}
}
onAttachmentRemove = (file) => {
if (!file.percent || file.percent == 100) {
Modal.confirm({
title: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
console.log("665")
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
}
deleteAttachment = (file) => {
console.log(file);
let id = file.response == undefined ? file.id : file.response.id
const url = `/attachments/${id}.json`
axios.delete(url, {})
.then((response) => {
if (response.data) {
const {status} = response.data;
if (status == 0) {
// console.log('--- success')
this.setState((state) => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
deleteisnot: true
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
bigClass = (value,e) => {
this.setState({
mainvalues:e.props.name
})
let list = [] let list = []
list.push(this.props.data.shixun.choice_main_type) list.push(this.state.choice_main_type)
this.props.data.shixun.choice_small_type.map((item,key)=>{ this.state.choice_small_type.map((item, key) => {
list.push(item) list.push(item)
}) })
let newshixun_service_configs=this.props.data.shixun.shixun_service_configs;
let newshixun_service_configs = this.state.shixun_service_configs;
let newshixun_service_configsagin = []; let newshixun_service_configsagin = [];
newshixun_service_configs.map((item, key) => { newshixun_service_configs.map((item, key) => {
list.map((its, index) => { list.map((its, index) => {
@ -240,6 +376,7 @@ class Shixuninformation extends Component {
}) })
this.props.data.shixun.main_type.some((item, key) => { this.props.data.shixun.main_type.some((item, key) => {
if (item.id === value) { if (item.id === value) {
newshixun_service_configsagin[0] = { newshixun_service_configsagin[0] = {
@ -254,28 +391,87 @@ class Shixuninformation extends Component {
} }
} }
) )
this.props.form.setFieldsValue({
selectleft: value,
})
let url = `/shixuns/get_mirror_script.json?mirror_id=` + value; let url = `/shixuns/get_mirror_script.json?mirror_id=` + value;
axios.get(url).then((response) => { axios.get(url).then((response) => {
if (response.status === 200) { if (response.status === 200) {
// console.log(response.data) this.setState({
choice_standard_scripts:{id: response.data[0].id, value: ""},
choice_standard_scriptssum:response.data[0].id
})
this.props.form.setFieldsValue({
selectscripts:response.data[0].id
})
this.get_mirror_script(response.data[0].id)
this.setState({ this.setState({
choice_main_type: value, choice_main_type: value,
standard_scripts: response.data, standard_scripts: response.data,
choice_standard_scripts:null,
shixun_service_configs: newshixun_service_configsagin, shixun_service_configs: newshixun_service_configsagin,
shixun_service_configlist: newshixun_service_configsagin, shixun_service_configlist: newshixun_service_configsagin,
}) })
} }
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
}); });
} }
Deselectlittle = (value,e) => {
let {shixun_service_configs, choice_small_type} = this.state;
let newshixun_service_configs = shixun_service_configs;
let newchoice_small_type = choice_small_type;
newshixun_service_configs.some((item, key) => {
if (item.mirror_repository_id === value) {
newshixun_service_configs.splice(key, 1)
return true
}
}
)
newchoice_small_type.some((item, key) => {
if (item === value) {
newchoice_small_type.splice(key, 1)
return true
}
}
)
this.setState({
choice_small_type: newchoice_small_type,
shixun_service_configs: newshixun_service_configs,
shixun_service_configlist: newshixun_service_configs,
})
}
littleClass = (value) => { showlittleClass=(value,e)=>{
let newshixun_service_configs=this.props.data.shixun.shixun_service_configs; let newlist = ""
let newchoice_small_type=this.props.data.shixun.choice_small_type; e.map((item, key) => {
if (item.props.name != "") {
newlist = newlist + `${item.props.name}`
}
})
this.setState({
subvalues: newlist
})
this.props.form.setFieldsValue({
selectright: value,
})
}
littleClass = (value,e) => {
let newshixun_service_configs = this.state.shixun_service_configs;
let newchoice_small_type = this.state.choice_small_type;
let list = [] let list = []
list.push(this.props.data.shixun.choice_main_type) list.push(this.state.choice_main_type)
newchoice_small_type.map((item, key) => { newchoice_small_type.map((item, key) => {
list.push(item) list.push(item)
}) })
@ -330,16 +526,22 @@ class Shixuninformation extends Component {
}) })
} }
get_mirror_script=()=>{ get_mirror_script = (ids) => {
let {choice_standard_scriptssum} = this.state; let {choice_standard_scriptssum} = this.state;
let id = this.props.match.params.shixunId; let id = this.props.match.params.shixunId;
let pul = "/shixuns/" + id + "/get_script_contents.json?script_id=" + choice_standard_scriptssum; let url = `/shixuns/${id}/get_script_contents.json`;
axios.get(pul).then((response) => { axios.get((url),{params:{
script_id:ids?ids:choice_standard_scriptssum
}}).then((response) => {
if (response.status === 200) { if (response.status === 200) {
// this.evaluate_scriptMD(response.data.content, "shixunmemoMD"); // this.evaluate_scriptMD(response.data.content, "shixunmemoMD");
if(ids==undefined){
this.setState({ this.setState({
standard_scriptsModal: false, standard_scriptsModal: false,
standard_scriptsModals: true, standard_scriptsModals: true,
})
}
this.setState({
shixunmemoMDvalue: response.data.content shixunmemoMDvalue: response.data.content
}) })
} }
@ -355,16 +557,151 @@ class Shixuninformation extends Component {
}) })
} }
showModal = () => {
this.setState({
visibleTemplate: true,
});
}
handleCancelTemplate = (e) => {
this.setState({
Executiveordervalue: "",
Compilecommandvalue: "",
visibleTemplate: false
})
}
hideModalTemplate = (e) => {
let id = this.props.match.params.shixunId;
let {Executiveordervalue, Compilecommandvalue} = this.state;
if (Executiveordervalue === "" || Executiveordervalue === undefined) {
this.setState({
Executivetyoe: true,
});
return
}
// Executiveordervalue=String(Executiveordervalue);
// Compilecommandvalue=String(Compilecommandvalue);
let trl = `/shixuns/${id}/get_custom_script.json?compile=${Executiveordervalue}&excutive=${Compilecommandvalue}`
axios.get(trl).then((response) => {
// this.evaluate_scriptMD(response.data.shixun_script, "shixunmemoMD");
this.setState({
shixunmemoMDvalue: response.data.shixun_script
})
}).catch((error) => {
console.log(error)
});
this.setState({
visibleTemplate: false
})
}
Executiveorder = (e) => {
this.setState({
Executiveordervalue: e.target.value
})
}
Compilecommand = (e) => {
this.setState({
Compilecommandvalue: e.target.value
})
}
setConfigsInputs=(e,keys,str)=>{
let {shixun_service_configs}=this.state;
let newshixun_service_configs=shixun_service_configs;
newshixun_service_configs.map((item,key)=>{
if(key===keys){
switch (str) {
case 1:
item.cpu_limit=e.target.value
break;
case 2:
item.lower_cpu_limit=e.target.value
break;
case 3:
item.memory_limit=e.target.value
break;
case 4:
item.request_limit=e.target.value
break;
}
}
})
this.setState({
shixun_service_configs:newshixun_service_configs,
shixun_service_configlist:newshixun_service_configs,
})
}
onSubmits=()=>{
const mdContnet = this.contentMdRef.current.getValue().trim();
let{choice_standard_scriptssum,choice_standard_scripts}=this.state;
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
let url = `/shixuns/${this.props.match.params.shixunId}.json`;
let newshixun_service_configlist = this.state.shixun_service_configlist.map(v => {
let v1 = Object.assign({},v);
delete v1.name;
return v1
});
let data={
main_type:this.state.choice_main_type,
sub_type:this.state.choice_small_type,
is_secret_repository:this.state.simichecked,
shixun:{
name: values.name,
trainee: this.state.trainee,
is_jupyter: this.props.shixunsDetails.is_jupyter,
mirror_script_id: this.props.shixunsDetails.is_jupyter===true?null:this.state.choice_standard_scriptssum===undefined?this.state.choice_standard_scripts:this.state.choice_standard_scriptssum,
},
shixun_info: {
description: mdContnet,
evaluate_script: this.props.shixunsDetails.is_jupyter===true?"":this.state.shixunmemoMDvalue
},
shixun_service_configs:newshixun_service_configlist
}
axios.put(url, data).then((result) => {
if (result) {
if (result.data) {
this.props.getdatas()
if(result.data.shixun_identifier){
this.props.showNotification("基本信息更新成功")
}
}
}
}).catch((error) => {
// ////console.log(error)
});
}
});
}
Selectthestudent = (value) => {
this.setState({
trainee: value
})
}
render() { render() {
let operateauthority = this.props.identity === 1 ? true : this.props.identity < 5 && this.props.data.shixun.status == 0 ? true : false; let operateauthority = this.props.identity === 1 ? true : this.props.identity < 5 && this.props.data.shixun.status == 0 ? true : false;
// console.log(operateauthority) // console.log(operateauthority)
const {getFieldDecorator} = this.props.form; const {getFieldDecorator} = this.props.form;
const {languagewrite, systemenvironment, testcoderunmode, fileList, choice_standard_scripts, postapplyvisible, shixunmemoMDvalue} = this.state; const { fileList, choice_standard_scripts, postapplyvisible, shixunmemoMDvalue} = this.state;
// console.log("1222") // console.log("1222")
// console.log(choice_standard_scripts) // console.log(choice_standard_scripts)
const {shixun_service_configs}=this.props;
const uploadProps = { const uploadProps = {
width: 600, width: 600,
fileList, fileList,
@ -384,17 +721,9 @@ class Shixuninformation extends Component {
const isLt150M = file.size / 1024 / 1024 < 50; const isLt150M = file.size / 1024 / 1024 < 50;
if (!isLt150M) { if (!isLt150M) {
// this.props.showNotification(`文件大小必须小于50MB`); // this.props.showNotification(`文件大小必须小于50MB`);
notification.open( this.props.showNotification("文件大小必须小于50MB")
{
message: '提示',
description:
'文件大小必须小于50MB',
}
)
} }
if (this.state.file !== undefined) { if (this.state.file !== undefined) {
console.log("763")
this.setState({ this.setState({
file: file file: file
}) })
@ -403,15 +732,10 @@ class Shixuninformation extends Component {
file: file file: file
}) })
} }
console.log("handleChange2");
return isLt150M; return isLt150M;
}, },
} }
return ( return (
<div> <div>
<div className="educontent mb50 edu-back-white padding10-20"> <div className="educontent mb50 edu-back-white padding10-20">
@ -487,7 +811,8 @@ class Shixuninformation extends Component {
rules: [{required: true, message: '请选择主类别'}], rules: [{required: true, message: '请选择主类别'}],
})( })(
<div className="width100 fl mr20"> <div className="width100 fl mr20">
<Select placeholder="请选择主类别" value={this.state.choice_main_type === "" ? undefined : this.state.choice_main_type} <Select placeholder="请选择主类别"
value={this.state.choice_main_type === "" ? undefined : this.state.choice_main_type}
style={{width: 180}} style={{width: 180}}
onChange={operateauthority ? this.bigClass : ""} onChange={operateauthority ? this.bigClass : ""}
optionFilterProp="children" optionFilterProp="children"
@ -499,7 +824,7 @@ class Shixuninformation extends Component {
{ {
this.props.data === undefined ? "" : this.props.data.shixun.main_type.map((item, key) => { this.props.data === undefined ? "" : this.props.data.shixun.main_type.map((item, key) => {
return ( return (
<Option value={item.id} key={key} > <Option value={item.id} key={key} name={item.description}>
<Tooltip placement="right" title={item.description === "" ? "无描述" : item.description}> <Tooltip placement="right" title={item.description === "" ? "无描述" : item.description}>
{item.type_name} {item.type_name}
</Tooltip> </Tooltip>
@ -516,28 +841,28 @@ class Shixuninformation extends Component {
<Form.Item <Form.Item
style={{"borderBottom": 'none', 'width': '61%', 'float': 'left', 'marginTop': '40px'}} style={{"borderBottom": 'none', 'width': '81%', 'float': 'left', 'marginTop': '40px'}}
className="chooseDes pr" className="chooseDes pr"
> >
<div className=" fl pr mr20"> <div className=" fl pr mr20">
{getFieldDecorator('selectright', { {getFieldDecorator('selectright', {
rules: [{required: true, message: '请选择小类别'}], rules: [{required: false, message: '请选择小类别'}],
})( })(
<div className=" fl pr mr20"> <div className=" fl pr mr20">
<Select placeholder="请选择小类别" <Select placeholder="请选择小类别"
mode="multiple" mode="multiple"
onChange={this.selectright}
value={this.state.choice_small_type.length === 0 || this.state.choice_small_type[0] === "" || this.state.choice_small_type === [] ? undefined : this.state.choice_small_type} value={this.state.choice_small_type.length === 0 || this.state.choice_small_type[0] === "" || this.state.choice_small_type === [] ? undefined : this.state.choice_small_type}
style={{width: 180,height:30}} style={{width: 200}}
disabled={operateauthority ? false : true} disabled={operateauthority ? false : true}
onDeselect={operateauthority ? this.Deselectlittle : ""} onDeselect={operateauthority ? this.Deselectlittle : ""}
onSelect={operateauthority ? this.littleClass : ""} onSelect={operateauthority ? this.littleClass : ""}
onChange={this.showlittleClass}
defaultOpen={false} defaultOpen={false}
> >
{ {
this.props.data === undefined ? "" : this.props.data.shixun.small_type.map((item, key) => { this.props.data === undefined ? "" : this.props.data.shixun.small_type.map((item, key) => {
return ( return (
<Option value={item.id} key={key}> <Option value={item.id} key={key} name={item.description}>
<Tooltip placement="right" title={item.description === "" ? "无描述" : item.description}> <Tooltip placement="right" title={item.description === "" ? "无描述" : item.description}>
{item.type_name} {item.type_name}
</Tooltip> </Tooltip>
@ -550,12 +875,13 @@ class Shixuninformation extends Component {
)} )}
<span className="fl ml20 color-grey lineh-20"> <span className="fl ml20 color-grey lineh-20">
<div> <div>
<div className={"font-12"}> {this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" :
已安装软件hadoop3.1.0jdk1.8 <div className={"font-12"} style={{'max-width': '600px'}}>
</div> {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`}
<div className={"font-12"}> {`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`}
说明添加了hadoop3.1.0jdk1.8的源码包添加了hadoop3.1.0jdk1.8的源码包 {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
</div> this.state.mainvalues === undefined || this.state.mainvalues === "" ? `说明:添加了` + this.state.subvalues : this.state.subvalues}`}
</div>}
</div> </div>
</span> </span>
</div> </div>
@ -568,12 +894,12 @@ class Shixuninformation extends Component {
</div> </div>
<Form.Item { this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter===true?"":<Form.Item
label={"评测脚本"} label={"评测脚本"}
style={{"borderBottom": 'none'}} style={{"borderBottom": 'none'}}
className="chooseDes pr" className="chooseDes pr"
> >
{getFieldDecorator('select123', { {getFieldDecorator('selectscripts', {
rules: [{required: true, message: '请选择评测脚本'}], rules: [{required: true, message: '请选择评测脚本'}],
})( })(
<div className="with15 fl pr"> <div className="with15 fl pr">
@ -584,7 +910,7 @@ class Shixuninformation extends Component {
value={choice_standard_scripts === undefined || choice_standard_scripts === null ? undefined : choice_standard_scripts.id === undefined ? choice_standard_scripts : choice_standard_scripts.id} value={choice_standard_scripts === undefined || choice_standard_scripts === null ? undefined : choice_standard_scripts.id === undefined ? choice_standard_scripts : choice_standard_scripts.id}
onChange={operateauthority ? this.SelectScput : ""}> onChange={operateauthority ? this.SelectScput : ""}>
{ {
this.props.data === undefined ? "" : this.props.data.shixun.standard_scripts.map((item, key) => { this.state.standard_scripts=== undefined ? "" : this.state.standard_scripts.map((item, key) => {
return ( return (
<Option value={parseInt(item.id)} name={item.scptname} key={key}>{item.scptname}</Option> <Option value={parseInt(item.id)} name={item.scptname} key={key}>{item.scptname}</Option>
) )
@ -594,13 +920,19 @@ class Shixuninformation extends Component {
</Select> </Select>
</div> </div>
)} )}
<span className="fl ml20 color-blue"> <span className="fl ml20 color-blue" style={{'line-height': '30px'}}>
使用自定义脚本 <span onClick={() => this.showModal()}>使用自定义脚本</span>
<span className={"color-grey ml10"} onClick={() => this.testscripttip(0)}> <span className={"color-grey ml10"} onClick={() => this.testscripttip(0)}>
<Icon type="exclamation-circle"/> <Icon type="exclamation-circle"/>
</span> </span>
<div className="invite-tip clearfix none " id="test_script_tip" <div className="invite-tip clearfix none " id="test_script_tip"
style={{top: '33px', left: '-15px',width: '450px',zIndex: '10',display: this.state.testscripttiptype===true?'block':"none"}}> style={{
top: '33px',
left: '-15px',
width: '450px',
zIndex: '10',
display: this.state.testscripttiptype === true ? 'block' : "none"
}}>
<style> <style>
{ {
` `
@ -638,9 +970,9 @@ class Shixuninformation extends Component {
</p> </p>
</div> </div>
</span> </span>
</Form.Item> </Form.Item>}
<div className="mt30 clearfix df"> { this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter===true?"": <div className="mt30 clearfix df">
<div <div
className={operateauthority === false ? 'nonemodel' : ""} className={operateauthority === false ? 'nonemodel' : ""}
></div> ></div>
@ -649,7 +981,7 @@ class Shixuninformation extends Component {
<MonacoEditor <MonacoEditor
height="450" height="450"
width="1150" width="1150"
language={this.state.language} // language={this.state.language}
value={shixunmemoMDvalue} value={shixunmemoMDvalue}
options={{ options={{
selectOnLineNumbers: true selectOnLineNumbers: true
@ -659,17 +991,18 @@ class Shixuninformation extends Component {
/> />
</div> </div>
</div> </div>
</div> </div>}
</Form> </Form>
<span className="ant-form-text mt20" >私密版本库 { this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter===true?"": <span className="ant-form-text mt20">私密版本库
<Checkbox onChange={this.simionChange} value={this.state.simichecked}>若需要对学员隐藏部分版本库内容时请选中选中即启用私密版本库请将需要对学员隐藏的文件存储在私密版本库</Checkbox> <Checkbox onChange={this.simionChange}
</span> value={this.state.simichecked}>若需要对学员隐藏部分版本库内容时请选中选中保存后表示启用私密版本库请将需要对学员隐藏的文件存储在私密版本库</Checkbox>
</span>}
{this.props.identity < 3 ? <div className="edu-back-white padding40-20 mb20"> {this.props.identity < 3 ? <div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">服务配置</p> <p className="color-grey-6 font-16 mb30">服务配置</p>
{ shixun_service_configs&&shixun_service_configs.map((item,key)=>{ {this.state.shixun_service_configs && this.state.shixun_service_configs.map((item, key) => {
return ( return (
<div key={key}> <div key={key}>
@ -689,7 +1022,8 @@ class Shixuninformation extends Component {
<div className="clearfix mb5"> <div className="clearfix mb5">
<label className="panel-form-label fl">最低CPU()</label> <label className="panel-form-label fl">最低CPU()</label>
<div className="pr fl with80 status_con"> <div className="pr fl with80 status_con">
<input type="text" value={item.lower_cpu_limit} onInput={(e)=>this.setConfigsInputs(e,key,2)} <input type="text" value={item.lower_cpu_limit}
onInput={(e) => this.setConfigsInputs(e, key, 2)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称"/> className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称"/>
</div> </div>
<div className="cl"></div> <div className="cl"></div>
@ -708,7 +1042,8 @@ class Shixuninformation extends Component {
<input type="text" value={item.request_limit} onInput={(e) => this.setConfigsInputs(e, key, 4)} <input type="text" value={item.request_limit} onInput={(e) => this.setConfigsInputs(e, key, 4)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称"/> className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称"/>
</div> </div>
<label className="panel-form-label fl" style={{width: '48%'}}>温馨提示纯编程类型实训建议使用默认值对于大数据等建议使用最大内存的30%</label> <label className="panel-form-label fl"
style={{width: '48%'}}>温馨提示纯编程类型实训建议使用默认值对于大数据等建议使用最大内存的30%</label>
<div className="cl"></div> <div className="cl"></div>
</div> </div>
</div> </div>
@ -760,6 +1095,44 @@ class Shixuninformation extends Component {
</div> </div>
</Modal> </Modal>
<Modal
keyboard={false}
title="自定义模板"
visible={this.state.visibleTemplate}
onCancel={this.handleCancelTemplate}
onOk={this.hideModalTemplate}
okText="确认"
cancelText="取消"
>
<div>
<li className="clearfix mb15">
<label className="panel-form-label fl"><span
className="color-orange mr5">*</span></label>
<textarea className="task-form-80 task-height-150 panel-box-sizing fl mt10"
onInput={this.Executiveorder}
value={this.state.Executiveordervalue}
style={{width: '100%'}}
id="executive_command"
>
</textarea>
<p className="-text-danger fl mt5"
id="executive_command_notice"
style={{display: this.state.Executivetyoe === false ? "none" : "block"}}
>执行命令不能为空</p>
</li>
<li className="clearfix mb15">
<label className="panel-form-label fl">编译命令</label>
<textarea className="task-form-80 task-height-150 panel-box-sizing fl mt10"
value={this.state.Compilecommandvalue}
onInput={this.Compilecommand}
id="compile_command"
style={{width: '100%'}}
>
</textarea>
</li>
</div>
</Modal>
<Modal <Modal
keyboard={false} keyboard={false}
@ -777,20 +1150,21 @@ class Shixuninformation extends Component {
<textarea <textarea
className={this.state.languagewritetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"} className={this.state.languagewritetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
style={{width: '89%', height: '100px'}} style={{width: '89%', height: '100px'}}
onInput={this.setlanguagewrite} onInput={this.setlanguage}
value={languagewrite} value={this.state.language}
placeholder="请填写该镜像是基于什么语言示例Python" placeholder="请填写该镜像是基于什么语言示例Python"
id="demand_info"></textarea> id="demand_info"></textarea>
</li> </li>
<div className={"color-red shixunspanred"}>{this.state.languagewritetype === true ? "请填写该镜像语言" : ""}</div> <div
className={"color-red shixunspanred"}>{this.state.languagewritetype === true ? "请填写该镜像语言" : ""}</div>
<li className="clearfix ml1"> <li className="clearfix ml1">
<label className="panel-form-label fl ml50"><span <label className="panel-form-label fl ml50"><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label> className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea <textarea
className={this.state.systemenvironmenttype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"} className={this.state.systemenvironmenttype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
onInput={this.setsystemenvironment} onInput={this.setruntime}
style={{height: '100px'}} style={{height: '100px'}}
value={systemenvironment} value={this.state.runtime}
placeholder="请填写该镜像是基于什么linux系统环境,代码运行环境" placeholder="请填写该镜像是基于什么linux系统环境,代码运行环境"
id="demand_info"></textarea> id="demand_info"></textarea>
</li> </li>
@ -802,8 +1176,8 @@ class Shixuninformation extends Component {
<textarea <textarea
className={this.state.testcoderunmodetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"} className={this.state.testcoderunmodetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
onInput={this.settestcoderunmode} onInput={this.setrun_method}
value={testcoderunmode} value={this.state.run_method}
style={{height: '100px'}} style={{height: '100px'}}
placeholder="请填写该镜像中测试代码运行方式" placeholder="请填写该镜像中测试代码运行方式"
id="demand_info"></textarea> id="demand_info"></textarea>
@ -837,10 +1211,11 @@ class Shixuninformation extends Component {
</li> </li>
<div className="cl"></div> <div className="cl"></div>
</div> </div>
{/*</Form>*/}
</Modal> </Modal>
</div> </div>
<Bottomsubmit url={`/shixuns/${this.props.match.params.shixunId}/challenges`} onSubmits={ this.sendsure_apply}/> {this.props.identity < 5 ?
<Bottomsubmit {...this.props} {...this.state} url={`/shixuns/${this.props.match.params.shixunId}/challenges`}
onSubmits={this.onSubmits}/> : ""}
</div> </div>
); );

@ -2,7 +2,8 @@ import React, {Component} from 'react';
import { import {
Button, Button,
Tabs Tabs,
Modal
} from 'antd'; } from 'antd';
import TopShixuninformation from './Shixuninformation'; import TopShixuninformation from './Shixuninformation';
@ -23,21 +24,18 @@ const {TabPane} = Tabs;
export default class TPMsettings extends Component { export default class TPMsettings extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {}
}
} }
componentDidMount() { componentDidMount() {
this.getdatas()
}
let id = this.props.match.params.shixunId; getdatas=()=>{
let id = this.props.match.params.shixunId;
let Url = `/shixuns/` + id + `/settings.json`; let Url = `/shixuns/` + id + `/settings.json`;
axios.get(Url).then((response) => { axios.get(Url).then((response) => {
// alert(response.data.shixun.choice_standard_scripts) // alert(response.data.shixun.choice_standard_scripts)
if (response.status === 200) { if (response.status === 200) {
@ -62,26 +60,60 @@ export default class TPMsettings extends Component {
}); });
}
let departmentsUrl = `/shixuns/departments.json`; operateshixuns = (value) => {
axios.get(departmentsUrl).then((response) => {
if (response.status === 200) {
if (response.data.message === undefined) {
this.setState({ this.setState({
departmentslist: response.data.shools_name operateshixunstype: true,
}); delType: value
})
} }
hideoperateshixuns = () => {
this.setState({
operateshixunstype: false
})
} }
}).catch((error) => {
console.log(error)
});
shixunsdel = () => {
let id = this.props.match.params.shixunId;
let cul = `/shixuns/` + id + `.json`;
axios.delete(cul).then((response) => {
if (response.data.status === 1) {
this.props.showSnackbar("操作成功");
this.setState({
operateshixunstype: false,
});
window.location.href = "/shixuns";
}
}).catch((error) => {
console.log(error)
})
} }
shixunsclose = () => {
let id = this.props.match.params.shixunId;
let cul = `/shixuns/` + id + `/close.json`;
axios.post(cul).then((response) => {
if (response.data.status === 1) {
this.props.showSnackbar("操作成功");
this.setState({
operateshixunstype: false,
});
window.location.href = "/shixuns/" + id + "/challenges";
}
}).catch((error) => {
console.log(error)
})
}
render() { render() {
let showtabs= this.props.shixunsDetails === undefined ?"":this.props.shixunsDetails.is_jupyter===true?"":"学习页面设置"
return ( return (
<div> <div>
@ -98,35 +130,68 @@ export default class TPMsettings extends Component {
` `
} }
</style> </style>
<Tabs tabBarExtraContent={ <Tabs animated={false} tabBarExtraContent={
<div className={"mb20 mr20"}> <div className={"mb20 mr20"}>
<Button type="primary" ghost className={"Permanentban"}>
永久关闭 {
</Button> this.props.identity < 5 && this.state.data && this.state.data.shixun.status == 0 ?
<Button type="primary" ghost className={"Permanentban ml20"}> <Button type="primary" ghost className={"Permanentban mr20"} onClick={() => this.operateshixuns(1)}>
删除实训 删除实训
</Button> </Button>
: ""
}
{
this.props.identity == 1 && this.state.data && this.state.data.shixun.status == 2 ?
<Button type="primary" ghost className={"Permanentban mr20"} onClick={() => this.operateshixuns(1)}>
删除实训
</Button> : ""
}
{
this.props.identity === 1 && this.state.data && this.state.data.shixun.status == 2 ?
<Button type="primary" ghost className={"Permanentban"} onClick={() => this.operateshixuns(2)}>
永久关闭
</Button> : ""
}
</div> </div>
}> }>
<TabPane tab="基本信息" key="1"> <TabPane tab="基本信息" key="1">
<TopShixuninformation <TopShixuninformation
{...this.state} {...this.state}
{...this.props} {...this.props}
getdatas={()=>this.getdatas()}
/> />
</TabPane> </TabPane>
<TabPane tab="权限配置" key="2"> <TabPane tab="权限配置" key="2">
<Configuration <Configuration
{...this.state} {...this.state}
{...this.props} {...this.props}
getdatas={()=>this.getdatas()}
/> />
</TabPane> </TabPane>
<TabPane tab="学习页面设置" key="3"> {/*{ this.props.shixunsDetails===undefined?"":this.props.shixunsDetails.is_jupyter===true?"":<TabPane tab={showtabs} key="3">*/}
<LearningSettings {/* <LearningSettings*/}
{...this.state} {/* {...this.state}*/}
{...this.props} {/* {...this.props}*/}
/> {/* />*/}
</TabPane> {/*</TabPane>}*/}
</Tabs> </Tabs>
<Modal
keyboard={false}
title="提示"
visible={this.state.operateshixunstype}
closable={false}
footer={null}
>
<div className="task-popup-content">
{this.state.delType === 1 ? <p className="task-popup-text-center font-16 pb20">是否确认删除 </p> :
<p className="task-popup-text-center font-16 pb20">关闭后,<br/>用户不能再开始挑战了是否确认关闭 </p>}
</div>
<div className="task-popup-submit clearfix">
<a onClick={this.hideoperateshixuns} className="task-btn fl">取消</a>
{this.state.delType === 1 ? <a className="task-btn task-btn-orange fr" onClick={this.shixunsdel}>确定</a> :
<a className="task-btn task-btn-orange fr" onClick={this.shixunsclose}>确定</a>}
</div>
</Modal>
</div> </div>
); );

@ -126,3 +126,12 @@ a.newuse_scope-btn {
.ant-tabs-extra-content{ .ant-tabs-extra-content{
margin-top: 18px; margin-top: 18px;
} }
.pdb30{
padding-bottom: 30px;
}
.openrenyuan{
margin-top: 5px !important;
display: inline-block;
}

@ -5,6 +5,10 @@ import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class TPMNav extends Component { class TPMNav extends Component {
render() { render() {
// console.log("componentDidMount");
// console.log("TPMNavTPMNavTPMNavTPMNav");
// console.log(this.props);
const { user, match, shixun, secret_repository,is_jupyter} = this.props; const { user, match, shixun, secret_repository,is_jupyter} = this.props;
let isAdminOrCreator = false; let isAdminOrCreator = false;
if (user) { if (user) {
@ -17,6 +21,7 @@ class TPMNav extends Component {
// console.log(match.path) // console.log(match.path)
// console.log("TPMNavTPMNavTPMNav"); // console.log("TPMNavTPMNavTPMNav");
// console.log(is_jupyter); // console.log(is_jupyter);
const is_teacher = this.props&&this.props.current_user&&this.props.current_user.is_teacher?this.props.current_user.is_teacher:"";
return ( return (
<div className="bor-bottom-greyE clearfix pl20 pr20 pt40 pb20 edu-back-white challengeNav"> <div className="bor-bottom-greyE clearfix pl20 pr20 pt40 pb20 edu-back-white challengeNav">
<Link <Link
@ -48,20 +53,44 @@ class TPMNav extends Component {
{/*jupyter*/} {/*jupyter*/}
{ {
this.props.is_jupyter===true? this.props.is_jupyter===true?
(
is_teacher===true?
<Link to={`/shixuns/${shixunId}/dataset`} <Link to={`/shixuns/${shixunId}/dataset`}
className={`${match.url.indexOf('dataset') != -1 ? 'active' : ''} fl mr40`}>数据集</Link> className={`${match.url.indexOf('dataset') != -1 ? 'active' : ''} fl mr40`}>数据集</Link>
:"" :""
} )
:""
}
{
this.props.is_jupyter === false ?
<Link to={`/shixuns/${shixunId}/shixun_discuss`} <Link to={`/shixuns/${shixunId}/shixun_discuss`}
className={`${match.url.indexOf('shixun_discuss') != -1 ? 'active' : ''} fl mr40`}>评论</Link> className={`${match.url.indexOf('shixun_discuss') != -1 ? 'active' : ''} fl mr40`}>评论</Link>
:""
}
{
this.props.is_jupyter === false ?
<Link to={`/shixuns/${shixunId}/ranking_list`} <Link to={`/shixuns/${shixunId}/ranking_list`}
className={`${match.url.indexOf('ranking_list') != -1 ? 'active' : ''} fl mr40`}>排行榜</Link> className={`${match.url.indexOf('ranking_list') != -1 ? 'active' : ''} fl mr40`}>排行榜</Link>:""
}
{this.props.identity >2||this.props.identity===undefined?"":
(this.props.is_jupyter === false?
<Link to={`/shixuns/${shixunId}/audit_situation`}
className={`${match.url.indexOf('audit_situation') != -1 ? 'active' : ''} fl`}>审核情况</Link>
:
is_teacher===true?
<Link to={`/shixuns/${shixunId}/audit_situation`}
className={`${match.url.indexOf('audit_situation') != -1 ? 'active' : ''} fl`}>审核情况</Link>
:
""
{this.props.identity >2||this.props.identity===undefined?"":<Link to={`/shixuns/${shixunId}/audit_situation`} )
className={`${match.url.indexOf('audit_situation') != -1 ? 'active' : ''} fl`}>审核情况</Link>}
}
{this.props.identity >4||this.props.identity===undefined ? "":<Link to={`/shixuns/${shixunId}/settings`} className="edu-default-btn edu-blueline-btn ml20 fr" {this.props.identity >4||this.props.identity===undefined ? "":<Link to={`/shixuns/${shixunId}/settings`} className="edu-default-btn edu-blueline-btn ml20 fr"
>配置</Link>} >配置</Link>}

@ -4,38 +4,165 @@
* @Github: * @Github:
* @Date: 2019-12-11 08:35:23 * @Date: 2019-12-11 08:35:23
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-11 09:13:09 * @LastEditTime: 2019-12-12 20:19:48
*/ */
import './index.scss'; import './index.scss';
import React from 'react'; import React, { useEffect, useState } from 'react';
import SplitPane from 'react-split-pane'; import SplitPane from 'react-split-pane';
import { Button } from 'antd'; import { Button, Modal } from 'antd';
import {
connect
} from 'react-redux';
import UserInfo from '../../developer/components/userInfo'; import UserInfo from '../../developer/components/userInfo';
import actions from '../../../redux/actions';
import LeftPane from './leftPane';
import RightPane from './rightPane';
function JupyterTPI (props) { function JupyterTPI (props) {
// 获取 identifier 值
const {
match: {
params = {}
},
url,
loading, // 保存按钮状态
dataSets, // 数据集
jupyter_info,
getJupyterInfo,
syncJupyterCode,
jupyter_tpi_url_state,
// getJupyterTpiDataSet,
getJupyterTpiUrl,
saveJupyterTpi,
changeLoadingState,
changeGetJupyterUrlState
} = props;
const {identifier} = params;
const [userInfo, setUserInfo] = useState({});
const [jupyterInfo, setJupyterInfo] = useState({});
const [updateTip, setUpdateTip] = useState(true);
const [myIdentifier, setMyIdentifier] = useState('');
useEffect(() => {
/* jupyter TPI
* 获取 用户信息,
* 实训的 identifier, 状态 名称 是否被修改等信息
*/
getJupyterInfo(identifier);
}, [identifier]);
useEffect(() => {
// 设置jupyter信息
setJupyterInfo(jupyter_info || {});
const {user, tpm_modified, myshixun_identifier} = jupyter_info;
if (user) {
setUserInfo(user);
}
if (myshixun_identifier) {
setMyIdentifier(myshixun_identifier);
}
// 同步代码
if (tpm_modified && updateTip && myshixun_identifier) {
setUpdateTip(false);
Modal.confirm({
title: '更新通知',
content: (<div className="update_notice">
<p className="update_txt">关卡任务的代码文件有更新啦</p>
<p className="update_txt">更新操作将保留已完成的评测记录和成绩</p>
<p className="update_txt">还未完成评测的任务代码请自行保存</p>
</div>),
okText: '确定',
cancelText: '取消',
onOk () {
syncJupyterCode(myshixun_identifier, '同步成功');
}
})
}
}, [props]);
// 重置实训
const handleClickResetTpi = () => {
Modal.confirm({
title: '重置实训',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重新加载初始代码
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
console.log('调用重置代码....', myIdentifier);
if (myIdentifier) {
syncJupyterCode(myIdentifier, '重置成功');
}
}
})
}
// 退出实训
const handleClickQuitTpi = () => {
// console.log(jupyterInfo);
const { identifier } = jupyterInfo;
props.history.push(`/shixuns/${identifier}/challenges`);
}
// 重新获取 jupyter url
const handleOnReloadUrl = (id) => {
// console.log('jupyter 信息: ', jupyterInfo);
// 改变加载状态值
changeGetJupyterUrlState(-1);
getJupyterTpiUrl({identifier: myIdentifier});
}
// 保存代码
const handleOnSave = () => {
// 改变按钮状态
changeLoadingState(true);
saveJupyterTpi();
}
return ( return (
<div className="jupyter_area"> <div className="jupyter_area">
<div className="jupyter_header"> <div className="jupyter_header">
<UserInfo userInfo={{}} /> <UserInfo userInfo={userInfo} />
<p className="jupyter_title"> <p className="jupyter_title">
<span className="title_desc">MySQL数据库编程开发实训(基础篇)</span> <span className="title_desc" style={{ marginTop: '20px' }}>{jupyterInfo.name}</span>
<span className="title_time">时间</span> <span className="title_time"></span>
</p> </p>
<p className="jupyter_btn"> <p className="jupyter_btn">
{/* sync | poweroff */} {/* sync | poweroff */}
<Button className="btn_common" type="link" icon="sync">重置实训</Button> <Button
<Button className="btn_common" type="link" icon="poweroff">退出实训</Button> className="btn_common"
type="link"
icon="sync"
onClick={handleClickResetTpi}
>重置实训</Button>
<Button
className="btn_common"
type="link"
icon="poweroff"
onClick={handleClickQuitTpi}
>退出实训</Button>
</p> </p>
</div> </div>
<div className="jupyter_ctx"> <div className="jupyter_ctx">
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="30%"> <SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="30%">
<div className={'split-pane-left'}> <div className={'split-pane-left'}>
左侧内容 <LeftPane dataSets={dataSets} />
</div> </div>
<SplitPane split="vertical" defaultSize="100%" allowResize={false}> <SplitPane split="vertical" defaultSize="100%" allowResize={false}>
<div>右侧内容</div> <RightPane
identifier={myIdentifier}
status={jupyter_tpi_url_state}
url={url}
loading={loading}
onReloadUrl={handleOnReloadUrl}
onSave={handleOnSave}
/>
<div /> <div />
</SplitPane> </SplitPane>
</SplitPane> </SplitPane>
@ -44,4 +171,35 @@ function JupyterTPI (props) {
); );
} }
export default JupyterTPI; const mapStateToProps = (state) => {
const {
jupyter_info,
jupyter_tpi_url,
jupyter_data_set,
jupyter_tpi_url_state
} = state.jupyterReducer;
const { loading } = state.commonReducer;
return {
loading,
jupyter_info,
url: jupyter_tpi_url,
dataSets: jupyter_data_set,
jupyter_tpi_url_state
};
}
const mapDispatchToProps = (dispatch) => ({
changeGetJupyterUrlState: (status) => dispatch(actions.changeGetJupyterUrlState(status)),
getJupyterInfo: (identifier) => dispatch(actions.getJupyterInfo(identifier)),
// 重置代码
syncJupyterCode: (identifier, msg) => dispatch(actions.syncJupyterCode(identifier, msg)),
// getJupyterTpiDataSet: (identifier) => dispatch(actions.getJupyterTpiDataSet(identifier)),
getJupyterTpiUrl: (identifier) => dispatch(actions.getJupyterTpiUrl(identifier)),
saveJupyterTpi: () => dispatch(actions.saveJupyterTpi()),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JupyterTPI);

@ -55,7 +55,7 @@
height: 60px; height: 60px;
line-height: 60px; line-height: 60px;
background-color: #070F1A; background-color: #070F1A;
padding-left: 30px;
.jupyter_title{ .jupyter_title{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -90,4 +90,12 @@
position: relative; position: relative;
height: calc(100vh - 60px); height: calc(100vh - 60px);
} }
.update_notice{
text-align: center;
.update_txt{
line-height: 18px;
font-size: 14px;
}
}
} }

@ -0,0 +1,84 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-12 10:34:03
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 20:18:46
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
import {Icon, Empty} from 'antd';
import MyIcon from '../../../../common/components/MyIcon';
function LeftPane (props) {
// 获取数据集
const { dataSets = [] } = props;
const emptyCtx = (
<div className="jupyter_empty">
<Empty />
</div>
);
// const listCtx = ;
const [renderCtx, setRenderCtx] = useState(() => (emptyCtx));
useEffect(() => {
if (dataSets.length > 0) {
console.log('数据集的个数: ', dataSets.length);
const oList = dataSets.map((item, i) => {
return (
<li className="jupyter_item" key={`key_${i}`}>
<Icon type="file-text" className="jupyter_icon"/>
<span className="jupyter_name">{item.title}</span>
</li>
);
});
const oUl = (
<ul className="jupyter_data_list">
{ oList }
</ul>
);
setRenderCtx(oUl);
}
}, [props]);
// 渲染数据集
// const renderList = () => {
// // 空数据
// if (dataSets.length === 0) {
// return <div className="jupyter_empty">
// <Empty />
// </div>
// } else {
// // 渲染列表
// const oList = dataSets.map((item, i) => {
// return (
// <li className="jupyter_item" key={`key_${i}`}>
// <Icon type="file-text" className="jupyter_icon"/>
// <span className="jupyter_name">{item.title}</span>
// </li>
// );
// });
// return (
// <ul className="jupyter_data_list">
// { oList }
// </ul>
// );
// }
// }
return (
<div className="jupyter_data_sets_area">
<h2 className="jupyter_h2_title">
<MyIcon type="iconwenti" className="jupyter_data_icon"/> 数据集
</h2>
{ renderCtx }
</div>
)
}
export default LeftPane;

@ -0,0 +1,55 @@
.jupyter_data_sets_area{
height: 100%;
.jupyter_h2_title{
height: 50px;
line-height: 50px;
background-color: #EEEEEE;
padding: 0 30px;
.jupyter_data_icon{
color: #7286ff;
font-size: 24px;
position: relative;
top: 2px;
transform: scale(1.5);
}
}
.jupyter_data_list,
.jupyter_empty{
height: calc(100vh - 110px);
overflow-y: auto;
}
.jupyter_data_list{
.jupyter_item{
line-height:45px;
border-bottom: 1px solid rgba(238,238,238, 1);
padding: 0 30px 0 60px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
cursor: pointer;
transition: .3s;
&:hover{
background-color: rgba(235, 235, 235, .3);
}
.jupyter_icon{
color: rgb(74, 188, 125);
font-size: 16px;
transform: scale(1.2);
margin-right: 5px;
}
.jupyter_name{
color: #000;
font-size: 16px;
}
}
}
.jupyter_empty{
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
}

@ -0,0 +1,90 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-12 15:04:20
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 17:41:41
*/
import './index.scss';
import React, { useEffect, useState } from 'react';
import { Spin, Button } from 'antd';
function RightPane (props) {
const {
status,
url,
onReloadUrl,
onSave,
loading
} = props;
const [renderCtx, setRenderCtx] = useState(() => loadInit);
// 重新获取 url
const handleClickReload = () => {
onReloadUrl && onReloadUrl();
}
const loadInit = (
<div className="jupyter_loading_init">
<Spin tip="加载中..."></Spin>
</div>
);
const loadError = (
<div className="jupyter_load_url_error">
<p className="jupyter_error_txt">
加载实训出错是否
<span
className="jupyter_reload"
onClick={handleClickReload}
>重新加载</span>
</p>
</div>
);
// 保存
const handleClickSubmit = () => {
console.log('调用了保存接口....');
onSave && onSave();
}
useEffect(() => {
if (status === -1) {
setRenderCtx(() => loadInit);
} else if (status === 0 && url) {
setRenderCtx(() => (
<div className="jupyter_result">
<div className="jupyter_iframe">
<iframe
title=" "
width="100%"
height="100%"
src={url}
className='jupyter_iframe_style'
></iframe>
</div>
<div className="jupyter_submit">
<Button
loading={loading}
type="primary"
onClick={handleClickSubmit}
>保存</Button>
</div>
</div>
));
} else {
setRenderCtx(() => loadError);
}
}, [status, url, loading]);
return (
<div className="jupyter_right_pane_area">
{ renderCtx }
</div>
)
}
export default RightPane;

@ -0,0 +1,62 @@
.jupyter_right_pane_area{
position: relative;
height: calc(100vh - 60px);
// background: pink;
.jupyter_load_url_error,
.jupyter_loading_init{
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 100%;
&::before{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
content: '';
}
}
.jupyter_loading_init{
&::before{
background-color: rgba(0,0,0,.2);
}
}
.jupyter_load_url_error{
// &::before{
// background-color: rgba(0,0,0,.2);
// }
.jupyter_error_txt{
position: relative;
z-index: 1;
.jupyter_reload{
cursor: pointer;
color: #1890ff;
}
}
}
.jupyter_result{
height: 100%;
.jupyter_iframe{
height: calc(100% - 56px);
// background: pink;
.jupyter_iframe_style{
border: none;
outline: none;
}
}
.jupyter_submit{
display: flex;
align-items: center;
height: 56px;
justify-content: flex-end;
padding-right: 30px;
}
}
}

@ -357,8 +357,7 @@ class Newshixuns extends Component {
console.log(file); console.log(file);
let id = file.response == undefined ? file.id : file.response.id let id = file.response == undefined ? file.id : file.response.id
const url = `/attachments/${id}.json` const url = `/attachments/${id}.json`
axios.delete(url, { axios.delete(url, {})
})
.then((response) => { .then((response) => {
if (response.data) { if (response.data) {
const {status} = response.data; const {status} = response.data;
@ -503,8 +502,8 @@ class Newshixuns extends Component {
> >
<Option value={1}>初级</Option> <Option value={1}>初级</Option>
<Option value={2}>中级</Option> <Option value={2}>中级</Option>
<Option value={3}>高级</Option> <Option value={3}>高级</Option>
<Option value={4}></Option> <Option value={4}></Option>
</Select> </Select>
</div> </div>
@ -567,7 +566,7 @@ class Newshixuns extends Component {
<div className=" fl pr mr20"> <div className=" fl pr mr20">
<Select placeholder="请选择小类别" <Select placeholder="请选择小类别"
mode="multiple" mode="multiple"
style={{width: 180}} style={{width: 280}}
onChange={this.sub_type} onChange={this.sub_type}
defaultOpen={false} defaultOpen={false}
className={"Selectlittle"} className={"Selectlittle"}
@ -590,7 +589,7 @@ class Newshixuns extends Component {
<span className="fl ml20 color-grey lineh-20"> <span className="fl ml20 color-grey lineh-20">
<div> <div>
{this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" : {this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" :
<div className={"font-12"} style={{'max-width':'700px'}}> <div className={"font-12"} style={{'max-width': '600px'}}>
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`} {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`}
{`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`} {`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : {`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
@ -704,7 +703,7 @@ class Newshixuns extends Component {
</div> </div>
</div> </div>
</div> </div>
<Bottomsubmit url={"/shixuns"} onSubmits={() => this.handleSubmit()}/> <Bottomsubmit {...this.props} {...this.state} url={"/shixuns"} onSubmits={() => this.handleSubmit()}/>
</div> </div>
); );

@ -392,9 +392,9 @@ a.white-btn.use_scope-btn:hover{
border-color: #096dd9; border-color: #096dd9;
} }
.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{ /*.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{*/
background-color: #4CACFF; /* background-color: #4CACFF;*/
} /*}*/
.newViewAfter .ant-input{ .newViewAfter .ant-input{
line-height: 40px !important; line-height: 40px !important;

@ -33,6 +33,9 @@ class Challengesjupyter extends Component {
iFrameHeight: '0px', iFrameHeight: '0px',
jupyter_port:0, jupyter_port:0,
jupyter_url:null, jupyter_url:null,
username:"",
booljupyterurls:false,
loading:false,
} }
} }
@ -53,102 +56,82 @@ class Challengesjupyter extends Component {
} }
} }
}).catch((error) => { }).catch((error) => {
console.log(error) //console.log(error)
}); });
} }
componentDidMount() { componentDidMount() {
setTimeout(this.ChallengesList(), 1000); setTimeout(this.ChallengesList(), 1000);
// console.log("componentDidMount");
// console.log("Challengesjupyter");
// console.log(this.props);
let id = this.props.match.params.shixunId; let id = this.props.match.params.shixunId;
let ChallengesURL = `/jupyters/get_info_with_tpm.json`; let ChallengesURL = `/jupyters/get_info_with_tpm.json`;
let datas={ let datas={
identifier:id, identifier:id,
} }
axios.get(ChallengesURL, {params: datas}).then((response) => { axios.get(ChallengesURL, {params: datas}).then((response) => {
debugger
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{ }else{
// console.log("componentDidMountChallengesjupyter");
// console.log(response.data);
debugger
if(response.data.status===0){ if(response.data.status===0){
this.setState({ this.setState({
jupyter_url:response.data.url, jupyter_url:response.data.url,
jupyter_port:response.data.port, jupyter_port:response.data.port,
}) })
}else{ }else{
} }
} }
this.setState({
booljupyterurls:true,
})
}).catch((error) => { }).catch((error) => {
console.log(error) this.setState({
booljupyterurls:true,
})
}); });
}
updatamakedown = (id) => {
} }
// 关卡的上移下移操作 updatamakedowns = () => {
operations = (sumid, type) => { this.setState({
loading:true,
} })
delOperations = (sumid) => { let id = this.props.match.params.shixunId;
let ChallengesURL = `/jupyters/get_info_with_tpm.json`;
let datas={
identifier:id,
} }
axios.get(ChallengesURL, {params: datas}).then((response) => {
clonedelOperationss = () => { if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
if(response.data.status===0){
this.setState({
jupyter_url:response.data.url,
jupyter_port:response.data.port,
})
}else{
} }
delOperationss = () => {
} }
this.setState({
startgameid=(id)=>{ booljupyterurls:true,
loading:false,
})
}).catch((error) => {
this.setState({
} booljupyterurls:true,
loading:false,
hidestartshixunsreplace=(url)=>{ })
});
} }
//编辑实训题目选择题
EditTraining=(type, ids, path)=>{
}
//开始实战按钮
startshixunCombat = (type, ids, id) => {
}
hidestartshixunCombattype=()=>{
}
hideAccountProfile=()=>{
};
modifyjupyter=()=>{ modifyjupyter=()=>{
// console.log("propsysl");
// console.log(propsysl);
let id=this.props.match.params.shixunId; let id=this.props.match.params.shixunId;
var jupyter_port=""; var jupyter_port="";
try{ try{
@ -162,7 +145,7 @@ class Challengesjupyter extends Component {
identifier:id, identifier:id,
jupyter_port:jupyter_port, jupyter_port:jupyter_port,
} }
axios.post(url, data) axios.get(url, {params: data})
.then((result) => { .then((result) => {
if (result.data.status === 0) { if (result.data.status === 0) {
this.props.showNotification(`应用成功`); this.props.showNotification(`应用成功`);
@ -171,47 +154,18 @@ class Challengesjupyter extends Component {
}) })
} }
sendToken=()=>{
// console.log("sendToken");
// const iframe = document.getElementById('iframe');
// console.log("modifyjupyter");
// const frameWindow = iframe.contentWindow;
// console.log("frameWindow");
// console.log(frameWindow);
}
render() { render() {
let{ChallengesDataList}=this.state; let{ChallengesDataList,booljupyterurls}=this.state;
let id = this.props.match.params.shixunId; let id = this.props.match.params.shixunId;
// var deptObjs=document.getElementById("IFRAMEID").contentWindow.document.getElementById("TAGID"); const is_teacher = this.props&&this.props.current_user&&this.props.current_user.is_teacher?this.props.current_user.is_teacher:false;
// //判断此元素是否存在
// if(deptObjs!=null){
// //设置该元素的样式或其他属性
// deptObjs.setAttribute('style',' height: 20px !important;'); //!important用来提升指定样式条目的应用优先权
// }
// var submitObj = document.getElementById('submit');
// if(submitObj){
// submitObj.style.color = 'green';
// }
// const dom = document.getElementById('shutdown');
// ReactDOM.unmountComponentAtNode(dom)
// // window.$('#picture_display').hide();
// window.$('.data-tip-right').hide()
// window.onload=()=>{
// debugger
// var _iframe = document.getElementById('header');
// console.log(_iframe);
// // .contentWindow.document.getElementById('shutdown_widget') //get iframe下的id
// // _iframe.style.display= "none"; //修改样式
// }
return ( return (
<React.Fragment> <React.Fragment>
<div className="mt30 pl20 pr20" > <div className="mt30 pl20 pr20" >
<Spin spinning={this.state.loading}>
<p className="clearfix mb20"> <p className="clearfix mb20">
<span className="font-16 fl">简介</span> <span className="font-16 fl">简介</span>
<Tooltip placement="bottom" title={"编辑"}> <Tooltip placement="bottom" title={"编辑"}>
@ -230,6 +184,23 @@ class Challengesjupyter extends Component {
<div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div> <div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div>
} }
</p> </p>
{
booljupyterurls===true?
(
this.state.jupyter_url === null?
<div className="mt50">
<p className="intermediatecenter sortinxdirection"><p className="colorbluetest">加载实训出错是否</p><p className="colorbluetwo" onClick={()=>this.updatamakedowns()}></p></p>
</div>
:""
)
:""
}
<style> <style>
{ {
` `
@ -256,6 +227,8 @@ class Challengesjupyter extends Component {
this.state.jupyter_url === null || this.state.jupyter_url === undefined ? this.state.jupyter_url === null || this.state.jupyter_url === undefined ?
"" ""
: :
(
is_teacher===true?
<div className="sortinxdirection mt60"> <div className="sortinxdirection mt60">
<div className="renwuxiangssi sortinxdirection"> <div className="renwuxiangssi sortinxdirection">
<div><p className="renwuxiangqdiv">任务详情</p></div> <div><p className="renwuxiangqdiv">任务详情</p></div>
@ -266,6 +239,10 @@ class Challengesjupyter extends Component {
className="challenbaocuntest">应用到实训</p></div> className="challenbaocuntest">应用到实训</p></div>
</div> </div>
</div> </div>
:
""
)
} }
<style> <style>
@ -289,9 +266,9 @@ class Challengesjupyter extends Component {
` `
} }
</style> </style>
{
is_teacher===true?
<div className="mt35"> <div className="mt35">
{/*https://48888.jupyter.educoder.net/tree?*/}
<div className="pb47"> <div className="pb47">
{ {
this.state.jupyter_url===null || this.state.jupyter_url===undefined? this.state.jupyter_url===null || this.state.jupyter_url===undefined?
@ -304,7 +281,10 @@ class Challengesjupyter extends Component {
} }
</div> </div>
</div> </div>
:""
}
</div> </div>
</Spin>
</div> </div>
</React.Fragment> </React.Fragment>

@ -31,6 +31,7 @@
height:30px; height:30px;
background:#29BD8B; background:#29BD8B;
border-radius:3px; border-radius:3px;
cursor:pointer
} }
.challenbaocuntest{ .challenbaocuntest{
width:103px; width:103px;
@ -39,7 +40,7 @@
color:#FFFFFF; color:#FFFFFF;
text-align: center; text-align: center;
line-height:30px; line-height:30px;
cursor:default cursor:pointer
} }
.renwuxiangqdiv{ .renwuxiangqdiv{
width:72px; width:72px;
@ -49,19 +50,28 @@
line-height:30px; line-height:30px;
} }
.renwuxiangqdivtest{ .renwuxiangqdivtest{
width:32px;
height:30px; height:30px;
font-size:16px; font-size:16px;
line-height:30px; line-height:30px;
} }
.renwuxiangssi{ .renwuxiangssi{
width: 30%; width: 50%;
} }
.renwuxiangssit{ .renwuxiangssit{
width: 70%; width: 50%;
} }
.pb47{ .pb47{
padding-bottom: 47px; padding-bottom: 47px;
} }
.colorbluetwo{
color: #1E8FFD;
font-size: 12px;
cursor:pointer;
}
.colorbluetest{
color: #06101A;
font-size: 12px;
cursor:default
}

@ -275,10 +275,10 @@ render() {
} }
<div className="fl pr shaiAllItem mt1"> <div className="fl pr shaiAllItem mt1">
<li className={this.state.diff===0?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(0)}>全部难度</li> <li className={this.state.diff===0?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(0)}>全部难度</li>
<li className={this.state.diff===1?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(1)}>初级学员</li> <li className={this.state.diff===1?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(1)}>初级</li>
<li className={this.state.diff===2?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(2)}>中级学员</li> <li className={this.state.diff===2?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(2)}>中级</li>
<li className={this.state.diff===3?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(3)}>高级学员</li> <li className={this.state.diff===3?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(3)}>高级</li>
<li className={this.state.diff===4?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(4)}>顶级学员</li> <li className={this.state.diff===4?"shaiItems shixun_repertoire active":"shaiItems shixun_repertoire"} onClick={()=>this.diff_search(4)}>高级</li>
</div> </div>
</div> </div>

@ -66,6 +66,8 @@
height:30px; height:30px;
background:#C4C4C4; background:#C4C4C4;
border-radius:3px; border-radius:3px;
cursor:pointer
} }
.deletebutomtext{ .deletebutomtext{
width:28px; width:28px;
@ -73,12 +75,14 @@
font-size:14px; font-size:14px;
color:#FFFFFF; color:#FFFFFF;
line-height:19px; line-height:19px;
cursor:pointer
} }
.deletebuttom{ .deletebuttom{
width:85px; width:85px;
height:30px; height:30px;
background:#29BD8B; background:#29BD8B;
border-radius:3px; border-radius:3px;
cursor:pointer
} }
.deletebuttomtest{ .deletebuttomtest{
width:56px; width:56px;
@ -86,6 +90,8 @@
font-size:14px; font-size:14px;
color:#FFFFFF; color:#FFFFFF;
line-height:19px; line-height:19px;
cursor:pointer
} }
.tpmwidth{ .tpmwidth{
width: 50%; width: 50%;
@ -111,6 +117,8 @@
height:30px; height:30px;
background:#FF5555; background:#FF5555;
border-radius:3px; border-radius:3px;
cursor:pointer
} }
.light-row{ .light-row{
background: #F7F7F8; background: #F7F7F8;

@ -329,6 +329,34 @@ class InfosShixun extends Component{
bottom: 100px; bottom: 100px;
} }
.square-list{width: 100%;box-sizing: border-box;margin-top:10px} .square-list{width: 100%;box-sizing: border-box;margin-top:10px}
.tag-org{
position: absolute;
left: 0px;
top: 20px;
}
.tag-org-name{
width:66px;
height:28px;
background:#FF6802;
width:66px;
height:28px;
border-radius:0px 20px 20px 0px;
}
.tag-org-name-test{
width:45px;
height:23px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
margin-right: 6px;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
` `
} }
</style> </style>
@ -350,6 +378,15 @@ class InfosShixun extends Component{
{/*<img className="fl" src={setImagesUrl("images/educoder/tag2.png")}/>*/} {/*<img className="fl" src={setImagesUrl("images/educoder/tag2.png")}/>*/}
</div> </div>
} }
{
item.is_jupyter===true?
<div className="tag-org">
<p className="tag-org-name intermediatecenter"> <span className="tag-org-name-test">Jupyter</span></p>
{/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/}
</div>
:""}
<a href="javascript:void(0)" className="square-img"> <a href="javascript:void(0)" className="square-img">
<img src={setImagesUrl(`${item.image_url}`)}/> <img src={setImagesUrl(`${item.image_url}`)}/>
</a> </a>

@ -50,6 +50,13 @@ const types = {
SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息 SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息
SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值 SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值
SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码 SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
/*** jupyter */
GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集
GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url
SAVE_JUPYTER_IDENTIFIER: 'SAVE_JUPYTER_IDENTIFIER', // 保存jupyter identifier
SAVE_JUPYTER_INFO: 'SAVE_JUPYTER_INFO', // 保存 jupyter 信息
CHANGE_JUPYTER_URL_STATE: 'CHANGE_JUPYTER_URL_STATE', // 获取url返回的状态值
SAVE_JUPYTER_TPI: 'SAVE_JUPYTER_TPI', // 保存 jupyter tpi
} }
export default types; export default types;

@ -62,6 +62,15 @@ import {
getUserInfoForNew getUserInfoForNew
} from './user'; } from './user';
import {
getJupyterTpiDataSet,
getJupyterTpiUrl,
getJupyterInfo,
syncJupyterCode,
changeGetJupyterUrlState,
saveJupyterTpi
} from './jupyter';
export default { export default {
toggleTodo, toggleTodo,
getOJList, getOJList,
@ -103,6 +112,13 @@ export default {
restoreInitialCode, restoreInitialCode,
getUserInfoForNew, getUserInfoForNew,
saveUserCodeForInterval, saveUserCodeForInterval,
saveEditorCodeForDetail saveEditorCodeForDetail,
// jupyter
getJupyterTpiDataSet,
getJupyterTpiUrl,
getJupyterInfo,
syncJupyterCode,
changeGetJupyterUrlState,
saveJupyterTpi
// isUpdateCodeCtx // isUpdateCodeCtx
} }

@ -0,0 +1,139 @@
/*
* @Description: jupyter tpi 相关内容
* @Author: tangjiang
* @Github:
* @Date: 2019-12-12 09:01:30
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 17:58:38
*/
import types from "./actionTypes";
import { message } from 'antd';
import {
fetchJupyterTpiDataSet,
fetchJupyterTpiUrl,
fetchJupyterInfo,
fetchSyncJupyterCode,
fetchSaveJupyterTpi
} from "../../services/jupyterServer";
// 获取 jupyter 相关信息
export const getJupyterInfo = (id) => {
return (dispatch) => {
fetchJupyterInfo(id).then(res => {
if (res.data.status === 401) return;
if (res.status === 200) {
const { data } = res;
console.log(data);
if (data.status === 0) {
dispatch({
type: types.SAVE_JUPYTER_INFO,
payload: data
});
const { identifier, myshixun_identifier } = data;
// 调用获取数据集接口
dispatch(getJupyterTpiDataSet(identifier));
// 调用获取url接口
dispatch(getJupyterTpiUrl({identifier: myshixun_identifier}));
}
}
})
}
}
// 获取 jupyter tpi 数据集
export const getJupyterTpiDataSet = (identifier) => {
return (dispatch) => {
fetchJupyterTpiDataSet(identifier).then(res => {
if (res.data.status === 401) return; // 用户未登录
console.log('数据集:', res);
if (res.status === 200) {
const {data_sets} = res.data;
dispatch({
type: types.GET_JUPYTER_DATA_SETS,
payload: data_sets
});
}
});
}
}
// 获取 jupyter tpi 地址
export const getJupyterTpiUrl = (obj) => {
return (dispatch, getState) => {
const {jupyter_info} = getState().jupyterReducer;
console.log(obj.identifier, jupyter_info.myshixun_identifier);
if (!obj.identifier && !jupyter_info.myshixun_identifier) return;
const id = obj.identifier || jupyter_info.myshixun_identifier;
fetchJupyterTpiUrl({identifier: id}).then(res => {
if (res.data.status === 401) return; // 用户未登录
console.log('获取url', res);
if (res.status === 200) {
const { status, url = '', port } = res.data;
dispatch({
type: types.GET_JUPYTER_TPI_URL,
payload: {
status,
url,
port
}
})
}
})
}
}
// 保存 jupyter identifer
export const saveJupyterIdentifier = (identifier) => {
return {
type: types.SAVE_JUPYTER_IDENTIFIER,
payload: identifier
}
}
// 重置代码
export const syncJupyterCode = (identifier, msg) => {
return (dispatch) => {
fetchSyncJupyterCode(identifier).then(res => {
// console.log('同步代码成功: ', res);
if (res.data.status === 401) return;
if (res.status === 200) {
const {status} = res.data
if (status === 0) message.success(msg);
}
})
}
}
// 改变状态值
export const changeGetJupyterUrlState = (status) => {
return {
type: types.CHANGE_JUPYTER_URL_STATE,
payload: status
}
}
// 保存 jupyter tpi
export const saveJupyterTpi = () => {
return (dispatch, getState) => {
const { jupyter_tpi_code, jupyter_info }= getState().jupyterReducer;
// console.log(jupyter_info.myshixun_identifier, jupyter_tpi_code);
if (!jupyter_info.myshixun_identifier) return;
const params = {
identifier: jupyter_info.myshixun_identifier,
jupyter_port: jupyter_tpi_code
};
console.log(params);
fetchSaveJupyterTpi(params).then(res => {
dispatch({
type: types.LOADING_STATUS,
payload: false
});
if (res.status === 200) {
const { data } = res;
if (data.status === 0) {
message.success('保存成功!')
}
}
}).catch(() => {
dispatch({
type: types.LOADING_STATUS,
payload: false
});
});
}
}

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 16:27:09 * @Date: 2019-11-27 16:27:09
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 11:00:19 * @LastEditTime: 2019-12-12 17:36:51
*/ */
import types from "../actions/actionTypes"; import types from "../actions/actionTypes";

@ -13,6 +13,7 @@ import ojListReducer from './ojListReducer';
import ojForUserReducer from './ojForUserReducer'; import ojForUserReducer from './ojForUserReducer';
import commonReducer from './commonReducer'; import commonReducer from './commonReducer';
import userReducer from './userReducer'; import userReducer from './userReducer';
import jupyterReducer from './jupyterReducer';
export default combineReducers({ export default combineReducers({
testReducer, testReducer,
@ -20,5 +21,6 @@ export default combineReducers({
ojListReducer, ojListReducer,
ojForUserReducer, ojForUserReducer,
commonReducer, commonReducer,
userReducer userReducer,
jupyterReducer
}); });

@ -0,0 +1,57 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-12 09:01:39
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 17:23:54
*/
import types from "../actions/actionTypes";
const initState = {
jupyter_tpi_url: '',
jupyter_info: {}, // 保存用户信息及实训相关的内容
jupyter_data_set: [],
jupyter_identifier: '',
jupyter_tpi_url_state: -1, // 获取 url 状态值: 0 成功, 其它 失败
jupyter_tpi_code: '' // 端口号
};
const JupyterReducer = (state = initState, action) => {
switch (action.type) {
case types.GET_JUPYTER_DATA_SETS:
return {
...state,
jupyter_data_set: action.payload
}
case types.GET_JUPYTER_TPI_URL:
const {url, status, port} = action.payload;
return {
...state,
jupyter_tpi_url: url,
jupyter_tpi_url_state: status,
jupyter_tpi_code: port
}
case types.SAVE_JUPYTER_IDENTIFIER:
return {
...state,
jupyter_identifier: action.payload
}
case types.SAVE_JUPYTER_INFO:
return {
...state,
jupyter_info: action.payload
}
case types.CHANGE_JUPYTER_URL_STATE:
return {
...state,
jupyter_tpi_url_state: action.payload
}
default:
return {
...state
}
}
}
export default JupyterReducer;

@ -215,7 +215,7 @@ class SearchPage extends Component{
type==="shixun"? type==="shixun"?
( (
item.is_jupyter===true? item.is_jupyter===true?
<div className="jupytertext intermediatecenter ml15"><p className="jupytertextp">Jupyter</p></div> <div className="jupytertext intermediatecenter ml20"><p className="jupytertextp">Jupyter</p></div>
:"" :""
) )
:"" :""

@ -135,17 +135,18 @@
.jupytertext{ .jupytertext{
width:54px; width:54px;
height:24px; height:24px;
background:#FF6802;
border-radius:2px 10px 10px 2px;
margin-top: 2px;
text-align: center; text-align: center;
border-radius:5px;
border:1px solid #FF6802;
margin-top: 4px;
} }
.jupytertextp{ .jupytertextp{
width:39px; width:54px;
height:16px; height:16px;
line-height:16px;
font-size:12px; font-size:12px;
color:#FFFFFF; color:#FF6802;
line-height:16px; line-height:16px;
} }
/* x轴正方向排序 */ /* x轴正方向排序 */

@ -0,0 +1,35 @@
/*
* @Description: jupyter相关接口
* @Author: tangjiang
* @Github:
* @Date: 2019-12-12 09:07:07
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 17:46:17
*/
import axios from 'axios';
// 获取 jupyter实训相关的内容
export async function fetchJupyterInfo (identifier) {
const url = `/tasks/${identifier}/jupyter.json`;
return axios.get(url);
}
// 获取数据集
export async function fetchJupyterTpiDataSet (identifier) {
const url = `/shixuns/${identifier}/jupyter_data_sets.json`;
return axios.get(url);
}
// 获取 tpi url
export async function fetchJupyterTpiUrl (params) {
const url = `/jupyters/get_info_with_tpi.json`;
return axios.get(url, { params });
}
// 同步代码功能
export async function fetchSyncJupyterCode (identifier) {
const url = `/myshixuns/${identifier}/sync_code.json`;
return axios.post(url);
}
// jupyter 保存
export async function fetchSaveJupyterTpi (params) {
const url = `/jupyters/save_with_tpi.json`;
return axios.get(url, { params });
}
Loading…
Cancel
Save