admins: competition prize && competition prize api

dev_auth
p31729568 5 years ago
parent 223e65e8f5
commit acd8a0584f

@ -600,6 +600,67 @@ $(document).on('turbolinks:load', function(){
$(".stage-update-form .section-start-time").datetimepicker(timeOptions); $(".stage-update-form .section-start-time").datetimepicker(timeOptions);
$(".stage-update-form .section-end-time").datetimepicker(timeOptions); $(".stage-update-form .section-end-time").datetimepicker(timeOptions);
}); });
// 奖项设置
var $prizeContainer = $('#competition-prize-card');
var competitionId = $prizeContainer.data('id');
$(document).on('prize.save.success', function(){
$.ajax({
method: 'GET',
url: '/admins/competitions/' + competitionId + '/competition_prizes',
dataType: 'script'
})
});
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $imageElement;
if(data.suffix === '_member'){
$imageElement = $('.prize-member-image-' + data.source_id);
} else if(data.suffix === '_team'){
$imageElement = $('.prize-team-image-' + data.source_id);
} else {
$imageElement = $('.prize-teacher-image-' + data.source_id);
}
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
})
// 生成获奖记录
$prizeContainer.on('click', '.generate-prize-user-action', function(){
var $link = $(this);
var generateRequest = function(){
return $.ajax({
method: 'POST',
url: '/admins/competitions/' + competitionId + '/competition_prize_users',
dataType: 'json',
success: function(data){
if(data && data.status === 0){
show_success_flash();
$link.remove();
} else {
showErrorNotify(data.message);
}
},
error: function(res){
var data = res.responseJSON;
showErrorNotify(data.message);
}
})
}
customConfirm({
content: '确认生成吗?',
ok: function () {
customLoading({
ajax: generateRequest
})
}
})
});
} else {
$(document).unbind('prize.save.success');
} }
}); });

@ -0,0 +1,46 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.admin-save-competition-prize-modal', function(event){
var $modal = $('.modal.admin-save-competition-prize-modal');
var $form = $modal.find('form.admin-save-competition-prize-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'competition_prize[name]': {
required: true,
maxlength: 10
},
'competition_prize[num]': {
required: true,
digits: true,
min: 1
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
var formMethod = $form.data('form-method')
if ($form.valid()) {
$.ajax({
method: formMethod,
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(data){
if(data && data.status === 0) {
show_success_flash();
$(document).trigger('prize.save.success');
$modal.modal('hide');
} else {
$modal.find('.error').html(data.message)
}
}
});
}
});
})
});

@ -66,10 +66,32 @@ function customConfirm(opts){
return $.confirm($.extend({}, defaultOpts, opts)) return $.confirm($.extend({}, defaultOpts, opts))
} }
function show_success_flash(message) { function customLoading(opts) {
var loading;
var defaultOpts = {
content: opts.ajax,
contentLoaded: function(){
setTimeout(function(){
loading.close()
}, 200);
}
}
loading = $.confirm($.extend({}, defaultOpts, opts));
return loading;
}
function show_success_flash(message){
$.notify({ $.notify({
message: message || '操作成功' message: message || '操作成功'
},{ },{
type: 'success' type: 'success'
}); });
} }
function showErrorNotify(message){
$.notify({
message: message || '操作失败'
},{
type: 'danger'
});
}

@ -0,0 +1,41 @@
class Admins::CompetitionPrizeUsersController < Admins::BaseController
def index
@competition = current_competition
prize_users = Admins::CompetitionPrizeUserQuery.call(params.merge(competition_id: current_competition.id))
include_class = [:competition_team, :competition_prize, :approver,
user: [:process_real_name_apply, :process_professional_apply, user_extension: :school]]
@prize_users = paginate(prize_users.preload(include_class))
end
def create
Admins::CreateCompetitionPrizeUsersService.call(current_competition)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def approve
Admins::ApproveCompetitionPrizeUserService.call(current_prize_user, current_user)
@prize_user = current_prize_user
rescue ApplicationService::Error => ex
render_js_error(ex.message, type: :notify)
end
def unapprove
Admins::UnapproveCompetitionPrizeUserService.call(current_prize_user, current_user)
@prize_user = current_prize_user
rescue ApplicationService::Error => ex
render_js_error(ex.message, type: :notify)
end
private
def current_prize_user
@_current_prize_user ||= current_competition.competition_prize_users.find(params[:id])
end
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
end

@ -0,0 +1,43 @@
class Admins::CompetitionPrizesController < Admins::BaseController
def index
@competition = current_competition
end
def new
@prize = current_competition.competition_prizes.new
end
def create
@prize = current_competition.competition_prizes.create!(save_params)
render_ok
end
def edit
@prize = current_competition_prize
end
def update
current_competition_prize.update!(save_params)
render_ok
end
def destroy
current_competition_prize.destroy!
render_delete_success
end
private
def current_competition_prize
@_current_competition_prize ||= current_competition.competition_prizes.find(params[:id])
end
def current_competition
@_current_competition ||= Competition.find(params[:competition_id])
end
def save_params
params.require(:competition_prize).permit(:name, :category, :num)
end
end

@ -0,0 +1,23 @@
class Competitions::CertificatesController < Competitions::BaseController
def personal
prize_user = CompetitionPrizeUser.find_by!(user: current_user, id: params[:id])
return render_not_found unless prize_user.certificate_exist?
team = prize_user.competition_team
prize = prize_user.competition_prize
filename = "#{current_competition.name}-#{prize.name}-#{team.name}-#{prize_user.user.real_name}.pdf"
send_file prize_user.certificate_path, filename: filename
end
def team
team = CompetitionTeam.find(id: params[:id])
return render_forbidden unless team.team_members.exists?(user_id: current_user.id)
return render_not_found unless team.certificate_exist?
prize = team.competition_prize_users.first.competition_prize
filename = "#{current_competition.name}-#{prize.name}-#{team.name}.pdf"
send_file team.certificate_path, filename: filename
end
end

@ -5,6 +5,11 @@ class Competitions::CompetitionModulesController < Competitions::BaseController
def index def index
@modules = current_competition.unhidden_competition_modules.order(position: :asc) @modules = current_competition.unhidden_competition_modules.order(position: :asc)
# 未登录、未获奖用户,不展示获奖证书栏目
if !current_user.logged? || !current_competition.competition_prize_users.exists?(user: current_user)
@modules = @modules.select { |mod| mod.name != '获奖证书' }
end
end end
def show def show

@ -0,0 +1,25 @@
class Competitions::PrizeLeaderAccountsController < Competitions::BaseController
before_action :require_prize_team_leader!
def update
Competitions::SavePrizeTeamAccountService.call(current_competition, current_user, update_params)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
private
def require_prize_team_leader!
prize_user = current_competition.competition_prize_users.joins(:competition_prize)
.where(competition_prizes: { category: :bonus })
.find_by(leader: true, user_id: current_user.id)
return if prize_user.present?
render_forbidden
end
def update_params
params.permit(:bank, :second_bank, :card_no)
end
end

