V.AISTUDIO / vai-excel-fix.js
bep40's picture
Upload vai-excel-fix.js
af4db02 verified
Raw
History Blame
5.99 kB
/**
* V.AI STUDIO — Excel & PDF Export Ultimate Fix v2.0
* ==============================================
* FIX: File Excel chỉ tải được 1 lần, lần 2+ thất bại
*
* GIẢI PHÁP:
* - KHÔNG revoke blob URL - cleanup khi tab đóng
* - Tạo filename unique
* - Sử dụng ExcelJS cho GH Excel để xuất .xlsx thật
*/
(function() {
'use strict';
// Registry quản lý blob URLs
var blobRegistry = [];
var isUnloading = false;
// Cleanup khi tab đóng
function cleanupBlobs() {
isUnloading = true;
blobRegistry.forEach(function(e) {
if (!e.revoked && e.url) {
try { URL.revokeObjectURL(e.url); e.revoked = true; } catch (err) {}
}
});
blobRegistry = [];
}
window.addEventListener('pagehide', cleanupBlobs);
window.addEventListener('beforeunload', cleanupBlobs);
window.addEventListener('unload', cleanupBlobs);
// PATCH URL.revokeObjectURL - không revoke blob URLs khi chưa unload
(function() {
var origRevoke = URL.revokeObjectURL;
URL.revokeObjectURL = function(url) {
if (isUnloading || !url || typeof url !== 'string' || !url.startsWith('blob:')) {
return origRevoke.apply(this, arguments);
}
var found = blobRegistry.find(function(e) { return e.url === url; });
if (!found) {
blobRegistry.push({ url: url, revoked: false, created: Date.now() });
}
};
})();
// Hàm download - KHÔNG revoke
function downloadBlob(blob, filename) {
var url = URL.createObjectURL(blob);
blobRegistry.push({ url: url, revoked: false, created: Date.now() });
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.style.cssText = 'position:fixed;top:-100px;left:-100px;width:1px;height:1px;';
document.body.appendChild(a);
a.click();
setTimeout(function() {
try { document.body.removeChild(a); } catch(e) {}
}, 100);
}
// ===== FIX: exportDeliveryExcel =====
window.exportDeliveryExcel = async function(order, opt) {
if (typeof ExcelJS === 'undefined') {
if (typeof showToast === 'function') showToast('⚠️ Chưa có ExcelJS');
return;
}
var qd;
if (order && order.items) {
qd = {
customer: {
name: order.customer || '',
phone: order.phone || '',
addr: order.addr || '',
date: order.date || ''
},
items: (order.items || []).map(function(it, i) {
return {
stt: i + 1,
name: it.name || '',
model: it.model || '',
qty: it.qty || 1,
price: it.price || 0,
note: it.note || ''
};
})
};
} else if (window.cart && window.cart.length > 0) {
qd = {
customer: {
name: '',
phone: '',
addr: '',
date: new Date().toLocaleDateString('vi-VN')
},
items: window.cart.map(function(item, idx) {
var p = (window.D && D[item.idx]) ? D[item.idx] : null;
return {
stt: idx + 1,
name: p ? (p.name || p.n || '') : (item.name || ''),
model: p ? (p.sku || p.mod || '') : (item.sku || item.model || ''),
qty: item.qty || 1,
price: item.priceNum || item.price || 0,
note: item.note || ''
};
})
};
} else {
if (typeof showToast === 'function') showToast('⚠️ Giỏ hàng trống!');
return;
}
var code = (order && order.code) ? order.code :
(window.VAI_QR && window.VAI_QR.getEffectiveOrderCode ?
window.VAI_QR.getEffectiveOrderCode() : 'VAS-GH');
try {
var wb = new ExcelJS.Workbook();
var ws = wb.addWorksheet('Phiếu Giao Hàng');
ws.views = [{ showGridLines: false }];
ws.columns = [{ width: 5 }, { width: 34 }, { width: 14 }, { width: 8 }, { width: 20 }];
ws.mergeCells('A1:E1');
ws.getCell('A1').value = 'PHIẾU GIAO HÀNG V.AI STUDIO';
ws.getCell('A1').font = { bold: true, size: 14, color: { argb: 'FF003F62' } };
ws.getCell('A1').alignment = { horizontal: 'center' };
ws.getCell('A1').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF0F7FF' } };
ws.getRow(1).height = 26;
ws.getCell('A2').value = 'Ngày giao:';
ws.getCell('B2').value = new Date().toLocaleDateString('vi-VN');
var hr = ws.getRow(4);
['STT', 'Tên sản phẩm', 'Mã SP', 'SL', 'Ghi chú'].forEach(function(h, i) {
var c = hr.getCell(i + 1);
c.value = h;
c.font = { bold: true, color: { argb: 'FFFFFFFF' } };
c.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF003F62' } };
});
hr.height = 20;
var cr = 5, totalQty = 0;
(qd.items || []).forEach(function(it, i) {
var row = ws.getRow(cr);
row.values = [i + 1, it.name || '', it.model || '', it.qty || 1, it.note || ''];
totalQty += (it.qty || 1);
cr++;
});
var tr = ws.getRow(cr);
ws.mergeCells(cr, 1, cr, 3);
ws.getCell('A' + cr).value = 'TỔNG CỘNG SỐ LƯỢNG';
ws.getCell('A' + cr).font = { bold: true, size: 10, color: { argb: 'FF1E40AF' } };
ws.getCell('D' + cr).value = totalQty;
var buf = await wb.xlsx.writeBuffer();
var blob = new Blob([buf], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
downloadBlob(blob, 'GH-' + code + '.xlsx');
if (typeof showToast === 'function') {
showToast('✅ Đã tải GH-' + code + '.xlsx');
}
} catch (e) {
console.error('exportDeliveryExcel error:', e);
if (typeof showToast === 'function') showToast('❌ Lỗi: ' + e.message);
}
};
console.log('[VAI Excel Fix v2.0] Multi-download enabled - blob cleanup on tab unload');
})();