diff --git a/.gitignore b/.gitignore index ea08c700e..12dc596a6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Ignore bundler config. /.bundle +/bundle # Ignore lock config file *.lock @@ -70,3 +71,13 @@ vendor/bundle/ /workspace /log /public/admin +/mysql_data + + +.generators +.rakeTasks +db/bak/ +docker/ +educoder.sql +redis_data/ +Dockerfile \ No newline at end of file diff --git a/Gemfile b/Gemfile index 55030971d..55478816f 100644 --- a/Gemfile +++ b/Gemfile @@ -103,3 +103,6 @@ gem 'diffy' # oauth2 gem 'omniauth', '~> 1.9.0' gem 'omniauth-oauth2', '~> 1.6.0' + +# global var +gem 'request_store' diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3ec8ad0f7..bda4bcc6c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -283,7 +283,7 @@ class ApplicationController < ActionController::Base # 测试版前端需求 logger.info("subdomain:#{request.subdomain}") - if request.subdomain == "test-newweb" + if request.subdomain != "www" if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 User.current = User.find 81403 elsif params[:debug] == 'student' @@ -303,7 +303,7 @@ class ApplicationController < ActionController::Base current_domain_session = session[:"#{default_yun_session}"] if current_domain_session # existing session - (User.active.find(current_domain_session) rescue nil) + User.current = (User.active.find(current_domain_session) rescue nil) elsif autologin_user = try_to_autologin autologin_user elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index a4ceeac09..5fc81c5d5 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -28,52 +28,56 @@ class AttachmentsController < ApplicationController def create # 1. 本地存储 # 2. 上传到云 - upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 - uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") - raise "未上传文件" unless upload_file - - folder = edu_setting('attachment_folder') - raise "存储目录未定义" unless folder.present? - - month_folder = current_month_folder - save_path = File.join(folder, month_folder) - - ext = file_ext(upload_file.original_filename) - - local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext) - - content_type = upload_file.content_type.presence || 'application/octet-stream' - - # remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) - remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端 - - logger.info "local_path: #{local_path}" - logger.info "remote_path: #{remote_path}" - - - disk_filename = local_path[save_path.size + 1, local_path.size] - #存数据库 - # - @attachment = Attachment.where(disk_filename: disk_filename, - author_id: current_user.id, - cloud_url: remote_path).first + begin + upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 + uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") + raise "未上传文件" unless upload_file + + folder = edu_setting('attachment_folder') + raise "存储目录未定义" unless folder.present? + + month_folder = current_month_folder + save_path = File.join(folder, month_folder) + + ext = file_ext(upload_file.original_filename) + + local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext) + + content_type = upload_file.content_type.presence || 'application/octet-stream' + + # remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) + remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端 + + logger.info "local_path: #{local_path}" + logger.info "remote_path: #{remote_path}" + + + disk_filename = local_path[save_path.size + 1, local_path.size] + #存数据库 + # + @attachment = Attachment.where(disk_filename: disk_filename, + author_id: current_user.id, + cloud_url: remote_path).first + if @attachment.blank? + @attachment = Attachment.new + @attachment.filename = upload_file.original_filename + @attachment.disk_filename = local_path[save_path.size + 1, local_path.size] + @attachment.filesize = upload_file.tempfile.size + @attachment.content_type = content_type + @attachment.digest = digest + @attachment.author_id = current_user.id + @attachment.disk_directory = month_folder + @attachment.cloud_url = remote_path + @attachment.save! + else + logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" + end - if @attachment.blank? - @attachment = Attachment.new - @attachment.filename = upload_file.original_filename - @attachment.disk_filename = local_path[save_path.size + 1, local_path.size] - @attachment.filesize = upload_file.tempfile.size - @attachment.content_type = content_type - @attachment.digest = digest - @attachment.author_id = current_user.id - @attachment.disk_directory = month_folder - @attachment.cloud_url = remote_path - @attachment.save! - else - logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" + render_json + rescue => e + uid_logger_error(e.message) + tip_exception(e.message) end - - render_json end def destroy @@ -196,4 +200,5 @@ class AttachmentsController < ApplicationController end end end + end diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb index 4528b7b90..354d63f6d 100644 --- a/app/controllers/challenges_controller.rb +++ b/app/controllers/challenges_controller.rb @@ -13,6 +13,9 @@ class ChallengesController < ApplicationController include ShixunsHelper include ChallengesHelper + + + # 新建实践题 def new @position = @shixun.challenges.count + 1 @@ -160,6 +163,8 @@ class ChallengesController < ApplicationController @shixun.increment!(:visits) end + + def show @tab = params[:tab].nil? ? 1 : params[:tab].to_i challenge_num = @shixun.challenges_count diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index 3f7a451fd..d55eb9211 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -1,15 +1,18 @@ class GamesController < ApplicationController before_action :require_login, :check_auth - before_action :find_game + before_action :find_game, except: [:jupyter] 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' include GamesHelper include ApplicationHelper + + + def show uid_logger("--games show start") # 防止评测中途ajaxE被取消;3改成0是为了处理首次进入下一关的问题 @@ -88,6 +91,22 @@ class GamesController < ApplicationController end end + + def jupyter + # Jupyter没有challenge + @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 + # 判断tpm是否修改了 + begin + @tpm_modified = @myshixun.repository_is_modified(@shixun.repo_path) # 判断TPM和TPI的版本库是否被改了 + rescue + uid_logger("实训平台繁忙,繁忙等级(81)") + end + end + def reset_vnc_link begin # 删除vnc的pod diff --git a/app/controllers/hack_user_lastest_codes_controller.rb b/app/controllers/hack_user_lastest_codes_controller.rb index b7ec6fb8e..814d16d51 100644 --- a/app/controllers/hack_user_lastest_codes_controller.rb +++ b/app/controllers/hack_user_lastest_codes_controller.rb @@ -23,7 +23,7 @@ class HackUserLastestCodesController < ApplicationController # 同步代码 def sync_code - @my_hack.update_attributes(code: @hack.code, modify_time: @hack.modify_time) + @my_hack.update_attributes(code: @hack.code, modify_time: Time.now) end # 调试代码 diff --git a/app/controllers/jupyters_controller.rb b/app/controllers/jupyters_controller.rb new file mode 100644 index 000000000..96ebf3452 --- /dev/null +++ b/app/controllers/jupyters_controller.rb @@ -0,0 +1,46 @@ + +class JupytersController < ApplicationController + include JupyterService + + before_action :shixun, only: [:open, :open1, :test, :save] + + def save_with_tpi + myshixun = Myshixun.find_by(identifier: params[:identifier]) + jupyter_save_with_game(myshixun, params[:jupyter_port]) + render json: {status: 0} + end + + def save_with_tpm + shixun = Shixun.find_by(identifier: params[:identifier]) + jupyter_save_with_shixun(shixun, params[:jupyter_port]) + render json: {status: 0} + end + + def get_info_with_tpi + myshixun = Myshixun.find_by(identifier: params[:identifier]) + url = jupyter_url_with_game(myshixun) + port = jupyter_port_with_game(myshixun) + render json: {status: 0, url: url, port: port} + end + + def get_info_with_tpm + shixun = Shixun.find_by(identifier: params[:identifier]) + url = jupyter_url_with_shixun(shixun) + port = jupyter_port_with_shixun(shixun) + render json: {status: 0, url: url, port: port} + end + + def reset_with_tpi + myshixun = Myshixun.find_by(identifier: params[:identifier]) + info = jupyter_tpi_reset(myshixun) + render json: {status: 0, url: info[:url], port: info[:port]} + end + + def reset_with_tpm + shixun = Shixun.find_by(identifier: params[:identifier]) + info = jupyter_tpm_reset(shixun) + render json: {status: 0, url: info[:url], port: info[:port]} + end + + +end \ No newline at end of file diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 1325d1423..987f4873a 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -366,6 +366,31 @@ class MyshixunsController < ApplicationController end end + def sync_code + shixun_tomcat = edu_setting('cloud_bridge') + begin + git_myshixun_url = repo_ip_url @myshixun.repo_path + git_shixun_url = repo_ip_url @myshixun.shixun.try(:repo_path) + git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url) + git_shixun_url = Base64.urlsafe_encode64(git_shixun_url) + # todo: identifier 是以前的密码,用来验证的,新版如果不需要,和中间层协调更改. + params = {tpiID: "#{@myshixun.try(:id)}", tpiGitURL: "#{git_myshixun_url}", tpmGitURL: "#{git_shixun_url}", + identifier: "xinhu1ji2qu3"} + uri = "#{shixun_tomcat}/bridge/game/resetTpmRepository" + res = uri_post uri, params + if (res && res['code'] != 0) + tip_exception("实训云平台繁忙(繁忙等级:95)") + end + shixun_new_commit = GitService.commits(repo_path: @myshixun.shixun.repo_path).first["id"] + @myshixun.update_attributes!(commit_id: shixun_new_commit, reset_time: @myshixun.shixun.try(:reset_time)) + # 更新完成后,弹框则隐藏不再提示 + @myshixun.update_column(:system_tip, false) + render_ok + rescue Exception => e + tip_exception("立即更新代码失败!#{e.message}") + end + end + # -----End diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 63bf059e0..1c8928d98 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -6,16 +6,17 @@ class ShixunsController < ApplicationController before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list, :discusses, :collaborators, :fork_list, :propaedeutics] - before_action :check_account, only: [:new, :create, :shixun_exec] + before_action :check_account, only: [:new, :create, :shixun_exec, :jupyter_exec] before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns, :propaedeutics, :departments, :apply_shixun_mirror, :get_mirror_script, :download_file, :shixun_list, :batch_send_to_course] before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns, - :propaedeutics, :departments, :apply_shixun_mirror, + :propaedeutics, :departments, :apply_shixun_mirror, :jupyter_exec, :get_mirror_script, :download_file, :shixun_list, :batch_send_to_course] - before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy, :add_file] + before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy, + :add_file, :jupyter_exec] before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public, :shixun_members_added, :change_manager, :collaborators_delete, @@ -206,7 +207,7 @@ class ShixunsController < ApplicationController @new_shixun = Shixun.new @new_shixun.attributes = @shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier", "averge_star", "homepage_show","repo_name", "myshixuns_count", "challenges_count", - "can_copy", "created_at", "updated_at") + "can_copy", "created_at", "updated_at", "public") @new_shixun.user_id = User.current.id @new_shixun.averge_star = 5 @new_shixun.identifier = generate_identifier Shixun, 8 @@ -364,73 +365,161 @@ class ShixunsController < ApplicationController end def create - # 评测脚本的一些操作 - main_type, sub_type = params[:main_type], params[:small_type] - mirror = MirrorScript.where(:mirror_repository_id => main_type) - - identifier = generate_identifier Shixun, 8 - @shixun = Shixun.new(shixun_params) - @shixun.identifier = identifier - @shixun.user_id = current_user.id - @shixun.reset_time, @shixun.modify_time = Time.now, Time.now - - if sub_type.blank? - shixun_script = mirror.first.try(:script) - else - main_mirror = MirrorRepository.find(main_type).type_name - sub_mirror = MirrorRepository.where(id: sub_type).pluck(:type_name) - if main_mirror == "Java" && sub_mirror.include?("Mysql") - shixun_script = mirror.last.try(:script) - else - shixun_script = mirror.first.try(:script) - shixun_script = modify_shixun_script @shixun, shixun_script - end - end + @shixun = CreateShixunService.call(current_user, shixun_params, params) + end - ActiveRecord::Base.transaction do - begin - @shixun.save! - # shixun_info关联ß - ShixunInfo.create!(shixun_id: @shixun.id, evaluate_script: shixun_script, description: params[:description]) - # 实训的公开范围 - if params[:scope_partment].present? - arr = [] - ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq - ids.each do |id| - arr << { :school_id => id, :shixun_id => @shixun.id } - end - ShixunSchool.create!(arr) - end + # 保存jupyter到版本库 + def update_jupyter + jupyter_save_with_shixun(@shixun, params[:jupyter_port]) + end - # 实训合作者 - @shixun.shixun_members.create!(user_id: current_user.id, role: 1) - - # 镜像-实训关联表 - ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => main_type.to_i) if main_type.present? - # 实训主镜像服务配置 - ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => main_type.to_i) - if sub_type.present? - sub_type.each do |mirror| - ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) - # 实训子镜像服务配置 - name = MirrorRepository.find_by(id: mirror).try(:name) #查看镜像是否有名称,如果没有名称就不用服务配置 - ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) if name.present? + def update + # 镜像方面 + mirror_ids = MirrorRepository.where(id: params[:main_type]) + .or( MirrorRepository.where(id: params[:sub_type])).pluck(:id).uniq + old_mirror_ids = @shixun.shixun_mirror_repositories + .where(mirror_repository_id: params[:main_type]) + .or(@shixun.shixun_mirror_repositories.where(mirror_repository_id: params[:sub_type])) + .pluck(:mirror_repository_id).uniq + new_mirror_id = (mirror_ids - old_mirror_ids).map{|id| {mirror_repository_id: id}} # 转换成数组hash方便操作 + logger.info("##########new_mirror_id: #{new_mirror_id}") + logger.info("##########old_mirror_ids: #{old_mirror_ids}") + logger.info("##########mirror_ids: #{mirror_ids}") + # 服务配置方面 + service_create_params = service_config_params[:shixun_service_configs] + .select{|config| !old_mirror_ids.include?(config[:mirror_repository_id]) && + MirrorRepository.find(config[:mirror_repository_id]).name.present?} + service_update_params = service_config_params[:shixun_service_configs] + .select{|config| old_mirror_ids.include?(config[:mirror_repository_id])} + logger.info("#########service_create_params: #{service_create_params}") + logger.info("#########service_update_params: #{service_update_params}") + begin + ActiveRecord::Base.transaction do + @shixun.update_attributes(shixun_params) + @shixun.shixun_info.update_attributes(shixun_info_params) + # 镜像变动 + @shixun.shixun_mirror_repositories.where.not(mirror_repository_id: old_mirror_ids).destroy_all + @shixun.shixun_mirror_repositories.create!(new_mirror_id) + # 镜像变动要更换服务配置 + @shixun.shixun_service_configs.where.not(mirror_repository_id: old_mirror_ids).destroy_all + @shixun.shixun_service_configs.create!(service_create_params) + service_update_params&.map do |service| + smr = @shixun.shixun_service_configs.find_by(mirror_repository_id: service[:mirror_repository_id]) + smr.update_attributes(service) + end + # 添加第二仓库(管理员权限) + if params[:is_secret_repository] + add_secret_repository if @shixun.shixun_secret_repository.blank? + else + # 如果有仓库,就要删 + if @shixun.shixun_secret_repository&.repo_name + @shixun.shixun_secret_repository.lock! + GitService.delete_repository(repo_path: @shixun.shixun_secret_repository.repo_path) + @shixun.shixun_secret_repository.destroy end end + end + rescue => e + uid_logger_error(e.message) + tip_exception("基本信息更新失败:#{e.message}") + end + end - # 创建版本库 - repo_path = repo_namespace(User.current.login, @shixun.identifier) - GitService.add_repository(repo_path: repo_path) - # todo: 为什么保存的时候要去除后面的.git呢?? - @shixun.update_column(:repo_name, repo_path.split(".")[0]) + # 实训权限设置 + def update_permission_setting + # 查找需要增删的高校id + school_id = School.where(:name => params[:scope_partment]).pluck(:id) + old_school_ids = @shixun.shixun_schools.pluck(:school_id) + school_params = (school_id - old_school_ids).map{|id| {school_id: id}} + begin + ActiveRecord::Base.transaction do + @shixun.update_attributes!(shixun_params) + @shixun.shixun_schools.where.not(school_id: school_id).destroy_all if school_id.present? + @shixun.shixun_schools.create!(school_params) + end + rescue => e + uid_logger_error("实训权限设置失败--------#{e.message}") + tip_exception("实训权限设置失败") + end + end - # 将实训标志为该云上实验室建立 - Laboratory.current.laboratory_shixuns.create!(shixun: @shixun, ownership: true) - rescue Exception => e - uid_logger_error(e.message) - tip_exception("实训创建失败") - raise ActiveRecord::Rollback + # 实训学习页面设置 + def update_learn_setting + begin + ActiveRecord::Base.transaction do + @shixun.update_attributes!(shixun_params) end + rescue => e + uid_logger_error("实训学习页面设置失败--------#{e.message}") + tip_exception("实训学习页面设置失败") + end + end + + # Jupyter数据集 + def get_data_sets + page = params[:page] || 1 + limit = params[:limit] || 10 + data_sets = @shixun.data_sets + @data_count = data_sets.count + @data_sets= data_sets.order("created_on desc").page(page).per(limit) + @absolute_folder = edu_setting('shixun_folder') + end + + # 实训测试集附件 + def upload_data_sets + begin + + upload_file = params["file"] + raise "未上传文件" unless upload_file + folder = edu_setting('shixun_folder') + raise "存储目录未定义" unless folder.present? + rep_name = @shixun.data_sets.pluck(:filename).include?(upload_file.original_filename) + raise "文件名已经存在\"#{upload_file.original_filename}\", 请删除后再上传" if rep_name + tpm_folder = params[:identifier] # 这个是实训的identifier + save_path = File.join(folder, tpm_folder) + ext = file_ext(upload_file.original_filename) + local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext) + content_type = upload_file.content_type.presence || 'application/octet-stream' + disk_filename = local_path[save_path.size + 1, local_path.size] + @attachment = Attachment.where(disk_filename: disk_filename, + author_id: current_user.id).first + if @attachment.blank? + @attachment = Attachment.new + @attachment.filename = upload_file.original_filename + @attachment.disk_filename = local_path[save_path.size + 1, local_path.size] + @attachment.filesize = upload_file.tempfile.size + @attachment.content_type = content_type + @attachment.digest = digest + @attachment.author_id = current_user.id + @attachment.disk_directory = tpm_folder + @attachment.container_id = @shixun.id + @attachment.container_type = @shixun.class.name + @attachment.attachtype = 2 + @attachment.save! + else + logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" + end + render_ok + rescue => e + uid_logger_error(e.message) + tip_exception(e.message) + end + end + + # 多文件删除 + def destroy_data_sets + files = Attachment.where(id: params[:id]) + shixun_folder= edu_setting("shixun_folder") + begin + files.each do |file| + file_path = "#{shixun_folder}/#{file.relative_path_filename}" + delete_file(file_path) + end + files.destroy_all + render_ok + rescue => e + uid_logger_error(e.message) + tip_exception(e.message) end end @@ -462,61 +551,6 @@ class ShixunsController < ApplicationController tip_exception("申请失败") end - def update - ActiveRecord::Base.transaction do - begin - @shixun.shixun_mirror_repositories.destroy_all - if params[:main_type].present? - ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => params[:main_type].to_i) - end - if params[:small_type].present? - params[:small_type].each do |mirror| - ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror) - end - end - @shixun.update_attributes(shixun_params) - @shixun.shixun_info.update_attributes(shixun_info_params) - @shixun.shixun_schools.delete_all - # scope_partment: 高校的名称 - if params[:scope_partment].present? - arr = [] - ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq - ids.each do |id| - arr << { :school_id => id, :shixun_id => @shixun.id } - end - ShixunSchool.create!(arr) - end - # 超级管理员和运营人员才能保存 中间层服务器pod信息的配置 - # 如果镜像改动了,则也需要更改 - mirror = @shixun.shixun_service_configs.map(&:mirror_repository_id).sort - new_mirror = params[:shixun_service_configs].map{|c| c[:mirror_repository_id]}.sort - if current_user.admin? || current_user.business? || (mirror != new_mirror) - @shixun.shixun_service_configs.destroy_all - service_config_params[:shixun_service_configs].each do |config| - name = MirrorRepository.find_by_id(config[:mirror_repository_id])&.name - # 不保存没有镜像的配置 - @shixun.shixun_service_configs.create!(config) if name.present? - end - end - # 添加第二仓库 - if params[:is_secret_repository] - add_secret_repository if @shixun.shixun_secret_repository.blank? - else - # 如果有仓库,就要删 - if @shixun.shixun_secret_repository&.repo_name - @shixun.shixun_secret_repository.lock! - GitService.delete_repository(repo_path: @shixun.shixun_secret_repository.repo_path) - @shixun.shixun_secret_repository.destroy - end - end - - rescue Exception => e - uid_logger_error("实训保存失败--------#{e.message}") - tip_exception("实训保存失败") - raise ActiveRecord::Rollback - end - end - end # 永久关闭实训 def close @@ -552,6 +586,8 @@ class ShixunsController < ApplicationController # @evaluate_scirpt = @shixun.evaluate_script || "无" end + + # 获取脚本内容 def get_script_contents mirrir_script = MirrorScript.find(params[:script_id]) @@ -708,112 +744,40 @@ class ShixunsController < ApplicationController end end - # def shixun_exec - # if is_shixun_opening? - # tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") - # end - # current_myshixun = @shixun.current_myshixun(current_user.id) - # - # min_challenges = @shixun.challenges.pluck(:id , :st) - # # 因为读写分离有延迟,所以如果是重置来的请求可以先跳过,重置过来的params[:reset]为1 - # if current_myshixun && params[:reset] != "1" - # games = current_myshixun.games - # # 如果TPM和TPI的管卡数不相等或者关卡顺序错了,说明实训被极大的改动,需要重置,实训发布前打过的实训都需要重置 - # if is_shixun_reset?(games, min_challenges, current_myshixun) - # # 这里页面弹框要收到 当前用户myshixun的identifier. - # tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game") - # end - # - # - # if current_myshixun.repo_name.nil? - # g = Gitlab.client - # repo_name = g.project(current_myshixun.gpid).try(:path_with_namespace) - # current_myshixun.update_column(:repo_name, repo_name) - # end - # - # # 如果存在实训,则直接进入实训 - # # 如果实训允许跳关,传参params[:challenge_id]跳入具体的关卡 - # @current_task = - # if params[:challenge_id] - # game = games.where(challenge_id: params[:challenge_id]).take - # if @shixun.task_pass || game.status != 3 - # game - # else - # current_myshixun.current_task(games) - # end - # else - # current_myshixun.current_task(games) - # end - # else - # # 如果未创建关卡一定不能开启实训,否则TPI没法找到当前的关卡 - # if @shixun.challenges_count == 0 - # tip_exception("开启实战前请先创建实训关卡") - # end - # - # # 判断实训是否全为选择题 - # is_choice_type = (min_challenges.size == min_challenges.select{|challenge| challenge.last == 1}.count) - # if !is_choice_type - # commit = GitService.commits(repo_path: @repo_path).try(:first) - # uid_logger("First comit########{commit}") - # tip_exception("开启实战前请先在版本库中提交代码") if commit.blank? - # commit_id = commit["id"] - # end - # - # begin - # ActiveRecord::Base.transaction do - # begin - # myshixun_identifier = generate_identifier Myshixun, 10 - # myshixun_params = {user_id: current_user.id, identifier: myshixun_identifier, - # modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, - # onclick_time: Time.now, commit_id: commit_id} - # @myshixun = @shixun.myshixuns.create!(myshixun_params) - # # 其它创建关卡等操作 - # challenges = @shixun.challenges - # # 之所以增加user_id是为了方便统计查询性能 - # game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at] - # Game.bulk_insert(*game_attrs) do |worker| - # base_attr = {myshixun_id: @myshixun.id, user_id: @myshixun.user_id} - # challenges.each_with_index do |challenge, index| - # status = (index == 0 ? 0 : 3) - # game_identifier = generate_identifier(Game, 12) - # worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now, - # identifier: game_identifier, modify_time: challenge.modify_time)) - # end - # end - # @current_task = @myshixun.current_task(@myshixun.games) - # rescue Exception => e - # logger.error("------ActiveRecord::RecordInvalid: #{e.message}") - # raise("ActiveRecord::RecordInvalid") - # end - # end - # # 如果实训是纯选择题,则不需要去fork仓库以及中间层的相关操作了 - # ActiveRecord::Base.transaction do - # unless is_choice_type - # # fork仓库 - # cloud_bridge = edu_setting('cloud_bridge') - # project_fork(@myshixun, @repo_path, current_user.login) - # rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path) - # uid_logger("start openGameInstance") - # uri = "#{cloud_bridge}/bridge/game/openGameInstance" - # logger.info("end openGameInstance") - # params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last} - # uid_logger("openGameInstance params is #{params}") - # interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" - # end - # end - # rescue Exception => e - # logger.info("shixun_exec error: #{e.message}") - # if e.message != "ActiveRecord::RecordInvalid" - # logger.error("##########project_fork error #{e.message}") - # @myshixun.destroy! - # end - # raise "实训云平台繁忙(繁忙等级:81)" - # end - # end - # end - - # gameID 及实训ID - # status: 0 , 1 申请过, 2,实训关卡路径未填, 3 实训标签未填, 4 实训未创建关卡 + # jupyter开启挑战 + def jupyter_exec + begin + if is_shixun_opening? + tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") + end + current_myshixun = @shixun.current_myshixun(current_user.id) + if current_myshixun + @myshixun = current_myshixun + else + commit = GitService.commits(repo_path: @repo_path).try(:first) + uid_logger("First comit########{commit}") + tip_exception("开启挑战前,请先在Jupyter中填写内容") if commit.blank? + commit_id = commit["id"] + cloud_bridge = edu_setting('cloud_bridge') + myshixun_identifier = generate_identifier Myshixun, 10 + ActiveRecord::Base.transaction do + @myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier, + modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, + onclick_time: Time.now, commit_id: commit_id) + # fork仓库 + project_fork(@myshixun, @repo_path, current_user.login) + rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path) + uri = "#{cloud_bridge}/bridge/game/openGameInstance" + params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last} + interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" + end + end + rescue => e + uid_logger_error(e.message) + tip_exception("#{e.message}") + end + end + def publish @status = 0 @position = [] @@ -849,7 +813,7 @@ class ShixunsController < ApplicationController def apply_public tip_exception(-1, "请先发布实训再申请公开") if @shixun.status != 2 ActiveRecord::Base.transaction do - @shixun.update_attributes!(pubic: 1) + @shixun.update_attributes!(public: 1) apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first if apply && apply.status == 0 @status = 0 @@ -1035,10 +999,9 @@ class ShixunsController < ApplicationController private def shixun_params - raise("实训名称不能为空") if params[:shixun][:name].blank? params.require(:shixun).permit(:name, :trainee, :webssh, :can_copy, :use_scope, :vnc, :test_set_permission, :task_pass, :multi_webssh, :opening_time, :mirror_script_id, :code_hidden, - :hide_code, :forbid_copy, :vnc_evaluate, :code_edit_permission) + :hide_code, :forbid_copy, :vnc_evaluate, :code_edit_permission, :is_jupyter) end def validate_review_shixun_params @@ -1047,8 +1010,6 @@ private end def shixun_info_params - raise("实训描述不能为空") if params[:shixun_info][:description].blank? - raise("评测脚本不能为空") if params[:shixun_info][:evaluate_script].blank? params.require(:shixun_info).permit(:description, :evaluate_script) end @@ -1116,4 +1077,47 @@ private ShixunSecretRepository.create!(repo_name: repo_path.split(".")[0], shixun_id: @shixun.id) end + def file_save_to_local(save_path, temp_file, ext) + unless Dir.exists?(save_path) + FileUtils.mkdir_p(save_path) ##不成功这里会抛异常 + end + + digest = md5_file(temp_file) + digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}" + local_file_path = File.join(save_path, digest) + ext + save_temp_file(temp_file, local_file_path) + + [local_file_path, digest] + end + + def save_temp_file(temp_file, save_file_path) + File.open(save_file_path, 'wb') do |f| + temp_file.rewind + while (buffer = temp_file.read(8192)) + f.write(buffer) + end + end + end + + def file_ext(file_name) + ext = '' + exts = file_name.split(".") + if exts.size > 1 + ext = ".#{exts.last}" + end + ext + end + + def delete_file(file_path) + File.delete(file_path) if File.exist?(file_path) + end + + def md5_file(temp_file) + md5 = Digest::MD5.new + temp_file.rewind + while (buffer = temp_file.read(8192)) + md5.update(buffer) + end + md5.hexdigest + end end diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index dfdce7bd2..946b65d24 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -529,7 +529,7 @@ class StudentWorksController < ApplicationController @echart_data = student_efficiency(@homework, @work) @myself_eff = @echart_data[:efficiency_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')}.pdf" + filename_ = "#{@user&.student_id}_#{@user&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf" filename = filename_.strip.tr("+/", "-_") stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css) if params[:export].present? && params[:export] diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index 0cd57ecc8..6a9438a79 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -204,7 +204,7 @@ class SubjectsController < ApplicationController def add_shixun_to_stage identifier = generate_identifier Shixun, 8 ActiveRecord::Base.transaction do - @shixun = Shixun.create!(name: params[:name], user_id: current_user.id, identifier: identifier) + @shixun = Shixun.create!(name: params[:name], user_id: current_user.id, identifier: identifier, is_jupyter: params[:is_jupyter]) # 添加合作者 @shixun.shixun_members.create!(user_id: current_user.id, role: 1) # 创建长字段 diff --git a/app/helpers/challenges_helper.rb b/app/helpers/challenges_helper.rb index c6d05817d..fc0101dff 100644 --- a/app/helpers/challenges_helper.rb +++ b/app/helpers/challenges_helper.rb @@ -4,4 +4,7 @@ module ChallengesHelper str.gsub(/\A\r/, "\r\r") end + + + end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index f18d9cd2a..ac051428f 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -33,6 +33,10 @@ class Attachment < ApplicationRecord File.join(File.join(Rails.root, "files"), disk_directory.to_s, disk_filename.to_s) end + def relative_path_filename + File.join(disk_directory.to_s, disk_filename.to_s) + end + def title title = filename if container && container.is_a?(StudentWork) && author_id != User.current.id diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 2ba86ed90..dab2f6f39 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -38,12 +38,20 @@ class Laboratory < ApplicationRecord find_by_identifier(subdomain) end - def self.current=(laboratory) - Thread.current[:current_laboratory] = laboratory + # def self.current=(laboratory) + # Thread.current[:current_laboratory] = laboratory + # end + # + # def self.current + # Thread.current[:current_laboratory] ||= Laboratory.find(1) + # end + + def self.current=(user) + RequestStore.store[:current_laboratory] = user end def self.current - Thread.current[:current_laboratory] ||= Laboratory.find(1) + RequestStore.store[:current_laboratory] ||= User.anonymous end def shixuns diff --git a/app/models/laboratory_setting.rb b/app/models/laboratory_setting.rb index 4eacaf460..e53b54cd3 100644 --- a/app/models/laboratory_setting.rb +++ b/app/models/laboratory_setting.rb @@ -67,6 +67,7 @@ class LaboratorySetting < ApplicationRecord { 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false }, { 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false }, { 'name' => '交流问答', 'link' => '/forums', 'hidden' => false }, + { 'name' => '开发者社区', 'link' => '/problems', 'hidden' => false }, ], footer: nil } diff --git a/app/models/myshixun.rb b/app/models/myshixun.rb index d510d880a..1a89c755e 100644 --- a/app/models/myshixun.rb +++ b/app/models/myshixun.rb @@ -28,6 +28,11 @@ class Myshixun < ApplicationRecord "#{self.repo_name}.git" end + + def repo_save_path + self.repo_name.split('/').last + end + def is_complete? self.status == 1 end diff --git a/app/models/searchable/shixun.rb b/app/models/searchable/shixun.rb index c574ecb1d..359b8b4dc 100644 --- a/app/models/searchable/shixun.rb +++ b/app/models/searchable/shixun.rb @@ -52,7 +52,8 @@ module Searchable::Shixun challenges_count: challenges_count, study_count: myshixuns_count, star: averge_star, - level: shixun_level + level: shixun_level, + is_jupyter: is_jupyter } end diff --git a/app/models/shixun.rb b/app/models/shixun.rb index dc5348450..404faff29 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -10,6 +10,7 @@ class Shixun < ApplicationRecord # webssh 0:不开启webssh;1:开启练习模式; 2:开启评测模式 # trainee 实训的难度 # vnc: VCN实训是否用于评测 + validates_presence_of :name, message: "实训名称不能为空" has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy has_many :challenge_tags, through: :challenges has_many :myshixuns, :dependent => :destroy @@ -55,6 +56,8 @@ class Shixun < ApplicationRecord has_many :laboratory_shixuns, dependent: :destroy belongs_to :laboratory, optional: true + # Jupyter数据集,附件 + has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy scope :search_by_name, ->(keyword) { where("name like ? or description like ? ", "%#{keyword}%", "%#{keyword}%") } diff --git a/app/models/shixun_info.rb b/app/models/shixun_info.rb index 74a49412e..321b4c44a 100644 --- a/app/models/shixun_info.rb +++ b/app/models/shixun_info.rb @@ -1,8 +1,6 @@ class ShixunInfo < ApplicationRecord belongs_to :shixun validates_uniqueness_of :shixun_id - validates_presence_of :shixun_id - after_commit :create_diff_record private diff --git a/app/models/shixun_mirror_repository.rb b/app/models/shixun_mirror_repository.rb index 9376aac0b..841be6bb2 100644 --- a/app/models/shixun_mirror_repository.rb +++ b/app/models/shixun_mirror_repository.rb @@ -2,4 +2,5 @@ class ShixunMirrorRepository < ApplicationRecord belongs_to :shixun belongs_to :mirror_repository validates_uniqueness_of :shixun_id, :scope => :mirror_repository_id + validates_presence_of :shixun_id, :mirror_repository_id end diff --git a/app/models/shixun_service_config.rb b/app/models/shixun_service_config.rb index 6d106fc07..4dda75a25 100644 --- a/app/models/shixun_service_config.rb +++ b/app/models/shixun_service_config.rb @@ -1,4 +1,6 @@ class ShixunServiceConfig < ApplicationRecord belongs_to :shixun belongs_to :mirror_repository + + validates_presence_of :shixun_id, :mirror_repository_id end diff --git a/app/models/user.rb b/app/models/user.rb index eb3ece0a4..a9b2f0b3a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -540,12 +540,20 @@ class User < ApplicationRecord mail.present? end + # def self.current=(user) + # Thread.current[:current_user] = user + # end + # + # def self.current + # Thread.current[:current_user] ||= User.anonymous + # end + def self.current=(user) - Thread.current[:current_user] = user + RequestStore.store[:current_user] = user end def self.current - Thread.current[:current_user] ||= User.anonymous + RequestStore.store[:current_user] ||= User.anonymous end def self.anonymous diff --git a/app/services/git_service.rb b/app/services/git_service.rb index 076f62920..544e830a4 100644 --- a/app/services/git_service.rb +++ b/app/services/git_service.rb @@ -45,4 +45,4 @@ class GitService end end -end \ No newline at end of file +end diff --git a/app/services/jupyter_service.rb b/app/services/jupyter_service.rb new file mode 100644 index 000000000..143b2eda7 --- /dev/null +++ b/app/services/jupyter_service.rb @@ -0,0 +1,219 @@ +#coding=utf-8 + +module JupyterService + + def _open_shixun_jupyter(shixun) + if shixun.is_jupyter? + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/get" + tpiID = "tpm#{shixun.id}" + mount = shixun.data_sets.present? + params = {tpiID: tpiID, identifier: shixun.identifier, needMount: mount, + :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"} + + logger.info "test_juypter: uri->#{uri}, params->#{params}" + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:99)") + end + + logger.info "test_juypter: #{res}" + + @shixun_jupyter_port = res['port'] + jupyter_service = edu_setting('jupyter_service') + + url = + if false + "https://#{jupyter_service}:#{res['port']}/notebooks/data/workspace/myshixun_#{tpiID}/01.ipynb" + else + "https://#{res['port']}.#{jupyter_service}/notebooks/data/workspace/myshixun_#{tpiID}/01.ipynb" + end + return url + end + end + + def jupyter_url_with_shixun(shixun) + #打开tpm - juypter接口 + _open_shixun_jupyter(shixun) + end + + def jupyter_port_with_shixun(shixun) + if @shixun_jupyter_port.to_i <=0 + _open_shixun_jupyter(shixun) + end + @shixun_jupyter_port + end + + + def _open_game_jupyter(myshixun) + ## 打开tpi + shixun = myshixun.shixun + + if shixun.is_jupyter? + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/get" + + tpiID = myshixun.id + mount = myshixun.shixun.data_sets.present? + params = {tpiID: tpiID, identifier: shixun.identifier, needMount: mount, + :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 + + @game_jupyter_port = res['port'] + + repo_save_path = myshixun.repo_save_path + + jupyter_service = edu_setting('jupyter_service') + + if false + "https://#{jupyter_service}:#{res['port']}/notebooks/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb" + else + "https://#{res['port']}.#{jupyter_service}/notebooks/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb" + end + + end + end + + + def jupyter_url_with_game(myshixun) + _open_game_jupyter(myshixun) + end + + def jupyter_port_with_game(myshixun) + if @game_jupyter_port.to_i <=0 + _open_game_jupyter(myshixun) + end + @game_jupyter_port + end + + def jupyter_save_with_shixun(shixun,jupyter_port) + author_name = current_user.real_name + author_email = current_user.git_mail + message = "User submitted" + + tpiID = "tpm#{shixun.id}" + + jupyter_service = edu_setting('jupyter_service') + src_url = + if false + "https://#{jupyter_service}:#{jupyter_port}/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/01.ipynb?download=true" + else + "https://#{jupyter_port}.#{jupyter_service}/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/01.ipynb?download=true" + end + #https://47526.jupyter.educoder.net/nbconvert/notebook/data/workspace/myshixun_570461/f2ef5p798r20191210163135/01.ipynb?download=true + response = Faraday.get(src_url) + + if response.status.to_i != 200 + raise("获取文件内容失败:#{response.status}") + end + + content = response.body.force_encoding('utf-8') + + 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) + + return c.size + end + + def jupyter_save_with_game(myshixun,jupyter_port) + author_name = current_user.real_name + author_email = current_user.git_mail + message = "User submitted" + + tpiID = myshixun.id + + repo_save_path = myshixun.repo_save_path + jupyter_service = edu_setting('jupyter_service') + + src_url = + if false + "https://#{jupyter_service}:#{jupyter_port}/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb?download=true" + else + "https://#{jupyter_port}.#{jupyter_service}/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb?download=true" + end + + response = Faraday.get(src_url) + + if response.status.to_i != 200 + raise("获取文件内容失败:#{response.status}") + end + + content = response.body.force_encoding('utf-8') + + c = GitService.update_file(repo_path: myshixun.repo_path, + file_path: "01.ipynb", + message: message, + content: content, + author_name: author_name, + author_email: author_email) + + return c.size + end + + + ##重置jupyter环境 + def jupyter_tpi_reset(myshixun) + jupyter_delete_tpi(myshixun) + url = jupyter_url_with_game(myshixun) + port = jupyter_port_with_game(myshixun) + {url: url, port: port} + end + + ## 重置tpm环境 + def jupyter_tpm_reset(shixun) + jupyter_delete_tpm(shixun) + + url = jupyter_url_with_shixun(shixun) + port = jupyter_port_with_shixun(shixun) + + {url: url, port: port} + end + + + + # 删除pod + def jupyter_delete_tpi(myshixun) + myshixun_id = myshixun.id + digest = myshixun.identifier + edu_setting('bridge_secret_key') + digest_key = Digest::SHA1.hexdigest("#{digest}") + begin + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/delete" + Rails.logger.info("#{current_user} => cloese_jupyter digest is #{digest}") + params = {:tpiID => myshixun_id, :digestKey => digest_key, :identifier => myshixun.identifier} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:110)") + end + end + end + + + def jupyter_delete_tpm(shixun) + tpiID = "tpm#{shixun.id}" + digest = shixun.identifier + edu_setting('bridge_secret_key') + digest_key = Digest::SHA1.hexdigest("#{digest}") + begin + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/delete" + Rails.logger.info("#{current_user} => cloese_jupyter digest is #{digest}") + params = {:tpiID => tpiID, :digestKey => digest_key, :identifier => shixun.identifier} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:110)") + end + end + end + + +end diff --git a/app/services/shixun_search_service.rb b/app/services/shixun_search_service.rb index 649de87bf..f5af69179 100644 --- a/app/services/shixun_search_service.rb +++ b/app/services/shixun_search_service.rb @@ -25,7 +25,7 @@ class ShixunSearchService < ApplicationService else none_shixun_ids = ShixunSchool.where("school_id != #{User.current.school_id}").pluck(:shixun_id) - @shixuns = @shixuns.where.not(id: none_shixun_ids).where(hidden: 0, status: 2, public: 2).or(@shixuns.where(id: current_user.shixuns)) + @shixuns = @shixuns.where.not(id: none_shixun_ids).where(hidden: 0, status: 2, public: 2).or(@shixuns.where(id: User.current.shixuns)) end end @@ -38,6 +38,7 @@ class ShixunSearchService < ApplicationService @shixuns = @shixuns.where(trainee: params[:diff]) end + Rails.logger.info("search_shixun_ids: #{@shixuns.pluck(:id)}") Shixun.search(keyword, search_options) end diff --git a/app/services/shixuns/create_shixun_service.rb b/app/services/shixuns/create_shixun_service.rb new file mode 100644 index 000000000..08b515163 --- /dev/null +++ b/app/services/shixuns/create_shixun_service.rb @@ -0,0 +1,115 @@ +class CreateShixunService < ApplicationService + attr_reader :user, :params, :permit_params + + def initialize(user, permit_params, params) + @user = user + @params = params + @permit_params = permit_params + end + + def call + shixun = Shixun.new(permit_params) + identifier = Util::UUID.generate_identifier(Shixun, 8) + shixun.identifier= identifier + shixun.user_id = user.id + main_mirror = MirrorRepository.find params[:main_type] + sub_mirrors = MirrorRepository.where(id: params[:sub_type]) + begin + ActiveRecord::Base.transaction do + shixun.save! + # 获取脚本内容 + shixun_script = get_shixun_script(shixun, main_mirror, sub_mirrors) + # 创建额外信息 + ShixunInfo.create!(shixun_id: shixun.id, evaluate_script: shixun_script, description: params[:description]) + # 创建合作者 + shixun.shixun_members.create!(user_id: user.id, role: 1) + # 创建镜像 + ShixunMirrorRepository.create!(:shixun_id => shixun.id, :mirror_repository_id => main_mirror.id) + # 创建主服务配置 + ShixunServiceConfig.create!(:shixun_id => shixun.id, :mirror_repository_id => main_mirror.id) + # 创建子镜像相关数据(实训镜像关联表,子镜像服务配置) + sub_mirrors.each do |sub| + ShixunMirrorRepository.create!(:shixun_id => shixun.id, :mirror_repository_id => sub.id) + # 实训子镜像服务配置 + name = sub.name #查看镜像是否有名称,如果没有名称就不用服务配置 + ShixunServiceConfig.create!(:shixun_id => shixun.id, :mirror_repository_id => sub.id) if name.present? + end + # 创建版本库 + repo_path = repo_namespace(user.login, shixun.identifier) + GitService.add_repository(repo_path: repo_path) + shixun.update_column(:repo_name, repo_path.split(".")[0]) + # 如果是云上实验室,创建相关记录 + if !Laboratory.current.main_site? + Laboratory.current.laboratory_shixuns.create!(shixun: shixun, ownership: true) + end + # 如果是jupyter,先创建一个目录,为了挂载(因为后续数据集,开启Pod后环境在没销毁前,你上传数据集是挂载不上目录的,因此要先创建目录,方便中间层挂载) + if shixun.is_jupyter? + folder = edu_setting('shixun_folder') + path = "#{folder}/#{identifier}" + FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(dir) + end + return shixun + end + rescue => e + Rails.logger.error("shixun_create_error: #{e.message}") + raise("创建实训失败!") + end + end + + private + + def get_shixun_script shixun, main_mirror, sub_mirrors + if !shixun.is_jupyter? + mirror = main_mirror.mirror_scripts + if main_mirror.blank? + modify_shixun_script shixun, mirror.first&.(:script) + else + sub_name = sub_mirrors.pluck(:type_name) + if main_mirror.type_name == "Java" && sub_name.include?("Mysql") + mirror.last.try(:script) + else + shixun_script = mirror.first&.script + modify_shixun_script shixun, shixun_script + end + end + end + end + + def modify_shixun_script shixun, script + if script.present? + source_class_name = [] + challenge_program_name = [] + shixun.challenges.map(&:exec_path).each do |exec_path| + challenge_program_name << "\"#{exec_path}\"" + if shixun.main_mirror_name == "Java" + if exec_path.nil? || exec_path.split("src/")[1].nil? + source = "\"\"" + else + source = "\"#{exec_path.split("src/")[1].split(".java")[0]}\"" + end + logger.info("----source: #{source}") + source_class_name << source.gsub("/", ".") if source.present? + elsif shixun.main_mirror_name.try(:first) == "C#" + if exec_path.nil? || exec_path.split(".")[1].nil? + source = "\"\"" + else + source = "\"#{exec_path.split(".")[0]}.exe\"" + end + source_class_name << source if source.present? + end + end + script = if script.include?("sourceClassName") && script.include?("challengeProgramName") + script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{source_class_name.reject(&:blank?).join(" ")}\)") + else + script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)") + end + end + return script + end + + # 版本库目录空间 + def repo_namespace(user, shixun_identifier) + "#{user}/#{shixun_identifier}.git" + end + +end diff --git a/app/services/subjects/copy_subject_service.rb b/app/services/subjects/copy_subject_service.rb index 94157dc7b..f44191fda 100644 --- a/app/services/subjects/copy_subject_service.rb +++ b/app/services/subjects/copy_subject_service.rb @@ -60,7 +60,7 @@ class Subjects::CopySubjectService < ApplicationService shixun = stage_shixun.shixun to_shixun = Shixun.new to_shixun.attributes = shixun.attributes.dup.except('id', 'user_id', 'identifier', 'homepage_show', - 'use_scope', 'averge_star', 'myshixuns_count', 'challenges_count') + 'use_scope', 'averge_star', 'myshixuns_count', 'challenges_count', "public") to_shixun.identifier = Util::UUID.generate_identifier(Shixun, 8) to_shixun.user_id = user.id if laboratory diff --git a/app/services/users/shixun_service.rb b/app/services/users/shixun_service.rb index ef399ce8c..279d147f4 100644 --- a/app/services/users/shixun_service.rb +++ b/app/services/users/shixun_service.rb @@ -44,7 +44,7 @@ class Users::ShixunService def user_policy_filter(relations) # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 if self_or_admin? - relations = relations.where.not(status: -1) + relations = relations.where.not(status: -1).where(hidden: false) status_filter(relations) else relations.where(status: [2, 3], hidden: false) diff --git a/app/services/users/subject_service.rb b/app/services/users/subject_service.rb index 8a4fdce3b..53ff3f4b9 100644 --- a/app/services/users/subject_service.rb +++ b/app/services/users/subject_service.rb @@ -35,7 +35,7 @@ class Users::SubjectService def user_policy_filter(relations) # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 if self_or_admin? - status_filter(relations) + status_filter(relations.unhidden) else relations.where(status: 2, hidden: false) end diff --git a/app/templates/shared/main.css b/app/templates/shared/main.css index 09d295421..704246b74 100644 --- a/app/templates/shared/main.css +++ b/app/templates/shared/main.css @@ -557,7 +557,6 @@ a.user_orangebg_btn{background-color:#FF6800;color: #fff;} a.user_greybg_btn{background-color:#747A7F;color: #fff;} /*.user_white_btn{border: 1px solid #ffffff;color: #ffffff!important;}*/ - .pointer{cursor: pointer} .cdefault{cursor: default} diff --git a/app/views/challenges/index.json.jbuilder b/app/views/challenges/index.json.jbuilder index 37ce94305..c53ab9c58 100644 --- a/app/views/challenges/index.json.jbuilder +++ b/app/views/challenges/index.json.jbuilder @@ -4,8 +4,10 @@ json.description @shixun.description json.power @editable json.shixun_identifier @shixun.identifier json.shixun_status @shixun.status +json.is_jupyter @shixun.is_jupyter? json.allow_skip @shixun.task_pass + # 列表 if @challenges.present? json.challenge_list @challenges do |challenge| diff --git a/app/views/games/jupyter.json.jbuilder b/app/views/games/jupyter.json.jbuilder new file mode 100644 index 000000000..94e43a24c --- /dev/null +++ b/app/views/games/jupyter.json.jbuilder @@ -0,0 +1,7 @@ +json.user do + json.partial! 'users/user', user: current_user +end + +json.(@shixun, :id, :identifier, :status, :name) +json.myshixun_identifier @myshixun.identifier +json.tpm_modified @tpm_modified \ No newline at end of file diff --git a/app/views/games/show.json.jbuilder b/app/views/games/show.json.jbuilder index 7c9d1f22a..3c7aa3e0c 100644 --- a/app/views/games/show.json.jbuilder +++ b/app/views/games/show.json.jbuilder @@ -19,4 +19,4 @@ else json.has_answer @has_answer json.choose_test_cases @choose_test_cases json.chooses @chooses -end +end \ No newline at end of file diff --git a/app/views/homework_commons/_homework_public_navigation.json.jbuilder b/app/views/homework_commons/_homework_public_navigation.json.jbuilder index 243c6aecd..5570cec02 100644 --- a/app/views/homework_commons/_homework_public_navigation.json.jbuilder +++ b/app/views/homework_commons/_homework_public_navigation.json.jbuilder @@ -12,4 +12,5 @@ json.homework_type homework.homework_type if homework.homework_type == "practice" json.shixun_identifier homework.shixuns.take.try(:identifier) json.shixun_id homework.shixuns.take.try(:id) + json.shixun_status homework.shixuns.take.try(:status).to_i end diff --git a/app/views/homework_commons/index.json.jbuilder b/app/views/homework_commons/index.json.jbuilder index 9f0f9fdfd..35f321f45 100644 --- a/app/views/homework_commons/index.json.jbuilder +++ b/app/views/homework_commons/index.json.jbuilder @@ -29,6 +29,7 @@ json.homeworks @homework_commons.each do |homework| if @user_course_identity < Course::STUDENT if homework.homework_type == "practice" json.shixun_identifier homework.shixuns.take.try(:identifier) + json.shixun_status homework.shixuns.take.try(:status).to_i end elsif @user_course_identity == Course::STUDENT if homework.homework_type == "practice" diff --git a/app/views/shixuns/_shixun.json.jbuilder b/app/views/shixuns/_shixun.json.jbuilder index e6dbd3115..89e8d3c62 100644 --- a/app/views/shixuns/_shixun.json.jbuilder +++ b/app/views/shixuns/_shixun.json.jbuilder @@ -13,6 +13,7 @@ json.array! shixuns do |shixun| json.identifier shixun.identifier json.name shixun.name json.status shixun.status + json.is_jupyter shixun.is_jupyter? json.power (current_user.shixun_permission(shixun)) # 现在首页只显示已发布的实训 # REDO: 局部缓存 json.tag_name @tag_name_map&.fetch(shixun.id, nil) || shixun.tag_repertoires.first.try(:name) diff --git a/app/views/shixuns/_top.json.jbuilder b/app/views/shixuns/_top.json.jbuilder index 32c00cc79..8cd78dd74 100644 --- a/app/views/shixuns/_top.json.jbuilder +++ b/app/views/shixuns/_top.json.jbuilder @@ -14,6 +14,7 @@ json.stu_num shixun.myshixuns_count json.experience shixun.all_score json.diffcult diff_to_s(shixun.trainee) json.score_info shixun.shixun_preference_info # todo: 这块可以改成只显示实训的平均分,不用每次都去取每种星的分数了。 +json.is_jupyter shixun.is_jupyter # 用于是否显示导航栏中的'背景知识' json.propaedeutics shixun.propaedeutics.present? diff --git a/app/views/shixuns/get_data_sets.json.jbuilder b/app/views/shixuns/get_data_sets.json.jbuilder new file mode 100644 index 000000000..20ced2acd --- /dev/null +++ b/app/views/shixuns/get_data_sets.json.jbuilder @@ -0,0 +1,11 @@ +json.data_sets do + json.array! @data_sets do |set| + json.id set.id + json.title set.title + json.author set.author.real_name + json.created_on set.created_on + json.filesize number_to_human_size(set.filesize) + json.file_path "#{@absolute_folder}/#{set.relative_path_filename}" + end +end +json.data_sets_count @data_count \ No newline at end of file diff --git a/app/views/shixuns/jupyter_exec.json.jbuilder b/app/views/shixuns/jupyter_exec.json.jbuilder new file mode 100644 index 000000000..44e5c979a --- /dev/null +++ b/app/views/shixuns/jupyter_exec.json.jbuilder @@ -0,0 +1 @@ +json.identifier @myshixun.identifier \ No newline at end of file diff --git a/app/views/shixuns/settings.json.jbuilder b/app/views/shixuns/settings.json.jbuilder index 3441a0a06..267547431 100644 --- a/app/views/shixuns/settings.json.jbuilder +++ b/app/views/shixuns/settings.json.jbuilder @@ -2,6 +2,7 @@ json.shixun do json.status @shixun.status json.name @shixun.name json.description @shixun.description + json.is_jupyter @shixun.is_jupyter # 镜像大小类别 json.main_type @main_type @@ -41,6 +42,9 @@ json.shixun do json.(config, :cpu_limit, :lower_cpu_limit, :memory_limit, :request_limit, :mirror_repository_id) end end + + + json.jupyter_url jupyter_url(@shixun) end diff --git a/app/views/users/shixuns/shared/_shixun.json.jbuilder b/app/views/users/shixuns/shared/_shixun.json.jbuilder index 8427ead58..663522e53 100644 --- a/app/views/users/shixuns/shared/_shixun.json.jbuilder +++ b/app/views/users/shixuns/shared/_shixun.json.jbuilder @@ -6,4 +6,5 @@ json.name shixun.name json.status shixun.status json.human_status shixun.human_status json.challenges_count shixun.challenges_count -json.finished_challenges_count @finished_challenges_count_map&.fetch(shixun.id, 0) || shixun.finished_challenges_count(user) \ No newline at end of file +json.finished_challenges_count @finished_challenges_count_map&.fetch(shixun.id, 0) || shixun.finished_challenges_count(user) +json.is_jupyter shixun.is_jupyter \ No newline at end of file diff --git a/bin/bundle b/bin/bundle index b48d3a0d5..f19acf5b5 100644 --- a/bin/bundle +++ b/bin/bundle @@ -1,3 +1,3 @@ -#!/usr/bin/env ruby -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -load Gem.bin_path('bundler', 'bundle') +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails index a017658c5..073966023 100644 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,4 @@ -#!/usr/bin/env ruby -APP_PATH = File.expand_path('../config/application', __dir__) -require_relative '../config/boot' -require 'rails/commands' +#!/usr/bin/env ruby +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake index 8704afdf3..2c877f116 100644 --- a/bin/rake +++ b/bin/rake @@ -1,4 +1,6 @@ -#!/usr/bin/env ruby -require_relative '../config/boot' -require 'rake' -Rake.application.run +#!/usr/bin/env ruby +require_relative '../config/boot' + + +require 'rake' +Rake.application.run diff --git a/config/routes.rb b/config/routes.rb index acc42e7e4..3549a3f5f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,8 @@ Rails.application.routes.draw do get 'auth/qq/callback', to: 'oauth/qq#create' get 'auth/failure', to: 'oauth/base#auth_failure' + + resources :edu_settings scope '/api' do get 'home/index' @@ -23,6 +25,17 @@ Rails.application.routes.draw do put 'commons/unhidden', to: 'commons#unhidden' delete 'commons/delete', to: 'commons#delete' + resources :jupyters do + collection do + get :save_with_tpi + get :save_with_tpm + get :get_info_with_tpi + get :get_info_with_tpm + get :reset_with_tpi + get :reset_with_tpm + end + end + resources :memos do member do post :sticky_or_cancel @@ -35,6 +48,9 @@ Rails.application.routes.draw do end end + + + resources :hacks, path: :problems, param: :identifier do collection do get :unpulished_list @@ -171,6 +187,7 @@ Rails.application.routes.draw do post :html_content get :open_webssh get :challenges + post :sync_code end collection do get :sigle_mul_test @@ -206,6 +223,7 @@ Rails.application.routes.draw do get :check_test_sets get :unlock_choose_answer get :get_choose_answer + get :jupyter end collection do @@ -264,6 +282,12 @@ Rails.application.routes.draw do get :shixun_exec post :review_shixun get :review_newest_record + post :update_permission_setting + post :update_learn_setting + get :get_data_sets + get :jupyter_exec + post :upload_data_sets + delete :destroy_data_sets end resources :challenges do @@ -748,7 +772,11 @@ Rails.application.routes.draw do resources :poll_bank_questions - resources :attachments + resources :attachments do + collection do + delete :destroy_files + end + end resources :schools do member do diff --git a/db/migrate/20191210070415_add_is_jupyter_for_shixuns.rb b/db/migrate/20191210070415_add_is_jupyter_for_shixuns.rb new file mode 100644 index 000000000..af2ae7ad4 --- /dev/null +++ b/db/migrate/20191210070415_add_is_jupyter_for_shixuns.rb @@ -0,0 +1,5 @@ +class AddIsJupyterForShixuns < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :is_jupyter, :boolean, :default => false + end +end diff --git a/db/migrate/20191211025413_add_index_for_shixun_secret_repositories.rb b/db/migrate/20191211025413_add_index_for_shixun_secret_repositories.rb new file mode 100644 index 000000000..650b821e1 --- /dev/null +++ b/db/migrate/20191211025413_add_index_for_shixun_secret_repositories.rb @@ -0,0 +1,17 @@ +class AddIndexForShixunSecretRepositories < ActiveRecord::Migration[5.2] + def change + shixun_ids = ShixunSecretRepository.pluck(:shixun_id).uniq + shixuns = Shixun.where(id: shixun_ids) + shixuns.find_each do |shixun| + id = shixun.shixun_secret_repository.id + shixun_secret_repositories = ShixunSecretRepository.where(shixun_id: shixun.id).where.not(id: id) + shixun_secret_repositories.destroy_all + end + + remove_index :shixun_secret_repositories, :shixun_id + add_index :shixun_secret_repositories, :shixun_id, unique: true + + + + end +end diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..16f600df4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +version: '3' +services: + mysql: + image: mysql:5.7.17 + command: --sql-mode="" + restart: always + volumes: + - ./mysql_data/:/var/lib/mysql + ports: + - "3306:3306" + environment: + MYSQL_ROOT_PASSWORD: 123456789 + MYSQL_DATABASE: educoder + + redis: + image: redis:3.2 + container_name: redis + restart: always + ports: + - "6379:6379" + volumes: + - ./redis_data:/data + + web: + image: guange/educoder:latest + command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 4000 -b '0.0.0.0'" + stdin_open: true + tty: true + volumes: + - .:/app + ports: + - "4000:4000" + depends_on: + - mysql + - redis \ No newline at end of file diff --git a/educoder-2019-12-11.sql.zip b/educoder-2019-12-11.sql.zip new file mode 100644 index 000000000..410bb2788 Binary files /dev/null and b/educoder-2019-12-11.sql.zip differ diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js index fbfbf23bc..596843f5f 100644 --- a/public/react/config/webpack.config.prod.js +++ b/public/react/config/webpack.config.prod.js @@ -326,7 +326,7 @@ module.exports = { comments: false }, compress: { - drop_debugger: true, + drop_debugger: false, drop_console: false } } diff --git a/public/react/public/css/iconfont.css b/public/react/public/css/iconfont.css index 29e19aee4..f9c2e1e68 100644 --- a/public/react/public/css/iconfont.css +++ b/public/react/public/css/iconfont.css @@ -1,10 +1,10 @@ @font-face {font-family: "iconfont"; - src: url('iconfont.eot?t=1572859243353'); /* IE9 */ - src: url('iconfont.eot?t=1572859243353#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), - url('iconfont.woff?t=1572859243353') format('woff'), - url('iconfont.ttf?t=1572859243353') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ - url('iconfont.svg?t=1572859243353#iconfont') format('svg'); /* iOS 4.1- */ + src: url('iconfont.eot?t=1576206033975'); /* IE9 */ + src: url('iconfont.eot?t=1576206033975#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), + url('iconfont.woff?t=1576206033975') format('woff'), + url('iconfont.ttf?t=1576206033975') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ + url('iconfont.svg?t=1576206033975#iconfont') format('svg'); /* iOS 4.1- */ } .iconfont { @@ -55,6 +55,10 @@ content: "\e6bc"; } +.icon-jinzhi:before { + content: "\e6d4"; +} + .icon-vs:before { content: "\e682"; } @@ -115,6 +119,10 @@ content: "\e609"; } +.icon-liulan:before { + content: "\e6c7"; +} + .icon-luyou:before { content: "\e677"; } @@ -295,6 +303,10 @@ content: "\e694"; } +.icon-bokeyuan:before { + content: "\e6c6"; +} + .icon-base:before { content: "\e683"; } @@ -799,6 +811,10 @@ content: "\e68c"; } +.icon-pinglun:before { + content: "\e6c8"; +} + .icon-gongcheng:before { content: "\e60f"; } @@ -811,6 +827,10 @@ content: "\e604"; } +.icon-shangjiantou-tianchong:before { + content: "\e733"; +} + .icon-zhuye:before { content: "\e6d3"; } @@ -839,6 +859,10 @@ content: "\e6a1"; } +.icon-shenglvehao:before { + content: "\e708"; +} + .icon-paixu1:before { content: "\e6aa"; } @@ -923,3 +947,43 @@ content: "\e6c4"; } +.icon-bangdingshoujihao:before { + content: "\e6ca"; +} + +.icon-biaoqian1:before { + content: "\e6ce"; +} + +.icon-jilu:before { + content: "\e6cf"; +} + +.icon-shu:before { + content: "\e6d0"; +} + +.icon-tuijian:before { + content: "\e6d1"; +} + +.icon-chuangjianzhe:before { + content: "\e6d2"; +} + +.icon-wancheng1:before { + content: "\e6cb"; +} + +.icon-qiyezhanghao:before { + content: "\e6cc"; +} + +.icon-gerenzhanghao:before { + content: "\e6cd"; +} + +.icon-jiazaishibai1:before { + content: "\e6d6"; +} + diff --git a/public/react/scripts/start.js b/public/react/scripts/start.js index 5c11cf35f..321148cd3 100644 --- a/public/react/scripts/start.js +++ b/public/react/scripts/start.js @@ -1,114 +1,114 @@ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'development'; -process.env.NODE_ENV = 'development'; - - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { - throw err; -}); - -// Ensure environment variables are read. -require('../config/env'); - -const fs = require('fs'); -const chalk = require('chalk'); -const webpack = require('webpack'); -const WebpackDevServer = require('webpack-dev-server'); -const clearConsole = require('react-dev-utils/clearConsole'); -const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); -const { - choosePort, - createCompiler, - prepareProxy, - prepareUrls, -} = require('react-dev-utils/WebpackDevServerUtils'); -const openBrowser = require('react-dev-utils/openBrowser'); -const paths = require('../config/paths'); -const config = require('../config/webpack.config.dev'); -const createDevServerConfig = require('../config/webpackDevServer.config'); - -const useYarn = fs.existsSync(paths.yarnLockFile); -const isInteractive = process.stdout.isTTY; - -const portSetting = require(paths.appPackageJson).port -if ( portSetting ) { - process.env.port = portSetting -} - -// Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { - process.exit(1); -} - -// Tools like Cloud9 rely on this. -const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3007; -const HOST = process.env.HOST || '0.0.0.0'; - -if (process.env.HOST) { - console.log( - chalk.cyan( - `Attempting to bind to HOST environment variable: ${chalk.yellow( - chalk.bold(process.env.HOST) - )}` - ) - ); - console.log( - `If this was unintentional, check that you haven't mistakenly set it in your shell.` - ); - console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`); - console.log(); -} - -// We attempt to use the default port but if it is busy, we offer the user to -// run on a different port. `choosePort()` Promise resolves to the next free port. -choosePort(HOST, DEFAULT_PORT) - .then(port => { - if (port == null) { - // We have not found a port. - return; - } - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; - const appName = require(paths.appPackageJson).name; - const urls = prepareUrls(protocol, HOST, port); - // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler(webpack, config, appName, urls, useYarn); - // Load proxy config - const proxySetting = require(paths.appPackageJson).proxy; - console.log('-------------------------proxySetting:', proxySetting) - const proxyConfig = prepareProxy(proxySetting, paths.appPublic); - // Serve webpack assets generated by the compiler over a web sever. - const serverConfig = createDevServerConfig( - proxyConfig, - urls.lanUrlForConfig - ); - const devServer = new WebpackDevServer(compiler, serverConfig); - // Launch WebpackDevServer. - devServer.listen(port, HOST, err => { - if (err) { - return console.log(err); - } - if (isInteractive) { - clearConsole(); - } - console.log(chalk.cyan('Starting the development server...\n')); - openBrowser(urls.localUrlForBrowser); - }); - - ['SIGINT', 'SIGTERM'].forEach(function(sig) { - process.on(sig, function() { - devServer.close(); - process.exit(); - }); - }); - }) - .catch(err => { - if (err && err.message) { - console.log(err.message); - } - process.exit(1); - }); +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'development'; +process.env.NODE_ENV = 'development'; + + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + +const fs = require('fs'); +const chalk = require('chalk'); +const webpack = require('webpack'); +const WebpackDevServer = require('webpack-dev-server'); +const clearConsole = require('react-dev-utils/clearConsole'); +const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); +const { + choosePort, + createCompiler, + prepareProxy, + prepareUrls, +} = require('react-dev-utils/WebpackDevServerUtils'); +const openBrowser = require('react-dev-utils/openBrowser'); +const paths = require('../config/paths'); +const config = require('../config/webpack.config.dev'); +const createDevServerConfig = require('../config/webpackDevServer.config'); + +const useYarn = fs.existsSync(paths.yarnLockFile); +const isInteractive = process.stdout.isTTY; + +const portSetting = require(paths.appPackageJson).port +if ( portSetting ) { + process.env.port = portSetting +} + +// Warn and crash if required files are missing +if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { + process.exit(1); +} + +// Tools like Cloud9 rely on this. +const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3007; +const HOST = process.env.HOST || '0.0.0.0'; + +if (process.env.HOST) { + console.log( + chalk.cyan( + `Attempting to bind to HOST environment variable: ${chalk.yellow( + chalk.bold(process.env.HOST) + )}` + ) + ); + console.log( + `If this was unintentional, check that you haven't mistakenly set it in your shell.` + ); + console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`); + console.log(); +} + +// We attempt to use the default port but if it is busy, we offer the user to +// run on a different port. `choosePort()` Promise resolves to the next free port. +choosePort(HOST, DEFAULT_PORT) + .then(port => { + if (port == null) { + // We have not found a port. + return; + } + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; + const appName = require(paths.appPackageJson).name; + const urls = prepareUrls(protocol, HOST, port); + // Create a webpack compiler that is configured with custom messages. + const compiler = createCompiler(webpack, config, appName, urls, useYarn); + // Load proxy config + const proxySetting = require(paths.appPackageJson).proxy; + console.log('-------------------------proxySetting:', proxySetting) + const proxyConfig = prepareProxy(proxySetting, paths.appPublic); + // Serve webpack assets generated by the compiler over a web sever. + const serverConfig = createDevServerConfig( + proxyConfig, + urls.lanUrlForConfig + ); + const devServer = new WebpackDevServer(compiler, serverConfig); + // Launch WebpackDevServer. + devServer.listen(port, HOST, err => { + if (err) { + return console.log(err); + } + if (isInteractive) { + clearConsole(); + } + console.log(chalk.cyan('Starting the development server...\n')); + openBrowser(urls.localUrlForBrowser); + }); + + ['SIGINT', 'SIGTERM'].forEach(function(sig) { + process.on(sig, function() { + devServer.close(); + process.exit(); + }); + }); + }) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }); diff --git a/public/react/src/App.js b/public/react/src/App.js index 2fa9e0765..7d83757aa 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -316,6 +316,11 @@ const RecordDetail = Loadable({ loader: () => import('./modules/developer/recordDetail'), loading: Loading }); +// jupyter tpi +const JupyterTPI = Loadable({ + loader: () => import('./modules/tpm/jupyter'), + loading: Loading +}); // //个人竞赛报名 // const PersonalCompetit = Loadable({ // loader: () => import('./modules/competition/personal/PersonalCompetit.js'), @@ -358,7 +363,7 @@ class App extends Component { mydisplay:true, }) }; - + disableVideoContextMenu = () => { window.$( "body" ).on( "mousedown", "video", function(event) { if(event.which === 3) { @@ -577,14 +582,14 @@ class App extends Component { { - + return () } }> { + (props) => { return () } }> @@ -610,12 +615,21 @@ class App extends Component { + {/* jupyter */} + { + return () + } + } + /> + - {/*列表页*/} + {/*列表页 实训项目列表*/} @@ -637,8 +651,8 @@ class App extends Component { () }/> - - () } @@ -671,7 +685,7 @@ class App extends Component { (props)=>() }/> - { return () @@ -679,11 +693,11 @@ class App extends Component { } /> () } /> - () } @@ -703,7 +717,7 @@ class App extends Component { (props)=>() } /> - + @@ -825,4 +839,4 @@ moment.defineLocale('zh-cn', { doy: 4 // The week that contains Jan 4th is the first week of the year. } }); -export default SnackbarHOC()(App) ; \ No newline at end of file +export default SnackbarHOC()(App) ; diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 064c64db1..acd18e6c3 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -13,10 +13,10 @@ function locationurl(list){ if (window.location.port === "3007") { } else { - window.location.replace(list) + window.location.href=list } } -let hashTimeout +let hashTimeout // TODO 开发期多个身份切换 let debugType ="" @@ -33,9 +33,9 @@ if (isDev) { // 超管 // debugType="admin"; // 老师 -// debugType="teacher"; +//ebugType="teacher"; // 学生 -//debugType="student"; +// debugType="student"; window._debugType = debugType; export function initAxiosInterceptors(props) { @@ -51,7 +51,8 @@ export function initAxiosInterceptors(props) { // proxy = "https://testeduplus2.educoder.net" //proxy="http://47.96.87.25:48080" proxy="https://pre-newweb.educoder.net" - proxy="https://test-newweb.educoder.net" + proxy="https://test-newweb.educoder.net" + proxy="https://test-jupyterweb.educoder.net" //proxy="http://192.168.2.63:3001" // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; @@ -88,7 +89,6 @@ export function initAxiosInterceptors(props) { url = `${config.url}`; } } - if(`${config[0]}`!=`true`){ if (window.location.port === "3007") { // if (url.indexOf('.json') == -1) { @@ -109,15 +109,15 @@ export function initAxiosInterceptors(props) { } // // console.log(config); - if (config.method === "post") { - if (requestMap[config.url] === true) { // 避免重复的请求 导致页面f5刷新 也会被阻止 显示这个方法会影响到定制信息 - // console.log(config); - // console.log(JSON.parse(config)); - // console.log(config.url); - // console.log("被阻止了是重复请求================================="); - return false; - } - } + // if (config.method === "post") { + // if (requestMap[config.url] === true) { // 避免重复的请求 导致页面f5刷新 也会被阻止 显示这个方法会影响到定制信息 + // // console.log(config); + // // console.log(JSON.parse(config)); + // // console.log(config.url); + // // console.log("被阻止了是重复请求================================="); + // return false; + // } + // } // 非file_update请求 if (config.url.indexOf('update_file') === -1) { requestMap[config.url] = true; @@ -224,7 +224,7 @@ export function initAxiosInterceptors(props) { return Promise.reject(error); }); // ----------------------------------------------------------------------------------- - + } diff --git a/public/react/src/common/Env.js b/public/react/src/common/Env.js index c80497509..9830d7725 100644 --- a/public/react/src/common/Env.js +++ b/public/react/src/common/Env.js @@ -1,8 +1,8 @@ -export function isDev() { - return window.location.port === "3007"; -} - -// const isMobile -export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); - -// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase())); +export function isDev() { + return window.location.port === "3007"; +} + +// const isMobile +export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); + +// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase())); diff --git a/public/react/src/common/UrlTool.js b/public/react/src/common/UrlTool.js index db97642b7..bc463e662 100644 --- a/public/react/src/common/UrlTool.js +++ b/public/react/src/common/UrlTool.js @@ -37,6 +37,22 @@ export function getUrl(path, goTest) { } return `${path ? path: ''}`; } + +export function getUrlmys(path, goTest) { + // https://www.educoder.net + // https://testbdweb.trustie.net + + // 如果想所有url定位到测试版,可以反注释掉下面这行 + //goTest = true + // testbdweb.educoder.net testbdweb.trustie.net + // const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000' + // const local = 'https://testeduplus2.educoder.net' + const local = 'https://test-jupyterweb.educoder.net' + if (isDev) { + return `${local}${path?path:''}` + } + return `${path ? path: ''}`; +} export function getStaticUrl() { const local = TEST_HOST; if (isDev) { @@ -55,6 +71,10 @@ export function getUrl2(path, goTest) { export function getUploadActionUrl(path, goTest) { return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}` } +export function getUploadActionUrltwo(id) { + + return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}` +} export function getUploadActionUrlOfAuth(id) { return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}` } @@ -85,4 +105,4 @@ export function htmlEncode(str) { s = s.replace(/\'/g, "'");//IE下不支持实体名称 s = s.replace(/\"/g, """); return s; -} \ No newline at end of file +} diff --git a/public/react/src/common/components/ModalConfirm.js b/public/react/src/common/components/ModalConfirm.js new file mode 100644 index 000000000..bb29fed03 --- /dev/null +++ b/public/react/src/common/components/ModalConfirm.js @@ -0,0 +1,30 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-13 10:28:15 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 10:37:17 + */ +import { Modal } from 'antd'; + +export function ModalConfirm ( + title, + content, + handleOk, + handleCancel +) { + + Modal.confirm({ + title, + content, + okText: '确定', + cancelText: '取消', + onOk () { + handleOk && handleOk(); + }, + onCancel () { + handleCancel && handleCancel(); + } + }); +} diff --git a/public/react/src/common/components/MyIcon.js b/public/react/src/common/components/MyIcon.js index 7c6f4bb94..aa9f29a19 100644 --- a/public/react/src/common/components/MyIcon.js +++ b/public/react/src/common/components/MyIcon.js @@ -4,12 +4,12 @@ * @Github: * @Date: 2019-12-10 09:03:48 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 09:05:41 + * @LastEditTime: 2019-12-12 10:53:47 */ import { Icon } from 'antd'; 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; diff --git a/public/react/src/common/educoder.js b/public/react/src/common/educoder.js index 004cd91c0..c9aa7ac77 100644 --- a/public/react/src/common/educoder.js +++ b/public/react/src/common/educoder.js @@ -2,11 +2,11 @@ // export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil'; -export { getImageUrl as getImageUrl, getUrl as getUrl, getUrl2 as getUrl2, setImagesUrl as setImagesUrl - , getUploadActionUrl as getUploadActionUrl, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth +export { getImageUrl as getImageUrl, getUrl as getUrl, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl + , getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo , getUploadActionUrlOfAuth as getUploadActionUrlOfAuth , getTaskUrlById as getTaskUrlById, TEST_HOST ,htmlEncode as htmlEncode } from './UrlTool'; export { default as queryString } from './UrlTool2'; - + export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC'; export { trigger as trigger, on as on, off as off @@ -31,7 +31,7 @@ export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info export { EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER , EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const' - + export { default as AttachmentList } from './components/attachment/AttachmentList' export { themes, ThemeContext } from './context/ThemeContext' diff --git a/public/react/src/context/TPIContextProvider.js b/public/react/src/context/TPIContextProvider.js index dce678480..ed7eb2210 100644 --- a/public/react/src/context/TPIContextProvider.js +++ b/public/react/src/context/TPIContextProvider.js @@ -41,17 +41,17 @@ const styles = MUIDialogStyleUtil.getTwoButtonStyle() // 主题自定义 const theme = createMuiTheme({ palette: { - primary: { + primary: { main: '#4CACFF', contrastText: 'rgba(255, 255, 255, 0.87)' - }, + }, secondary: { main: '#4CACFF' }, // This is just green.A700 as hex. }, }); -const testSetsExpandedArrayInitVal = [false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, +const testSetsExpandedArrayInitVal = [false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false] window.__fetchAllFlag = false; // 是否调用过fetchAll TODO 如何多次使用provider? @@ -70,7 +70,7 @@ class TPIContextProvider extends Component { this.readGameAnswer = this.readGameAnswer.bind(this) this.praisePlus = this.praisePlus.bind(this) - + this.onGamePassed = this.onGamePassed.bind(this) this.onPathChange = this.onPathChange.bind(this) @@ -80,7 +80,7 @@ class TPIContextProvider extends Component { this.onShowUpdateDialog = this.onShowUpdateDialog.bind(this) this.updateDialogClose = this.updateDialogClose.bind(this) - + // this.showEffectDisplay(); this.state = { @@ -142,7 +142,7 @@ class TPIContextProvider extends Component { // request // var shixunId = this.props.match.params.shixunId; var stageId = this.props.match.params.stageId; - + window.__fetchAllFlag = false; this.fetchAll(stageId); this.costTimeInterval = window.setInterval(()=> { @@ -192,7 +192,7 @@ class TPIContextProvider extends Component { onGamePassed(passed) { const { game } = this.state // 随便给个分,以免重新评测时又出现评星组件(注意:目前game.star没有显示在界面上,如果有则不能这么做) - // game.star = 6; + // game.star = 6; this.setState({ game: update(game, {star: { $set: 6 }}), currentGamePassed: !!passed @@ -253,14 +253,14 @@ pop_box_new(htmlvalue, 480, 182); const { praise_count, praise } = response.data; // challenge.praise_count = praise_tread_count; // challenge.user_praise = praise; - this.setState({ challenge: update(challenge, + this.setState({ challenge: update(challenge, { praise_count: { $set: praise_count }, user_praise: { $set: praise }, }) }) } - + }) .catch(function (error) { console.log(error); @@ -286,11 +286,11 @@ pop_box_new(htmlvalue, 480, 182); } const { myshixun } = this.state; // myshixun.system_tip = false; - + challenge.path = path; const newChallenge = this.handleChallengePath(challenge); - this.setState({ challenge: newChallenge, + this.setState({ challenge: newChallenge, myshixun: update(myshixun, {system_tip: { $set: false }}), }) } @@ -313,7 +313,7 @@ pop_box_new(htmlvalue, 480, 182); newResData2OldResData(newResData) { newResData.latest_output = newResData.last_compile_output - // newResData.power + // newResData.power newResData.record = newResData.record_onsume_time // 老版用的hide_code @@ -329,7 +329,7 @@ pop_box_new(htmlvalue, 480, 182); newResData.output_sets.test_sets = newResData.test_sets // JSON.stringify() newResData.output_sets.test_sets_count = newResData.test_sets_count // newResData.output_sets.had_passed_testsests_error_count = newResData.sets_error_count - newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count + newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count - newResData.sets_error_count // allowed_hidden_testset // sets_error_count @@ -354,8 +354,8 @@ pop_box_new(htmlvalue, 480, 182); let output_sets = resData.output_sets; if (resData.st === 0) { // 代码题 challenge = this.handleChallengePath(challenge) - - const mirror_name = (resData.mirror_name && resData.mirror_name.join) + + const mirror_name = (resData.mirror_name && resData.mirror_name.join) ? resData.mirror_name.join(';') : (resData.mirror_name || ''); if (mirror_name.indexOf('Html') !== -1) { challenge.isHtml = true; @@ -364,7 +364,7 @@ pop_box_new(htmlvalue, 480, 182); challenge.isWeb = true; } else if (mirror_name.indexOf('Android') !== -1) { challenge.isAndroid = true; - } + } if (output_sets && output_sets.test_sets && typeof output_sets.test_sets == 'string') { const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]"); @@ -378,7 +378,7 @@ pop_box_new(htmlvalue, 480, 182); const $ = window.$ window.setTimeout(()=>{ var lens = $("#choiceRepositoryView textarea").length; - + for(var i = 1; i <= lens; i++){ window.editormd.markdownToHTML("choose_subject_" + i, { htmlDecode: "style,script,iframe", // you can filter tags decode @@ -404,14 +404,14 @@ pop_box_new(htmlvalue, 480, 182); game.isPassThrough = true } resData.game = game; - + const { tpm_cases_modified, tpm_modified, tpm_script_modified, myshixun } = resData; if (myshixun.system_tip) { // system_tip为true的时候 不弹框提示用户更新 resData.showUpdateDialog = false } else { let needUpdateScript = (tpm_modified || tpm_script_modified) && challenge.st === 0; - resData.showUpdateDialog = needUpdateScript || tpm_cases_modified + resData.showUpdateDialog = needUpdateScript || tpm_cases_modified } /** @@ -458,7 +458,7 @@ pop_box_new(htmlvalue, 480, 182); // const EDU_NORMAL = 7 // 普通用户 - /** + /** EDU_ADMIN = 1 # 超级管理员 EDU_BUSINESS = 2 # 运营人员 EDU_SHIXUN_MANAGER = 3 # 实训管理员 @@ -467,7 +467,7 @@ pop_box_new(htmlvalue, 480, 182); EDU_GAME_MANAGER = 6 # TPI的创建者 EDU_TEACHER = 7 # 平台老师,但是未认证 EDU_NORMAL = 8 # 普通用户 - */ + */ // myshixun_manager power is_teacher resData.power = 0 @@ -495,8 +495,8 @@ pop_box_new(htmlvalue, 480, 182); } else if (resData.user.identity === EDU_TEACHER) { // resData.is_teacher = true } else if (resData.user.identity === EDU_NORMAL) { - - } + + } return resData } @@ -524,7 +524,7 @@ pop_box_new(htmlvalue, 480, 182); loading: true, currentGamePassed: false, // 切换game时重置passed字段 }) - + // test // var data = {"st":0,"discusses_count":0,"game_count":3,"record_onsume_time":0.36,"prev_game":null,"next_game":"7p9xwo2hklqv","praise_count":0,"user_praise":false,"time_limit":20,"tomcat_url":"http://47.96.157.89","is_teacher":false,"myshixun_manager":true,"game":{"id":2192828,"myshixun_id":580911,"user_id":57844,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:51:05.000+08:00","status":2,"final_score":0,"challenge_id":10010,"open_time":"2019-09-03T15:50:49.000+08:00","identifier":"hknvz4oaw825","answer_open":0,"end_time":"2019-09-03T15:51:04.000+08:00","retry_status":0,"resubmit_identifier":null,"test_sets_view":false,"picture_path":null,"accuracy":1.0,"modify_time":"2019-09-03T15:23:33.000+08:00","star":0,"cost_time":14,"evaluate_count":1,"answer_deduction":0},"challenge":{"id":10010,"shixun_id":3516,"subject":"1.1 列表操作","position":1,"task_pass":"[TOC]\n\n---\n\n####任务描述\n\n\n数据集a包含1-10共10个整数,请以a为输入数据,编写python程序,实现如下功能:\n①\t用2种方法输出a中所有奇数\n②\t输出大于3,小于7的偶数\n③\t用2种方法输出[1,2,3,…10,11,…20]\n④\t输出a的最大值、最小值。\n⑤\t用2种方法输出[10,9,…2,1]\n⑥\t输出[1,2,3,1,2,3,1,2,3,1,2,3]\n\n\n####相关知识\n\n\n请自行学习相关知识\n\n\n---\n开始你的任务吧,祝你成功!","score":100,"path":"1-1-stu.py","st":0,"web_route":null,"modify_time":"2019-09-03T15:23:33.000+08:00","exec_time":20,"praises_count":0},"shixun":{"id":3516,"name":"作业1——Python程序设计","user_id":77620,"gpid":null,"visits":23,"created_at":"2019-09-03T14:18:17.000+08:00","updated_at":"2019-09-03T15:58:16.000+08:00","status":0,"language":null,"authentication":false,"identifier":"6lzjig58","trainee":1,"major_id":null,"webssh":2,"homepage_show":false,"hidden":false,"fork_from":null,"can_copy":true,"modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","publish_time":null,"closer_id":null,"end_time":null,"git_url":null,"vnc":null,"myshixuns_count":3,"challenges_count":3,"use_scope":0,"mirror_script_id":20,"image_text":null,"code_hidden":false,"task_pass":true,"exec_time":20,"test_set_permission":true,"sigle_training":false,"hide_code":false,"multi_webssh":false,"excute_time":null,"repo_name":"p09218567/6lzjig58","averge_star":5.0,"opening_time":null,"users_count":1,"forbid_copy":false,"pod_life":0},"myshixun":{"id":580911,"shixun_id":3516,"is_public":true,"user_id":57844,"gpid":null,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:59:04.000+08:00","status":0,"identifier":"k36hm4rwav","commit_id":"f25e1713882156480fc45ce0af57eff395a5037f","modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","system_tip":false,"git_url":null,"onclick_time":"2019-09-03T15:50:49.000+08:00","repo_name":"p53276410/k36hm4rwav20190903155049"},"user":{"user_id":57844,"login":"p53276410","name":"文振乾","grade":24624,"identity":1,"image_url":"avatars/User/57844","school":"EduCoder团队"},"tpm_modified":true,"tpm_cases_modified":false,"mirror_name":["Python3.6"],"has_answer":false,"test_sets":[{"is_public":true,"result":true,"input":"","output":"result of a:\n[1, 3, 5, 7, 9]\n[1, 3, 5, 7, 9]\nresult of b:\n[2, 4, 6, 8, 10]\nresult of c:\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\nresult of d:\nThe minimum is:1\nThe maxium is:10\nresult of e:\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nresult of f:\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\n","actual_output":"result of a:\r\n[1, 3, 5, 7, 9]\r\n[1, 3, 5, 7, 9]\r\nresult of b:\r\n[2, 4, 6, 8, 10]\r\nresult of c:\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\nresult of d:\r\nThe minimum is:1\r\nThe maxium is:10\r\nresult of e:\r\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\r\nresult of f:\r\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\r\n","compile_success":1,"ts_time":0.05,"ts_mem":8.77}],"allowed_unlock":true,"last_compile_output":"compile successfully","test_sets_count":1,"sets_error_count":0} // data.test_sets[0].actual_output = data.test_sets[0].actual_output.replace(/\r\n/g, '\n') @@ -534,7 +534,7 @@ pop_box_new(htmlvalue, 480, 182); // data.vnc_url= "http://47.96.157.89:41158/vnc_lite.html?password=headless" // this._handleResponseData(data) - // return + // return axios.get(url, { // https://stackoverflow.com/questions/48861290/the-value-of-the-access-control-allow-origin-header-in-the-response-must-not-b @@ -550,7 +550,7 @@ pop_box_new(htmlvalue, 480, 182); return; } if (response.data.status == 404) { - // 如果第一次发生404,则隔1s后再调用一次本接口;(因为ucloud主从同步可能有延迟) + // 如果第一次发生404,则隔1s后再调用一次本接口;(因为ucloud主从同步可能有延迟) if (!noTimeout) { setTimeout(() => { this.fetchAll(stageId, true) @@ -562,12 +562,12 @@ pop_box_new(htmlvalue, 480, 182); } this._handleResponseData(response.data) - + }) .catch(function (error) { console.log(error); }); - + } readGameAnswer(resData) { @@ -583,7 +583,7 @@ pop_box_new(htmlvalue, 480, 182); grade: resData.grade }) } - + } closeTaskResultLayer() { this.setState({ @@ -605,7 +605,7 @@ pop_box_new(htmlvalue, 480, 182); currentGamePassed = true; - + this._updateCostTime(true, true); } this.setState({ @@ -618,14 +618,14 @@ pop_box_new(htmlvalue, 480, 182); currentPassedGameGainGold: gold, currentPassedGameGainExperience: experience, }) - } + } initDisplayInterval = () => { const challenge = this.state.challenge if (this.showWebDisplayButtonTimeout) { window.clearTimeout(this.showWebDisplayButtonTimeout) } this.showWebDisplayButtonTimeout = window.setTimeout(() => { - this.setState({ challenge: update(challenge, + this.setState({ challenge: update(challenge, { showWebDisplayButton: { $set: false }, }) @@ -650,7 +650,7 @@ pop_box_new(htmlvalue, 480, 182); this.displayInterval = null return; } - + remain -= 1; }, 1000) } @@ -716,7 +716,7 @@ pop_box_new(htmlvalue, 480, 182); const currentGamePassed = this.props.game !== 2 && status === 2 - + // 评测通过了,立即同步costTime currentGamePassed && this._updateCostTime(true, true); @@ -738,7 +738,7 @@ pop_box_new(htmlvalue, 480, 182); // const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]"); // output_sets.test_sets_array = test_sets_array; // } - + // 检查是否编译通过 let compileSuccess = false; if (test_sets && test_sets.length) { @@ -754,7 +754,7 @@ pop_box_new(htmlvalue, 480, 182); if (currentGamePassed) { game.status = 2; // game.isPassThrough = true - game.next_game = next_game; + game.next_game = next_game; } else { this.showDialog({ contentText:
@@ -764,7 +764,7 @@ pop_box_new(htmlvalue, 480, 182); isSingleButton: true }) } - + this.setState({ testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0), // 重置测试集展开状态 @@ -775,12 +775,12 @@ pop_box_new(htmlvalue, 480, 182); output_sets, game, next_game, - + latest_output: last_compile_output, record: record_consume_time, grade, had_done, - + }) } resetTestSetsExpandedArray = () => { @@ -809,15 +809,15 @@ pop_box_new(htmlvalue, 480, 182); output_sets = Object.assign({}, output_sets); // const test_sets_array = JSON.parse("[" + response.data.test_sets + "]"); output_sets.test_sets_array = response.data.test_sets; - this.setState({ + this.setState({ output_sets: output_sets, grade: this.state.grade + deltaScore, - game : update(game, {test_sets_view: { $set: true }}), - testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0) + game : update(game, {test_sets_view: { $set: true }}), + testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0) }) this.handleGdialogClose(); } - + }) .catch(function (error) { console.log(error); @@ -841,10 +841,10 @@ pop_box_new(htmlvalue, 480, 182); }) } - /* + /* TODO 写成HOC组件,更好复用 全局的Dialog this.props.showDialog调用即可 - @param contentText dialog显示的提示文本 + @param contentText dialog显示的提示文本 @param callback 确定按钮回调方法 @param moreButtonsRender 除了“确定”、“取消”按钮外的其他按钮 @param okButtonText “确定”按钮显示文本,如 继续查看 @@ -908,13 +908,13 @@ pop_box_new(htmlvalue, 480, 182); match: this.props.match }} - > + > this.handleGdialogClose()} - > + > {"提示"} @@ -930,7 +930,7 @@ pop_box_new(htmlvalue, 480, 182); >知道啦
: - @@ -938,7 +938,7 @@ pop_box_new(htmlvalue, 480, 182); onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus> { this.okButtonText ? this.okButtonText : '确定' } - } + } {this.moreButtonsRender && this.moreButtonsRender()} diff --git a/public/react/src/images/oj/oj_banner.jpg b/public/react/src/images/oj/oj_banner.jpg new file mode 100644 index 000000000..8b74270d3 Binary files /dev/null and b/public/react/src/images/oj/oj_banner.jpg differ diff --git a/public/react/src/modules/courses/busyWork/CommonWorkItem.js b/public/react/src/modules/courses/busyWork/CommonWorkItem.js index 75676557a..82e2d2d96 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkItem.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkItem.js @@ -205,15 +205,16 @@ class CommonWorkItem extends Component{ {item.uncommit_count===undefined?"":{item.uncommit_count} 未交} { item.status_time!="" && - + {item.status_time} - - } + } + {/**/} + {/**/} {isAdmin &&
{ this.props.toEditPage(this.props.match.params, item.homework_id) }}>编辑 { this.props.toWorkSettingPage(this.props.match.params, item.homework_id) }}>设置 diff --git a/public/react/src/modules/courses/coursesPublic/NewShixunModel.js b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js index 462df7608..5ee763951 100644 --- a/public/react/src/modules/courses/coursesPublic/NewShixunModel.js +++ b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js @@ -493,8 +493,8 @@ class NewShixunModel extends Component{ {this.props.type==='shixuns'?

筛选:

-

this.belongto("all")}>全部实训

-

this.belongto("mine")}>普通实训

