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

675 lines
27 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
logger.info("##########__________exercise_end_time__________###############{exercise_end_time}")
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?
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 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