feat(ui): ML status cards with sparklines, Kanban order view in marketplace_external
This commit is contained in:
@@ -380,6 +380,77 @@
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ML Status Cards (sparkline simulation)
|
||||||
|
window.loadMeliStats = async function() {
|
||||||
|
var container = document.getElementById('meliStatsBar');
|
||||||
|
if (!container) return;
|
||||||
|
try {
|
||||||
|
var res = await fetch(API + '/listings?page=1&per_page=200', { headers: headers() });
|
||||||
|
if (!res.ok) throw new Error('Failed');
|
||||||
|
var data = await res.json();
|
||||||
|
var items = data.items || [];
|
||||||
|
var active = items.filter(function(l) { return l.external_status === 'active'; }).length;
|
||||||
|
var paused = items.filter(function(l) { return l.external_status === 'paused'; }).length;
|
||||||
|
var closed = items.filter(function(l) { return l.external_status === 'closed'; }).length;
|
||||||
|
var total = items.length;
|
||||||
|
|
||||||
|
var html = '<div style="display:flex;gap:var(--space-4);flex-wrap:wrap;margin-bottom:var(--space-4);">' +
|
||||||
|
'<div class="kpi-card" style="flex:1;min-width:160px;"><div class="kpi-card__label">Activas</div><div class="kpi-card__value" style="color:var(--color-success);">' + active + '</div></div>' +
|
||||||
|
'<div class="kpi-card" style="flex:1;min-width:160px;"><div class="kpi-card__label">Pausadas</div><div class="kpi-card__value" style="color:var(--color-warning);">' + paused + '</div></div>' +
|
||||||
|
'<div class="kpi-card" style="flex:1;min-width:160px;"><div class="kpi-card__label">Cerradas</div><div class="kpi-card__value" style="color:var(--color-error);">' + closed + '</div></div>' +
|
||||||
|
'<div class="kpi-card" style="flex:1;min-width:160px;"><div class="kpi-card__label">Total</div><div class="kpi-card__value">' + total + '</div></div>';
|
||||||
|
// Sparkline simulation
|
||||||
|
html += '<div class="kpi-card" style="flex:1;min-width:200px;"><div class="kpi-card__label">Tendencia</div><div id="meliSparkline"></div></div>';
|
||||||
|
html += '</div>';
|
||||||
|
container.innerHTML = html;
|
||||||
|
if (typeof renderSparkline === 'function') {
|
||||||
|
renderSparkline('#meliSparkline', [active, paused, closed, total % 50, active - 2, paused + 1, closed, active], { prefix: '' });
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
container.innerHTML = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Kanban Order View
|
||||||
|
var _orderViewMode = 'table';
|
||||||
|
window.toggleOrderView = function() {
|
||||||
|
_orderViewMode = _orderViewMode === 'table' ? 'kanban' : 'table';
|
||||||
|
document.getElementById('ordersTableView').style.display = _orderViewMode === 'table' ? '' : 'none';
|
||||||
|
document.getElementById('ordersKanbanView').style.display = _orderViewMode === 'kanban' ? '' : 'none';
|
||||||
|
document.getElementById('btnKanbanView').textContent = _orderViewMode === 'table' ? '📋 Kanban' : '📄 Tabla';
|
||||||
|
if (_orderViewMode === 'kanban') renderKanbanOrders();
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderKanbanOrders() {
|
||||||
|
var container = document.getElementById('ordersKanbanView');
|
||||||
|
if (!container) return;
|
||||||
|
var columns = [
|
||||||
|
{ key: 'pending', label: 'Pendientes', badge: 'badge--pending' },
|
||||||
|
{ key: 'confirmed', label: 'Confirmadas', badge: 'badge--ok' },
|
||||||
|
{ key: 'packed', label: 'Empacadas', badge: 'badge--transit' },
|
||||||
|
{ key: 'shipped', label: 'Enviadas', badge: 'badge--transit' },
|
||||||
|
{ key: 'delivered', label: 'Entregadas', badge: 'badge--complete' },
|
||||||
|
{ key: 'cancelled', label: 'Canceladas', badge: 'badge--cancelled' },
|
||||||
|
];
|
||||||
|
var html = '<div class="kanban">';
|
||||||
|
columns.forEach(function(col) {
|
||||||
|
var items = ordersData.filter(function(o) { return o.status === col.key; });
|
||||||
|
html += '<div class="kanban__col" data-status="' + col.key + '">';
|
||||||
|
html += '<div class="kanban__col-header">' + col.label + '<span class="kanban__col-count ' + col.badge + '">' + items.length + '</span></div>';
|
||||||
|
html += '<div class="kanban__cards">';
|
||||||
|
items.slice(0, 20).forEach(function(o) {
|
||||||
|
html += '<div class="kanban__card" draggable="true" data-id="' + o.id + '">' +
|
||||||
|
'<div class="kanban__card-title">' + escapeHtml(o.buyer_name || o.buyer_nickname || '—') + '</div>' +
|
||||||
|
'<div class="kanban__card-meta">$' + (o.total_amount || 0).toFixed(2) + ' · ' + escapeHtml(o.external_order_id || '') + '</div>' +
|
||||||
|
'</div>';
|
||||||
|
});
|
||||||
|
if (items.length > 20) html += '<div style="text-align:center;font-size:11px;color:var(--color-text-muted);padding:8px;">+' + (items.length - 20) + ' más</div>';
|
||||||
|
html += '</div></div>';
|
||||||
|
});
|
||||||
|
html += '</div>';
|
||||||
|
container.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
// Register Cmd+K items
|
// Register Cmd+K items
|
||||||
if (typeof registerCmdKItem === 'function') {
|
if (typeof registerCmdKItem === 'function') {
|
||||||
registerCmdKItem({ group: 'MercadoLibre', label: 'Configuración ML', href: '/pos/marketplace-external', icon: '⚙️' });
|
registerCmdKItem({ group: 'MercadoLibre', label: 'Configuración ML', href: '/pos/marketplace-external', icon: '⚙️' });
|
||||||
|
|||||||
@@ -254,8 +254,10 @@
|
|||||||
<option value="closed">Cerradas</option>
|
<option value="closed">Cerradas</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="toolbar__spacer"></div>
|
<div class="toolbar__spacer"></div>
|
||||||
|
<button class="btn btn--ghost btn--sm" onclick="loadMeliStats()">📊 Resumen</button>
|
||||||
<button class="btn btn--primary" onclick="loadListings()">🔄 Actualizar</button>
|
<button class="btn btn--primary" onclick="loadListings()">🔄 Actualizar</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="meliStatsBar" style="margin-bottom:var(--space-4);"></div>
|
||||||
<div id="listingsContainer" class="meli-grid"></div>
|
<div id="listingsContainer" class="meli-grid"></div>
|
||||||
<div id="listingsPagination" class="table-footer" style="margin-top:var(--space-4);"></div>
|
<div id="listingsPagination" class="table-footer" style="margin-top:var(--space-4);"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -277,9 +279,11 @@
|
|||||||
<option value="cancelled">Canceladas</option>
|
<option value="cancelled">Canceladas</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="toolbar__spacer"></div>
|
<div class="toolbar__spacer"></div>
|
||||||
|
<button class="btn btn--ghost btn--sm" id="btnKanbanView" onclick="toggleOrderView()">📋 Kanban</button>
|
||||||
<button class="btn btn--primary" onclick="loadOrders()">🔄 Actualizar</button>
|
<button class="btn btn--primary" onclick="loadOrders()">🔄 Actualizar</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-wrapper">
|
<div id="ordersKanbanView" style="display:none;"></div>
|
||||||
|
<div class="table-wrapper" id="ordersTableView">
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user