From a6360c5e5dd5d2251d4156b992a5c3ff7e525294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B1=E5=8D=9A=E4=BA=9E?= Date: Sun, 15 Sep 2024 11:41:37 +0800 Subject: [PATCH] Move export to multithread. --- .../admin/event_news_controller.rb | 52 ++++++++++-- .../admin/event_news/export_excel.xlsx.axlsx | 19 ++++- app/views/admin/event_news/import.html.erb | 85 ++++++++++++++++++- config/locales/en.yml | 1 + config/locales/zh_tw.yml | 1 + config/routes.rb | 1 + 6 files changed, 152 insertions(+), 7 deletions(-) diff --git a/app/controllers/admin/event_news_controller.rb b/app/controllers/admin/event_news_controller.rb index 19b87c1..14f260f 100644 --- a/app/controllers/admin/event_news_controller.rb +++ b/app/controllers/admin/event_news_controller.rb @@ -112,11 +112,52 @@ class Admin::EventNewsController < OrbitAdminController end def export_excel - @event_news = EventNews.where(:category_id.ne=>nil).desc(:created_at) - respond_to do |format| - format.xlsx { - response.headers['Content-Disposition'] = 'attachment; filename="event_news_export.xlsx"' - } + @thread = Multithread.where(:key=>'export_event_news').first + update_flag = true + if @thread.nil? + @thread = Multithread.create(:key=>'export_event_news',: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 + @event_news = EventNews.where(:category_id.ne=>nil).desc(:created_at) + last_updated = EventNews.max(:updated_at).to_i + filename = "public/event_news_export_#{last_updated}.xlsx" + if File.exist?(filename) + @thread.update(:status=>{:status=>'finish','finish_percent'=>100,'info'=>I18n.t('event_news.read_from_cache')}) + else + excel_contents = render_to_string( handlers: [:axlsx], formats: [:xlsx] , layout: false, template: 'admin/event_news/export_excel.xlsx', locals: {:@event_news=>@event_news,:@thread=>@thread} ) + File.open(filename, 'w') do |f| + f.write excel_contents + end + end + @thread.status[:file] = filename + @thread.status[:filename] = "event_news_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_event_news_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 @@ -127,6 +168,7 @@ class Admin::EventNewsController < OrbitAdminController end def import + @thread = Multithread.where(:id=>params[:thread_id]).first if params[:thread_id].present? end diff --git a/app/views/admin/event_news/export_excel.xlsx.axlsx b/app/views/admin/event_news/export_excel.xlsx.axlsx index b564b9f..e0bc7eb 100644 --- a/app/views/admin/event_news/export_excel.xlsx.axlsx +++ b/app/views/admin/event_news/export_excel.xlsx.axlsx @@ -165,7 +165,13 @@ wb.add_worksheet(name: "EventNewsModule") do |sheet| sheet.add_row row, :style => heading sheet.add_row row1 sheet.add_row row2, :style => example - + if @thread + all_count = @event_news.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 @event_news.each do |anns| row = [] row << categories.to_a.index(anns.category) @@ -230,6 +236,17 @@ wb.add_worksheet(name: "EventNewsModule") do |sheet| t = carousel_images.collect{|l|l.description_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 diff --git a/app/views/admin/event_news/import.html.erb b/app/views/admin/event_news/import.html.erb index 9b1524a..6464d48 100644 --- a/app/views/admin/event_news/import.html.erb +++ b/app/views/admin/event_news/import.html.erb @@ -1,11 +1,40 @@ <% content_for :page_specific_javascript do %> <% end %> +<% if @thread %> + +<% end %>

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

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

@@ -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 997ec1d..914259e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4,6 +4,7 @@ en: event_news_mod: event_news_mod: Event News event_news: + read_from_cache: "Read from cache!" manually_sort: Manually Sort enable_manually_sort: Enable Manually Sort manual_update_sort: Manually Update Sort diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index bffacff..a2a8fef 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -4,6 +4,7 @@ zh_tw: event_news_mod: event_news_mod: 活動公告 event_news: + read_from_cache: "從暫存中讀取!" manually_sort: 手動排序 enable_manually_sort: 開啟手動排序 manual_update_sort: 手動更新排序 diff --git a/config/routes.rb b/config/routes.rb index fb50bb0..499f0e3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,6 +22,7 @@ Rails.application.routes.draw do get 'event_news/feedform', to: 'event_news#feedform' get 'event_news/settings', to: 'event_news#settings' get 'event_news/import', to: 'event_news#import' + get 'event_news/download_file_from_thread', to: 'event_news#download_file_from_thread' post 'event_news/createsettings', to: 'event_news#createsettings' patch 'event_news/updatesettings', to: 'event_news#updatesettings' post 'event_news/import_from_wp', to: 'event_news#import_from_wp'