diff --git a/app/controllers/admins/competition_stages_controller.rb b/app/controllers/admins/competition_stages_controller.rb index bea2f1a63..c7f95159c 100644 --- a/app/controllers/admins/competition_stages_controller.rb +++ b/app/controllers/admins/competition_stages_controller.rb @@ -60,7 +60,7 @@ class Admins::CompetitionStagesController < Admins::BaseController end # 如果计算的是最后一个阶段,则同时计算总成绩(只有一个阶段则不需计算) - if current_stage.max_end_time == current_competition.max_stage_end_time && current_competition.competition_stages.size != 0 + if current_stage.max_end_time == current_competition.max_stage_end_time && current_competition.competition_stages.size > 1 calculate_total_score current_competition end end @@ -174,6 +174,7 @@ class Admins::CompetitionStagesController < Admins::BaseController end def calculate_total_score competition + competition.competition_scores.where(competition_stage_id: 0).destroy_all competition.competition_teams.each do |team| total_score = 0 total_time = 0 @@ -183,8 +184,11 @@ class Admins::CompetitionStagesController < Admins::BaseController total_score += stage_score.try(:score).to_f * stage.score_rate total_time += stage_score.try(:cost_time).to_i end - CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: competition.id, - competition_stage_id: 0, score: total_score, cost_time: total_time) + + unless team.competition_scores.exists?(competition_id: competition.id, competition_stage_id: 0) + CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: competition.id, + competition_stage_id: 0, score: total_score, cost_time: total_time) + end end end end \ No newline at end of file diff --git a/app/controllers/competitions/competition_modules_controller.rb b/app/controllers/competitions/competition_modules_controller.rb index 8c66368fb..8eec4acc5 100644 --- a/app/controllers/competitions/competition_modules_controller.rb +++ b/app/controllers/competitions/competition_modules_controller.rb @@ -7,7 +7,7 @@ class Competitions::CompetitionModulesController < Competitions::BaseController @modules = current_competition.unhidden_competition_modules.order(position: :asc) # 未登录、未获奖用户,不展示获奖证书栏目 - if !current_user.logged? || !current_competition.competition_prize_users.exists?(user: current_user) + if !current_user.logged? || !current_competition.finished? || !current_competition.competition_prize_users.exists?(user: current_user) @modules = @modules.select { |mod| mod.name != '获奖证书' } end end diff --git a/app/controllers/competitions/competitions_controller.rb b/app/controllers/competitions/competitions_controller.rb index 31ed4367d..1eaa0dc22 100644 --- a/app/controllers/competitions/competitions_controller.rb +++ b/app/controllers/competitions/competitions_controller.rb @@ -44,6 +44,12 @@ class Competitions::CompetitionsController < Competitions::BaseController def common_header @competition = current_competition @competition_modules = @competition.unhidden_competition_modules + + # 未登录、未获奖用户,不展示获奖证书栏目 + if !current_user.logged? || !current_competition.finished? || !current_competition.competition_prize_users.exists?(user: current_user) + @competition_modules = @competition_modules.select { |mod| mod.name != '获奖证书' } + end + @user = current_user current_competition.increment!(:visits) @@ -113,6 +119,8 @@ class Competitions::CompetitionsController < Competitions::BaseController @competition = current_competition if params[:stage_id] @stage = @competition.competition_stages.find_by(id: params[:stage_id]) + elsif @competition.competition_stages.count == 1 + @stage = @competition.competition_stages.take end @records = @competition.competition_teams.joins(:competition_scores).where(competition_scores: {competition_stage_id: @stage&.id.to_i}) diff --git a/app/helpers/competitions_helper.rb b/app/helpers/competitions_helper.rb index b980aba3d..0a5b8804c 100644 --- a/app/helpers/competitions_helper.rb +++ b/app/helpers/competitions_helper.rb @@ -39,9 +39,11 @@ module CompetitionsHelper stages = [] statistic_stages = competition.competition_stages.where("score_rate > 0") - end_time = competition.max_stage_end_time || competition.end_time - if end_time && end_time < Time.now - stages << {id: nil, name: statistic_stages.size > 1 ? "总排行榜" : "排行榜", rate: 1.0, start_time: competition.start_time, end_time: competition.end_time} + unless statistic_stages.size == 1 + end_time = competition.max_stage_end_time || competition.end_time + if end_time && end_time < Time.now + stages << {id: nil, name: statistic_stages.size > 1 ? "总排行榜" : "排行榜", rate: 1.0, start_time: competition.start_time, end_time: competition.end_time} + end end statistic_stages.each do |stage| diff --git a/app/helpers/pdfkit_helper.rb b/app/helpers/pdfkit_helper.rb new file mode 100644 index 000000000..950ccc61f --- /dev/null +++ b/app/helpers/pdfkit_helper.rb @@ -0,0 +1,5 @@ +module PdfkitHelper + def download_image(url) + 'data:image/png;base64,' + Base64.encode64(open(url) { |io| io.read }) + end +end \ No newline at end of file diff --git a/app/jobs/generate_competition_personal_certificate_job.rb b/app/jobs/generate_competition_personal_certificate_job.rb new file mode 100644 index 000000000..efe0c8ff6 --- /dev/null +++ b/app/jobs/generate_competition_personal_certificate_job.rb @@ -0,0 +1,19 @@ +# 生成竞赛个人证书Job +class GenerateCompetitionPersonalCertificateJob < ApplicationJob + queue_as :default + + def perform(prize_user_id) + @prize_user = CompetitionPrizeUser.find_by(id: prize_user_id) + return if @prize_user.blank? || @prize_user.certificate_exist? + + template = @prize_user.user.is_teacher? ? 'teacher' : 'personal' + file = File.open(Rails.root.join("app/templates/competition_certificates/#{template}.html.erb")) + html = ERB.new(file.read).result(binding) + kit = PDFKit.new(html, page_width: 842, page_height: 595) + + path = @prize_user.certificate_path + dir = File.dirname(path) + FileUtils.mkdir_p(dir) unless File.directory?(dir) + kit.to_pdf(path) + end +end \ No newline at end of file diff --git a/app/jobs/generate_competition_team_certificate_job.rb b/app/jobs/generate_competition_team_certificate_job.rb new file mode 100644 index 000000000..4e119c5dc --- /dev/null +++ b/app/jobs/generate_competition_team_certificate_job.rb @@ -0,0 +1,24 @@ +# 生成竞赛团体证书Job +class GenerateCompetitionTeamCertificateJob < ApplicationJob + queue_as :default + + def perform(competition_team_id) + @team = CompetitionTeam.find_by(id: competition_team_id) + @prize = @team&.competition_prize_users&.first&.competition_prize + return if @team.blank? || !@prize.team_certificate_exists? || @team.certificate_exists? + + members = @team.team_members.includes(user: :user_extension).to_a + + @member_names = members.select { |m| !m.user.is_teacher? }.map(&:user_name).join('、') + @teacher_names = members.select { |m| m.user.is_teacher? }.map(&:user_name).join('、') + + file = File.open(Rails.root.join("app/templates/competition_certificates/team.html.erb")) + html = ERB.new(file.read).result(binding) + kit = PDFKit.new(html, page_width: 842, page_height: 595) + + path = @team.certificate_path + dir = File.dirname(path) + FileUtils.mkdir_p(dir) unless File.directory?(dir) + kit.to_pdf(path) + end +end \ No newline at end of file diff --git a/app/models/competition_prize.rb b/app/models/competition_prize.rb index 8acbc6713..dd551fabe 100644 --- a/app/models/competition_prize.rb +++ b/app/models/competition_prize.rb @@ -7,6 +7,30 @@ class CompetitionPrize < ApplicationRecord enumerize :category, in: %i[bonus unset] + def member_certificate_exists? + Util::FileManage.exists?(self, self.class.member_suffix) + end + + def teacher_certificate_exists? + Util::FileManage.exists?(self, self.class.teacher_suffix) + end + + def team_certificate_exists? + Util::FileManage.exists?(self, self.class.team_suffix) + end + + def member_certificate_path + Util::FileManage.source_disk_filename(self, self.class.member_suffix) + end + + def teacher_certificate_path + Util::FileManage.source_disk_filename(self, self.class.teacher_suffix) + end + + def team_certificate_path + Util::FileManage.source_disk_filename(self, self.class.team_suffix) + end + def self.member_suffix '_member' end diff --git a/app/models/team_member.rb b/app/models/team_member.rb index 31890ea2e..90bbe1613 100644 --- a/app/models/team_member.rb +++ b/app/models/team_member.rb @@ -13,4 +13,8 @@ class TeamMember < ApplicationRecord def en_role is_teacher? ? 'teacher' : 'member' end + + def user_name + user&.real_name + end end \ No newline at end of file diff --git a/app/services/admins/approve_competition_prize_user_service.rb b/app/services/admins/approve_competition_prize_user_service.rb index cd1c2101b..efdd72253 100644 --- a/app/services/admins/approve_competition_prize_user_service.rb +++ b/app/services/admins/approve_competition_prize_user_service.rb @@ -1,26 +1,35 @@ class Admins::ApproveCompetitionPrizeUserService < ApplicationService - attr_reader :prize_user, :approver + attr_reader :competition, :prize_user, :approver def initialize(prize_user, approver) - @prize_user = prize_user - @approver = approver + @competition = prize_user.competition + @prize_user = prize_user + @approver = approver end def call raise Error, '请勿重复审批' if prize_user.approved? raise Error, '该用户未认证完成' unless prize_user.user_certified? + prize = prize_user.competition_prize + 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: 生成团队证书 + # 生成个人证书 + # 是老师并且教师证书模板存在 或者是学生而且个人证书模板存在 + if (prize_user.user.is_teacher? && prize.teacher_certificate_exists?) || + (!prize_user.user.is_teacher? && prize.member_certificate_exists?) + GenerateCompetitionPersonalCertificateJob.perform_later(prize_user.id) end - # TODO: 生成个人证书 + # 生成团队证书 + if !competition.personal? && prize_user.competition_team.all_prize_approved? && prize.team_certificate_exists? + GenerateCompetitionTeamCertificateJob.perform_later(prize_user.competition_team.id) + end end end end \ No newline at end of file diff --git a/app/templates/competition_certificates/personal.html.erb b/app/templates/competition_certificates/personal.html.erb new file mode 100644 index 000000000..cec70e5d5 --- /dev/null +++ b/app/templates/competition_certificates/personal.html.erb @@ -0,0 +1,19 @@ + + + + + + + +
+ +
+