@ -0,0 +1,26 @@
class Competitions::PrizesController < Competitions::BaseController
before_action :require_prize_user!
def show
self_prizes = current_competition.competition_prize_users.where(user_id: current_user.id).includes(:competition_team)
@leader = self_prizes.any?(&:leader?) # 是否为队长
@bank_account = self_prizes.find(&:leader?).extra if @leader
@self_prizes = self_prizes.select(&:certificate_exist?) # 个人证书quit
@team_prizes = self_prizes.map(&:competition_team).uniq.select(&:certificate_exists?) # 团队证书
prize_users = current_competition.competition_prize_users.where(competition_team_id: self_prizes.map(&:competition_team_id))
.includes(:competition_team, user: [:user_extension, :process_real_name_apply, :process_professional_apply])
@prize_user_map = prize_users.group_by(&:competition_team)
end
private
def require_prize_user!
return if current_competition.competition_prize_users.exists?(user: current_user)
render_forbidden
end
end

@ -0,0 +1,9 @@
class Competitions::SavePrizeTeamAccountForm
include ActiveModel::Model
attr_accessor :bank, :second_bank, :card_no
validates :bank, presence: true
validates :second_bank, presence: true
validates :card_no, presence: true
end

@ -0,0 +1,10 @@
module Admins::CompetitionPrizeUsersHelper
def display_auth_state(flag, other = false, success: nil, normal: nil, error: nil)
success ||= '<i class="fa fa-check text-success font-16"/>'.html_safe
normal ||= '--'
error ||= '<i class="fa fa-close text-secondary font-16"/>'.html_safe
return success if flag
other ? normal : error
end
end

@ -29,6 +29,9 @@ class Competition < ApplicationRecord
has_many :competition_managers, dependent: :destroy has_many :competition_managers, dependent: :destroy
has_many :managers, through: :competition_managers, source: :user has_many :managers, through: :competition_managers, source: :user
has_many :competition_prizes, dependent: :destroy
has_many :competition_prize_users, dependent: :destroy
after_create :create_competition_modules after_create :create_competition_modules
def mode_type def mode_type
@ -131,7 +134,7 @@ class Competition < ApplicationRecord
end end
def all_module_types def all_module_types
%w[home enroll inform chart resource] %w[home enroll inform chart resource certificate]
end end
def max_stage_end_time def max_stage_end_time
@ -146,6 +149,10 @@ class Competition < ApplicationRecord
user && competition_managers.exists?(user_id: user.id) user && competition_managers.exists?(user_id: user.id)
end end
def finished?
end_time.blank? || end_time < Time.now
end
private private
def get_module_name type def get_module_name type
@ -155,6 +162,7 @@ class Competition < ApplicationRecord
when 'inform' then '通知公告' when 'inform' then '通知公告'
when 'chart' then '排行榜' when 'chart' then '排行榜'
when 'resource' then '资料下载' when 'resource' then '资料下载'
when 'certificate' then '获奖证书'
else '' else ''
end end
end end

@ -0,0 +1,21 @@
class CompetitionPrize < ApplicationRecord
extend Enumerize
belongs_to :competition
has_many :competition_prize_users, dependent: :destroy
enumerize :category, in: %i[bonus unset]
def self.member_suffix
'_member'
end
def self.teacher_suffix
'_teacher'
end
def self.team_suffix
'_team'
end
end

@ -0,0 +1,48 @@
class CompetitionPrizeUser < ApplicationRecord
include AASM
belongs_to :competition
belongs_to :competition_team
belongs_to :competition_prize
belongs_to :user
belongs_to :approver, class_name: 'User', optional: true # 审批人
serialize :extra, JSON
aasm(:status) do
state :pending, initial: true
state :approved
event :approve do
transitions from: [:pending], to: :approved, guard: :user_certified?
end
event :unapprove do
transitions from: [:approved], to: :pending
end
end
delegate :bank, :second_bank, :card_no, to: :extra, allow_nil: true
def user_certified?
user.certification? && user.professional_certification?
end
def certificate_exist?
Util::FileManage.exists?(self)
end
def certificate_url
Util::FileManage.source_disk_file_url(self)
end
def certificate_path
Util::FileManage.source_disk_filename(self)
end
def role_text
return '队长' if leader?
user.is_teacher? ? '教师' : '队员'
end
end

@ -11,6 +11,8 @@ class CompetitionTeam < ApplicationRecord
has_many :members, -> { without_teachers }, class_name: 'TeamMember' has_many :members, -> { without_teachers }, class_name: 'TeamMember'
has_many :teachers, -> { only_teachers }, class_name: 'TeamMember' has_many :teachers, -> { only_teachers }, class_name: 'TeamMember'
has_many :competition_prize_users, dependent: :destroy
def group_team_type? def group_team_type?
team_type.zero? team_type.zero?
end end
@ -48,4 +50,24 @@ class CompetitionTeam < ApplicationRecord
def members_name def members_name
members.map{|member| member.user.real_name}.join(",") members.map{|member| member.user.real_name}.join(",")
end end
def all_prize_approved?
!competition_prize_users.exists?(status: :pending)
end
def certificate_exists?
Util::FileManage.exists?(self, self.class.certificate_suffix)
end
def certificate_url
Util::FileManage.source_disk_file_url(self, self.class.certificate_suffix)
end
def certificate_path
Util::FileManage.source_disk_filename(self, self.class.certificate_suffix)
end
def self.certificate_suffix
'_CERT'
end
end end

@ -503,6 +503,10 @@ class User < ApplicationRecord
phone.present? phone.present?
end end
def email_binded?
mail.present?
end
def self.current=(user) def self.current=(user)
Thread.current[:current_user] = user Thread.current[:current_user] = user
end end

