parent
4ff44c382e
commit
ed125af92d
@ -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
|
@ -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,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>
|
Loading…
Reference in new issue