bep40 commited on
Commit
5f86a9d
·
verified ·
1 Parent(s): a08eb83

Khôi phục vai-fix-order-download-v1042.js về commit a75919ca

Browse files
Files changed (1) hide show
  1. vai-fix-order-download-v1042.js +84 -180
vai-fix-order-download-v1042.js CHANGED
@@ -1,20 +1,17 @@
1
  /**
2
- * V.AI STUDIO - Order Download Fix v1045 FINAL
3
  *
4
- * VẤN ĐỀ:
5
- * - Excel/PDF GH chỉ tải 1 lần, download lần 2+ không hoạt động
6
- * - Modal chi tiết đơn hàng bấm "GH Excel" không nhận order data
7
  *
8
  * NGĂN NHÂN GỐC:
9
- * - Hàm exportDeliveryExcel/PDF trong qr-payment.js không nhận tham số order
10
- * - URL.revokeObjectURL được gọi quá sớn
11
- * - Click nhiều lần gây xung đột
12
  *
13
  * FIX:
14
- * - Patch exportDeliveryExcel/PDF để nhận order parameter từ order-store.js
15
  * - Monkey-patch URL.revokeObjectURL để delay 5 phút
16
- * - Thêm click protection (chống bấm nhiều lần)
17
  * - Store blob reference để dùng lại
 
18
  */
