diff --git a/app/controllers/admins/competition_stages_controller.rb b/app/controllers/admins/competition_stages_controller.rb
index 1e68b3f50..eb42efe84 100644
--- a/app/controllers/admins/competition_stages_controller.rb
+++ b/app/controllers/admins/competition_stages_controller.rb
@@ -16,85 +16,62 @@ class Admins::CompetitionStagesController < Admins::BaseController
 
   def calculate_stage_score
     if current_stage.max_end_time && current_stage.max_end_time < Time.now
-      current_stage.competition_scores.destroy_all
 
-      if current_stage.competition_stage_sections.size > 0
-        # 是否只有老师参赛
-        only_teacher = current_competition.member_staff.blank?
-        stage_sections = current_stage.competition_stage_sections.includes(:competition_entries)
-        shixuns = Shixun.where(identifier: current_stage.competition_entries.pluck(:shixun_identifier).reject(&:blank?))
-
-
-        # 计算每个战队的成绩
-        current_competition.competition_teams.each do |team|
-          totoal_score = 0
-          total_time = 0
-          user_ids = only_teacher ? team.team_members.pluck(:user_id) : team.team_members.where(is_teacher: 0).pluck(:user_id)
-
-          stage_sections.each do |section|
-            shixun_identifiers = section.competition_entries.pluck(:shixun_identifier).reject(&:blank?)
-            shixun_ids = shixuns.select{ |shixun| shixun_identifiers.include?(shixun.identifier) }.map(&:id)
+      ActiveRecord::Base.transaction do
+        begin
 
+          current_stage.competition_scores.destroy_all
+
+          if current_stage.competition_stage_sections.size > 0
+            # 是否只有老师参赛
+            only_teacher = current_competition.member_staff.blank?
+            stage_sections = current_stage.competition_stage_sections.includes(:competition_entries)
+            shixuns = Shixun.where(identifier: current_stage.competition_entries.pluck(:shixun_identifier).reject(&:blank?))
+            challenges = Challenge.where(shixun_id: shixuns.pluck(:id))
+
+            # 计算每个战队的成绩
+            current_competition.competition_teams.each do |team|
+              totoal_score = 0
+              total_time = 0
+              # 只有老师参赛则计算所有参赛队员的成绩,否则只计算学生的成绩
+              user_ids = only_teacher ? team.team_members.pluck(:user_id) : team.team_members.where(is_teacher: 0).pluck(:user_id)
+
+              stage_sections.each do |section|
+                shixun_identifiers = section.competition_entries.pluck(:shixun_identifier).reject(&:blank?)
+                shixun_ids = shixuns.select{ |shixun| shixun_identifiers.include?(shixun.identifier) }.map(&:id)
+                section_challenges = challenges.select{ |challenge| shixun_ids.include?(challenge.shixun_id) }
+                if section.score_source == 0
+                  result1 = chart_stage_score user_ids, section.start_time, section.end_time, section_challenges, section_challenges.length/shixun_ids.length
+                else
+                  result1 = chart_stage_rate user_ids, section.start_time, section.end_time, section_challenges, section_challenges.length/shixun_ids.length
+                end
+                score = result1[0]
+                time = result1[1]
+
+                totoal_score += score
+                total_time += time
+              end
+
+              # 比赛已截止且未有分数纪录 则创建
+              unless team.competition_scores.exists?(competition_id: current_competition.id, competition_stage_id: current_stage.id)
+                CompetitionScore.create!(user_id: team.user_id, competition_team_id: team.id, competition_id: current_competition.id,
+                                         competition_stage_id: current_stage.id, score: totoal_score, cost_time: total_time)
+              end
+            end
+
+            # 如果计算的是最后一个阶段,则同时计算总成绩(只有一个阶段则不需计算)
+            if current_stage.max_end_time == current_competition.max_stage_end_time && current_competition.competition_stages.size != 0
+              calculate_total_score current_competition
+            end
           end
-        end
-      end
 
