Merge branches 'dev_aliyun' and 'dev_newshixunModel' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_newshixunModel

dev_cs
杨树明 5 years ago
commit 031b9df0ba

@ -1,5 +1,6 @@
function createMDEditor(element, opts){
var defaults = {
height: 600,
path: '/editormd/lib/',
syncScrolling: "single",
tex: true,

@ -5,6 +5,8 @@ class Admins::BaseController < ApplicationController
layout 'admin'
skip_before_action :verify_authenticity_token
before_action :require_login, :require_admin!
after_action :rebind_event_if_ajax_render_partial

@ -191,21 +191,28 @@ class ChallengesController < ApplicationController
sets_input = test_set.map(&:input)
sets_open = test_set.map(&:is_public)
set_score = test_set.map(&:score)
set_match_rule = test_set.map(&:match_rule)
params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0}
params_output = params[:test_set].map{|set| set[:output] }
params_input = params[:test_set].map{|set| set[:input] }
params_score = params[:test_set].map{|set| set[:score]}
params_test_set = params[:test_set].map{|set| set[:match_rule]}
# 测试集变化则需要更新(输入、 输出、 是否隐藏)
if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || set_score != params_score
if sets_output != params_output || sets_open != params_hidden || sets_input != params_input ||
set_score != params_score || params_test_set != set_match_rule
test_set.delete_all unless test_set.blank?
params[:test_set].each_with_index do |set, index|
TestSet.create(:challenge_id => @challenge.id,
:input => "#{set[:input]}",
:output => "#{set[:output]}",
:is_public => params_hidden[index],
:score => set[:score],
:position => (index + 1))
end
params[:test_set].each_with_index do |set, index|
# last 末尾匹配, full: 全完匹配
logger.info("set: #{set}; match_rule : #{set[:match_rule]}")
match_rule = set[:match_rule] == 'last' ? 'last' : 'full'
TestSet.create(:challenge_id => @challenge.id,
:input => "#{set[:input]}",
:output => "#{set[:output]}",
:is_public => params_hidden[index],
:score => set[:score],
:match_rule => "#{match_rule}",
:position => (index + 1))
end
@challenge.update_column(:modify_time, Time.now)
# 测试集的
@shixun.myshixuns.update_all(:system_tip => 0)

@ -33,10 +33,11 @@ class CoursesController < ApplicationController
before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate,
:transfer_to_course_group, :delete_from_course, :export_member_scores_excel,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup,
:add_teacher, :export_couser_info, :export_member_act_score]
:add_teacher, :export_couser_info, :export_member_act_score,
:update_informs, :new_informs, :delete_informs]
before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin,
:set_course_group, :create_group_by_importing_file, :update_informs, :new_informs,
:update_task_position, :tasks_list, :delete_informs]
:set_course_group, :create_group_by_importing_file,
:update_task_position, :tasks_list]
before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group,
:change_course_teacher, :course_group_list,
:teacher_application_review, :apply_teachers, :delete_course_teacher]

@ -67,13 +67,19 @@ class GamesController < ApplicationController
uri = "#{shixun_tomcat}/bridge/vnc/getvnc"
params = {tpiID: @myshixun.id, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(@shixun))}"}
res = uri_post uri, params
logger.info("###############---- ")
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级99")
end
# 无域名版本
#@vnc_url = "http://#{service_host}:#{res['port']}/vnc_lite.html?password=headless"
# 有域名版本
@vnc_url = "https://#{res['port']}.#{service_host}/vnc_lite.html?password=headless"
if request.subdomain == "pre-newweb"
# 无域名版本
@vnc_url = "http://#{service_host}:#{res['port']}/vnc_lite.html?password=headless"
else
# 有域名版本
@vnc_url = "https://#{res['port']}.#{service_host}/vnc_lite.html?password=headless"
end
@vnc_evaluate = @shixun.vnc_evaluate
rescue Exception => e
Rails.logger.error(e.message)
@ -531,10 +537,12 @@ class GamesController < ApplicationController
game_challenge.test_sets.each do |test_set|
input = test_set.input.nil? ? "" : test_set.input.gsub("\r\n", "\n")
output = test_set.output.nil? ? "" : test_set.output.gsub("\r\n", "\n")
test_cases = {:input => input, :output => output}
test_cases = {:input => input, :output => output, :matchRule => test_set.match_rule}
testSet << test_cases
end
logger.info("##############testSet: #{testSet}")
testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank?
# 评测类型: 012 用于webssh的评测 3用于vnc
podType = @shixun.vnc_evaluate ? 3 : @shixun.webssh
@ -554,6 +562,15 @@ class GamesController < ApplicationController
# needPortMapping web类型需要pod端口映射
br_params[:needPortMapping] = 8080 if @myshixun.mirror_name.include?("Web")
# 私密仓库的设置
secret_rep = @shixun.shixun_secret_repository
logger.info("############secret_rep: #{secret_rep}")
if secret_rep&.repo_name
secretGitUrl = repo_url secret_rep.repo_path
br_params.merge!({secretGitUrl: Base64.urlsafe_encode64(secretGitUrl), secretDir: secret_rep.secret_dir_path})
logger.info("#######br_params:#{br_params}")
end
# 中间层交互
uri = "#{shixun_tomcat}/bridge/game/gameEvaluate"
res = interface_post uri, br_params, 502, "gameEvaluate failed"

@ -109,8 +109,8 @@ class GraduationTopicsController < ApplicationController
@attachments = @graduation_topic.attachments
left_banner_content = @course.course_modules.search_by_module_type("graduation")
if left_banner_content.present?
@left_banner_id = left_banner_content.first.course_second_categories.first.id
@left_banner_name = left_banner_content.first.course_second_categories.first.name
@left_banner_id = left_banner_content.first.id
@left_banner_name = "毕设选题"
end
end

@ -265,6 +265,7 @@ class QuestionBanksController < ApplicationController
# exercise.update_column(:quotes, exercise.quotes+1)
# end
new_exercise if new_exercise.save!
exercise.update_column(:quotes, exercise.quotes+1)
end
end
@ -292,6 +293,7 @@ class QuestionBanksController < ApplicationController
# poll.update_column(:quotes, poll.quotes+1)
# end
new_poll if new_poll.save!
poll.update_column(:quotes, poll.quotes+1)
end
end

@ -220,6 +220,16 @@ class ShixunsController < ApplicationController
evaluate_script: @shixun.evaluate_script)
end
# 同步私密版本库
if @shixun.shixun_secret_repository
repo_name = "#{current_user.login}/secret_#{@shixun.identifier}"
fork_repository_name = "#{current_user.login}/secret_#{@new_shixun.identifier}"
ShixunSecretRepository.create!(shixun_id: @new_shixun.id,
repo_name: "#{repo_name}",
secret_dir_path: @shixun.shixun_secret_repository.secret_dir_path)
GitService.fork_repository(repo_path: "#{repo_name}.git", fork_repository_path: (fork_repository_name + ".git"))
end
# 同步镜像
if @shixun.mirror_repositories.present?
@shixun.mirror_repositories.each do |mirror|
@ -448,6 +458,7 @@ class ShixunsController < ApplicationController
ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror)
end
end
logger.info("#########shixun_params#{shixun_params}")
@shixun.update_attributes(shixun_params)
logger.info("##########shixun_info_params: #{shixun_info_params}")
logger.info("##########params[:shixun_info][:evaluate_script]: #{params[:shixun_info][:evaluate_script]}")
@ -472,8 +483,20 @@ class ShixunsController < ApplicationController
@shixun.shixun_service_configs.create!(config) if name.present?
end
end
# 添加第二仓库
if params[:is_secret_repository]
add_secret_repository
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)
uid_logger_error("实训保存失败--------#{e.message}")
tip_exception("实训保存失败")
raise ActiveRecord::Rollback
end
@ -818,6 +841,30 @@ class ShixunsController < ApplicationController
end
end
# 设置私密版本库的在tpm中的目录
def set_secret_dir
raise("设置路径不能为空") if params[:secret_dir_path].blank?
raise("请先配置私密版本库") if @shixun.shixun_secret_repository.blank?
@shixun.shixun_secret_repository.update_attributes(:secret_dir_path => params[:secret_dir_path])
normal_status("设置成功")
end
def secret_repository
begin
@repo_path = @shixun.shixun_secret_repository&.repo_path
@repo_url = repo_url @repo_path
@trees = GitService.file_tree(repo_path: @repo_path, path: params[:path])
logger.info("#11@@#@#@#@111#@@@@###{@trees}")
if @trees
logger.info("#@@#@#@#@#@@@@###{@trees.try(:count)}")
@latest_commit = [GitService.commits(repo_path: @repo_path).first]
Rails.logger.info("########## #{@latest_commit}")
end
rescue Exception => e
logger.error(e.message)
end
end
include GitCommon
def update_file
@ -954,7 +1001,13 @@ private
end
def find_repo_name
@repo_path = @shixun.try(:repo_path)
# 有私密版本库的参数时,需要拿私密仓库
@repo_path = if params[:secret_repository]
@shixun.shixun_secret_repository&.repo_path
else
@shixun.try(:repo_path)
end
logger.info("######{@repo_path}")
@path = params[:path]
end
@ -989,4 +1042,13 @@ private
modify_shixun = ShixunModify.exists?(:myshixun_id => current_myshixun.id, :shixun_id => @shixun.id, :status => 1)
games.size != min_challenges.size || modify_shixun
end
# 添加私密仓库
def add_secret_repository
# 防止跟tpm版本库重名加了前缀secret
repo_path = repo_namespace(current_user.login, "secret_#{@shixun.identifier}")
GitService.add_repository(repo_path: repo_path)
ShixunSecretRepository.create!(repo_name: repo_path.split(".")[0], shixun_id: @shixun.id)
end
end

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

@ -12,7 +12,7 @@ class TaskBanksController < ApplicationController
ActiveRecord::Base.transaction do
begin
@bank.update_attributes(gtask_bank_params)
Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids].blank?
Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
normal_status(0, "更新成功")
rescue Exception => e
uid_logger(e.message)

@ -1,11 +1,12 @@
class Users::QuestionBanksController < Users::BaseController
before_action :require_login
before_action :private_user_resources!
skip_before_action :check_observed_user_exists!
# before_action :private_user_resources!
before_action :check_query_params!
before_action :check_user_permission!
def index
service = Users::QuestionBankService.new(observed_user, query_params)
service = Users::QuestionBankService.new(User.current, query_params)
question_banks = service.call
@count = question_banks.count
@ -30,7 +31,7 @@ class Users::QuestionBanksController < Users::BaseController
.where(commit_status: 1, exercises: { exercise_bank_id: question_bank_ids })
.group('exercises.exercise_bank_id').count
when 'poll' then
PollUser.joins(:poll).where(polls: { exercise_bank_id: question_bank_ids })
PollUser.joins(:poll).where(commit_status: 1, polls: { exercise_bank_id: question_bank_ids })
.group('polls.exercise_bank_id').count
when 'gtask' then
GraduationWork.has_committed.joins(:graduation_task)

@ -1,7 +1,7 @@
class GtopicBank < ApplicationRecord
belongs_to :user
belongs_to :graduation_topic
belongs_to :course_list
belongs_to :graduation_topic, optional: true
belongs_to :course_list, optional: true
has_many :attachments, as: :container, dependent: :destroy
has_many :graduation_topics, dependent: :nullify

@ -24,7 +24,7 @@ module Searchable::Course
author_name: teacher&.real_name,
author_school_name: teacher&.school_name,
visits_count: visits,
members_count: members_count,
members_count: course_members_count,
is_public: is_public == 1,
first_category_url: ApplicationController.helpers.module_url(none_hidden_course_modules.first, self)
}

@ -38,6 +38,9 @@ class Shixun < ApplicationRecord
has_one :shixun_info, dependent: :destroy
# 第二版本库
has_one :shixun_secret_repository, dependent: :destroy
belongs_to :user
# 实训服务配置
has_many :shixun_service_configs, :dependent => :destroy

@ -0,0 +1,11 @@
class ShixunSecretRepository < ApplicationRecord
# repo_name: 仓库名
# secret_dir_name: 在tpm仓库的那个目录下
belongs_to :shixun
def repo_path
"#{repo_name}.git"
end
end

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

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

@ -1,2 +1,3 @@
class TestSet < ApplicationRecord
# match_rule: 匹配规则: full 完全匹配, last 末尾匹配
end

@ -16,7 +16,7 @@ elsif @tab == 1
json.has_web_route @shixun.has_web_route?
json.test_sets @challenge.test_sets do |set|
json.hidden (set.is_public ? 0 : 1)
json.(set, :input, :output, :score)
json.(set, :input, :output, :score, :match_rule)
end
elsif @tab == 2
# 参考答案

@ -6,6 +6,12 @@ json.results do
json.title highlights.delete(:name)&.join('...') || obj.searchable_title
# json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('<br/>')
# 去除开头标点符号
reg = /^[,。?:;‘’!“”—……、]/
highlights[:description]&.first&.sub!(reg, '')
highlights[:content]&.first&.sub!(reg, '')
json.content highlights
end
end

@ -0,0 +1,8 @@
json.trees @trees
if @trees.present?
json.partial! 'shixuns/commit', locals: { commits: @latest_commit }
end
json.git_url @repo_url
json.secret_dir_path @shixun.shixun_secret_repository&.secret_dir_path

@ -30,6 +30,8 @@ json.shixun do
json.scope_partment @shixun.schools.map(&:name) # 公开范围
json.opening_time @shixun.opening_time
json.forbid_copy @shixun.forbid_copy
# 私密仓库
json.is_secret_repository @shixun.shixun_secret_repository.present?
# 实训服务配置
json.shixun_service_configs do

@ -2,3 +2,4 @@ json.fork_from @fork_from
json.identity User.current.shixun_identity(@shixun)
json.power @power
json.partial! 'shixuns/top', locals: { shixun: @shixun, current_myshixun: @current_myshixun }
json.secret_repository @shixun.shixun_secret_repository.present?

@ -0,0 +1,3 @@
json.comment_id @comment.id
json.status 0
json.message "评阅成功"

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

@ -1,35 +1,33 @@
#coding=utf-8
module SessionExtenstions
module EntryExtension
def compressed?
@compressed
end
def value
if @value
begin
Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value)
rescue TypeError
compressed? ? Zlib::Inflate.inflate(@value) : @value
end
end
end
def size
if @value.nil?
0
else
@value.bytesize
end
end
end
end
ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1)
ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension)
#coding=utf-8
module SessionExtenstions
module EntryExtension
def compressed?
@compressed
end
def value
if @value
begin
Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value)
rescue TypeError
compressed? ? Zlib::Inflate.inflate(@value) : @value
end
end
end
def size
if @value.nil?
0
else
@value.bytesize
end
end
end
end
ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1)
ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension)

@ -55,12 +55,14 @@ Rails.application.routes.draw do
get :homepage_info
end
get :question_banks, on: :collection, to: 'users/question_banks#index'
scope module: :users do
resources :courses, only: [:index]
resources :shixuns, only: [:index]
resources :projects, only: [:index]
resources :subjects, only: [:index]
resources :question_banks, only: [:index]
# resources :question_banks, only: [:index]
resource :experience_records, only: [:show]
resource :grade_records, only: [:show]
resource :watch, only: [:create, :destroy]
@ -195,6 +197,8 @@ Rails.application.routes.draw do
get :get_script_contents
get :get_custom_script
post :repository
post :secret_repository
post :set_secret_dir
post :commits
post :file_content
post :update_file

@ -0,0 +1,31 @@
class MigrateBankReferenceId < ActiveRecord::Migration[5.2]
def change
HomeworkBank.all.each do |bank|
if bank.homework_common
bank.homework_common.update_column("homework_bank_id", bank.id) if bank.homework_common.homework_bank_id.nil?
end
end
GtopicBank.all.each do |bank|
if bank.graduation_topic
bank.graduation_topic.update_column("gtopic_bank_id", bank.id) if bank.graduation_topic.gtopic_bank_id.nil?
end
end
GtaskBank.all.each do |bank|
if bank.graduation_task
bank.graduation_task.update_column("gtask_bank_id", bank.id) if bank.graduation_task.gtask_bank_id.nil?
end
end
ExerciseBank.all.each do |bank|
if bank.container_type == 'Exercise'
exercise = Exercise.find_by(id: bank.container_id)
exercise.update_column("exercise_bank_id", bank.id) if exercise && exercise.exercise_bank_id.nil?
elsif bank.container_type == 'Poll'
poll = Poll.find_by(id: bank.container_id)
poll.update_column("exercise_bank_id", bank.id) if poll && poll.exercise_bank_id.nil?
end
end
end
end

@ -0,0 +1,28 @@
class MigrateBankQuotes < ActiveRecord::Migration[5.2]
def change
HomeworkBank.all.each do |bank|
task_count = bank.homework_commons.count
bank.update_column("quotes", task_count == 0 ? 1 : task_count)
end
GtopicBank.all.each do |bank|
task_count = bank.graduation_topics.count
bank.update_column("quotes", task_count == 0 ? 1 : task_count)
end
GtaskBank.all.each do |bank|
task_count = bank.graduation_tasks.count
bank.update_column("quotes", task_count == 0 ? 1 : task_count)
end
ExerciseBank.all.each do |bank|
if bank.container_type == 'Exercise'
task_count = bank.exercises.count
bank.update_column("quotes", task_count == 0 ? 1 : task_count)
elsif bank.container_type == 'Poll'
task_count = bank.polls.count
bank.update_column("quotes", task_count == 0 ? 1 : task_count)
end
end
end
end

@ -0,0 +1,10 @@
class CreateShixunSecretRepositories < ActiveRecord::Migration[5.2]
def change
create_table :shixun_secret_repositories do |t|
t.references :shixun
t.string :repo_name
t.string :secret_dir_path
t.timestamps
end
end
end

@ -0,0 +1,7 @@
class AddMatchRuleForTestSets < ActiveRecord::Migration[5.2]
def change
add_column :test_sets, :match_rule, :string
TestSet.update_all(match_rule: 'full')
end
end

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

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