19
  (function() {
20
  'use strict';
@@ -23,211 +20,86 @@
23
  var blobRegistry = new Map();
24
  var urlRegistry = new Map();
25
 
26
- // Override revoke để trì hoãn 5 phút
27
  var originalRevoke = URL.revokeObjectURL;
28
  URL.revokeObjectURL = function(url) {
29
  if (!url || !url.startsWith('blob:')) {
30
  return originalRevoke.call(URL, url);
31
  }
 
32
  // Track for delayed cleanup
33
- blobRegistry.set(url, { revoked: false, revokeTime: Date.now() + 300000 });
 
34
  // Do NOT revoke immediately - let it be cleaned on unload
35
  return undefined;
36
  };
37
 
38
- // === HELPER: Convert order to VAIData format ===
39
- function orderToVAIData(order) {
40
- if (!order || !order.items) return null;
41
- return {
42
- qd: {
43
- customer: {
44
- name: order.customer || '',
45
- phone: order.phone || '',
46
- email: order.email || '',
47
- addr: order.addr || '',
48
- date: order.date || ''
49
- },
50
- items: (order.items || []).map(function(it, i) {
51
- return {
52
- stt: i + 1,
53
- image: it.image || '',
54
- name: it.name || '',
55
- model: it.model || '',
56
- specs: it.specs || it.info || '',
57
- qty: it.qty || 1,
58
- price: it.price || it.listPrice || it.discPrice || 0,
59
- discPrice: it.discPrice || it.price || 0,
60
- total: it.total || 0,
61
- note: it.note || ''
62
- };
63
- }),
64
- grandTotal: order.grandTotal || 0
65
- },
66
- fees: order.fees || [],
67
- deposit: order.deposit || 0,
68
- remaining: order.remaining || 0
69
- };
70
- }
71
-
72
- // === CLICK PROTECTION HELPER ===
73
- function setExportButtonState(btn, exporting) {
74
- if (!btn) return;
75
- if (exporting) {
76
- btn.disabled = true;
77
- btn.dataset.vaiExporting = '1';
78
- var origText = btn.innerHTML;
79
- btn.dataset.vaiOrigText = origText;
80
- btn.innerHTML = '<span style="opacity:0.7">⏳</span>';
81
- } else {
82
- btn.disabled = false;
83
- btn.dataset.vaiExporting = '0';
84
- if (btn.dataset.vaiOrigText) {
85
- btn.innerHTML = btn.dataset.vaiOrigText;
86
- }
87
- }
88
- }
89
-
90
- // === PATCH EXPORT FUNCTIONS ===
91
  function patchExportFunctions() {
92
- // Store original functions for fallback
93
- var origExportDeliveryExcel = window.exportDeliveryExcel;
94
- var origExportDeliveryPDF = window.exportDeliveryPDF;
95
-
96
- // Patch exportDeliveryExcel - now accepts order parameter
97
- window.exportDeliveryExcel = async function(order, opt) {
98
- var activeBtn = document.activeElement;
99
- // Click protection
100
- if (activeBtn && activeBtn.dataset.vaiExporting === '1') return;
101
- if (activeBtn) {
102
- setExportButtonState(activeBtn, true);
103
- }
104
-
105
  try {
106
- // If order provided, use it; otherwise fallback to cart
107
- if (order && order.items) {
108
- // Convert order to quote data format
109
- var vaData = orderToVAIData(order);
110
- var code = order.code || 'GH-' + Date.now();
111
-
112
- // Use VAI_QR if available (has the fixed version)
113
- if (window.VAI_QR && window.VAI_QR._doExportDeliveryExcel) {
114
- await window.VAI_QR._doExportDeliveryExcel(vaData.qd, code);
115
- console.log('[Fix v1045] GH Excel exported with order data: ' + code);
116
- return;
117
- }
118
- }
119
-
120
- // Fallback to original or cart-based export
121
- if (origExportDeliveryExcel) {
122
- var result = origExportDeliveryExcel.call(this, order, opt);
123
- // Handle promise if returned
124
  if (result && typeof result.then === 'function') {
125
- return result;
 
 
126
  }
 
 
 
 
 
127
  }
128
  } catch (e) {
129
- console.error('[Fix v1045] Delivery Excel error:', e);
130
- showToast('❌ Xuất Excel thất bại: ' + (e.message || e));
131
- } finally {
132
- // Reset button state after delay
133
- setTimeout(function() {
134
- if (activeBtn) {
135
- setExportButtonState(activeBtn, false);
136
- }
137
- }, 1000);
138
  }
139
  };
140
 
141
- // Patch exportDeliveryPDF - now accepts order parameter
142
- window.exportDeliveryPDF = async function(order, opt) {
143
- var activeBtn = document.activeElement;
144
- // Click protection
145
- if (activeBtn && activeBtn.dataset.vaiExporting === '1') return;
146
- if (activeBtn) {
147
- setExportButtonState(activeBtn, true);
148
- }
149
-
150
  try {
151
- if (order && order.items) {
152
- var vaData = orderToVAIData(order);
153
- var code = order.code || 'GH-' + Date.now();
154
-
155
- if (window.VAI_QR && window.VAI_QR._doExportDeliveryPDF) {
156
- await window.VAI_QR._doExportDeliveryPDF(vaData.qd, code);
157
- console.log('[Fix v1045] GH PDF exported with order data: ' + code);
158
- return;
159
- }
160
- }
161
-
162
- if (origExportDeliveryPDF) {
163
- var result = origExportDeliveryPDF.call(this, order, opt);
164
  if (result && typeof result.then === 'function') {
165
- return result;
 
 
166
  }
 
167
  }
168
  } catch (e) {
169
- console.error('[Fix v1045] Delivery PDF error:', e);
170
- showToast('❌ Xuất PDF thất bại: ' + (e.message || e));
171
- } finally {
172
- setTimeout(function() {
173
- if (activeBtn) {
174
- setExportButtonState(activeBtn, false);
175
- }
176
- }, 1000);
177
  }
178
  };
179
 
180
- // Also patch exportExcel/exportPDF for click protection
181
- var origExportExcel = window.exportExcel;
182
- var origExportPDF = window.exportPDF;
183
-
184
- window.exportExcel = async function() {
185
- var activeBtn = document.activeElement;
186
- if (activeBtn && activeBtn.dataset.vaiExporting === '1') return;
187
- if (activeBtn) setExportButtonState(activeBtn, true);
188
-
189
  try {
190
- if (origExportExcel) {
191
- var result = origExportExcel.call(this);
192
- if (result && typeof result.then === 'function') {
193
- return result.finally(function() {
194
- setTimeout(function() { if (activeBtn) setExportButtonState(activeBtn, false); }, 500);
195
- });
196
- }
197
- }
198
  } catch (e) {
199
- console.error('[Fix v1045] Excel error:', e);
200
- showToast('❌ Xuất Excel thất bại');
201
- } finally {
202
- setTimeout(function() { if (activeBtn) setExportButtonState(activeBtn, false); }, 500);
203
  }
204
  };
205
 
206
- window.exportPDF = async function() {
207
- var activeBtn = document.activeElement;
208
- if (activeBtn && activeBtn.dataset.vaiExporting === '1') return;
209
- if (activeBtn) setExportButtonState(activeBtn, true);
210
-
211
  try {
212
- if (origExportPDF) {
213
- var result = origExportPDF.call(this);
214
- if (result && typeof result.then === 'function') {
215
- return result.finally(function() {
216
- setTimeout(function() { if (activeBtn) setExportButtonState(activeBtn, false); }, 500);
217
- });
218
- }
219
- }
220
  } catch (e) {
221
- console.error('[Fix v1045] PDF error:', e);
222
- showToast('❌ Xuất PDF thất bại');
223
- } finally {
224
- setTimeout(function() { if (activeBtn) setExportButtonState(activeBtn, false); }, 500);
225
  }
226
  };
227
  }
228
 
229
  // === CLEANUP ON PAGE UNLOAD ===
230
  window.addEventListener('pagehide', function() {
 
231
  blobRegistry.forEach(function(info, url) {
232
  if (!info.revoked) {
233
  try {
@@ -239,10 +111,46 @@
239
  blobRegistry.clear();
240
  });
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  // === INIT ===
243
  function init() {
244
  patchExportFunctions();
245
- console.log('[Fix v1045] Loaded - GH Excel/PDF patched with order support + click protection');
 
246
  }
247
 
248
  if (document.readyState === 'loading') {
@@ -251,9 +159,5 @@
251
  init();
252
  }
253
 
254
- // Also run after all scripts load (for HF Spaces dynamic loading)
255
- setTimeout(init, 2000);
256
- setTimeout(init, 5000);
257
-
258
- console.log('[Fix v1045] Module ready');
259
  })();
 
1
  /**
2
+ * V.AI STUDIO - Order Download Fix v1042 FINAL
3
  *
4
+ * VẤN ĐỀ: Excel/PDF chỉ tải 1 lần, download lần 2+ không hoạt động
 
 
5
  *
6
  * NGĂN NHÂN GỐC:
7
+ * - URL.revokeObjectURL() được gọi quá sớm (5s - 60s)
8
+ * - Safari/Firefox cần thời gian download lâu hơn
9
+ * - Blob reference không được giữ
10
  *
11
  * FIX:
 
12
  * - Monkey-patch URL.revokeObjectURL để delay 5 phút
 
13
  * - Store blob reference để dùng lại
14
+ * - Chỉ revoke khi tab unload hoặc timeout
15
  */
16
  (function() {
17
  'use strict';
 
20
  var blobRegistry = new Map();
21
  var urlRegistry = new Map();
22
 
23
+ // Override revoke để trì hoãn
24
  var originalRevoke = URL.revokeObjectURL;
25
  URL.revokeObjectURL = function(url) {
26
  if (!url || !url.startsWith('blob:')) {
27
  return originalRevoke.call(URL, url);
28
  }
29
+
30
  // Track for delayed cleanup
31
+ blobRegistry.set(url, { revoked: false, revokeTime: Date.now() + 300000 }); // 5 minutes
32
+
33
  // Do NOT revoke immediately - let it be cleaned on unload
34
  return undefined;
35
  };
36
 
37
+ // === PATCH window.saveAs / FileSaver pattern ===
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  function patchExportFunctions() {
39
+ // Patch exportExcel
40
+ var origExportExcel = window.exportExcel;
41
+ window.exportExcel = function(order, opt) {
 
 
 
 
 
 
 
 
 
 
42
  try {
43
+ if (origExportExcel) {
44
+ var result = origExportExcel.call(this, order, opt);
45
+ // Clear any pending revoke timer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  if (result && typeof result.then === 'function') {
47
+ result.then(function() {
48
+ console.log('[Fix v1042] Excel export completed');
49
+ }).catch(console.error);
50
  }
51
+ return result;
52
+ }
53
+ // Fallback - try VAI_QR
54
+ if (window.VAI_QR && window.VAI_QR.exportExcel) {
55
+ return window.VAI_QR.exportExcel(orderToVAIData(order), order.code, null, null, !!(opt && opt.bw));
56
  }
57
  } catch (e) {
58
+ console.error('[Fix v1042] Excel export error:', e);
 
 
 
 
 
 
 
 
59
  }
60
  };
61
 
62
+ // Patch exportPDF
63
+ var origExportPDF = window.exportPDF;
64
+ window.exportPDF = function(order, opt) {
 
 
 
 
 
 
65
  try {
66
+ if (origExportPDF) {
67
+ var result = origExportPDF.call(this, order, opt);
 
 
 
 
 
 
 
 
 
 
 
68
  if (result && typeof result.then === 'function') {
69
+ result.then(function() {
70
+ console.log('[Fix v1042] PDF export completed');
71
+ }).catch(console.error);
72
  }
73
+ return result;
74
  }
75
  } catch (e) {
76
+ console.error('[Fix v1042] PDF export error:', e);
 
 
 
 
 
 
 
77
  }
78
  };
79
 
80
+ // Patch delivery exports
81
+ var origDE = window.exportDeliveryExcel;
82
+ window.exportDeliveryExcel = function() {
 
 
 
 
 
 
83
  try {
84
+ if (origDE) return origDE.call(this);
 
 
 
 
 
 
 
85
  } catch (e) {
86
+ console.error('[Fix v1042] Delivery Excel error:', e);
 
 
 
87
  }
88
  };
89
 
90
+ var origDP = window.exportDeliveryPDF;
91
+ window.exportDeliveryPDF = function() {
 
 
 
92
  try {
93
+ if (origDP) return origDP.call(this);
 
 
 
 
 
 
 
94
  } catch (e) {
95
+ console.error('[Fix v1042] Delivery PDF error:', e);
 
 
 
96
  }
97
  };
98
  }
99
 
100
  // === CLEANUP ON PAGE UNLOAD ===
101
  window.addEventListener('pagehide', function() {
102
+ // Revoke all pending blobs when user leaves page
103
  blobRegistry.forEach(function(info, url) {
104
  if (!info.revoked) {
105
  try {
 
111
  blobRegistry.clear();
112
  });
113
 
114
+ // === REMOVE FOOTER BUGS ===
115
+ function removeFooterBugs() {
116
+ var footer = document.querySelector('.footer');
117
+ if (!footer) return;
118
+
119
+ // Remove any elements after footer that look like bugs
120
+ var next = footer.nextElementSibling;
121
+ while (next) {
122
+ var remove = false;
123
+
124
+ // Remove empty divs
125
+ if (next.tagName === 'DIV' && !next.textContent.trim()) {
126
+ remove = true;
127
+ }
128
+
129
+ // Remove scripts with undefined src
130
+ if (next.tagName === 'SCRIPT' && next.src && next.src.includes('undefined')) {
131
+ remove = true;
132
+ }
133
+
134
+ // Remove divs with invalid styles
135
+ if (next.tagName === 'DIV' && next.style.cssText && next.style.cssText.includes('undefined')) {
136
+ remove = true;
137
+ }
138
+
139
+ if (remove) {
140
+ var toRemove = next;
141
+ next = next.nextElementSibling;
142
+ toRemove.remove();
143
+ } else {
144
+ break;
145
+ }
146
+ }
147
+ }
148
+
149
  // === INIT ===
150
  function init() {
151
  patchExportFunctions();
152
+ removeFooterBugs();
153
+ console.log('[Fix v1042] Loaded - 5 minute blob retention + footer cleanup');
154
  }
155
 
156
  if (document.readyState === 'loading') {
 
159
  init();
160
  }
161
 
162
+ console.log('[Fix v1042] Module ready');
 
 
 
 
163
  })();