You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
educoder/app/helpers/exercises_helper.rb

674 lines
27 KiB

6 years ago
module ExercisesHelper
#获取每个学生对每个题的答案状态
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|
if q.question_type == 5
ques_score = q.exercise_shixun_answers.search_shixun_answers("user_id",user_id).pluck(:score).sum
else
ques_score = q.exercise_answers.search_answer_users("user_id",user_id).score_reviewed.pluck(:score).sum
end
if 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",4) #主观题
@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
# stand_status = 1
sub_answer_score = sub_answer.first.score
else
stand_status = 0
sub_answer_score = 0.0
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.round(1).to_s
}
@ex_sub_array.push(sub_score)
end
@ex_obj_array.sort_by {|k| k[:q_position]}
@ex_sub_array.sort_by {|k| k[:q_position]}
end
#试卷的统计结果页面计算各题的
def exercise_commit_result(questions,user_ids)
question_infos = []
questions.each do |ex|
ex_total_score = user_ids.count * ex&.question_score #该试卷的已回答的总分
ex_answers = ex.exercise_answers
if ex.question_type != 5
ques_title = ex.question_title
ques_less_title = nil
effictive_users = ex_answers.search_answer_users("user_id",user_ids)
else
ques_title = ex.shixun.name
ques_less_title = ex.question_title
effictive_users = ex.exercise_shixun_answers.search_shixun_answers("user_id",user_ids)
end
effictive_users_count = effictive_users.count #有效回答数可能有重复的用户id这里仅统计是否回答这个问题的全部人数
ex_answered_scores = effictive_users.score_reviewed.pluck(:score).sum #该问题的全部得分
if ex_total_score == 0.0
percent = 0.0
else
percent = (ex_answered_scores / ex_total_score.to_f).round(3) * 100 #正确率
end
question_answer_infos = []
if ex.question_type <= 2 #单选题
standard_answer = ex.exercise_standard_answers.pluck(:exercise_choice_id) #标准答案的位置
ex.exercise_choices.each do |c|
if standard_answer.include?(c.choice_position) #选项的标准答案为选项的位置
right_answer = true
else
right_answer = false
end
answer_this_choice = effictive_users.search_exercise_answer("exercise_choice_id",c.id)
answer_users_count = answer_this_choice.count
if effictive_users_count == 0
answer_percent = 0.0
else
answer_percent = (answer_users_count / effictive_users_count.to_f ).round(3)
end
answer_option = {
:choice_position => c.choice_position,
:choice_text => c.choice_text,
:choice_users_count => answer_users_count,
:choice_percent => answer_percent.round(1),
:right_answer => right_answer
}
question_answer_infos.push(answer_option)
end
elsif ex.question_type == 3 #填空题
ex_ordered = ex.is_ordered
null_standard_answer = ex.exercise_standard_answers
null_stand_choice = null_standard_answer.pluck(:exercise_choice_id)
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.search_answer_users("user_id",u).search_answer_users("exercise_choice_id",s)
user_answers_choice = user_answers.present? ? user_answers.first.answer_text : ""
if s_choice_text == user_answers_choice
user_count += 1
end
end
else
user_count = user_count + effictive_users.search_exercise_answer("answer_text",s_choice_text).count #回答了标准答案的用户
end
if effictive_users_count == 0
answer_percent = 0.0
else
answer_percent = (user_count / effictive_users_count.to_f ).round(3)
end
answer_option = {
:choice_position => index+1,
:choice_text => s_choice_text,
:choice_users_count => user_count,
:choice_percent => answer_percent.round(1),
:right_answer => true
}
question_answer_infos.push(answer_option)
all_user_count += user_count
standard_answer_count += 1
end
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),
:right_answer => false
}
question_answer_infos.push(wrong_answer_position)
elsif ex.question_type == 4 #主观题
ex_score = ex&.question_score
full_scores = effictive_users.search_exercise_answer("score",ex_score).count #满分人数
no_full_scores = effictive_users.exercise_no_full_scores(ex_score).count #部分分数人数
all_zero_scores = effictive_users.search_exercise_answer("score",0.0).count #包含为0分的及未评阅的
review_scores = ex.exercise_answer_comments.count #主观题的评阅数量
un_review_scores = effictive_users_count - review_scores #未评阅数
zero_scores = all_zero_scores - un_review_scores #已评阅且答案未0分的人数
main_scores_array = [full_scores,no_full_scores,zero_scores,un_review_scores]
main_scores_array.each_with_index do |s,index|
if index == 0
right_answer = true
else
right_answer = false
end
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),
:right_answer => right_answer
}
question_answer_infos.push(answer_option)
end
elsif ex.question_type == 5 #实训题
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.count #实训题的每个关卡的有效填写量
full_scores = cha_shixun_answer.search_shixun_keys("score",cha_score).count #满分人数
no_full_scores = cha_shixun_answer.shixun_no_full_scores(cha_score).count #部分分数人数c
all_zero_scores = cha_shixun_answer.search_shixun_keys("score",0.0).count #满分人数
shixun_score_array = [full_scores,no_full_scores,all_zero_scores]
shixun_chas = []
shixun_score_array.each_with_index do |s,index|
if index == 0
right_answer = true
else
right_answer = false
end
if effictive_users_count == 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),
: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
}
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)
@commit_ex_users = ex_users.commit_exercise_by_status(1) #当前老师的全部学生中已提交的
@exercise_answers = @commit_ex_users.present? ? @commit_ex_users.size : 0 #表示已经提交了的用户
course_all_members_count = ex_users.present? ? ex_users.size : 0
@exercise_unanswers = (course_all_members_count - @exercise_answers)
end
def exercise_index_show(exercise,course,is_teacher_or,user)
# exercise_all_users = exercise.exercise_users
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.id) #当前用户查看的试卷的发布状态
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_users_list.exercise_unreview.size
get_exercise_answers(exercise_users_list)
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 = 1 #不显示锁图标
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) # 未答和已答的
unreview_count = 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 = 1 #不显示锁图标
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_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 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)
elsif exercise_status == 3 && course.end_date.present?
ex_left_time = how_much_time(course.end_date.to_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
exercise_questions.each do |q|
if q.question_type != 5
answers_content = q.exercise_answers.search_answer_users("user_id",user.id) #学生的答案
else
answers_content = q.exercise_shixun_answers.search_shixun_answers("user_id",user.id) #学生的答案
end
if q.question_type <= 2 #为选择题或判断题时
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.count > 0
multi_each_score = (q.question_score / standard_answer.count) #当多选答案正确时每个answer的分数均摊。
else
multi_each_score = 0.0
end
answers_content.update_all(:score => multi_each_score)
score1 = score1 + q.question_score
end
elsif q.question_type == 3 #填空题
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 #存在标准答案时才有分数
each_standard_score = (q.question_score.to_f / standard_answer_count).round(1) #每一空的得分
else
each_standard_score = 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_attribute("score",each_standard_score)
score2 = score2 + each_standard_score
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_attribute("score",each_standard_score)
score2 = score2 + each_standard_score
st_answer_text.delete(u_answer_text)
end
end
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
answer_status = 0
cha_path = challenge_path exercise_cha.challenge.path
if game.status == 2 && game.final_score >= 0
exercise_cha_score = game.real_score exercise_cha.question_score #每一关卡的得分
answer_status = 1
end
if exercise_cha.exercise_shixun_answers.search_shixun_answers("user_id",user.id).blank? #把关卡的答案存入试卷的实训里
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(exercise_cha.shixun.repo_path,cha_path)
end
sx_option = {
:exercise_question_id => q.id,
:exercise_shixun_challenge_id => exercise_cha.id,
:user_id => user.id,
:score => exercise_cha_score,
:answer_text => code,
:status => answer_status
}
ExerciseShixunAnswer.create(sx_option)
end
score5 += exercise_cha_score
end
end
end
user_scores = answers_content.score_reviewed.pluck(:score).sum
if user_scores > 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 #每个问题的总得分
}
ques_stand.push(ques_option)
end
total_score = score1 + score2 + score5
{
"total_score":total_score,
"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(exercise_user_id)
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?
6 years ago
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
6 years ago
teacher_review = ex_user.subjective_score < 0.0 ? false : true
if ex_user_exercise_status != 3 || commit_status != 1 #试卷未截止或用户未提交
# if (user_status != 0 && ex_user_exercise_status != 3)|| commit_status == 0 #不为教师,且试卷未截止;当前用户未提交 不显示分数
ex_object_score = nil
ex_subject_score = nil
score = nil
else
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
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 = 0.0
shixun_type = 0
question_comment = []
if q.question_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 = exercise_answers.score_reviewed.pluck(:score).sum
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.round(1),
"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 content_line(content)
content.split(/\r?\n/).length
end
end