diff --git a/Gemfile b/Gemfile index a5bf637a..7d4ab7bf 100644 --- a/Gemfile +++ b/Gemfile @@ -60,6 +60,9 @@ gem 'kaminari' gem 'elasticsearch-model' gem 'elasticsearch-rails' +# cronjob +gem 'whenever', require: false + #Ruby 2.2+ has removed test/unit from the core library. if RUBY_VERSION>='2.2' gem 'test-unit', '~> 3.0' diff --git a/app/controllers/managements/schools_controller.rb b/app/controllers/managements/schools_controller.rb index 6684db66..6dfe84fb 100644 --- a/app/controllers/managements/schools_controller.rb +++ b/app/controllers/managements/schools_controller.rb @@ -1,20 +1,44 @@ class Managements::SchoolsController < Managements::BaseController before_filter :set_navigation_bar - before_filter :set_default_sort_params, only: :statistics + before_filter :contrast_column_select_options, only: [:data_contrast] def statistics @sub_type = 1 + params[:sort_by] ||= :teacher_count + params[:sort_direction] ||= :desc + schools = Management::SchoolReportService.new(params).call @schools = paginateHelper schools end + def yesterday_data + @sub_type = 2 + params[:sort_by] ||= :teacher_increase_count + params[:sort_direction] ||= :desc + + reports = Management::SchoolYesterdayDataService.new(params).call + @reports = paginateHelper reports + end + + def data_contrast + params[:contrast_column] = :teacher_increase_count if params[:contrast_column].blank? + params[:sort_direction] ||= :desc + params[:sort_by] ||= :percentage + + @obj_count, @reports = Management::SchoolDataContrastService.new(params).call + @obj_pages = Paginator.new(@obj_count, Management::SchoolDataContrastService::PAGE_SIZE, params[:page]) + rescue Management::SchoolDataContrastService::ParameterError + raise '参数错误' + end + private def set_navigation_bar @menu_type = 1 end - def set_default_sort_params - params[:sort_by] ||= :teacher_count - params[:sort_direction] ||= :desc + def contrast_column_select_options + @select_options = Management::SchoolDataContrastService::CONTRAST_COLUMN_LIST.map do |column| + [I18n.t("school_daily_report.#{column}"), column] + end end -end \ No newline at end of file +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c02f7e5a..6a5f8b8d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -671,7 +671,7 @@ module ApplicationHelper when 1 case sub_type when 1 then "统计总表" - when 2 then "变化报表" + when 2 then "数据变化报表" end when 2 sub_type == 1 ? "课程列表" : (sub_type == 2? "课堂列表" : (sub_type == 3? "实训作业" : "项目列表")) diff --git a/app/libs/custom_sortable.rb b/app/libs/custom_sortable.rb index 721cbd1e..a8549452 100644 --- a/app/libs/custom_sortable.rb +++ b/app/libs/custom_sortable.rb @@ -11,7 +11,7 @@ module CustomSortable sort_by ||= self.class.sort_options[:default_by] sort_direction ||= self.class.sort_options[:default_direction] - return relations unless self.class.check_sort_parameter_validate(sort_by, sort_direction) + return relations unless self.class.check_sort_parameter_validate(sort_by.to_s, sort_direction.to_s) order_method = self.class.sort_options[:reorder] ? :reorder : :order relations.send(order_method, "#{sort_by} #{sort_direction}") diff --git a/app/models/school_daily_report.rb b/app/models/school_daily_report.rb new file mode 100644 index 00000000..494eacfd --- /dev/null +++ b/app/models/school_daily_report.rb @@ -0,0 +1,3 @@ +class SchoolDailyReport < ActiveRecord::Base + belongs_to :school +end \ No newline at end of file diff --git a/app/models/shixun.rb b/app/models/shixun.rb index 6ab98172..54882be1 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -28,6 +28,7 @@ class Shixun < ActiveRecord::Base :propaedeutics, :trainee, :major_id, :homepage_show, :webssh, :hidden, :fork_from, :can_copy, :modify_time, :reset_time, :git_url, :use_scope, :vnc, :evaluate_script, :image_text, :exec_time, :test_set_permission, :hide_code, :excute_time, :forbid_copy + belongs_to :creator, foreign_key: :user_id, class_name: 'User' has_many :users, :through => :shixun_members has_many :shixun_members, :dependent => :destroy has_one :repository, :dependent => :destroy diff --git a/app/services/management/school_data_contrast_service.rb b/app/services/management/school_data_contrast_service.rb new file mode 100644 index 00000000..a1ad4c24 --- /dev/null +++ b/app/services/management/school_data_contrast_service.rb @@ -0,0 +1,66 @@ +class Management::SchoolDataContrastService + ParameterError = Class.new(StandardError) + + PAGE_SIZE = 20 + CONTRAST_COLUMN_LIST = %w( + teacher_increase_count student_increase_count course_increase_count + shixun_increase_count active_user_count + ).freeze + + attr_reader :params, :sort_direction, :contrast_column + + def initialize(params) + @params = params + @sort_direction = params[:sort_direction].to_s + @contrast_column = params[:contrast_column].to_s + end + + def call + validate_parameter! + reports = SchoolDailyReport.select(select_columns) + + keyword = params[:keyword].try(:to_s).try(:strip) + if keyword.present? + reports = reports.where("school_name LIKE :keyword OR school_id LIKE :keyword", keyword: "%#{keyword}%") + end + + reports = reports.group(:school_id) + count = reports.count.count + + [count, SchoolDailyReport.find_by_sql(query_report_sql(reports.to_sql))] + end + + private + def validate_parameter! + if %i[begin_date end_date other_begin_date other_end_date].any? { |key| params[key].blank? } + raise ParameterError + end + + unless %w(desc asc).include?(sort_direction) + raise ParameterError + end + + unless CONTRAST_COLUMN_LIST.include?(contrast_column) + raise ParameterError + end + end + + def format_date(date) + Time.zone.parse(date).strftime("%Y-%m-%d") + end + + def offset + (params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * PAGE_SIZE + end + + def select_columns + "school_id, school_name,"\ + "SUM(IF(date BETWEEN '#{format_date(params[:begin_date])}' AND '#{format_date(params[:end_date])}', #{contrast_column}, 0)) total,"\ + "SUM(IF(date BETWEEN '#{format_date(params[:other_begin_date])}' AND '#{format_date(params[:other_end_date])}', #{contrast_column}, 0)) other_total" + end + + def query_report_sql(from_sql) + "SELECT reports.*, (other_total - total) increase, (IF(other_total - total = 0, 0.0, round((other_total - total) / IF(total = 0, 1, total), 5))) percentage "\ + "FROM (#{from_sql}) reports ORDER BY percentage #{sort_direction} LIMIT #{PAGE_SIZE} OFFSET #{offset}" + end +end diff --git a/app/services/management/school_report_service.rb b/app/services/management/school_report_service.rb index 9b794b7b..5a962bd5 100644 --- a/app/services/management/school_report_service.rb +++ b/app/services/management/school_report_service.rb @@ -29,16 +29,12 @@ class Management::SchoolReportService <<-SQL schools.id, schools.name, ( - SELECT COUNT(*) FROM users u - LEFT JOIN user_extensions ue ON ue.user_id = u.id - LEFT JOIN ec_school_users esu ON esu.user_id = u.id - WHERE esu.school_id = schools.id AND ue.identity = #{User::STUDENT} + SELECT COUNT(*) FROM user_extensions ue + WHERE ue.school_id = schools.id AND ue.identity = #{User::STUDENT} ) student_count, ( - SELECT COUNT(*) FROM users u - LEFT JOIN user_extensions ue ON ue.user_id = u.id - LEFT JOIN ec_school_users esu ON esu.user_id = u.id - WHERE esu.school_id = schools.id AND ue.identity = #{User::TEACHER} + SELECT COUNT(*) FROM user_extensions ue + WHERE ue.school_id = schools.id AND ue.identity = #{User::TEACHER} ) teacher_count, ( SELECT COUNT(*) FROM homework_commons hc diff --git a/app/services/management/school_yesterday_data_service.rb b/app/services/management/school_yesterday_data_service.rb new file mode 100644 index 00000000..238a7297 --- /dev/null +++ b/app/services/management/school_yesterday_data_service.rb @@ -0,0 +1,32 @@ +class Management::SchoolYesterdayDataService + include CustomSortable + + attr_reader :params + + sort_columns :student_increase_count, :teacher_increase_count, + :course_increase_count, :shixun_increase_count, :active_user_count, + default_by: :teacher_increase_count, default_direction: :desc + + def initialize(params) + @params = params + end + + def call + reports = SchoolDailyReport.where(date: yesterday) + + keyword = params[:keyword].try(:to_s).try(:strip) + if keyword.present? + reports = reports.where("school_name LIKE :keyword OR school_id LIKE :keyword", keyword: "%#{keyword}%") + end + + reports = custom_sort(reports, params[:sort_by], params[:sort_direction]) + + reports + end + + private + def yesterday + # 每日凌晨5点为节点, 25日凌晨4点、3点、2点等等,未到更新数据时间点,看到的数据是:23日-24日的统计数据 + (Time.zone.now - 5.hours).beginning_of_day - 1.days + end +end diff --git a/app/tasks/statistic_school_daily_report_task.rb b/app/tasks/statistic_school_daily_report_task.rb new file mode 100644 index 00000000..3569351f --- /dev/null +++ b/app/tasks/statistic_school_daily_report_task.rb @@ -0,0 +1,44 @@ +class StatisticSchoolDailyReportTask + def call + School.find_each do |school| + # 新增教师和学生 + users = User.joins(:user_extensions) + .where(user_extensions: { school_id: school.id }) + + teacher_count = users.where(created_on: yesterday, user_extensions: { identity: User::TEACHER }).count + student_count = users.where(created_on: yesterday, user_extensions: { identity: User::STUDENT }).count + + # 活跃用户 + active_user_count = users.where(last_login_on: yesterday).count + + # 新增课堂 + course_count = school.courses.where(created_at: yesterday).count + + # 新增实训 + shixun_count = Shixun.joins(creator: :user_extensions) + .where('user_extensions.school_id = ?', school.id) + .where(created_at: yesterday).count + + create_params = { + school_id: school.id, school_name: school.name, teacher_increase_count: teacher_count, + student_increase_count: student_count, course_increase_count: course_count, + shixun_increase_count: shixun_count, active_user_count: active_user_count, date: current_date + } + SchoolDailyReport.create!(create_params) + end + end + + private + def current_date + @_current_date ||= Time.zone.now.beginning_of_day - 1.day + end + + def yesterday + @_yesterday ||= begin + # 每日凌晨5点为节点 + end_time = Time.zone.now.beginning_of_day + 5.hour + begin_time = end_time - 1.day + begin_time..end_time + end + end +end diff --git a/app/views/layouts/base_management.html.erb b/app/views/layouts/base_management.html.erb index c38bf3eb..9d1d77c8 100644 --- a/app/views/layouts/base_management.html.erb +++ b/app/views/layouts/base_management.html.erb @@ -35,6 +35,7 @@
序号 | +ID | +单位名称 | +时段一 <%= "(#{params[:begin_date]}至#{params[:end_date]})" %> |
+ 时段二 <%= "(#{params[:other_begin_date]}至#{params[:other_end_date]})" %> |
+
+ <%= sort_tag('变化情况', name: 'percentage', path: school_data_contrast_managements_path) %>
+ ( 新 增 数 | 新增百分比) + |
+ |||||
---|---|---|---|---|---|---|---|---|---|---|
<%= (@obj_pages.page - 1) * @obj_pages.per_page + index + 1 %> | +<%= report.school_id %> | +<%= report.school_name %> | +<%= report['total'] %> | +<%= report['other_total'] %> | + <% if report['increase'] > 0 %> ++ +<%= report['increase'] %> + | ++<%= report['percentage'] %>% | + <% elsif report['increase'].zero? %> ++ <%= report['increase'] %> + | +<%= report['percentage'] %> | + <% else %> ++ <%= report['increase'] %> + | +<%= report['percentage'] %>% | + <% end %> +
序号 | +ID | +单位名称 | + +<%= sort_tag('新增教师', name: 'teacher_increase_count', path: school_yesterday_data_managements_path) %> | +<%= sort_tag('新增学生', name: 'student_increase_count', path: school_yesterday_data_managements_path) %> | +<%= sort_tag('新增课堂', name: 'course_increase_count', path: school_yesterday_data_managements_path) %> | +<%= sort_tag('新增实训', name: 'shixun_increase_count', path: school_yesterday_data_managements_path) %> | +<%= sort_tag('活跃用户', name: 'active_user_count', path: school_yesterday_data_managements_path) %> | +
---|---|---|---|---|---|---|---|
<%= (@obj_pages.page - 1) * @obj_pages.per_page + index + 1 %> | +<%= report.school_id %> | +<%= report.school_name %> | +<%= report.teacher_increase_count %> | +<%= report.student_increase_count %> | +<%= report.course_increase_count %> | +<%= report.shixun_increase_count %> | +<%= report.active_user_count %> | +