您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Tự động format hóa đơn, đánh số, inject CSS, thêm nút in cho AppSheet trên mobile
// ==UserScript== // @name AppSheet Bill Formatter & Print (Mobile) // @namespace http://tampermonkey.net/ // @version 2.3 // @description Tự động format hóa đơn, đánh số, inject CSS, thêm nút in cho AppSheet trên mobile // @match https://*.appsheet.com/* // @grant none // ==/UserScript== (function() { 'use strict'; // Inject CSS cho hóa đơn (có mobile responsive) function injectBillCss() { if (document.getElementById('bill-css-style')) return; const style = document.createElement('style'); style.id = 'bill-css-style'; style.textContent = ` .CommonLongTextRichTextDisplay { width: 100% !important; font-family: monospace !important; max-width: 100% !important; margin: 0 auto !important; padding: 10px !important; font-size: 12px !important; display: block !important; } @media print { .CommonLongTextRichTextDisplay { margin: 0 !important; padding: 0 !important; } } .CommonLongTextRichTextDisplay table, .CommonLongTextRichTextDisplay h1, .CommonLongTextRichTextDisplay h3, .CommonLongTextRichTextDisplay td, .CommonLongTextRichTextDisplay th, .CommonLongTextRichTextDisplay tr { margin: 0 !important; padding: 2px !important; border: none !important; border-collapse: collapse !important; } .CommonLongTextRichTextDisplay table { width: 100% !important; margin: 0 auto !important; table-layout: fixed !important; } .CommonLongTextRichTextDisplay table:first-of-type { margin-bottom: 4px !important; text-align: center !important; border: none !important; } .CommonLongTextRichTextDisplay table:first-of-type td { text-align: center !important; border: none !important; } .CommonLongTextRichTextDisplay table:first-of-type h1 { font-size: 20px !important; font-weight: 700 !important; letter-spacing: 1px !important; line-height: 1.2 !important; text-align: center !important; } .CommonLongTextRichTextDisplay table:first-of-type h3 { font-size: 11px !important; font-weight: normal !important; line-height: 1.2 !important; text-align: center !important; } .CommonLongTextRichTextDisplay table:nth-of-type(2) { margin: 4px 0 !important; border: none !important; } .CommonLongTextRichTextDisplay table:nth-of-type(2) td { border: none !important; } .CommonLongTextRichTextDisplay table:nth-of-type(2) td:first-child { width: 80px !important; font-weight: 700 !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) { margin: 15px 0 !important; border: 1px solid black !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) th, .CommonLongTextRichTextDisplay table:nth-of-type(3) td { border: 1px solid black !important; padding: 8px !important; text-align: center !important; font-weight: normal !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr td { font-weight: normal !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) td:nth-child(3) { text-align: left !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) td:first-child, .CommonLongTextRichTextDisplay table:nth-of-type(3) th:first-child { width: 50px !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) td:nth-child(2), .CommonLongTextRichTextDisplay table:nth-of-type(3) th:nth-child(2) { width: 120px !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) td:nth-child(4), .CommonLongTextRichTextDisplay table:nth-of-type(3) th:nth-child(4) { width: 80px !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td { border: 1px solid #000 !important; font-weight: normal !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:first-child { text-align: center !important; padding-left: 8px !important; border-right: none !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:nth-child(5) { width: 100px !important; border: 1px solid #000 !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:nth-child(6) { border: 1px solid #000 !important; background: none !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:nth-child(2), .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:nth-child(3), .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:nth-child(4) { border: none !important; background: none !important; } .CommonLongTextRichTextDisplay table:nth-of-type(3) tr:last-child td:first-child[colspan=\"3\"] ~ td { display: none !important; } .CommonLongTextRichTextDisplay table:nth-of-type(4) { margin-top: 5px !important; page-break-inside: avoid !important; } .CommonLongTextRichTextDisplay table:nth-of-type(4) td { text-align: center !important; width: 25% !important; padding: 0 !important; vertical-align: top !important; } .CommonLongTextRichTextDisplay table:nth-of-type(4) strong { display: block !important; margin-bottom: 0px !important; font-weight: normal !important; } .CommonLongTextRichTextDisplay table:nth-of-type(4) p, .CommonLongTextRichTextDisplay table:nth-of-type(4) i { font-style: italic !important; margin: 0 !important; padding: 0 !important; } @media (max-width: 600px) { .CommonLongTextRichTextDisplay table { display: block !important; width: 100% !important; overflow-x: auto !important; box-sizing: border-box !important; } .CommonLongTextRichTextDisplay th, .CommonLongTextRichTextDisplay td { font-size: 11px !important; padding: 4px !important; word-break: break-word !important; } } `; document.head.appendChild(style); } // Đánh số thứ tự và xử lý dòng tổng cộng function numberRows() { const tableContainer = document.querySelector('.CommonLongTextRichTextDisplay'); if (!tableContainer) return; const tables = tableContainer.getElementsByTagName('table'); if (tables.length < 3) return; const productTable = tables[2]; if (!productTable) return; const rows = productTable.rows; if (rows.length < 2) return; // Đánh số thứ tự từ 1 let stt = 1; for (let i = 1; i < rows.length - 1; i++) { const row = rows[i]; if (!row || !row.cells || row.cells.length < 2) continue; const sttCell = row.cells[0]; const codeCell = row.cells[1]; // Chỉ đánh số nếu có mã hàng if (codeCell && codeCell.textContent.trim() !== '') { sttCell.textContent = stt++; sttCell.style.textAlign = 'center'; } } // Xử lý dòng tổng cộng const lastRow = rows[rows.length - 1]; if (lastRow && lastRow.cells.length > 0) { const firstCell = lastRow.cells[0]; if (firstCell.textContent.trim().toLowerCase().includes('tổng')) { firstCell.setAttribute('colspan', '4'); firstCell.style.textAlign = 'left'; firstCell.style.paddingLeft = '8px'; firstCell.style.borderRight = 'none'; lastRow.cells[1].style.display = 'none'; lastRow.cells[2].style.display = 'none'; lastRow.cells[3].style.display = 'none'; } } } // Thêm nút in vào đầu action bar function addPrintButton() { var actionBar = document.querySelector('.SlideshowPage__action-bar'); if (!actionBar || document.getElementById('bookmarklet-print-btn')) return; // Tạo nút in giống các action khác, chỉ icon, dùng đúng class var btn = document.createElement('span'); btn.id = 'bookmarklet-print-btn'; btn.className = 'ASTappable GenericActionButton CSSRolloutContainer OutsideReactRootRollout GenericActionButton--large-mode GenericActionButton--max-height ASTappable--pointer'; btn.setAttribute('tabindex', '0'); btn.setAttribute('role', 'button'); btn.setAttribute('title', 'In hóa đơn'); btn.style = 'margin-left:10px;'; // Sử dụng SVG icon giống action mặc định (nếu AppSheet dùng SVG) btn.innerHTML = ` <div class="GenericActionButton__paddington" style="display:flex;align-items:center;justify-content:center;"> <svg width="28" height="28" viewBox="0 0 24 24" fill="none"> <rect x="3" y="7" width="18" height="13" rx="2" fill="#1976d2"/> <rect x="6" y="3" width="12" height="4" rx="1" fill="#1976d2"/> <rect x="8" y="15" width="8" height="2" rx="1" fill="white"/> <rect x="8" y="11" width="8" height="2" rx="1" fill="white"/> </svg> <span class="sr-only">In hóa đơn</span> </div> `; // Hiệu ứng hover btn.onmouseover = function() { btn.querySelector('rect').setAttribute('fill', '#1251a3'); }; btn.onmouseout = function() { btn.querySelector('rect').setAttribute('fill', '#1976d2'); }; btn.onclick = function() { var el = document.querySelector('.CommonLongTextRichTextDisplay'); if (!el) { alert('Không tìm thấy hóa đơn!'); return; } var clone = el.cloneNode(true); var w = window.open('', '', 'width=1122,height=793'); w.document.write('<html><head><title>In hóa đơn</title><style>' + document.getElementById('bill-css-style').textContent + '</style></head><body>' + clone.outerHTML + '</body></html>'); w.document.close(); setTimeout(function () { w.print(); w.close(); }, 500); }; var wrap = document.createElement('div'); wrap.className = 'SlideshowPage__header-action'; wrap.appendChild(btn); actionBar.insertBefore(wrap, actionBar.firstChild); } // Hàm khởi tạo function initAutoBillFormatter() { injectBillCss(); setTimeout(() => { numberRows(); addPrintButton(); }, 500); // Theo dõi thay đổi DOM để tự động format lại khi cần const observer = new MutationObserver(() => { setTimeout(() => { numberRows(); addPrintButton(); }, 100); }); observer.observe(document.body, { childList: true, subtree: true }); } // Khởi động khi trang load if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAutoBillFormatter); } else { initAutoBillFormatter(); } })();