|
|
|
|
|
|
|
|
|
module ExercisesHelper
|
|
|
|
|
# include GitHelper
|
|
|
|
|
|
|
|
|
|
#获取每个学生对每个题的答案状态
|
|
|
|
|
def get_each_student_exercise(exercise_id,exercise_questions,user_id)
|
|
|
|
|
@exercise_user = ExerciseUser.current_exercise_user(user_id,exercise_id)&.first
|
|
|
|
|
exercise_obj_status = exercise_questions.find_objective_questions
|
|
|
|
|
@ex_obj_array = []
|
|
|
|
|
exercise_obj_status.each do |q|
|
|
|
|
|
q_type = q.question_type
|
|
|
|
|
if q_type == Exercise::PRACTICAL
|
|
|
|
|
answers_content = q.exercise_shixun_answers.search_shixun_answers("user_id",user_id)
|
|
|
|
|
else
|
|
|
|
|
answers_content = q.exercise_answers.search_answer_users("user_id",user_id)
|
|
|
|
|
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
|
|
|
|
|
else
|
|
|
|
|
ques_score = 0.0
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
ques_score = answers_content.select(:score).pluck(:score).sum
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if ques_score >= q.question_score #满分作答为正确
|
|
|
|
|
ques_score = q.question_score
|
|
|
|
|
stand_answer = 1
|
|
|
|
|
elsif ques_score > 0.0 #部分作答
|
|
|
|
|
stand_answer = 2
|
|
|
|
|
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, #用户是否回答
|
|
|
|
|
"user_score":ques_score.round(1).to_s #每个问题的总得分
|
|
|
|
|
}
|
|
|
|
|
@ex_obj_array.push(ques_option)
|
|
|
|
|
end
|
|
|
|
|
exercise_sub_status = exercise_questions.find_by_custom("question_type",Exercise::SUBJECTIVE) #主观题
|
|
|
|
|
@ex_sub_array = [] #主观题的已答/未答
|
|
|
|
|
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
|
|
|
|
|
stand_status = 2
|
|
|
|
|
end
|
|
|
|
|
sub_answer_score = sub_answer.first.score
|
|
|
|
|
else
|
|
|
|
|
stand_status = 0
|
|
|
|
|
sub_answer_score = nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
sub_score = {
|
|
|
|
|
"q_id":s.id,
|
|
|
|
|
"q_type":s.question_type,
|
|
|
|
|
"q_position":s.question_number,
|
|
|
|
|
"stand_status":stand_status,
|
|
|
|
|
"user_score":sub_answer_score.present? ? sub_answer_score.round(1).to_s : nil
|
|
|
|
|
}
|
|
|
|
|
@ex_sub_array.push(sub_score)
|
|
|
|
|
end
|
|
|
|
|
@ex_obj_array = @ex_obj_array.sort_by {|k| k[:q_position]}
|
|
|
|
|
@ex_sub_array = @ex_sub_array.sort_by {|k| k[:q_position]}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#试卷的统计结果页面计算各题的
|
|
|
|
|
def exercise_commit_result(questions,user_ids)
|
|
|
|
|
question_infos = []
|
|
|
|
|
percent = 0.0
|
|
|
|
|
questions.includes(:exercise_choices).each do |ex|
|
|
|
|
|
ex_total_score = user_ids.count * ex&.question_score.to_f #该试卷的已回答的总分
|
|
|
|
|
# ex_answers = ex.exercise_answers
|
|
|
|
|
if ex.question_type != Exercise::PRACTICAL
|
|
|
|
|
ques_title = ex.question_title
|
|
|
|
|
ques_less_title = nil
|
|
|
|
|
ex_answers = ex.exercise_answers
|
|
|
|
|
effictive_users = ex_answers.search_answer_users("user_id",user_ids)
|
|
|
|
|
else
|
|
|
|
|
ques_title = ex.shixun.name
|
|
|
|
|
ques_less_title = ex.question_title
|
|
|
|
|
ex_answers = ex.exercise_shixun_answers
|
|
|
|
|
effictive_users = ex_answers.search_shixun_answers("user_id",user_ids)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
effictive_users_count = effictive_users.size #有效回答数,可能有重复的用户id,这里仅统计是否回答这个问题的全部人数
|
|
|
|
|
ex_answered_scores = effictive_users.score_reviewed.pluck(:score).sum #该问题的全部得分
|
|
|
|
|
|
|
|
|
|
if ex.question_type > Exercise::COMPLETION #当为主观题和实训题时,
|
|
|
|
|
percent = (ex_total_score == 0.0 ? 0.0 : (ex_answered_scores / ex_total_score.to_f).round(3) * 100) #正确率
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
question_answer_infos = []
|
|
|
|
|
if ex.question_type <= Exercise::JUDGMENT #选择题和判断题
|
|
|
|
|
ex_choices = ex.exercise_choices
|
|
|
|
|
standard_answer = ex.exercise_standard_answers.pluck(:exercise_choice_id).sort #标准答案的位置
|
|
|
|
|
right_users_count = 0
|
|
|
|
|
#该问题的正确率
|
|
|
|
|
if ex.question_type == Exercise::MULTIPLE #多选题
|
|
|
|
|
user_ids.each do |user_id|
|
|
|
|
|
ex_choice_ids = effictive_users.map{|e| e.exercise_choice_id if e.user_id == user_id}.reject(&:blank?).uniq
|
|
|
|
|
answer_choice_array = ex_choices.map{|a| a.choice_position if ex_choice_ids.include?(a.id)}.reject(&:blank?).uniq
|
|
|
|
|
if answer_choice_array.sort == standard_answer
|
|
|
|
|
right_users_count += 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else #单选题和判断题
|
|
|
|
|
standard_answer_choice_id = ex.exercise_choices.find_by(choice_position: standard_answer.first)&.id
|
|
|
|
|
right_users_count = effictive_users.select{|answer| answer.exercise_choice_id == standard_answer_choice_id}.size
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
percent = effictive_users_count > 0 ? (right_users_count / effictive_users_count.to_f).round(3)*100 : 0.0
|
|
|
|
|
|
|
|
|
|
#每个选项的正确率
|
|
|
|
|
ex_choices.each do |c|
|
|
|
|
|
right_answer = standard_answer.include?(c.choice_position) #选项的标准答案为选项的位置
|
|
|
|
|
answer_users_count = effictive_users.select{|answer| answer.exercise_choice_id == c.id}.size
|
|
|
|
|
|
|
|
|
|
answer_percent = (effictive_users_count == 0 ? 0.0 : (answer_users_count / effictive_users_count.to_f ).round(3))
|
|
|
|
|
|
|
|
|
|
answer_option = {
|
|
|
|
|
:choice_position => c.choice_position,
|
|
|
|
|
:choice_text => c.choice_text,
|
|
|
|
|
:choice_users_count => answer_users_count,
|
|
|
|
|
:choice_percent => answer_percent.round(1).to_s,
|
|
|
|
|
:right_answer => right_answer
|
|
|
|
|
}
|
|
|
|
|
question_answer_infos.push(answer_option)
|
|
|
|
|
end
|
|
|
|
|
elsif ex.question_type == Exercise::COMPLETION #填空题
|
|
|
|
|
ex_ordered = ex.is_ordered
|
|
|
|
|
null_standard_answer = ex.exercise_standard_answers
|
|
|
|
|
null_stand_choice = null_standard_answer.pluck(:exercise_choice_id) #一个exercise_choice_id可能对应多个answer_text
|
|
|
|
|
null_stand_text = null_standard_answer.pluck(:answer_text)
|
|
|
|
|
standard_answer_count = 0
|
|
|
|
|
all_user_count = 0
|
|
|
|
|
null_stand_choice.each_with_index do |s,index|
|
|
|
|
|
user_count = 0
|
|
|
|
|
s_choice_text = null_stand_text[index]
|
|
|
|
|
if ex_ordered #有序排列
|
|
|
|
|
user_ids.each do |u|
|
|
|
|
|
user_answers = ex_answers.where(user_id:u,exercise_choice_id:s).select(:answer_text)
|
|
|
|
|
user_answers_choice = user_answers.exists? ? user_answers&.first&.answer_text.to_s : ""
|
|
|
|
|
if s_choice_text == user_answers_choice
|
|
|
|
|
user_count += 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
user_count = user_count + effictive_users.select{|answer| answer.answer_text == s_choice_text }.size #回答了标准答案的用户
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
answer_percent = ((effictive_users_count == 0) ? 0.0 : (user_count / effictive_users_count.to_f ).round(3))
|
|
|
|
|
answer_option = {
|
|
|
|
|
:choice_position => index+1,
|
|
|
|
|
:choice_text => s_choice_text,
|
|
|
|
|
:choice_users_count => user_count,
|
|
|
|
|
:choice_percent => answer_percent.round(1).to_s,
|
|
|
|
|
:right_answer => true
|
|
|
|
|
}
|
|
|
|
|
question_answer_infos.push(answer_option)
|
|
|
|
|
all_user_count += user_count
|
|
|
|
|
standard_answer_count += 1
|
|
|
|
|
end
|
|
|
|
|
percent = effictive_users_count > 0 ? (all_user_count / effictive_users_count.to_f).round(3)*100 : 0.0
|
|
|
|
|
user_wrong_count = (effictive_users_count - all_user_count )
|
|
|
|
|
|
|
|
|
|
if effictive_users_count > 0 && user_wrong_count >= 0
|
|
|
|
|
wrong_percent = (user_wrong_count / effictive_users_count.to_f ).round(3)
|
|
|
|
|
else
|
|
|
|
|
wrong_percent = 0.0
|
|
|
|
|
end
|
|
|
|
|
wrong_answer_position = {
|
|
|
|
|
:choice_position => (standard_answer_count + 1),
|
|
|
|
|
:choice_text => "wrong",
|
|
|
|
|
:choice_users_count => user_wrong_count,
|
|
|
|
|
:choice_percent => wrong_percent.round(1).to_s,
|
|
|
|
|
:right_answer => false
|
|
|
|
|
}
|
|
|
|
|
question_answer_infos.push(wrong_answer_position)
|
|
|
|
|
elsif ex.question_type == Exercise::SUBJECTIVE #主观题
|
|
|
|
|
ex_score = ex&.question_score
|
|
|
|
|
full_scores = effictive_users.search_exercise_answer("score",ex_score).size #满分人数
|
|
|
|
|
no_full_scores = effictive_users.exercise_no_full_scores(ex_score).size #部分分数人数
|
|
|
|
|
zero_scores = effictive_users.search_exercise_answer("score",0.0).size #包含为0分的,及未评阅的
|
|
|
|
|
un_review_scores = effictive_users_count - full_scores - no_full_scores - zero_scores #未评阅数
|
|
|
|
|
if un_review_scores < 0
|
|
|
|
|
un_review_scores = 0
|
|
|
|
|
end
|
|
|
|
|
main_scores_array = [full_scores,no_full_scores,zero_scores,un_review_scores]
|
|
|
|
|
main_scores_array.each_with_index do |s,index|
|
|
|
|
|
right_answer = (index == 0)
|
|
|
|
|
if effictive_users_count == 0 || s < 0
|
|
|
|
|
s = 0
|
|
|
|
|
score_percent = 0.0
|
|
|
|
|
else
|
|
|
|
|
score_percent = (s.to_i / effictive_users_count.to_f ).round(3)
|
|
|
|
|
end
|
|
|
|
|
answer_option = {
|
|
|
|
|
:choice_position => index+1,
|
|
|
|
|
:choice_text => index+1,
|
|
|
|
|
:choice_users_count => s,
|
|
|
|
|
:choice_percent => score_percent.round(1).to_s,
|
|
|
|
|
:right_answer => right_answer
|
|
|
|
|
}
|
|
|
|
|
question_answer_infos.push(answer_option)
|
|
|
|
|
end
|
|
|
|
|
elsif ex.question_type == Exercise::PRACTICAL #实训题
|
|
|
|
|
ex.exercise_shixun_challenges.each do |c|
|
|
|
|
|
cha_score = c&.question_score
|
|
|
|
|
cha_shixun_answer = effictive_users.search_shixun_keys("exercise_shixun_challenge_id",c.id)
|
|
|
|
|
effictive_users_count = cha_shixun_answer.size #实训题的每个关卡的有效填写量
|
|
|
|
|
full_scores = cha_shixun_answer.search_shixun_keys("score",cha_score).size #满分人数
|
|
|
|
|
no_full_scores = cha_shixun_answer.shixun_no_full_scores(cha_score).size #部分分数人数c
|
|
|
|
|
all_zero_scores = cha_shixun_answer.search_shixun_keys("score",0.0).size #零分人数
|
|
|
|
|
shixun_scores = user_ids.count * cha_score
|
|
|
|
|
shixun_answered_scores = cha_shixun_answer.score_reviewed.pluck(:score).sum #该问题的全部得分
|
|
|
|
|
game_percent = (shixun_answered_scores == 0.0 ? 0.0 : (shixun_answered_scores / shixun_scores.to_f).round(3) * 100) #正确率
|
|
|
|
|
|
|
|
|
|
shixun_score_array = [full_scores,no_full_scores,all_zero_scores]
|
|
|
|
|
shixun_chas = []
|
|
|
|
|
shixun_score_array.each_with_index do |s,index|
|
|
|
|
|
right_answer = (index == 0)
|
|
|
|
|
score_percent = (effictive_users_count == 0 ? 0.0 : (s.to_i / effictive_users_count.to_f ).round(3))
|
|
|
|
|
answer_option = {
|
|
|
|
|
:choice_position => index+1,
|
|
|
|
|
:choice_text => index+1,
|
|
|
|
|
:choice_users_count => s,
|
|
|
|
|
:choice_percent => score_percent.round(1).to_s,
|
|
|
|
|
:right_answer => right_answer
|
|
|
|
|
}
|
|
|
|
|
shixun_chas.push(answer_option)
|
|
|
|
|
end
|
|
|
|
|
shixun_new_chas = {
|
|
|
|
|
:cha_id => c.challenge_id,
|
|
|
|
|
:cha_name => c.challenge.subject,
|
|
|
|
|
:cha_position => c.position,
|
|
|
|
|
:cha_details => shixun_chas,
|
|
|
|
|
:cha_percent => game_percent.round(1).to_s
|
|
|
|
|
}
|
|
|
|
|
question_answer_infos.push(shixun_new_chas)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
ques_option = {
|
|
|
|
|
:ques_title => ques_title,
|
|
|
|
|
:ques_less_title => ques_less_title, #副标题,仅实训题才有
|
|
|
|
|
:type => ex.question_type,
|
|
|
|
|
:position => ex.question_number,
|
|
|
|
|
:percent => percent.round(1).to_s,
|
|
|
|
|
:ques_effictive_counts => effictive_users_count,
|
|
|
|
|
:ques_details => question_answer_infos
|
|
|
|
|
}
|
|
|
|
|
question_infos.push(ques_option)
|
|
|
|
|
end
|
|
|
|
|
question_infos
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#获取试卷的已答/未答人数
|
|
|
|
|
def get_exercise_answers(ex_users, status)
|
|
|
|
|
@exercise_answers = 0
|
|
|
|
|
@exercise_unanswers = 0
|
|
|
|
|
unless status == Exercise::UNPUBLISHED
|
|
|
|
|
@exercise_answers = ex_users.commit_exercise_by_status(1).size #表示已经提交了的用户
|
|
|
|
|
course_all_members_count = ex_users.size
|
|
|
|
|
@exercise_unanswers = (course_all_members_count - @exercise_answers)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def exercise_index_show(exercise,course,is_teacher_or,user)
|
|
|
|
|
# lock_icon 0出现锁,1不出现锁
|
|
|
|
|
ex_show_text = []
|
|
|
|
|
|
|
|
|
|
if course.is_end #课堂停止后,试卷显示为已结束
|
|
|
|
|
exercise_status = 4
|
|
|
|
|
elsif is_teacher_or == 1 #当前为老师的时候,显示的是老师身份的对应试卷的状态,因为该试卷,可能对应老师的多个分班
|
|
|
|
|
exercise_status = exercise.exercise_status
|
|
|
|
|
else
|
|
|
|
|
exercise_status = exercise.get_exercise_status(user) #当前用户查看的试卷的发布状态
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
case exercise_status
|
|
|
|
|
when 2
|
|
|
|
|
ex_show_text.push("提交中")
|
|
|
|
|
when 3
|
|
|
|
|
ex_show_text.push("已截止")
|
|
|
|
|
when 4
|
|
|
|
|
ex_show_text.push("已结束")
|
|
|
|
|
else
|
|
|
|
|
ex_show_text
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if is_teacher_or == 1
|
|
|
|
|
exercise_users_list = exercise.all_exercise_users(user.id) #当前老师所在班级的全部学生
|
|
|
|
|
unreview_count = exercise_status == 1 ? 0 : exercise_users_list.exercise_unreview.size
|
|
|
|
|
get_exercise_answers(exercise_users_list, exercise_status)
|
|
|
|
|
ex_pb_time = exercise.get_exercise_times(user.id,true)
|
|
|
|
|
exercise_publish_time = ex_pb_time[:publish_time]
|
|
|
|
|
exercise_end_time = ex_pb_time[:end_time]
|
|
|
|
|
current_status = 3
|
|
|
|
|
lock_icon = 0
|
|
|
|
|
if exercise_status == 1
|
|
|
|
|
ex_show_text.push("未发布")
|
|
|
|
|
elsif exercise_status == 3
|
|
|
|
|
ex_show_text.push("评阅中")
|
|
|
|
|
end
|
|
|
|
|
elsif is_teacher_or == 2
|
|
|
|
|
exercise_users_list = exercise.get_stu_exercise_users
|
|
|
|
|
get_exercise_answers(exercise_users_list, exercise_status) # 未答和已答的
|
|
|
|
|
unreview_count = exercise_status == 1 ? 0 : exercise_users_list.exercise_unreview.size
|
|
|
|
|
ex_pb_time = exercise.get_exercise_times(user.id,false)
|
|
|
|
|
exercise_publish_time = ex_pb_time[:publish_time]
|
|
|
|
|
exercise_end_time = ex_pb_time[:end_time]
|
|
|
|
|
current_status = exercise.check_user_answer_status(user)
|
|
|
|
|
lock_icon = 0
|
|
|
|
|
if current_status == 4
|
|
|
|
|
ex_show_text.push("未提交")
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
exercise_users_list = exercise.get_stu_exercise_users
|
|
|
|
|
get_exercise_answers(exercise_users_list, exercise_status) # 未答和已答的
|
|
|
|
|
exercise_publish_time = exercise.publish_time
|
|
|
|
|
exercise_end_time = exercise.end_time
|
|
|
|
|
unreview_count = nil
|
|
|
|
|
if exercise.is_public
|
|
|
|
|
current_status = exercise.check_user_answer_status(user)
|
|
|
|
|
lock_icon = 1 #不出现锁
|
|
|
|
|
if current_status == 4
|
|
|
|
|
ex_show_text.push("未提交")
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
current_status = 4
|
|
|
|
|
lock_icon = 0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if (course.is_public == 1) && exercise.is_public
|
|
|
|
|
lock_icon = 1
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if exercise_status > 1
|
|
|
|
|
show_unreview_count = unreview_count
|
|
|
|
|
else
|
|
|
|
|
show_unreview_count = nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if exercise_status == 2 && exercise_end_time.present?
|
|
|
|
|
ex_left_time = how_much_time(exercise_end_time)
|
|
|
|
|
else #已截止后不显示时间
|
|
|
|
|
ex_left_time = nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
"publish_time":exercise_publish_time,
|
|
|
|
|
"end_time":exercise_end_time,
|
|
|
|
|
"exercise_answer":@exercise_answers,
|
|
|
|
|
"exercise_unanswer":@exercise_unanswers,
|
|
|
|
|
"current_status":current_status,
|
|
|
|
|
"lock_icon":lock_icon,
|
|
|
|
|
"unreview_count": show_unreview_count,
|
|
|
|
|
"ex_status":exercise_status,
|
|
|
|
|
"ex_tips":ex_show_text,
|
|
|
|
|
"ex_left_time": ex_left_time
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#计算试卷的总分和试卷的答题状态
|
|
|
|
|
def calculate_student_score(exercise,user)
|
|
|
|
|
score1 = 0.0 #选择题/判断题
|
|
|
|
|
score2 = 0.0 #填空题
|
|
|
|
|
score5 = 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 #该问题的标准答案,可能有多个
|
|
|
|
|
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 == 3 #填空题
|
|
|
|
|
if answers_content.present?
|
|
|
|
|
null_standard_answer = q.exercise_standard_answers
|
|
|
|
|
standard_answer_array = null_standard_answer.select(:exercise_choice_id,:answer_text)
|
|
|
|
|
standard_answer_ids = standard_answer_array.pluck(:exercise_choice_id).reject(&:blank?).uniq #标准答案的exercise_choice_id数组
|
|
|
|
|
standard_answer_count = standard_answer_ids.count
|
|
|
|
|
if standard_answer_count > 0 #存在标准答案时才有分数
|
|
|
|
|
q_score_2 = (q.question_score.to_f / standard_answer_count) #每一空的得分
|
|
|
|
|
else
|
|
|
|
|
q_score_2 = 0.0
|
|
|
|
|
end
|
|
|
|
|
if q.is_ordered
|
|
|
|
|
answers_content.each do |u|
|
|
|
|
|
i_standard_answer = standard_answer_array.where(exercise_choice_id:u.exercise_choice_id).pluck(:answer_text).reject(&:blank?).map!(&:downcase) #该选项的全部标准答案
|
|
|
|
|
if i_standard_answer.include?(u.answer_text.downcase) #该空的标准答案包含用户的答案才有分数
|
|
|
|
|
u.update_column('score',q_score_2)
|
|
|
|
|
score2 = score2 + q_score_2
|
|
|
|
|
else
|
|
|
|
|
u.update_column('score',-1.0)
|
|
|
|
|
score2 += 0.0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
st_answer_text = standard_answer_array.pluck(:answer_text).reject(&:blank?).map!(&:downcase)
|
|
|
|
|
answers_content.each do |u|
|
|
|
|
|
u_answer_text = u.answer_text.downcase
|
|
|
|
|
if st_answer_text.include?(u_answer_text) #只要标准答案包含用户的答案,就有分数。同时,下一次循环时,就会删除该标准答案。防止用户的相同答案获分
|
|
|
|
|
u.update_column("score",q_score_2)
|
|
|
|
|
score2 = score2 + q_score_2
|
|
|
|
|
st_answer_text.delete(u_answer_text)
|
|
|
|
|
else
|
|
|
|
|
u.update_column('score',-1.0)
|
|
|
|
|
score2 += 0.0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
score2 += 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
|
|
|
|
|
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":total_score.round(1),
|
|
|
|
|
"stand_status":ques_stand
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#获取用户的相关信息
|
|
|
|
|
def exercise_use_info(ex_user,user_status,exercise)
|
|
|
|
|
course = exercise.course
|
|
|
|
|
current_user_group_id = ""
|
|
|
|
|
current_user_group_name = ""
|
|
|
|
|
ex_user_user = ex_user.user
|
|
|
|
|
exercise_user_name = ex_user_user.real_name
|
|
|
|
|
exercise_user_id = ex_user_user.id
|
|
|
|
|
ex_user_exercise_status = exercise.get_exercise_status(ex_user_user)
|
|
|
|
|
ex_user_student_id = ex_user_user.student_id
|
|
|
|
|
if ex_user.start_at.present? && (ex_user.commit_status == 0) #用户已回答,但未提交
|
|
|
|
|
commit_status = 2 #继续答题
|
|
|
|
|
else
|
|
|
|
|
commit_status = ex_user.commit_status
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
ex_user_end_at = ex_user.end_at
|
|
|
|
|
course_member = course.students.course_find_by_ids("user_id",ex_user.user.id)
|
|
|
|
|
current_user_group_id = course_member.first.course_group_id if course_member.present?
|
|
|
|
|
if current_user_group_id == 0
|
|
|
|
|
current_user_group_name = "未分班"
|
|
|
|
|
else
|
|
|
|
|
course_group = course.course_groups.by_group_ids(current_user_group_id)
|
|
|
|
|
current_user_group_name = course_group.first.name if course_group.present?
|
|
|
|
|
end
|
|
|
|
|
teacher_review = ex_user.subjective_score < 0.0 ? false : true
|
|
|
|
|
if (user_status == 0 && commit_status == 1) || (user_status == 1 && ex_user_exercise_status == 3 && commit_status == 1) #老师都可以看,学生,需在试卷已提交,且已截止的情况下看
|
|
|
|
|
ex_object_score = ex_user.objective_score < 0.0 ? 0.0 : ex_user.objective_score.round(1).to_s
|
|
|
|
|
ex_subject_score = ex_user.subjective_score < 0.0 ? nil : ex_user.subjective_score.round(1).to_s
|
|
|
|
|
score = ex_user.score.present? ? ex_user.score.round(1).to_s : 0.0.to_s
|
|
|
|
|
else
|
|
|
|
|
ex_object_score = nil
|
|
|
|
|
ex_subject_score = nil
|
|
|
|
|
score = nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
"user_name":exercise_user_name,
|
|
|
|
|
"login":ex_user_user.login,
|
|
|
|
|
"user_group_id":current_user_group_id,
|
|
|
|
|
"user_group_name":current_user_group_name,
|
|
|
|
|
"teacher_review":teacher_review,
|
|
|
|
|
"ex_object_score":ex_object_score,
|
|
|
|
|
"ex_subject_score":ex_subject_score,
|
|
|
|
|
"score":score,
|
|
|
|
|
"user_id":exercise_user_id,
|
|
|
|
|
"commit_status":commit_status,
|
|
|
|
|
"student_id":ex_user_student_id,
|
|
|
|
|
"end_at":ex_user_end_at
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#公用tab页的相关信息
|
|
|
|
|
def ex_common_header(is_teacher_or,exercise)
|
|
|
|
|
exercise_url_status = []
|
|
|
|
|
if is_teacher_or == 1 #当为老师的
|
|
|
|
|
common_tabs = %w(1 2 3 4)
|
|
|
|
|
else
|
|
|
|
|
if exercise.show_statistic #开启了公开统计
|
|
|
|
|
common_tabs = %w(1 2)
|
|
|
|
|
else
|
|
|
|
|
common_tabs = %w(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
common_tabs.each do |c|
|
|
|
|
|
if request.url.include?("exercise_lists")
|
|
|
|
|
active_status = 1
|
|
|
|
|
elsif request.url.include?("exercises_result")
|
|
|
|
|
active_status = 1
|
|
|
|
|
elsif request.url.include?("exercise_setting")
|
|
|
|
|
active_status = 1
|
|
|
|
|
elsif request.url == exercise_path(exercise)
|
|
|
|
|
active_status = 1
|
|
|
|
|
else
|
|
|
|
|
active_status = 0
|
|
|
|
|
end
|
|
|
|
|
common_tab = {
|
|
|
|
|
:common_tab => c,
|
|
|
|
|
:active_status => active_status
|
|
|
|
|
}
|
|
|
|
|
exercise_url_status.push(common_tab)
|
|
|
|
|
end
|
|
|
|
|
exercise_url_status
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#试卷/问卷 设置页面的发布规则返回内容
|
|
|
|
|
def get_user_setting_course(user_published_setting,user_course_groups)
|
|
|
|
|
loop_course_publish_time = []
|
|
|
|
|
total_array_groups = []
|
|
|
|
|
user_published_setting.each do |u|
|
|
|
|
|
new_json_array_group = {}
|
|
|
|
|
setting_group_name = user_course_groups.detect{|g| g[:group_id] == u.course_group_id}
|
|
|
|
|
if loop_course_publish_time.length > 0
|
|
|
|
|
time_length = loop_course_publish_time.length #问卷发布时间和截止时间相同的集合
|
|
|
|
|
(1..time_length).each do |i|
|
|
|
|
|
if (loop_course_publish_time[i-1][:publish_time] == u.publish_time) && (loop_course_publish_time[i-1][:end_time] == u.end_time) #当起止时间已存在时,直接更新
|
|
|
|
|
loop_course_ids = total_array_groups[i-1][:course_group_id] +[u.course_group_id]
|
|
|
|
|
loop_course_names = total_array_groups[i-1][:course_group_name] + [setting_group_name[:group_name]]
|
|
|
|
|
new_json_array_group = {
|
|
|
|
|
"loop_times":i-1,
|
|
|
|
|
"course_group_id":loop_course_ids,
|
|
|
|
|
"course_group_name":loop_course_names,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if new_json_array_group.length > 0
|
|
|
|
|
loop_times = new_json_array_group[:loop_times]
|
|
|
|
|
total_array_groups[loop_times][:course_group_id] = new_json_array_group[:course_group_id]
|
|
|
|
|
total_array_groups[loop_times][:course_group_name] = new_json_array_group[:course_group_name]
|
|
|
|
|
else
|
|
|
|
|
loop_course_times = {
|
|
|
|
|
"publish_time":u.publish_time,
|
|
|
|
|
"end_time": u.end_time
|
|
|
|
|
}
|
|
|
|
|
loop_course_publish_time.push(loop_course_times)
|
|
|
|
|
json_array_group = {
|
|
|
|
|
"course_group_id":[u.course_group_id],
|
|
|
|
|
"course_group_name":[setting_group_name[:group_name]],
|
|
|
|
|
"course_publish_time":u.publish_time,
|
|
|
|
|
"course_end_time":u.end_time
|
|
|
|
|
}
|
|
|
|
|
total_array_groups.push(json_array_group)
|
|
|
|
|
end
|
|
|
|
|
else #第一次循环获得初始值 第一步
|
|
|
|
|
loop_course_times = {
|
|
|
|
|
"publish_time":u.publish_time,
|
|
|
|
|
"end_time": u.end_time
|
|
|
|
|
}
|
|
|
|
|
loop_course_publish_time.push(loop_course_times)
|
|
|
|
|
json_array_group = { #第一个问卷发布规则的第一条记录
|
|
|
|
|
"course_group_id":[u.course_group_id],
|
|
|
|
|
"course_group_name":[setting_group_name[:group_name]],
|
|
|
|
|
"course_publish_time":u.publish_time,
|
|
|
|
|
"course_end_time":u.end_time
|
|
|
|
|
}
|
|
|
|
|
total_array_groups.push(json_array_group)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
total_array_groups
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#学生的分数状态及回答的内容
|
|
|
|
|
def user_question_answers(q,ex_answerer_id,student_status,is_teacher_or,ex_status,ques_type,ex_type)
|
|
|
|
|
answered_content = []
|
|
|
|
|
user_score = nil
|
|
|
|
|
shixun_type = 0
|
|
|
|
|
question_comment = []
|
|
|
|
|
# user_score_pre = nil
|
|
|
|
|
if ques_type == 5
|
|
|
|
|
exercise_answers = q.exercise_shixun_answers.search_shixun_answers("user_id",ex_answerer_id)
|
|
|
|
|
else
|
|
|
|
|
exercise_answers = q.exercise_answers.search_exercise_answer("user_id",ex_answerer_id) #试卷用户的回答
|
|
|
|
|
end
|
|
|
|
|
if student_status == 2 #当前为老师,或为学生且已提交
|
|
|
|
|
user_score_pre = exercise_answers.score_reviewed
|
|
|
|
|
if ques_type == 4 #主观题时,且没有大于0的分数时,为空
|
|
|
|
|
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
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if user_score.present? && (user_score > q.question_score)
|
|
|
|
|
user_score = q.question_score
|
|
|
|
|
end
|
|
|
|
|
if ques_type <= 2
|
|
|
|
|
answered_content = exercise_answers&.pluck(:exercise_choice_id)
|
|
|
|
|
elsif ques_type == 3
|
|
|
|
|
exercise_answers&.each do |a|
|
|
|
|
|
u_answer = {
|
|
|
|
|
"choice_id":a.exercise_choice_id,
|
|
|
|
|
"answer_text": a.answer_text
|
|
|
|
|
}
|
|
|
|
|
answered_content.push(u_answer)
|
|
|
|
|
end
|
|
|
|
|
elsif ques_type == 4
|
|
|
|
|
answered_content = exercise_answers&.pluck(:answer_text)
|
|
|
|
|
end
|
|
|
|
|
if ques_type == 5 #存在实训题,及已经做了实训题的
|
|
|
|
|
if ex_status == 3 || is_teacher_or == 1 #如果试卷已截止,则可以看到分数,否则不能查看分数
|
|
|
|
|
shixun_type = 2
|
|
|
|
|
elsif ex_status == 2 && q.exercise_shixun_answers.present? #试卷未截止,且用户已回答的,则能看到答题的状态
|
|
|
|
|
shixun_type =1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if ex_type == 4 #填空题/主观题/实训题有评论的
|
|
|
|
|
q_answer_id = exercise_answers.present? ? exercise_answers.first.id : nil
|
|
|
|
|
question_comment = q.exercise_answer_comments.search_answer_comments("exercise_answer_id",q_answer_id)
|
|
|
|
|
end
|
|
|
|
|
{
|
|
|
|
|
"user_score": (user_score.present? ? user_score.round(1).to_s : nil),
|
|
|
|
|
"answered_content":answered_content,
|
|
|
|
|
"shixun_type":shixun_type,
|
|
|
|
|
"question_comment":question_comment
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def convert_to_char(str)
|
|
|
|
|
result = ""
|
|
|
|
|
length = str.length
|
|
|
|
|
unless str.nil?
|
|
|
|
|
if length === 1
|
|
|
|
|
result += (str.to_i + 64).chr
|
|
|
|
|
return result
|
|
|
|
|
elsif length > 1
|
|
|
|
|
for i in 0...length
|
|
|
|
|
result += (str[i].to_i + 64).chr
|
|
|
|
|
end
|
|
|
|
|
return result
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
result
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def get_exercise_left_time(exercise,user)
|
|
|
|
|
ex_time = exercise.time
|
|
|
|
|
user_left_time = nil
|
|
|
|
|
time_now_i = Time.now.to_i
|
|
|
|
|
if ex_time > 0
|
|
|
|
|
exercise_user = exercise.exercise_users.find_by(user_id:user.id)
|
|
|
|
|
time_mill = ex_time * 60 #转为秒
|
|
|
|
|
exercise_end_time = exercise.end_time.present? ? exercise.end_time.to_i : 0
|
|
|
|
|
exercise_user_start = exercise_user&.start_at.present? ? exercise_user.start_at.to_i : 0
|
|
|
|
|
#用户未开始答题时,即exercise_user_start为0
|
|
|
|
|
if exercise_user_start == 0
|
|
|
|
|
if (exercise_end_time - time_now_i) > time_mill
|
|
|
|
|
user_left_time = time_mill
|
|
|
|
|
else
|
|
|
|
|
user_left_time = (exercise_end_time < time_now_i) ? nil : (exercise_end_time - time_now_i)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
if (exercise_user_start + time_mill) > exercise_end_time
|
|
|
|
|
time_mill = exercise_end_time - exercise_user_start #如果开始答题时间加试卷的限时长大于试卷的截止时间,则以试卷的截止时间到开始答题时间为试卷的限时
|
|
|
|
|
end
|
|
|
|
|
exercise_user_left_time = time_now_i - exercise_user_start #用户已回答的时间
|
|
|
|
|
user_left_time = (time_mill < exercise_user_left_time) ? nil : (time_mill - exercise_user_left_time) #当前用户对试卷的回答剩余时间
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
user_left_time
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
#实训题学生代码的行数
|
|
|
|
|
def content_line(content)
|
|
|
|
|
content.split(/\r?\n/).length + 1
|
|
|
|
|
end
|
|
|
|
|
end
|