Move export to multithread.

This commit is contained in:
邱博亞 2024-09-15 11:41:37 +08:00
parent 917056ea84
commit a6360c5e5d
6 changed files with 152 additions and 7 deletions

View File

@ -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

View File

@ -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

View File

@ -1,11 +1,40 @@
<% content_for :page_specific_javascript do %>
<script type="text/javascript" src="/assets/validator.js"></script>
<% end %>
<% if @thread %>
<div id="threadModal" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="threadModal" aria-hidden="false">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h3 id="threadModal"><%=t("e_paper.#{@thread.key}")%></h3>
</div>
<div class="modal-body">
<div class="thread-status"><%= @thread.status[:status] %></div>
<div class="thread-count-zone <%= 'hide' unless @thread.status[:current_count]%>">
<span class="thread-current-count"><%= @thread.status[:current_count].to_i %></span>/<span class="thread-all-count"><%= @thread.status[:all_count].to_i %></span>
</div>
<span class="thread-finish_percent"><%= @thread.status[:finish_percent].to_i %></span> % finished
<br>
<span class="thread-info"><%= @thread.status[:info].to_s.html_safe %></span>
<br>
<span class="thread-file">
<% if @thread.status[:filename] %>
<a href="<%=admin_event_news_download_file_from_thread_path(:id=>@thread.id.to_s) %>" title="<%= @thread.status[:filename] %>"><%= @thread.status[:filename] %></a>
<% end %>
</span>
</div>
<div class="modal-footer">
<button class="btn" id="modal-close-btn" style="width: 4em;" data-dismiss="modal" aria-hidden="true"><%=t('close')%></button>
</div>
</div>
</div>
</div>
<% end %>
<form action="<%= admin_event_news_importanns_path %>" method="post" class="form-horizontal main-forms" id="import-anns-xls" enctype="multipart/form-data">
<h3 style="padding-left: 30px;"><%= t("event_news.export_to_excel") %></h3>
<div class="control-group">
<div class="controls">
<a href="<%= admin_event_news_export_excel_path(:format => "xlsx") %>"><%= t("event_news.export_all_anns") %></a>
<a href="<%= admin_event_news_export_excel_path %>"><%= t("event_news.export_all_anns") %></a>
</div>
</div>
<h3 style="padding-left: 30px;"><%= t("event_news.import_from_excel") %></h3>
@ -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(`<a href="<%=admin_event_news_download_file_from_thread_path%>?id=${id}" title="${filename}">${filename}</a>`);
}
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");
})
}
})
</script>

View File

@ -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

View File

@ -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: 手動更新排序

View File

@ -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'