Add weight and average score compute.

This commit is contained in:
BoHung Chiu 2021-10-13 17:15:47 +08:00
parent d35c12f1fc
commit 25f87ef24c
15 changed files with 259 additions and 16 deletions

View File

@ -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){

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -49,6 +49,12 @@
</div>
</div>
</div>
<div class="control-group weight_block" {{if _type[2] != 0 && _type[2] != 1 && _type[2] != 6 }}class="hide"{{/if}}>
<label class="control-label muted" for=""><%= t('survey.weight') %> </label>
<div class="controls">
<input type="number" name="${_weight[1]}" value="${_weight[2]}" min="1">
</div>
</div>
<div class="control-group">
<label class="control-label muted" for=""><%= t('survey_question.type') %> </label>
<div class="controls">

View File

@ -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 %>
<div class="radiogroup">

View File

@ -80,6 +80,13 @@
<label style="padding-left:0px;" for="" class="radio inline"> Question from : <input name="questionnaire_survey[result_criteria][0][questions][]" class="span1" max="<%= @surveysurvey_questionscount %>" type="number" min="1"></label>
<label for="" class="radio inline"> Question to : <input name="questionnaire_survey[result_criteria][0][questions][]" class="span1" min="1" max="<%= @survey.survey_questions.count %>" type="number"></label>
</div>
<div class="criteria" style="margin-left:0px;display:block;">
<label style="padding-left:0px;" for="" class="radio inline"> Type : <select name="questionnaire_survey[result_criteria][0][type]">
<% [0,1].each do |i| %>
<option value="<%=i%>"><%=t("survey.type.#{i}")%></option>
<% end %>
</select></label>
</div>
<div class="criteria" style="margin-left:0px;display:block;">
<label style="padding-left:0px;" for="" class="radio inline"> From : <input name="questionnaire_survey[result_criteria][0][range][]" class="span1" max="<%= @survey.total_points %>" type="number"></label>
<label for="" class="radio inline"> To : <input name="questionnaire_survey[result_criteria][0][range][]" class="span1" max="<%= @survey.total_points %>" type="number"></label>
@ -93,6 +100,13 @@
<label style="padding-left:0px;" for="" class="radio inline"> Question from : <input name="questionnaire_survey[result_criteria][<%= idx %>][questions][]" class="span1" max="<%= @survey.survey_questions.count %>" min="1" type="number" value="<%= criteria["questions"][0] rescue "" %>"></label>
<label for="" class="radio inline"> Question to : <input name="questionnaire_survey[result_criteria][<%= idx %>][questions][]" class="span1" max="<%= @survey.survey_questions.count %>" min="1" type="number" value="<%= criteria["questions"][1] rescue "" %>"></label>
</div>
<div class="criteria" style="margin-left:0px;display:block;">
<label style="padding-left:0px;" for="" class="radio inline"> Type : <select name="questionnaire_survey[result_criteria][<%= idx %>][type]">
<% [0,1].each do |i| %>
<option value="<%=i%>" <%=(criteria["type"].to_i == i) ? "selected" : ""%>><%=t("survey.type.#{i}")%></option>
<% end %>
</select></label>
</div>
<div class="criteria" style="margin-left:0px;display:block;margin-bottom:50px;">
<label style="padding-left:0px;" for="" class="radio inline"> From : <input name="questionnaire_survey[result_criteria][<%= idx %>][range][]" class="span1" max="<%= @survey.total_points %>" type="number" value="<%= criteria["range"][0] rescue "" %>"></label>
<label for="" class="radio inline"> To : <input name="questionnaire_survey[result_criteria][<%= idx %>][range][]" class="span1" max="<%= @survey.total_points %>" type="number" value="<%= criteria["range"][1] rescue "" %>"></label>
@ -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 = '<div class="criteria-block"><div><label style="padding-left:0px;" for="" class="radio inline"> Questions from : <input name="questionnaire_survey[result_criteria][{index}][questions][]" class="span1" min="1" max="<%= @survey.survey_questions.count %>" type="number"></label><label for="" class="radio inline"> Questions to : <input name="questionnaire_survey[result_criteria][{index}][questions][]" class="span1" min="1" max="<%= @survey.survey_questions.count %>" type="number"></label></div><div data-critera-number="criteria_{index}" class="criteria" style="width:800px;"><label style="padding-left:0px;" for="" class="radio inline"> From : <input name="questionnaire_survey[result_criteria][{index}][range][]" class="span1" max="<%= @survey.total_points %>" type="number"></label><label for="" class="radio inline"> To : <input name="questionnaire_survey[result_criteria][{index}][range][]" class="span1" max="<%= @survey.total_points %>" type="number"></label><a href="" style="margin-left:5px;" class="btn btn-primary delete-critera"><i class="icon icon-trash"></i></a><span class="radio inline">Save to add text</span></div></div>';
html = '<div class="criteria-block"><div><label style="padding-left:0px;" for="" class="radio inline"> Questions from : <input name="questionnaire_survey[result_criteria][{index}][questions][]" class="span1" min="1" max="<%= @survey.survey_questions.count %>" type="number"></label><label for="" class="radio inline"> Questions to : <input name="questionnaire_survey[result_criteria][{index}][questions][]" class="span1" min="1" max="<%= @survey.survey_questions.count %>" type="number"></label></div><div data-critera-number="criteria_{index}" class="criteria" style="margin-left:0px;display:block;"><label style="padding-left:0px;" for="" class="radio inline"> Type : <select name="questionnaire_survey[result_criteria][{index}][type]">'
<% [0,1].each do |i| %>
html += '<option value="<%=i%>"><%=t("survey.type.#{i}")%></option>'
<% end %>
html += '</select></label></div><div data-critera-number="criteria_{index}" class="criteria" style="width:800px;"><label style="padding-left:0px;" for="" class="radio inline"> From : <input name="questionnaire_survey[result_criteria][{index}][range][]" class="span1" max="<%= @survey.total_points %>" type="number"></label><label for="" class="radio inline"> To : <input name="questionnaire_survey[result_criteria][{index}][range][]" class="span1" max="<%= @survey.total_points %>" type="number"></label><a href="" style="margin-left:5px;" class="btn btn-primary delete-critera"><i class="icon icon-trash"></i></a><span class="radio inline">Save to add text</span></div></div>';
$("#add-criteria").on("click",function(){
var newhtml = html.replace(/{index}/g,index);

View File

@ -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| %>

View File

@ -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 %>
<h3>Your total score is <%= @answer_model.scored_points %> </h3>
<% 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) %>
<div> <%= criteria["msg"].html_safe %> </div>
<% 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) %>
<h3>Your total score is <%= @answer_model.scored_points %> </h3>
<% end %>
<% if types.include?(1) %>
<h3>Your average score is <%= @answer_model.get_avg_points %> </h3>
<% end %>
<% tmp_msgs.each do |msg| %>
<div><%=msg.html_safe%></div>
<% end %>
<% else %>
<h3><%= t('survey.answer_success')%></h3>
<% end %>

View File

@ -52,7 +52,48 @@
<a class="btn btn-primary" href="/admin/surveys/<%= sa.id.to_s %>/answer_list" title="<%= t("survey.view") %>"><%= t("survey.view") %>(<%=sa.survey_answer_ids.count%>)</a>
<button class="btn btn-primary export-xls" data-href="/admin/surveys/<%= sa.id.to_s %>/export_answers" title="<%= t("survey.export") %>"><%= t("survey.export") %></button>
<% 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) %>
<h4>Your total score is <%= sa.scored_points %> </h4>
<% end %>
<% if types.include?(1) %>
<h4>Your average score is <%= sa.get_avg_points %> </h4>
<% end %>
<% tmp_msgs.each do |msg| %>
<div><%=msg.html_safe%></div>
<% end %>
<% else %>
<a class="btn btn-primary" href="/admin/surveys/<%= @is_answer_list ? sa.id : sa.survey_answer_ids.last.to_s %>/answer_set" title="<%= t("survey.view_answers") %>"><%= t("survey.view_answers") %></a>
<% end %>
<% end %>
</td>
</tr>

View File

@ -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

View File

@ -4,6 +4,10 @@ zh_tw:
survey: 問卷調查
survey:
type:
'0': "總分"
'1': "平均"
weight: 權重
taken_survey: "填寫問卷"
please_login_first: "請先登入網站!"
view: 查看