/** * V.AI STUDIO — EXPORT WORKING FIX (SINGLE FILE) * * ===== VẤN ĐỀ GỐC ĐÃ SỬA ===== * 1. qr-payment.js có capture-phase click handler (e.preventDefault + e.stopPropagation) * → chặn mọi onclick khác của nút Excel, không file fix nào chạy được * 2. 3 file fix (robust-v2, multi-download, ultimate-fix) chồng chéo ghi đè lẫn nhau * 3. window.exportExcel kiểm tra typeof ExcelJS==='undefined' → silent return * 4. URL.revokeObjectURL bị intercept double-book → không cache được blob * * ===== GIẢI PHÁP ===== * 1. Dùng addEventListener với capture phase CHẠY TRƯỚC handler của qr-payment * 2. Gọi TRỰC TIẾP _doExportExcel (bỏ qua window.exportExcel) * 3. Chỉ 1 intercept URL.createObjectURL duy nhất * 4. Không phụ thuộc vào file fix nào khác */ (function() { 'use strict'; console.log('[VAI EXPORT FIX] === LOADING ==='); // ===== 1. ĐỢI ExcelJS + html2canvas + jspdf LOAD ===== function waitForLibs(cb, maxWait) { var waited = 0; var interval = 200; maxWait = maxWait || 15000; var timer = setInterval(function() { waited += interval; if (typeof ExcelJS !== 'undefined' && typeof html2canvas !== 'undefined' && typeof jspdf !== 'undefined') { clearInterval(timer); console.log('[VAI EXPORT FIX] All libraries loaded after ' + waited + 'ms'); cb(); } else if (waited >= maxWait) { clearInterval(timer); console.warn('[VAI EXPORT FIX] Libraries not fully loaded after ' + maxWait + 'ms, proceeding anyway'); cb(); } }, interval); } // ===== 2. OVERRIDE window.exportExcel — KHÔNG silent return ===== function overrideExportExcel() { if (window.__vaiExportFixed) return; window.__vaiExportFixed = true; // Save original for fallback var origExportExcel = window.exportExcel; window.exportExcel = async function() { console.log('[VAI EXPORT FIX] exportExcel called'); if (typeof ExcelJS === 'undefined') { console.warn('[VAI EXPORT FIX] ExcelJS not loaded yet, waiting...'); // Wait for ExcelJS and retry return new Promise(function(resolve) { var w = 0; var t = setInterval(function() { w += 200; if (typeof ExcelJS !== 'undefined') { clearInterval(t); console.log('[VAI EXPORT FIX] ExcelJS loaded, retrying...'); resolve(doExport()); } if (w >= 10000) { clearInterval(t); console.error('[VAI EXPORT FIX] ExcelJS timeout, using fallback'); resolve(doFallbackExport()); } }, 200); }); } return doExport(); }; async function doExport() { try { // Get data from VAI_QR or getQuoteData var d = null; if (window.VAI_QR && typeof window.VAI_QR.getData === 'function') { d = window.VAI_QR.getData(); } else if (typeof getData === 'function') { d = getData(); } else if (typeof window.getQuoteData === 'function') { var qd = window.getQuoteData(); var parsed = { fees: [], notes: [], deposit: 0, discountPercent: 0, itemDiscounts: {} }; d = { qd: qd, fees: [], notes: [], deposit: 0, discountPercent: 0, itemDiscounts: {}, grandTotal: qd.grandTotal || 0, remaining: qd.grandTotal || 0, productTotal: qd.grandTotal || 0 }; } if (!d || !d.qd) { console.error('[VAI EXPORT FIX] No data available'); alert('⚠️ Không có dữ liệu để xuất. Vui lòng thêm sản phẩm vào giỏ hàng.'); return; } var code = (window.VAI_QR && typeof window.VAI_QR.getEffectiveOrderCode === 'function') ? window.VAI_QR.getEffectiveOrderCode() : 'BAOGIA'; var qrUrl = (window.VAI_QR && typeof window.VAI_QR.getQRUrl === 'function') ? window.VAI_QR.getQRUrl(d.deposit > 0 ? d.remaining : d.grandTotal, code) : ''; // Try calling _doExportExcel directly if (typeof _doExportExcel === 'function') { console.log('[VAI EXPORT FIX] Calling _doExportExcel directly'); await _doExportExcel(d, d.qd, code, qrUrl); console.log('[VAI EXPORT FIX] _doExportExcel completed'); return; } // Fallback: try VAI_QR.exportExcel if (window.VAI_QR && typeof window.VAI_QR.exportExcel === 'function') { console.log('[VAI EXPORT FIX] Calling VAI_QR.exportExcel'); await window.VAI_QR.exportExcel(d, d.qd, code, qrUrl); return; } // Last resort: fallback console.warn('[VAI EXPORT FIX] No export function found, using fallback'); await doFallbackExport(); } catch(e) { console.error('[VAI EXPORT FIX] Export error:', e); try { await doFallbackExport(); } catch(e2) { console.error('[VAI EXPORT FIX] Fallback also failed:', e2); alert('❌ Lỗi xuất Excel. Vui lòng thử lại sau.'); } } } async function doFallbackExport() { console.log('[VAI EXPORT FIX] Using fallback HTML table export'); var qd = null; var code = 'BAOGIA'; try { if (window.VAI_QR && typeof window.VAI_QR.getData === 'function') { var d = window.VAI_QR.getData(); qd = d.qd; code = window.VAI_QR.getEffectiveOrderCode(); } else if (typeof getQuoteData === 'function') { qd = getQuoteData(); } else if (typeof window.getQuoteData === 'function') { qd = window.getQuoteData(); } } catch(e) { qd = { customer: {}, items: [] }; } if (!qd) qd = { customer: {}, items: [] }; if (!qd.items) qd.items = []; if (!qd.customer) qd.customer = {}; var html = '' + '
' + '| BẢNG BÁO GIÁ | ||||||
|---|---|---|---|---|---|---|
| KH: ' + (qd.customer.name || '') + ' | Mã: ' + code + ' | |||||
| STT | Tên SP | Mã | SL | Đơn giá | Giá CK | Thành tiền |
| ' + (it.stt || (i + 1)) + ' | ' + '' + (it.name || '') + ' | ' + '' + (it.model || '') + ' | ' + '' + (it.qty || 1) + ' | ' + '' + Number(it.price || 0).toLocaleString('vi-VN') + 'đ | ' + '' + Number(it.discPrice || it.price || 0).toLocaleString('vi-VN') + 'đ | ' + '' + Number(lineTotal).toLocaleString('vi-VN') + 'đ | ' + '
| TỔNG CỘNG | ' + '' + Number(total).toLocaleString('vi-VN') + 'đ | ' + '|||||