Sản phẩm
Đang tải...
// Load QRCode library với nhiều fallback CDN (function () { var loaded = false; var cdnIndex = 0; var cdns = [ 'https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js', 'https://unpkg.com/qrcode@1.5.3/build/qrcode.min.js', 'https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js' ]; function loadQRCode() { if (loaded) return; if (cdnIndex >= cdns.length) { console.warn('All QRCode CDN sources failed. Will use API fallback.'); // Đánh dấu là sẽ dùng API fallback window.QRCodeUseAPI = true; return; } var script = document.createElement('script'); script.src = cdns[cdnIndex]; script.async = true; script.onload = function () { loaded = true; window.QRCodeUseAPI = false; // Trigger custom event để code khác biết window.dispatchEvent(new Event('qrcode-loaded')); }; script.onerror = function () { console.warn('Failed to load QRCode from:', cdns[cdnIndex]); cdnIndex++; // Thử CDN tiếp theo loadQRCode(); }; document.head.appendChild(script); } // Bắt đầu load loadQRCode(); })(); // Load Html5Qrcode library (function () { var script = document.createElement('script'); script.src = 'https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js'; script.async = true; script.onload = function () { window.dispatchEvent(new Event('html5qrcode-loaded')); }; script.onerror = function () { console.error('Failed to load Html5Qrcode library'); }; document.head.appendChild(script); })();

Mã SKU: Đang tải...