-      if @type == "预赛"
-        # 'nyog9r7c','yugrij4n','48flws5g','bfgau7s6','mfv6zrj7','f398leqr','qwaffs2p','ose7482b','y5wh2ofx'
-        # 预赛的实训id  第一阶段:1185,1197,1195  第二阶段:1202, 1210, 1207  第三阶段:1254,1255,1243
-        shixun1_id = [2303]
-        shixun2_id = [2994, 3012, 3024]
-        shixun3_id = [2944, 2938, 2943]
-      elsif @type == "决赛"
-        # '92b7vt8x','a7fxenvc','wt2xfzny','xa4m9cng','tng6heyf','am5o73er','9fla2zry','fzp3iu4w','qlsy6xb4'
-        # 预赛的实训id  第一阶段:1289,1373,1256  第二阶段:1488, 1453, 1487  第三阶段:1470, 1473, 1408
-        shixun1_id = Shixun.where(:identifier => ['ftlc4x38']).pluck(:id)
-        shixun2_id = Shixun.where(:identifier => ['y9npgih2','ucqt7fw3','2p7ouzwk']).pluck(:id)
-        shixun3_id = Shixun.where(:identifier => ['fj49r7xv','gf2cvxfh','cmoxhtbs']).pluck(:id)
-      end
-
-      if @competition.competition_scores.where(:competition_stage_id => @stage.id).count == 0
-        # 三个阶段的开始时间和结束时间
-        s1_time = @stage.competition_stage_sections[0].start_time
-        e1_time = @stage.competition_stage_sections[0].end_time
-        s2_time = @stage.competition_stage_sections[1].start_time
-        e2_time = @stage.competition_stage_sections[1].end_time
-        s3_time = @stage.competition_stage_sections[2].start_time
-        e3_time = @stage.competition_stage_sections[2].end_time
-
-        @records = @competition.competition_teams.includes(:user => [:user_extensions => [:school]])
-        @records.each do |team|
-          user_ids = team.team_members.where(:is_teacher => 0).pluck(:user_id)
-          # 第一阶段的得分和耗时
-          challenges_1 = Challenge.where(:shixun_id => shixun1_id)
-          challenge_rate1 = 1.0
-          result1 = chart_exp_score_pre user_ids, s1_time, e1_time, challenges_1, challenge_rate1, 2
-          score1 = result1[0]
-          time1 = result1[1]
-
-          # 第二阶段的得分和耗时
-          challenge_rate2 = 1.0
-          challenges_2 = Challenge.where(:shixun_id => shixun2_id)
-          result2 = chart_exp_score_pre user_ids, s2_time, e2_time, challenges_2, challenge_rate2, 2
-          score2 = result2[0]
-          time2 = result2[1]
-
-
-          # 第三阶段的得分和耗时
-          challenges_3 = Challenge.where(:shixun_id => shixun3_id)
-          result3 = chart_exp_score_third user_ids, s3_time, e3_time, challenges_3
-          score3 = result3[0]
-          time3 = result3[1]
-
-          team[:s_score] = (score1 + score2 + score3).try(:round, 2)
-          team[:s_spend_time] = time1 + time2 + time3
-
-          # 比赛已截止且未有分数纪录 则创建
-          if Time.now > e3_time && team.competition_scores.where(:competition_id => @competition.id, :competition_stage_id => @stage.id).count == 0
-            CompetitionScore.create(:user_id => team.user_id, :competition_team_id => team.id, :competition_id => @competition.id, :competition_stage_id => @stage.id, :score => team[:s_score], :cost_time => team[:s_spend_time])
-          end
+        rescue Exception => e
+          uid_logger_error(e.message)
+          render_error(e.message)
         end
       end
+
+      render_ok
     else
       render_error("#{current_stage.name}还未结束")
     end
@@ -139,16 +116,16 @@ class Admins::CompetitionStagesController < Admins::BaseController
   # rate 关卡经验值与分数的比值
   # challenge_count 每个实训的关卡数
   # 对三个实训的所有关卡循环: 找到在比赛时间内通关的最低耗时
-  def chart_stage_score user_ids, s_time, e_time, challenges, s_rate, challenge_count
+  def chart_stage_score user_ids, s_time, e_time, challenges, challenge_count
     total_score = 0
     total_time = 0
     length = challenge_count   #每个实训的关卡数
     for i in 1..length
       score = 0
       time = 0
-      challenges.where(:position => i).each do |challenge|
+      challenges.select{|challenge| challenge.position == i}.each do |challenge|
         Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game|
-          game_score = challenge.score * s_rate
+          game_score = challenge.score
           cost_time = (game.end_time.to_i - s_time.to_i) > 0 ? (game.end_time.to_i -  s_time.to_i) : 0
           if score < game_score
             score = game_score
@@ -164,27 +141,50 @@ class Admins::CompetitionStagesController < Admins::BaseController
     return [total_score, total_time]
   end
 
-  def chart_stage_rate user_ids, s_time, e_time, challenges
+  def chart_stage_rate user_ids, s_time, e_time, challenges, challenge_count
     # 第三阶段的得分和耗时
