From a3f6657dfceb062e3e29b24565e2f9aa69751442 Mon Sep 17 00:00:00 2001 From: Bohung Date: Sun, 26 Jun 2022 15:35:23 +0800 Subject: [PATCH] Move export to multithread. --- .../admin/announcements_controller.rb | 53 +++++++++-- ...el.xlsx.axlsx => _export_excel.xlsx.axlsx} | 20 ++++- app/views/admin/announcements/import.html.erb | 87 ++++++++++++++++++- config/locales/en.yml | 1 + config/locales/zh_tw.yml | 1 + config/routes.rb | 1 + 6 files changed, 153 insertions(+), 10 deletions(-) rename app/views/admin/announcements/{export_excel.xlsx.axlsx => _export_excel.xlsx.axlsx} (86%) diff --git a/app/controllers/admin/announcements_controller.rb b/app/controllers/admin/announcements_controller.rb index 7646ffe..7302021 100644 --- a/app/controllers/admin/announcements_controller.rb +++ b/app/controllers/admin/announcements_controller.rb @@ -169,14 +169,54 @@ class Admin::AnnouncementsController < OrbitAdminController end def export_excel - @announcements = Bulletin.all.desc(:created_at) - respond_to do |format| - format.xlsx { - response.headers['Content-Disposition'] = 'attachment; filename="announcement_export.xlsx"' - } + @thread = Multithread.where(:key=>'export_announcements').first + update_flag = true + if @thread.nil? + @thread = Multithread.create(:key=>'export_announcements',:status=>{:status=>'Processing'}) + else + update_flag = false if @thread.status[:status] == 'Processing' && @thread.respond_to?(:updated_at) && (@thread.updated_at > DateTime.now - 1.minute rescue false) + if update_flag + @thread.update(:status=>{:status=>'Processing'}) + end + end + if update_flag + Thread.new do + begin + @announcements = Bulletin.all.desc(:created_at) + last_updated = Bulletin.max(:updated_at).to_i + filename = "public/announcement_export_#{last_updated}.xlsx" + if File.exist?(filename) + @thread.update(:status=>{:status=>'finish','finish_percent'=>100,'info'=>I18n.t('announcement.read_from_cache')}) + else + excel_contents = render_to_string( handlers: [:axlsx], formats: [:xlsx] ,partial: 'export_excel.xlsx',locals: {:@announcements=>@announcements,:@thread=>@thread} ) + File.open(filename, 'w') do |f| + f.write excel_contents + end + end + @thread.status[:file] = filename + @thread.status[:filename] = "announcement_export_#{DateTime.now.in_time_zone(Time.zone.utc_offset / 3600).strftime('%Y_%m_%d_%H%M')}.xlsx" + @thread.save + rescue => e + @thread.status[:status] = 'error' + # @thread.status[:info] = [e.to_s, e.backtrace] + puts [e.to_s, e.backtrace] + @thread.save + end + end + end + redirect_to admin_announcement_import_path(:thread_id=>@thread.id.to_s) + end + def render_404 + render :file => "#{Rails.root}/app/views/errors/404.html", :layout => false, :status => 404, :formats => [:html] + end + def download_file_from_thread + @thread = Multithread.where(:id=>params[:id]).first if params[:id].present? + if @thread && @thread.status[:file] + send_file(@thread.status[:file],:filename=>@thread.status[:filename]) + else + render_404 end end - def import_from_xml download_tmp_xml params["import_xml"] import_from_tmp_xml File.read(File.join(Rails.root, "tmp", "ann_cc_ntu.xml")) @@ -184,6 +224,7 @@ class Admin::AnnouncementsController < OrbitAdminController end def import + @thread = Multithread.where(:id=>params[:thread_id]).first if params[:thread_id].present? end diff --git a/app/views/admin/announcements/export_excel.xlsx.axlsx b/app/views/admin/announcements/_export_excel.xlsx.axlsx similarity index 86% rename from app/views/admin/announcements/export_excel.xlsx.axlsx rename to app/views/admin/announcements/_export_excel.xlsx.axlsx index d2454a2..128cf7c 100644 --- a/app/views/admin/announcements/export_excel.xlsx.axlsx +++ b/app/views/admin/announcements/_export_excel.xlsx.axlsx @@ -123,7 +123,13 @@ wb.add_worksheet(name: "Annoucement") do |sheet| sheet.add_row row, :style => heading sheet.add_row row1 sheet.add_row row2, :style => example - + if @thread + all_count = @announcements.count + puts_every_count = [all_count * 3 / 100, 1].max + current_count = 0 + finish_percent = 0 + @thread.update(:status=>{:status=>'Processing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent}) + end @announcements.each do |anns| row = [] row << categories.to_a.index(anns.category) @@ -168,10 +174,20 @@ wb.add_worksheet(name: "Annoucement") do |sheet| t = files.collect{|l|l.title_translations["zh_tw"]} row << t.join(";") sheet.add_row row + if @thread + current_count += 1 + if current_count % puts_every_count == 0 + finish_percent = (current_count * 100.0 / all_count).round(1) + @thread.update(:status=>{:status=>'Processing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent}) + end + end + end + if @thread + finish_percent = 100 + @thread.update(:status=>{:status=>'finish','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent}) end - end \ No newline at end of file diff --git a/app/views/admin/announcements/import.html.erb b/app/views/admin/announcements/import.html.erb index 00ce443..126758c 100644 --- a/app/views/admin/announcements/import.html.erb +++ b/app/views/admin/announcements/import.html.erb @@ -1,12 +1,41 @@ <% content_for :page_specific_javascript do %> <% end %> +<% if @thread %> + +<% end %>