@ -0,0 +1,77 @@
class Admins::CompetitionPrizeUserQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :rank, default_by: :rank, default_direction: :asc
def initialize(params)
@params = params
end
def call
records = CompetitionPrizeUser.all
# 竞赛过滤
records = records.where(competition_id: params[:competition_id]) if params[:competition_id].present?
# 关键字检索
keyword = params[:keyword].to_s.strip
if keyword.present?
like_sql = 'competition_teams.name LIKE :keyword OR schools.name LIKE :keyword'
records = records.left_joins(:competition_team, user: { user_extension: :school })
.where(like_sql, keyword: "%#{keyword}%")
end
# 奖项过滤
records = records.where(competition_prize_id: params[:prize_id]) if params[:prize_id].present?
# 审批状态过滤
records = records.where(status: params[:status]) if params[:status].present?
# 职业过滤
if params[:identity].present?
records = records.left_joins(user: :user_extension).where(user_extensions: { identity: params[:identity] })
end
# 实名认证过滤
records = real_name_auth_filter(records) if params[:real_name_auth].present?
# 职业认证过滤
records = professional_auth_filter(records) if params[:professional_auth].present?
custom_sort(records, params[:sort_by], params[:sort_direction])
end
private
def real_name_auth_filter(records)
records = records.left_joins(:user)
sql = ApplyUserAuthentication.real_name_auth.processing.where('apply_user_authentications.user_id = users.id').to_sql
case params[:real_name_auth]
when 'authed' then
records.where(users: { authentication: true })
when 'not_authed' then
records.where(users: { authentication: false }).where("NOT EXISTS (#{sql})")
when 'authing' then
records.where(users: { authentication: false }).where("EXISTS (#{sql})")
else records
end
end
def professional_auth_filter(records)
records = records.left_joins(:user)
sql = ApplyUserAuthentication.professional_auth.processing.where('apply_user_authentications.user_id = users.id').to_sql
case params[:professional_auth]
when 'authed' then
records.where(users: { professional_certification: true })
when 'not_authed' then
records.where(users: { professional_certification: false }).where("NOT EXISTS (#{sql})")
when 'authing' then
records.where(users: { professional_certification: false }).where("EXISTS (#{sql})")
else records
end
end
end

@ -0,0 +1,26 @@
class Admins::ApproveCompetitionPrizeUserService < ApplicationService
attr_reader :prize_user, :approver
def initialize(prize_user, approver)
@prize_user = prize_user
@approver = approver
end
def call
raise Error, '请勿重复审批' if prize_user.approved?
raise Error, '该用户未认证完成' unless prize_user.user_certified?
ActiveRecord::Base.transaction do
prize_user.approve
prize_user.approver = approver
prize_user.approved_at = Time.now
prize_user.save!
if prize_user.competition_team.all_prize_approved?
# TODO: 生成团队证书
end
# TODO: 生成个人证书
end
end
end

@ -0,0 +1,70 @@
class Admins::CreateCompetitionPrizeUsersService < ApplicationService
attr_reader :competition
def initialize(competition)
@competition = competition
end
def call
raise Error, '竞赛还未结束' unless competition.finished?
raise Error, '请勿重复生成' if competition.competition_prize_users.exists?
raise Error, '请先设置奖项' if prizes.blank?
raise Error, '无获奖队伍' if prize_teams.blank?
ActiveRecord::Base.transaction do
columns = %i[competition_id competition_team_id competition_prize_id user_id
status rank leader created_at updated_at]
CompetitionPrizeUser.bulk_insert(*columns) do |worker|
prize_teams.each_with_index do |team, index|
rank = index + 1
prize = team_prize(rank) # 根据排名获取当前队伍奖项
team.team_members.each do |member|
attr = {
competition_id: competition.id,
competition_team_id: team.id,
competition_prize_id: prize.id,
user_id: member.user_id,
leader: member.creator?,
status: :pending,
rank: rank
}
worker.add(attr)
end
end
end
end
end
private
def prizes
@_prizes ||= competition.competition_prizes.order(id: :asc).to_a
end
def team_prize(rank)
current = 0
prizes.each do |prize|
return prize if rank > current && rank <= current + prize.num
current += prize.num
end
end
def prize_teams
@_prize_teams ||= begin
prize_num_total = prizes.sum(&:num)
# 只有一个阶段则成绩为该阶段成绩否则为stage ID为0的总成绩
stage_id = competition.competition_stages.count == 1 ? competition.competition_stages.first.id : 0
competition.competition_teams.joins(:competition_scores)
.where(competition_scores: { competition_stage_id: stage_id })
.order("competition_scores.score desc, competition_scores.cost_time desc")
.includes(:team_members)
.limit(prize_num_total)
end
end
end

@ -0,0 +1,27 @@
class Admins::UnapproveCompetitionPrizeUserService < ApplicationService
attr_reader :prize_user, :approver
def initialize(prize_user, approver)
@prize_user = prize_user
@approver = approver
end
def call
raise Error, '状态有误' if prize_user.pending?
ActiveRecord::Base.transaction do
prize_user.unapprove
prize_user.approver = approver
prize_user.approved_at = nil
prize_user.save!
# 删除团队证书
team_certificate_path = Util::FileManage.source_disk_filename(prize_user.competition_team, CompetitionTeam.certificate_suffix)
File.delete(team_certificate_path) if File.exist?(team_certificate_path)
# 删除个人证书
user_certificate_path = Util::FileManage.source_disk_filename(prize_user)
File.delete(user_certificate_path) if File.exist?(user_certificate_path)
end
end
end

@ -0,0 +1,19 @@
class Competitions::SavePrizeTeamAccountService < ApplicationService
attr_reader :competition, :user, :params
def initialize(competition, user, params)
@competition = competition
@user = user
@params = params
end
def call
Competitions::SavePrizeTeamAccountForm.new(params).validate!
prize_leaders = competition.competition_prize_users.where(competition.competition_prize_users)
raise Error, '审批通过后不能修改' if prize_leaders.exists?(status: :approved)
prize_leaders.update_all(extra: params)
end
end

@ -0,0 +1 @@
$('.competition-prize-user-list-container .competition-prize-user-item-<%= @prize_user.id %>').html("<%= j( render partial: 'admins/competition_prize_users/shared/tr', locals: { prize_user: @prize_user } ) %>");

@ -0,0 +1,58 @@
<%
define_admin_breadcrumbs do
add_admin_breadcrumb('竞赛列表', admins_competitions_path)
add_admin_breadcrumb(@competition.name)
end
%>
<div class="box search-form-container flex-column mb-0 pb-0 competition-prize-user-form">
<ul class="nav nav-tabs w-100 search-form-tabs">
<li class="nav-item">
<%= link_to '报名列表', admins_competition_enroll_lists_path(@competition), class: "nav-link search-form-tab" %>
</li>
<li class="nav-item">
<%= link_to '获奖证书审批', admins_competition_competition_prize_users_path(@competition), class: "nav-link search-form-tab active" %>
</li>
</ul>
<div class="d-flex">
<%= form_tag(admins_competition_competition_prize_users_path(unsafe_params), method: :get, class: 'search-form mt-3 flex-1 d-flex align-items-end', remote: true) do %>
<div class="form-group mb-0 mr-3">
<label for="status">奖项:</label>
<% prize_options = [['不限', '']] + @competition.competition_prizes.map{ |p| [p.name, p.id] } %>
<%= select_tag(:prize_id, options_for_select(prize_options), class: 'form-control') %>
</div>
<% auth_options = [['不限', ''], %w(未认证 not_authed), %w(待认证 authing), %w(已认证 authed)] %>
<div class="form-group mb-0 mr-3">
<label for="status">实名认证状态:</label>
<%= select_tag(:real_name_auth, options_for_select(auth_options), class: 'form-control') %>
</div>
<div class="form-group mb-0 mr-3">
<label for="status">职业认证状态:</label>
<%= select_tag(:professional_auth, options_for_select(auth_options), class: 'form-control') %>
</div>
<div class="form-group mb-0 mr-3">
<label for="status">职业:</label>
<%- identity_options = [['不限', ''], %w(教师 0), %w(学生 1)] %>
<%= select_tag(:identity, options_for_select(identity_options), class: 'form-control') %>
</div>
<div class="form-group mb-0 mr-3">
<label for="status">审批状态:</label>
<%- status_options = [['不限', ''], %w(未审批 pending), %w(已审批 approved)] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '战队/学校名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<%= link_to '清除', admins_competition_competition_prize_users_path(@competition), class: "btn btn-default",'data-disable-with': '清除中...' %>
<% end %>
</div>
</div>
<div class="box competition-prize-user-list-container">
<%= render(partial: 'admins/competition_prize_users/shared/list', locals: { prize_users: @prize_users }) %>
</div>

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