+

this.belongto("all")}>全部实训

+

this.belongto("mine")}>我的实训

:"" } {/*{this.props.type==='shixuns'? */} @@ -581,11 +581,26 @@ class NewShixunModel extends Component{ className="fl task-hide edu-txt-left mt3" name="shixun_homework[]" > + + { + this.props.type==='shixuns'? + ( + item.is_jupyter===true? +
+

+ Jupyter +

+
+ :"" + ) + :"" + } +
+ 上传附件 + (单个文件150M以内) diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js index 855f860ef..ab75b6c89 100644 --- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js +++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js @@ -4005,7 +4005,7 @@ class Listofworksstudentone extends Component { height: 58px; } .ysltableows .ant-table-thead > tr > th, .ant-table-tbody > tr > td { - padding: 9px; + padding: 9px; } ` } diff --git a/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js b/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js index 5073a6e9c..05a3eb5cd 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js @@ -232,9 +232,9 @@ class ShixunHomeworkPage extends Component { typelist={teacherdatapage === undefined ? [""] : teacherdatapage.homework_status} /> this.gotohome()}>返回 - 1?实训详情 + target={"_blank"}>实训详情:""}
@@ -336,10 +336,10 @@ class ShixunHomeworkPage extends Component { {teacherdatapage.commit_des} } - {teacherdatapage === undefined ? "" : 1?} + />:""} {this.props.isStudent() ? ( teacherdatapage&&teacherdatapage.redo_work===true? diff --git a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js index 23f590dcd..10b12eb0a 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js @@ -315,6 +315,7 @@ class ShixunWorkReport extends Component { // let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment===null||work_comment===undefined?false:true:work_comment===null||work_comment===undefined?false:true; let showAppraiseModals=work_comment===null||work_comment===undefined?false:true; document.title=data&&data.course_name; + return ( data===undefined?"": @@ -366,10 +367,15 @@ class ShixunWorkReport extends Component {

{data&&data.shixun_name}

{/*{this.props.isAdmin()?导出实训报告数据:""}*/} 返回 - {this.props.isAdmin() ? this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)} - > 导出实训报告数据 : ""} + > 导出实训报告数据: + parseInt(this.props&&this.props.user.user_id)===parseInt(data&&data.user_id)?this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)} + > 导出实训报告数据:"" + } {/*{this.props.isAdmin() ?work_comment_hidden===true? "":this.showAppraiseModal(1)}*/} diff --git a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js index dc59d93ed..fc39effdd 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js @@ -355,18 +355,22 @@ class ShixunhomeWorkItem extends Component{ .homepagePostSettingbox{ width:139px !important; } + .colorfff{ + color:#fff !important; + } ` } {this.props.isAdmin?this.stopPro(event)} className={this.props.isAdminOrCreator()?"homepagePostSetting homepagePostSettingname":"homepagePostSetting homepagePostSettingbox"} style={{"right":"-2px","top":"6px","display":"block"}}> - 实训详情 + {discussMessage&&discussMessage.shixun_status>1?实训详情: + 实训详情} {this.props.isAdminOrCreator()?this.editname(discussMessage.name,discussMessage.homework_id,event)} className={"btn colorblue ml20 font-16 fontweight400"}>重命名:""} {/* 设置*/} 设置 :""} - {this.props.isStudent===true?this.props.course_identity===5? + {this.props.isStudent===true?this.props.course_identity===5?discussMessage&&discussMessage.shixun_status>1? {startbtn===false? (discussMessage.task_operation[0] == '继续挑战' || discussMessage.task_operation[0] == '查看实战' ? @@ -377,7 +381,7 @@ class ShixunhomeWorkItem extends Component{ this.taskoperationId(discussMessage.task_operation[1])}> {discussMessage.task_operation[0]} ):开启中} - :"":"" + :"":"":"" } @@ -393,21 +397,13 @@ class ShixunhomeWorkItem extends Component{ { discussMessage.time_status===1? - {discussMessage.status_time} - :discussMessage.time_status===2? - {discussMessage.status_time} - :discussMessage.time_status===3? - {discussMessage.status_time} - :discussMessage.time_status===4? - {discussMessage.status_time} - : {discussMessage.status_time} } diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js index 178e13ef5..5f787659e 100644 --- a/public/react/src/modules/developer/DeveloperHome.js +++ b/public/react/src/modules/developer/DeveloperHome.js @@ -44,6 +44,13 @@ const maps = { 'value': '2' } ], + 'languageMenu': [ + { + 'key': 'c', + 'name': 'C语言', + 'value': 'c' + } + ], 'difficultMenu': [ { 'key': '1', @@ -119,15 +126,14 @@ class DeveloperHome extends React.PureComponent { > {/* */} - ), @@ -197,7 +203,6 @@ class DeveloperHome extends React.PureComponent { componentDidMount() { // 是否是我的,如果是我的 显示编辑按钮 const { isMySource } = this.props; - console.log(this.props); if (isMySource) { this.handleFilterSearch({come_from: 'mine'}); let _columns = this.columns.concat([this.options]); @@ -346,6 +351,14 @@ class DeveloperHome extends React.PureComponent { }); this.handleFilterSearch({category: +item.key === 0 ? '' : +item.key}); } + // 下拉语言 + handleLanguageMenuClick = (item) => { + this.addShowFilterCtx({ + type: 'language', + key: item.key + }); + this.handleFilterSearch({language: item.key}) + } // 难度下拉 handleHardMenuClick = (item) => { this.addShowFilterCtx({ @@ -421,6 +434,7 @@ class DeveloperHome extends React.PureComponent { // const { testReducer, handleClick } = this.props; const { ojListReducer: {hacks_list, top_data, hacks_count}, + user, pagination } = this.props; const {passed_count = 0, simple_count = 0, medium_count = 0, diff_count = 0} = top_data; @@ -443,7 +457,11 @@ class DeveloperHome extends React.PureComponent { >{ctx} )}); }; - + // console.log('=====>>>>>>>>>.', this.props); + + const newBtnStyle = user && (user.admin || (user.is_teacher && user.professional_certification) || user.business) + ? { display: 'block'} + : { display: 'none'}; return (
@@ -457,7 +475,8 @@ class DeveloperHome extends React.PureComponent {
-
@@ -468,6 +487,9 @@ class DeveloperHome extends React.PureComponent { 分类 + + 语言 + 难度 diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js index 690bbad36..587e1bee9 100644 --- a/public/react/src/modules/developer/components/controlSetting/index.js +++ b/public/react/src/modules/developer/components/controlSetting/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 16:02:36 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 09:30:27 + * @LastEditTime: 2019-12-13 17:32:33 */ import './index.scss'; import React, { useState, useRef } from 'react'; @@ -84,7 +84,7 @@ const ControlSetting = (props) => { diff --git a/public/react/src/modules/developer/components/controlSetting/index.scss b/public/react/src/modules/developer/components/controlSetting/index.scss index 4a2c221c1..97838ce5c 100644 --- a/public/react/src/modules/developer/components/controlSetting/index.scss +++ b/public/react/src/modules/developer/components/controlSetting/index.scss @@ -2,6 +2,7 @@ position: absolute; bottom: 0; width: 100%; + background:rgba(30,30,30,1); // height: 56px; .control_tab{ position: absolute; @@ -51,7 +52,8 @@ height: 56px; padding-right: 30px; padding-left: 10px; - background: #000; + // background: #000; + background:rgba(48,48,48,1); } .setting_drawer{ diff --git a/public/react/src/modules/developer/components/initTabCtx/index.js b/public/react/src/modules/developer/components/initTabCtx/index.js index 19f4230b1..3834a3e11 100644 --- a/public/react/src/modules/developer/components/initTabCtx/index.js +++ b/public/react/src/modules/developer/components/initTabCtx/index.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 19:46:14 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 09:31:00 + * @LastEditTime: 2019-12-13 17:38:42 */ import './index.scss'; import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react'; @@ -50,6 +50,7 @@ function InitTabCtx (props, ref) { ], initialValue: inputValue })( +

执行命令不能为空

+ + +
  • + + +
  • + + + + +
    +
  • + + +
  • +
    {this.state.languagewritetype === true ? "请填写该镜像语言" : ""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype === true ? "请填写该镜像语言系统环境" : ""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype === true ? "请填写该镜像测试代码运行方式" : ""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + + +
    + +
  • +
    + {this.state.attachmentidstype === true ? "请上传附件" : ""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    +
    + + {this.props.identity < 5 ? + : ""} + + + ); + } +} + +const TopShixuninformation = Form.create({name: 'newshixun'})(Shixuninformation); + +export default TopShixuninformation; + + + diff --git a/public/react/src/modules/tpm/TPMsettings/TPMsettings.js b/public/react/src/modules/tpm/TPMsettings/TPMsettings.js index 7acaf98d6..651818da7 100644 --- a/public/react/src/modules/tpm/TPMsettings/TPMsettings.js +++ b/public/react/src/modules/tpm/TPMsettings/TPMsettings.js @@ -1,2435 +1,232 @@ -import React, { Component } from 'react'; +import React, {Component} from 'react'; -import MonacoEditor from 'react-monaco-editor'; - -//MonacoDiffEditor 对比模式 -import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip} from 'antd'; - -// import "antd/dist/antd.css"; - -import locale from 'antd/lib/date-picker/locale/zh_CN'; - -import moment from 'moment'; - -import axios from 'axios'; +import { + Button, + Tabs, + Modal +} from 'antd'; import './css/TPMsettings.css'; -import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder'; - -let origin = getUrl(); +import TopShixuninformation from './Shixuninformation'; -let path = getUrl("/editormd/lib/") +import Configuration from './Configuration'; -const $ = window.$; +import LearningSettings from './LearningSettings'; -let timeout; - -let currentValue; +import axios from 'axios'; -const Option = Select.Option; +const {TabPane} = Tabs; -const RadioGroup = Radio.Group; -const confirm = Modal.confirm; // 处理整点 半点 -// 取传入时间往后的第一个半点 -export function handleDateStrings(dateString) { - if (!dateString) return dateString; - const ar = dateString.split(':') - if (ar[1] == '00' || ar[1] == '30') { - return dateString - } - const miniute = parseInt(ar[1]); - if (miniute < 30 || miniute == 60) { - return [ar[0], '30'].join(':') - } - if (miniute < 60) { - // 加一个小时 - const tempStr = [ar[0], '00'].join(':'); - const format = "YYYY-MM-DD HH:mm"; - const _moment = moment(tempStr, format) - _moment.add(1, 'hours') - return _moment.format(format) - } - - return dateString -} - -// 恢复数据 -function md_rec_data(k,mdu,id, editor){ - if(window.sessionStorage.getItem(k+mdu) !== null){ - editor.setValue(window.sessionStorage.getItem(k+mdu)); - md_clear_data(k,mdu,id); - } -} - -// 保存数据 -function md_add_data(k,mdu,d){ - window.sessionStorage.setItem(k+mdu,d); -} - -// 清空保存的数据 -function md_clear_data(k,mdu,id){ - window.sessionStorage.removeItem(k+mdu); - var id1 = "#e_tip_"+id; - var id2 = "#e_tips_"+id; - if(k == 'content'){ - $(id2).html(""); - }else{ - $(id1).html(""); - } -} - -function md_elocalStorage(editor,mdu,id){ - if (window.sessionStorage){ - var oc = window.sessionStorage.getItem('content'+mdu); - if(oc !== null ){ - $("#e_tips_"+id).data('editor', editor); - var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; - $("#e_tips_"+id).html(h); - } - setInterval(function() { - var d = new Date(); - var h = d.getHours(); - var m = d.getMinutes(); - var s = d.getSeconds(); - h = h < 10 ? '0' + h : h; - m = m < 10 ? '0' + m : m; - s = s < 10 ? '0' + s : s; - if(editor.getValue().trim() != ""){ - md_add_data("content",mdu,editor.getValue()); - var id1 = "#e_tip_"+id; - var id2 = "#e_tips_"+id; - - $(id1).html(" 数据已于 " + h + ':' + m + ':' + s +" 保存 "); - $(id2).html(""); - } - },10000); - - }else{ - $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); - } -} - -function create_editorMD(id, width, high, placeholder, imageUrl,initValue, callback) { - var editorName = window.editormd(id, { - width: width, - height: high, - path: path, // "/editormd/lib/" - markdown : initValue, - syncScrolling: "single", - tex: true, - tocm: true, - emoji: true, - taskList: true, - codeFold: true, - searchReplace: true, - htmlDecode: "style,script,iframe", - sequenceDiagram: true, - autoFocus: false, - placeholder: placeholder, - toolbarIcons: function () { - // Or return editormd.toolbarModes[name]; // full, simple, mini - // Using "||" set icons align right. - return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] - }, - toolbarCustomIcons: { - testIcon: "
    ", - testIcon1: "
    " - }, - //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 - saveHTMLToTextarea: true, - // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 - dialogMaskOpacity: 0.6, - imageUpload: true, - imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], - imageUploadURL: imageUrl,//url - onload: function () { - // this.previewing(); - $("#" + id + " [type=\"latex\"]").bind("click", function () { - editorName.cm.replaceSelection("```latex"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("```"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line - 1, 0); - }); - - $("#" + id + " [type=\"inline\"]").bind("click", function () { - editorName.cm.replaceSelection("`$$$$`"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); - editorName.cm.focus(); - }); - $("[type=\"inline\"]").attr("title", "行内公式"); - $("[type=\"latex\"]").attr("title", "多行公式"); - callback && callback() - } - }); - return editorName; -} - - -function updatamakedown(id){ - setTimeout(()=>{ - var shixunDescr = window.editormd.markdownToHTML(id, { - htmlDecode: "style,script,iframe", - taskList: true, - tex: true, - flowChart: true, - sequenceDiagram: true - }); - $("#"+id+" p:first").addClass("ReactMarkdown"); - $('#collaborators_list_info').show() - }, 200) -} - -function range(start, end) { - const result = []; - for (let i = start; i < end; i++) { - result.push(i); - } - return result; -} -function disabledDateTime() { - return { - // disabledHours: () => range(0, 24).splice(4, 20), - disabledMinutes: () => range(1, 30).concat(range(31, 60)), - // disabledSeconds: () => [0, 60], - }; -} -function disabledDate(current) { - return current && current < moment().endOf('day').subtract(1, 'days'); -} export default class TPMsettings extends Component { constructor(props) { super(props) this.state = { - fileList: [], - commandLine: 0, - Openpublic: 0, - settingsData: undefined, - webssh: 0, - use_scope: 0, - shixunsstatus: 0, - shixunsID: undefined, - exec_time: undefined, - trainee: undefined, - can_copy: undefined, - task_pass: undefined, - test_set_permission: undefined, - code_edit_permission: undefined, - hide_code: undefined, - code_hidden: undefined, - forbid_copy: undefined, - vnc: undefined, - name: undefined, - scope_partment: undefined, - scopetype: false, - departmentslist: undefined, - description: '', - evaluate_script:undefined, - standard_scripts: undefined, - choice_main_type: "", - choice_small_type: [], - choice_standard_scripts:undefined, - editordescriptios: undefined, - editorevaluate_scripts: undefined, - choice_standard_scriptssum: undefined, - visibleTemplate: false, - Executiveordervalue: "", - Compilecommandvalue: "", - Executivetyoe: false, - postapplyvisible: false, - sendsure_applyvalue: undefined, - postapplytitle: false, - shixunnametype: false, - shixunmaintype: false, - evaluate_scripttype: false, - exec_timetype: false, - traineetype: false, - standard_scriptsModal:false, - standard_scriptsModals:false, - SelectTheCommandtype:false, - multi_webssh:false, - status:0, - opers:false, - operss:false, - testscripttiptype:false, - opersss:false, - operateshixunstype:false, - opening_time:"", - opensmail:false, - scope_partmenttype:false, - newuse_scope:undefined, - scope_partments:0, - shixun_service_configs:undefined, - shixun_service_configlist:undefined, - pod_exist_time: undefined, - pod_exist_timetype: false, - shixunmemoMDvalue:"", - language:"", - deleteisnot:true + activeKeys:"1" } } - descriptionMD=(initValue, id)=> { - - this.contentChanged = false; - const placeholder = ""; -// amp; -// 编辑时要传memoId - const imageUrl = `/api/attachments.json`; -// 创建editorMd - - const description_editormd =create_editorMD(id, '100%', 400, placeholder, imageUrl, initValue,()=> { - setTimeout(() => { - description_editormd.resize() - description_editormd.cm && description_editormd.cm.refresh() - }, 500) - - if (initValue != undefined) { - description_editormd.setValue(initValue) - } - description_editormd.cm.on("change", (_cm, changeObj) => { - console.log('....contentChanged') - this.contentChanged = true; - }) - }); - md_elocalStorage(description_editormd, `MemoQuestion_${id}`, `${id}Question`); - this.description_editormd = description_editormd; - window.description_editormd = description_editormd; - } - - evaluate_scriptMD=(initValue, id)=> { - this.contentChanged = false; - const placeholder = ""; -// amp; -// 编辑时要传memoId - const imageUrl = `/api/attachments.json`; -// 创建editorMd - - const evaluate_script_editormd =create_editorMD(id, '100%', 400, placeholder, imageUrl, initValue,()=> { - setTimeout(() => { - evaluate_script_editormd.resize() - evaluate_script_editormd.cm && evaluate_script_editormd.cm.refresh() - }, 500) - - if (initValue != undefined) { - evaluate_script_editormd.setValue(initValue) - } - evaluate_script_editormd.cm.on("change", (_cm, changeObj) => { - console.log('....contentChanged') - this.contentChanged = true; - }) - }); - md_elocalStorage(evaluate_script_editormd, `MemoQuestion_${id}`, `${id}Question`); - this.evaluate_script_editormd = evaluate_script_editormd; - window.evaluate_script_editormd = evaluate_script_editormd; - - } - componentDidMount() { + this.getdatas("1") + } - let id=this.props.match.params.shixunId; - - let Url=`/shixuns/`+id+`/settings.json`; + getdatas = (key) => { - axios.get(Url).then((response)=> { + let id = this.props.match.params.shixunId; + let Url = `/shixuns/` + id + `/settings.json`; + axios.get(Url).then((response) => { // alert(response.data.shixun.choice_standard_scripts) - if(response.status===200){ - this.setState({ - shixunsID: id, - settingsData: response.data, - webssh: response.data.shixun.webssh, - use_scope: response.data.shixun.use_scope, - shixunsstatus: response.data.shixun.status, - exec_time: response.data.shixun.exec_time, - trainee: response.data.shixun.trainee, - can_copy: response.data.shixun.can_copy, - task_pass: response.data.shixun.task_pass, - test_set_permission: response.data.shixun.test_set_permission, - hide_code: response.data.shixun.hide_code, - code_edit_permission: response.data.shixun.code_edit_permission, - code_hidden: response.data.shixun.code_hidden, - is_secret_repository: response.data.shixun.is_secret_repository, - init_is_secret_repository: response.data.shixun.is_secret_repository, - forbid_copy: response.data.shixun.forbid_copy, - vnc: response.data.shixun.vnc, - vnc_evaluate: response.data.shixun.vnc_evaluate, - name: response.data.shixun.name, - scope_partment: response.data.shixun.scope_partment, - description: response.data.shixun.description, - evaluate_script: response.data.shixun.evaluate_script, - choice_main_type: response.data.shixun.choice_main_type, - choice_small_type: response.data.shixun.choice_small_type, - choice_standard_scripts: response.data.shixun.choice_standard_scripts, - standard_scripts:response.data.shixun.standard_scripts, - multi_webssh:response.data.shixun.multi_webssh, - status:response.data.shixun.status, - opening_time:response.data.shixun.opening_time, - newuse_scope:response.data.shixun.use_scope, - scope_partments: response.data.shixun.scope_partment.length, - shixunmemoMDvalue:response.data.shixun.evaluate_script, - shixun_service_configs:response.data.shixun.shixun_service_configs, - shixun_service_configlist:response.data.shixun.shixun_service_configs, - }) - - // if(response.data.status===403){ - // message: "您没有权限进行该操作" - // this.setState({ - // :true - // message403:response.data.message - // }) - // } - - - if(response.data.shixun.multi_webssh===true){ - this.setState({ - SelectTheCommandtype:true - }) - }else{ - this.setState({ - SelectTheCommandtype:false - }) - } - if (response.data.shixun.scope_partment.length > 0) { - this.setState({ - scopetype: true - }) - } - // console.log(response.data.shixun.description) - // console.log(response.data.shixun.evaluate_script) - // console.log(response.data.shixun.description) - // this.props.identity<4&&this.props.status==0||this.props.identity===1&&this.props.status==2 - - - // this.evaluate_scriptMD(response.data.shixun.evaluate_script, "shixunmemoMD"); - - this.descriptionMD(response.data.shixun.description, "shixundescription"); - - // this.bigClass() - // if (response.data.shixun.status === 2) { - // - // } else if (response.data.shixun.status === 1) { - // this.props.showSnackbar("这个实训已发布不能修改!"); - // } else if (response.data.shixun.status === 3) { - // this.props.showSnackbar("这个实训已关闭不能修改!"); - // } - } - - }); - - - 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) - }); - - - - } - - SelectshixunCommand=(e)=>{ - // console.log( e.target.value) - const webssh = e.target.value - if (webssh == 2) { - this.setState({ - webssh: webssh, - SelectTheCommandtype: true, - multi_webssh:false - }); - } else { - if (this.state.init_is_secret_repository && !this.state.vnc && this.state.is_secret_repository == true) { - this.confirmDeleteSecretRepo({ - onOk: () => { - this.setState({ - webssh: webssh, - SelectTheCommandtype: false, - multi_webssh:false - }); - } - }) - } else { - if (!this.state.vnc) { - this.setState({ - is_secret_repository: false, - }) - } - this.setState({ - webssh: webssh, - SelectTheCommandtype: false, - multi_webssh:false - }); - } - } - - // this.setState({ - // webssh: webssh, - // }); - // if(webssh===2){ - // this.setState({ - // SelectTheCommandtype: true, - // multi_webssh:false - // }); - // }else{ - // this.setState({ - // SelectTheCommandtype: false, - // multi_webssh:false - // }); - // } - } - - SelectOpenpublic=(e)=>{ - this.setState({ - Openpublic: e.target.value - }); - } - - can_copy=(e)=>{ - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - can_copy: sum, - }); - - } - - task_pass=(e)=>{ - - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - task_pass: sum, - }); - } - - test_set_permission=(e)=>{ - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - test_set_permission: sum, - }); - - } - - hide_code=(e)=>{ - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - hide_code: sum, - }); - - } - code_edit_permission = (e) => { - this.setState({ - code_edit_permission: e.target.checked - }) - } - code_hidden=(e)=>{ - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - code_hidden: sum, - }); - - } - confirmDeleteSecretRepo = ({title, onOk}) => { - confirm({ - title: title ||
    -
    已创建的私密版本库及其内容,将在“保存”时被删除。
    -
    是否确认取消勾选?
    -
    , - okText: '确定', - cancelText: '取消', - onOk: () => { - this.setState({ is_secret_repository: false }) - onOk && onOk() - }, - onCancel() { - }, - }); - } - is_secret_repository = (e) => { - const checked = e.target.checked - if (!checked) { - if (this.state.init_is_secret_repository) { - this.confirmDeleteSecretRepo({ - }) - } else { - this.setState({ is_secret_repository: false }) - } - } else { - this.setState({ is_secret_repository: true }) - } - } - forbid_copy = (e) => { - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - forbid_copy: sum, - }); - } - shixun_vnc_evaluate=(e) => { - this.setState({ - vnc_evaluate: e.target.checked, - }); - - } - - shixun_vnc=(e)=>{ - // let sum = "" - // if (e.target.checked === false) { - // sum = 0 - // } else if (e.target.checked === true) { - // sum = 1 - // } - const vnc = e.target.checked; - if (!vnc) { - if (this.state.init_is_secret_repository && this.state.webssh != 2 && this.state.is_secret_repository == true) { - this.confirmDeleteSecretRepo({ - onOk: () => { - this.setState({ - vnc: e.target.checked, - vnc_evaluate: false, - }); - } - }) - } else { - if (this.state.webssh != 2) { - this.setState({ - is_secret_repository: false - }) - } - this.setState({ - vnc: e.target.checked, - vnc_evaluate: false, - }); - } - } else { - this.setState({ - vnc: e.target.checked, - vnc_evaluate: false, - }); - } - } - shixunsname = (e) => { - // let {shixunsstatus}=this.state; - // if(shixunsstatus>0){ - // return - // } - this.setState({ - name: e.target.value, - shixunnametype:false - }) - } - - bigClass = (value) => { - // choice_main_type - // choice_small_type - let {settingsData,shixun_service_configs,choice_main_type,choice_small_type}=this.state; - - let list=[] - list.push(choice_main_type) - choice_small_type.map((item,key)=>{ - list.push(item) - }) - - let newshixun_service_configs=shixun_service_configs; - - let newshixun_service_configsagin=[] - - newshixun_service_configs.map((item,key)=>{ - list.map((its,index)=>{ - if(item.mirror_repository_id===its){ - newshixun_service_configsagin.push(item) - } - }) - }) - + if(response.data){ + if (response.data.shixun&&response.data.shixun.scope_partment.length > 0) { + this.setState({ + scopetype: true + }) + } + } - settingsData.shixun.main_type.some((item,key)=> { - if (item.id === value) { - newshixun_service_configsagin[0]={ - mirror_repository_id:value, - name:item.type_name, - cpu_limit:1, - lower_cpu_limit:0.1, - memory_limit:1024, - request_limit:10 - } - return true - } - } - ) - let url = `/shixuns/get_mirror_script.json?mirror_id=`+value; - axios.get(url).then((response) => { - if (response.status === 200) { - // console.log(response.data) this.setState({ - choice_main_type: value, - standard_scripts:response.data, - choice_standard_scripts:null, - shixun_service_configs:newshixun_service_configsagin, - shixun_service_configlist:newshixun_service_configsagin, + data: response.data }) } - }).catch((error) => { - console.log(error) - }); - - - } - Deselectlittle=(value)=>{ - - 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) => { - - let {settingsData,shixun_service_configs,choice_small_type,choice_main_type}=this.state; - let newshixun_service_configs=shixun_service_configs; - let newchoice_small_type=choice_small_type; - // if(Array.isArray(value)===true){ - // value.map((item,key)=>{ - // settingsData.shixun.small_type.some((items,keys)=> { - // if (items.id === item) { - // newshixun_service_configs.push({ - // mirror_repository_id:value, - // name:items.type_name, - // cpu_limit:1, - // lower_cpu_limit:0.1, - // memory_limit:1024, - // request_limit:10 - // }) - // return true - // } - // } - // ) - // }) - // } - - let list=[] - list.push(choice_main_type) - choice_small_type.map((item,key)=>{ - list.push(item) - }) - - let newshixun_service_configsagin=[] - - newshixun_service_configs.map((item,key)=>{ - list.map((its,index)=>{ - if(item.mirror_repository_id===its){ - newshixun_service_configsagin.push(item) - } - }) - }) - - settingsData.shixun.small_type.some((items,keys)=> { - if (items.id === value) { - newshixun_service_configsagin.push({ - mirror_repository_id:value, - name:items.type_name, - cpu_limit:1, - lower_cpu_limit:0.1, - memory_limit:1024, - request_limit:10 - }) - return true - } - } - ) - - newchoice_small_type.push(value) - - this.setState({ - choice_small_type: newchoice_small_type, - shixun_service_configs:newshixun_service_configsagin, - shixun_service_configlist:newshixun_service_configsagin, - }) - } - onPodExistTimeChange = (e) => { - this.setState({ - pod_exist_time: e.target.value, - pod_exist_timetype: false, - }) - } - Timevalue = (e) => { - this.setState({ - exec_time: e.target.value - }) - } - SelectOpenpublic = (e) => { - this.setState({ - scopetype: false, - use_scope: e.target.value, }); - if (e.target.value === 1) { - this.setState({ - scopetype: true - }); - } - } - deleteScopeInput = (key) => { - let {scope_partment} = this.state; - let datalist = scope_partment; - datalist.splice(key, 1); - this.setState({ - scope_partment: datalist - }); - } - - shixunScopeInput = (e) => { - let {scope_partment} = this.state; - let datalist = scope_partment; - if (datalist===undefined) { - datalist=[] - } - - datalist.push(e) - // else { - // datalist[id] = e - // } - this.setState({ - scope_partment: datalist - }); - } - // adduse_scopeinput = () => { - // let {scope_partment} = this.state; - // let array = scope_partment; - // let newarray = "" - // array.push(newarray) - // this.setState({ - // scope_partment: array, - // }); - // } - submit_edit_shixun = () => { - if (this.saving == true) return; - this.saving = true; - if(this.state.status===-1){ - this.props.showSnackbar("该实训已被删除,保存失败!"); - return - } - - let { - name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate, - evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh, - opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository, code_edit_permission - } = this.state; - - let newshixun_service_configlist = shixun_service_configlist.map(v => { - let v1 = Object.assign({},v); - delete v1.name; - return v1 - }); - - // let operateauthority= - // this.props.identity===1?true:this.props.identity<5&&this.state.status==0?true:false; - // this.props.identity<5&&this.state.status==0||this.props.identity===1&&this.state.status==2||this.props.identity===1&&this.state.status==1; - - const description_editormd = this.description_editormd.getValue(); - - let evaluate_script_editormd; - - if(this.state.status==0||this.state.status==1||this.state.status==2&&this.props.identity===1){ - // evaluate_script_editormd = this.evaluate_script_editormd.getValue(); - evaluate_script_editormd = shixunmemoMDvalue + if(key==="3"&&this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter === true){ + this.props.history.replace(`/shixuns/${this.props.match.params.shixunId}/challenges`); }else{ - evaluate_script_editormd = evaluate_script; - } - - - - if (name === "") { - this.setState({ - shixunnametype: true - }) - $('html').animate({ - scrollTop: 10 - }, 1000); - return - } - if (choice_main_type === "") { - this.setState({ - shixunmaintype: true - }) - $('html').animate({ - scrollTop: 800 - }, 1000); - return - } - if (evaluate_script_editormd === "") { - this.setState({ - evaluate_scripttype: true - }) - $('html').animate({ - scrollTop: 1200 - }, 1000); - return - } - if(use_scope===1){ - - if(scope_partment===undefined||scope_partment.length===0){ + if(key){ this.setState({ - scope_partmenttype: true + activeKeys:key }) - $('html').animate({ - scrollTop: 2500 - }, 1000); - this.props.showSnackbar("公开程度,指定单位为空"); - return + }else{ + this.props.history.replace(`/shixuns/${this.props.match.params.shixunId}/challenges`); } - } - // if (exec_time === "") { - // this.setState({ - // exec_timetype: true - // }) - // $('html').animate({ - // scrollTop: 1500 - // }, 1000); - // return - // } - // if (!pod_exist_time) { - // this.setState({ - // pod_exist_timetype: true - // }) - // $("html, body").animate({ scrollTop: $('#pod_exist_time').offset().top - 100 }, 1000) - // return - // } - - if (trainee === "") { - this.setState({ - traineetype: true - }) - return } - let id = this.props.match.params.shixunId; - - let newmulti_webssh=multi_webssh; - - - if(newmulti_webssh===null){ - newmulti_webssh=false - } - - //exec_time: exec_time, - let Url = `/shixuns/` + id + `.json`; - let data = { - shixun:{ - - name: name, - webssh: webssh, - use_scope: use_scope, - can_copy: can_copy, - vnc: vnc===null?undefined:vnc, - vnc_evaluate: vnc_evaluate===null?undefined:vnc_evaluate, - test_set_permission: test_set_permission, - code_hidden: code_hidden, - code_edit_permission: code_edit_permission, - trainee: trainee, - task_pass: task_pass, - hide_code: hide_code, - forbid_copy: forbid_copy, - multi_webssh:newmulti_webssh, - opening_time:opening_time, - mirror_script_id:choice_standard_scriptssum===undefined?choice_standard_scripts:choice_standard_scriptssum, - }, - shixun_info:{ - description: description_editormd, - evaluate_script: evaluate_script_editormd, - }, - is_secret_repository: is_secret_repository, - main_type: choice_main_type, - small_type: choice_small_type, - scope_partment: scope_partment, - shixun_service_configs:newshixun_service_configlist - } - - axios.put(Url, data).then((response) => { - // console.log(response) - this.saving = false; - if(response.status){ - if (response.data.status === -1) { - this.props.showSnackbar(response.data.message); - return - } else { - window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; - } - } + } - }).catch((error) => { - console.log(error) - this.saving = false; + operateshixuns = (value) => { + this.setState({ + operateshixunstype: true, + delType: value }) - - } - 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})); + hideoperateshixuns = () => { + this.setState({ + operateshixunstype: false + }) } - - - shixunsclose = () => { + shixunsdel = () => { let id = this.props.match.params.shixunId; - let cul = `/shixuns/` + id + `/close.json`; - axios.post(cul).then((response) => { - if(response.data.status===1){ + 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/" + id + "/challenges"; + window.location.href = "/shixuns"; + // this.props.history.replace( "/shixuns/"); } }).catch((error) => { console.log(error) }) } - shixunsdel= () => { + shixunsclose = () => { let id = this.props.match.params.shixunId; - let cul = `/shixuns/` + id +`.json`; - - axios.delete(cul).then((response) => { - if(response.data.status===1){ + 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"; - } - }).catch((error) => { - console.log(error) - }) - } - - Executiveorder = (e) => { - this.setState({ - Executiveordervalue: e.target.value - }) - } - - Compilecommand = (e) => { - this.setState({ - Compilecommandvalue: e.target.value - }) - } - - handleCancelTemplate = (e) => { - this.setState({ - Executiveordervalue: "", - Compilecommandvalue: "", - visibleTemplate: false - }) - } - - hideModalTemplate = (e) => { - let id = this.props.match.params.shixunId; - let {Executiveordervalue, Compilecommandvalue} = this.state; - - if (Executiveordervalue === "") { - 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 - }) - } - - showModal = () => { - this.setState({ - visibleTemplate: true, - }); - } - Selecttrainee = (value) => { - this.setState({ - trainee: value, - }); - } - - post_apply = () => { - this.setState({ - postapplyvisible: true - }) - } - - sendsure_applyvalues = (e) => { - this.setState({ - sendsure_applyvalue: e.target.value - }) - } - - setlanguagewrite = (e)=>{ - this.setState({ - languagewrite: e.target.value - }) - } - - setsystemenvironment = (e) => { - this.setState({ - systemenvironment: e.target.value - }) - } - - settestcoderunmode = (e) => { - this.setState({ - testcoderunmode: e.target.value - }) - - } - - sendsure_apply = () => { - let {languagewrite,systemenvironment,testcoderunmode} = this.state; - // console.log("点击确定") - // console.log("languagewrite"+languagewrite); - // console.log("systemenvironment"+systemenvironment); - // console.log("testcoderunmode"+testcoderunmode); - - // let attachment_ids = undefined - // if (this.state.fileList) { - // attachment_ids = this.state.fileList.map(item => { - // return item.response ? item.response.id : item.id - // }) - // } - if(languagewrite === undefined || languagewrite === "" ){ - // this.props.showNotification(`请填写该镜像是基于什么语言`); - this.setState({ - languagewritetype:true - }) - return - } - if(systemenvironment === undefined || systemenvironment === ""){ - // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`); - this.setState({ - systemenvironmenttype:true - }) - return; - - } - if(testcoderunmode === undefined || testcoderunmode === "") { - // this.props.showNotification(`请填写该镜像中测试代码运行方式`); - this.setState({ - testcoderunmodetype:true - }) - return; - } - var attachment_ids=undefined; - if (this.state.fileList) { - attachment_ids = this.state.fileList.map(item => { - return item.response ? item.response.id : item.id - }) - } - - if( attachment_ids === undefined || attachment_ids.length===0){ - - // notification.open( - // { - // message: '提示', - // description: - // '请上传附件!', - // - // } - // ) - this.setState({ - attachmentidstype:true - }) - return; - } - // console.log("attachment_ids"+attachment_ids); - - // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids); - - var data={ - language:languagewrite, - runtime:systemenvironment, - run_method:testcoderunmode, - attachment_id:attachment_ids[0], - } - var url =`/shixuns/apply_shixun_mirror.json`; - axios.post(url,data - ).then((response) => { - - try { - if (response.data) { - // const { id } = response.data; - // if (id) { - if(this.state.file !== undefined){ - console.log("549"); - // this.deleteAttachment(this.state.file); - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - }else { - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - } - // this.props.showNotification('提交成功!'); - notification.open( - { - message: '提示', - description: - '提交成功!', - - } - ) - this.sendhideModaly() - // this.props.history.push(`/courses/${cid}/graduation_topics`); - // } - } - }catch (e) { - - } - - }) - - } - - sendhideModaly = () => { - this.setState({ - postapplyvisible: false, - }) - if(this.state.file !== undefined){ - console.log("580"); - // this.deleteAttachment(this.state.file); - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - }else { - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - } - } - - yeshidemodel = () => { - this.setState({ - postapplytitle: false - }) - } - - SelectScput = (value, e) => { - this.setState({ - choice_standard_scriptssum: value, - language:e.props.name, - choice_standard_scripts: {id:e.props.value,value:""}, - standard_scriptsModal:true - }) - } - - hidestandard_scriptsModal=()=>{ - this.setState({ - standard_scriptsModal:false, - standard_scriptsModals:false - }) - } - - get_mirror_script=()=>{ - let {choice_standard_scriptssum}=this.state; - let id = this.props.match.params.shixunId; - let pul = "/shixuns/" + id + "/get_script_contents.json?script_id=" + choice_standard_scriptssum; - axios.get(pul).then((response) => { - if(response.status===200){ - // this.evaluate_scriptMD(response.data.content, "shixunmemoMD"); - this.setState({ - standard_scriptsModal:false, - standard_scriptsModals:true, - shixunmemoMDvalue:response.data.content - }) + window.location.href = "/shixuns/" + id + "/challenges"; + // this.props.history.replace( "/shixuns/" + id + "/challenges"); } - }).catch((error) => { console.log(error) }) } - - SelectTheCommandonChange=(e)=>{ + callback = (key) => { this.setState({ - multi_webssh:e.target.checked + activeKeys:key }) } - bigopen=()=>{ - this.setState({ - opers:true - }) - - } - - bigopens=()=>{ - this.setState({ - opers:false, - operss:false, - opersss:false, - opensmail:false - }) + render() { - } - bigopensmal=(e)=>{ - this.setState({ - opensmail:true - }) + let showtabs = this.props.shixunsDetails === undefined ? "" : this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter === true ? "" : "学习页面设置" - } - sbigopen=(e)=>{ - this.setState({ - operss:true - }) - - } - - sbigopens=()=>{ - this.setState({ - operss:false - }) - } - sbigopenss=(e)=>{ - this.setState({ - opersss:true - }) - - } - - sbigopensss=()=>{ - this.setState({ - opersss:false - }) - } - testscripttip=(val)=>{ - if(val===0){ - this.setState({ - testscripttiptype:true - }) - }else if(val===1){ - this.setState({ - testscripttiptype:false - }) - } - } - - operateshixuns=(value)=>{ - this.setState({ - operateshixunstype:true, - delType:value - }) - } - - hideoperateshixuns=()=>{ - this.setState({ - operateshixunstype:false - }) - } - onChangeTimePicker =(value, dateString)=> { - this.setState({ - opening_time: dateString=== ""?"":moment(handleDateStrings(dateString)) - }) - } - - getshixunmemoMDvalue=(value, e)=>{ - - this.setState({ - shixunmemoMDvalue: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, - }) - - } - - handleChange = (info) => { - 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:fileLists, - deleteisnot:false}); - // } - } - } - - onAttachmentRemove = (file) => { - if(!file.percent || file.percent == 100){ - 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); - }); - } - - - - render() { - let { - postapplyvisible, - postapplytitle, - shixunnametype, - shixunmaintype, - evaluate_scripttype, - traineetype, - standard_scripts, - name, - settingsData, - webssh, - is_secret_repository, - use_scope, - shixunsID, - can_copy, - choice_standard_scripts, - Executiveordervalue, - Executivetyoe, - Compilecommandvalue, - task_pass, - test_set_permission, - hide_code, - forbid_copy, - code_edit_permission, - code_hidden, - vnc, - vnc_evaluate, - scopetype, - scope_partment, - departmentslist, - trainee, - choice_main_type, - choice_small_type, - standard_scriptsModal, - standard_scriptsModals, - SelectTheCommandtype, - testscripttiptype, - operateshixunstype, - opening_time, - scope_partmenttype, - newuse_scope, - scope_partments, - shixunmemoMDvalue,delType, - shixun_service_configs, - fileList, - } = this.state; - - let options; - - if (departmentslist != undefined) { - options = this.state.departmentslist.map((d, k) => { - return ( - - ) - }) - } - const uploadProps = { - width: 600, - fileList, - multiple: true, - // https://github.com/ant-design/ant-design/issues/15505 - // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 - // showUploadList: false, - action: `${getUploadActionUrl()}`, - onChange: this.handleChange, - onRemove: this.onAttachmentRemove, - beforeUpload: (file, fileList) => { - if (this.state.fileList.length >= 1) { - return false - } - // console.log('beforeUpload', file.name); - const isLt150M = file.size / 1024 / 1024 < 50; - if (!isLt150M) { - // this.props.showNotification(`文件大小必须小于50MB`); - notification.open( - { - message: '提示', - description: - '文件大小必须小于50MB', - - } - ) - } - if(this.state.file !== undefined){ - console.log("763") - this.setState({ - file:file - }) - }else { - this.setState({ - file:file - }) - } - - console.log("handleChange2"); - return isLt150M; - }, - } - const dateFormat = 'YYYY-MM-DD HH:mm:ss'; - let operateauthority=this.props.identity===1?true:this.props.identity<5&&this.state.status==0?true:false; + // let a="isvnc"; + // let b="isVNC"; + // console.log(a.indexOf("vnc")) + // console.log(b.indexOf("vnc")) + // console.log( this.props.shixunsDetails === undefined ? "" : this.props.shixunsDetails.is_jupyter === false ? "学习页面设置" : "") return ( -
    - - 实训详情 - 配置 - - -
    -
    - 配置 - { - this.props.identity===1&&this.state.status==2? - this.operateshixuns(2)}> - 永久关闭 - :"" - } - { - this.props.identity < 5 && this.state.status==0? - this.operateshixuns(1)}> - 删除实训 - :"" - } - { - this.props.identity == 1 && this.state.status == 2 ? - this.operateshixuns(1)}> - 删除实训 - :"" - } - - -
    - {delType===1?

    是否确认删除 ?

    :

    关闭后,
    用户不能再开始挑战了是否确认关闭 ?

    } -
    -
    - 取消 - {delType===1?确定:确定} -
    -
    - -
    - -
    - -

    实训名称

    - -
    - * -
    -
    - {settingsData === undefined ? "" : - } -
    -
    - 必填项 -
    -
    - - -
    - -
    -
    - -
    - -

    简介

    - -
    - -
    -
    -
    -

    -

    -
    - -
    -
    -

    技术平台

    - - -
    - * -
    - -

    - 列表中没有? - 申请新建 -

    - - -
    -
  • - - -
  • -
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    -
  • - - -
  • -
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    -
  • - - - -
  • -
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    -
  • - -
    - - - 上传附件 - (单个文件50M以内) - -
    -
  • -
    - {this.state.attachmentidstype===true?"请上传附件":""} -
    -
  • - this.sendhideModaly()} - >取消 - -
  • -
    -
    - -
    - - - - - -
    -

    新建申请已提交,请等待管理员的审核

    -
  • 我们将在1-2个工作日内与您联系 -
  • -
    -
    - 知道啦 -
    -
    -
    -
    - -
    - -
    -
    - 必填项 -
    - {/*

    请在配置页面完成后续的评测脚本设置操作

    */} - -
    -
    - {/*
    */} - {/*
    */} -
    -

    评测脚本

    -
    - - -
    -

    原有脚本将被新的脚本覆盖,无法撤销

    -

    是否确认执行覆盖操作

    -
    - - -
    - - -

    评测脚本生成成功!

    - -
    - - { - this.props.identity<5||this.props.power==true? - 使用自定义脚本 : "" - } -
    - this.testscripttip(0)}> -
    - -
    -

    - 使用自定义模板,平台无法自动更新脚本,
    - 请在关卡创建完后手动更新脚本中的必填参
    - 数和以下2个数组元素:
    - challengeProgramNames
    - sourceClassNames

    - 示例:有2个关卡的实训

    - 各关卡的待编译文件为:
    - src/step1/HelloWorld.java
    - src/step2/Other.java

    - 各关卡的编译后生成的执行文件为:
    - step1.HelloWorld
    - step2.Other

    - 则数组元素更新如下:
    - challengeProgramNames=("src/step1/
    - HelloWorld.java" "src/step2/Other.java")
    - sourceClassNames=("step1.HelloWorld
    - " "step2.Other")

    - 其它参数可按实际需求定制 -

    -
    -

    - this.testscripttip(1)}>知道了 -

    -
    -
    - - -
    -
  • - - -

    执行命令不能为空

    -
  • - -
  • - - -
  • -
    -
    -
    -
    - -
    -
    - * -
    - - -
    - {/**/} - -
    - - - {/*
    */} - {/*{evaluate_script===undefined?"":evaluate_script}*/} - - {/*
    */} - - - -
    - -
    -
    -
    - - 必填项 -
    -

    -

    -
    -
    - - {/*
    */} - {/***/} - - {/*

    程序最大执行时间

    */} - - {/* 秒*/} - - {/*
    */} - {/*必填项*/} - {/*
    */} - {/*
    */} - - {/*
    - * - -

    Pod存活时间

    - - - -
    - 必填项 -
    -
    */} - - -
    -

    命令行

    - - 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) - 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) - 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) - - 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) - - -
    - -
    -

    公开程度

    - - 对所有公开 (选中则所有已被试用授权的用户可以学习) - 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) - - -
    -
    -
    -
    -
    - -
    - (搜索并选中添加单位名称) -
    - {/*+*/} - {/*添加*/} -
    - -
    - - {/*{*/} - {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/} - {/*return(*/} - {/*
    */} - {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/} - {/*value={item}*/} - {/*/>*/} - {/*
    */} - - {/*)*/} - {/*})*/} - {/*}*/} -
    - - - 请选择需要公开的单位 - -
    -
    -
    - -
    -

    发布信息

    - -
    - * - 面向学员: - -
    - -
    - 实训难易度定位,不限定用户群体 -
    - 必填项 -
    - -
    -
    - 复制: - - - - -
    - -
    - 跳关: - - - - -
    -
    - 测试集解锁: - - - - -
    - - {!code_hidden && !hide_code &&
    - 代码开放修改: - - - - -
    } - -
    - 隐藏代码窗口: - - - - -
    - -
    - 代码目录隐藏: - - - - -
    - - { (vnc || webssh == 2) &&
    - 私密版本库: - - - - -
    } - -
    - 禁用复制粘贴: - - - - -
    - -
    - 开启时间: - - - - -
    - - {this.props.identity<3?
    - VNC图形化: - - - - -
    :""} - {this.props.identity<3 && vnc ?
    - VNC图形化评测: - - - - -
    :""} - - - -
    - - {this.props.identity<3?
    -

    服务配置

    - { shixun_service_configs&&shixun_service_configs.map((item,key)=>{ - - return( -
    -
    -
    - {item.name} - {/*this.Deselectlittle(item.mirror_repository_id)}>*/} -
    -
    - -
    - this.setConfigsInputs(e,key,1)} - className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> -
    -
    -
    -
    - -
    - this.setConfigsInputs(e,key,2)} - className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> -
    -
    -
    -
    - -
    - this.setConfigsInputs(e,key,3)} - className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> -
    -
    -
    -
    - -
    - this.setConfigsInputs(e,key,4)} - className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> -
    - -
    -
    -
    -
    - ) - - })} -
    :""} - -

    - { - // this.props.identity<4&&this.props.status==0? - this.props.identity<5? -

    - 保存 - 取消 -
    :"" - } -

    +
    + + + + + { + this.props.identity < 5 && this.state.data && this.state.data.shixun.status == 0 ? + + : "" + } + { + this.props.identity == 1 && this.state.data && this.state.data.shixun.status == 2 ? + : "" + } + { + this.props.identity === 1 && this.state.data && this.state.data.shixun.status == 2 ? + : "" + } +
    + }> + + this.getdatas(key)} + /> + + + this.getdatas(key)} + /> + + {this.props.shixunsDetails === undefined ? "" : this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter === false ? + + this.getdatas(key)} + /> + :"" } + + +
    + {this.state.delType === 1 ?

    是否确认删除 ?

    : +

    关闭后,
    用户不能再开始挑战了是否确认关闭 ?

    } +
    +
    + 取消 + {this.state.delType === 1 ? 确定 : + 确定} +
    +
    +
    - ); } } diff --git a/public/react/src/modules/tpm/TPMsettings/css/TPMsettings.css b/public/react/src/modules/tpm/TPMsettings/css/TPMsettings.css index 8047bbde8..7abf2c70b 100644 --- a/public/react/src/modules/tpm/TPMsettings/css/TPMsettings.css +++ b/public/react/src/modules/tpm/TPMsettings/css/TPMsettings.css @@ -111,3 +111,43 @@ a.newuse_scope-btn { .ml82{ margin-left:82px; } + +.Permanentban{ + color:#5091FF !important; + border-color: #5091FF !important; +} + +/*tab*/ +.ant-tabs-nav{ + padding-bottom:18px; + padding-top: 18px; +} + +.ant-tabs-extra-content{ + margin-top: 18px; +} + +.pdb30{ + padding-bottom: 30px; +} + +.openrenyuan{ + margin-top: 5px !important; + display: inline-block; +} + +.ml81{ + margin-left:81px; +} + +.ml32s{ + margin-left: 32px; +} + +.ml64{ + margin-left: 64px; +} + +.ml160{ + margin-left: 160px; +} \ No newline at end of file diff --git a/public/react/src/modules/tpm/TPMsettings/oldTPMsettings.js b/public/react/src/modules/tpm/TPMsettings/oldTPMsettings.js new file mode 100644 index 000000000..8688e9669 --- /dev/null +++ b/public/react/src/modules/tpm/TPMsettings/oldTPMsettings.js @@ -0,0 +1,2437 @@ +import React, { Component } from 'react'; + +import MonacoEditor from 'react-monaco-editor'; + +//MonacoDiffEditor 对比模式 +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip} from 'antd'; + +// import "antd/dist/antd.css"; + +import locale from 'antd/lib/date-picker/locale/zh_CN'; + +import moment from 'moment'; + +import axios from 'axios'; + +import './css/TPMsettings.css'; + +import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder'; + +let origin = getUrl(); + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; +const confirm = Modal.confirm; +// 处理整点 半点 +// 取传入时间往后的第一个半点 +export function handleDateStrings(dateString) { + if (!dateString) return dateString; + const ar = dateString.split(':') + if (ar[1] == '00' || ar[1] == '30') { + return dateString + } + const miniute = parseInt(ar[1]); + if (miniute < 30 || miniute == 60) { + return [ar[0], '30'].join(':') + } + if (miniute < 60) { + // 加一个小时 + const tempStr = [ar[0], '00'].join(':'); + const format = "YYYY-MM-DD HH:mm"; + const _moment = moment(tempStr, format) + _moment.add(1, 'hours') + return _moment.format(format) + } + + return dateString +} + +// 恢复数据 +function md_rec_data(k,mdu,id, editor){ + if(window.sessionStorage.getItem(k+mdu) !== null){ + editor.setValue(window.sessionStorage.getItem(k+mdu)); + md_clear_data(k,mdu,id); + } +} + +// 保存数据 +function md_add_data(k,mdu,d){ + window.sessionStorage.setItem(k+mdu,d); +} + +// 清空保存的数据 +function md_clear_data(k,mdu,id){ + window.sessionStorage.removeItem(k+mdu); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + if(k == 'content'){ + $(id2).html(""); + }else{ + $(id1).html(""); + } +} + +function md_elocalStorage(editor,mdu,id){ + if (window.sessionStorage){ + var oc = window.sessionStorage.getItem('content'+mdu); + if(oc !== null ){ + $("#e_tips_"+id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_"+id).html(h); + } + setInterval(function() { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if(editor.getValue().trim() != ""){ + md_add_data("content",mdu,editor.getValue()); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + + $(id1).html(" 数据已于 " + h + ':' + m + ':' + s +" 保存 "); + $(id2).html(""); + } + },10000); + + }else{ + $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + +function create_editorMD(id, width, high, placeholder, imageUrl,initValue, callback) { + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + markdown : initValue, + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + placeholder: placeholder, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + callback && callback() + } + }); + return editorName; +} + + +function updatamakedown(id){ + setTimeout(()=>{ + var shixunDescr = window.editormd.markdownToHTML(id, { + htmlDecode: "style,script,iframe", + taskList: true, + tex: true, + flowChart: true, + sequenceDiagram: true + }); + $("#"+id+" p:first").addClass("ReactMarkdown"); + $('#collaborators_list_info').show() + }, 200) +} + +function range(start, end) { + const result = []; + for (let i = start; i < end; i++) { + result.push(i); + } + return result; +} +function disabledDateTime() { + return { + // disabledHours: () => range(0, 24).splice(4, 20), + disabledMinutes: () => range(1, 30).concat(range(31, 60)), + // disabledSeconds: () => [0, 60], + }; +} + +function disabledDate(current) { + return current && current < moment().endOf('day').subtract(1, 'days'); +} +export default class TPMsettings extends Component { + constructor(props) { + super(props) + this.state = { + fileList: [], + commandLine: 0, + Openpublic: 0, + settingsData: undefined, + webssh: 0, + use_scope: 0, + shixunsstatus: 0, + shixunsID: undefined, + exec_time: undefined, + trainee: undefined, + can_copy: undefined, + task_pass: undefined, + test_set_permission: undefined, + code_edit_permission: undefined, + hide_code: undefined, + code_hidden: undefined, + forbid_copy: undefined, + vnc: undefined, + name: undefined, + scope_partment: undefined, + scopetype: false, + departmentslist: undefined, + description: '', + evaluate_script:undefined, + standard_scripts: undefined, + choice_main_type: "", + choice_small_type: [], + choice_standard_scripts:undefined, + editordescriptios: undefined, + editorevaluate_scripts: undefined, + choice_standard_scriptssum: undefined, + visibleTemplate: false, + Executiveordervalue: "", + Compilecommandvalue: "", + Executivetyoe: false, + postapplyvisible: false, + sendsure_applyvalue: undefined, + postapplytitle: false, + shixunnametype: false, + shixunmaintype: false, + evaluate_scripttype: false, + exec_timetype: false, + traineetype: false, + standard_scriptsModal:false, + standard_scriptsModals:false, + SelectTheCommandtype:false, + multi_webssh:false, + status:0, + opers:false, + operss:false, + testscripttiptype:false, + opersss:false, + operateshixunstype:false, + opening_time:"", + opensmail:false, + scope_partmenttype:false, + newuse_scope:undefined, + scope_partments:0, + shixun_service_configs:undefined, + shixun_service_configlist:undefined, + pod_exist_time: undefined, + pod_exist_timetype: false, + shixunmemoMDvalue:"", + language:"", + deleteisnot:true + } + } + descriptionMD=(initValue, id)=> { + + this.contentChanged = false; + const placeholder = ""; +// amp; +// 编辑时要传memoId + const imageUrl = `/api/attachments.json`; +// 创建editorMd + + const description_editormd =create_editorMD(id, '100%', 400, placeholder, imageUrl, initValue,()=> { + setTimeout(() => { + description_editormd.resize() + description_editormd.cm && description_editormd.cm.refresh() + }, 500) + + if (initValue != undefined) { + description_editormd.setValue(initValue) + } + description_editormd.cm.on("change", (_cm, changeObj) => { + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + md_elocalStorage(description_editormd, `MemoQuestion_${id}`, `${id}Question`); + this.description_editormd = description_editormd; + window.description_editormd = description_editormd; + } + + evaluate_scriptMD=(initValue, id)=> { + this.contentChanged = false; + const placeholder = ""; +// amp; +// 编辑时要传memoId + const imageUrl = `/api/attachments.json`; +// 创建editorMd + + const evaluate_script_editormd =create_editorMD(id, '100%', 400, placeholder, imageUrl, initValue,()=> { + setTimeout(() => { + evaluate_script_editormd.resize() + evaluate_script_editormd.cm && evaluate_script_editormd.cm.refresh() + }, 500) + + if (initValue != undefined) { + evaluate_script_editormd.setValue(initValue) + } + evaluate_script_editormd.cm.on("change", (_cm, changeObj) => { + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + md_elocalStorage(evaluate_script_editormd, `MemoQuestion_${id}`, `${id}Question`); + this.evaluate_script_editormd = evaluate_script_editormd; + window.evaluate_script_editormd = evaluate_script_editormd; + + } + + + + componentDidMount() { + + let id=this.props.match.params.shixunId; + + let Url=`/shixuns/`+id+`/settings.json`; + + axios.get(Url).then((response)=> { + // alert(response.data.shixun.choice_standard_scripts) + if(response.status===200){ + this.setState({ + shixunsID: id, + settingsData: response.data, + webssh: response.data.shixun.webssh, + use_scope: response.data.shixun.use_scope, + shixunsstatus: response.data.shixun.status, + exec_time: response.data.shixun.exec_time, + trainee: response.data.shixun.trainee, + can_copy: response.data.shixun.can_copy, + task_pass: response.data.shixun.task_pass, + test_set_permission: response.data.shixun.test_set_permission, + hide_code: response.data.shixun.hide_code, + code_edit_permission: response.data.shixun.code_edit_permission, + code_hidden: response.data.shixun.code_hidden, + is_secret_repository: response.data.shixun.is_secret_repository, + init_is_secret_repository: response.data.shixun.is_secret_repository, + forbid_copy: response.data.shixun.forbid_copy, + vnc: response.data.shixun.vnc, + vnc_evaluate: response.data.shixun.vnc_evaluate, + name: response.data.shixun.name, + scope_partment: response.data.shixun.scope_partment, + description: response.data.shixun.description, + evaluate_script: response.data.shixun.evaluate_script, + choice_main_type: response.data.shixun.choice_main_type, + choice_small_type: response.data.shixun.choice_small_type, + choice_standard_scripts: response.data.shixun.choice_standard_scripts, + standard_scripts:response.data.shixun.standard_scripts, + multi_webssh:response.data.shixun.multi_webssh, + status:response.data.shixun.status, + opening_time:response.data.shixun.opening_time, + newuse_scope:response.data.shixun.use_scope, + scope_partments: response.data.shixun.scope_partment.length, + shixunmemoMDvalue:response.data.shixun.evaluate_script, + shixun_service_configs:response.data.shixun.shixun_service_configs, + shixun_service_configlist:response.data.shixun.shixun_service_configs, + }) + + // if(response.data.status===403){ + // message: "您没有权限进行该操作" + // this.setState({ + // :true + // message403:response.data.message + // }) + // } + + + if(response.data.shixun.multi_webssh===true){ + this.setState({ + SelectTheCommandtype:true + }) + }else{ + this.setState({ + SelectTheCommandtype:false + }) + } + if (response.data.shixun.scope_partment.length > 0) { + this.setState({ + scopetype: true + }) + } + // console.log(response.data.shixun.description) + // console.log(response.data.shixun.evaluate_script) + // console.log(response.data.shixun.description) + // this.props.identity<4&&this.props.status==0||this.props.identity===1&&this.props.status==2 + + + // this.evaluate_scriptMD(response.data.shixun.evaluate_script, "shixunmemoMD"); + + this.descriptionMD(response.data.shixun.description, "shixundescription"); + + // this.bigClass() + // if (response.data.shixun.status === 2) { + // + // } else if (response.data.shixun.status === 1) { + // this.props.showSnackbar("这个实训已发布不能修改!"); + // } else if (response.data.shixun.status === 3) { + // this.props.showSnackbar("这个实训已关闭不能修改!"); + // } + } + + }); + + + 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) + }); + + + + } + + SelectshixunCommand=(e)=>{ + // console.log( e.target.value) + const webssh = e.target.value + if (webssh == 2) { + this.setState({ + webssh: webssh, + SelectTheCommandtype: true, + multi_webssh:false + }); + } else { + if (this.state.init_is_secret_repository && !this.state.vnc && this.state.is_secret_repository == true) { + this.confirmDeleteSecretRepo({ + onOk: () => { + this.setState({ + webssh: webssh, + SelectTheCommandtype: false, + multi_webssh:false + }); + } + }) + } else { + if (!this.state.vnc) { + this.setState({ + is_secret_repository: false, + }) + } + this.setState({ + webssh: webssh, + SelectTheCommandtype: false, + multi_webssh:false + }); + } + } + + // this.setState({ + // webssh: webssh, + // }); + // if(webssh===2){ + // this.setState({ + // SelectTheCommandtype: true, + // multi_webssh:false + // }); + // }else{ + // this.setState({ + // SelectTheCommandtype: false, + // multi_webssh:false + // }); + // } + } + + SelectOpenpublic=(e)=>{ + this.setState({ + Openpublic: e.target.value + }); + } + + can_copy=(e)=>{ + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + can_copy: sum, + }); + + } + + task_pass=(e)=>{ + + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + task_pass: sum, + }); + } + + test_set_permission=(e)=>{ + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + test_set_permission: sum, + }); + + } + + hide_code=(e)=>{ + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + hide_code: sum, + }); + + } + code_edit_permission = (e) => { + this.setState({ + code_edit_permission: e.target.checked + }) + } + code_hidden=(e)=>{ + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + code_hidden: sum, + }); + + } + confirmDeleteSecretRepo = ({title, onOk}) => { + confirm({ + title: title ||
    +
    已创建的私密版本库及其内容,将在“保存”时被删除。
    +
    是否确认取消勾选?
    +
    , + okText: '确定', + cancelText: '取消', + onOk: () => { + this.setState({ is_secret_repository: false }) + onOk && onOk() + }, + onCancel() { + }, + }); + } + is_secret_repository = (e) => { + const checked = e.target.checked + if (!checked) { + if (this.state.init_is_secret_repository) { + this.confirmDeleteSecretRepo({ + }) + } else { + this.setState({ is_secret_repository: false }) + } + } else { + this.setState({ is_secret_repository: true }) + } + } + forbid_copy = (e) => { + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + forbid_copy: sum, + }); + } + shixun_vnc_evaluate=(e) => { + this.setState({ + vnc_evaluate: e.target.checked, + }); + + } + + shixun_vnc=(e)=>{ + // let sum = "" + // if (e.target.checked === false) { + // sum = 0 + // } else if (e.target.checked === true) { + // sum = 1 + // } + const vnc = e.target.checked; + if (!vnc) { + if (this.state.init_is_secret_repository && this.state.webssh != 2 && this.state.is_secret_repository == true) { + this.confirmDeleteSecretRepo({ + onOk: () => { + this.setState({ + vnc: e.target.checked, + vnc_evaluate: false, + }); + } + }) + } else { + if (this.state.webssh != 2) { + this.setState({ + is_secret_repository: false + }) + } + this.setState({ + vnc: e.target.checked, + vnc_evaluate: false, + }); + } + } else { + this.setState({ + vnc: e.target.checked, + vnc_evaluate: false, + }); + } + } + shixunsname = (e) => { + // let {shixunsstatus}=this.state; + // if(shixunsstatus>0){ + // return + // } + this.setState({ + name: e.target.value, + shixunnametype:false + }) + } + + bigClass = (value) => { + // choice_main_type + // choice_small_type + let {settingsData,shixun_service_configs,choice_main_type,choice_small_type}=this.state; + + let list=[] + list.push(choice_main_type) + choice_small_type.map((item,key)=>{ + list.push(item) + }) + + let newshixun_service_configs=shixun_service_configs; + + let newshixun_service_configsagin=[] + + newshixun_service_configs.map((item,key)=>{ + list.map((its,index)=>{ + if(item.mirror_repository_id===its){ + newshixun_service_configsagin.push(item) + } + }) + }) + + + settingsData.shixun.main_type.some((item,key)=> { + if (item.id === value) { + newshixun_service_configsagin[0]={ + mirror_repository_id:value, + name:item.type_name, + cpu_limit:1, + lower_cpu_limit:0.1, + memory_limit:1024, + request_limit:10 + } + return true + } + } + ) + let url = `/shixuns/get_mirror_script.json?mirror_id=`+value; + axios.get(url).then((response) => { + if (response.status === 200) { + // console.log(response.data) + this.setState({ + choice_main_type: value, + standard_scripts:response.data, + choice_standard_scripts:null, + shixun_service_configs:newshixun_service_configsagin, + shixun_service_configlist:newshixun_service_configsagin, + }) + } + }).catch((error) => { + console.log(error) + }); + + + + } + Deselectlittle=(value)=>{ + + 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) => { + + let {settingsData,shixun_service_configs,choice_small_type,choice_main_type}=this.state; + let newshixun_service_configs=shixun_service_configs; + let newchoice_small_type=choice_small_type; + // if(Array.isArray(value)===true){ + // value.map((item,key)=>{ + // settingsData.shixun.small_type.some((items,keys)=> { + // if (items.id === item) { + // newshixun_service_configs.push({ + // mirror_repository_id:value, + // name:items.type_name, + // cpu_limit:1, + // lower_cpu_limit:0.1, + // memory_limit:1024, + // request_limit:10 + // }) + // return true + // } + // } + // ) + // }) + // } + + let list=[] + list.push(choice_main_type) + choice_small_type.map((item,key)=>{ + list.push(item) + }) + + let newshixun_service_configsagin=[] + + newshixun_service_configs.map((item,key)=>{ + list.map((its,index)=>{ + if(item.mirror_repository_id===its){ + newshixun_service_configsagin.push(item) + } + }) + }) + + settingsData.shixun.small_type.some((items,keys)=> { + if (items.id === value) { + newshixun_service_configsagin.push({ + mirror_repository_id:value, + name:items.type_name, + cpu_limit:1, + lower_cpu_limit:0.1, + memory_limit:1024, + request_limit:10 + }) + return true + } + } + ) + + newchoice_small_type.push(value) + + this.setState({ + choice_small_type: newchoice_small_type, + shixun_service_configs:newshixun_service_configsagin, + shixun_service_configlist:newshixun_service_configsagin, + }) + } + onPodExistTimeChange = (e) => { + this.setState({ + pod_exist_time: e.target.value, + pod_exist_timetype: false, + }) + } + Timevalue = (e) => { + this.setState({ + exec_time: e.target.value + }) + } + SelectOpenpublic = (e) => { + this.setState({ + scopetype: false, + use_scope: e.target.value, + }); + if (e.target.value === 1) { + this.setState({ + scopetype: true + }); + } + + } + deleteScopeInput = (key) => { + let {scope_partment} = this.state; + let datalist = scope_partment; + datalist.splice(key, 1); + this.setState({ + scope_partment: datalist + }); + } + + shixunScopeInput = (e) => { + let {scope_partment} = this.state; + let datalist = scope_partment; + if (datalist===undefined) { + datalist=[] + } + + datalist.push(e) + // else { + // datalist[id] = e + // } + this.setState({ + scope_partment: datalist + }); + } + // adduse_scopeinput = () => { + // let {scope_partment} = this.state; + // let array = scope_partment; + // let newarray = "" + // array.push(newarray) + // this.setState({ + // scope_partment: array, + // }); + // } + submit_edit_shixun = () => { + if (this.saving == true) return; + this.saving = true; + if(this.state.status===-1){ + this.props.showSnackbar("该实训已被删除,保存失败!"); + return + } + + let { + name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate, + evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh, + opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository, code_edit_permission + } = this.state; + + let newshixun_service_configlist = shixun_service_configlist.map(v => { + let v1 = Object.assign({},v); + delete v1.name; + return v1 + }); + + // let operateauthority= + // this.props.identity===1?true:this.props.identity<5&&this.state.status==0?true:false; + // this.props.identity<5&&this.state.status==0||this.props.identity===1&&this.state.status==2||this.props.identity===1&&this.state.status==1; + + const description_editormd = this.description_editormd.getValue(); + + let evaluate_script_editormd; + + if(this.state.status==0||this.state.status==1||this.state.status==2&&this.props.identity===1){ + // evaluate_script_editormd = this.evaluate_script_editormd.getValue(); + evaluate_script_editormd = shixunmemoMDvalue + }else{ + evaluate_script_editormd = evaluate_script; + } + + + + if (name === "") { + this.setState({ + shixunnametype: true + }) + $('html').animate({ + scrollTop: 10 + }, 1000); + return + } + if (choice_main_type === "") { + this.setState({ + shixunmaintype: true + }) + $('html').animate({ + scrollTop: 800 + }, 1000); + return + } + if (evaluate_script_editormd === "") { + this.setState({ + evaluate_scripttype: true + }) + $('html').animate({ + scrollTop: 1200 + }, 1000); + return + } + if(use_scope===1){ + + if(scope_partment===undefined||scope_partment.length===0){ + this.setState({ + scope_partmenttype: true + }) + $('html').animate({ + scrollTop: 2500 + }, 1000); + this.props.showSnackbar("公开程度,指定单位为空"); + return + } + } + // if (exec_time === "") { + // this.setState({ + // exec_timetype: true + // }) + // $('html').animate({ + // scrollTop: 1500 + // }, 1000); + // return + // } + + // if (!pod_exist_time) { + // this.setState({ + // pod_exist_timetype: true + // }) + // $("html, body").animate({ scrollTop: $('#pod_exist_time').offset().top - 100 }, 1000) + // return + // } + + if (trainee === "") { + this.setState({ + traineetype: true + }) + return + } + + let id = this.props.match.params.shixunId; + + let newmulti_webssh=multi_webssh; + + + if(newmulti_webssh===null){ + newmulti_webssh=false + } + + //exec_time: exec_time, + let Url = `/shixuns/` + id + `.json`; + let data = { + shixun:{ + + name: name, + webssh: webssh, + use_scope: use_scope, + can_copy: can_copy, + vnc: vnc===null?undefined:vnc, + vnc_evaluate: vnc_evaluate===null?undefined:vnc_evaluate, + test_set_permission: test_set_permission, + code_hidden: code_hidden, + code_edit_permission: code_edit_permission, + trainee: trainee, + task_pass: task_pass, + hide_code: hide_code, + forbid_copy: forbid_copy, + multi_webssh:newmulti_webssh, + opening_time:opening_time, + mirror_script_id:choice_standard_scriptssum===undefined?choice_standard_scripts:choice_standard_scriptssum, + }, + shixun_info:{ + description: description_editormd, + evaluate_script: evaluate_script_editormd, + }, + is_secret_repository: is_secret_repository, + main_type: choice_main_type, + small_type: choice_small_type, + scope_partment: scope_partment, + shixun_service_configs:newshixun_service_configlist + } + + axios.put(Url, data).then((response) => { + // console.log(response) + this.saving = false; + if(response.status){ + if (response.data.status === -1) { + this.props.showSnackbar(response.data.message); + return + } else { + window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; + } + } + + }).catch((error) => { + console.log(error) + this.saving = false; + }) + + + } + 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})); + } + + + + + 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) + }) + } + + 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) + }) + } + + Executiveorder = (e) => { + this.setState({ + Executiveordervalue: e.target.value + }) + } + + Compilecommand = (e) => { + this.setState({ + Compilecommandvalue: e.target.value + }) + } + + handleCancelTemplate = (e) => { + this.setState({ + Executiveordervalue: "", + Compilecommandvalue: "", + visibleTemplate: false + }) + } + + hideModalTemplate = (e) => { + let id = this.props.match.params.shixunId; + let {Executiveordervalue, Compilecommandvalue} = this.state; + + if (Executiveordervalue === "") { + 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 + }) + } + + showModal = () => { + this.setState({ + visibleTemplate: true, + }); + } + Selecttrainee = (value) => { + this.setState({ + trainee: value, + }); + } + + post_apply = () => { + this.setState({ + postapplyvisible: true + }) + } + + sendsure_applyvalues = (e) => { + this.setState({ + sendsure_applyvalue: e.target.value + }) + } + + setlanguagewrite = (e)=>{ + this.setState({ + languagewrite: e.target.value + }) + } + + setsystemenvironment = (e) => { + this.setState({ + systemenvironment: e.target.value + }) + } + + settestcoderunmode = (e) => { + this.setState({ + testcoderunmode: e.target.value + }) + + } + + sendsure_apply = () => { + let {languagewrite,systemenvironment,testcoderunmode} = this.state; + // console.log("点击确定") + // console.log("languagewrite"+languagewrite); + // console.log("systemenvironment"+systemenvironment); + // console.log("testcoderunmode"+testcoderunmode); + + // let attachment_ids = undefined + // if (this.state.fileList) { + // attachment_ids = this.state.fileList.map(item => { + // return item.response ? item.response.id : item.id + // }) + // } + if(languagewrite === undefined || languagewrite === "" ){ + // this.props.showNotification(`请填写该镜像是基于什么语言`); + this.setState({ + languagewritetype:true + }) + return + } + if(systemenvironment === undefined || systemenvironment === ""){ + // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`); + this.setState({ + systemenvironmenttype:true + }) + return; + + } + if(testcoderunmode === undefined || testcoderunmode === "") { + // this.props.showNotification(`请填写该镜像中测试代码运行方式`); + this.setState({ + testcoderunmodetype:true + }) + return; + } + var attachment_ids=undefined; + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + + if( attachment_ids === undefined || attachment_ids.length===0){ + + // notification.open( + // { + // message: '提示', + // description: + // '请上传附件!', + // + // } + // ) + this.setState({ + attachmentidstype:true + }) + return; + } + // console.log("attachment_ids"+attachment_ids); + + // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids); + + var data={ + language:languagewrite, + runtime:systemenvironment, + run_method:testcoderunmode, + attachment_id:attachment_ids[0], + } + var url =`/shixuns/apply_shixun_mirror.json`; + axios.post(url,data + ).then((response) => { + + try { + if (response.data) { + // const { id } = response.data; + // if (id) { + if(this.state.file !== undefined){ + console.log("549"); + // this.deleteAttachment(this.state.file); + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + }else { + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + } + // this.props.showNotification('提交成功!'); + notification.open( + { + message: '提示', + description: + '提交成功!', + + } + ) + this.sendhideModaly() + // this.props.history.push(`/courses/${cid}/graduation_topics`); + // } + } + }catch (e) { + + } + + }) + + } + + sendhideModaly = () => { + this.setState({ + postapplyvisible: false, + }) + if(this.state.file !== undefined){ + console.log("580"); + // this.deleteAttachment(this.state.file); + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + }else { + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + } + } + + yeshidemodel = () => { + this.setState({ + postapplytitle: false + }) + } + + SelectScput = (value, e) => { + this.setState({ + choice_standard_scriptssum: value, + language:e.props.name, + choice_standard_scripts: {id:e.props.value,value:""}, + standard_scriptsModal:true + }) + } + + hidestandard_scriptsModal=()=>{ + this.setState({ + standard_scriptsModal:false, + standard_scriptsModals:false + }) + } + + get_mirror_script=()=>{ + let {choice_standard_scriptssum}=this.state; + let id = this.props.match.params.shixunId; + let pul = "/shixuns/" + id + "/get_script_contents.json?script_id=" + choice_standard_scriptssum; + axios.get(pul).then((response) => { + if(response.status===200){ + // this.evaluate_scriptMD(response.data.content, "shixunmemoMD"); + this.setState({ + standard_scriptsModal:false, + standard_scriptsModals:true, + shixunmemoMDvalue:response.data.content + }) + } + + }).catch((error) => { + console.log(error) + }) + } + + + SelectTheCommandonChange=(e)=>{ + this.setState({ + multi_webssh:e.target.checked + }) + } + + bigopen=()=>{ + this.setState({ + opers:true + }) + + } + + bigopens=()=>{ + this.setState({ + opers:false, + operss:false, + opersss:false, + opensmail:false + }) + + } + bigopensmal=(e)=>{ + this.setState({ + opensmail:true + }) + + } + sbigopen=(e)=>{ + this.setState({ + operss:true + }) + + } + + sbigopens=()=>{ + this.setState({ + operss:false + }) + } + sbigopenss=(e)=>{ + this.setState({ + opersss:true + }) + + } + + sbigopensss=()=>{ + this.setState({ + opersss:false + }) + } + testscripttip=(val)=>{ + if(val===0){ + this.setState({ + testscripttiptype:true + }) + }else if(val===1){ + this.setState({ + testscripttiptype:false + }) + } + } + + operateshixuns=(value)=>{ + this.setState({ + operateshixunstype:true, + delType:value + }) + } + + hideoperateshixuns=()=>{ + this.setState({ + operateshixunstype:false + }) + } + onChangeTimePicker =(value, dateString)=> { + this.setState({ + opening_time: dateString=== ""?"":moment(handleDateStrings(dateString)) + }) + } + + getshixunmemoMDvalue=(value, e)=>{ + + this.setState({ + shixunmemoMDvalue: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, + }) + + } + + handleChange = (info) => { + 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:fileLists, + deleteisnot:false}); + // } + } + } + + onAttachmentRemove = (file) => { + if(!file.percent || file.percent == 100){ + 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); + }); + } + + + + render() { + let { + postapplyvisible, + postapplytitle, + shixunnametype, + shixunmaintype, + evaluate_scripttype, + traineetype, + standard_scripts, + name, + settingsData, + webssh, + is_secret_repository, + use_scope, + shixunsID, + can_copy, + choice_standard_scripts, + Executiveordervalue, + Executivetyoe, + Compilecommandvalue, + task_pass, + test_set_permission, + hide_code, + forbid_copy, + code_edit_permission, + code_hidden, + vnc, + vnc_evaluate, + scopetype, + scope_partment, + departmentslist, + trainee, + choice_main_type, + choice_small_type, + standard_scriptsModal, + standard_scriptsModals, + SelectTheCommandtype, + testscripttiptype, + operateshixunstype, + opening_time, + scope_partmenttype, + newuse_scope, + scope_partments, + shixunmemoMDvalue,delType, + shixun_service_configs, + fileList, + } = this.state; + + let options; + + if (departmentslist != undefined) { + options = this.state.departmentslist.map((d, k) => { + return ( + + ) + }) + } + const uploadProps = { + width: 600, + fileList, + multiple: true, + // https://github.com/ant-design/ant-design/issues/15505 + // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // showUploadList: false, + action: `${getUploadActionUrl()}`, + onChange: this.handleChange, + onRemove: this.onAttachmentRemove, + beforeUpload: (file, fileList) => { + if (this.state.fileList.length >= 1) { + return false + } + // console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 50; + if (!isLt150M) { + // this.props.showNotification(`文件大小必须小于50MB`); + notification.open( + { + message: '提示', + description: + '文件大小必须小于50MB', + + } + ) + } + if(this.state.file !== undefined){ + console.log("763") + this.setState({ + file:file + }) + }else { + this.setState({ + file:file + }) + } + + console.log("handleChange2"); + return isLt150M; + }, + } + const dateFormat = 'YYYY-MM-DD HH:mm:ss'; + let operateauthority=this.props.identity===1?true:this.props.identity<5&&this.state.status==0?true:false; + + return ( +
    + + 实训详情 + 配置 + + +
    +
    + 配置 + { + this.props.identity===1&&this.state.status==2? + this.operateshixuns(2)}> + 永久关闭 + :"" + } + { + this.props.identity < 5 && this.state.status==0? + this.operateshixuns(1)}> + 删除实训 + :"" + } + { + this.props.identity == 1 && this.state.status == 2 ? + this.operateshixuns(1)}> + 删除实训 + :"" + } + + +
    + {delType===1?

    是否确认删除 ?

    :

    关闭后,
    用户不能再开始挑战了是否确认关闭 ?

    } +
    +
    + 取消 + {delType===1?确定:确定} +
    +
    + +
    + +
    + +

    实训名称

    + +
    + * +
    +
    + {settingsData === undefined ? "" : + } +
    +
    + 必填项 +
    +
    + + +
    + +
    +
    + +
    + +

    简介

    + +
    + +
    +
    +
    +

    +

    +
    + +
    +
    +

    技术平台

    + + +
    + * +
    + +

    + 列表中没有? + 申请新建 +

    + + +
    +
  • + + +
  • +
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + +
    +
  • +
    + {this.state.attachmentidstype===true?"请上传附件":""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    + +
    + + + + + +
    +

    新建申请已提交,请等待管理员的审核

    +
  • 我们将在1-2个工作日内与您联系 +
  • +
    +
    + 知道啦 +
    +
    +
    +
    + +
    + +
    +
    + 必填项 +
    + {/*

    请在配置页面完成后续的评测脚本设置操作

    */} + +
    +
    + {/*
    */} + {/*
    */} +
    +

    评测脚本

    +
    + + +
    +

    原有脚本将被新的脚本覆盖,无法撤销

    +

    是否确认执行覆盖操作

    +
    + + +
    + + +

    评测脚本生成成功!

    + +
    + + { + this.props.identity<5||this.props.power==true? + 使用自定义脚本 : "" + } +
    + this.testscripttip(0)}> +
    + +
    +

    + 使用自定义模板,平台无法自动更新脚本,
    + 请在关卡创建完后手动更新脚本中的必填参
    + 数和以下2个数组元素:
    + challengeProgramNames
    + sourceClassNames

    + 示例:有2个关卡的实训

    + 各关卡的待编译文件为:
    + src/step1/HelloWorld.java
    + src/step2/Other.java

    + 各关卡的编译后生成的执行文件为:
    + step1.HelloWorld
    + step2.Other

    + 则数组元素更新如下:
    + challengeProgramNames=("src/step1/
    + HelloWorld.java" "src/step2/Other.java")
    + sourceClassNames=("step1.HelloWorld
    + " "step2.Other")

    + 其它参数可按实际需求定制 +

    +
    +

    + this.testscripttip(1)}>知道了 +

    +
    +
    + + +
    +
  • + + +

    执行命令不能为空

    +
  • + +
  • + + +
  • +
    +
    +
    +
    + +
    +
    + * +
    + + +
    + {/**/} + +
    + + + {/*
    */} + {/*{evaluate_script===undefined?"":evaluate_script}*/} + + {/*
    */} + + + +
    + +
    +
    +
    + + 必填项 +
    +

    +

    +
    +
    + + {/*
    */} + {/***/} + + {/*

    程序最大执行时间

    */} + + {/* 秒*/} + + {/*
    */} + {/*必填项*/} + {/*
    */} + {/*
    */} + + {/*
    + * + +

    Pod存活时间

    + + + +
    + 必填项 +
    +
    */} + + +
    +

    命令行

    + + 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) + 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) + 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) + + 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) + + +
    + +
    +

    公开程度

    + + 对所有公开 (选中则所有已被试用授权的用户可以学习) + 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) + + +
    +
    +
    +
    +
    + +
    + (搜索并选中添加单位名称) +
    + {/*+*/} + {/*添加*/} +
    + +
    + + {/*{*/} + {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/} + {/*return(*/} + {/*
    */} + {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/} + {/*value={item}*/} + {/*/>*/} + {/*
    */} + + {/*)*/} + {/*})*/} + {/*}*/} +
    + + + 请选择需要公开的单位 + +
    +
    +
    + +
    +

    发布信息

    + +
    + * + 面向学员: + +
    + +
    + 实训难易度定位,不限定用户群体 +
    + 必填项 +
    + +
    +
    + 复制: + + + + +
    + +
    + 跳关: + + + + +
    +
    + 测试集解锁: + + + + +
    + + {!code_hidden && !hide_code &&
    + 代码开放修改: + + + + +
    } + +
    + 隐藏代码窗口: + + + + +
    + +
    + 代码目录隐藏: + + + + +
    + + { (vnc || webssh == 2) &&
    + 私密版本库: + + + + +
    } + +
    + 禁用复制粘贴: + + + + +
    + +
    + 开启时间: + + + + +
    + + {this.props.identity<3?
    + VNC图形化: + + + + +
    :""} + {this.props.identity<3 && vnc ?
    + VNC图形化评测: + + + + +
    :""} + + + +
    + + {this.props.identity<3?
    +

    服务配置

    + { shixun_service_configs&&shixun_service_configs.map((item,key)=>{ + + return( +
    +
    +
    + {item.name} + {/*this.Deselectlittle(item.mirror_repository_id)}>*/} +
    +
    + +
    + this.setConfigsInputs(e,key,1)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    +
    +
    +
    + +
    + this.setConfigsInputs(e,key,2)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    +
    +
    +
    + +
    + this.setConfigsInputs(e,key,3)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    +
    +
    +
    + +
    + this.setConfigsInputs(e,key,4)} + className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" /> +
    + +
    +
    +
    +
    + ) + + })} +
    :""} + +

    + { + // this.props.identity<4&&this.props.status==0? + this.props.identity<5? +

    + 保存 + 取消 +
    :"" + } + +

    + +
    + ); + } +} + + diff --git a/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js b/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js index 11b88a037..22326e9e7 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js +++ b/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js @@ -344,7 +344,7 @@ export default class TPMMDEditor extends Component {
    - {noStorage == true ? ' ' :

     

    } + {noStorage == true ? ' ' :
     
    } {/* {noStorage == true ? ' ' :

     

    } */}
    diff --git a/public/react/src/modules/tpm/component/TPMNav.js b/public/react/src/modules/tpm/component/TPMNav.js index ff8f57aa5..ac5128f26 100644 --- a/public/react/src/modules/tpm/component/TPMNav.js +++ b/public/react/src/modules/tpm/component/TPMNav.js @@ -5,7 +5,11 @@ import { BrowserRouter as Router, Route, Link } from "react-router-dom"; class TPMNav extends Component { render() { - const { user, match, shixun, secret_repository } = this.props; + // console.log("componentDidMount"); + // console.log("TPMNavTPMNavTPMNavTPMNav"); + // console.log(this.props); + + const { user, match, shixun, secret_repository,is_jupyter} = this.props; let isAdminOrCreator = false; if (user) { isAdminOrCreator = user.admin || user.manager @@ -15,6 +19,9 @@ class TPMNav extends Component { // console.log(this.props.propaedeutics) const challengesPath = `/shixuns/${shixunId}/challenges`; // console.log(match.path) + // console.log("TPMNavTPMNavTPMNav"); + // 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 (
    背景知识 } - { this.props.identity >4||this.props.identity===undefined ?"":版本库} + { this.props.identity >4||this.props.identity===undefined ?"": + (this.props.is_jupyter===false? + 版本库 + :"") + } + + + {this.props.identity >4||this.props.identity===undefined ?"": secret_repository && 私密版本库} 合作者 - 评论 + {/*jupyter*/} + { + this.props.is_jupyter===true? + ( + is_teacher===true? + 数据集 + :"" + ) + + :"" + } + { + this.props.is_jupyter === false ? + 评论 + :"" + } + { + this.props.is_jupyter === false ? 排行榜 + className={`${match.url.indexOf('ranking_list') != -1 ? 'active' : ''} fl mr40`}>排行榜:"" + } + + {this.props.identity >2||this.props.identity===undefined?"": + (this.props.is_jupyter === false? + 审核情况 + : + is_teacher===true? + 审核情况 + : + "" + + ) + + - {this.props.identity >2||this.props.identity===undefined?"":审核情况} + } - 4||this.props.identity===undefined ? "none" : 'block'}} - >配置 + {this.props.identity >4||this.props.identity===undefined ? "":配置}
    ); } diff --git a/public/react/src/modules/tpm/jupyter/index.js b/public/react/src/modules/tpm/jupyter/index.js new file mode 100644 index 000000000..cd947df85 --- /dev/null +++ b/public/react/src/modules/tpm/jupyter/index.js @@ -0,0 +1,230 @@ +/* + * @Description: jupyter tpi + * @Author: tangjiang + * @Github: + * @Date: 2019-12-11 08:35:23 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 15:25:50 + */ +import './index.scss'; +import React, { useEffect, useState } from 'react'; +import SplitPane from 'react-split-pane'; +import { Button, Modal } from 'antd'; +import { + connect +} from 'react-redux'; +import UserInfo from '../../developer/components/userInfo'; +import actions from '../../../redux/actions'; +import LeftPane from './leftPane'; +import RightPane from './rightPane'; +function JupyterTPI (props) { + + // 获取 identifier 值 + const { + match: { + params = {} + }, + url, + loading, // 保存按钮状态 + total, + pagination, + dataSets, // 数据集 + jupyter_info, + getJupyterInfo, + syncJupyterCode, + jupyter_tpi_url_state, + getJupyterTpiDataSet, + getJupyterTpiUrl, + saveJupyterTpi, + changeLoadingState, + changeGetJupyterUrlState, + jupyter_identifier, + changeCurrentPage + } = 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: (
    +

    关卡任务的代码文件有更新啦

    +

    更新操作将保留已完成的评测记录和成绩

    +

    还未完成评测的任务代码,请自行保存

    +
    ), + okText: '确定', + cancelText: '取消', + onOk () { + syncJupyterCode(myshixun_identifier, '同步成功'); + } + }) + } + }, [props]); + + // 重置实训 + const handleClickResetTpi = () => { + Modal.confirm({ + title: '重置实训', + content: ( +

    + 你在本文件中修改的内容将丢失,
    + 是否确定重新加载初始代码? +

    + ), + okText: '确定', + cancelText: '取消', + onOk () { + console.log('调用重置代码....', myIdentifier); + if (myIdentifier) { + syncJupyterCode(myIdentifier, '重置成功'); + } + } + }) + } + + // 退出实训 + const handleClickQuitTpi = () => { + // console.log(jupyterInfo); + const { identifier } = jupyterInfo; + if (!identifier) return; + 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(); + } + + // 分页信息改变时 + const handlePageChange = (current) => { + // 改变当前页 + changeCurrentPage(current); + // 分页查找数据 + getJupyterTpiDataSet(jupyter_identifier); + } + + return ( +
    +
    + +

    + {jupyterInfo.name} + +

    +

    + {/* sync | poweroff */} + + +

    +
    +
    + +
    + +
    + + +
    + + +
    +
    + ); +} + +const mapStateToProps = (state) => { + const { + jupyter_info, + jupyter_tpi_url, + jupyter_data_set, + jupyter_tpi_url_state, + jupyter_data_set_count, + jupyter_pagination, + jupyter_identifier + } = state.jupyterReducer; + const { loading } = state.commonReducer; + return { + loading, + jupyter_info, + url: jupyter_tpi_url, + dataSets: jupyter_data_set, + jupyter_tpi_url_state, + total: jupyter_data_set_count, + pagination: jupyter_pagination, + jupyter_identifier + }; +} + +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, current) => dispatch(actions.getJupyterTpiDataSet(identifier, current)), + getJupyterTpiUrl: (identifier) => dispatch(actions.getJupyterTpiUrl(identifier)), + saveJupyterTpi: () => dispatch(actions.saveJupyterTpi()), + changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag)), + changeCurrentPage: (current) => dispatch(actions.changeCurrentPage(current)) +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(JupyterTPI); diff --git a/public/react/src/modules/tpm/jupyter/index.scss b/public/react/src/modules/tpm/jupyter/index.scss new file mode 100644 index 000000000..430bb1c6e --- /dev/null +++ b/public/react/src/modules/tpm/jupyter/index.scss @@ -0,0 +1,105 @@ +.Resizer { + background: #000; + opacity: 0.2; + z-index: 1; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -moz-background-clip: padding; + -webkit-background-clip: padding; + background-clip: padding-box; +} + +.Resizer:hover { + -webkit-transition: all 2s ease; + transition: all 2s ease; +} + +.Resizer.horizontal { + height: 11px; + margin: -5px 0; + border-top: 5px solid rgba(255, 255, 255, 0); + border-bottom: 5px solid rgba(255, 255, 255, 0); + cursor: row-resize; + width: 100%; +} + +.Resizer.horizontal:hover { + border-top: 5px solid rgba(0, 0, 0, 0.5); + border-bottom: 5px solid rgba(0, 0, 0, 0.5); +} + +.Resizer.vertical { + width: 11px; + margin: 0 -5px; + border-left: 5px solid rgba(255, 255, 255, 0); + border-right: 5px solid rgba(255, 255, 255, 0); + cursor: col-resize; +} + +.Resizer.vertical:hover { + border-left: 5px solid rgba(0, 0, 0, 0.5); + border-right: 5px solid rgba(0, 0, 0, 0.5); +} +.Resizer.disabled { + cursor: not-allowed; +} +.Resizer.disabled:hover { + border-color: transparent; +} + +.jupyter_area{ + + .jupyter_header{ + position: relative; + height: 60px; + line-height: 60px; + background-color: #070F1A; + padding-left: 30px; + .jupyter_title{ + display: flex; + flex-direction: column; + // justify-content: space-around; + align-items: center; + height: 100%; + color: #fff; + .title_desc{ + margin-top: 12px; + font-size: 16px; + } + .title_time{ + font-size: 12px; + } + // text-align: center; + } + + .jupyter_btn{ + position: absolute; + right: 10px; + top: 14px; + + .btn_common{ + color: #888; + } + .btn_common:hover{ + // background-color: #29BD8B; + // color: #29BD8B; + color: #1890ff; + } + } + } + + + .jupyter_ctx{ + position: relative; + height: calc(100vh - 60px); + } + + .update_notice{ + text-align: center; + .update_txt{ + line-height: 18px; + font-size: 14px; + } + } +} \ No newline at end of file diff --git a/public/react/src/modules/tpm/jupyter/leftPane/index.js b/public/react/src/modules/tpm/jupyter/leftPane/index.js new file mode 100644 index 000000000..ea3c7a6c7 --- /dev/null +++ b/public/react/src/modules/tpm/jupyter/leftPane/index.js @@ -0,0 +1,88 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 10:34:03 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 21:19:30 + */ +import './index.scss'; +import React, { useState, useEffect } from 'react'; +import {Icon, Empty, Pagination, Tooltip } from 'antd'; +import MyIcon from '../../../../common/components/MyIcon'; + +function LeftPane (props) { + + // 获取数据集 + const { + dataSets = [], + total, + pagination, + onPageChange + } = props; + + const emptyCtx = ( +
    + +
    + ); + + // const listCtx = ; + const [renderCtx, setRenderCtx] = useState(() => (emptyCtx)); + + useEffect(() => { + if (dataSets.length > 0) { + console.log('数据集的个数: ', dataSets.length); + const oList = dataSets.map((item, i) => { + return ( +
  • + + + {item.title} + +
  • + ); + }); + + const oUl = ( +
      + { oList } +
    + ); + + setRenderCtx(oUl); + } + }, [props]); + + // 分页处理 + const handleChangePage = (page) => { + // console.log(page, pageSize); + // setCurrent(page); + onPageChange && onPageChange(page); + } + return ( +
    +

    + 数据集 + {/* 数据集 */} +

    + { renderCtx } +
    0 ? 'flex' : 'none'}}> + +
    + +
    + ) +} + +export default LeftPane; \ No newline at end of file diff --git a/public/react/src/modules/tpm/jupyter/leftPane/index.scss b/public/react/src/modules/tpm/jupyter/leftPane/index.scss new file mode 100644 index 000000000..9c95b1aae --- /dev/null +++ b/public/react/src/modules/tpm/jupyter/leftPane/index.scss @@ -0,0 +1,72 @@ +.jupyter_data_sets_area{ + height: 100%; + background: #fff; + .jupyter_h2_title{ + height: 44px; + line-height: 44px; + // background-color: #EEEEEE; + background: #fff; + padding: 0 30px; + font-size: 16px; + // box-size: border-box; + box-sizing: border-box; + border-bottom: 1px solid rgba(238,238,238,1); + .jupyter_data_icon{ + // color: #7286ff; + color: #1890ff; + font-size: 24px; + position: relative; + top: 2px; + transform: scale(1.5); + margin-right: 5px; + } + } + + .jupyter_data_list, + .jupyter_empty{ + height: calc(100vh - 160px); + 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%; + } + + .jupyter_pagination{ + display: flex; + justify-content: center; + align-items: center; + height: 56px; + box-sizing: border-box; + border-top: 1px solid rgba(238,238,238,1); + } +} \ No newline at end of file diff --git a/public/react/src/modules/tpm/jupyter/rightPane/index.js b/public/react/src/modules/tpm/jupyter/rightPane/index.js new file mode 100644 index 000000000..020639abc --- /dev/null +++ b/public/react/src/modules/tpm/jupyter/rightPane/index.js @@ -0,0 +1,91 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 15:04:20 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 11:25:22 + */ +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 = ( +
    + +
    + ); + + const loadError = ( +
    + +

    + 实训加载失败, + 重新加载 +

    +
    + ); + + // 保存 + const handleClickSubmit = () => { + console.log('调用了保存接口....'); + onSave && onSave(); + } + + useEffect(() => { + if (status === -1) { + setRenderCtx(() => loadInit); + } else if (status === 0 && url) { + setRenderCtx(() => ( + +
    +
    + +
    +
    + +
    +
    + + )); + } else { + setRenderCtx(() => loadError); + } + }, [status, url, loading]); + + return ( +
    + { renderCtx } +
    + ) +} + +export default RightPane; + diff --git a/public/react/src/modules/tpm/jupyter/rightPane/index.scss b/public/react/src/modules/tpm/jupyter/rightPane/index.scss new file mode 100644 index 000000000..4facded6b --- /dev/null +++ b/public/react/src/modules/tpm/jupyter/rightPane/index.scss @@ -0,0 +1,74 @@ +.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{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + // &::before{ + // background-color: rgba(0,0,0,.2); + // } + .jupyter_error_txt{ + position: relative; + z-index: 1; + font-size: 12px; + .jupyter_reload{ + cursor: pointer; + color: #1890ff; + } + } + + .icon-error{ + position: relative; + color: #DCE0E6; + transform: scale(5); + top: -35px; + } + } + + .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; + } + } +} \ No newline at end of file diff --git a/public/react/src/modules/tpm/newshixuns/Newshixuns.js b/public/react/src/modules/tpm/newshixuns/Newshixuns.js index 1eaee9ad6..8355efb52 100644 --- a/public/react/src/modules/tpm/newshixuns/Newshixuns.js +++ b/public/react/src/modules/tpm/newshixuns/Newshixuns.js @@ -2,1351 +2,746 @@ import React, {Component} from 'react'; import {TPMIndexHOC} from '../TPMIndexHOC'; -import {SnackbarHOC,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder'; +import {SnackbarHOC} from 'educoder'; -import {Input, Select, Radio, Checkbox, Modal, Icon, DatePicker,Upload,Button,message,Form,notification,Tooltip} from 'antd'; - -// import "antd/dist/antd.css"; - -import locale from 'antd/lib/date-picker/locale/zh_CN'; +import {Select, Radio, Input, Modal, Button, Form, Tooltip, Upload, Icon, notification} from 'antd'; import axios from 'axios'; -import './css/Newshixuns.css'; - -import {getUrl} from 'educoder' +import {getUploadActionUrl} from 'educoder'; -import moment from 'moment'; - -let path = getUrl("/editormd/lib/") - -const $ = window.$; +import './css/Newshixuns.css'; -let timeout; +import TPMMDEditor from "../challengesnew/TPMMDEditor"; -let currentValue; +import Bottomsubmit from "../../modals/Bottomsubmit"; const Option = Select.Option; -const RadioGroup = Radio.Group; -const confirm = Modal.confirm; - - -// 处理整点 半点 -// 取传入时间往后的第一个半点 -export function handleDateStrings(dateString) { - if (!dateString) return dateString; - const ar = dateString.split(':') - if (ar[1] == '00' || ar[1] == '30') { - return dateString - } - const miniute = parseInt(ar[1]); - if (miniute < 30 || miniute == 60) { - return [ar[0], '30'].join(':') - } - if (miniute < 60) { - // 加一个小时 - const tempStr = [ar[0], '00'].join(':'); - const format = "YYYY-MM-DD HH:mm"; - const _moment = moment(tempStr, format) - _moment.add(1, 'hours') - return _moment.format(format) - } - - return dateString -} - - - -// 恢复数据 -function md_rec_data(k, mdu, id, editor) { - if (window.sessionStorage.getItem(k + mdu) !== null) { - editor.setValue(window.sessionStorage.getItem(k + mdu)); - md_clear_data(k, mdu, id); - } -} - -// 保存数据 -function md_add_data(k, mdu, d) { - window.sessionStorage.setItem(k + mdu, d); -} - -// 清空保存的数据 -function md_clear_data(k, mdu, id) { - window.sessionStorage.removeItem(k + mdu); - var id1 = "#e_tip_" + id; - var id2 = "#e_tips_" + id; - if (k == 'content') { - $(id2).html(""); - } else { - $(id1).html(""); - } -} - -function md_elocalStorage(editor, mdu, id) { - if (window.sessionStorage) { - var oc = window.sessionStorage.getItem('content' + mdu); - if (oc !== null) { - $("#e_tips_" + id).data('editor', editor); - var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; - $("#e_tips_" + id).html(h); - } - setInterval(function () { - var d = new Date(); - var h = d.getHours(); - var m = d.getMinutes(); - var s = d.getSeconds(); - h = h < 10 ? '0' + h : h; - m = m < 10 ? '0' + m : m; - s = s < 10 ? '0' + s : s; - if (editor.getValue().trim() != "") { - md_add_data("content", mdu, editor.getValue()); - var id1 = "#e_tip_" + id; - var id2 = "#e_tips_" + id; - - $(id1).html(" 数据已于 " + h + ':' + m + ':' + s + " 保存 "); - $(id2).html(""); - } - }, 10000); - - } else { - $("#e_tip_" + id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); - } -} - - -function create_editorMD(id, width, high, placeholder, imageUrl, callback) { - var editorName = window.editormd(id, { - width: width, - height: high, - path: path, // "/editormd/lib/" - - syncScrolling: "single", - tex: true, - tocm: true, - emoji: true, - taskList: true, - codeFold: true, - searchReplace: true, - htmlDecode: "style,script,iframe", - sequenceDiagram: true, - autoFocus: false, - toolbarIcons: function () { - // Or return editormd.toolbarModes[name]; // full, simple, mini - // Using "||" set icons align right. - return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] - }, - toolbarCustomIcons: { - testIcon: "
    ", - testIcon1: "
    " - }, - //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 - saveHTMLToTextarea: true, - // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 - dialogMaskOpacity: 0.6, - placeholder: placeholder, - imageUpload: true, - imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], - imageUploadURL: imageUrl,//url - onload: function () { - // this.previewing(); - $("#" + id + " [type=\"latex\"]").bind("click", function () { - editorName.cm.replaceSelection("```latex"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("\n"); - editorName.cm.replaceSelection("```"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line - 1, 0); - }); - - $("#" + id + " [type=\"inline\"]").bind("click", function () { - editorName.cm.replaceSelection("`$$$$`"); - var __Cursor = editorName.cm.getDoc().getCursor(); - editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); - editorName.cm.focus(); - }); - $("[type=\"inline\"]").attr("title", "行内公式"); - $("[type=\"latex\"]").attr("title", "多行公式"); - - md_elocalStorage(editorName, `memoNew_${id}`, "memoNew"); +class Newshixuns extends Component { + constructor(props) { + super(props) + this.contentMdRef = React.createRef(); + this.state = { + shixunName: undefined, + NAME_COUNT: 60, + is_jupyter: "1", + newshixunlist: undefined, + language: undefined, + runtime: undefined, + run_method: undefined, + postapplyvisible: undefined, + fileList: [], + Radiovalue:"1" + } + } + + + componentDidMount() { + this.props.form.setFieldsValue({ + is_jupyter: `1`, + }); - callback && callback() + let newshixunUrl = `/shixuns/new.json`; + axios.get(newshixunUrl).then((response) => { + if (response.status === 200) { + if (response.data.message === undefined) { + this.setState({ + newshixunlist: response.data + }); + this.contentMdRef.current.setValue(!response.data.sample[0][1] ? "" : response.data.sample[0][1]); } + } + }).catch((error) => { + console.log(error) }); - return editorName; -} - -function range(start, end) { - const result = []; - for (let i = start; i < end; i++) { - result.push(i); - } - return result; -} -function disabledDateTime() { - return { - // disabledHours: () => range(0, 24).splice(4, 20), - disabledMinutes: () => range(1, 30).concat(range(31, 60)), - // disabledSeconds: () => [0, 60], - }; -} -function disabledDate(current) { - return current && current < moment().endOf('day').subtract(1, 'days'); -} -class Newshixuns extends Component { - constructor(props) { - super(props) - this.state = { - fileList: [], - newshixunlist: undefined, - departmentslist: undefined, - name: "", - main_type: "", - small_type: "", - trainee: "", - webssh: 0, - use_scope: 0, - can_copy: "", - scope_partment: undefined, - vnc: "", - scopetype: false, - postapplyvisible: false, - sendsure_applyvalue: undefined, - postapplytitle: false, - shixun_nametype: false, - main_types: false, - trainee_types: false, - SelectTheCommandtype: false, - opers: false, - operss: false, - TimePickervalue: "", - opensmail: false, - onSearchvalue: "", - scope_partmenttype: false, - languagewrite: undefined, - systemenvironment:undefined, - testcoderunmode:undefined, - file:undefined, - deleteisnot:true, - languagewritetype:false, - systemenvironmenttype:false, - testcoderunmodetype:false, - attachmentidstype:false, - datalisttype:false, - bottonloading:false + 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) + }); - initMD(initValue) { - this.contentChanged = false; - const placeholder = ""; - // amp; - // 编辑时要传memoId - const imageUrl = `/api/attachments.json`; - // 创建editorMd - - const taskpass_editormd = create_editorMD("memoMD", '100%', 400, placeholder, imageUrl, () => { - setTimeout(() => { - taskpass_editormd.resize() - taskpass_editormd.cm && taskpass_editormd.cm.refresh() - }, 500) - - if (initValue) { - taskpass_editormd.setValue(initValue) - } - taskpass_editormd.cm.on("change", (_cm, changeObj) => { - // console.log('....contentChanged') - this.contentChanged = true; - }) - }); - this.taskpass_editormd = taskpass_editormd; - window.taskpass_editormd = taskpass_editormd; - } + } - componentDidMount() { - let newshixunUrl = `/shixuns/new.json`; - axios.get(newshixunUrl).then((response) => { - if (response.status === 200) { - if (response.data.message===undefined) { - this.setState({ - newshixunlist: response.data - }); - this.initMD(response.data.sample[0][1]); - } + shixunNameInput = (e) => { + this.setState({ + shixunName: e.target.value + }) - } - }).catch((error) => { - console.log(error) - }); + this.props.form.setFieldsValue({ + name: e.target.value, + }); + } - 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 - }); - } + RadiovalueonChange = (e) => { + this.setState({ + Radiovalue: e.target.value, + }); + this.props.form.setFieldsValue({ + is_jupyter: e.target.value, + }); + }; + + handleSubmit = (e) => { + this.setState({ + loading: true + }) + const mdContnet = this.contentMdRef.current.getValue().trim(); + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + console.log('Received values of form: ', values); + + let Url = `/shixuns.json`; + axios.post(Url, { + description: mdContnet, + main_type: values.main_type, + sub_type: values.sub_type, + shixun: { + name: values.name, + trainee: values.select, + is_jupyter: values.is_jupyter === "2" ? true : false, } + } + ).then((response) => { + if (response.status === 200) { + window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; + // window.open("/shixuns/"+response.data.shixun_identifier+"/challenges"); + } else { + this.setState({ + loading: true + }) + } }).catch((error) => { - console.log(error) - }); - } - - setlanguagewrite = (e)=>{ - this.setState({ - languagewrite: e.target.value - }) - } - - setsystemenvironment = (e) => { - this.setState({ - systemenvironment: e.target.value - }) - } - settestcoderunmode = (e) => { - this.setState({ - testcoderunmode: e.target.value + this.setState({ + loading: true + }) }) - } - shixunname = (e) => { - this.setState({ - name: e.target.value, - shixun_nametype: false - }); - } - bigClass = (value) => { - this.setState({ - main_type: value - }) - } + } + }); + this.setState({ + loading: false + }) + }; + Selectthestudent = (value) => { + this.props.form.setFieldsValue({ + select: value, + }); + } - littleClass = (value) => { - this.setState({ - small_type: value - }) + main_type = (value, e) => { + this.props.form.setFieldsValue({ + main_type: value, + }); + this.setState({ + mainvalues: e.props.name + }) + } + + sub_type = (value, e) => { + this.props.form.setFieldsValue({ + sub_type: value, + }); + let newlist = "" + e.map((item, key) => { + if (item.props.name != "") { + newlist = newlist + `${item.props.name}` + } + }) + this.setState({ + subvalues: newlist + }) + } + + post_apply = () => { + this.setState({ + postapplyvisible: true + }) + } + + + sendhideModaly = () => { + this.setState({ + postapplyvisible: false, + }) + if (this.state.file !== undefined) { + // this.deleteAttachment(this.state.file); + this.setState({ + file: undefined, + deleteisnot: true, + language: "", + runtime: "", + run_method: "", + fileList: [] + }) + } else { + this.setState({ + file: undefined, + deleteisnot: true, + language: "", + runtime: "", + run_method: "", + fileList: [] + }) } + } - Selectthestudent = (value) => { - this.setState({ - trainee: value - }) - } - SelectTheCommand = (e) => { - this.setState({ - webssh: e.target.value, - }); + sendsure_apply = () => { + let {language, runtime, run_method} = this.state; - if (e.target.value === 2) { - this.setState({ - SelectTheCommandtype: true, - multi_webssh: false - }); - } else { - this.setState({ - SelectTheCommandtype: false, - multi_webssh: false - }); - } + if (!language || language === "") { + // this.props.showNotification(`请填写该镜像是基于什么语言`); + this.setState({ + languagewritetype: true + }) + return } - - Selectpublic = (e) => { - this.setState({ - scopetype: false, - use_scope: e.target.value, - }); - if (e.target.value === 1) { - this.setState({ - scopetype: true - }); - } + if (!runtime || runtime === "") { + // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`); + this.setState({ + systemenvironmenttype: true + }) + return; } - - Teacherscopy = (e) => { - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - can_copy: sum, - }); - } - - TeachersUbuntu = (e) => { - let sum = "" - if (e.target.checked === false) { - sum = 0 - } else if (e.target.checked === true) { - sum = 1 - } - this.setState({ - vnc: sum, - }); + if (!run_method || run_method === "") { + // this.props.showNotification(`请填写该镜像中测试代码运行方式`); + this.setState({ + testcoderunmodetype: true + }) + return; } - adduse_scopeinput = () => { - let {scope_partment} = this.state; - let array = scope_partment; - let newarray = "" - array.push(newarray) - this.setState({ - scope_partment: array, - }); + var attachment_ids = undefined; + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) } - shixunScopeInput = (e, id) => { - let types=false - let {scope_partment} = this.state; - let datalist = scope_partment; - if (datalist === undefined) { - datalist = [] - } - - datalist.map((item,key)=>{ - if(e===item){ - types=true - this.setState({ - datalisttype:true - }) - return - } - }) - - if(types===false){ - datalist.push(e) - this.setState({ - scope_partment: datalist, - onSearchvalue: "" - }); - } - - + if (attachment_ids === undefined || attachment_ids.length === 0) { + this.setState({ + attachmentidstype: true + }) + return; } - deleteScopeInput = (key) => { - let {scope_partment} = this.state; - let datalist = scope_partment; - datalist.splice(key, 1); - this.setState({ - scope_partment: datalist - }); + var data = { + language: language, + runtime: runtime, + run_method: run_method, + attachment_id: attachment_ids[0], } + var url = `/shixuns/apply_shixun_mirror.json`; + axios.post(url, data + ).then((response) => { - //提交数据 - submit_new_shixun = () => { - const mdVal = this.taskpass_editormd.getValue(); - let {can_copy, main_type, name, scope_partment, small_type, trainee, use_scope, vnc, webssh, multi_webssh, TimePickervalue} = this.state; - let Url = `/shixuns.json` - if (name === "") { - this.setState({ - shixun_nametype: true - }) - this.props.showSnackbar("实训名称为空"); - $('html').animate({ - scrollTop: 10 - }, 1000); - return - } - if (main_type === "") { - this.setState({ - main_types: true - }) - $('html').animate({ - scrollTop: 700 - }, 1000); - this.props.showSnackbar("请选择技术平台大类别"); - - return - } + try { + if (response.data) { - if (use_scope === 1) { - if (scope_partment === undefined || scope_partment.length === 0) { - this.setState({ - scope_partmenttype: true - }) - $('html').animate({ - scrollTop: 900 - }, 1000); - this.props.showSnackbar("公开程度,指定单位为空"); - return - } - } - if (trainee === "") { + if (this.state.file !== undefined) { this.setState({ - trainee_types: true + file: undefined, + deleteisnot: true, + language: "", + runtime: "", + run_method: "", + fileList: [] }) - // $('html').animate({ - // scrollTop: 700 - // }, 1000); - this.props.showSnackbar("请选择发布信息"); - return - } - let newmulti_webssh = multi_webssh; - if (newmulti_webssh === true) { - newmulti_webssh = 1 - } else { - newmulti_webssh = "" - } - this.setState({ - bottonloading:true - }) - axios.post(Url, { - name: name, - can_copy: can_copy, - description: mdVal, - main_type: main_type, - scope_partment: scope_partment, - small_type: small_type, - trainee: trainee, - use_scope: use_scope, - vnc: vnc, - webssh: webssh, - multi_webssh: newmulti_webssh, - task_pass: 1, - opening_time: TimePickervalue - } - ).then((response) => { - if (response.status === 200) { - window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; - // window.open("/shixuns/"+response.data.shixun_identifier+"/challenges"); - }else{ - this.setState({ - bottonloading:false - }) - } - }).catch((error) => { - console.log(error) - this.setState({ - bottonloading:false - }) - }) - } - - - 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) => { - if (response.data.message===undefined) { - callback(response.data.shools_name); - } - }).catch((error) => { - console.log(error) - }); - } - - timeout = setTimeout(fake, 300); - } - - shixunHandleSearch = (value) => { - - this.shixunsfetch(value, departmentslist => this.setState({departmentslist})); - - this.setState({ - onSearchvalue: "" - }) - } - - post_apply = () => { - this.setState({ - postapplyvisible: true - }) - } - sendsure_apply = () => { - let {languagewrite,systemenvironment,testcoderunmode} = this.state; - // console.log("点击确定") - // console.log("languagewrite"+languagewrite); - // console.log("systemenvironment"+systemenvironment); - // console.log("testcoderunmode"+testcoderunmode); - - // let attachment_ids = undefined - // if (this.state.fileList) { - // attachment_ids = this.state.fileList.map(item => { - // return item.response ? item.response.id : item.id - // }) - // } - if(languagewrite === undefined || languagewrite === "" ){ - // this.props.showNotification(`请填写该镜像是基于什么语言`); + } else { this.setState({ - languagewritetype:true - }) - return - } - if(systemenvironment === undefined || systemenvironment === ""){ - // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`); - this.setState({ - systemenvironmenttype:true - }) - return; - - } - if(testcoderunmode === undefined || testcoderunmode === "") { - // this.props.showNotification(`请填写该镜像中测试代码运行方式`); - this.setState({ - testcoderunmodetype:true - }) - return; - } - var attachment_ids=undefined; - if (this.state.fileList) { - attachment_ids = this.state.fileList.map(item => { - return item.response ? item.response.id : item.id + file: undefined, + deleteisnot: true, + language: "", + runtime: "", + run_method: "", + fileList: [] }) - } - - if( attachment_ids === undefined || attachment_ids.length===0){ - - // notification.open( - // { - // message: '提示', - // description: - // '请上传附件!', - // - // } - // ) - this.setState({ - attachmentidstype:true - }) - return; - } - // console.log("attachment_ids"+attachment_ids); - - // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids); - - var data={ - language:languagewrite, - runtime:systemenvironment, - run_method:testcoderunmode, - attachment_id:attachment_ids[0], - } - var url =`/shixuns/apply_shixun_mirror.json`; - axios.post(url,data - ).then((response) => { + } - try { - if (response.data) { - // const { id } = response.data; - // if (id) { - if(this.state.file !== undefined){ - console.log("549"); - // this.deleteAttachment(this.state.file); - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - }else { - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - } - // this.props.showNotification('提交成功!'); - notification.open( - { - message: '提示', - description: - '提交成功!', - - } - ) - this.sendhideModaly() - // this.props.history.push(`/courses/${cid}/graduation_topics`); - // } - } - }catch (e) { + notification.open( + { + message: '提示', + description: + '新建申请已提交,请等待管理员审核。', } + ) + this.sendhideModaly() - }) - - } - sendhideModaly = () => { - this.setState({ - postapplyvisible: false, - }) - if(this.state.file !== undefined){ - console.log("580"); - // this.deleteAttachment(this.state.file); - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) - }else { - this.setState({ - file:undefined, - deleteisnot:true, - languagewrite:"", - systemenvironment:"", - testcoderunmode:"", - fileList:[] - }) } - } - sendsure_applyvalues = (e) => { - this.setState({ - sendsure_applyvalue: e.target.value - }) - } - yeshidemodel = () => { - this.setState({ - postapplytitle: false - }) - } + } catch (e) { - SelectTheCommandonChange = (e) => { - this.setState({ - multi_webssh: e.target.checked - }) - } + } + }) - bigopen = (e) => { - this.setState({ - opers: true - }) + } + setlanguage = (e) => { + this.setState({ + language: e.target.value + }) + if (e.target.value) { + this.setState({ + languagewritetype: false + }) } - - bigopens = (e) => { - this.setState({ - opers: false, - operss: false, - opensmail: false - }) - + } + setruntime = (e) => { + this.setState({ + runtime: e.target.value + }) + if (e.target.value) { + this.setState({ + systemenvironmenttype: false + }) } - bigopensmal = (e) => { - this.setState({ - opensmail: true - }) + } + setrun_method = (e) => { + this.setState({ + run_method: e.target.value + }) + if (e.target.value) { + this.setState({ + testcoderunmodetype: false + }) } + } - sbigopen = (e) => { - this.setState({ - operss: true - }) - - } - // sbigopens=()=>{ - // this.setState({ - // operss:false - // }) - // } + // 附件相关 START + handleChange = (info) => { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let {fileList} = this.state; - onChangeTimePicker = (value, dateString) => { + 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({ - TimePickervalue: dateString=== ""?"":moment(handleDateStrings(dateString)) - }) - } - - // 附件相关 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){ - 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); + // 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 + }; }); - } - - - handleSubmit=()=>{ - // console.log(this.state.languagewrite) - // console.log(this.state.systemenvironment) - // console.log(this.state.testcoderunmode) - var attachment_ids; - if (this.state.fileList) { - attachment_ids = this.state.fileList.map(item => { - return item.response ? item.response.id : item.id - }) + } + } + }) + .catch(function (error) { + console.log(error); + }); + } + + render() { + const {getFieldDecorator} = this.props.form; + const {newshixunlist, fileList, postapplytitle, postapplyvisible} = this.state; + const uploadProps = { + width: 600, + fileList, + multiple: true, + action: `${getUploadActionUrl()}`, + onChange: this.handleChange, + onRemove: this.onAttachmentRemove, + beforeUpload: (file, fileList) => { + + if (this.state.fileList.length >= 1) { + return false } - // console.log(attachment_ids); - // var data={ - // language:"", - // runtime:"", - // run_method:"", - // attachment_id:"", - // } - // axios.post(url,data - // ).then((response) => { - // if (response.data) { - // // const { id } = response.data; - // // if (id) { - // this.props.showNotification('提交成功!'); - // // this.props.history.push(`/courses/${cid}/graduation_topics`); - // // } - // } - // }) + const isLt150M = file.size / 1024 / 1024 < 50; + if (!isLt150M) { + notification.open( + { + message: '提示', + description: + '文件大小必须小于50MB', - } - render() { - const { getFieldDecorator } = this.props.form; - let {testcoderunmode ,systemenvironment,languagewrite,deleteisnot, fileList,TimePickervalue, scope_partmenttype, opensmail, newshixunlist, name, scope_partment, departmentslist, postapplyvisible, sendsure_applyvalue, postapplytitle, shixun_nametype, main_types, trainee_types, SelectTheCommandtype, opers, datalisttype, onSearchvalue} = this.state; - let options - if (departmentslist != undefined) { - options = this.state.departmentslist.map((d, k) => { - return ( - - ) - }) + } + ) } - const uploadProps = { - width: 600, - fileList, - multiple: true, - // https://github.com/ant-design/ant-design/issues/15505 - // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 - // showUploadList: false, - action: `${getUploadActionUrl()}`, - onChange: this.handleChange, - onRemove: this.onAttachmentRemove, - beforeUpload: (file, fileList) => { - - if (this.state.fileList.length >= 1) { - return false - } - // console.log('beforeUpload', file.name); - const isLt150M = file.size / 1024 / 1024 < 50; - if (!isLt150M) { - // this.props.showNotification(`文件大小必须小于50MB`); - notification.open( - { - message: '提示', - description: - '文件大小必须小于50MB', - - } - ) - } - if(this.state.file !== undefined){ - console.log("763") - this.setState({ - file:file - }) - }else { - this.setState({ - file:file - }) - } - - console.log("handleChange2"); - return isLt150M; - }, + if (this.state.file !== undefined) { + this.setState({ + file: file + }) + } else { + this.setState({ + file: file + }) } - // const uploadProps = { - // width: 600, - // fileList, - // multiple: true, - // // https://github.com/ant-design/ant-design/issues/15505 - // // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 - // // showUploadList: false, - // action: `${getUrl()}/api/attachments.json`, - // onChange: this.handleChange, - // onRemove: this.onAttachmentRemove, - // beforeUpload: (file) => { - // // console.log('beforeUpload', file.name); - // const isLt50M = file.size / 1024 / 1024 < 50; - // if (!isLt50M) { - // this.props.showNotification('文件大小必须小于150MB!'); - // } - // return isLt50M; - // }, - // }; - - return ( - -
    -
    -
    - -
    -

    - 创建实训 - {this.props.user&&this.props.user.main_site===true?实训制作指南:""} -

    - -
    -

    实训名称

    -
    - * -
    - - - 必填项 - -
    - -
    -
    - -
    - - -
    - -

    简介

    - -
    -
    - -
    -
    -

    -

    -
    - -
    -

    技术平台

    -
    - * -
    - -

    - 列表中没有? - 申请新建 -

    - - - {/*
    */} -
    -
  • - - -
  • -
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    -
  • - - -
  • -
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    -
  • - - - -
  • -
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    -
  • - -
    - - - 上传附件 - (单个文件50M以内) - - -
    - -
  • -
    - {this.state.attachmentidstype===true?"请上传附件":""} -
    -
  • - this.sendhideModaly()} - >取消 - -
  • -
    -
    - {/*
    */} -
    - - - - -
    -

    新建申请已提交,请等待管理员的审核

    -
  • 我们将在1-2个工作日内与您联系 -
  • -
    -
    - 知道啦 -
    -
    -
    -
    -
    - -
    -

    请在配置页面完成后续的评测脚本设置操作

    -
    - 必填项 -
    -
    -
    - - -
    -

    命令行

    -
    - - 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) - 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) - 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) - - 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) - - -
    -
    - - -
    -

    公开程度

    -
    - - 对所有公开 (选中则所有已被试用授权的用户可以学习) - 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) - - -
    -
    -
    -
    -
    - -
    - (搜索选中添加单位名称) - {this.state.datalisttype===true?请勿选择重复单位:""} - {/*+ 添加*/} -
    -
    - -
    -
    - { - scope_partment === undefined ? "" : scope_partment.map((item, key) => { - return ( -
  • {item} - this.deleteScopeInput(key)}>× -
  • - ) - }) - } -
    - {/*{*/} - {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/} - {/*return(*/} - {/*
    */} - {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/} - {/*value={item}*/} - {/*/>*/} - {/*
    */} - - {/*)*/} - {/*})*/} - {/*}*/} -
    - - - - 请选择需要公开的单位 - -
    -
    -
    -
    + return isLt150M; + }, + } + return ( +
    + +
    +
    + +
    + +
    + 新建实训项目 + {this.props.user && this.props.user.main_site === true ? + 实训制作指南 : ""} +
    +
    +
    + {this.props.user&&this.props.user.admin===true||this.props.user&&this.props.user.business===true? + {getFieldDecorator('is_jupyter')( + + 普通实训 + Jupyter实训 + , + )} + :""} + + {getFieldDecorator('name', { + rules: [{ + required: true, message: '请输入名称', + }, { + max: 60, message: '请输入名称,最大限制60个字符', + }, { + whitespace: true, message: '请勿输入空格' + }], + })( + + )} + + + + + + + + {getFieldDecorator('select', { + rules: [{required: true, message: '请选择难易度'}], + })( +
    + + +
    + )} + (实训的难易程度) +
    + + + +
    + + {getFieldDecorator('main_type', { + rules: [{required: true, message: '请选择主类别'}], + })( +
    + + -
    -

    发布信息

    -
    -
    - *面向学员: -
    - -
    - 实训难易度定位,不限定用户群体 -
    - 必填项 -
    -
    -
    -
  • - 复制: - - -
  • -
    - 开启时间: -
  • - - -
  • -
    - {/*
    */} - {/*

    VNC图形化

    */} - {/*
  • */} - {/**/} - {/**/} - {/*
  • */} - {/*
    */} - - -
    - - 取消 + )} +
    + + + + +
    + {getFieldDecorator('sub_type')( +
    +
    + )} + +
    + {this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && 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.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.subvalues : this.state.subvalues}`} +
    } + +
    +
    +
    +
    -
    + +
    +
    + 没有实验环境? + 申请新建
    + {postapplyvisible === true ? : ""} + + +
    +
  • + + +
  • +
    {this.state.languagewritetype === true ? "请填写该镜像语言" : ""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype === true ? "请填写该镜像语言系统环境" : ""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype === true ? "请填写该镜像测试代码运行方式" : ""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + + +
    + +
  • +
    + {this.state.attachmentidstype === true ? "请上传附件" : ""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    + {/**/} +
    + +
    +
    +
    +
    + this.handleSubmit()} loadings={this.state.loading}/> +
    - ); - } + ); + } } -const NewshixunsNew = Form.create({ name: 'newshixunsnew' })(Newshixuns); + +const NewshixunsNew = Form.create({name: 'newshixun'})(Newshixuns); + export default SnackbarHOC()(TPMIndexHOC(NewshixunsNew)); diff --git a/public/react/src/modules/tpm/newshixuns/Shixunmd.js b/public/react/src/modules/tpm/newshixuns/Shixunmd.js new file mode 100644 index 000000000..608c7ea63 --- /dev/null +++ b/public/react/src/modules/tpm/newshixuns/Shixunmd.js @@ -0,0 +1,111 @@ +import React, { Component } from 'react'; +import {Button,Form,Input} from 'antd'; +import axios from 'axios'; +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; +class Osshackathonmd extends Component{ + constructor(props) { + super(props) + this.contentMdRef = React.createRef(); + this.state={ + title_num: 0, + title_value: undefined + } + } + componentDidUpdate =(prevState)=>{ + // if(prevState!=this.props){ + // let url=`/osshackathon/edit_hackathon.json`; + // axios.get(url).then((result)=>{ + // if(result.status==200){ + // this.setState({ + // title_value:result.data.name + // }) + // this.contentMdRef.current.setValue(result.data.description); + // } + // }) + // } + } + componentDidMount(){ + let url=`/osshackathon/edit_hackathon.json`; + axios.get(url).then((result)=>{ + if(result.status==200){ + this.setState({ + title_value:result.data.name + }) + this.contentMdRef.current.setValue(result.data.description === null ? "" : result.data.description); + } + }) + } + + + // 输入title + changeTitle = (e) => { + // title_num: 60 - parseInt(e.target.value.length), + this.setState({ + title_num: e.target.value.length, + title_value: e.target.value + }) + + } + handleSubmit = () => { + let {title_value}=this.state; + const mdContnet = this.contentMdRef.current.getValue().trim(); + // if(mdContnet.length>10000){ + // this.props.showNotification("内容超过10000个字"); + // return + // } + + let url=`/osshackathon/update_hackathon.json`; + axios.post(url,{ + name:title_value, + description:mdContnet, + } + ).then((response) => { + if(response.data.status===0){ + this.props.getosshackathon() + this.props.hidehackathonedit() + this.props.showNotification(`提交成功`); + } + }).catch((error) => { + console.log(error) + }) + + } + render() { + + + // console.log(this.props.tabkey) + // console.log(chart_rules) + + return ( +
    +
    + + + + + + + +
    + + + + +
    + + ) + } +} +export default Osshackathonmd; diff --git a/public/react/src/modules/tpm/newshixuns/css/Newshixuns.css b/public/react/src/modules/tpm/newshixuns/css/Newshixuns.css index e241dcf0d..9a85f33d4 100644 --- a/public/react/src/modules/tpm/newshixuns/css/Newshixuns.css +++ b/public/react/src/modules/tpm/newshixuns/css/Newshixuns.css @@ -392,6 +392,442 @@ a.white-btn.use_scope-btn:hover{ border-color: #096dd9; } -.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{ - background-color: #4CACFF; +/*.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{*/ +/* background-color: #4CACFF;*/ +/*}*/ + +.newViewAfter .ant-input{ + line-height: 40px !important; + height: 40px !important; + box-shadow: none!important; +} + +.width30{ + width: 30%; +} + +.newshixunheadersear{ + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; + margin: 0 auto; +} +.packinput .ant-input{ + height: 55px; + width:663px !important; + font-size: 14px; + /*color: #681616 !important;*/ + border-color: #E1EDF8 !important; + padding-left: 20px; +} + +.packinput .ant-input-group-addon .ant-btn{ + width:137px !important; + font-size: 18px; + height: 53px; + background:rgba(76,172,255,1); + +} +.tabtitle{ + height: 62px !important; + -webkit-box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15); + box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15); + border-radius: 6px; + background: #fff; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; +} +.tabtitles2{ + background: #fff; + height: 62px !important; + width: 1200px; +} + +.tabtitless{ + height: 62px !important; + line-height: 62px !important; + +} +.tabtitle1{ + +} +.tabtitle2{ + margin-left: 30px !important; + +} + + +.counttit{ + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; +} + +.counttittext{ + text-align: left; + width: 1200px; + height: 18px; + color: #888888; + font-size: 13px; + margin-top: 24px; + + +} +.counttittexts{ + color: #4CACFF !important; + font-size: 13px; +} + +.mainx{ + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; + margin-top: 17px; +} +.project-packages-list{ + +} +.project-package-item{ + display: -ms-flexbox; + display: flex; + -ms-flex-direction:column; + flex-direction:column; + margin-bottom: 20px; + padding: 20px; + background: white; + /* box-shadow: 1px 3px 3px 1px rgba(156,156,156,0.16); */ + +} +.xuxianpro{ + height: 20px; + border-bottom: 1px dashed; + border-color: #EAEAEA; + margin-bottom: 18px; +} +.magr11{ + margin-top: 11px; +} +.highlight{ + color: #4CACFF; +} +.fonttext{ + font-size: 20px; + font-weight:bold; +} + +.fontextcolor{ + color: #777777; +} +.tzbq{ + margin-left: 68px; +} +.tzbqx{ + /* margin-left: 24px; */ +} +.bjyss{ + background: #F8F8F8; +} +.zj{ + overflow:hidden; + -o-text-overflow:ellipsis; + text-overflow:ellipsis; + white-space:nowrap +} +.ziticor{ + color: #777777; + font-size: 13px; +} +.foohter{ + margin-top: 20px; + display: -ms-flexbox; + display: flex; + -ms-flex-direction:row; + flex-direction:row; +} + +.maxwidth1100{ + max-width: 1100px; + overflow:hidden; + -o-text-overflow:ellipsis; + text-overflow:ellipsis; + white-space:nowrap; + font-size: 18px !important; + font-weight: 500; + color: rgba(51,51,51,1) !important; +} + + +.newshixunmodelmidfont{ + font-size: 14px; + font-weight: 400; + color: #999999; + margin-top: 15px; + margin-left: 30px; + max-width: 1100px; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; +} + +.newshixunmodelbotfont{ + font-size:12px; + font-weight:400; + color:rgba(102,102,102,1); + margin-top: 15px; + margin-left: 30px; +} + +.newshixunlist{ + max-height:227px; + width: 1200px; +} + +.xuxianpro { + height: 20px; + border-bottom: 1px dashed; + border-color: #eaeaea; + margin-bottom: 18px; +} + +.newshixunpd030{ + padding: 0px 30px; +} + +.pd303010{ + padding: 30px 30px 10px; +} + +.newshixunfont12{ + font-size: 12px; + color: rgba(76,172,255,1); + line-height: 21px; +} + +.newshixunmode{ + width: 100px; + height: 38px; + border-radius: 3px; + /*border: 1px solid rgba(191,191,191,1);*/ +} + +.ntopsj { + position: absolute; + top: -4px; +} + +.nyslbottomsj { + position: absolute; + bottom: -6px; +} + +.inherits .ant-dropdown-menu-item{ + cursor: inherit !important; +} + +.menus{ + width: 91px; + text-align: center; +} + +.newshixunmodelbotfont span{ + display: inline-block; + margin-right: 34px; +} + +.minhegiht300{ + min-height: 300px; +} + +.newshixunlist:hover{ + -webkit-box-shadow: 1px 6px 16px rgba(156,156,156,0.16); + box-shadow: 1px 6px 16px rgba(156,156,156,0.16); + opacity: 1; + border-radius: 2px; +} + +.newshixun500{ + max-width: 500px; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mt3 { + margin-top: 3px !important; +} + +.highlight{ + color: #4CACFF; +} + +.newshixunbottombtn{ + position: fixed; + z-index: 1000; + bottom: 0px; + width: 100%; + height: 63px; + background: rgba(255,255,255,1); + -webkit-box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05); + box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05); +} + + +.mb60shixun{ + margin-bottom: 60px !important; +} + +.padding13-30 { + padding: 13px 30px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.displaymodulat { + display: -ms-flexbox; + display: flex; + display: -webkit-flex; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-align: center; + align-items: center; +} + +.WordNumberTextarea { + outline: none; /* 去掉输入字符时的默认样式 */ + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background-color: white; + text-shadow: none; + -webkit-writing-mode: horizontal-tb !important; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + resize: none; /*禁止拉伸*/ + border: none; /*去掉默认边框*/ + width: 100%; + height: 130px; + border: none; + display: block; +} + +.WordNumbernote { + padding: 0; + margin: 0; + list-style: none; + text-decoration: none; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + height: auto; + border: 1px solid rgba(234, 234, 234, 1); + border-radius: 0.125rem; + margin: 10px 10px 0px 10px; + padding: 10px 10px 5px 10px; + backgroud: rgba(234, 234, 234, 1); + width: 530px; + margin-left: 10px; + margin-top: 25px; + height: 214px !important; +} + +.WordNumbernote .WordNumberTextarea { + outline: none; + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background-color: white; + text-shadow: none; + -webkit-writing-mode: horizontal-tb !important; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + resize: none; + border: none; + width: 100%; + height: 169px !important; + border: none; + display: block; +} + +.WordNumberTextarea-count { + display: inline-block; + float: right; + font-size: 16px; + color: #adadad; + padding-right: 0.25rem; +} + +.borerinput { + border: 1px solid #DD1717 !important; +} + +.borerinputs { + border: 1px solid #eee !important; +} + + +.mexertwo { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: initial; + flex-direction: initial; +} + +.mexeheigth { + line-height: 40px; +} + +.mexeheigth2 { + line-height: 40px; + width: 74px; +} + +.minbuttionte { + /* display: flex; */ + margin-top: 20px; + width: 100%; + /* align-items: center; */ + margin-bottom: 17px; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + -ms-flex-direction: initial; + flex-direction: initial; +} + +.initialflex{ + display: -ms-flexbox; + display: flex; + -ms-flex-direction:initial; + flex-direction:initial; +} + +.newshixunheadersear{ + margin: 0 auto; +} + +.newshixunmodels{ + margin: 0 auto; +} + +.backgroundFFF{ + background: #FFF !important; +} + +.relative{ + position: relative; +} + +.pd40px{ + padding-bottom: 40px; } \ No newline at end of file diff --git a/public/react/src/modules/tpm/newshixuns/oldNewshixuns.js b/public/react/src/modules/tpm/newshixuns/oldNewshixuns.js new file mode 100644 index 000000000..1eaee9ad6 --- /dev/null +++ b/public/react/src/modules/tpm/newshixuns/oldNewshixuns.js @@ -0,0 +1,1356 @@ +import React, {Component} from 'react'; + +import {TPMIndexHOC} from '../TPMIndexHOC'; + +import {SnackbarHOC,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder'; + +import {Input, Select, Radio, Checkbox, Modal, Icon, DatePicker,Upload,Button,message,Form,notification,Tooltip} from 'antd'; + +// import "antd/dist/antd.css"; + +import locale from 'antd/lib/date-picker/locale/zh_CN'; + +import axios from 'axios'; + +import './css/Newshixuns.css'; + +import {getUrl} from 'educoder' + +import moment from 'moment'; + +let path = getUrl("/editormd/lib/") + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; +const confirm = Modal.confirm; + + +// 处理整点 半点 +// 取传入时间往后的第一个半点 +export function handleDateStrings(dateString) { + if (!dateString) return dateString; + const ar = dateString.split(':') + if (ar[1] == '00' || ar[1] == '30') { + return dateString + } + const miniute = parseInt(ar[1]); + if (miniute < 30 || miniute == 60) { + return [ar[0], '30'].join(':') + } + if (miniute < 60) { + // 加一个小时 + const tempStr = [ar[0], '00'].join(':'); + const format = "YYYY-MM-DD HH:mm"; + const _moment = moment(tempStr, format) + _moment.add(1, 'hours') + return _moment.format(format) + } + + return dateString +} + + + +// 恢复数据 +function md_rec_data(k, mdu, id, editor) { + if (window.sessionStorage.getItem(k + mdu) !== null) { + editor.setValue(window.sessionStorage.getItem(k + mdu)); + md_clear_data(k, mdu, id); + } +} + +// 保存数据 +function md_add_data(k, mdu, d) { + window.sessionStorage.setItem(k + mdu, d); +} + +// 清空保存的数据 +function md_clear_data(k, mdu, id) { + window.sessionStorage.removeItem(k + mdu); + var id1 = "#e_tip_" + id; + var id2 = "#e_tips_" + id; + if (k == 'content') { + $(id2).html(""); + } else { + $(id1).html(""); + } +} + +function md_elocalStorage(editor, mdu, id) { + if (window.sessionStorage) { + var oc = window.sessionStorage.getItem('content' + mdu); + if (oc !== null) { + $("#e_tips_" + id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_" + id).html(h); + } + setInterval(function () { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if (editor.getValue().trim() != "") { + md_add_data("content", mdu, editor.getValue()); + var id1 = "#e_tip_" + id; + var id2 = "#e_tips_" + id; + + $(id1).html(" 数据已于 " + h + ':' + m + ':' + s + " 保存 "); + $(id2).html(""); + } + }, 10000); + + } else { + $("#e_tip_" + id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback) { + var editorName = window.editormd(id, { + width: width, + height: high, + path: path, // "/editormd/lib/" + + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onload: function () { + // this.previewing(); + $("#" + id + " [type=\"latex\"]").bind("click", function () { + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + id + " [type=\"inline\"]").bind("click", function () { + editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + md_elocalStorage(editorName, `memoNew_${id}`, "memoNew"); + + callback && callback() + } + }); + return editorName; +} + +function range(start, end) { + const result = []; + for (let i = start; i < end; i++) { + result.push(i); + } + return result; +} +function disabledDateTime() { + return { + // disabledHours: () => range(0, 24).splice(4, 20), + disabledMinutes: () => range(1, 30).concat(range(31, 60)), + // disabledSeconds: () => [0, 60], + }; +} + +function disabledDate(current) { + return current && current < moment().endOf('day').subtract(1, 'days'); +} +class Newshixuns extends Component { + constructor(props) { + super(props) + this.state = { + fileList: [], + newshixunlist: undefined, + departmentslist: undefined, + name: "", + main_type: "", + small_type: "", + trainee: "", + webssh: 0, + use_scope: 0, + can_copy: "", + scope_partment: undefined, + vnc: "", + scopetype: false, + postapplyvisible: false, + sendsure_applyvalue: undefined, + postapplytitle: false, + shixun_nametype: false, + main_types: false, + trainee_types: false, + SelectTheCommandtype: false, + opers: false, + operss: false, + TimePickervalue: "", + opensmail: false, + onSearchvalue: "", + scope_partmenttype: false, + languagewrite: undefined, + systemenvironment:undefined, + testcoderunmode:undefined, + file:undefined, + deleteisnot:true, + languagewritetype:false, + systemenvironmenttype:false, + testcoderunmodetype:false, + attachmentidstype:false, + datalisttype:false, + bottonloading:false + } + } + + initMD(initValue) { + this.contentChanged = false; + const placeholder = ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/api/attachments.json`; + // 创建editorMd + + const taskpass_editormd = create_editorMD("memoMD", '100%', 400, placeholder, imageUrl, () => { + setTimeout(() => { + taskpass_editormd.resize() + taskpass_editormd.cm && taskpass_editormd.cm.refresh() + }, 500) + + if (initValue) { + taskpass_editormd.setValue(initValue) + } + taskpass_editormd.cm.on("change", (_cm, changeObj) => { + // console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.taskpass_editormd = taskpass_editormd; + window.taskpass_editormd = taskpass_editormd; + + } + + componentDidMount() { + let newshixunUrl = `/shixuns/new.json`; + axios.get(newshixunUrl).then((response) => { + if (response.status === 200) { + if (response.data.message===undefined) { + this.setState({ + newshixunlist: response.data + }); + this.initMD(response.data.sample[0][1]); + } + + } + }).catch((error) => { + console.log(error) + }); + + 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) + }); + } + + setlanguagewrite = (e)=>{ + this.setState({ + languagewrite: e.target.value + }) + } + + setsystemenvironment = (e) => { + this.setState({ + systemenvironment: e.target.value + }) + } + settestcoderunmode = (e) => { + this.setState({ + testcoderunmode: e.target.value + }) + + } + shixunname = (e) => { + this.setState({ + name: e.target.value, + shixun_nametype: false + }); + } + + bigClass = (value) => { + this.setState({ + main_type: value + }) + } + + littleClass = (value) => { + this.setState({ + small_type: value + }) + } + + Selectthestudent = (value) => { + this.setState({ + trainee: value + }) + } + + SelectTheCommand = (e) => { + this.setState({ + webssh: e.target.value, + }); + + if (e.target.value === 2) { + this.setState({ + SelectTheCommandtype: true, + multi_webssh: false + }); + } else { + this.setState({ + SelectTheCommandtype: false, + multi_webssh: false + }); + } + } + + Selectpublic = (e) => { + this.setState({ + scopetype: false, + use_scope: e.target.value, + }); + if (e.target.value === 1) { + this.setState({ + scopetype: true + }); + } + + } + + Teacherscopy = (e) => { + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + can_copy: sum, + }); + } + + TeachersUbuntu = (e) => { + let sum = "" + if (e.target.checked === false) { + sum = 0 + } else if (e.target.checked === true) { + sum = 1 + } + this.setState({ + vnc: sum, + }); + } + + adduse_scopeinput = () => { + let {scope_partment} = this.state; + let array = scope_partment; + let newarray = "" + array.push(newarray) + this.setState({ + scope_partment: array, + }); + } + + shixunScopeInput = (e, id) => { + let types=false + let {scope_partment} = this.state; + let datalist = scope_partment; + if (datalist === undefined) { + datalist = [] + } + + datalist.map((item,key)=>{ + if(e===item){ + types=true + this.setState({ + datalisttype:true + }) + return + } + }) + + if(types===false){ + datalist.push(e) + this.setState({ + scope_partment: datalist, + onSearchvalue: "" + }); + } + + + } + + deleteScopeInput = (key) => { + let {scope_partment} = this.state; + let datalist = scope_partment; + datalist.splice(key, 1); + this.setState({ + scope_partment: datalist + }); + } + + //提交数据 + submit_new_shixun = () => { + const mdVal = this.taskpass_editormd.getValue(); + let {can_copy, main_type, name, scope_partment, small_type, trainee, use_scope, vnc, webssh, multi_webssh, TimePickervalue} = this.state; + let Url = `/shixuns.json` + if (name === "") { + this.setState({ + shixun_nametype: true + }) + this.props.showSnackbar("实训名称为空"); + $('html').animate({ + scrollTop: 10 + }, 1000); + return + } + if (main_type === "") { + this.setState({ + main_types: true + }) + $('html').animate({ + scrollTop: 700 + }, 1000); + this.props.showSnackbar("请选择技术平台大类别"); + + return + } + + if (use_scope === 1) { + if (scope_partment === undefined || scope_partment.length === 0) { + this.setState({ + scope_partmenttype: true + }) + $('html').animate({ + scrollTop: 900 + }, 1000); + this.props.showSnackbar("公开程度,指定单位为空"); + return + } + } + if (trainee === "") { + this.setState({ + trainee_types: true + }) + // $('html').animate({ + // scrollTop: 700 + // }, 1000); + this.props.showSnackbar("请选择发布信息"); + return + } + let newmulti_webssh = multi_webssh; + if (newmulti_webssh === true) { + newmulti_webssh = 1 + } else { + newmulti_webssh = "" + } + this.setState({ + bottonloading:true + }) + axios.post(Url, { + name: name, + can_copy: can_copy, + description: mdVal, + main_type: main_type, + scope_partment: scope_partment, + small_type: small_type, + trainee: trainee, + use_scope: use_scope, + vnc: vnc, + webssh: webssh, + multi_webssh: newmulti_webssh, + task_pass: 1, + opening_time: TimePickervalue + } + ).then((response) => { + if (response.status === 200) { + window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; + // window.open("/shixuns/"+response.data.shixun_identifier+"/challenges"); + }else{ + this.setState({ + bottonloading:false + }) + } + }).catch((error) => { + console.log(error) + this.setState({ + bottonloading:false + }) + }) + } + + + 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) => { + if (response.data.message===undefined) { + callback(response.data.shools_name); + } + }).catch((error) => { + console.log(error) + }); + } + + timeout = setTimeout(fake, 300); + } + + shixunHandleSearch = (value) => { + + this.shixunsfetch(value, departmentslist => this.setState({departmentslist})); + + this.setState({ + onSearchvalue: "" + }) + } + + post_apply = () => { + this.setState({ + postapplyvisible: true + }) + } + sendsure_apply = () => { + let {languagewrite,systemenvironment,testcoderunmode} = this.state; + // console.log("点击确定") + // console.log("languagewrite"+languagewrite); + // console.log("systemenvironment"+systemenvironment); + // console.log("testcoderunmode"+testcoderunmode); + + // let attachment_ids = undefined + // if (this.state.fileList) { + // attachment_ids = this.state.fileList.map(item => { + // return item.response ? item.response.id : item.id + // }) + // } + if(languagewrite === undefined || languagewrite === "" ){ + // this.props.showNotification(`请填写该镜像是基于什么语言`); + this.setState({ + languagewritetype:true + }) + return + } + if(systemenvironment === undefined || systemenvironment === ""){ + // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`); + this.setState({ + systemenvironmenttype:true + }) + return; + + } + if(testcoderunmode === undefined || testcoderunmode === "") { + // this.props.showNotification(`请填写该镜像中测试代码运行方式`); + this.setState({ + testcoderunmodetype:true + }) + return; + } + var attachment_ids=undefined; + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + + if( attachment_ids === undefined || attachment_ids.length===0){ + + // notification.open( + // { + // message: '提示', + // description: + // '请上传附件!', + // + // } + // ) + this.setState({ + attachmentidstype:true + }) + return; + } + // console.log("attachment_ids"+attachment_ids); + + // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids); + + var data={ + language:languagewrite, + runtime:systemenvironment, + run_method:testcoderunmode, + attachment_id:attachment_ids[0], + } + var url =`/shixuns/apply_shixun_mirror.json`; + axios.post(url,data + ).then((response) => { + + try { + if (response.data) { + // const { id } = response.data; + // if (id) { + if(this.state.file !== undefined){ + console.log("549"); + // this.deleteAttachment(this.state.file); + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + }else { + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + } + // this.props.showNotification('提交成功!'); + notification.open( + { + message: '提示', + description: + '提交成功!', + + } + ) + this.sendhideModaly() + // this.props.history.push(`/courses/${cid}/graduation_topics`); + // } + } + }catch (e) { + + } + + }) + + } + sendhideModaly = () => { + this.setState({ + postapplyvisible: false, + }) + if(this.state.file !== undefined){ + console.log("580"); + // this.deleteAttachment(this.state.file); + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + }else { + this.setState({ + file:undefined, + deleteisnot:true, + languagewrite:"", + systemenvironment:"", + testcoderunmode:"", + fileList:[] + }) + } + } + sendsure_applyvalues = (e) => { + this.setState({ + sendsure_applyvalue: e.target.value + }) + } + yeshidemodel = () => { + this.setState({ + postapplytitle: false + }) + } + + SelectTheCommandonChange = (e) => { + this.setState({ + multi_webssh: e.target.checked + }) + } + + + bigopen = (e) => { + this.setState({ + opers: true + }) + + } + + bigopens = (e) => { + this.setState({ + opers: false, + operss: false, + opensmail: false + }) + + } + + bigopensmal = (e) => { + this.setState({ + opensmail: true + }) + + } + + sbigopen = (e) => { + this.setState({ + operss: true + }) + + } + + // sbigopens=()=>{ + // this.setState({ + // operss:false + // }) + // } + + onChangeTimePicker = (value, dateString) => { + this.setState({ + TimePickervalue: dateString=== ""?"":moment(handleDateStrings(dateString)) + }) + } + + // 附件相关 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){ + 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); + }); + } + + + handleSubmit=()=>{ + // console.log(this.state.languagewrite) + // console.log(this.state.systemenvironment) + // console.log(this.state.testcoderunmode) + var attachment_ids; + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + // console.log(attachment_ids); + // var data={ + // language:"", + // runtime:"", + // run_method:"", + // attachment_id:"", + // } + // axios.post(url,data + // ).then((response) => { + // if (response.data) { + // // const { id } = response.data; + // // if (id) { + // this.props.showNotification('提交成功!'); + // // this.props.history.push(`/courses/${cid}/graduation_topics`); + // // } + // } + // }) + + + + } + render() { + const { getFieldDecorator } = this.props.form; + let {testcoderunmode ,systemenvironment,languagewrite,deleteisnot, fileList,TimePickervalue, scope_partmenttype, opensmail, newshixunlist, name, scope_partment, departmentslist, postapplyvisible, sendsure_applyvalue, postapplytitle, shixun_nametype, main_types, trainee_types, SelectTheCommandtype, opers, datalisttype, onSearchvalue} = this.state; + let options + if (departmentslist != undefined) { + options = this.state.departmentslist.map((d, k) => { + return ( + + ) + }) + } + const uploadProps = { + width: 600, + fileList, + multiple: true, + // https://github.com/ant-design/ant-design/issues/15505 + // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // showUploadList: false, + action: `${getUploadActionUrl()}`, + onChange: this.handleChange, + onRemove: this.onAttachmentRemove, + beforeUpload: (file, fileList) => { + + if (this.state.fileList.length >= 1) { + return false + } + // console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 50; + if (!isLt150M) { + // this.props.showNotification(`文件大小必须小于50MB`); + notification.open( + { + message: '提示', + description: + '文件大小必须小于50MB', + + } + ) + } + if(this.state.file !== undefined){ + console.log("763") + this.setState({ + file:file + }) + }else { + this.setState({ + file:file + }) + } + + console.log("handleChange2"); + return isLt150M; + }, + } + // const uploadProps = { + // width: 600, + // fileList, + // multiple: true, + // // https://github.com/ant-design/ant-design/issues/15505 + // // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // // showUploadList: false, + // action: `${getUrl()}/api/attachments.json`, + // onChange: this.handleChange, + // onRemove: this.onAttachmentRemove, + // beforeUpload: (file) => { + // // console.log('beforeUpload', file.name); + // const isLt50M = file.size / 1024 / 1024 < 50; + // if (!isLt50M) { + // this.props.showNotification('文件大小必须小于150MB!'); + // } + // return isLt50M; + // }, + // }; + + return ( + +
    +
    +
    + +
    +

    + 创建实训 + {this.props.user&&this.props.user.main_site===true?实训制作指南:""} +

    + +
    +

    实训名称

    +
    + * +
    + + + 必填项 + +
    + +
    +
    + +
    + + +
    + +

    简介

    + +
    +
    + +
    +
    +

    +

    +
    + +
    +

    技术平台

    +
    + * +
    + +

    + 列表中没有? + 申请新建 +

    + + + {/*
    */} +
    +
  • + + +
  • +
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + + +
    + +
  • +
    + {this.state.attachmentidstype===true?"请上传附件":""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    + {/*
    */} +
    + + + + +
    +

    新建申请已提交,请等待管理员的审核

    +
  • 我们将在1-2个工作日内与您联系 +
  • +
    +
    + 知道啦 +
    +
    +
    +
    +
    + +
    +

    请在配置页面完成后续的评测脚本设置操作

    +
    + 必填项 +
    +
    +
    + + +
    +

    命令行

    +
    + + 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) + 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) + 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) + + 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) + + +
    +
    + + +
    +

    公开程度

    +
    + + 对所有公开 (选中则所有已被试用授权的用户可以学习) + 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) + + +
    +
    +
    +
    +
    + +
    + (搜索选中添加单位名称) + {this.state.datalisttype===true?请勿选择重复单位:""} + {/*+ 添加*/} +
    +
    + +
    +
    + { + scope_partment === undefined ? "" : scope_partment.map((item, key) => { + return ( +
  • {item} + this.deleteScopeInput(key)}>× +
  • + ) + }) + } +
    + {/*{*/} + {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/} + {/*return(*/} + {/*
    */} + {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/} + {/*value={item}*/} + {/*/>*/} + {/*
    */} + + {/*)*/} + {/*})*/} + {/*}*/} +
    + + + + 请选择需要公开的单位 + +
    +
    +
    +
    + + +
    +

    发布信息

    +
    +
    + *面向学员: +
    + +
    + 实训难易度定位,不限定用户群体 +
    + 必填项 +
    +
    +
    +
  • + 复制: + + +
  • +
    + 开启时间: +
  • + + +
  • +
    +
    + {/*
    */} + {/*

    VNC图形化

    */} + {/*
  • */} + {/**/} + {/**/} + {/*
  • */} + {/*
    */} + + +
    + + 取消 +
    + + +
    +
    +
    + + ); + } +} +const NewshixunsNew = Form.create({ name: 'newshixunsnew' })(Newshixuns); +export default SnackbarHOC()(TPMIndexHOC(NewshixunsNew)); + + + + + + diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js new file mode 100644 index 000000000..cfa143ee0 --- /dev/null +++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js @@ -0,0 +1,329 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import { getImageUrl ,markdownToHTML, configShareForCustom} from 'educoder' + +import { CircularProgress } from 'material-ui/Progress'; + +import { Modal, Spin, Tooltip ,message,Icon} from 'antd'; +import LoadingSpin from '../../../../common/LoadingSpin'; +import 'antd/lib/pagination/style/index.css'; + +import '../shixunchildCss/Challenges.css' +import ReactDOM from 'react-dom'; +import axios from 'axios'; +import AccountProfile from"../../../user/AccountProfile"; +const $ = window.$; + + +class Challengesjupyter extends Component { + constructor(props) { + super(props) + this.state = { + ChallengesDataList: undefined, + operate: true, + startbtns: false, + iFrameHeight: '0px', + jupyter_port:0, + jupyter_url:null, + username:"", + booljupyterurls:false, + loading:false, + } + } + + ChallengesList = () => { + let id = this.props.match.params.shixunId; + let ChallengesURL = `/shixuns/` + id + `/challenges.json`; + + axios.get(ChallengesURL).then((response) => { + if (response.status === 200) { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + + }else{ + configShareForCustom(this.props.shixunsDetails.name, response.data.description) + this.setState({ + ChallengesDataList: response.data, + sumidtype: false, + }); + } + } + }).catch((error) => { + //console.log(error) + }); + } + + componentDidMount() { + setTimeout(this.ChallengesList(), 1000); + 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) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + setTimeout(() => { + this.setState({ + booljupyterurls:true, + }) + }, 600) + }else{ + if(response.data.status===0){ + + setTimeout(() => { + this.setState({ + jupyter_url:response.data.url, + jupyter_port:response.data.port, + booljupyterurls:true, + }) + }, 800) + + }else{ + setTimeout(() => { + this.setState({ + booljupyterurls:true, + }) + }, 600) + + } + } + + + }).catch((error) => { + setTimeout(() => { + this.setState({ + booljupyterurls:true, + }) + }, 600) + + }); + } + + updatamakedowns = () => { + this.setState({ + loading:true, + booljupyterurls:false + }) + 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) => { + if (response.data.status === 403||response.data.status === 401||response.data.status === 500) { + setTimeout(() => { + this.setState({ + booljupyterurls:true, + }) + }, 600) + }else{ + if(response.data.status===0){ + setTimeout(() => { + this.setState({ + jupyter_url:response.data.url, + jupyter_port:response.data.port, + booljupyterurls:true, + }) + }, 800) + this.setState({ + + }) + }else{ + setTimeout(() => { + this.setState({ + booljupyterurls:true, + }) + }, 600) + } + } + }).catch((error) => { + setTimeout(() => { + this.setState({ + booljupyterurls:true, + }) + }, 600) + + }); + + } + + + modifyjupyter=()=>{ + let id=this.props.match.params.shixunId; + var jupyter_port=""; + try{ + jupyter_port= parseInt(this.state.jupyter_port); + }catch (e) { + jupyter_port=this.state.jupyter_port; + + } + const url=`/jupyters/save_with_tpm.json`; + const data={ + identifier:id, + jupyter_port:jupyter_port, + } + axios.get(url, {params: data}) + .then((result) => { + if (result.data.status === 0) { + this.props.showNotification(`应用成功`); + } + }).catch((error) => { + }) + + } + + + render() { + let{ChallengesDataList,booljupyterurls}=this.state; + let id = this.props.match.params.shixunId; + const is_teacher = this.props&&this.props.current_user&&this.props.current_user.is_teacher?this.props.current_user.is_teacher:false; + + + + return ( + +
    +

    + 简介 + + + + + + +

    + +
    +

    + {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"": +

    + } +

    + { + booljupyterurls===true? + ( + this.state.jupyter_url === null? +
    + +

    加载实训失败,

    this.updatamakedowns()}>重新加载

    + +
    + + :"" + ) + :"" + } + + + + + { + this.state.jupyter_url === null || this.state.jupyter_url === undefined ? + "" + : + ( + is_teacher===true? +
    +
    +

    任务详情

    +

    (请将实训题目写在下方并保存)

    +
    +
    +
    this.modifyjupyter(this.state)}>

    应用到实训

    +
    +
    + : + "" + ) + + } + + + { + is_teacher===true? +
    +
    + { + this.state.jupyter_url===null || this.state.jupyter_url===undefined? + ( + booljupyterurls===false? + + :"" + ) + : + + } +
    +
    + :"" + } +
    +
    + +
    + + ) + } +} + +export default Challengesjupyter; diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css index 31917086f..112f381ee 100644 --- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css +++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css @@ -3,7 +3,134 @@ line-height: 30px; } +.height28 { + height: 30px; + line-height:28px; +} + .line27{ line-height: 27px; vertical-align: 1px; -} \ No newline at end of file +} +/* 中间居中 */ +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +/* 简单居中 */ +.intermediatecenterysls{ + display: flex; + align-items: center; +} +.spacearound{ + display: flex; + justify-content: space-around; + +} +.spacebetween{ + display: flex; + justify-content: space-between; +} +/* 头顶部居中 */ +.topcenter{ + display: -webkit-flex; + flex-direction: column; + align-items: center; + +} + + +/* x轴正方向排序 */ +/* 一 二 三 四 五 六 七 八 */ +.sortinxdirection{ + display: flex; + flex-direction:row; + +} +/* x轴反方向排序 */ +/* 八 七 六 五 四 三 二 一 */ +.xaxisreverseorder{ + display: flex; + flex-direction:row-reverse; +} +/* 垂直布局 正方向*/ +/* 一 + 二 + 三 + 四 + 五 + 六 + 七 + 八 */ +.verticallayout{ + display: flex; + flex-direction:column; +} +/* 垂直布局 反方向*/ +.reversedirection{ + display: flex; + flex-direction:column-reverse; +} + +.yslwushiwidth{ + width: 50%; +} +.yslwushiwidth90{ + width: 90%; +} +.yslwushiwidth10{ + width: 10%; +} +.yslwushiwidthbuton{ + width: 110px; +} +.yslwushiwidthcolortest{ + color: #A8A8A8; + font-size:16px; +} +.yslusername{ + color: #000000; + font-size: 18px; +} +.yslusercjz{ + width:60px; + height:28px; + border-radius:3px; + border:1px solid #F38B03; +} +.yslusercjztest{ + width:60px; + height:28px; + font-size:16px; + color:#F38B03; + line-height:28px; + text-align: center; +} +.w18{ + width: 18px; +} + +.maxnamewidth150{ + width: 150px; + max-width: 150px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.fabushixunwidth{ + color: #000000; + font-size: 16px; +} +.fabushixunwidthcolor{ + color: #4CACFF; + font-size: 16px; +} +.divfontexdivs{ + border-left: 1px solid #eeeeee; + border-top: 1px solid #eeeeee; + border-right: 1px solid #eeeeee; + border-bottom: 1px solid #eeeeee; +} diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js index d67599bf1..7a8e2ed75 100644 --- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js +++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { Redirect } from 'react-router'; -import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon} from 'antd'; +import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon,Pagination} from 'antd'; import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; @@ -48,7 +48,9 @@ class Collaborators extends Component { user_name:undefined, school_name:undefined, spinnings:false, - useristrue:false + useristrue:false, + mylistansum:6, + limit:20, } } componentDidMount() { @@ -434,7 +436,10 @@ class Collaborators extends Component { collaboratorListsumtype, user_name, school_name, - useristrue + useristrue, + mylistansum, + page, + limit } = this.state; let {loadingContent} = this.props; const radioStyle = { @@ -448,18 +453,32 @@ class Collaborators extends Component { console.log(Searchadmin) return ( -

    - this.showCollaboratorsvisible("cooperation")} - className="edu-default-btn edu-greenback-btn fr mr20 height40" - data-remote="true"> - + 添加合作者 - - this.showCollaboratorsvisible("admin")} - style={{display:this.props.identity===1?"block":"none"}} - data-remote="true" - className="edu-default-btn edu-greenback-btn fr mr20 height40">更换管理员 +

    +

    共{collaboratorList&&collaboratorList.length}人

    +
    + + +

    职业 单位

    + +
    @@ -584,39 +605,58 @@ class Collaborators extends Component { onClick={() => this.submit_add_collaborators_form()}>确定
    :""} - +
    { collaboratorList===undefined?"":collaboratorList.map((item,key)=>{ if(key - - 用户头像 -
    -

    - {item.user.name} - - {item.user.shixun_manager === true ? "(管理员)" : ""} -

    +
    + + 用户头像 -

    {item.user.identity}{item.user.school_name}

    -

    - 发布  {item.user.user_shixuns_count} - {/*粉丝  */} - {/*{item.user.fans_count}*/} - {/**/} -

    +
    +

    + {item.user.name} - {/*

    {item.user.brief_introduction}

    */} +

    {item.user.shixun_manager === true ? "创建者" : ""}

    +

    +

    +

    +

    {item.user.identity}

    +

    {item.user.school_name}

    +

    发布实训项目  {item.user.user_shixuns_count}

    +

    +
    + {item.user.shixun_manager === true ? "" : + + this.collaborators_delete(item.user.user_id)}> + + } +
    +

    + {/*

    */} + {/* */} + {/* /!*粉丝  *!/*/} + {/* /!*{item.user.fans_count}*!/*/} + {/* /!**!/*/} + {/*

    */} + {/*

    {item.user.brief_introduction}

    */}
    - - {item.user.shixun_manager === true ? "" : this.collaborators_delete(item.user.user_id)}>删除} {/*取消关注*/}
    @@ -647,7 +687,18 @@ class Collaborators extends Component { className={collaboratorList.length>10&&collaboratorListsumtype===true?"":"none"} style={{textAlign:'center',borderTop:'1px solid #eee'}}> 加载更多 -
    + {/*{*/} + {/* mylistansum>5?*/} + {/*
    */} + {/* */} + {/*
    */} + {/* :""*/} + {/*}*/} + +
    diff --git a/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js b/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js index 663c5fcf3..37a4217a6 100644 --- a/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js +++ b/public/react/src/modules/tpm/shixunchild/Repository/TPMRepositoryCommits.js @@ -1,145 +1,146 @@ -import React, { Component } from 'react'; - -import { Redirect } from 'react-router'; - -import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; - -import PropTypes from 'prop-types'; - -import classNames from 'classnames'; - -import axios from 'axios'; - -import TPMNav from '../../component/TPMNav' -import TPMRightSection from '../../component/TPMRightSection' -import { CircularProgress } from 'material-ui/Progress'; - -import { trace_collapse } from 'educoder' -const $ = window.$; - -// 点击按钮复制功能 -function jsCopy(){ - var e = document.getElementById("copy_rep_content"); - e.select(); - document.execCommand("Copy"); -} -class TPMRepositoryCommits extends Component { - constructor(props) { - super(props) - this.state = { - RepositoryList: undefined, - } - } - componentDidMount() { - let id = this.props.match.params.shixunId; - - let collaborators=`/shixuns/`+id+`/commits.json`; - axios.post(collaborators, { - secret_repository: this.props.secret_repository_tab - }).then((response)=> { - - if(response.status===200){ - this.setState({ - RepositoryList: response.data - }); - } - trace_collapse('repo commits res', response.data) - - }).catch((error)=>{ - console.log(error) - }); - - } - render() { - const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched, - aboutFocus, user, match - } = this.props; - let { RepositoryList } = this.state; - return ( - - -
    - {/* 可能会影响到其他页面的样式,需要测试、协商 */} -
    - - { loadingContent ? - - : - -
    -
    - - 提交记录 - - {/*  35 */} - - 返回 - -
    - - -
    -
      - { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{ - return ( -
    • - {item.email} -

      - {item.title} -

      - {item.time} - -
      -
    • ) - }) - } -
    -
    -
    - } -
    - -
    - -
    -
    - - -
    - - ); - } -} - -/** - { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{ - // {"email":"李暾","title":"2\n","id":"80cb6fc55a14bdd64a9c99913f416966238ed3de","time":"49年前"} - return ( -
    -
    {item.email}
    -
    {item.title}
    -
    {item.id}
    -
    {item.time}
    -
    - ) - }) - */ -export default TPMRepositoryCommits; +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import PropTypes from 'prop-types'; + +import classNames from 'classnames'; + +import axios from 'axios'; + +import TPMNav from '../../component/TPMNav' +import TPMRightSection from '../../component/TPMRightSection' +import { CircularProgress } from 'material-ui/Progress'; + +import { trace_collapse } from 'educoder' +const $ = window.$; + +// 点击按钮复制功能 +function jsCopy(){ + var e = document.getElementById("copy_rep_content"); + e.select(); + document.execCommand("Copy"); +} +class TPMRepositoryCommits extends Component { + constructor(props) { + super(props) + this.state = { + RepositoryList: undefined, + } + } + componentDidMount() { + let id = this.props.match.params.shixunId; + + let collaborators=`/shixuns/`+id+`/commits.json`; + axios.post(collaborators, { + secret_repository: this.props.secret_repository_tab + }).then((response)=> { + + if(response.status===200){ + this.setState({ + RepositoryList: response.data + }); + } + trace_collapse('repo commits res', response.data) + + }).catch((error)=>{ + console.log(error) + }); + + } + render() { + const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched, + aboutFocus, user, match + } = this.props; + let { RepositoryList } = this.state; + return ( + + +
    + {/* 可能会影响到其他页面的样式,需要测试、协商 */} +
    + + { loadingContent ? + + : + +
    +
    + + 提交记录 + + {/*  35 */} + + 返回 + +
    + + +
    +
      + { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{ + return ( +
    • + {item.email} +

      + {item.title} +

      + {item.time} + +
      +
    • ) + }) + } +
    +
    +
    + } +
    + +
    + +
    +
    + + +
    + + ); + } +} + +/** + { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{ + // {"email":"李暾","title":"2\n","id":"80cb6fc55a14bdd64a9c99913f416966238ed3de","time":"49年前"} + return ( +
    +
    {item.email}
    +
    {item.title}
    +
    {item.id}
    +
    {item.time}
    +
    + ) + }) + */ +export default TPMRepositoryCommits; diff --git a/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css b/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css index 493a95301..10d48c120 100644 --- a/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css +++ b/public/react/src/modules/tpm/shixunchild/shixunchildCss/Challenges.css @@ -25,4 +25,81 @@ .addshixuns{ height: 27px; line-height: 25px; -} \ No newline at end of file +} +.challenbaocun{ + width:103px; + height:30px; + background:#29BD8B; + border-radius:3px; + cursor:pointer +} +.challenbaocuntest{ + width:103px; + height:30px; + font-size:16px; + color:#FFFFFF; + text-align: center; + line-height:30px; + cursor:pointer +} +.renwuxiangqdiv{ + width:72px; + height:30px; + font-size:18px; + color:#000000; + line-height:30px; +} +.renwuxiangqdivtest{ + height:30px; + font-size:16px; + line-height:30px; +} + +.renwuxiangssi{ + width: 50%; +} +.renwuxiangssit{ + width: 50%; +} + +.pb47{ + padding-bottom: 47px; +} +.colorbluetwo{ + color: #1E8FFD; + font-size: 12px; + cursor:pointer; + margin-right: 18px; +} +.colorbluetest{ + color: #06101A; + font-size: 12px; + cursor:default +} +.shixunbingbaocun{ + font-size:14px; + color:#888888; +} +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +.iconfontysl{ + vertical-align:middle; + font-family:"iconfont" !important; + font-style:normal; + -webkit-font-smoothing: antialiased; + -webkit-text-stroke-width: 0.2px; + font-size: 100px; + color: #F5F5F5; +} +.juplbool{ + position: relative; +} + +.juplboolp{ + position: absolute; + bottom: 21px; +} diff --git a/public/react/src/modules/tpm/shixuns/ShixunCard.js b/public/react/src/modules/tpm/shixuns/ShixunCard.js index 9f62ed6b7..045f0009b 100644 --- a/public/react/src/modules/tpm/shixuns/ShixunCard.js +++ b/public/react/src/modules/tpm/shixuns/ShixunCard.js @@ -95,6 +95,33 @@ class ShixunCard extends Component { left: 10px; bottom: 125px; } + .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; + } ` } @@ -105,6 +132,14 @@ class ShixunCard extends Component { {/**/}
    } + { + item.is_jupyter===true? +
    +

    Jupyter

    + {/**/} +
    + :""} +
    diff --git a/public/react/src/modules/tpm/shixuns/ShixunSearchBar.js b/public/react/src/modules/tpm/shixuns/ShixunSearchBar.js index f9c4a7936..65f78502a 100644 --- a/public/react/src/modules/tpm/shixuns/ShixunSearchBar.js +++ b/public/react/src/modules/tpm/shixuns/ShixunSearchBar.js @@ -275,10 +275,10 @@ render() { }
  • this.diff_search(0)}>全部难度
  • -
  • this.diff_search(1)}>初级学员
  • -
  • this.diff_search(2)}>中级学员
  • -
  • this.diff_search(3)}>高级学员
  • -
  • this.diff_search(4)}>顶级学员
  • +
  • this.diff_search(1)}>初级
  • +
  • this.diff_search(2)}>中级
  • +
  • this.diff_search(3)}>中高级
  • +
  • this.diff_search(4)}>高级
  • diff --git a/public/react/src/modules/tpm/shixuns/ShixunsIndex.js b/public/react/src/modules/tpm/shixuns/ShixunsIndex.js index 15579610d..581301766 100644 --- a/public/react/src/modules/tpm/shixuns/ShixunsIndex.js +++ b/public/react/src/modules/tpm/shixuns/ShixunsIndex.js @@ -404,7 +404,7 @@ class ShixunsIndex extends Component { {...this.state} OnSearchInput={this.OnSearchInput.bind(this)} /> - + {/*下方图片*/} { + this.props.modalCancel() + } + + + + + render() { + + return( + +
    + { + this.props.itemtypebool===true? + +

    文件名重复

    + + :"" + } +

    {this.props.tittest}

    + +
    +
    + ) + } +} + +export default Tpmdatasetmodel; diff --git a/public/react/src/modules/tpm/tpmmodel/common.css b/public/react/src/modules/tpm/tpmmodel/common.css new file mode 100644 index 000000000..66780b2da --- /dev/null +++ b/public/react/src/modules/tpm/tpmmodel/common.css @@ -0,0 +1,318 @@ +/*.login_register_content, .login_register_content .ant-tabs-tabpane {*/ +/* !*display: flex;*!*/ +/* justify-content: center;*/ +/*}*/ +.login_register_content .ant-input { + background:rgb(244,244,244); +} +.login_register_content .loginInputzhucheyslass{ + border:1px solid red !important; +} +.login_register_content .loginInputzhucheyslass:hover{ + border:1px solid red !important; +} +.login_register_content { + width: 434px; + box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15); + border-radius:6px; + background: #fff; +} + .login_register_content .ant-tabs-ink-bar { + width: 21px !important; + left: 19px; + } + .login_register_content .ant-tabs { + width: 354px; + } + + .login_section { + width: 100%; + display:flex; + justify-content: center; + align-items: center; + flex-direction: column; + } +.login_sectionysl{ + width: 100%; + display:flex; + align-items: center; + flex-direction: column; +} + .loginInput { + width: 100%; + margin-bottom: 16px; + height: 45px; + } + + .educouddiv { + display: flex; + flex-direction: column; + } + + + .left_right { + width: 100%; + display: flex; + justify-content: space-between; + } + .login_btn { + width: 100%; + margin-top: 26px; + margin-bottom: 26px; + } + .dragValidator { + margin-bottom: 16px; + } + .ysldivhome1{ + display: flex; + flex-direction: row; + margin-left: 100px; + margin-right: 129px; + } + .ysldivhome2{ + width: 800px; + display: flex; + flex-flow: row wrap; + align-content:stretch; + } + .ysldivhomediv{ + width: 101px; + } + .ysldivhomediv1{ + width: 17%; + height: 100px; + border-radius:50%; + box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15); + background: #fff; + display: flex; + flex-direction:column; + margin-left: 6.5%; + margin-top: 1%; + } +.ysldivhomediv2{ + width: 17%; + height: 100px; + border-radius:50%; + box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15); + background: #fff; + display: flex; + flex-direction:column; + margin-left: 6.5%; + margin-top: 3%; +} + .ysldivhomedivtxt{ + width:86%; + height:27px; + margin-bottom: 5px; + font-size: 14px; + text-align: center; + + } + .ysldivhomedivimgsy{ + + } + .ysldivhomedivimg{ + width: 80%; + } + .ysllogin_register_contents{ + display: flex; + justify-content: center; + + } + .ysllogin_section { + display: flex; + align-items: center; + flex-direction: column; + box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15); + border-radius:6px; + background: #fff; + } + .yslspans1{ + text-align: center; + font-size: 13px; + color: #111C24; + } + .yslspans2{ + text-align: center; + font-size: 13px; + color: #05101A; + margin-top: 1%; + } + .yslspans3{ + text-align: center; + font-size: 12px; + color: #656565; + } + .yslbutton{ + width:255px; + height: 36px; + margin-top: 20px; + + } + .mt22{ + margin-top: 22px; + } + .gouxuanimg{ + margin-right: 10px; + margin-bottom: 2px; + } + .textall{ + text-align: center; + font-size: 13px; + color: #4B4B4B; + } + .div1img{ + display: flex; + justify-content:center; + width: 42%; + margin-left: 30%; + + } +.yslgouxuanimg{ + width: 20%; + height: 20px; + margin-left: 86%; + float: right; +} +.yslgouxuanimg2{ + height: 20px; +} + +.yslbutondls{ + display: flex; + flex-direction:row; +} +。yslinpulsy input{ + +} +.loginInputzhuche{ + width: 100%; + background-color: #fff!important; + height: 45px !important; + padding: 5px; + +} +.loginInputzhucheyslass { + width: 100%; + background-color: #fff!important; + height: 45px !important; + padding: 5px; + +} +.loginInputzhucheyslass .ant-input{ + width: 100%; + background-color: #fff!important; + height: 45px !important; + padding: 5px; + position: relative; + right: 5px; + width: 103%; + border: 1px solid #FF0000!important; + border-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.loginInputzhucheyslass .ant-input:hover{ + border: 1px solid #FF0000!important; + +} +.loginInputzhuche .ant-input{ + width: 100%; + background-color: #fff!important; + height: 45px !important; + padding: 5px; + position: relative; + right: 5px; + width: 103%; +} + +.loginInputzhucheysl{ + width: 100%; + background-color: #fff!important; + height: 45px !important; + padding: 5px; + border-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + +} +.loginInputzhucheysl .ant-input{ + width: 100%; + background-color: #fff!important; + height: 45px !important; + padding: 5px; + position: relative; + right: 5px; + width: 103%; + border: 1px solid #FF0000!important; + border-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.loginInputzhucheysl .ant-input:hover{ + border: 1px solid #FF0000!important; +} + +.bth100{ + width: 100px; + margin: 0 auto; +} +.ant-input-affix-wrapper .ant-input-prefix, .ant-input-affix-wrapper .ant-input-suffix { + background: transparent !important; +} + +.startlogin{ + color:#888; +} +.weixinheight390{ + height: 390px; +} +#log_reg_content { + padding: 38px 30px 20px !important; +} +.task-btn-blues{ + background:#5091FF; + color:#fff; + width:100px; + height:32px; + border-radius:4px; +} +a:hover.task-btn-blue-test{ + height:16px; + font-size:14px; + font-family:MicrosoftYaHei; + color:#FFFFff; + line-height:30px; +} +.task-btn-blue-test{ + height:16px; + font-size:14px; + font-family:MicrosoftYaHei; + color:#FFFFff; + line-height:30px; +} +.tabeltext-alignleftysl{ + font-size:14px; + color:#000000; + line-height:19px; + +} +.tabeltext-alignleftysltwo{ + font-size:14px; + color:#848282; + line-height:19px; + +} +/* 中间居中 */ +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/public/react/src/modules/tpm/tpmmodel/tpmmodel.css b/public/react/src/modules/tpm/tpmmodel/tpmmodel.css new file mode 100644 index 000000000..168de71b3 --- /dev/null +++ b/public/react/src/modules/tpm/tpmmodel/tpmmodel.css @@ -0,0 +1,129 @@ +.tpmborder{ + border: 1px solid; +} +/* 中间居中 */ +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +/* 简单居中 */ +.intermediatecenterysls{ + display: flex; + align-items: center; +} +.spacearound{ + display: flex; + justify-content: space-around; + +} +.spacebetween{ + display: flex; + justify-content: space-between; +} +/* 头顶部居中 */ +.topcenter{ + display: -webkit-flex; + flex-direction: column; + align-items: center; + +} + + +/* x轴正方向排序 */ +/* 一 二 三 四 五 六 七 八 */ +.sortinxdirection{ + display: flex; + flex-direction:row; +} +/* x轴反方向排序 */ +/* 八 七 六 五 四 三 二 一 */ +.xaxisreverseorder{ + display: flex; + flex-direction:row-reverse; +} +/* 垂直布局 正方向*/ +/* 一 + 二 + 三 + 四 + 五 + 六 + 七 + 八 */ +.verticallayout{ + display: flex; + flex-direction:column; +} +/* 垂直布局 反方向*/ +.reversedirection{ + display: flex; + flex-direction:column-reverse; +} +.deletebutom{ + width:85px; + height:30px; + background:#C4C4C4; + border-radius:3px; + cursor:pointer + +} +.deletebutomtext{ + width:28px; + height:19px; + font-size:14px; + color:#FFFFFF; + line-height:19px; + cursor:pointer +} +.deletebuttom{ + width:85px; + height:30px; + background:#29BD8B; + border-radius:3px; + cursor:pointer +} +.deletebuttomtest{ + width:56px; + height:19px; + font-size:14px; + color:#FFFFFF; + line-height:19px; + cursor:pointer + +} +.tpmwidth{ + width: 50%; +} +.mr21{ + margin-right: 21px; +} + +.wenjiantit{ + width: 220px; +} +.zuihoushijian{ + width: 125px; +} +.zuihouxiugairen{ + width: 70px; +} +.wenjiandaxiao{ + width: 56px; +} +.deletebutomtextcode{ + width:85px; + height:30px; + background:#FF5555; + border-radius:3px; + cursor:pointer + +} +.light-row{ + background: #F7F7F8; +} +.dark-row{ + background: #FFFFFF; + +} diff --git a/public/react/src/modules/user/usersInfo/InfosShixun.js b/public/react/src/modules/user/usersInfo/InfosShixun.js index 22c4e7fcf..4816b4ca6 100644 --- a/public/react/src/modules/user/usersInfo/InfosShixun.js +++ b/public/react/src/modules/user/usersInfo/InfosShixun.js @@ -329,6 +329,34 @@ class InfosShixun extends Component{ bottom: 100px; } .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; + } ` } @@ -350,6 +378,15 @@ class InfosShixun extends Component{ {/**/}
    } + { + item.is_jupyter===true? +
    +

    Jupyter

    + {/**/} +
    + :""} + + diff --git a/public/react/src/redux/actions/actionTypes.js b/public/react/src/redux/actions/actionTypes.js index 0f33b435c..55aa42799 100644 --- a/public/react/src/redux/actions/actionTypes.js +++ b/public/react/src/redux/actions/actionTypes.js @@ -50,6 +50,14 @@ const types = { SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息 SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值 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 + CHANGE_JUPYTER_CURRENT_PAGE: 'CHANGE_JUPYTER_CURRENT_PAGE' } export default types; diff --git a/public/react/src/redux/actions/index.js b/public/react/src/redux/actions/index.js index e52b88fc5..ad33061ba 100644 --- a/public/react/src/redux/actions/index.js +++ b/public/react/src/redux/actions/index.js @@ -31,6 +31,7 @@ import { testCaseOutputChange, updateTestAndValidate, updateOpenTestCaseIndex, + handleClickCancelPublish, } from './ojForm'; import { @@ -62,6 +63,16 @@ import { getUserInfoForNew } from './user'; +import { + getJupyterTpiDataSet, + getJupyterTpiUrl, + getJupyterInfo, + syncJupyterCode, + changeGetJupyterUrlState, + saveJupyterTpi, + changeCurrentPage +} from './jupyter'; + export default { toggleTodo, getOJList, @@ -79,6 +90,7 @@ export default { validateOjTimeLimit, validateOjCategory, validateOpenOrNot, + handleClickCancelPublish, addTestCase, deleteTestCase, testCaseInputChange, @@ -103,6 +115,14 @@ export default { restoreInitialCode, getUserInfoForNew, saveUserCodeForInterval, - saveEditorCodeForDetail + saveEditorCodeForDetail, + // jupyter + getJupyterTpiDataSet, + getJupyterTpiUrl, + getJupyterInfo, + syncJupyterCode, + changeGetJupyterUrlState, + saveJupyterTpi, + changeCurrentPage // isUpdateCodeCtx } \ No newline at end of file diff --git a/public/react/src/redux/actions/jupyter.js b/public/react/src/redux/actions/jupyter.js new file mode 100644 index 000000000..f641bb20f --- /dev/null +++ b/public/react/src/redux/actions/jupyter.js @@ -0,0 +1,152 @@ +/* + * @Description: jupyter tpi 相关内容 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 09:01:30 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 21:02:48 + */ +import types from "./actionTypes"; +import { message } from 'antd'; +import { + fetchJupyterTpiDataSet, + fetchJupyterTpiUrl, + fetchJupyterInfo, + fetchSyncJupyterCode, + fetchSaveJupyterTpi +} from "../../services/jupyterServer"; + +// 获取 jupyter 相关信息 +export const getJupyterInfo = (id) => { + return (dispatch, getState) => { + const { jupyter_pagination } = getState().jupyterReducer; + console.log(jupyter_pagination); + fetchJupyterInfo(id).then(res => { + if (res.data.status === 401) return; + if (res.status === 200) { + const { data } = res; + // if (data.status === 0) { + dispatch({ + type: types.SAVE_JUPYTER_INFO, + payload: data + }); + const { identifier, myshixun_identifier } = data; + dispatch(saveJupyterIdentifier(identifier)); + // 调用获取数据集接口 + dispatch(getJupyterTpiDataSet(identifier, jupyter_pagination)); + // 调用获取url接口 + dispatch(getJupyterTpiUrl({identifier: myshixun_identifier})); + // } + } + }) + } +} +// 获取 jupyter tpi 数据集 +export const getJupyterTpiDataSet = (identifier, params) => { + return (dispatch, getState) => { + if (!params) { + params = getState().jupyterReducer.jupyter_pagination; + } + fetchJupyterTpiDataSet(identifier, params).then(res => { + if (res.data.status === 401) return; // 用户未登录 + if (res.status === 200) { + const {data_sets, data_sets_count} = res.data; + dispatch({ + type: types.GET_JUPYTER_DATA_SETS, + payload: { + data_sets, + data_sets_count + } + }); + } + }); + } +} +// 获取 jupyter tpi 地址 +export const getJupyterTpiUrl = (obj) => { + return (dispatch, getState) => { + const {jupyter_info} = getState().jupyterReducer; + 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 + }); + }); + } +} +// 改变当前页数 +export const changeCurrentPage = (current) => { + return { + type: types.CHANGE_JUPYTER_CURRENT_PAGE, + payload: current + } +} \ No newline at end of file diff --git a/public/react/src/redux/actions/ojForUser.js b/public/react/src/redux/actions/ojForUser.js index e3480a435..79e2045d6 100644 --- a/public/react/src/redux/actions/ojForUser.js +++ b/public/react/src/redux/actions/ojForUser.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 13:42:11 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 19:05:36 + * @LastEditTime: 2019-12-13 16:49:42 */ import types from "./actionTypes"; import { Base64 } from 'js-base64'; @@ -19,6 +19,7 @@ import { fetchUserCodeSubmit, fetchRestoreInitialCode } from "../../services/ojService"; +import { notification } from "antd"; // 进入编程页面时,首先调用开启编程题接口 export const startProgramQuestion = (id, props) => { @@ -384,17 +385,21 @@ export const submitUserCode = (identifier, inputValue, type) => { } // 恢复初始代码 -export const restoreInitialCode = (identifier) => { +export const restoreInitialCode = (identifier, msg) => { return (dispatch) => { fetchRestoreInitialCode(identifier).then(res => { if (res.data.status === 401) return; - console.log('恢复初始代码====》》》》', res); + // console.log('恢复初始代码====》》》》', res); const {status, data} = res; if (status === 200) { dispatch({ type: types.RESTORE_INITIAL_CODE, payload: data.code - }) + }); + notification.success({ + message: '提示', + description: msg + }); } }); } diff --git a/public/react/src/redux/actions/ojForm.js b/public/react/src/redux/actions/ojForm.js index c49e628f3..3eaac9023 100644 --- a/public/react/src/redux/actions/ojForm.js +++ b/public/react/src/redux/actions/ojForm.js @@ -4,11 +4,16 @@ * @Github: * @Date: 2019-11-20 16:35:46 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 19:54:56 + * @LastEditTime: 2019-12-13 16:56:22 */ import types from './actionTypes'; import CONST from '../../constants'; -import { fetchPostOjForm, fetchGetOjById, publishTask } from '../../services/ojService'; +import { + fetchPostOjForm, + fetchGetOjById, + publishTask, + cancelPublicTask +} from '../../services/ojService'; import { Base64 } from 'js-base64'; import { message, notification, Modal } from 'antd'; import { toStore } from 'educoder'; @@ -80,6 +85,18 @@ const payloadInfo = (key, value, errMsg, validateInfo) => ({ } }); +// 接口调用成功后,跳转至列表页 +function linkToDev (dispatch, props) { + toStore('oj_description', ''); + dispatch({ + type: types.IS_MY_SOURCE, + payload: true + }); + setTimeout(() => { + props.history.push('/problems'); + }, 1000); +} + // 表单提交验证 export const validateOjForm = (props, type) => { return (dispatch, getState) => { @@ -229,59 +246,39 @@ export const validateOjForm = (props, type) => { paramsObj['identifier'] = identifier; } - // 接口调用成功后,跳转至列表页 - function linkToDev () { - toStore('oj_description', ''); - dispatch({ - type: types.IS_MY_SOURCE, - payload: true - }); - setTimeout(() => { - props.history.push('/problems'); - }, 1000); - } - // 调用保存或更新 if (type === 'publish') { // 提示发布信息 - Modal.confirm({ - title: '提示', - content: ` - 发布后即可应用到自己管理的课堂, - 是否确定发布?`, - okText: '确定', - cancelText: '取消', - onOk () { - publishTask(identifier).then(res => { - if (res.data.status === 0) { - message.success('发布成功!'); - linkToDev(); - } - dispatch({ - type: types.PUBLISH_LOADING_STATUS, - payload: false - }); - }).catch(() => { - dispatch({ - type: types.PUBLISH_LOADING_STATUS, - payload: false - }); - }); - }, - onCancel () { - dispatch({ - type: types.PUBLISH_LOADING_STATUS, - payload: false + publishTask(identifier).then(res => { + if (res.data.status === 0) { + // message.success('发布成功!'); + notification.success({ + message: '提示', + description: '发布成功!' }); + linkToDev(dispatch, props); } + dispatch({ + type: types.PUBLISH_LOADING_STATUS, + payload: false + }); + }).catch(() => { + dispatch({ + type: types.PUBLISH_LOADING_STATUS, + payload: false + }); }); } else { // 调用更新 fetchPostOjForm(paramsObj).then(res => { if (res.status === 200) { // 保存成功后,重新跳转至列表页 - if (res.data.identifier) { - message.success('保存成功!'); - linkToDev(); + if (res.data.status === 0) { + // message.success(paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功'); + notification.success({ + message: '提示', + description: paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功' + }); + linkToDev(dispatch, props); } dispatch({ type: types.SUBMIT_LOADING_STATUS, @@ -299,6 +296,33 @@ export const validateOjForm = (props, type) => { } } }; +// 撤销发布 +export const handleClickCancelPublish = (props, identifier) => { + return (dispatch) => { + cancelPublicTask(identifier).then(res => { + dispatch({ + type: types.PUBLISH_LOADING_STATUS, + payload: false + }); + if (res.status = 200) { + const { data} = res; + if (data.status === 0) { + // message.success('撤销发布成功!'); + notification.success({ + message: '提示', + description: '撤销发布成功!' + }); + linkToDev(dispatch, props); + } + } + }).catch(() => { + dispatch({ + type: types.PUBLISH_LOADING_STATUS, + payload: false + }); + }) + } +} // 保存提交的代码 export const saveOjFormCode = (value) => { return { diff --git a/public/react/src/redux/reducers/commonReducer.js b/public/react/src/redux/reducers/commonReducer.js index c551a803f..8a2e927cc 100644 --- a/public/react/src/redux/reducers/commonReducer.js +++ b/public/react/src/redux/reducers/commonReducer.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-27 16:27:09 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-03 11:00:19 + * @LastEditTime: 2019-12-12 17:36:51 */ import types from "../actions/actionTypes"; diff --git a/public/react/src/redux/reducers/index.js b/public/react/src/redux/reducers/index.js index 620905459..9c28448a3 100644 --- a/public/react/src/redux/reducers/index.js +++ b/public/react/src/redux/reducers/index.js @@ -13,6 +13,7 @@ import ojListReducer from './ojListReducer'; import ojForUserReducer from './ojForUserReducer'; import commonReducer from './commonReducer'; import userReducer from './userReducer'; +import jupyterReducer from './jupyterReducer'; export default combineReducers({ testReducer, @@ -20,5 +21,6 @@ export default combineReducers({ ojListReducer, ojForUserReducer, commonReducer, - userReducer + userReducer, + jupyterReducer }); diff --git a/public/react/src/redux/reducers/jupyterReducer.js b/public/react/src/redux/reducers/jupyterReducer.js new file mode 100644 index 000000000..f8825fb36 --- /dev/null +++ b/public/react/src/redux/reducers/jupyterReducer.js @@ -0,0 +1,70 @@ +/* + * @Description: + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 09:01:39 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 15:28:45 + */ +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: '', // 端口号 + jupyter_data_set_count: 1, // 数据集总数 + jupyter_pagination: { + page: 1, + limit: 20 // 默认加载20条 + } +}; + +const JupyterReducer = (state = initState, action) => { + switch (action.type) { + case types.GET_JUPYTER_DATA_SETS: + const { data_sets, data_sets_count } = action.payload; + return { + ...state, + jupyter_data_set: data_sets, + jupyter_data_set_count: data_sets_count + } + 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: + console.log('保存的jupyter_identifier', action.payload); + 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 + } + case types.CHANGE_JUPYTER_CURRENT_PAGE: + return { + ...state, + jupyter_pagination: Object.assign({}, state.jupyter_pagination, { page: action.payload }) + } + default: + return { + ...state + } + } +} + +export default JupyterReducer; diff --git a/public/react/src/redux/reducers/ojFormReducer.js b/public/react/src/redux/reducers/ojFormReducer.js index ce89bce9a..c2ba0f4d8 100644 --- a/public/react/src/redux/reducers/ojFormReducer.js +++ b/public/react/src/redux/reducers/ojFormReducer.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-20 16:40:32 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-09 16:30:46 + * @LastEditTime: 2019-12-13 11:54:35 */ import { Base64 } from 'js-base64'; import types from '../actions/actionTypes'; @@ -146,12 +146,16 @@ const ojFormReducer = (state = initialState, action) => { const { position } = action.payload; // 根据 position 去查找当前元素在数组中的位置 const index = state.testCases.findIndex((item) => item.position === position); + const tempTestCase = state.testCases || []; + const tempTestValicate = state.testCasesValidate || []; if (index > -1) { - state.testCases.splice(index, 1); // 删除当前元素 - state.testCasesValidate.splice(index, 1); // 删除测试用例对应的校验 + tempTestCase.splice(index, 1); // 删除当前元素 + tempTestValicate.splice(index, 1); // 删除测试用例对应的校验 } return { - ...state + ...state, + testCases: [...tempTestCase], + testCasesValidate: [...tempTestValicate] }; case types.SAVE_OJ_FORM_ID: state.identifier = action.payload; diff --git a/public/react/src/search/SearchPage.js b/public/react/src/search/SearchPage.js index 1bf1d83d4..c5e405861 100644 --- a/public/react/src/search/SearchPage.js +++ b/public/react/src/search/SearchPage.js @@ -20,12 +20,13 @@ class SearchPage extends Component{ page:1, perpages:20, data:[], + jupyterbool:false, } } //切换tab changeTab=(e)=>{ - // course 课堂, shixun 开发社区 subject 实践课程 memo 交流问答 + // course 2 课堂, shixun 0 实训项目 subject 1 实践课程 memo 3交流问答 let types =""; if(parseInt(e.key)===0){ @@ -106,7 +107,7 @@ class SearchPage extends Component{ } }).then((response) => { this.setState({ loading: false }) - + if(response === undefined){ return @@ -178,7 +179,19 @@ class SearchPage extends Component{
    - +
    {data === undefined ? "" : data.map((item, key) => { return ( @@ -193,10 +206,28 @@ class SearchPage extends Component{
    {/*标题*/} - +
    + + + { + type==="shixun"? + ( + item.is_jupyter===true? +

    Jupyter

    + :"" + ) + :"" + } +
    + {/*描述*/}
    + + + + {item.content.content === undefined || item.content.content===0?"": item.content.content.map((item4, key4) => { return ( {/*挑战名字*/} - - + + {item.content.challenge_names === undefined || item.content.challenge_names===0?"": item.content.challenge_names.map((item5, key5) => { return (
    @@ -269,13 +300,13 @@ class SearchPage extends Component{ {/* 主讲:{item.author_name} - {item.author_school_name} + {item.author_school_name} 任务: {item.challenges_count===undefined?0:item.challenges_count} - + 学习人数: @@ -287,7 +318,7 @@ class SearchPage extends Component{ {/* */} {item.author_name} {item.author_school_name} - + {!!item.challenges_count && {/* */} 任务: @@ -325,7 +356,7 @@ class SearchPage extends Component{ {/* */} 回复数:{item.all_replies_count} } - + {/* @@ -354,7 +385,7 @@ class SearchPage extends Component{ { count && count && count> perpages ? -
    +
    @@ -368,4 +399,4 @@ class SearchPage extends Component{ } } -export default SnackbarHOC() (TPMIndexHOC ( SearchPage )); \ No newline at end of file +export default SnackbarHOC() (TPMIndexHOC ( SearchPage )); diff --git a/public/react/src/search/searchc.css b/public/react/src/search/searchc.css index 15c34650b..a885f3a12 100644 --- a/public/react/src/search/searchc.css +++ b/public/react/src/search/searchc.css @@ -131,4 +131,46 @@ margin-top: 20px; display: flex; flex-direction:row; -} \ No newline at end of file +} +.jupytertext{ + width:54px; + height:24px; + text-align: center; + border-radius:5px; + border:1px solid #FF6802; + margin-top: 3px; + +} +.jupytertextp{ + width:54px; + height:16px; + line-height:16px; + font-size:12px; + color:#FF6802; + line-height:16px; +} +/* x轴正方向排序 */ +/* 一 二 三 四 五 六 七 八 */ +.sortinxdirection{ + display: flex; + flex-direction:row; +} +/* x轴反方向排序 */ +/* 八 七 六 五 四 三 二 一 */ +.xaxisreverseorder{ + display: flex; + flex-direction:row-reverse; +} +.intermediatecenter{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +.jupytertextheig{ + height: 32px; + line-height: 32px; +} +.ml9{ + margin-left: 9px; +} diff --git a/public/react/src/services/jupyterServer.js b/public/react/src/services/jupyterServer.js new file mode 100644 index 000000000..6ee5ec828 --- /dev/null +++ b/public/react/src/services/jupyterServer.js @@ -0,0 +1,35 @@ +/* + * @Description: jupyter相关接口 + * @Author: tangjiang + * @Github: + * @Date: 2019-12-12 09:07:07 + * @LastEditors: tangjiang + * @LastEditTime: 2019-12-13 16:00:45 + */ +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, params) { + const url = `/shixuns/${identifier}/get_data_sets.json`; + return axios.get(url, { params }); +} +// 获取 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 }); +} \ No newline at end of file diff --git a/public/react/src/services/ojService.js b/public/react/src/services/ojService.js index 74c243379..e13b66397 100644 --- a/public/react/src/services/ojService.js +++ b/public/react/src/services/ojService.js @@ -4,7 +4,7 @@ * @Github: * @Date: 2019-11-20 10:55:38 * @LastEditors: tangjiang - * @LastEditTime: 2019-12-10 20:46:16 + * @LastEditTime: 2019-12-13 17:03:47 */ import axios from 'axios'; @@ -84,10 +84,10 @@ export async function fetchUserCommitRecordDetail (identifier) { } // 恢复初始代码 -export async function restoreInitialCode (identifier) { - const url = `/myproblems/${identifier}/restore_initial_code.json`; - return axios.get(url); -} +// export async function restoreInitialCode (identifier) { +// const url = `/myproblems/${identifier}/restore_initial_code.json`; +// return axios.get(url); +// } // 发布任务 export async function publishTask (identifier) { @@ -95,6 +95,12 @@ export async function publishTask (identifier) { return axios.post(url); } +// 撤销发布 +export async function cancelPublicTask (identifier) { + const url = `/problems/${identifier}/cancel_publish.json`; + return axios.post(url); +} + // 更新用户编辑代码 export async function fetchUpdateCode (identifier, params) { const url = `/myproblems/${identifier}/update_code.json`; @@ -109,7 +115,8 @@ export async function fetchUserCodeSubmit (identifier) { // 恢复初始代码 export async function fetchRestoreInitialCode (identifier) { - const url = `/myproblems/${identifier}/restore_initial_code.json`; + // const url = `/myproblems/${identifier}/restore_initial_code.json`; + const url = `/myproblems/${identifier}/sync_code.json`; return axios.post(url); } diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css index 89b62856d..84bca6a78 100644 --- a/public/stylesheets/educoder/edu-main.css +++ b/public/stylesheets/educoder/edu-main.css @@ -674,7 +674,7 @@ input.radio-width90{ width: 90px; } .ringauto{width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 50%;background-color: #F4FAFF;margin-right:5px;} /*-------------------个人主页:右侧提示区域--------------------------*/ -.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;} +.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:80px;z-index: 10;} .-task-sidebar div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;} .-task-sidebar div i{ color:#fff;} .-task-sidebar div i:hover{color: #fff!important;} @@ -820,4 +820,4 @@ html>body #ajax-indicator { position: fixed; } .footer_con-p{ color: #898989 !important; -} \ No newline at end of file +} diff --git a/public/stylesheets/educoder/iconfont/iconfont.css b/public/stylesheets/educoder/iconfont/iconfont.css index 29e19aee4..f9c2e1e68 100644 --- a/public/stylesheets/educoder/iconfont/iconfont.css +++ b/public/stylesheets/educoder/iconfont/iconfont.css @@ -1,10 +1,10 @@ @font-face {font-family: "iconfont"; - src: url('iconfont.eot?t=1572859243353'); /* IE9 */ - src: url('iconfont.eot?t=1572859243353#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), - url('iconfont.woff?t=1572859243353') format('woff'), - url('iconfont.ttf?t=1572859243353') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ - url('iconfont.svg?t=1572859243353#iconfont') format('svg'); /* iOS 4.1- */ + src: url('iconfont.eot?t=1576206033975'); /* IE9 */ + src: url('iconfont.eot?t=1576206033975#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), + url('iconfont.woff?t=1576206033975') format('woff'), + url('iconfont.ttf?t=1576206033975') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ + url('iconfont.svg?t=1576206033975#iconfont') format('svg'); /* iOS 4.1- */ } .iconfont { @@ -55,6 +55,10 @@ content: "\e6bc"; } +.icon-jinzhi:before { + content: "\e6d4"; +} + .icon-vs:before { content: "\e682"; } @@ -115,6 +119,10 @@ content: "\e609"; } +.icon-liulan:before { + content: "\e6c7"; +} + .icon-luyou:before { content: "\e677"; } @@ -295,6 +303,10 @@ content: "\e694"; } +.icon-bokeyuan:before { + content: "\e6c6"; +} + .icon-base:before { content: "\e683"; } @@ -799,6 +811,10 @@ content: "\e68c"; } +.icon-pinglun:before { + content: "\e6c8"; +} + .icon-gongcheng:before { content: "\e60f"; } @@ -811,6 +827,10 @@ content: "\e604"; } +.icon-shangjiantou-tianchong:before { + content: "\e733"; +} + .icon-zhuye:before { content: "\e6d3"; } @@ -839,6 +859,10 @@ content: "\e6a1"; } +.icon-shenglvehao:before { + content: "\e708"; +} + .icon-paixu1:before { content: "\e6aa"; } @@ -923,3 +947,43 @@ content: "\e6c4"; } +.icon-bangdingshoujihao:before { + content: "\e6ca"; +} + +.icon-biaoqian1:before { + content: "\e6ce"; +} + +.icon-jilu:before { + content: "\e6cf"; +} + +.icon-shu:before { + content: "\e6d0"; +} + +.icon-tuijian:before { + content: "\e6d1"; +} + +.icon-chuangjianzhe:before { + content: "\e6d2"; +} + +.icon-wancheng1:before { + content: "\e6cb"; +} + +.icon-qiyezhanghao:before { + content: "\e6cc"; +} + +.icon-gerenzhanghao:before { + content: "\e6cd"; +} + +.icon-jiazaishibai1:before { + content: "\e6d6"; +} +