Bloqueantes POS: modal-pago, ticket-termico, banner-cliente, fkeys-footer, columnas-costo-margen Componentes nuevos: calculadora-cambio, panel-deslizante, badge-cfdi, arbol-colapsable, tarjeta-metrica, grafica-barras, selector-periodo, etiqueta-codigo-barras Estados: estado-vacio, banner-offline, modal-confirmacion Páginas actualizadas: facturación, contabilidad, dashboard, configuración, reportes
508 lines
20 KiB
HTML
508 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="es" data-theme="industrial">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Nexus Autoparts — Columnas Costo y Margen</title>
|
||
<link rel="stylesheet" href="../tokens/tokens.css">
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body {
|
||
font-family: var(--font-body); background: var(--color-bg-base);
|
||
color: var(--color-text-primary); padding: var(--space-8);
|
||
transition: var(--transition-normal);
|
||
}
|
||
.theme-switcher {
|
||
position: sticky; top: 0; z-index: calc(var(--z-modal) + 10);
|
||
display: flex; gap: var(--space-2);
|
||
padding: var(--space-3) var(--space-4);
|
||
background: var(--color-bg-elevated);
|
||
border-bottom: 1px solid var(--color-border);
|
||
margin: calc(-1 * var(--space-8)); margin-bottom: var(--space-8);
|
||
}
|
||
.theme-switcher button {
|
||
padding: var(--space-2) var(--space-4);
|
||
border: 1px solid var(--color-border);
|
||
background: var(--color-bg-base); color: var(--color-text-primary);
|
||
border-radius: var(--radius-md); cursor: pointer;
|
||
font-family: var(--font-body); font-size: var(--text-body-sm);
|
||
transition: var(--transition-fast);
|
||
}
|
||
.theme-switcher button.active {
|
||
background: var(--color-primary); color: var(--color-text-inverse);
|
||
border-color: var(--color-primary);
|
||
}
|
||
h1 { font-family: var(--font-heading); font-size: var(--text-h2);
|
||
font-weight: var(--heading-weight-primary); margin-bottom: var(--space-2);
|
||
color: var(--color-text-accent); }
|
||
.subtitle { color: var(--color-text-muted); font-size: var(--text-body); margin-bottom: var(--space-8); }
|
||
section { margin-bottom: var(--space-10); }
|
||
section > h2 {
|
||
font-family: var(--font-heading); font-size: var(--text-h4);
|
||
font-weight: var(--heading-weight-secondary); color: var(--color-text-secondary);
|
||
margin-bottom: var(--space-4); padding-bottom: var(--space-2);
|
||
border-bottom: 1px solid var(--color-border);
|
||
}
|
||
.label-text {
|
||
font-size: var(--text-caption); color: var(--color-text-muted);
|
||
text-transform: uppercase; letter-spacing: var(--tracking-widest);
|
||
font-weight: var(--font-weight-semibold); margin-bottom: var(--space-3);
|
||
}
|
||
|
||
/* ====== Toggle Permission ====== */
|
||
.perm-toggle {
|
||
display: flex; align-items: center; gap: var(--space-3);
|
||
padding: var(--space-3) var(--space-4);
|
||
background: var(--color-surface-1);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-md);
|
||
margin-bottom: var(--space-4);
|
||
}
|
||
.perm-toggle label {
|
||
font-size: var(--text-body-sm); font-weight: var(--font-weight-semibold);
|
||
color: var(--color-text-secondary); cursor: pointer;
|
||
}
|
||
.toggle-switch {
|
||
position: relative; width: 44px; height: 24px;
|
||
}
|
||
.toggle-switch input {
|
||
opacity: 0; width: 0; height: 0;
|
||
}
|
||
.toggle-slider {
|
||
position: absolute; inset: 0;
|
||
background: var(--color-border-strong);
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer; transition: var(--transition-fast);
|
||
}
|
||
.toggle-slider::after {
|
||
content: ''; position: absolute;
|
||
left: 3px; top: 3px;
|
||
width: 18px; height: 18px;
|
||
background: var(--color-text-primary);
|
||
border-radius: var(--radius-full);
|
||
transition: var(--transition-fast);
|
||
}
|
||
.toggle-switch input:checked + .toggle-slider {
|
||
background: var(--color-primary);
|
||
}
|
||
.toggle-switch input:checked + .toggle-slider::after {
|
||
transform: translateX(20px);
|
||
background: var(--color-text-inverse);
|
||
}
|
||
.perm-badge {
|
||
font-size: var(--text-caption); font-weight: var(--font-weight-semibold);
|
||
padding: 2px var(--space-2); border-radius: var(--radius-sm);
|
||
text-transform: uppercase; letter-spacing: var(--tracking-wide);
|
||
}
|
||
.perm-badge.admin { background: var(--color-primary-muted); color: var(--color-text-accent); }
|
||
.perm-badge.owner { background: var(--color-success-light); color: var(--color-success-dark); }
|
||
|
||
/* ====== Table ====== */
|
||
.sale-table-container {
|
||
background: var(--color-bg-elevated);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
overflow-x: auto;
|
||
}
|
||
.sale-table {
|
||
width: 100%; border-collapse: collapse;
|
||
font-size: var(--text-body-sm);
|
||
}
|
||
.sale-table thead {
|
||
background: var(--color-surface-2);
|
||
}
|
||
.sale-table th {
|
||
padding: var(--space-3) var(--space-4);
|
||
text-align: left; font-weight: var(--font-weight-semibold);
|
||
color: var(--color-text-muted); font-size: var(--text-caption);
|
||
text-transform: uppercase; letter-spacing: var(--tracking-widest);
|
||
border-bottom: 2px solid var(--color-border);
|
||
white-space: nowrap;
|
||
}
|
||
.sale-table td {
|
||
padding: var(--space-3) var(--space-4);
|
||
border-bottom: 1px solid var(--color-border);
|
||
vertical-align: middle;
|
||
}
|
||
.sale-table tbody tr:hover {
|
||
background: var(--color-primary-muted);
|
||
}
|
||
.sale-table th.right, .sale-table td.right { text-align: right; }
|
||
.sale-table th.center, .sale-table td.center { text-align: center; }
|
||
|
||
/* Product cell */
|
||
.product-cell {
|
||
display: flex; flex-direction: column; gap: 2px;
|
||
}
|
||
.product-name {
|
||
font-weight: var(--font-weight-semibold);
|
||
color: var(--color-text-primary);
|
||
}
|
||
.product-sku {
|
||
font-family: var(--font-mono); font-size: 11px;
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
/* Price cells */
|
||
.price {
|
||
font-family: var(--font-mono); font-weight: var(--font-weight-semibold);
|
||
}
|
||
|
||
/* ====== Margin Column Styles ====== */
|
||
.col-cost, .col-margin {
|
||
transition: var(--transition-normal);
|
||
}
|
||
.col-cost.hidden, .col-margin.hidden {
|
||
display: none;
|
||
}
|
||
|
||
.cost-value {
|
||
font-family: var(--font-mono); font-size: var(--text-body-sm);
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
.margin-badge {
|
||
display: inline-flex; align-items: center; gap: 4px;
|
||
padding: 2px var(--space-2);
|
||
border-radius: var(--radius-sm);
|
||
font-family: var(--font-mono); font-size: var(--text-caption);
|
||
font-weight: var(--font-weight-bold);
|
||
white-space: nowrap;
|
||
}
|
||
.margin-high {
|
||
background: var(--color-success-light); color: var(--color-success-dark);
|
||
}
|
||
.margin-mid {
|
||
background: var(--color-warning-light); color: var(--color-warning-dark);
|
||
}
|
||
.margin-low {
|
||
background: var(--color-error-light); color: var(--color-error-dark);
|
||
}
|
||
|
||
/* Margin bar (visual) */
|
||
.margin-bar-container {
|
||
display: flex; align-items: center; gap: var(--space-2);
|
||
}
|
||
.margin-bar {
|
||
width: 60px; height: 6px;
|
||
background: var(--color-surface-3);
|
||
border-radius: var(--radius-full);
|
||
overflow: hidden;
|
||
}
|
||
.margin-bar-fill {
|
||
height: 100%;
|
||
border-radius: var(--radius-full);
|
||
transition: var(--transition-normal);
|
||
}
|
||
.margin-bar-fill.high { background: var(--color-success); }
|
||
.margin-bar-fill.mid { background: var(--color-warning); }
|
||
.margin-bar-fill.low { background: var(--color-error); }
|
||
|
||
/* ====== Totals Row ====== */
|
||
.sale-table tfoot td {
|
||
padding: var(--space-3) var(--space-4);
|
||
font-weight: var(--font-weight-bold);
|
||
border-top: 2px solid var(--color-border);
|
||
background: var(--color-surface-1);
|
||
}
|
||
.total-margin {
|
||
font-family: var(--font-mono); font-size: var(--text-body);
|
||
font-weight: var(--font-weight-bold);
|
||
}
|
||
|
||
/* ====== Legend ====== */
|
||
.legend {
|
||
display: flex; gap: var(--space-6); margin-top: var(--space-4);
|
||
padding: var(--space-3) var(--space-4);
|
||
background: var(--color-surface-1);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-md);
|
||
flex-wrap: wrap;
|
||
}
|
||
.legend-item {
|
||
display: flex; align-items: center; gap: var(--space-2);
|
||
font-size: var(--text-caption); color: var(--color-text-secondary);
|
||
}
|
||
.legend-dot {
|
||
width: 10px; height: 10px; border-radius: var(--radius-full);
|
||
}
|
||
.legend-dot.high { background: var(--color-success); }
|
||
.legend-dot.mid { background: var(--color-warning); }
|
||
.legend-dot.low { background: var(--color-error); }
|
||
|
||
/* ====== Qty controls ====== */
|
||
.qty-cell {
|
||
display: flex; align-items: center; gap: var(--space-1);
|
||
}
|
||
.qty-btn {
|
||
width: 24px; height: 24px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
background: var(--color-surface-2); border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-sm); cursor: pointer;
|
||
font-size: 14px; font-weight: bold;
|
||
color: var(--color-text-secondary);
|
||
transition: var(--transition-fast);
|
||
}
|
||
.qty-btn:hover { background: var(--color-primary-muted); border-color: var(--color-primary); }
|
||
.qty-value {
|
||
min-width: 28px; text-align: center;
|
||
font-family: var(--font-mono); font-weight: var(--font-weight-bold);
|
||
}
|
||
|
||
/* ====== Delete btn ====== */
|
||
.del-btn {
|
||
width: 28px; height: 28px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
background: transparent; border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-sm); cursor: pointer;
|
||
color: var(--color-text-muted); font-size: 14px;
|
||
transition: var(--transition-fast);
|
||
}
|
||
.del-btn:hover { background: var(--color-error-light); color: var(--color-error); border-color: var(--color-error); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- Theme Switcher -->
|
||
<div class="theme-switcher">
|
||
<button class="active" onclick="setTheme('industrial')">A — Industrial Robusto</button>
|
||
<button onclick="setTheme('modern')">B — Técnico Moderno</button>
|
||
</div>
|
||
|
||
<h1>Columnas Costo y Margen</h1>
|
||
<p class="subtitle">2 columnas extra en la tabla de venta, visibles solo con permiso Admin/Owner. Costo unitario + Margen % con color semántico.</p>
|
||
|
||
<!-- ============================================== -->
|
||
<!-- SECTION: With Columns Visible -->
|
||
<!-- ============================================== -->
|
||
<section>
|
||
<h2>Tabla de Venta — Columnas Visibles (Admin/Owner)</h2>
|
||
|
||
<div class="perm-toggle">
|
||
<label class="toggle-switch">
|
||
<input type="checkbox" id="toggle-cols" checked onchange="toggleColumns()">
|
||
<span class="toggle-slider"></span>
|
||
</label>
|
||
<label for="toggle-cols">Mostrar Costo y Margen</label>
|
||
<span class="perm-badge admin">Admin</span>
|
||
<span class="perm-badge owner">Owner</span>
|
||
</div>
|
||
|
||
<div class="sale-table-container">
|
||
<table class="sale-table">
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 32px;">#</th>
|
||
<th>Producto</th>
|
||
<th class="center" style="width: 90px;">Cantidad</th>
|
||
<th class="right">P. Unitario</th>
|
||
<th class="right col-cost">Costo Unit.</th>
|
||
<th class="center col-margin" style="width: 140px;">Margen</th>
|
||
<th class="right">Importe</th>
|
||
<th style="width: 40px;"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<!-- Row 1: High margin -->
|
||
<tr>
|
||
<td style="color: var(--color-text-muted);">1</td>
|
||
<td>
|
||
<div class="product-cell">
|
||
<span class="product-name">Balatas cerám. del. Brembo P68034</span>
|
||
<span class="product-sku">BRM-P68034</span>
|
||
</div>
|
||
</td>
|
||
<td class="center">
|
||
<div class="qty-cell" style="justify-content: center;">
|
||
<button class="qty-btn">-</button>
|
||
<span class="qty-value">2</span>
|
||
<button class="qty-btn">+</button>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$1,250.00</span></td>
|
||
<td class="right col-cost"><span class="cost-value">$720.00</span></td>
|
||
<td class="center col-margin">
|
||
<div class="margin-bar-container" style="justify-content: center;">
|
||
<span class="margin-badge margin-high">42.4%</span>
|
||
<div class="margin-bar"><div class="margin-bar-fill high" style="width: 42.4%;"></div></div>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$2,500.00</span></td>
|
||
<td class="center"><button class="del-btn">✕</button></td>
|
||
</tr>
|
||
|
||
<!-- Row 2: Mid margin -->
|
||
<tr>
|
||
<td style="color: var(--color-text-muted);">2</td>
|
||
<td>
|
||
<div class="product-cell">
|
||
<span class="product-name">Filtro aceite Wix WL7200</span>
|
||
<span class="product-sku">WIX-7200</span>
|
||
</div>
|
||
</td>
|
||
<td class="center">
|
||
<div class="qty-cell" style="justify-content: center;">
|
||
<button class="qty-btn">-</button>
|
||
<span class="qty-value">1</span>
|
||
<button class="qty-btn">+</button>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$185.00</span></td>
|
||
<td class="right col-cost"><span class="cost-value">$138.00</span></td>
|
||
<td class="center col-margin">
|
||
<div class="margin-bar-container" style="justify-content: center;">
|
||
<span class="margin-badge margin-mid">25.4%</span>
|
||
<div class="margin-bar"><div class="margin-bar-fill mid" style="width: 25.4%;"></div></div>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$185.00</span></td>
|
||
<td class="center"><button class="del-btn">✕</button></td>
|
||
</tr>
|
||
|
||
<!-- Row 3: Low margin -->
|
||
<tr>
|
||
<td style="color: var(--color-text-muted);">3</td>
|
||
<td>
|
||
<div class="product-cell">
|
||
<span class="product-name">Amortiguador tras. Monroe OESpec 72364</span>
|
||
<span class="product-sku">MON-72364</span>
|
||
</div>
|
||
</td>
|
||
<td class="center">
|
||
<div class="qty-cell" style="justify-content: center;">
|
||
<button class="qty-btn">-</button>
|
||
<span class="qty-value">2</span>
|
||
<button class="qty-btn">+</button>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$1,071.25</span></td>
|
||
<td class="right col-cost"><span class="cost-value">$950.00</span></td>
|
||
<td class="center col-margin">
|
||
<div class="margin-bar-container" style="justify-content: center;">
|
||
<span class="margin-badge margin-low">11.3%</span>
|
||
<div class="margin-bar"><div class="margin-bar-fill low" style="width: 11.3%;"></div></div>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$2,142.50</span></td>
|
||
<td class="center"><button class="del-btn">✕</button></td>
|
||
</tr>
|
||
|
||
<!-- Row 4: High margin -->
|
||
<tr>
|
||
<td style="color: var(--color-text-muted);">4</td>
|
||
<td>
|
||
<div class="product-cell">
|
||
<span class="product-name">Aceite Motor Mobil 1 5W-30 Sintético 5L</span>
|
||
<span class="product-sku">MOB-5W30-5L</span>
|
||
</div>
|
||
</td>
|
||
<td class="center">
|
||
<div class="qty-cell" style="justify-content: center;">
|
||
<button class="qty-btn">-</button>
|
||
<span class="qty-value">1</span>
|
||
<button class="qty-btn">+</button>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$890.00</span></td>
|
||
<td class="right col-cost"><span class="cost-value">$520.00</span></td>
|
||
<td class="center col-margin">
|
||
<div class="margin-bar-container" style="justify-content: center;">
|
||
<span class="margin-badge margin-high">41.6%</span>
|
||
<div class="margin-bar"><div class="margin-bar-fill high" style="width: 41.6%;"></div></div>
|
||
</div>
|
||
</td>
|
||
<td class="right"><span class="price">$890.00</span></td>
|
||
<td class="center"><button class="del-btn">✕</button></td>
|
||
</tr>
|
||
</tbody>
|
||
<tfoot>
|
||
<tr>
|
||
<td colspan="3" style="text-align: right; color: var(--color-text-muted);">5 artículos, 6 piezas</td>
|
||
<td class="right">Subtotal:</td>
|
||
<td class="right col-cost">
|
||
<span class="cost-value">$4,098.00</span>
|
||
</td>
|
||
<td class="center col-margin">
|
||
<span class="total-margin margin-badge margin-high" style="font-size: var(--text-body-sm);">
|
||
Promedio: 32.8%
|
||
</span>
|
||
</td>
|
||
<td class="right"><span class="price" style="font-size: var(--text-body);">$5,717.50</span></td>
|
||
<td></td>
|
||
</tr>
|
||
</tfoot>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Legend -->
|
||
<div class="legend">
|
||
<div class="legend-item">
|
||
<span class="legend-dot high"></span>
|
||
<span>Verde: margen > 30%</span>
|
||
</div>
|
||
<div class="legend-item">
|
||
<span class="legend-dot mid"></span>
|
||
<span>Amarillo: margen 15% – 30%</span>
|
||
</div>
|
||
<div class="legend-item">
|
||
<span class="legend-dot low"></span>
|
||
<span>Rojo: margen < 15%</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================================== -->
|
||
<!-- SECTION: Margin Badge Variants -->
|
||
<!-- ============================================== -->
|
||
<section>
|
||
<h2>Variantes del Badge de Margen</h2>
|
||
<p class="label-text">Los 3 niveles de color semántico</p>
|
||
|
||
<div style="display: flex; gap: var(--space-6); flex-wrap: wrap; align-items: center;">
|
||
<div style="text-align: center;">
|
||
<p class="label-text">Alto (>30%)</p>
|
||
<div class="margin-bar-container">
|
||
<span class="margin-badge margin-high">42.4%</span>
|
||
<div class="margin-bar" style="width: 80px;"><div class="margin-bar-fill high" style="width: 42.4%;"></div></div>
|
||
</div>
|
||
</div>
|
||
<div style="text-align: center;">
|
||
<p class="label-text">Medio (15-30%)</p>
|
||
<div class="margin-bar-container">
|
||
<span class="margin-badge margin-mid">25.4%</span>
|
||
<div class="margin-bar" style="width: 80px;"><div class="margin-bar-fill mid" style="width: 25.4%;"></div></div>
|
||
</div>
|
||
</div>
|
||
<div style="text-align: center;">
|
||
<p class="label-text">Bajo (<15%)</p>
|
||
<div class="margin-bar-container">
|
||
<span class="margin-badge margin-low">11.3%</span>
|
||
<div class="margin-bar" style="width: 80px;"><div class="margin-bar-fill low" style="width: 11.3%;"></div></div>
|
||
</div>
|
||
</div>
|
||
<div style="text-align: center;">
|
||
<p class="label-text">Negativo</p>
|
||
<div class="margin-bar-container">
|
||
<span class="margin-badge margin-low">-5.2%</span>
|
||
<div class="margin-bar" style="width: 80px;"><div class="margin-bar-fill low" style="width: 0%;"></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<script>
|
||
function setTheme(theme) {
|
||
document.documentElement.setAttribute('data-theme', theme);
|
||
document.querySelectorAll('.theme-switcher button').forEach(b => b.classList.remove('active'));
|
||
event.target.classList.add('active');
|
||
}
|
||
|
||
function toggleColumns() {
|
||
const checked = document.getElementById('toggle-cols').checked;
|
||
document.querySelectorAll('.col-cost, .col-margin').forEach(el => {
|
||
el.classList.toggle('hidden', !checked);
|
||
});
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|