@ -0,0 +1,33 @@
<table class="table table-hover text-center competition-prize-user-list-table">
<thead class="thead-light">
<tr>
<th width="6%">奖项</th>
<th width="5%">排名</th>
<th width="10%" class="text-left">战队名称</th>
<th width="8%">真实姓名</th>
<th width="5%">职业</th>
<th width="8%">学号</th>
<th width="10%">单位</th>
<th width="5%">实名</th>
<th width="5%">职业</th>
<th width="5%">手机</th>
<th width="5%">队长</th>
<th width="10%">审批时间</th>
<th width="8%">审批人</th>
<th width="10%">操作</th>
</tr>
</thead>
<tbody style="overflow-wrap:break-word;">
<% if prize_users.present? %>
<% prize_users.each do |prize_user| %>
<tr class="competition-prize-user-item-<%= prize_user.id %>">
<%= render('admins/competition_prize_users/shared/tr', prize_user: prize_user) %>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: prize_users } %>

@ -0,0 +1,26 @@
<%- user = prize_user.user -%>
<td><%= prize_user.competition_prize.name %></td>
<td><%= prize_user.rank %></td>
<td class="text-left"><%= prize_user.competition_team.name %></td>
<td><%= user.real_name %></td>
<td><%= user.identity %></td>
<td><%= user.is_teacher? ? user.user_extension.technical_title : user.user_extension.student_id %></td>
<td><%= user.school_name %></td>
<td><%= display_auth_state(user.authentication?, user.process_real_name_apply.present?) %></td>
<td><%= display_auth_state(user.professional_certification?, user.process_professional_apply.present?) %></td>
<td><%= display_auth_state user.phone_binded? %></td>
<td><%= display_auth_state prize_user.leader?, error: '' %></td>
<td><%= display_text prize_user.approved_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td><%= display_text prize_user.approver&.real_name %></td>
<td class="action-container">
<% if prize_user.pending? %>
<%= link_to('审批通过', approve_admins_competition_competition_prize_user_path(prize_user.competition, prize_user),
data: { confirm: '确认审批通过吗?' },
remote: true, method: :post, class: 'approve-action') %>
<% else %>
<%= link_to('撤销审批', unapprove_admins_competition_competition_prize_user_path(prize_user.competition, prize_user),
data: { confirm: '确认撤销审批吗?' },
remote: true, method: :post, class: 'approve-action') %>
<% end %>
</td>

@ -0,0 +1 @@
$('.competition-prize-user-list-container .competition-prize-user-item-<%= @prize_user.id %>').html("<%= j( render partial: 'admins/competition_prize_users/shared/tr', locals: { prize_user: @prize_user } ) %>");

@ -0,0 +1,2 @@
$('.admin-modal-container').html("<%= j( render partial: 'admins/competition_prizes/shared/save_competition_prize_modal', locals: { prize: @prize, title: '编辑奖项', form_method: 'PATCH' } ) %>");
$('.modal.admin-save-competition-prize-modal').modal('show');

@ -0,0 +1 @@
$('#competition-prize-card .competition-prize-table tbody').html("<%= j( render partial: 'admins/competition_settings/shared/competition_prizes', locals: { competition: @competition } ) %>");

@ -0,0 +1,2 @@
$('.admin-modal-container').html("<%= j( render partial: 'admins/competition_prizes/shared/save_competition_prize_modal', locals: { prize: @prize, title: '新建奖项', form_method: 'POST' } ) %>");
$('.modal.admin-save-competition-prize-modal').modal('show');

