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

dev_cs
杨树明 6 years ago
commit 031b9df0ba

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

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

@ -191,21 +191,28 @@ class ChallengesController < ApplicationController
sets_input = test_set.map(&:input) sets_input = test_set.map(&:input)
sets_open = test_set.map(&:is_public) sets_open = test_set.map(&:is_public)
set_score = test_set.map(&:score) 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_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0}
params_output = params[:test_set].map{|set| set[:output] } params_output = params[:test_set].map{|set| set[:output] }
params_input = params[:test_set].map{|set| set[:input] } params_input = params[:test_set].map{|set| set[:input] }
params_score = params[:test_set].map{|set| set[:score]} 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? test_set.delete_all unless test_set.blank?
params[:test_set].each_with_index do |set, index| params[:test_set].each_with_index do |set, index|
TestSet.create(:challenge_id => @challenge.id, # last 末尾匹配, full: 全完匹配
:input => "#{set[:input]}", logger.info("set: #{set}; match_rule : #{set[:match_rule]}")
:output => "#{set[:output]}", match_rule = set[:match_rule] == 'last' ? 'last' : 'full'
:is_public => params_hidden[index], TestSet.create(:challenge_id => @challenge.id,
:score => set[:score], :input => "#{set[:input]}",
:position => (index + 1)) :output => "#{set[:output]}",
end :is_public => params_hidden[index],
:score => set[:score],
:match_rule => "#{match_rule}",
:position => (index + 1))
end
@challenge.update_column(:modify_time, Time.now) @challenge.update_column(:modify_time, Time.now)
# 测试集的 # 测试集的
@shixun.myshixuns.update_all(:system_tip => 0) @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, before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate,
:transfer_to_course_group, :delete_from_course, :export_member_scores_excel, :transfer_to_course_group, :delete_from_course, :export_member_scores_excel,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :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, 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, :set_course_group, :create_group_by_importing_file,
:update_task_position, :tasks_list, :delete_informs] :update_task_position, :tasks_list]
before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group, before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group,
:change_course_teacher, :course_group_list, :change_course_teacher, :course_group_list,
:teacher_application_review, :apply_teachers, :delete_course_teacher] :teacher_application_review, :apply_teachers, :delete_course_teacher]

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

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

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

@ -220,6 +220,16 @@ class ShixunsController < ApplicationController
evaluate_script: @shixun.evaluate_script) evaluate_script: @shixun.evaluate_script)
end 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? if @shixun.mirror_repositories.present?
@shixun.mirror_repositories.each do |mirror| @shixun.mirror_repositories.each do |mirror|
@ -448,6 +458,7 @@ class ShixunsController < ApplicationController
ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror) ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror)
end end
end end
logger.info("#########shixun_params#{shixun_params}")
@shixun.update_attributes(shixun_params) @shixun.update_attributes(shixun_params)
logger.info("##########shixun_info_params: #{shixun_info_params}") logger.info("##########shixun_info_params: #{shixun_info_params}")
logger.info("##########params[:shixun_info][:evaluate_script]: #{params[:shixun_info][:evaluate_script]}") 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? @shixun.shixun_service_configs.create!(config) if name.present?
end end
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 rescue Exception => e
uid_logger_error(e.message) uid_logger_error("实训保存失败--------#{e.message}")
tip_exception("实训保存失败") tip_exception("实训保存失败")
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
end end
@ -818,6 +841,30 @@ class ShixunsController < ApplicationController
end end
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 include GitCommon
def update_file def update_file
@ -954,7 +1001,13 @@ private
end end
def find_repo_name 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] @path = params[:path]
end end
@ -989,4 +1042,13 @@ private
modify_shixun = ShixunModify.exists?(:myshixun_id => current_myshixun.id, :shixun_id => @shixun.id, :status => 1) modify_shixun = ShixunModify.exists?(:myshixun_id => current_myshixun.id, :shixun_id => @shixun.id, :status => 1)
games.size != min_challenges.size || modify_shixun games.size != min_challenges.size || modify_shixun
end 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 end

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

@ -12,7 +12,7 @@ class TaskBanksController < ApplicationController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
@bank.update_attributes(gtask_bank_params) @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, "更新成功") normal_status(0, "更新成功")
rescue Exception => e rescue Exception => e
uid_logger(e.message) uid_logger(e.message)

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

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

@ -24,7 +24,7 @@ module Searchable::Course
author_name: teacher&.real_name, author_name: teacher&.real_name,
author_school_name: teacher&.school_name, author_school_name: teacher&.school_name,
visits_count: visits, visits_count: visits,
members_count: members_count, members_count: course_members_count,
is_public: is_public == 1, is_public: is_public == 1,
first_category_url: ApplicationController.helpers.module_url(none_hidden_course_modules.first, self) 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_info, dependent: :destroy
# 第二版本库
has_one :shixun_secret_repository, dependent: :destroy
belongs_to :user belongs_to :user
# 实训服务配置 # 实训服务配置
has_many :shixun_service_configs, :dependent => :destroy 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 belongs_to :myshixun, optional: true
has_many :student_works_evaluation_distributions, dependent: :destroy has_many :student_works_evaluation_distributions, dependent: :destroy
has_many :student_works_scores, dependent: :destroy has_many :student_works_scores, dependent: :destroy
has_many :shixun_work_comments, dependent: :destroy
belongs_to :project, optional: true belongs_to :project, optional: true
# attachtype: 1正常提交的附件 7补交的附件 # attachtype: 1正常提交的附件 7补交的附件

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

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

@ -6,6 +6,12 @@ json.results do
json.title highlights.delete(:name)&.join('...') || obj.searchable_title 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/>') # 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 json.content highlights
end end
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.scope_partment @shixun.schools.map(&:name) # 公开范围
json.opening_time @shixun.opening_time json.opening_time @shixun.opening_time
json.forbid_copy @shixun.forbid_copy json.forbid_copy @shixun.forbid_copy
# 私密仓库
json.is_secret_repository @shixun.shixun_secret_repository.present?
# 实训服务配置 # 实训服务配置
json.shixun_service_configs do json.shixun_service_configs do

