From 3fa24d31c39a656e793da362398e463b74ace769 Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Mon, 21 Oct 2019 09:47:01 +0800 Subject: [PATCH 01/31] =?UTF-8?q?fork=E6=97=B6=EF=BC=8C=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E9=AB=98=E6=A0=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/shixuns_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 98af25b7d..76ba2a1f4 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -262,6 +262,11 @@ class ShixunsController < ApplicationController :mirror_repository_id => config.mirror_repository_id) end + # 同步高校限制 + @shixun.shixun_schools.each do |school| + ShixunSchool.create!(shixun_id: @new_shixun.id, school_id: school.school_id) + end + # fork版本库 logger.info("###########fork_repo_path: ######{@repo_path}") project_fork(@new_shixun, @repo_path, current_user.login) From ac145a4e63636e535e3e7192ba843ba4ce98f580 Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Mon, 21 Oct 2019 10:39:27 +0800 Subject: [PATCH 02/31] =?UTF-8?q?fork=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/shixuns_controller.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 76ba2a1f4..05c3500ee 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -232,10 +232,12 @@ class ShixunsController < ApplicationController # 同步私密版本库 if @shixun.shixun_secret_repository - repo_name = "#{current_user.login}/secret_#{@shixun.identifier}" + # 源仓库的的私密版本库地址 + repo_name = @shixun.shixun_secret_repository.repo_name + # 新生成的地址 fork_repository_name = "#{current_user.login}/secret_#{@new_shixun.identifier}" ShixunSecretRepository.create!(shixun_id: @new_shixun.id, - repo_name: "#{repo_name}", + repo_name: "#{fork_repository_name}", secret_dir_path: @shixun.shixun_secret_repository.secret_dir_path) GitService.fork_repository(repo_path: "#{repo_name}.git", fork_repository_path: (fork_repository_name + ".git")) end @@ -335,7 +337,10 @@ class ShixunsController < ApplicationController end rescue Exception => e uid_logger_error("copy shixun failed ##{e.message}") - g.delete_project(gshixungshixun.id) if gshixun.try(:id).present? # 异常后,如果已经创建了版本库需要删除该版本库 + # 删除版本库 + # 删除私密版本库 + GitService.delete_repository(repo_path: "#{fork_repository_name}.git") if @new_shixun.shixun_secret_repository&.repo_name + GitService.delete_repository(repo_path: @new_shixun.repo_path) if @new_shixun.repo_path tip_exception("实训Fork失败") raise ActiveRecord::Rollback end From eaae25d87b331f3a341a00c12fa89b52179af336 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 13:51:57 +0800 Subject: [PATCH 03/31] admins: user shixun statistic --- .../admins/user_statistics/index.js | 60 ++++++++ .../admins/user_statistics_controller.rb | 9 ++ .../concerns/base/paginate_helper.rb | 5 + app/models/application_record.rb | 6 + app/queries/admins/user_statistic_query.rb | 136 ++++++++++++++++++ app/views/admins/shared/_sidebar.html.erb | 1 + .../admins/user_statistics/index.html.erb | 26 ++++ app/views/admins/user_statistics/index.js.erb | 1 + .../user_statistics/shared/_list.html.erb | 34 +++++ config/routes.rb | 1 + 10 files changed, 279 insertions(+) create mode 100644 app/assets/javascripts/admins/user_statistics/index.js create mode 100644 app/controllers/admins/user_statistics_controller.rb create mode 100644 app/queries/admins/user_statistic_query.rb create mode 100644 app/views/admins/user_statistics/index.html.erb create mode 100644 app/views/admins/user_statistics/index.js.erb create mode 100644 app/views/admins/user_statistics/shared/_list.html.erb diff --git a/app/assets/javascripts/admins/user_statistics/index.js b/app/assets/javascripts/admins/user_statistics/index.js new file mode 100644 index 000000000..0d9df5f4b --- /dev/null +++ b/app/assets/javascripts/admins/user_statistics/index.js @@ -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'); + }) + } +}); \ No newline at end of file diff --git a/app/controllers/admins/user_statistics_controller.rb b/app/controllers/admins/user_statistics_controller.rb new file mode 100644 index 000000000..f60fb8dcd --- /dev/null +++ b/app/controllers/admins/user_statistics_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/concerns/base/paginate_helper.rb b/app/controllers/concerns/base/paginate_helper.rb index a10d7eb2e..7a81da2b9 100644 --- a/app/controllers/concerns/base/paginate_helper.rb +++ b/app/controllers/concerns/base/paginate_helper.rb @@ -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 diff --git a/app/models/application_record.rb b/app/models/application_record.rb index a876440c3..ded4119cd 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -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 diff --git a/app/queries/admins/user_statistic_query.rb b/app/queries/admins/user_statistic_query.rb new file mode 100644 index 000000000..866ec4d0b --- /dev/null +++ b/app/queries/admins/user_statistic_query.rb @@ -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 diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 694e9d1ff..4d6986bc6 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -39,6 +39,7 @@
  • <%= sidebar_item_group('#user-submenu', '用户', icon: 'user') do %>
  • <%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users') %>
  • +
  • <%= sidebar_item(admins_user_statistics_path, '用户实训情况', icon: 'area-chart', controller: 'admins-user_statistics') %>
  • <% end %> diff --git a/app/views/admins/user_statistics/index.html.erb b/app/views/admins/user_statistics/index.html.erb new file mode 100644 index 000000000..fdc6259e5 --- /dev/null +++ b/app/views/admins/user_statistics/index.html.erb @@ -0,0 +1,26 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('用户实训情况') %> +<% end %> + +
    + <%= form_tag(admins_user_statistics_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> +
    + + <% data_arrs = [['不限', ''], ['最近一周', 'weekly'], ['最近一个月', 'monthly'], ['最近三个月', 'quarterly'], ['最近一年', 'yearly']] %> + <%= select_tag(:date, options_for_select(data_arrs, params[:date]), class: 'form-control') %> +
    + +
    + + <%= 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' %> +
    + + <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> + + <% end %> +
    + +
    + <%= render partial: 'admins/user_statistics/shared/list', locals: { users: @users } %> +
    \ No newline at end of file diff --git a/app/views/admins/user_statistics/index.js.erb b/app/views/admins/user_statistics/index.js.erb new file mode 100644 index 000000000..c3d2cc9de --- /dev/null +++ b/app/views/admins/user_statistics/index.js.erb @@ -0,0 +1 @@ +$('.user-statistic-list-container').html("<%= j( render partial: 'admins/user_statistics/shared/list', locals: { users: @users } ) %>"); \ No newline at end of file diff --git a/app/views/admins/user_statistics/shared/_list.html.erb b/app/views/admins/user_statistics/shared/_list.html.erb new file mode 100644 index 000000000..1e1b14ea3 --- /dev/null +++ b/app/views/admins/user_statistics/shared/_list.html.erb @@ -0,0 +1,34 @@ + + + + + + + + + + + + + <% if users.present? %> + <% users.each do |user| %> + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
    姓名单位部门<%= sort_tag('学习关卡数', name: 'study_challenge_count', path: admins_user_statistics_path) %><%= sort_tag('完成关卡数', name: 'finish_challenge_count', path: admins_user_statistics_path) %><%= sort_tag('学习实训数', name: 'study_shixun_count', path: admins_user_statistics_path) %><%= sort_tag('完成实训数', name: 'finish_shixun_count', path: admins_user_statistics_path) %>
    + <%= link_to "/users/#{user.login}", target: '_blank' do %> + <%= overflow_hidden_span user.real_name, width: 100 %> + <% end %> + <%= display_text [user.school_name.presence, user.department_name.presence].compact.join(' - ') %><%= user.display_extra_data(:study_challenge_count) %><%= user.display_extra_data(:finish_challenge_count) %><%= user.display_extra_data(:study_shixun_count) %><%= user.display_extra_data(:finish_shixun_count) %>
    + +<%= render partial: 'admins/shared/paginate', locals: { objects: users } %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index e7fb7ee04..1acaac57e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 From d2c2fd7f406eaee2dbad4e2562eb6e8f894ccb28 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 13:53:41 +0800 Subject: [PATCH 04/31] admin: precompile --- ...fest-4627fa5586ef7fed55ca286af7c028e9.json | 2 +- ...f28fe8d05f7bc3b8221e0695b2216255c52ba6.js} | 71 ++++++++++++++++++ ...fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz} | Bin 961157 -> 961314 bytes 3 files changed, 72 insertions(+), 1 deletion(-) rename public/assets/{admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js => admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js} (99%) rename public/assets/{admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js.gz => admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz} (98%) diff --git a/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json index 34d5f9d73..49c70bf4d 100644 --- a/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json +++ b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json @@ -1 +1 @@ -{"files":{"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js":{"logical_path":"admin.js","mtime":"2019-09-11T16:20:07+08:00","size":4350881,"digest":"cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121","integrity":"sha256-zZyousyXPOLbrOMMl/bEC8COLC7kSXL2aOc44ZAsASE="},"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css":{"logical_path":"admin.css","mtime":"2019-09-11T16:20:07+08:00","size":773445,"digest":"a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa","integrity":"sha256-obM1bv5Q/0cXzyJHVjm1MzxTVLoD/RB8m3qNSudvR6o="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-10-17T09:44:58+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css":{"logical_path":"college.css","mtime":"2019-09-11T16:20:07+08:00","size":546841,"digest":"944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9","integrity":"sha256-lE1Cc/YsdTg2i5AX/dM4e1476jGoeHN3DrIxMkVG1Nk="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-09-03T08:55:53+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-10-17T09:44:58+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css":{"logical_path":"application.css","mtime":"2019-09-11T16:20:07+08:00","size":1844002,"digest":"5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2","integrity":"sha256-Xrh8bhNnbQGDMX3rzhf63ifmjErO4oxBlDjaFdU8lPI="},"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js":{"logical_path":"admin.js","mtime":"2019-09-21T15:28:08+08:00","size":4382031,"digest":"c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4","integrity":"sha256-yeXr5hkVSFUOJ1FBluoSXPu0AoIOwSWgyaz5nS03j+Q="},"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css":{"logical_path":"admin.css","mtime":"2019-09-21T14:49:04+08:00","size":840093,"digest":"59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38","integrity":"sha256-WcWfjK6L70qDWShsmFRYEQydA+oSFRZZXJiJQ/RxfDg="},"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css":{"logical_path":"college.css","mtime":"2019-09-16T13:56:09+08:00","size":579109,"digest":"38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437","integrity":"sha256-OPlT1rpbhdP6tjyzwrvw0FfMxkVNB8+q+sOwbaN7hDc="},"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.css":{"logical_path":"application.css","mtime":"2019-09-21T14:49:04+08:00","size":1988767,"digest":"646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3","integrity":"sha256-ZGsRWKTowfE+aE1v6QJavHX407pSVuRAgCwDmCIzdPM="},"admin-a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:33:05+08:00","size":4383107,"digest":"a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751","integrity":"sha256-pH43wOx89fIjgCSXdtHoLWW2tqonLtc4kYWqIA+kB1E="},"admin-432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:35:20+08:00","size":4383103,"digest":"432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9","integrity":"sha256-QyxOrAmwNsV/8eiNkCuKp9+BFk5LQZusVXzxNmwdOtk="},"admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js":{"logical_path":"admin.js","mtime":"2019-09-30T14:43:41+08:00","size":4387200,"digest":"978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a","integrity":"sha256-l45c5gf3fCaBShdPSA2nmsJGwiAYaO+EZUqgO7Zye1o="},"admin-896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7.css":{"logical_path":"admin.css","mtime":"2019-09-30T14:43:41+08:00","size":842269,"digest":"896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7","integrity":"sha256-iWKB9HMXIrDAhNuxryHQ80pbwULViv9Xs5GGSrcd3Kc="},"application-97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd.css":{"logical_path":"application.css","mtime":"2019-09-30T14:43:41+08:00","size":1993118,"digest":"97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd","integrity":"sha256-l/MT6bt9JUdmSffXIVlZz0IUgP0KN4XRlWlTv5Sh6L0="},"admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js":{"logical_path":"admin.js","mtime":"2019-10-11T14:38:33+08:00","size":4394616,"digest":"2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888","integrity":"sha256-LNsjRC+nNQJThbiPKQDfBP7zi2FTAEGm2+N17w8K6Ig="},"admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css":{"logical_path":"admin.css","mtime":"2019-10-10T17:12:05+08:00","size":846514,"digest":"2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc","integrity":"sha256-LChUuaAhWN7VqAmq9xRKhjCxA1SrTlb+zE3/zHE3lsw="},"application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css":{"logical_path":"application.css","mtime":"2019-10-10T17:12:05+08:00","size":2001607,"digest":"50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af","integrity":"sha256-UAWa6SmGYEO0cBUShwL8+6U9MqLfFI5k4dlhwQZRxq8="},"admin-992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2.js":{"logical_path":"admin.js","mtime":"2019-10-16T16:11:32+08:00","size":4394790,"digest":"992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2","integrity":"sha256-mSzeCbbRfwCklXauLZ8c7RJyRLpAHvW31nfKuXQWiNI="},"admin-84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257.css":{"logical_path":"admin.css","mtime":"2019-10-16T19:25:40+08:00","size":846676,"digest":"84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257","integrity":"sha256-hPKneR4nXW+CBRQ3Cz+WgXa5lLnde4w7qL9IM2sD8lc="},"application-ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997.css":{"logical_path":"application.css","mtime":"2019-10-16T19:25:40+08:00","size":2001931,"digest":"ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997","integrity":"sha256-72urhIUrqvaakf5q+HW24bEYxVtMfRZWZcSI+sgMSZc="},"admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js":{"logical_path":"admin.js","mtime":"2019-10-17T09:44:58+08:00","size":4394897,"digest":"c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a","integrity":"sha256-yZAw0wVmL3QKqEtskloa27qtqgf9dOJlXmTUS0uX/Eo="},"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css":{"logical_path":"admin.css","mtime":"2019-10-17T10:22:41+08:00","size":846699,"digest":"534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d","integrity":"sha256-U0vehx1n9Nb8jaYRkX14vkBm/HWTulPukqoXBooZnW0="},"cooperative-04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T10:17:56+08:00","size":4330072,"digest":"04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7","integrity":"sha256-BM1qYNQSINOO5FzkCx0ATh0LzYfBMvsae6thRMHeuNc="},"cooperative-a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T10:21:41+08:00","size":830628,"digest":"a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3","integrity":"sha256-o0W7/Y44twyShezBdHAS/83kKRh5g+KupWV6u1a5tPM="},"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css":{"logical_path":"application.css","mtime":"2019-09-03T08:55:53+08:00","size":442932,"digest":"0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8","integrity":"sha256-DkF0eNVvQkZ+hXzRhrKcu8DWx8boXIpvQvOaxhiUPeg="},"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T14:03:03+08:00","size":4338033,"digest":"149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b","integrity":"sha256-FJ9HuGddYKgBTM/1DwD5Mv9p4r4ob/t0NDvEo+/7E1s="},"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T11:13:07+08:00","size":832914,"digest":"6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8","integrity":"sha256-YnO3ZtbvEd1WF02Gi6tV5/F68XVGyIjSug3Qprzadsg="}},"assets":{"admin.js":"admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js","admin.css":"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css","cooperative.js":"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js","cooperative.css":"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css"}} \ No newline at end of file +{"files":{"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js":{"logical_path":"admin.js","mtime":"2019-09-11T16:20:07+08:00","size":4350881,"digest":"cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121","integrity":"sha256-zZyousyXPOLbrOMMl/bEC8COLC7kSXL2aOc44ZAsASE="},"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css":{"logical_path":"admin.css","mtime":"2019-09-11T16:20:07+08:00","size":773445,"digest":"a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa","integrity":"sha256-obM1bv5Q/0cXzyJHVjm1MzxTVLoD/RB8m3qNSudvR6o="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-10-17T09:44:58+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css":{"logical_path":"college.css","mtime":"2019-09-11T16:20:07+08:00","size":546841,"digest":"944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9","integrity":"sha256-lE1Cc/YsdTg2i5AX/dM4e1476jGoeHN3DrIxMkVG1Nk="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-09-03T08:55:53+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-10-17T09:44:58+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css":{"logical_path":"application.css","mtime":"2019-09-11T16:20:07+08:00","size":1844002,"digest":"5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2","integrity":"sha256-Xrh8bhNnbQGDMX3rzhf63ifmjErO4oxBlDjaFdU8lPI="},"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js":{"logical_path":"admin.js","mtime":"2019-09-21T15:28:08+08:00","size":4382031,"digest":"c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4","integrity":"sha256-yeXr5hkVSFUOJ1FBluoSXPu0AoIOwSWgyaz5nS03j+Q="},"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css":{"logical_path":"admin.css","mtime":"2019-09-21T14:49:04+08:00","size":840093,"digest":"59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38","integrity":"sha256-WcWfjK6L70qDWShsmFRYEQydA+oSFRZZXJiJQ/RxfDg="},"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css":{"logical_path":"college.css","mtime":"2019-09-16T13:56:09+08:00","size":579109,"digest":"38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437","integrity":"sha256-OPlT1rpbhdP6tjyzwrvw0FfMxkVNB8+q+sOwbaN7hDc="},"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.css":{"logical_path":"application.css","mtime":"2019-09-21T14:49:04+08:00","size":1988767,"digest":"646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3","integrity":"sha256-ZGsRWKTowfE+aE1v6QJavHX407pSVuRAgCwDmCIzdPM="},"admin-a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:33:05+08:00","size":4383107,"digest":"a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751","integrity":"sha256-pH43wOx89fIjgCSXdtHoLWW2tqonLtc4kYWqIA+kB1E="},"admin-432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:35:20+08:00","size":4383103,"digest":"432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9","integrity":"sha256-QyxOrAmwNsV/8eiNkCuKp9+BFk5LQZusVXzxNmwdOtk="},"admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js":{"logical_path":"admin.js","mtime":"2019-09-30T14:43:41+08:00","size":4387200,"digest":"978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a","integrity":"sha256-l45c5gf3fCaBShdPSA2nmsJGwiAYaO+EZUqgO7Zye1o="},"admin-896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7.css":{"logical_path":"admin.css","mtime":"2019-09-30T14:43:41+08:00","size":842269,"digest":"896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7","integrity":"sha256-iWKB9HMXIrDAhNuxryHQ80pbwULViv9Xs5GGSrcd3Kc="},"application-97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd.css":{"logical_path":"application.css","mtime":"2019-09-30T14:43:41+08:00","size":1993118,"digest":"97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd","integrity":"sha256-l/MT6bt9JUdmSffXIVlZz0IUgP0KN4XRlWlTv5Sh6L0="},"admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js":{"logical_path":"admin.js","mtime":"2019-10-11T14:38:33+08:00","size":4394616,"digest":"2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888","integrity":"sha256-LNsjRC+nNQJThbiPKQDfBP7zi2FTAEGm2+N17w8K6Ig="},"admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css":{"logical_path":"admin.css","mtime":"2019-10-10T17:12:05+08:00","size":846514,"digest":"2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc","integrity":"sha256-LChUuaAhWN7VqAmq9xRKhjCxA1SrTlb+zE3/zHE3lsw="},"application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css":{"logical_path":"application.css","mtime":"2019-10-10T17:12:05+08:00","size":2001607,"digest":"50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af","integrity":"sha256-UAWa6SmGYEO0cBUShwL8+6U9MqLfFI5k4dlhwQZRxq8="},"admin-992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2.js":{"logical_path":"admin.js","mtime":"2019-10-16T16:11:32+08:00","size":4394790,"digest":"992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2","integrity":"sha256-mSzeCbbRfwCklXauLZ8c7RJyRLpAHvW31nfKuXQWiNI="},"admin-84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257.css":{"logical_path":"admin.css","mtime":"2019-10-16T19:25:40+08:00","size":846676,"digest":"84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257","integrity":"sha256-hPKneR4nXW+CBRQ3Cz+WgXa5lLnde4w7qL9IM2sD8lc="},"application-ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997.css":{"logical_path":"application.css","mtime":"2019-10-16T19:25:40+08:00","size":2001931,"digest":"ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997","integrity":"sha256-72urhIUrqvaakf5q+HW24bEYxVtMfRZWZcSI+sgMSZc="},"admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js":{"logical_path":"admin.js","mtime":"2019-10-17T09:44:58+08:00","size":4394897,"digest":"c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a","integrity":"sha256-yZAw0wVmL3QKqEtskloa27qtqgf9dOJlXmTUS0uX/Eo="},"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css":{"logical_path":"admin.css","mtime":"2019-10-17T10:22:41+08:00","size":846699,"digest":"534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d","integrity":"sha256-U0vehx1n9Nb8jaYRkX14vkBm/HWTulPukqoXBooZnW0="},"cooperative-04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T10:17:56+08:00","size":4330072,"digest":"04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7","integrity":"sha256-BM1qYNQSINOO5FzkCx0ATh0LzYfBMvsae6thRMHeuNc="},"cooperative-a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T10:21:41+08:00","size":830628,"digest":"a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3","integrity":"sha256-o0W7/Y44twyShezBdHAS/83kKRh5g+KupWV6u1a5tPM="},"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css":{"logical_path":"application.css","mtime":"2019-09-03T08:55:53+08:00","size":442932,"digest":"0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8","integrity":"sha256-DkF0eNVvQkZ+hXzRhrKcu8DWx8boXIpvQvOaxhiUPeg="},"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T14:03:03+08:00","size":4338033,"digest":"149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b","integrity":"sha256-FJ9HuGddYKgBTM/1DwD5Mv9p4r4ob/t0NDvEo+/7E1s="},"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T11:13:07+08:00","size":832914,"digest":"6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8","integrity":"sha256-YnO3ZtbvEd1WF02Gi6tV5/F68XVGyIjSug3Qprzadsg="},"admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js":{"logical_path":"admin.js","mtime":"2019-10-21T13:51:43+08:00","size":4397012,"digest":"82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6","integrity":"sha256-gvZsyAtWScZTClYlZ/KP6NBfe8O4Ih4GlbIhYlXFK6Y="}},"assets":{"admin.js":"admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js","admin.css":"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css","cooperative.js":"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js","cooperative.css":"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css"}} \ No newline at end of file diff --git a/public/assets/admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js b/public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js similarity index 99% rename from public/assets/admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js rename to public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js index 72a1ca344..3298a4984 100644 --- a/public/assets/admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js +++ b/public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js @@ -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; diff --git a/public/assets/admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js.gz b/public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz similarity index 98% rename from public/assets/admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js.gz rename to public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz index f24a42fc6051d533fbaedfb63809cc7e0a27a430..b7bf437da44a43ffbb147646f847be39f373514a 100644 GIT binary patch delta 11678 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 delta 11520 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 Date: Mon, 21 Oct 2019 14:08:49 +0800 Subject: [PATCH 05/31] =?UTF-8?q?cdn=E5=8E=9F=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/main_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb index 869ba27f6..0e2628c3e 100644 --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -1,5 +1,5 @@ class MainController < ApplicationController def index - render file: 'public/react/build/index', formats: [:html] + render file: 'public/react/build/index.html', :layout => false end end \ No newline at end of file From 8d016468720dacb9243cee613ff8d521ad0e09de Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Mon, 21 Oct 2019 14:15:05 +0800 Subject: [PATCH 06/31] =?UTF-8?q?cdn=E5=8A=A0=E8=BD=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/main_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb index 869ba27f6..0e2628c3e 100644 --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -1,5 +1,5 @@ class MainController < ApplicationController def index - render file: 'public/react/build/index', formats: [:html] + render file: 'public/react/build/index.html', :layout => false end end \ No newline at end of file From 436628e6376fad5ab735527114e5fefe45f4f149 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 14:57:02 +0800 Subject: [PATCH 07/31] weapp: fix api --- app/controllers/weapps/code_sessions_controller.rb | 13 +++++++++++-- app/libs/wechat/weapp.rb | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/controllers/weapps/code_sessions_controller.rb b/app/controllers/weapps/code_sessions_controller.rb index b5886efd8..5e2b88d95 100644 --- a/app/controllers/weapps/code_sessions_controller.rb +++ b/app/controllers/weapps/code_sessions_controller.rb @@ -5,16 +5,23 @@ class Weapps::CodeSessionsController < Weapps::BaseController result = Wechat::Weapp.jscode2session(params[:code]) - # 已授权,绑定过账号 + # 能根据 code 拿到 unionid open_user = OpenUsers::Wechat.find_by(uid: result['unionid']) if open_user.present? && open_user.user successful_authentication(open_user.user) set_session_unionid(result['unionid']) logged = true else - # 新用户 + # 根据 code没拿到 unionid user_info = Wechat::Weapp.decrypt(result['session_key'], params[:encrypted_data], params[:iv]) + # 老用户,已绑定 + open_user = OpenUsers::Wechat.find_by(uid: user_info['unionid']) + if open_user.present? && open_user.user + successful_authentication(open_user.user) + logged = true + end + set_session_unionid(user_info['unionId']) end @@ -22,5 +29,7 @@ class Weapps::CodeSessionsController < Weapps::BaseController set_weapp_session_key(result['session_key']) # weapp session_key写入缓存 后续解密需要 render_ok(openid: result['openid'], logged: logged) + rescue Wechat::Error => ex + render_error(ex.message) end end \ No newline at end of file diff --git a/app/libs/wechat/weapp.rb b/app/libs/wechat/weapp.rb index 755c9351a..9684206cd 100644 --- a/app/libs/wechat/weapp.rb +++ b/app/libs/wechat/weapp.rb @@ -34,7 +34,7 @@ class Wechat::Weapp data = cipher.update(encrypted_data) << cipher.final result = JSON.parse(data[0...-data.last.ord]) - raise Wechat::Error, '解密错误' if result.dig('watermark', 'appid') != appid + raise Wechat::Error.new(-1, '解密错误') if result.dig('watermark', 'appid') != appid result end From 59b374e0e3621d2bfa4dbe86717586de5e1d658e Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 15:02:49 +0800 Subject: [PATCH 08/31] weapp: fix code session api --- app/controllers/weapps/code_sessions_controller.rb | 2 +- app/libs/wechat/client.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/weapps/code_sessions_controller.rb b/app/controllers/weapps/code_sessions_controller.rb index 5e2b88d95..687605fc4 100644 --- a/app/controllers/weapps/code_sessions_controller.rb +++ b/app/controllers/weapps/code_sessions_controller.rb @@ -16,7 +16,7 @@ class Weapps::CodeSessionsController < Weapps::BaseController user_info = Wechat::Weapp.decrypt(result['session_key'], params[:encrypted_data], params[:iv]) # 老用户,已绑定 - open_user = OpenUsers::Wechat.find_by(uid: user_info['unionid']) + open_user = OpenUsers::Wechat.find_by(uid: user_info['unionId']) if open_user.present? && open_user.user successful_authentication(open_user.user) logged = true diff --git a/app/libs/wechat/client.rb b/app/libs/wechat/client.rb index 5ac0a28f2..43d5b0732 100644 --- a/app/libs/wechat/client.rb +++ b/app/libs/wechat/client.rb @@ -53,13 +53,13 @@ class Wechat::Client private def request(method, url, **params) - Rails.logger.error("[wechat] request: #{method} #{url} #{params.except(:secret).inspect}") + Rails.logger.info("[wechat] request: #{method} #{url} #{params.except(:secret).inspect}") client = Faraday.new(url: BASE_SITE) response = client.public_send(method, url, params) result = JSON.parse(response.body) - Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}") + Rails.logger.info("[wechat] response:#{response.status} #{result.inspect}") if response.status != 200 raise Wechat::Error.parse(result) From 382b6cfd639dc19418457caf089fabc549f54d79 Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Mon, 21 Oct 2019 15:40:23 +0800 Subject: [PATCH 09/31] =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=9A=90=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/application_controller.rb | 8 +++--- app/controllers/concerns/logger_helper.rb | 6 ++++ app/controllers/games_controller.rb | 34 +++++++++++------------ app/controllers/myshixuns_controller.rb | 21 +++++--------- 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e6b58bc3b..d94325a5b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -353,10 +353,10 @@ class ApplicationController < ActionController::Base # Post请求 def uri_post(uri, params) begin - uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uid_logger_dubug("--uri_exec: params is #{params}, url is #{uri}") uri = URI.parse(URI.encode(uri.strip)) res = Net::HTTP.post_form(uri, params).body - logger.info("--uri_exec: .....res is #{res}") + uid_logger_dubug("--uri_exec: .....res is #{res}") JSON.parse(res) rescue Exception => e uid_logger_error("--uri_exec: exception #{e.message}") @@ -367,10 +367,10 @@ class ApplicationController < ActionController::Base # 处理返回非0就报错的请求 def interface_post(uri, params, status, message) begin - uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uid_logger_dubug("--uri_exec: params is #{params}, url is #{uri}") uri = URI.parse(URI.encode(uri.strip)) res = Net::HTTP.post_form(uri, params).body - logger.info("--uri_exec: .....res is #{res}") + uid_logger_dubug("--uri_exec: .....res is #{res}") res = JSON.parse(res) if (res && res['code'] != 0) tip_exception(status, message) diff --git a/app/controllers/concerns/logger_helper.rb b/app/controllers/concerns/logger_helper.rb index 44d0448ce..af368a007 100644 --- a/app/controllers/concerns/logger_helper.rb +++ b/app/controllers/concerns/logger_helper.rb @@ -9,6 +9,12 @@ module LoggerHelper Rails.logger.info("##:#{current_user.try(:id)} --#{message}") end + # debug日志 + def uid_logger_dubug(message) + Rails.logger.info("##dubug-#{current_user.try(:id)} --#{message}") + + end + # 以用户id开始的日志定义 def uid_logger_error(message) Rails.logger.error("##:#{current_user.try(:id)} --#{message}") diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index 97c3dc6e2..67a2e0ee8 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -11,7 +11,7 @@ class GamesController < ApplicationController include ApplicationHelper def show - uid_logger("--games show start") + uid_logger_dubug("--games show start") # 防止评测中途ajaxE被取消;3改成0是为了处理首次进入下一关的问题 update_game_parameter(@game) @@ -439,7 +439,7 @@ class GamesController < ApplicationController path = params[:path] || path status = params[:status].to_i path = path.try(:strip) - uid_logger("--rep_content: path is #{path}") + uid_logger_dubug("--rep_content: path is #{path}") begin @content = git_fle_content(@myshixun.repo_path, path) || "" rescue Exception => e @@ -455,7 +455,7 @@ class GamesController < ApplicationController # 监测版本库HEAD是否存在,不存在则取最新的HEAD uri = "#{shixun_tomcat}/bridge/game/check" res = uri_post uri, rep_params - uid_logger("repo_content to bridge: res is #{res}") + uid_logger_dubug("repo_content to bridge: res is #{res}") # res值:0 表示正常;-1表示有错误;-2表示代码版本库没了 # if status == 0 && res @@ -507,11 +507,10 @@ class GamesController < ApplicationController else {updated_at: Time.now} end - logger.info("#############myshixuns_update: ##{myshixuns_update}") @myshixun.update_attributes!(myshixuns_update) gitUrl = repo_ip_url @myshixun.repo_path - logger.info("#############giturl: ##{gitUrl}") + uid_logger_dubug("#############giturl: ##{gitUrl}") gitUrl = Base64.urlsafe_encode64(gitUrl) shixun_tomcat = edu_setting('cloud_bridge') @@ -537,7 +536,7 @@ class GamesController < ApplicationController testSet << test_cases end - logger.info("##############testSet: #{testSet}") + uid_logger_dubug("##############testSet: #{testSet}") testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank? # 评测类型: 0,1,2 用于webssh的评测, 3用于vnc @@ -560,11 +559,11 @@ class GamesController < ApplicationController # 私密仓库的设置 secret_rep = @shixun.shixun_secret_repository - logger.info("############secret_rep: #{secret_rep}") + uid_logger_dubug("############secret_rep: #{secret_rep}") if secret_rep&.repo_name secretGitUrl = repo_ip_url secret_rep.repo_path br_params.merge!({secretGitUrl: Base64.urlsafe_encode64(secretGitUrl), secretDir: secret_rep.secret_dir_path}) - logger.info("#######br_params:#{br_params}") + uid_logger_dubug("#######br_params:#{br_params}") end # 中间层交互 @@ -580,7 +579,6 @@ class GamesController < ApplicationController # 选择题评测 def choose_build - Rails.logger.error("#################{params}") # 选择题如果通关了,则不让再评测 if @game.status == 2 raise Educoder::TipException.new("您已通过该关卡") @@ -623,7 +621,7 @@ class GamesController < ApplicationController end # 批量插入评测结果 - uid_logger("#------------chooice score: #{score}") + uid_logger_dubug("#------------chooice score: #{score}") sql = "INSERT INTO outputs (game_id, test_set_position, actual_output, result, query_index, created_at, updated_at) VALUES" + str ActiveRecord::Base.connection.execute sql @@ -683,10 +681,10 @@ class GamesController < ApplicationController resubmit_identifier = @game.resubmit_identifier # 如果没有超时并且正在评测中 # 判断评测中的状态有两种:1、如果之前没有通关的,只需判断status为1即可;如果通过关,则判断game的resubmit_identifier是否更新 - uid_logger("################game_status: #{@game.status}") - uid_logger("################params[:resubmit]: #{params[:resubmit]}") - uid_logger("################resubmit_identifier: #{resubmit_identifier}") - uid_logger("################time_out: #{params[:time_out]}") + uid_logger_dubug("################game_status: #{@game.status}") + uid_logger_dubug("################params[:resubmit]: #{params[:resubmit]}") + uid_logger_dubug("################resubmit_identifier: #{resubmit_identifier}") + uid_logger_dubug("################time_out: #{params[:time_out]}") sec_key = params[:sec_key] if (params[:time_out] == "false") && ((params[:resubmit].blank? && @game.status == 1) || (params[:resubmit].present? && (params[:resubmit] != resubmit_identifier))) @@ -696,7 +694,7 @@ class GamesController < ApplicationController render :json => { running_code_status: running_code_status, running_code_message: running_code_message } end - uid_logger("##### resubmit_identifier is #{resubmit_identifier}") + uid_logger_dubug("##### resubmit_identifier is #{resubmit_identifier}") port = params[:port] score = 0 experience = 0 @@ -745,7 +743,7 @@ class GamesController < ApplicationController end end - uid_logger("game is #{@game.id}, record id is #{e_record.try(:id)}, time is**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + uid_logger_dubug("game is #{@game.id}, record id is #{e_record.try(:id)}, time is**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") # 记录前端总耗时 record_consume_time = e_record.try(:pod_execute) max_mem = e_record.try(:max_mem) @@ -791,7 +789,7 @@ class GamesController < ApplicationController begin shixun_tomcat = edu_setting('cloud_bridge') uri = "#{shixun_tomcat}/bridge/webssh/delete" - Rails.logger.info("#{current_user} => cloese_webssh digest is #{digest}") + uid_logger_dubug("#{current_user} => cloese_webssh digest is #{digest}") params = {:tpiID => myshixun_id, :digestKey => digest_key, :identifier => @game.identifier} res = uri_post uri, params if res && res['code'].to_i != 0 @@ -830,7 +828,7 @@ class GamesController < ApplicationController @allowed_hidden_testset = @identity < User::EDU_GAME_MANAGER || @game.test_sets_view #解锁的用户 if max_query_index > 0 - uid_logger("max_query_index is #{max_query_index} game id is #{@game.id}, challenge_id is #{challenge.id}") + uid_logger_dubug("max_query_index is #{max_query_index} game id is #{@game.id}, challenge_id is #{challenge.id}") @qurey_test_sets = TestSet.find_by_sql("SELECT o.code, o.actual_output, o.out_put, o.result, o.test_set_position, o.ts_time, o.ts_mem, o.query_index, t.is_public, t.input, t.output, o.compile_success FROM outputs o, games g, challenges c, test_sets t where g.id=#{@game.id} and c.id=#{challenge.id} and o.query_index=#{max_query_index} diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 74f02f1ab..a9cc76296 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -90,7 +90,7 @@ class MyshixunsController < ApplicationController ActiveRecord::Base.transaction do begin t1 = Time.now - Rails.logger.info("@@@222222#{params[:jsonTestDetails]}") + uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}") jsonTestDetails = JSON.parse(params[:jsonTestDetails]) timeCost = JSON.parse(params[:timeCost]) brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present? @@ -99,7 +99,7 @@ class MyshixunsController < ApplicationController game_id = jsonTestDetails['buildID'] sec_key = jsonTestDetails['sec_key'] - logger.info("training_task_status start#1**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") resubmit = jsonTestDetails['resubmit'] outPut = tran_base64_decode64(jsonTestDetails['outPut']) @@ -116,17 +116,14 @@ class MyshixunsController < ApplicationController pics = params[:tpiRepoPath] game.update_column(:picture_path, pics) end - logger.info("training_task_status start#2**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1 test_set_score = 0 unless jenkins_testsets.blank? jenkins_testsets.each_with_index do |j_test_set, i| - logger.info("j_test_set: ############## #{j_test_set}") actual_output = tran_base64_decode64(j_test_set['output']) #ts_time += j_test_set['testSetTime'].to_i # is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public) - logger.info "actual_output:################################################# #{actual_output}" ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime'] ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem'] @@ -139,15 +136,12 @@ class MyshixunsController < ApplicationController end end end - uid_logger("#############status: #{status}") record = EvaluateRecord.where(:identifier => sec_key).first - logger.info("training_task_status start#3**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") answer_deduction_percentage = (100 - game.answer_deduction) / 100.to_f # 查看答案后剩余分数的百分比. # answer_deduction是查看答案的扣分比例 # status:0表示评测成功 if status == "0" if resubmit.present? - uid_logger("#############resubmitdaiao: #{resubmit}") game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit) challenge.path.split(";").each do |path| game_passed_code(path.try(:strip), myshixun, game_id) @@ -205,7 +199,6 @@ class MyshixunsController < ApplicationController :pod_execute => timeCost['execute'], :test_cases => test_cases_time, :brige => timeCost['evaluateAllTime'], :return_back => return_back_time) end - uid_logger("training_task_status start#4**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") sucess_status # rescue Exception => e # tip_exception(e.message) @@ -265,7 +258,7 @@ class MyshixunsController < ApplicationController @sec_key = generate_identifier(EvaluateRecord, 12) record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id, :identifier => @sec_key, :exec_time => exec_time) - uid_logger("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") end # 隐藏代码文件 和 VNC的都不需要走版本库 unless @hide_code || @myshixun.shixun&.vnc_evaluate @@ -276,8 +269,8 @@ class MyshixunsController < ApplicationController else params[:content] end - Rails.logger.info("###11222333####{content}") - Rails.logger.info("###222333####{last_content}") + uid_logger_dubug("###11222333####{content}") + uid_logger_dubug("###222333####{last_content}") if content != last_content @content_modified = 1 @@ -285,8 +278,8 @@ class MyshixunsController < ApplicationController author_name = current_user.real_name author_email = current_user.git_mail message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted" - uid_logger("112233#{author_name}") - uid_logger("112233#{author_email}") + uid_logger_dubug("112233#{author_name}") + uid_logger_dubug("112233#{author_email}") @content = GitService.update_file(repo_path: @repo_path, file_path: path, message: message, From cb8dd3dc9f961eaa1080b5bbc348305ff02cb887 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 15:55:58 +0800 Subject: [PATCH 10/31] weapps: hot search keywords && search api --- app/controllers/application_controller.rb | 9 +++++ app/controllers/searchs_controller.rb | 3 ++ .../weapps/hot_keywords_controller.rb | 7 ++++ app/controllers/weapps/searchs_controller.rb | 13 +++++++ app/libs/hot_search_keyword.rb | 1 + app/queries/weapps/search_query.rb | 37 +++++++++++++++++++ app/views/weapps/searchs/index.json.jbuilder | 9 +++++ config/routes.rb | 3 ++ 8 files changed, 82 insertions(+) create mode 100644 app/controllers/weapps/hot_keywords_controller.rb create mode 100644 app/controllers/weapps/searchs_controller.rb create mode 100644 app/queries/weapps/search_query.rb create mode 100644 app/views/weapps/searchs/index.json.jbuilder diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d94325a5b..df3e9c96e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -623,4 +623,13 @@ class ApplicationController < ActionController::Base end user end + + # 记录热门搜索关键字 + def record_search_keyword + keyword = params[:keyword].to_s.strip + return if keyword.blank? || keyword.size <= 1 + return unless HotSearchKeyword.available? + + HotSearchKeyword.add(keyword) + end end diff --git a/app/controllers/searchs_controller.rb b/app/controllers/searchs_controller.rb index 1ea1c5d05..130e8a5cd 100644 --- a/app/controllers/searchs_controller.rb +++ b/app/controllers/searchs_controller.rb @@ -1,9 +1,12 @@ class SearchsController < ApplicationController + after_action :record_search_keyword, only: [:index] + def index @results = SearchService.call(search_params) end private + def search_params params.permit(:keyword, :type, :page, :per_page) end diff --git a/app/controllers/weapps/hot_keywords_controller.rb b/app/controllers/weapps/hot_keywords_controller.rb new file mode 100644 index 000000000..f915d9c47 --- /dev/null +++ b/app/controllers/weapps/hot_keywords_controller.rb @@ -0,0 +1,7 @@ +class Weapps::HotKeywordsController < Weapps::BaseController + def index + keywords = [] + keywords = HotSearchKeyword.hot(8) if HotSearchKeyword.available? + render_ok(keywords: keywords) + end +end \ No newline at end of file diff --git a/app/controllers/weapps/searchs_controller.rb b/app/controllers/weapps/searchs_controller.rb new file mode 100644 index 000000000..b4960e7b1 --- /dev/null +++ b/app/controllers/weapps/searchs_controller.rb @@ -0,0 +1,13 @@ +class Weapps::SearchsController < Weapps::BaseController + after_action :record_search_keyword, only: [:index] + + def index + @results = Weapps::SearchQuery.call(search_params) + end + + private + + def search_params + params.permit(:keyword, :type, :page, :per_page) + end +end \ No newline at end of file diff --git a/app/libs/hot_search_keyword.rb b/app/libs/hot_search_keyword.rb index f026142cb..f79d1641e 100644 --- a/app/libs/hot_search_keyword.rb +++ b/app/libs/hot_search_keyword.rb @@ -3,6 +3,7 @@ class HotSearchKeyword class << self def add(keyword) return if keyword.blank? + Rails.logger.info("[Hot Keyword] #{keyword} score increment ~") Rails.cache.data.zincrby(redis_key, 1, keyword) end diff --git a/app/queries/weapps/search_query.rb b/app/queries/weapps/search_query.rb new file mode 100644 index 000000000..665480073 --- /dev/null +++ b/app/queries/weapps/search_query.rb @@ -0,0 +1,37 @@ +class Weapps::SearchQuery < ApplicationQuery + include ElasticsearchAble + + attr_reader :params + + def initialize(params) + @params = params + end + + def call + modal_name.search(keyword, search_options) + end + + private + + def search_options + hash = { + fields: [:name], + page: page, + per_page: per_page + } + hash.merge(where: { status: 2 }) if modal_name == Shixun + + hash + end + + def modal_name + @_modal_name ||= begin + case params[:type].to_s + when 'subject' then Subject + when 'shixun' then Shixun + when 'course' then Course + else Subject + end + end + end +end \ No newline at end of file diff --git a/app/views/weapps/searchs/index.json.jbuilder b/app/views/weapps/searchs/index.json.jbuilder new file mode 100644 index 000000000..25a1a6a34 --- /dev/null +++ b/app/views/weapps/searchs/index.json.jbuilder @@ -0,0 +1,9 @@ +json.count @results.total_count +json.results do + json.array! @results.with_highlights(multiple: true) do |obj, highlights| + json.merge! obj.to_searchable_json + json.type obj.class.name.downcase + + json.title highlights.delete(:name)&.join('...') || obj.searchable_title + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 1acaac57e..17fb5dde3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -852,6 +852,9 @@ Rails.application.routes.draw do resource :register, only: [:create] resource :code_session, only: [:create] resource :verify, only: [:create] + + resources :searchs, only: [:index] + resources :hot_keywords, only: [:index] end end From aa9570d4f391fc65b3d0fd8eabe4e8574a8de0fa Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 15:58:29 +0800 Subject: [PATCH 11/31] move hot keyword api out weapp --- app/controllers/{weapps => }/hot_keywords_controller.rb | 2 +- config/routes.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) rename app/controllers/{weapps => }/hot_keywords_controller.rb (68%) diff --git a/app/controllers/weapps/hot_keywords_controller.rb b/app/controllers/hot_keywords_controller.rb similarity index 68% rename from app/controllers/weapps/hot_keywords_controller.rb rename to app/controllers/hot_keywords_controller.rb index f915d9c47..e0c536e42 100644 --- a/app/controllers/weapps/hot_keywords_controller.rb +++ b/app/controllers/hot_keywords_controller.rb @@ -1,4 +1,4 @@ -class Weapps::HotKeywordsController < Weapps::BaseController +class HotKeywordsController < ApplicationController def index keywords = [] keywords = HotSearchKeyword.hot(8) if HotSearchKeyword.available? diff --git a/config/routes.rb b/config/routes.rb index 17fb5dde3..f0c290096 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -846,6 +846,8 @@ Rails.application.routes.draw do get '/auth/wechat/callback', to: 'oauth/wechat#create' resource :bind_user, only: [:create] + resources :hot_keywords, only: [:index] + namespace :weapps do resource :home, only: [:show] resource :session, only: [:create] @@ -854,7 +856,6 @@ Rails.application.routes.draw do resource :verify, only: [:create] resources :searchs, only: [:index] - resources :hot_keywords, only: [:index] end end From c51802281a05e3f97764ade83ca87076317fb0dc Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 16:50:32 +0800 Subject: [PATCH 12/31] admins: export user statistic --- .../admins/user_statistics/index.js | 13 +++++++++++++ .../admins/user_statistics_controller.rb | 10 ++++++++++ .../admins/user_statistics/export.xlsx.axlsx | 16 ++++++++++++++++ .../admins/user_statistics/index.html.erb | 2 ++ config/routes.rb | 4 +++- ...fest-4627fa5586ef7fed55ca286af7c028e9.json | 2 +- ...d94c3b6f31966bc65d7f89be077fc2ea512bec.js} | 13 +++++++++++++ ...c3b6f31966bc65d7f89be077fc2ea512bec.js.gz} | Bin 961314 -> 961433 bytes 8 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 app/views/admins/user_statistics/export.xlsx.axlsx rename public/assets/{admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js => admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js} (99%) rename public/assets/{admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz => admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js.gz} (98%) diff --git a/app/assets/javascripts/admins/user_statistics/index.js b/app/assets/javascripts/admins/user_statistics/index.js index 0d9df5f4b..3ffb288ac 100644 --- a/app/assets/javascripts/admins/user_statistics/index.js +++ b/app/assets/javascripts/admins/user_statistics/index.js @@ -51,10 +51,23 @@ $(document).on('turbolinks:load', function() { } }); + // 清空 $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'); }) + + + // 导出 + $('.export-action').on('click', function(){ + var form = $(".user-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); + }); } }); \ No newline at end of file diff --git a/app/controllers/admins/user_statistics_controller.rb b/app/controllers/admins/user_statistics_controller.rb index f60fb8dcd..71dc3096a 100644 --- a/app/controllers/admins/user_statistics_controller.rb +++ b/app/controllers/admins/user_statistics_controller.rb @@ -6,4 +6,14 @@ class Admins::UserStatisticsController < Admins::BaseController @users = paginate users, total_count: total_count end + + def export + default_sort('finish_shixun_count', 'desc') + + params[:per_page] = 10000 + _count, @users = Admins::UserStatisticQuery.call(params) + + filename = ['用户实训情况', Time.zone.now.strftime('%Y%m%d%H%M%S')].join('-') << '.xlsx' + render xlsx: 'export', filename: filename + end end \ No newline at end of file diff --git a/app/views/admins/user_statistics/export.xlsx.axlsx b/app/views/admins/user_statistics/export.xlsx.axlsx new file mode 100644 index 000000000..b66e62a99 --- /dev/null +++ b/app/views/admins/user_statistics/export.xlsx.axlsx @@ -0,0 +1,16 @@ +wb = xlsx_package.workbook +wb.add_worksheet(name: '用户实训情况') do |sheet| + sheet.add_row %w(姓名 单位部门 学习关卡数 完成关卡数 学习实训数 完成实训数) + + @users.each do |user| + data = [ + user.real_name, + [user.school_name.presence, user.department_name.presence].compact.join(' - '), + user.display_extra_data(:study_challenge_count), + user.display_extra_data(:finish_challenge_count), + user.display_extra_data(:study_shixun_count), + user.display_extra_data(:finish_shixun_count) + ] + sheet.add_row(data) + end +end \ No newline at end of file diff --git a/app/views/admins/user_statistics/index.html.erb b/app/views/admins/user_statistics/index.html.erb index fdc6259e5..30f8a7edf 100644 --- a/app/views/admins/user_statistics/index.html.erb +++ b/app/views/admins/user_statistics/index.html.erb @@ -19,6 +19,8 @@ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> <% end %> + + <%= javascript_void_link '导出', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_user_statistics_path(format: :xlsx) %>
    diff --git a/config/routes.rb b/config/routes.rb index f0c290096..5b6aebac8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -908,7 +908,9 @@ Rails.application.routes.draw do end resource :import_users, only: [:create] resource :import_course_members, only: [:create] - resources :user_statistics, only: [:index] + resources :user_statistics, only: [:index] do + get :export, on: :collection + end resources :library_applies, only: [:index] do member do diff --git a/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json index 49c70bf4d..81a6274f1 100644 --- a/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json +++ b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json @@ -1 +1 @@ -{"files":{"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js":{"logical_path":"admin.js","mtime":"2019-09-11T16:20:07+08:00","size":4350881,"digest":"cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121","integrity":"sha256-zZyousyXPOLbrOMMl/bEC8COLC7kSXL2aOc44ZAsASE="},"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css":{"logical_path":"admin.css","mtime":"2019-09-11T16:20:07+08:00","size":773445,"digest":"a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa","integrity":"sha256-obM1bv5Q/0cXzyJHVjm1MzxTVLoD/RB8m3qNSudvR6o="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-10-17T09:44:58+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css":{"logical_path":"college.css","mtime":"2019-09-11T16:20:07+08:00","size":546841,"digest":"944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9","integrity":"sha256-lE1Cc/YsdTg2i5AX/dM4e1476jGoeHN3DrIxMkVG1Nk="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-09-03T08:55:53+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-10-17T09:44:58+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css":{"logical_path":"application.css","mtime":"2019-09-11T16:20:07+08:00","size":1844002,"digest":"5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2","integrity":"sha256-Xrh8bhNnbQGDMX3rzhf63ifmjErO4oxBlDjaFdU8lPI="},"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js":{"logical_path":"admin.js","mtime":"2019-09-21T15:28:08+08:00","size":4382031,"digest":"c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4","integrity":"sha256-yeXr5hkVSFUOJ1FBluoSXPu0AoIOwSWgyaz5nS03j+Q="},"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css":{"logical_path":"admin.css","mtime":"2019-09-21T14:49:04+08:00","size":840093,"digest":"59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38","integrity":"sha256-WcWfjK6L70qDWShsmFRYEQydA+oSFRZZXJiJQ/RxfDg="},"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css":{"logical_path":"college.css","mtime":"2019-09-16T13:56:09+08:00","size":579109,"digest":"38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437","integrity":"sha256-OPlT1rpbhdP6tjyzwrvw0FfMxkVNB8+q+sOwbaN7hDc="},"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.css":{"logical_path":"application.css","mtime":"2019-09-21T14:49:04+08:00","size":1988767,"digest":"646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3","integrity":"sha256-ZGsRWKTowfE+aE1v6QJavHX407pSVuRAgCwDmCIzdPM="},"admin-a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:33:05+08:00","size":4383107,"digest":"a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751","integrity":"sha256-pH43wOx89fIjgCSXdtHoLWW2tqonLtc4kYWqIA+kB1E="},"admin-432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:35:20+08:00","size":4383103,"digest":"432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9","integrity":"sha256-QyxOrAmwNsV/8eiNkCuKp9+BFk5LQZusVXzxNmwdOtk="},"admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js":{"logical_path":"admin.js","mtime":"2019-09-30T14:43:41+08:00","size":4387200,"digest":"978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a","integrity":"sha256-l45c5gf3fCaBShdPSA2nmsJGwiAYaO+EZUqgO7Zye1o="},"admin-896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7.css":{"logical_path":"admin.css","mtime":"2019-09-30T14:43:41+08:00","size":842269,"digest":"896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7","integrity":"sha256-iWKB9HMXIrDAhNuxryHQ80pbwULViv9Xs5GGSrcd3Kc="},"application-97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd.css":{"logical_path":"application.css","mtime":"2019-09-30T14:43:41+08:00","size":1993118,"digest":"97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd","integrity":"sha256-l/MT6bt9JUdmSffXIVlZz0IUgP0KN4XRlWlTv5Sh6L0="},"admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js":{"logical_path":"admin.js","mtime":"2019-10-11T14:38:33+08:00","size":4394616,"digest":"2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888","integrity":"sha256-LNsjRC+nNQJThbiPKQDfBP7zi2FTAEGm2+N17w8K6Ig="},"admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css":{"logical_path":"admin.css","mtime":"2019-10-10T17:12:05+08:00","size":846514,"digest":"2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc","integrity":"sha256-LChUuaAhWN7VqAmq9xRKhjCxA1SrTlb+zE3/zHE3lsw="},"application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css":{"logical_path":"application.css","mtime":"2019-10-10T17:12:05+08:00","size":2001607,"digest":"50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af","integrity":"sha256-UAWa6SmGYEO0cBUShwL8+6U9MqLfFI5k4dlhwQZRxq8="},"admin-992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2.js":{"logical_path":"admin.js","mtime":"2019-10-16T16:11:32+08:00","size":4394790,"digest":"992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2","integrity":"sha256-mSzeCbbRfwCklXauLZ8c7RJyRLpAHvW31nfKuXQWiNI="},"admin-84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257.css":{"logical_path":"admin.css","mtime":"2019-10-16T19:25:40+08:00","size":846676,"digest":"84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257","integrity":"sha256-hPKneR4nXW+CBRQ3Cz+WgXa5lLnde4w7qL9IM2sD8lc="},"application-ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997.css":{"logical_path":"application.css","mtime":"2019-10-16T19:25:40+08:00","size":2001931,"digest":"ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997","integrity":"sha256-72urhIUrqvaakf5q+HW24bEYxVtMfRZWZcSI+sgMSZc="},"admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js":{"logical_path":"admin.js","mtime":"2019-10-17T09:44:58+08:00","size":4394897,"digest":"c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a","integrity":"sha256-yZAw0wVmL3QKqEtskloa27qtqgf9dOJlXmTUS0uX/Eo="},"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css":{"logical_path":"admin.css","mtime":"2019-10-17T10:22:41+08:00","size":846699,"digest":"534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d","integrity":"sha256-U0vehx1n9Nb8jaYRkX14vkBm/HWTulPukqoXBooZnW0="},"cooperative-04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T10:17:56+08:00","size":4330072,"digest":"04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7","integrity":"sha256-BM1qYNQSINOO5FzkCx0ATh0LzYfBMvsae6thRMHeuNc="},"cooperative-a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T10:21:41+08:00","size":830628,"digest":"a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3","integrity":"sha256-o0W7/Y44twyShezBdHAS/83kKRh5g+KupWV6u1a5tPM="},"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css":{"logical_path":"application.css","mtime":"2019-09-03T08:55:53+08:00","size":442932,"digest":"0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8","integrity":"sha256-DkF0eNVvQkZ+hXzRhrKcu8DWx8boXIpvQvOaxhiUPeg="},"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T14:03:03+08:00","size":4338033,"digest":"149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b","integrity":"sha256-FJ9HuGddYKgBTM/1DwD5Mv9p4r4ob/t0NDvEo+/7E1s="},"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T11:13:07+08:00","size":832914,"digest":"6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8","integrity":"sha256-YnO3ZtbvEd1WF02Gi6tV5/F68XVGyIjSug3Qprzadsg="},"admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js":{"logical_path":"admin.js","mtime":"2019-10-21T13:51:43+08:00","size":4397012,"digest":"82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6","integrity":"sha256-gvZsyAtWScZTClYlZ/KP6NBfe8O4Ih4GlbIhYlXFK6Y="}},"assets":{"admin.js":"admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js","admin.css":"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css","cooperative.js":"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js","cooperative.css":"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css"}} \ No newline at end of file +{"files":{"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js":{"logical_path":"admin.js","mtime":"2019-09-11T16:20:07+08:00","size":4350881,"digest":"cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121","integrity":"sha256-zZyousyXPOLbrOMMl/bEC8COLC7kSXL2aOc44ZAsASE="},"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css":{"logical_path":"admin.css","mtime":"2019-09-11T16:20:07+08:00","size":773445,"digest":"a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa","integrity":"sha256-obM1bv5Q/0cXzyJHVjm1MzxTVLoD/RB8m3qNSudvR6o="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-14T17:22:43+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-14T17:22:43+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-14T17:22:43+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-14T17:22:43+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-10-17T09:44:58+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css":{"logical_path":"college.css","mtime":"2019-09-11T16:20:07+08:00","size":546841,"digest":"944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9","integrity":"sha256-lE1Cc/YsdTg2i5AX/dM4e1476jGoeHN3DrIxMkVG1Nk="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-09-03T08:55:53+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-10-17T09:44:58+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css":{"logical_path":"application.css","mtime":"2019-09-11T16:20:07+08:00","size":1844002,"digest":"5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2","integrity":"sha256-Xrh8bhNnbQGDMX3rzhf63ifmjErO4oxBlDjaFdU8lPI="},"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js":{"logical_path":"admin.js","mtime":"2019-09-21T15:28:08+08:00","size":4382031,"digest":"c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4","integrity":"sha256-yeXr5hkVSFUOJ1FBluoSXPu0AoIOwSWgyaz5nS03j+Q="},"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css":{"logical_path":"admin.css","mtime":"2019-09-21T14:49:04+08:00","size":840093,"digest":"59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38","integrity":"sha256-WcWfjK6L70qDWShsmFRYEQydA+oSFRZZXJiJQ/RxfDg="},"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css":{"logical_path":"college.css","mtime":"2019-09-16T13:56:09+08:00","size":579109,"digest":"38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437","integrity":"sha256-OPlT1rpbhdP6tjyzwrvw0FfMxkVNB8+q+sOwbaN7hDc="},"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.css":{"logical_path":"application.css","mtime":"2019-09-21T14:49:04+08:00","size":1988767,"digest":"646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3","integrity":"sha256-ZGsRWKTowfE+aE1v6QJavHX407pSVuRAgCwDmCIzdPM="},"admin-a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:33:05+08:00","size":4383107,"digest":"a47e37c0ec7cf5f22380249776d1e82d65b6b6aa272ed7389185aa200fa40751","integrity":"sha256-pH43wOx89fIjgCSXdtHoLWW2tqonLtc4kYWqIA+kB1E="},"admin-432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9.js":{"logical_path":"admin.js","mtime":"2019-09-25T15:35:20+08:00","size":4383103,"digest":"432c4eac09b036c57ff1e88d902b8aa7df81164e4b419bac557cf1366c1d3ad9","integrity":"sha256-QyxOrAmwNsV/8eiNkCuKp9+BFk5LQZusVXzxNmwdOtk="},"admin-978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a.js":{"logical_path":"admin.js","mtime":"2019-09-30T14:43:41+08:00","size":4387200,"digest":"978e5ce607f77c26814a174f480da79ac246c2201868ef84654aa03bb6727b5a","integrity":"sha256-l45c5gf3fCaBShdPSA2nmsJGwiAYaO+EZUqgO7Zye1o="},"admin-896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7.css":{"logical_path":"admin.css","mtime":"2019-09-30T14:43:41+08:00","size":842269,"digest":"896281f4731722b0c084dbb1af21d0f34a5bc142d58aff57b391864ab71ddca7","integrity":"sha256-iWKB9HMXIrDAhNuxryHQ80pbwULViv9Xs5GGSrcd3Kc="},"application-97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd.css":{"logical_path":"application.css","mtime":"2019-09-30T14:43:41+08:00","size":1993118,"digest":"97f313e9bb7d25476649f7d7215959cf421480fd0a3785d1956953bf94a1e8bd","integrity":"sha256-l/MT6bt9JUdmSffXIVlZz0IUgP0KN4XRlWlTv5Sh6L0="},"admin-2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888.js":{"logical_path":"admin.js","mtime":"2019-10-11T14:38:33+08:00","size":4394616,"digest":"2cdb23442fa735025385b88f2900df04fef38b61530041a6dbe375ef0f0ae888","integrity":"sha256-LNsjRC+nNQJThbiPKQDfBP7zi2FTAEGm2+N17w8K6Ig="},"admin-2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc.css":{"logical_path":"admin.css","mtime":"2019-10-10T17:12:05+08:00","size":846514,"digest":"2c2854b9a02158ded5a809aaf7144a8630b10354ab4e56fecc4dffcc713796cc","integrity":"sha256-LChUuaAhWN7VqAmq9xRKhjCxA1SrTlb+zE3/zHE3lsw="},"application-50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af.css":{"logical_path":"application.css","mtime":"2019-10-10T17:12:05+08:00","size":2001607,"digest":"50059ae929866043b47015128702fcfba53d32a2df148e64e1d961c10651c6af","integrity":"sha256-UAWa6SmGYEO0cBUShwL8+6U9MqLfFI5k4dlhwQZRxq8="},"admin-992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2.js":{"logical_path":"admin.js","mtime":"2019-10-16T16:11:32+08:00","size":4394790,"digest":"992cde09b6d17f00a49576ae2d9f1ced127244ba401ef5b7d677cab9741688d2","integrity":"sha256-mSzeCbbRfwCklXauLZ8c7RJyRLpAHvW31nfKuXQWiNI="},"admin-84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257.css":{"logical_path":"admin.css","mtime":"2019-10-16T19:25:40+08:00","size":846676,"digest":"84f2a7791e275d6f820514370b3f968176b994b9dd7b8c3ba8bf48336b03f257","integrity":"sha256-hPKneR4nXW+CBRQ3Cz+WgXa5lLnde4w7qL9IM2sD8lc="},"application-ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997.css":{"logical_path":"application.css","mtime":"2019-10-16T19:25:40+08:00","size":2001931,"digest":"ef6bab84852baaf69a91fe6af875b6e1b118c55b4c7d165665c488fac80c4997","integrity":"sha256-72urhIUrqvaakf5q+HW24bEYxVtMfRZWZcSI+sgMSZc="},"admin-c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a.js":{"logical_path":"admin.js","mtime":"2019-10-17T09:44:58+08:00","size":4394897,"digest":"c99030d305662f740aa84b6c925a1adbbaadaa07fd74e2655e64d44b4b97fc4a","integrity":"sha256-yZAw0wVmL3QKqEtskloa27qtqgf9dOJlXmTUS0uX/Eo="},"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css":{"logical_path":"admin.css","mtime":"2019-10-17T10:22:41+08:00","size":846699,"digest":"534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d","integrity":"sha256-U0vehx1n9Nb8jaYRkX14vkBm/HWTulPukqoXBooZnW0="},"cooperative-04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T10:17:56+08:00","size":4330072,"digest":"04cd6a60d41220d38ee45ce40b1d004e1d0bcd87c132fb1a7bab6144c1deb8d7","integrity":"sha256-BM1qYNQSINOO5FzkCx0ATh0LzYfBMvsae6thRMHeuNc="},"cooperative-a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T10:21:41+08:00","size":830628,"digest":"a345bbfd8e38b70c9285ecc1747012ffcde429187983e2aea5657abb56b9b4f3","integrity":"sha256-o0W7/Y44twyShezBdHAS/83kKRh5g+KupWV6u1a5tPM="},"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css":{"logical_path":"application.css","mtime":"2019-09-03T08:55:53+08:00","size":442932,"digest":"0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8","integrity":"sha256-DkF0eNVvQkZ+hXzRhrKcu8DWx8boXIpvQvOaxhiUPeg="},"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js":{"logical_path":"cooperative.js","mtime":"2019-10-17T14:03:03+08:00","size":4338033,"digest":"149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b","integrity":"sha256-FJ9HuGddYKgBTM/1DwD5Mv9p4r4ob/t0NDvEo+/7E1s="},"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css":{"logical_path":"cooperative.css","mtime":"2019-10-17T11:13:07+08:00","size":832914,"digest":"6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8","integrity":"sha256-YnO3ZtbvEd1WF02Gi6tV5/F68XVGyIjSug3Qprzadsg="},"admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js":{"logical_path":"admin.js","mtime":"2019-10-21T13:51:43+08:00","size":4397012,"digest":"82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6","integrity":"sha256-gvZsyAtWScZTClYlZ/KP6NBfe8O4Ih4GlbIhYlXFK6Y="},"admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js":{"logical_path":"admin.js","mtime":"2019-10-21T16:41:06+08:00","size":4397437,"digest":"1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec","integrity":"sha256-G1co2U9rzPvO9FKnYNlMO28xlmvGXX+Jvgd/wupRK+w="}},"assets":{"admin.js":"admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js","admin.css":"admin-534bde871d67f4d6fc8da611917d78be4066fc7593ba53ee92aa17068a199d6d.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-0e417478d56f42467e857cd186b29cbbc0d6c7c6e85c8a6f42f39ac618943de8.css","cooperative.js":"cooperative-149f47b8675d60a8014ccff50f00f932ff69e2be286ffb74343bc4a3effb135b.js","cooperative.css":"cooperative-6273b766d6ef11dd56174d868bab55e7f17af17546c888d2ba0dd0a6bcda76c8.css"}} \ No newline at end of file diff --git a/public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js b/public/assets/admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js similarity index 99% rename from public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js rename to public/assets/admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js index 3298a4984..1c9d07222 100644 --- a/public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js +++ b/public/assets/admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js @@ -135709,11 +135709,24 @@ $(document).on('turbolinks:load', function() { } }); + // 清空 $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'); }) + + + // 导出 + $('.export-action').on('click', function(){ + var form = $(".user-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() { diff --git a/public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz b/public/assets/admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js.gz similarity index 98% rename from public/assets/admin-82f66cc80b5649c6530a562567f28fe8d05f7bc3b8221e0695b2216255c52ba6.js.gz rename to public/assets/admin-1b5728d94f6bccfbcef452a760d94c3b6f31966bc65d7f89be077fc2ea512bec.js.gz index b7bf437da44a43ffbb147646f847be39f373514a..519d4b32f2b50587740e213c03763515e552ac36 100644 GIT binary patch delta 11649 zcmV-{Eq>CX);gKjItCw$2mm5)fd+*J0fhzvg$4tK1_Xr$1%(C%g$4(O1_*@)355m< zg$4_S1`LG;4YdXi5`KT~Hi~S~@BS5?CU;r}Np`|;&OL^}g1|h^;L< zTOg@*q*h2US_>8f36BinGQ0yJOhUrUnFQ`(Amar1G1rpqPyB_mcRjjxRaduKicB)# zut@B#s$ILPcJ11=U*-2;BXz5*Vb}m9xmonPt_@3HE4a7u zl1jZ+VH*evfQ4drGyO5=l%uEDuQuRn0=2yIk{?x9OMatKs;&mrr%OxWu|#XfLH@Rv zRRDr^4gkDpwch1}LFf{Wf-zfecfvOGgkJ*0C~jY_cMINvESTjpJv);F%~2@AFb;CC z497$>)u|*46qA4L=<^E3`1E;7j!_{XN7bLw)&=n?1S$bq0s07zrBgS~Lj(3?2T$AM zzZElan`&Q$TZ<3;r31}jqxc1nR`=wh&doU`^2gcu{-eQP-`jrcyWt-$(2{tDNDmzkjidrrT&#;$r$TtjKE<2n7fGrWx8;Ua(Ui+}mF`B4Py zu2%2*OAUWUu2H8K$n{1P{HOe51%(s4gLreC0_S2XsR!LT9KJ?ncR-T*rfef1?4T2gY7z>mi>Hm}?Zg&g zWMkVQj~zNZ)&{|Gf_%Fm1`NW}GThSHmw0qzZW_Cs;_|;XVsbr#6(Se(# zu>o)?g4yzF)NJrdFe&?V0-nvF;JAZM(A6O0QsOXR8KDU1v)c|~?EiY`u}AN=as$N- ze>N{(8@zgHaQ@4!uP*#>{q?~g&JI5O;7ZHJx6hkIfZ zmih?$d(ov8s0tg8O&gW!Kv29I7e-&_m)iW{664*sywv3jLgkC#DBg->S3v(kfAp(* zBls;!(ntyg%Tko<&6UzJ)RF=>5gC$|Sw$RE*ApAq6Q-JXPHbHJS`tAz?&J#7TWZ#$ z#Qi0nDZ2ckceb!`$DR^e*cHztm%{8UnRZ&tyH>Xf%>bJ#41WcJTkw?f7YN2Ka96d49IBQs zC*{6;%0N16hOH7Wri_>E0MaT&m$7$Q@MKyw!ISk~BvX!I`0aKBPA$e(?6CMUmr&*6 zF!E-6@PNx&!o<6aNr24qn+cBDc-8T+{No)Au)(@$7E9;iMN&eHWBcdlNAh>rW^8=e z3(VIt0ObRu6OqOD9l`h=f4lC76@oOxOvHzo(5yHoQ}prm9H9^b@-}L~7rja(mylG7 z7mZW{0m`fepY%$&x)m-DLtPgIVwY%vgngd(xaYtD$LqDYrXSEIj9ifxXM?Q4tf9~$ z@DR0ha5_?0S@HcD+N0PVOnD_fC}zV5S50BjQJh0BWwTPGy^`})ehWV z^d*oVDYvX?z;g*K%PFD?*=+`<at0oP%cL9oZV`t-i|z4%C5Zd zm)T-LpaECTI*jbuf1og{s=yVc7Pf*yie`b%IXCk#n$dI$Rza&jnPI?g8VH;10JsEH z8)+Tb8KH*oa3(*A!%T`c3cnI7&XQ{ciWE$i++uHloTHFgqXj#!5Z?!gjHoXiUoo~; z)3M@&VLRyfsQ((dRO1_9!VrbM4D$=j+oaYP0G{`}C8)$we=KVrs~!;#tFdGnb_zPj zb8+8O(dkMSva`zETgdwGv(SEO1ar%(H-9EtMajdYst`@?b-x9N1TNDQHH-wK{o`Q- zyDb%&{i(?8&xy>P;~^8&da20VnTpJvH$nHRcG(ovuLRi5*1!TT6fNYb9eD-9Neqsm zb*kjE4vcF}3Z;ruq~MnA{gxW=4?8!UGWY0Zzqqpme+cjP;ne%k)4}m)!VXHHN_*lG z7UhWw-l7}daS~T0)d^>VE_{aS-F5@Gf_I;X+YFZ5y-xr;;KFa>XNk-+&@&toKryWX zUB4-N;MV-^>QV?d%RKki;hB?MUfBHOrQykMW|VN>idGM<`W;ja1XcW@TducYu&ELc zYf|Dae43QIfxw3 z;}jxRv{s$(lcFWR`t(XC?6qnK!v;#?UT0;=FU%L&f8~Fkg&Boe*n08x;rmzOR&5Ym z&~w~5@;{5tzWGJ0GkE!>t?&N6_0300wm%kifBb{p?qT==0565dO5IhzhN#cOe|NTz zIjpn&cimNV)L--EU(Vjmx*dK468tCI?|n7+_RAQmf2`hpJgm3aaMlpH!AGZupPbnG z_N(FRCpOQo58l6o;=cU2b@8*o8*lPJ8Y0aIiJv3nA(-uJ?`>T^kG_c?ezm#&J;He7 ze+uw&_=2|vbS(3n=i(+w0Z7g&YTtq`90o_?I#iD0o`2rfs8l&k`(SPgvH#e@nI5_|L z)|KB6|MuGOKhF){{z4Wq{s=s+2dDjbyIHm>;X=(SlYj;-F?^_y*wO5pZBvT^>%JCc zDO+2Vj=#G_!_gaDRGj`E7l3bgn+rJ8+UWvZU;WZ2Q+@1yKo{{8omGJVR>ID4e-9%& zVEX;e@n8F};LCoaD+DgwvKoxz1`MR5z|*S48)q#BQIypg)r1JyWdL$cQ80XjxWcCOPV1l+bc+2n!vsfex6AvQ|4-3nPr>H-*IEPx$ zhR%2(PmV~3y#uW^q z3;*l%OBlgfyAdNPA8`3ql3jxZ>yu)#c@>65JD~kxx}9t5+b>?)e)p15c0i4|nWEg` zw?49P7WIx4$(t$O8wn7J`Br6*0+Gj#9Lsk7fT~@=4~FvwzYp*LLKCa9f4nTP(wpMC z5r=+_>&It|dOS^(1S2Eh$HIu*;9q%u@a4yYQ*Up4d&(Q7?@IL}Y3A@CAsQMBaU?A0 zbkSveZUN5=+<}g5m)x%XaRz_=Z1~AJK1#hz-ES~REa;fl4?xaub`6yQ<9)bSo1(l7 zr*?CeMWg}Vnkx^6^sv@MkC<{g0SLKge8oSzmypx zer#Ds^j@d5&-4L+RjM!7gW7}K`VgmBSnKoA$EG|3A=)m17%asTyxPAb;{T4AVulDr z0|mfdqvo{2$XN=US{?4r{_&tTlQQ1ESYBo#VH0#nX9n@2iO@_!e`Qt*QsW1d*d1jl z45Kaxct>ak9*9faD6%LwLe?Xu%U0i_4-Zek3?+ZG@ zQFi0pmg6j{pjP6v5U(`)G(}TKTy&Xax_SBB=INIQZ@%ZGNvLrDek8!GHAydIG#XL~ zl~uC{sxb(8HPB(o5oZBSh_3v*5;yH2lYo>6YLSA8GqZ+swlK{7m<2O1@EF71IG)9i zB5j!c$e^i@e@AkhjPcX2#2tvvZw|@MUO!eGr=Q}9GhAdn`RoNwrkI^c(&*sgTZ7Z; zNN@H~cZK=|>Uo`c%p)^g&{#eQHVe4Hiz$9AsAues;iF>6r?YFxGjvTTUWwo*y*Ui- z((Z)FJ!LYL3~#6ybVt_ZwkO1%G70lyl3%=;Sh%4je{dyfRH%HDKqQB3lOoylvwO4( zEap*e*}eJCbQ{Y^KiqAb*uF!xeb4vVZ);t4$EKUkNRZ%YI~%Vasww>?&7XBb!6D5@ zSSj$7E{Zu4YFMHbmT*>%q{YUt<{)JQ=LJGn!?GTR3G2VH##RsGDR>oI)NnzyB*{FN z9**V2e~C|Bx2&~q1<&y0HtHmkg%vcqS46Un7>F>ZmSrt&n&;+t3dN5izq%?;Hl8Ra z3rt0;Z$+o7DH4rw=-NG3NiCb#-`V=^&F%Mpzj5vB8OkCQJX{HvZBUkEk!3N8hljNQ zDc7#vUL%%`2% z0bwnX+H*L#b5F8#%3!7%WZbv$L#U!5e`wN%h3jQG_1ZvUh+6DkXL#XN#5w~^I9VMO z;ZSc%Jd9|qG7ti)U|o)Bj8R5Bg`h7Mz*rnXrv_Oq(5~&2DeSrC&EY|QC(+Axj3AS= zGzBg;Ek0J(_*f>~yvGB(Vi`Kqv@=lFP2V>+B5D>`@RVwW%x&TncEKM6;4xCR-UPC&{f?aBm}%B7(?a z*GLjs(WDr?dPNRdi6kqUn`yz-15Q0LtXLKizneaw)45Wt290*98lZDZY8Fqe&bWCz zN#mW&MGBmw1>5#`2{U-&kNl7wf5%N5IrDfg~=YdOr$cPW10nNSXft>t>BNkkjL;V{ze z+~uvy=LeV14L`ZM{rm@8-=Fy5`dOmC37<~01o2#l-H|C~n|@oFbSgzBm|c_lzP*J& zc!gsi7J7~8W+978%T!KDf5uTU*w7q9sKORdQ%7ZK#j*`*N|nX5SUC2+UY;Wec7imV zXa3s zExLalJHC_9lBwV{@2{%iV8_5z6c~^4p+>k8@_>~_upD`_`bA9he|=*&n?)~Ow%fZb zW8>_>93r*}zbB%ac+48ij)+>DW51MdpQHL~2H+RJ;89J8RGE1a6yk;ndpLSLvFT)2 zIB50+`%utW8-Bs`tUwCHHHD5Y9-+wn84tAF205=4>DvTr$ul|;0VKNPR+-sy71MPJ ze;Sk%mS6)u?Ippff83s{ez(NH5(80UH2BZ`?6UXd6A!a_OFKP{v&oe92=y(8p)T_| zt3iEbHDbw(ifMMc!TA%zb0;^xKR0~gibu}Co%8f#^&UrT7!+k(#qY&{1J|ra1@SRn z%`!|fpKh*EETN}*+nv>zTcQyQJ?Guf#W9n$%67DRx;-x8f49g_q~$tuKF^hQik+2* z>QRvH(>T5(qaOH3ULIlA6g&ZukBE+y>ZZViN4W|`!zLQ1F2+X41^%sY-+_NCuiaVP zf7f08y|YLB(zExM{`Y+8Ulxy))X!`4#edr0FZ`c!X8G(Ldt+`Q1OxEm2j36eCP zd#(^8QI3Lcf5eeSTNLopUNyuWRt=kRXhpy14$ht(oIZt*teieM{I9ovxc-8xlltV| zK&0+$GHHh;$HWLv8I8RRIE6R`6Xb+Z3MLp! zi~@Z-CU=a2YIJjA6wDX%h*6OYS&LCfjFT~Y`gJ!(VK+u$H%8&di&02yV(Si_G)6&# ze#^utjDEU{uvV5o>!%W;(5NqUd|=AV(KVRRfBnV;vg>xUGj2CG?n!eqonxkIuW$NK zg`E<5vS1dfyq;rA;V~IZB0^IvaFPKk;sr+8RQGeQhK+{b?gq@vp5fqLS@wzZqHsKQ zX_Nt0A*RV?ACu4rQK^GwSj{@gYEnB!qOvlds3N#bv{Z+N;W7gxZ)bxjI-4Sk%GBSA ze+veciPJ&q-M%PN#vrO_GSq=S)2CfNG!HEgYKC z37Hu^zxWqNRl9BDpO7kb87}(wY;L+Z}fAd@xw{;W_|>xI?0lZT&LO zl&N>k<Ix~xeCCo zang#TaB$UI(UYw@Y^q;ks>qFNf7<-yh0W`qZ+-va#?|$WtIuy-{WHj$n;-ms>zj`@ zKf5+VRLT!@fRP1}fq>tO!Y6`df4B;->IL1V--&+9dK3k7bHn%7w_f~qcYDD6blHwlM?ZAyj{QhzSbM|1>|}K6X<%49D+?SWTXS{wKm; zlq!-RUDRdWrhhXG)vIBM?>zE7nkIx~+qx|v#<6p2&9yBayB4XpChV6kf8oUaJLX-L zo@P)GLyK)&caivh>lwe*!|DPekw54yNfR7&Rmb4_m$uJcD0NHG^ldG6Yl`k3q*-L>+8D1UOj&<2<#*tk6TAR7do#8t zJD(G&I>+3gb|7PHQ4@gve}v1A$j(UuBJMrtP4r@_P1#IAuZGS6!vdFgr(=!{7 ztpu?>nKY{Z^!`XL=VUu-q8#^0o#xaZ)8X+fNMLx%{!Tg|TjTmt#2yiEGaEZf8-CKc znkgS@JuGl}^jk+J;iL&XsS*#_MN7SUqsGm3LUToDBk{ zqUOEYoKd9iIN*5qMCirqRPjJO;Id!bd+&iOqhE_Z;xDBJQ-VTK2aE6J5tsMO!H@VW zN0dJS$Un|u#W~g%YT%vxUXQqkC^TUaAJSa#6FyW)oDqlGf4ykJVs=I5)^P_E%tbZ5 zM26(Wg@~4?%UkJlGsp3Ue{o*!^-`#XwA*PhnH;ai#x#ytu6e=8QkjQ;jfpuJMETc0 z4bEKRlvpm8J$(|U>#C$eP#Lxreol!DXkCkaag@t{w$p#M+kej3Q_I|efYyyV;c;&Q zA1G7Lo#Y}Me~F@V!#+|s;vO}|sBfMp)lL~)IxA_965OzWmH?jONlzT0QqIKKSJZf- zAOuOL-g?lM?llDxZ&67kd$nedO>yxjBf5!h{@M_x=jxvetP(PK(&0Rg{<|LcKL?Nd z2a}se9XKjcsP$C};ZhVd+tG0v$C#)w%~u5k0h=Cme+1W`xGO$kl(%V{|7QB-XRUhD zA9NbgMBFXb8OJY{RFwyr;S?)BTa`$pp6)cSAB$`eX9E&Y6A++=FDFQn>NJw`GU0`RtJBYZ80+m(j zwIXwvC)!$yE1k-xKZpt34`miIa*ff916T8B=CK0xpua#3De5KRawDrvZTa zwkjk%1m}(0EsyrpR=Xtmp_N0(khyZlw^O9g5z`Pn#*VQ}0OqnX&FiKZl6kTiD5D2Lvl> zf8d;^R7K%(k&38O!(OKvq)1enK9yBWN>Thfu2)_VEbH>3XCd4j2|$%2H1FBsvuCL+ z5)vk>V}W+-rnARy-Qo*z^w%ed)MDuiNhIs!M*5k205pU81g3LkH`SaV@>$c(-0SJV z1}Oto8&C=2%RhHZ`_8icWxKsp&O9oMe-FW8wN_&OPuTC>J8dOpgn1t-m2_loO*^SI zMH+h@V}zn3-VJ<9FNp3uVa~{-9QirvE-axGu(->B089Beo#gTv5O*V8cN5I-CYaw% zFrS`ao-&W!B=bM>B=bNFPrHp(uFi&yQdKuk>6Jrt^y zDNCVukap_TT=c4^h%LBf6N(a@97;{}J<*j;_zXgLlIffjM6rBW%qdW)py(r19lsl8 zw3St~_A{6NoDM{P4TzzU1R~8dT%;IW`TOw7ABXQ=7@j%HRrSMjFDsAp0Non^M6L;D zwJX@8KF6?ua>IbS76>7n=$!|~LWVV|q@l!09~uKM4o=4|p2>H<7<~FMpU4uE}U!#E|jrHl}!C@~+n5~~1X1pc|9f}va8a8^( zmNe-nG=gC7}#**^C-(xrX^kr{Q- zotK_0Mwz<1CeIEN%!n!$Z)2r4HoT3k`0mNTcTawN_l(AO&p7xd_2ZNxbe?8LnlVeu zDB3unHiT_Y(PsKCp(CKjg-VVknXwY#EB!MMnMq@nrjt`5J zWL{>+6O6`hU1LwyGlO8FePXn67oEU@cB6WDK(p=T1{o3kNgf>ekk5Q zzwe(*^S><3?^7;<{D^?U(!QEU{S8Tc2m1UVcTR?Pm@l)j%T7EV6}-ZxqPu{~SJ8r~ zPdfbaS#-)!m;LC?_KS3Gh+A3Q9_zJ1Rt-9ZFs_xXmgvUQno>y<$7#2#+aM}jDLfB< zGcw632Vem!RBTBXg{c$>%jWTuGk>z*+r8GY*DmOk=p@Nj1IF zv~956)%vksi`h!UPW{;%F}~VB?OI)bck>JHbbet$cku(iBZ#*VM2_t-HMeX6ifLDh z!>Xy$mYa{KxkUrGTxIj^HA5F-c5cyyqzQJ~+rV5=!B$~}W7^ytrcXGro{k;gTkdTp zZox6kgJ4gfY#J6Jl0-Rmkw^+?dXUrt(+RSRE$VFCA4hwx5)}O&Mi$YSy@hHlat7XBFo}! zT{!QTP`kjh}wvX{X(wE1R+3?sZGnOjH)`~g+Qa+$ckQ3JCUI#fXJ5hK=b(KiKuw5$@Ovf)v z1hd3`+M?Hp-zX^a^yqp^nKC_osX!zd)(7MGN7$LA#&E!8G2V$exWn;O+<*j@diRJc z#P6(&A3TD$M_wNw_)hW0f6`lG&NNfGve;nl-dT3GK{ z>G=s~>B;#lu48!@S9=Owf7<%S((nkWi_zEI?o+w>^7GspZ{`BGknCb`@}t4U*9Nb@ zLm7p958@yDRbBLtx%$%P=j$Znf_@G&t6HwWEba6_mAdtG&Dv|Ce=gC^tWtfxV+nH0 zt=S>VNiQp2ncqQ5GR5_X2n6D%f;XMC)5h=yC5?G^4;w;@7Q4ip0hFTNKGI#k$HorPri^}_2LS3j@}M#-%B`X0a&)PF=EKwhjn>Ml5L6!^HIlffwOw`c2C2g)YuD<|vHZPysJpJ<4^Do6C zGQYlX*#T-dzy8l6(}yPDfXRa>Q3KZlMiRgLdzN!Y)Ov9*TZ zhb0|mf9xfGc2a_sQ;BEy^WkGOet_M3BrDs3{Y1=jMn0g2e94no$*DiArmc!;pYmST$BRfrGei+rMj%8oh zpQJtYTR}J?P1le52q*S?qzw(xo|FFYW+DX+e+YN-(YCv6@`nx>A5F*X4$KNRVJ})9 zoB!zfjl&`AEiO~Ze%vwhi;jV%>T=`i`Qd+_8(evL^OF~NBqd1v8&{v-I`Ng8ns;<( z-X@*cD4(kN$uJkGh&9*}hqxf}D9gxT4~$Ux8q6nz%q$Y|QmvT+o^*dPMc4RA9cC1WV5wj$C?P zZLB>{n`G|#RPsrKkcWJIz{m{|kNs%9TL;YYjJ`GEIoUDsWDCo%Tn6#7Yt7A&P2G;3 z=r!9qJgxN9@p7eDa?R=Axd&8SozuFM)4Fqfx+;8@Z}_2=q_T4)qfI|S9ifYef@VoS zADpOG<_jzm^l5oNS&7+4g6byEe^zR0)zb)Cqn@-ZabsjB)!ZLmy1;c~GsOKKt^QBK zBt4S-)HR#cB;Qx@fkPrNy>_*?o$7_bKXI?kQ?3f2+uyUOf+; zTc4-aw(~#66V*&u82K`_KD=A{jcRl0cVDYcN%)?F%5Q_ zt3q@#|8UNG2+o=|W4}uQENE~Dz>?j1Y_%iF4}OG|kDdtrqX(PwH*f%>F#Eqs2M;~* ztJ2}{>7d1e6Fp$xzQDQKf9))nA}nHf^Jv}pB1ZPo4AEx^`|o~dr4cT{?S$F6R^np7 zd$}b&!OAsmX6hnlum#Z@3`vx@gW*n1Zy~b|VI!V)2(dXFZ)L3Ycqd!|PSbtB?>rbZ z{NsiF?8VI)X)+R~t}dHJ!xV&^@L3*DzTo@|{J{@3gtFiOn0Y?>e^~W{R8d#CP5X++|dC)3|ZDH7m>TT|S&ws|Vo?mY8daxQERr$*k z&D&uc%UN^rv(RYZb@jvVHeWe0JbPjD%xi=57vWb9qTXC#cEx(|437|p#_Z5p<&A8>ctVf3FYEy}Whe&x2Pl4PN@M?RWngM`VkuDXU3!3G9O{AUpHj)=>Z# zUve#VvuqBX146Dz{CMkw%(u#N8!C!ns7Lif%=2G8#G; zxe!%KF8YY;BXY39c(%0Fri2p)^=0H%noD)>6n04E)YVk&09`Y_=PLk*q5lG16o-a{DaE@w13~4Zgg6?r+0) zzuvfdYU|=>gE!v9`{IQY!{`63a8H>{OZJBm6B@T5XlHf7<+uDD$od9&AaI><@#B93 LS>FeMeHlXlKV!2t delta 11530 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 Date: Mon, 21 Oct 2019 16:53:31 +0800 Subject: [PATCH 13/31] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/admins/user_statistics/index.html.erb | 1 - config/routes.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/app/views/admins/user_statistics/index.html.erb b/app/views/admins/user_statistics/index.html.erb index 30f8a7edf..31f968eab 100644 --- a/app/views/admins/user_statistics/index.html.erb +++ b/app/views/admins/user_statistics/index.html.erb @@ -19,7 +19,6 @@ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> <% end %> - <%= javascript_void_link '导出', class: 'btn btn-outline-primary export-action', 'data-url': export_admins_user_statistics_path(format: :xlsx) %>
    diff --git a/config/routes.rb b/config/routes.rb index 5b6aebac8..ff7f798de 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -911,7 +911,6 @@ Rails.application.routes.draw do resources :user_statistics, only: [:index] do get :export, on: :collection end - resources :library_applies, only: [:index] do member do post :agree From 74714547e708ca9950bdba979a8a24d5f2e1e9c2 Mon Sep 17 00:00:00 2001 From: hjm <63528605@qq.com> Date: Mon, 21 Oct 2019 17:06:05 +0800 Subject: [PATCH 14/31] shixun={this.props.shixun} --- public/react/src/modules/page/VNCContainer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/react/src/modules/page/VNCContainer.js b/public/react/src/modules/page/VNCContainer.js index 6ef10888a..f923dede8 100644 --- a/public/react/src/modules/page/VNCContainer.js +++ b/public/react/src/modules/page/VNCContainer.js @@ -55,6 +55,7 @@ class VNCContainer extends Component { codeLoading={readingCodeLoading} repositoryCode={repositoryCode} isEditablePath={false} + shixun={this.props.shixun} > From bc1b9866fabf0c6744d466d42b522e26fff90f55 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 17:17:28 +0800 Subject: [PATCH 15/31] admins: shixun weapp image config --- .../admins/modals/admin-upload-file-modal.js | 4 ++++ .../javascripts/admins/shixun_settings/index.js | 15 +++++++++++---- app/controllers/admins/files_controller.rb | 13 +++++++++---- .../shared/modal/_upload_file_modal.html.erb | 1 + .../shixun_settings/shared/_list.html.erb | 4 ++-- .../admins/shixun_settings/shared/_td.html.erb | 8 +++++++- app/views/weapps/homes/show.json.jbuilder | 17 ++++++++++++++++- 7 files changed, 50 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/admins/modals/admin-upload-file-modal.js b/app/assets/javascripts/admins/modals/admin-upload-file-modal.js index cf1333381..a53173959 100644 --- a/app/assets/javascripts/admins/modals/admin-upload-file-modal.js +++ b/app/assets/javascripts/admins/modals/admin-upload-file-modal.js @@ -4,14 +4,17 @@ $(document).on('turbolinks:load', function() { var $form = $modal.find('form.admin-upload-file-form') var $sourceIdInput = $modal.find('input[name="source_id"]'); var $sourceTypeInput = $modal.find('input[name="source_type"]'); + var $suffixInput = $modal.find('input[name="suffix"]'); $modal.on('show.bs.modal', function(event){ var $link = $(event.relatedTarget); var sourceId = $link.data('sourceId'); var sourceType = $link.data('sourceType'); + var suffix = $link.data('suffix'); $sourceIdInput.val(sourceId); $sourceTypeInput.val(sourceType); + if(suffix != undefined){ $suffixInput.val(suffix); } $modal.find('.upload-file-input').trigger('click'); }); @@ -48,6 +51,7 @@ $(document).on('turbolinks:load', function() { contentType: false, success: function(data){ $.notify({ message: '上传成功' }); + $modal.find('.file-names').html(''); $modal.trigger('upload:success', data); $modal.modal('hide'); }, diff --git a/app/assets/javascripts/admins/shixun_settings/index.js b/app/assets/javascripts/admins/shixun_settings/index.js index f99574673..8b3eee505 100644 --- a/app/assets/javascripts/admins/shixun_settings/index.js +++ b/app/assets/javascripts/admins/shixun_settings/index.js @@ -34,10 +34,17 @@ $(document).on('turbolinks:load', function() { }); $('.modal.admin-upload-file-modal').on('upload:success', function(e, data){ - var $imageElement = $('.shixun-image-' + data.source_id); - $imageElement.attr('src', data.url); - $imageElement.show(); - $imageElement.next().html('重新上传'); + if(data.suffix == '_weapp'){ + var $imageElement = $('.shixun-weapp-image-' + data.source_id); + $imageElement.attr('src', data.url); + $imageElement.show(); + $imageElement.next().html('重新上传'); + } else { + var $imageElement = $('.shixun-image-' + data.source_id); + $imageElement.attr('src', data.url); + $imageElement.show(); + $imageElement.next().html('重新上传'); + } }) } }); diff --git a/app/controllers/admins/files_controller.rb b/app/controllers/admins/files_controller.rb index b269f8e27..cb8b66119 100644 --- a/app/controllers/admins/files_controller.rb +++ b/app/controllers/admins/files_controller.rb @@ -6,7 +6,12 @@ class Admins::FilesController < Admins::BaseController Util.write_file(@file, file_path) - render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url + "?t=#{Random.rand}") + render_ok( + source_id: params[:source_id], + source_type: params[:source_type].to_s, + suffix: params[:suffix].presence, + url: file_url + ) rescue StandardError => ex logger_error(ex) render_error('上传失败') @@ -33,14 +38,14 @@ class Admins::FilesController < Admins::BaseController @_file_path ||= begin case params[:source_type].to_s when 'Shixun' then - Util::FileManage.disk_filename('Shixun', params[:source_id]) + Util::FileManage.disk_filename('Shixun', params[:source_id], params[:suffix].presence) else - Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s) + Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s, params[:suffix].presence) end end end def file_url - Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s) + Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s, params[:suffix].presence) end end \ No newline at end of file diff --git a/app/views/admins/shared/modal/_upload_file_modal.html.erb b/app/views/admins/shared/modal/_upload_file_modal.html.erb index 036f1122a..a32058cd3 100644 --- a/app/views/admins/shared/modal/_upload_file_modal.html.erb +++ b/app/views/admins/shared/modal/_upload_file_modal.html.erb @@ -11,6 +11,7 @@
    <%= hidden_field_tag(:source_type, nil) %> <%= hidden_field_tag(:source_id, nil) %> + <%= hidden_field_tag(:suffix, nil) %>
    文件 diff --git a/app/views/admins/shixun_settings/shared/_list.html.erb b/app/views/admins/shixun_settings/shared/_list.html.erb index 0235e5ef8..7591fe323 100644 --- a/app/views/admins/shixun_settings/shared/_list.html.erb +++ b/app/views/admins/shixun_settings/shared/_list.html.erb @@ -1,12 +1,12 @@ - - + + diff --git a/app/views/admins/shixun_settings/shared/_td.html.erb b/app/views/admins/shixun_settings/shared/_td.html.erb index f72dc8a38..ddbbdff02 100644 --- a/app/views/admins/shixun_settings/shared/_td.html.erb +++ b/app/views/admins/shixun_settings/shared/_td.html.erb @@ -1,4 +1,3 @@ - + <% page_no = list_index_no(@params_page.to_i, index) %> - <%= render partial: "admins/competitions/shared/td",locals: {competition: competition, page_no: page_no} %> + <%= render partial: "admins/competitions/shared/td", locals: {competition: competition, page_no: page_no} %> <% end %> <% else %> diff --git a/app/views/admins/competitions/shared/_td.html.erb b/app/views/admins/competitions/shared/_td.html.erb index 09dcf48b3..394a41d79 100644 --- a/app/views/admins/competitions/shared/_td.html.erb +++ b/app/views/admins/competitions/shared/_td.html.erb @@ -1,6 +1,6 @@ @@ -15,7 +15,7 @@
    序号 ID 实训名称 技术平台 权限 技术体系上传图片上传图片小程序封面 创建者 关闭 复制<%= page_no %> <%= shixun.identifier %> @@ -21,6 +20,13 @@ <%= image_tag(imageUrl, width: 60, height: 40, class: "preview-image shixun-image-#{shixun.id}", data: { toggle: 'tooltip', title: '点击预览' }, style: imageExists ? '' : 'display:none') %> <%= javascript_void_link imageExists ? '重新上传' : '上传图片', class: 'action upload-shixun-image-action', data: { source_id: shixun.id, source_type: 'Shixun', toggle: 'modal', target: '.admin-upload-file-modal' } %> + <% weappImageExists = Util::FileManage.exists?(shixun, '_weapp') %> + <% imageUrl = weappImageExists ? Util::FileManage.source_disk_file_url(shixun, '_weapp') : '' %> + <%= image_tag(imageUrl, width: 60, height: 40, class: "preview-image shixun-weapp-image-#{shixun.id}", data: { toggle: 'tooltip', title: '点击预览' }, style: weappImageExists ? '' : 'display:none') %> + <%= raw '
    ' if weappImageExists %> + <%= javascript_void_link weappImageExists ? '重新上传' : '上传图片', class: 'action upload-shixun-weapp-image-action', data: { source_id: shixun.id, source_type: 'Shixun', suffix: '_weapp', toggle: 'modal', target: '.admin-upload-file-modal' } %> +
    <%= link_to shixun.owner.try(:real_name),"/users/#{shixun.owner.login}",target:'_blank' %> <% if shixun.status.to_i < 3 %> diff --git a/app/views/weapps/homes/show.json.jbuilder b/app/views/weapps/homes/show.json.jbuilder index d2a451030..eb5b238ac 100644 --- a/app/views/weapps/homes/show.json.jbuilder +++ b/app/views/weapps/homes/show.json.jbuilder @@ -6,7 +6,22 @@ json.images do end json.shixuns do - json.partial! 'shixuns/shixun', locals: { shixuns: @shixuns } + json.array! @shixuns do |shixun| + json.id shixun.id + json.identifier shixun.identifier + json.name shixun.name + json.status shixun.status + json.power (current_user.shixun_permission(shixun)) # 现在首页只显示已发布的实训 + # REDO: 局部缓存 + json.tag_name @tag_name_map&.fetch(shixun.id, nil) || shixun.tag_repertoires.first.try(:name) + json.myshixuns_count shixun.myshixuns_count + json.stu_num shixun.myshixuns_count + json.score_info shixun.averge_star + json.challenges_count shixun.challenges_count + #json.exp shixun.all_score + json.level level_to_s(shixun.trainee) + json.pic Util::FileManage.source_disk_file_url(shixun, '_weapp') + end end json.subjects do From dc52b5f5039a00cc5b4c65e699df6ea274c6dcb8 Mon Sep 17 00:00:00 2001 From: hjm <63528605@qq.com> Date: Mon, 21 Oct 2019 17:41:39 +0800 Subject: [PATCH 16/31] =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/page/VNCContainer.js | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/public/react/src/modules/page/VNCContainer.js b/public/react/src/modules/page/VNCContainer.js index f923dede8..36943f73b 100644 --- a/public/react/src/modules/page/VNCContainer.js +++ b/public/react/src/modules/page/VNCContainer.js @@ -24,7 +24,7 @@ class VNCContainer extends Component { repositoryCode: '', displayKey: 1, vnc_reseting: false, - + saving: false, } } componentDidMount() { @@ -40,28 +40,56 @@ class VNCContainer extends Component { getSecondDrawerWidth = () => { return $('#game_right_contents').width() - firstDrawerWidth } + doFileUpdateRequestOnCodeMirrorBlur = () => { + if (!this.currentPath) { + console.error('未找到文件path') + return; + } + const { myshixun, game } = this.props + var url = `/myshixuns/${myshixun.identifier}/update_file.json` + const codeContent = window.editor_monaco.getValue() + + this.setState({saving: true}) + axios.post(url, { + content: codeContent, + // 评测的时候传1,其它情况不用传,主要是为了区分是用户自己提交还是自动提交 + // evaluate: 0, + game_id : game.id, + path: this.currentPath + } + ).then(res => { + this.setState({saving: false}) + }).catch(e => { + this.setState({saving: false}) + console.error('update_file error') + }) + } renderSecondDrawerChildren = () => { - const { readingCodeLoading, repositoryCode } = this.state; + const { readingCodeLoading, repositoryCode, saving } = this.state; + const { shixun } = this.props const height = $(window).height() - 130 const isEditablePath = false; return ( - +
    + {/* (isEditablePath ? 'none' : 'block') */}
    + style={{ backgroundImage: `url('${notEditablePathImg}')`, display: (shixun.code_edit_permission ? 'none' : 'block') }}>
    ); } fetchReadRepositoryCode = (path) => { + this.currentPath = path; const status = 1 const fetchRepoCodeUrl = `/tasks/${this.props.game.identifier}/rep_content.json?path=${path}&status=${status}` this.setState({ readingCodeLoading: true }); From ffe79c2e888028b8e8dfbd32be210b07fa11a6ce Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Mon, 21 Oct 2019 17:52:12 +0800 Subject: [PATCH 17/31] =?UTF-8?q?=E5=90=8E=E7=AB=AFvnc=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/myshixuns_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index a9cc76296..2520e0069 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -261,7 +261,7 @@ class MyshixunsController < ApplicationController uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") end # 隐藏代码文件 和 VNC的都不需要走版本库 - unless @hide_code || @myshixun.shixun&.vnc_evaluate + unless @hide_code # 远程版本库文件内容 last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] content = if @myshixun.mirror_name.select {|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? From 3c512142d3098143eb4a13ab7da7c275106ecb90 Mon Sep 17 00:00:00 2001 From: daiao <358551898@qq.com> Date: Mon, 21 Oct 2019 17:55:30 +0800 Subject: [PATCH 18/31] =?UTF-8?q?vnc=E4=BB=A3=E7=A0=81=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/myshixuns_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 2520e0069..4e587513a 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -261,7 +261,7 @@ class MyshixunsController < ApplicationController uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") end # 隐藏代码文件 和 VNC的都不需要走版本库 - unless @hide_code + unless @hide_code || (@myshixun.shixun&.vnc_evaluate && params[:evaluate].present?) # 远程版本库文件内容 last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] content = if @myshixun.mirror_name.select {|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? From 82ac7e2fc2e5020fff308f36cf15b33594fe0561 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 21 Oct 2019 18:19:10 +0800 Subject: [PATCH 19/31] admins: fix user statistic --- app/queries/admins/user_statistic_query.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/queries/admins/user_statistic_query.rb b/app/queries/admins/user_statistic_query.rb index 866ec4d0b..d1811e5ab 100644 --- a/app/queries/admins/user_statistic_query.rb +++ b/app/queries/admins/user_statistic_query.rb @@ -83,7 +83,7 @@ class Admins::UserStatisticQuery < ApplicationQuery 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 }) + 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") @@ -94,7 +94,8 @@ class Admins::UserStatisticQuery < ApplicationQuery .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] }) + 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") @@ -105,7 +106,8 @@ class Admins::UserStatisticQuery < ApplicationQuery .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 }) + 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") end users.select("#{base_query_column}, COUNT(*) finish_challenge_count") From ab6ee862f4292aa6bdeb17f8d299cf6d17d05266 Mon Sep 17 00:00:00 2001 From: hjm <63528605@qq.com> Date: Mon, 21 Oct 2019 18:23:10 +0800 Subject: [PATCH 20/31] blur --- public/react/src/modules/page/VNCContainer.js | 5 +++++ public/react/src/modules/page/component/monaco/TPIMonaco.js | 3 +++ 2 files changed, 8 insertions(+) diff --git a/public/react/src/modules/page/VNCContainer.js b/public/react/src/modules/page/VNCContainer.js index 36943f73b..4a591f4ac 100644 --- a/public/react/src/modules/page/VNCContainer.js +++ b/public/react/src/modules/page/VNCContainer.js @@ -40,6 +40,10 @@ class VNCContainer extends Component { getSecondDrawerWidth = () => { return $('#game_right_contents').width() - firstDrawerWidth } + onEditBlur = () => { + console.log('blurblur') + this.doFileUpdateRequestOnCodeMirrorBlur() + } doFileUpdateRequestOnCodeMirrorBlur = () => { if (!this.currentPath) { console.error('未找到文件path') @@ -83,6 +87,7 @@ class VNCContainer extends Component { isEditablePath={shixun.code_edit_permission} shixun={this.props.shixun} doFileUpdateRequestOnCodeMirrorBlur={this.doFileUpdateRequestOnCodeMirrorBlur} + onEditBlur={this.onEditBlur} > diff --git a/public/react/src/modules/page/component/monaco/TPIMonaco.js b/public/react/src/modules/page/component/monaco/TPIMonaco.js index 0d5eb2d34..b814ecb44 100644 --- a/public/react/src/modules/page/component/monaco/TPIMonaco.js +++ b/public/react/src/modules/page/component/monaco/TPIMonaco.js @@ -347,6 +347,9 @@ class TPIMonaco extends Component { this.props.doFileUpdateRequestOnCodeMirrorBlur(); return false; }); + window.editor_monaco.onDidBlurEditorWidget(() => { + this.props.onEditBlur && this.props.onEditBlur(); + }) }) // window.document.onkeydown = (e) => { From beab5fecbe7eb5c298295a65b2e29cd875e3aac5 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Mon, 21 Oct 2019 21:37:31 +0800 Subject: [PATCH 21/31] =?UTF-8?q?=E7=AB=9E=E8=B5=9B=E8=B6=85=E7=AE=A1?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../javascripts/admins/competitions/index.js | 64 ++++++++++++++++++- .../javascripts/admins/enroll_lists/index.js | 9 +++ .../admins/competitions_controller.rb | 23 +++++-- .../admins/enroll_lists_controller.rb | 25 ++++++++ .../competition_teams_controller.rb | 1 + app/models/competition.rb | 4 +- app/models/competition_team.rb | 9 +++ app/models/user.rb | 5 ++ .../admins/competition_enroll_list_query.rb | 40 ++++++++++++ .../admins/competitions/enroll_list.html.erb | 0 app/views/admins/competitions/index.html.erb | 33 ++++++---- app/views/admins/competitions/index.js.erb | 1 + .../admins/competitions/online_switch.js.erb | 4 ++ app/views/admins/competitions/publish.js.erb | 4 ++ .../shared/_create_competition_modal.html.erb | 28 ++++++++ .../admins/competitions/shared/_list.html.erb | 2 +- .../admins/competitions/shared/_td.html.erb | 4 +- .../admins/competitions/unpublish.js.erb | 4 ++ app/views/admins/enroll_lists/_list.html.erb | 42 ++++++++++++ app/views/admins/enroll_lists/index.html.erb | 33 ++++++++++ app/views/admins/enroll_lists/index.js.erb | 1 + .../competition_teams/index.json.jbuilder | 1 + config/routes.rb | 10 ++- 23 files changed, 318 insertions(+), 29 deletions(-) create mode 100644 app/assets/javascripts/admins/enroll_lists/index.js create mode 100644 app/controllers/admins/enroll_lists_controller.rb create mode 100644 app/queries/admins/competition_enroll_list_query.rb delete mode 100644 app/views/admins/competitions/enroll_list.html.erb create mode 100644 app/views/admins/competitions/index.js.erb create mode 100644 app/views/admins/competitions/shared/_create_competition_modal.html.erb create mode 100644 app/views/admins/enroll_lists/_list.html.erb create mode 100644 app/views/admins/enroll_lists/index.html.erb create mode 100644 app/views/admins/enroll_lists/index.js.erb diff --git a/app/assets/javascripts/admins/competitions/index.js b/app/assets/javascripts/admins/competitions/index.js index ae4593d33..c476dbf24 100644 --- a/app/assets/javascripts/admins/competitions/index.js +++ b/app/assets/javascripts/admins/competitions/index.js @@ -5,7 +5,69 @@ $(document).on('turbolinks:load', function() { $imageElement.attr('src', data.url); $imageElement.show(); $imageElement.next().html('重新上传'); - }) + }); } + + $(".admin-competition-list-form").on("change", '.competitions-hot-select', function () { + var s_value = $(this).get(0).checked ? 1 : 0; + var json = {}; + json["hot"] = s_value; + $.ajax({ + url: "/admins/competitions/hot_setting", + type: "POST", + dataType:'json', + data: json, + success: function(){ + $.notify({ message: '操作成功' }); + } + }); + }); + + // ============== 新增竞赛 =============== + var $modal = $('.modal.admin-create-competition-modal'); + var $form = $modal.find('form.admin-create-competition-form'); + var $competitionNameInput = $form.find('input[name="competition_name"]'); + + $form.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + competition_name: { + required: true + } + } + }); + + // modal ready fire + $modal.on('show.bs.modal', function () { + $competitionNameInput.val(''); + }); + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if ($form.valid()) { + var url = $form.data('url'); + + $.ajax({ + method: 'POST', + dataType: 'json', + url: url, + data: $form.serialize(), + success: function(){ + $.notify({ message: '创建成功' }); + $modal.modal('hide'); + + setTimeout(function(){ + window.location.reload(); + }, 500); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + } + }); + } + }); }); diff --git a/app/assets/javascripts/admins/enroll_lists/index.js b/app/assets/javascripts/admins/enroll_lists/index.js new file mode 100644 index 000000000..04bd95070 --- /dev/null +++ b/app/assets/javascripts/admins/enroll_lists/index.js @@ -0,0 +1,9 @@ +$(document).on('turbolinks:load', function() { + if($('body.admins-enroll-lists-index-page').length > 0){ + let search_form = $(".search-form"); + //导出 + $(".competition-enroll-list-form").on("click","#enroll-lists-export",function () { + window.location.href = "/admins/competitions/"+$(this).attr("data-competition-id")+"/enroll_lists.xls?" + search_form.serialize(); + }); + } +}); \ No newline at end of file diff --git a/app/controllers/admins/competitions_controller.rb b/app/controllers/admins/competitions_controller.rb index f501564ab..2e2dbd4e2 100644 --- a/app/controllers/admins/competitions_controller.rb +++ b/app/controllers/admins/competitions_controller.rb @@ -18,12 +18,27 @@ class Admins::CompetitionsController < Admins::BaseController end end + def create + name = params[:competition_name].to_s.strip + Competition.create!(name: name) + render_ok + end + + def hot_setting + if params[:hot].to_i == 1 && !ModuleSetting.exists?(module_type: "Competition", property: "hot") + ModuleSetting.create!(module_type: "Competition", property: "hot") + elsif params[:hot].to_i == 0 && ModuleSetting.exists?(module_type: "Competition", property: "hot") + ModuleSetting.where(module_type: "Competition", property: "hot").destroy_all + end + render_ok + end + def publish - @competition.update_attributes!(:published_at, Time.now) + @competition.update_attributes!(published_at: Time.now) end def unpublish - @competition.update_attributes!(:published_at, nil) + @competition.update_attributes!(published_at: nil) end def online_switch @@ -34,10 +49,6 @@ class Admins::CompetitionsController < Admins::BaseController end end - def enroll_list - - end - private def find_competition diff --git a/app/controllers/admins/enroll_lists_controller.rb b/app/controllers/admins/enroll_lists_controller.rb new file mode 100644 index 000000000..ccac6a72d --- /dev/null +++ b/app/controllers/admins/enroll_lists_controller.rb @@ -0,0 +1,25 @@ +class Admins::EnrollListsController < Admins::BaseController + + def index + @competition = current_competition + params[:sort_by] = params[:sort_by].presence || 'created_at' + params[:sort_direction] = params[:sort_direction].presence || 'desc' + enroll_lists = Admins::CompetitionEnrollListQuery.call(@competition, params) + + @params_page = params[:page] || 1 + @enroll_lists = paginate enroll_lists.preload(competition_team: [:user, :teachers], user: { user_extension: :school }) + @personal = @competition.personal? + + respond_to do |format| + format.js + format.html + format.xls + end + end + + private + def current_competition + @_current_competition ||= Competition.find(params[:competition_id]) + end + +end \ No newline at end of file diff --git a/app/controllers/competitions/competition_teams_controller.rb b/app/controllers/competitions/competition_teams_controller.rb index f504b226e..6a4dbfd34 100644 --- a/app/controllers/competitions/competition_teams_controller.rb +++ b/app/controllers/competitions/competition_teams_controller.rb @@ -59,6 +59,7 @@ class Competitions::CompetitionTeamsController < Competitions::BaseController end def index + @personal = current_competition.personal? admin_or_business? ? all_competition_teams : user_competition_teams end diff --git a/app/models/competition.rb b/app/models/competition.rb index 23b1e3c81..684db8fa5 100644 --- a/app/models/competition.rb +++ b/app/models/competition.rb @@ -55,7 +55,7 @@ class Competition < ApplicationRecord # 是否为个人赛 def personal? - competition_staffs.maximum(:maximum) == 1 + competition_staffs.maximum(:maximum) == 1 || max_num == 1 end # 报名是否结束 @@ -101,7 +101,7 @@ class Competition < ApplicationRecord private def create_competition_modules - CompetitionModule.bulk_insert(*%i[competition_id name position]) do |worker| + CompetitionModule.bulk_insert(*%i[competition_id name position created_at updated_at]) do |worker| %w(首页 报名 通知公告 排行榜 资料下载).each_with_index do |name, index| worker.add(competition_id: id, name: name, position: index + 1) end diff --git a/app/models/competition_team.rb b/app/models/competition_team.rb index 878f58882..6c2b99859 100644 --- a/app/models/competition_team.rb +++ b/app/models/competition_team.rb @@ -32,6 +32,15 @@ class CompetitionTeam < ApplicationRecord code end + def teachers_info + info = "" + teachers.each do |teacher| + teacher_info = "#{teacher.user.real_name}/#{teacher.user.school_name}" + info += info == "" ? teacher_info : "、#{teacher_info}" + end + info + end + def teachers_name teachers.map{|teacher| teacher.user.real_name}.join(",") end diff --git a/app/models/user.rb b/app/models/user.rb index 103f9e0b5..135b85e25 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -237,6 +237,11 @@ class User < ApplicationRecord professional_certification end + # 学校所在的地区 + def school_province + user_extension&.school&.province || '' + end + # 用户的学校名称 def school_name user_extension&.school&.name || '' diff --git a/app/queries/admins/competition_enroll_list_query.rb b/app/queries/admins/competition_enroll_list_query.rb new file mode 100644 index 000000000..64f5dc7f8 --- /dev/null +++ b/app/queries/admins/competition_enroll_list_query.rb @@ -0,0 +1,40 @@ +class Admins::CompetitionEnrollListQuery < ApplicationQuery + include CustomSortable + + attr_reader :competition, :params + + sort_columns :created_at, :competition_team_id, default_by: :created_at, default_direction: :desc + + def initialize(competition, params) + @competition = competition + @params = params + end + + def call + members = competition.team_members + only_teacher = competition.competition_staffs.count == 1 && competition.competition_staffs.first.category == 'teacher' + members = members.where("team_members.is_teacher = 0") unless only_teacher # 只有老师报名时才显示老师,此时老师作为队员 + + + school = params[:school].to_s.strip + if school.present? + school_ids = School.where("schools.name like ?", "%#{school}%").pluck(:id) + school_ids = school_ids.size == 0 ? "(-1)" : "(" + school_ids.join(",") + ")" + members = members.joins(user: :user_extension).where("user_extensions.school_id in #{school_ids}") + end + + location = params[:location].to_s.strip + if location.present? + members = members.joins(user: { user_extension: :school }).where("schools.province like ?", "%#{location}%") + end + + # 关键字模糊查询 + keyword = params[:keyword].to_s.strip + if keyword.present? + members = members.joins(:competition_team) + .where('competition_teams.name LIKE :keyword', keyword: "%#{keyword}%") + end + + custom_sort(members, params[:sort_by], params[:sort_direction]) + end +end \ No newline at end of file diff --git a/app/views/admins/competitions/enroll_list.html.erb b/app/views/admins/competitions/enroll_list.html.erb deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/views/admins/competitions/index.html.erb b/app/views/admins/competitions/index.html.erb index 736f0514e..41e061fc1 100644 --- a/app/views/admins/competitions/index.html.erb +++ b/app/views/admins/competitions/index.html.erb @@ -2,22 +2,26 @@ <% add_admin_breadcrumb('竞赛列表', admins_competitions_path) %> <% end %> -
    -
    -
    - <% imageExists = File.exist?(disk_filename("Competition", "banner")) %> - <% imageUrl = imageExists ? '/' + banner_img("Competition") + "?#{Time.now.to_i}" : '' %> - 竞赛主页banner - <%= image_tag(imageUrl, width: 150, height: 50, class: "preview-image competition-image-banner mr-1", data: { toggle: 'tooltip', title: '点击预览' }) %> - <%= javascript_void_link imageExists ? '重新上传' : '上传图片', class: 'action upload-competition-image-action', data: { source_id: "banner", source_type: 'Competition', toggle: 'modal', target: '.admin-upload-file-modal' } %> -
    +
    +
    +
    +
    + <% imageExists = File.exist?(disk_filename("Competition", "banner")) %> + <% imageUrl = imageExists ? '/' + banner_img("Competition") + "?#{Time.now.to_i}" : '' %> + 竞赛主页banner + <%= image_tag(imageUrl, width: 150, height: 50, class: "preview-image competition-image-banner mr-1", data: { toggle: 'tooltip', title: '点击预览' }) %> + <%= javascript_void_link imageExists ? '重新上传' : '上传图片', class: 'action upload-competition-image-action', data: { source_id: "banner", source_type: 'Competition', toggle: 'modal', target: '.admin-upload-file-modal' } %> +
    -
    - +
    + +
    + + <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-competition-modal' } %>
    @@ -25,4 +29,5 @@ <%= render partial: 'admins/competitions/shared/list', locals: { competitions: @competitions } %>
    +<%= render 'admins/competitions/shared/create_competition_modal' %> <%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片' } %> \ No newline at end of file diff --git a/app/views/admins/competitions/index.js.erb b/app/views/admins/competitions/index.js.erb new file mode 100644 index 000000000..e0985ce5e --- /dev/null +++ b/app/views/admins/competitions/index.js.erb @@ -0,0 +1 @@ +$('.competitions-list-container').html("<%= j( render partial: 'admins/competitions/shared/list', locals: { competitions: @competitions } ) %>"); \ No newline at end of file diff --git a/app/views/admins/competitions/online_switch.js.erb b/app/views/admins/competitions/online_switch.js.erb index e69de29bb..f67122e46 100644 --- a/app/views/admins/competitions/online_switch.js.erb +++ b/app/views/admins/competitions/online_switch.js.erb @@ -0,0 +1,4 @@ +var page_no = $("#competition-item-<%= @competition.id %>").children(":first").html(); +$("#competition-item-<%= @competition.id %>").html("<%= j render partial: "admins/competitions/shared/td", locals: {competition: @competition, page_no: 1} %>"); +$("#competition-item-<%= @competition.id %>").children(":first").html(page_no); +show_success_flash(); \ No newline at end of file diff --git a/app/views/admins/competitions/publish.js.erb b/app/views/admins/competitions/publish.js.erb index e69de29bb..f67122e46 100644 --- a/app/views/admins/competitions/publish.js.erb +++ b/app/views/admins/competitions/publish.js.erb @@ -0,0 +1,4 @@ +var page_no = $("#competition-item-<%= @competition.id %>").children(":first").html(); +$("#competition-item-<%= @competition.id %>").html("<%= j render partial: "admins/competitions/shared/td", locals: {competition: @competition, page_no: 1} %>"); +$("#competition-item-<%= @competition.id %>").children(":first").html(page_no); +show_success_flash(); \ No newline at end of file diff --git a/app/views/admins/competitions/shared/_create_competition_modal.html.erb b/app/views/admins/competitions/shared/_create_competition_modal.html.erb new file mode 100644 index 000000000..94d12ba32 --- /dev/null +++ b/app/views/admins/competitions/shared/_create_competition_modal.html.erb @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/app/views/admins/competitions/shared/_list.html.erb b/app/views/admins/competitions/shared/_list.html.erb index 8f215d54c..6e9620a39 100644 --- a/app/views/admins/competitions/shared/_list.html.erb +++ b/app/views/admins/competitions/shared/_list.html.erb @@ -18,7 +18,7 @@ <% competitions.each_with_index do |competition, index| %>
    <%= page_no %> - <%= link_to competition.name, enroll_list_admins_competition_path(competition), :target => "_blank", :title => competition.name %> + <%= link_to competition.name, admins_competition_enroll_lists_path(competition), :title => competition.name %> <%= competition.sub_title %> <%= competition.mode_type %> <%= competition.created_at.strftime('%Y-%m-%d %H:%M') %> - <%= link_to '配置', admins_competition_competition_setting_path(competition), class: 'action edit-action' %> + <%= link_to '配置', admins_competition_competition_settings_path(competition), class: 'action edit-action' %> <% if !competition.status? && competition.published_at.blank? %> <%= link_to '发布', publish_admins_competition_path(competition), class: 'action publish-action', method: :post, remote: true %> diff --git a/app/views/admins/competitions/unpublish.js.erb b/app/views/admins/competitions/unpublish.js.erb index e69de29bb..f67122e46 100644 --- a/app/views/admins/competitions/unpublish.js.erb +++ b/app/views/admins/competitions/unpublish.js.erb @@ -0,0 +1,4 @@ +var page_no = $("#competition-item-<%= @competition.id %>").children(":first").html(); +$("#competition-item-<%= @competition.id %>").html("<%= j render partial: "admins/competitions/shared/td", locals: {competition: @competition, page_no: 1} %>"); +$("#competition-item-<%= @competition.id %>").children(":first").html(page_no); +show_success_flash(); \ No newline at end of file diff --git a/app/views/admins/enroll_lists/_list.html.erb b/app/views/admins/enroll_lists/_list.html.erb new file mode 100644 index 000000000..2b86a3507 --- /dev/null +++ b/app/views/admins/enroll_lists/_list.html.erb @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + <% if enroll_lists.present? %> + <% enroll_lists.each_with_index do |member, index| %> + + <% team = member.competition_team %> + <% page_no = list_index_no(@params_page.to_i, index) %> + + + + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
    序号<%= sort_tag('战队ID', name: 'competition_team_id', path: admins_competition_enroll_lists_path(@competition)) %>战队名称创建者队员姓名职业学号队员学校地区指导老师<%= sort_tag('报名时间', name: 'created_at', path: admins_competition_enroll_lists_path(@competition)) %>
    <%= page_no %><%= member.competition_team_id %><%= @personal ? "--" : team.name %><%= team.user.real_name %><%= member.user.real_name %><%= member.user.identity %><%= member.user.student_id %><%= member.user.school_name %><%= member.user.school_province %><%= @personal ? "--" : team.teachers_info %><%= member.created_at.strftime('%Y-%m-%d %H:%M') %>
    + +<%= render partial: 'admins/shared/paginate', locals: { objects: enroll_lists } %> \ No newline at end of file diff --git a/app/views/admins/enroll_lists/index.html.erb b/app/views/admins/enroll_lists/index.html.erb new file mode 100644 index 000000000..95787d54c --- /dev/null +++ b/app/views/admins/enroll_lists/index.html.erb @@ -0,0 +1,33 @@ +<% + define_admin_breadcrumbs do + add_admin_breadcrumb('竞赛列表', admins_competitions_path) + add_admin_breadcrumb(@competition.name) + end +%> + +
    + + +
    + <%= form_tag(admins_competition_enroll_lists_path(unsafe_params), method: :get, class: 'form-inline search-form mt-3 flex-1 d-flex', remote: true) do %> + <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '战队名称检索') %> + <%= text_field_tag(:school, params[:school], class: 'form-control col-sm-2 ml-3', placeholder: '队员学校名称检索') %> + <%= text_field_tag(:location, params[:location], class: 'form-control col-sm-2 ml-3', placeholder: '队员地区检索') %> + <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> + <%= link_to "清除", admins_competition_enroll_lists_path(@competition), class: "btn btn-default",'data-disable-with': '清除中...' %> + <% end %> + + 导出 +
    +
    + +
    + <%= render(partial: 'admins/enroll_lists/list', locals: { enroll_lists: @enroll_lists }) %> +
    \ No newline at end of file diff --git a/app/views/admins/enroll_lists/index.js.erb b/app/views/admins/enroll_lists/index.js.erb new file mode 100644 index 000000000..18edd97f2 --- /dev/null +++ b/app/views/admins/enroll_lists/index.js.erb @@ -0,0 +1 @@ +$('.competition-enroll-list-container').html("<%= j( render(partial: 'admins/enroll_lists/list', locals: { enroll_lists: @enroll_lists }) ) %>"); \ No newline at end of file diff --git a/app/views/competitions/competition_teams/index.json.jbuilder b/app/views/competitions/competition_teams/index.json.jbuilder index b641b28e6..d44fcdf1c 100644 --- a/app/views/competitions/competition_teams/index.json.jbuilder +++ b/app/views/competitions/competition_teams/index.json.jbuilder @@ -1,4 +1,5 @@ json.count @count +json.personal @personal json.competition_teams do json.array! @teams.each do |team| json.extract! team, :id, :name, :invite_code diff --git a/config/routes.rb b/config/routes.rb index e7fb7ee04..7b7a2bc6e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1006,14 +1006,18 @@ Rails.application.routes.draw do end end - resources :competitions, only: [:index, :destroy] do + resources :competitions, only: [:index, :destroy, :create] do member do post :publish post :unpublish post :online_switch - get :enroll_list end - resource :competition_setting, only: [:show, :update] + collection do + post :hot_setting + end + + resources :competition_settings, only: [:index, :update] + resources :enroll_lists, only: [:index] end end From d3b63963a86b8e10b1b28054979e9c3cbbeb0d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Mon, 21 Oct 2019 22:08:45 +0800 Subject: [PATCH 22/31] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=97=AE=E5=8D=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/AppConfig.js | 3 ++- .../react/src/modules/courses/poll/PollDetailTabSecond.js | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 9cf68503d..793542f4b 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -47,7 +47,8 @@ export function initAxiosInterceptors(props) { proxy="https://pre-newweb.educoder.net" proxy="https://test-newweb.educoder.net" - // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; + + // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; // 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制 const requestMap = {}; diff --git a/public/react/src/modules/courses/poll/PollDetailTabSecond.js b/public/react/src/modules/courses/poll/PollDetailTabSecond.js index cebae4153..823cacaed 100644 --- a/public/react/src/modules/courses/poll/PollDetailTabSecond.js +++ b/public/react/src/modules/courses/poll/PollDetailTabSecond.js @@ -55,7 +55,7 @@ class PollDetailTabSecond extends Component{ } render(){ - let{page,limit,questions,question_types}=this.state; + let {page, limit, questions, questionsInfo} = this.state; return(
    { @@ -160,9 +160,10 @@ class PollDetailTabSecond extends Component{ }): } { - question_types && question_types.q_counts>limit && + questionsInfo && questionsInfo.q_counts > limit &&
    - +
    } From 44d7f47d76b9767557bf9fbb1529dce6d791be0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Mon, 21 Oct 2019 22:18:03 +0800 Subject: [PATCH 23/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/courses/poll/PollDetailTabSecond.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/react/src/modules/courses/poll/PollDetailTabSecond.js b/public/react/src/modules/courses/poll/PollDetailTabSecond.js index 823cacaed..bf8d8b5f8 100644 --- a/public/react/src/modules/courses/poll/PollDetailTabSecond.js +++ b/public/react/src/modules/courses/poll/PollDetailTabSecond.js @@ -25,6 +25,7 @@ class PollDetailTabSecond extends Component{ axios.get(url).then((result)=>{ if(result){ this.setState({ + page: page, questions:result.data.questions, questionsInfo:result.data.question_types }) From 9767091ba43aef4f5c67a6a944364a8531823e92 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Mon, 21 Oct 2019 22:40:47 +0800 Subject: [PATCH 24/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/exercises_controller.rb | 2 +- app/helpers/exercises_helper.rb | 2 +- app/tasks/exercise_publish_task.rb | 2 +- ...141738_migrate_exercise_challenge_score.rb | 25 +++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20191021141738_migrate_exercise_challenge_score.rb diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index d71b72618..99356946f 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -1129,7 +1129,7 @@ class ExercisesController < ApplicationController :subjective_score => subjective_score, :commit_method => @answer_committed_user&.commit_method.to_i > 0 ? @answer_committed_user&.commit_method.to_i : params[:commit_method].to_i } - @answer_committed_user.update_attributes(commit_option) + @answer_committed_user.update_attributes!(commit_option) CommitExercsieNotifyJobJob.perform_later(@exercise.id, current_user.id) normal_status(0,"试卷提交成功!") else diff --git a/app/helpers/exercises_helper.rb b/app/helpers/exercises_helper.rb index 395d67913..eadbfa05c 100644 --- a/app/helpers/exercises_helper.rb +++ b/app/helpers/exercises_helper.rb @@ -414,7 +414,7 @@ module ExercisesHelper score2 = 0.0 #填空题 score5 = 0.0 #实训题 ques_stand = [] #问题是否正确 - exercise_questions = exercise.exercise_questions.includes(:exercise_answers,:exercise_shixun_answers,:exercise_standard_answers,:exercise_shixun_challenges) + exercise_questions = exercise.exercise_questions.includes(:exercise_standard_answers,:exercise_shixun_challenges) exercise_questions&.each do |q| begin if q.question_type != 5 diff --git a/app/tasks/exercise_publish_task.rb b/app/tasks/exercise_publish_task.rb index a7b533d05..4e34320ea 100644 --- a/app/tasks/exercise_publish_task.rb +++ b/app/tasks/exercise_publish_task.rb @@ -69,7 +69,7 @@ class ExercisePublishTask :subjective_score => subjective_score, :commit_method => exercise_user&.commit_method.to_i > 0 ? exercise_user&.commit_method.to_i : 3 } - exercise_user.update_attributes(commit_option) + exercise_user.update_attributes!(commit_option) end rescue Exception => e Rails.logger.info("rescue errors ___________________________#{e}") diff --git a/db/migrate/20191021141738_migrate_exercise_challenge_score.rb b/db/migrate/20191021141738_migrate_exercise_challenge_score.rb new file mode 100644 index 000000000..6d67398db --- /dev/null +++ b/db/migrate/20191021141738_migrate_exercise_challenge_score.rb @@ -0,0 +1,25 @@ +class MigrateExerciseChallengeScore < ActiveRecord::Migration[5.2] + include ExercisesHelper + def change + exercise = Exercise.find_by(id: 2734) + if exercise + exercise.exercise_users.where("start_at is not null").each do |exercise_user| + if exercise_user.end_at.nil? + calculate_score = calculate_student_score(exercise, exercise_user.user)[:total_score] + subjective_score = exercise_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = calculate_score + total_score_subjective_score + exercise_user.update_attributes!(score:total_score,objective_score:calculate_score,end_at:exercise.end_time,commit_status:1,status:1,commit_method:3) + puts exercise_user.id + else + calculate_score = ExerciseShixunAnswer.where(user_id: exercise_user.user_id, exercise_question_id: exercise.exercise_questions.pluck(:id)).pluck(:score).sum + subjective_score = exercise_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = calculate_score + total_score_subjective_score + exercise_user.update_attributes!(score:total_score,objective_score:calculate_score) if total_score > exercise_user.score + puts exercise_user.id + end + end + end + end +end From 8cc4770c51b4f5fa5369b9f7de387f50ee89cd9d Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Mon, 21 Oct 2019 23:33:15 +0800 Subject: [PATCH 25/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...021150220_migrate_exercise_answer_score.rb | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 db/migrate/20191021150220_migrate_exercise_answer_score.rb diff --git a/db/migrate/20191021150220_migrate_exercise_answer_score.rb b/db/migrate/20191021150220_migrate_exercise_answer_score.rb new file mode 100644 index 000000000..22bfb8455 --- /dev/null +++ b/db/migrate/20191021150220_migrate_exercise_answer_score.rb @@ -0,0 +1,73 @@ +class MigrateExerciseAnswerScore < ActiveRecord::Migration[5.2] + def calculate_student_score(exercise,user) + score5 = 0.0 #实训题 + exercise_questions = exercise.exercise_questions.includes(:exercise_standard_answers,:exercise_shixun_challenges) + exercise_questions.each do |q| + if q.question_type == 5 + q.exercise_shixun_challenges.each do |exercise_cha| + game = Game.user_games(user.id,exercise_cha.challenge_id)&.first #当前用户的关卡 + if game.present? + exercise_cha_score = 0.0 + answer_status = 0 + # if game.status == 2 && game.final_score >= 0 + if game.final_score > 0 && game.end_time < exercise.end_time + exercise_cha_score = game.real_score(exercise_cha.question_score) + # exercise_cha_score = exercise_cha.question_score #每一关卡的得分 + answer_status = 1 + end + ex_shixun_answer_content = exercise_cha.exercise_shixun_answers.where(user_id:user.id,exercise_question_id:q.id) + code = nil + if exercise_cha.challenge&.path.present? + cha_path = challenge_path(exercise_cha.challenge&.path) + game_challenge = game.game_codes.search_challenge_path(cha_path)&.first + if game_challenge.present? + game_code = game_challenge + code = game_code.try(:new_code) + else + begin + code = git_fle_content(game.myshixun.repo_path,cha_path) + rescue + code = "" + end + end + end + if ex_shixun_answer_content.blank? #把关卡的答案存入试卷的实训里 + ### Todo 实训题的_shixun_details里的代码是不是直接从这里取出就可以了?涉及到code的多个版本库的修改 + sx_option = { + :exercise_question_id => q.id, + :exercise_shixun_challenge_id => exercise_cha.id, + :user_id => user.id, + :score => exercise_cha_score.round(1), + :answer_text => code, + :status => answer_status + } + ExerciseShixunAnswer.create!(sx_option) + else + ex_shixun_answer_content.first.update_attributes!(score:exercise_cha_score.round(1),answer_text:code,answer_status:answer_status) + end + score5 += exercise_cha_score + else + score5 += 0.0 + end + end + end + end + score5 + end + + def change + user_ids = [111887, 111892, 111883, 111880] + exercise = Exercise.find_by(id: 2734) + if exercise + exercise_users = exercise.exercise_users.where(user_id: user_ids) + exercise_users.each do |exercise_user| + calculate_score = calculate_student_score(exercise, exercise_user.user) + subjective_score = exercise_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = calculate_score + total_score_subjective_score + exercise_user.update_attributes!(score:total_score,objective_score:calculate_score) + puts exercise_user.id + end + end + end +end From 2bf952388bd845af9dbea0bb9086b1bab6128691 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Mon, 21 Oct 2019 23:36:15 +0800 Subject: [PATCH 26/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...021150220_migrate_exercise_answer_score.rb | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/db/migrate/20191021150220_migrate_exercise_answer_score.rb b/db/migrate/20191021150220_migrate_exercise_answer_score.rb index 22bfb8455..73b162cf0 100644 --- a/db/migrate/20191021150220_migrate_exercise_answer_score.rb +++ b/db/migrate/20191021150220_migrate_exercise_answer_score.rb @@ -1,4 +1,41 @@ class MigrateExerciseAnswerScore < ActiveRecord::Migration[5.2] + def challenge_path(path) + cha_path = path.present? ? path.split(";") : [] + cha_path.reject(&:blank?)[0].try(:strip) + end + + # 版本库文件内容,带转码 + def git_fle_content(repo_path, path) + begin + Rails.logger.info("git file content: repo_path is #{repo_path}, path is #{path}") + + content = GitService.file_content(repo_path: repo_path, path: path) + + Rails.logger.info("git file content: content is #{content}") + decode_content = nil + if content.present? + content = content["content"] #6.24 -hs 这个为新增,因为当实训题里含有选择题时,这里会报错,undefined method `[]' for nil:NilClass + + content = Base64.decode64(content) + cd = CharDet.detect(content) + Rails.logger.info "encoding: #{cd['encoding']} confidence: #{cd['confidence']}" + # 字符编码问题,GB18030编码识别率不行 + decode_content = + if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8 + content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '}) + else + content.force_encoding('UTF-8') + end + end + + decode_content + + rescue Exception => e + Rails.logger.error(e.message) + raise Educoder::TipException.new("文档内容获取异常") + end + end + def calculate_student_score(exercise,user) score5 = 0.0 #实训题 exercise_questions = exercise.exercise_questions.includes(:exercise_standard_answers,:exercise_shixun_challenges) From c6987f906274b6fce8fec89f6f9282466ff6361c Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Mon, 21 Oct 2019 23:37:30 +0800 Subject: [PATCH 27/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/migrate/20191021150220_migrate_exercise_answer_score.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20191021150220_migrate_exercise_answer_score.rb b/db/migrate/20191021150220_migrate_exercise_answer_score.rb index 73b162cf0..aa209bc4a 100644 --- a/db/migrate/20191021150220_migrate_exercise_answer_score.rb +++ b/db/migrate/20191021150220_migrate_exercise_answer_score.rb @@ -80,7 +80,7 @@ class MigrateExerciseAnswerScore < ActiveRecord::Migration[5.2] } ExerciseShixunAnswer.create!(sx_option) else - ex_shixun_answer_content.first.update_attributes!(score:exercise_cha_score.round(1),answer_text:code,answer_status:answer_status) + ex_shixun_answer_content.first.update_attributes!(score:exercise_cha_score.round(1),answer_text:code,status:answer_status) end score5 += exercise_cha_score else From 8125760e23c3011e4690b33fc6bd1938fb00e3c0 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Mon, 21 Oct 2019 23:42:24 +0800 Subject: [PATCH 28/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4016_migrate_2734_exercise_answer_score.rb | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 db/migrate/20191021154016_migrate_2734_exercise_answer_score.rb diff --git a/db/migrate/20191021154016_migrate_2734_exercise_answer_score.rb b/db/migrate/20191021154016_migrate_2734_exercise_answer_score.rb new file mode 100644 index 000000000..344233dd1 --- /dev/null +++ b/db/migrate/20191021154016_migrate_2734_exercise_answer_score.rb @@ -0,0 +1,113 @@ +class Migrate2734ExerciseAnswerScore < ActiveRecord::Migration[5.2] + def challenge_path(path) + cha_path = path.present? ? path.split(";") : [] + cha_path.reject(&:blank?)[0].try(:strip) + end + + # 版本库文件内容,带转码 + def git_fle_content(repo_path, path) + begin + Rails.logger.info("git file content: repo_path is #{repo_path}, path is #{path}") + + content = GitService.file_content(repo_path: repo_path, path: path) + + Rails.logger.info("git file content: content is #{content}") + decode_content = nil + if content.present? + content = content["content"] #6.24 -hs 这个为新增,因为当实训题里含有选择题时,这里会报错,undefined method `[]' for nil:NilClass + + content = Base64.decode64(content) + cd = CharDet.detect(content) + Rails.logger.info "encoding: #{cd['encoding']} confidence: #{cd['confidence']}" + # 字符编码问题,GB18030编码识别率不行 + decode_content = + if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8 + content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '}) + else + content.force_encoding('UTF-8') + end + end + + decode_content + + rescue Exception => e + Rails.logger.error(e.message) + raise Educoder::TipException.new("文档内容获取异常") + end + end + + def calculate_student_score(exercise,user) + score5 = 0.0 #实训题 + exercise_questions = exercise.exercise_questions.includes(:exercise_standard_answers,:exercise_shixun_challenges) + exercise_questions.each do |q| + if q.question_type == 5 + q.exercise_shixun_challenges.each do |exercise_cha| + game = Game.user_games(user.id,exercise_cha.challenge_id)&.first #当前用户的关卡 + if game.present? + exercise_cha_score = 0.0 + answer_status = 0 + # if game.status == 2 && game.final_score >= 0 + if game.final_score > 0 && game.end_time < exercise.end_time + exercise_cha_score = game.real_score(exercise_cha.question_score) + # exercise_cha_score = exercise_cha.question_score #每一关卡的得分 + answer_status = 1 + end + ex_shixun_answer_content = exercise_cha.exercise_shixun_answers.where(user_id:user.id,exercise_question_id:q.id) + code = nil + if exercise_cha.challenge&.path.present? + cha_path = challenge_path(exercise_cha.challenge&.path) + game_challenge = game.game_codes.search_challenge_path(cha_path)&.first + if game_challenge.present? + game_code = game_challenge + code = game_code.try(:new_code) + else + begin + code = git_fle_content(game.myshixun.repo_path,cha_path) + rescue + code = "" + end + end + end + if ex_shixun_answer_content.blank? #把关卡的答案存入试卷的实训里 + ### Todo 实训题的_shixun_details里的代码是不是直接从这里取出就可以了?涉及到code的多个版本库的修改 + sx_option = { + :exercise_question_id => q.id, + :exercise_shixun_challenge_id => exercise_cha.id, + :user_id => user.id, + :score => exercise_cha_score.round(1), + :answer_text => code, + :status => answer_status + } + ExerciseShixunAnswer.create!(sx_option) + else + ex_shixun_answer_content.first.update_attributes!(score:exercise_cha_score.round(1),answer_text:code,status:answer_status) + end + score5 += exercise_cha_score + else + score5 += 0.0 + end + end + end + end + score5 + end + + def change + exercise = Exercise.find_by(id: 2734) + if exercise + exercise_users = exercise.exercise_users.where("start_at is not null") + exercise_users.each do |exercise_user| + calculate_score = calculate_student_score(exercise, exercise_user.user) + subjective_score = exercise_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = calculate_score + total_score_subjective_score + if exercise_user.end_at.nil? + exercise_user.update_attributes!(score:total_score,objective_score:calculate_score,end_at:exercise.end_time,commit_status:1,status:1,commit_method:3) + else + exercise_user.update_attributes!(score:total_score,objective_score:calculate_score) + end + puts exercise_user.id + end + end + end +end From fc1972efa00b857a6a490b366ed2db9057bfe10b Mon Sep 17 00:00:00 2001 From: hjm <63528605@qq.com> Date: Tue, 22 Oct 2019 09:12:05 +0800 Subject: [PATCH 29/31] =?UTF-8?q?=E5=8E=BB=E6=8E=89title?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react/src/modules/courses/members/CourseGroupListTable.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/react/src/modules/courses/members/CourseGroupListTable.js b/public/react/src/modules/courses/members/CourseGroupListTable.js index 656ae67bc..88d0598b1 100644 --- a/public/react/src/modules/courses/members/CourseGroupListTable.js +++ b/public/react/src/modules/courses/members/CourseGroupListTable.js @@ -92,8 +92,9 @@ function CourseGroupListTable(props) { width:"27%", className:"color-grey-6", render: (member_manager, record, index) => { + // 加title 文本太长会出现卡死 https://www.trustie.net/issues/24950 + // title={record.subStringOfMember_manager ? member_manager : ''} return {record.subStringOfMember_manager || member_manager} } }) From 8f3c907b31f1e5d22ccabe2e064dff8da8d94467 Mon Sep 17 00:00:00 2001 From: cxt <853663049@qq.com> Date: Tue, 22 Oct 2019 09:13:15 +0800 Subject: [PATCH 30/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/competition.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/competition.rb b/app/models/competition.rb index 684db8fa5..8b9d59ed2 100644 --- a/app/models/competition.rb +++ b/app/models/competition.rb @@ -80,12 +80,12 @@ class Competition < ApplicationRecord # 老师是否能多次报名 def teacher_multiple_limited? - teacher_staff.mutiple_limited? + teacher_staff&.mutiple_limited? end # 队员是否能多次报名 def member_multiple_limited? - member_staff.mutiple_limited? + member_staff&.mutiple_limited? end def max_min_stage_time From f3d9a89ff5f0b9ebdd87ba0623d8141ed8b92e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Tue, 22 Oct 2019 09:36:18 +0800 Subject: [PATCH 31/31] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/courses/css/members.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/react/src/modules/courses/css/members.css b/public/react/src/modules/courses/css/members.css index ab7effaa0..22e83a93e 100644 --- a/public/react/src/modules/courses/css/members.css +++ b/public/react/src/modules/courses/css/members.css @@ -1,6 +1,6 @@ .studentList_operation_ul{ color: #999; - font-size: 12px; + font-size: 14px; float: right; margin-top: 2px; }