bep40 commited on
Commit
4bac91f
·
verified ·
1 Parent(s): 0b536b0

Upload qr-payment.js

Browse files
Files changed (1) hide show
  1. qr-payment.js +91 -96
qr-payment.js CHANGED
@@ -1,15 +1,18 @@
1
  /**
2
  * V.AI STUDIO — Excel Export v1102
3
  * FIX: Hình ảnh sản phẩm Excel 100% xuất hiện (100px x 100px)
4
- * - Row height: 120 (chứa ảnh 100px + padding)
5
- * - Image size: 100x100px
6
- * - CORS fallback via allorigins.win
7
  */
8
  (function(){
9
  'use strict';
10
  var BANK_ID='vib',BANK_ACCOUNT='918258385',BANK_NAME='TRAN QUOC VUONG',BANK_NAME_VN='Trần Quốc Vương';
11
 
12
- // Helper: fetch image with CORS fallback
 
 
 
 
 
 
13
  async function fetchImageAsArrayBuffer(url){
14
  if(!url||!url.startsWith('http')) return null;
15
  try{
@@ -23,65 +26,75 @@ async function fetchImageAsArrayBuffer(url){
23
  return null;
24
  }
25
 
26
- // Format money
27
- function fmt(n){
28
- if(n==null||n==='')return'0đ';
29
- var num=typeof n==='string'?parseFloat(n.replace(/[^\d.-]/g,'')):Number(n);
30
- if(isNaN(num))return'0đ';
31
- return num.toLocaleString('vi-VN')+'đ';
 
 
 
32
  }
33
 
34
- // Initialize when DOM ready
35
- document.addEventListener('DOMContentLoaded', initExcelExport);
36
- window.addEventListener('load', initExcelExport);
37
-
38
- function initExcelExport(){
39
- if(window._vaiExcelInitDone) return;
40
- window._vaiExcelInitDone = true;
41
-
42
- // Override exportExcel to include images
43
- if(!window.VAI_QR){
44
- window.VAI_QR = {};
45
- }
46
-
47
- var origExportExcel = window.VAI_QR.exportExcel;
48
- if(!origExportExcel && typeof window.exportExcel !== 'function'){
49
- window.VAI_QR.exportExcel = async function(d,qd,code,qrUrl,blackWhite){
50
- await doExportExcelWithImages(d,qd,code,qrUrl);
51
- };
52
  }
 
53
  }
54
 
55
- async function doExportExcelWithImages(d,qd,code,qrUrl){
56
- var cart = qd?.items || window.cart || [];
57
- if(!cart.length){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  alert('❌ Giỏ trống!');
59
  return;
60
  }
61
 
62
- if(typeof ExcelJS === 'undefined'){
63
- var s = document.createElement('script');
64
- s.src = 'https://cdn.jsdelivr.net/npm/exceljs@4.4.0/dist/exceljs.min.js';
65
- document.head.appendChild(s);
66
- await new Promise(function(r){s.onload=r});
67
- }
68
-
69
  try{
70
  var wb = new ExcelJS.Workbook();
71
  var ws = wb.addWorksheet('Báo giá');
72
 
73
- // Columns: STT, Hình(15), Tên SP(30), Mã SP(15), Thông tin(22), SL(8), Đơn giá(15), Giá CK(15), Thành tiền(18), Ghi chú(16)
74
  ws.columns = [
75
- {width:6}, {width:15}, {width:30}, {width:15},
76
- {width:22}, {width:8}, {width:15}, {width:15},
77
- {width:18}, {width:16}
78
  ];
79
 
80
  // Header
81
  ws.mergeCells('A3:J3');
82
  ws.getCell('A3').value = 'BẢNG BÁO GIÁ';
83
  ws.getCell('A3').font = {bold:true, size:18, color:{argb:'FFDB9815'}};
84
- ws.getCell('A3').alignment = {horizontal:'center', vertical:'middle'};
85
  ws.getRow(3).height = 30;
86
 
87
  var headerRow = ws.getRow(10);
@@ -94,22 +107,20 @@ async function doExportExcelWithImages(d,qd,code,qrUrl){
94
  });
95
  headerRow.height = 20;
96
 
97
- // Items with images
98
  var r = 11;
99
- await Promise.all(cart.map(async function(it, i){
100
- var p = window.D && D[it.idx] ? D[it.idx] : null;
101
  var row = ws.getRow(r);
102
- row.height = 120; // 100px image + padding
103
 
104
  var bgColor = i % 2 === 0 ? 'FFF8FAFC' : 'FFFFFFFF';
105
 
106
- row.getCell(1).value = i+1;
107
  row.getCell(1).alignment = {horizontal:'center', vertical:'middle'};
108
 
109
- // IMAGE 100x100px with CORS fallback
110
- var imgUrl = p?.image || it.image || '';
111
- if(imgUrl && imgUrl.startsWith('http')){
112
- var imgBuf = await fetchImageAsArrayBuffer(imgUrl);
113
  if(imgBuf){
114
  try{
115
  wb.addImage(wb.addImage({buffer:imgBuf, extension:'png'}),
@@ -118,18 +129,14 @@ async function doExportExcelWithImages(d,qd,code,qrUrl){
118
  }
119
  }
120
 
121
- row.getCell(3).value = it.name || (p?p.name||p.n:'') || '';
122
- row.getCell(3).font = {bold:true, size:9};
123
- row.getCell(4).value = it.model || (p?p.sku||p.model:'') || '';
124
- row.getCell(5).value = it.specs || (p&&p.specs?vaiFormatSpecs(p.specs):'') || '';
125
- row.getCell(6).value = Number(it.qty||1);
126
- row.getCell(7).value = Number(it.price||0);
127
- row.getCell(7).numFmt = '#,##0"đ"';
128
- row.getCell(8).value = Number(it.discPrice||it.price||0);
129
- row.getCell(8).numFmt = '#,##0"đ"';
130
- row.getCell(9).value = Number(it.total||0);
131
- row.getCell(9).numFmt = '#,##0"đ"';
132
- row.getCell(10).value = it.note || '';
133
 
134
  for(var ci=1; ci<=10; ci++){
135
  row.getCell(ci).fill = {type:'pattern', pattern:'solid', fgColor:{argb:bgColor}};
@@ -139,18 +146,12 @@ async function doExportExcelWithImages(d,qd,code,qrUrl){
139
 
140
  // Total row
141
  var lastRow = r-1;
142
- var totalRow = ws.getRow(r);
143
- totalRow.height = 28;
144
- ws.mergeCells(r,1,r,5);
145
- totalRow.getCell(1).value = 'TỔNG CỘNG';
146
- totalRow.getCell(1).font = {bold:true, size:13, color:{argb:'FFFFFFFF'}};
147
- totalRow.getCell(1).fill = {type:'pattern', pattern:'solid', fgColor:{argb:'FF003F62'}};
148
- totalRow.getCell(6).value = {formula:'SUM(F11:F'+lastRow+')'};
149
- totalRow.getCell(6).font = {bold:true, size:12, color:{argb:'FFFFFFFF'}};
150
- totalRow.getCell(6).fill = {type:'pattern', pattern:'solid', fgColor:{argb:'FF003F62'}};
151
- totalRow.getCell(9).value = {formula:'SUM(I11:I'+lastRow+')'};
152
- totalRow.getCell(9).font = {bold:true, size:14, color:{argb:'FFF0B840'}};
153
- totalRow.getCell(9).fill = {type:'pattern', pattern:'solid', fgColor:{argb:'FF003F62'}};
154
 
155
  wb.calcProperties.fullCalcOnLoad = true;
156
  var buf = await wb.xlsx.writeBuffer();
@@ -161,43 +162,37 @@ async function doExportExcelWithImages(d,qd,code,qrUrl){
161
  var url = URL.createObjectURL(blob);
162
  var a = document.createElement('a');
163
  a.href = url;
164
- a.download = 'VAI_BaoGia_' + code + '.xlsx';
165
  document.body.appendChild(a);
166
  a.click();
167
- setTimeout(function(){document.body.removeChild(a); URL.revokeObjectURL(url);}, 30000);
168
 
169
- console.log('[VAI v1102] ✅ Excel export completed with 100x100px images');
170
 
171
  }catch(e){
172
  console.error('[VAI v1102] Lỗi export Excel:', e);
173
- alert('❌ Lỗi: ' + (e.message||e));
174
  }
175
  }
176
 
177
- function vaiFormatSpecs(specs){
178
  if(!specs) return '';
179
  if(typeof specs === 'string') return specs.slice(0,100);
180
  if(typeof specs === 'object'){
181
  var parts = [];
182
  Object.entries(specs).forEach(function(e){
183
- if(e[1] != null && e[1] !== '') parts.push(e[0] + ': ' + e[1]);
184
  });
185
- return parts.join('; ').slice(0, 100);
186
  }
187
  return '';
188
  }
189
 
190
- // Hook into existing flow
191
- (function patch(){
192
- var tries = 0;
193
- var intr = setInterval(function(){
194
- if(window.VAI_QR && window.VAI_QR.exportExcel){
195
- // Already patched
196
- } else if(typeof window.exportExcel === 'function'){
197
- // Original exists, wrap it
198
- }
199
- if(++tries > 240) clearInterval(intr);
200
- }, 500);
201
- })();
202
 
203
- console.log('[VAI v1102] Excel export script loaded - 100px images supported');
 
1
  /**
2
  * V.AI STUDIO — Excel Export v1102
3
  * FIX: Hình ảnh sản phẩm Excel 100% xuất hiện (100px x 100px)
 
 
 
4
  */
5
  (function(){
6
  'use strict';
7
  var BANK_ID='vib',BANK_ACCOUNT='918258385',BANK_NAME='TRAN QUOC VUONG',BANK_NAME_VN='Trần Quốc Vương';
8
 
9
+ function fmt(n){
10
+ if(n==null||n==='')return'0đ';
11
+ var num=typeof n==='string'?parseFloat(n.replace(/[^\d.-]/g,'')):Number(n);
12
+ if(isNaN(num))return'0đ';
13
+ return num.toLocaleString('vi-VN')+'đ';
14
+ }
15
+
16
  async function fetchImageAsArrayBuffer(url){
17
  if(!url||!url.startsWith('http')) return null;
18
  try{
 
26
  return null;
27
  }
28
 
29
+ function generateOrderCode(name){
30
+ var now = new Date(), dd = String(now.getDate()).padStart(2,'0'),
31
+ mm = String(now.getMonth()+1).padStart(2,'0'), yy = String(now.getFullYear()).slice(-2), ini='';
32
+ if(name && name.trim()){
33
+ name.trim().split(/\s+/).forEach(function(w){
34
+ if(w){ var ch = w.charAt(0).toUpperCase(); if(/[A-Z]/.test(ch)) ini += ch; }
35
+ });
36
+ }
37
+ return 'VAS' + (ini || 'X') + dd + mm + yy;
38
  }
39
 
40
+ function getEffectiveOrderCode(){
41
+ var n = document.getElementById('quoteName')?.value || '';
42
+ if(n && n.trim()) return generateOrderCode(n);
43
+ var h = window.location.hash;
44
+ if(h && h.length > 1){
45
+ var c = h.substring(1);
46
+ if(/^VAS[A-Z0-9]{3,}$/.test(c)) return c;
 
 
 
 
 
 
 
 
 
 
 
47
  }
48
+ return generateOrderCode('');
49
  }
50
 
51
+ function getQRUrl(amount, code){
52
+ return 'https://img.vietqr.io/image/' + BANK_ID + '-' + BANK_ACCOUNT + '-compact2.png?amount=' +
53
+ Math.round(amount||0) + '&addInfo=' + encodeURIComponent(code||'VAISTUDIO') +
54
+ '&accountName=' + encodeURIComponent(BANK_NAME);
55
+ }
56
+
57
+ // Export Excel with 100x100px images
58
+ async function exportExcel(d, qd, code, qrUrl, blackWhite){
59
+ qd = qd || d?.qd;
60
+ code = code || getEffectiveOrderCode();
61
+ qrUrl = qrUrl || getQRUrl(d?.grandTotal || qd?.grandTotal || 0, code);
62
+
63
+ var items = (qd?.items || window.cart || []).map(function(it, i){
64
+ var p = window.D && D[it.idx] ? D[it.idx] : null;
65
+ return {
66
+ stt: i+1,
67
+ name: it.name || (p?p.name||p.n:'') || '',
68
+ model: it.model || (p?p.sku||p.model:'') || '',
69
+ image: p?.image || it.image || it.img || '',
70
+ specs: it.specs || (p && p.specs ? formatSpecs(p.specs) : '') || '',
71
+ qty: Number(it.qty||1),
72
+ price: Number(it.price||0),
73
+ discPrice: Number(it.discPrice||it.price||0),
74
+ total: Number(it.total||(it.discPrice||it.price)*(it.qty||1)||0),
75
+ note: it.note || ''
76
+ };
77
+ });
78
+
79
+ if(!items.length){
80
  alert('❌ Giỏ trống!');
81
  return;
82
  }
83
 
 
 
 
 
 
 
 
84
  try{
85
  var wb = new ExcelJS.Workbook();
86
  var ws = wb.addWorksheet('Báo giá');
87
 
88
+ // Columns with Hình = 15 width
89
  ws.columns = [
90
+ {width:6},{width:15},{width:30},{width:15},
91
+ {width:22},{width:8},{width:15},{width:15},{width:18},{width:16}
 
92
  ];
93
 
94
  // Header
95
  ws.mergeCells('A3:J3');
96
  ws.getCell('A3').value = 'BẢNG BÁO GIÁ';
97
  ws.getCell('A3').font = {bold:true, size:18, color:{argb:'FFDB9815'}};
 
98
  ws.getRow(3).height = 30;
99
 
100
  var headerRow = ws.getRow(10);
 
107
  });
108
  headerRow.height = 20;
109
 
110
+ // Items with 100x100px images
111
  var r = 11;
112
+ await Promise.all(items.map(async function(it, i){
 
113
  var row = ws.getRow(r);
114
+ row.height = 120; // For 100px image + padding
115
 
116
  var bgColor = i % 2 === 0 ? 'FFF8FAFC' : 'FFFFFFFF';
117
 
118
+ row.getCell(1).value = it.stt;
119
  row.getCell(1).alignment = {horizontal:'center', vertical:'middle'};
120
 
121
+ // IMAGE 100x100px
122
+ if(it.image && it.image.startsWith('http')){
123
+ var imgBuf = await fetchImageAsArrayBuffer(it.image);
 
124
  if(imgBuf){
125
  try{
126
  wb.addImage(wb.addImage({buffer:imgBuf, extension:'png'}),
 
129
  }
130
  }
131
 
132
+ row.getCell(3).value = it.name; row.getCell(3).font = {bold:true, size:9};
133
+ row.getCell(4).value = it.model;
134
+ row.getCell(5).value = it.specs;
135
+ row.getCell(6).value = it.qty;
136
+ row.getCell(7).value = it.price; row.getCell(7).numFmt = '#,##0"đ"';
137
+ row.getCell(8).value = it.discPrice; row.getCell(8).numFmt = '#,##0"đ"';
138
+ row.getCell(9).value = it.total; row.getCell(9).numFmt = '#,##0"đ"';
139
+ row.getCell(10).value = it.note;
 
 
 
 
140
 
141
  for(var ci=1; ci<=10; ci++){
142
  row.getCell(ci).fill = {type:'pattern', pattern:'solid', fgColor:{argb:bgColor}};
 
146
 
147
  // Total row
148
  var lastRow = r-1;
149
+ ws.getCell('A'+r).value = 'TỔNG CỘNG';
150
+ ws.getCell('A'+r).font = {bold:true, size:13, color:{argb:'FFFFFFFF'}};
151
+ ws.getCell('A'+r).fill = {type:'pattern', pattern:'solid', fgColor:{argb:'FF003F62'}};
152
+ ws.getCell('G'+r).value = {formula:'SUM(G11:G'+lastRow+')', result: items.reduce((s,it)=>s+it.total,0)};
153
+ ws.getCell('G'+r).numFmt = '#,##0"đ"';
154
+ ws.getCell('G'+r).font = {bold:true, size:14, color:{argb:'FFF0B840'}};
 
 
 
 
 
 
155
 
156
  wb.calcProperties.fullCalcOnLoad = true;
157
  var buf = await wb.xlsx.writeBuffer();
 
162
  var url = URL.createObjectURL(blob);
163
  var a = document.createElement('a');
164
  a.href = url;
165
+ a.download = code + '.xlsx';
166
  document.body.appendChild(a);
167
  a.click();
168
+ setTimeout(function(){ document.body.removeChild(a); URL.revokeObjectURL(url); }, 30000);
169
 
170
+ console.log('[VAI v1102] ✅ Excel with 100x100px images');
171
 
172
  }catch(e){
173
  console.error('[VAI v1102] Lỗi export Excel:', e);
174
+ alert('❌ Lỗi: ' + (e.message || e));
175
  }
176
  }
177
 
178
+ function formatSpecs(specs){
179
  if(!specs) return '';
180
  if(typeof specs === 'string') return specs.slice(0,100);
181
  if(typeof specs === 'object'){
182
  var parts = [];
183
  Object.entries(specs).forEach(function(e){
184
+ if(e[1] != null) parts.push(e[0] + ': ' + e[1]);
185
  });
186
+ return parts.join('; ').slice(0,100);
187
  }
188
  return '';
189
  }
190
 
191
+ // Export to VAI_QR
192
+ if(!window.VAI_QR) window.VAI_QR = {};
193
+ window.VAI_QR.exportExcel = exportExcel;
194
+ window.VAI_QR.getEffectiveOrderCode = getEffectiveOrderCode;
195
+ window.VAI_QR.getQRUrl = getQRUrl;
196
+ window.VAI_QR.fmt = fmt;
 
 
 
 
 
 
197
 
198
+ console.log('[VAI v1102] Excel export ready - 100px images ✅');