Đã bán 0 | '; // Đợi QRCode library load xong (giảm thời gian đợi xuống 3 giây) waitForQRCode(function (QRCodeLib) { if (!QRCodeLib) { // Fallback: Sử dụng API online generateQRCodeWithAPI(data); return; } // Xóa loading container.innerHTML = ''; // Tạo canvas element const canvas = document.createElement('canvas'); container.appendChild(canvas); // Tạo QR code mới try { QRCodeLib.toCanvas(canvas, data.traceUrl, { width: 300, margin: 2, color: { dark: '#000000', light: '#FFFFFF' } }, function (error) { if (error) { console.error('Error generating QR code:', error); // Fallback: Sử dụng API online generateQRCodeWithAPI(data); } }); } catch (e) { console.error('Exception generating QR code:', e); // Fallback: Sử dụng API online generateQRCodeWithAPI(data); } }, 30); // Giảm từ 50 xuống 30 (3 giây) } // Hiển thị modal QR code function showQRCodeModal() { const modal = document.getElementById('qr-code-modal'); if (!modal) return; const traceData = getProductTraceData(); if (!traceData) { showToastSPNB('Không thể lấy thông tin sản phẩm để tạo mã QR', true); return; } generateQRCode(traceData); modal.classList.remove('hidden'); } // Đóng modal QR code function closeQRCodeModal() { const modal = document.getElementById('qr-code-modal'); if (modal) { modal.classList.add('hidden'); } } // Hiển thị modal quét QR function showScanQRModal() { const modal = document.getElementById('scan-qr-modal'); if (!modal) return; closeQRCodeModal(); modal.classList.remove('hidden'); // Khởi tạo HTML5 QR Code Scanner const readerContainer = document.getElementById('qr-reader'); if (readerContainer && !html5QrCode) { html5QrCode = new Html5Qrcode("qr-reader"); html5QrCode.start( { facingMode: "environment" }, // Sử dụng camera sau { fps: 10, qrbox: { width: 250, height: 250 } }, function (decodedText, decodedResult) { // Khi quét được QR code handleScannedQR(decodedText); }, function (errorMessage) { // Lỗi khi quét (không hiển thị lỗi thường xuyên) } ).catch(function (err) { console.error('Error starting QR scanner:', err); showToastSPNB('Không thể khởi động camera. Vui lòng kiểm tra quyền truy cập camera.', true); }); } } // Đóng modal quét QR function closeScanQRModal() { const modal = document.getElementById('scan-qr-modal'); if (modal) { modal.classList.add('hidden'); } // Dừng scanner if (html5QrCode) { html5QrCode.stop().then(function () { html5QrCode.clear(); html5QrCode = null; }).catch(function (err) { console.error('Error stopping QR scanner:', err); }); } } // Trích productId từ nội dung QR (URL đủ/không scheme, hoặc chỉ số) function extractProductIdFromQrPayload(qrData) { const raw = (qrData || '').toString().trim(); if (!raw) return null; if (/^\d+$/.test(raw)) return raw; function idFromSearch(str) { try { const u = new URL(str); const p = u.searchParams.get('productId'); if (p) { const digits = String(p).replace(/[^\d]/g, ''); return digits || String(p); } } catch (e) { } return null; } let id = idFromSearch(raw); if (id) return id; // Nhiều app quét QR trả về URL không có scheme → new URL() lỗi if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) { id = idFromSearch('https://' + raw.replace(/^\/+/, '')); if (id) return id; } const m1 = raw.match(/[?&#]productId=(\d+)/i); if (m1) return m1[1]; const m2 = raw.match(/productId[=:]\s*(\d+)/i); if (m2) return m2[1]; return null; } // Xử lý khi quét được QR code function handleScannedQR(qrData) { closeScanQRModal(); const productId = extractProductIdFromQrPayload(qrData); if (!productId) { showToastSPNB('Mã QR không hợp lệ. Vui lòng thử lại.', true); return; } showTraceInfoModal(productId); } // Lấy thông tin sản phẩm: ưu tiên API storefront by-id (cùng nguồn với trang chi tiết), // vì headless-commerce-admin-catalog thường yêu cầu quyền admin — khách quét QR sẽ bị lỗi. async function fetchProductTraceInfo(productId) { const idStr = String(productId || '').trim(); if (!idStr) { throw new Error('Thiếu mã sản phẩm'); } const csrf = (typeof Liferay !== 'undefined' && Liferay.authToken) ? Liferay.authToken : ''; const headers = { 'Accept': 'application/json' }; if (csrf) { headers['x-csrf-token'] = csrf; } const fetchOpts = { method: 'GET', headers: headers, credentials: 'include' }; let productData = null; try { const byIdUrl = '/o/gocgac-commerce/v1.0/products/by-id?id=' + encodeURIComponent(idStr); const byIdRes = await fetch(byIdUrl, fetchOpts); if (byIdRes.ok) { const responseText = await byIdRes.text().catch(function () { return ''; }); const trimmed = (responseText || '').trim(); if (trimmed) { try { productData = JSON.parse(trimmed); } catch (e) { console.warn('fetchProductTraceInfo: by-id JSON parse failed', e); } } } } catch (e) { console.error('fetchProductTraceInfo: by-id request error', e); } if (!productData) { try { const adminUrl = APP_CONFIG.API_BASE_ADMIN + '/products/' + encodeURIComponent(idStr); const response = await fetch(adminUrl, fetchOpts); if (response.ok) { productData = (window.safeResponseJson ? await window.safeResponseJson(response) : null); } } catch (e) { console.error('fetchProductTraceInfo: admin product request error', e); } } if (!productData) { throw new Error('Không thể tải thông tin sản phẩm (kiểm tra mạng hoặc đăng nhập).'); } const product = Object.assign({}, productData, { productId: productData.productId != null ? productData.productId : idStr, id: productData.id != null ? productData.id : (productData.productId || idStr) }); let catalogData = null; let accountData = null; const catalogId = product.catalogId || productData.catalogId; if (catalogId) { try { const catalogUrl = APP_CONFIG.API_BASE_ADMIN + '/catalog/' + catalogId; const catalogRes = await fetch(catalogUrl, fetchOpts); if (catalogRes.ok) { catalogData = (window.safeResponseJson ? await window.safeResponseJson(catalogRes) : null); if (catalogData && catalogData.accountId) { try { const accountUrl = APP_CONFIG.API_BASE_ACCOUNT + '/accounts/' + catalogData.accountId; const accountRes = await fetch(accountUrl, fetchOpts); if (accountRes.ok) { accountData = (window.safeResponseJson ? await window.safeResponseJson(accountRes) : null); } } catch (e) { console.error('Error fetching account info:', e); } } } } catch (e) { console.error('Error fetching catalog/account info:', e); } } return { product: product, catalog: catalogData, account: accountData }; } // Hiển thị modal thông tin truy xuất nguồn gốc async function showTraceInfoModal(productId) { const modal = document.getElementById('trace-info-modal'); const content = document.getElementById('trace-info-content'); if (!modal || !content) return; modal.classList.remove('hidden'); // Hiển thị loading content.innerHTML = ` Chia sẻ `; try { const traceInfo = await fetchProductTraceInfo(productId); renderTraceInfo(traceInfo); } catch (error) { const errorMsg = error.message || 'Vui lòng thử lại sau'; content.innerHTML = '
' + '| ' + ' ' + '' + ' ' + ' Truy xuất nguồn gốc

Đảm bảo chất lượng

Giao hàng nhanh

Đóng gói cẩn thận

Thông số kỹ thuật

Thông tin chi tiết về sản phẩm

Đang tải thông số kỹ thuật...

🏢

Đang tải...

—
Xem cửa hàng
Đang tải...

Voucher của cửa hàng

Chọn voucher và nhấn Lưu để dùng khi thanh toán

Đánh giá sản phẩm

0

Dựa trên 0 đánh giá

Gợi ý sản phẩm

Sản phẩm tương tự