Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

problem_set
daiao 5 years ago
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,6 +1,11 @@
module Base::PaginateHelper
extend ActiveSupport::Concern
def default_sort(sort_by, direction)
params[:sort_by] = params[:sort_by].presence || sort_by
params[:sort_direction] = params[:sort_direction].presence || direction
end
def offset
(page - 1) * per_page
end

@ -1,9 +1,15 @@
class ApplicationRecord < ActiveRecord::Base
include NumberDisplayHelper
attr_accessor :_extra_data
self.abstract_class = true
def format_time(time)
time.present? ? time.strftime('%Y-%m-%d %H:%M') : ''
end
def display_extra_data(key)
_extra_data&.[](key)
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

@ -39,6 +39,7 @@
<li>
<%= sidebar_item_group('#user-submenu', '用户', icon: 'user') do %>
<li><%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users') %></li>
<li><%= sidebar_item(admins_user_statistics_path, '用户实训情况', icon: 'area-chart', controller: 'admins-user_statistics') %></li>
<% end %>
</li>

@ -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 } %>

@ -904,6 +904,7 @@ Rails.application.routes.draw do
end
resource :import_users, only: [:create]
resource :import_course_members, only: [:create]
resources :user_statistics, only: [:index]
resources :library_applies, only: [:index] do
member do

File diff suppressed because one or more lines are too long

@ -134049,6 +134049,17 @@ $(document).on('turbolinks:load', function() {
});
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-competitions-index-page').length > 0) {
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $imageElement = $('.competition-image-' + data.source_id);
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
})
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-cooperatives-index-page').length > 0) {
// ------------ 保存链接 -----------
@ -135645,6 +135656,66 @@ $(document).on('turbolinks:load', function() {
}
})
;
$(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');
})
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-users-edit-page, body.admins-users-update-page').length > 0) {
var initDepartmentSelect = true;
Loading…
Cancel
Save