-    score3 = 0
-    time3 = 0
-
-    challenges.each do |challenge|
-      Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game|
-        outputs = game.outputs.select{|output| !output.text_scor.nil? && output.created_at <= e_time }
-        if outputs.present?
-          outputs = outputs.sort { |a, b| b[:text_scor].to_f <=> a[:text_scor].to_f }
-          myshixun_score = outputs.first.text_scor.to_f
-          myshixun_time = outputs.first.created_at.to_i - s_time.to_i
-          if score3 < myshixun_score
-            score3 = myshixun_score
-            time3 = myshixun_time
-          elsif score3 == myshixun_score
-            time3 = myshixun_time > time3 ? time3 : myshixun_time
+    total_score = 0
+    total_time = 0
+    length = challenge_count   #每个实训的关卡数
+    for i in 1..length
+      score3 = 0
+      time3 = 0
+
+      challenges.select{|challenge| challenge.position == i}.each do |challenge|
+        Game.where(:challenge_id => challenge.id, :user_id => user_ids, :status => 2).select{|game| game.open_time >= s_time && game.end_time <= e_time }.each do |game|
+          outputs = game.outputs.select{|output| !output.text_scor.nil? && output.created_at <= e_time }
+          if outputs.present?
+            outputs = outputs.sort { |a, b| b[:text_scor].to_f <=> a[:text_scor].to_f }
+            myshixun_score = outputs.first.text_scor.to_f
+            myshixun_time = outputs.first.created_at.to_i - s_time.to_i
+            if score3 < myshixun_score
+              score3 = myshixun_score
+              time3 = myshixun_time
+            elsif score3 == myshixun_score
+              time3 = myshixun_time > time3 ? time3 : myshixun_time
+            end
           end
         end
       end
+
+      total_score += score3
+      total_time += time3
+    end
+    return [total_score, total_time]
+  end
+
+  def calculate_total_score competition
+    competition.competition_teams.each do |team|
+      total_score = 0
+      total_time = 0
+
+      competition.competition_stages.where("score_rate > 0").each do |stage|
+        stage_score = team.competition_scores.where(competition_stage_id: stage.id).take
+        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)
     end
-    return [score3, time3]
   end
 end
\ No newline at end of file
diff --git a/app/controllers/competitions/competitions_controller.rb b/app/controllers/competitions/competitions_controller.rb
index 85e463d9e..e02ccb4a5 100644
--- a/app/controllers/competitions/competitions_controller.rb
+++ b/app/controllers/competitions/competitions_controller.rb
@@ -118,6 +118,7 @@ class Competitions::CompetitionsController < Competitions::BaseController
     current_team_ids = @competition.team_members.where(user_id: current_user.id).pluck(:competition_team_id).uniq
     @user_ranks = @records.select{|com_team| current_team_ids.include?(com_team.id)}
     @records = @records.where("score > 0")
+    @record_ids = @records.pluck(:id)
     if params[:format] == "xlsx"
       @records = @records.includes(user: [user_extension: :school], team_members: :user)
       respond_to do |format|
diff --git a/app/models/competition.rb b/app/models/competition.rb
index 47be8f9d9..eb1d2a5fa 100644
--- a/app/models/competition.rb
+++ b/app/models/competition.rb
@@ -122,6 +122,10 @@ class Competition < ApplicationRecord
     %w[home enroll inform chart resource]
   end
 
+  def max_stage_end_time
+    competition_stages.map(&:max_end_time).max
+  end
+
   # def awards_count
   #   competition_awards.pluck(:num)&.sum > 0 ? competition_awards.pluck(:num)&.sum : 20
   # end
diff --git a/app/views/admins/competition_settings/index.html.erb b/app/views/admins/competition_settings/index.html.erb
index 392d539ab..1b5052018 100644
--- a/app/views/admins/competition_settings/index.html.erb
+++ b/app/views/admins/competition_settings/index.html.erb
@@ -351,10 +351,10 @@
                       <%= agree_link '发送短信提醒', send_message_admins_competition_competition_stage_path(@competition, stage, element: ".send-message-#{stage.id}"),
                                      class: 'btn btn-outline-primary ml20', 'data-confirm': '确认执行发送短信操作?' %>
                     <% end %>
-                    <% if stage.max_end_time < Time.now %>
+                    <%# if stage.max_end_time && stage.max_end_time < Time.now && Time.now < Time.at(stage.max_end_time.to_i + 30*24*3600) %>
                       <%= agree_link '计算成绩', calculate_stage_score_admins_competition_competition_stage_path(@competition, stage, element: ".calculate-score-#{stage.id}"),
                                      class: 'btn btn-outline-primary ml20', 'data-confirm': '确认执行计算成绩操作?' %>
-                  <% end %>
+                    <%# end %>
                   </div>
                   <%= delete_link '删除', admins_competition_competition_stage_path(competition_id: @competition.id, id: stage.id), class: 'btn btn-default delete-stage ml20' %>
                   <a href="javascript:void(0)" class="btn btn-outline-primary export-action update-stage ml20">保存</a>
diff --git a/app/views/competitions/competitions/charts.json.jbuilder b/app/views/competitions/competitions/charts.json.jbuilder
index e0d501fbd..e1952b5f3 100644
--- a/app/views/competitions/competitions/charts.json.jbuilder
+++ b/app/views/competitions/competitions/charts.json.jbuilder
@@ -1,5 +1,5 @@
 json.user_ranks @user_ranks.each do |user_rank|
-  rank = @records.map(&:id).index(user_rank.id)
+  rank = @record_ids.index(user_rank.id)
   rank = rank.present? ? (rank+1) : 0
   json.rank rank == 0 ? "--" : rank
   json.team_name user_rank.name