#coding=utf-8 # 执行示例 bundle exec rake excellent_course_exercise:student_answer args=2933,1042,823 # args 第一个是course_id, 第二个是参与人数, 第三个是通过人数 desc "同步精品课的学生试卷数据" namespace :excellent_course_exercise do if ENV['args'] course_id = ENV['args'].split(",")[0] # 对应课堂的id participant_count = ENV['args'].split(",")[1].to_i # 表示参与人数 pass_count = ENV['args'].split(",")[2].to_i # 表示通过人数 end task :student_answer => :environment do course = Course.find_by(id: course_id) course.exercises.each_with_index do |exercise, index| if exercise.exercise_users.where(commit_status: 1).count == 0 # 第一个试卷的参与人数和通过人数都是传的数据,后续的随机 if index == 0 members = course.students.order("id asc").limit(participant_count) update_exercise_user(exercise, members, pass_count) else new_participant_count = rand((participant_count - 423)..participant_count) new_pass_count = rand((new_participant_count - 113)..new_participant_count) members = course.students.order("id asc").limit(new_participant_count) update_exercise_user(exercise, members, new_pass_count) end end end end def update_exercise_user exercise, members, pass_count exercise_question_ids = exercise.exercise_questions.where(question_type: 0).pluck(:id) # index < pass_count 之前的学生都是通关的,之后的未通过 members.each_with_index do |member, index| exercise_user = exercise.exercise_users.where(user_id: member.user_id).take if exercise_question_ids.length == 20 rand_num = index < pass_count - 1 ? rand(15..20) : rand(1..10) elsif exercise_question_ids.length == 17 rand_num = index < pass_count - 1 ? rand(12..17) : rand(1..9) elsif exercise_question_ids.length == 39 rand_num = index < pass_count - 1 ? rand(30..39) : rand(1..18) else rand_num = exercise_question_ids.length end if exercise_user && exercise_user.commit_status == 0 question_ids = exercise_question_ids.sample(rand_num) questions = exercise.exercise_questions.where(id: question_ids) create_exercise_answer questions, member.user_id total_score = calculate_student_score(exercise, member.user) commit_option = { :status => 1, :commit_status => 1, :start_at => exercise.publish_time, :end_at => exercise.end_time, :objective_score => total_score, :score => total_score, :subjective_score => 0 } exercise_user.update_columns(commit_option) end end end def create_exercise_answer questions, user_id questions.each do |question| choice_position = question.exercise_standard_answers.take&.exercise_choice_id choice = question.exercise_choices.where(choice_position: choice_position).take answer_option = { :user_id => user_id, :exercise_question_id => question.id, :exercise_choice_id => choice&.id, :answer_text => "" } ex_a = ExerciseAnswer.new(answer_option) ex_a.save! end end #计算试卷的总分和试卷的答题状态 def calculate_student_score(exercise,user) score1 = 0.0 #选择题/判断题 score2 = 0.0 #填空题 score5 = 0.0 #实训题 total_score = 0.0 ques_stand = [] #问题是否正确 exercise_questions = exercise.exercise_questions.includes(:exercise_answers,:exercise_shixun_answers,:exercise_standard_answers,:exercise_shixun_challenges) exercise_questions&.each do |q| begin if q.question_type != 5 answers_content = q.exercise_answers.where(user_id: user.id) #学生的答案 else answers_content = q.exercise_shixun_answers.where(user_id: user.id) #学生的答案 end if q.question_type <= 2 #为选择题或判断题时 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 #该问题的标准答案,可能有多个 #TODO: 旧版多选题的标准答案是放在一个里面的,新版又做成了一个题有多个标准答案(exercise_choice_id存放的是标准答案的位置..) if q.question_type == 1 && standard_answer.size == 1 standard_answer = standard_answer.first.to_s.split("").map(&:to_i) end if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 if standard_answer.size > 0 q_score_1 = q.question_score # q_score_1 = (q.question_score.to_f / standard_answer.count) #当多选答案正确时,每个answer的分数均摊。 else q_score_1 = 0.0 end answers_content.update_all(:score => q_score_1) score1 = score1 + q.question_score else answers_content.update_all(:score => -1.0) score1 += 0.0 end else score1 += 0.0 end elsif q.question_type == 5 #实训题时,主观题这里不评分 q.exercise_shixun_challenges&.each do |exercise_cha| game = Game.user_games(user.id,exercise_cha.challenge_id)&.first #当前用户的关卡 if game.present? exercise_cha_score = 0.0 answer_status = 0 # if game.status == 2 && game.final_score >= 0 if game.final_score > 0 exercise_cha_score = game.real_score(exercise_cha.question_score) # exercise_cha_score = exercise_cha.question_score #每一关卡的得分 answer_status = 1 end ex_shixun_answer_content = answers_content&.where(exercise_shixun_challenge_id: exercise_cha.id) code = nil if exercise_cha.challenge&.path.present? cha_path = challenge_path(exercise_cha.challenge&.path) game_challenge = game.game_codes.search_challenge_path(cha_path)&.first if game_challenge.present? game_code = game_challenge code = game_code.try(:new_code) else begin #8-23,hs code = git_fle_content(game.myshixun.repo_path,cha_path) rescue code = "" end # code = git_fle_content(game.myshixun.repo_path,cha_path) end end if ex_shixun_answer_content.blank? #把关卡的答案存入试卷的实训里 ### Todo 实训题的_shixun_details里的代码是不是直接从这里取出就可以了?涉及到code的多个版本库的修改 sx_option = { :exercise_question_id => q.id, :exercise_shixun_challenge_id => exercise_cha.id, :user_id => user.id, :score => exercise_cha_score.round(1), :answer_text => code, :status => answer_status } ExerciseShixunAnswer.create(sx_option) else ex_shixun_answer_content.first.update_attributes(score:exercise_cha_score.round(1),answer_text:code) end score5 += exercise_cha_score else score5 += 0.0 end end end user_scores = answers_content.blank? ? 0.0 : answers_content.score_reviewed.pluck(:score).sum if user_scores > 0.0 stand_answer = 1 else stand_answer = 0 end ques_option = { "q_id":q.id, #该问题的id "q_type":q.question_type, "q_position":q.question_number, #该问题的位置 "stand_status":stand_answer, #该问题是否正确,1为正确,0为错误 "user_score":user_scores.round(1) #每个问题的总得分 } ques_stand.push(ques_option) rescue Exception => e Rails.logger.info("calcuclate_score_have_error____________________________#{e}") next end end total_score = score1 + score2 + score5 total_score end end