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 |