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

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