@ -37,7 +37,7 @@ import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
import history from './history';
import {SnackbarHOC} from 'educoder'
import {SnackbarHOC, configShareForIndex} from 'educoder'
import {initAxiosInterceptors} from './AppConfig'
@ -326,22 +326,7 @@ class App extends Component {
});
wx.ready(function () {
console.log('wx is ready')
var shareData = {
title: 'EduCoder',
desc: '创新源于实践',
link: currentUrl,
imgUrl: window.__testImageUrl
|| (currentUrl.endsWith('/') ? currentUrl : currentUrl + '/') + 'images/educoder/index/subject/subject15.jpg'
};
wx.onMenuShareAppMessage(shareData);//分享给好友
wx.onMenuShareTimeline(shareData);//分享到朋友圈
wx.onMenuShareQQ(shareData);//分享给手机QQ
wx.onMenuShareWeibo(shareData);//分享腾讯微博
wx.onMenuShareQZone(shareData);//分享到QQ空间
configShareForIndex()
});
wx.error(function (res) {
console.log('wx is error')

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

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

@ -391,7 +391,7 @@ class CommonWorkDetailIndex extends Component{
{ work_statuses && work_statuses.indexOf('补交作品') != -1 &&
<a className={"fr color-blue font-16"} href={"javascript:void(0)"}
onClick={() => { this.props.toWorkPostPage(this.props.match.params, null, true, work_id)}}>
onClick={() => { this.props.toWorkPostPage(this.props.match.params)}}>
补交作品</a> }
{work_statuses && work_statuses.indexOf('修改作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}

@ -100,6 +100,7 @@ class NewWorkForm extends Component{
const courseId = this.state.course_id || this.props.match.params.coursesId ;
this.props.form.validateFieldsAndScroll((err, values) => {
if(err && err.personNum) delete err.personNum;
console.log(values)
const mdContnet = this.contentMdRef.current.getValue().trim();
console.log(mdContnet)
@ -135,7 +136,7 @@ class NewWorkForm extends Component{
}
// const errKeys = Object.keys(err); // || errKeys.length == 1 && errKeys[0] == 'content' && mdContnet
if (!err) {
if (!err || Object.keys(err).length == 0) {
if (this.state.isEdit) {
this.doEdit(courseId, values)
} else {
@ -450,12 +451,13 @@ class NewWorkForm extends Component{
className="AboutInputForm groupSetting"
>
{getFieldDecorator('personNum', {
rules: [{
validateTrigger: 'onNone',
// rules: [{
// required: true,
// message: '人数不能为空'
// validator: this.personNumValidator
// required: true, message: '请输入最小人数和最大人数'
}],
// }],
})(
<div>
<p className="clearfix">

@ -53,7 +53,7 @@ class ModalWrapper extends Component{
{this.props.checkBoxValuestype===true?<div className={"mt10 color-red"}>
请先选择课堂
</div>:""}
<div className="mt30 marginauto clearfix edu-txt-center">
<div className="mt20 marginauto clearfix edu-txt-center">
<a onClick={this.onCancel} className="pop_close task-btn mr30">{ cancelText || '取消' }</a>
<a onClick={this.onOk} className="task-btn task-btn-orange" id="submit_send_shixun">{ okText || "确定" }</a>
</div>

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

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

@ -62,6 +62,8 @@ class ExerciseDisplay extends Component{
response.data.exercise.exercise_status = response.data.exercise.exercise_status == undefined ? 1 : response.data.exercise.exercise_status
this.setState({...response.data})
this.props.detailFetchCallback && this.props.detailFetchCallback(response);
} else {
this.props.detailFetchCallback && this.props.detailFetchCallback(response);
}
})
.catch(function (error) {

@ -0,0 +1,49 @@
.maxnamewidth100{
max-width: 100px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth110{
max-width: 100px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth200{
max-width: 200px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth145{
max-width: 145px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth215{
max-width: 215px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth255{
max-width: 255px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth175{
max-width: 175px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}

@ -6,6 +6,7 @@ import axios from 'axios';
import TPMMDEditor from "../../tpm/challengesnew/TPMMDEditor";
import moment from "../new/CoursesNew";
import Fileslistitem from "../Resource/Fileslistitem";
import Modals from "../../modals/Modals";
// 公告栏
class Bullsubdirectory extends Component{
constructor(props){
@ -19,6 +20,10 @@ class Bullsubdirectory extends Component{
addonAfter:0,
eduintits:"",
informs:[],
Modalstype:false,
Modalstopval:"是否确认删除?",
ModalCancel:"",
ModalSave:"",
}
@ -47,6 +52,61 @@ class Bullsubdirectory extends Component{
}
setModeltrue=()=>{
this.setState({
Modalstype:true,
Modalstopval:"是否确认删除?",
ModalCancel:this.cancelmodel,
ModalSave:this.saveonOpen,
})
}
cancelmodel=()=>{
//取消
this.setState({
Modalstype:false,
Modalstopval:"是否确认删除?",
ModalCancel:"",
ModalSave:"",
})
}
saveonOpen=()=>{
//确认
// /
// 删除公告
var id=this.props.match.params.coursesId
const url =`/courses/${id}/delete_informs.json`;
axios.delete(url, { data: {
inform_id: this.props.id
}})
.then((response) => {
if(response){
if(response.data){
if(response.data.status===0){
this.setState({
Modalstype:false,
Modalstopval:"是否确认删除?",
ModalCancel:"",
ModalSave:"",
})
this.props.showNotification(`删除成功`);
this.props.getinputdata();
}else{
this.props.showNotification(`删除失败`);
}
}else{
this.props.showNotification(`删除失败`);
}
}
})
.catch(function (error) {
console.log(error);
this.props.showNotification(`删除失败`);
});
}
bianji = (bians)=>{
this.setState({
@ -113,7 +173,7 @@ class Bullsubdirectory extends Component{
}
var url = `/courses/${id}/update_informs.json`;
axios.post(url,{
inform_id:this.state.id,
inform_id:this.props.id,
name:titname,
description:values.description,
}).then((result) => {
@ -154,12 +214,20 @@ class Bullsubdirectory extends Component{
render(){
let{description,whethertoeditysl,addonAfter,eduintits,informs,isSpinysl} =this.state;
let{myname,mydescription}=this.props;
let{myname,mydescription,id}=this.props;
const {getFieldDecorator} = this.props.form;
// console.log("Bullsubdirectory");
// console.log(this.props.isAdmin());
// console.log(this.props.yslbool);
return(
<React.Fragment >
<div >
{this.state.Modalstype&&this.state.Modalstype===true?<Modals
modalsType={this.state.Modalstype}
modalsTopval={this.state.Modalstopval}
modalCancel={this.state.ModalCancel}
modalSave={this.state.ModalSave}
/>:""}
<Spin size="large" spinning={isSpinysl} >
<div className="edu-back-white ">
{
@ -171,11 +239,30 @@ class Bullsubdirectory extends Component{
<span className="ysltitbt">{myname}</span>
</div>
<div>
<span className="fr pr25 yslbianji">
<span className="fr yslbianji" style={{marginRight:"17px"}}>
{
this.props.isAdmin() === true ?
(this.props.yslbool===false?
<Tooltip placement="bottom" title={<div>
编辑
</div>}>
<i className="iconfont icon-bianji1 newbianji1" onClick={()=>this.bianji(true)}></i>
</Tooltip>
:
""
)
:""
}
</span>
<span className="fr yslbianji" style={{marginRight:"22px"}}>
{
this.props.isAdmin() === true ?
(this.props.yslbool===false?
<Tooltip placement="bottom" title={<div>
删除
</div>}>
<i className="iconfont icon-shanchu newbianji1" style={{ color: "#4CACFF"}} onClick={()=>this.setModeltrue(true)}></i>
</Tooltip>
:
""
)

@ -67,10 +67,22 @@ class GroupPackage extends Component {
<span className="ysltextcolor05">{datas&&datas.min_num}~ {datas&&datas.max_num} 学生提交作品时需要关联同组成员组内成员作品共享</span>
</p>
}
<p>
<span className="ysltextcolor66">基于项目实施</span>
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span>
</p>
{
datas===undefined?"":datas.base_on_project===undefined?"":
datas.base_on_project===true?
<p>
<span className="ysltextcolor66">基于项目实施</span>
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span>
</p>
:datas.base_on_project===false?
<p>
<span className="ysltextcolor66">不基于项目</span>
<span className="ysltextcolor05">无需在平台创建项目任意小组成员均可以提交作品</span>
</p>
:""
}
</div>
:<div className="ml47text">
{
@ -82,11 +94,16 @@ class GroupPackage extends Component {
</p>
}
{
datas&&datas.group_info&&datas.group_info.base_on_project?
datas&&datas.group_info&&datas.group_info.base_on_project===1?
<p>
<span className="ysltextcolor66">基于项目实施</span>
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span>
</p>
:datas&&datas.group_info&&datas.group_info.base_on_project===0?
<p>
<span className="ysltextcolor66">不基于项目</span>
<span className="ysltextcolor05">无需在平台创建项目任意小组成员均可以提交作品</span>
</p>
:""
}
</div>

@ -41,7 +41,7 @@ function CourseGroupChooser({ course_groups, isAdminOrCreator = true, item, inde
console.log('arg_course_groups', arg_course_groups)
const urlStyle = {"lef":"tunset", minWidth: '262px'};
const urlStyle = {"left":"unset", minWidth: '262px'};
if (alwaysShow == true) {
urlStyle.display = 'block'
}
@ -89,7 +89,7 @@ function CourseGroupChooser({ course_groups, isAdminOrCreator = true, item, inde
<p className="drop_down_btn">
<a href="javascript:void(0)" className="color-grey-6"
onClick={() => trigger('groupAdd')}
>添加分班...</a>
>添加分班</a>
</p>
</ul>
)

@ -65,22 +65,34 @@ function CourseGroupChooserModal({ course_groups = [], isAdminOrCreator, item, i
className="courseGroupChooserModal"
>
<style>{`
.courseGroupChooserModal .ant-modal-body{
padding:20px 30px;
}
.courseGroupChooserModal .description {
font-size: 16px;
text-align: center;
margin-bottom: 20px;
}
.courseGroupChooserModal .drop_down_menu {
.courseGroupChooserModal .marginauto{
margin-top:10px!important;
}
.courseGroupChooserModal .drop_down_menu {
position: relative;
top: auto;
box-shadow: none;
padding:0px;
}
.courseGroupChooserModal .drop_down_menu .mainGroup{
background: #f2f9ff;
padding: 0 20px;
}
.courseGroupChooserModal .drop_down_menu li:hover,.courseGroupChooserModal .drop_down_normal li:hover{
background: #f2f9ff;
padding-top: 12px;
}
.courseGroupChooserModal .drop_down_menu .mainGroup.ant-checkbox-group {
width: 100%;
max-height: 300px
max-height: 300px!important;
height: 300px;
}
.courseGroupChooserModal .drop_down_search {
margin: 0;
@ -90,9 +102,15 @@ function CourseGroupChooserModal({ course_groups = [], isAdminOrCreator, item, i
padding: 0px;
}
.courseGroupChooserModal .drop_down_menu .drop_down_btn {
height: 26px;
line-height: 26px;
padding: 0px 20px;
margin: 0;
}
.mainGroup .drop_down_menu .drop_down_btn{
height: 26px;
line-height: 26px;
}
`}</style>
{/* <React.Fragment>
<React.Fragment> */}

@ -663,7 +663,7 @@ class studentsList extends Component{
<style>{`
/* CourseGroupChooser */
.drop_down_menu .mainGroup.ant-checkbox-group {
max-height: 380px;
max-height: 170px;
overflow-y: auto;
}
.task_menu_ul .ant-menu-item, .task_menu_ul .ant-menu-submenu-title{

@ -48,7 +48,8 @@ class CoursesNew extends Component {
addonAfteronelenone:0,
addonAfteronelentwo:0,
bordebool:false,
smallspinning:false
smallspinning:false,
bottonloading:false
}
}
componentDidMount() {
@ -217,7 +218,9 @@ class CoursesNew extends Component {
if (!err) {
this.setState({
bottonloading:true
})
// console.log('Received values of form: ', values);
@ -240,7 +243,7 @@ class CoursesNew extends Component {
if (response.data.status === 0) {
// this.goback()
window.location.href=first_category_url;
window.location.href=first_category_url;
if(this.state.boolxinjian===true) {
var yslGuideone = window.localStorage.getItem('yslGuideone');
try {
@ -257,11 +260,19 @@ class CoursesNew extends Component {
}
}
}
}else{
this.setState({
bottonloading:false
})
}
}).catch((error) => {
console.log(error)
})
}
}else{
this.setState({
bottonloading:false
})
}
});
} else {
this.props.form.validateFields((err, values) => {
@ -283,6 +294,9 @@ class CoursesNew extends Component {
// debugger
//新建
// console.log('Received values of form: ', values);
this.setState({
bottonloading:true
})
let url = "/courses.json";
axios.post(url, {
@ -300,6 +314,7 @@ class CoursesNew extends Component {
).then((response) => {
if (response.status === 200) {
// this.goback
window.location.href=response.data.first_category_url;
if(this.state.boolxinjian===true){
var yslGuideone = window.localStorage.getItem('yslGuideone');
@ -318,11 +333,19 @@ class CoursesNew extends Component {
}
}
}else{
this.setState({
bottonloading:false
})
}
}).catch((error) => {
console.log(error)
})
}
}else{
this.setState({
bottonloading:false
})
}
});
}
@ -934,7 +957,7 @@ class CoursesNew extends Component {
<div className={"FAFAFA"}>
<Form.Item >
<div className="clearfix mt40 mb30">
<Button type="primary" htmlType="submit" className="defalutSubmitbtn fl mr20">
<Button type="primary" htmlType="submit" loading={this.state.bottonloading} className="defalutSubmitbtn fl mr20">
提交
</Button>
{/*<a className="defalutSubmitbtn fl mr20">提交</a>*/}

@ -55,7 +55,8 @@ class Goldsubject extends Component {
addonAfteronelentwo:"",
Whethertocreateanewclassroom:true,
bordebool:false,
smallspinning:false
smallspinning:false,
bottonloading:false
}
}
// disabledEndDate= endValue => {
@ -351,7 +352,9 @@ class Goldsubject extends Component {
}catch (e) {
}
this.setState({
bottonloading:true
})
let url = "/courses/" + coursesId + ".json";
axios.put(url,
datasysl
@ -372,12 +375,21 @@ class Goldsubject extends Component {
return
}
}catch (e) {
this.setState({
bottonloading:false
})
}
}else{
this.setState({
bottonloading:false
})
}
}).catch((error) => {
console.log(error)
this.setState({
bottonloading:false
})
})
}
@ -424,20 +436,15 @@ class Goldsubject extends Component {
course_module_types: values.checkboxgroup,
school:values.school
};
try {
// console.log("提交的ysldatas数据");
// console.log(ysldatas);
// console.log(JSON.stringify(ysldatas));
// console.log(moment(values.starttime).format("YYYY-MM-DD"));
// console.log(moment(values.endtime).format("YYYY-MM-DD"));
}catch (e) {
}
this.setState({
bottonloading:true
})
axios.post(url,
ysldatas
).then((response) => {
if (response.status === 200) {
// this.goback
window.location.href=response.data.first_category_url;
var yslGuideone = window.localStorage.getItem('yslGuideone');
@ -451,11 +458,16 @@ class Goldsubject extends Component {
return
}
}catch (e) {
this.setState({
bottonloading:false
})
}
}
}).catch((error) => {
console.log(error)
this.setState({
bottonloading:false
})
})
}
});
@ -1074,9 +1086,11 @@ class Goldsubject extends Component {
<div className={"FAFAFA"}>
<Form.Item >
<div className="clearfix mt40 mb30">
<Button type="primary" htmlType="submit" className="defalutSubmitbtn fl mr20">
<Button type="primary" htmlType="submit" loading={this.state.bottonloading} className="defalutSubmitbtn fl mr20">
提交
</Button>
{/*<a className="defalutSubmitbtn fl mr20">提交</a>*/}
<a className="defalutCancelbtn fl" onClick={this.goback}>取消</a>
</div>

@ -11,6 +11,7 @@ import Coursesshixundetails from './shixunreport/Coursesshixundetails';
import Shixunechart from './shixunreport/Shixunechart';
import DownloadMessageysl from "../../modals/DownloadMessageysl"
import AppraiseModal from "../coursesPublic/AppraiseModal";
import ShowAppraiseList from './ShowAppraiseList';
import {UnControlled as CodeMirror} from 'react-codemirror2';
import 'codemirror/mode/cmake/cmake';
import 'codemirror/mode/xml/xml';
@ -34,9 +35,8 @@ class ShixunWorkReport extends Component {
DownloadMessageval:undefined,
isspinning:false,
showAppraiseModaltype:false,
work_comment_hidden:false,
showAppraiseModalsshow:true,
work_comment:null
work_comment_hidden:undefined,
work_comment:undefined,
}
}
@ -102,7 +102,7 @@ class ShixunWorkReport extends Component {
let homeworkid=this.props.match.params.homeworkid;
let url = `/student_works/${homeworkid}/shixun_work_report.json`
axios.get(url).then((result) => {
if (result.data.status === 403||result.data.status === 401||result.data.status === 407||result.data.status === 408||result.data.status === 409) {
if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) {
}else{
this.setState({
@ -155,85 +155,153 @@ class ShixunWorkReport extends Component {
})
}
showAppraiseModal=(sum)=>{
// if(sum===undefined){
// this.setState({
// showAppraiseModaltype:true,
// })
// }else{
// this.setState({
// showAppraiseModaltype:true,
// work_comment:undefined,
// work_type:0,
// })
//
// }
let{work_comment,work_comment_hidden}=this.state;
this.setState({
showAppraiseModaltype:true,
work_comment_hidden:work_comment===null||work_comment===undefined?this.state.work_type?true:false:work_comment_hidden,
})
showAppraiseModal=(type,id,show,hidden)=>{
let{data}=this.state;
if(type==="child"){
data.stage_list.forEach((item,key)=>{
if(item.challenge_id===id){
item.challenge_comment=show;
item.challenge_comment_hidden=hidden;
}
})
this.setState({
showAppraiseModaltype:true,
showAppraisetype:type,
challenge_id:id,
data:data
})
}else{
this.setState({
showAppraiseModaltype:true,
showAppraisetype:type,
challenge_id:undefined,
work_comment:show,
work_comment_hidden:hidden
})
}
}
hideAppraiseModal=()=>{
let{work_comment,work_comment_hidden}=this.state;
this.setState({
showAppraiseModaltype:false,
work_comment_hidden:work_comment===null||work_comment===undefined?this.state.work_type===1?true:false:work_comment_hidden,
})
}
showAppraiseModals=(list,type)=>{
showAppraiseModals=(show,hidden,id,comment_id)=>{
let{data,showAppraisetype}=this.state;
if(showAppraisetype==="child"){
data.stage_list.forEach((item,key)=>{
if(item.challenge_id===id){
item.challenge_comment=show;
item.challenge_comment_hidden=hidden;
item.comment_id=comment_id
}
})
this.setState({
showAppraiseModaltype:false,
data:data
})
}else{
data.comment_id=comment_id;
this.setState({
showAppraiseModaltype:false,
work_comment:show,
work_comment_hidden:hidden,
data:data
})
}
this.setState({
showAppraiseModaltype:false,
work_comment_hidden:type===0?false:true,
work_comment:list,
work_type:type,
showAppraiseModals:true,
showAppraiseModalsshow:true,
})
}
isdeleteModal=()=>{
isdeleteModal=(comment_id,visible_comment,type)=>{
let newcomment_id=comment_id;
let newvisible_comment=visible_comment;
let newtype=type;
this.setState({
modalsType: true,
modalsTopval:"是否确认删除?",
modalSave: ()=>this.isdeleteModals(),
modalCancel:()=>this.hideisdeleteModal(),
modalSave: ()=>this.isdeleteModals(newcomment_id,newvisible_comment,newtype),
modalCancel:()=>this.hideisdeleteModals(),
})
}
hideisdeleteModal=()=>{
hideisdeleteModals=()=>{
this.setState({
modalsType: false,
modalsType:false,
modalsTopval:"是否确认删除?",
modalSave: ()=>this.isdeleteModals(),
modalCancel:()=>this.hideisdeleteModal(),
modalSave: "",
modalCancel:"",
})
}
isdeleteModals=()=>{
let url =`/student_works/${this.props.match.params.homeworkid}/destroy_work_comment.json`
axios.delete(url).then((response) => {
// const { status } = response.data;
if(response.data.status===0){
this.props.showNotification(response.data.message)
this.setState({
showAppraiseModalsshow:false,
work_comment_hidden:false,
work_comment:undefined,
work_type:0,
})
this.hideisdeleteModal()
}else{
this.props.showNotification(response.data.message)
hideisdeleteModal=(comment_id,visible_comment,type)=>{
let{data,work_comment,work_comment_hidden}=this.state;
if(type==="child"){
data.stage_list.map((item,key)=>{
console.log(item)
if(item.comment_id!=null){
if(item.comment_id===comment_id){
item.challenge_comment=null;
item.challenge_comment_hidden=null;
}
}
})
.catch(function (error) {
console.log(error);
});
this.setState({
modalsType:false,
modalsTopval:"是否确认删除?",
modalSave: "",
modalCancel:"",
data:data
})
}else{
this.setState({
modalsType:false,
modalsTopval:"是否确认删除?",
modalSave: "",
modalCancel:"",
work_comment:null,
work_comment_hidden:null
})
}
}
isdeleteModals=(comment_id,visible_comment,type)=>{
let newcomment_id=comment_id;
let newvisible_comment=visible_comment;
let newtype=type;
if(comment_id!=null){
let url =`/student_works/${this.props.match.params.homeworkid}/destroy_work_comment.json`
axios.delete(url, { data: {
comment_id:comment_id,
}}).then((response) => {
// const { status } = response.data;
if(response.data.status===0){
this.props.showNotification(response.data.message)
this.hideisdeleteModal(newcomment_id,newvisible_comment,newtype)
}else{
this.props.showNotification(response.data.message)
}
})
.catch(function (error) {
console.log(error);
});
}
}
render() {
let{data,showAppraiseModaltype,work_comment_hidden,showAppraiseModalsshow,work_comment} =this.state;
let{data,showAppraiseModaltype,work_comment_hidden,work_comment} =this.state;
let category_id=data===undefined?"":data.category===null?"":data.category.category_id;
let homework_common_id=data===undefined?"":data.homework_common_id;
@ -242,7 +310,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;
console.log(showAppraiseModals)
return (
data===undefined?"":<Spin indicator={antIcon} spinning={this.state.spinning}>
@ -253,15 +321,20 @@ class ShixunWorkReport extends Component {
modalSave={this.state.modalSave}
modalCancel={this.state.modalCancel}
></Modals>
{showAppraiseModaltype===true?<AppraiseModal
{...this.props}
{...this.state}
visible={showAppraiseModaltype}
Cancel={()=>this.hideAppraiseModal()}
showCancel={(list,type)=>this.showAppraiseModals(list,type)}
showCancel={(show,hidden,id,comment_id)=>this.showAppraiseModals(show,hidden,id,comment_id)}
work_comment={this.state.work_comment}
work_type={work_comment===null||work_comment===undefined?this.state.work_type:work_comment_hidden===true?1:0}
/>:""}
<div className="newMain clearfix ">
<div className={"educontent mb20" }>
<div className="educontent">
@ -299,9 +372,11 @@ class ShixunWorkReport extends Component {
{/*>评阅</a> : ""}*/}
{this.props.isAdmin() ?<a
className=" color-blue font-14 fr ml20 mt15"
onClick={()=>this.showAppraiseModal(1)}
onClick={()=>this.showAppraiseModal("main",undefined,work_comment,work_comment_hidden)}
>评阅</a>:""}
</div>
{/*{work_comment===null||work_comment===undefined?"评阅":"编辑评阅"}*/}
<style>{
`
@ -421,6 +496,7 @@ class ShixunWorkReport extends Component {
jumptopic={this.jumptopic}
getdatalist={()=>this.getdatalist()}
setupdalist={(challenge_score,overall_appraisal,work_score)=>this.setupdalist(challenge_score,overall_appraisal,work_score)}
showAppraiseModal={(type,id,show,hidden)=>this.showAppraiseModal(type,id,show,hidden)}
/>
</div>
@ -472,33 +548,12 @@ class ShixunWorkReport extends Component {
</div>
{showAppraiseModals===true&&showAppraiseModalsshow===true?<div className="stud-class-set mt17">
<div className="clearfix edu-back-white poll_list">
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20 color333">
老师评阅<span>{work_comment_hidden===true||this.state.work_type===1?"(仅对课堂老师可见)":""}</span>
{this.props&&this.props.isAdminOrTeacher()===true?<a className="color-blue font-14 fr ml20"
onClick={()=>this.isdeleteModal()}
>删除</a>:""}
{this.props&&this.props.isAdminOrTeacher()===true?<a className="color-blue font-14 fr"
onClick={()=>this.showAppraiseModal()}
>编辑</a>:""}
</div>
<div className="font-16 color-dark-21 shixunreporttitleboxbom pd30">
<div style={{minHeight:'50px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(work_comment).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>
</div>
</div>
</div>:""}
<ShowAppraiseList
{...this.props}
{...this.state}
isdeleteModal={(comment_id,visible_comment,type)=>this.isdeleteModal(comment_id,visible_comment,type)}
showAppraiseModal={(type,id,show,hidden)=>this.showAppraiseModal(type,id,show,hidden)}
/>
<div className="stud-class-set bor-bottom-greyE mt17">

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

@ -0,0 +1,176 @@
import React,{ Component } from "react";
import { Modal,Checkbox,Upload,Button,Icon,message,Input,Radio} from "antd";
import { WordNumberTextarea,markdownToHTML } from 'educoder';
import axios from 'axios';
import './style.css';
class ShowAppraiseList extends Component{
constructor(props){
super(props);
this.state={
}
}
render(){
let {data, work_comment,work_comment_hidden}=this.props;
let work_commenttype=work_comment===undefined||work_comment===null||work_comment==="";
let work_comment_hiddentype=work_comment_hidden===undefined||work_comment_hidden===null||work_comment_hidden==="";
return(
<div>
<style>
{
`
.appraisebox{
width: 65px;
height: 22px;
background: rgba(76,172,255,1);
border-radius: 2px;
display: inline-block;
margin-right: 20px;
color: #fff;
font-size: 14px;
text-align: center;
line-height: 22px;
}
.markdown-body{
padding-bottom: 10px;
}
.borderbom{
margin-bottom: 15px;
border-bottom: 2px solid #fafafa;
}
`
}
</style>
{data===undefined?"":work_commenttype===true&&work_comment_hiddentype===true?"":
<div className="stud-class-set mt17">
<div className="clearfix edu-back-white poll_list">
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20 color333">
<span className={"appraisebox"}>总体评阅</span>
{this.props&&this.props.isAdmin()===true?<a className="color-blue font-14 fr ml20"
onClick={()=>this.props.isdeleteModal(data.comment_id,true,"main")}
>删除</a>:""}
{this.props&&this.props.isAdmin()===true?<a className="color-blue font-14 fr"
onClick={()=>this.props.showAppraiseModal("main",undefined,work_comment,work_comment_hidden)}
>编辑</a>:""}
</div>
{this.props&&this.props.isAdmin()===true?
<div className="font-16 color-dark-21 shixunreporttitleboxbom pd30bt">
{work_commenttype===true?"":<div>
<span className={"z000"}>学生可见<span className={"z666"}>学生可查看老师的评阅内容</span></span>
</div>}
{work_commenttype===true?"":<div className={work_comment_hiddentype===true?"":"borderbom"} style={{minHeight:'40px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(work_comment).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>}
{work_comment_hiddentype===true?"":<div>
<span className={"z000"}>学生不可见<span className={"z666"}>仅对课堂老师可见</span></span>
</div>}
{work_comment_hiddentype===true?"":<div style={{minHeight:'40px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(work_comment_hidden).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>}
</div>:<div className="font-16 color-dark-21 shixunreporttitleboxbom pd30">
<div style={{minHeight:'40px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(work_comment).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>
</div>}
</div>
</div>}
{data===undefined?"":data.stage_list.map((item,key)=>{
let challenge_comment_hidden=item.challenge_comment_hidden===undefined||item.challenge_comment_hidden===null||item.challenge_comment_hidden==="";
let challenge_comment=item.challenge_comment===undefined||item.challenge_comment===null||item.challenge_comment==="";
return(
<div key={key}>
{challenge_comment===false||challenge_comment_hidden==false?<div className="stud-class-set mt17" >
<div className="clearfix edu-back-white poll_list">
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20 color333">
<span className={"appraisebox"}>{key+1}</span>{item.name}
{this.props&&this.props.isAdmin()===true?<a className="color-blue font-14 fr ml20"
onClick={()=>this.props.isdeleteModal(item.comment_id,true,"child")}
>删除</a>:""}
{this.props&&this.props.isAdmin()===true?<a className="color-blue font-14 fr"
onClick={()=>this.props.showAppraiseModal("child",item.challenge_id,item.challenge_comment,item.challenge_comment_hidden)}
>编辑</a>:""}
</div>
{this.props&&this.props.isAdmin()===true?
<div className="font-16 color-dark-21 shixunreporttitleboxbom pd30bt">
{challenge_comment===true?"":<div>
<span className={"z000"}>学生可见<span className={"z666"}>学生可查看老师的评阅内容</span></span>
</div>}
{challenge_comment===true?"":<div className={challenge_comment_hidden===true?"":"borderbom"} style={{minHeight:'40px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(item.challenge_comment).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>}
{challenge_comment_hidden===true?"":<div>
<span className={"z000"}>学生不可见<span className={"z666"}>仅对课堂老师可见</span></span>
</div>}
{challenge_comment_hidden===true?"":<div style={{minHeight:'40px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(item.challenge_comment_hidden).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>}
</div>: <div className="font-16 color-dark-21 shixunreporttitleboxbom pd30">
<div style={{minHeight:'40px'}}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(item.challenge_comment).replace(/▁/g, "▁▁▁")}}></div>
</div>
</div>
</div>}
</div>
</div>:""}
</div>)
})
}
</div>
)
}
}
export default ShowAppraiseList;

@ -15,29 +15,7 @@ class OfficialAcademicTranscript extends Component {
}
componentDidMount() {
let {data}=this.props;
let datas=[];
if(data!=undefined){
data.stage_list===undefined?"":data.stage_list.forEach((item,key)=>{
datas.push({
customs: key+1,
taskname:{name:item.name,complete_status:item.complete_status},
openingtime:item.open_time,
evaluating: item.evaluate_count,
finishtime:item.finished_time,
elapsedtime:item.time_consuming,
empvalue:{myself:item.myself_experience,experience:item.experience},
game_scores:{game_score:item.game_score,game_score_full:item.game_score_full},
challenge_id:{id:item.challenge_id}
// adjustmentminute:asdasd
})
})
this.setState({
datas:datas
})
}
}
myjumptopic=(e)=>{
console.log("获取到值");
@ -96,7 +74,28 @@ class OfficialAcademicTranscript extends Component {
}
render() {
let {datas,customsids}=this.state;
let {customsids}=this.state;
let {data}=this.props;
let datas=[];
if(data!=undefined){
data.stage_list===undefined?"":data.stage_list.forEach((item,key)=>{
datas.push({
customs: key+1,
taskname:{name:item.name,complete_status:item.complete_status},
openingtime:item.open_time,
evaluating: item.evaluate_count,
finishtime:item.finished_time,
elapsedtime:item.time_consuming,
empvalue:{myself:item.myself_experience,experience:item.experience},
game_scores:{game_score:item.game_score,game_score_full:item.game_score_full},
challenge_id:{id:item.challenge_id},
challenge_comment: item.challenge_comment,
challenge_comment_hidden: item.challenge_comment_hidden,
// adjustmentminute:asdasd
})
})
}
let columns=[{
title: '关卡',
@ -196,6 +195,20 @@ class OfficialAcademicTranscript extends Component {
// min={0} max={record.game_scores.game_score_full}
/></a>
{/*<a style={{textAlign: "center"}} className="color-blue font-14 mr20">查看</a>*/}
</span>
),
},{
title: '操作',
key: 'operation',
dataIndex: 'operation',
render: (text, record) => (
<span>
<a
className=" color-blue font-14 fr mr22"
onClick={()=>this.props.showAppraiseModal("child",record.challenge_id.id,record.challenge_comment,record.challenge_comment_hidden)}
>评阅</a>
</span>
),
}];
@ -210,6 +223,13 @@ class OfficialAcademicTranscript extends Component {
}
}
)
columns.some((item,key)=> {
if (item.title === "操作") {
columns.splice(key, 1)
return true
}
}
)
}
return (
<div>
@ -276,6 +296,9 @@ class OfficialAcademicTranscript extends Component {
.linhe15{
line-height: 15px;
}
.mr22{
margin-right: 22px;
}
`}
</style>
{datas===undefined?"":<Table

@ -38,13 +38,34 @@
.TopicDetailTable .bottomBody li:last-child{border-bottom: none;}
.maxnamewidth100{
max-width: 145px;
max-width: 100px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth110{
max-width: 100px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth200{
max-width: 200px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth145{
max-width: 145px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.maxnamewidth145{
max-width: 145px;
overflow:hidden;
text-overflow:ellipsis;
@ -53,4 +74,17 @@
}
.ysyslxh{
background: #fafafa;
}
.z666{
color: #666;
font-size:14px;
}
.z000{
color: #000;
font-size:16px;
}
.pd30bt{
padding: 10px 30px 0px 30px;
}

@ -16,6 +16,7 @@ class AboutUs extends React.Component {
}
componentDidMount(){
window.document.title = "关于我们";
this.getContent();
}

@ -16,6 +16,7 @@ class Agreement extends React.Component {
}
componentDidMount(){
window.document.title = "服务协议";
this.getContent();
}

@ -17,6 +17,7 @@ class ContactUs extends React.Component {
}
componentDidMount(){
window.document.title = "联系我们";
this.getData();
}

@ -21,6 +21,7 @@ class Cooperatives extends React.Component {
}
componentDidMount(){
window.document.title = "合作伙伴";
this.getCooperatives();
}

@ -13,6 +13,10 @@ class Feedback extends React.Component {
super(props);
}
componentDidMount() {
window.document.title = "意见反馈";
}
componentDidUpdate(prevProps) {
if (prevProps.current_user !== this.props.current_user) {
if(!this.props.checkIfLogin()) {

@ -16,6 +16,7 @@ class HelpCenter extends React.Component {
}
componentDidMount(){
window.document.title = "帮助中心";
this.getContent();
}

@ -12,7 +12,7 @@ import SiderBar from '../tpm/SiderBar';
import UpgradeModals from '../modals/UpgradeModals';
import { SnackbarHOC , getImageUrl} from 'educoder';
import { SnackbarHOC , getImageUrl, configShareForIndex} from 'educoder';
import Slider from '@icedesign/base/lib/slider';
@ -37,6 +37,7 @@ class ShixunsHome extends Component {
}
}
componentDidMount(){
configShareForIndex()
const upsystem=`/users/system_update.json`;
axios.get(upsystem).then((response)=>{
let updata=response.data;

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

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

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

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

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

@ -1,204 +1,206 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom'
import { withStyles } from 'material-ui/styles';
import Button from 'material-ui/Button';
import Tooltip from 'material-ui/Tooltip';
import './ActionView.css'
/*
color: #1B4061 !important;
background-color: transparent;
border: 1px solid #1B4061 !important;
*/
const styles = theme => ({
button: {
margin: theme.spacing.unit,
border: '1px solid #1B4061',
color: '#1B4061',
height: '30px',
padding: '0 16px',
'&:hover': {
color: '#4CACFF',
border: '1px solid #4CACFF'
}
},
hoverButton: {
margin: theme.spacing.unit,
height: '30px',
padding: '0 16px',
color: '#4CACFF',
border: '1px solid #4CACFF'
},
buttonText: {
color: '#1B4061 !important',
'&:hover': {
color: '#1B4061',
}
}
});
class ActionView extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
// request
window._tpiWidthResize = () => {
const _w = window.$('#actionView').width();
// if (_w < 446) {
// window.$('#time-consuming').hide()
// // window.$('#time-consuming').hide()
// } else if (_w < 746) {
// // 文字放出来之前是 580
// window.$('#time-consuming').show()
// window.$('.time_limit').hide()
// } else {
// window.$('#time-consuming').show()
// window.$('.time_limit').show()
// }
}
}
showWebDisplay(challenge) {
window.open(challenge.webDisplayUrl, '_blank');
}
/*<span className="mt10 -flex c_grey ml15" id="time-consuming">耗时0 天 3 小时 11 分钟 57 秒 </span>*/
render() {
const { onRunCodeTest, onShowPrevStage, onShowNextStage, gameBuilding
, game, classes, st, shixun, record, challenge, time_limit, real_time_limit } = this.props;
return (
<div className="-flex -layout-h" id="game_operate_action">
<style>{`
#game_operate_action {
width: 100%;
}
.time_limit {
margin-right: 0px;
}
.spliter {
border-right: 1px solid;
padding-right: 8px;
margin-right: 8px;
height: 14px;
display: inline-block;
position: relative;
top: 3px;
}
#time-consuming {
flex: auto;
overflow: hidden;
white-space: nowrap;
}
#game_operate_action .act_btn {
flex: 0 0 90px;
}
`}</style>
<span className="mt10 -flex c_grey ml15" id="time-consuming">
{!!time_limit &&
<span className="time_limit">{`本关最大执行时间:${real_time_limit}`}
{!gameBuilding && record && <span className="spliter"></span>}
</span>}
{!gameBuilding && record ?
// <Tooltip title={ "本次评测耗时(编译、运行总时间)" }></Tooltip>
<span>本次评测耗时(编译运行总时间){ record } </span>
: ""}
</span>
{/*将第一个按钮改为visibility方式隐藏不然加载时测评按钮会出现没有垂直居中的情况*/}
<Tooltip title={ "倒计时为0时服务将被关闭" }>
<Button size="small" className={classes.button + ' actionViewfirstButton'} onClick={()=>this.showWebDisplay(challenge)}
style={{ visibility: challenge.showWebDisplayButton ? '': 'hidden',
minWidth: challenge.showWebDisplayButton ? '': '1px',
width: challenge.showWebDisplayButton ? '': '1px',
flex: `0 0 ${challenge.showWebDisplayButton ? '110px': '1px'}`
}}
id="showWebDisplayButton"
// style={{ display: challenge.showWebDisplayButton ? 'flex': 'none'}}
>
查看效果
</Button>
</Tooltip>
{
!gameBuilding &&
(game && !!game.prev_game) ?
<Link to={`/tasks/${game.prev_game}`} className={classes.buttonText + ' act_btn'}>
<Button size="small" className={classes.button}>
上一关
</Button>
</Link>
: ''}
{/*未发布的都能跳转*/}
{ !gameBuilding &&
((game && (game.status === 2 || shixun.status < 2) || shixun && shixun.task_pass ) && !!game.next_game) ?
<Link to={`/tasks/${game.next_game}`} className={classes.buttonText + ' act_btn'}>
<Button size="small" className={classes.button}>
下一关
</Button>
</Link>
: ''}
<div id="code_test" className="act_btn">
{
st === 1 && game.status === 2 ?
<Tooltip title={ "已通关的选择题任务无法再次测评" }>
<a href="javascript:void(0)" className="shixun-task-btn mr15 gray "
>
<i className="fa fa-play-circle font-16"></i>
测评
</a>
</Tooltip>
:
gameBuilding ?
<a href="javascript:void(0)" className="shixun-task-btn mr15 gray "
>
<i className="fa fa-play-circle font-16"></i>
测评
</a>
:
<a href="javascript:void(0)" className="shixun-task-btn mr15 "
onClick={onRunCodeTest}>
<i className="fa fa-play-circle font-16"></i>
测评
</a>}
</div>
</div>
);
/*
<a href="/shixuns/8arufxzl" id="exit_shixun" className="shixun-task-btn task-newbtn-grey mt8 mr15">离开</a>
<a href="javascript:void(0)" className="shixun-task-btn task-btn-blue mr15 mt8" id="prev_step"
onClick={onShowNextStage}>下一关 </a>
onclick="training_task_submmit();"
{game && !!game.prev_game ?
<div id="prev_step_area">
<Link to={`/tasks/${game.prev_game}`} className="shixun-task-btn task-btn-blue mr15 mt8">上一关</Link>
</div>
: ''}
{game && !!game.next_game ?
<div id="next_step_area">
<Link to={`/tasks/${game.next_game}`} className="shixun-task-btn task-btn-blue mr15 mt8">下一关</Link>
</div>
: ''}
*/
}
}
export default withStyles(styles)( ActionView );
import React, { Component } from 'react';
import { Link } from 'react-router-dom'
import { withStyles } from 'material-ui/styles';
import Button from 'material-ui/Button';
import Tooltip from 'material-ui/Tooltip';
import './ActionView.css'
/*
color: #1B4061 !important;
background-color: transparent;
border: 1px solid #1B4061 !important;
*/
const styles = theme => ({
button: {
margin: theme.spacing.unit,
border: '1px solid #1B4061',
color: '#1B4061',
height: '30px',
padding: '0 16px',
'&:hover': {
color: '#4CACFF',
border: '1px solid #4CACFF'
}
},
hoverButton: {
margin: theme.spacing.unit,
height: '30px',
padding: '0 16px',
color: '#4CACFF',
border: '1px solid #4CACFF'
},
buttonText: {
color: '#1B4061 !important',
'&:hover': {
color: '#1B4061',
}
}
});
class ActionView extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
// request
window._tpiWidthResize = () => {
const _w = window.$('#actionView').width();
// if (_w < 446) {
// window.$('#time-consuming').hide()
// // window.$('#time-consuming').hide()
// } else if (_w < 746) {
// // 文字放出来之前是 580
// window.$('#time-consuming').show()
// window.$('.time_limit').hide()
// } else {
// window.$('#time-consuming').show()
// window.$('.time_limit').show()
// }
}
}
showWebDisplay(challenge) {
window.open(challenge.webDisplayUrl, '_blank');
}
/*<span className="mt10 -flex c_grey ml15" id="time-consuming">耗时0 天 3 小时 11 分钟 57 秒 </span>*/
render() {
const { onRunCodeTest, onShowPrevStage, onShowNextStage, gameBuilding
, game, classes, st, shixun, record, challenge, time_limit, real_time_limit } = this.props;
console.log(shixun)
return (
<div className="-flex -layout-h" id="game_operate_action">
<style>{`
#game_operate_action {
width: 100%;
}
.time_limit {
margin-right: 0px;
}
.spliter {
border-right: 1px solid;
padding-right: 8px;
margin-right: 8px;
height: 14px;
display: inline-block;
position: relative;
top: 3px;
}
#time-consuming {
flex: auto;
overflow: hidden;
white-space: nowrap;
}
#game_operate_action .act_btn {
flex: 0 0 90px;
}
`}</style>
<span className="mt10 -flex c_grey ml15" id="time-consuming">
{!!time_limit &&
<span className="time_limit">{`本关最大执行时间:${real_time_limit}`}
{!gameBuilding && record && <span className="spliter"></span>}
</span>}
{!gameBuilding && record ?
// <Tooltip title={ "本次评测耗时(编译、运行总时间)" }></Tooltip>
<span>本次评测耗时(编译运行总时间){ record } </span>
: ""}
</span>
{/*将第一个按钮改为visibility方式隐藏不然加载时测评按钮会出现没有垂直居中的情况*/}
<Tooltip title={ "倒计时为0时服务将被关闭" }>
<Button size="small" className={classes.button + ' actionViewfirstButton'} onClick={()=>this.showWebDisplay(challenge)}
style={{ visibility: challenge.showWebDisplayButton ? '': 'hidden',
minWidth: challenge.showWebDisplayButton ? '': '1px',
width: challenge.showWebDisplayButton ? '': '1px',
flex: `0 0 ${challenge.showWebDisplayButton ? '110px': '1px'}`
}}
id="showWebDisplayButton"
// style={{ display: challenge.showWebDisplayButton ? 'flex': 'none'}}
>
查看效果
</Button>
</Tooltip>
{
!gameBuilding &&
(game && !!game.prev_game) ?
<Link to={`/tasks/${game.prev_game}`} className={classes.buttonText + ' act_btn'}>
<Button size="small" className={classes.button}>
上一关
</Button>
</Link>
: ''}
{/*未发布的都能跳转*/}
{ !gameBuilding &&
((game && (game.status === 2 || shixun.status < 2) || shixun && shixun.task_pass ) && !!game.next_game) ?
<Link to={`/tasks/${game.next_game}`} className={classes.buttonText + ' act_btn'}>
<Button size="small" className={classes.button}>
下一关
</Button>
</Link>
: ''}
{(shixun&&!shixun.vnc || shixun&&shixun.vnc_evaluate) && <div id="code_test" className="act_btn">
{
st === 1 && game.status === 2 ?
<Tooltip title={ "已通关的选择题任务无法再次测评" }>
<a href="javascript:void(0)" className="shixun-task-btn mr15 gray "
>
<i className="fa fa-play-circle font-16"></i>
测评
</a>
</Tooltip>
:
gameBuilding ?
<a href="javascript:void(0)" className="shixun-task-btn mr15 gray "
>
<i className="fa fa-play-circle font-16"></i>
测评
</a>
:
<a href="javascript:void(0)" className="shixun-task-btn mr15 "
onClick={onRunCodeTest}>
<i className="fa fa-play-circle font-16"></i>
测评
</a>}
</div>}
</div>
);
/*
<a href="/shixuns/8arufxzl" id="exit_shixun" className="shixun-task-btn task-newbtn-grey mt8 mr15">离开</a>
<a href="javascript:void(0)" className="shixun-task-btn task-btn-blue mr15 mt8" id="prev_step"
onClick={onShowNextStage}>下一关 </a>
onclick="training_task_submmit();"
{game && !!game.prev_game ?
<div id="prev_step_area">
<Link to={`/tasks/${game.prev_game}`} className="shixun-task-btn task-btn-blue mr15 mt8">上一关</Link>
</div>
: ''}
{game && !!game.next_game ?
<div id="next_step_area">
<Link to={`/tasks/${game.next_game}`} className="shixun-task-btn task-btn-blue mr15 mt8">下一关</Link>
</div>
: ''}
*/
}
}
export default withStyles(styles)( ActionView );

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

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

@ -1,309 +1,312 @@
import React, { Component } from 'react';
import CodeRepositoryView from './CodeRepositoryView'
import axios from 'axios'
import './CodeRepositoryView.css'
// 自己处理path加上父节点的path, 这里是处理树节点了所以是set key
function addPrePath(treeData, parentNodePath) {
return treeData.map(item => {
return {
...item,
key: `${parentNodePath}/${item.name}`
}
})
}
function getNewTreeData(treeData, curKey, child, level) {
const loop = (data) => {
data.forEach((item) => {
// 这里不能用indexOf 同一级可能出现test目录和test.py文件
if (item.key == curKey) {
child = addPrePath(child, curKey);
item.children = child;
} else {
if (item.children) {
loop(item.children);
}
}
});
};
loop(treeData);
}
function fileData2TreeData(repoFilesData) {
const fileTreeData = [];
repoFilesData.forEach((item) => {
if (item.kind === 'file') {
fileTreeData.push({
key: item.path,
name: item.name,
isLeaf: true
})
} else {
fileTreeData.push({
key: item.path,
name: item.name,
// isLeaf: false
})
}
})
return fileTreeData;
}
class CodeRepositoryViewContainer extends Component {
constructor(props) {
super(props)
this.showFilesDrawer = this.showFilesDrawer.bind(this)
this.onRepositoryViewExpand = this.onRepositoryViewExpand.bind(this)
this.state = {
drawerOpen: false,
loadingFirstRepoFiles: false,
fileTreeData: "",
fileTreeSelectedKeys: [],
codeRepositoryViewExpanded: false,
tabIndex: 0,
settingDrawerOpen: false
}
}
showSettingDrawer = (open) => {
this.setState({settingDrawerOpen: open})
}
tabIndexChange = (index) => {
this.setState({tabIndex: index});
}
onRepositoryViewExpand() {
window.repository_extend_and_zoom();
this.setState({
evaluateViewExpanded: !this.state.evaluateViewExpanded
}, () => {
setTimeout(()=>{
window.__tpiOnResize()
}, 300)
})
}
showFilesDrawer(open) {
if (this.props.loading === true) {
return;
}
if (!this.state.fileTreeData) {
this.fetchRepoFiles();
}
this.setState({
drawerOpen: open,
})
}
loadRepoFiles = () => {
if (!this.state.fileTreeData) {
this.fetchRepoFiles();
}
}
componentWillReceiveProps(newProps, oldProps) {
}
componentDidMount() {
}
componentDidUpdate(prevProps, prevState, snapshot) {
const { game, challenge } = this.props
if (this.props.game && (!prevProps.game || prevProps.game.identifier !== this.props.game.identifier) ) {
this.setState({
fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ]
})
// 初始化
} else if (this.state.fileTreeSelectedKeys.length === 0 && challenge && challenge.path) {
this.setState({
fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ]
})
} else if (challenge && prevProps && prevProps.challenge
&& challenge.pathIndex != prevProps.challenge.pathIndex
&& challenge.pathIndex !== -1) {
this.setState({
fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[challenge.pathIndex] : challenge.path ]
})
}
}
handleDialogClose() {
this.setState({
dialogOpen: false
})
}
onLoadData = (treeNode) => {
if (treeNode.props.children && treeNode.props.children.length) {
return new Promise((resolve) => {
resolve();
});
}
return new Promise((resolve, reject) => {
this.fetchRepoFiles(treeNode, resolve, reject)
});
}
map2OldData = (treeData) => {
if (!treeData || treeData.length === 0) return treeData;
treeData = treeData.map(item => {
return {
kind: item.type == "blob" ? "file" : "dir", // blob->file tree->dir
path: item.name,
name: item.name
}
})
return treeData;
}
fetchRepoFiles(treeNode, resolve, reject) {
// http://localhost:3000/api/v1/games/829al3mst4fy/entries?path=src/step1&rev=master
if (!this.props.challenge || !this.props.game) {
return;
}
// var ar = this.props.challenge.path.split('/');
// ar.length = ar.length - 2;
// var _path = ar.join('/');
var _path = treeNode ? treeNode.props.eventKey : '' ;
if (_path.charAt(0) === '/') {
_path = _path.substring(1)
}
// var url = `/api/v1/games/${this.props.game.identifier}/entries?path=${_path}&rev=master&gpid=${this.props.myshixun.gpid}`
let url = `/myshixuns/${this.props.myshixun.identifier}/repository.json`
if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) {
this.setState({
loadingFirstRepoFiles: true,
})
}
var that = this;
axios.post(url, {
path: _path
// withCredentials: true,
})
.then((response) => {
const repoFilesData = this.map2OldData(response.data.trees)
if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) { // 还没树节点,没加载过
const fileTreeData = fileData2TreeData(repoFilesData)
this.setState({
fileTreeData,
loadingFirstRepoFiles: false,
});
} else {
var _treeNode = treeNode;
var _eventKey = _treeNode.props.eventKey;
const fileTreeData = that.state.fileTreeData;
// 新的数组放置到treenode下
const tempFileTreeData = fileData2TreeData(repoFilesData)
getNewTreeData(fileTreeData, _eventKey, tempFileTreeData, 2);
this.setState({
fileTreeData,
})
}
resolve && resolve();
})
.catch(function (error) {
console.log(error);
reject && reject();
});
}
onTreeSelect = (selectedKeys, info) => {
const isLeaf = info.node.props.isLeaf;
if (isLeaf) { // 叶子节点
selectedKeys.length && this.setState({
fileTreeSelectedKeys: selectedKeys
})
const { fetchRepositoryCode, onPathChange, showSnackbar, challenge } = this.props;
const nodePath = info.node.props.eventKey;
// 设置pathIndex为-1那么代码文件下拉可以切回可编辑的文件
if (!challenge.multiPath) { // 单path任务 多path任务 path是数组
if (challenge.path.trim() == nodePath.trim()) {
if (challenge.pathIndex === 0) {
showSnackbar(`当前编辑文件已经是${nodePath}`)
} else {
onPathChange(0)
}
return;
} else {
onPathChange(-1)
}
} else {
let isCurrentFile = false;
let cur_index = -1;
if (challenge.path && challenge.path.forEach) {
challenge.path.forEach((item, index) => {
if (nodePath == item) {
isCurrentFile = true;
cur_index = index;
}
})
}
if (isCurrentFile) {
onPathChange(cur_index)
showSnackbar(`当前编辑文件已经是${nodePath}`)
} else {
onPathChange(-1)
}
}
if (nodePath) {
const filetype = nodePath.split('.').pop().toLowerCase();
if (filetype == 'jpg' || filetype == 'png' || filetype == 'gif' || filetype == 'jpeg'
|| filetype == 'jar'
|| filetype == 'doc' || filetype == 'pdf' || filetype == 'xsl' || filetype == 'ppt') {
showSnackbar(`不支持加载${filetype}类型的文件。`)
return;
}
fetchRepositoryCode(null, nodePath, 1);
} else {
console.error('no eventKey:', info.node)
}
}
}
// /shixuns/mnf6b7z3/shixun_discuss?challenge_id=88
render() {
return (
<React.Fragment>
{this.props.isOnlyContainer == true ?
React.Children.map(this.props.children, child => {
if(!child) {
return ''
}
return React.cloneElement(child, Object.assign({...this.state}, {
loadRepoFiles: this.loadRepoFiles,
onTreeSelect: this.onTreeSelect,
onLoadData: this.onLoadData,
}))
})
:
<CodeRepositoryView {...this.props}
{...this.state}
showFilesDrawer={this.showFilesDrawer}
loadRepoFiles={this.loadRepoFiles}
onLoadData={this.onLoadData}
onTreeSelect={ this.onTreeSelect }
onRepositoryViewExpand={this.onRepositoryViewExpand}
tabIndexChange={this.tabIndexChange}
showSettingDrawer={this.showSettingDrawer}
></CodeRepositoryView> }
</React.Fragment>
);
}
}
export default CodeRepositoryViewContainer;
import React, { Component } from 'react';
import CodeRepositoryView from './CodeRepositoryView'
import axios from 'axios'
import './CodeRepositoryView.css'
// 自己处理path加上父节点的path, 这里是处理树节点了所以是set key
function addPrePath(treeData, parentNodePath) {
return treeData.map(item => {
return {
...item,
key: `${parentNodePath}/${item.name}`
}
})
}
function getNewTreeData(treeData, curKey, child, level) {
const loop = (data) => {
data.forEach((item) => {
// 这里不能用indexOf 同一级可能出现test目录和test.py文件
if (item.key == curKey) {
child = addPrePath(child, curKey);
item.children = child;
} else {
if (item.children) {
loop(item.children);
}
}
});
};
loop(treeData);
}
function fileData2TreeData(repoFilesData) {
if(repoFilesData!=null){
const fileTreeData = [];
repoFilesData.forEach((item) => {
if (item.kind === 'file') {
fileTreeData.push({
key: item.path,
name: item.name,
isLeaf: true
})
} else {
fileTreeData.push({
key: item.path,
name: item.name,
// isLeaf: false
})
}
})
return fileTreeData;
}
}
class CodeRepositoryViewContainer extends Component {
constructor(props) {
super(props)
this.showFilesDrawer = this.showFilesDrawer.bind(this)
this.onRepositoryViewExpand = this.onRepositoryViewExpand.bind(this)
this.state = {
drawerOpen: false,
loadingFirstRepoFiles: false,
fileTreeData: "",
fileTreeSelectedKeys: [],
codeRepositoryViewExpanded: false,
tabIndex: 0,
settingDrawerOpen: false
}
}
showSettingDrawer = (open) => {
this.setState({settingDrawerOpen: open})
}
tabIndexChange = (index) => {
this.setState({tabIndex: index});
}
onRepositoryViewExpand() {
window.repository_extend_and_zoom();
this.setState({
evaluateViewExpanded: !this.state.evaluateViewExpanded
}, () => {
setTimeout(()=>{
window.__tpiOnResize()
}, 300)
})
}
showFilesDrawer(open) {
if (this.props.loading === true) {
return;
}
if (!this.state.fileTreeData) {
this.fetchRepoFiles();
}
this.setState({
drawerOpen: open,
})
}
loadRepoFiles = () => {
if (!this.state.fileTreeData) {
this.fetchRepoFiles();
}
}
componentWillReceiveProps(newProps, oldProps) {
}
componentDidMount() {
}
componentDidUpdate(prevProps, prevState, snapshot) {
const { game, challenge } = this.props
if (this.props.game && (!prevProps.game || prevProps.game.identifier !== this.props.game.identifier) ) {
this.setState({
fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ]
})
// 初始化
} else if (this.state.fileTreeSelectedKeys.length === 0 && challenge && challenge.path) {
this.setState({
fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ]
})
} else if (challenge && prevProps && prevProps.challenge
&& challenge.pathIndex != prevProps.challenge.pathIndex
&& challenge.pathIndex !== -1) {
this.setState({
fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[challenge.pathIndex] : challenge.path ]
})
}
}
handleDialogClose() {
this.setState({
dialogOpen: false
})
}
onLoadData = (treeNode) => {
if (treeNode.props.children && treeNode.props.children.length) {
return new Promise((resolve) => {
resolve();
});
}
return new Promise((resolve, reject) => {
this.fetchRepoFiles(treeNode, resolve, reject)
});
}
map2OldData = (treeData) => {
if (!treeData || treeData.length === 0) return treeData;
treeData = treeData.map(item => {
return {
kind: item.type == "blob" ? "file" : "dir", // blob->file tree->dir
path: item.name,
name: item.name
}
})
return treeData;
}
fetchRepoFiles(treeNode, resolve, reject) {
// http://localhost:3000/api/v1/games/829al3mst4fy/entries?path=src/step1&rev=master
if (!this.props.challenge || !this.props.game) {
return;
}
// var ar = this.props.challenge.path.split('/');
// ar.length = ar.length - 2;
// var _path = ar.join('/');
var _path = treeNode ? treeNode.props.eventKey : '' ;
if (_path.charAt(0) === '/') {
_path = _path.substring(1)
}
// var url = `/api/v1/games/${this.props.game.identifier}/entries?path=${_path}&rev=master&gpid=${this.props.myshixun.gpid}`
let url = `/myshixuns/${this.props.myshixun.identifier}/repository.json`
if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) {
this.setState({
loadingFirstRepoFiles: true,
})
}
var that = this;
axios.post(url, {
path: _path
// withCredentials: true,
})
.then((response) => {
const repoFilesData = this.map2OldData(response.data.trees)
if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) { // 还没树节点,没加载过
const fileTreeData = fileData2TreeData(repoFilesData)
this.setState({
fileTreeData,
loadingFirstRepoFiles: false,
});
} else {
var _treeNode = treeNode;
var _eventKey = _treeNode.props.eventKey;
const fileTreeData = that.state.fileTreeData;
// 新的数组放置到treenode下
const tempFileTreeData = fileData2TreeData(repoFilesData)
getNewTreeData(fileTreeData, _eventKey, tempFileTreeData, 2);
this.setState({
fileTreeData,
})
}
resolve && resolve();
})
.catch(function (error) {
console.log(error);
reject && reject();
});
}
onTreeSelect = (selectedKeys, info) => {
const isLeaf = info.node.props.isLeaf;
if (isLeaf) { // 叶子节点
selectedKeys.length && this.setState({
fileTreeSelectedKeys: selectedKeys
})
const { fetchRepositoryCode, onPathChange, showSnackbar, challenge } = this.props;
const nodePath = info.node.props.eventKey;
// 设置pathIndex为-1那么代码文件下拉可以切回可编辑的文件
if (!challenge.multiPath) { // 单path任务 多path任务 path是数组
if (challenge.path.trim() == nodePath.trim()) {
if (challenge.pathIndex === 0) {
showSnackbar(`当前编辑文件已经是${nodePath}`)
} else {
onPathChange(0)
}
return;
} else {
onPathChange(-1)
}
} else {
let isCurrentFile = false;
let cur_index = -1;
if (challenge.path && challenge.path.forEach) {
challenge.path.forEach((item, index) => {
if (nodePath == item) {
isCurrentFile = true;
cur_index = index;
}
})
}
if (isCurrentFile) {
onPathChange(cur_index)
showSnackbar(`当前编辑文件已经是${nodePath}`)
} else {
onPathChange(-1)
}
}
if (nodePath) {
const filetype = nodePath.split('.').pop().toLowerCase();
if (filetype == 'jpg' || filetype == 'png' || filetype == 'gif' || filetype == 'jpeg'
|| filetype == 'jar'
|| filetype == 'doc' || filetype == 'pdf' || filetype == 'xsl' || filetype == 'ppt') {
showSnackbar(`不支持加载${filetype}类型的文件。`)
return;
}
fetchRepositoryCode(null, nodePath, 1);
} else {
console.error('no eventKey:', info.node)
}
}
}
// /shixuns/mnf6b7z3/shixun_discuss?challenge_id=88
render() {
return (
<React.Fragment>
{this.props.isOnlyContainer == true ?
React.Children.map(this.props.children, child => {
if(!child) {
return ''
}
return React.cloneElement(child, Object.assign({...this.state}, {
loadRepoFiles: this.loadRepoFiles,
onTreeSelect: this.onTreeSelect,
onLoadData: this.onLoadData,
}))
})
:
<CodeRepositoryView {...this.props}
{...this.state}
showFilesDrawer={this.showFilesDrawer}
loadRepoFiles={this.loadRepoFiles}
onLoadData={this.onLoadData}
onTreeSelect={ this.onTreeSelect }
onRepositoryViewExpand={this.onRepositoryViewExpand}
tabIndexChange={this.tabIndexChange}
showSettingDrawer={this.showSettingDrawer}
></CodeRepositoryView> }
</React.Fragment>
);
}
}
export default CodeRepositoryViewContainer;

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

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

@ -14,24 +14,24 @@ import TPMRightSection from "../../tpm/component/TPMRightSection";
import styled from "styled-components";
const getItemStyle = (isDragging, draggableStyle) => ({
// change background colour if dragging
background: isDragging ? '#dceeff' : '',
// styles we need to apply on draggables
...draggableStyle,
// change background colour if dragging
background: isDragging ? '#dceeff' : '',
// styles we need to apply on draggables
...draggableStyle,
});
const getItems = count =>
Array.from({ length: count }, (v, k) => k).map(k => ({
id: `item-${k}`,
content: `item ${k}`
}));
Array.from({ length: count }, (v, k) => k).map(k => ({
id: `item-${k}`,
content: `item ${k}`
}));
// a little function to help us with reordering the result
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
return result;
};
const List = styled.div`
@ -66,90 +66,90 @@ const DragHandle = styled.div`
`;
const $ =window.$
class PathDetailIndex extends Component{
constructor(props){
super(props)
this.state={
constructor(props){
super(props)
this.state={
progress:undefined,
tags:undefined,
members:undefined,
detailInfoList:undefined,
clickdetailInfoListtype:false,
Modalstype:false,
Modalstopval:undefined,
Modalsbottomval:undefined,
cardsModalcancel:this.cardsModalcancel,
cardsModalsave:this.cardsModalsave,
user_id:undefined,
loadtype:false,
detailInfoList:undefined,
clickdetailInfoListtype:false,
Modalstype:false,
Modalstopval:undefined,
Modalsbottomval:undefined,
cardsModalcancel:this.cardsModalcancel,
cardsModalsave:this.cardsModalsave,
user_id:undefined,
loadtype:false,
courses:undefined,
items: getItems(10),
items: getItems(10),
pathtopskey:1
}
this.onDragEnd = this.onDragEnd.bind(this);
}
this.onDragEnd = this.onDragEnd.bind(this);
}
onDragEnd(result) {
// dropped outside the list
if (!result.destination) {
return;
}
}
onDragEnd(result) {
// dropped outside the list
if (!result.destination) {
return;
}
try {
try {
}catch (e) {
}catch (e) {
}
const items = reorder(
this.state.members,
result.source.index,
result.destination.index
);
}
const items = reorder(
this.state.members,
result.source.index,
result.destination.index
);
this.setState({
detailInfoList:this.state.detailInfoList,
this.setState({
detailInfoList:this.state.detailInfoList,
members:items,
items
});
console.log(this.state.members)
console.log("items 数组数组数组数组")
console.log(items)
}
cardsModalcancel=()=>{
this.setState({
Modalstype:false,
})
// TODO 这个是临时处理,还需要优化,这里要看怎么区分处理
if (this.state.Modalstopval == '你确定要删除该成员吗?') {
return;
}
items
});
console.log(this.state.members)
console.log("items 数组数组数组数组")
console.log(items)
}
cardsModalcancel=()=>{
this.setState({
Modalstype:false,
})
// TODO 这个是临时处理,还需要优化,这里要看怎么区分处理
if (this.state.Modalstopval == '你确定要删除该成员吗?') {
return;
}
this.props.history.goBack()
}
}
cardsModalsave=()=>{
this.setState({
Modalstype:false,
})
cardsModalsave=()=>{
this.setState({
Modalstype:false,
})
this.props.history.goBack()
}
// 加载markdown
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");
}, 200)
}
}
// 加载markdown
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");
}, 200)
}
componentDidMount(){
this.getdatasindex()
}
componentDidMount(){
this.getdatasindex()
}
getdatasindex=(key)=>{
getdatasindex=(key)=>{
let pathid=this.props.match.params.pathId;
let url="/paths/"+pathid+".json";
@ -168,7 +168,7 @@ class PathDetailIndex extends Component{
if(result.data.allow_visit===true){
this.setState({
detailInfoList:result.data,
courses:result.data.courses,
courses:result.data.courses,
pathtopskey:key===undefined?1:key,
// items: getItems(result.data.members.length),
})
@ -205,157 +205,157 @@ class PathDetailIndex extends Component{
})
}
updatadetailInfoList=()=>{
this.getdatasindex();
}
clickNewsubscript=(val)=>{
if(val===0){
this.setState({
clickdetailInfoListtype:true
})
}else{
this.setState({
clickdetailInfoListtype:false
})
}
updatadetailInfoList=()=>{
this.getdatasindex();
}
}
clickNewsubscript=(val)=>{
if(val===0){
this.setState({
clickdetailInfoListtype:true
})
}else{
this.setState({
clickdetailInfoListtype:false
})
}
timeStamp=(value)=>{
var secondTime = parseInt(value);// 秒
var minuteTime = 0;// 分
var hourTime = 0;// 小时
if(secondTime > 60) {//如果秒数大于60将秒数转换成整数
//获取分钟除以60取整数得到整数分钟
minuteTime = parseInt(secondTime / 60);
//获取秒数,秒数取佘,得到整数秒数
secondTime = parseInt(secondTime % 60);
//如果分钟大于60将分钟转换成小时
if(minuteTime > 60) {
//获取小时获取分钟除以60得到整数小时
hourTime = parseInt(minuteTime / 60);
//获取小时后取佘的分获取分钟除以60取佘的分
minuteTime = parseInt(minuteTime % 60);
}
}
var result = "" + parseInt(secondTime) + "秒";
if(minuteTime > 0) {
result = "" + parseInt(minuteTime) + "分" + result;
}
if(hourTime > 0) {
result = "" + parseInt(hourTime) + "小时" + result;
}
return result;
}
}
timeStamp=(value)=>{
var secondTime = parseInt(value);// 秒
var minuteTime = 0;// 分
var hourTime = 0;// 小时
if(secondTime > 60) {//如果秒数大于60将秒数转换成整数
//获取分钟除以60取整数得到整数分钟
minuteTime = parseInt(secondTime / 60);
//获取秒数,秒数取佘,得到整数秒数
secondTime = parseInt(secondTime % 60);
//如果分钟大于60将分钟转换成小时
if(minuteTime > 60) {
//获取小时获取分钟除以60得到整数小时
hourTime = parseInt(minuteTime / 60);
//获取小时后取佘的分获取分钟除以60取佘的分
minuteTime = parseInt(minuteTime % 60);
}
}
var result = "" + parseInt(secondTime) + "秒";
if(minuteTime > 0) {
result = "" + parseInt(minuteTime) + "分" + result;
}
if(hourTime > 0) {
result = "" + parseInt(hourTime) + "小时" + result;
}
return result;
}
shanchuallow=(id)=>{
this.setState({
user_id:id,
Modalstype:true,
Modalstopval:"你确定要删除该成员吗?",
cardsModalsave:this.delectshanchuallow,
loadtype:false
})
}
delectshanchuallow=()=>{
let{user_id}=this.state;
let pathid=this.props.match.params.pathId;
let url="/paths/"+pathid+"/delete_member.json";
let param={user_id:user_id};
axios.delete(url,{data:param}).then((response) => {
if(response.data.status===1){
if (this.props.current_user.user_id == user_id) {
this.props.history.push('/paths')
return;
}
this.props.showNotification(response.data.message)
this.setState({
Modalstype:false,
// Modalstopval:response.data.message,
loadtype:false,
// cardsModalsave:this.cardsModalsave,
})
this.updatadetailInfoList();
}
}).catch((error) => {
console.log(error)
})
}
shanchuallow=(id)=>{
this.setState({
user_id:id,
Modalstype:true,
Modalstopval:"你确定要删除该成员吗?",
cardsModalsave:this.delectshanchuallow,
loadtype:false
})
}
//上移
moveup=(data)=>{
// console.log(data);
let pathid=this.props.match.params.pathId;
let url=`/paths/${pathid}/up_member_position.json`;
axios.post(url,{
user_id:data.id
}).then((response) => {
if(response.status === 200){
console.log("上移");
// console.log(this.state.detailInfoList.members);
// console.log(response);
this.setState({
detailInfoList:this.state.detailInfoList,
delectshanchuallow=()=>{
let{user_id}=this.state;
let pathid=this.props.match.params.pathId;
let url="/paths/"+pathid+"/delete_member.json";
let param={user_id:user_id};
axios.delete(url,{data:param}).then((response) => {
if(response.data.status===1){
if (this.props.current_user.user_id == user_id) {
this.props.history.push('/paths')
return;
}
this.props.showNotification(response.data.message)
this.setState({
Modalstype:false,
// Modalstopval:response.data.message,
loadtype:false,
// cardsModalsave:this.cardsModalsave,
})
this.updatadetailInfoList();
}
}).catch((error) => {
console.log(error)
})
}
//上移
moveup=(data)=>{
// console.log(data);
let pathid=this.props.match.params.pathId;
let url=`/paths/${pathid}/up_member_position.json`;
axios.post(url,{
user_id:data.id
}).then((response) => {
if(response.status === 200){
console.log("上移");
// console.log(this.state.detailInfoList.members);
// console.log(response);
this.setState({
detailInfoList:this.state.detailInfoList,
members:response.data.members
});
// console.log(this.state.detailInfoList.members);
});
// console.log(this.state.detailInfoList.members);
}
}
}).catch((error) => {
console.log(error)
})
}
}).catch((error) => {
console.log(error)
})
}
//下移
movedown =(data) => {
// console.log(data);
let pathid=this.props.match.params.pathId;
let url=`/paths/${pathid}/down_member_position.json`;
axios.post(url,{
user_id:data.id
}).then((response) => {
if( response.status === 200){
console.log("下移");
// console.log(this.state.detailInfoList.members);
// console.log(response);
this.setState({
detailInfoList:this.state.detailInfoList,
members:response.data.members
});
// console.log(this.state.detailInfoList.members);
}
}).catch((error) => {
console.log(error)
})
}
render(){
this.updatamakedown("shixuns_propaedeutics");
this.updatamakedown("subject_learning_notes");
let {detailInfoList,
clickdetailInfoListtype,
Modalstype,
Modalstopval,
Modalsbottomval,
cardsModalcancel,
cardsModalsave,
loadtype,
//下移
movedown =(data) => {
// console.log(data);
let pathid=this.props.match.params.pathId;
let url=`/paths/${pathid}/down_member_position.json`;
axios.post(url,{
user_id:data.id
}).then((response) => {
if( response.status === 200){
console.log("下移");
// console.log(this.state.detailInfoList.members);
// console.log(response);
this.setState({
detailInfoList:this.state.detailInfoList,
members:response.data.members
});
// console.log(this.state.detailInfoList.members);
}
}).catch((error) => {
console.log(error)
})
}
render(){
this.updatamakedown("shixuns_propaedeutics");
this.updatamakedown("subject_learning_notes");
let {detailInfoList,
clickdetailInfoListtype,
Modalstype,
Modalstopval,
Modalsbottomval,
cardsModalcancel,
cardsModalsave,
loadtype,
progress,
members,
tags,
courses,
} = this.state
} = this.state
return(
<div className="newContainer">
return(
<div className="newContainer">
<style>
{
`
@ -365,206 +365,206 @@ class PathDetailIndex extends Component{
`
}
</style>
<Modals
modalsType={Modalstype}
modalsTopval={Modalstopval}
modalsBottomval={Modalsbottomval}
modalCancel={cardsModalcancel}
modalSave={cardsModalsave}
loadtype={loadtype}
>
</Modals>
<div className="newMain clearfix">
<DetailTop {...this.state} {...this.props} getdatasindex={(key)=>this.getdatasindex(key)}></DetailTop>
<div className="educontent clearfix mb80">
<div className="with65 fl">
<div className="produce-content mb10">
<p className="clearfix mb20">
<span className="fl font-18 font-bd">简介</span>
{/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/}
{/*<Tooltip placement="bottom" title={"编辑"}>*/}
{/*<Link className="fr" to={"/paths/"+this.props.match.params.pathId+"/edit"}>*/}
{/*<i className="iconfont icon-bianjidaibeijing font-20 color-green"></i>*/}
{/*</Link>*/}
{/*</Tooltip>*/}
{/*:""*/}
{/*}*/}
</p>
<div className="color-grey-6 clearfix">
<div id="shixuns_propaedeutics" className="new_li fl" style={{"padding":" 0px","textAlign": "justify;"}}>
{detailInfoList === undefined ? "" :detailInfoList.description===null?"":
<div className={"markdown-body font-14"} dangerouslySetInnerHTML={{__html: markdownToHTML(detailInfoList.description).replace(/▁/g,"▁▁▁")}}></div>
}
</div>
</div>
</div>
<DetailCards
{...this.props}
{...this.state}
updatadetailInfoLists={this.updatadetailInfoList}
></DetailCards>
</div>
<div className="with35 fr pl20">
<div className="edu-back-white mustlearn mb10">
<p className="clearfix mb30">
<span className="font-16">课程须知</span>
{/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/}
{/*<Tooltip placement="bottom" title={"编辑"}>*/}
{/*<Link to={"/paths/"+this.props.match.params.pathId+"/edit#learning_notes"} className="fr mtf5">*/}
{/*<i className="iconfont icon-bianjidaibeijing font-20 color-green"></i>*/}
{/*</Link>*/}
{/*</Tooltip>*/}
{/*:""*/}
{/*}*/}
</p>
<div id="subject_learning_notes" className="color-grey-6 new_li markdown-body editormd-html-preview justify">
{detailInfoList === undefined ? "" :detailInfoList.learning_notes===null?"":
<div className={"markdown-body font-14"} dangerouslySetInnerHTML={{__html: markdownToHTML(detailInfoList.learning_notes).replace(/▁/g,"▁▁▁")}}></div>
<Modals
modalsType={Modalstype}
modalsTopval={Modalstopval}
modalsBottomval={Modalsbottomval}
modalCancel={cardsModalcancel}
modalSave={cardsModalsave}
loadtype={loadtype}
>
</Modals>
<div className="newMain clearfix">
<DetailTop {...this.state} {...this.props} getdatasindex={(key)=>this.getdatasindex(key)}></DetailTop>
<div className="educontent clearfix mb80">
<div className="with65 fl">
<div className="produce-content mb10">
<p className="clearfix mb20">
<span className="fl font-18 font-bd">简介</span>
{/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/}
{/*<Tooltip placement="bottom" title={"编辑"}>*/}
{/*<Link className="fr" to={"/paths/"+this.props.match.params.pathId+"/edit"}>*/}
{/*<i className="iconfont icon-bianjidaibeijing font-20 color-green"></i>*/}
{/*</Link>*/}
{/*</Tooltip>*/}
{/*:""*/}
{/*}*/}
</p>
<div className="color-grey-6 clearfix">
<div id="shixuns_propaedeutics" className="new_li fl" style={{"padding":" 0px","textAlign": "justify;"}}>
{detailInfoList === undefined ? "" :detailInfoList.description===null?"":
<div className={"markdown-body font-14"} dangerouslySetInnerHTML={{__html: markdownToHTML(detailInfoList.description).replace(/▁/g,"▁▁▁")}}></div>
}
</div>
</div>
{tags === undefined ? "" :tags === null ? "":
<div className="edu-back-white padding40-20 mb10 relative">
<p className="font-16 mb20">技能标签 <span className="color-grey-c">{tags.length}</span></p>
<div className={clickdetailInfoListtype===false?"newedbox newedboxheight":"newedbox newminheight"}>
<div className="clearfix" id="boxheight">
{
tags && tags.map((item,key)=>{
return(
<span value={key} className = {item.status == true ? "edu-filter-btn29BD8B fl" : "newedu-filter-btn fl"}>{item.tag_name}</span>
)
})
}
</div>
</div>
<Tooltip placement="bottom" title={"显示全部"}>
<div className={tags.length>20&&clickdetailInfoListtype===false?"newsubscript mb9 color-grey-9 fr":"newsubscript mb9 color-grey-9 none"}
onClick={()=>this.clickNewsubscript(0)}
><span className="mr8">...</span><Icon type="caret-down" />
</div>
</Tooltip>
<Tooltip placement="bottom" title={"收起"}>
<div className={clickdetailInfoListtype===false?"newsubscript mb9 color-grey-9 none":"newsubscript mb9 color-grey-9 fr"}
onClick={()=>this.clickNewsubscript(1)}><Icon type="caret-up" />
</div>
</Tooltip>
</div>
}
{
this.props.checkIfLogin()===false?"":progress === undefined ? "" : progress === null ? "" :
<div className="edu-back-white myProgress padding40-20 mb10">
<p className="mb20">
<span className="font-16 mr10">我的进展</span>
<Tooltip placement="bottom" title="获得经验值/总经验值">
<span className="color-green" >{progress.my_score} / {progress.all_score}</span>
</Tooltip>
</p>
<p className="clearfix mb10">
<span className="fl color-green">已学 {progress.learned}%</span>
<span className="fr color-grey-9" id="time-consuming">学习耗时{this.timeStamp(progress.time)} </span>
</p>
<div className="myProgressNav"><div className="myProgressGreen" style={{"width":`${progress.learned+"%"}`}}></div></div>
</div>
}
{
members ===undefined ?"":members === null ?"":
<div className="teacherTeam edu-back-white clearfix" id="subject_members">
<p className="font-16 clearfix">教学团队</p>
{ members===undefined?
members && members.map((item,key)=>{
return(
<div className="teacherTeamItem clearfix df" key={key}>
<a href={item.user_url} target="_blank" className="fl">
<img alt="头像" className="radius" height="80" src={getImageUrl(`${"images/"+item.image_url}`)} width="80"/>
</a>
<div className="fl ml15 flex1">
<p className="mb10 mt5">{item.name}
{/*{*/}
{/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/}
{/* <a className="fr" onClick={()=>this.shanchuallow(item.id)}><i className="iconfont icon-shanchu color-grey-c font-14 font-n"></i></a>:""*/}
{/*}*/}
</p>
<div className="clearfix">
<p className="color-grey-9 font-12 fl"><span className="mr10">{item.school}</span><span>{item.identity}</span></p>
</div>
</div>
</div>
)
})
:detailInfoList===undefined?"":detailInfoList.allow_add_member===true?
members && members.map((item,key)=>{
return(
<div className="teacherTeamItem clearfix df" key={key}>
<a href={item.user_url} target="_blank" className="fl">
<img alt="头像" className="radius" height="80" src={getImageUrl(`${"images/"+item.image_url}`)} width="80"/>
</a>
<div className="fl ml15 flex1">
<p className="mb10 mt5">{item.name}
{/* 新增role 判断是否能删除 1 管理员 2 合作者 */}
{
detailInfoList===undefined?"":detailInfoList.allow_add_member===true && item.role == 2?
<a className="fr" onClick={()=>this.shanchuallow(item.id)}><i className="iconfont icon-shanchu color-grey-c font-14 font-n"></i></a>:""
}
</p>
<div className="clearfix">
<p className="color-grey-9 font-12 fl"><span className="mr10">{item.school}</span><span>{item.identity}</span></p>
</div>
{
detailInfoList===undefined?"":detailInfoList.allow_add_member===true? <div>
{key!=0?<div className="fr ml15 flex1"><a onClick={()=>this.moveup(item)}><Tooltip title="上移"><i className="color-green font-18 iconfont icon-xiangshangyi"></i></Tooltip></a></div>:""}
{key+1== members.length?"":<div className="fr ml15 flex1 "><a onClick={()=>this.movedown(item)}><Tooltip title="下移"><i className="color-green font-18 iconfont icon-xiangxiayi"></i></Tooltip></a></div>}
</div>
:""
}
</div>
</div>
)
})
: members && members.map((item,key)=>{
return(
<div className="teacherTeamItem clearfix df" key={key}>
<a href={item.user_url} target="_blank" className="fl">
<img alt="头像" className="radius" height="80" src={getImageUrl(`${"images/"+item.image_url}`)} width="80"/>
</a>
<div className="fl ml15 flex1">
<p className="mb10 mt5">{item.name}
{/*{*/}
{/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/}
{/* <a className="fr" onClick={()=>this.shanchuallow(item.id)}><i className="iconfont icon-shanchu color-grey-c font-14 font-n"></i></a>:""*/}
{/*}*/}
</p>
<div className="clearfix">
<p className="color-grey-9 font-12 fl"><span className="mr10">{item.school}</span><span>{item.identity}</span></p>
</div>
</div>
</div>
)
})}
</div>
}
<AddCollaborators {...this.props} {...this.state} updatadetailInfoLists={this.updatadetailInfoList}></AddCollaborators>
</div>
</div>
</div>
</div>
)
}
</div>
</div>
</div>
<DetailCards
{...this.props}
{...this.state}
updatadetailInfoLists={this.updatadetailInfoList}
></DetailCards>
</div>
<div className="with35 fr pl20">
<div className="edu-back-white mustlearn mb10">
<p className="clearfix mb30">
<span className="font-16">课程须知</span>
{/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/}
{/*<Tooltip placement="bottom" title={"编辑"}>*/}
{/*<Link to={"/paths/"+this.props.match.params.pathId+"/edit#learning_notes"} className="fr mtf5">*/}
{/*<i className="iconfont icon-bianjidaibeijing font-20 color-green"></i>*/}
{/*</Link>*/}
{/*</Tooltip>*/}
{/*:""*/}
{/*}*/}
</p>
<div id="subject_learning_notes" className="color-grey-6 new_li markdown-body editormd-html-preview justify">
{detailInfoList === undefined ? "" :detailInfoList.learning_notes===null?"":
<div className={"markdown-body font-14"} dangerouslySetInnerHTML={{__html: markdownToHTML(detailInfoList.learning_notes).replace(/▁/g,"▁▁▁")}}></div>
}
</div>
</div>
{tags === undefined ? "" :tags === null ? "":
<div className="edu-back-white padding40-20 mb10 relative">
<p className="font-16 mb20">技能标签 <span className="color-grey-c">{tags.length}</span></p>
<div className={clickdetailInfoListtype===false?"newedbox newedboxheight":"newedbox newminheight"}>
<div className="clearfix" id="boxheight">
{
tags && tags.map((item,key)=>{
return(
<span value={key} className = {item.status == true ? "edu-filter-btn29BD8B fl" : "newedu-filter-btn fl"}>{item.tag_name}</span>
)
})
}
</div>
</div>
<Tooltip placement="bottom" title={"显示全部"}>
<div className={tags.length>20&&clickdetailInfoListtype===false?"newsubscript mb9 color-grey-9 fr":"newsubscript mb9 color-grey-9 none"}
onClick={()=>this.clickNewsubscript(0)}
><span className="mr8">...</span><Icon type="caret-down" />
</div>
</Tooltip>
<Tooltip placement="bottom" title={"收起"}>
<div className={clickdetailInfoListtype===false?"newsubscript mb9 color-grey-9 none":"newsubscript mb9 color-grey-9 fr"}
onClick={()=>this.clickNewsubscript(1)}><Icon type="caret-up" />
</div>
</Tooltip>
</div>
}
{
this.props.checkIfLogin()===false?"":progress === undefined ? "" : progress === null ? "" :
<div className="edu-back-white myProgress padding40-20 mb10">
<p className="mb20">
<span className="font-16 mr10">我的进展</span>
<Tooltip placement="bottom" title="获得经验值/总经验值">
<span className="color-green" >{progress.my_score} / {progress.all_score}</span>
</Tooltip>
</p>
<p className="clearfix mb10">
<span className="fl color-green">已学 {progress.learned}%</span>
<span className="fr color-grey-9" id="time-consuming">学习耗时{this.timeStamp(progress.time)} </span>
</p>
<div className="myProgressNav"><div className="myProgressGreen" style={{"width":`${progress.learned+"%"}`}}></div></div>
</div>
}
{
members ===undefined ?"":members === null ?"":
<div className="teacherTeam edu-back-white clearfix" id="subject_members">
<p className="font-16 clearfix">教学团队</p>
{ members===undefined?
members && members.map((item,key)=>{
return(
<div className="teacherTeamItem clearfix df" key={key}>
<a href={item.user_url} target="_blank" className="fl">
<img alt="头像" className="radius" height="80" src={getImageUrl(`${"images/"+item.image_url}`)} width="80"/>
</a>
<div className="fl ml15 flex1">
<p className="mb10 mt5">{item.name}
{/*{*/}
{/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/}
{/* <a className="fr" onClick={()=>this.shanchuallow(item.id)}><i className="iconfont icon-shanchu color-grey-c font-14 font-n"></i></a>:""*/}
{/*}*/}
</p>
<div className="clearfix">
<p className="color-grey-9 font-12 fl"><span className="mr10">{item.school}</span><span>{item.identity}</span></p>
</div>
</div>
</div>
)
})
:detailInfoList===undefined?"":detailInfoList.allow_add_member===true?
members && members.map((item,key)=>{
return(
<div className="teacherTeamItem clearfix df" key={key}>
<a href={item.user_url} target="_blank" className="fl">
<img alt="头像" className="radius" height="80" src={getImageUrl(`${"images/"+item.image_url}`)} width="80"/>
</a>
<div className="fl ml15 flex1">
<p className="mb10 mt5">{item.name}
{/* 新增role 判断是否能删除 1 管理员 2 合作者 */}
{
detailInfoList===undefined?"":detailInfoList.allow_add_member===true && item.role == 2?
<a className="fr" onClick={()=>this.shanchuallow(item.id)}><i className="iconfont icon-shanchu color-grey-c font-14 font-n"></i></a>:""
}
</p>
<div className="clearfix">
<p className="color-grey-9 font-12 fl"><span className="mr10">{item.school}</span><span>{item.identity}</span></p>
</div>
{
detailInfoList===undefined?"":detailInfoList.allow_add_member===true? <div>
{key!=0?<div className="fr ml15 flex1"><a onClick={()=>this.moveup(item)}><Tooltip title="上移"><i className="color-green font-18 iconfont icon-xiangshangyi"></i></Tooltip></a></div>:""}
{key+1== members.length?"":<div className="fr ml15 flex1 "><a onClick={()=>this.movedown(item)}><Tooltip title="下移"><i className="color-green font-18 iconfont icon-xiangxiayi"></i></Tooltip></a></div>}
</div>
:""
}
</div>
</div>
)
})
: members && members.map((item,key)=>{
return(
<div className="teacherTeamItem clearfix df" key={key}>
<a href={item.user_url} target="_blank" className="fl">
<img alt="头像" className="radius" height="80" src={getImageUrl(`${"images/"+item.image_url}`)} width="80"/>
</a>
<div className="fl ml15 flex1">
<p className="mb10 mt5">{item.name}
{/*{*/}
{/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/}
{/* <a className="fr" onClick={()=>this.shanchuallow(item.id)}><i className="iconfont icon-shanchu color-grey-c font-14 font-n"></i></a>:""*/}
{/*}*/}
</p>
<div className="clearfix">
<p className="color-grey-9 font-12 fl"><span className="mr10">{item.school}</span><span>{item.identity}</span></p>
</div>
</div>
</div>
)
})}
</div>
}
<AddCollaborators {...this.props} {...this.state} updatadetailInfoLists={this.updatadetailInfoList}></AddCollaborators>
</div>
</div>
</div>
</div>
)
}
}
export default PathDetailIndex;

@ -1,7 +1,7 @@
import React,{ Component } from "react";
import {getUrl,markdownToHTML} from 'educoder';
import {Input} from 'antd';
import {Input,Button} from 'antd';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import axios from 'axios';
@ -86,7 +86,8 @@ class PathNew extends Component{
pathName:"",
description:"",
point:"",
flag_name:true
flag_name:true,
bottonloading:false
}
}
@ -124,6 +125,9 @@ class PathNew extends Component{
return;
}
if (this.isEditPage == true) {
this.setState({
bottonloading:true
})
let pathId = this.props.match.params.pathId;
const editUrl = `/paths/${pathId}.json`
@ -135,11 +139,21 @@ class PathNew extends Component{
// console.log(response.data.subject_id);
if (response.data.subject_id) {
this.props.history.push(`/paths/${response.data.subject_id}`)
}
}else{
this.setState({
bottonloading:false
})
}
}).catch((error)=>{
console.log(error);
this.setState({
bottonloading:false
})
})
} else {
this.setState({
bottonloading:true
})
let url="/paths.json"
axios.post(url,{
name:pathName,
@ -149,9 +163,16 @@ class PathNew extends Component{
// console.log(response.data.subject_id);
if (response.data.subject_id) {
this.props.history.push(`/paths/${response.data.subject_id}`)
}
}else{
this.setState({
bottonloading:false
})
}
}).catch((error)=>{
console.log(error);
this.setState({
bottonloading:false
})
})
}
@ -267,7 +288,7 @@ class PathNew extends Component{
</div>
<div className="clearfix mb30 mt30">
<a href="javascript:void(0)" className="defalutSubmitbtn fl mr20" onClick={this.submitNewPath}>提交</a>
<Button className="defalutSubmitbtn fl mr20" loading={this.state.bottonloading} onClick={this.submitNewPath}>提交</Button>
{this.isEditPage ?
<Link to={`/paths/${this.props.match.params.pathId}`}
className="defalutCancelbtn fl">取消</Link>

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

@ -1,12 +1,16 @@
import React, { Component } from 'react';
import PathSearch from './ShixunPathSearch.js';
import { configShareForPaths } from 'educoder'
class ShixunPath extends Component{
constructor(props) {
super(props)
}
componentDidMount() {
configShareForPaths()
}
render(){
return(
<div>

@ -190,6 +190,8 @@ class TPMIndex extends Component {
identity: response.data.identity,
propaedeutics:response.data.propaedeutics,
status: response.data.shixun_status,
secret_repository: response.data.secret_repository,
});
}
}).catch((error) => {
@ -285,6 +287,10 @@ class TPMIndex extends Component {
(props) => (<TPMRepositoryCommits {...this.props} {...this.state} {...props}
/>)
}></Route>
<Route path="/shixuns/:shixunId/secret_repository/:repoId/commits" render={
(props) => (<TPMRepositoryCommits {...this.props} {...this.state} {...props} secret_repository_tab={true}
/>)
}></Route>
<Route exact path="/shixuns/:shixunId/challenges" render={
(props) => (<TPMChallengeComponent {...this.props} {...this.state} {...props}
@ -300,6 +306,11 @@ class TPMIndex extends Component {
(props) => (<TPMRepositoryComponent {...this.props} {...this.state} {...props}
/>)
}></Route>
<Route path="/shixuns/:shixunId/secret_repository" render={
(props) => (<TPMRepositoryComponent {...this.props} {...this.state} {...props} secret_repository_tab={true}
/>)
}></Route>
{/* <Route exact path="/shixuns/:shixunId/propaedeutics" component={TPMPropaedeuticsComponent}></Route> */}
<Route exact path="/shixuns/:shixunId/propaedeutics" render={

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

@ -30,6 +30,12 @@ class TPMRepositoryComponent extends Component {
isContentWidth100: this._isFileInPathArray(pathArray)
}
}
componentDidUpdate(prevProps, prevState) {
if (this.props.secret_repository_tab != prevProps.secret_repository_tab) {
this.fetchRepo()
}
}
componentDidMount = () => {
this.fetchRepo()
@ -72,7 +78,8 @@ class TPMRepositoryComponent extends Component {
let id = this.props.match.params.shixunId;
let url = `/shixuns/${id}/file_content.json`;
axios.post(url, {
path: path
path: path,
secret_repository: this.props.secret_repository_tab
}).then((response) => {
trace_collapse('repository res: ', response)
@ -138,7 +145,7 @@ class TPMRepositoryComponent extends Component {
const path = urlNewPathArray.join('/')
let id = this.props.match.params.shixunId;
let url = `/shixuns/${id}/repository.json`;
let url = `/shixuns/${id}/${this.props.secret_repository_tab ? 'secret_repository' : 'repository'}.json`;
// this.props.setLoadingContent(true)
axios.post(url, {
path: path ? path : ''

@ -353,6 +353,8 @@ export default class TPMsettings extends Component {
test_set_permission: response.data.shixun.test_set_permission,
hide_code: response.data.shixun.hide_code,
code_hidden: response.data.shixun.code_hidden,
is_secret_repository: response.data.shixun.is_secret_repository,
init_is_secret_repository: response.data.shixun.is_secret_repository,
forbid_copy: response.data.shixun.forbid_copy,
vnc: response.data.shixun.vnc,
vnc_evaluate: response.data.shixun.vnc_evaluate,
@ -439,20 +441,52 @@ export default class TPMsettings extends Component {
SelectshixunCommand=(e)=>{
// console.log( e.target.value)
this.setState({
webssh: e.target.value,
});
if(e.target.value===2){
this.setState({
SelectTheCommandtype: true,
multi_webssh:false
});
}else{
this.setState({
SelectTheCommandtype: false,
multi_webssh:false
});
}
const webssh = e.target.value
if (webssh == 2) {
this.setState({
webssh: webssh,
SelectTheCommandtype: true,
multi_webssh:false
});
} else {
if (this.state.init_is_secret_repository && !this.state.vnc && this.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)=>{
@ -525,6 +559,35 @@ export default class TPMsettings extends Component {
});
}
confirmDeleteSecretRepo = ({title, onOk}) => {
confirm({
title: title || <div>
<div>已创建的私密版本库及其内容将在保存时被删除</div>
<div>是否确认取消勾选</div>
</div>,
okText: '确定',
cancelText: '取消',
onOk: () => {
this.setState({ is_secret_repository: false })
onOk && onOk()
},
onCancel() {
},
});
}
is_secret_repository = (e) => {
const checked = e.target.checked
if (!checked) {
if (this.state.init_is_secret_repository) {
this.confirmDeleteSecretRepo({
})
} else {
this.setState({ is_secret_repository: false })
}
} else {
this.setState({ is_secret_repository: true })
}
}
forbid_copy = (e) => {
let sum = ""
if (e.target.checked === false) {
@ -550,11 +613,34 @@ export default class TPMsettings extends Component {
// } else if (e.target.checked === true) {
// sum = 1
// }
this.setState({
vnc: e.target.checked,
vnc_evaluate: false,
});
const vnc = e.target.checked;
if (!vnc) {
if (this.state.init_is_secret_repository && this.state.webssh != 2 && this.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;
@ -773,7 +859,8 @@ export default class TPMsettings extends Component {
// });
// }
submit_edit_shixun = () => {
if (this.saving == true) return;
this.saving = true;
if(this.state.status===-1){
this.props.showSnackbar("该实训已被删除,保存失败!");
return
@ -782,7 +869,7 @@ export default class TPMsettings extends Component {
let {
name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate,
evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh,
opening_time,shixunmemoMDvalue,shixun_service_configlist
opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository
} = this.state;
let newshixun_service_configlist = shixun_service_configlist.map(v => {
@ -886,6 +973,7 @@ export default class TPMsettings extends Component {
let Url = `/shixuns/` + id + `.json`;
let data = {
shixun:{
name: name,
webssh: webssh,
use_scope: use_scope,
@ -906,6 +994,7 @@ export default class TPMsettings extends Component {
description: description_editormd,
evaluate_script: evaluate_script_editormd,
},
is_secret_repository: is_secret_repository,
main_type: choice_main_type,
small_type: choice_small_type,
scope_partment: scope_partment,
@ -914,6 +1003,7 @@ export default class TPMsettings extends Component {
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);
@ -925,6 +1015,7 @@ export default class TPMsettings extends Component {
}).catch((error) => {
console.log(error)
this.saving = false;
})
@ -1460,6 +1551,7 @@ export default class TPMsettings extends Component {
name,
settingsData,
webssh,
is_secret_repository,
use_scope,
shixunsID,
can_copy,
@ -1653,8 +1745,6 @@ export default class TPMsettings extends Component {
// onMouseEnter={operateauthority?this.bigopen:""}
onSelect={operateauthority?this.bigopens:""}
// open={opers}
showSearch
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
@ -2201,6 +2291,15 @@ export default class TPMsettings extends Component {
</span>
</div>
{ (vnc || webssh == 2) && <div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>私密版本库:</span>
<span className="fl mt5">
<Checkbox checked={is_secret_repository === undefined ? false : is_secret_repository}
onChange={this.is_secret_repository}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则启用私密版本库学员页面不能查看该版本库目录</label>
</span>
</div>}
<div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>禁用复制粘贴:</span>
<span className="fl mt5">
@ -2241,7 +2340,7 @@ export default class TPMsettings extends Component {
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>VNC图形化评测:</span>
<span className="fl mt5 ml5">
<Checkbox checked={vnc_evaluate === undefined ? false : vnc_evaluate} onChange={this.shixun_vnc_evaluate}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则在VNC图形化实训中给学员开启评测</label>
<label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则在学员的VNC图形化页面中开启评测功能</label>
</span>
</div>:""}

@ -240,6 +240,7 @@ export default class TPMevaluation extends Component {
this.setState({
evaluationlist:newevaluationlist
})
console.log(newevaluationlist)
}
@ -539,6 +540,14 @@ export default class TPMevaluation extends Component {
this.setevaluationlist(newevaluationlist);
}
// 修改测试集的匹配规则
changeEvaluationRule=(e,key)=>{
let {evaluationlist}=this.state;
let newevaluationlist=evaluationlist;
newevaluationlist[key].match_rule=e.target.value
this.setevaluationlist(newevaluationlist);
}
evaluationoninputvalue=(e,key,type)=>{
$.fn.autoHeight = function(){
function autoHeight(elem){
@ -1159,6 +1168,13 @@ export default class TPMevaluation extends Component {
autoHeight="true"
onInput={(e)=>this.evaluationoninputvalue(e,key,"yq")}
></textarea>
<div className="clearfix lineh-30">
<span className="fl mr10 color-grey-6">匹配规则</span>
<RadioGroup className="fl" value={item.match_rule} onChange={(e)=>this.changeEvaluationRule(e,key)}>
<Radio value='full'>完全匹配</Radio>
<Radio value='last'>末尾匹配</Radio>
</RadioGroup>
</div>
</div>
)
})}

@ -5,7 +5,7 @@ import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class TPMNav extends Component {
render() {
const { user, match, shixun } = this.props;
const { user, match, shixun, secret_repository } = this.props;
let isAdminOrCreator = false;
if (user) {
isAdminOrCreator = user.admin || user.manager
@ -30,7 +30,10 @@ class TPMNav extends Component {
<Link to={`/shixuns/${shixunId}/repository`}
style={{display: this.props.identity >4||this.props.identity===undefined ? "none" : 'block'}}
className={`${match.url.indexOf('repository') != -1 ? 'active' : ''} fl mr40`}>版本库</Link>
className={`${match.url.indexOf('/repository') != -1 ? 'active' : ''} fl mr40`}>版本库</Link>
{secret_repository && <Link to={`/shixuns/${shixunId}/secret_repository`}
style={{display: this.props.identity >4||this.props.identity===undefined ? "none" : 'block'}}
className={`${match.url.indexOf('secret_repository') != -1 ? 'active' : ''} fl mr40`}>私密版本库</Link>}
<Link to={`/shixuns/${shixunId}/collaborators`}
className={`${match.url.indexOf('collaborators') != -1 ? 'active' : ''} fl mr40`}>合作者</Link>

@ -13,192 +13,193 @@ import {Icon,Tooltip} from 'antd';
// import "antd/dist/antd.css";
class TPMRightSection extends Component {
constructor(props) {
super(props)
this.state = {
TPMRightSection:false,
clickNewsubscripttype:false
}
}
// componentDidMount() {
// let id=this.props.match.params.shixunId;
//
// let shixunsDetailsURL=`/shixuns/`+id+`/show_right.json`;
//
// axios.get(shixunsDetailsURL).then((response)=> {
// if(response.status===200){
// this.setState({
// TPMRightSectionData: response.data
// });
// }
// }).catch((error)=>{
// console.log(error)
// });
// }
// shouldComponentUpdate(nextProps, nextState) {
// return nextProps.TPMRightSectionData !== this.state.TPMRightSectionData
// }
clickNewsubscript=(val)=>{
if(val===0){
this.setState({
TPMRightSection:true,
clickNewsubscripttype:true
})
}else{
this.setState({
TPMRightSection:false,
clickNewsubscripttype:false
})
}
}
render() {
let {TPMRightSection,clickNewsubscripttype}=this.state;
let {TPMRightSectionData}=this.props
return (
<div>
{
TPMRightSectionData===undefined?"":
<div>
<div className="edu-back-white padding40-20 mb10">
<p className="font-16 mb20">创建者</p>
<div className="df">
<a href={TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":`/users/${TPMRightSectionData.creator.login}/courses`}>
<img alt="头像" className="radius mr10" height="80" src={getImageUrl(TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":'images/'+TPMRightSectionData.creator.image_url+"?1532489442")} width="80" />
</a>
<div className="flex1">
<p className="mb20">{TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":TPMRightSectionData.creator.name}</p>
<div className="clearfix">
<span>发布 {TPMRightSectionData.user_shixuns_count}</span>
{/*<span className="ml20">粉丝 <span id="user_h_fan_count">{TPMRightSectionData.fans_count}</span></span>*/}
{/* <a href="/watchers/unwatch?className=fr+user_watch_btn+edu-default-btn+edu-focus-btn&amp;object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr edu-default-btn user_watch_btn edu-focus-btn" data-method="post" data-remote="true" id="cancel_watch" rel="nofollow">取消关注</a> */}
</div>
</div>
</div>
</div>
{
TPMRightSectionData === undefined ? "" :TPMRightSectionData.tags===undefined?"": TPMRightSectionData.tags.length === 0 ? "" :
<div className="edu-back-white padding40-20 mb10 relative">
<p className="font-16 mb20">技能标签 <span className="color-grey-c">{TPMRightSectionData.tags.length}</span></p>
<div className={TPMRightSection===false?"newedbox newedboxheight":"newedbox newminheight"}>
<div className="clearfix" id="boxheight">
{ TPMRightSectionData.tags.map((item,key)=>{
return(
<span className={item.status===false?"newedu-filter-btn fl":"edu-filter-btn29BD8B fl"}
style={{display:item.tag_name===" "||item.tag_name===""?"none":""}}
key={key}>{item.tag_name}</span>
)})
}
</div>
</div>
<div className={TPMRightSectionData.tags.length>15&&clickNewsubscripttype===false?"newsubscript mb9 color-grey-9":"newsubscript mb9 color-grey-9 none"}
data-tip-down="显示全部"
onClick={()=>this.clickNewsubscript(0)}><span className="mr8">...</span><Icon type="caret-down" />
</div>
<div className={clickNewsubscripttype===false?"newsubscript mb9 color-grey-9 none":"newsubscript mb9 color-grey-9"}
data-tip-down="显示全部"
onClick={()=>this.clickNewsubscript(1)}><Icon type="caret-up" />
</div>
</div>
}
<div className="padding20 edu-back-white mb10 mt10" style={{
display: TPMRightSectionData === undefined?"none":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "none" : "block"
}}>
<p className="mb20 font-16 clearfix">相关实践课程</p>
<div className="recommend-list" >
{
TPMRightSectionData===undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.map((i,k)=>{
return(
<div className="recomments clearfix df" key={k}>
<a href={"/paths/"+i.id} height="96" width="128" target="_blank">
<img alt="实训" height="96" src={"/"+i.image_url} width="128" />
</a>
<div className="ml10 flex1">
<a href={"/paths/"+i.id} target="_blank" data-tip-down={i.name} className="color-grey-6 task-hide mb12 recomment-name">{i.name}</a>
<p className="clearfix mt8 font-12 color-grey-B4">
<Tooltip placement="bottom" title={"章节"}>
<span className="mr10 fl squareIconSpan"><i className="iconfont icon-shixun fl mr3"></i>{i.stages_count}</span>
</Tooltip>
{/*<Tooltip placement="bottom" title={"经验值"}>*/}
{/*<span className="mr10 fl squareIconSpan"><i className="iconfont icon-jingyan fl mr3"></i>{i.score_count}</span>*/}
{/*</Tooltip>*/}
<Tooltip placement="bottom" title={"学习人数"}>
<span className="mr10 fl squareIconSpan"><i className="iconfont icon-chengyuan fl mr3"></i>{i.members_count}</span>
</Tooltip>
</p>
</div>
</div>
)
})
}
</div>
</div>
<div className="padding20 edu-back-white"
style={{
display:
TPMRightSectionData === undefined?"none":TPMRightSectionData.recommands===undefined?"none":TPMRightSectionData.recommands.length === 0 ? "none" : "block"
}}
>
<p className="mb20 font-16 clearfix">推荐实训</p>
<div className="recommend-list">
{
TPMRightSectionData===undefined?"":TPMRightSectionData.recommands===undefined?"":TPMRightSectionData.recommands.map((item,key)=>{
return(
<div className="recomments clearfix df" key={key}>
<a href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">
<img alt="69?1526971094" height="96" src={"/"+item.pic} width="128"/>
</a>
<div className="ml10 flex1">
<Tooltip placement="bottom" title={item.name}>
<a href={"/shixuns/"+item.identifier+"/challenges"} target="_blank" className="color-grey-6 task-hide mb12 recomment-name">{item.name}</a>
</Tooltip>
<p className="clearfix mt8 font-12 color-grey-B4">
{item.stu_num} 人学习
</p>
<p className="edu-txt-right color-orange pr10">{item.level}</p>
</div>
</div>
)
})
}
</div>
</div>
</div>
}
</div>
)
constructor(props) {
super(props)
this.state = {
TPMRightSection:false,
clickNewsubscripttype:false
}
}
// componentDidMount() {
// let id=this.props.match.params.shixunId;
//
// let shixunsDetailsURL=`/shixuns/`+id+`/show_right.json`;
//
// axios.get(shixunsDetailsURL).then((response)=> {
// if(response.status===200){
// this.setState({
// TPMRightSectionData: response.data
// });
// }
// }).catch((error)=>{
// console.log(error)
// });
// }
// shouldComponentUpdate(nextProps, nextState) {
// return nextProps.TPMRightSectionData !== this.state.TPMRightSectionData
// }
clickNewsubscript=(val)=>{
if(val===0){
this.setState({
TPMRightSection:true,
clickNewsubscripttype:true
})
}else{
this.setState({
TPMRightSection:false,
clickNewsubscripttype:false
})
}
}
render() {
let {TPMRightSection,clickNewsubscripttype}=this.state;
let {TPMRightSectionData}=this.props
return (
<div>
{
TPMRightSectionData===undefined?"":
<div>
<div className="edu-back-white padding40-20 mb10">
<p className="font-16 mb20">创建者</p>
<div className="df">
<a href={TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":`/users/${TPMRightSectionData.creator.login}/courses`}>
<img alt="头像" className="radius mr10" height="80" src={getImageUrl(TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":'images/'+TPMRightSectionData.creator.image_url+"?1532489442")} width="80" />
</a>
<div className="flex1">
<p className="mb20">{TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":TPMRightSectionData.creator.name}</p>
<div className="clearfix">
<span>发布 {TPMRightSectionData.user_shixuns_count}</span>
{/*<span className="ml20">粉丝 <span id="user_h_fan_count">{TPMRightSectionData.fans_count}</span></span>*/}
{/* <a href="/watchers/unwatch?className=fr+user_watch_btn+edu-default-btn+edu-focus-btn&amp;object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr edu-default-btn user_watch_btn edu-focus-btn" data-method="post" data-remote="true" id="cancel_watch" rel="nofollow">取消关注</a> */}
</div>
</div>
</div>
</div>
{
TPMRightSectionData === undefined ? "" :TPMRightSectionData.tags===undefined?"": TPMRightSectionData.tags.length === 0 ? "" :
<div className="edu-back-white padding40-20 mb10 relative">
<p className="font-16 mb20">技能标签 <span className="color-grey-c">{TPMRightSectionData.tags.length}</span></p>
<div className={TPMRightSection===false?"newedbox newedboxheight":"newedbox newminheight"}>
<div className="clearfix" id="boxheight">
{ TPMRightSectionData.tags.map((item,key)=>{
return(
<span className={item.status===false?"newedu-filter-btn fl":"edu-filter-btn29BD8B fl"}
style={{display:item.tag_name===" "||item.tag_name===""?"none":""}}
key={key}>{item.tag_name}</span>
)})
}
</div>
</div>
<div className={TPMRightSectionData.tags.length>15&&clickNewsubscripttype===false?"newsubscript mb9 color-grey-9":"newsubscript mb9 color-grey-9 none"}
data-tip-down="显示全部"
onClick={()=>this.clickNewsubscript(0)}><span className="mr8">...</span><Icon type="caret-down" />
</div>
<div className={clickNewsubscripttype===false?"newsubscript mb9 color-grey-9 none":"newsubscript mb9 color-grey-9"}
data-tip-down="显示全部"
onClick={()=>this.clickNewsubscript(1)}><Icon type="caret-up" />
</div>
</div>
}
<div className="padding20 edu-back-white mb10 mt10" style={{
display: TPMRightSectionData === undefined?"none":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "none" : "block"
}}>
<p className="mb20 font-16 clearfix">所属课程</p>
<div className="recommend-list" >
{
TPMRightSectionData===undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.map((i,k)=>{
return(
<div className="recomments clearfix df" key={k}>
<a href={"/paths/"+i.id} height="96" width="128" target="_blank">
<img alt="实训" height="96" src={"/"+i.image_url} width="128" />
</a>
<div className="ml10 flex1">
<a href={"/paths/"+i.id} target="_blank" data-tip-down={i.name} className="color-grey-6 task-hide mb12 recomment-name">{i.name}</a>
<p className="clearfix mt8 font-12 color-grey-B4">
<Tooltip placement="bottom" title={"章节"}>
<span className="mr10 fl squareIconSpan"><i className="iconfont icon-shixun fl mr3"></i>{i.stages_count}</span>
</Tooltip>
{/*<Tooltip placement="bottom" title={"经验值"}>*/}
{/*<span className="mr10 fl squareIconSpan"><i className="iconfont icon-jingyan fl mr3"></i>{i.score_count}</span>*/}
{/*</Tooltip>*/}
<Tooltip placement="bottom" title={"学习人数"}>
<span className="mr10 fl squareIconSpan"><i className="iconfont icon-chengyuan fl mr3"></i>{i.members_count}</span>
</Tooltip>
</p>
</div>
</div>
)
})
}
</div>
</div>
{TPMRightSectionData === undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "" :
<div className="padding20 edu-back-white"
style={{
display:
TPMRightSectionData === undefined?"none":TPMRightSectionData.recommands===undefined?"none":TPMRightSectionData.recommands.length === 0 ? "none" : "block"
}}
>
<p className="mb20 font-16 clearfix">推荐实训</p>
<div className="recommend-list">
{
TPMRightSectionData===undefined?"":TPMRightSectionData.recommands===undefined?"":TPMRightSectionData.recommands.map((item,key)=>{
return(
<div className="recomments clearfix df" key={key}>
<a href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">
<img alt="69?1526971094" height="96" src={"/"+item.pic} width="128"/>
</a>
<div className="ml10 flex1">
<Tooltip placement="bottom" title={item.name}>
<a href={"/shixuns/"+item.identifier+"/challenges"} target="_blank" className="color-grey-6 task-hide mb12 recomment-name">{item.name}</a>
</Tooltip>
<p className="clearfix mt8 font-12 color-grey-B4">
{item.stu_num} 人学习
</p>
<p className="edu-txt-right color-orange pr10">{item.level}</p>
</div>
</div>
)
})
}
</div>
</div> }
</div>
}
</div>
)
}
}
}
export default TPMRightSection;

@ -0,0 +1,153 @@
// import React, { useState, useEffect, memo } from 'react';
// import axios from 'axios'
// import { Modal, Input } from 'antd';
// function RepositoryChooseModal(props) {
// const [trees, setTrees] = useState([])
// const [path, setPath] = useState('')
// const [pathArray, setPathArray] = useState([{val: "根目录/", path: ""}])
// const [modalVisible, setModalVisible] = useState(true)
// useEffect(() => {
// repository('')
// }, [])
// function onOk() {
// }
// function onCancel() {
// }
// /**
// 点nav 会传入key
// 点item 会传入 newPath
// item => name, type type tree/leaf
// */
// const repository=(item, key, newPath)=>{
// let newPathArray = [] //
// //
// if (key) {
// for(var i=0; i<=key; i++){
// newPathArray.push(pathArray[i])
// }
// } else if (item) {
// newPathArray = pathArray.slice(0)
// newPathArray.push({val: item.name, path: pathArray[pathArray.length - 1] + "/" + item.name})
// }
// const path = item || key ? newPathArray[newPathArray.length - 1] : ''
// let id = props.match.params.shixunId;
// let url ="/shixuns/"+id+"/repository.json";
// axios.post(url,{
// path: path
// }).then((response) => {
// if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
// }else{
// setTrees(response.data.trees)
// setPath(path)
// pathArray(newPathArray)
// }
// }).catch((error) => {
// console.log(error)
// });
// }
// const savegetfilepath=(value)=>{
// const state = {}
// let {selectpath,saveshixunfilepath,pathtype} = state
// if(pathtype===1){
// let newselectpath;
// if(saveshixunfilepath==="shixunfilepathplay"){
// newselectpath=value
// }else{
// const type = selectpath.split('');
// let types=false;
// for(var i=0; i<type.length; i++){
// if(type[i]===value){
// types=true
// return
// }
// }
// if(types===false){
// newselectpath=selectpath+value+ ""
// }else{
// newselectpath=selectpath
// }
// }
// // this.setState({
// // // selectpatharr:newarr,
// // selectpath: newselectpath,
// // })
// }
// }
// const goblakepath=(path,key)=>{
// }
// function sendgetfilepath() {
// }
// return (
// <Modal
// keyboard={false}
// title="文件路径"
// visible={modalVisible}
// closable={false}
// footer={false}
// >
// <div className="task_popup_con">
// <div className="newupload_conbox clearfix">
// <ul id="directory_file">
// {/*文件导航*/}
// {
// pathArray.length===0?"":pathArray.map((item,key)=>{
// return(
// <a className="f14 fb" onClick={()=>goblakepath(item.path,key,item)}>{item.val}</a>
// )
// })
// }
// {/*文件*/}
// {trees === undefined || trees === null ? "" : trees.map((item, key) => {
// return(
// <li className="entry" key={key}>
// <div className="filename_no_report hidden">{
// item.type==="tree"?<a onClick={()=>sendgetfilepath(item.name,item.type,path+item.name)} data-remote="true">
// <i className="iconfont icon-wenjianjia color-blue mr2"></i>
// {path+item.name}</a>:<a data-remote="true">
// <i className="iconfont icon-zuoye color-blue mr2"></i>
// <span onClick={()=>savegetfilepath(path+item.name,item.type)}>{path+item.name}</span>
// </a>
// }
// </div>
// </li>
// )
// })}
// </ul>
// <div className="clearfix mt20">
// <label className="fl mt5 directory_filepath">选中的文件路径:</label>
// <Input id="points_tusi" placeholder="选中的文件路径" className="fl input-60-40"
// style={{width:"400px"}}
// onInput={(e)=>saveselectpath(e)}
// value={path}/>
// </div>
// <a className="task-btn task-btn-orange fr"
// style={{marginTop: '20px',marginLeft:'20px'}} id="add_path" onClick={()=>onOk()}>确定</a>
// <a className="pop_close task-btn mb10 fr"
// style={{marginTop: '20px'}} id="back_page" onClick={()=>onCancel()}>取消</a>
// </div>
// </div>
// </Modal>
// )
// }
// export default RepositoryChooseModal

@ -233,7 +233,8 @@ class Newshixuns extends Component {
systemenvironmenttype:false,
testcoderunmodetype:false,
attachmentidstype:false,
datalisttype:false
datalisttype:false,
bottonloading:false
}
}
@ -494,6 +495,9 @@ class Newshixuns extends Component {
} else {
newmulti_webssh = ""
}
this.setState({
bottonloading:true
})
axios.post(Url, {
name: name,
can_copy: can_copy,
@ -513,9 +517,16 @@ class Newshixuns extends Component {
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
})
})
}
@ -1321,7 +1332,9 @@ class Newshixuns extends Component {
<div className="clearfix mt30">
<a className="defalutSubmitbtn fl mr20" onClick={this.submit_new_shixun}>提交</a>
<Button className="defalutSubmitbtn fl mr20" loading={this.state.bottonloading} onClick={this.submit_new_shixun}>
提交
</Button>
<a href="/shixuns" className="defalutCancelbtn fl">取消</a>
</div>

@ -384,4 +384,14 @@ a.white-btn.use_scope-btn:hover{
.ml82{
margin-left: 82px;
}
.ant-btn-primary.active, .ant-btn-primary:active {
color: #fff;
background-color: #096dd9;
border-color: #096dd9;
}
.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{
background-color: #4CACFF;
}

@ -15,7 +15,7 @@ import { trace, trace_collapse ,getImageUrl, toPath} from "educoder";
import RepositoryDirectories from './RepositoryDirectories'
import { ActionBtn , NoneData } from 'educoder'
import RepositoryCombinePath from './RepositoryCombinePath'
const $ = window.$;
// 点击按钮复制功能
@ -85,10 +85,13 @@ class Repository extends Component {
className=" guideBtn" >Git使用指南</a>
{
this.props.current_user && (this.props.current_user.admin ==true || (TPMRightSectionData && TPMRightSectionData.creator && TPMRightSectionData.creator.login == this.props.current_user.login)) ?
<ActionBtn style="orangeLine" className="ml20" to={`/shixuns/${match.params.shixunId}/repository/add_file`}>+添加文件</ActionBtn>:""
!this.props.secret_repository_tab &&
<ActionBtn style="orangeLine" className="ml20" to={`/shixuns/${match.params.shixunId}/repository/add_file`}>+添加文件</ActionBtn>
:""
}
<div className="fr font-12 color-grey-9 pr">
<label className="fl mt2">网址克隆</label>
<input type="text" id="copy_rep_content" className="fl url-input mt2"
@ -155,6 +158,10 @@ class Repository extends Component {
</div>
</div>
{this.props.secret_repository_tab && <RepositoryCombinePath {...this.props}>
</RepositoryCombinePath>}
</div>
</div>
@ -181,7 +188,7 @@ class Repository extends Component {
{commits===undefined?"":commits[0].time}
</acronym> {commits===undefined?"":commits[0].title}
</span>
<a href={`/shixuns/${match.params.shixunId}/repository/${match.params.shixunId}/commits`}
<a href={`/shixuns/${match.params.shixunId}/${this.props.secret_repository_tab ? 'secret_repository' : 'repository'}/${match.params.shixunId}/commits`}
className="color-grey-6 fr font-16 ">
<i className="iconfont icon-tijiaojilu font-18 fl mr5"></i>
<span className="fl mt2">提交记录</span>

@ -121,6 +121,7 @@ class RepositoryCodeEditor extends Component {
const path = pathArray.join('/')
this.setState({ codeSaving: true })
axios.post(url, {
secret_repository: this.props.secret_repository_tab,
content: this.extend_editor.getValue(),
// type: forTest === true ? 1 : 0,
path: path

@ -0,0 +1,82 @@
import React, { Component } from 'react';
import { Redirect } from 'react-router';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import PropTypes from 'prop-types';
import classNames from 'classnames';
import axios from 'axios';
import { trace_collapse, WordsBtn } from 'educoder'
import { message, Input } from 'antd';
const $ = window.$;
class RepositoryCombinePath extends Component {
constructor(props) {
super(props)
this.state = {
value: this.props.secret_dir_path || '',
isEdit: false,
}
}
onSave = () => {
const { shixunId, pathArray } = this.props;
const url = `/shixuns/${shixunId}/set_secret_dir.json`
this.setState({ codeSaving: true })
axios.post(url, {
secret_dir_path: this.state.value
}
).then((response) => {
if (response.data) {
message.success('保存成功');
this.setState({isEdit: false})
}
})
}
onChange = (e) => {
const { value } = e.target;
this.setState({ value })
}
onEdit = () => {
this.setState({isEdit: true}, () => {
window.$('.combinePathEditRow input')[0].focus()
});
}
render() {
const { fileContent, match, saveCode } = this.props;
const { isEdit, value } = this.state;
return (
<div className="df combinePathEditRow">
<style>{`
.combinePathEditRow {
margin: 4px 0;
}
.combinePathEditRow input {
flex: 0 0 300px;
border: none;
}
.combinePathEditRow .wordsBtn {
margin-left: 24px;
}
`}</style>
<span>第一版本库合并路径</span>
<Input disabled={!isEdit} value={value} onChange={this.onChange}></Input>
{!isEdit && <WordsBtn className="wordsBtn" onClick={this.onEdit} style="blue">修改</WordsBtn>}
{isEdit && <WordsBtn className="wordsBtn" onClick={this.onSave} style="blue">保存</WordsBtn>}
</div>
);
}
}
export default RepositoryCombinePath;

@ -34,7 +34,9 @@ class TPMRepositoryCommits extends Component {
let id = this.props.match.params.shixunId;
let collaborators=`/shixuns/`+id+`/commits.json`;
axios.post(collaborators).then((response)=> {
axios.post(collaborators, {
secret_repository: this.props.secret_repository_tab
}).then((response)=> {
if(response.status===200){
this.setState({

@ -6,9 +6,6 @@
margin-left: 32%;
}
.square-Item{
/*min-height: 324px;*/
}
.square-img{
min-height: 210px;
}

@ -31,8 +31,8 @@ class InfosBanner extends Component{
let user_type=this.props.current_user&&this.props.current_user.user_identity;
let targetuserid=this.props.data&&this.props.data.id;
// console.log(is_current)
// console.log(current_user)
// console.log(is_current)
// console.log(current_user)
// console.log(current_user.is_teacher)
// console.log(current_user.admin)
return(
@ -124,7 +124,7 @@ class InfosBanner extends Component{
</li>}
{/*自己的主页且不是学生显示题库按钮*/}
{((is_current && current_user && current_user.is_teacher ) || current_user && current_user.admin)
{(is_current && current_user)
&&<li className={`${moduleName == 'topics' ? 'active' : '' }`}>
<Link
onClick={() => this.setState({moduleName: 'topics'})}

@ -103,7 +103,7 @@ class InfosCourse extends Component{
} = this.state;
let is_current=this.props.is_current;
console.log(this.props.current_user&&this.props.current_user.user_identity==="学生")
// console.log(this.props.current_user&&this.props.current_user.user_identity==="学生")
return(
<div className="educontent">
<Spin size="large" spinning={isSpin}>

@ -31,33 +31,34 @@ class InfosTopics extends Component{
}
componentDidMount(){
let types=this.props.match.params.topicstype;
let professional_certification=this.props.current_user&&this.props.current_user.professional_certification;
if(professional_certification===false&&types==="publicly"){
this.setState({
isshowprofes:true
})
}else{
this.updataslist()
}
}
componentDidUpdate(prevProps) {
if(prevProps.current_user!=this.props.current_user){
let types=this.props.match.params.topicstype;
let professional_certification=this.props.current_user&&this.props.current_user.professional_certification;
console.log(professional_certification)
if(professional_certification===false&&types==="publicly"){
this.setState({
isshowprofes:true
})
}else{
this.updataslist()
}
}
// let types=this.props.match.params.topicstype;
// let professional_certification=this.props.current_user&&this.props.current_user.professional_certification;
//
// if(professional_certification===false&&types==="publicly"){
// this.setState({
// isshowprofes:true
// })
// }else{
// this.updataslist()
// }
this.updataslist()
}
// componentDidUpdate(prevProps) {
//
// if(prevProps.current_user!=this.props.current_user){
// let types=this.props.match.params.topicstype;
// let professional_certification=this.props.current_user&&this.props.current_user.professional_certification;
//
// console.log(professional_certification)
// if(professional_certification===false&&types==="publicly"){
// this.setState({
// isshowprofes:true
// })
// }else{
// this.updataslist()
// }
// }
// }
updataslist=()=>{
let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state;
@ -65,55 +66,49 @@ class InfosTopics extends Component{
}
searchAlldata=(type,category,course_list_id,sort_by,sort_direction,page)=>{
// if(this.props.current_user.login!=this.props.match.params.username){
// return
// }else{
//
// }
this.setState({
isSpin:true
})
let types=this.props.match.params.topicstype;
let user_id="";
if(types==="publicly"){
user_id=this.props.current_user&&this.props.current_user.login;
}else{
user_id=this.props.match.params&&this.props.match.params.username;
}
if(user_id===undefined){
user_id=this.props.match.params&&this.props.match.params.username;
}
if(user_id!=undefined){
let {per_page}=this.state;
let url=`/users/${user_id}/question_banks.json`;
axios.get(encodeURI(url),{params:{
type,
object_type:category,
course_list_id,
sort_by,
sort_direction,
page,
per_page
let {per_page}=this.state;
let url=`/users/question_banks.json`;
axios.get(encodeURI(url),{params:{
type,
object_type:category,
course_list_id,
sort_by,
sort_direction,
page,
per_page
}
}).then((response) => {
if(response){
if(response.status){
if(response.data.status == -2){
this.setState({
isshowprofes:true,
isSpin:false
})
}else if(response.data.status === 403||response.data.status === 401||response.data.status === 500){
this.setState({
isSpin:false
})
}else{
this.setState({
data:response.data,
checkBoxValues:[],
isSpin:false
})
}
}).then((response) => {
this.setState({
data:response.data,
checkBoxValues:[],
isSpin:false
})
}).catch((error) => {
this.setState({
isSpin:false
})
});
}
}
}).catch((error) => {
this.setState({
isSpin:false
})
});
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save