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.
114 lines
4.3 KiB
114 lines
4.3 KiB
class Ecs::QueryCourseEvaluationService < ApplicationService
|
|
attr_reader :ec_course, :evaluation_status
|
|
|
|
def initialize(ec_course)
|
|
@ec_course = ec_course
|
|
@_course_achievement = 0
|
|
end
|
|
|
|
def course_targets
|
|
@_course_targets ||= calculate_course_targets
|
|
end
|
|
|
|
def course_achievement
|
|
course_targets
|
|
|
|
@_course_achievement.round(2)
|
|
end
|
|
|
|
def graduation_subitem_evaluations
|
|
student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id)
|
|
student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id')
|
|
student_score_map = student_scores.group_by { |item| item.ec_course_target_id }
|
|
|
|
subitem_targets = ec_course.ec_graduation_subitem_course_targets
|
|
.includes(ec_graduation_subitem: :ec_graduation_requirement)
|
|
|
|
subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr|
|
|
subitem = arr.first.ec_graduation_subitem
|
|
|
|
support = subitem.ec_course_supports.find_by(ec_course_id: ec_course.id)
|
|
|
|
weight = support.weights.to_f
|
|
objective_achievement = (weight * ec_course.ec_year.calculation_value.to_f).round(3)
|
|
|
|
target_total_rates = 0
|
|
reach_real_target = 0
|
|
|
|
arr.map(&:ec_course_target).uniq.each do |target|
|
|
target_total_rates += target.weight.to_f
|
|
student_score = student_score_map[target.id]
|
|
|
|
reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score
|
|
end
|
|
|
|
actually_achievement = target_total_rates.zero? ? 0 : (reach_real_target * weight) / (target_total_rates.round(3) * 100)
|
|
|
|
{
|
|
graduation_subitem_id: subitem.id,
|
|
content: subitem.content,
|
|
position: subitem.position,
|
|
graduation_requirement_position: subitem.ec_graduation_requirement.position,
|
|
weights: format('%.02f', weight),
|
|
support_course_target_ids: arr.map(&:ec_course_target_id),
|
|
objective_achievement: format('%.03f', objective_achievement),
|
|
actually_achievement: format('%.03f', actually_achievement),
|
|
status: achieve_status(objective_achievement, actually_achievement)
|
|
}
|
|
end
|
|
end
|
|
|
|
def score_levels_map
|
|
@_score_levels_map ||= begin
|
|
ec_course.ec_score_levels.each_with_object({}) do |level, obj|
|
|
obj[level.id.to_s] = level.as_json(only: %i[id position score level])
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def calculate_course_targets
|
|
score_levels = ec_course.ec_score_levels.to_a
|
|
|
|
ec_course.ec_course_targets.includes(:ec_student_score_targets).map do |course_target|
|
|
data = course_target.as_json(only: %i[id position content standard_grade])
|
|
data[:weight] = course_target.weight
|
|
|
|
score_targets = course_target.ec_student_score_targets.to_a
|
|
data[:average_score] = score_targets.size.zero? ? 0 : score_targets.sum(&:score).fdiv(score_targets.size).round(2)
|
|
data[:maximum_score] = score_targets.max_by(&:score)&.score
|
|
data[:minimum_score] = score_targets.min_by(&:score)&.score
|
|
data[:actually_grade] = data[:average_score]
|
|
|
|
data[:status] = achieve_status(course_target.standard_grade, data[:average_score])
|
|
|
|
# 计算总评成绩
|
|
@_course_achievement += data[:average_score].to_f * course_target.weight.to_f
|
|
|
|
# 计算学生成绩分布区间
|
|
data[:score_levels] = score_levels.map do |score_level|
|
|
level_condition_proc =
|
|
if (score_level.position - 1).zero? # 第一区间
|
|
-> (score_target){ score_target.score >= score_level.score ? 1 : 0 }
|
|
elsif score_levels.position == score_levels.size # 末尾区间
|
|
-> (score_target){ score_target.score < score_level.score ? 1 : 0 }
|
|
else
|
|
# 中间区间
|
|
-> (score_target){ score_target.score >= score_level.score && score_target.score < score_targets[score_level.position - 1] ? 1 : 0 }
|
|
end
|
|
|
|
# 计算该成绩区间人数
|
|
count = score_targets.sum(&level_condition_proc)
|
|
|
|
{ id: score_level.id, count: count }
|
|
end
|
|
|
|
data
|
|
end
|
|
end
|
|
|
|
def achieve_status(standard_value, real_value)
|
|
standard_value && real_value && real_value >= standard_value ? 'achieved' : 'not_achieved'
|
|
end
|
|
end |