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/controllers/exercise_bank_questions_con...

419 lines
23 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.

class ExerciseBankQuestionsController < ApplicationController
before_action :require_login, :check_auth #用户需登陆
before_action :get_exercise, only:[:create] #获取试卷
before_action :get_exercise_question, except: [:create] #获取试卷的问题及试卷
before_action :bank_admin #是否为老师
before_action :validate_params, only: [:create, :update] #传入参数的验证
def create
ActiveRecord::Base.transaction do
begin
question_options = {
:question_title => params[:question_title],
:question_type => params[:question_type].present? ? params[:question_type].to_i : 0, #默认为单选题
:question_number => @exercise.exercise_bank_questions.count + 1,
:question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0,
:shixun_id => params[:shixun_id].blank? ? "" : params[:shixun_id],
:is_ordered => params[:is_ordered] # 填空题的答案是否为一一对应关系,默认为true即为一一对应
}
@exercise_question = @exercise.exercise_bank_questions.new(question_options)
#插入问题时那么从插入的这个id以后的question_num都将要+1
if params[:insert_id].present?
insert_exercise = @exercise.exercise_bank_questions.find_by(id: params[:insert_id])
if insert_exercise.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入
ques_num = insert_exercise.question_number.to_i
@exercise_question.question_number = ques_num + 1 #更新了问题的位置
@exercise.exercise_bank_questions.insert_question_ex(ques_num).update_all("question_number = question_number + 1")
end
end
if @exercise_question.save
#为选择题(包括单选和多选)的时候,创建问题选项
ques_type = @exercise_question.question_type
if ques_type <= Exercise::MULTIPLE
choices_array = params[:question_choices]
choices_count= choices_array.count
standard_answer = params[:standard_answers] #为数组格式,因为可能会有单选和多选,标准答案,已提前判断不能为空,
standard_answer = standard_answer.uniq.reject(&:blank?)
(1..choices_count).each do |c|
choice = choices_array[c-1] #每一个选项的内容
choice_option = {
:choice_position => c,
:choice_text => choice.strip
}
question_choices = @exercise_question.exercise_bank_choices.new(choice_option)
question_choices.save
end
#标准答案的存储,如:["1","2","3"..]等1对应A2对应B3对应C。。。
standard_answer.each do |a|
choice_id = a.to_i
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => choice_id #即为选择的位置参数
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
if standard_answer.count > 1 && ques_type == Exercise::SINGLE #当标准答案数大于1且不为多选时修改为多选
@exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
elsif standard_answer.count == 1 && ques_type == Exercise::MULTIPLE
@exercise_question.update_attribute("question_type",Exercise::SINGLE)
end
end
elsif ques_type == Exercise::JUDGMENT #这个为判断题
choices_array = params[:question_choices] #判断的选项,对/错等等
choices_count= choices_array.count
(1..choices_count).each do |c|
choice = choices_array[c-1] #每一个选项的内容
choice_option = {
:choice_position => c,
:choice_text => choice.strip
}
question_choices = @exercise_question.exercise_bank_choices.create(choice_option)
question_choices.save
end
standard_answer = params[:standard_answers] #对应选项的id
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => standard_answer.first.to_i
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
elsif ques_type == Exercise::COMPLETION #填空题,每空的参考答案有多个,那么以位置对应
standard_answer = params[:standard_answers]
standard_answer.each do |a|
null_choice_id = a[:choice_id]
null_choice_text = a[:answer_text]
null_choice_text.each do |n|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => n
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
elsif ques_type == Exercise::SUBJECTIVE #简答题
if params[:standard_answers].present? && params[:standard_answers].reject(&:blank?).count > 0
standard_answer = params[:standard_answers]
standard_answer.each do |a|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:answer_text => a,
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
elsif ques_type == Exercise::PRACTICAL #实训题
shixun = Shixun.find_by(id: params[:shixun_id])
shixun_scores = params[:question_scores] #试卷有多个的分值有多个分数表,所以为分数的数组
shixun_name = params[:shixun_name] || shixun.name
question_score = 0
shixun.challenges.try(:each_with_index) do |challenge,index|
shixun_option = {
:challenge_id => challenge.id,
:shixun_id => shixun.id,
:exercise_bank_question_id => @exercise_question.id,
:position => (index + 1),
:question_score => shixun_scores[index].present? ? shixun_scores[index].to_f.round(1) : 5
}
ex_shixun_challenge = ExerciseBankShixunChallenge.create(shixun_option)
question_score += ex_shixun_challenge.question_score # 问题的分数,为各个关卡分数的总和
end
@exercise_question.update_attributes(:question_score => question_score, :shixun_name=> shixun_name)
end
end
normal_status("创建成功")
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end
end
def update
ActiveRecord::Base.transaction do
begin
# 更新试卷题目的内容
question_options = {
:question_title => params[:question_title],
:is_ordered => params[:is_ordered], # 填空题的答案是否为一一对应关系,默认为true即为一一对应
:question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0 #不可修改分数
}
choices_array = params[:question_choices]
stan_answer_params = params[:standard_answers]
standard_answer = stan_answer_params.present? ? stan_answer_params.uniq.reject(&:blank?) : []
@exercise_question.update_attributes(question_options)
#当选项存在时,可修改选项内容,但是不能更改选项的位置(即不能增删选项)
if choices_array.present?
ex_choices = @exercise_question.exercise_bank_choices
ex_choice_count = ex_choices.count
choice_array_count = choices_array.count
ex_choice_count_array = (1..ex_choice_count).to_a
choice_array_count_array = (1..choice_array_count).to_a
if ex_choice_count > choice_array_count #如果选项有减少的,那么只更新传入的,删除以前的
choice_array_count_array.each do |c|
choice = choices_array[c-1] #每一个选项的内容
exercise_choice = @exercise_question.exercise_bank_choices.find_choice_custom("choice_position",(c))
exercise_choice.update(choice_text:choice)
end
drop_ex_choice = @exercise_question.exercise_bank_choices.left_choice_choose("choice_position",(choice_array_count))
drop_ex_choice.destroy_all
else
ex_choice_count_array.each do |c|
choice = choices_array[c-1] #每一个选项的内容
exercise_choice = @exercise_question.exercise_bank_choices.find_choice_custom("choice_position",(c))
exercise_choice.update(choice_text:choice)
end
new_add_choice = choice_array_count_array - ex_choice_count_array #新传入的需新增
if new_add_choice.count > 0
new_add_choice.each do |i|
choice_option = {
:choice_position => i,
:choice_text => choices_array[i-1].strip
}
question_choices = @exercise_question.exercise_bank_choices.new(choice_option)
question_choices.save
end
end
end
end
#试卷未发布时,当标准答案存在时,可修改标准答案内容,可增删标准答案,否则只能修改标准答案,不能增删标准答案
@exercise_answers_array = @exercise_question.exercise_bank_standard_answers #问卷的全部标准答案
if standard_answer.present?
if @exercise_question.question_type <= Exercise::JUDGMENT #选择题/判断题,标准答案为一个或多个
exercise_standard_choices = @exercise_answers_array.pluck(:exercise_bank_choice_id) #问题以前的全部标准答案选项位置
if exercise_standard_choices.sort != standard_answer.sort #表示答案有更改的
common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的
old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉
new_left_standard_choices = standard_answer - common_standard_choices # 传入的标准答案差集共同的,剩余的表示需要新建
if old_left_standard_choices.count > 0
@exercise_answers_array.standard_by_ids(old_left_standard_choices).destroy_all
end
if new_left_standard_choices.count > 0 #新建标准答案
new_left_standard_choices.each do |s|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => s.to_i #即为选择的位置参数
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
if standard_answer.count > 1 && @exercise_question.question_type == Exercise::SINGLE #当标准答案数大于1且不为多选时修改为多选
@exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
elsif standard_answer.count == 1 && @exercise_question.question_type == Exercise::MULTIPLE
@exercise_question.update_attribute("question_type",Exercise::SINGLE)
end
end
elsif @exercise_question.question_type == Exercise::COMPLETION #填空题
old_ex_answer = @exercise_question.exercise_bank_standard_answers #当前问题的全部标准答案
old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).uniq.sort
new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.uniq.sort
if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案
new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_bank_choice_id).uniq #全部的答案数组序号
#删除多余的选项
if old_ex_answer_choice_ids.count > new_ex_answer_choice_ids.count #有减少的填空
delete_ex_answer_choice_ids = old_ex_answer_choice_ids - new_ex_answer_choice_ids
old_ex_answer.standard_by_ids(delete_ex_answer_choice_ids).destroy_all
end
standard_answer.each do |aa|
null_choice_id = aa[:choice_id]
null_choice_text = aa[:answer_text]
null_choice_text_count = null_choice_text.count #当前传入的答案数量
null_choice_text_count_array = (1..null_choice_text_count).to_a
ex_answer_pre = old_ex_answer.standard_by_ids(null_choice_id) #当前问题的全部答案
ex_answer_pre_count = ex_answer_pre.count
ex_answer_pre_count_array = (1..ex_answer_pre_count).to_a
if old_ex_answer_choice_ids.include?(null_choice_id) #以前的填空题答案包含有现在的填空序号
if null_choice_text_count >= ex_answer_pre_count
new_add_choice = null_choice_text_count_array - ex_answer_pre_count_array
ex_answer_pre_count_array.each do |n|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => null_choice_text[n-1]
}
ex_answer_pre[n-1].update(standard_option)
end
if new_add_choice.count > 0 #表示有新增的
new_add_choice.each do |i|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => null_choice_text[i-1]
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
else
new_delete_choice = ex_answer_pre_count_array - null_choice_text_count_array
null_choice_text.each_with_index do |n,index|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => n
}
ex_answer_pre[index].update(standard_option)
end
if new_delete_choice.count > 0 #表示填空题的答案有删减的
new_delete_choice.each do |d|
ex_answer_pre[d-1].destroy
end
end
end
else
null_choice_text.each do |n|
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:exercise_bank_choice_id => null_choice_id,
:answer_text => n
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
end
end
end
end
end
if @exercise_question.question_type == Exercise::SUBJECTIVE #主观题
main_standard_answer = standard_answer.present? ? standard_answer.first : nil
if @exercise_answers_array.present?
@exercise_answers_array.first.update_attribute("answer_text",main_standard_answer)
else
standard_option = {
:exercise_bank_question_id => @exercise_question.id,
:answer_text => main_standard_answer,
}
question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
question_standard_answer.save
end
elsif @exercise_question.question_type == Exercise::PRACTICAL
question_score = 0
shixun_name = params[:shixun_name] || @exercise_question.shixun_name
@exercise_question.exercise_bank_shixun_challenges.each_with_index do |challenge, index|
challenge.question_score = params[:question_scores][index].to_f.round(1)
challenge.save
question_score += params[:question_scores][index].to_f.round(1)
end
@exercise_question.question_score = question_score
@exercise_question.shixun_name = shixun_name
@exercise_question.save
end
normal_status(0,"试卷更新成功")
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end
end
def up_down
ActiveRecord::Base.transaction do
begin
opr = params[:opr]
current_q_p = @exercise_question.question_number.to_i #问题的当前位置
if opr.present?
if opr.to_s == "up"
last_q_p = @exercise.exercise_bank_questions.find_by(question_number: (current_q_p - 1)) # 当前问题的前一个问题
if last_q_p.present?
@exercise_question.update_attribute('question_number', (current_q_p - 1))
last_q_p.update_attribute('question_number', current_q_p) # 重新获取当前问题的位置
normal_status(0, "问题上移成功!")
else
normal_status(-1, "移动失败,已经是第一个问题了!")
end
elsif opr.to_s == "down"
next_q_p = @exercise.exercise_bank_questions.find_by(question_number: (current_q_p + 1)) # 当前问题的前一个问题
if next_q_p.present?
@exercise_question.update_attribute('question_number', (current_q_p + 1))
next_q_p.update_attribute('question_number', current_q_p)
normal_status(0, "问题下移成功!")
else
normal_status(-1, "移动失败,已经是最后一个问题了!")
end
end
else
normal_status(-1, "移动失败,请输入参数")
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
end
end
#试卷问题的删除
def destroy
ActiveRecord::Base.transaction do
begin
question_d_id = @exercise_question.question_number.to_i #问题的当前位置
exercise_questions = @exercise.exercise_bank_questions
left_questions = exercise_questions.where("question_number > ?", question_d_id)
left_questions.update_all("question_number = question_number - 1") if left_questions
@exercise_question.destroy
normal_status(0, "删除成功")
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
end
end
private
def bank_admin
tip_exception(403, "无权限") unless @exercise.user_id == current_user.id || current_user.admin?
end
def get_exercise
@exercise = ExerciseBank.find_by!(id:params[:exercise_bank_id])
end
def get_exercise_question
@exercise_question = ExerciseBankQuestion.find_by!(id: params[:id])
@exercise = @exercise_question.exercise_bank
end
def validate_params
normal_status(-1,"题目不允许为空!") if (params[:question_title].blank? && params[:question_type].to_i != Exercise::PRACTICAL ) #除了实训题,其余题目必需有题干
normal_status(-1,"问题类型不允许为空!" ) if params[:question_type].blank?
normal_status(-1,"分值不允许为空!" ) if params[:question_score].blank? && params[:question_scores].blank? #分值的数组或参数必需存在一个
if params[:question_score].present? && params[:question_score].to_f <= 0.0 #问题类型存在,则分值不能为空,且必需大于0
normal_status(-1,"分值必需大于0")
elsif (params[:question_score].present? && params[:question_score].to_f.round(1) > 100.0) || (params[:question_scores].present? && (params[:question_scores].map{|a| a.to_f.round(1)}.max > 100.0))
normal_status(-1,"分值不能超过100分")
elsif params[:question_scores].present? && params[:question_scores].include?(0.0) #如果有负数,则自动取绝对值,#多个分数值,针对实训题的
normal_status(-1,"分值必需大于0")
elsif params[:standard_answers].present? && params[:question_choices].present? && (params[:standard_answers].count > params[:question_choices].count)
normal_status(-1,"标准答案数不能大于选项数!")
elsif [0,1,2,3].include?(params[:question_type].to_i) && (params[:standard_answers].blank? || params[:standard_answers].include?("")) #选择题/判断题/填空题 问题选项/标准答案不能为空,也不能包含空的内容
normal_status(-1,"标准答案不能为空!")
elsif params[:question_type].to_i == 2 && (params[:standard_answers].count > 1 || params[:question_choices].blank? || params[:question_choices].include?("")) #判断题的标准答案不能大于1个选项不能为空
normal_status(-1,"判断题选项不能为空/标准答案不能大于1个")
elsif params[:question_type].to_i <= 1 && (params[:question_choices].blank? || params[:question_choices].include?("") || params[:question_choices].count < 2) #选择题选项不能为空,且不能小于2
normal_status(-1,"选择题选项内容不能为空且不能少于2个")
elsif params[:question_type].to_i == 3 && (params[:standard_answers].blank? || params[:standard_answers].count > 5 ) #填空题选项最多为5个,且如果为1个的话不允许修改is_ordered
normal_status(-1,"填空题标准答案不能为空/不能超过5个")
elsif params[:question_type].to_i == 4 && params[:standard_answers].count > 2 #简单题参考答案最多为1个
normal_status(-1,"简答题的参考答案不能大于2个")
elsif params[:question_type].to_i == 5
if params[:shixun_id].blank? #实训题的id不能为空
normal_status(-1,"实训题id不能为空")
elsif params[:shixun_name].blank?
normal_status(-1,"实训题名称不能为空!")
end
end
end
end