feat(nakui): Fase 5 del ERP — tablero de KPIs

View::Dashboard: grilla de tarjetas de agregados. Metric Count/Sum/
GroupBy con filtro opcional (CardFilter), computado por compute_metric
en meta-runtime (MetricResult Scalar/Breakdown). meta-form render_dashboard
pinta cada tarjeta con el número grande formateado o un breakdown con
barras de texto. El CRM gana una vista «Panorama»: clientes,
oportunidades, pipeline, ganadas, y breakdowns por etapa y canal.

Tests de compute_metric; verificación del panorama en nakui-ui. Clippy
limpio en las libs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-21 19:29:27 +00:00
parent ab1cf9998a
commit ab2b8f6638
10 changed files with 386 additions and 12 deletions
+38
View File
@@ -40,6 +40,7 @@
}
],
"menu": [
{ "label": "Panorama", "view": "panorama", "icon": "📊" },
{ "label": "Clientes", "view": "cliente_list", "icon": "👤" },
{ "label": "+ Cliente", "view": "cliente_form", "icon": "✚" },
{ "label": "Oportunidades", "view": "oportunidad_list", "icon": "🎯" },
@@ -49,6 +50,43 @@
{ "label": "Registrar interacción", "view": "interaccion_form", "icon": "✚" }
],
"views": {
"panorama": {
"kind": "dashboard",
"title": "Panorama del CRM",
"cards": [
{ "label": "Clientes", "entity": "Cliente", "metric": { "kind": "count" } },
{ "label": "Oportunidades", "entity": "Oportunidad", "metric": { "kind": "count" } },
{
"label": "Pipeline (monto total)",
"entity": "Oportunidad",
"metric": { "kind": "sum", "field": "monto" },
"format": { "kind": "currency", "symbol": "$" }
},
{
"label": "Oportunidades ganadas",
"entity": "Oportunidad",
"metric": { "kind": "count" },
"filter": { "field": "etapa", "equals": "ganada" }
},
{
"label": "Monto ganado",
"entity": "Oportunidad",
"metric": { "kind": "sum", "field": "monto" },
"filter": { "field": "etapa", "equals": "ganada" },
"format": { "kind": "currency", "symbol": "$" }
},
{
"label": "Oportunidades por etapa",
"entity": "Oportunidad",
"metric": { "kind": "group_by", "field": "etapa" }
},
{
"label": "Interacciones por canal",
"entity": "Interaccion",
"metric": { "kind": "group_by", "field": "canal" }
}
]
},
"cliente_list": {
"kind": "list",
"title": "Clientes",