<%= t("announcement.export_to_excel") %>

<%= t("announcement.import_from_excel") %>

<%= hidden_field_tag :authenticity_token, form_authenticity_token %> @@ -84,4 +113,58 @@ ext = t[t.length - 1]; return (ext == "xml") } + $(document).ready(function(){ + function update_thread(){ + $.post("<%=admin_threads_get_status_path%>",{"id": "<%=params[:thread_id]%>"}).done(function(data){ + var finish_percent = data["finish_percent"]; + var current_count = data["current_count"]; + var all_count = data["all_count"]; + var is_finish = (data["status"] == "finish" || data["status"] == "error"); + var info = data["info"] + if(finish_percent){ + $("#threadModal .modal-body .thread-status").text(data["status"]); + if(data["current_count"]){ + $("#threadModal .modal-body .thread-count-zone").removeClass('hide'); + $("#threadModal .modal-body .thread-current-count").text(current_count); + $("#threadModal .modal-body .thread-all-count").text(all_count); + }else{ + $("#threadModal .modal-body .thread-count-zone").addClass('hide'); + } + $("#threadModal .modal-body .thread-finish_percent").text(finish_percent); + if(info){ + $("#threadModal .modal-body .thread-info").text(info); + } + } + if(!is_finish){ + window.time_out_id = window.setTimeout(update_thread, 1000); + }else{ + var id = "<%=@thread.id if @thread%>"; + var filename = data["filename"]; + if(filename){ + $("#threadModal .modal-body .thread-file").html(`${filename}`); + } + if(window.time_out_id) + window.clearTimeout(window.time_out_id); + // window.setTimeout(function(){ + // $("#threadModal").modal("hide"); + // alert(data["status"]); + // }, 3000); + return; + } + }); + } + if($("#threadModal").length != 0){ + $("#threadModal").on('hidden.bs.modal',function(){ + window.clearTimeout(window.time_out_id); + window.history.replaceState(null,$('title').text(),window.location.pathname); + }) + $("#threadModal").on('shown.bs.modal',function(){ + window.time_out_id = window.setTimeout(update_thread, 1000); + }) + $("#threadModal").modal("show"); + $(".show_progress").click(function(){ + $("#threadModal").modal("show"); + }) + } + }) \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 873c229..ccd2136 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3,6 +3,7 @@ en: feed: Feed import: Import announcement: + read_from_cache: "Read from cache!" delete_selected: "Delete Selected" expired: This announcement has been expired. go_back: Go back to the list of announcements. diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index bd302e9..9c7d21c 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -4,6 +4,7 @@ zh_tw: import: 匯入 get_all_anncs_without_subannc: "選擇相關公告" announcement: + read_from_cache: "從暫存中讀取!" delete_selected: "刪除所選" expired: 此則公告已過期 go_back: 回到公告列表 diff --git a/config/routes.rb b/config/routes.rb index 58fa275..bbfaba3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -28,6 +28,7 @@ Rails.application.routes.draw do get 'announcements/feedform', to: 'announcements#feedform' get 'announcement/settings', to: 'announcements#settings' get 'announcement/import', to: 'announcements#import' + get 'announcement/download_file_from_thread', to: 'announcements#download_file_from_thread' post 'announcement/createsettings', to: 'announcements#createsettings' patch 'announcement/updatesettings', to: 'announcements#updatesettings' post 'announcement/import_from_wp', to: 'announcements#import_from_wp'