<%= @prize_user.user.school_name %> <%= @prize_user.user.real_name %>(学号 <%= @prize_user.student_id %>):

+

+ 荣获第二届“全国高校绿色计算大赛”( <%= @prize_user.competition.sub_title %> )“全国<%= @prize_user.competition_prize.name %>”。 +
特发此证,以资鼓励。 +

+
+
+ + \ No newline at end of file diff --git a/app/templates/competition_certificates/teacher.html.erb b/app/templates/competition_certificates/teacher.html.erb new file mode 100644 index 000000000..d57e620a7 --- /dev/null +++ b/app/templates/competition_certificates/teacher.html.erb @@ -0,0 +1,19 @@ + + + + + + + +
+ +
+

<%= @prize_user.user.school_name %> <%= @prize_user.user.real_name %> 老师:

+

+ 在第二届“全国高校绿色计算大赛”(<%= @prize_user.competition.sub_title %>)中,带领学生团队 表现突出,成绩优异,荣获“优秀指导教师”称号。 +

+

特发此证,以资鼓励。

+
+
+ + \ No newline at end of file diff --git a/app/templates/competition_certificates/team.html.erb b/app/templates/competition_certificates/team.html.erb new file mode 100644 index 000000000..e889d3c62 --- /dev/null +++ b/app/templates/competition_certificates/team.html.erb @@ -0,0 +1,18 @@ + + + + + + + +
+ +
+

