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

video_log
cxt 5 years ago
commit 5bc4b58755

@ -0,0 +1,75 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-user-schools-statistics-index-page').length > 0) {
var $form = $('.user-schools-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('select[name="province"]').val('');
$form.find('.school-select').val('').trigger('change');
$form.find('input[type="submit"]').trigger('click');
})
// 导出
$('.export-action').on('click', function(){
var form = $(".user-schools-statistic-list-form .search-form")
var exportLink = $(this);
var date = form.find("select[name='date']").val();
var schoolId = form.find('input[name="school_id"]').val();
var url = exportLink.data("url").split('?')[0] + "?date=" + date + "&school_id=" + schoolId;
window.open(url);
});
}
});

@ -6,12 +6,14 @@ class Admins::DashboardsController < Admins::BaseController
@new_user_count = User.where(created_on: current_month).count
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/monitor/getPodsInfo"
res = interface_get uri, 502, "数据接口延迟"
if res['code'] == 0
@pod_num = res['sum'] || 0
unless Rails.env.development?
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/monitor/getPodsInfo"
res = interface_get uri, 502, "数据接口延迟"
if res['code'] == 0
@pod_num = res['sum'] || 0
end
end
end

@ -0,0 +1,18 @@
class Admins::UserSchoolsStatisticsController < Admins::BaseController
def export
params[:per_page] = 10000
_count, @schools = Admins::UserSchoolsStatisticQuery.call(params)
filename = ['用户运营统计', Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx'
render xlsx: 'export', filename: filename
end
def index
default_sort('finish_challenge_count', 'desc')
total_count, schools = Admins::UserSchoolsStatisticQuery.call(params)
@schools = paginate schools, total_count: total_count
end
end

@ -46,7 +46,7 @@ class DiscussesController < ApplicationController
end
sql = "select d.id from discusses d join shixuns s on d.dis_id = s.id where s.status = 2 and s.hidden = false and d.root_id is null
and d.hidden = false #{sql1} #{sql2} order by d.created_at desc"
and d.hidden = false and d.dis_type = 'Shixun' #{sql1} #{sql2} order by d.created_at desc"
memo_ids = Discuss.find_by_sql(sql).pluck(:id)
@memo_count = memo_ids.size

@ -418,8 +418,8 @@ class ShixunsController < ApplicationController
logger.info("#########service_update_params: #{service_update_params}")
begin
ActiveRecord::Base.transaction do
@shixun.update_attributes(shixun_params)
@shixun.shixun_info.update_attributes(shixun_info_params)
@shixun.update_attributes!(shixun_params)
@shixun.shixun_info.update_attributes!(shixun_info_params)
# 镜像变动
@shixun.shixun_mirror_repositories.where.not(mirror_repository_id: old_mirror_ids).destroy_all
@shixun.shixun_mirror_repositories.create!(new_mirror_id) if new_mirror_id.present?

@ -5,7 +5,7 @@ class ShixunInfo < ApplicationRecord
# validates_presence_of :evaluate_script, message: "实训脚本不能为空"
after_commit :create_diff_record
validates :description, length: { maximum: 5000, too_long: "不能超过5000个字符" }
validates :description, length: { maximum: 10000, too_long: "不能超过10000个字符" }
private

@ -0,0 +1,160 @@
class Admins::UserSchoolsStatisticQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :study_challenge_count, :finish_challenge_count, :study_shixun_count, :finish_shixun_count,
default_by: :finish_challenge_count, default_direction: :desc
def initialize(params)
@params = params
end
def call
schools = School.all
if params[:province].present?
schools = schools.where("province like ?", "%#{params[:province]}%")
end
if params[:school_id].present?
schools = schools.where(id: params[:school_id])
end
total = schools.count
# 根据排序字段进行查询
#schools = query_by_sort_column(schools, params[:sort_by])
#schools = custom_sort(schools, params[:sort_by], params[:sort_direction])
#
schools = schools.limit(page_size).offset(offset).to_a
# 查询并组装其它数据
schools = package_other_data(schools)
[total, schools]
end
private
def package_other_data(schools)
ids = schools.map(&:id)
user_e = UserExtension.where(school_id: schools.map(&:id))
#study_myshixun = Myshixun.joins("join user_extensions ue on ue.user_id = myshixuns.user_id").where(ue: {school_id: ids})
#finish_myshixun = Myshixun.joins("join user_extensions ue on ue.user_id = myshixuns.user_id")
# .where(ue: {school_id: ids}, myshixuns: {status: 1})
study_challenge = Game.joins("join user_extensions ue on ue.user_id = games.user_id")
.where(ue: {school_id: ids},).where( games:{status: [0, 1, 2]})
finish_challenge = Game.joins("join user_extensions ue on ue.user_id = games.user_id")
.where(ue: {school_id: ids}).where(games: {status: 2})
reg_teacher = user_e.where(identity: 'teacher')
reg_student = user_e.where.not(identity: 'teacher')
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)
reg_teacher = reg_teacher.where(created_at: time_range)
reg_student = reg_student.where(created_at: time_range)
user_e = user_e.joins(:user).where(users: {last_login_on: time_range})
end
#study_myshixun_map = study_myshixun.reorder(nil).group(:school_id).count
#finish_myshixun_map = finish_myshixun.reorder(nil).group(:school_id).count
study_challenge_map = study_challenge.reorder(nil).group(:school_id).count
finish_challenge_map = finish_challenge.reorder(nil).group(:school_id).count
evaluate_count_map = study_challenge.reorder(nil).group(:school_id).sum(:evaluate_count)
reg_teacher_map = reg_teacher.reorder(nil).group(:school_id).count
reg_student_map = reg_student.reorder(nil).group(:school_id).count
user_e_map = user_e.reorder(nil).group(:school_id).count
schools.each do |school|
school._extra_data = {
#study_shixun_count: study_myshixun_map.fetch(schools.id, 0),
#finish_shixun_count: finish_myshixun_map.fetch(schools.id, 0),
study_challenge_count: study_challenge_map.fetch(school.id, 0),
finish_challenge_count: finish_challenge_map.fetch(school.id, 0),
evaluate_count: evaluate_count_map.fetch(school.id, 0),
reg_teacher_count: reg_teacher_map.fetch(school.id, 0),
reg_student_count: reg_student_map.fetch(school.id, 0),
user_active_count: user_e_map.fetch(school.id, 0)
}
end
schools
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.joins('LEFT JOIN myshixuns ON myshixuns.user_id = users.id AND 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.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)")
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.user_id = users.id "\
"AND games.status = 2 AND games.updated_at BETWEEN '#{time_range.min}' AND '#{time_range.max}'")
else
users#.joins('LEFT JOIN myshixuns ON myshixuns.user_id = users.id')
.joins("LEFT JOIN games ON games.user_id = users.id AND 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 'dayly' then 1.days.ago..Time.now
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

@ -62,6 +62,7 @@
<%= 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>
<li><%= sidebar_item(admins_user_schools_statistics_path, '用户运营统计', icon: 'user-md', controller: 'admins-user_schools_statistics') %></li>
<% end %>
</li>

@ -0,0 +1,18 @@
wb = xlsx_package.workbook
wb.add_worksheet(name: '用户运营统计') do |sheet|
sheet.add_row %w(单位名称 省份 注册老师数量 注册学生数量 活跃用户 学习关卡数 完成关卡数 评测次数)
@schools.each do |school|
data = [
school.name,
school.province,
school.display_extra_data(:reg_teacher_count),
school.display_extra_data(:reg_student_count),
school.display_extra_data(:user_active_count),
school.display_extra_data(:study_challenge_count),
school.display_extra_data(:finish_challenge_count),
school.display_extra_data(:evaluate_count),
]
sheet.add_row(data)
end
end

@ -0,0 +1,30 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('用户运营情况') %>
<% end %>
<div class="box search-form-container user-schools-statistic-list-form">
<%= form_tag(admins_user_schools_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 = [['不限', ''],['最近一天', 'dayly'], ['最近一周', '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>
<%= text_field_tag(:province, params[:province], class: 'form-control col-sm-2 ml-3', placeholder: '所属省份') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
<% end %>
<%= javascript_void_link '导出', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_user_schools_statistics_path(format: :xlsx) %>
</div>
<div class="box admin-list-container user-schools-statistic-list-container">
<%= render partial: 'admins/user_schools_statistics/shared/list', locals: { schools: @schools } %>
</div>

@ -0,0 +1 @@
$('.user-schools-statistic-list-container').html("<%= j( render partial: 'admins/user_schools_statistics/shared/list', locals: { schools: @schools } ) %>");

@ -0,0 +1,38 @@
<table class="table table-hover text-center user-statistic-list-table">
<thead class="thead-light">
<tr>
<th width="6%">序号</th>
<th width="22%" class="text-left">单位名称</th>
<th width="8%" class="text-left">省份</th>
<th width="10%">注册老师数量<%#= sort_tag('学习关卡数', name: 'study_challenge_count', path: admins_user_statistics_path) %></th>
<th width="10%">注册学生数量<%#= sort_tag('完成关卡数', name: 'finish_challenge_count', path: admins_user_statistics_path) %></th>
<th width="10%">活跃用户<%#= sort_tag('活跃用户', name: 'user_active_count', path: admins_user_schools_statistics_path) %></th>
<th width="10%">学习关卡数<%#= sort_tag('学习关卡数', name: 'finish_shixun_count', path: admins_user_schools_statistics_path) %></th>
<th width="10%">完成关卡数</th>
<th width="14%">评测次数</th>
</tr>
</thead>
<tbody>
<% if schools.present? %>
<% schools.each_with_index do |school, index| %>
<tr class="user-statistic-item-<%= school.id %>">
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<td class="text-left">
<%= school.name %>
</td>
<td class="text-left"><%= school.province %></td>
<td><%= school.display_extra_data(:reg_teacher_count) %></td>
<td><%= school.display_extra_data(:reg_student_count) %></td>
<td><%= school.display_extra_data(:user_active_count) %></td>
<td><%= school.display_extra_data(:study_challenge_count) %></td>
<td><%= school.display_extra_data(:finish_challenge_count) %></td>
<td><%= school.display_extra_data(:evaluate_count) %></td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %>

@ -870,6 +870,7 @@ Rails.application.routes.draw do
collection do
get :school_list
get :for_option
get :for_province_option
get :search
end
@ -1163,6 +1164,9 @@ Rails.application.routes.draw do
resources :user_statistics, only: [:index] do
get :export, on: :collection
end
resources :user_schools_statistics, only: [:index] do
get :export, on: :collection
end
resources :library_applies, only: [:index] do
member do
post :agree

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -140264,6 +140264,81 @@ $(document).on('turbolinks:load', function() {
});
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-user-schools-statistics-index-page').length > 0) {
var $form = $('.user-schools-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('select[name="province"]').val('');
$form.find('.school-select').val('').trigger('change');
$form.find('input[type="submit"]').trigger('click');
})
// 导出
$('.export-action').on('click', function(){
var form = $(".user-schools-statistic-list-form .search-form")
var exportLink = $(this);
var date = form.find("select[name='date']").val();
var schoolId = form.find('input[name="school_id"]').val();
var url = exportLink.data("url").split('?')[0] + "?date=" + date + "&school_id=" + schoolId;
window.open(url);
});
}
});
$(document).on('turbolinks:load', function() {
if ($('body.admins-user-statistics-index-page').length > 0) {
var $form = $('.user-statistic-list-form');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save