@ -0,0 +1,29 @@
<div class="modal fade admin-save-competition-prize-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"><%= title ||= '保存奖项设置' %></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<%= simple_form_for([:admins, prize.competition, prize], data: { form_method: form_method }, html: { class: 'admin-save-competition-prize-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
<%= f.input :name, label: '奖项名称:', placeholder: '请输入奖项名称' %>
<%= f.input :num, as: :integer, label: '数量:', placeholder: '请输入数量', input_html: { min: 1 } %>
<%= f.input :category, label: '奖励类型:' do %>
<%= f.select :category, [%w(奖金 bonus), %w(无 unset)], {}, class: 'form-control' %>
<% end %>
<div class="error text-danger"></div>
<% end %>
</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>

@ -266,7 +266,7 @@
<% end %> <% end %>
</div> </div>
<% when 'inform', 'chart', 'resource' %> <% when 'inform', 'chart', 'resource', 'certificate' %>
<div class="row mt-2 new_module_div linkFormItem"> <div class="row mt-2 new_module_div linkFormItem">
<div class="col-1 text-right"> <div class="col-1 text-right">
<label class="checkbox checkbox-primary mt-1"> <label class="checkbox checkbox-primary mt-1">
@ -315,16 +315,6 @@
<% end %> <% end %>
<% end %> <% end %>
<!-- <div class="row mt-2">-->
<!-- <div class="col-1 text-right">-->
<!-- <label class="checkbox checkbox-primary mt-1">-->
<!-- <input id="checkbox2" type="checkbox">-->
<!-- <label for="checkbox2">&nbsp;</label>-->
<!-- </label>-->
<!-- </div>-->
<!-- <div class="col-md-label mt-2">获奖证书</div>-->
<!-- </div>-->
<div class="error my-2 danger text-danger"></div> <div class="error my-2 danger text-danger"></div>
<div class="row mt-2 mb-4"> <div class="row mt-2 mb-4">
@ -518,5 +508,36 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card mb-5" id="competition-prize-card" data-id="<%= @competition.id %>">
<div class="card-header d-flex justify-content-between align-items-center">
<span class="flex-1">奖项配置</span>
<%= link_to '新增奖项', new_admins_competition_competition_prize_path(@competition), remote: true, class: 'btn btn-primary btn-sm add-competition-prize-btn' %>
<% if @competition.finished? && !@competition.competition_prize_users.exists? %>
<%= javascript_void_link '生成获奖记录', class: 'btn btn-primary btn-sm ml-2 generate-prize-user-action' %>
<% end %>
</div>
<div class="card-body row pt-0">
<table class="table text-center competition-prize-table">
<thead>
<th width="8%">序号</th>
<th width="10%">奖项名称</th>
<th width="10%">数量</th>
<th width="10%">奖励类型</th>
<th width="16%">队员个人证书模板</th>
<th width="16%">团队证书模板</th>
<th width="16%">指导老师证书模板</th>
<th width="14%">操作</th>
</thead>
<tbody>
<%= render 'admins/competition_settings/shared/competition_prizes', competition: @competition %>
</tbody>
</table>
</div>
</div>
<div style="margin-bottom: 8.5rem;"></div> <div style="margin-bottom: 8.5rem;"></div>
<%# end %> <%# end %>
<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传证书模板', accept: 'image/*' } %>

@ -0,0 +1,27 @@
<% competition.competition_prizes.each_with_index do |prize, index| %>
<tr class="competition-prize-item-<%= prize.id %>">
<td><%= index + 1 %></td>
<td><%= prize.name %></td>
<td><%= prize.num %></td>
<td><%= prize.category_text %></td>
<td>
<% member_image_exists = Util::FileManage.exists?(prize, CompetitionPrize.member_suffix) %>
<%= image_tag(member_image_exists ? Util::FileManage.source_disk_file_url(prize, CompetitionPrize.member_suffix) : '', height: 60, class: "w-100 preview-image prize-member-image-#{prize.id}", style: member_image_exists ? '' : 'display:none') %>
<%= javascript_void_link member_image_exists ? '重新上传' : '上传模板', class: 'action upload-prize-member-image-action', data: { source_id: prize.id, source_type: 'CompetitionPrize', suffix: CompetitionPrize.member_suffix, toggle: 'modal', target: '.admin-upload-file-modal' } %>
</td>
<td>
<% team_image_exists = Util::FileManage.exists?(prize, CompetitionPrize.team_suffix) %>
<%= image_tag(team_image_exists ? Util::FileManage.source_disk_file_url(prize, CompetitionPrize.team_suffix) : '', height: 60, class: "w-100 preview-image prize-team-image-#{prize.id}", style: team_image_exists ? '' : 'display:none') %>
<%= javascript_void_link team_image_exists ? '重新上传' : '上传模板', class: 'action upload-prize-team-image-action', data: { source_id: prize.id, source_type: 'CompetitionPrize', suffix: CompetitionPrize.team_suffix, toggle: 'modal', target: '.admin-upload-file-modal' } %>
</td>
<td>
<% teacher_image_exists = Util::FileManage.exists?(prize, CompetitionPrize.teacher_suffix) %>
<%= image_tag(teacher_image_exists ? Util::FileManage.source_disk_file_url(prize, CompetitionPrize.teacher_suffix) : '', height: 60, class: "w-100 preview-image prize-teacher-image-#{prize.id}", style: teacher_image_exists ? '' : 'display:none') %>
<%= javascript_void_link teacher_image_exists ? '重新上传' : '上传模板', class: 'action upload-prize-teacher-image-action', data: { source_id: prize.id, source_type: 'CompetitionPrize', suffix: CompetitionPrize.teacher_suffix, toggle: 'modal', target: '.admin-upload-file-modal' } %>
</td>
<td class="action-container">
<%= link_to '编辑', edit_admins_competition_competition_prize_path(competition, prize), remote: true, class: 'action edit-competition-prize-action' %>
<%= delete_link '删除', admins_competition_competition_prize_path(competition, prize, element: ".competition-prize-item-#{prize.id}"), class: 'action delete-competition-prize-action' %>
</td>
</tr>
<% end %>

@ -11,7 +11,7 @@
<%= link_to '报名列表', admins_competition_enroll_lists_path(@competition), class: "nav-link search-form-tab active" %> <%= link_to '报名列表', admins_competition_enroll_lists_path(@competition), class: "nav-link search-form-tab active" %>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<%= link_to '获奖证书审批', admins_competition_enroll_lists_path(@competition), class: "nav-link search-form-tab" %> <%= link_to '获奖证书审批', admins_competition_competition_prize_users_path(@competition), class: "nav-link search-form-tab" %>
</li> </li>
</ul> </ul>

@ -37,3 +37,5 @@
<div class="box subject-list-container"> <div class="box subject-list-container">
<%= render partial: 'admins/subjects/shared/list', locals: { subjects: @subjects } %> <%= render partial: 'admins/subjects/shared/list', locals: { subjects: @subjects } %>
</div> </div>
<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片', accept: 'image/*' } %>

@ -70,4 +70,3 @@
</table> </table>
<%= render partial: 'admins/shared/paginate', locals: { objects: subjects } %> <%= render partial: 'admins/shared/paginate', locals: { objects: subjects } %>
<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片', accept: 'image/*' } %>

@ -0,0 +1,55 @@
json.leader @leader
json.bank_account @bank_account if @leader
json.personal_certifications do
json.array! @self_prizes do |prize_user|
json.url personal_competitions_certificate_path(current_competition, prize_user)
end
end
json.team_certifications do
json.array! @team_prizes do |team|
json.url team_competitions_certificate_path(current_competition, team)
end
end
json.teams do
json.array! @prize_user_map do |team, prize_users|
json.extract! team, :id, :name
json.bank_account prize_users.find(&:leader?).extra
json.team_members do
json.array! prize_users do |prize_user|
user = prize_user.user
json.role prize_user.role_text
json.name user.real_name
real_name_auth =
if user.authentication?
'authed'
elsif user.process_real_name_apply.present?
'authing'
else
'not_authed'
end
json.real_name_auth real_name_auth
professional_auth =
if user.professional_certification?
'authed'
elsif user.process_professional_apply.present?
'authing'
else
'not_authed'
end
json.professional_auth professional_auth
json.phone_binded user.phone_binded?
json.email_binded user.email_binded?
end
end
end
end

@ -2,3 +2,5 @@ admins-mirror_scripts: 'admins-mirror_repositories'
admins-laboratory_settings: 'admins-laboratories' admins-laboratory_settings: 'admins-laboratories'
admins-carousels: 'admins-laboratories' admins-carousels: 'admins-laboratories'
admins-competition_settings: 'admins-competitions' admins-competition_settings: 'admins-competitions'
admins-enroll_lists: 'admins-competitions'
admins-competition_prize_users: 'admins-competitions'

@ -0,0 +1,6 @@
zh-CN:
enumerize:
competition_prize:
category:
bonus: '奖金'
unset: '无'

@ -0,0 +1,8 @@
'zh-CN':
activemodel:
attributes:
competitions/save_prize_team_account_form:
bank: '开户行'
second_bank: '支行'
card_no: '卡号'

@ -809,6 +809,14 @@ Rails.application.routes.draw do
get :chart_rules get :chart_rules
post :update_chart_rules post :update_chart_rules
end end
resource :prize_leader_account, only: [:update]
resource :prize, only: [:show]
resources :certificates, only: [] do
member do
get :personal
get :team
end
end
end end
end end
@ -1043,6 +1051,14 @@ Rails.application.routes.draw do
post :calculate_stage_score post :calculate_stage_score
end end
end end
resources :competition_prizes, only: [:index, :new, :create, :edit, :update, :destroy]
resources :competition_prize_users, only: [:index, :create] do
member do
post :approve
post :unapprove
end
end
end end
resources :weapp_carousels, only: [:index, :create, :update, :destroy] do resources :weapp_carousels, only: [:index, :create, :update, :destroy] do

@ -0,0 +1,10 @@
class InitCompetitionCertificateModuleData < ActiveRecord::Migration[5.2]
def change
Competition.find_each do |competition|
competition.competition_modules.where(module_type: 'certificate').delete_all
position = competition.competition_modules.maximum(:position) + 1
competition.competition_modules.create(module_type: 'certificate', position: position, name: '获奖证书', hidden: true)
end
end
end

@ -0,0 +1,13 @@
class CreateCompetitionPrizes < ActiveRecord::Migration[5.2]
def change
create_table :competition_prizes do |t|
t.references :competition
t.string :name
t.string :category
t.integer :num
t.timestamps
end
end
end

@ -0,0 +1,20 @@
class CreateCompetitionPrizeUsers < ActiveRecord::Migration[5.2]
def change
create_table :competition_prize_users do |t|
t.references :competition
t.references :competition_team
t.references :competition_prize
t.references :user
t.references :approver
t.string :status
t.integer :rank
t.boolean :leader, default: false
t.text :extra
t.datetime :approved_at
t.timestamps
end
end
end

File diff suppressed because one or more lines are too long

@ -29898,13 +29898,35 @@ function customConfirm(opts){
return $.confirm($.extend({}, defaultOpts, opts)) return $.confirm($.extend({}, defaultOpts, opts))
} }
function show_success_flash(message) { function customLoading(opts) {
var loading;
var defaultOpts = {
content: opts.ajax,
contentLoaded: function(){
setTimeout(function(){
loading.close()
}, 200);
}
}
loading = $.confirm($.extend({}, defaultOpts, opts));
return loading;
}
function show_success_flash(message){
$.notify({ $.notify({
message: message || '操作成功' message: message || '操作成功'
},{ },{
type: 'success' type: 'success'
}); });
} }
function showErrorNotify(message){
$.notify({
message: message || '操作失败'
},{
type: 'danger'
});
}
; ;
(function (global, factory) { (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
@ -136519,45 +136541,45 @@ $(document).on('turbolinks:load', function(){
' </div>\n' + ' </div>\n' +
' <div id="small_panel_'+count+'" class="small_panel">\n' + ' <div id="small_panel_'+count+'" class="small_panel">\n' +
' <div class="row d-flex small_panel_item" attr_line="sub_new_new" count="1">\n' + ' <div class="row d-flex small_panel_item" attr_line="sub_new_new" count="1">\n' +
' <span class="col-1 mt-2 subName">第1阶段</span>\n' + ' <span class="mt-2 subName mr10">第1阶段</span>\n' +
' <div class="flex-1">\n' + ' <div class="flex-1">\n' +
' <div class="row">\n' + ' <div class="row">\n' +
' <span class="mt-2 ml20">有效时间:</span>\n' + ' <div class="row col-6"><span class="mt-2 ml20">有效时间:</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-4 no_padding">\n' +
' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' + ' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' +
' </div>\n' + ' </div>\n' +
' <span class="mt-2">~</span>\n' + ' <span class="mt-2">~</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' + ' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' +
' </div>\n' + ' </div></div>\n' +
' <span class="col-2 text-right mt-2 no_padding">总任务数:</span>\n' + ' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding">总任务数:</span>\n' +
' <div class="col-1 no_padding input_small">\n' + ' <div class="col-6 no_padding ">\n' +
' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' + ' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' +
' </div>\n' + ' </div></div>\n' +
' <span class="col-1 text-right mt-2 no_padding">成绩来源:</span>\n' + ' <div class="row col-4"><span class="col-3 text-right mt-2 no_padding">成绩来源:</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-7 no_padding ">\n' +
' <select class="form-control" name="stage[][score_source]">\n' + ' <select class="form-control" name="stage[][score_source]">\n' +
' <option value="0">经验值</option>\n' + ' <option value="0">经验值</option>\n' +
' <option value="1">预测准确率</option>\n' + ' <option value="1">预测准确率</option>\n' +
' </select>\n' + ' </select>\n' +
' </div>\n' + ' </div></div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="row mt-2" id="task_Input_sub_new_new">\n' + ' <div class="row mt-2" id="task_Input_sub_new_new">\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务1</span>\n' + ' <span class="col-4 text-right mt-3 no_padding mr10">任务1</span>\n' +
' <div class="col-8">\n' + ' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务2</span>\n' + ' <span class="col-4 text-right mt-3 no_padding mr10">任务2</span>\n' +
' <div class="col-8">\n' + ' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务3</span>\n' + ' <span class="col-4 text-right mt-3 no_padding mr10">任务3</span>\n' +
' <div class="col-8">\n' + ' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
@ -136595,45 +136617,45 @@ $(document).on('turbolinks:load', function(){
var html='<div class="row d-flex small_panel_item" attr_line="sub_'+index+'_'+count+'" count="'+count+'">\n' + var html='<div class="row d-flex small_panel_item" attr_line="sub_'+index+'_'+count+'" count="'+count+'">\n' +
' <span class="col-1 mt-2 subName">第'+showCount+'阶段</span>\n' + ' <span class="mr10 mt-2 subName">第'+showCount+'阶段</span>\n' +
' <div class="flex-1">\n' + ' <div class="flex-1">\n' +
' <div class="row">\n' + ' <div class="row">\n' +
' <span class="mt-2 ml20">有效时间:</span>\n' + ' <div class="row col-6"><span class="mt-2 ml20 mr10">有效时间:</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' + ' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' +
' </div>\n' + ' </div>\n' +
' <span class="mt-2">~</span>\n' + ' <span class="mt-2">~</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' + ' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' +
' </div>\n' + ' </div></div>\n' +
' <span class="col-2 text-right mt-2 no_padding">总任务数:</span>\n' + ' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding mr10">总任务数:</span>\n' +
' <div class="col-1 no_padding input_small">\n' + ' <div class="col-6 no_padding ">\n' +
' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' + ' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' +
' </div>\n' + ' </div></div>\n' +
' <span class="col-1 text-right mt-2 no_padding">成绩来源:</span>\n' + ' <div class="row col-4"><span class="col-3 mr10 text-right mt-2 no_padding">成绩来源:</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-7 no_padding ">\n' +
' <select class="form-control" name="stage[][score_source]">\n' + ' <select class="form-control" name="stage[][score_source]">\n' +
' <option value="0">经验值</option>\n' + ' <option value="0">经验值</option>\n' +
' <option value="1">预测准确率</option>\n' + ' <option value="1">预测准确率</option>\n' +
' </select>\n' + ' </select>\n' +
' </div>\n' + ' </div></div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="row mt-2" id="task_Input_sub_'+index+'_'+count+'">\n'+ ' <div class="row mt-2" id="task_Input_sub_'+index+'_'+count+'">\n'+
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务1</span>\n' + ' <span class="col-4 text-right mt-3 no_padding mr10">任务1</span>\n' +
' <div class="col-8">\n' + ' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务2</span>\n' + ' <span class="col-4 text-right mt-3 no_padding mr10">任务2</span>\n' +
' <div class="col-8">\n' + ' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务3</span>\n' + ' <span class="col-4 text-right mt-3 no_padding mr10">任务3</span>\n' +
' <div class="col-8">\n' + ' <div class="col-6 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
@ -136648,6 +136670,67 @@ $(document).on('turbolinks:load', function(){
$(".stage-update-form .section-start-time").datetimepicker(timeOptions); $(".stage-update-form .section-start-time").datetimepicker(timeOptions);
$(".stage-update-form .section-end-time").datetimepicker(timeOptions); $(".stage-update-form .section-end-time").datetimepicker(timeOptions);
}); });
// 奖项设置
var $prizeContainer = $('#competition-prize-card');
var competitionId = $prizeContainer.data('id');
$(document).on('prize.save.success', function(){
$.ajax({
method: 'GET',
url: '/admins/competitions/' + competitionId + '/competition_prizes',
dataType: 'script'
})
});
$('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
var $imageElement;
if(data.suffix === '_member'){
$imageElement = $('.prize-member-image-' + data.source_id);
} else if(data.suffix === '_team'){
$imageElement = $('.prize-team-image-' + data.source_id);
} else {
$imageElement = $('.prize-teacher-image-' + data.source_id);
}
$imageElement.attr('src', data.url);
$imageElement.show();
$imageElement.next().html('重新上传');
})
// 生成获奖记录
$prizeContainer.on('click', '.generate-prize-user-action', function(){
var $link = $(this);
var generateRequest = function(){
return $.ajax({
method: 'POST',
url: '/admins/competitions/' + competitionId + '/competition_prize_users',
dataType: 'json',
success: function(data){
if(data && data.status === 0){
show_success_flash();
$link.remove();
} else {
showErrorNotify(data.message);
}
},
error: function(res){
var data = res.responseJSON;
showErrorNotify(data.message);
}
})
}
customConfirm({
content: '确认生成吗?',
ok: function () {
customLoading({
ajax: generateRequest
})
}
})
});
} else {
$(document).unbind('prize.save.success');
} }
}); });
@ -136681,8 +136764,8 @@ function change_total(item) {
var html = ""; var html = "";
if(count > divCount){ if(count > divCount){
for(var i=0;i < count-divCount ;i++){ for(var i=0;i < count-divCount ;i++){
html+='<div class="col-4 row task_Input_div"><span class="col-3 text-center mt-3">任务'+(divCount+i+1)+'</span>\n' + html+='<div class="col-4 row task_Input_div"><span class="col-4 text-right mt-3 no_padding mr10">任务'+(divCount+i+1)+'</span>\n' +
'<div class="col-8">\n' + '<div class="col-6 no_padding">\n' +
'<input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + '<input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
'</div>\n' + '</div>\n' +
'</div>'; '</div>';
@ -136736,45 +136819,45 @@ function addNewTab(competition_id) {
' </div>\n' + ' </div>\n' +
' <div id="small_panel_'+count+'" class="small_panel">\n' + ' <div id="small_panel_'+count+'" class="small_panel">\n' +
' <div class="row d-flex small_panel_item" attr_line="sub_new_new" count="1">\n' + ' <div class="row d-flex small_panel_item" attr_line="sub_new_new" count="1">\n' +
' <span class="col-1 mt-2 subName">第1阶段</span>\n' + ' <span class="mt-2 subName mr10">第1阶段</span>\n' +
' <div class="flex-1">\n' + ' <div class="flex-1">\n' +
' <div class="row">\n' + ' <div class="row">\n' +
' <span class="mt-2 ml20">有效时间:</span>\n' + ' <div class="row col-6"><span class="mt-2 ml20 mr10">有效时间:</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-4 no_padding ">\n' +
' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' + ' <input type="text" name="stage[][start_time]" id="stage__start_time" value="" autocomplete="off" class="section-start-time form-control" placeholder="有效开始时间">\n' +
' </div>\n' + ' </div>\n' +
' <span class="mt-2">~</span>\n' + ' <span class="mt-2">~</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-4 no_padding input_middle">\n' +
' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' + ' <input type="text" name="stage[][end_time]" id="stage__end_time" value="" autocomplete="off" class="section-end-time form-control" placeholder="有效结束时间">\n' +
' </div>\n' + ' </div></div>\n' +
' <span class="col-2 text-right mt-2 no_padding">总任务数:</span>\n' + ' <div class="row col-3"><span class="col-4 text-right mt-2 no_padding mr10">总任务数:</span>\n' +
' <div class="col-1 no_padding input_small">\n' + ' <div class="col-6 no_padding ">\n' +
' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' + ' <input type="number" class="form-control" onchange="change_total(this)" value="3" name="stage[][entry]">\n' +
' </div>\n' + ' </div></div>\n' +
' <span class="col-1 text-right mt-2 no_padding">成绩来源:</span>\n' + ' <div class="row col-4"><span class="col-3 text-right mt-2 no_padding mr10">成绩来源:</span>\n' +
' <div class="col-2 no_padding input_middle">\n' + ' <div class="col-7 no_padding ">\n' +
' <select class="form-control" name="stage[][score_source]">\n' + ' <select class="form-control" name="stage[][score_source]">\n' +
' <option value="0">经验值</option>\n' + ' <option value="0">经验值</option>\n' +
' <option value="1">预测准确率</option>\n' + ' <option value="1">预测准确率</option>\n' +
' </select>\n' + ' </select>\n' +
' </div>\n' + ' </div></div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="row mt-2" id="task_Input_sub_new_new">\n' + ' <div class="row mt-2" id="task_Input_sub_new_new">\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务1</span>\n' + ' <span class="col-3 text-right mt-3 no_padding mr10">任务1</span>\n' +
' <div class="col-8">\n' + ' <div class="col-8 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务2</span>\n' + ' <span class="col-3 text-right mt-3 no_padding mr10">任务2</span>\n' +
' <div class="col-8">\n' + ' <div class="col-8 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
' <div class="col-4 row task_Input_div">\n' + ' <div class="col-4 row task_Input_div">\n' +
' <span class="col-3 text-center mt-3">任务3</span>\n' + ' <span class="col-3 text-right no_padding mr10 mt-3">任务3</span>\n' +
' <div class="col-8">\n' + ' <div class="col-8 no_padding">\n' +
' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' + ' <input type="text" class="form-control mt-2" name="stage[][identifiers][]" placeholder="请填写实训ID">\n' +
' </div>\n' + ' </div>\n' +
' </div>\n' + ' </div>\n' +
@ -138085,6 +138168,52 @@ $(document).on('turbolinks:load', function() {
}); });
} }
}); });
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.admin-save-competition-prize-modal', function(event){
var $modal = $('.modal.admin-save-competition-prize-modal');
var $form = $modal.find('form.admin-save-competition-prize-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'competition_prize[name]': {
required: true,
maxlength: 10
},
'competition_prize[num]': {
required: true,
digits: true,
min: 1
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
var formMethod = $form.data('form-method')
if ($form.valid()) {
$.ajax({
method: formMethod,
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(data){
if(data && data.status === 0) {
show_success_flash();
$(document).trigger('prize.save.success');
$modal.modal('hide');
} else {
$modal.find('.error').html(data.message)
}
}
});
}
});
})
});
$(document).on('turbolinks:load', function() { $(document).on('turbolinks:load', function() {
var $modal = $('.modal.admin-upload-file-modal'); var $modal = $('.modal.admin-upload-file-modal');
if ($modal.length > 0) { if ($modal.length > 0) {

@ -25681,6 +25681,48 @@ input.form-control {
border: none; border: none;
} }
/* line 91, app/assets/stylesheets/admins/competition_settings.scss */
.admins-competition-settings-index-page .large_panel .task_Input_div:nth-child(3n-2) > span.col-4 {
-webkit-box-flex: 0;
flex: 0 0 81px;
max-width: 81px;
}
/* line 95, app/assets/stylesheets/admins/competition_settings.scss */
.admins-competition-settings-index-page .large_panel .task_Input_div:nth-child(3n-2) {
-webkit-box-flex: 0;
flex: 0 0 50%;
max-width: 50%;
}
/* line 99, app/assets/stylesheets/admins/competition_settings.scss */
.admins-competition-settings-index-page .large_panel .task_Input_div:nth-child(3n-1) {
-webkit-box-flex: 0;
flex: 0 0 25%;
max-width: 25%;
}
/* line 103, app/assets/stylesheets/admins/competition_settings.scss */
.admins-competition-settings-index-page .large_panel .task_Input_div:nth-child(3n) {
-webkit-box-flex: 0;
flex: 0 0 33.3%;
max-width: 33.3%;
}
/* line 107, app/assets/stylesheets/admins/competition_settings.scss */
.admins-competition-settings-index-page .large_panel .task_Input_div:nth-child(3n) > span.col-4 {
-webkit-box-flex: 0;
flex: 0 0 25%;
max-width: 25%;
}
/* line 111, app/assets/stylesheets/admins/competition_settings.scss */
.admins-competition-settings-index-page .large_panel .task_Input_div:nth-child(3n) > div.col-6 {
-webkit-box-flex: 0;
flex: 0 0 58.3%;
max-width: 58.3%;
}
/* line 4, app/assets/stylesheets/admins/cooperatives.scss */ /* line 4, app/assets/stylesheets/admins/cooperatives.scss */
.admins-cooperatives-index-page .coo-img-card .coo-img-item > .drag { .admins-cooperatives-index-page .coo-img-card .coo-img-item > .drag {
cursor: move; cursor: move;
@ -26346,46 +26388,38 @@ input.form-control {
-webkit-transform: none; -webkit-transform: none;
transform: none; transform: none;
} }
/* line 190, app/assets/stylesheets/admins/sidebar.scss */ /* line 190, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active .sidebar-header { #sidebar.active .sidebar-header {
padding: 0px; padding: 0px;
} }
/* line 193, app/assets/stylesheets/admins/sidebar.scss */ /* line 193, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active .sidebar-header .sidebar-header-logo { #sidebar.active .sidebar-header .sidebar-header-logo {
display: none; display: none;
} }
/* line 197, app/assets/stylesheets/admins/sidebar.scss */ /* line 197, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active .sidebar-header #sidebarCollapse { #sidebar.active .sidebar-header #sidebarCollapse {
width: 30px; width: 30px;
height: 20px; height: 20px;
} }
/* line 203, app/assets/stylesheets/admins/sidebar.scss */ /* line 203, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active ul li a { #sidebar.active ul li a {
padding: 10px; padding: 10px;
font-size: 0.85em; font-size: 0.85em;
} }
/* line 207, app/assets/stylesheets/admins/sidebar.scss */ /* line 207, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active ul li a i { #sidebar.active ul li a i {
margin-right: 0; margin-right: 0;
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
} }
/* line 214, app/assets/stylesheets/admins/sidebar.scss */ /* line 214, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active > ul > li > a > i { #sidebar.active > ul > li > a > i {
font-size: 1.8em; font-size: 1.8em;
} }
/* line 218, app/assets/stylesheets/admins/sidebar.scss */ /* line 218, app/assets/stylesheets/admins/sidebar.scss */
#sidebar.active ul ul a { #sidebar.active ul ul a {
padding: 10px !important; padding: 10px !important;
} }
/* line 227, app/assets/stylesheets/admins/sidebar.scss */ /* line 227, app/assets/stylesheets/admins/sidebar.scss */
.dropdown-toggle::after { .dropdown-toggle::after {
top: auto; top: auto;

@ -29891,13 +29891,35 @@ function customConfirm(opts){
return $.confirm($.extend({}, defaultOpts, opts)) return $.confirm($.extend({}, defaultOpts, opts))
} }
function show_success_flash(){ function customLoading(opts) {
var loading;
var defaultOpts = {
content: opts.ajax,
contentLoaded: function(){
setTimeout(function(){
loading.close()
}, 200);
}
}
loading = $.confirm($.extend({}, defaultOpts, opts));
return loading;
}
function show_success_flash(message){
$.notify({ $.notify({
message: '操作成功' message: message || '操作成功'
},{ },{
type: 'success' type: 'success'
}); });
} }
function showErrorNotify(message){
$.notify({
message: message || '操作失败'
},{
type: 'danger'
});
}
; ;
(function (global, factory) { (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :

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