+ <%= @member_names %>(指导老师:<%= @teacher_names %>) 在第二届“全国高校绿色计算大赛”(任务挑战组)中成绩突出,荣获“团体 <%= @prize.name %>”。 +

+

特发此证,以资鼓励。

+
+
+ + \ No newline at end of file diff --git a/app/views/admins/competition_settings/index.html.erb b/app/views/admins/competition_settings/index.html.erb index 8547c5a8b..8f483b219 100644 --- a/app/views/admins/competition_settings/index.html.erb +++ b/app/views/admins/competition_settings/index.html.erb @@ -513,7 +513,9 @@
奖项配置 - <%= link_to '新增奖项', new_admins_competition_competition_prize_path(@competition), remote: true, class: 'btn btn-primary btn-sm add-competition-prize-btn' %> + <% unless @competition.competition_prize_users.exists? %> + <%= link_to '新增奖项', new_admins_competition_competition_prize_path(@competition), remote: true, class: 'btn btn-primary btn-sm add-competition-prize-btn' %> + <% end %> <% if @competition.finished? && !@competition.competition_prize_users.exists? %> <%= javascript_void_link '生成获奖记录', class: 'btn btn-primary btn-sm ml-2 generate-prize-user-action' %> diff --git a/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js b/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js index 0109d3d01..a379f2607 100644 --- a/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js +++ b/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js @@ -1,29 +1,28 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import {Tabs} from 'antd'; import axios from 'axios'; -import {markdownToHTML, getImageUrl, AttachmentList} from 'educoder'; +import {markdownToHTML,getImageUrl,AttachmentList} from 'educoder'; import CompetitionContentspdfdownload from './CompetitionContentspdfChild/CompetitionContentspdfdownload'; import CompetitionContentspdfpeopledata from './CompetitionContentspdfChild/CompetitionContentspdfpeopledata'; // import NoneData from "../../../courses/shixunHomework/shixunHomework"; -const {TabPane} = Tabs; - -class CompetitionContentspdf extends Component { +const { TabPane } = Tabs; +class CompetitionContentspdf extends Component{ constructor(props) { super(props) - this.state = { - Tabskey: "1" + this.state={ + Tabskey:"1" } } - componentDidMount() { + componentDidMount(){ window.document.title = '竞赛'; } - Competitioncallback = (key) => { + Competitioncallback=(key)=>{ this.setState({ - Tabskey: key + Tabskey:key }) } @@ -35,18 +34,18 @@ class CompetitionContentspdf extends Component {
this.Competitioncallback(e)} activeKey={this.state.Tabskey}> - - + {this.state.Tabskey==="1"? this.Competitioncallback(e)} - /> + Competitioncallback={(e)=>this.Competitioncallback(e)} + />:""} - + />:""}
@@ -55,5 +54,4 @@ class CompetitionContentspdf extends Component { ) } } - -export default CompetitionContentspdf; +export default CompetitionContentspdf; \ No newline at end of file diff --git a/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js b/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js index 760dca819..dd9e38b6f 100644 --- a/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js +++ b/public/react/src/modules/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js @@ -1,43 +1,42 @@ -import React, {Component} from 'react'; -import {Button, Layout, Row, Col, Divider, Table} from 'antd'; +import React, { Component } from 'react'; +import {Button,Layout,Row, Col,Divider,Table} from 'antd'; import axios from 'axios'; import {getImageUrl} from 'educoder'; import './CompetitionContentspdfdownload.css'; - // import NoneData from "../../../courses/shixunHomework/shixunHomework"; -class CompetitionContentspdfdownload extends Component { +class CompetitionContentspdfdownload extends Component{ constructor(props) { super(props) - this.state = { - data: undefined, - teams: undefined + this.state={ + data:undefined, + teams:undefined } } - componentDidMount() { + componentDidMount(){ window.document.title = '竞赛'; - let url = `/competitions/${this.props.match.params.identifier}/prize.json`; + let url=`/competitions/${this.props.match.params.identifier}/prize.json`; axios.get(url).then((response) => { - if (response.status === 200) { + if(response.status===200){ - let datas = response.data.teams; - if (datas.length > 0) { - datas.map((item, key) => { - let lista = item.team_members; - if (lista.length > 0) { + let datas=response.data.teams; + if(datas.length>0){ + datas.map((item,key)=>{ + let lista=item.team_members; + if(lista.length>0){ console.log(lista) - lista.map((i, k) => { - i["bank_account"] = item.bank_account; + lista.map((i,k)=>{ + i["bank_account"]=item.bank_account; }) } }) } this.setState({ - data: response.data, - teams: datas, + data:response.data, + teams:datas, }) } }).catch((error) => { @@ -48,96 +47,88 @@ class CompetitionContentspdfdownload extends Component { render() { - let {data, teams} = this.state; + + let {data,teams}=this.state; const columns = [ - { - title: '角色', - dataIndex: 'type', - key: 'type', - render: (text, record) => ( - + { + title: '角色', + dataIndex: 'type', + key: 'type', + render: (text, record) => ( + {record.role} - ), - }, - { - title: '姓名', - dataIndex: 'name', - key: 'name', - render: (text, record) => ( - + ), + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + render: (text, record) => ( + {record.name} - ), - }, - { - title: '实名认证', - dataIndex: 'namecertify', - key: 'namecertify', - render: (text, record) => ( - - {record.real_name_auth === "authed" ? - 已认证 : record.real_name_auth === "authing" ? - 待审核 : record.real_name_auth === "not_authed" ? - 未认证 : ""} + ), + }, + { + title: '实名认证', + dataIndex: 'namecertify', + key: 'namecertify', + render: (text, record) => ( + + {record.real_name_auth==="authed"?已认证:record.real_name_auth==="authing"?待审核:record.real_name_auth==="not_authed"?未认证:""} - ), - }, - { - title: '职业认证', - key: 'certify', - dataIndex: 'certify', - render: (text, record) => ( - - {record.professional_auth === "authed" ? - 已认证 : record.real_name_auth === "authing" ? - 待审核 : record.real_name_auth === "not_authed" ? - 未认证 : ""} + ), + }, + { + title: '职业认证', + key: 'certify', + dataIndex: 'certify', + render: (text, record) => ( + + {record.professional_auth==="authed"?已认证:record.real_name_auth==="authing"?待审核:record.real_name_auth==="not_authed"?未认证:""} - ), - }, - { - title: '手机绑定', - key: 'mobile', - dataIndex: 'mobile', - render: (text, record) => ( - - {record.phone_binded === true ? 已绑定 : - 未绑定} + ), + }, + { + title: '手机绑定', + key: 'mobile', + dataIndex: 'mobile', + render: (text, record) => ( + + {record.phone_binded===true?已绑定:未绑定} - ), - }, - { - title: '邮箱绑定', - key: 'mail', - dataIndex: 'mail', - render: (text, record) => ( - - {record.email_binded === true ? 已绑定 : - 未绑定} + ), + }, + { + title: '邮箱绑定', + key: 'mail', + dataIndex: 'mail', + render: (text, record) => ( + + {record.email_binded===true?已绑定:未绑定} - ), - }, + ), + }, { title: '开户行及银行卡号信息(队长填写)', key: 'idcard', dataIndex: 'idcard', render: (value, record, index) => { - if (index === 0 && record.bank_account != null) { + if (index === 0&&record.bank_account!=null) { return { - children: - {record.bank_account.bank + record.bank_account.second_bank + record.bank_account.card_no}, + children: {record.bank_account.bank + record.bank_account.second_bank + record.bank_account.card_no}, }; } }, }, - ]; + ]; - let people = [{url: '/api/competitions/xxxxx/certificates/1/personal'}, - {url: '/api/competitions/xxxxx/certificates/2/personal'},] + let people=[ { url: '/api/competitions/xxxxx/certificates/1/personal' }, + { url: '/api/competitions/xxxxx/certificates/2/personal' },] return ( @@ -149,16 +140,13 @@ class CompetitionContentspdfdownload extends Component { - 个人证书: {data && data.personal_certifications.length === 0 ? - 暂未生成 原因:还未认证个人信息, this.props.Competitioncallback("2")}>立即查看 : - data && data.personal_certifications.map((item, key) => { - return ( + 个人证书:{data&&data.personal_certifications.length===0?暂未生成 原因:还未认证个人信息,this.props.Competitioncallback("2")}>立即查看: + data&&data.personal_certifications.map((item,key)=>{ + return( - - 立即下载 + + 立即下载 ) })} @@ -166,19 +154,19 @@ class CompetitionContentspdfdownload extends Component { 团队证书: - {data && data.team_certifications.length === 0 ? 暂未生成 - : data && data.team_certifications.map((item, key) => { - return ( + {data&&data.team_certifications.length===0?暂未生成 + :data&&data.team_certifications.map((item,key)=>{ + return( - - 立即下载 + + 立即下载 ) })} - + - {teams && teams.map((item, key) => { - return ( + {teams&&teams.map((item,key)=>{ + return( {item.name}战队信息填报概况 - +
) }) @@ -212,5 +199,4 @@ class CompetitionContentspdfdownload extends Component { ) } } - -export default CompetitionContentspdfdownload; +export default CompetitionContentspdfdownload; \ No newline at end of file