diff --git a/app/controllers/exercise_bank_questions_controller.rb b/app/controllers/exercise_bank_questions_controller.rb index c7babb949..416358af6 100644 --- a/app/controllers/exercise_bank_questions_controller.rb +++ b/app/controllers/exercise_bank_questions_controller.rb @@ -1,2 +1,388 @@ 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对应A,2对应B,3对应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 + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷问题创建失败!") + 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 #表示答案有更改的 + standard_answer_change = true + 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 #全部的答案数组序号 + standard_answer_change = true + #删除多余的选项 + 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_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 + + #当试卷已发布时(试卷的总状态),当标准答案修改时,如有已提交的学生,需重新计算分数. + + if standard_answer_change && @exercise.exercise_status >= Exercise::PUBLISHED + # ex_users_committed = @exercise.exercise_users.exercise_user_committed + # if ex_users_committed.size > 0 + # ex_users_committed.each do |ex_user| + # update_objective_score = update_single_score(@exercise_question,ex_user.user_id,standard_answer) + # if update_objective_score != 0 + # objective_score = ex_user.objective_score + # new_objective_score = objective_score + update_objective_score + # total_score = ex_user.score + update_objective_score + # total_score = total_score < 0.0 ? 0.0 : total_score + # ex_user.update_attributes(objective_score:new_objective_score,score:total_score) + # end + # end + # end + normal_status(3,"修改了标准答案\n是否重新计算学生答题的成绩?") + else + normal_status(0,"试卷更新成功!") + end + + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + private + + def bank_admin + tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.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 diff --git a/app/controllers/exercise_banks_controller.rb b/app/controllers/exercise_banks_controller.rb index e3d9718b3..29af3c42b 100644 --- a/app/controllers/exercise_banks_controller.rb +++ b/app/controllers/exercise_banks_controller.rb @@ -42,7 +42,9 @@ class ExerciseBanksController < ApplicationController end def update - + tip_exception("试卷标题不能为空!") if params[:exercise_name].blank? + @bank.update_attributes!(name: params[:exercise_name], description: params[:exercise_description]) + normal_status(0,"试卷更新成功!") end private @@ -55,18 +57,4 @@ class ExerciseBanksController < ApplicationController def bank_admin tip_exception(403, "无权限") unless (current_user.certification_teacher? && @bank.user_id == current_user.id) || current_user.admin? end - - def gtask_bank_params - tip_exception("name参数不能为空") if params[:gtask_bank][:name].blank? - tip_exception("description参数不能为空") if params[:gtask_bank][:description].blank? - if @bank.homework_type == 3 - tip_exception("base_on_project参数不能为空") if params[:gtask_bank][:base_on_project].nil? - tip_exception("min_num参数不能为空") if params[:gtask_bank][:min_num].blank? - tip_exception("max_num参数不能为空") if params[:gtask_bank][:max_num].blank? - tip_exception("最小人数不能小于1") if params[:gtask_bank][:min_num].to_i < 1 - tip_exception("最大人数不能小于最小人数") if params[:gtask_bank][:max_num].to_i < params[:gtask_bank][:min_num].to_i - end - params.require(:gtask_bank).permit(:name, :description) if @bank.task_type == 1 - params.require(:gtask_bank).permit(:name, :description, :min_num, :max_num, :base_on_project) if @bank.task_type == 2 - end end diff --git a/app/controllers/gtopic_banks_controller.rb b/app/controllers/gtopic_banks_controller.rb index da56c7acf..6269173ec 100644 --- a/app/controllers/gtopic_banks_controller.rb +++ b/app/controllers/gtopic_banks_controller.rb @@ -1,12 +1,16 @@ class GtopicBanksController < ApplicationController before_action :require_login before_action :find_bank - before_action :bank_admin, only: [:update] + before_action :bank_admin, only: [:edit, :update] def show @bank_attachments = @bank.attachments end + def edit + @attachments = @bank.attachments + end + def update ActiveRecord::Base.transaction do @bank.update_attributes(gtopic_bank_params) diff --git a/app/models/exercise_bank.rb b/app/models/exercise_bank.rb index 22c2a5041..067d080b5 100644 --- a/app/models/exercise_bank.rb +++ b/app/models/exercise_bank.rb @@ -18,4 +18,7 @@ class ExerciseBank < ApplicationRecord scope :exercise_bank_search, lambda { |keywords| where("name LIKE ?", "%#{keywords}%") unless keywords.blank?} + validates :name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" } + validates :description, length: { maximum: 100, too_long: "100 characters is the maximum allowed" } + end \ No newline at end of file diff --git a/app/models/exercise_bank_choice.rb b/app/models/exercise_bank_choice.rb index d3a91bb02..be29ca786 100644 --- a/app/models/exercise_bank_choice.rb +++ b/app/models/exercise_bank_choice.rb @@ -1,4 +1,7 @@ class ExerciseBankChoice < ApplicationRecord belongs_to :exercise_bank_question has_many :exercise_bank_standard_answers + + scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 + scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 end \ No newline at end of file diff --git a/app/models/exercise_bank_question.rb b/app/models/exercise_bank_question.rb index af533836b..14b166333 100644 --- a/app/models/exercise_bank_question.rb +++ b/app/models/exercise_bank_question.rb @@ -5,7 +5,11 @@ class ExerciseBankQuestion < ApplicationRecord has_many :exercise_bank_choices, :dependent => :destroy has_many :exercise_bank_standard_answers, :dependent => :destroy #attr_accessible :question_number, :question_score, :question_title, :question_type + + scope :insert_question_ex, lambda {|k| where("question_number > ?",k)} scope :find_by_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 + scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 + scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题 def question_type_name case self.question_type diff --git a/app/views/exercise_bank_questions/_exercise_bank_questions.json.jbuilder b/app/views/exercise_bank_questions/_exercise_bank_questions.json.jbuilder index a77b8a975..5cc439706 100644 --- a/app/views/exercise_bank_questions/_exercise_bank_questions.json.jbuilder +++ b/app/views/exercise_bank_questions/_exercise_bank_questions.json.jbuilder @@ -34,8 +34,11 @@ if question.question_type <= 2 #当为选择题或判断题时,只显示选 if question.question_type == 2 #返回答案的文字 standard_text = standard_answers_array.first.to_i == 1 ? "正确" : "错误" else + if question.question_type == 1 && standard_answers_array.size == 1 + standard_answers_array = standard_answers_array.first.to_s.split("") + end array_text_answer = [] - standard_answers_array.each{|a| array_text_answer.push((a+64).chr)} + standard_answers_array.each{|a| array_text_answer.push((a.to_i+64).chr)} standard_text = array_text_answer.join("") end json.standard_answer_show standard_text diff --git a/app/views/gtopic_banks/edit.json.jbuilder b/app/views/gtopic_banks/edit.json.jbuilder new file mode 100644 index 000000000..1abc812ac --- /dev/null +++ b/app/views/gtopic_banks/edit.json.jbuilder @@ -0,0 +1,15 @@ +json.topic_type topic_type +json.topic_source topic_source +json.topic_property_first topic_property_first +json.topic_property_second topic_property_second +json.topic_repeat topic_repeat + +json.selected_data do + json.(@bank, :name, :topic_type, :topic_source, :topic_property_first, + :description, :topic_property_second, :source_unit, :topic_repeat, + :province, :city, :is_public) +end + +json.attachments @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} +end \ No newline at end of file