Files
Autoparts-DB/pos/static/js/pos-utils.min.js
consultoria-as 21959f1b37 FASE 7d: Lazy Loading + Minificación + Auto-serve minified
Cambios implementados:

1. Lazy loading de imágenes:
   - catalog.js: loading="lazy" decoding="async" en part cards y detail panel
   - inventory.js: lazy loading en imagen de detalle de item

2. Minificación de assets:
   - scripts/minify-assets.sh: minifica JS (terser) y CSS para POS y Dashboard
   - 25 archivos .min.js + 5 .min.css generados en pos/static/
   - 14 archivos .min.js + 8 .min.css generados en dashboard/

3. Nginx auto-serve minified:
   - try_files $1.min.js antes de servir .js original
   - try_files $1.min.css antes de servir .css original
   - Transparente para los templates HTML (cero cambios en HTML)

4. Cache warming script:
   - scripts/warm_vehicle_cache.py: pobla Redis con vehicle info por batches
   - Mitiga DISTINCT ON + 4 JOINs sobre 2B filas
   - Corre en background, procesa ~1.5M parts

Tests: 73/73 pasando
2026-04-27 08:34:24 +00:00

1 line
9.0 KiB
JavaScript

!function(){"use strict";window.exportVisibleTableCSV=function(t){t=t||"datos";for(var e=document.querySelectorAll("table"),o=null,n=0;n<e.length;n++)if(null!==e[n].offsetParent&&e[n].querySelector("tbody tr")){o=e[n];break}if(o){var r=[],a=o.querySelectorAll("thead th");if(a.length&&r.push(Array.from(a).map((function(t){return'"'+t.textContent.trim().replace(/"/g,'""')+'"'})).join(",")),o.querySelectorAll("tbody tr").forEach((function(t){var e=t.querySelectorAll("td");r.push(Array.from(e).map((function(t){return'"'+t.textContent.trim().replace(/"/g,'""')+'"'})).join(","))})),r.length<=1)showToast("La tabla está vacía — no hay datos para exportar.","warn");else{var i=r.join("\n"),l=new Blob(["\ufeff"+i],{type:"text/csv;charset=utf-8;"}),s=URL.createObjectURL(l),c=document.createElement("a");c.href=s,c.download=t+"_nexus_"+(new Date).toISOString().slice(0,10)+".csv",document.body.appendChild(c),c.click(),document.body.removeChild(c),URL.revokeObjectURL(s),showToast("CSV descargado: "+c.download,"ok")}}else showToast("No hay tabla de datos para exportar en esta vista.","warn")},window.printPage=function(){window.print()},window.showToast=function(t,e){e=e||"info";var o=document.getElementById("toast-container");o||((o=document.createElement("div")).id="toast-container",o.style.cssText="position:fixed;top:16px;right:16px;z-index:9999;display:flex;flex-direction:column;gap:8px;pointer-events:none;",document.body.appendChild(o));var n={ok:"background:#1a7a3a;color:#fff;",error:"background:#c0392b;color:#fff;",warn:"background:#d4a017;color:#000;",info:"background:var(--color-surface-3,#333);color:var(--color-text-primary,#fff);"},r=document.createElement("div");r.style.cssText=(n[e]||n.info)+"padding:10px 20px;border-radius:8px;font-size:14px;font-weight:500;box-shadow:0 4px 12px rgba(0,0,0,0.3);pointer-events:auto;animation:slideInRight 0.3s ease;max-width:400px;",r.textContent=t,o.appendChild(r),setTimeout((function(){r.style.opacity="0",r.style.transition="opacity 0.3s",setTimeout((function(){r.remove()}),300)}),3e3)},window.featureProximamente=function(t){showToast((t||"Esta función")+" estará disponible próximamente.","info")};var t=null;function e(t){for(var e=t.querySelectorAll("select[data-filter-column]"),o=document.querySelectorAll("table"),n=null,r=0;r<o.length;r++)if(null!==o[r].offsetParent){n=o[r];break}if(n){var a=n.querySelectorAll("tbody tr");a.forEach((function(t){var o=!0;e.forEach((function(e){var n=parseInt(e.dataset.filterColumn),r=e.value.toLowerCase();if(r){var a=t.querySelectorAll("td");if(a[n])-1===a[n].textContent.trim().toLowerCase().indexOf(r.toLowerCase())&&(o=!1)}})),t.style.display=o?"":"none"}));var i=0;a.forEach((function(t){"none"!==t.style.display&&i++}));var l=document.querySelector(".filter-count-badge");l&&(l.textContent=i+" resultados")}}window.toggleFilterPanel=function(o,n){if(t)return t.remove(),void(t=null);var r=document.createElement("div");r.className="filter-panel",r.style.cssText="position:absolute;top:100%;right:0;z-index:1000;background:var(--glass-bg-strong,#1a1a1a);backdrop-filter:blur(16px);border:1px solid var(--glass-border,#333);border-radius:var(--radius-lg,12px);padding:16px;min-width:260px;box-shadow:0 8px 32px rgba(0,0,0,0.3);display:flex;flex-direction:column;gap:12px;";var a=document.createElement("div");a.style.cssText="font-weight:700;font-size:14px;display:flex;justify-content:space-between;align-items:center;",a.innerHTML='Filtros <button onclick="closeFilterPanel()" style="background:none;border:none;color:var(--color-text-muted);cursor:pointer;font-size:18px;">✕</button>',r.appendChild(a),n.forEach((function(t){var o=document.createElement("div"),n=document.createElement("label");n.style.cssText="display:block;font-size:12px;color:var(--color-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:0.05em;",n.textContent=t.label,o.appendChild(n);var a=document.createElement("select");a.style.cssText="width:100%;padding:8px 10px;background:var(--glass-bg,#222);border:1px solid var(--glass-border,#444);border-radius:6px;color:var(--color-text-primary,#fff);font-size:13px;",a.dataset.filterColumn=t.column;var i=document.createElement("option");i.value="",i.textContent=t.allLabel||"Todos",a.appendChild(i),(t.values||[]).forEach((function(t){if(t){var e=document.createElement("option");e.value=t,e.textContent=t,a.appendChild(e)}})),a.addEventListener("change",(function(){e(r)})),o.appendChild(a),r.appendChild(o)}));var i=document.createElement("button");i.style.cssText="padding:8px;background:transparent;border:1px dashed var(--glass-border,#444);border-radius:6px;color:var(--color-text-muted);cursor:pointer;font-size:12px;",i.textContent="Limpiar filtros",i.addEventListener("click",(function(){r.querySelectorAll("select").forEach((function(t){t.value=""})),e(r)})),r.appendChild(i);var l=o.parentElement;l&&(l.style.position="relative"),(l||document.body).appendChild(r),t=r,setTimeout((function(){document.addEventListener("click",(function t(e){r.contains(e.target)||e.target===o||(closeFilterPanel(),document.removeEventListener("click",t))}))}),100)},window.closeFilterPanel=function(){t&&(t.remove(),t=null)},window.getUniqueColumnValues=function(t,e,o){o=o||30;var n={};return t?(t.querySelectorAll("tbody tr").forEach((function(t){var o=t.querySelectorAll("td");if(o[e]){var r=o[e].textContent.trim();r&&"-"!==r&&""!==r&&(n[r]=(n[r]||0)+1)}})),Object.keys(n).sort((function(t,e){return n[e]-n[t]})).slice(0,o)):[]};var o=null;function n(t,e){fetch("/pos/api/quotations/"+t+"/print",{method:"POST",headers:{Authorization:"Bearer "+e,"Content-Type":"application/json"},body:JSON.stringify({printer_type:"browser"})}).then((function(t){return t.json()})).then((function(o){var n="<html><head><title>Cotización #"+o.id+"</title>";n+="<style>body{font-family:monospace;font-size:12px;width:80mm;margin:0 auto;padding:10px;}",n+="h1{font-size:18px;text-align:center;margin:0;}",n+=".center{text-align:center;}.right{text-align:right;}",n+="hr{border:none;border-top:1px dashed #000;}",n+="table{width:100%;border-collapse:collapse;}td{padding:2px 4px;}</style></head><body>",n+="<h1>COTIZACIÓN</h1>",n+='<p class="center">COT-'+o.id+"</p>",n+="<p>Fecha: "+(o.created_at||"").substring(0,10)+"</p>",o.customer_name&&(n+="<p>Cliente: "+o.customer_name+"</p>"),o.wa_phone&&(n+="<p>WhatsApp: "+o.wa_phone+"</p>"),n+="<hr><table>",(o.items||[]).forEach((function(t){n+="<tr><td>"+t.quantity+"x "+t.name+'</td><td class="right">$'+t.subtotal.toFixed(2)+"</td></tr>",t.part_number&&(n+='<tr><td colspan="2" style="font-size:10px;color:#666;"> #'+t.part_number+"</td></tr>")})),n+="</table><hr>",n+='<p class="right">Subtotal: $'+o.subtotal.toFixed(2)+"</p>",n+='<p class="right">IVA: $'+o.tax_total.toFixed(2)+"</p>",n+='<p class="right" style="font-size:16px;font-weight:bold;">TOTAL: $'+o.total.toFixed(2)+"</p>",n+='<hr><p class="center" style="font-size:10px;">Esta cotización no es comprobante fiscal<br>Precios sujetos a disponibilidad</p>',n+="</body></html>";var a=window.open("","_blank","width=400,height=600");a.document.write(n),a.document.close(),setTimeout((function(){a.print()}),500),r(t,e)})).catch((function(t){console.error("[auto-print] Browser print failed:",t)}))}function r(t,e){fetch("/pos/api/quotations/"+t+"/mark-printed",{method:"POST",headers:{Authorization:"Bearer "+e}}).catch((function(){}))}(window.startAutoPrint=function(){if(!o){0;var t=localStorage.getItem("pos_token");t&&(o=setInterval((function(){fetch("/pos/api/quotations/print-queue",{headers:{Authorization:"Bearer "+t}}).then((function(t){return t.json()})).then((function(e){e.data&&e.data.length&&e.data.forEach((function(e){console.log("[auto-print] Cotización #"+e.id+" confirmada por WhatsApp — imprimiendo..."),showToast("🖨️ Imprimiendo cotización #"+e.id+" (WhatsApp)","ok"),function(t,e){"undefined"!=typeof NexusPrinter&&NexusPrinter.isConnected&&NexusPrinter.isConnected()?fetch("/pos/api/quotations/"+t+"/print",{method:"POST",headers:{Authorization:"Bearer "+e,"Content-Type":"application/json"},body:JSON.stringify({printer_type:"escpos_raw",width:80})}).then((function(t){return t.arrayBuffer()})).then((function(o){NexusPrinter.sendRaw(new Uint8Array(o)),r(t,e)})).catch((function(o){console.error("[auto-print] Thermal print failed:",o),n(t,e)})):n(t,e)}(e.id,t)}))})).catch((function(){}))}),15e3),console.log("[auto-print] Enabled — polling every 15s"))}},window.stopAutoPrint=function(){o&&(clearInterval(o),o=null)},-1!==window.location.pathname.indexOf("/pos/sale")||-1!==window.location.pathname.indexOf("/pos/quotation")||-1!==window.location.pathname.indexOf("/pos/dashboard"))&&(localStorage.getItem("pos_token")&&setTimeout((function(){startAutoPrint()}),3e3));if(!document.getElementById("pos-utils-styles")){var a=document.createElement("style");a.id="pos-utils-styles",a.textContent="@keyframes slideInRight{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}.filter-panel select:focus{outline:none;border-color:var(--color-primary,#F5A623);box-shadow:0 0 0 2px var(--glow-color-soft,rgba(245,166,35,0.15));}",document.head.appendChild(a)}}();