feat(pos): dashboard funcional con datos reales — ventas, alertas, cajas

Replace all hardcoded/demo data with live API calls:
- KPIs from /pos/api/register/daily-summary (ventas, tickets, promedio, cajas)
- Inventory alerts from /pos/api/inventory/alerts (zero, low, over stock)
- Top products aggregated from /pos/api/sales detail items
- Weekly bar chart from 7-day daily summaries
- Recent sales table with real items from sale detail endpoint
- Auto-refresh every 2 minutes, manual refresh button
- Dynamic greeting with time-of-day and JWT user name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 02:17:02 +00:00
parent cc2336ca06
commit f55925fa6a
2 changed files with 484 additions and 343 deletions

View File

@@ -1422,8 +1422,8 @@
</svg>
</button>
<div class="header__greeting">
<div class="header__title">Buenos días, Carlos</div>
<div class="header__subtitle">Miércoles, 1 de abril de 2026 &nbsp;·&nbsp; Sucursal Centro</div>
<div class="header__title" id="header-greeting">Buenos días</div>
<div class="header__subtitle" id="header-subtitle">Cargando...</div>
</div>
</div>
<div class="header__right">
@@ -1440,7 +1440,7 @@
</svg>
<span class="notif-dot"></span>
</button>
<button class="icon-btn" title="Refrescar datos">
<button class="icon-btn" title="Refrescar datos" onclick="Dashboard.init()">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M13.5 8a5.5 5.5 0 11-1.5-3.8" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
<path d="M14 2v4h-4" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
@@ -1464,7 +1464,7 @@
<div class="kpi-grid">
<!-- Card 1: Ventas Hoy -->
<div class="kpi-card">
<div class="kpi-card" id="kpi-ventas-hoy">
<div class="kpi-card__accent-bar"></div>
<div class="kpi-card__label">
Ventas Hoy
@@ -1474,47 +1474,14 @@
</svg>
</span>
</div>
<div class="kpi-card__value">$45,230</div>
<div class="kpi-card__meta">
<span class="kpi-tag kpi-tag--up">
<svg width="9" height="9" viewBox="0 0 9 9" fill="none">
<path d="M4.5 7V2M2 4.5L4.5 2 7 4.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
+12%
</span>
<span class="kpi-meta-text">vs ayer $40,382</span>
<div class="kpi-card__value" id="kpi-ventas-total">--</div>
<div class="kpi-card__meta" id="kpi-ventas-meta">
<span class="kpi-tag kpi-tag--neutral">Cargando...</span>
</div>
</div>
<!-- Card 2: Ventas Mes -->
<div class="kpi-card">
<div class="kpi-card__accent-bar"></div>
<div class="kpi-card__label">
Ventas Mes
<span class="kpi-card__icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<rect x="1" y="2" width="12" height="11" rx="1.5" stroke="currentColor" stroke-width="1.4"/>
<path d="M4 1v2M10 1v2M1 6h12" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
</svg>
</span>
</div>
<div class="kpi-card__value">$892,150</div>
<div class="kpi-card__meta">
<span class="kpi-meta-text">Meta: $1,310,000</span>
</div>
<div class="kpi-progress">
<div class="kpi-progress__track">
<div class="kpi-progress__fill" style="width: 68%"></div>
</div>
<div class="kpi-progress__label">
<span>68% de meta</span>
<span>$417,850 restante</span>
</div>
</div>
</div>
<!-- Card 3: Tickets Hoy -->
<div class="kpi-card">
<!-- Card 2: Tickets Hoy -->
<div class="kpi-card" id="kpi-tickets">
<div class="kpi-card__accent-bar"></div>
<div class="kpi-card__label">
Tickets Hoy
@@ -1525,28 +1492,44 @@
</svg>
</span>
</div>
<div class="kpi-card__value">23</div>
<div class="kpi-card__meta">
<span class="kpi-tag kpi-tag--neutral">Promedio</span>
<span class="kpi-meta-text">$1,966 por ticket</span>
<div class="kpi-card__value" id="kpi-tickets-count">--</div>
<div class="kpi-card__meta" id="kpi-tickets-meta">
<span class="kpi-tag kpi-tag--neutral">Cargando...</span>
</div>
</div>
<!-- Card 4: Utilidad Mes -->
<div class="kpi-card">
<!-- Card 3: Ticket Promedio -->
<div class="kpi-card" id="kpi-promedio">
<div class="kpi-card__accent-bar"></div>
<div class="kpi-card__label">
Utilidad Mes
Ticket Promedio
<span class="kpi-card__icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<rect x="1" y="2" width="12" height="11" rx="1.5" stroke="currentColor" stroke-width="1.4"/>
<path d="M4 1v2M10 1v2M1 6h12" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
</svg>
</span>
</div>
<div class="kpi-card__value" id="kpi-promedio-value">--</div>
<div class="kpi-card__meta" id="kpi-promedio-meta">
<span class="kpi-tag kpi-tag--neutral">Cargando...</span>
</div>
</div>
<!-- Card 4: Cajas Activas -->
<div class="kpi-card" id="kpi-cajas">
<div class="kpi-card__accent-bar"></div>
<div class="kpi-card__label">
Cajas del Día
<span class="kpi-card__icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<path d="M2 11L5 8l2.5 2L10 5l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
</div>
<div class="kpi-card__value">$178,430</div>
<div class="kpi-card__meta">
<span class="kpi-tag kpi-tag--up">20%</span>
<span class="kpi-meta-text">margen neto</span>
<div class="kpi-card__value" id="kpi-cajas-count">--</div>
<div class="kpi-card__meta" id="kpi-cajas-meta">
<span class="kpi-tag kpi-tag--neutral">Cargando...</span>
</div>
</div>
@@ -1562,8 +1545,8 @@
<div class="chart-header">
<div>
<div class="section-title">Ventas Semanales</div>
<div style="font-size:var(--text-caption);color:var(--color-text-muted);margin-top:2px;">
Total semana: <strong style="color:var(--color-primary);font-family:var(--font-mono);">$267,840</strong>
<div style="font-size:var(--text-caption);color:var(--color-text-muted);margin-top:2px;" id="chart-week-total">
Total semana: <strong style="color:var(--color-primary);font-family:var(--font-mono);">--</strong>
</div>
</div>
<div class="period-selector">
@@ -1574,68 +1557,15 @@
</div>
</div>
<!-- Bar chart: heights are % of max (Jue = max $52k) -->
<!-- Bar chart: populated by JS -->
<div class="bar-chart" id="bar-chart">
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar" style="height:62%" data-value="$32,100"></div>
</div>
<span class="bar-chart__label">Lun</span>
</div>
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar" style="height:79%" data-value="$41,200"></div>
</div>
<span class="bar-chart__label">Mar</span>
</div>
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar" style="height:71%" data-value="$36,800"></div>
</div>
<span class="bar-chart__label">Mié</span>
</div>
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar" style="height:100%" data-value="$52,000"></div>
</div>
<span class="bar-chart__label">Jue</span>
</div>
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar" style="height:88%" data-value="$45,800"></div>
</div>
<span class="bar-chart__label">Vie</span>
</div>
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar" style="height:55%" data-value="$28,600"></div>
</div>
<span class="bar-chart__label">Sáb</span>
</div>
<div class="bar-chart__col">
<div class="bar-chart__bar-wrap">
<div class="bar-chart__bar today" style="height:87%" data-value="$45,230 ← Hoy"></div>
</div>
<span class="bar-chart__label" style="color:var(--color-primary);font-weight:700;">Dom</span>
</div>
<!-- Filled dynamically -->
</div>
<div class="chart-legend">
<div class="chart-legend" id="chart-legend">
<div class="legend-item">
<div class="legend-dot"></div>
Ventas brutas
</div>
<div class="legend-item">
<div class="legend-dot legend-dot--success"></div>
Semana anterior promedio: $38,400
Ventas brutas (7 días)
</div>
</div>
@@ -1656,147 +1586,27 @@
<div class="rank-card">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-4);">
<div style="font-family:var(--font-heading);font-weight:var(--heading-weight-secondary);font-size:var(--text-body-sm);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--color-text-secondary);">
Top Productos
Top Productos Hoy
</div>
<a href="/pos/inventory" style="font-size:var(--text-caption);color:var(--color-primary);font-weight:var(--font-weight-semibold);cursor:pointer;text-decoration:none;">Ver todos</a>
</div>
<div class="rank-list">
<div class="rank-item">
<div class="rank-num rank-num--1">1</div>
<div class="rank-item__info">
<div class="rank-item__name">Balatas Brembo Delanteras</div>
<div class="rank-item__sub">SKU-0041 &nbsp;·&nbsp; 84 pzas vendidas</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:100%"></div>
</div>
</div>
<div class="rank-item__value">$67,200</div>
</div>
<div class="rank-item">
<div class="rank-num rank-num--2">2</div>
<div class="rank-item__info">
<div class="rank-item__name">Filtro de Aceite Mann</div>
<div class="rank-item__sub">SKU-0087 &nbsp;·&nbsp; 121 pzas vendidas</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:78%"></div>
</div>
</div>
<div class="rank-item__value">$52,360</div>
</div>
<div class="rank-item">
<div class="rank-num">3</div>
<div class="rank-item__info">
<div class="rank-item__name">Amortiguador KYB Trasero</div>
<div class="rank-item__sub">SKU-0023 &nbsp;·&nbsp; 38 pzas vendidas</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:61%"></div>
</div>
</div>
<div class="rank-item__value">$41,040</div>
</div>
<div class="rank-item">
<div class="rank-num">4</div>
<div class="rank-item__info">
<div class="rank-item__name">Bujía NGK Iridium</div>
<div class="rank-item__sub">SKU-0156 &nbsp;·&nbsp; 204 pzas vendidas</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:49%"></div>
</div>
</div>
<div class="rank-item__value">$32,844</div>
</div>
<div class="rank-item">
<div class="rank-num">5</div>
<div class="rank-item__info">
<div class="rank-item__name">Banda de Distribución Gates</div>
<div class="rank-item__sub">SKU-0072 &nbsp;·&nbsp; 27 pzas vendidas</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:38%"></div>
</div>
</div>
<div class="rank-item__value">$25,650</div>
</div>
<div class="rank-list" id="top-products-list">
<div class="rank-item" style="justify-content:center;color:var(--color-text-muted);font-size:var(--text-caption);">Cargando...</div>
</div>
</div><!-- end Top Productos -->
<!-- Top Clientes -->
<!-- Desglose por Caja -->
<div class="rank-card">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-4);">
<div style="font-family:var(--font-heading);font-weight:var(--heading-weight-secondary);font-size:var(--text-body-sm);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--color-text-secondary);">
Top Clientes
Cajas del Día
</div>
<a href="/pos/customers" style="font-size:var(--text-caption);color:var(--color-primary);font-weight:var(--font-weight-semibold);cursor:pointer;text-decoration:none;">Ver todos</a>
<a href="/pos/config" style="font-size:var(--text-caption);color:var(--color-primary);font-weight:var(--font-weight-semibold);cursor:pointer;text-decoration:none;">Gestionar</a>
</div>
<div class="rank-list">
<div class="rank-item">
<div class="rank-num rank-num--1">1</div>
<div class="rank-item__info">
<div class="rank-item__name">Taller Mecánico Ramírez</div>
<div class="rank-item__sub">RFC TMR-210415 &nbsp;·&nbsp; 18 compras/mes</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:100%"></div>
</div>
</div>
<div class="rank-item__value">$89,400</div>
</div>
<div class="rank-item">
<div class="rank-num rank-num--2">2</div>
<div class="rank-item__info">
<div class="rank-item__name">Distribuidora Automotriz López</div>
<div class="rank-item__sub">RFC DAL-190302 &nbsp;·&nbsp; 11 compras/mes</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:74%"></div>
</div>
</div>
<div class="rank-item__value">$66,100</div>
</div>
<div class="rank-item">
<div class="rank-num">3</div>
<div class="rank-item__info">
<div class="rank-item__name">Servicio Automotriz Torres</div>
<div class="rank-item__sub">RFC SAT-180720 &nbsp;·&nbsp; 9 compras/mes</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:57%"></div>
</div>
</div>
<div class="rank-item__value">$50,820</div>
</div>
<div class="rank-item">
<div class="rank-num">4</div>
<div class="rank-item__info">
<div class="rank-item__name">Flotilla Empresarial Hernández</div>
<div class="rank-item__sub">RFC FEH-200115 &nbsp;·&nbsp; 7 compras/mes</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:43%"></div>
</div>
</div>
<div class="rank-item__value">$38,250</div>
</div>
<div class="rank-item">
<div class="rank-num">5</div>
<div class="rank-item__info">
<div class="rank-item__name">Refaccionaria El Pistón</div>
<div class="rank-item__sub">RFC REP-221108 &nbsp;·&nbsp; 5 compras/mes</div>
<div class="rank-item__bar-bg">
<div class="rank-item__bar-fill" style="width:30%"></div>
</div>
</div>
<div class="rank-item__value">$26,700</div>
</div>
<div class="rank-list" id="registers-list">
<div class="rank-item" style="justify-content:center;color:var(--color-text-muted);font-size:var(--text-caption);">Cargando...</div>
</div>
</div><!-- end Top Clientes -->
</div><!-- end Cajas del Día -->
</div><!-- end two-col-grid -->
</section>
@@ -1810,62 +1620,8 @@
<span class="section-title">Alertas &amp; Pendientes</span>
<span class="section-action">Gestionar todo &rarr;</span>
</div>
<div class="alerts-grid">
<!-- Alert 1: Low stock (red) -->
<div class="alert-item alert-item--error">
<div class="alert-icon-wrap alert-icon-wrap--error">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path d="M9 3L16.5 15H1.5L9 3z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
<path d="M9 8v3M9 12.5v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</div>
<div class="alert-content">
<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:3px;">
<span class="alert-title">Stock Crítico</span>
<span class="alert-badge alert-badge--error">3 items</span>
</div>
<div class="alert-desc">Balatas Brembo: <strong>3 unidades</strong> · Filtro Mann: <strong>2 unidades</strong> · Bujía NGK: <strong>5 unidades</strong></div>
</div>
<div class="alert-action">Reabastecer</div>
</div>
<!-- Alert 2: Pending invoices (yellow) -->
<div class="alert-item alert-item--warning">
<div class="alert-icon-wrap alert-icon-wrap--warning">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path d="M4 2h10a1 1 0 011 1v12a1 1 0 01-1 1H4a1 1 0 01-1-1V3a1 1 0 011-1z" stroke="currentColor" stroke-width="1.5"/>
<path d="M6 7h6M6 9.5h4M6 12h2" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>
</svg>
</div>
<div class="alert-content">
<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:3px;">
<span class="alert-title">Ventas sin Facturar</span>
<span class="alert-badge alert-badge--warning">8 ventas</span>
</div>
<div class="alert-desc">8 ventas del día sin timbrar ante el SAT · Total: <strong>$34,820</strong> · Plazo límite hoy</div>
</div>
<div class="alert-action">Facturar</div>
</div>
<!-- Alert 3: Credits due (orange) -->
<div class="alert-item alert-item--orange">
<div class="alert-icon-wrap alert-icon-wrap--orange">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<circle cx="9" cy="9" r="7" stroke="currentColor" stroke-width="1.5"/>
<path d="M9 5v4l2.5 2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="alert-content">
<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:3px;">
<span class="alert-title">Crédito Vencido</span>
<span class="alert-badge alert-badge--orange">Urgente</span>
</div>
<div class="alert-desc">Taller Ramírez: <strong>$12,500</strong> vencido hace 15 días · Distribuidora López: <strong>$8,200</strong> vence hoy</div>
</div>
<div class="alert-action">Cobrar</div>
</div>
<div class="alerts-grid" id="alerts-grid">
<div class="alert-item" style="justify-content:center;color:var(--color-text-muted);font-size:var(--text-caption);border-left:none;">Cargando alertas...</div>
</div><!-- end alerts-grid -->
</section>
@@ -1902,42 +1658,8 @@
<th>Método Pago</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="td-time">14:32</span></td>
<td><span class="td-client">Taller Ramírez</span></td>
<td class="td-products">Balatas Brembo (x2), Filtro Mann (x1)</td>
<td><span class="td-mono">$3,840</span></td>
<td><span class="pago-badge pago-badge--credito">Crédito 30d</span></td>
</tr>
<tr>
<td><span class="td-time">13:18</span></td>
<td><span class="td-client">Público General</span></td>
<td class="td-products">Amortiguador KYB (x1), Bujía NGK (x4)</td>
<td><span class="td-mono">$2,156</span></td>
<td><span class="pago-badge pago-badge--tarjeta">Tarjeta</span></td>
</tr>
<tr>
<td><span class="td-time">12:45</span></td>
<td><span class="td-client">Flotilla Hernández</span></td>
<td class="td-products">Banda Gates (x3), Filtro aceite (x6)</td>
<td><span class="td-mono">$7,380</span></td>
<td><span class="pago-badge pago-badge--transferencia">Transferencia</span></td>
</tr>
<tr>
<td><span class="td-time">11:07</span></td>
<td><span class="td-client">Servicio Torres</span></td>
<td class="td-products">Amortiguador KYB (x2)</td>
<td><span class="td-mono">$2,160</span></td>
<td><span class="pago-badge pago-badge--efectivo">Efectivo</span></td>
</tr>
<tr>
<td><span class="td-time">10:23</span></td>
<td><span class="td-client">Distribuidora López</span></td>
<td class="td-products">Bujía NGK (x24), Filtro Mann (x12), Balatas (x4)</td>
<td><span class="td-mono">$18,440</span></td>
<td><span class="pago-badge pago-badge--transferencia">Transferencia</span></td>
</tr>
<tbody id="recent-sales-tbody">
<tr><td colspan="5" style="text-align:center;color:var(--color-text-muted);font-size:var(--text-caption);">Cargando ventas recientes...</td></tr>
</tbody>
</table>
</div>