Merge branch 'develop' of https://bdgit.educoder.net/Hjqreturn/pgfqe6ch8 into develop
	
		
	
				
					
				
			
						commit
						0486340146
					
				| @ -1,20 +1,44 @@ | |||||||
| class Managements::SchoolsController < Managements::BaseController | class Managements::SchoolsController < Managements::BaseController | ||||||
|   before_filter :set_navigation_bar |   before_filter :set_navigation_bar | ||||||
|   before_filter :set_default_sort_params, only: :statistics |   before_filter :contrast_column_select_options, only: [:data_contrast] | ||||||
| 
 | 
 | ||||||
|   def statistics |   def statistics | ||||||
|     @sub_type = 1 |     @sub_type = 1 | ||||||
|  |     params[:sort_by] ||= :teacher_count | ||||||
|  |     params[:sort_direction] ||= :desc | ||||||
|  | 
 | ||||||
|     schools = Management::SchoolReportService.new(params).call |     schools = Management::SchoolReportService.new(params).call | ||||||
|     @schools = paginateHelper schools |     @schools = paginateHelper schools | ||||||
|   end |   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 |   private | ||||||
|   def set_navigation_bar |   def set_navigation_bar | ||||||
|     @menu_type = 1 |     @menu_type = 1 | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def set_default_sort_params |   def contrast_column_select_options | ||||||
|     params[:sort_by] ||= :teacher_count |     @select_options = Management::SchoolDataContrastService::CONTRAST_COLUMN_LIST.map do |column| | ||||||
|     params[:sort_direction] ||= :desc |       [I18n.t("school_daily_report.#{column}"), column] | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | class SchoolDailyReport < ActiveRecord::Base | ||||||
|  |   belongs_to :school | ||||||
|  | end | ||||||
| @ -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 | ||||||
| @ -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 | ||||||
| @ -0,0 +1,31 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |   <meta charset="utf-8" /> | ||||||
|  |   <title><%= h html_title %></title> | ||||||
|  |   <meta name="description" content="高校智能课堂与综合实训平台" /> | ||||||
|  |   <meta name="keywords" content="智能课堂,实训项目" /> | ||||||
|  |   <%= csrf_meta_tag %> | ||||||
|  |   <%= favicon %> | ||||||
|  |   <%= javascript_edu_index_heads %> | ||||||
|  |   <%= stylesheet_link_tag 'educoder/edu-main', 'educoder/edu-all', 'educoder/magic-check'  %> | ||||||
|  | 
 | ||||||
|  | </head> | ||||||
|  | 
 | ||||||
|  | <div class="newContainer"> | ||||||
|  |   <div class="newHeader" id="nHeader"> | ||||||
|  |     <%= render 'layouts/logined_header' %> | ||||||
|  |   </div> | ||||||
|  |   <div class="newMain clearfix"> | ||||||
|  |     <%= yield %> | ||||||
|  |   </div> | ||||||
|  |   <%= render :partial => 'layouts/footer' %> | ||||||
|  | </div> | ||||||
|  | <div id="ajax-indicator" style="display:none;"> | ||||||
|  |   <span><%= l(:label_loading) %></span> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | </body> | ||||||
|  | <%= javascript_include_tag 'educoder/edu_application','educoder/jquery.raty' %> | ||||||
|  | </html> | ||||||
|  | 
 | ||||||
| @ -0,0 +1,223 @@ | |||||||
|  | <form class="management-school-data-form"> | ||||||
|  |   <div style="float: left; margin: 10px 10px 10px 25px;"> | ||||||
|  |     <%= hidden_field_tag :contrast_column, params[:contrast_column] %> | ||||||
|  |     <%= hidden_field_tag :begin_date, params[:begin_date] %> | ||||||
|  |     <%= hidden_field_tag :end_date, params[:end_date] %> | ||||||
|  |     <%= hidden_field_tag :other_begin_date, params[:other_begin_date] %> | ||||||
|  |     <%= hidden_field_tag :other_end_date, params[:other_end_date] %> | ||||||
|  | 
 | ||||||
