From 7498740e87527587e5d752760fb784afb526f566 Mon Sep 17 00:00:00 2001
From: cxt <853663049@qq.com>
Date: Wed, 16 Oct 2019 18:35:01 +0800
Subject: [PATCH 01/33] =?UTF-8?q?=E7=AB=9E=E8=B5=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../competitions/competitions_controller.rb | 14 ++++---
.../competitions/common_header.json.jbuilder | 12 ++++++
.../competitions/index.json.jbuilder | 26 ++++++-------
.../competitions/show.json.jbuilder | 38 +------------------
config/routes.rb | 2 +-
5 files changed, 37 insertions(+), 55 deletions(-)
create mode 100644 app/views/competitions/competitions/common_header.json.jbuilder
diff --git a/app/controllers/competitions/competitions_controller.rb b/app/controllers/competitions/competitions_controller.rb
index 77159fdaf..30df949f6 100644
--- a/app/controllers/competitions/competitions_controller.rb
+++ b/app/controllers/competitions/competitions_controller.rb
@@ -1,6 +1,7 @@
class Competitions::CompetitionsController < Competitions::BaseController
skip_before_action :require_login
before_action :allow_visit, except: [:index]
+ before_action :require_admin, only: [:update]
def index
# 已上架 或者 即将上架
@@ -25,10 +26,16 @@ class Competitions::CompetitionsController < Competitions::BaseController
end
def show
+ @competition = current_competition
end
- def common_header
+ def update
+ @competition.update_attributes!(introduction: params[:introduction])
+ normal_status("更新成功")
+ end
+ def common_header
+ @competition = current_competition
end
private
@@ -38,9 +45,6 @@ class Competitions::CompetitionsController < Competitions::BaseController
end
def allow_visit
- unless current_competition.published? || admin_or_business?
- render_forbidden
- return
- end
+ render_forbidden unless current_competition.published? || admin_or_business?
end
end
\ No newline at end of file
diff --git a/app/views/competitions/competitions/common_header.json.jbuilder b/app/views/competitions/competitions/common_header.json.jbuilder
new file mode 100644
index 000000000..f172dae86
--- /dev/null
+++ b/app/views/competitions/competitions/common_header.json.jbuilder
@@ -0,0 +1,12 @@
+json.extract! @competition, :id, :name, :sub_title, :identifier, :bonus, :mode
+json.visits_count @competition.visits
+member_count = @competition.team_members.count
+json.member_count member_count.zero? ? 268 : member_count
+
+json.start_time @competition.start_time&.strftime("%Y-%m-%d")
+json.end_time @competition.end_time&.strftime("%Y-%m-%d")
+json.enroll_end_time @competition.enroll_end_time&.strftime("%Y-%m-%d %H:%M:%S")
+
+json.published @competition.published?
+json.nearly_published @competition.published_at.present?
+
diff --git a/app/views/competitions/competitions/index.json.jbuilder b/app/views/competitions/competitions/index.json.jbuilder
index 4b8390a7d..8e99d754d 100644
--- a/app/views/competitions/competitions/index.json.jbuilder
+++ b/app/views/competitions/competitions/index.json.jbuilder
@@ -1,7 +1,7 @@
json.count @count
json.competitions do
json.array! @competitions.each do |competition|
- json.extract! competition, :id, :identifier, :name, :sub_title, :bonus, :description
+ json.extract! competition, :id, :identifier, :name, :sub_title, :bonus, :description, :mode
json.visits_count competition.visits
member_count = @member_count_map&.fetch(competition.id, 0) || competition.team_members.count
@@ -12,18 +12,18 @@ json.competitions do
json.nearly_published competition.published_at.present?
json.single_stage (@stage_count_map&.fetch(competition.id, 0) || competition.competition_stages.count) == 1
- json.start_time competition.display_start_time
- json.end_time competition.display_end_time
- json.enroll_end_time competition.display_enroll_end_time
+ json.start_time competition.start_time&.strftime("%Y-%m-%d")
+ json.end_time competition.end_time&.strftime("%Y-%m-%d")
+ json.enroll_end_time competition.enroll_end_time&.strftime("%Y-%m-%d %H:%M:%S")
- section = competition.current_stage_section
- if section
- json.current_stage do
-
- json.name section.competition_stage.name
- json.start_time section.display_start_time
- json.end_time section.display_end_time
- end
- end
+ # section = competition.current_stage_section
+ # if section
+ # json.current_stage do
+ #
+ # json.name section.competition_stage.name
+ # json.start_time section.display_start_time
+ # json.end_time section.display_end_time
+ # end
+ # end
end
end
\ No newline at end of file
diff --git a/app/views/competitions/competitions/show.json.jbuilder b/app/views/competitions/competitions/show.json.jbuilder
index 18216ee92..f96949398 100644
--- a/app/views/competitions/competitions/show.json.jbuilder
+++ b/app/views/competitions/competitions/show.json.jbuilder
@@ -1,36 +1,2 @@
-competition = current_competition
-json.extract! competition, :id, :name, :sub_title, :identifier
-
-json.start_time competition.display_start_time
-json.end_time competition.display_end_time
-json.enroll_end_time competition.display_enroll_end_time
-
-json.images do
- json.array! competition.attachments, partial: 'attachments/attachment_simple', as: :attachment
-end
-
-json.competition_stages do
- stages = competition.competition_stages.includes(competition_stage_sections: :competition_entries)
- json.array! stages.each do |stage|
- json.extract! stage, :id, :name
-
- json.sections do
- json.array! stage.competition_stage_sections.each do |section|
- json.extract! section, :id, :name
-
- decorator_section = ActiveDecorator::Decorator.instance.decorate(section)
- json.start_time decorator_section.display_start_time
- json.end_time decorator_section.display_end_time
-
- is_start = section.start_time > Time.now
- json.entries do
- json.array! section.competition_entries.each do |entry|
- json.extract! entry, :id, :name
-
- json.url is_start ? entry.url : ''
- end
- end
- end
- end
- end
-end
\ No newline at end of file
+json.extract! @competition, :id, :introduction
+json.image_url url_to_avatar(@competition)
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index a2e7337b1..f9efaf794 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -781,7 +781,7 @@ Rails.application.routes.draw do
resources :repertoires, only: [:index]
scope module: :competitions do
- resources :competitions, only: [:index, :show] do
+ resources :competitions, only: [:index, :show, :update] do
resources :competition_modules, only: [:index, :show, :update]
resource :competition_staff
resources :competition_teams, only: [:index, :show] do
From a1796ee2c4010f8ef025ba337f6bbf07ea3c6e32 Mon Sep 17 00:00:00 2001
From: cxt <853663049@qq.com>
Date: Sat, 19 Oct 2019 10:45:55 +0800
Subject: [PATCH 02/33] =?UTF-8?q?=E7=AB=9E=E8=B5=9BAPI?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../competition_teams_controller.rb | 92 +++++++++++
.../competitions/competitions_controller.rb | 151 +++++++++++++++++-
app/helpers/competitions_helper.rb | 54 +++++++
app/models/chart_rule.rb | 6 +
app/models/competition.rb | 19 ++-
app/models/competition_award.rb | 3 +
app/models/competition_mode_setting.rb | 3 +-
app/models/competition_module.rb | 17 ++
app/models/competition_score.rb | 6 +
app/models/competition_stage.rb | 10 ++
app/models/competition_team.rb | 9 ++
app/models/inform.rb | 2 +
app/models/shixun.rb | 1 +
.../course_detail.json.jbuilder | 28 ++++
.../shixun_detail.json.jbuilder | 41 +++++
.../competitions/chart_list.xlsx.axlsx | 18 +++
.../competitions/chart_rules.json.jbuilder | 5 +
.../competitions/charts.json.jbuilder | 21 +++
.../competitions/common_header.json.jbuilder | 12 ++
.../competitions/enroll.json.jbuilder | 0
.../competitions/informs.json.jbuilder | 6 +
.../competitions/md_content.json.jbuilder | 4 +
config/routes.rb | 9 ++
...3840_add_competition_id_to_mode_setting.rb | 7 +
...0191017092449_migrate_competition_score.rb | 29 ++++
...0191018022821_create_competition_awards.rb | 12 ++
...018030029_add_rate_to_competition_stage.rb | 5 +
spec/models/chart_rule_spec.rb | 5 +
spec/models/competition_award_spec.rb | 5 +
spec/models/competition_score_spec.rb | 5 +
30 files changed, 582 insertions(+), 3 deletions(-)
create mode 100644 app/helpers/competitions_helper.rb
create mode 100644 app/models/chart_rule.rb
create mode 100644 app/models/competition_award.rb
create mode 100644 app/models/competition_score.rb
create mode 100644 app/views/competitions/competition_teams/course_detail.json.jbuilder
create mode 100644 app/views/competitions/competition_teams/shixun_detail.json.jbuilder
create mode 100644 app/views/competitions/competitions/chart_list.xlsx.axlsx
create mode 100644 app/views/competitions/competitions/chart_rules.json.jbuilder
create mode 100644 app/views/competitions/competitions/charts.json.jbuilder
create mode 100644 app/views/competitions/competitions/enroll.json.jbuilder
create mode 100644 app/views/competitions/competitions/informs.json.jbuilder
create mode 100644 app/views/competitions/competitions/md_content.json.jbuilder
create mode 100644 db/migrate/20191017063840_add_competition_id_to_mode_setting.rb
create mode 100644 db/migrate/20191017092449_migrate_competition_score.rb
create mode 100644 db/migrate/20191018022821_create_competition_awards.rb
create mode 100644 db/migrate/20191018030029_add_rate_to_competition_stage.rb
create mode 100644 spec/models/chart_rule_spec.rb
create mode 100644 spec/models/competition_award_spec.rb
create mode 100644 spec/models/competition_score_spec.rb
diff --git a/app/controllers/competitions/competition_teams_controller.rb b/app/controllers/competitions/competition_teams_controller.rb
index e03810b61..f504b226e 100644
--- a/app/controllers/competitions/competition_teams_controller.rb
+++ b/app/controllers/competitions/competition_teams_controller.rb
@@ -1,4 +1,63 @@
class Competitions::CompetitionTeamsController < Competitions::BaseController
+ before_action :tech_mode, only: [:shixun_detail, :course_detail]
+
+ def shixun_detail
+ start_time = current_competition.competition_mode_setting&.start_time || current_competition.start_time
+ end_time = current_competition.competition_mode_setting&.end_time || current_competition.end_time
+
+ team_user_ids = @team.team_members.pluck(:user_id)
+ shixuns = Shixun.where(user_id: team_user_ids, status: 2)
+ .where('shixuns.created_at > ? && shixuns.created_at <= ?', start_time, end_time)
+ shixuns = shixuns.joins('left join shixuns forked_shixuns on forked_shixuns.fork_from = shixuns.id and forked_shixuns.status = 2')
+ shixuns = shixuns.select('shixuns.id, shixuns.identifier, shixuns.user_id, shixuns.myshixuns_count, shixuns.name, shixuns.fork_from, sum(forked_shixuns.myshixuns_count) forked_myshixun_count')
+ @shixuns = shixuns.group('shixuns.id').order('shixuns.myshixuns_count desc').includes(:user)
+
+ shixun_ids = @shixuns.map(&:id)
+ @myshixun_count_map = get_valid_myshixun_count(shixun_ids)
+ @original_myshixun_count_map = @myshixun_count_map.clone
+ # forked shixun valid myshixun count
+ forked_shixun_map = Shixun.where(status: 2, fork_from: shixun_ids).select('id, fork_from')
+ forked_shixun_map = forked_shixun_map.each_with_object({}) { |sx, obj| obj[sx.id] = sx.fork_from }
+ @forked_myshixun_count_map = get_valid_myshixun_count(forked_shixun_map.keys)
+ @forked_myshixun_count_map.each { |k, v| @myshixun_count_map[forked_shixun_map[k]] += v }
+
+ @course_count_map = get_valid_course_count(shixun_ids)
+ @forked_map = get_valid_course_count(forked_shixun_map.keys)
+ @forked_course_count_map = {}
+ @forked_map.each do |forked_id, course_count|
+ @forked_course_count_map[forked_shixun_map[forked_id]] ||= 0
+ @forked_course_count_map[forked_shixun_map[forked_id]] += course_count
+ end
+ @forked_shixun_map = forked_shixun_map
+ end
+
+ def course_detail
+ start_time = current_competition.competition_mode_setting&.start_time || current_competition.start_time
+ end_time = current_competition.competition_mode_setting&.end_time || current_competition.end_time
+ @team_user_ids = @team.team_members.pluck(:user_id)
+
+ student_count_subquery = CourseMember.where('course_id = courses.id AND role = 4').select('count(*)').to_sql
+ subquery = StudentWork.where('homework_common_id = hcs.id')
+ .select('sum(compelete_status !=0 ) as finish, count(*) as total')
+ .having('total != 0 and finish >= (total / 2)').to_sql
+ course_ids = Course.where('courses.created_at > ?', start_time)
+ .where('courses.created_at <= ?', end_time)
+ .where("(#{student_count_subquery}) >= 3")
+ .where("exists(select 1 from homework_commons hcs where hcs.course_id = courses.id and hcs.publish_time is not null and hcs.publish_time < NOW() and hcs.homework_type = 4 and exists(#{subquery}))")
+ .joins('join course_members on course_members.course_id = courses.id and course_members.role in (1,2,3)')
+ .where(course_members: { user_id: @team_user_ids }).pluck(:id)
+ courses = Course.where(id: course_ids).joins(:practice_homeworks).where('homework_commons.publish_time < now()')
+ @courses = courses.select('courses.id, courses.name, courses.members_count, count(*) shixun_homework_count')
+ .group('courses.id').order('shixun_homework_count desc').having('shixun_homework_count > 0')
+
+ course_ids = @courses.map(&:id)
+ @course_myshixun_map = Myshixun.joins(student_works: :homework_common)
+ .where(homework_commons: { course_id: course_ids })
+ .where('exists(select 1 from games where games.myshixun_id = myshixuns.id and games.status = 2)')
+ .group('homework_commons.course_id').count
+ @course_shixun_count_map = get_valid_shixun_count(course_ids)
+ end
+
def index
admin_or_business? ? all_competition_teams : user_competition_teams
end
@@ -67,4 +126,37 @@ class Competitions::CompetitionTeamsController < Competitions::BaseController
def save_params
params.permit(:name, teacher_ids: [], member_ids: [])
end
+
+ def tech_mode
+ # render_not_found if current_competition.mode != 3
+ @team = current_competition.competition_teams.find_by(id: params[:id])
+ end
+
+ def get_valid_myshixun_count(ids)
+ Myshixun.where(shixun_id: ids)
+ .where('exists(select 1 from games where games.myshixun_id = myshixuns.id and games.status = 2)')
+ .group('shixun_id').count
+ end
+
+ def get_valid_course_count(ids)
+ percentage_sql = StudentWork.where('homework_common_id = homework_commons.id and homework_commons.publish_time is not null and homework_commons.publish_time < NOW()')
+ .select('sum(compelete_status !=0 ) as finish, count(*) as total')
+ .having('total != 0 and finish >= (total / 2)').to_sql
+
+ Course.joins(practice_homeworks: :homework_commons_shixun)
+ .where('shixun_id in (?)', ids)
+ .where("exists (#{percentage_sql})")
+ .group('shixun_id').count
+ end
+
+ def get_valid_shixun_count(ids)
+ percentage_sql = StudentWork.where('homework_common_id = homework_commons.id and homework_commons.publish_time is not null and homework_commons.publish_time < NOW()')
+ .select('sum(compelete_status !=0 ) as finish, count(*) as total')
+ .having('total != 0 and finish >= (total / 2)').to_sql
+ Shixun.joins(homework_commons_shixuns: :homework_common)
+ .where(homework_commons: { homework_type: 4 })
+ .where('course_id in (?)', ids)
+ .where("exists (#{percentage_sql})")
+ .group('course_id').count
+ end
end
diff --git a/app/controllers/competitions/competitions_controller.rb b/app/controllers/competitions/competitions_controller.rb
index 30df949f6..03a276952 100644
--- a/app/controllers/competitions/competitions_controller.rb
+++ b/app/controllers/competitions/competitions_controller.rb
@@ -1,7 +1,10 @@
class Competitions::CompetitionsController < Competitions::BaseController
+ include CompetitionsHelper
+
skip_before_action :require_login
before_action :allow_visit, except: [:index]
- before_action :require_admin, only: [:update]
+ before_action :require_admin, only: [:update, :update_inform]
+ before_action :chart_visible, only: [:charts, :chart_rules]
def index
# 已上架 或者 即将上架
@@ -36,6 +39,98 @@ class Competitions::CompetitionsController < Competitions::BaseController
def common_header
@competition = current_competition
+ @competition_modules = @competition.unhidden_competition_modules
+ @user = current_user
+ end
+
+ def informs
+ status = params[:status] || 1
+ @informs = current_competition.informs.where(status: status)
+ end
+
+ def update_inform
+ tip_exception("标题和内容不能为空") if params[:name].blank? || params[:description].blank?
+ tip_exception("status参数有误") if params[:status].blank? || ![1, 2].include?(params[:status].to_i)
+ ActiveRecord::Base.transaction do
+ if params[:inform_id]
+ inform = current_competition.informs.find_by!(id: params[:inform_id])
+ inform.update_attributes!(name: params[:name], description: params[:description])
+ else
+ inform = current_competition.informs.create!(name: params[:name], description: params[:description], status: params[:status])
+ end
+ Attachment.associate_container(params[:attachment_ids], inform.id, inform.class) if params[:attachment_ids]
+ normal_status("更新成功")
+ end
+ end
+
+ def md_content
+ @md_content = CompetitionModuleMdContent.find_by!(id: params[:md_content_id])
+ end
+
+ def update_md_content
+ tip_exception("标题和内容不能为空") if params[:name].blank? || params[:content].blank?
+ ActiveRecord::Base.transaction do
+ if params[:md_content_id]
+ md_content = CompetitionModuleMdContent.find_by!(id: params[:md_content_id])
+ md_content.update_attributes!(name: params[:name], content: params[:content])
+ else
+ md_content = CompetitionModuleMdContent.create!(name: params[:name], content: params[:content])
+ end
+ Attachment.associate_container(params[:attachment_ids], md_content.id, md_content.class) if params[:attachment_ids]
+ normal_status("更新成功")
+ end
+ end
+
+ def chart_rules
+ @competition = current_competition
+ @stages = @competition.competition_stages
+ @rule_contents = @competition.chart_rules
+ end
+
+ def update_chart_rules
+ tip_exception("内容不能为空") if params[:content].blank?
+ @competition = current_competition
+ @stage = @competition.competition_stages.find_by!(id: params[:stage_id]) if params[:stage_id]
+ chart_rule = @competition.chart_rules.where(competition_stage_id: @stage&.id).first
+ if chart_rule
+ chart_rule.update_attributes!(content: params[:content])
+ else
+ @competition.chart_rules.create!(competition_stage_id: @stage&.id, content: params[:content])
+ end
+ normal_status("更新成功")
+ end
+
+ def charts
+ @competition = current_competition
+ if params[:stage_id]
+ @stage = @competition.competition_stages.find_by(id: params[:stage_id])
+ end
+
+ if @competition.identifier == "gcc-annotation-2018"
+ @records = @competition.competition_teams.joins(:competition_scores)
+ .select("competition_teams.*, score, cost_time").order("score desc, cost_time desc")
+ else
+ @records = @competition.competition_teams.joins(:competition_scores).where(competition_scores: {competition_stage_id: @stage&.id.to_i})
+ .select("competition_teams.*, score, cost_time").order("score desc, cost_time desc")
+ end
+
+ current_team_ids = @competition.team_members.where(user_id: current_user.id).pluck(:competition_team_id).uniq
+ @user_ranks = @records.select{|com_team| current_team_ids.include?(com_team.id)}
+ @records = @records.where("score > 0")
+ if params[:format] == "xlsx"
+ @records = @records.includes(user: [user_extension: :school], team_members: :user)
+ respond_to do |format|
+ format.xlsx{
+ set_export_cookies
+ chart_to_xlsx(@records, @competition)
+ exercise_export_name = "#{@competition.name}比赛成绩"
+ render xlsx: "#{exercise_export_name.strip}",template: "competitions/competitions/chart_list.xlsx.axlsx",locals:
+ {table_columns: @competition_head_cells, chart_lists: @competition_cells_column}
+ }
+ end
+ else
+ @records = @records.includes(:user, :team_members).limit(@competition.awards_count)
+ end
end
private
@@ -47,4 +142,58 @@ class Competitions::CompetitionsController < Competitions::BaseController
def allow_visit
render_forbidden unless current_competition.published? || admin_or_business?
end
+
+ def chart_visible
+ chart_module = current_competition.competition_modules.find_by(name: "排行榜")
+ render_forbidden unless (chart_module.present? && !chart_module.hidden) || admin_or_business?
+ end
+
+ # 竞赛成绩导出
+ def chart_to_xlsx records, competition
+ @competition_head_cells = []
+ @competition_cells_column = []
+
+ max_staff = competition.competition_staffs.sum(:maximum)
+ if max_staff < 2 # 个人赛
+ @competition_head_cells = %w(序号 姓名 学校 学号)
+ else # 战队赛
+ @competition_head_cells = %w(序号 战队名 指导老师 队员 学校)
+ end
+
+ statistic_stages = competition.competition_stages.where("rate > 0")
+ statistic_stages.each do |stage|
+ @competition_head_cells += ["#{stage.name}得分", "#{stage.name}用时"]
+ end
+ @competition_head_cells += ["总得分", "总用时"] if statistic_stages.size > 1
+ competition_scores = competition.competition_scores
+
+ records.each_with_index do |record, index|
+ row_cells_column = []
+ row_cells_column << index + 1
+ record_user = record.user
+ if max_staff < 2
+ row_cells_column << record_user.real_name
+ row_cells_column << record_user.school_name
+ row_cells_column << record_user.student_id
+ else
+ row_cells_column << record.name
+ row_cells_column << record.teachers_name
+ row_cells_column << record.members_name
+ row_cells_column << chart_school_str(record.team_members.select{|member| !member.is_teacher}.pluck(:user_id))
+ end
+
+ statistic_stages.each do |stage|
+ stage_score = competition_scores.select{|score| score.competition_stage_id == stage.id && score.competition_team_id == record.id}.first
+ row_cells_column << stage_score&.score.to_f.round(2)
+ row_cells_column << com_spend_time(stage_score&.cost_time.to_i)
+ end
+
+ if statistic_stages.size > 1
+ row_cells_column << record&.score.to_f.round(2)
+ row_cells_column << com_spend_time(record&.cost_time.to_i)
+ end
+
+ @competition_cells_column.push(row_cells_column)
+ end
+ end
end
\ No newline at end of file
diff --git a/app/helpers/competitions_helper.rb b/app/helpers/competitions_helper.rb
new file mode 100644
index 000000000..66c7eec41
--- /dev/null
+++ b/app/helpers/competitions_helper.rb
@@ -0,0 +1,54 @@
+module CompetitionsHelper
+ def chart_school_str user_ids
+ chart_school_name = ""
+ chart_school_name = School.where(id: UserExtension.where(user_id: user_ids).pluck(:school_id).uniq).pluck(:name).join("、")
+ end
+
+ # 耗时:小时、分、秒 00:00:00
+ # 小于1秒钟则不显示
+ def com_spend_time time
+ hour = time / (60*60)
+ min = time % (60*60) / 60
+ sec = time % (60*60) % 60
+ hour_str = "00"
+ min_str = "00"
+ sec_str = "00"
+ if hour >= 1 && hour < 10
+ hour_str = "0#{hour}"
+ elsif hour >= 10
+ hour_str = "#{hour}"
+ end
+
+ if min >= 1 && min < 10
+ min_str = "0#{min}"
+ elsif min >= 10
+ min_str = "#{min}"
+ end
+
+ if sec >= 1 && sec < 10
+ sec_str = "0#{sec}"
+ elsif sec >= 10
+ sec_str = "#{sec}"
+ end
+
+ time = "#{hour_str} : #{min_str} : #{sec_str}"
+ return time
+ end
+
+ def chart_stages competition
+ stages = []
+ statistic_stages = competition.competition_stages.where("rate > 0")
+ if competition.end_time && competition.end_time < Time.now && statistic_stages.size > 1
+ stages << {id: nil, name: "总排行榜", rate: 1.0, start_time: competition.start_time, end_time: competition.end_time}
+ end
+
+ statistic_stages.each do |stage|
+ if stage.max_end_time && stage.max_end_time < Time.now
+ stages << {id: stage.id, name: "#{stage.name}排行榜", rate: stage.rate, start_time: stage.min_start_time, end_time: stage.max_end_time}
+ end
+ end
+
+ stages = stages.sort { |a, b| b[:end_time] <=> a[:end_time] } if stages.size > 0
+ return stages
+ end
+end
\ No newline at end of file
diff --git a/app/models/chart_rule.rb b/app/models/chart_rule.rb
new file mode 100644
index 000000000..de8fceaf1
--- /dev/null
+++ b/app/models/chart_rule.rb
@@ -0,0 +1,6 @@
+class ChartRule < ApplicationRecord
+ belongs_to :competition
+ belongs_to :competition_stage, optional: true
+
+ validates :content, length: { maximum: 1000 }
+end
diff --git a/app/models/competition.rb b/app/models/competition.rb
index 9055adefc..23b1e3c81 100644
--- a/app/models/competition.rb
+++ b/app/models/competition.rb
@@ -9,12 +9,19 @@ class Competition < ApplicationRecord
has_many :competition_teams, dependent: :destroy
has_many :team_members, dependent: :destroy
+ has_many :chart_rules, dependent: :destroy
+
+ has_many :competition_scores, dependent: :destroy
has_many :competition_staffs, dependent: :destroy
has_one :teacher_staff, -> { where(category: :teacher) }, class_name: 'CompetitionStaff'
has_one :member_staff, -> { where.not(category: :teacher) }, class_name: 'CompetitionStaff'
+ has_one :competition_mode_setting, dependent: :destroy
+
+ has_many :informs, as: :container, dependent: :destroy
+ has_many :attachments, as: :container, dependent: :destroy
- has_many :attachments, as: :container
+ has_many :competition_awards, dependent: :destroy
after_create :create_competition_modules
@@ -81,6 +88,16 @@ class Competition < ApplicationRecord
member_staff.mutiple_limited?
end
+ def max_min_stage_time
+ CompetitionStageSection.find_by_sql("SELECT MAX(end_time) as max_end_time, MIN(start_time) as min_start_time,
+ competition_stage_id FROM competition_stage_sections WHERE competition_id = #{id}
+ GROUP BY competition_stage_id order by competition_stage_id")
+ end
+
+ def awards_count
+ competition_awards.pluck(:num)&.sum > 0 ? competition_awards.pluck(:num)&.sum : 20
+ end
+
private
def create_competition_modules
diff --git a/app/models/competition_award.rb b/app/models/competition_award.rb
new file mode 100644
index 000000000..715d82ee2
--- /dev/null
+++ b/app/models/competition_award.rb
@@ -0,0 +1,3 @@
+class CompetitionAward < ApplicationRecord
+ belongs_to :competition
+end
diff --git a/app/models/competition_mode_setting.rb b/app/models/competition_mode_setting.rb
index b6bafa7c3..e8d6c17d7 100644
--- a/app/models/competition_mode_setting.rb
+++ b/app/models/competition_mode_setting.rb
@@ -1,3 +1,4 @@
class CompetitionModeSetting < ApplicationRecord
- belongs_to :course
+ belongs_to :course, optional: true
+ belongs_to :competition
end
diff --git a/app/models/competition_module.rb b/app/models/competition_module.rb
index be73bf3c1..9579533da 100644
--- a/app/models/competition_module.rb
+++ b/app/models/competition_module.rb
@@ -4,4 +4,21 @@ class CompetitionModule < ApplicationRecord
belongs_to :competition
has_one :competition_module_md_content, dependent: :destroy
+
+ def module_url
+ case name
+ when "首页", "赛制介绍"
+ "/competitions/#{competition.identifier}"
+ when "通知公告"
+ "/competitions/#{competition.identifier}/informs?status=1"
+ when "参赛手册"
+ "/competitions/#{competition.identifier}/informs?status=2"
+ when "排行榜"
+ "/competitions/#{competition.identifier}/charts"
+ when "报名"
+ "/competitions/#{competition.identifier}/competition_teams"
+ else
+ url || "/competitions/#{competition.identifier}/md_content?md_content_id=#{competition_module_md_content&.id}"
+ end
+ end
end
diff --git a/app/models/competition_score.rb b/app/models/competition_score.rb
new file mode 100644
index 000000000..ce7bad427
--- /dev/null
+++ b/app/models/competition_score.rb
@@ -0,0 +1,6 @@
+class CompetitionScore < ApplicationRecord
+ belongs_to :user
+ belongs_to :competition
+ belongs_to :competition_stage, optional: true
+ belongs_to :competition_team, optional: true
+end
diff --git a/app/models/competition_stage.rb b/app/models/competition_stage.rb
index 60d4b1644..dec777b39 100644
--- a/app/models/competition_stage.rb
+++ b/app/models/competition_stage.rb
@@ -3,5 +3,15 @@ class CompetitionStage < ApplicationRecord
has_many :competition_stage_sections, dependent: :destroy
has_many :competition_entries, dependent: :destroy
+ has_many :competition_scores, dependent: :destroy
+ has_one :chart_rule, dependent: :destroy
+
+ def min_start_time
+ competition_stage_sections.where("start_time is not null").pluck(:start_time).min
+ end
+
+ def max_end_time
+ competition_stage_sections.where("end_time is not null").pluck(:end_time).max
+ end
end
\ No newline at end of file
diff --git a/app/models/competition_team.rb b/app/models/competition_team.rb
index 625b29421..878f58882 100644
--- a/app/models/competition_team.rb
+++ b/app/models/competition_team.rb
@@ -7,6 +7,7 @@ class CompetitionTeam < ApplicationRecord
has_many :team_members, dependent: :destroy
has_many :users, through: :team_members, source: :user
+ has_many :competition_scores, dependent: :destroy
has_many :members, -> { without_teachers }, class_name: 'TeamMember'
has_many :teachers, -> { only_teachers }, class_name: 'TeamMember'
@@ -30,4 +31,12 @@ class CompetitionTeam < ApplicationRecord
self.code = code
code
end
+
+ def teachers_name
+ teachers.map{|teacher| teacher.user.real_name}.join(",")
+ end
+
+ def members_name
+ members.map{|member| member.user.real_name}.join(",")
+ end
end
\ No newline at end of file
diff --git a/app/models/inform.rb b/app/models/inform.rb
index 5caf80c5f..d486b6f11 100644
--- a/app/models/inform.rb
+++ b/app/models/inform.rb
@@ -3,4 +3,6 @@ class Inform < ApplicationRecord
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 5000 }
+
+ has_many :attachments, as: :container, dependent: :destroy
end
diff --git a/app/models/shixun.rb b/app/models/shixun.rb
index 0cdb2e82b..efa3098fc 100644
--- a/app/models/shixun.rb
+++ b/app/models/shixun.rb
@@ -27,6 +27,7 @@ class Shixun < ApplicationRecord
has_one :first_shixun_tag_repertoire, class_name: 'ShixunTagRepertoire'
has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire, source: :tag_repertoire
+ has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun'
#实训的关卡
has_many :exercise_shixun_challenges, :dependent => :destroy
diff --git a/app/views/competitions/competition_teams/course_detail.json.jbuilder b/app/views/competitions/competition_teams/course_detail.json.jbuilder
new file mode 100644
index 000000000..ce37d9568
--- /dev/null
+++ b/app/views/competitions/competition_teams/course_detail.json.jbuilder
@@ -0,0 +1,28 @@
+total_students_count = 0
+total_shixun_homework_count = 0
+total_course_score = 0
+
+json.courses @courses.each do |course|
+ students_count = course.students.count
+ total_students_count += students_count
+ total_shixun_homework_count += course['shixun_homework_count'].to_i
+
+ score = 500 + 5 * @course_shixun_count_map.fetch(course.id, 0) * @course_myshixun_map.fetch(course.id, 0)
+ total_course_score += score
+
+ teacher = course.teachers.where(user_id: @team_user_ids).first.user
+ json.creator teacher&.real_name
+ json.creator_login teacher&.login
+ json.course_name course.name
+ json.course_id course.id
+ json.students_count students_count
+ json.shixun_homework_count course['shixun_homework_count']
+ json.valid_count @course_myshixun_map.fetch(course.id, 0)
+ json.score score
+end
+
+json.total_course_count @courses.size
+json.total_students_count total_students_count
+json.total_shixun_homework_count total_shixun_homework_count
+json.total_valid_count @course_myshixun_map.values.reduce(:+)
+json.total_course_score total_course_score
\ No newline at end of file
diff --git a/app/views/competitions/competition_teams/shixun_detail.json.jbuilder b/app/views/competitions/competition_teams/shixun_detail.json.jbuilder
new file mode 100644
index 000000000..abeb8c85c
--- /dev/null
+++ b/app/views/competitions/competition_teams/shixun_detail.json.jbuilder
@@ -0,0 +1,41 @@
+total_myshixun_count = 0
+total_forked_myshixun_count = 0
+total_shixun_score = 0
+
+json.shixuns @shixuns.each do |shixun|
+ total_myshixun_count += shixun.myshixuns_count
+ total_forked_myshixun_count += shixun['forked_myshixun_count'].to_i
+
+ valid_course_count = @course_count_map.fetch(shixun.id, 0)
+ valid_student_count = @original_myshixun_count_map.fetch(shixun.id, 0)
+ score =
+ if shixun.fork_from.blank?
+ 500 + 50 * valid_course_count + 10 * valid_student_count
+ else
+ 100 + 10 * valid_course_count + 5 * valid_student_count
+ end
+
+ @forked_shixun_map.each do |shixun_id, fork_from_id|
+ next if fork_from_id != shixun.id
+
+ score += 100 + 10 * @forked_map.fetch(shixun_id, 0) + 5 * @forked_myshixun_count_map.fetch(shixun_id, 0)
+ end
+
+ total_shixun_score += score
+
+ json.creator shixun.user.real_name
+ json.creator_login shixun.user.login
+ json.shixun_name shixun.name
+ json.shixun_identifier shixun.identifier
+ json.forked shixun.fork_from.present?
+ json.myshixuns_count shixun.myshixuns_count
+ json.forked_myshixun_count shixun['forked_myshixun_count'].to_i
+ json.valid_count @myshixun_count_map.fetch(shixun.id, 0)
+ json.score score
+end
+
+json.shixun_count @shixuns.size
+json.total_myshixun_count total_myshixun_count
+json.total_forked_myshixun_count total_forked_myshixun_count
+json.total_valid_count @myshixun_count_map.values.reduce(:+)
+json.total_shixun_score total_shixun_score
\ No newline at end of file
diff --git a/app/views/competitions/competitions/chart_list.xlsx.axlsx b/app/views/competitions/competitions/chart_list.xlsx.axlsx
new file mode 100644
index 000000000..2186b6ffd
--- /dev/null
+++ b/app/views/competitions/competitions/chart_list.xlsx.axlsx
@@ -0,0 +1,18 @@
+
+wb = xlsx_package.workbook
+# wb.use_autowidth = false
+wb.styles do |s|
+ sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center}
+ blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center}
+ wb.add_worksheet(:name => "比赛成绩") do |sheet|
+ sheet.sheet_view.show_grid_lines = false
+ sheet.add_row table_columns, :style => blue_cell
+ if chart_lists.count > 0
+ chart_lists.each do |user|
+ sheet.add_row user, :height => 20,:style => sz_all
+ end #each_widh_index
+ end
+ sheet.column_widths *([20]*sheet.column_info.count)
+ sheet.column_info.first.width = 12
+ end #add_worksheet
+end
\ No newline at end of file
diff --git a/app/views/competitions/competitions/chart_rules.json.jbuilder b/app/views/competitions/competitions/chart_rules.json.jbuilder
new file mode 100644
index 000000000..bf1d04689
--- /dev/null
+++ b/app/views/competitions/competitions/chart_rules.json.jbuilder
@@ -0,0 +1,5 @@
+json.rule_contents @rule_contents.each do |rule|
+ json.(rule, :id, :content, :competition_stage_id)
+end
+
+json.stages chart_stages @competition
\ No newline at end of file
diff --git a/app/views/competitions/competitions/charts.json.jbuilder b/app/views/competitions/competitions/charts.json.jbuilder
new file mode 100644
index 000000000..f59f377f7
--- /dev/null
+++ b/app/views/competitions/competitions/charts.json.jbuilder
@@ -0,0 +1,21 @@
+json.user_ranks @user_ranks.each do |user_rank|
+ rank = @records.map(&:id).index(user_rank.id)
+ rank = rank.present? ? (rank+1) : 0
+ json.rank rank == 0 ? "--" : user_rank.rank
+ json.team_name user_rank.name
+ json.user_name user_rank.user.real_name
+ json.cost_time rank == 0 && user_rank.cost_time ? "--" : com_spend_time(user_rank.cost_time)
+ json.score rank == 0 ? "--" : user_rank.score.round(2)
+end
+
+json.teams @records.each do |record|
+ record_user = record.user
+ json.team_name record.name
+ json.record_user_name record_user.real_name
+ json.user_image url_to_avatar(record_user)
+ json.user_login record_user.login
+ school_name = chart_school_str record.team_members.select{|member| !member.is_teacher}.pluck(:user_id)
+ json.school_name school_name
+ json.score record&.score&.round(2)
+ json.spend_time record.cost_time ? com_spend_time(record.cost_time) : "--"
+end
\ No newline at end of file
diff --git a/app/views/competitions/competitions/common_header.json.jbuilder b/app/views/competitions/competitions/common_header.json.jbuilder
index f172dae86..882d1d1c0 100644
--- a/app/views/competitions/competitions/common_header.json.jbuilder
+++ b/app/views/competitions/competitions/common_header.json.jbuilder
@@ -10,3 +10,15 @@ json.enroll_end_time @competition.enroll_end_time&.strftime("%Y-%m-%d %H:%M:%S")
json.published @competition.published?
json.nearly_published @competition.published_at.present?
+json.competition_modules @competition_modules do |com_module|
+ json.(com_module, :name, :position)
+ json.module_url com_module.module_url
+end
+
+json.stages
+
+if @competition.mode == 1
+ json.course_id @competition.competition_mode_setting&.course_id
+ json.member_of_course @user.member_of_course?(@competition.competition_mode_setting&.course)
+end
+
diff --git a/app/views/competitions/competitions/enroll.json.jbuilder b/app/views/competitions/competitions/enroll.json.jbuilder
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/views/competitions/competitions/informs.json.jbuilder b/app/views/competitions/competitions/informs.json.jbuilder
new file mode 100644
index 000000000..1b40c93e7
--- /dev/null
+++ b/app/views/competitions/competitions/informs.json.jbuilder
@@ -0,0 +1,6 @@
+json.informs @informs.each do |inform|
+ json.(inform, :id, :name, :description)
+ json.attachments inform.attachments do |atta|
+ json.partial! "attachments/attachment_simple", locals: {attachment: atta}
+ end
+end
\ No newline at end of file
diff --git a/app/views/competitions/competitions/md_content.json.jbuilder b/app/views/competitions/competitions/md_content.json.jbuilder
new file mode 100644
index 000000000..45325cecb
--- /dev/null
+++ b/app/views/competitions/competitions/md_content.json.jbuilder
@@ -0,0 +1,4 @@
+json.(@md_content, :id, :name, :content)
+json.attachments @md_content.attachments do |atta|
+ json.partial! "attachments/attachment_simple", locals: {attachment: atta}
+end
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index f9efaf794..75fcf9a04 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -787,12 +787,21 @@ Rails.application.routes.draw do
resources :competition_teams, only: [:index, :show] do
post :join, on: :collection
post :leave, on: :member
+ get :course_detail, on: :member
+ get :shixun_detail, on: :member
end
resources :teachers, only: [:index]
resources :students, only: [:index]
member do
get :common_header
+ get :informs
+ post :update_inform
+ get :md_content
+ post :update_md_content
+ get :charts
+ get :chart_rules
+ post :update_chart_rules
end
end
end
diff --git a/db/migrate/20191017063840_add_competition_id_to_mode_setting.rb b/db/migrate/20191017063840_add_competition_id_to_mode_setting.rb
new file mode 100644
index 000000000..ef68d395b
--- /dev/null
+++ b/db/migrate/20191017063840_add_competition_id_to_mode_setting.rb
@@ -0,0 +1,7 @@
+class AddCompetitionIdToModeSetting < ActiveRecord::Migration[5.2]
+ def change
+ add_column :competition_mode_settings, :competition_id, :integer
+
+ add_index :competition_mode_settings, :competition_id
+ end
+end
diff --git a/db/migrate/20191017092449_migrate_competition_score.rb b/db/migrate/20191017092449_migrate_competition_score.rb
new file mode 100644
index 000000000..095f403c5
--- /dev/null
+++ b/db/migrate/20191017092449_migrate_competition_score.rb
@@ -0,0 +1,29 @@
+class MigrateCompetitionScore < ActiveRecord::Migration[5.2]
+ def change
+ CompetitionModule.where(name: "排行榜", hidden: 0).each do |com_module|
+ competition = com_module.competition
+ if competition.present?
+ puts competition.id
+ if competition.identifier == 'hn' || competition.identifier == 'gcc-task-2019'
+ p_rate = 0.2
+ f_rate = 0.8
+ else
+ p_rate = 0.15
+ f_rate = 0.85
+ end
+ pre_stage = competition.competition_stages.where(:name => "预赛").first
+ final_stage = competition.competition_stages.where(:name => "决赛").first
+
+ competition.competition_teams.each do |team|
+ f_score = team.competition_scores.where(:competition_stage_id => final_stage.try(:id)).first
+ # 预赛记录
+ p_score = team.competition_scores.where(:competition_stage_id => pre_stage.try(:id)).first
+ s_score = (f_score.try(:score).to_f * f_rate + p_score.try(:score).to_f * p_rate).try(:round, 2)
+ s_spend_time = f_score.try(:cost_time).to_i + p_score.try(:cost_time).to_i
+ CompetitionScore.create(:user_id => team.user_id, :competition_team_id => team.id, :competition_id => competition.id,
+ :competition_stage_id => 0, :score => s_score, :cost_time => s_spend_time)
+ end
+ end
+ end
+ end
+end
diff --git a/db/migrate/20191018022821_create_competition_awards.rb b/db/migrate/20191018022821_create_competition_awards.rb
new file mode 100644
index 000000000..9da6068ce
--- /dev/null
+++ b/db/migrate/20191018022821_create_competition_awards.rb
@@ -0,0 +1,12 @@
+class CreateCompetitionAwards < ActiveRecord::Migration[5.2]
+ def change
+ create_table :competition_awards do |t|
+ t.references :competition, index: true
+ t.string :name
+ t.integer :num, default: 0
+ t.integer :award_type, default: 0
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20191018030029_add_rate_to_competition_stage.rb b/db/migrate/20191018030029_add_rate_to_competition_stage.rb
new file mode 100644
index 000000000..6e819cc17
--- /dev/null
+++ b/db/migrate/20191018030029_add_rate_to_competition_stage.rb
@@ -0,0 +1,5 @@
+class AddRateToCompetitionStage < ActiveRecord::Migration[5.2]
+ def change
+ add_column :competition_stages, :rate, :float, default: 1.0
+ end
+end
diff --git a/spec/models/chart_rule_spec.rb b/spec/models/chart_rule_spec.rb
new file mode 100644
index 000000000..b3059c94d
--- /dev/null
+++ b/spec/models/chart_rule_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe ChartRule, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/competition_award_spec.rb b/spec/models/competition_award_spec.rb
new file mode 100644
index 000000000..dac3bddcf
--- /dev/null
+++ b/spec/models/competition_award_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe CompetitionAward, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/competition_score_spec.rb b/spec/models/competition_score_spec.rb
new file mode 100644
index 000000000..d0f1372b1
--- /dev/null
+++ b/spec/models/competition_score_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe CompetitionScore, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
From c337d36794aacf075a31d4e58164b39841a7a376 Mon Sep 17 00:00:00 2001
From: cxt <853663049@qq.com>
Date: Sat, 19 Oct 2019 14:11:13 +0800
Subject: [PATCH 03/33] =?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/assets/javascripts/admins/competitions/index.js | 11 +++++++++++
app/controllers/homework_commons_controller.rb | 2 +-
app/views/admins/competition_settings/show.html.erb | 9 +++++++++
config/admins/sidebar.yml | 3 ++-
4 files changed, 23 insertions(+), 2 deletions(-)
create mode 100644 app/assets/javascripts/admins/competitions/index.js
diff --git a/app/assets/javascripts/admins/competitions/index.js b/app/assets/javascripts/admins/competitions/index.js
new file mode 100644
index 000000000..ae4593d33
--- /dev/null
+++ b/app/assets/javascripts/admins/competitions/index.js
@@ -0,0 +1,11 @@
+$(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('重新上传');
+ })
+ }
+});
+
diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb
index 60cf2d6c5..168d05299 100644
--- a/app/controllers/homework_commons_controller.rb
+++ b/app/controllers/homework_commons_controller.rb
@@ -1058,8 +1058,8 @@ class HomeworkCommonsController < ApplicationController
tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if
@course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day)
else
+ tip_exception("缺少分班截止时间参数") if params[:group_end_times].blank?
group_end_times = params[:group_end_times].reject(&:blank?).map{|time| time.to_time}
- tip_exception("缺少截止时间参数") if group_end_times.blank?
tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length
group_end_times.each do |time|
tip_exception("分班截止时间不能早于当前时间") if time <= Time.now
diff --git a/app/views/admins/competition_settings/show.html.erb b/app/views/admins/competition_settings/show.html.erb
index e69de29bb..8249f2737 100644
--- a/app/views/admins/competition_settings/show.html.erb
+++ b/app/views/admins/competition_settings/show.html.erb
@@ -0,0 +1,9 @@
+<%
+ define_admin_breadcrumbs do
+ add_admin_breadcrumb('竞赛列表', admins_competitions_path)
+ add_admin_breadcrumb(@competition.name)
+ end
+%>
+
+
+
diff --git a/config/admins/sidebar.yml b/config/admins/sidebar.yml
index 71e77e218..b722f2505 100644
--- a/config/admins/sidebar.yml
+++ b/config/admins/sidebar.yml
@@ -1,3 +1,4 @@
admins-mirror_scripts: 'admins-mirror_repositories'
admins-laboratory_settings: 'admins-laboratories'
-admins-carousels: 'admins-laboratories'
\ No newline at end of file
+admins-carousels: 'admins-laboratories'
+admins-competition_settings: 'admins-competitions'
\ No newline at end of file
From b53c3137d133052c7ce71b1cd41f7ec44633f6b7 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Sat, 19 Oct 2019 15:17:22 +0800
Subject: [PATCH 04/33] =?UTF-8?q?=E4=BA=91=E5=AE=9E=E9=AA=8C=E5=AE=9A?=
=?UTF-8?q?=E5=88=B6=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/models/laboratory_setting.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/models/laboratory_setting.rb b/app/models/laboratory_setting.rb
index 32848dca2..ca62f5c91 100644
--- a/app/models/laboratory_setting.rb
+++ b/app/models/laboratory_setting.rb
@@ -43,7 +43,7 @@ class LaboratorySetting < ApplicationRecord
navbar: [
{ 'name' => '实践课程', 'link' => '/paths', 'hidden' => false },
{ 'name' => '翻转课堂', 'link' => '/courses', 'hidden' => false },
- { 'name' => '实现项目', 'link' => '/shixuns', 'hidden' => false },
+ { 'name' => '实训项目', 'link' => '/shixuns', 'hidden' => false },
{ 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false },
{ 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false },
{ 'name' => '交流问答', 'link' => '/forums', 'hidden' => false },
From acd5c28bb136eef547cef472b7c08ae6bfada3c5 Mon Sep 17 00:00:00 2001
From: cxt <853663049@qq.com>
Date: Sat, 19 Oct 2019 16:28:17 +0800
Subject: [PATCH 05/33] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../admins/competitions_controller.rb | 1 +
app/helpers/application_helper.rb | 8 ++++++++
app/models/module_setting.rb | 2 ++
.../admins/competition_settings/show.html.erb | 7 +++++++
app/views/admins/competitions/index.html.erb | 19 +++++++++++++++++++
.../admins/competitions/shared/_td.html.erb | 2 +-
.../20191019075105_create_module_settings.rb | 12 ++++++++++++
spec/models/module_setting_spec.rb | 5 +++++
8 files changed, 55 insertions(+), 1 deletion(-)
create mode 100644 app/models/module_setting.rb
create mode 100644 db/migrate/20191019075105_create_module_settings.rb
create mode 100644 spec/models/module_setting_spec.rb
diff --git a/app/controllers/admins/competitions_controller.rb b/app/controllers/admins/competitions_controller.rb
index 3b9b63243..f501564ab 100644
--- a/app/controllers/admins/competitions_controller.rb
+++ b/app/controllers/admins/competitions_controller.rb
@@ -11,6 +11,7 @@ class Admins::CompetitionsController < Admins::BaseController
ids = @competitions.map(&:id)
@member_count_map = TeamMember.where(competition_id: ids).group(:competition_id).count
+ @competition_hot = ModuleSetting.exists?(module_type: "Competition", property: "hot")
respond_to do |format|
format.js
format.html
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index dbdcaea40..1d684350c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -142,6 +142,14 @@ module ApplicationHelper
end
end
+ # 主页banner图
+ def banner_img(source_type)
+ if File.exist?(disk_filename(source_type, "banner"))
+ ctime = File.ctime(disk_filename(source_type, "banner")).to_i
+ File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}"
+ end
+ end
+
def disk_filename(source_type,source_id,image_file=nil)
File.join(storage_path, "#{source_type}", "#{source_id}")
end
diff --git a/app/models/module_setting.rb b/app/models/module_setting.rb
new file mode 100644
index 000000000..36fc45e6f
--- /dev/null
+++ b/app/models/module_setting.rb
@@ -0,0 +1,2 @@
+class ModuleSetting < ApplicationRecord
+end
diff --git a/app/views/admins/competition_settings/show.html.erb b/app/views/admins/competition_settings/show.html.erb
index 8249f2737..6272687e4 100644
--- a/app/views/admins/competition_settings/show.html.erb
+++ b/app/views/admins/competition_settings/show.html.erb
@@ -5,5 +5,12 @@
end
%>
+
diff --git a/app/views/admins/competitions/index.html.erb b/app/views/admins/competitions/index.html.erb
index b97e26f94..736f0514e 100644
--- a/app/views/admins/competitions/index.html.erb
+++ b/app/views/admins/competitions/index.html.erb
@@ -2,6 +2,25 @@
<% 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' } %>
+
+
+
+
+
+
+
+
<%= render partial: 'admins/competitions/shared/list', locals: { competitions: @competitions } %>
diff --git a/app/views/admins/competitions/shared/_td.html.erb b/app/views/admins/competitions/shared/_td.html.erb
index d05974c86..09dcf48b3 100644
--- a/app/views/admins/competitions/shared/_td.html.erb
+++ b/app/views/admins/competitions/shared/_td.html.erb
@@ -7,7 +7,7 @@
<%= @member_count_map&.fetch(competition.id, 0) || competition.team_members.count %> |
<%= competition.teacher_staff_num %> |
<%= competition.member_staff_num %> |
-
+ |
<% imageExists = File.exist?(disk_filename("Competition", competition.id)) %>
<% imageUrl = imageExists ? '/' + url_to_avatar(competition) + "?#{Time.now.to_i}" : '' %>
<%= image_tag(imageUrl, width: 60, height: 40, class: "preview-image competition-image-#{competition.id}", data: { toggle: 'tooltip', title: '点击预览' }, style: imageExists ? '' : 'display:none') %>
diff --git a/db/migrate/20191019075105_create_module_settings.rb b/db/migrate/20191019075105_create_module_settings.rb
new file mode 100644
index 000000000..85e3ddb9f
--- /dev/null
+++ b/db/migrate/20191019075105_create_module_settings.rb
@@ -0,0 +1,12 @@
+class CreateModuleSettings < ActiveRecord::Migration[5.2]
+ def change
+ create_table :module_settings do |t|
+ t.string :module_type
+ t.string :property
+
+ t.timestamps
+ end
+
+ add_index :module_settings, :module_type
+ end
+end
diff --git a/spec/models/module_setting_spec.rb b/spec/models/module_setting_spec.rb
new file mode 100644
index 000000000..ede893338
--- /dev/null
+++ b/spec/models/module_setting_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe ModuleSetting, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
From 7ac6dd7e586a32029d5fe804b7379c055d7d3b96 Mon Sep 17 00:00:00 2001
From: cxt <853663049@qq.com>
Date: Sat, 19 Oct 2019 16:29:42 +0800
Subject: [PATCH 06/33] =?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/20191019082903_change_column_competition_stage.rb | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 db/migrate/20191019082903_change_column_competition_stage.rb
diff --git a/db/migrate/20191019082903_change_column_competition_stage.rb b/db/migrate/20191019082903_change_column_competition_stage.rb
new file mode 100644
index 000000000..a9942ec08
--- /dev/null
+++ b/db/migrate/20191019082903_change_column_competition_stage.rb
@@ -0,0 +1,5 @@
+class ChangeColumnCompetitionStage < ActiveRecord::Migration[5.2]
+ def change
+ rename_column :competition_stages, :rate, :score_rate
+ end
+end
From 14958006b84ce60798b9a25bd0553f7ecaa6e711 Mon Sep 17 00:00:00 2001
From: cxt <853663049@qq.com>
Date: Sat, 19 Oct 2019 16:41:48 +0800
Subject: [PATCH 07/33] =?UTF-8?q?=E7=AB=9E=E8=B5=9Bapi=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/competitions/competitions_controller.rb | 2 +-
app/helpers/competitions_helper.rb | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/controllers/competitions/competitions_controller.rb b/app/controllers/competitions/competitions_controller.rb
index 03a276952..a17564737 100644
--- a/app/controllers/competitions/competitions_controller.rb
+++ b/app/controllers/competitions/competitions_controller.rb
@@ -160,7 +160,7 @@ class Competitions::CompetitionsController < Competitions::BaseController
@competition_head_cells = %w(序号 战队名 指导老师 队员 学校)
end
- statistic_stages = competition.competition_stages.where("rate > 0")
+ statistic_stages = competition.competition_stages.where("score_rate > 0")
statistic_stages.each do |stage|
@competition_head_cells += ["#{stage.name}得分", "#{stage.name}用时"]
end
diff --git a/app/helpers/competitions_helper.rb b/app/helpers/competitions_helper.rb
index 66c7eec41..9e3e7f62a 100644
--- a/app/helpers/competitions_helper.rb
+++ b/app/helpers/competitions_helper.rb
@@ -44,7 +44,7 @@ module CompetitionsHelper
statistic_stages.each do |stage|
if stage.max_end_time && stage.max_end_time < Time.now
- stages << {id: stage.id, name: "#{stage.name}排行榜", rate: stage.rate, start_time: stage.min_start_time, end_time: stage.max_end_time}
+ stages << {id: stage.id, name: "#{stage.name}排行榜", rate: stage.score_rate, start_time: stage.min_start_time, end_time: stage.max_end_time}
end
end
From 9f351aa8b08ccfa96fb5f5cea56299fae5e07a97 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Sat, 19 Oct 2019 20:14:21 +0800
Subject: [PATCH 08/33] =?UTF-8?q?vnc=E6=A8=A1=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/games_controller.rb | 2 +-
app/views/games/show.json.jbuilder | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb
index 8a3999410..2441037b0 100644
--- a/app/controllers/games_controller.rb
+++ b/app/controllers/games_controller.rb
@@ -60,7 +60,7 @@ class GamesController < ApplicationController
praise_count: praise_count, user_praise: user_praise, time_limit: time_limit,
tomcat_url: edu_setting('cloud_tomcat_php'), is_teacher: is_teacher,
myshixun_manager: myshixun_manager, git_url: (@shixun.vnc ? repo_url(@myshixun.repo_path) : "")}
- if @shixun.vnc
+ if @shixun.vnc && @st == 0
get_vnc_link(@game)
end
diff --git a/app/views/games/show.json.jbuilder b/app/views/games/show.json.jbuilder
index 048188746..7c9d1f22a 100644
--- a/app/views/games/show.json.jbuilder
+++ b/app/views/games/show.json.jbuilder
@@ -1,7 +1,7 @@
json.(@base_date, :st, :discusses_count, :game_count, :record_onsume_time, :prev_game, :next_game, :praise_count,
:user_praise, :time_limit, :tomcat_url, :is_teacher, :myshixun_manager, :game, :challenge,
:shixun, :myshixun, :git_url)
-if @shixun.vnc
+if @shixun.vnc && @st == 0
json.vnc_url @vnc_url
json.vnc_evaluate @vnc_evaluate
end
From 509c081a155612aff571180e3cb9e9e2d1a9df82 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Sat, 19 Oct 2019 23:14:22 +0800
Subject: [PATCH 09/33] =?UTF-8?q?=E9=80=89=E6=8B=A9=E9=A2=98=E4=B9=9F?=
=?UTF-8?q?=E5=8F=AF=E4=BB=A5=E4=B8=8D=E6=98=BE=E7=A4=BA=E7=AD=94=E6=A1=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/games_controller.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb
index 5a86fa06e..8c777a214 100644
--- a/app/controllers/games_controller.rb
+++ b/app/controllers/games_controller.rb
@@ -881,7 +881,7 @@ class GamesController < ApplicationController
end
# actual_output为空表示暂时没有评测答题,不允许查看
actual_output = output.try(:actual_output).try(:strip)
- #has_answer << choose.answer if choose.answer.present?
+ has_answer << choose.answer if choose.answer.present?
# 标准答案处理,错误的不让用户查看,用-1替代
standard_answer = (actual_output.blank? || !output.try(:result)) ? -1 : choose.standard_answer
result = output.try(:result)
@@ -892,7 +892,7 @@ class GamesController < ApplicationController
@chooses << sin_choose
test_sets << sin_test_set
end
- @has_answer = true # 选择题永远都有答案
+ @has_answer = has_answer.presence
@choose_test_cases = {:had_submmit => had_submmit, :challenge_chooses_count => challenge_chooses_count,
:choose_correct_num => choose_correct_num, :test_sets => test_sets}
end
From 4bc32cb9e98df675f31e9078b92143c682476dff Mon Sep 17 00:00:00 2001
From: hjm <63528605@qq.com>
Date: Mon, 21 Oct 2019 08:58:03 +0800
Subject: [PATCH 10/33] vnc
---
public/react/src/context/TPIContextProvider.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/public/react/src/context/TPIContextProvider.js b/public/react/src/context/TPIContextProvider.js
index ee01c3c72..bcd470134 100644
--- a/public/react/src/context/TPIContextProvider.js
+++ b/public/react/src/context/TPIContextProvider.js
@@ -435,6 +435,9 @@ pop_box_new(htmlvalue, 480, 182);
// TODO 测试
// resData.power = 0;
+ resData.shixun.vnc = !!resData.vnc_url
+ resData.shixun.vnc_evaluate = resData.vnc_evaluate
+
this.setState({
...resData,
From f98b88df106aba42c12c24a9ac944fe9bbae4eb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Mon, 21 Oct 2019 09:44:06 +0800
Subject: [PATCH 11/33] =?UTF-8?q?=E3=80=90=E5=AE=9E=E8=AE=AD=E9=A1=B9?=
=?UTF-8?q?=E7=9B=AE=E3=80=91=E9=80=89=E6=8B=A9=E9=A2=98=E5=AE=9E=E8=AE=AD?=
=?UTF-8?q?=E5=A6=82=E6=9E=9C=E7=94=A8=E6=88=B7=E4=B8=8D=E5=86=99=E7=AD=94?=
=?UTF-8?q?=E6=A1=88=EF=BC=8C=E4=B8=8D=E7=94=A8=E4=BC=A0=E5=8F=82=E6=95=B0?=
=?UTF-8?q?=E5=88=B0=E6=A0=87=E5=87=86=E7=AD=94=E6=A1=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/modules/tpm/challengesnew/TPMquestion.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/react/src/modules/tpm/challengesnew/TPMquestion.js b/public/react/src/modules/tpm/challengesnew/TPMquestion.js
index 8fc2b1133..b76e17b17 100644
--- a/public/react/src/modules/tpm/challengesnew/TPMquestion.js
+++ b/public/react/src/modules/tpm/challengesnew/TPMquestion.js
@@ -698,7 +698,7 @@ export default class TPMquestion extends Component {
let newnewanswerMDvalue = this.editanswersRef.current.getValue().trim();
console.log(newnewanswerMDvalue)
if(newnewanswerMDvalue===""||newnewanswerMDvalue===" "){
- newnewanswerMDvalue=newlist
+ newnewanswerMDvalue=undefined
}
url="/shixuns/" + id + "/challenges/" + challenge_id + "/update_choose_question.json?choose_id="+challenge_choose_id;
@@ -747,7 +747,7 @@ export default class TPMquestion extends Component {
let newnewanswerMDvalue = this.newquestioMDMdCont.current.getValue().trim();
if(newnewanswerMDvalue===""||newnewanswerMDvalue===" "){
- newnewanswerMDvalue=newlist
+ newnewanswerMDvalue=undefined
}
url="/shixuns/" + id + "/challenges/" + challenge_id + "/create_choose_question.json";
axios.post(url, {
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 12/33] =?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 13/33] =?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 14/33] 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 %>
+
+
+
+
+ <%= 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 @@
+
+
+
+ 姓名 |
+ 单位部门 |
+ <%= 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) %> |
+
+
+
+ <% if users.present? %>
+ <% users.each do |user| %>
+
+
+ <%= 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) %> |
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= 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 15/33] 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
zcmV;PEn(7y)jFcqItL$%2mo(Kt$_!H2LXi#0)+rv)&p_mXxXz
zNJ@>AGB$n^(eFP`csT=2^345}Or|rq#
zh?%%ewXedh#RvYNEZ7Tu&1A9Ko#Y|n#rN#ZKNGWjrz&Ly1WW4
zIo|N>nXOMh2LTDrvCXR+Tc2%s&Y-x?u6j^hLus$;IfJ+}yo})CB7Yx`ssLB=C?Cz^y|8VREII3JRhQV`MK*s+d}#)%X0KnZ!jvs3lESuR
zZc}D=^!l02Z_bTQpB=t*UY|q)oQYyf4$jO2_~S!=49>6pcC8t7RW*=3JIw%ZV@bMJ
z3m{|yeHm!Ka@p7|HAczUim(~+B6=3@1v{U-xpU!f!!O?0y0~Ff8nZFika*b64BLQQ
zkjY%>2>>;+HmIzVvPr9oKgTuo^FY>C<^Pa$+l&0D4@4;kJOhH|EZ9b{d~W5+
z=;b#@FMs1Cw;QfP*uEd6f?onEuoy8$L9^&oBEP#DMDRl|?02gm!S)&}u=iHAU4|%%
zV>@Whr)(o2?4TQoY7z>mi>Hm}?Zy^iWMkWZArBupI?)Efae{oiBnAw^Qyp&U>`Oel
z2{(;h&T;J9p&bG%4E*Yv(o{0hs_4MY(%1mF6v2FXEowD+C76^0IswmTP;lHqH|S}Q
zaVc>au#8Xy^x5l#F!uj(}I6r*v!|$(u
zzl+OW!B%mhlTJ&!jXqXjXAuo%6LuXY71V=OXW
zCMOC`L?y9gvR=2}44{f4A-5BDBOmUGEm-Pf?C)ilR-h_uJT`4qsslmsYEl>jonLD6
zhf9oi-||Y2F9?+{g5!8Al3fA)2hlGZ&EPjENh2u~EK5;tv{p-Xs3iq%A~Ga@E3=9?
zrk*D@uqRA4Z=Tw`_LU@pblk}mroYl^M2Y)LJX3V}Mel53K6aGSFnrn21%Bgm`RmnXN$&ewb{X
z7@T_;ICj5sU~j~uFjsFbMN-~>Idulu#^%+RHm`rkM{eUE3k%(#)AXwW-vbpm9%J#D
zGLe1?TwZ{)k&rrpA?MHv1Xj&~
z{{d4jNB6o_k0VuvVX6t7USY?^)D7y;C*{6;%0N16h3yhAri_>E0MaUdMVGO^E_gDn
zn&8QLFOn(8F#JxZ38xlgD|T3XnMIrI~==Mf#owD_5D5)0s&M_&T@v2x4020WL*Qcn?8$Zj(*C3lVF9!XG+
z>dta!RhLZyg>o@+=j>IxjZWmzQg-Eqzswd(0u8uwHeh5=1%-K41+FNyupJaqGz)aj
zxtWL2jHXkt3R;7I=?nvQ(?Hnj1i&Sr+F0wr?g%x6hco#}9A;9qQTUZuah6;oP^4h8
z}8g1Blh4?-|WJG=G_=>T$nvE4F3_C&BNB!5>rJCFT6NV`4Wtd-J-lny_
z0Pwu$EkPxgVp;Q8^@w;_jU}_NQ_wkHi2I(2PFJ#!-Bsp)-a^)gpM>^PBbZxOz4;T-
zDoP$ERfTABZ}@FEBygE#s9_`+9h?j!*lnrE985*#U`}N2m<*Yq)=x#|j#OmsxCy#f
zwaaFpekH(ewgwh(slb{{rhNTT=uIcMyA$5sT0NS)O^dIdi4xIgQmu@d^VJHnq2>6}
zBmnJcb@#M?x<9y97v#*=D%I(lQgE6sx7-PPQ6WWwHJdSeY+_(^=frr#dSQyluIhtR
z?macX(L5=<9ZTpL(db2u>ewp~PGWEZty3kRbzod;QYclNA_cc>@3+*1f7rR-FpPELoWO#ewN5Q2|dFh0Tk0N(Dj?K2X4*pt*wM`v&?gE9i2PP<%O+3UK*YL
zdQJ)V?P%@rn%_m$Kv2aWdgVqN2AeAJuqGw$GQ!+s<6}z!gGG!U?lAl%9YnC;QKLf-
zV?0ZLmmC+*VOPo0QMa+Wic*n>n}f*lJWe5EMeEhY0V!JXt52+U!+yJVIBcRM?sZpJ
z{K8_9{a5~%d6-d{h3)5F8NG8QZq)(71wF@|WBQ&9-~RUR+h4!0Wcw3Q
z*FW6r9fcnN@Je{1)LZjwi25S@cSq-h!#X>Ec;}r(NBy-}{`ve}tlQDoAi;mQ^Y)j+
zZ@!43`X?H_N5V#%4QCyZ8@_*b^x>)PZ@wJ8a%$`1#_*j>DDKOT+n;_ieDyURNJFF<
zA@OsBJOs0I?d|Q$7tuHIy)U;mzC#$VUIAVXU+~s|j%A+nblfB<0LfWJ?OV`;!{Atd
zT!+e0-1E=dzWm+JTbD=ge>~bat10&cW}QZ$eeU|T20CGRci#Emyrkmq*m44)W$oOg
zGzR1&LNermy&tJnv2C?Q7Favs=u|KF>iL`Q+`y-
zb4vf1>;biu#%Kmq^xyvOwau%~4KIFwwteOIqrbg8`p*laH$Inzj6VWT>%(b3*>0At
zO1Mz-$|RscOAH?>Bz83WX4}-Fz`CzRS<2QHrIYV&(Qy0*7Zqo}#|7XU-sS?%taiEp
zH&DL}$W))W7tlpKMQ2qYfYq>j(!f1Ac-?RIgusPcR)cZUfPr*>6nI*d
zc;l?cAd0d&!@B684dzI665~nN2hLzwHXfu>Xp$K~opgR6TaRS}4C5TTfy^FZ0Zh==
z25%WYVHV3|Vd7z=;bCDJ@e~ba7Uxh4I?x#p2ietgELC(}epFfsyuB8&h2Y$n`55LSGDim-$c@|QAW#1GeXMDKP=2TUITSfxh25!CMI)`vL7!uo)Z
zJ~rhU2+?*4#9%2N<<D8$M$Ss$)EaPi_D=@2xs>q^#PTu|
z37eoJIx~nDO@w9=Dzj3M8b6@K?kFo^81+EF>-?PDIGDC(Eo|0*n9yn8EyU`?qo)}m
z|5o^A9WYHy0zq<>4O$)4y7GYLC9+je1fJKnE=Hx{*K(tV#xnV%Bt9{3>@(8TUD~c!
zWk?-X!==Q9&lXG2puFr68yy*rVp&Gh>Ms2;_mL`IQPmzll0+~bpgt0Ut=P9qbOX=n
z?i+#{4O5~tBz78q3t~AI;Gn34OkOK%mccZOp^!v>^?))jrq}|>)FerlZ(T{Wccs`D
zTDP8eP#%9D)B2iaf1T3N$2RL`5QsHI^YnWlJK1Bh;t4lggS09j-XCqWg0LSI(mIZn
ze9f@RQsJO^1q5o-#RZt`or{b5zMvxP+2vLpc;daR|6fU9B~%Vgy_n@D{<2fG6_hD
zpcW~ZI5TTFXA8sJk6ADS1CI&pjgwjYDAI=6j|`gncqGTk7(e|=+=1x)=8){{^<%|x
z`YE0`!$sDAlTV)IWQy6DB#jO~eSLUV9qFw;>aI|~Ks~QBk9lN4&>*6We#Fw(t2q`%SIK
z?$~tG83_^`ZD-@vLp7zpr1`T>DLAD02rC7i(nT>xLJdo_!V=EPk+j$t)*Ym5;JiTS
zYFO68Fk$^S*4XM{JOi&{iyAJdmL!?y(!;TwIPt0LmbLcn;7Oj`MxA7`u!2VSib%E*
z0}Db~HAh*5f`=>NvJJ|TEV3*{@$j$~Am!TC8w|k;u4?(cE(HvTQ19AhKqhx+GDT
z>B98d64CTVF_xCrl~!-n-UA-cS6RwL>ffPcq+0erpE+ks$+uDxV>fLdIW1d5IgbBq!q(~eO>Zs~wa
z4yfcl6#b$q)7XD95f$L
zUQFAX8Yzw6qjqOxm+24`sNMp)dT5}Da)q5=E=SX)Zs3fKu;YydE;jgeaRJ3Y*CH6Y
zMnU2V>?AY~(~(RvAY%%mG3m~}i}|!OJ0PqjQhN>uckW4+P8rNpgN*w&eh5`G1Wnqo
zaJ?+2UK>aZQH$N{3@^NjSZ9ChA{^>XiH8xbRR%&p6|BoKjWNoIrx5hT0vL;9
z=+q#qCEB%}GKD?YygA&@?<9KJt`TICmS(`kX2r+K8XwDqoA-ENS1dzknsx@ty6OAo
zMnug5OMb|u%+;=6>oXRG&Ut9@*WAloP1=+$fuc2wprq26Az?{?(zwWWbB2U}r8bp?
zflC2RlW10R%Veu#>5cTtC|#}SFgw+E0JVXb2BZtdcdhCh84>q
z;&;;rbT(ItwV>H4RReTRNzLM^)tNMpCuzK!xk!O?v|-zxEMW#u{E;8BlejDVvKvYt
z;S^{|w*}HvT-dqlN+|hwx-k`hJB&QP(OxxO5Lk0VSD-u`N|C>kKRD3vOHhbW<)iRc
zwFWg$I3j*d1U1dZZPESf*zui&mP`ewd4E+62RjC)qQH2R4>iNp
zkO!r6>lZQ2_l@0bmc4Y@Zhu|I#@T~8L~Ij&Pee8Gm^GMx9TBy*zp
z8GwKKCmz*=NR^ogvlcW~*CLk8sF-HA8(us$x^Q~)y9=XduXyAP
z+&xb}R__tShCxxrRs3EIIB?B+R1hEI)hxp#^XcXq#S(g|cief6xg{F0&~x4mT^uu6
zt87QBr`zKaevAA>syCSPd9Jim?5sS}h=O#V#>pKS^}t7e^706?rr-&Pd_;7tR5t}C
zJjzul8aB~5bul(VF7R)Kdk+0udHs&!!8`99?4Lj8m!7(}^uHEM|GIpvq<&ssEdKMs
zLE(RwGt1|1-yd@mAs{eT#NCKMN|2=S^wWhHiEetG>=}H2WaaGX(SN=1{q<*Eoz$oI1|oImlSw-)IVQ&V5~-{Q&QZT_-Vif4xF}Y(DRHK^{qhP+6M~sSO$Xbj-Vw{ZG
z)319m3VSgMdoc<>T#Q0u6I*xav@r@A^jjuIVf@owgtfB#SwEH#g=S-=>jP6}j;_I!
z?l&foJ-3_Pal5&3Pnw(Q95YjUeanA5?3U1flLfO-<@Fp}2~Wsi5)qnWfs+hS5ic;x
zrn;YdHEcHhPA_0)_6!I2O5G>Ui^B2LrBMc0g_tJmJ|>|LqEZ*lu$py})ueWeL}g_@
zQAKc>XsZql!(|3Y-p&S5bT&g4m8riK7Yr)NbB4qY!TX|iQr$|_^YL>@t(1q7$VEAS
z?adN$vbOBckyvbT3cqr{y@CxA`6bQg(I4a^Wye7Q;T4^#-)v%5wI5`jQc%XXO$8b(
z4n|q_;Pe*C$hZPyWO7uJj}gF>lgESO6EZh`e(^7ks&?DP$-^NGX2oY%-tSU3=!Ct7
zu&kuG-P)?=@(YSnt#U&H1J8lo6a#^O%lodx13Ae&gesFfX_z9))=9o*b>pO7ko$Cf
z(z+9rJ6(3~yg#V>a2)_b+$B-Swtkss%FMgwa_Tq&leGwKW!A&M(Xo|;U27sj&ZQUxZ^FHg0McQo`XH-Xu7iMqsT}VGL^2ZDa?<2r#6RADd@-g;
zOhx!mA0_FYaRY~*SSrS#*;HCst^#mtoV4O799;Ew^jNzAo9gG7DsuDMpSC`HcI*0Q
z+uyynd39s+>NA^H{|xfx*1Nyo{`&o`Pp-`omGXUEU}QmLAmI0-@X??SSK&3ipx5%d
z(QjCfqF`ZR^v=fibKi{4e6)Rk;T2g8Gb`T9a-sef2C2h()rHbT77j;>;>E8@P^;#I>JCA&irU@b0wr&fE
zN$lKOb8U;qu0`st3Hzl>IC1}uc~_;U85G3OX4}?XCcfW##&7kox`0T3DPDk^zZu(;ozIC>ofB?QJCF&ss0l!S!sQ2K=Oh6U_a5}7
zdNI|eY^I>s!d?Vd@P0dgGCQa>RvYrX9eYOH0y{L-W}3M{4KKnO?$BM@WSQjOXt5V5
zU_HBd&LmQaW!}{DY!7P(iGwWp=np;4m}mVui3b;6-R#F|6L}dwrCe9N1H=lsCZ#Z+
zb~>cm-%=C|IUis*o6$#EF{_K
zBrrT>eDNf(MrG3tZ{Rl
z&|J~kNIdc*^i#hEgz$~$U(_1M?;c*cK79V;t!uB3J~;RN^>?{%g&RNj!`(FS8JE%f
z7cgx;dtA>I#dW`b5wi(iqUPP&oKd81Kje77h|r7Isp5fn$YsB{cmD#e
zjD9Wth`*GYObH4_T`azvM_m450e-|^IimatK>l$7D=x6MPy_GecYDM=M4<_b_<-hu
zpYWkd;*2=d?nV<9vnw*Uj@zMNA*$&mG9)i9M6^6z-b$Z;n+1+H{EPE)x0gaKq}^_d
z$>ex7Hl}gJa?J}ymdZT*>rBkSAj-e~X?X4ur^Ir(?CFy*TUR9&g37S1@N-IJK
zT}^wG;D!Z%v;^=JPkQ12m2xJ=zM{qx1tCZ}jrRSvbgwCpc#BFR*{d~sY>JCN8PQF2
z^VfzjJ6Hc)V3m-;lMd%`^xyNi|0#If-=Ew(>cCNnLanb-2$!Ou)rn5hIL1VcS-vVD
z2-x(fBe?#^UGWK{yiMEuH`6aaYt@tfptFc3;%>2j&Ln=Zq^dl~45wK6*{Vb$^>n9s
z{a9p+Ait>TNjdshZF}x;M8k+NR=pP;^(tn@Q}84r0xufzu=O;*>ERMta`I8BNtq%&HS93a(6eV_{PKlNh8Mb-Y^6JUhN@~OPo|>
zDX$gCm@*3zaFMhn76C&1*r-y(4YU|zKa|+VJc_s{9ej
ze%ef_oq9(a%uRGZ`YA;8-oj2MyC7Im1LrKIDhij2R79N`_Pf;}MWWL5sjOmBisIjY
zalP__U|E-!JqzLPN&u=Hp?S|1pFK-uk&rN19SgKuH=R9x>lR;#qrW~uq!vqGNFrIM
zH`34L1E3kyr!bu>yQ$^`kvnsooOx6hAA!Yc
zug3hJu;06O+e*p^^BzB!ugc2aA9iZu2*#u!CMyc_tIUJ~7T!km#uIr3A|U06aX
zU~%h!089Beo8Hp
z(uFi&d#4c@k>70QJcn4#pLVW=6snaeOQCm=b{f@O^s1+bEx2V9iV~e1N=@{CJ<-)}
z_#{GjjOm;dM6rBW%qdW)py(r1UB4G)w3St~_H$GUrdkftJoyeKR%Ut*d;m%zA!s-k
z2vJuDAW`Ju`ib`CcnEO(o3obIhE17KU&4XwP(U*Qo2@<7V@*D{ns}uGI~Wg$p^*e4
z%`;r27+(4N=*k~QZ+$#Ecb=<%>PHt|P#)(2x;FrbTocS{SFlHYj$s4kh5>ag5JEW7
zyZ23m3~N$JLy46>Facg1oQ_>QlW%@L{OAKdpJ_A6=w+e-V2f1zv2YUf8L$-WIURiQ
z#@5A+;ptPOGaoH!wDJF*d6o{4hdisk=!s=)mlO$^Y&nvL#b-g+E^0-8q+lrJ1g>Da
zU$BdUD*>pKC|o_mLoszbTPmjUCQZRoZ1CwY#Kz;Wi|7CBxveih8ol!3&i@%Rxq^YG
zAq~^g3!4GHMgvD0>(k4F!+w%5TR%6OPQ+~?&)C=@85gI2sWkV+!Mq?76!Zn2(-m~uMoapWX=j?!gesDC?nxY+OY{g%
zf9W)7rV)nAR2z-D!noY*;~IjuE!3QgzP4%NuC(Up_R-OinPZAo&Ea+U{H2}eE^S`j
z*!pZ^^wwA3Uw>ui+%sqxW~>K4G6u7A;cui%{RAR2>Y_U@Jz0!@GIe)No*gEbF;y(y
z#!78$cpF>s-IsyyzWn&^8;|e4N$^eT$0)qa8M7eIfToF9iED&aqKmI9s#+7+#jgZ3)@jCVhK_a2IOK4%
zro=K#cac{7UhpvUnMR%FI!P;3ZH7HFArNrL
zK3Cd3wN^U(P^={6c@E+8N%&K0wMw;`%0M6aUAFvCd~or9z`v9he_mQVpj-s`5dnpz
z12vEO8p6zSX$
zx3aiB*6V<*8gvU`Tq{{E(T%4yrIIF&({5L{K~%U>cpheCl2Z=A0#>Nlk}e8a=U2N+
z^QY|a$1W3ph6SXwhSRiR6r0i840WXzv+hBWZjT8Mgvz3P3##1+9
ze6@kvv%2o(7vAms!h-JN2Y$y8Z!?G-+hb~O*#s1S)2mQm-#k*0+%Zj%bMnClBLwN(H@W>dY}dz-)^oe7}^KX@s@2qlZ0@Ey8;AQ9
zEcq#pN(z0+oT6}bwP}}W30NSFY@u=iAMzWhA5#+$joEhM`bo_>G$>C3}c-lU8|z6bFS
z{;F=>bc6BA%#M~T6iYiVP>F6mPqTKHs7v%QYgB{pSi;(J>vCo)TCwLI)1EZpg?V1d
zfgK-NvWIc^fxY8t?|8BuPqRLMl}6`3-oEnD-l>%50eAKqW}XwtaaIGewOL%ItXNFR
z-gWSYKhv@k86Hf_WGE+wd@J|cy|qR?DqxfjGpBn+@%*kgI`?PJuUO0qJ40W+vU&9k
ze5AX6pN$=&C)0j=0@65ZBHVufCca^`@xu0V-wZFFAHMg&@WNksp2PTm{Ua-{74BGM
zbJ=>D%?8_f=c9#0?nT=MTm0#!W|W)kmPyMNggb^R};##p`)T4baXN}0&e)g5ktM6I{qhwZm)D7SX>OUqB
zAP=D(cb6PD3Vhs9%B1DEZTvoZJ|A0;OGkfzQUOH#Iw*?b;fq&{8tO}2
zY5Vg3Wj%-*;#URZrO%*+0>FPAESs5@%mMYHK8`#wARzLsKb}v23}`Go8bq4_x_R|=
zScc7wjp3jEk~UYH*Pn$tTbD0voqb{ZndjpXncw4)^P?x(!2GTn{N?SfjZcSPf4p_+
zWjdwicQv<(sPb4x*h~EEqy#Ic688>!a1Hj_aoZ*`
zp~EJMg6dkk0i3aa1O?3?xt}C@NzCkdYxFpFVjSnkvLHA!g@7H6(vu*9bnJ><%xHsp
z^VM$H@07U+%VG1QHAfOxcT;9_2s!e)DJudyC6|RI(p;!nBnWV5z#?yn1o;
zpBIK#UfBBZSstJV694AaXSPp$>87T$+?^*cr?&N`YJM`T5GoJ~w!{%Gh&;ps{q6qt
zDh+`7GL4y>AYQ6TH6^d
zJcoI!EWNq3=F*#_k+t;P{a}iv=MBd$J+C&=o~KQJGIxC{`J_R}Lq1yD9}oFx!?N&>
zT_UfaC9c5T;7Pw*b5^^4Ef9&Qe`dW2vvuXQe}$DFB$-5o{~)7NUZunUW;`NmLb9X|
zO@g~=Ps+0H^S&Z$fBv;NVfydH1np)faB@o9^MI$VS6bqGCbTw`TMqBQNI4LX{dl9-
z0L=1#jJ`eQmC_0EWDCo%tb=&jvxfX8kKqzTx*flFH7pj5hrQb%ZV=3R)%od~l*#nJ=)&`=+InWF=-F396eu38tx4
zPa|lJdeV}QO_20b>44dLlUz48N4&bx!S^wLn4|}@Ur=VVn&kVcy$mZcAf~>U%m9kq
z(R0GRTW^`~0b|?az;+xmo(Xo+@SfmBvgBd
zu{#N7wcK*kB`Ird{V;?-$hj&XqeQYj&
z{oW(UDS5^kHA^eVeEG$fCUYX09dkH
zPpow%`N5B{^3kKgfAnE<{u&No6lVWt>F|+9e_1*jJ`uE8%$o=7+ZQ-jd);~|!Xkz@
z4+4!ZVq`DP5q*}h{~mN!o8b!FPMDp4Yc(zgyz6c030AIgGgA*SgDr^OU`V3G9SnDB
zdJCD%1{?8gHi*s9cq?PAN4nuEaGKtIe)s;M>7OhdWDhycNt2N
zr}dBN?N6o7Afp#FgHzqoFxy=
z%m%hT&2ZMH1C8REN9Kd&qAYt*VXsF-ForV=={f9
z=UyIO{1krWAR4VzW>;(kPx8QHXdEx`@8By1!lupfn?W}ky?S=*;>PI03)`puJbdZW
z@cIARdF!unps%=^vYJ$vz&_Z2;(Rlo104r&30APce-tXpdE65CJMz}Br&6XA8EM41
zJa3>=t-ti{?v&lxBd1+LB%Di>s_0haCWCBqkqc3!#NPHXSP56Wccc9cwhYZ)aaQ%E8J6N
o(~?wR%!I}*2-;a)aQQ8N2eQ5a9td0~T>SX|0e|%_KhzgP09_c(w*UYD
delta 11520
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
Date: Mon, 21 Oct 2019 14:08:49 +0800
Subject: [PATCH 16/33] =?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 436628e6376fad5ab735527114e5fefe45f4f149 Mon Sep 17 00:00:00 2001
From: p31729568
Date: Mon, 21 Oct 2019 14:57:02 +0800
Subject: [PATCH 17/33] 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 18/33] 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 cb8dd3dc9f961eaa1080b5bbc348305ff02cb887 Mon Sep 17 00:00:00 2001
From: p31729568
Date: Mon, 21 Oct 2019 15:55:58 +0800
Subject: [PATCH 19/33] 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 20/33] 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 21/33] 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<
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
LS>FeMeHlXlKV!2t
delta 11530
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 |