diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb index c19c6fdd6..9242b87ac 100644 --- a/app/controllers/concerns/git_helper.rb +++ b/app/controllers/concerns/git_helper.rb @@ -23,7 +23,7 @@ module GitHelper Rails.logger.info "encoding: #{cd['encoding']} confidence: #{cd['confidence']}" # 字符编码问题,GB18030编码识别率不行 decode_content = - if cd["encoding"] == 'GB18030' && cd['confidence'] == 1.0 + if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8 content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '}) else content.force_encoding('UTF-8') diff --git a/app/controllers/exercise_questions_controller.rb b/app/controllers/exercise_questions_controller.rb index 57116a9e5..bb28fff54 100644 --- a/app/controllers/exercise_questions_controller.rb +++ b/app/controllers/exercise_questions_controller.rb @@ -494,20 +494,88 @@ class ExerciseQuestionsController < ApplicationController def adjust_score ActiveRecord::Base.transaction do begin + ex_all_scores = @exercise.exercise_questions.pluck(:question_score).sum ex_obj_score = @exercise_current_user.objective_score #全部客观题得分 ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分 ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分 - if @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分, - ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 - each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数 - new_obj_score = ex_obj_score - ex_answer_old + @c_score + if @exercise_question.question_type == Exercise::MULTIPLE + if ex_answers.present? #学生有回答时 取学生的答题得分,否则0分 + answer_choice_array = [] + ex_answers.each do |a| + if a.try(:exercise_choice).try(:choice_position).present? + answer_choice_array.push(a&.exercise_choice&.choice_position) #学生答案的位置 + end + end + user_answer_content = answer_choice_array.reject(&:blank?).sort + standard_answer = @exercise_question.exercise_standard_answers.pluck(:exercise_choice_id).sort + if standard_answer.size == 1 # 老数据需要判断学生答题是否正确, 正确取原题得分,否则是0分 + standard_answer = standard_answer.first.to_s.split("").map(&:to_i).sort + if user_answer_content == standard_answer + ex_answer_old = @exercise_question.question_score + else + ex_answer_old = 0 + end + else # 新多选题只需取第一条答题记录的得分 + ex_answer_old = ex_answers.first.score > 0 ? ex_answers.first.score : 0 + end + ex_answers.update_all(:score => @c_score) #所有的正确选项需重新更新 + else + answer_option = { + :user_id => @user_id, + :exercise_question_id => @exercise_question.id, + :score => @c_score, + :answer_text => "" + } + ExerciseAnswer.create(answer_option) + ex_answer_old = 0 + end + if ex_obj_score <= 0.0 + new_obj_score = @c_score + else + new_obj_score = ex_obj_score - ex_answer_old + @c_score + end + total_scores = new_obj_score + ex_subj_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end + ex_scores = { + :objective_score => new_obj_score, + :score => total_scores + } + @exercise_current_user.update_attributes(ex_scores) + + elsif @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分, + + if ex_answers.exists? + ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 + each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数 + new_obj_score = ex_obj_score - ex_answer_old + @c_score + ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新 + else #如果学生未答,则创建新的答题记录 + answer_option = { + :user_id => @user_id, + :exercise_question_id => @exercise_question.id, + :score => @c_score, + :answer_text => "" + } + ExerciseAnswer.create(answer_option) + new_obj_score = ex_obj_score + @c_score + end + + total_scores = new_obj_score + ex_subj_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end ex_scores = { :objective_score => new_obj_score, :score => total_scores } @exercise_current_user.update_attributes(ex_scores) - ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新 elsif @exercise_question.question_type == Exercise::SUBJECTIVE #当为主观题时 if ex_answers.exists? ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0,取0 @@ -524,6 +592,11 @@ class ExerciseQuestionsController < ApplicationController new_sub_score = ex_subj_score + @c_score end total_scores = ex_obj_score + new_sub_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end ex_scores = { :subjective_score => new_sub_score, :score => total_scores @@ -549,6 +622,11 @@ class ExerciseQuestionsController < ApplicationController new_obj_score = @c_score end total_scores = new_obj_score + ex_subj_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end ex_scores = { :objective_score => new_obj_score, :score => total_scores @@ -556,30 +634,33 @@ class ExerciseQuestionsController < ApplicationController @exercise_current_user.update_attributes(ex_scores) end comments = params[:comment] - question_comment = @exercise_question.exercise_answer_comments.first + question_comment = @exercise_question.exercise_answer_comments&.first + if question_comment.present? comment_option = { - :comment => comments.present? ? comments : question_comment.comment, + :comment => comments, :score => @c_score, - :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil + :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil, + :user_id => current_user.id } question_comment.update_attributes(comment_option) @exercise_comments = question_comment else + ex_answer_comment_id = @exercise_question.exercise_answers.find_by(user_id: @user_id).try(:id) comment_option = { :user_id => current_user.id, :comment => comments, :score => @c_score, :exercise_question_id => @exercise_question.id, :exercise_shixun_answer_id => @shixun_a_id.present? ? @shixun_a_id : nil, - :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil + :exercise_answer_id => ex_answer_comment_id } @exercise_comments = ExerciseAnswerComment.new(comment_option) @exercise_comments.save end rescue Exception => e uid_logger_error(e.message) - tip_exception("没有权限") + tip_exception(e.message) raise ActiveRecord::Rollback end end @@ -703,8 +784,8 @@ class ExerciseQuestionsController < ApplicationController normal_status(-1,"用户不存在!") elsif @c_score.blank? normal_status(-1,"分数不能为空!") - elsif @exercise_question.question_type <= Exercise::JUDGMENT - normal_status(-1,"选择题/判断题不能调分!") + elsif @exercise_question.question_type == Exercise::SINGLE || @exercise_question.question_type == Exercise::JUDGMENT + normal_status(-1,"单选题/判断题不能调分!") elsif params[:comment].present? && params[:comment].length > 100 normal_status(-1,"评语不能超过100个字符!") else diff --git a/app/controllers/graduation_tasks_controller.rb b/app/controllers/graduation_tasks_controller.rb index a159cff59..841b516bb 100644 --- a/app/controllers/graduation_tasks_controller.rb +++ b/app/controllers/graduation_tasks_controller.rb @@ -324,7 +324,7 @@ class GraduationTasksController < ApplicationController tip_exception("缺少截止时间参数") if params[:end_time].blank? tip_exception("截止时间必须晚于当前时间") if params[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) # ActiveRecord::Base.transaction do begin @@ -401,7 +401,7 @@ class GraduationTasksController < ApplicationController tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") tip_exception("截止时间不能早于发布时间") if params[:publish_time] > params[:end_time] tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @task.publish_time = params[:publish_time] @task.end_time = params[:end_time] @@ -414,7 +414,7 @@ class GraduationTasksController < ApplicationController tip_exception("截止时间不能为空") if params[:end_time].blank? tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @task.end_time = params[:end_time] end @@ -426,7 +426,7 @@ class GraduationTasksController < ApplicationController tip_exception("补交结束时间不能为空") if params[:late_time].blank? tip_exception("补交结束时间不能早于截止时间") if params[:late_time] <= @task.end_time tip_exception("补交结束时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:late_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:late_time] > strf_time(@course.end_date.end_of_day) tip_exception("迟交扣分应为正整数") if params[:late_penalty] && params[:late_penalty].to_i < 0 @task.allow_late = true diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index fc5db713f..bf067b389 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -271,7 +271,11 @@ class MyshixunsController < ApplicationController unless @hide_code || @myshixun.shixun&.vnc_evaluate # 远程版本库文件内容 last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] - content = params[:content] + content = if @myshixun.mirror_name.select {|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? + params[:content].gsub(/\t/, ' ').gsub(/ /, ' ') # 这个不是空格,在windows机器上带来的问题 + else + params[:content] + end Rails.logger.info("###11222333####{content}") Rails.logger.info("###222333####{last_content}") diff --git a/app/controllers/question_banks_controller.rb b/app/controllers/question_banks_controller.rb index b4e98e05f..60b9a807c 100644 --- a/app/controllers/question_banks_controller.rb +++ b/app/controllers/question_banks_controller.rb @@ -264,8 +264,9 @@ class QuestionBanksController < ApplicationController # new_exercise.create_exercise_list # exercise.update_column(:quotes, exercise.quotes+1) # end - new_exercise if new_exercise.save! + new_exercise.save! exercise.update_column(:quotes, exercise.quotes+1) + new_exercise end end @@ -292,8 +293,9 @@ class QuestionBanksController < ApplicationController # new_poll.create_polls_list # poll.update_column(:quotes, poll.quotes+1) # end - new_poll if new_poll.save! + new_poll.save! poll.update_column(:quotes, poll.quotes+1) + new_poll end end diff --git a/app/controllers/shixun_lists_controller.rb b/app/controllers/shixun_lists_controller.rb new file mode 100644 index 000000000..e92e857ad --- /dev/null +++ b/app/controllers/shixun_lists_controller.rb @@ -0,0 +1,10 @@ +class ShixunListsController < ApplicationController + def index + @results = ShixunSearchService.call(search_params) + end + + private + def search_params + params.permit(:keyword, :type, :page, :limit, :order, :type, :status, :diff) + end +end \ No newline at end of file diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 490b9e970..8a120d6bd 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -1,6 +1,7 @@ class ShixunsController < ApplicationController include ShixunsHelper include ApplicationHelper + include ElasticsearchAble before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list, :discusses, :collaborators, :fork_list, :propaedeutics] @@ -131,8 +132,16 @@ class ShixunsController < ApplicationController offset = (page.to_i - 1) * (limit.to_i) order = params[:order] || "desc" ## 搜索关键字创建者、实训名称、院校名称 - keyword = params[:search].blank? ? "*" : params[:search] - @shixuns = Shixun.search keyword, where: {id: @shixuns.pluck(:id)}, order: {"myshixuns_count" => order}, limit: limit, offset: offset + keyword = params[:keyword].to_s.strip.presence || '*' + + model_options = { + index_name: [Shixun], + model_includes: Shixun.searchable_includes + } + model_options.merge(where: { id: @shixuns.pluck(:id) }).merge(order: {"myshixuns_count" => order}).merge(limit: limit, offset: offset) + model_options.merge(default_options) + @shixuns = Searchkick.search(keyword, model_options) + # @shixuns = Shixun.search keyword, where: {id: @shixuns.pluck(:id)}, order: {"myshixuns_count" => order}, limit: limit, offset: offset @total_count = @shixuns.total_count end diff --git a/app/helpers/exercises_helper.rb b/app/helpers/exercises_helper.rb index 2c417ea74..98a580ecc 100644 --- a/app/helpers/exercises_helper.rb +++ b/app/helpers/exercises_helper.rb @@ -16,18 +16,26 @@ module ExercisesHelper end if q_type <= Exercise::JUDGMENT - if answers_content.present? #学生有回答时 - answer_choice_array = [] - answers_content.each do |a| - answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 - end - user_answer_content = answer_choice_array.sort - standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 - if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 - ques_score = q.question_score - else - ques_score = 0.0 - end + if answers_content.present? #学生有回答时,分数已经全部存到exercise_answer 表,所以可以直接取第一个值 + ques_score = answers_content.first.score + ques_score = ques_score < 0 ? 0.0 : ques_score + # answer_choice_array = [] + # answers_content.each do |a| + # answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 + # end + # user_answer_content = answer_choice_array.sort + # standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 + # if q_type == Exercise::MULTIPLE && standard_answer.size == 1 # 老数据的问题 + # ques_score = answers_content.first.score + # else + # + # end + + # if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 + # ques_score = q.question_score + # else + # ques_score = 0.0 + # end else ques_score = 0.0 end @@ -58,7 +66,6 @@ module ExercisesHelper exercise_sub_status.each do |s| sub_answer = s.exercise_answers.search_answer_users("user_id",user_id) #主观题只有一个回答 if sub_answer.present? && sub_answer.first.score >= 0.0 - if s.question_score <= sub_answer.first.score stand_status = 1 else @@ -775,22 +782,24 @@ module ExercisesHelper user_score = user_score_pre.present? ? user_score_pre.pluck(:score).sum : nil elsif ques_type == 5 || ques_type == 3 user_score = user_score_pre.present? ? user_score_pre.pluck(:score).sum : 0.0 - else - if exercise_answers.present? #判断题和选择题时, - answer_choice_array = [] - exercise_answers.each do |a| - answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 - end - user_answer_content = answer_choice_array.sort - standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 - if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 - user_score = q.question_score - else - user_score = 0.0 - end - else - user_score = 0.0 - end + else #选择题,判断题根据第一个记录查分 + user_score = user_score_pre.present? ? user_score_pre.first.score : 0.0 + + # if exercise_answers.present? #判断题和选择题时, + # answer_choice_array = [] + # exercise_answers.each do |a| + # answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 + # end + # user_answer_content = answer_choice_array.sort + # standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 + # if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 + # user_score = q.question_score + # else + # user_score = 0.0 + # end + # else + # user_score = 0.0 + # end end end diff --git a/app/models/exercise_answer_comment.rb b/app/models/exercise_answer_comment.rb index 7da0ec4c7..4279ba445 100644 --- a/app/models/exercise_answer_comment.rb +++ b/app/models/exercise_answer_comment.rb @@ -3,7 +3,7 @@ class ExerciseAnswerComment < ApplicationRecord belongs_to :user belongs_to :exercise_question belongs_to :exercise_shixun_answer, optional: true - belongs_to :exercise_answer,optional: true + belongs_to :exercise_answer, optional: true scope :search_answer_comments, lambda {|name,ids| where("#{name}":ids)} end diff --git a/app/models/searchable/shixun.rb b/app/models/searchable/shixun.rb index c1584829d..41bc94b04 100644 --- a/app/models/searchable/shixun.rb +++ b/app/models/searchable/shixun.rb @@ -51,13 +51,12 @@ module Searchable::Shixun visits_count: visits, challenges_count: challenges_count, study_count: myshixuns_count, - description: description } end module ClassMethods def searchable_includes - { user: { user_extension: :school } } + [ :shixun_info, user: { user_extension: :school } ] end end end diff --git a/app/models/subject.rb b/app/models/subject.rb index 6ecb5ed18..d5ea3f433 100644 --- a/app/models/subject.rb +++ b/app/models/subject.rb @@ -46,8 +46,7 @@ class Subject < ApplicationRecord # 挑战过路径的成员数(金课统计去重后的报名人数) def member_count - excellent && CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length > shixuns.pluck(:myshixuns_count).sum ? - CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum + excellent ? CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum end def all_score diff --git a/app/models/tiding.rb b/app/models/tiding.rb index d885f93fd..02692085a 100644 --- a/app/models/tiding.rb +++ b/app/models/tiding.rb @@ -22,4 +22,9 @@ class Tiding < ApplicationRecord value end + + def anonymous? + (container_type == 'StudentWorksScore' && extra.to_i == 3) || + (container_type == 'StudentWorksScoresAppeal' && parent_container_type == 'StudentWork' && tiding_type == 'System') + end end \ No newline at end of file diff --git a/app/services/concerns/elasticsearch_able.rb b/app/services/concerns/elasticsearch_able.rb index 80ca5467e..015aac29b 100644 --- a/app/services/concerns/elasticsearch_able.rb +++ b/app/services/concerns/elasticsearch_able.rb @@ -28,9 +28,11 @@ module ElasticsearchAble end def body_options - { - min_score: EduSetting.get('es_min_score') || 10 - } + hash = {} + + hash[:min_score] = (EduSetting.get('es_min_score') || 10) if keyword != '*' + + hash end def per_page diff --git a/app/services/shixun_search_service.rb b/app/services/shixun_search_service.rb new file mode 100644 index 000000000..911f341f8 --- /dev/null +++ b/app/services/shixun_search_service.rb @@ -0,0 +1,56 @@ +class ShixunSearchService < ApplicationService + include ElasticsearchAble + + attr_reader :params + + def initialize(params) + @params = params + end + + def call + # 全部实训/我的实训 + type = params[:type] || "all" + # 状态:已发布/未发布 + status = params[:status] || "all" + + # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭) + if type == "mine" + @shixuns = User.current.shixuns.none_closed + else + if User.current.admin? || User.current.business? + @shixuns = Shixun.none_closed.where(hidden: 0) + else + none_shixun_ids = ShixunSchool.where("school_id != #{User.current.school_id}").pluck(:shixun_id) + + @shixuns = Shixun.where.not(id: none_shixun_ids).none_closed.where(hidden: 0) + end + end + + unless status == "all" + @shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1]) + end + + ## 筛选 难度 + if params[:diff].present? && params[:diff].to_i != 0 + @shixuns = @shixuns.where(trainee: params[:diff]) + end + + Shixun.search(keyword, search_options) + end + + private + + def search_options + model_options = { + includes: [ :shixun_info, :challenges, :subjects, user: { user_extension: :school } ] + } + model_options.merge!(where: { id: @shixuns.pluck(:id) }) + model_options.merge!(order: {"myshixuns_count" => sort_str}) + model_options.merge!(default_options) + model_options + end + + def sort_str + params[:order] || "desc" + end +end \ No newline at end of file diff --git a/app/views/homework_commons/shixuns.json.jbuilder b/app/views/homework_commons/shixuns.json.jbuilder index bd97f5e8d..79f22e42a 100644 --- a/app/views/homework_commons/shixuns.json.jbuilder +++ b/app/views/homework_commons/shixuns.json.jbuilder @@ -1,4 +1,4 @@ -# json.shixun_list @shixuns do |shixun| +# json.shixun_lists @shixuns do |shixun| # json.shixun_identifier shixun.identifier # json.name shixun.name # json.creator shixun.user&.full_name diff --git a/app/views/shixun_lists/index.json.jbuilder b/app/views/shixun_lists/index.json.jbuilder new file mode 100644 index 000000000..d6c651743 --- /dev/null +++ b/app/views/shixun_lists/index.json.jbuilder @@ -0,0 +1,22 @@ +json.shixuns_count @results.total_count + +json.shixun_list do + json.array! @results.with_highlights(multiple: true) do |obj, highlights| + json.merge! obj.to_searchable_json + json.challenge_names obj.challenges.pluck(:subject) + + # 去除开头标点符号 + reg = /^[,。?:;‘’!“”—……、]/ + highlights[:description]&.first&.sub!(reg, '') + highlights[:content]&.first&.sub!(reg, '') + + json.title highlights.delete(:name)&.join('...') || obj.searchable_title + json.description highlights[:description]&.join('...') || Util.extract_content(obj.description)[0..300] + + json.content highlights + json.level level_to_s(obj.trainee) + json.subjects obj.subjects.uniq do |subject| + json.(subject, :id, :name) + end + end +end \ No newline at end of file diff --git a/app/views/shixuns/shixun_list.json.jbuilder b/app/views/shixuns/shixun_list.json.jbuilder index 54ac65a0a..2f1d4905c 100644 --- a/app/views/shixuns/shixun_list.json.jbuilder +++ b/app/views/shixuns/shixun_list.json.jbuilder @@ -10,7 +10,7 @@ json.shixun_list do # json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('<br/>') json.content highlights json.level level_to_s(obj.trainee) - json.subjects obj.subjects do |subject| + json.subjects obj.subjects.uniq do |subject| json.(subject, :id, :name) end end diff --git a/app/views/tidings/_tiding.json.jbuilder b/app/views/tidings/_tiding.json.jbuilder index 959a96ebd..210e5c8f8 100644 --- a/app/views/tidings/_tiding.json.jbuilder +++ b/app/views/tidings/_tiding.json.jbuilder @@ -17,8 +17,13 @@ json.homework_type homework_type json.time tiding.how_long_time json.new_tiding tiding.unread?(@onclick_time) +# 需要系统头像 +show_system_user = tiding.trigger_user_id.zero? || + (tiding.trigger_user_id == 1 && tiding.tiding_type == 'System') || + tiding.anonymous? + json.trigger_user do - if tiding.trigger_user_id.zero? || (tiding.trigger_user_id == 1 && tiding.tiding_type == 'System') + if show_system_user json.id 0 json.name "系统" json.login "" diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml index e6e8e676d..21c020d04 100644 --- a/config/locales/tidings/zh-CN.yml +++ b/config/locales/tidings/zh-CN.yml @@ -202,6 +202,7 @@ 2_end: "别人对你的匿评发起的申诉申请:%s,审核未通过" StudentWork: Apply_end: "发起了匿评申诉申请:%s" + HomeworkCommon_end: "发起了匿评申诉申请:%s" System_end: "有人对你的匿评发起了申诉:%s" Department_end: "你选填的二级单位:%s(%s)因不符合规范,已被系统删除.请重新选择" Library: diff --git a/config/routes.rb b/config/routes.rb index f5c1a54d3..b786862ce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -174,7 +174,10 @@ Rails.application.routes.draw do end end + resources :shixun_lists + resources :shixuns, param: :identifier do + collection do get :menus get :get_recommend_shixuns @@ -182,7 +185,7 @@ Rails.application.routes.draw do get :get_mirror_script post :apply_shixun_mirror get :download_file - get :shixun_list + get :shixun_lists end member do diff --git a/dump.rdb b/dump.rdb index bcf064366..9f62f75c7 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/lib/tasks/public_course_sync.rake b/lib/tasks/public_course_sync.rake index a22a9f1f8..c26090e81 100644 --- a/lib/tasks/public_course_sync.rake +++ b/lib/tasks/public_course_sync.rake @@ -81,8 +81,10 @@ namespace :public_classes do homework.update_columns(publish_time: publish_time, end_time: end_time, created_at: created_at, updated_at: updated_at) homework.homework_detail_manual.update_columns(comment_status: 6, created_at: created_at, updated_at: updated_at) + homework.update_homework_work_score + homework.update_attribute('calculation_time', end_time) - homework.student_works.where("work_status !=0 and update_time > '#{end_time}'").update_all(update_time: end_time) + # homework.student_works.where("work_status !=0 and update_time > '#{end_time}'").update_all(update_time: end_time) end when 3 # 试卷 diff --git a/public/editormd/lib/marked.min.js b/public/editormd/lib/marked.min.js index 4db085adb..88ec3e856 100644 --- a/public/editormd/lib/marked.min.js +++ b/public/editormd/lib/marked.min.js @@ -10,7 +10,5 @@ out+=this.renderer.em(this.output(cap[2]||cap[1])) --> out+=this.renderer.em(this.output(cap[2]||cap[1]), cap.input) */ -(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else{if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else{if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose){loose=next}}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq); -this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if((!bq&&top)&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else{if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else{if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else{if(this.options.pedantic){this.rules=inline.pedantic}}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else{if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]), cap.input);continue -}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants){return text}return text.replace(/--/g,"\u2014").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1\u2018").replace(/'/g,"\u2019").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1\u201c").replace(/"/g,"\u201d").replace(/\.{3}/g,"\u2026")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>0.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]}) -}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body);case"blockquote_start":var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body);case"list_start":var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered);case"list_item_start":var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body);case"loose_item_start":var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body);case"html":var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html);case"paragraph":return this.renderer.paragraph(this.inline.output(this.token.text));case"text":return this.renderer.paragraph(this.parseText())}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon"){return":"}if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name){return new RegExp(regex,opt)}val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(err){if(err){opt.highlight=highlight;return callback(err)}var out;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending){return done()}for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return --pending||done()}return highlight(token.text,token.lang,function(err,code){if(err){return done(err)}if(code==null||code===token.text){return --pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt){opt=merge({},marked.defaults,opt)}return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else{if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); +// 0.4.0 /^ *(#{1,6}) ——》/^ *(#{1,6}) 去掉了一个空格 TODO 行内公式带_ +!function(e){"use strict";var t={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:d,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6})*([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:d,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|<![A-Z][\\s\\S]*?>\\n*|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:d,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function n(e){this.tokens=[],this.tokens.links={},this.options=e||m.defaults,this.rules=t.normal,this.options.pedantic?this.rules=t.pedantic:this.options.gfm&&(this.options.tables?this.rules=t.tables:this.rules=t.gfm)}t._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,t._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,t.def=p(t.def).replace("label",t._label).replace("title",t._title).getRegex(),t.bullet=/(?:[*+-]|\d+\.)/,t.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,t.item=p(t.item,"gm").replace(/bull/g,t.bullet).getRegex(),t.list=p(t.list).replace(/bull/g,t.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+t.def.source+")").getRegex(),t._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",t._comment=/<!--(?!-?>)[\s\S]*?-->/,t.html=p(t.html,"i").replace("comment",t._comment).replace("tag",t._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),t.paragraph=p(t.paragraph).replace("hr",t.hr).replace("heading",t.heading).replace("lheading",t.lheading).replace("tag",t._tag).getRegex(),t.blockquote=p(t.blockquote).replace("paragraph",t.paragraph).getRegex(),t.normal=f({},t),t.gfm=f({},t.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6})+([^\n]+?) *#* *(?:\n+|$)/}),t.gfm.paragraph=p(t.paragraph).replace("(?!","(?!"+t.gfm.fences.source.replace("\\1","\\2")+"|"+t.list.source.replace("\\1","\\3")+"|").getRegex(),t.tables=f({},t.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),t.pedantic=f({},t.normal,{html:p("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",t._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),n.rules=t,n.lex=function(e,t){return new n(t).lex(e)},n.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},n.prototype.token=function(e,n){var r,s,i,l,o,a,h,p,u,c,g,d,f;for(e=e.replace(/^ +$/gm,"");e;)if((i=this.rules.newline.exec(e))&&(e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"})),i=this.rules.code.exec(e))e=e.substring(i[0].length),i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?i:i.replace(/\n+$/,"")});else if(i=this.rules.fences.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2],text:i[3]||""});else if(i=this.rules.heading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});else if(n&&(i=this.rules.nptable.exec(e))&&(a={type:"table",header:b(i[1].replace(/^ *| *\| *$/g,"")),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3]?i[3].replace(/\n$/,"").split("\n"):[]}).header.length===a.align.length){for(e=e.substring(i[0].length),p=0;p<a.align.length;p++)/^ *-+: *$/.test(a.align[p])?a.align[p]="right":/^ *:-+: *$/.test(a.align[p])?a.align[p]="center":/^ *:-+ *$/.test(a.align[p])?a.align[p]="left":a.align[p]=null;for(p=0;p<a.cells.length;p++)a.cells[p]=b(a.cells[p],a.header.length);this.tokens.push(a)}else if(i=this.rules.hr.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"hr"});else if(i=this.rules.blockquote.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"blockquote_start"}),i=i[0].replace(/^ *> ?/gm,""),this.token(i,n),this.tokens.push({type:"blockquote_end"});else if(i=this.rules.list.exec(e)){for(e=e.substring(i[0].length),g=(l=i[2]).length>1,this.tokens.push({type:"list_start",ordered:g,start:g?+l:""}),r=!1,c=(i=i[0].match(this.rules.item)).length,p=0;p<c;p++)h=(a=i[p]).length,~(a=a.replace(/^ *([*+-]|\d+\.) +/,"")).indexOf("\n ")&&(h-=a.length,a=this.options.pedantic?a.replace(/^ {1,4}/gm,""):a.replace(new RegExp("^ {1,"+h+"}","gm"),"")),this.options.smartLists&&p!==c-1&&(l===(o=t.bullet.exec(i[p+1])[0])||l.length>1&&o.length>1||(e=i.slice(p+1).join("\n")+e,p=c-1)),s=r||/\n\n(?!\s*$)/.test(a),p!==c-1&&(r="\n"===a.charAt(a.length-1),s||(s=r)),f=void 0,(d=/^\[[ xX]\] /.test(a))&&(f=" "!==a[1],a=a.replace(/^\[[ xX]\] +/,"")),this.tokens.push({type:s?"loose_item_start":"list_item_start",task:d,checked:f}),this.token(a,!1),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(i=this.rules.html.exec(e))e=e.substring(i[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===i[1]||"script"===i[1]||"style"===i[1]),text:i[0]});else if(n&&(i=this.rules.def.exec(e)))e=e.substring(i[0].length),i[3]&&(i[3]=i[3].substring(1,i[3].length-1)),u=i[1].toLowerCase().replace(/\s+/g," "),this.tokens.links[u]||(this.tokens.links[u]={href:i[2],title:i[3]});else if(n&&(i=this.rules.table.exec(e))&&(a={type:"table",header:b(i[1].replace(/^ *| *\| *$/g,"")),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3]?i[3].replace(/(?: *\| *)?\n$/,"").split("\n"):[]}).header.length===a.align.length){for(e=e.substring(i[0].length),p=0;p<a.align.length;p++)/^ *-+: *$/.test(a.align[p])?a.align[p]="right":/^ *:-+: *$/.test(a.align[p])?a.align[p]="center":/^ *:-+ *$/.test(a.align[p])?a.align[p]="left":a.align[p]=null;for(p=0;p<a.cells.length;p++)a.cells[p]=b(a.cells[p].replace(/^ *\| *| *\| *$/g,""),a.header.length);this.tokens.push(a)}else if(i=this.rules.lheading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:"="===i[2]?1:2,text:i[1]});else if(n&&(i=this.rules.paragraph.exec(e)))e=e.substring(i[0].length),this.tokens.push({type:"paragraph",text:"\n"===i[1].charAt(i[1].length-1)?i[1].slice(0,-1):i[1]});else if(i=this.rules.text.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"text",text:i[0]});else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0));return this.tokens};var r={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:d,tag:"^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)|^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)/,em:/^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*][\s\S]*?[^\s])\*(?!\*)|^_([^\s_])_(?!_)|^\*([^\s*])\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:d,text:/^[\s\S]+?(?=[\\<!\[`*]|\b_| {2,}\n|$)/};function s(e,t){if(this.options=t||m.defaults,this.links=e,this.rules=r.normal,this.renderer=this.options.renderer||new i,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.pedantic?this.rules=r.pedantic:this.options.gfm&&(this.options.breaks?this.rules=r.breaks:this.rules=r.gfm)}function i(e){this.options=e||m.defaults}function l(){}function o(e){this.tokens=[],this.token=null,this.options=e||m.defaults,this.options.renderer=this.options.renderer||new i,this.renderer=this.options.renderer,this.renderer.options=this.options}function a(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function h(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function p(e,t){return e=e.source||e,t=t||"",{replace:function(t,n){return n=(n=n.source||n).replace(/(^|[^\[])\^/g,"$1"),e=e.replace(t,n),this},getRegex:function(){return new RegExp(e,t)}}}function u(e,t){return c[" "+e]||(/^[^:]+:\/*[^/]*$/.test(e)?c[" "+e]=e+"/":c[" "+e]=e.replace(/[^/]*$/,"")),e=c[" "+e],"//"===t.slice(0,2)?e.replace(/:[\s\S]*/,":")+t:"/"===t.charAt(0)?e.replace(/(:\/*[^/]*)[\s\S]*/,"$1")+t:e+t}r._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,r._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,r._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,r.autolink=p(r.autolink).replace("scheme",r._scheme).replace("email",r._email).getRegex(),r._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,r.tag=p(r.tag).replace("comment",t._comment).replace("attribute",r._attribute).getRegex(),r._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,r._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)/,r._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,r.link=p(r.link).replace("label",r._label).replace("href",r._href).replace("title",r._title).getRegex(),r.reflink=p(r.reflink).replace("label",r._label).getRegex(),r.normal=f({},r),r.pedantic=f({},r.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:p(/^!?\[(label)\]\((.*?)\)/).replace("label",r._label).getRegex(),reflink:p(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",r._label).getRegex()}),r.gfm=f({},r.normal,{escape:p(r.escape).replace("])","~|])").getRegex(),url:p(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("email",r._email).getRegex(),_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:p(r.text).replace("]|","~]|").replace("|","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|").getRegex()}),r.breaks=f({},r.gfm,{br:p(r.br).replace("{2,}","*").getRegex(),text:p(r.gfm.text).replace("{2,}","*").getRegex()}),s.rules=r,s.output=function(e,t,n){return new s(t,n).output(e)},s.prototype.output=function(e){for(var t,n,r,i,l,o="";e;)if(l=this.rules.escape.exec(e))e=e.substring(l[0].length),o+=l[1];else if(l=this.rules.autolink.exec(e))e=e.substring(l[0].length),r="@"===l[2]?"mailto:"+(n=a(this.mangle(l[1]))):n=a(l[1]),o+=this.renderer.link(r,null,n);else if(this.inLink||!(l=this.rules.url.exec(e))){if(l=this.rules.tag.exec(e))!this.inLink&&/^<a /i.test(l[0])?this.inLink=!0:this.inLink&&/^<\/a>/i.test(l[0])&&(this.inLink=!1),e=e.substring(l[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(l[0]):a(l[0]):l[0];else if(l=this.rules.link.exec(e))e=e.substring(l[0].length),this.inLink=!0,r=l[2],this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],i=t[3]):i="":i=l[3]?l[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),o+=this.outputLink(l,{href:s.escapes(r),title:s.escapes(i)}),this.inLink=!1;else if((l=this.rules.reflink.exec(e))||(l=this.rules.nolink.exec(e))){if(e=e.substring(l[0].length),t=(l[2]||l[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=l[0].charAt(0),e=l[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(l,t),this.inLink=!1}else if(l=this.rules.strong.exec(e))e=e.substring(l[0].length),o+=this.renderer.strong(this.output(l[4]||l[3]||l[2]||l[1]));else if(l=this.rules.em.exec(e))e=e.substring(l[0].length),o+=this.renderer.em(this.output(l[6]||l[5]||l[4]||l[3]||l[2]||l[1]));else if(l=this.rules.code.exec(e))e=e.substring(l[0].length),o+=this.renderer.codespan(a(l[2].trim(),!0));else if(l=this.rules.br.exec(e))e=e.substring(l[0].length),o+=this.renderer.br();else if(l=this.rules.del.exec(e))e=e.substring(l[0].length),o+=this.renderer.del(this.output(l[1]));else if(l=this.rules.text.exec(e))e=e.substring(l[0].length),o+=this.renderer.text(a(this.smartypants(l[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else l[0]=this.rules._backpedal.exec(l[0])[0],e=e.substring(l[0].length),"@"===l[2]?r="mailto:"+(n=a(l[0])):(n=a(l[0]),r="www."===l[1]?"http://"+n:n),o+=this.renderer.link(r,null,n);return o},s.escapes=function(e){return e?e.replace(s.rules._escapes,"$1"):e},s.prototype.outputLink=function(e,t){var n=t.href,r=t.title?a(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,a(e[1]))},s.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},s.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;s<r;s++)t=e.charCodeAt(s),Math.random()>.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},i.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'<pre><code class="'+this.options.langPrefix+a(t,!0)+'">'+(n?e:a(e,!0))+"</code></pre>\n":"<pre><code>"+(n?e:a(e,!0))+"</code></pre>"},i.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},i.prototype.html=function(e){return e},i.prototype.heading=function(e,t,n){return this.options.headerIds?"<h"+t+' id="'+this.options.headerPrefix+n.toLowerCase().replace(/[^\w]+/g,"-")+'">'+e+"</h"+t+">\n":"<h"+t+">"+e+"</h"+t+">\n"},i.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},i.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"</"+r+">\n"},i.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},i.prototype.checkbox=function(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"'+(this.options.xhtml?" /":"")+"> "},i.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},i.prototype.table=function(e,t){return t&&(t="<tbody>"+t+"</tbody>"),"<table>\n<thead>\n"+e+"</thead>\n"+t+"</table>\n"},i.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},i.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"</"+n+">\n"},i.prototype.strong=function(e){return"<strong>"+e+"</strong>"},i.prototype.em=function(e){return"<em>"+e+"</em>"},i.prototype.codespan=function(e){return"<code>"+e+"</code>"},i.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},i.prototype.del=function(e){return"<del>"+e+"</del>"},i.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(h(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return n}this.options.baseUrl&&!g.test(e)&&(e=u(this.options.baseUrl,e));try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return n}var s='<a href="'+a(e)+'"';return t&&(s+=' title="'+t+'"'),s+=">"+n+"</a>"},i.prototype.image=function(e,t,n){this.options.baseUrl&&!g.test(e)&&(e=u(this.options.baseUrl,e));var r='<img src="'+e+'" alt="'+n+'"';return t&&(r+=' title="'+t+'"'),r+=this.options.xhtml?"/>":">"},i.prototype.text=function(e){return e},l.prototype.strong=l.prototype.em=l.prototype.codespan=l.prototype.del=l.prototype.text=function(e){return e},l.prototype.link=l.prototype.image=function(e,t,n){return""+n},l.prototype.br=function(){return""},o.parse=function(e,t){return new o(t).parse(e)},o.prototype.parse=function(e){this.inline=new s(e.links,this.options),this.inlineText=new s(e.links,f({},this.options,{renderer:new l})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},o.prototype.next=function(){return this.token=this.tokens.pop()},o.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},o.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},o.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,h(this.inlineText.output(this.token.text)));case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s="",i="";for(n="",e=0;e<this.token.header.length;e++)n+=this.renderer.tablecell(this.inline.output(this.token.header[e]),{header:!0,align:this.token.align[e]});for(s+=this.renderer.tablerow(n),e=0;e<this.token.cells.length;e++){for(t=this.token.cells[e],n="",r=0;r<t.length;r++)n+=this.renderer.tablecell(this.inline.output(t[r]),{header:!1,align:this.token.align[r]});i+=this.renderer.tablerow(n)}return this.renderer.table(s,i);case"blockquote_start":for(i="";"blockquote_end"!==this.next().type;)i+=this.tok();return this.renderer.blockquote(i);case"list_start":i="";for(var l=this.token.ordered,o=this.token.start;"list_end"!==this.next().type;)i+=this.tok();return this.renderer.list(i,l,o);case"list_item_start":for(i="",this.token.task&&(i+=this.renderer.checkbox(this.token.checked));"list_item_end"!==this.next().type;)i+="text"===this.token.type?this.parseText():this.tok();return this.renderer.listitem(i);case"loose_item_start":for(i="";"list_item_end"!==this.next().type;)i+=this.tok();return this.renderer.listitem(i);case"html":return this.renderer.html(this.token.text);case"paragraph":return this.renderer.paragraph(this.inline.output(this.token.text));case"text":return this.renderer.paragraph(this.parseText())}};var c={},g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function d(){}function f(e){for(var t,n,r=1;r<arguments.length;r++)for(n in t=arguments[r])Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e}function b(e,t){var n=e.replace(/([^\\])\|/g,"$1 |").split(/ +\| */),r=0;if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;r<n.length;r++)n[r]=n[r].replace(/\\\|/g,"|");return n}function m(e,t,r){if(null==e)throw new Error("marked(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");if(r||"function"==typeof t){r||(r=t,t=null);var s,i,l=(t=f({},m.defaults,t||{})).highlight,h=0;try{s=n.lex(e,t)}catch(e){return r(e)}i=s.length;var p=function(e){if(e)return t.highlight=l,r(e);var n;try{n=o.parse(s,t)}catch(t){e=t}return t.highlight=l,e?r(e):r(null,n)};if(!l||l.length<3)return p();if(delete t.highlight,!i)return p();for(;h<s.length;h++)!function(e){"code"!==e.type?--i||p():l(e.text,e.lang,function(t,n){return t?p(t):null==n||n===e.text?--i||p():(e.text=n,e.escaped=!0,void(--i||p()))})}(s[h])}else try{return t&&(t=f({},m.defaults,t)),o.parse(n.lex(e,t),t)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",(t||m.defaults).silent)return"<p>An error occurred:</p><pre>"+a(e.message+"",!0)+"</pre>";throw e}}d.exec=d,m.options=m.setOptions=function(e){return f(m.defaults,e),m},m.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new i,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},m.defaults=m.getDefaults(),m.Parser=o,m.parser=o.parse,m.Renderer=i,m.TextRenderer=l,m.Lexer=n,m.lexer=n.lex,m.InlineLexer=s,m.inlineLexer=s.output,m.parse=m,"undefined"!=typeof module&&"object"==typeof exports?module.exports=m:"function"==typeof define&&define.amd?define(function(){return m}):e.marked=m}(this||("undefined"!=typeof window?window:global)); diff --git a/public/react/public/index.html b/public/react/public/index.html index 166760eab..4fd2c4356 100755 --- a/public/react/public/index.html +++ b/public/react/public/index.html @@ -34,8 +34,9 @@ // location.href = './compatibility' location.href = '/compatibility.html' } - const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); - if (isMobile) { + // const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); + const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase())); + if (isWeiXin) { document.write('<script type="text/javascript" src="/javascripts/wx/jweixin-1.3.0.js"><\/script>'); } </script> diff --git a/public/react/src/App.js b/public/react/src/App.js index ddb8de809..9b85acfa8 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -9,7 +9,7 @@ import { Route, Switch } from 'react-router-dom'; -import axios from 'axios'; + import '@icedesign/base/dist/ICEDesignBase.css'; import '@icedesign/base/index.scss'; @@ -37,7 +37,7 @@ import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles'; import history from './history'; -import {SnackbarHOC, configShareForIndex} from 'educoder' +import {SnackbarHOC} from 'educoder' import {initAxiosInterceptors} from './AppConfig' @@ -303,47 +303,7 @@ class App extends Component { mydisplay:true, }) }; - initWXShare = () => { - if (window.wx) { - const wx = window.wx - const url = '/wechats/js_sdk_signature.json' - const currentUrl = window.location.href.split('#')[0] - // window.encodeURIComponent() - axios.post(url, { - url: window.__testUrl || currentUrl, - }).then((response) => { - console.log('got res') - const data = response.data; - wx.config({ - debug: false, - appId: data.appid, - timestamp: data.timestamp, - nonceStr: data.noncestr, - signature: data.signature, - jsApiList: [ - 'onMenuShareTimeline',// - 'onMenuShareAppMessage', - 'onMenuShareQQ', - 'onMenuShareWeibo', - 'onMenuShareQZone' - ] - }); - wx.ready(function () { - console.log('wx is ready') - configShareForIndex('/') - }); - wx.error(function (res) { - console.log('wx is error') - console.log(res) - //alert(res.errMsg);//错误提示 - - }); - }).catch((error) => { - console.log(error) - }) - } - } disableVideoContextMenu = () => { window.$( "body" ).on( "mousedown", "video", function(event) { if(event.which === 3) { @@ -365,7 +325,6 @@ class App extends Component { }); initAxiosInterceptors(this.props) - this.initWXShare() // // axios.interceptors.response.use((response) => { // // console.log("response"+response); diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 5d2373e84..cc8c7cf5f 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -10,7 +10,7 @@ broadcastChannelOnmessage('refreshPage', () => { }) function locationurl(list){ - debugger + if (window.location.port === "3007") { } else { diff --git a/public/react/src/common/Env.js b/public/react/src/common/Env.js index 283e82c48..c80497509 100644 --- a/public/react/src/common/Env.js +++ b/public/react/src/common/Env.js @@ -3,4 +3,6 @@ export function isDev() { } // const isMobile -export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); \ No newline at end of file +export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); + +// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase())); diff --git a/public/react/src/common/util/ShareUtil.js b/public/react/src/common/util/ShareUtil.js index 24fffbf15..e591effaf 100644 --- a/public/react/src/common/util/ShareUtil.js +++ b/public/react/src/common/util/ShareUtil.js @@ -1,4 +1,5 @@ -const host = window.location.host +import axios from 'axios' +const host = window.location.protocol + '//' + window.location.host const wx = window.wx function share(shareData) { try { @@ -11,7 +12,47 @@ function share(shareData) { console.log(e) } } +const urlDoneMap = {} +function requestForSignatrue (callback) { + const currentUrl = window.location.href.split('#')[0] + if (window.wx && !urlDoneMap[currentUrl]) { + const wx = window.wx + const url = '/wechats/js_sdk_signature.json' + urlDoneMap[currentUrl] = true + // window.encodeURIComponent() + axios.post(url, { + url: window.__testUrl || currentUrl, + }).then((response) => { + console.log('got res') + const data = response.data; + wx.config({ + debug: false, + appId: data.appid, + timestamp: data.timestamp, + nonceStr: data.noncestr, + signature: data.signature, + jsApiList: [ + 'onMenuShareTimeline',// + 'onMenuShareAppMessage', + 'onMenuShareQQ', + 'onMenuShareWeibo', + 'onMenuShareQZone' + ] + }); + wx.ready(function () { + callback && callback() + }); + wx.error(function (res) { + console.log('wx is error') + console.log(res) + //alert(res.errMsg);//错误提示 + }); + }).catch((error) => { + console.log(error) + }) + } +} /** 实践课程 平台提供涵盖基础入门、案例实践和创新应用的完整实训项目体系,通过由浅入深的实训路径,帮助学生快速提升实战能力。 实训项目 覆盖不同专业的IT实验和实训,每周更新,无需配置本机实验环境,随时随地开启企业级真实实训。 @@ -19,60 +60,72 @@ function share(shareData) { 单个课程和实训 获取课程/实训的简介 该课程或者实训展示的缩略图 */ -export function configShareForIndex (path) { - if (!wx) return; - var shareData = { - title: 'EduCoder - 首页', - desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台,提供企业级工程实训,以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动,将传统的知识传授和时兴的工程实战一体化。', - link: host + (path || ''), - imgUrl: window.__testImageUrl - || host + '/react/build/images/share_logo_icon.jpg' - }; - share(shareData) +export function configShareForIndex (path) { + requestForSignatrue(() => { + var shareData = { + title: 'EduCoder - 首页', + desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台,提供企业级工程实训,以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动,将传统的知识传授和时兴的工程实战一体化。', + link: host + (path || ''), + 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) + requestForSignatrue(() => { + console.log('configShareForPaths', host) + 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) + requestForSignatrue(() => { + console.log('configShareForShixuns', host) + + 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) + requestForSignatrue(() => { + console.log('configShareForCourses', host) + + 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) + requestForSignatrue(() => { + console.log('configShareForCustom', host) + + var shareData = { + title: title, + desc: desc, + link: `${host}/${path}`, + imgUrl: imgUrl || window.__testImageUrl + || host + '/react/build/images/share_logo_icon.jpg' + }; + share(shareData) + }) } diff --git a/public/react/src/context/TPIContextProvider.js b/public/react/src/context/TPIContextProvider.js index 2d58140e6..ee01c3c72 100644 --- a/public/react/src/context/TPIContextProvider.js +++ b/public/react/src/context/TPIContextProvider.js @@ -174,7 +174,7 @@ class TPIContextProvider extends Component { } let testPath = '' if (window.location.port == 3007) { - testPath = 'http://pre-newweb.educoder.net' + testPath = 'http://test-newweb.educoder.net' } // var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time` var url = `${testPath}/api/tasks/${ game.identifier }/cost_time` diff --git a/public/react/src/modules/courses/ListPageIndex.js b/public/react/src/modules/courses/ListPageIndex.js index e025004e0..c16959ab9 100644 --- a/public/react/src/modules/courses/ListPageIndex.js +++ b/public/react/src/modules/courses/ListPageIndex.js @@ -93,13 +93,13 @@ class ListPageIndex extends Component{ } componentDidMount(){ - console.log("77"); + // console.log("77"); var yslGuideone = window.localStorage.getItem('yslGuideone'); - console.log("78"); - console.log(yslGuideone); + // console.log("78"); + // console.log(yslGuideone); try { if (yslGuideone === "true") { - console.log("true 字符串"); + // console.log("true 字符串"); this.setState({ yslGuideone:true, }) @@ -107,7 +107,7 @@ class ListPageIndex extends Component{ this.setState({ yslGuideone:false, }); - console.log("false 字符串"); + // console.log("false 字符串"); } }catch (e) { console.log(e); @@ -133,8 +133,7 @@ class ListPageIndex extends Component{ window.localStorage.setItem('yslGuideone', bool); try { if (bool === "true") { - console.log("115"); - console.log("true 字符串"); + this.setState({ yslGuideone:true, }) @@ -142,11 +141,10 @@ class ListPageIndex extends Component{ this.setState({ yslGuideone:false, }); - console.log("124"); - console.log("false 字符串"); + } }catch (e) { - console.log(e); + // console.log(e); this.setState({ yslGuideone:false, }); diff --git a/public/react/src/modules/courses/coursesPublic/NewShixunModel.js b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js new file mode 100644 index 000000000..fbb97cbb5 --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js @@ -0,0 +1,555 @@ +import React,{Component} from 'react'; +import { Modal,Checkbox,Select,Input,Tooltip,Spin,Icon,Drawer,Dropdown,Menu,Breadcrumb,Pagination,Button,notification} from "antd"; +import axios from'axios'; +import NoneData from "../coursesPublic/NoneData"; +import './Newshixunmodel.css'; +const Search = Input.Search; +class NewShixunModel extends Component{ + constructor(props){ + super(props) + this.state={ + shixun_list:undefined, + shixuns_count:undefined, + Grouplist:[], + allGrouplist:[{page:1,list:[]}], + page:1, + type:'all', + status:'all', + keyword:undefined, + order:'desc', + diff:0, + limit:15, + } + } + componentDidMount() { + let{page,type,keyword,order,diff,limit,status}=this.state; + this.getdatalist(page,type,status,keyword,order,diff,limit) + } + + getdatalist=(page,type,newstatus,keyword,order,diff,limit,pagetype)=>{ + this.setState({ + isspinning:true + }) + let status=this.props.statustype===undefined?newstatus:'published'; + let url="/shixun_lists.json" + axios.get(url,{params:{ + page, + type, + status, + keyword, + order, + diff, + limit + }}).then((response) => { + if(response.data){ + if(pagetype===undefined){ + this.setState({ + shixun_list:response.data.shixun_list, + shixuns_count:response.data.shixuns_count, + Grouplist:[], + isspinning:false + }) + }else if(pagetype==="pagetype"){ + this.setState({ + shixun_list:response.data.shixun_list, + shixuns_count:response.data.shixuns_count, + isspinning:false + }) + } + + } + }).catch((error) => { + this.setState({ + isspinning:false + }) + }) + } + + DropdownClick=(diff)=>{ + this.setState({ + diff:diff + }) + let{page,type,status,keyword,order,limit}=this.state; + this.getdatalist(page,type,status,keyword,order,diff,limit) + } + + ItsCourse=(item)=>{ + return <Menu> + {item.map((list,key)=>{ + return( + <Menu.Item key={key} id={list.id}> + <a target="_blank" href={`/paths/${list.id}`} className={"newshixun500"} title={list.name}>{list.name}</a> + </Menu.Item> + ) + })} + </Menu> + } + + getGrouplist=(Grouplist)=>{ + let {page,allGrouplist}=this.state; + let newallGrouplist=allGrouplist; + var a=newallGrouplist.find((value,index,arr)=>{ + return value.page==page + }); + + if(a!=undefined){ + newallGrouplist.map((item,key)=>{ + if(item.page===page){ + item.list=Grouplist + } + }) + } + + + let newGrouplist=[]; + + newallGrouplist.map((item,key)=>{ + item.list.map((items,ke)=>{ + newGrouplist.push(items) + }) + }) + + + this.setState({ + Grouplist: newGrouplist, + allGrouplist:newallGrouplist + }) + } + + PaginationCourse=(pageNumber)=>{ + let {allGrouplist}=this.state; + let newallGrouplist=allGrouplist; + var v=newallGrouplist.find((value,index,arr)=>{ + return value.page==pageNumber + }); + + if(v===undefined){ + newallGrouplist.push({page:pageNumber,list:[]}) + } + + let{type,status,keyword,order,diff,limit}=this.state; + this.getdatalist(pageNumber,type,status,keyword,order,diff,limit,"pagetype") + this.setState({ + page:pageNumber, + allGrouplist:newallGrouplist + }) + + } + + belongto=(value)=>{ + this.setState({ + type:value, + keyword:undefined, + page:1 + }) + let{status,order,diff,limit}=this.state; + this.getdatalist(1,value,status,undefined,order,diff,limit) + } + + updatedlist=(order)=>{ + + if(order==="desc"){ + this.setState({ + order:"asc" + }) + let{type,page,status,keyword,diff,limit}=this.state; + this.getdatalist(page,type,status,keyword,"asc",diff,limit) + }else{ + this.setState({ + order:"desc" + }) + let{type,page,status,keyword,diff,limit}=this.state; + this.getdatalist(page,type,status,keyword,"desc",diff,limit) + } + + } + + setdatafunsval=(e)=>{ + this.setState({ + keyword:e.target.value + }) + } + + setdatafuns=(value)=>{ + + this.setState({ + keyword:value, + type:undefined, + page:1, + status:'all', + order:'desc', + diff:0, + limit:15, + }) + this.getdatalist(1,undefined,'all',value,'desc',0,15) + } + + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } + savecouseShixunModal=()=>{ + + this.setState({ + hometypepvisible:true + }) + let {coursesId}=this.props; + let{Grouplist}=this.state; + if(Grouplist.length===0){ + this.setState({ + hometypepvisible:false + }) + this.showNotification("请先选择实训") + return + } + + if (this.props.chooseShixun) { + if(Grouplist.length>1){ + this.setState({ + hometypepvisible:false + }) + this.showNotification("试卷选择的实训数不能大于1") + return + } + this.props.chooseShixun(Grouplist) + this.setState({ + hometypepvisible:false + }) + return; + } + + if (this.props.pathShixun) { + this.setState({ + hometypepvisible:false + }) + this.props.pathShixun(Grouplist) + return; + } + let url="/courses/"+coursesId+"/homework_commons/create_shixun_homework.json"; + axios.post(url, { + category_id:this.props.category_id===null||this.props.category_id===undefined?undefined:parseInt(this.props.category_id), + shixun_ids:Grouplist, + } + ).then((response) => { + if(response.data.status===-1){ + // this.props.showNotification(response.data.message) + + }else{ + // this.props.courseshomeworkstart(response.data.category_id,response.data.homework_ids) + this.showNotification("操作成功") + this.props.homeworkupdatalists(this.props.Coursename,this.props.page,this.props.order); + this.props.hideNewShixunModelType() + + } + this.setState({ + hometypepvisible:false + }) + // category_id: 3 + // homework_ids: (5) [9171, 9172, 9173, 9174, 9175] + }).catch((error) => { + console.log(error) + this.setState({ + hometypepvisible:false + }) + }) + } + + poststatus=(status)=>{ + this.setState({ + status:status + }) + let{page,type,keyword,order,diff,limit}=this.state; + this.getdatalist(page,type,status,keyword,order,diff,limit) + } + + render() { + + let {diff,Grouplist,status,shixun_list,shixuns_count,page,type,order}=this.state; + // let {visible,patheditarry}=this.props; + // console.log(Grouplist) + // console.log(allGrouplist) + const statusmenus=( + <Menu className="menus"> + <Menu.Item> + <a className={status==="all"?"color-blue":""} onClick={()=>this.poststatus("all")}> + 所有 + </a> + </Menu.Item> + + <Menu.Item > + <a className={status==="published"?"color-blue":""} onClick={()=>this.poststatus("published")} > + 已发布 + </a> + </Menu.Item> + + <Menu.Item> + <a className={status==="unpublished"?"color-blue":""} onClick={()=>this.poststatus("unpublished")}> + 未发布 + </a> + </Menu.Item> + + </Menu> + ); + const menus = ( + <Menu className="menus"> + <Menu.Item> + <a className={diff===0?"color-blue":""} onClick={()=>this.DropdownClick(0)}> + 所有 + </a> + </Menu.Item> + + <Menu.Item > + <a className={diff===1?"color-blue":""} onClick={()=>this.DropdownClick(1)} > + 初级 + </a> + </Menu.Item> + + <Menu.Item> + <a className={diff===2?"color-blue":""} onClick={()=>this.DropdownClick(2)}> + 中级 + </a> + </Menu.Item> + + <Menu.Item> + <a className={diff===3?"color-blue":""} onClick={()=>this.DropdownClick(3)}> + 高级 + </a> + </Menu.Item> + + <Menu.Item> + <a className={diff===4?"color-blue":""} onClick={()=>this.DropdownClick(4)}> + 顶级 + </a> + </Menu.Item> + </Menu> + ); + + + + return( + + <div> + <style> + { + `body{ overflow: hidden !important; } + .ant-drawer-content{ overflow:auto !important; background: #f5f5f5; } + .yslbottomsj{position: absolute;bottom: -8px;} + ` + } + </style> + + <Drawer + placement="bottom" + closable={false} + destroyOnClose={true} + visible={this.props.NewShixunModelType} + height={'100%'} + > + <Spin spinning={this.state.isspinning}> + <div className={"clearfix educontent pr"}> + + <div className={"square-list clearfix"}> + + <div className="newshixunheadersear"> + <div style={{height:"53px"}}></div> + <Search + style={{ width: "800px"}} + className="packinput" + placeholder="实训信息 / 院校名称 / 创建者" + value={this.state.keyword} + enterButton={<span>搜索</span>} + onInput={(e)=>this.setdatafunsval(e)} + onSearch={ (value)=>this.setdatafuns(value)} /> + </div> + + <div className="clearfix font-12 mt30"> + + <div className="font-12 ml5 fl"> + + <span className="fl color-grey-9 mr20">已选 <span className={"color-blue"}>{Grouplist.length}</span> 个实训</span> + <span className="fl color-grey-9 mr20">共 <span className={"color-blue"}>{shixuns_count===undefined?"":shixuns_count}</span> 个实训</span> + + <span className="fl color-grey-9 pointer mr30"> + <a className={" color-grey-6"} onClick={()=>this.updatedlist(order)}>学习人数</a> + <sapn className="relativef ml5 " > + <i className={order==="desc"?"iconfont icon-sanjiaoxing-up font-12 ntopsj color-grey-9 color-blue":"iconfont icon-sanjiaoxing-up font-12 ntopsj color-grey-9"}></i> + <i className={order==="asc"?"iconfont icon-sanjiaoxing-down font-12 nyslbottomsj color-grey-9 color-blue":"iconfont icon-sanjiaoxing-down font-12 nyslbottomsj color-grey-9"}></i> + </sapn> + </span> + + {this.props.statustype===undefined?<Dropdown overlay={statusmenus}> + <a className="ant-dropdown-link color-grey-6 mr20"> + {status==='all'?"发布状态":status==='published'?"已发布":status==="unpublished"?"未发布":""}<Icon type="down" className={"color-grey-6"}/> + </a> + </Dropdown>:""} + + <Dropdown overlay={menus}> + <a className="ant-dropdown-link color-grey-6"> + {diff===0?"难度":diff===1?"初级":diff===2?"中级":diff===3?"高级":diff===4?"顶级":""}<Icon type="down" className={"color-grey-6"}/> + </a> + </Dropdown> + </div> + + <div className="font-12 alltopiscright ml25 fr"> + <span className={"fr pointer color-grey-3"} onClick={()=>this.props.hideNewShixunModelType()}>返回</span> + <span className={type==="mine"?"fr mr30 topcsactive pointer color-grey-3 color-blue":"fr mr30 pointer color-grey-3"} onClick={()=>this.belongto("mine")}>我的实训</span> + <span className={type==="all"?"fr mr30 topcsactive pointer color-grey-3 color-blue":"fr mr30 pointer color-grey-3"} onClick={()=>this.belongto("all")}>全部实训</span> + </div> + + </div> + + <Checkbox.Group onChange={this.getGrouplist} value={Grouplist} > + + {shixun_list===undefined?"":shixun_list.length===0?"":shixun_list.map((item,key)=>{ + + return( + <div className="mt20 edu-back-white pd20 relativef newshixunlist" key={key}> + <div className="clearfix"> + <div className="item-body"> + <div className="clearfix ds pr contentSection"> + <Checkbox + value={item.id} + key={item.id} + className="fl task-hide edu-txt-left mt3" + name="shixun_homework[]" + ></Checkbox> + <a target="_blank" href={`/shixuns/${item.identifier}/challenges`} title={item.title} className="ml15 fl font-16 color-dark maxwidth1100" + dangerouslySetInnerHTML={{__html: item.title}} + > + </a> + + <div className="cl"></div> + <style> + { + ` + .newradioStyles{ + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + max-height: 42px; + } + ` + } + </style> + {JSON.stringify(item.description) == "{}"?"":<div className="newshixunmodelmidfont newradioStyles" title={item.description} dangerouslySetInnerHTML={{__html: item.description}}> + </div>} + + {item.challenge_names.length===0?"":<div className="newshixunmodelbotfont"> + {item.challenge_names.map((item,key)=>{ + return( + <span>第{key+1}关:{item}</span> + ) + })} + </div>} + + <div className={"newshixunpd030"}> + <div className="xuxianpro"></div> + </div> + + <div className="color-grey panel-lightgrey fl ml30"> + <style> + {` + .ant-breadcrumb-separator{ + color: #D7D7D7 !important; + } + .panel-lightgrey, .panel-lightgrey span{ + color: #999 !important; + } + .ant-breadcrumb-link{ + margin-right:10px !important; + } + .ant-breadcrumb-separator{ + margin-right:20px !important; + } + `} + </style> + <Breadcrumb separator="|"> + <Breadcrumb.Item>{item.author_name}</Breadcrumb.Item> + <Breadcrumb.Item>{item.author_school_name}</Breadcrumb.Item> + <Breadcrumb.Item>难度系数:{item.level}</Breadcrumb.Item> + <Breadcrumb.Item>学习人数:{item.study_count}</Breadcrumb.Item> + </Breadcrumb> + + </div> + {item.subjects.length===0?"":<Dropdown overlay={()=>this.ItsCourse(item.subjects)}> + <a className="ant-dropdown-link fl ml30 newshixunfont12 color-blue" > + 所属课程<Icon className={"color-blue"} type="down" /> + </a> + </Dropdown>} + + </div> + </div> + </div> + </div> + )}) + } + </Checkbox.Group> + + {shixun_list===undefined||shixuns_count===undefined?"":shixun_list.length===0||shixuns_count===0?"":shixuns_count>15?<div className={" edu-txt-center pd303010"}> + <Pagination + showQuickJumper + defaultCurrent={1} + pageSize={15} + total={shixuns_count===undefined?"":shixuns_count} + current={page} + onChange={this.PaginationCourse} + /> + </div>:""} + { + shixun_list===undefined? + <div className={"minhegiht300"}> + + </div> + :shixun_list.length===0? <NoneData></NoneData>:"" + } + + { + shixun_list===undefined?"":shixun_list.length===0?"":<div className={" edu-txt-center padding20-30"}> + <Button className={"mr20 newshixunmode"} onClick={()=>this.props.hideNewShixunModelType()}>取消</Button> + <Button className={"newshixunmode"} type="primary" onClick={()=>this.savecouseShixunModal()} loading={this.state.hometypepvisible}>确定</Button> + </div>} + + </div> + + </div> + </Spin> + </Drawer> + </div> + + ) + } +} + +export default NewShixunModel; + + +// {JSON.stringify(item.content) == "{}"?<div className="newshixunmodelmidfont newradioStyles" title={item.description} dangerouslySetInnerHTML={{__html: item.description}}> +// </div>:<div className="newshixunmodelbotfont"> +// {item.content.description === undefined || item.content.description===0?"":item.content.description.map((item,key)=>{ +// return( +// <span dangerouslySetInnerHTML={{__html: item}}>{}</span> +// ) +// })} +// </div>} +// +// {JSON.stringify(item.content) == "{}"?item.challenge_names.length===0?"":<div className="newshixunmodelbotfont"> +// {item.challenge_names.map((item,key)=>{ +// return( +// <span>第{key+1}关:{item}</span> +// ) +// })} +// </div>:<div className="newshixunmodelbotfont"> +// {item.content.challenge_names === undefined || item.content.challenge_names===0?"":item.content.challenge_names.map((item,key)=>{ +// return( +// <span dangerouslySetInnerHTML={{__html: item}}>{}</span> +// ) +// })} +// </div>} \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css b/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css new file mode 100644 index 000000000..2e8abce53 --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css @@ -0,0 +1,250 @@ +.searchinput{ + width: 800px; + margin-top: 53px; +} +.newshixunheadersear{ + display: flex; + justify-content: center; +} +.packinput .ant-input{ + height: 55px; + width:663px !important; + font-size: 14px; + /*color: #681616 !important;*/ + border-color: #E1EDF8 !important; + padding-left: 20px; +} + +.packinput .ant-input-group-addon .ant-btn{ + width:137px !important; + font-size: 18px; + height: 53px; + background:rgba(76,172,255,1); + +} +.tabtitle{ + height: 62px !important; + box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15); + border-radius: 6px; + background: #fff; + display: flex; + justify-content: center; +} +.tabtitles2{ + background: #fff; + height: 62px !important; + width: 1200px; +} + +.tabtitless{ + height: 62px !important; + line-height: 62px !important; + +} +.tabtitle1{ + +} +.tabtitle2{ + margin-left: 30px !important; + +} + + +.counttit{ + display: flex; + justify-content: center; +} + +.counttittext{ + text-align: left; + width: 1200px; + height: 18px; + color: #888888; + font-size: 13px; + margin-top: 24px; + + +} +.counttittexts{ + color: #4CACFF !important; + font-size: 13px; +} + +.mainx{ + display: flex; + justify-content: center; + margin-top: 17px; +} +.project-packages-list{ + +} +.project-package-item{ + display: -webkit-flex; + display: flex; + flex-direction:column; + margin-bottom: 20px; + padding: 20px; + background: white; + /* box-shadow: 1px 3px 3px 1px rgba(156,156,156,0.16); */ + +} +.xuxianpro{ + height: 20px; + border-bottom: 1px dashed; + border-color: #EAEAEA; + margin-bottom: 18px; +} +.magr11{ + margin-top: 11px; +} +.highlight{ + color: #4CACFF; +} +.fonttext{ + font-size: 20px; + font-weight:bold; +} + +.fontextcolor{ + color: #777777; +} +.tzbq{ + margin-left: 68px; +} +.tzbqx{ + /* margin-left: 24px; */ +} +.bjyss{ + background: #F8F8F8; +} +.zj{ + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap +} +.ziticor{ + color: #777777; + font-size: 13px; +} +.foohter{ + margin-top: 20px; + display: flex; + flex-direction:row; +} + +.maxwidth1100{ + max-width: 1100px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + font-size: 18px !important; + font-weight: 500; + color: rgba(51,51,51,1) !important; +} + + +.newshixunmodelmidfont{ + font-size: 14px; + font-weight: 400; + color: #999999; + margin-top: 15px; + margin-left: 30px; + max-width: 1100px; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.newshixunmodelbotfont{ + font-size:12px; + font-weight:400; + color:rgba(102,102,102,1); + margin-top: 15px; + margin-left: 30px; +} + +.newshixunlist{ + max-height:227px; + width: 1200px; +} + +.xuxianpro { + height: 20px; + border-bottom: 1px dashed; + border-color: #eaeaea; + margin-bottom: 18px; +} + +.newshixunpd030{ + padding: 0px 30px; +} + +.pd303010{ + padding: 30px 30px 10px; +} + +.newshixunfont12{ + font-size: 12px; + color: rgba(76,172,255,1); + line-height: 21px; +} + +.newshixunmode{ + width: 100px; + height: 38px; + border-radius: 3px; + border: 1px solid rgba(191,191,191,1); +} + +.ntopsj { + position: absolute; + top: -4px; +} + +.nyslbottomsj { + position: absolute; + bottom: -6px; +} + +.inherits .ant-dropdown-menu-item{ + cursor: inherit !important; +} + +.menus{ + width: 91px; + text-align: center; +} + +.newshixunmodelbotfont span{ + display: inline-block; + margin-right: 34px; +} + +.minhegiht300{ + min-height: 300px; +} + +.newshixunlist:hover{ + box-shadow: 1px 6px 16px rgba(156,156,156,0.16); + opacity: 1; + border-radius: 2px; +} + +.newshixun500{ + max-width: 500px; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mt3 { + margin-top: 3px !important; +} + +.highlight{ + color: #4CACFF; +} + diff --git a/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js b/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js index cca75fc86..f4f00e5e0 100644 --- a/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js +++ b/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js @@ -1,120 +1,122 @@ -import React,{ Component } from "react"; -import { Modal,Checkbox,Select,Input,Tooltip} from "antd"; -import axios from'axios'; -import ShixunModal from './ShixunModal' - -const Option = Select.Option; -const Search = Input.Search; -class ShixunChooseModal extends Component{ - constructor(props){ - super(props); - this.state={ - shixunmodal: false, - hometypepvisible: false, - } - } - setVisible = (visible) => { - if (visible) { - this.createCommonWork() - } else { - this.setState({ shixunmodal: visible }) - } - } - hidecouseShixunModal = () => { - this.setVisible(false) - } - componentDidMount() { - - - } - funshixunmodallist=(search,type,loading,page)=>{ - let{newshixunmodallist}=this.state; - let newshixunmodallists=[] - if(page>1){ - newshixunmodallists=newshixunmodallist; - } - this.setState({ - hometypepvisible:loading - }) - let coursesId=this.props.match.params.coursesId; - let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; - - axios.get(url, { - params: { - search: search, - type:type, - page:page - } - }).then((result)=>{ - if(result.status===200){ - - let shixun_list=result.data.shixun_list; - for(var i=0; i<shixun_list.length;i++){ - newshixunmodallists.push(shixun_list[i]) - } - this.setState({ - shixunmodal:true, - shixunmodallist:result.data, - newshixunmodallist:newshixunmodallists, - hometypepvisible:false - }) - } - }).catch((error)=>{ - console.log(error); - }) - } - funpatheditarry=(list)=>{ - this.setState({ - patheditarry:list - }) - } - createCommonWork=()=>{ - - this.setState({ - hometypepvisible:true, - patheditarry:[] - }) - - let coursesId=this.props.match.params.coursesId; - let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; - - axios.get(url).then((result)=>{ - if(result.status===200){ - this.setState({ - shixunmodal:true, - shixunmodallist:result.data, - hometypepvisible:false, - newshixunmodallist:result.data.shixun_list, - }) - } - }).catch((error)=>{ - console.log(error); - }) - } - render(){ - let {Searchvalue,type,category_id, datas, shixunmodal, shixunmodallist - , hometypepvisible, newshixunmodallist, patheditarry }=this.state; - let {visible}=this.props; - - // console.log(patheditarry) - return( - <ShixunModal - datas={datas} - category_id={this.props.match.params.category_id} - visible={shixunmodal} - shixunmodallist={shixunmodallist} - funshixunmodallist={(search,type,loading,page)=>this.funshixunmodallist(search,type,loading,page)} - hometypepvisible={hometypepvisible} - hidecouseShixunModal={this.hidecouseShixunModal} - newshixunmodallist={newshixunmodallist} - coursesId={this.props.match.params.coursesId} - courseshomeworkstart={(category_id,homework_ids)=> this.props.newhomeworkstart - && this.props.newhomeworkstart(category_id,homework_ids)} - funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)} - patheditarry={patheditarry} - {...this.props} - ></ShixunModal> - ) - } -} +import React,{ Component } from "react"; +import { Modal,Checkbox,Select,Input,Tooltip} from "antd"; +import axios from'axios'; +import NewShixunModel from '../coursesPublic/NewShixunModel'; + +const Option = Select.Option; +const Search = Input.Search; +class ShixunChooseModal extends Component{ + constructor(props){ + super(props); + this.state={ + shixunmodal: false, + hometypepvisible: false, + } + } + setVisible = (visible) => { + // if (visible) { + // this.createCommonWork() + // } else { + // + // } + this.setState({ shixunmodal: visible }) + } + hidecouseShixunModal = () => { + this.setVisible(false) + } + componentDidMount() { + + + } + funshixunmodallist=(search,type,loading,page)=>{ + let{newshixunmodallist}=this.state; + let newshixunmodallists=[] + if(page>1){ + newshixunmodallists=newshixunmodallist; + } + this.setState({ + hometypepvisible:loading + }) + let coursesId=this.props.match.params.coursesId; + let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; + + axios.get(url, { + params: { + search: search, + type:type, + page:page + } + }).then((result)=>{ + if(result.status===200){ + + let shixun_list=result.data.shixun_list; + for(var i=0; i<shixun_list.length;i++){ + newshixunmodallists.push(shixun_list[i]) + } + this.setState({ + shixunmodal:true, + shixunmodallist:result.data, + newshixunmodallist:newshixunmodallists, + hometypepvisible:false + }) + } + }).catch((error)=>{ + console.log(error); + }) + } + funpatheditarry=(list)=>{ + this.setState({ + patheditarry:list + }) + } + createCommonWork=()=>{ + + this.setState({ + hometypepvisible:true, + patheditarry:[] + }) + + let coursesId=this.props.match.params.coursesId; + let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; + + axios.get(url).then((result)=>{ + if(result.status===200){ + this.setState({ + shixunmodal:true, + shixunmodallist:result.data, + hometypepvisible:false, + newshixunmodallist:result.data.shixun_list, + }) + } + }).catch((error)=>{ + console.log(error); + }) + } + render(){ + let {Searchvalue,type,category_id, datas, shixunmodal, shixunmodallist + , hometypepvisible, newshixunmodallist, patheditarry }=this.state; + let {visible}=this.props; + + // console.log(patheditarry) + return( + shixunmodal===true?<NewShixunModel + statustype={'published'} + datas={datas} + category_id={this.props.match.params.category_id} + NewShixunModelType={shixunmodal} + shixunmodallist={shixunmodallist} + funshixunmodallist={(search,type,loading,page)=>this.funshixunmodallist(search,type,loading,page)} + hometypepvisible={hometypepvisible} + hideNewShixunModelType={this.hidecouseShixunModal} + newshixunmodallist={newshixunmodallist} + coursesId={this.props.match.params.coursesId} + courseshomeworkstart={(category_id,homework_ids)=> this.props.newhomeworkstart + && this.props.newhomeworkstart(category_id,homework_ids)} + funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)} + patheditarry={patheditarry} + {...this.props} + ></NewShixunModel>:"" + ) + } +} export default ShixunChooseModal; \ No newline at end of file diff --git a/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js b/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js index 930593c15..f45de9b64 100644 --- a/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js +++ b/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js @@ -77,7 +77,9 @@ class ExerciseReviewAndAnswer extends Component{ exerciseTotalScore:undefined, // 加载效果 - isSpin:false + isSpin:false, + // 调分数组 + ajustSore:undefined } } componentDidUpdate (prevProps) { @@ -190,7 +192,23 @@ class ExerciseReviewAndAnswer extends Component{ user_exercise_status:1, Id:result.data.exercise_answer_user.user_id, exerciseTotalScore:result.data.exercise_answer_user.score, - isSpin:false + isSpin:false, + }) + // 先将未批的简答题放入到调分数组中 + let ajustSore = []; + result.data && result.data.exercise_questions.length>0 && result.data.exercise_questions.map((item,key)=>{ + if( item.question_type == 4 && item.answer_status == 0 ){ + ajustSore.push({ + inputSore:0, + desc:undefined, + id:item.question_id, + position:item.q_position, + setTip:"" + }) + } + }) + this.setState({ + ajustSore }) } }).catch((error)=>{ @@ -227,7 +245,7 @@ class ExerciseReviewAndAnswer extends Component{ } scrollToAnchor=(index)=>{ let name="Anchor_"+index; - console.log($("#Anchor_"+index).scrollTop()); + // console.log($("#Anchor_"+index).scrollTop()); if (index) { // let anchorElement = document.getElementById(name); // if(anchorElement) { anchorElement.scrollIntoView(); } @@ -244,62 +262,115 @@ class ExerciseReviewAndAnswer extends Component{ ) } // 调分 - showSetScore=(key,flag,setId)=>{ + showSetScore=(key,flag,position,type,id)=>{ this.setState( (prevState) => ({ exercise_questions : update(prevState.exercise_questions, {[key]: { setScore: {$set: flag == undefined || flag==false ? true : false}}}) }),()=>{ - if (setId && (flag == undefined || flag==false)) { - $("html").animate({ scrollTop: $("#Anchor_"+setId).offset().top - 150 }) + if (position && type && (flag == undefined || flag==false)) { + $("#input_"+position+"_"+type).focus(); + $("html").animate({ scrollTop: $("#Anchor_"+position+"_"+type).offset().top - 150 }); + if(id){ + let { ajustSore } = this.state; + let obj = ajustSore.filter(obj => obj.id === id).length > 0; + if(!obj){ + ajustSore.push({ + id, + inputSore:0, + desc:undefined, + position:position, + setTip:"" + }) + } + } } } ) - this.setState({ - score:undefined - }) + // this.setState({ + // score:undefined + // }) } - inputScore=(value)=>{ - + inputScore=(value,id)=>{ + let { ajustSore } = this.state; + var index = ajustSore.map(function (item) { return item.id; }).indexOf(id); let reg = /^[0-9]+.?[0-9]*$/; if(reg.test(value)==false){ - this.setState({ - setTip:"请输入数字" - }) + // this.setState({ + // setTip:"请输入数字" + // }) + this.setState( + (prevState) => ({ + ajustSore : update(prevState.ajustSore, {[index]: { setTip: {$set: "请输入数字"}}}) + }) + ) return; }else{ - this.setState({ - setTip:"", - score:value - }) + // this.setState({ + // setTip:"", + // score:value + // }) + this.setState( + (prevState) => ({ + ajustSore : update(prevState.ajustSore, {[index]: { inputSore: {$set: value},setTip:{$set: ""}}}) + }) + ) } } - changeScoreReasons=(e)=>{ - console.log(e.target.value); - this.setState({ - setScoreReason:e.target.value - }) + changeScoreReasons=(e,id)=>{ + // console.log(e.target.value); + // this.setState({ + // setScoreReason:e.target.value + // }) + let value = e.target.value; + let { ajustSore } = this.state; + var index = ajustSore.map(function (item) { return item.id; }).indexOf(id); + this.setState( + (prevState) => ({ + ajustSore : update(prevState.ajustSore, {[index]: { desc: {$set: value}}}) + }) + ) } //确认调分 - setAction=(key,q_id,maxScore)=>{ - - let{ score,setScoreReason ,setTip }=this.state; + setAction=(key,q_id,maxScore,oldScore)=>{ + let {ajustSore}=this.state; + let list = ajustSore.filter(obj => obj.id == q_id); + let index = ajustSore.map(function (item) { return item.id; }).indexOf(q_id); + + let score = list[0].inputSore; + let setScoreReason = list[0].desc; + let{ setTip }=this.state; if(!score && score != 0){ - this.setState({ - setTip:"请输入分数" - }) + // this.setState({ + // setTip:"请输入分数" + // }) + this.setState( + (prevState) => ({ + ajustSore : update(prevState.ajustSore, {[index]: { setTip: {$set: "请输入分数"}}}) + }) + ) return; } if(score < 0){ - this.setState({ - setTip:"分数必须大于或者等于0" - }) + // this.setState({ + // setTip:"分数必须大于或者等于0" + // }) + this.setState( + (prevState) => ({ + ajustSore : update(prevState.ajustSore, {[index]: { setTip: {$set: "分数必须大于或者等于0"}}}) + }) + ) return; } if(score > maxScore){ - this.setState({ - setTip:"分数不能大于当前题目的分数" - }) + // this.setState({ + // setTip:"分数不能大于当前题目的分数" + // }) + this.setState( + (prevState) => ({ + ajustSore : update(prevState.ajustSore, {[index]: { setTip: {$set: "分数不能大于当前题目的分数"}}}) + }) + ) return; } if(setTip==""){ @@ -311,21 +382,26 @@ class ExerciseReviewAndAnswer extends Component{ }).then((result)=>{ if(result.status==200){ this.props.showNotification('调分成功'); - console.log(this.state.exercise_questions); - let statusScore = score==0 ? 0 : score > 0 && score < maxScore ? 2 : 1; - console.log(statusScore); - this.setState( - (prevState) => ({ - exercise_questions : update(prevState.exercise_questions, {[key]: { user_score: {$set: score},answer_status : {$set: statusScore},question_comments:{$set:result.data.question_comments} }}), - }) - ) - console.log(this.state.exercise_questions); - this.setState({ - score:undefined, - setTip:"", - setScoreReason:undefined - }) - this.showSetScore(key,true); + this.getInfo(); + // let statusScore = score==0 ? 0 : score > 0 && score < maxScore ? 2 : 1; + + // this.setState( + // (prevState) => ({ + // exercise_questions : update(prevState.exercise_questions, {[key]: { user_score: {$set: parseFloat(score).toFixed(1)},answer_status : {$set: statusScore},question_comments:{$set:result.data.question_comments} }}), + // }) + // ) + + // this.setState( + // (prevState) => ({ + // ajustSore : update(prevState.ajustSore, {[index]: { desc: {$set: undefined},inputSore:{ $set:undefined }}}) + // }) + // ) + // let {exerciseTotalScore} = this.state; + // let newScore = parseFloat(parseFloat(exerciseTotalScore)+parseFloat(score)-parseFloat(oldScore)).toFixed(1); + // this.setState({ + // exerciseTotalScore:newScore + // }) + // this.showSetScore(key,true); } }).catch((error)=>{ console.log(error); @@ -518,12 +594,13 @@ class ExerciseReviewAndAnswer extends Component{ ModalSave, Loadtype, exerciseTotalScore, - isSpin + isSpin, + ajustSore }=this.state let isAdmin = this.props.isAdmin(); let isStudent =this.props.isStudent(); const { current_user } = this.props - console.log(data&&data.exercise.user_name) + // console.log(data&&data.exercise.user_name) return( <div className="newMain" style={{paddingTop:"0px"}}> <Spin size="large" spinning={isSpin}> @@ -709,6 +786,7 @@ class ExerciseReviewAndAnswer extends Component{ <div> { exercise_questions && exercise_questions.map((item,key)=>{ + let list = ajustSore && ajustSore.filter(obj => obj.id === item.question_id); return( <div className="bor-top-greyE pt30 pb30" id={"Anchor_"+parseInt(key+1)}> <p className="clearfix font-16 pl30 pr30"> @@ -716,32 +794,32 @@ class ExerciseReviewAndAnswer extends Component{ <span className="fr"> { // 填空(一直都有调分),和简答题调分:老师身份 已经评分的才能出现调分按钮 - isAdmin && ((parseInt(item.answer_status) != 0 && item.question_type == 4) || item.question_type == 3) ? - <WordsBtn style="blue" className="mr20 font-16 fl" onClick={()=>this.showSetScore(key,item.setScore,item.q_position+"_"+item.question_type)}>调分</WordsBtn>:"" + isAdmin && ((parseInt(item.answer_status) != 0 && item.question_type == 4) || item.question_type == 3 || item.question_type == 1) ? + <WordsBtn style="blue" className="ml20 font-16 fl" onClick={()=>this.showSetScore(key,item.setScore,item.q_position,item.question_type,item.question_id)}>调分</WordsBtn>:"" } { // 简答题,未评分的显示未批 isAdmin && parseInt(item.answer_status) == 0 && item.question_type == 4 ? - <span className="color-red fl mr20">未批</span>:"" + <span className="color-red fl ml20">未批</span>:"" } { // 客观题:老师||学生(试卷已截止且答案公开)显示正确答案 item.question_type < 3 && item.standard_answer_show ? - <span className="font-16 ml20"> + <span className="font-16 fl ml20"> 正确答案:{ item.standard_answer_show } </span>:"" } { //(老师身份且除实训题外) || (学生身份且试卷已经截止)就显示用户当前题目所得分数 ( isAdmin || (isStudent && exercise.exercise_status == 3)) && item.question_type != 5 && item.user_score ? - <span className="font-16 ml20"> + <span className="font-16 ml20 fl"> <span><span className={parseInt(item.answer_status) == 0 ?"color-red":parseInt(item.answer_status) == 1 ?"color-green":"color-orange-tip"}>{item.user_score}</span> 分</span> </span> : "" } { //实训题 ,答题 item.question_type == 5 && - <a href={"/shixuns/"+item.shixun_identifier+"/challenges"} target="_blank" class="font-16 color-blue" target={"_blank"}>实训详情</a> + <a href={"/shixuns/"+item.shixun_identifier+"/challenges"} target="_blank" class="font-16 color-blue fl" target={"_blank"}>实训详情</a> } </span> </p> @@ -825,7 +903,7 @@ class ExerciseReviewAndAnswer extends Component{ { //调分理由部分 - item.question_comments && item.question_comments.comment && (item.question_type == 3 || item.question_type == 4) && + item.question_comments && item.question_comments.comment && (item.question_type == 3 || item.question_type == 4 || item.question_type == 1) && <div className="ml30 mr30 bor-top-greyE pt30 mt20 clearfix df"> <img src={getImageUrl(`images/${item.question_comments.user_picture}`)} width="48" height="48" className="radius mr10"/> <div className="flex1"> @@ -839,7 +917,7 @@ class ExerciseReviewAndAnswer extends Component{ } { // 调分输入部分 - isAdmin && ((item.setScore && item.question_type == 3) || ((item.setScore || parseInt(item.answer_status) == 0) && item.question_type == 4))? + isAdmin && ((item.setScore && item.question_type == 3) || (item.setScore && item.question_type == 1) || ((item.setScore || parseInt(item.answer_status) == 0) && item.question_type == 4))? <div className="ml30 mr30 bor-top-greyE pt20 mt20" id={`${"Anchor_"+item.q_position+"_"+item.question_type}`}> <div className="edu-txt-right"> <span><span className="color-red">*</span>调分:</span> @@ -848,25 +926,26 @@ class ExerciseReviewAndAnswer extends Component{ <InputNumber placeholder="请填写分数" min={0} - max={item.question_score} - value={score} + // max={item.question_score} + value={list && list.length>0 && list[0].inputSore} step={0.1} precision={1} - className={ setTip !="" ? "edu-txt-center winput-115-40 fl mt3 noticeTip inputNumber30" : "edu-txt-center winput-115-40 fl mt3 inputNumber30"} - onChange={this.inputScore} + className={ list && list.length>0 && list[0].setTip !="" ? "edu-txt-center winput-115-40 fl mt3 noticeTip inputNumber30" : "edu-txt-center winput-115-40 fl mt3 inputNumber30"} + onChange={(value)=>this.inputScore(value,item.question_id)} + id={`${"input_"+item.q_position+"_"+item.question_type}`} ></InputNumber> <span className="ml5">分</span> { parseInt(item.answer_status) == 0 && item.question_type == 4 ? <span className="color-red ml10 font-16">未评分</span> : '' } - <ActionBtn style="blue" className="middle ml20" onClick={()=>this.setAction(key,item.question_id,item.question_score)}>确认</ActionBtn> + <ActionBtn style="blue" className="middle ml20" onClick={()=>this.setAction(key,item.question_id,item.question_score,item.user_score)}>确认</ActionBtn> </p> { - setTip !="" ? <p className="color-red edu-txt-left">{setTip}</p> :"" + list && list.length > 0 && list[0].setTip !="" ? <p className="color-red edu-txt-left">{ list[0].setTip }</p> :"" } </li> </div> - <Textarea className="winput-100-150 mt20" value={setScoreReason} style={{height:"180px"}} maxLength="100" onChange={this.changeScoreReasons} placeholder="请您输入评语,最大限制100个字符"></Textarea> + <Textarea className="winput-100-150 mt20" value={list && list.length>0 && list[0].desc} style={{height:"180px"}} maxLength="100" onChange={(e)=>this.changeScoreReasons(e,item.question_id)} placeholder="请您输入评语,最大限制100个字符"></Textarea> </div>:"" } </div> diff --git a/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js b/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js index 967a6ca61..8254b148e 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js @@ -35,10 +35,15 @@ class ShixunWorkDetails extends Component { } }).then((result) => { if (result.status === 200) { - this.setState({ - data:result.data, - spinning:false - }) + if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) { + + }else{ + this.setState({ + data:result.data, + spinning:false + }) + } + } }).catch((error) => { console.log(error) @@ -50,7 +55,33 @@ class ShixunWorkDetails extends Component { shixuntypes:type[3] }) } + updatas=()=>{ + this.setState({ + spinning:true + }) + let homeworkid=this.props.match.params.homeworkid; + let userid=this.props.match.params.userid; + let url = "/homework_commons/"+homeworkid+"/code_review_detail.json"; + axios.get(url,{ + params: { + user_id:userid, + } + }).then((result) => { + if (result.status === 200) { + if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) { + }else{ + this.setState({ + data:result.data, + spinning:false + }) + } + + } + }).catch((error) => { + console.log(error) + }) + } goback=(sum)=>{ // let{data}=this.state // if(sum===1){ @@ -102,14 +133,18 @@ class ShixunWorkDetails extends Component { <span className="fl color-orange font-14">非编程类型任务,不参与查重</span> <span className="fr mt4"> <span className={"color656565"}>被查作品:</span> - <span className={"mr20"}>{data&&data.username}</span> - <span className={"color-orange"}>{data&&data.final_score}分</span> + <span className={"mr50"}><span className={"color-orange"}>{data&&data.username}</span></span> + {data&&data.eff_score===null||data&&data.eff_score===undefined||data&&data.eff_score_full===null||data&&data.eff_score_full===undefined?"":<span className={"mr50"}>效率分:<span className={"color-orange"}>{data&&data.eff_score}</span>/{data&&data.eff_score_full}</span>} + <span className={""}>最终成绩:<span className={"color-orange"}>{data&&data.final_score}</span>分</span> </span> </div> <div className="stud-class-set bor-bottom-greyE"> <div className="clearfix edu-back-white poll_list"> <ShixunCustomsPass + {...this.props} + {...this.state} + updatas={()=>this.updatas()} data={data} /> </div> diff --git a/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js b/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js index 8ffa8a1dd..0b5b04cfc 100644 --- a/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js +++ b/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js @@ -1,10 +1,10 @@ import React, {Component} from "react"; import {WordsBtn} from 'educoder'; -import {Table} from "antd"; +import {Table,InputNumber} from "antd"; import {Link,Switch,Route,Redirect} from 'react-router-dom'; import moment from 'moment'; import { MonacoDiffEditor } from 'react-monaco-editor'; - +import axios from 'axios'; class ShixunCustomsPass extends Component { constructor(props) { @@ -18,10 +18,51 @@ class ShixunCustomsPass extends Component { componentDidMount() { } + editgame_scores=(e,id,maxsum,code_rate,copy_user_id)=>{ + + let{datas}=this.state; + let newdatas=datas; + let score=e.target.value; + + if(score!=null&&score!=undefined&&score!=""){ + if(score<0){ + this.props.showNotification("不能小于0"); + this.setState({ + customsids:id + }) + }else if(score>maxsum){ + this.props.showNotification(`不能大于关卡分值${maxsum}`); + this.setState({ + customsids:id + }) + }else{ + let work_id=this.props.data.work_id; + let url=`/student_works/${work_id}/adjust_review_score.json` + axios.post(url,{ + type:"review", + score:score, + challenge_id:id, + code_rate:code_rate, + copy_user_id:copy_user_id + }).then((result)=>{ + if(result.data.status===0){ + this.props.updatas(); + this.props.showNotification(result.data.message); + }else{ + this.props.showNotification(result.data.message); + } + }).catch((error)=>{ + }) + } + }else{ + this.props.showNotification("调分为空将不会修改之前的分数"); + } + } render() { let {data}=this.props; - console.log(data) + let {customsids}=this.state; + // console.log(data) let datas=[]; data&&data.challenge_list.forEach((item,key)=>{ @@ -33,6 +74,8 @@ class ShixunCustomsPass extends Component { finishtime:item.copy_username, elapsedtime:item.copy_end_time===null?"无":item.copy_end_time===undefined?"无":item.copy_end_time===""?"无":moment(item.copy_end_time).format('YYYY-MM-DD HH:mm:ss'), empvalue:item.code_rate, + challenge_id:{id:item.id}, + copy_user_id:item.copy_user_id // adjustmentminute:asdasd }) }) @@ -112,6 +155,22 @@ class ShixunCustomsPass extends Component { render: (text, record) => ( <span className={"color-grey-9"}> {record.elapsedtime} + </span> + ), + },{ + title: '调分', + key: 'adjustmentminute', + dataIndex: 'adjustmentminute', + + render: (text, record) => ( + <span> + <a> + {record.copy_user_id===null?"":<InputNumber size="small" className={customsids===record.challenge_id.id?"bor-red":""} defaultValue={record.evaluating.final_score} + onBlur={(e) => this.editgame_scores(e,record.challenge_id.id,record.evaluating.all_score,record.empvalue,record.copy_user_id)} + // min={0} max={record.game_scores.game_score_full} + />} + </a> + {/*<a style={{textAlign: "center"}} className="color-blue font-14 mr20">查看</a>*/} </span> ), }, { @@ -138,7 +197,15 @@ class ShixunCustomsPass extends Component { // }, - + if(this.props.isAdmin()===false){ + columns.some((item,key)=> { + if (item.title === "调分") { + columns.splice(key, 1) + return true + } + } + ) + } return ( <div> @@ -177,6 +244,9 @@ class ShixunCustomsPass extends Component { .customsPass{ text-align: left !important; } + .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 16px 12px; + } `} </style> {datas===undefined?"":<Table diff --git a/public/react/src/modules/courses/shixunHomework/shixunHomework.js b/public/react/src/modules/courses/shixunHomework/shixunHomework.js index a2cd5a938..55dfac7fc 100644 --- a/public/react/src/modules/courses/shixunHomework/shixunHomework.js +++ b/public/react/src/modules/courses/shixunHomework/shixunHomework.js @@ -6,6 +6,7 @@ import axios from'axios'; import HomeworkModal from "../coursesPublic/HomeworkModal"; import ShixunModal from "../coursesPublic/ShixunModal"; import PathModal from "../coursesPublic/PathModal"; +import NewShixunModel from '../coursesPublic/NewShixunModel'; import AddcoursesNav from "../coursesPublic/AddcoursesNav"; import Modals from '../../modals/Modals'; import moment from 'moment'; @@ -445,18 +446,18 @@ class ShixunHomework extends Component{ } - // 选用实训 - createCommonWork=()=>{ - - this.setState({ - hometypepvisible:true, - shixunmodal:true, - patheditarry:[], - checkBoxValues:[] - }) - - - } + // // 选用实训 + // createCommonWork=()=>{ + // + // this.setState({ + // hometypepvisible:true, + // shixunmodal:true, + // patheditarry:[], + // checkBoxValues:[] + // }) + // + // + // } // 选用实训路径 createCommonpath=()=>{ @@ -502,9 +503,9 @@ class ShixunHomework extends Component{ // }).then((result)=>{ // if(result.status===200){ // - // let shixun_list=result.data.shixun_list; - // for(var i=0; i<shixun_list.length;i++){ - // newshixunmodallists.push(shixun_list[i]) + // let shixun_lists=result.data.shixun_lists; + // for(var i=0; i<shixun_lists.length;i++){ + // newshixunmodallists.push(shixun_lists[i]) // } // this.setState({ // shixunmodal:true, @@ -540,9 +541,9 @@ class ShixunHomework extends Component{ // }).then((result)=>{ // if(result.status===200){ // - // let shixun_list=result.data.subject_list; - // for(var i=0; i<shixun_list.length;i++){ - // newshixunmodallists.push(shixun_list[i]) + // let shixun_lists=result.data.subject_list; + // for(var i=0; i<shixun_lists.length;i++){ + // newshixunmodallists.push(shixun_lists[i]) // } // this.setState({ // shixunpath:true, @@ -896,6 +897,18 @@ class ShixunHomework extends Component{ this.props.history.push(this.props.current_user.first_category_url); } } + showNewShixunModelType=()=>{ + this.setState({ + NewShixunModelType:true, + patheditarry:[], + checkBoxValues:[] + }) + } + hideNewShixunModelType=()=>{ + this.setState({ + NewShixunModelType:false + }) + } render(){ let { modalname, @@ -931,7 +944,7 @@ class ShixunHomework extends Component{ course_modules, shixunpath, order, - antIcon, + NewShixunModelType, }=this.state; let main_id=this.props.match.params.main_id; @@ -940,6 +953,23 @@ class ShixunHomework extends Component{ return( <React.Fragment > <div> + + {/*新版实训model*/} + {NewShixunModelType===true?<NewShixunModel + {...this.props} + {...this.state} + category_id={this.props.match.params.category_id} + type={'shixuns'} + hideNewShixunModelType={()=>this.hideNewShixunModelType()} + coursesId={this.props.match.params.coursesId} + homeworkupdatalists={(Coursename,page,order)=>this.homeworkupdatalist(Coursename,page,order)} + Coursename={Coursename} + page={page} + order={order} + statustype={'published'} + />:""} + + {/*提示*/} {Modalstype&&Modalstype===true?<Modals modalsType={this.state.Modalstype} @@ -973,23 +1003,23 @@ class ShixunHomework extends Component{ getcourse_groupslist={(id)=>this.getcourse_groupslist(id)} />:""} - {/*选择实训*/} - {shixunmodal===true?<ShixunModal - {...this.props} - {...this.state} - datas={datas} - category_id={this.props.match.params.category_id} - visible={shixunmodal} - shixunmodallist={shixunmodallist} - homeworkupdatalists={(Coursename,page,order)=>this.homeworkupdatalist(Coursename,page,order)} - hometypepvisible={hometypepvisible} - hidecouseShixunModal={this.hidecouseShixunModal} - newshixunmodallist={newshixunmodallist} - coursesId={this.props.match.params.coursesId} - courseshomeworkstart={(category_id,homework_ids)=>this.newhomeworkstart(category_id,homework_ids)} - funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)} - patheditarry={patheditarry} - />:""} + {/*/!*选择实训*!/*/} + {/*{shixunmodal===true?<ShixunModal*/} + {/*{...this.props}*/} + {/*{...this.state}*/} + {/*datas={datas}*/} + {/*category_id={this.props.match.params.category_id}*/} + {/*visible={shixunmodal}*/} + {/*shixunmodallist={shixunmodallist}*/} + {/*homeworkupdatalists={(Coursename,page,order)=>this.homeworkupdatalist(Coursename,page,order)}*/} + {/*hometypepvisible={hometypepvisible}*/} + {/*hidecouseShixunModal={this.hidecouseShixunModal}*/} + {/*newshixunmodallist={newshixunmodallist}*/} + {/*coursesId={this.props.match.params.coursesId}*/} + {/*courseshomeworkstart={(category_id,homework_ids)=>this.newhomeworkstart(category_id,homework_ids)}*/} + {/*funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)}*/} + {/*patheditarry={patheditarry}*/} + {/*/>:""}*/} {shixunmodal===true||shixunpath===true?<style> { @@ -1051,7 +1081,7 @@ class ShixunHomework extends Component{ </span>: <WordsBtn style="blue" onClick={()=>this.editDir(datas&&datas.category_name)} className={"mr30 font-16"}>目录重命名</WordsBtn>:""} {this.props.isAdmin()===true?datas&&datas.category_name===undefined||datas&&datas.category_name===null?<WordsBtn style="blue" className="mr30 font-16" onClick={this.createCommonpath}>选用实践课程</WordsBtn>:"":""} - {this.props.isAdmin()===true?<a className={"btn colorblue font-16"} onClick={()=>this.createCommonWork()}>选用实训</a>:""} + {this.props.isAdmin()===true?<a className={"btn colorblue font-16"} onClick={()=>this.showNewShixunModelType()}>选用实训</a>:""} </li> </p> diff --git a/public/react/src/modules/page/MainContentContainer.js b/public/react/src/modules/page/MainContentContainer.js index 8d6153186..50eacdd4b 100644 --- a/public/react/src/modules/page/MainContentContainer.js +++ b/public/react/src/modules/page/MainContentContainer.js @@ -391,9 +391,16 @@ class MainContentContainer extends Component { // var fileUpdatePromise = this.doFileUpdateRequest(true) // }); // } + + window.addEventListener("beforeunload", this.beforeunload); + } componentWillUnmount() { // window.$(window).off( "unload" ) + window.removeEventListener("beforeunload", this.beforeunload); + } + beforeunload = () => { + this.doFileUpdateRequestOnCodeMirrorBlur() } diff --git a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js index 87e398888..433146b8c 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js +++ b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js @@ -1,10 +1,11 @@ import React, { Component } from 'react'; import {getImageUrl} from 'educoder'; -import {Modal,Input,Checkbox,Tooltip,Spin} from "antd"; +import {Modal,Input,Checkbox,Tooltip,Spin,notification} from "antd"; import { DragDropContext , Draggable, Droppable} from 'react-beautiful-dnd'; import Modals from '../../modals/Modals'; import '../ShixunPaths.css'; import axios from 'axios'; +import NewShixunModel from '../../courses/coursesPublic/NewShixunModel'; const $ = window.$; const Search = Input.Search; @@ -60,36 +61,34 @@ class DetailCardsEditAndAdd extends Component{ this.setState({ selectShixun:true, patheditarry:[], - page:1 }) - this.changeTag(0,""); + // this.changeTag(0,""); } //关闭选择实训弹框 cloasShixunBox =()=>{ this.setState({ selectShixun:false, - page:1, patheditarry:[] }) } - clickShixunchoose=()=>{ - - let{patheditarry,shixuns_listeditlist,shixuns_listedit}=this.state + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } + clickShixunchoose=(patheditarry)=>{ + + let{shixuns_listeditlist,shixuns_listedit}=this.state let newshixuns_listedit=shixuns_listedit; let list=shixuns_listeditlist - if(patheditarry.length===0){ - this.setState({ - Modalstype:true, - Modalstopval:'请选择实训', - cardsModalsave:this.cardsModalsave - }) - - return - } - let url='/paths/append_to_stage.json' axios.post(url,{ shixun_id:patheditarry @@ -98,6 +97,19 @@ class DetailCardsEditAndAdd extends Component{ if(response.data){ let newshixun_lists=response.data.shixun_lists; + for(var j=0; j<newshixuns_listedit.length; j++){ + for(var a=0; a<newshixun_lists.length; a++){ + if(newshixuns_listedit[j].shixun_id===newshixun_lists[a].shixun_id){ + // this.setState({ + // Modalstype:true, + // Modalstopval:'请勿重复选择'+newshixun_lists[a].shixun_name+'实训', + // }) + this.showNotification('请勿重复选择:'+newshixun_lists[a].shixun_name+'实训') + return + } + } + } + for(var z=0; z<newshixun_lists.length; z++){ newshixuns_listedit.push(newshixun_lists[z]); } @@ -148,38 +160,7 @@ class DetailCardsEditAndAdd extends Component{ }) } - //打开选择实训弹框初始化tag标签和列表 - changeTag=(id,search)=>{ - - this.setState({ - ChooseShixunListshixun_list:[], - page:1, - hometypepvisible:true, - }) - let pathId=this.props.pathid; - - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 - if(search!="" && search!=undefined){ - url+="&search="+search; - } - if(id!=0){ - url+="&type="+id; - } - - axios.get(encodeURI(url)).then((result)=>{ - if(result.status===200){ - this.setState({ - ChooseShixunList:result.data, - hometypepvisible:false, - type:id, - ChooseShixunListshixun_list:result.data.shixun_list - }) - } - }).catch((error)=>{ - console.log(error); - }) - } //勾选实训 shixunhomeworkedit=(list)=>{ @@ -307,57 +288,7 @@ class DetailCardsEditAndAdd extends Component{ } - contentViewScrolladd=(e)=>{ - const {ChooseShixunList}=this.state; - //滑动到底判断 - let newscrollTop=parseInt(e.currentTarget.scrollTop); - let allclientHeight=e.currentTarget.clientHeight+newscrollTop; - - if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ - - if(ChooseShixunList.shixun_list.length===0){ - return - }else{ - // console.log("到达底部"); - this.setState({ - hometypepvisible:true - }) - let pathId=this.props.pathid; - let {search,page,type,ChooseShixunListshixun_list}=this.state; - let newpage=page+1; - let newChooseShixunListshixun_list=ChooseShixunListshixun_list; - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage - if(search!="" && search!=undefined){ - url+="&search="+search; - } - if(type!=0){ - url+="&type="+type; - } - axios.get(encodeURI(url)).then((result)=>{ - if(result.status===200){ - let list =result.data.shixun_list; - - for(var i=0; i<list.length; i++){ - newChooseShixunListshixun_list.push(list[i]) - } - this.setState({ - ChooseShixunList:result.data, - hometypepvisible:false, - type:type, - search:search, - page:newpage, - ChooseShixunListshixun_list:newChooseShixunListshixun_list - }) - } - }).catch((error)=>{ - console.log(error); - }) - - } - } - - } onDragEnd (result) { let {shixuns_listedit,shixuns_listeditlist} =this.state; @@ -456,99 +387,13 @@ class DetailCardsEditAndAdd extends Component{ ` } </style>:""} + {selectShixun===true?<NewShixunModel + NewShixunModelType={selectShixun} + hideNewShixunModelType={this.cloasShixunBox} + pathShixun={this.clickShixunchoose} + {...this.props} + ></NewShixunModel>:""} - <Modal - keyboard={false} - title="选择实训" - visible={selectShixun} - closable={false} - footer={null} - width="840px" - destroyOnClose={true} - > - <Spin spinning={hometypepvisible} size="large" style={{marginTop:'15%'}}> - <div className="newupload_conbox"> - <div className="clearfix mb20 shixun_work_div newshixun_tab_div cdefault" style={{"marginRight":"4px"}} id="shixun_tab_div"> - <li className="fl mr5 mt5"> <a onClick={()=>this.changeTag(0,`${search}`)} className={ parseInt(type)===0 ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>全部</a></li> - { - ChooseShixunList && ChooseShixunList.tags.map((item,key)=>{ - return( - <li className="fl mr5 mt5" key={key}> - <a onClick={()=>this.changeTag(`${item.tag_id}`,`${search}`)} className={ parseInt(type) === parseInt(item.tag_id) ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>{item.tag_name}</a> - </li> - ) - }) - } - - - </div> - <div className="clearfix mb20" id="shixun_search_form_div"> - <span className="fl color-grey-9 font-16 mt3"> - <span>共</span> - <span className="color-orange-tip">{ChooseShixunList && ChooseShixunList.shixuns_count}</span> - <span>个实训</span> - </span> - <div className="fr search-new mb0"> - <Search - placeholder="请输入创建者或者实训名称进行搜索" - onInput={this.searchNameInput} - onSearch={()=>this.changeTag(`${type}`,`${search}`)} - style={{width: '115%'}} - ></Search> - </div> - </div> - <ul className="clearfix greybackHead edu-txt-center" style={{marginBottom: '0px'}}> - <li className="fl with40 paddingleft22">实训名称</li> - <li className="fl with30 edu-txt-left">使用院校</li> - <li className="fl with10">使用人数</li> - <li className="fl with10">评价等级</li> - <li className="fl with10"></li> - </ul> - - <style> - { - ` - .over180{min-height: 180px;max-height: 180px;overflow-y: auto} - ` - } - </style> - {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"": <div className="over180 pl20 pr20" - onScroll={this.contentViewScrolladd} - > - <Checkbox.Group style={{ width: '100%' }} onChange={this.shixunhomeworkedit}> - { - ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ - return( - <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> - <li className="fl with40"> - <Checkbox - id={"shixun_input_"+item.shixun_id} - value={item.shixun_id} - key={item.shixun_id} - className="fl task-hide edu-txt-left" - style={{"width":"298px"}} - name="shixun_homework[]" - > - <label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title={item.shixun_name}>{item.shixun_name}</label> - </Checkbox> - </li> - <li className="fl with30 edu-txt-left task-hide paddingl5">{item.school_users}</li> - <li className="fl with10 paddingl10">{item.myshixuns_count}</li> - <li className="fl with10 color-orange-tip paddingl10">{item.preference}</li> - <li className="fl with10"><a className="color-blue" href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">详情</a></li> - </div> - ) - }) - } - </Checkbox.Group> - </div>} - <div className="mt20 marginauto clearfix edu-txt-center"> - <a className="pop_close task-btn mr30 margin-tp26" onClick={this.cloasShixunBox}>取消</a> - <a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.clickShixunchoose}>确定</a> - </div> - </div> - </Spin> - </Modal> </div> {/* 可拖拽选择实训列表*/} @@ -650,4 +495,185 @@ class DetailCardsEditAndAdd extends Component{ ) } } -export default DetailCardsEditAndAdd; \ No newline at end of file +export default DetailCardsEditAndAdd; + + + + +// +// <Modal +// keyboard={false} +// title="选择实训" +// visible={selectShixun} +// closable={false} +// footer={null} +// width="840px" +// destroyOnClose={true} +// > +// <Spin spinning={hometypepvisible} size="large" style={{marginTop:'15%'}}> +// <div className="newupload_conbox"> +// <div className="clearfix mb20 shixun_work_div newshixun_tab_div cdefault" style={{"marginRight":"4px"}} id="shixun_tab_div"> +// <li className="fl mr5 mt5"> <a onClick={()=>this.changeTag(0,`${search}`)} className={ parseInt(type)===0 ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>全部</a></li> +// { +// ChooseShixunList && ChooseShixunList.tags.map((item,key)=>{ +// return( +// <li className="fl mr5 mt5" key={key}> +// <a onClick={()=>this.changeTag(`${item.tag_id}`,`${search}`)} className={ parseInt(type) === parseInt(item.tag_id) ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>{item.tag_name}</a> +// </li> +// ) +// }) +// } +// +// +// </div> +// <div className="clearfix mb20" id="shixun_search_form_div"> +// <span className="fl color-grey-9 font-16 mt3"> +// <span>共</span> +// <span className="color-orange-tip">{ChooseShixunList && ChooseShixunList.shixuns_count}</span> +// <span>个实训</span> +// </span> +// <div className="fr search-new mb0"> +// <Search +// placeholder="请输入创建者或者实训名称进行搜索" +// onInput={this.searchNameInput} +// onSearch={()=>this.changeTag(`${type}`,`${search}`)} +// style={{width: '115%'}} +// ></Search> +// </div> +// </div> +// <ul className="clearfix greybackHead edu-txt-center" style={{marginBottom: '0px'}}> +// <li className="fl with40 paddingleft22">实训名称</li> +// <li className="fl with30 edu-txt-left">使用院校</li> +// <li className="fl with10">使用人数</li> +// <li className="fl with10">评价等级</li> +// <li className="fl with10"></li> +// </ul> +// +// <style> +// { +// ` +// .over180{min-height: 180px;max-height: 180px;overflow-y: auto} +// ` +// } +// </style> +// {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"": <div className="over180 pl20 pr20" +// onScroll={this.contentViewScrolladd} +// > +// <Checkbox.Group style={{ width: '100%' }} onChange={this.shixunhomeworkedit}> +// { +// ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ +// return( +// <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> +// <li className="fl with40"> +// <Checkbox +// id={"shixun_input_"+item.shixun_id} +// value={item.shixun_id} +// key={item.shixun_id} +// className="fl task-hide edu-txt-left" +// style={{"width":"298px"}} +// name="shixun_homework[]" +// > +// <label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title={item.shixun_name}>{item.shixun_name}</label> +// </Checkbox> +// </li> +// <li className="fl with30 edu-txt-left task-hide paddingl5">{item.school_users}</li> +// <li className="fl with10 paddingl10">{item.myshixuns_count}</li> +// <li className="fl with10 color-orange-tip paddingl10">{item.preference}</li> +// <li className="fl with10"><a className="color-blue" href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">详情</a></li> +// </div> +// ) +// }) +// } +// </Checkbox.Group> +// </div>} +// <div className="mt20 marginauto clearfix edu-txt-center"> +// <a className="pop_close task-btn mr30 margin-tp26" onClick={this.cloasShixunBox}>取消</a> +// <a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.clickShixunchoose}>确定</a> +// </div> +// </div> +// </Spin> +// </Modal> +// contentViewScrolladd=(e)=>{ +// const {ChooseShixunList}=this.state; +// //滑动到底判断 +// let newscrollTop=parseInt(e.currentTarget.scrollTop); +// let allclientHeight=e.currentTarget.clientHeight+newscrollTop; +// +// if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ +// +// if(ChooseShixunList.shixun_list.length===0){ +// return +// }else{ +// // console.log("到达底部"); +// this.setState({ +// hometypepvisible:true +// }) +// let pathId=this.props.pathid; +// let {search,page,type,ChooseShixunListshixun_list}=this.state; +// let newpage=page+1; +// let newChooseShixunListshixun_list=ChooseShixunListshixun_list; +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// if(type!=0){ +// url+="&type="+type; +// } +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// let list =result.data.shixun_list; +// +// for(var i=0; i<list.length; i++){ +// newChooseShixunListshixun_list.push(list[i]) +// } +// this.setState({ +// ChooseShixunList:result.data, +// hometypepvisible:false, +// type:type, +// search:search, +// page:newpage, +// ChooseShixunListshixun_list:newChooseShixunListshixun_list +// }) +// } +// }).catch((error)=>{ +// console.log(error); +// }) +// +// } +// +// } +// +// } +// +// //打开选择实训弹框初始化tag标签和列表 +// changeTag=(id,search)=>{ +// +// this.setState({ +// ChooseShixunListshixun_list:[], +// page:1, +// hometypepvisible:true, +// }) +// +// let pathId=this.props.pathid; +// +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// if(id!=0){ +// url+="&type="+id; +// } +// +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// this.setState({ +// ChooseShixunList:result.data, +// hometypepvisible:false, +// type:id, +// ChooseShixunListshixun_list:result.data.shixun_list +// }) +// } +// }).catch((error)=>{ +// console.log(error); +// }) +// } \ No newline at end of file diff --git a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js index e52ad0ad6..3d1559797 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js +++ b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js @@ -1,8 +1,9 @@ import React, { Component } from 'react'; import {getImageUrl} from 'educoder'; -import {Modal,Input,Checkbox,Tooltip,Spin} from "antd"; +import {Modal,Input,Checkbox,Tooltip,Spin,notification} from "antd"; import { DragDropContext,Draggable, Droppable} from 'react-beautiful-dnd'; import Modals from '../../modals/Modals'; +import NewShixunModel from '../../courses/coursesPublic/NewShixunModel'; import '../ShixunPaths.css'; import axios from 'axios'; const $ = window.$; @@ -63,7 +64,7 @@ class DetailCardsEditAndEdit extends Component{ selectShixun:true, patheditarry:[] }) - this.changeTag(0,""); + // this.changeTag(0,""); } //关闭选择实训弹框 cloasShixunBox =()=>{ @@ -79,36 +80,7 @@ class DetailCardsEditAndEdit extends Component{ }) } - //打开选择实训弹框初始化tag标签和列表 - changeTag(id,search){ - this.setState({ - ChooseShixunListshixun_list:[], - page:1, - hometypepvisible:true - }) - let pathId=this.props.pathid; - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 - if(search!="" && search!=undefined){ - url+="&search="+search; - } - if(id!=0){ - url+="&type="+id; - } - axios.get(encodeURI(url)).then((result)=>{ - if(result.status===200){ - this.setState({ - ChooseShixunList:result.data, - hometypepvisible:false, - type:id, - search:search, - ChooseShixunListshixun_list:result.data.shixun_list - }) - } - }).catch((error)=>{ - console.log(error); - }) - } shixunhomeworkedit=(list)=>{ @@ -158,22 +130,12 @@ class DetailCardsEditAndEdit extends Component{ } - clickShixunchoose=()=>{ + clickShixunchoose=(patheditarry)=>{ - let{patheditarry,shixuns_listedit,shixuns_listeditlist}=this.state + let{shixuns_listedit,shixuns_listeditlist}=this.state let newshixuns_listedit=shixuns_listedit; let list=shixuns_listeditlist - if(patheditarry.length===0){ - this.setState({ - Modalstype:true, - Modalstopval:'请选择实训', - - }) - - return - } - let url='/paths/append_to_stage.json' axios.post(url,{ shixun_id:patheditarry @@ -184,10 +146,11 @@ class DetailCardsEditAndEdit extends Component{ for(var j=0; j<newshixuns_listedit.length; j++){ for(var a=0; a<newshixun_lists.length; a++){ if(newshixuns_listedit[j].shixun_id===newshixun_lists[a].shixun_id){ - this.setState({ - Modalstype:true, - Modalstopval:'请勿重复选择'+newshixun_lists[a].shixun_name+'实训', - }) + // this.setState({ + // Modalstype:true, + // Modalstopval:'请勿重复选择'+newshixun_lists[a].shixun_name+'实训', + // }) + this.showNotification('请勿重复选择:'+newshixun_lists[a].shixun_name+'实训') return } } @@ -338,69 +301,16 @@ class DetailCardsEditAndEdit extends Component{ }) } - contentViewScrolledit=(e)=>{ - //滑动到底判断 - const {ChooseShixunList}=this.state; - let newscrollTop=parseInt(e.currentTarget.scrollTop); - let allclientHeight=e.currentTarget.clientHeight+newscrollTop; - - if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ - - if(ChooseShixunList.shixun_list.length===0){ - return - }else{ - this.setState({ - hometypepvisible:true - }) - // console.log("到达底部"); - - let {page,type,search,ChooseShixunListshixun_list}=this.state; - - let newpage=page+1; - - let pathId=this.props.pathid; - - let newChooseShixunListshixun_list=ChooseShixunListshixun_list; - - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage - - if(search!="" && search!=undefined){ - url+="&search="+search; - } - - if(type!=0){ - url+="&type="+type; - } - axios.get(encodeURI(url)).then((result)=>{ - if(result.status===200){ - - let list =result.data.shixun_list; - - for(var i=0; i<list.length; i++){ - newChooseShixunListshixun_list.push(list[i]) - } - this.setState({ - ChooseShixunList:result.data, - hometypepvisible:false, - type:type, - page:newpage, - search:search, - ChooseShixunListshixun_list:newChooseShixunListshixun_list - }) - } - }).catch((error)=>{ - console.log(error); - }) - - - } - - - - } - - } - + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } render(){ let {selectShixun, @@ -483,99 +393,13 @@ class DetailCardsEditAndEdit extends Component{ } </style>:""} + {selectShixun===true?<NewShixunModel + NewShixunModelType={selectShixun} + hideNewShixunModelType={this.cloasShixunBox} + pathShixun={this.clickShixunchoose} + {...this.props} + ></NewShixunModel>:""} - <Modal - keyboard={false} - title="选择实训" - visible={selectShixun} - closable={false} - footer={null} - width="840px" - destroyOnClose={true} - > - <Spin spinning={hometypepvisible} size="large" style={{marginTop:'15%'}}> - <div className="newupload_conbox"> - <div className="clearfix mb20 shixun_work_div newshixun_tab_div cdefault" style={{"marginRight":"4px"}} id="shixun_tab_div"> - <li className="fl mr5 mt5"> <a onClick={()=>this.changeTag(0,`${search}`)} className={ parseInt(type)===0 ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>全部</a></li> - { - ChooseShixunList && ChooseShixunList.tags.map((item,key)=>{ - return( - <li className="fl mr5 mt5" key={key}> - <a onClick={()=>this.changeTag(`${item.tag_id}`,`${search}`)} className={ parseInt(type) === parseInt(item.tag_id) ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>{item.tag_name}</a> - </li> - ) - }) - } - - - </div> - <div className="clearfix mb20" id="shixun_search_form_div"> - <span className="fl color-grey-9 font-16 mt3"> - <span>共</span> - <span className="color-orange-tip">{ChooseShixunList && ChooseShixunList.shixuns_count}</span> - <span>个实训</span> - </span> - <div className="fr search-new mb0"> - <Search - placeholder="请输入创建者或者实训名称进行搜索" - onInput={this.searchNameInput} - onSearch={()=>this.changeTag(`${type}`,`${search}`)} - style={{width: '115%'}} - ></Search> - </div> - </div> - <ul className="clearfix greybackHead edu-txt-center" style={{marginBottom: '0px'}}> - <li className="fl with40 paddingleft22">实训名称</li> - <li className="fl with30 edu-txt-left">使用院校</li> - <li className="fl with10">使用人数</li> - <li className="fl with10">评价等级</li> - <li className="fl with10"></li> - </ul> - - <style> - { - ` - .over180{min-height: 180px;max-height: 180px;overflow-y: auto} - ` - } - </style> - {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"":<div className="over180 pl20 pr20" - onScroll={this.contentViewScrolledit} - > - <Checkbox.Group style={{ width: '100%' }} onChange={this.shixunhomeworkedit}> - { - ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ - return( - <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> - <li className="fl with40"> - <Checkbox - id={"shixun_input_"+item.shixun_id} - value={item.shixun_id} - key={item.shixun_id} - className="fl task-hide edu-txt-left" - style={{"width":"298px"}} - name="shixun_homework[]" - > - <label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title={item.shixun_name}>{item.shixun_name}</label> - </Checkbox> - </li> - <li className="fl with30 edu-txt-left task-hide paddingl5">{item.school_users}</li> - <li className="fl with10 paddingl10">{item.myshixuns_count}</li> - <li className="fl with10 color-orange-tip paddingl10">{item.preference}</li> - <li className="fl with10"><a className="color-blue" href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">详情</a></li> - </div> - ) - }) - } - </Checkbox.Group> - </div>} - <div className="mt20 marginauto clearfix edu-txt-center"> - <a className="pop_close task-btn mr30 margin-tp26" onClick={this.cloasShixunBox}>取消</a> - <a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.clickShixunchoose}>确定</a> - </div> - </div> - </Spin> - </Modal> </div> {/* 可拖拽选择实训列表*/} @@ -716,4 +540,191 @@ export default DetailCardsEditAndEdit; // </div> // ) // }) -// } \ No newline at end of file +// } + +// <Modal +// keyboard={false} +// title="选择实训" +// visible={selectShixun} +// closable={false} +// footer={null} +// width="840px" +// destroyOnClose={true} +// > +// <Spin spinning={hometypepvisible} size="large" style={{marginTop:'15%'}}> +// <div className="newupload_conbox"> +// <div className="clearfix mb20 shixun_work_div newshixun_tab_div cdefault" style={{"marginRight":"4px"}} id="shixun_tab_div"> +// <li className="fl mr5 mt5"> <a onClick={()=>this.changeTag(0,`${search}`)} className={ parseInt(type)===0 ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>全部</a></li> +// { +// ChooseShixunList && ChooseShixunList.tags.map((item,key)=>{ +// return( +// <li className="fl mr5 mt5" key={key}> +// <a onClick={()=>this.changeTag(`${item.tag_id}`,`${search}`)} className={ parseInt(type) === parseInt(item.tag_id) ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>{item.tag_name}</a> +// </li> +// ) +// }) +// } +// +// +// </div> +// <div className="clearfix mb20" id="shixun_search_form_div"> +// <span className="fl color-grey-9 font-16 mt3"> +// <span>共</span> +// <span className="color-orange-tip">{ChooseShixunList && ChooseShixunList.shixuns_count}</span> +// <span>个实训</span> +// </span> +// <div className="fr search-new mb0"> +// <Search +// placeholder="请输入创建者或者实训名称进行搜索" +// onInput={this.searchNameInput} +// onSearch={()=>this.changeTag(`${type}`,`${search}`)} +// style={{width: '115%'}} +// ></Search> +// </div> +// </div> +// <ul className="clearfix greybackHead edu-txt-center" style={{marginBottom: '0px'}}> +// <li className="fl with40 paddingleft22">实训名称</li> +// <li className="fl with30 edu-txt-left">使用院校</li> +// <li className="fl with10">使用人数</li> +// <li className="fl with10">评价等级</li> +// <li className="fl with10"></li> +// </ul> +// +// <style> +// { +// ` +// .over180{min-height: 180px;max-height: 180px;overflow-y: auto} +// ` +// } +// </style> +// {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"":<div className="over180 pl20 pr20" +// onScroll={this.contentViewScrolledit} +// > +// <Checkbox.Group style={{ width: '100%' }} onChange={this.shixunhomeworkedit}> +// { +// ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ +// return( +// <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> +// <li className="fl with40"> +// <Checkbox +// id={"shixun_input_"+item.shixun_id} +// value={item.shixun_id} +// key={item.shixun_id} +// className="fl task-hide edu-txt-left" +// style={{"width":"298px"}} +// name="shixun_homework[]" +// > +// <label style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name" title={item.shixun_name}>{item.shixun_name}</label> +// </Checkbox> +// </li> +// <li className="fl with30 edu-txt-left task-hide paddingl5">{item.school_users}</li> +// <li className="fl with10 paddingl10">{item.myshixuns_count}</li> +// <li className="fl with10 color-orange-tip paddingl10">{item.preference}</li> +// <li className="fl with10"><a className="color-blue" href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">详情</a></li> +// </div> +// ) +// }) +// } +// </Checkbox.Group> +// </div>} +// <div className="mt20 marginauto clearfix edu-txt-center"> +// <a className="pop_close task-btn mr30 margin-tp26" onClick={this.cloasShixunBox}>取消</a> +// <a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.clickShixunchoose}>确定</a> +// </div> +// </div> +// </Spin> +// </Modal> + +// //打开选择实训弹框初始化tag标签和列表 +// changeTag(id,search){ +// +// this.setState({ +// ChooseShixunListshixun_list:[], +// page:1, +// hometypepvisible:true +// }) +// let pathId=this.props.pathid; +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// if(id!=0){ +// url+="&type="+id; +// } +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// this.setState({ +// ChooseShixunList:result.data, +// hometypepvisible:false, +// type:id, +// search:search, +// ChooseShixunListshixun_list:result.data.shixun_list +// }) +// } +// }).catch((error)=>{ +// console.log(error); +// }) +// } + +// contentViewScrolledit=(e)=>{ +// //滑动到底判断 +// const {ChooseShixunList}=this.state; +// let newscrollTop=parseInt(e.currentTarget.scrollTop); +// let allclientHeight=e.currentTarget.clientHeight+newscrollTop; +// +// if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ +// +// if(ChooseShixunList.shixun_list.length===0){ +// return +// }else{ +// this.setState({ +// hometypepvisible:true +// }) +// // console.log("到达底部"); +// +// let {page,type,search,ChooseShixunListshixun_list}=this.state; +// +// let newpage=page+1; +// +// let pathId=this.props.pathid; +// +// let newChooseShixunListshixun_list=ChooseShixunListshixun_list; +// +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage +// +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// +// if(type!=0){ +// url+="&type="+type; +// } +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// +// let list =result.data.shixun_list; +// +// for(var i=0; i<list.length; i++){ +// newChooseShixunListshixun_list.push(list[i]) +// } +// this.setState({ +// ChooseShixunList:result.data, +// hometypepvisible:false, +// type:type, +// page:newpage, +// search:search, +// ChooseShixunListshixun_list:newChooseShixunListshixun_list +// }) +// } +// }).catch((error)=>{ +// console.log(error); +// }) +// +// +// } +// +// +// +// } +// +// } \ No newline at end of file diff --git a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js index 86c3f68a9..c8cece9fd 100644 --- a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js +++ b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js @@ -362,6 +362,9 @@ class PathDetailIndex extends Component{ .head-right{ line-height: 30px; } + .padding40-20-30{ + padding:40px 20px 30px; + } ` } </style> @@ -457,7 +460,7 @@ class PathDetailIndex extends Component{ } { this.props.checkIfLogin()===false?"":progress === undefined ? "" : progress === null ? "" : - <div className="edu-back-white myProgress padding40-20 mb10"> + <div className="edu-back-white myProgress padding40-20-30 mb10"> <p className="mb20"> <span className="font-16 mr10">关卡数</span> <Tooltip placement="bottom" title="已通关数/关卡总数"> @@ -468,7 +471,8 @@ class PathDetailIndex extends Component{ <span className="fl color-green">已学 {progress.learned}%</span> <span className="fr color-grey-9" id="time-consuming">学习耗时{this.timeStamp(progress.time)} </span> </p> - <div className="myProgressNav"><div className="myProgressGreen" style={{"width":`${progress.learned+"%"}`}}></div></div> + <div className="myProgressNav mb20"><div className="myProgressGreen" style={{"width":`${progress.learned+"%"}`}}></div></div> + <span className="font-14 color-grey-8">注: “我的进展”以已发布的实训详情关卡数为准。</span> </div> } diff --git a/public/react/src/modules/paths/ShixunPaths.js b/public/react/src/modules/paths/ShixunPaths.js index c2bc0d869..d943634b3 100644 --- a/public/react/src/modules/paths/ShixunPaths.js +++ b/public/react/src/modules/paths/ShixunPaths.js @@ -8,6 +8,7 @@ class ShixunPath extends Component{ super(props) } componentDidMount() { + console.log('configShareForPaths') configShareForPaths() } diff --git a/public/react/src/modules/tpm/TPMsettings/TPMsettings.js b/public/react/src/modules/tpm/TPMsettings/TPMsettings.js index f78d62637..b2767887d 100644 --- a/public/react/src/modules/tpm/TPMsettings/TPMsettings.js +++ b/public/react/src/modules/tpm/TPMsettings/TPMsettings.js @@ -220,6 +220,7 @@ export default class TPMsettings extends Component { can_copy: undefined, task_pass: undefined, test_set_permission: undefined, + code_edit_permission: undefined, hide_code: undefined, code_hidden: undefined, forbid_copy: undefined, @@ -352,6 +353,7 @@ export default class TPMsettings extends Component { task_pass: response.data.shixun.task_pass, test_set_permission: response.data.shixun.test_set_permission, hide_code: response.data.shixun.hide_code, + code_edit_permission: response.data.shixun.code_edit_permission, code_hidden: response.data.shixun.code_hidden, is_secret_repository: response.data.shixun.is_secret_repository, init_is_secret_repository: response.data.shixun.is_secret_repository, @@ -546,7 +548,11 @@ export default class TPMsettings extends Component { }); } - + code_edit_permission = (e) => { + this.setState({ + code_edit_permission: e.target.checked + }) + } code_hidden=(e)=>{ let sum = "" if (e.target.checked === false) { @@ -869,7 +875,7 @@ export default class TPMsettings extends Component { let { name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate, evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh, - opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository + opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository, code_edit_permission } = this.state; let newshixun_service_configlist = shixun_service_configlist.map(v => { @@ -982,6 +988,7 @@ export default class TPMsettings extends Component { vnc_evaluate: vnc_evaluate===null?undefined:vnc_evaluate, test_set_permission: test_set_permission, code_hidden: code_hidden, + code_edit_permission: code_edit_permission, trainee: trainee, task_pass: task_pass, hide_code: hide_code, @@ -1563,6 +1570,7 @@ export default class TPMsettings extends Component { test_set_permission, hide_code, forbid_copy, + code_edit_permission, code_hidden, vnc, vnc_evaluate, @@ -2274,6 +2282,15 @@ export default class TPMsettings extends Component { </span> </div> + {!code_hidden && !hide_code && <div className="clearfix mt20 ml30"> + <span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>代码开放修改:</span> + <span className="fl mt5"> + <Checkbox checked={code_edit_permission === undefined ? false : code_edit_permission} + onChange={this.code_edit_permission}></Checkbox> + <label style={{top:'6px'}} className="color-grey-9 ml10" >勾选则学员可以修改版本库目录中的任意文件内容</label> + </span> + </div>} + <div className="clearfix mt20 ml30"> <span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>隐藏代码窗口:</span> <span className="fl mt5"> diff --git a/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js b/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js index ba4f1bc21..c4a08e171 100644 --- a/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js +++ b/public/react/src/modules/tpm/challengesnew/TPMMDEditor.js @@ -16,8 +16,8 @@ require('codemirror/lib/codemirror.css'); let origin = getUrl(); -let path = getUrl("/editormd/lib/") - +let path = '/editormd/lib/' + path = getUrl("/editormd/lib/") const $ = window.$; let timeout; @@ -171,7 +171,7 @@ function create_editorMD(id, width, high, placeholder, imageUrl, callback, initV $("#" + _id + " [type=\"inline\"]").bind("click", function () { _editorName.cm.replaceSelection("`$$$$`"); var __Cursor = _editorName.cm.getDoc().getCursor(); - _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 2); + _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); _editorName.cm.focus(); }); $("[type=\"inline\"]").attr("title", "行内公式"); diff --git a/public/react/src/search/searchc.css b/public/react/src/search/searchc.css index 99f35738a..15c34650b 100644 --- a/public/react/src/search/searchc.css +++ b/public/react/src/search/searchc.css @@ -12,7 +12,7 @@ height: 55px; width:663px !important; font-size: 18px; - color: #681616 !important; + /*color: #681616 !important;*/ border-color: #E1EDF8 !important; }