OPCIÓN A: A2 Virtual Scroll + A3 Celery + A4 asyncpg PoC + A5 particionamiento
A2 — Virtual scroll en tablas grandes: - Nuevo helper VirtualScroll en pos/static/js/virtual-scroll.js - inventory.js: tabla de productos con virtual scroll - customers.js: tabla de clientes con virtual scroll - fleet.js: renderMaintenance() y renderHistory() con virtual scroll - Templates envueltos en .vs-container para scroll A3 — Celery worker queue: - pos/celery_app.py + pos/tasks.py (warm cache, bulk import, reports) - Blueprint tasks_bp.py con endpoints /pos/api/tasks/* - Script scripts/start_celery.sh A4 — asyncpg + Quart PoC: - pos/async_catalog.py: endpoint /pos/api/catalog/async-search - scripts/benchmark_async_catalog.py: benchmark Flask vs Quart A5 — Particionar vehicle_parts: - scripts/partition_vehicle_parts.py: migración segura por hash (16 particiones) - Soporta --dry-run, --skip-swap, --skip-drop Tests: 36/36 pasando
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
var currentPage = 1;
|
||||
var currentSearch = '';
|
||||
var draftCountId = null;
|
||||
var inventoryVS = null;
|
||||
|
||||
// --- API helper ---
|
||||
function apiFetch(url, opts) {
|
||||
@@ -52,6 +53,24 @@
|
||||
// STOCK / PRODUCTS (panel-stock)
|
||||
// =====================================================================
|
||||
|
||||
function renderInventoryRow(it) {
|
||||
return '<tr style="cursor:pointer;" onclick="viewProductDetail(' + it.id + ')">' +
|
||||
'<td class="td--mono">' + esc(it.barcode) + '</td>' +
|
||||
'<td class="td--mono">' + esc(it.part_number) + '</td>' +
|
||||
'<td class="td--primary">' + esc(it.name) + '</td>' +
|
||||
'<td>' + esc(it.brand) + '</td>' +
|
||||
'<td style="text-align:right" class="td--primary">' + it.stock + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.cost) + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.price_1) + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.price_2) + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.price_3) + '</td>' +
|
||||
'<td>' + esc(it.location) + '</td>' +
|
||||
'<td>' +
|
||||
'<button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();viewHistory(' + it.id + ')">Historial</button> ' +
|
||||
'<button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();printBarcode(\'' + esc(it.barcode) + '\',\'' + esc(it.part_number) + '\',\'' + esc(it.name) + '\')">Etiqueta</button>' +
|
||||
'</td></tr>';
|
||||
}
|
||||
|
||||
function loadItems(page, search) {
|
||||
currentPage = page || 1;
|
||||
currentSearch = search !== undefined ? search : currentSearch;
|
||||
@@ -69,23 +88,16 @@
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = items.map(function (it) {
|
||||
return '<tr style="cursor:pointer;" onclick="viewProductDetail(' + it.id + ')">' +
|
||||
'<td class="td--mono">' + esc(it.barcode) + '</td>' +
|
||||
'<td class="td--mono">' + esc(it.part_number) + '</td>' +
|
||||
'<td class="td--primary">' + esc(it.name) + '</td>' +
|
||||
'<td>' + esc(it.brand) + '</td>' +
|
||||
'<td style="text-align:right" class="td--primary">' + it.stock + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.cost) + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.price_1) + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.price_2) + '</td>' +
|
||||
'<td style="text-align:right" class="td--amount">$' + fmt(it.price_3) + '</td>' +
|
||||
'<td>' + esc(it.location) + '</td>' +
|
||||
'<td>' +
|
||||
'<button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();viewHistory(' + it.id + ')">Historial</button> ' +
|
||||
'<button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();printBarcode(\'' + esc(it.barcode) + '\',\'' + esc(it.part_number) + '\',\'' + esc(it.name) + '\')">Etiqueta</button>' +
|
||||
'</td></tr>';
|
||||
}).join('');
|
||||
if (!inventoryVS) {
|
||||
inventoryVS = new VirtualScroll({
|
||||
container: tbody,
|
||||
rowHeight: 48,
|
||||
buffer: 3,
|
||||
renderRow: renderInventoryRow,
|
||||
emptyHtml: '<tr><td colspan="11" style="text-align:center;padding:30px;color:var(--color-text-muted);">Sin productos</td></tr>'
|
||||
});
|
||||
}
|
||||
inventoryVS.setData(items);
|
||||
|
||||
// Pagination
|
||||
var pg = data.pagination || {};
|
||||
|
||||
Reference in New Issue
Block a user