@ -2,3 +2,4 @@ json.fork_from @fork_from
json.identity User.current.shixun_identity(@shixun) json.identity User.current.shixun_identity(@shixun)
json.power @power json.power @power
json.partial! 'shixuns/top', locals: { shixun: @shixun, current_myshixun: @current_myshixun } 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 challenge_score = @homework.challenge_score game.challenge_id
json.game_score_full challenge_score json.game_score_full challenge_score
json.game_score @work.work_challenge_score game, 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
end end
@ -54,8 +58,9 @@ if @shixun
json.passed_time @work.myshixun&.passed_time json.passed_time @work.myshixun&.passed_time
# 评阅信息 # 评阅信息
json.work_comment @user_course_identity < Course::STUDENT || !@comment&.is_hidden ? @comment&.comment : nil json.work_comment @comment&.comment
json.work_comment_hidden @comment&.is_hidden json.work_comment_hidden @user_course_identity < Course::STUDENT ? @comment&.hidden_comment : nil
json.comment_id @comment&.id
# 图形统计 # 图形统计
# 1 效率 # 1 效率

@ -31,5 +31,3 @@ end
ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1) ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1)
ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension) ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension)

@ -55,12 +55,14 @@ Rails.application.routes.draw do
get :homepage_info get :homepage_info
end end
get :question_banks, on: :collection, to: 'users/question_banks#index'
scope module: :users do scope module: :users do
resources :courses, only: [:index] resources :courses, only: [:index]
resources :shixuns, only: [:index] resources :shixuns, only: [:index]
resources :projects, only: [:index] resources :projects, only: [:index]
resources :subjects, only: [:index] resources :subjects, only: [:index]
resources :question_banks, only: [:index] # resources :question_banks, only: [:index]
resource :experience_records, only: [:show] resource :experience_records, only: [:show]
resource :grade_records, only: [:show] resource :grade_records, only: [:show]
resource :watch, only: [:create, :destroy] resource :watch, only: [:create, :destroy]
@ -195,6 +197,8 @@ Rails.application.routes.draw do
get :get_script_contents get :get_script_contents
get :get_custom_script get :get_custom_script
post :repository post :repository
post :secret_repository
post :set_secret_dir
post :commits post :commits
post :file_content post :file_content
post :update_file 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() { $(function() {
loadHeader(); // loadHeader();
_initSider(); _initSider();
$(window).scroll(function() { $(window).scroll(function() {
@ -436,86 +436,86 @@ function editormd_to_html(id, callback) {
} }
function loadHeader() { function loadHeader() {
//头部导航条的----------显示搜索框 // //头部导航条的----------显示搜索框
$("#search-open").on("click", function(e) { // $("#search-open").on("click", function(e) {
$(this).hide(); // $(this).hide();
// $("#header-nav").animate({opacity:"0"},1000); // // $("#header-nav").animate({opacity:"0"},1000);
$(".posi-search").show() // $(".posi-search").show()
// .animate({opacity:"1"},1000); // // .animate({opacity:"1"},1000);
$("#header-nav").css("z-index", "2"); // $("#header-nav").css("z-index", "2");
$(".posi-search").css("z-index", "3"); // $(".posi-search").css("z-index", "3");
// $(".search-input").val(""); // 不清空 // // $(".search-input").val(""); // 不清空
$(".search-input").focus(); // $(".search-input").focus();
$(".search-all .search-content").hide(); // $(".search-all .search-content").hide();
e.stopPropagation(); // e.stopPropagation();
//阻止冒泡 // //阻止冒泡
}); // });
$(".search-input").on("click", function(e) { // $(".search-input").on("click", function(e) {
e.stopPropagation(); // e.stopPropagation();
//阻止冒泡 // //阻止冒泡
}); // });
//搜索框输入内容 // //搜索框输入内容
$(".search-input").on("input", function(e) { // $(".search-input").on("input", function(e) {
if ($(".search-input").val() == "") { // if ($(".search-input").val() == "") {
$(".search-all .search-content").hide(); // $(".search-all .search-content").hide();
} else { // } else {
$(".search-all .search-content").show(); // $(".search-all .search-content").show();
} // }
e.stopPropagation(); // e.stopPropagation();
//阻止冒泡 // //阻止冒泡
}); // });
//搜索 // //搜索
$("#header_keyword_search").on("click", header_search); // $("#header_keyword_search").on("click", header_search);
$("input[name='search_keyword']").on("keydown", function(event) { // $("input[name='search_keyword']").on("keydown", function(event) {
var code; // var code;
if (!event) { // if (!event) {
event = window.event; // event = window.event;
//针对ie浏览器 // //针对ie浏览器
code = event.keyCode; // code = event.keyCode;
} else { // } else {
code = event.keyCode; // code = event.keyCode;
} // }
if (code == 13) { // if (code == 13) {
header_search(); // header_search();
return false; // return false;
} // }
}); // });
$(".search-clear").click(function(e) { // $(".search-clear").click(function(e) {
e.stopPropagation(); // e.stopPropagation();
}); // });
//切换搜索条件 // //切换搜索条件
$("#searchkey li").click(function(e) { // $("#searchkey li").click(function(e) {
var key = $($(this).children("a")[0]).html(); // var key = $($(this).children("a")[0]).html();
switch (key) { // switch (key) {
case '实训': // case '实训':
$("#search_type").val('1'); // $("#search_type").val('1');
break; // break;
case '课堂': // case '课堂':
$("#search_type").val('2'); // $("#search_type").val('2');
break; // break;
case '用户': // case '用户':
$("#search_type").val('3'); // $("#search_type").val('3');
break; // break;
} // }
$("#searchkey").siblings(".searchkey").html(key); // $("#searchkey").siblings(".searchkey").html(key);
// $("#searchkey").hide(); // // $("#searchkey").hide();
e.stopPropagation(); // e.stopPropagation();
//阻止冒泡 // //阻止冒泡
}); // });
//切换选择导航条 // //切换选择导航条
$("#header-nav li").click(function() { // $("#header-nav li").click(function() {
$("#header-nav li").removeClass("active"); // $("#header-nav li").removeClass("active");
$(this).addClass("active"); // $(this).addClass("active");
}); // });
//点击页面其它(与搜索框无关的地方)都会将搜索框隐藏,所以与搜索框有关的地方需要阻止冒泡 // //点击页面其它(与搜索框无关的地方)都会将搜索框隐藏,所以与搜索框有关的地方需要阻止冒泡
$("body").on("click", function() { // $("body").on("click", function() {
closeSearch(); // closeSearch();
}); // });
//
$(".search_history").on("click", function() { // $(".search_history").on("click", function() {
$("input[name='search_keyword']").val($(this).html()); // $("input[name='search_keyword']").val($(this).html());
header_search(); // header_search();
}); // });
} }
function header_search() { function header_search() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

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

@ -37,7 +37,7 @@ import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
import history from './history'; import history from './history';
import {SnackbarHOC} from 'educoder' import {SnackbarHOC, configShareForIndex} from 'educoder'
import {initAxiosInterceptors} from './AppConfig' import {initAxiosInterceptors} from './AppConfig'
@ -326,22 +326,7 @@ class App extends Component {
}); });
wx.ready(function () { wx.ready(function () {
console.log('wx is ready') console.log('wx is ready')
var shareData = { configShareForIndex()
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空间
}); });
wx.error(function (res) { wx.error(function (res) {
console.log('wx is error') console.log('wx is error')

@ -20,6 +20,8 @@ export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, ap
downloadFile, sortDirections } from './TextUtil' downloadFile, sortDirections } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil' export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
export { isDev as isDev, isMobile } from './Env' export { isDev as isDev, isMobile } from './Env'
export { toStore as toStore, fromStore as fromStore } from './Store' 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 && { work_statuses && work_statuses.indexOf('补交作品') != -1 &&
<a className={"fr color-blue font-16"} href={"javascript:void(0)"} <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> } 补交作品</a> }
{work_statuses && work_statuses.indexOf('修改作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"} {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 ; const courseId = this.state.course_id || this.props.match.params.coursesId ;
this.props.form.validateFieldsAndScroll((err, values) => { this.props.form.validateFieldsAndScroll((err, values) => {
if(err && err.personNum) delete err.personNum;
console.log(values) console.log(values)
const mdContnet = this.contentMdRef.current.getValue().trim(); const mdContnet = this.contentMdRef.current.getValue().trim();
console.log(mdContnet) console.log(mdContnet)
@ -135,7 +136,7 @@ class NewWorkForm extends Component{
} }
// const errKeys = Object.keys(err); // || errKeys.length == 1 && errKeys[0] == 'content' && mdContnet // 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) { if (this.state.isEdit) {
this.doEdit(courseId, values) this.doEdit(courseId, values)
} else { } else {
@ -450,12 +451,13 @@ class NewWorkForm extends Component{
className="AboutInputForm groupSetting" className="AboutInputForm groupSetting"
> >
{getFieldDecorator('personNum', { {getFieldDecorator('personNum', {
rules: [{ validateTrigger: 'onNone',
// rules: [{
// required: true, // required: true,
// message: '人数不能为空' // message: '人数不能为空'
// validator: this.personNumValidator // validator: this.personNumValidator
// required: true, message: '请输入最小人数和最大人数' // required: true, message: '请输入最小人数和最大人数'
}], // }],
})( })(
<div> <div>
<p className="clearfix"> <p className="clearfix">

@ -53,7 +53,7 @@ class ModalWrapper extends Component{
{this.props.checkBoxValuestype===true?<div className={"mt10 color-red"}> {this.props.checkBoxValuestype===true?<div className={"mt10 color-red"}>
请先选择课堂 请先选择课堂
</div>:""} </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.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> <a onClick={this.onOk} className="task-btn task-btn-orange" id="submit_send_shixun">{ okText || "确定" }</a>
</div> </div>

@ -9,52 +9,71 @@ class AppraiseModal extends Component{
this.state={ this.state={
group_ids:[], group_ids:[],
fileList:[], fileList:[],
textareaval:undefined,
Inputsval:undefined, Inputsval:undefined,
valuetype:0, textareavaltype:false,
textareavaltype:false comment:undefined,
hidden_comment:undefined
} }
} }
componentDidMount() { componentDidMount() {
let{data,work_comment,work_comment_hidden}=this.props;
this.setState({ if(this.props.showAppraisetype==="child"){
valuetype:this.props.work_type===undefined?0:this.props.work_type, data.stage_list.map((item,key)=>{
textareaval:this.props.work_comment, 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)=>{ comment=(e)=>{
this.setState({ this.setState({
valuetype:e.target.value comment:e.target.value
}) })
} }
settextarea=(e)=>{ hidden_comment=(e)=>{
this.setState({ this.setState({
textareaval:e.target.value hidden_comment:e.target.value
}) })
} }
Saves=()=>{ 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({ this.setState({
textareavaltype:true textareavaltype:true
}) })
return 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` let url=`/student_works/${this.props.match.params.homeworkid}/shixun_work_comment.json`
axios.post(url, { axios.post(url, {
comment:textareaval, comment:comment,
is_hidden:valuetype hidden_comment:hidden_comment,
challenge_id:challenge_id
}).then((response) => { }).then((response) => {
if(response.data.status===0){ 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.showNotification(response.data.message)
this.props.showCancel(textareaval,valuetype)
}else{ }else{
this.props.showNotification(response.data.message) this.props.showNotification(response.data.message)
} }
@ -64,15 +83,41 @@ class AppraiseModal extends Component{
} }
render(){ render(){
let {textareaval,Inputsval,textareavaltype,Inputsvaltype}=this.state; let {textareavaltype,comment,hidden_comment}=this.state;
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
return( return(
<div> <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 <Modal
keyboard={false} keyboard={false}
className={"HomeworkModal"} className={"HomeworkModal"}
@ -91,12 +136,9 @@ class AppraiseModal extends Component{
padding: 0px 15px 15px 15px; padding: 0px 15px 15px 15px;
} }
.font{ .font{
width: 48px; font-size: 14px;
height: 16px; font-weight: 400;
font-size: 16px; color: rgba(5,16,26,1);
font-weight: 400;
color: rgba(5,16,26,1);
line-height: 16px;
} }
.newfont{ .newfont{
height: 16px; height: 16px;
@ -110,25 +152,31 @@ class AppraiseModal extends Component{
} }
</style> </style>
<div className="clearfix"> <div className="clearfix">
<p className={"font mt10 mb10"}> <p className={"font mt10 mb10 ml10"}>
权限 可见:(学生可查看老师的评阅内容
</p> </p>
<Radio.Group onChange={this.onChanges} value={this.state.valuetype}> {/*<Radio.Group onChange={this.onChanges} value={this.state.valuetype}>*/}
<Radio value={0} style={radioStyle} className={"newfont"}>可见 (学生查看老师的评阅内容</Radio> {/*<Radio value={0} style={radioStyle} className={"newfont"}>可见 (学生查看老师的评阅内容)</Radio>*/}
<Radio value={1} style={radioStyle} className={"newfont"}>不可见 (仅对课堂老师可见</Radio> {/*<Radio value={1} style={radioStyle} className={"newfont"}>不可见 (仅对课堂老师可见)</Radio>*/}
</Radio.Group> {/*</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> </p>
<WordNumberTextarea <WordNumberTextarea
placeholder={"请填写评阅内容"} placeholder={"请填写评阅内容"}
onInput={(e)=>this.settextarea(e)} onInput={(e)=>this.hidden_comment(e)}
value={textareaval} value={hidden_comment}
maxlength={500} 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>
<div className={textareavaltype===false?"mt20 clearfix edu-txt-center":"clearfix edu-txt-center"}> <div className={textareavaltype===false?"mt20 clearfix edu-txt-center":"clearfix edu-txt-center"}>

@ -157,6 +157,42 @@ class Ecerciseallbackagain extends Component{
console.log() console.log()
return( return(
<div> <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 <Modal
className={"HomeworkModal"} className={"HomeworkModal"}
title={this.props.modalname} title={this.props.modalname}
@ -169,11 +205,12 @@ class Ecerciseallbackagain extends Component{
<div className="task-popup-content"> <div className="task-popup-content">
<style>{` <style>{`
.greybackHead{ .greybackHead{
padding:0px 30px; padding:0px 30px;
} }
.fontlefts{text-align: left;} .fontlefts{text-align: left;}
`}</style> `}</style>
<div className="clearfix edu-txt-center mb10" style={{color:"#333333",fontSize: '15px'}}>学生将得到一次重新答题的机会现有的答题情况将被清空</div> <div className="clearfix edu-txt-center mb10" style={{color:"#333333",fontSize: '15px'}}>学生将得到一次重新答题的机会现有的答题情况将被清空</div>
<ul className="clearfix edu-txt-center ml35"> <ul className="clearfix edu-txt-center ml35">
<li className="fl paddingleft22 fontlefts" style={{width:'160px'}}>姓名</li> <li className="fl paddingleft22 fontlefts" style={{width:'160px'}}>姓名</li>
@ -182,7 +219,7 @@ class Ecerciseallbackagain extends Component{
</ul> </ul>
{datalist===undefined?"": {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" id="search_not_members_list"
onScroll={this.contentViewScroll} onScroll={this.contentViewScroll}
> >
@ -190,7 +227,7 @@ class Ecerciseallbackagain extends Component{
{ datalist.map((item,key)=>{ { datalist.map((item,key)=>{
return( 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'}}> <li className="fl" style={{width: '158px'}}>
<Checkbox <Checkbox
className="fl task-hide edu-txt-left" className="fl task-hide edu-txt-left"
@ -198,8 +235,12 @@ class Ecerciseallbackagain extends Component{
value={item.user_id} value={item.user_id}
key={item.user_id} key={item.user_id}
> >
<label style={{"textAlign": "left", "color": "#05101A"}} <a style={{"textAlign": "left"}}
className="task-hide color-grey-name" title="frerere">{item.user_name}</label> className="task-hide color-grey-name"
href={`/users/${item.user_id}/courses`}
target={'_blank'}
title={item.user_name}
>{item.user_name}</a>
</Checkbox> </Checkbox>
</li> </li>
<li className="fl" style={{width: '150px'}}> <li className="fl" style={{width: '150px'}}>
@ -220,7 +261,7 @@ class Ecerciseallbackagain extends Component{
<Checkbox checked={onChangetype} onChange={this.onChange}>{onChangetype===true?"清除":"全选"}</Checkbox> <Checkbox checked={onChangetype} onChange={this.onChange}>{onChangetype===true?"清除":"全选"}</Checkbox>
</div> </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 color-white mr30" onClick={this.issCancel}>取消</a>
<a className="task-btn task-btn-orange" onClick={this.isSave}>确认</a> <a className="task-btn task-btn-orange" onClick={this.isSave}>确认</a>
</div> </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 response.data.exercise.exercise_status = response.data.exercise.exercise_status == undefined ? 1 : response.data.exercise.exercise_status
this.setState({...response.data}) this.setState({...response.data})
this.props.detailFetchCallback && this.props.detailFetchCallback(response); this.props.detailFetchCallback && this.props.detailFetchCallback(response);
} else {
this.props.detailFetchCallback && this.props.detailFetchCallback(response);
} }
}) })
.catch(function (error) { .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 TPMMDEditor from "../../tpm/challengesnew/TPMMDEditor";
import moment from "../new/CoursesNew"; import moment from "../new/CoursesNew";
import Fileslistitem from "../Resource/Fileslistitem"; import Fileslistitem from "../Resource/Fileslistitem";
import Modals from "../../modals/Modals";
// 公告栏 // 公告栏
class Bullsubdirectory extends Component{ class Bullsubdirectory extends Component{
constructor(props){ constructor(props){
@ -19,6 +20,10 @@ class Bullsubdirectory extends Component{
addonAfter:0, addonAfter:0,
eduintits:"", eduintits:"",
informs:[], 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)=>{ bianji = (bians)=>{
this.setState({ this.setState({
@ -113,7 +173,7 @@ class Bullsubdirectory extends Component{
} }
var url = `/courses/${id}/update_informs.json`; var url = `/courses/${id}/update_informs.json`;
axios.post(url,{ axios.post(url,{
inform_id:this.state.id, inform_id:this.props.id,
name:titname, name:titname,
description:values.description, description:values.description,
}).then((result) => { }).then((result) => {
@ -154,12 +214,20 @@ class Bullsubdirectory extends Component{
render(){ render(){
let{description,whethertoeditysl,addonAfter,eduintits,informs,isSpinysl} =this.state; 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; const {getFieldDecorator} = this.props.form;
// console.log("Bullsubdirectory");
// console.log(this.props.isAdmin());
// console.log(this.props.yslbool);
return( return(
<React.Fragment > <React.Fragment >
<div > <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} > <Spin size="large" spinning={isSpinysl} >
<div className="edu-back-white "> <div className="edu-back-white ">
{ {
@ -171,11 +239,30 @@ class Bullsubdirectory extends Component{
<span className="ysltitbt">{myname}</span> <span className="ysltitbt">{myname}</span>
</div> </div>
<div> <div>
<span className="fr pr25 yslbianji"> <span className="fr yslbianji" style={{marginRight:"17px"}}>
{ {
this.props.isAdmin() === true ? this.props.isAdmin() === true ?
(this.props.yslbool===false? (this.props.yslbool===false?
<Tooltip placement="bottom" title={<div>
编辑
</div>}>
<i className="iconfont icon-bianji1 newbianji1" onClick={()=>this.bianji(true)}></i> <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> <span className="ysltextcolor05">{datas&&datas.min_num}~ {datas&&datas.max_num} 学生提交作品时需要关联同组成员组内成员作品共享</span>
</p> </p>
} }
<p>
<span className="ysltextcolor66">基于项目实施</span> {
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span> datas===undefined?"":datas.base_on_project===undefined?"":
</p> 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>
:<div className="ml47text"> :<div className="ml47text">
{ {
@ -82,11 +94,16 @@ class GroupPackage extends Component {
</p> </p>
} }
{ {
datas&&datas.group_info&&datas.group_info.base_on_project? datas&&datas.group_info&&datas.group_info.base_on_project===1?
<p> <p>
<span className="ysltextcolor66">基于项目实施</span> <span className="ysltextcolor66">基于项目实施</span>
<span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span> <span className="ysltextcolor05">学生必须在本平台创建项目项目管理员可以提交作品</span>
</p> </p>
:datas&&datas.group_info&&datas.group_info.base_on_project===0?
<p>
<span className="ysltextcolor66">不基于项目</span>
<span className="ysltextcolor05">无需在平台创建项目任意小组成员均可以提交作品</span>
</p>
:"" :""
} }
</div> </div>

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

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

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

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

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

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

@ -273,7 +273,7 @@ class ShixunWorkModal extends Component{
</div> </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} onScroll={this.contentViewScroll}
> >
@ -286,7 +286,7 @@ class ShixunWorkModal extends Component{
group_list&&group_list.length===0?"":group_list.map((item,key)=>{ group_list&&group_list.length===0?"":group_list.map((item,key)=>{
return( return(
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> <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 <Checkbox
className="fl task-hide edu-txt-left" className="fl task-hide edu-txt-left"
name="shixun_homework[]" name="shixun_homework[]"
@ -294,7 +294,7 @@ class ShixunWorkModal extends Component{
key={item=== undefined?"":item.id} key={item=== undefined?"":item.id}
> >
<label style={{"textAlign": "left", "color": "#05101A"}} <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> </Checkbox>
</li> </li>
<li className="fl" style={{width: '100px'}}> <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() { 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)=>{ myjumptopic=(e)=>{
console.log("获取到值"); console.log("获取到值");
@ -96,7 +74,28 @@ class OfficialAcademicTranscript extends Component {
} }
render() { 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=[{ let columns=[{
title: '关卡', title: '关卡',
@ -196,6 +195,20 @@ class OfficialAcademicTranscript extends Component {
// min={0} max={record.game_scores.game_score_full} // min={0} max={record.game_scores.game_score_full}
/></a> /></a>
{/*<a style={{textAlign: "center"}} className="color-blue font-14 mr20">查看</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> </span>
), ),
}]; }];
@ -210,6 +223,13 @@ class OfficialAcademicTranscript extends Component {
} }
} }
) )
columns.some((item,key)=> {
if (item.title === "操作") {
columns.splice(key, 1)
return true
}
}
)
} }
return ( return (
<div> <div>
@ -276,6 +296,9 @@ class OfficialAcademicTranscript extends Component {
.linhe15{ .linhe15{
line-height: 15px; line-height: 15px;
} }
.mr22{
margin-right: 22px;
}
`} `}
</style> </style>
{datas===undefined?"":<Table {datas===undefined?"":<Table

@ -38,13 +38,34 @@
.TopicDetailTable .bottomBody li:last-child{border-bottom: none;} .TopicDetailTable .bottomBody li:last-child{border-bottom: none;}
.maxnamewidth100{ .maxnamewidth100{
max-width: 145px; max-width: 100px;
overflow:hidden; overflow:hidden;
text-overflow:ellipsis; text-overflow:ellipsis;
white-space:nowrap; white-space:nowrap;
cursor: default; cursor: default;
} }
.maxnamewidth110{ .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; max-width: 145px;
overflow:hidden; overflow:hidden;
text-overflow:ellipsis; text-overflow:ellipsis;
@ -54,3 +75,16 @@
.ysyslxh{ .ysyslxh{
background: #fafafa; 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(){ componentDidMount(){
window.document.title = "关于我们";
this.getContent(); this.getContent();
} }

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

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

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

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

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

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

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

@ -31,8 +31,22 @@ class MainContent extends Component {
onResizeButtonClick = () => { onResizeButtonClick = () => {
// console.log('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() { 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 onTestSetHeaderClick, loading, codeLoading, shixun, vnc_url} = this.props
// if (output_sets && output_sets.test_sets) { // if (output_sets && output_sets.test_sets) {
@ -97,11 +111,23 @@ class MainContent extends Component {
{ showIframeContent && vnc_url ? { showIframeContent && vnc_url ?
<CodeRepositoryViewContainer { ...this.props } isOnlyContainer={true}> <CodeRepositoryViewContainer { ...this.props } isOnlyContainer={true}>
<VNCContainer <VNCContainer
ref="vncContainer"
vnc_url={vnc_url} vnc_url={vnc_url}
{...this.props} {...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> ></VNCContainer>
<div id="actionView" className="-layout-h -center -bg-grey-90 -grey-20 -bg-darkblack" style={{height:'48px'}}> <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> </div>
</CodeRepositoryViewContainer> </CodeRepositoryViewContainer>
: :
@ -158,7 +184,7 @@ class MainContent extends Component {
</div> </div>
<div id="actionView" className="-layout-h -center -bg-grey-90 -grey-20 -bg-darkblack" style={{height:'48px'}}> <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> </div>
</React.Fragment> </React.Fragment>

@ -10,6 +10,8 @@ import RepoTree from './component/repo/RepoTree'
import TPIMonaco from './component/monaco/TPIMonaco' import TPIMonaco from './component/monaco/TPIMonaco'
import notEditablePathImg from '../../images/tpi/notEditablePath.png' import notEditablePathImg from '../../images/tpi/notEditablePath.png'
import { Drawer } from "antd";
import './VNC.css' import './VNC.css'
const $ = window.$; const $ = window.$;
const firstDrawerWidth = 260; 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} selectedKeys={fileTreeSelectedKeys}
onSelect={onTreeSelect} onSelect={onTreeSelect}
@ -125,6 +137,28 @@ class VNCContainer extends Component {
secondDrawerClassName="codeInDrawer" secondDrawerClassName="codeInDrawer"
> >
<style>{` <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 { .vncDrawer .ant-drawer-body {
padding: 0px; padding: 0px;
} }
@ -173,10 +207,36 @@ class VNCContainer extends Component {
></RepoTree> ></RepoTree>
</SecondDrawer> </SecondDrawer>
<FloatButton></FloatButton> {/* <FloatButton></FloatButton> */}
<VNCDisplay <VNCDisplay
{...this.props} {...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> </React.Fragment>

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

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

@ -74,6 +74,8 @@ class ActionView extends Component {
render() { render() {
const { onRunCodeTest, onShowPrevStage, onShowNextStage, gameBuilding const { onRunCodeTest, onShowPrevStage, onShowNextStage, gameBuilding
, game, classes, st, shixun, record, challenge, time_limit, real_time_limit } = this.props; , game, classes, st, shixun, record, challenge, time_limit, real_time_limit } = this.props;
console.log(shixun)
return ( return (
<div className="-flex -layout-h" id="game_operate_action"> <div className="-flex -layout-h" id="game_operate_action">
<style>{` <style>{`
@ -150,7 +152,7 @@ class ActionView extends Component {
<div id="code_test" className="act_btn"> {(shixun&&!shixun.vnc || shixun&&shixun.vnc_evaluate) && <div id="code_test" className="act_btn">
{ {
st === 1 && game.status === 2 ? st === 1 && game.status === 2 ?
<Tooltip title={ "已通关的选择题任务无法再次测评" }> <Tooltip title={ "已通关的选择题任务无法再次测评" }>
@ -174,7 +176,7 @@ class ActionView extends Component {
<i className="fa fa-play-circle font-16"></i> <i className="fa fa-play-circle font-16"></i>
测评 测评
</a>} </a>}
</div> </div>}
</div> </div>
); );
/* /*

@ -128,3 +128,10 @@
margin: 5px 0; margin: 5px 0;
float: right; 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"> <div className="clearfix df inputTitle">
<span className="fl fb color-grey">测试输入</span> <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>
</div> </div>
@ -307,14 +312,21 @@ class CodeEvaluateView extends Component {
<a href="javascript:void(0);" className="tab_type tab_color">测试结果</a> <a href="javascript:void(0);" className="tab_type tab_color">测试结果</a>
</li> </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*/} {/*TODO 按钮大小改造css*/}
<a className="iconButton fr mr15" onClick={this.onEvaluateViewExpand} id="extend_and_zoom" > <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> <i className={ evaluateViewExpanded ? "font-18 iconfont icon-shousuo" : "iconfont icon-zhankai font-18" }></i>
</a> </a>
</Tooltip> </Tooltip>}
<div className="cl"></div> <div className="cl"></div>
</ul> </ul>

@ -34,23 +34,26 @@ function getNewTreeData(treeData, curKey, child, level) {
} }
function fileData2TreeData(repoFilesData) { function fileData2TreeData(repoFilesData) {
const fileTreeData = []; if(repoFilesData!=null){
repoFilesData.forEach((item) => { const fileTreeData = [];
if (item.kind === 'file') { repoFilesData.forEach((item) => {
fileTreeData.push({ if (item.kind === 'file') {
key: item.path, fileTreeData.push({
name: item.name, key: item.path,
isLeaf: true name: item.name,
}) isLeaf: true
} else { })
fileTreeData.push({ } else {
key: item.path, fileTreeData.push({
name: item.name, key: item.path,
// isLeaf: false name: item.name,
}) // isLeaf: false
} })
}) }
return fileTreeData; })
return fileTreeData;
}
} }
class CodeRepositoryViewContainer extends Component { class CodeRepositoryViewContainer extends Component {

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

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

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

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

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

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

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

@ -353,6 +353,8 @@ export default class TPMsettings extends Component {
test_set_permission: response.data.shixun.test_set_permission, test_set_permission: response.data.shixun.test_set_permission,
hide_code: response.data.shixun.hide_code, hide_code: response.data.shixun.hide_code,
code_hidden: response.data.shixun.code_hidden, 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, forbid_copy: response.data.shixun.forbid_copy,
vnc: response.data.shixun.vnc, vnc: response.data.shixun.vnc,
vnc_evaluate: response.data.shixun.vnc_evaluate, vnc_evaluate: response.data.shixun.vnc_evaluate,
@ -439,20 +441,52 @@ export default class TPMsettings extends Component {
SelectshixunCommand=(e)=>{ SelectshixunCommand=(e)=>{
// console.log( e.target.value) // console.log( e.target.value)
this.setState({ const webssh = e.target.value
webssh: e.target.value, if (webssh == 2) {
}); this.setState({
if(e.target.value===2){ webssh: webssh,
this.setState({ SelectTheCommandtype: true,
SelectTheCommandtype: true, multi_webssh:false
multi_webssh:false });
}); } else {
}else{ if (this.state.init_is_secret_repository && !this.state.vnc && this.state.is_secret_repository == true) {
this.setState({ this.confirmDeleteSecretRepo({
SelectTheCommandtype: false, onOk: () => {
multi_webssh:false 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)=>{ 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) => { forbid_copy = (e) => {
let sum = "" let sum = ""
if (e.target.checked === false) { if (e.target.checked === false) {
@ -550,11 +613,34 @@ export default class TPMsettings extends Component {
// } else if (e.target.checked === true) { // } else if (e.target.checked === true) {
// sum = 1 // sum = 1
// } // }
this.setState({ const vnc = e.target.checked;
vnc: e.target.checked, if (!vnc) {
vnc_evaluate: false, 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) => { shixunsname = (e) => {
// let {shixunsstatus}=this.state; // let {shixunsstatus}=this.state;
@ -773,7 +859,8 @@ export default class TPMsettings extends Component {
// }); // });
// } // }
submit_edit_shixun = () => { submit_edit_shixun = () => {
if (this.saving == true) return;
this.saving = true;
if(this.state.status===-1){ if(this.state.status===-1){
this.props.showSnackbar("该实训已被删除,保存失败!"); this.props.showSnackbar("该实训已被删除,保存失败!");
return return
@ -782,7 +869,7 @@ export default class TPMsettings extends Component {
let { let {
name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate, name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate,
evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh, evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh,
opening_time,shixunmemoMDvalue,shixun_service_configlist opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository
} = this.state; } = this.state;
let newshixun_service_configlist = shixun_service_configlist.map(v => { 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 Url = `/shixuns/` + id + `.json`;
let data = { let data = {
shixun:{ shixun:{
name: name, name: name,
webssh: webssh, webssh: webssh,
use_scope: use_scope, use_scope: use_scope,
@ -906,6 +994,7 @@ export default class TPMsettings extends Component {
description: description_editormd, description: description_editormd,
evaluate_script: evaluate_script_editormd, evaluate_script: evaluate_script_editormd,
}, },
is_secret_repository: is_secret_repository,
main_type: choice_main_type, main_type: choice_main_type,
small_type: choice_small_type, small_type: choice_small_type,
scope_partment: scope_partment, scope_partment: scope_partment,
@ -914,6 +1003,7 @@ export default class TPMsettings extends Component {
axios.put(Url, data).then((response) => { axios.put(Url, data).then((response) => {
// console.log(response) // console.log(response)
this.saving = false;
if(response.status){ if(response.status){
if (response.data.status === -1) { if (response.data.status === -1) {
this.props.showSnackbar(response.data.message); this.props.showSnackbar(response.data.message);
@ -925,6 +1015,7 @@ export default class TPMsettings extends Component {
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
this.saving = false;
}) })
@ -1460,6 +1551,7 @@ export default class TPMsettings extends Component {
name, name,
settingsData, settingsData,
webssh, webssh,
is_secret_repository,
use_scope, use_scope,
shixunsID, shixunsID,
can_copy, can_copy,
@ -1653,8 +1745,6 @@ export default class TPMsettings extends Component {
// onMouseEnter={operateauthority?this.bigopen:""} // onMouseEnter={operateauthority?this.bigopen:""}
onSelect={operateauthority?this.bigopens:""} onSelect={operateauthority?this.bigopens:""}
// open={opers} // open={opers}
showSearch
optionFilterProp="children" optionFilterProp="children"
filterOption={(input, option) => filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
@ -2201,6 +2291,15 @@ export default class TPMsettings extends Component {
</span> </span>
</div> </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"> <div className="clearfix mt20 ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>禁用复制粘贴:</span> <span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>禁用复制粘贴:</span>
<span className="fl mt5"> <span className="fl mt5">
@ -2241,7 +2340,7 @@ export default class TPMsettings extends Component {
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>VNC图形化评测:</span> <span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>VNC图形化评测:</span>
<span className="fl mt5 ml5"> <span className="fl mt5 ml5">
<Checkbox checked={vnc_evaluate === undefined ? false : vnc_evaluate} onChange={this.shixun_vnc_evaluate}></Checkbox> <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> </span>
</div>:""} </div>:""}

@ -240,6 +240,7 @@ export default class TPMevaluation extends Component {
this.setState({ this.setState({
evaluationlist:newevaluationlist evaluationlist:newevaluationlist
}) })
console.log(newevaluationlist)
} }
@ -539,6 +540,14 @@ export default class TPMevaluation extends Component {
this.setevaluationlist(newevaluationlist); 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)=>{ evaluationoninputvalue=(e,key,type)=>{
$.fn.autoHeight = function(){ $.fn.autoHeight = function(){
function autoHeight(elem){ function autoHeight(elem){
@ -1159,6 +1168,13 @@ export default class TPMevaluation extends Component {
autoHeight="true" autoHeight="true"
onInput={(e)=>this.evaluationoninputvalue(e,key,"yq")} onInput={(e)=>this.evaluationoninputvalue(e,key,"yq")}
></textarea> ></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> </div>
) )
})} })}

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

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

@ -385,3 +385,13 @@ a.white-btn.use_scope-btn:hover{
.ml82{ .ml82{
margin-left: 82px; 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 RepositoryDirectories from './RepositoryDirectories'
import { ActionBtn , NoneData } from 'educoder' import { ActionBtn , NoneData } from 'educoder'
import RepositoryCombinePath from './RepositoryCombinePath'
const $ = window.$; const $ = window.$;
// 点击按钮复制功能 // 点击按钮复制功能
@ -85,10 +85,13 @@ class Repository extends Component {
className=" guideBtn" >Git使用指南</a> 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)) ? 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"> <div className="fr font-12 color-grey-9 pr">
<label className="fl mt2">网址克隆</label> <label className="fl mt2">网址克隆</label>
<input type="text" id="copy_rep_content" className="fl url-input mt2" <input type="text" id="copy_rep_content" className="fl url-input mt2"
@ -155,6 +158,10 @@ class Repository extends Component {
</div> </div>
</div> </div>
{this.props.secret_repository_tab && <RepositoryCombinePath {...this.props}>
</RepositoryCombinePath>}
</div> </div>
</div> </div>
@ -181,7 +188,7 @@ class Repository extends Component {
{commits===undefined?"":commits[0].time} {commits===undefined?"":commits[0].time}
</acronym> {commits===undefined?"":commits[0].title} </acronym> {commits===undefined?"":commits[0].title}
</span> </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 "> className="color-grey-6 fr font-16 ">
<i className="iconfont icon-tijiaojilu font-18 fl mr5"></i> <i className="iconfont icon-tijiaojilu font-18 fl mr5"></i>
<span className="fl mt2">提交记录</span> <span className="fl mt2">提交记录</span>

@ -121,6 +121,7 @@ class RepositoryCodeEditor extends Component {
const path = pathArray.join('/') const path = pathArray.join('/')
this.setState({ codeSaving: true }) this.setState({ codeSaving: true })
axios.post(url, { axios.post(url, {
secret_repository: this.props.secret_repository_tab,
content: this.extend_editor.getValue(), content: this.extend_editor.getValue(),
// type: forTest === true ? 1 : 0, // type: forTest === true ? 1 : 0,
path: path 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 id = this.props.match.params.shixunId;
let collaborators=`/shixuns/`+id+`/commits.json`; 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){ if(response.status===200){
this.setState({ this.setState({

@ -6,9 +6,6 @@
margin-left: 32%; margin-left: 32%;
} }
.square-Item{
/*min-height: 324px;*/
}
.square-img{ .square-img{
min-height: 210px; 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 user_type=this.props.current_user&&this.props.current_user.user_identity;
let targetuserid=this.props.data&&this.props.data.id; let targetuserid=this.props.data&&this.props.data.id;
// console.log(is_current) // console.log(is_current)
// console.log(current_user) // console.log(current_user)
// console.log(current_user.is_teacher) // console.log(current_user.is_teacher)
// console.log(current_user.admin) // console.log(current_user.admin)
return( return(
@ -124,7 +124,7 @@ class InfosBanner extends Component{
</li>} </li>}
{/*自己的主页且不是学生显示题库按钮*/} {/*自己的主页且不是学生显示题库按钮*/}
{((is_current && current_user && current_user.is_teacher ) || current_user && current_user.admin) {(is_current && current_user)
&&<li className={`${moduleName == 'topics' ? 'active' : '' }`}> &&<li className={`${moduleName == 'topics' ? 'active' : '' }`}>
<Link <Link
onClick={() => this.setState({moduleName: 'topics'})} onClick={() => this.setState({moduleName: 'topics'})}

@ -103,7 +103,7 @@ class InfosCourse extends Component{
} = this.state; } = this.state;
let is_current=this.props.is_current; 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( return(
<div className="educontent"> <div className="educontent">
<Spin size="large" spinning={isSpin}> <Spin size="large" spinning={isSpin}>

@ -31,33 +31,34 @@ class InfosTopics extends Component{
} }
componentDidMount(){ componentDidMount(){
let types=this.props.match.params.topicstype; // let types=this.props.match.params.topicstype;
let professional_certification=this.props.current_user&&this.props.current_user.professional_certification; // let professional_certification=this.props.current_user&&this.props.current_user.professional_certification;
//
if(professional_certification===false&&types==="publicly"){ // if(professional_certification===false&&types==="publicly"){
this.setState({ // this.setState({
isshowprofes:true // isshowprofes:true
}) // })
}else{ // }else{
this.updataslist() // 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()
}
}
} }
// 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=()=>{ updataslist=()=>{
let types=this.props.match.params.topicstype; let types=this.props.match.params.topicstype;
let { category,course_list_id,sort_by,sort_direction,page}=this.state; 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)=>{ 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({ this.setState({
isSpin:true 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 {per_page}=this.state; let url=`/users/question_banks.json`;
let url=`/users/${user_id}/question_banks.json`;
axios.get(encodeURI(url),{params:{
axios.get(encodeURI(url),{params:{ type,
type, object_type:category,
object_type:category, course_list_id,
course_list_id, sort_by,
sort_by, sort_direction,
sort_direction, page,
page, per_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