From 25f87ef24cd0b3297c7723cbcae36b8643c076ce Mon Sep 17 00:00:00 2001 From: Bohung Date: Wed, 13 Oct 2021 17:15:47 +0800 Subject: [PATCH] Add weight and average score compute. --- app/assets/javascripts/survey.js | 5 + app/controllers/admin/surveys_controller.rb | 3 + app/controllers/surveys_controller.rb | 11 +- app/models/questionnaire_survey.rb | 120 ++++++++++++++++++- app/models/survey_answer.rb | 11 ++ app/models/survey_answer_group.rb | 3 + app/models/survey_question.rb | 6 +- app/views/admin/surveys/_questions.html.erb | 6 + app/views/admin/surveys/answer_set.html.erb | 1 - app/views/admin/surveys/set_answers.html.erb | 20 +++- app/views/surveys/_answer_success.erb | 2 +- app/views/surveys/answer_success.html.erb | 35 +++++- app/views/surveys/my_record.html.erb | 41 +++++++ config/locales/en.yml | 7 +- config/locales/zh_tw.yml | 4 + 15 files changed, 259 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/survey.js b/app/assets/javascripts/survey.js index 1c20029..9691e5a 100644 --- a/app/assets/javascripts/survey.js +++ b/app/assets/javascripts/survey.js @@ -32,6 +32,7 @@ function setData(l, length, optionsI, className) { _title_translations: [id+l+"_title_translations", name+l+"][title_translations]", "questions_title_"+l,{"en":"","zh_tw":""}], _description_translations: [id+l+"_description_translations", name+l+"][description_translations]", "questions_depiction_"+l,{"en":"","zh_tw":""}], _type: [id+l+"_type", name+l+"][type]"], + _weight: [id+l+"_weight", name+l+"][weight]", 1], _selectable_question: [name+l+"][selectable_question]", ''], _selectable_question_type: [name+l+"][selectable_question_type]",''], _question_type: [question_type_name,'',String(question_type_name).replaceAll(/\[|\]/g,'')], @@ -73,6 +74,7 @@ function setEditData(l, length, d, optionsI, className) { _title_translations: [id+l+"_title_translations", name+l+"][title_translations]", "questions_title_"+l,d.title_translations], _description_translations: [id+l+"_description_translations", name+l+"][description_translations]", "questions_depiction_"+l,d.description_translations], _type: [id+l+"_type", name+l+"][type]",d.type], + _weight: [id+l+"_weight", name+l+"][weight]", d.weight], _selectable_question: [name+l+"][selectable_question]", d.selectable_question], _selectable_question_type: [name+l+"][selectable_question_type]",d.selectable_question_type], _question_type: [name+l+"][question_type]",d.question_type,String(name+l+"][question_type]").replaceAll(/\[|\]/g,'')], @@ -213,10 +215,13 @@ function onQuestionTypeChanged ( $fieldType, _val ){ if(_val < 2) { $fieldType.fadeOut(300); $fieldType.next(".date-format").fadeOut(300); + $fieldType.siblings(".weight_block").addClass("hide"); }else if(_val == 6){ $fieldType.fadeOut(300); $fieldType.next(".date-format").fadeIn(300); + $fieldType.siblings(".weight_block").addClass("hide"); } else { + $fieldType.siblings(".weight_block").removeClass("hide"); $fieldType.fadeIn(300); $fieldType.next(".date-format").fadeOut(300); if (_val == 7){ diff --git a/app/controllers/admin/surveys_controller.rb b/app/controllers/admin/surveys_controller.rb index 33f8075..e12db27 100644 --- a/app/controllers/admin/surveys_controller.rb +++ b/app/controllers/admin/surveys_controller.rb @@ -94,6 +94,7 @@ class Admin::SurveysController < OrbitAdminController respond_to do |format| if @survey.save + @survey.update_total_weight format.html { redirect_to(admin_surveys_path) } format.xml { render :xml => @survey, :status => :created, :location => @survey } else @@ -124,6 +125,8 @@ class Admin::SurveysController < OrbitAdminController @survey.total_points = total respond_to do |format| if @survey.update_attributes(survey_params) + @survey.update_answer_score + @survey.update_total_weight if params[:et] == "result" format.html { redirect_to(set_answers_admin_survey_path(@survey.id)) } else diff --git a/app/controllers/surveys_controller.rb b/app/controllers/surveys_controller.rb index 53caee4..efc8b8c 100644 --- a/app/controllers/surveys_controller.rb +++ b/app/controllers/surveys_controller.rb @@ -141,6 +141,7 @@ class SurveysController < ApplicationController @answer_model.select_question = answer['select_question'].values.flatten unless answer['select_question'].blank? @survey.survey_questions.each do |question| qid = question.id.to_s + weight = (question.weight.nil? ? 1 : question.weight) if question.selectable_question && @answer_model.select_question.exclude?(qid) next end @@ -161,7 +162,7 @@ class SurveysController < ApplicationController tmp['other'] = answer["#{qid}_#{answer[qid]}_custom_option"] end @answer_model[qid] = tmp - p = (opt.points == nil ? 0 : opt.points) rescue 0 + p = (opt.points.to_i * weight) rescue 0 total = total + p individual_total << p end @@ -182,7 +183,7 @@ class SurveysController < ApplicationController tmp['other'] = answer["#{qid}_#{oid}_custom_option"] end @answer_model[qid] << tmp - p = (opt.points == nil ? 0 : opt.points) rescue 0 + p = (opt.points.to_i * weight) rescue 0 total = total + p t = t + p end @@ -192,7 +193,7 @@ class SurveysController < ApplicationController end when SurveyQuestion::Radiogroup @answer_model[qid] = {} - options = Hash[question.survey_question_options.collect{|o| [ o.id.to_s, (o.points.nil? ? 0 : o.points) ] }] + options = Hash[question.survey_question_options.collect{|o| [ o.id.to_s, (o.points.nil? ? 0 : o.points * weight) ] }] radiogroups = Hash[question.survey_question_radiogroups.collect{|rg| [ rg.id.to_s, rg.name_translations] }] if answer[qid] t = 0 @@ -234,10 +235,10 @@ class SurveysController < ApplicationController if question.custom_option_each_option && !answer["#{qid}_#{oid}_custom_option"].blank? tmp['other'] = answer["#{qid}_#{oid}_custom_option"] end - p = (opt.points == nil ? 0 : opt.points) rescue 0 + p = (opt.points.to_i * weight) rescue 0 opt2_names = Array(answer["#{qid}_#{oid}"]).collect do |o2id| opt2 = opt.level2.find(o2id) - p += opt2.points.to_i + p += opt2.points.to_i * weight opt2.name_translations end tmp['level2'] = opt2_names diff --git a/app/models/questionnaire_survey.rb b/app/models/questionnaire_survey.rb index 82b07e8..499018e 100644 --- a/app/models/questionnaire_survey.rb +++ b/app/models/questionnaire_survey.rb @@ -28,7 +28,7 @@ class QuestionnaireSurvey field :needs_login, :type => Boolean, :default => false field :answer_repeat, :type => Boolean, :default => false field :total_points, type: Integer, :default => 0 - + field :total_weight, type: Integer field :result_type, :type => Integer, :default => 0 field :extern_link mount_uploader :upload_file, AssetUploader @@ -373,6 +373,123 @@ class QuestionnaireSurvey return new_object, clone_target end end + def update_answer_score + if self.survey_questions.where(:need_update_score => true).count != 0 + puts "Updating answer's scores" + tmp_weights = [] + tmp_score_data = self.survey_questions.map do |question| + qid = question.id.to_s + tmp = {} + weight = (question.weight.nil? ? 1 : question.weight) + tmp_weights << weight + case question.type + when SurveyQuestion::Radio, SurveyQuestion::Select, SurveyQuestion::Check, SurveyQuestion::Radiogroup + question.survey_question_options.each do |opt| + oid = opt.id.to_s + tmp[oid] = {"base"=>(opt.points.to_i * weight)} + end + when SurveyQuestion::Oneline, SurveyQuestion::Multiline, SurveyQuestion::DateTime + tmp = 0 + when SurveyQuestion::DoubleLevelOption + question.survey_question_options.each do |opt| + oid = opt.id.to_s + tmp[oid] = {"base"=>(opt.points.to_i * weight)} + opt.level2.each do |opt2| + tmp[oid][opt2.id.to_s] = opt2.points.to_i * weight + end + end + end + [qid,tmp] + end.to_h + self.survey_answers.each do |answer| + total = 0 + individual_total = [] + tmp_total_weight = 0 + tmp_score_data.each_with_index do |(qid,tmp),i| + if answer[qid] + tmp_total_weight += tmp_weights[i] + if tmp.class == Fixnum #Oneline, Multiline, DateTime + total += tmp + individual_total << tmp + else + if answer[qid].class == Array #Check , DoubleLevelOption + t = 0 + answer[qid].each do |d| + if d.class != BSON::Document + break + end + level2s = [] + oid = nil + if d.has_key?("level1_id") + oid = d["level1_id"] + level2s = Array(d["level1_ids"]) + else + oid = d['oid'] + end + t2 += tmp[oid]["base"] rescue nil + if t2 + t += t2 + level2s.each do |level2_id| + t += tmp[oid][level2_id] + end + end + end + total += t + individual_total << t + elsif answer[qid].class == BSON::Document #Radio, Select, Radiogroup + if (answer[qid].has_key?('oid') rescue true) + t = tmp[answer[qid]['oid']]["base"] rescue nil + if t + total += t + individual_total << t + end + else + tmp[answer[qid]].each do |oid,d| + t = tmp[oid]["base"] rescue nil + if t + total += t + individual_total << t + end + end + end + else + total += 0 + individual_total << 0 + end + end + else + total += 0 + individual_total << 0 + end + end + answer.scored_points = total + answer.individual_total = individual_total + if tmp_total_weight != 0 + answer.avg_points = (individual_total.to_f / tmp_total_weight).round + else + answer.avg_points = 0 + end + answer.save + end + self.survey_questions.update_all(:need_update_score => false) + end + end + def update_total_weight + self.total_weight = self.survey_questions.pluck(:weight).map{|w| w.nil? ? 1 : w}.sum + self.save + end + def get_total_weight(ans=nil) + if ans.nil? + if self.total_weight.nil? + self.update_total_weight + self.total_weight + else + self.total_weight + end + else + self.survey_questions.where(:id.in=>ans.attributes.keys).pluck(:weight).map{|w| w.nil? ? 1 : w}.sum + end + end protected def check_deadline @@ -380,7 +497,6 @@ class QuestionnaireSurvey self.deadline = nil end end - # def update_avliable_language # VALID_LOCALES.each do |locale| # if (title_translations[locale].blank? rescue true) diff --git a/app/models/survey_answer.rb b/app/models/survey_answer.rb index 73f00e1..6d8f276 100644 --- a/app/models/survey_answer.rb +++ b/app/models/survey_answer.rb @@ -5,6 +5,7 @@ class SurveyAnswer field :user, type: BSON::ObjectId field :scored_points, type: Integer, :default => 0 + field :avg_points, type: Integer field :individual_total, type: Array, :default => [] field :select_question, type: Array, :default => [] belongs_to :questionnaire_survey @@ -41,4 +42,14 @@ class SurveyAnswer end end end + def get_avg_points + if self.avg_points.nil? + total_weight = self.questionnaire_survey.get_total_weight(self) + self.avg_points = (scored_points.to_f / total_weight).round + self.save + self.avg_points + else + self.avg_points + end + end end \ No newline at end of file diff --git a/app/models/survey_answer_group.rb b/app/models/survey_answer_group.rb index 90074b5..d9e03ac 100644 --- a/app/models/survey_answer_group.rb +++ b/app/models/survey_answer_group.rb @@ -7,4 +7,7 @@ class SurveyAnswerGroup def survey_answers SurveyAnswer.where(:id.in=>survey_answer_ids) end + after_destroy do + SurveyAnswer.where(:id.in=>survey_answer_ids).destroy + end end \ No newline at end of file diff --git a/app/models/survey_question.rb b/app/models/survey_question.rb index 031f48e..66207c8 100644 --- a/app/models/survey_question.rb +++ b/app/models/survey_question.rb @@ -11,7 +11,8 @@ class SurveyQuestion include Mongoid::Document include Mongoid::Attributes::Dynamic - + field :need_update_score, :type => Boolean, :default => false + field :weight, :type => Integer, :default => 1 field :title, :localize => true field :description, :localize => true field :is_required, :type => Boolean @@ -43,6 +44,9 @@ class SurveyQuestion before_save do self.custom_option_type = self.custom_option_type.map(&:to_i) + if self.weight_changed? || (self.survey_question_options.select{|opt| opt.points_changed? || (opt.level2.select{|sub_opt| sub_opt.points_changed?}.count != 0)}.count != 0) + self.need_update_score = true + end end def jumpable? diff --git a/app/views/admin/surveys/_questions.html.erb b/app/views/admin/surveys/_questions.html.erb index 977f43f..1579f98 100644 --- a/app/views/admin/surveys/_questions.html.erb +++ b/app/views/admin/surveys/_questions.html.erb @@ -49,6 +49,12 @@ +
+ +
+ +
+
diff --git a/app/views/admin/surveys/answer_set.html.erb b/app/views/admin/surveys/answer_set.html.erb index d55fc88..adea825 100644 --- a/app/views/admin/surveys/answer_set.html.erb +++ b/app/views/admin/surveys/answer_set.html.erb @@ -64,7 +64,6 @@ <% when SurveyQuestion::Radio, SurveyQuestion::Select %> <%= SurveysHelper.parse_value(@survey_answer[sq.id.to_s]) %> <% when SurveyQuestion::Check %> - <% puts sq.id %> <%= SurveysHelper.parse_checkbox_value_html(@survey_answer[sq.id.to_s]) %> <% when SurveyQuestion::Radiogroup %>
diff --git a/app/views/admin/surveys/set_answers.html.erb b/app/views/admin/surveys/set_answers.html.erb index d29d676..14f7a29 100644 --- a/app/views/admin/surveys/set_answers.html.erb +++ b/app/views/admin/surveys/set_answers.html.erb @@ -80,6 +80,13 @@
+
+ +
@@ -93,6 +100,13 @@
+
+ +
@@ -130,7 +144,11 @@ $(".selectable[data-type=" + selectedOption.value + "]").removeClass("hide"); } var index = <%= @survey.result_criteria.count == 0 ? 1 : @survey.result_criteria.count + 1 %>, - html = '
Save to add text
'; + html = '
Save to add text
'; $("#add-criteria").on("click",function(){ var newhtml = html.replace(/{index}/g,index); diff --git a/app/views/surveys/_answer_success.erb b/app/views/surveys/_answer_success.erb index cb81004..2b1ee63 100644 --- a/app/views/surveys/_answer_success.erb +++ b/app/views/surveys/_answer_success.erb @@ -1,6 +1,6 @@ <% @survey.result_type.inspect %> -<% if @survey.result_type == 3 %> +<% if @survey.result_type == QuestionnaireSurvey::ResultCriteria %> var scoredPoints = <%= @answer_model.scored_points %>, msg = ""; <% @survey.result_criteria.each do |criteria| %> diff --git a/app/views/surveys/answer_success.html.erb b/app/views/surveys/answer_success.html.erb index 9bd1616..26bb245 100644 --- a/app/views/surveys/answer_success.html.erb +++ b/app/views/surveys/answer_success.html.erb @@ -2,21 +2,48 @@ data = action_data @survey = data['survey'] @answer_model = data['answer'] + answer_model_attrs = @answer_model.attributes + weight_relations = @survey.survey_questions.map{|q| [q.id.to_s,(q.weight.nil? ? 1 : q.weight)]}.to_h %> -<% if @survey.result_type == 3 %> -

Your total score is <%= @answer_model.scored_points %>

+<% if @survey.result_type == QuestionnaireSurvey::ResultCriteria %> + <% tmp_msgs = [] + types = [] %> <% @survey.result_criteria.each do |criteria| %> <% total_criteria_score = 0 + total_weight = 0 ((criteria["questions"][0].to_i - 1)..(criteria["questions"][1].to_i - 1)).each do |x| total_criteria_score = (total_criteria_score + @answer_model.individual_total[x].to_i) rescue 0 + k = weight_relations.keys[x] + if k && answer_model_attrs.has_key?(k) + total_weight += weight_relations[k] + end end + type = criteria["type"].to_i %> - <% if (criteria["range"][0].to_i..criteria["range"][1].to_i).cover?(total_criteria_score) %> -
<%= criteria["msg"].html_safe %>
+ <% if type == 0 %> + <% if (criteria["range"][0].to_i..criteria["range"][1].to_i).cover?(total_criteria_score) %> + <% tmp_msgs << criteria["msg"] %> + <% types << type %> + <% end %> + <% else %> + <% avg = (total_criteria_score.to_f / total_weight).round %> + <% if (criteria["range"][0].to_i..criteria["range"][1].to_i).cover?(avg) %> + <% tmp_msgs << criteria["msg"] %> + <% types << type %> + <% end %> <% end %> <% end %> + <% if types.include?(0) %> +

Your total score is <%= @answer_model.scored_points %>

+ <% end %> + <% if types.include?(1) %> +

Your average score is <%= @answer_model.get_avg_points %>

+ <% end %> + <% tmp_msgs.each do |msg| %> +
<%=msg.html_safe%>
+ <% end %> <% else %>

<%= t('survey.answer_success')%>

<% end %> diff --git a/app/views/surveys/my_record.html.erb b/app/views/surveys/my_record.html.erb index 0c6a382..c99e47e 100644 --- a/app/views/surveys/my_record.html.erb +++ b/app/views/surveys/my_record.html.erb @@ -52,7 +52,48 @@ "><%= t("survey.view") %>(<%=sa.survey_answer_ids.count%>) <% else %> + <% if @survey.result_type == QuestionnaireSurvey::ResultCriteria %> + <% tmp_msgs = [] + answer_model_attrs = sa.attributes + weight_relations = @survey.survey_questions.map{|q| [q.id.to_s,(q.weight.nil? ? 1 : q.weight)]}.to_h + types = [] %> + <% @survey.result_criteria.each do |criteria| %> + <% + total_criteria_score = 0 + total_weight = 0 + ((criteria["questions"][0].to_i - 1)..(criteria["questions"][1].to_i - 1)).each do |x| + total_criteria_score = (total_criteria_score + sa.individual_total[x].to_i) rescue 0 + k = weight_relations.keys[x] + if k && answer_model_attrs.has_key?(k) + total_weight += weight_relations[k] + end + end + type = criteria["type"].to_i + %> + <% if type == 0 %> + <% if (criteria["range"][0].to_i..criteria["range"][1].to_i).cover?(total_criteria_score) %> + <% tmp_msgs << criteria["msg"] %> + <% types << type %> + <% end %> + <% else %> + <% if (criteria["range"][0].to_i..criteria["range"][1].to_i).cover?(total_criteria_score / total_weight) %> + <% tmp_msgs << criteria["msg"] %> + <% types << type %> + <% end %> + <% end %> + <% end %> + <% if types.include?(0) %> +

Your total score is <%= sa.scored_points %>

+ <% end %> + <% if types.include?(1) %> +

Your average score is <%= sa.get_avg_points %>

+ <% end %> + <% tmp_msgs.each do |msg| %> +
<%=msg.html_safe%>
+ <% end %> + <% else %> "><%= t("survey.view_answers") %> + <% end %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 574cac4..775933f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,6 +1,11 @@ en: - + module_name: + survey: Survey survey: + type: + '0': "Total" + '1': "Average" + weight: Weight taken_survey: "Taken Survey" please_login_first: "Please login first!" view: View diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 6ce1f05..ddc9cab 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -4,6 +4,10 @@ zh_tw: survey: 問卷調查 survey: + type: + '0': "總分" + '1': "平均" + weight: 權重 taken_survey: "填寫問卷" please_login_first: "請先登入網站!" view: 查看