commit
7297309b4d
@ -0,0 +1,14 @@
|
||||
class Admins::ImportCompetitionScoresController < Admins::BaseController
|
||||
def create
|
||||
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
|
||||
|
||||
result = Admins::ImportCompetitionScoreService.call(params[:file].to_io, current_competition)
|
||||
render_ok(result)
|
||||
rescue Admins::ImportCompetitionScoreService::Error => ex
|
||||
render_error(ex)
|
||||
end
|
||||
|
||||
def current_competition
|
||||
competition = Competition.find_by!(id: params[:competition_id])
|
||||
end
|
||||
end
|
@ -1,4 +1,6 @@
|
||||
class Competitions::CompetitionStaffsController < Competitions::BaseController
|
||||
skip_before_action :require_login
|
||||
|
||||
def show
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,20 @@
|
||||
class Admins::ImportCompetitionScoreExcel < BaseImportXlsx
|
||||
Data = Struct.new(:competition_team_id, :score)
|
||||
|
||||
def read_each(&block)
|
||||
sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
|
||||
data = row.map(&method(:cell_value))[0..1]
|
||||
block.call Data.new(*data)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_sheet_valid!
|
||||
raise_import_error('请按照模板格式导入') if sheet.row(1).size != 2
|
||||
end
|
||||
|
||||
def cell_value(obj)
|
||||
obj&.cell_value&.to_s&.strip
|
||||
end
|
||||
end
|
@ -0,0 +1,2 @@
|
||||
class CompetitionCourseCourseRecord < CompetitionCourseRecord
|
||||
end
|
@ -0,0 +1,6 @@
|
||||
class CompetitionCourseRecord < ApplicationRecord
|
||||
belongs_to :competition
|
||||
belongs_to :competition_team
|
||||
|
||||
serialize :snapshot, JSON
|
||||
end
|
@ -0,0 +1,2 @@
|
||||
class CompetitionCourseShixunRecord < CompetitionCourseRecord
|
||||
end
|
@ -0,0 +1,59 @@
|
||||
class Admins::ImportCompetitionScoreService < ApplicationService
|
||||
Error = Class.new(StandardError)
|
||||
|
||||
attr_reader :file, :competition, :result
|
||||
|
||||
def initialize(file, competition)
|
||||
@file = file
|
||||
@competition = competition
|
||||
@result = { success: 0, fail: [] }
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, '文件不存在' if file.blank?
|
||||
|
||||
# 创建所有战队的得分记录
|
||||
create_all_records
|
||||
|
||||
excel = Admins::ImportCompetitionScoreExcel.new(file)
|
||||
excel.read_each(&method(:update_competition_score)) # 更新单个战队成绩
|
||||
|
||||
result
|
||||
rescue ApplicationImport::Error => ex
|
||||
raise Error, ex.message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_competition_score(data)
|
||||
team = competition.competition_scores.find_by(competition_team_id: data.competition_team_id)
|
||||
raise "id为#{data.id}的战队不存在" if team.blank?
|
||||
team.update!(score: data.score)
|
||||
|
||||
result[:success] += 1
|
||||
rescue Exception => ex
|
||||
fail_data = data.as_json
|
||||
fail_data[:data] = fail_data.values.join(',')
|
||||
fail_data[:message] = ex.message
|
||||
|
||||
result[:fail] << fail_data
|
||||
end
|
||||
|
||||
def create_all_records
|
||||
competition.competition_scores.destroy_all
|
||||
|
||||
stage = competition.competition_stages.first
|
||||
|
||||
attrs = %i[
|
||||
competition_id competition_stage_id score cost_time user_id competition_team_id created_at updated_at
|
||||
]
|
||||
|
||||
CompetitionScore.bulk_insert(*attrs) do |worker|
|
||||
base_attr = { competition_id: competition.id, competition_stage_id: stage&.id.to_i,
|
||||
score: 0, cost_time: 0 }
|
||||
competition.competition_teams.each do |team|
|
||||
worker.add(base_attr.merge(user_id: team.user_id).merge(competition_team_id: team.id))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,32 @@
|
||||
<div class="modal fade admin-import-competition-score-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">导入成绩</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="admin-import-competition-score-form" enctype="multipart/form-data">
|
||||
<%= hidden_field_tag(:competition_id, nil) %>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">文件</span>
|
||||
</div>
|
||||
<div class="custom-file">
|
||||
<input type="file" name="file" class="upload-file-input" id="import-competition-score-input" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
|
||||
<label class="custom-file-label file-names" for="import-user-input">选择文件</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="error text-danger"></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary submit-btn">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,193 @@
|
||||
|
||||
namespace :competition do
|
||||
desc "statistic gcc_course competition score"
|
||||
task :extra_course_statistic, [:end_time] => :environment do |_, args|
|
||||
end_time = Time.parse(args[:end_time])
|
||||
start_time = Time.parse('2018-06-01')
|
||||
|
||||
old_competition = Competition.find 9
|
||||
competition = Competition.find 13
|
||||
|
||||
old_competition_user_ids = old_competition.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
|
||||
shixun_user_ids = Shixun.where.not(user_id: old_competition_user_ids).where(status: 2).where('shixuns.created_at > ? && shixuns.created_at <= ?', start_time, end_time).pluck(:user_id).uniq
|
||||
course_user_ids = Course.where.not(tea_id: old_competition_user_ids).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 < ? and hcs.homework_type = 4 and exists(#{subquery}))", end_time)
|
||||
.joins('join course_members on course_members.course_id = courses.id and course_members.role in (1,2,3)').pluck(:tea_id)
|
||||
|
||||
user_ids = shixun_user_ids + course_user_ids
|
||||
|
||||
users = User.joins(:user_extension).where(id: user_ids).where(user_extensions: {identity: 0})
|
||||
|
||||
users.each do |user|
|
||||
team = CompetitionTeam.create!(competition_id: competition.id, user_id: user.id, name: user.real_name)
|
||||
TeamMember.create!(competition_team_id: team.id, user_id: user.id, role: 1, competition_id: competition.id)
|
||||
end
|
||||
|
||||
custom_logger("Start Statistic Competition Score ~")
|
||||
|
||||
custom_logger("Clear Old Competition Scores ~")
|
||||
CompetitionScore.where(competition_id: competition.id).delete_all
|
||||
CompetitionCourseRecord.where(competition_id: competition.id).delete_all
|
||||
custom_logger("Clear Old Competition Scores Completed!")
|
||||
|
||||
CompetitionTeam.where(competition_id: competition.id).each do |team|
|
||||
custom_logger("Start Statistic Competition Team: #{team.id}|#{team.name} ~")
|
||||
team_user_ids = team.team_members.pluck(:user_id)
|
||||
total_score = 0
|
||||
|
||||
# =========== Shixun ===========
|
||||
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, end_time)
|
||||
forked_map = get_valid_course_count(forked_shixun_map.keys, end_time)
|
||||
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
|
||||
|
||||
custom_logger("Start Shixun Score ~")
|
||||
shixuns.each do |shixun|
|
||||
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_score += score
|
||||
|
||||
attr = {
|
||||
competition_id: competition.id,
|
||||
competition_team_id: team.id,
|
||||
user_id: shixun.user.id,
|
||||
username: shixun.user.show_real_name,
|
||||
score: score,
|
||||
type: 'CompetitionCourseShixunRecord',
|
||||
snapshot: {
|
||||
shixun: shixun.as_json(only: [:id, :name, :identifier, :fork_from]),
|
||||
myshixuns_count: shixun.myshixuns_count.to_i,
|
||||
forked_myshixun_count: shixun['forked_myshixun_count'].to_i,
|
||||
valid_myshixun_count: myshixun_count_map.fetch(shixun.id, 0),
|
||||
}
|
||||
}
|
||||
CompetitionCourseRecord.create(attr)
|
||||
end
|
||||
custom_logger("Shixun Score Completed!")
|
||||
|
||||
|
||||
# =========== Course ===========
|
||||
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 < ? and hcs.homework_type = 4 and exists(#{subquery}))", end_time)
|
||||
.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 < ?', end_time)
|
||||
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_time)
|
||||
|
||||
custom_logger("Start Course Score ~")
|
||||
courses.each do |course|
|
||||
user = course.teachers.where(user_id: team_user_ids).first.user
|
||||
|
||||
score = 500 + 5 * course_shixun_count_map.fetch(course.id, 0) * course_myshixun_map.fetch(course.id, 0)
|
||||
total_score += score
|
||||
|
||||
attr = {
|
||||
competition_id: competition.id,
|
||||
competition_team_id: team.id,
|
||||
user_id: user.id,
|
||||
username: user.show_real_name,
|
||||
score: score,
|
||||
type: 'CompetitionCourseCourseRecord',
|
||||
snapshot: {
|
||||
course: course.as_json(only: [:id, :name]),
|
||||
members_count: course.students.count.to_i,
|
||||
shixun_homework_count: course['shixun_homework_count'].to_i,
|
||||
valid_myshixun_count: course_myshixun_map.fetch(course.id, 0),
|
||||
}
|
||||
}
|
||||
CompetitionCourseRecord.create(attr)
|
||||
end
|
||||
custom_logger("Course Score Completed!")
|
||||
|
||||
custom_logger('Create Competition Score ~')
|
||||
CompetitionScore.create(user_id: team.user_id, competition_team_id: team.id, competition_id: competition.id, score: total_score)
|
||||
|
||||
custom_logger("Statistic Competition Team: #{team.id}|#{team.name} Completed!")
|
||||
end
|
||||
end
|
||||
|
||||
def custom_logger(msg)
|
||||
Rails.logger.info(msg)
|
||||
p msg
|
||||
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, end_time)
|
||||
percentage_sql = StudentWork.where('homework_common_id = homework_commons.id and homework_commons.publish_time is not null and homework_commons.publish_time < ?', end_time)
|
||||
.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, end_time)
|
||||
percentage_sql = StudentWork.where('homework_common_id = homework_commons.id and homework_commons.publish_time is not null and homework_commons.publish_time < ?', end_time)
|
||||
.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
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CompetitionCourseCourseRecord, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CompetitionCourseRecord, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CompetitionCourseShixunRecord, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
Reference in new issue