|  |     <%= text_field_tag :date_input, params[:date_input], | ||||||
|  |                        class: 'date-input winput-200-30', placeholder: '请选择时间段一' %> | ||||||
|  |     <span>VS</span> | ||||||
|  |     <%= text_field_tag :other_date_input, params[:other_date_input], | ||||||
|  |                        class: 'other-date-input winput-200-30', placeholder: '请选择时间段二' %> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <div style="float: left;"> | ||||||
|  |     <%= hidden_field_tag :data_type, params[:data_type] || 'yesterday' %> | ||||||
|  |     <% if params[:data_type] == 'contrast' %> | ||||||
|  |       <a href="javascript:void(0)" class="fl task-btn ml5 mt10 contrast-btn task-btn-orange">时间对比</a> | ||||||
|  |       <a href="javascript:void(0)" class="fl task-btn ml5 mt10 yesterday-btn">日新增</a> | ||||||
|  |     <% else %> | ||||||
|  |       <a href="javascript:void(0)" class="fl task-btn ml5 mt10 contrast-btn">时间对比</a> | ||||||
|  |       <a href="javascript:void(0)" class="fl task-btn ml5 mt10 yesterday-btn task-btn-orange">日新增</a> | ||||||
|  |     <% end %> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <%= text_field_tag :keyword, params[:keyword], placeholder: '请输入单位名称或者ID关键字进行搜索', | ||||||
|  |                      class: 'fl task-form-30 task-height-30 mt10', style: 'margin: 10px 10px 10px 25px;' %> | ||||||
|  |   <%= link_to '搜索', 'javascript:void(0)', class: 'fl task-btn task-btn-orange ml5 mt10 search-btn' %> | ||||||
|  |   <%= link_to '清除', 'javascript:void(0)', class: 'fl task-btn ml5 mt2 mt10 reset-btn' %> | ||||||
|  | </form> | ||||||
|  | <script> | ||||||
|  |   $(function(){ | ||||||
|  |     var yesterdayFormUrl = "<%= school_yesterday_data_managements_path %>"; | ||||||
|  |     var contrastFormUrl = "<%= school_data_contrast_managements_path %>"; | ||||||
|  | 
 | ||||||
|  |     var searchForm = $(".management-school-data-form"); | ||||||
|  |     var dataTypeInput = searchForm.find("input[name='data_type']"); | ||||||
|  |     var keywordInput = searchForm.find("input[name='keyword']"); | ||||||
|  |     var contrastBtn = searchForm.find(".contrast-btn"); | ||||||
|  |     var yesterdayBtn = searchForm.find(".yesterday-btn"); | ||||||
|  | 
 | ||||||
|  |     var beginDateInput = searchForm.find("input[name='begin_date']"); | ||||||
|  |     var endDateInput = searchForm.find("input[name='end_date']"); | ||||||
|  |     var otherBeginDateInput = searchForm.find("input[name='other_begin_date']"); | ||||||
|  |     var otherEndDateInput = searchForm.find("input[name='other_end_date']"); | ||||||
|  | 
 | ||||||
|  |     // 数据展示切换: 数据对比、日新增 | ||||||
|  |     searchForm.on('click', ".contrast-btn", function(){ | ||||||
|  |       if(contrastBtn.hasClass("task-btn-orange")) { return } | ||||||
|  |       changeDataType("contrast"); | ||||||
|  |     }); | ||||||
|  |     searchForm.on('click', ".yesterday-btn", function(){ | ||||||
|  |       if(yesterdayBtn.hasClass("task-btn-orange")) { return } | ||||||
|  |       changeDataType("yesterday"); | ||||||
|  |       submitForm(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // 搜索按钮 | ||||||
|  |     searchForm.on('click', ".search-btn", function(){ | ||||||
|  |       submitForm(); | ||||||
|  |     }); | ||||||
|  |     searchForm.on("click", ".reset-btn", function(){ | ||||||
|  |       keywordInput.val(""); | ||||||
|  |       submitForm(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     $('.contrast-column-select').on('change', function() { | ||||||
|  |       searchForm.find("input[name='contrast_column']").val($('.contrast-column-select').val()); | ||||||
|  |       submitForm(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     var submitForm = function(){ | ||||||
|  |       if(!validateFrom()) { return } | ||||||
|  | 
 | ||||||
|  |       var form = searchForm; | ||||||
|  |       var url = dataTypeInput.val() == "contrast" ? contrastFormUrl : yesterdayFormUrl; | ||||||
|  | 
 | ||||||
|  |       $.ajax({ | ||||||
|  |         url: url, | ||||||
|  |         data: form.serialize(), | ||||||
|  |         dataType: "script" | ||||||
|  |       }) | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var validateFrom = function(){ | ||||||
|  |       if (dataTypeInput.val() != "contrast") { return true; } | ||||||
|  | 
 | ||||||
|  |       if (beginDateInput.val() == "" || endDateInput.val() == "" || | ||||||
|  |         otherBeginDateInput.val() == "" || otherBeginDateInput.val() == "") { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return true; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var changeDataType = function(dataType){ | ||||||
|  |       if (dataTypeInput.val() == dataType) { return } | ||||||
|  | 
 | ||||||
|  |       if (dataType == "contrast") { | ||||||
|  |         contrastBtn.addClass("task-btn-orange"); | ||||||
|  |         yesterdayBtn.removeClass("task-btn-orange"); | ||||||
|  |         dataTypeInput.val('contrast'); | ||||||
|  |       } else { | ||||||
|  |         contrastBtn.removeClass("task-btn-orange"); | ||||||
|  |         yesterdayBtn.addClass("task-btn-orange"); | ||||||
|  |         dataTypeInput.val('yesterday'); | ||||||
|  | 
 | ||||||
|  |         clearContrastDateInput(); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var clearContrastDateInput = function(){ | ||||||
|  |       searchForm.find("input[name='begin_date']").val(''); | ||||||
|  |       searchForm.find("input[name='end_date']").val(''); | ||||||
|  |       searchForm.find("input[name='other_begin_date']").val(''); | ||||||
|  |       searchForm.find("input[name='other_end_date']").val(''); | ||||||
|  |       searchForm.find("input[name='date_input']").val(''); | ||||||
|  |       searchForm.find("input[name='other_date_input']").val(''); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // 日期选择 | ||||||
|  |     var locale = { | ||||||
|  |       clearText: '清除', | ||||||
|  |       clearStatus: '清除已选日期', | ||||||
|  |       closeText: '关闭', | ||||||
|  |       closeStatus: '不改变当前选择', | ||||||
|  |       prevText: '< 上月', | ||||||
|  |       prevStatus: '显示上月', | ||||||
|  |       prevBigText: '<<', | ||||||
|  |       prevBigStatus: '显示上一年', | ||||||
|  |       nextText: '下月>', | ||||||
|  |       nextStatus: '显示下月', | ||||||
|  |       nextBigText: '>>', | ||||||
|  |       nextBigStatus: '显示下一年', | ||||||
|  |       currentText: '今天', | ||||||
|  |       currentStatus: '显示本月', | ||||||
|  |       monthNames: ['一月','二月','三月','四月','五月','六月', '七月','八月','九月','十月','十一月','十二月'], | ||||||
|  |       monthNamesShort: ['一月','二月','三月','四月','五月','六月', '七月','八月','九月','十月','十一月','十二月'], | ||||||
|  |       monthStatus: '选择月份', | ||||||
|  |       yearStatus: '选择年份', | ||||||
|  |       weekHeader: '周', | ||||||
|  |       weekStatus: '年内周次', | ||||||
|  |       dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], | ||||||
|  |       dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], | ||||||
|  |       dayNamesMin: ['日','一','二','三','四','五','六'], | ||||||
|  |       dayStatus: '设置 DD 为一周起始', | ||||||
|  |       dateStatus: '选择 m月 d日, DD', | ||||||
|  |       dateFormat: 'yy-mm-dd', | ||||||
|  |       firstDay: 1, | ||||||
|  |       initStatus: '请选择日期', | ||||||
|  |       isRTL: false | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var options = { | ||||||
|  |       dateFormat: 'yy-mm-dd', | ||||||
|  |       minDate: new Date('2017-04-01'), | ||||||
|  |       maxDate: -1, | ||||||
|  |       onSelect: function(selectedDate) { | ||||||
|  |         if(!$(this).data().datepicker.first){ | ||||||
|  |           $(this).data().datepicker.inline = true; | ||||||
|  |           $(this).data().datepicker.first = selectedDate; | ||||||
|  | 
 | ||||||
|  |           if($(this).hasClass("date-input")){ | ||||||
|  |             beginDateInput.val(""); | ||||||
|  |             endDateInput.val(""); | ||||||
|  |           } else { | ||||||
|  |             otherBeginDateInput.val(""); | ||||||
|  |             otherEndDateInput.val(""); | ||||||
|  |           } | ||||||
|  |         }else{ | ||||||
|  |           // 计算时间先后顺序 | ||||||
|  |           var begin_date = null; | ||||||
|  |           var end_date = null; | ||||||
|  |           if(selectedDate > $(this).data().datepicker.first){ | ||||||
|  |             begin_date = $(this).data().datepicker.first; | ||||||
|  |             end_date = selectedDate; | ||||||
|  |           }else{ | ||||||
|  |             begin_date = selectedDate; | ||||||
|  |             end_date = $(this).data().datepicker.first; | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           // 记录所选时间 | ||||||
|  |           if($(this).hasClass("date-input")){ | ||||||
|  |             beginDateInput.val(begin_date); | ||||||
|  |             endDateInput.val(end_date); | ||||||
|  |           } else { | ||||||
|  |             otherBeginDateInput.val(begin_date); | ||||||
|  |             otherEndDateInput.val(end_date); | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           // 展示所选时间 | ||||||
|  |           $(this).val(begin_date + " 至 " + end_date); | ||||||
|  |           $(this).data().datepicker.inline = false; | ||||||
|  | 
 | ||||||
|  |           // 切换数据类型 | ||||||
|  |           changeDataType("contrast"); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       onClose:function(){ | ||||||
|  |         var date = $(this).data().datepicker.first; | ||||||
|  | 
 | ||||||
|  |         if (date) { | ||||||
|  |           if($(this).hasClass("date-input") && beginDateInput.val() == ""){ | ||||||
|  |             beginDateInput.val(date); | ||||||
|  |             endDateInput.val(date); | ||||||
|  |           } else if ($(this).hasClass("other-date-input") && otherBeginDateInput.val() == "") { | ||||||
|  |             otherBeginDateInput.val(date); | ||||||
|  |             otherEndDateInput.val(date); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         delete $(this).data().datepicker.first; | ||||||
|  |         $(this).data().datepicker.inline = false; | ||||||
|  | 
 | ||||||
|  |         submitForm(); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |     options = $.extend({}, locale, options); | ||||||
|  |     searchForm.find(".date-input").datepicker(options); | ||||||
|  |     searchForm.find(".other-date-input").datepicker(options); | ||||||
|  |   }); | ||||||
|  | </script> | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | <table class="edu-pop-table edu-txt-center" cellpadding="0" cellspacing="0" style="table-layout: fixed"> | ||||||
|  |   <thead> | ||||||
|  |   <tr> | ||||||
|  |     <th width="6%">序号</th> | ||||||
|  |     <th width="10%">ID</th> | ||||||
|  |     <th width="24%" class="edu-txt-left">单位名称</th> | ||||||
|  | 
 | ||||||
|  |     <th width="12%"><%= sort_tag('新增教师', name: 'teacher_increase_count', path: school_yesterday_data_managements_path) %></th> | ||||||
|  |     <th width="12%"><%= sort_tag('新增学生', name: 'student_increase_count', path: school_yesterday_data_managements_path) %></th> | ||||||
|  |     <th width="12%"><%= sort_tag('新增课堂', name: 'course_increase_count', path: school_yesterday_data_managements_path) %></th> | ||||||
|  |     <th width="12%"><%= sort_tag('新增实训', name: 'shixun_increase_count', path: school_yesterday_data_managements_path) %></th> | ||||||
|  |     <th width="12%"><%= sort_tag('活跃用户', name: 'active_user_count', path: school_yesterday_data_managements_path) %></th> | ||||||
|  |   </tr> | ||||||
|  |   </thead> | ||||||
|  |   <tbody> | ||||||
|  |     <% @reports.each_with_index do |report, index| %> | ||||||
|  |       <tr> | ||||||
|  |         <td><%= (@obj_pages.page - 1) * @obj_pages.per_page + index + 1 %></td> | ||||||
|  |         <td><%= report.school_id %></td> | ||||||
|  |         <td class="edu-txt-left"><%= report.school_name %></td> | ||||||
|  |         <td><%= report.teacher_increase_count %></td> | ||||||
|  |         <td><%= report.student_increase_count %></td> | ||||||
|  |         <td><%= report.course_increase_count %></td> | ||||||
|  |         <td><%= report.shixun_increase_count %></td> | ||||||
|  |         <td><%= report.active_user_count %></td> | ||||||
|  |       </tr> | ||||||
|  |     <% end %> | ||||||
|  |   </tbody> | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | <div style="text-align:center;" class="new_expand"> | ||||||
|  |   <div class="pages_user_show" style="width:auto; display:inline-block;margin: 18px 0;"> | ||||||
|  |     <ul id="school_yesterday_data_ref_pages"> | ||||||
|  |       <%= pagination_links_full @obj_pages, @obj_count, per_page_links: false, remote: true, flag: true, is_new: true, path: school_yesterday_data_managements_path(params.except(:page)) %> | ||||||
|  |     </ul> | ||||||
|  |     <div class="cl"></div> | ||||||
|  |   </div> | ||||||
|  | </div> | ||||||
| @ -0,0 +1,2 @@ | |||||||
|  | $("#managements-school-data").html("<%= j(render 'managements/schools/data_contrast_list') %>") | ||||||
|  | $(".management-school-data-form-box").html("<%= j(render 'managements/schools/contrast_search_form') %>") | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | <div class="edu-con-top clearfix xmt10 bor-grey-e mt10"> | ||||||
|  |   <div class="management-school-data-form-box"> | ||||||
|  |     <%= render 'managements/schools/contrast_search_form' %> | ||||||
|  |   </div> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <div class="edu-con-bg01 mt15" id="managements-school-data"> | ||||||
|  |   <%= render 'managements/schools/yesterday_data_list'%> | ||||||
|  | </div> | ||||||
| @ -0,0 +1,2 @@ | |||||||
|  | $("#managements-school-data").html("<%= j(render 'managements/schools/yesterday_data_list') %>") | ||||||
|  | $(".management-school-data-form-box").html("<%= j(render 'managements/schools/contrast_search_form') %>") | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | zh: | ||||||
|  |   school_daily_report: | ||||||
|  |     teacher_increase_count: 新增教师 | ||||||
|  |     student_increase_count: 新增学生 | ||||||
|  |     course_increase_count: 新增课堂 | ||||||
|  |     shixun_increase_count: 新增实训 | ||||||
|  |     active_user_count: 活跃用户 | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | # Use this file to easily define all of your cron jobs. | ||||||
|  | # | ||||||
|  | # It's helpful, but not entirely necessary to understand cron before proceeding. | ||||||
|  | # http://en.wikipedia.org/wiki/Cron | ||||||
|  | 
 | ||||||
|  | # Example: | ||||||
|  | # | ||||||
|  | # set :output, "/path/to/my/cron_log.log" | ||||||
|  | # | ||||||
|  | # every 2.hours do | ||||||
|  | #   command "/usr/bin/some_great_command" | ||||||
|  | #   runner "MyModel.some_method" | ||||||
|  | #   rake "some:great:rake:task" | ||||||
|  | # end | ||||||
|  | # | ||||||
|  | # every 4.days do | ||||||
|  | #   runner "AnotherModel.prune_old_records" | ||||||
|  | # end | ||||||
|  | 
 | ||||||
|  | # Learn more: http://github.com/javan/whenever | ||||||
|  | 
 | ||||||
|  | every 1.days, at: '5:00 am' do | ||||||
|  |   runner 'StatisticSchoolDailyReportTask.new.call' | ||||||
|  | end | ||||||
| @ -0,0 +1,18 @@ | |||||||
|  | class CreateSchoolDailyReports < ActiveRecord::Migration | ||||||
|  |   def change | ||||||
|  |     create_table :school_daily_reports do |t| | ||||||
|  |       t.integer :school_id | ||||||
|  |       t.string :school_name | ||||||
|  |       t.integer :teacher_increase_count | ||||||
|  |       t.integer :student_increase_count | ||||||
|  |       t.integer :course_increase_count | ||||||
|  |       t.integer :shixun_increase_count | ||||||
|  |       t.integer :active_user_count | ||||||
|  | 
 | ||||||
|  |       t.date :date | ||||||
|  |       t.timestamps | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     add_index :school_daily_reports, [:school_id, :date], unique: true | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,5 @@ | |||||||
|  | class AddBusinessToUser < ActiveRecord::Migration | ||||||
|  |   def change | ||||||
|  |     add_column :users, :business, :boolean, :default => false | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,103 @@ | |||||||
|  | #coding=utf-8 | ||||||
|  | 
 | ||||||
|  | namespace :school_daily_report do | ||||||
|  |   desc 'statistic school daily report data before now' | ||||||
|  |   task :statistic, [:date] => :environment do |_, args| | ||||||
|  |     date = Time.zone.parse(args[:date]).beginning_of_day | ||||||
|  |     current_date = (Time.zone.now - 5.hour).beginning_of_day | ||||||
|  |     custom_logger("statistic range: #{date}..#{current_date}") | ||||||
|  | 
 | ||||||
|  |     while current_date > date | ||||||
|  |       date_str = date.strftime('%Y-%m-%d') | ||||||
|  |       # 检查当天数据是否已经统计 | ||||||
|  |       if SchoolDailyReport.exists?(date: date) | ||||||
|  |         custom_logger("Skip! statistics data exist, date: #{date_str}") | ||||||
|  |         date += 1.day | ||||||
|  |         next | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       school_count = School.count | ||||||
|  |       query_times = school_count % query_size == 0 ? school_count / query_size : (school_count / query_size) + 1 | ||||||
|  | 
 | ||||||
|  |       custom_logger("Start statistic => Date: #{date_str}, school count: #{school_count}, insert times: #{query_times} ~") | ||||||
|  |       query_times.times do |index| | ||||||
|  |         sql = school_daily_report_sql(date, query_size, index * query_size) | ||||||
|  |         reports = School.find_by_sql(sql) | ||||||
|  | 
 | ||||||
|  |         data = reports.map do |report| | ||||||
|  |           [ | ||||||
|  |             report['id'], report['name'], report['teacher_count'], report['student_count'], report['course_count'], | ||||||
|  |             report['shixun_count'], report['active_user_count'], date_str, current_datetime, current_datetime | ||||||
|  |           ] | ||||||
|  |         end | ||||||
|  |         batch_create_school_daily_reports!(data) | ||||||
|  |       end | ||||||
|  |       custom_logger("Statistic complete! date: #{date_str}") | ||||||
|  | 
 | ||||||
|  |       date += 1.day | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   desc 'clear school daily report data' | ||||||
|  |   task clear: :environment do | ||||||
|  |     SchoolDailyReport.destroy_all | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def query_size | ||||||
|  |     100 | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def current_datetime | ||||||
|  |     Time.zone.now.strftime('%Y-%m-%d %H:%M:%S') | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def custom_logger(str) | ||||||
|  |     p(str) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def batch_create_school_daily_reports!(arr) | ||||||
|  |     sql = build_insert_report_sql(arr) | ||||||
|  |     SchoolDailyReport.connection.execute(sql) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def build_insert_report_sql(arr) | ||||||
|  |     prefix = 'INSERT INTO school_daily_reports(school_id, school_name, teacher_increase_count, student_increase_count, '\ | ||||||
|  |       'course_increase_count, shixun_increase_count, active_user_count, date, created_at, updated_at) VALUES' | ||||||
|  |     # [[1,2], [3,4]] => ['"1", "2"', '"3", "4"'] => '("1", "2"),("3", "4")' | ||||||
|  |     values = '(' + arr.map { |item| '"' + item.join('","') + '"' }.join('),(') + ')' | ||||||
|  | 
 | ||||||
|  |     prefix + values | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def school_daily_report_sql(date, limit, offset) | ||||||
|  |     begin_date = (date + 5.hour).strftime('%Y-%m-%d %H:%M:%S') | ||||||
|  |     end_date   = (date + 1.day + 5.hour).strftime('%Y-%m-%d %H:%M:%S') | ||||||
|  | 
 | ||||||
|  |     <<-SQL | ||||||
|  |     SELECT schools.id, schools.name, ( | ||||||
|  |       SELECT COUNT(*) FROM users u  | ||||||
|  |       LEFT JOIN user_extensions ue ON ue.user_id = u.id  | ||||||
|  |       WHERE ue.school_id = schools.id AND ue.identity = #{User::STUDENT} | ||||||
|  |         AND u.created_on BETWEEN "#{begin_date}" AND "#{end_date}" | ||||||
|  |     ) student_count, ( | ||||||
|  |       SELECT COUNT(*) FROM users u  | ||||||
|  |       LEFT JOIN user_extensions ue ON ue.user_id = u.id  | ||||||
|  |       WHERE ue.school_id = schools.id AND ue.identity = #{User::TEACHER} | ||||||
|  |         AND u.created_on BETWEEN "#{begin_date}" AND "#{end_date}" | ||||||
|  |     ) teacher_count, ( | ||||||
|  |       SELECT COUNT(*) FROM courses cs  | ||||||
|  |       WHERE cs.school_id = schools.id  | ||||||
|  |         AND cs.created_at BETWEEN "#{begin_date}" AND "#{end_date}" | ||||||
|  |     ) course_count, ( | ||||||
|  |       SELECT COUNT(*) FROM shixuns sx  | ||||||
|  |       LEFT JOIN users u ON sx.user_id = u.id  | ||||||
|  |       LEFT JOIN user_extensions ue ON ue.user_id = u.id  | ||||||
|  |       WHERE ue.school_id = schools.id AND sx.created_at BETWEEN "#{begin_date}" AND "#{end_date}" | ||||||
|  |     ) shixun_count, ( | ||||||
|  |       SELECT COUNT(*) FROM users u  | ||||||
|  |       LEFT JOIN user_extensions ue ON ue.user_id = u.id  | ||||||
|  |       WHERE ue.school_id = schools.id AND u.last_login_on BETWEEN "#{begin_date}" AND "#{end_date}" | ||||||
|  |     ) active_user_count FROM schools LIMIT #{limit} OFFSET #{offset} | ||||||
|  |     SQL | ||||||
|  |   end | ||||||
|  | end | ||||||
					Loading…
					
					
				
		Reference in new issue