Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun
	
		
	
				
					
				
			
						commit
						dda031a599
					
				@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					$(document).on('turbolinks:load', function() {
 | 
				
			||||||
 | 
					  if ($('body.admins-user-statistics-index-page').length > 0) {
 | 
				
			||||||
 | 
					    var $form = $('.user-statistic-list-form');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ************** 学校选择 *************
 | 
				
			||||||
 | 
					    var matcherFunc = function(params, data){
 | 
				
			||||||
 | 
					      if ($.trim(params.term) === '') {
 | 
				
			||||||
 | 
					        return data;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (typeof data.text === 'undefined') {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (data.name && data.name.indexOf(params.term) > -1) {
 | 
				
			||||||
 | 
					        var modifiedData = $.extend({}, data, true);
 | 
				
			||||||
 | 
					        return modifiedData;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Return `null` if the term should not be displayed
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var defineSchoolSelect = function (schools) {
 | 
				
			||||||
 | 
					      $form.find('.school-select').select2({
 | 
				
			||||||
 | 
					        theme: 'bootstrap4',
 | 
				
			||||||
 | 
					        placeholder: '选择学校/单位',
 | 
				
			||||||
 | 
					        minimumInputLength: 1,
 | 
				
			||||||
 | 
					        data: schools,
 | 
				
			||||||
 | 
					        templateResult: function (item) {
 | 
				
			||||||
 | 
					          if(!item.id || item.id === '') return item.text;
 | 
				
			||||||
 | 
					          return item.name;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        templateSelection: function(item){
 | 
				
			||||||
 | 
					          if (item.id) {
 | 
				
			||||||
 | 
					            $form.find('#school_id').val(item.id);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return item.name || item.text;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        matcher: matcherFunc
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 初始化学校选择器
 | 
				
			||||||
 | 
					    $.ajax({
 | 
				
			||||||
 | 
					      url: '/api/schools/for_option.json',
 | 
				
			||||||
 | 
					      dataType: 'json',
 | 
				
			||||||
 | 
					      type: 'GET',
 | 
				
			||||||
 | 
					      success: function(data) {
 | 
				
			||||||
 | 
					        defineSchoolSelect(data.schools);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $form.on('click', '.clear-btn', function(){
 | 
				
			||||||
 | 
					      $form.find('select[name="date"]').val('');
 | 
				
			||||||
 | 
					      $form.find('.school-select').val('').trigger('change');
 | 
				
			||||||
 | 
					      $form.find('input[type="submit"]').trigger('click');
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					class Admins::UserStatisticsController < Admins::BaseController
 | 
				
			||||||
 | 
					  def index
 | 
				
			||||||
 | 
					    default_sort('finish_shixun_count', 'desc')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    total_count, users = Admins::UserStatisticQuery.call(params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @users = paginate users, total_count: total_count
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -1,9 +1,15 @@
 | 
				
			|||||||
class ApplicationRecord < ActiveRecord::Base
 | 
					class ApplicationRecord < ActiveRecord::Base
 | 
				
			||||||
  include NumberDisplayHelper
 | 
					  include NumberDisplayHelper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  attr_accessor :_extra_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  self.abstract_class = true
 | 
					  self.abstract_class = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def format_time(time)
 | 
					  def format_time(time)
 | 
				
			||||||
    time.present? ? time.strftime('%Y-%m-%d %H:%M') : ''
 | 
					    time.present? ? time.strftime('%Y-%m-%d %H:%M') : ''
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def display_extra_data(key)
 | 
				
			||||||
 | 
					    _extra_data&.[](key)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					class Admins::UserStatisticQuery < ApplicationQuery
 | 
				
			||||||
 | 
					  include CustomSortable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  attr_reader :params
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  sort_columns :study_challenge_count, :finish_challenge_count, :study_shixun_count, :finish_shixun_count,
 | 
				
			||||||
 | 
					               default_by: :finish_shixun_count, default_direction: :desc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(params)
 | 
				
			||||||
 | 
					    @params = params
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def call
 | 
				
			||||||
 | 
					    users = User.where(type: 'User').group(:id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    users = users.joins(:user_extension).where(user_extensions: { school_id: params[:school_id] }) if params[:school_id].present?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    total = users.count.count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 根据排序字段进行查询
 | 
				
			||||||
 | 
					    users = query_by_sort_column(users, params[:sort_by])
 | 
				
			||||||
 | 
					    users = custom_sort(users, params[:sort_by], params[:sort_direction])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    users = users.includes(user_extension: [:school, :department])
 | 
				
			||||||
 | 
					    users = users.limit(page_size).offset(offset).to_a
 | 
				
			||||||
 | 
					    # 查询并组装其它数据
 | 
				
			||||||
 | 
					    users = package_other_data(users)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [total, users]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def package_other_data(users)
 | 
				
			||||||
 | 
					    ids = users.map(&:id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    study_myshixun   = Myshixun.where(user_id: ids)
 | 
				
			||||||
 | 
					    finish_myshixun  = Myshixun.where(user_id: ids, status: 1)
 | 
				
			||||||
 | 
					    study_challenge  = Game.joins(:myshixun).where(myshixuns: { user_id: ids }).where(status: [0, 1, 2])
 | 
				
			||||||
 | 
					    finish_challenge = Game.joins(:myshixun).where(myshixuns: { user_id: ids }).where(status: 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if time_range.present?
 | 
				
			||||||
 | 
					      study_myshixun   = study_myshixun.where(updated_at: time_range)
 | 
				
			||||||
 | 
					      finish_myshixun  = finish_myshixun.where(updated_at: time_range)
 | 
				
			||||||
 | 
					      study_challenge  = study_challenge.where(updated_at: time_range)
 | 
				
			||||||
 | 
					      finish_challenge = finish_challenge.where(updated_at: time_range)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    study_myshixun_map   = study_myshixun.group(:user_id).count
 | 
				
			||||||
 | 
					    finish_myshixun_map  = finish_myshixun.group(:user_id).count
 | 
				
			||||||
 | 
					    study_challenge_map  = study_challenge.group(:user_id).count
 | 
				
			||||||
 | 
					    finish_challenge_map = finish_challenge.group(:user_id).count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    users.each do |user|
 | 
				
			||||||
 | 
					      user._extra_data = {
 | 
				
			||||||
 | 
					        study_shixun_count: study_myshixun_map.fetch(user.id, 0),
 | 
				
			||||||
 | 
					        finish_shixun_count: finish_myshixun_map.fetch(user.id, 0),
 | 
				
			||||||
 | 
					        study_challenge_count: study_challenge_map.fetch(user.id, 0),
 | 
				
			||||||
 | 
					        finish_challenge_count: finish_challenge_map.fetch(user.id, 0),
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    users
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def query_by_sort_column(users, sort_by_column)
 | 
				
			||||||
 | 
					    base_query_column = 'users.*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case sort_by_column.to_s
 | 
				
			||||||
 | 
					    when 'study_shixun_count' then
 | 
				
			||||||
 | 
					      users =
 | 
				
			||||||
 | 
					        if time_range.present?
 | 
				
			||||||
 | 
					          users.joins("LEFT JOIN myshixuns ON myshixuns.user_id = users.id "\
 | 
				
			||||||
 | 
					                      "AND myshixuns.updated_at BETWEEN '#{time_range.min}' AND '#{time_range.max}'")
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          users.left_joins(:myshixuns)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      users.select("#{base_query_column}, COUNT(*) study_shixun_count")
 | 
				
			||||||
 | 
					    when 'finish_shixun_count' then
 | 
				
			||||||
 | 
					      users =
 | 
				
			||||||
 | 
					        if time_range.present?
 | 
				
			||||||
 | 
					          users.joins("LEFT JOIN myshixuns ON myshixuns.user_id = users.id AND myshixuns.status = 1 AND "\
 | 
				
			||||||
 | 
					                      "myshixuns.updated_at BETWEEN '#{time_range.min}' AND '#{time_range.max}'")
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          users.left_joins(:myshixuns).where(myshixuns: { status: 1 })
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      users.select("#{base_query_column}, COUNT(*) finish_shixun_count")
 | 
				
			||||||
 | 
					    when 'study_challenge_count' then
 | 
				
			||||||
 | 
					      users =
 | 
				
			||||||
 | 
					        if time_range.present?
 | 
				
			||||||
 | 
					          users.joins('LEFT JOIN myshixuns ON myshixuns.user_id = users.id')
 | 
				
			||||||
 | 
					            .joins("LEFT JOIN games ON games.myshixun_id = myshixuns.id "\
 | 
				
			||||||
 | 
					                   "AND games.status IN (0,1,2) AND games.updated_at BETWEEN '#{time_range.min}' AND '#{time_range.max}'")
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          users.left_joins(myshixuns: :games).where(games: { status: [0, 1, 2] })
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      users.select("#{base_query_column}, COUNT(*) study_challenge_count")
 | 
				
			||||||
 | 
					    when 'finish_challenge_count' then
 | 
				
			||||||
 | 
					      users =
 | 
				
			||||||
 | 
					        if time_range.present?
 | 
				
			||||||
 | 
					          users.joins('LEFT JOIN myshixuns ON myshixuns.user_id = users.id')
 | 
				
			||||||
 | 
					            .joins("LEFT JOIN games ON games.myshixun_id = myshixuns.id "\
 | 
				
			||||||
 | 
					                   "AND games.status = 2 AND games.updated_at BETWEEN '#{time_range.min}' AND '#{time_range.max}'")
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          users.left_joins(myshixuns: :games).where(games: { status: 2 })
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      users.select("#{base_query_column}, COUNT(*) finish_challenge_count")
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      users
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def time_range
 | 
				
			||||||
 | 
					    @_time_range ||= begin
 | 
				
			||||||
 | 
					      case params[:date]
 | 
				
			||||||
 | 
					      when 'weekly'    then 1.weeks.ago..Time.now
 | 
				
			||||||
 | 
					      when 'monthly'   then 1.months.ago..Time.now
 | 
				
			||||||
 | 
					      when 'quarterly' then 3.months.ago..Time.now
 | 
				
			||||||
 | 
					      when 'yearly'    then 1.years.ago..Time.now
 | 
				
			||||||
 | 
					      else ''
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def page_size
 | 
				
			||||||
 | 
					    params[:per_page].to_i.zero? ? 20 : params[:per_page].to_i
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def offset
 | 
				
			||||||
 | 
					    (params[:page].to_i.zero? ? 0 : params[:page].to_i - 1) * page_size
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					<% define_admin_breadcrumbs do %>
 | 
				
			||||||
 | 
					  <% add_admin_breadcrumb('用户实训情况') %>
 | 
				
			||||||
 | 
					<% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="box search-form-container user-statistic-list-form">
 | 
				
			||||||
 | 
					  <%= form_tag(admins_user_statistics_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
 | 
				
			||||||
 | 
					    <div class="form-group col-12 col-md-auto">
 | 
				
			||||||
 | 
					      <label for="status">时间范围:</label>
 | 
				
			||||||
 | 
					      <% data_arrs = [['不限', ''], ['最近一周', 'weekly'], ['最近一个月', 'monthly'], ['最近三个月', 'quarterly'], ['最近一年', 'yearly']] %>
 | 
				
			||||||
 | 
					      <%= select_tag(:date, options_for_select(data_arrs, params[:date]), class: 'form-control') %>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="form-group col-12 col-md-3">
 | 
				
			||||||
 | 
					      <label for="school_name">所属单位:</label>
 | 
				
			||||||
 | 
					      <%= hidden_field_tag(:school_id, params[:school_id]) %>
 | 
				
			||||||
 | 
					      <%= select_tag :school_name, options_for_select([''], params[:school_id]), class: 'form-control school-select flex-1' %>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
 | 
				
			||||||
 | 
					    <input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
 | 
				
			||||||
 | 
					  <% end %>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="box user-statistic-list-container">
 | 
				
			||||||
 | 
					  <%= render partial: 'admins/user_statistics/shared/list', locals: { users: @users } %>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					$('.user-statistic-list-container').html("<%= j( render partial: 'admins/user_statistics/shared/list', locals: { users: @users } ) %>");
 | 
				
			||||||
@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					<table class="table table-hover text-center user-statistic-list-table">
 | 
				
			||||||
 | 
					  <thead class="thead-light">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <th width="14%" class="text-left">姓名</th>
 | 
				
			||||||
 | 
					    <th width="38%" class="text-left">单位部门</th>
 | 
				
			||||||
 | 
					    <th width="12%"><%= sort_tag('学习关卡数', name: 'study_challenge_count', path: admins_user_statistics_path) %></th>
 | 
				
			||||||
 | 
					    <th width="12%"><%= sort_tag('完成关卡数', name: 'finish_challenge_count', path: admins_user_statistics_path) %></th>
 | 
				
			||||||
 | 
					    <th width="12%"><%= sort_tag('学习实训数', name: 'study_shixun_count', path: admins_user_statistics_path) %></th>
 | 
				
			||||||
 | 
					    <th width="12%"><%= sort_tag('完成实训数', name: 'finish_shixun_count', path: admins_user_statistics_path) %></th>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  </thead>
 | 
				
			||||||
 | 
					  <tbody>
 | 
				
			||||||
 | 
					  <% if users.present? %>
 | 
				
			||||||
 | 
					    <% users.each do |user| %>
 | 
				
			||||||
 | 
					      <tr class="user-statistic-item-<%= user.id %>">
 | 
				
			||||||
 | 
					        <td class="text-left">
 | 
				
			||||||
 | 
					          <%= link_to "/users/#{user.login}", target: '_blank' do %>
 | 
				
			||||||
 | 
					            <%= overflow_hidden_span user.real_name, width: 100 %>
 | 
				
			||||||
 | 
					          <% end %>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td class="text-left"><%= display_text [user.school_name.presence, user.department_name.presence].compact.join(' - ') %></td>
 | 
				
			||||||
 | 
					        <td><%= user.display_extra_data(:study_challenge_count) %></td>
 | 
				
			||||||
 | 
					        <td><%= user.display_extra_data(:finish_challenge_count) %></td>
 | 
				
			||||||
 | 
					        <td><%= user.display_extra_data(:study_shixun_count) %></td>
 | 
				
			||||||
 | 
					        <td><%= user.display_extra_data(:finish_shixun_count) %></td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					  <% else %>
 | 
				
			||||||
 | 
					    <%= render 'admins/shared/no_data_for_table' %>
 | 
				
			||||||
 | 
					  <% end %>
 | 
				
			||||||
 | 
					  </tbody>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<%= render partial: 'admins/shared/paginate', locals: { objects: users } %>
 | 
				
			||||||
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								
					Loading…
					
					
				
		Reference in new issue