- Resumen de activos en la esquina inferior izq del resumen

- Correccion en la habilidad de reordenamiento
- Se agregaron los activos, penalizacin y potencial al reordenamiento
This commit is contained in:
2026-06-11 21:56:02 -06:00
parent f8e7a0d7b9
commit fea2ae1659
4 changed files with 401 additions and 61 deletions
+145 -61
View File
@@ -443,9 +443,6 @@ function llenaProyectoGde(proyectoNum) {
$('#activoReqProyectoCant2').text(proyectos[proyectoNum].activoAsignado2)
$('#activoReqProyectoCant3').text(proyectos[proyectoNum].activoAsignado3)
$('#mantoGde').text('MANTENIMIENTO ' + proyectos[proyectoNum].mantenimiento)
// Quitamos el proyecto actual del arreglo siguientesProyectos.
siguientesProyectos.splice(0, 1)
}
/**
@@ -972,6 +969,15 @@ function redibujarTablero() {
// Prioridad 3: Si no hay ninguno 'En proceso', tomar el primero de la cola 'En siguientes'.
if (!nuevoProyectoGde) {
nuevoProyectoGde = proyectos.find((p) => p.estatus === 'En siguientes')
if (nuevoProyectoGde) {
let index = siguientesProyectos.findIndex(
(p) => p.id === nuevoProyectoGde.id
)
if (index !== -1) {
siguientesProyectos.splice(index, 1)
sincronizarColaSiguientes()
}
}
}
// 2. Limpiar todos los slots de proyectos chicos.
@@ -1980,7 +1986,7 @@ $('#accionHabilidadEspecial').click(function () {
guardaSesion()
}
} else if (accionQuincenal === 'Ordenar los próximos 5 proyectos') {
abrirDialogoOrdenarProyectos(elArreglo, quincenaActual);
abrirDialogoOrdenarProyectos(elArreglo, quincenaActual)
} else if (accionQuincenal === 'Omitir un mantenimiento') {
// Actualizamos lastUsed
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual)
@@ -3373,6 +3379,8 @@ function continuamos() {
obtenerProyectosPendientes()
if (siguientesProyectos.length > 0) {
llenaProyectoGde(siguientesProyectos[0].id)
siguientesProyectos.splice(0, 1)
sincronizarColaSiguientes()
}
} else {
// JUEGO CARGADO
@@ -3431,7 +3439,17 @@ function continuamos() {
// 4. Reconstruir la cola de 'siguientesProyectos'.
// Primero, tomar los que ya estaban 'En siguientes' del estado guardado.
siguientesProyectos = proyectos.filter((p) => p.estatus === 'En siguientes')
let tempSiguientes = proyectos.filter((p) => p.estatus === 'En siguientes')
if (arregloGeneral.siguientesProyectosIds) {
tempSiguientes.sort((a, b) => {
let idxA = arregloGeneral.siguientesProyectosIds.indexOf(a.id)
let idxB = arregloGeneral.siguientesProyectosIds.indexOf(b.id)
if (idxA === -1) idxA = 999
if (idxB === -1) idxB = 999
return idxA - idxB
})
}
siguientesProyectos = tempSiguientes
// Luego, completar la cola con proyectos 'Pendiente' si es necesario.
const proyectosPendientes = proyectos.filter(
@@ -3455,6 +3473,7 @@ function continuamos() {
siguientesProyectos.push(proyectoElegido)
proyectosDisponibles.splice(randomIndex, 1)
}
sincronizarColaSiguientes()
// 5. Llenar el proyecto grande.
if (proyectoGde) {
@@ -3462,6 +3481,8 @@ function continuamos() {
} else if (siguientesProyectos.length > 0) {
// Si no había ningún proyecto en el tablero, tomar el primero de la cola.
llenaProyectoGde(siguientesProyectos[0].id)
siguientesProyectos.splice(0, 1)
sincronizarColaSiguientes()
}
}
@@ -3696,82 +3717,145 @@ window.confirm = function (message, callback, customWidth) {
})
}
function sincronizarColaSiguientes() {
if (typeof arregloGeneral !== 'undefined' && siguientesProyectos) {
arregloGeneral.siguientesProyectosIds = siguientesProyectos.map((p) => p.id)
}
}
function abrirDialogoOrdenarProyectos(elArreglo, quincenaActual) {
let proyectosAOrdenar = siguientesProyectos.slice(0, 5);
let proyectosRestantes = siguientesProyectos.slice(5);
let proyectosAOrdenar = siguientesProyectos.slice(0, 5)
let proyectosRestantes = siguientesProyectos.slice(5)
let container = $('<div></div>');
container.append('<p style="margin-bottom: 15px; font-size: 14px;">Arrastra los proyectos para ordenar la prioridad en la que aparecerán:</p>');
let container = $('<div></div>')
container.append(
'<p style="margin-bottom: 15px; font-size: 14px;">Arrastra los proyectos para ordenar la prioridad en la que aparecerán:</p>'
)
let list = $(
'<ul id="sortable-proyectos" style="list-style-type: none; padding: 0; margin: 0;"></ul>'
)
const claseMapa = {
amarillo: 'actPersonalCalificado',
naranjas: 'actAnalistas',
verdes: 'actFlujoDeEfectivo',
azules: 'actTransporteYMaquinaria',
rojos: 'actTecnologia',
morados: 'actCreditoEInversion',
}
const colores = [
'amarillo',
'naranjas',
'verdes',
'azules',
'rojos',
'morados',
]
let list = $('<ul id="sortable-proyectos" style="list-style-type: none; padding: 0; margin: 0;"></ul>');
proyectosAOrdenar.forEach((p, idx) => {
let activosReqHtml = ''
colores.forEach((color) => {
const valor = p[color]
if (valor !== null && valor > 0) {
const claseActivo = claseMapa[color]
const textColor =
color === 'amarillo' || color === 'naranjas' || color === 'verdes'
? 'black'
: 'white'
activosReqHtml += `<span class="${claseActivo}" style="padding: 2px 6px; border-radius: 3px; color: ${textColor}; font-weight: bold; font-size: 11px; margin-right: 4px;">${valor}</span>`
}
})
const penVal = parseInt(p.penalizacion) || 0
const penalizacionFormateada =
penVal > 0 ? '$' + new Intl.NumberFormat('es-MX').format(penVal) : 'N/A'
let item = $(`
<li class="ui-state-default" data-id="${p.id}" style="margin: 8px 0; padding: 10px; border: 2px solid gray; border-radius: 4px; background-color: #f9f9f9; cursor: grab; display: flex; justify-content: space-between; align-items: center; font-size: 14px;">
<span style="font-weight: bold;">${idx + 1}. ${p.nombreProyecto}</span>
<span style="font-size: 11px; background-color: #eee; padding: 2px 6px; border-radius: 3px; color: #555;">${p.departamento}</span>
<li class="ui-state-default" data-id="${p.id}" style="margin: 8px 0; padding: 10px; border: 2px solid gray; border-radius: 4px; background-color: #f9f9f9; cursor: grab; display: flex; flex-direction: column; gap: 6px; font-size: 14px;">
<div style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
<span style="font-weight: bold;">${idx + 1}. ${p.nombreProyecto}</span>
<span style="font-size: 11px; background-color: #eee; padding: 2px 6px; border-radius: 3px; color: #555;">${p.departamento}</span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; width: 100%; font-size: 12px; color: #666;">
<div style="display: flex; gap: 4px;">
${activosReqHtml}
</div>
<div style="text-align: left; line-height: 1.4;">
Potencial: <b>${p.potencial || 'N/A'}</b><br>
Penalización: <b>${penalizacionFormateada}</b>
</div>
</div>
</li>
`);
list.append(item);
});
container.append(list);
`)
list.append(item)
})
container.append(list)
container.dialog({
modal: true,
title: 'Ordenar Próximos 5 Proyectos',
width: 500,
open: function() {
open: function () {
list.sortable({
placeholder: "ui-state-highlight",
placeholder: 'ui-state-highlight',
forcePlaceholderSize: true,
update: function(event, ui) {
list.find('li').each(function(index) {
let nombre = $(this).find('span').first().text();
nombre = nombre.replace(/^\d+\.\s*/, '');
$(this).find('span').first().text((index + 1) + '. ' + nombre);
});
}
});
list.disableSelection();
$('<style id="sortable-style">.ui-state-highlight { height: 40px; background-color: #ffffcc; border: 2px dashed #999; margin: 8px 0; border-radius: 4px; }</style>').appendTo('head');
update: function (event, ui) {
list.find('li').each(function (index) {
let nombre = $(this).find('span').first().text()
nombre = nombre.replace(/^\d+\.\s*/, '')
$(this)
.find('span')
.first()
.text(index + 1 + '. ' + nombre)
})
},
})
list.disableSelection()
$(
'<style id="sortable-style">.ui-state-highlight { height: 40px; background-color: #ffffcc; border: 2px dashed #999; margin: 8px 0; border-radius: 4px; }</style>'
).appendTo('head')
},
close: function() {
$('#sortable-style').remove();
$(this).dialog('destroy').remove();
close: function () {
$('#sortable-style').remove()
$(this).dialog('destroy').remove()
},
buttons: {
"Guardar Orden": function() {
let nuevoOrdenIds = [];
list.find('li').each(function() {
nuevoOrdenIds.push(parseInt($(this).data('id')));
});
'Guardar Orden': function () {
let nuevoOrdenIds = []
list.find('li').each(function () {
nuevoOrdenIds.push(parseInt($(this).data('id')))
})
let nuevosSiguientes = [];
nuevoOrdenIds.forEach(id => {
let proj = proyectos.find(p => p.id === id);
if (proj) nuevosSiguientes.push(proj);
});
nuevosSiguientes = nuevosSiguientes.concat(proyectosRestantes);
siguientesProyectos = nuevosSiguientes;
let nuevosSiguientes = []
nuevoOrdenIds.forEach((id) => {
let proj = proyectos.find((p) => p.id === id)
if (proj) nuevosSiguientes.push(proj)
})
proyectos.forEach(p => {
if (p.estatus === 'En siguientes') p.estatus = 'Pendiente';
});
siguientesProyectos.forEach(p => {
let proj = proyectos.find(pr => pr.id === p.id);
if (proj) proj.estatus = 'En siguientes';
});
nuevosSiguientes = nuevosSiguientes.concat(proyectosRestantes)
siguientesProyectos = nuevosSiguientes
sincronizarColaSiguientes()
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual);
var audio = new Audio('./Microwave_bell.wav');
audio.play();
window.alert('¡Orden de proyectos actualizado con éxito!');
proyectos.forEach((p) => {
if (p.estatus === 'En siguientes') p.estatus = 'Pendiente'
})
siguientesProyectos.forEach((p) => {
let proj = proyectos.find((pr) => pr.id === p.id)
if (proj) proj.estatus = 'En siguientes'
})
if (typeof guardaSesion === 'function') guardaSesion();
$(this).dialog('close');
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual)
var audio = new Audio('./Microwave_bell.wav')
audio.play()
window.alert('¡Orden de proyectos actualizado con éxito!')
if (typeof guardaSesion === 'function') guardaSesion()
$(this).dialog('close')
},
"Cancelar": function() { $(this).dialog('close'); }
}
});
Cancelar: function () {
$(this).dialog('close')
},
},
})
}
// </script>
+2
View File
@@ -164,6 +164,8 @@ function guardarDatosEnServidor() {
.catch((error) => console.error('Error:', error))
}
const guardaSesion = guardarDatosEnServidor;
// Cargar datos al iniciar la página
document.addEventListener('DOMContentLoaded', cargarDatosDesdeServidor)
+66
View File
@@ -0,0 +1,66 @@
# Plan de Implementación: Contabilización de Activos (Producidos, Recuperados y Perdidos)
Este documento detalla la lógica matemática y los pasos técnicos necesarios para implementar la visualización y el cálculo de estadísticas de activos en la pantalla de resumen de la aplicación **Colaborando**.
---
## 📋 Resumen del Enfoque
Para evitar desincronizaciones de datos y la necesidad de alterar la base de datos o los esquemas JSON de persistencia de sesión, utilizaremos un **cálculo dinámico en el cliente** (JavaScript). Toda la información necesaria ya existe dentro del arreglo global `proyectos` y el objeto `arregloGeneral`, que se guardan y cargan automáticamente con la sesión.
---
## 🧮 Lógica de Cálculo de Métricas
Para cada tipo de activo (p. ej., *Personal Calificado*, *Analistas*, *Flujo de Efectivo*, etc.), los valores se calculan recorriendo el arreglo global `proyectos` buscando proyectos con `estatus === 'Completado'`:
### 1. Activos Producidos (Total)
* **Definición:** Activos que fueron creados/asignados para completar los proyectos finalizados.
* **Lógica:** Suma de los requerimientos originales de todos los proyectos completados.
* **Fórmula:**
$$\text{Producidos}(c) = \sum_{p \in \text{Completados}} p[c]$$
*(Donde $c$ es el campo de requerimiento del activo, como `amarillo`, `naranjas`, etc.)*
### 2. Activos Recuperados
* **Definición:** Activos que se arrastraron exitosamente desde los proyectos terminados hacia los departamentos (lo cual resta del proyecto y suma al departamento).
* **Lógica:** La diferencia entre el requerimiento original del proyecto completado y su valor de asignación actual (que disminuye al ser arrastrado).
* **Fórmula:**
$$\text{Recuperados}(c) = \sum_{p \in \text{Completados}} (p[c] - p['activoAsignado' + (i+1)])$$
*(Donde $i$ es el índice del slot correspondiente al tipo de activo en el proyecto)*
### 3. Activos Perdidos
* **Definición:** Activos que no se pudieron recuperar de proyectos finalizados por falta de recursos o de espacio antes de cambiar de periodo.
* **Lógica:** Suma de los activos remanentes (`activoAsignadoX`) en proyectos completados que pertenecen a trimestres anteriores (ya que en el trimestre actual todavía es posible recuperarlos).
* **Fórmula:**
$$\text{Perdidos}(c) = \sum_{p \in \text{Completados}, p.\text{trimestreCompletado} < \text{trimestreActual}} p['activoAsignado' + (i+1)]$$
---
## 🛠️ Archivos y Cambios Requeridos
Todo el cambio se centraliza en el archivo **[resumen.php](file:///C:/CHV/ludotecaLocal/Colaborando/resumen.php)**.
### Paso 1: Interfaz de Usuario (HTML)
Modificar la estructura de la tabla `#tablaActivos` (líneas ~308-348) para cambiar sus encabezados a:
1. **Activo**
2. **Producidos**
3. **Recuperados**
4. **Perdidos**
Asignar identificadores de celda descriptivos para inyectar los datos, por ejemplo:
* Para Personal Calificado: `producidosPersonalCalificado`, `recuperadosPersonalCalificado`, `perdidosPersonalCalificado`.
* Para Analistas: `producidosAnalistas`, `recuperadosAnalistas`, `perdidosAnalistas`.
* *(Repetir para los 6 tipos de activos)*.
### Paso 2: Motor de Cálculo (JavaScript)
Dentro de la función `actualizarResumenUI()` (línea ~720):
1. **Inicializar:** Crear un objeto local para llevar las cuentas por tipo de activo e indicador (ej. `const stats = { PersonalCalificado: { producidos: 0, recuperados: 0, perdidos: 0 }, ... }`).
2. **Procesar:** Iterar sobre el arreglo `proyectos` y clasificar según las fórmulas explicadas.
3. **Renderizar:** Actualizar el contenido de las celdas del HTML utilizando jQuery (ej. `$('#producidosPersonalCalificado').text(stats.PersonalCalificado.producidos)`).
---
## 🎯 Beneficios de esta Solución
* **Integridad de datos:** No requiere modificar la estructura JSON del archivo de datos (`datos.json` / `cheve.json`).
* **Sincronización total:** Si el usuario recarga la página o arrastra activos, la tabla se vuelve a calcular en tiempo real reflejando el estado real del juego.
* **Mantenibilidad:** El código queda autocontenido en la vista de resumen.
+188
View File
@@ -391,6 +391,57 @@
<!-- Contenido se llenará con JS -->
</table>
</div>
<div class="card">
<h2>CONTABILIZACIÓN DE ACTIVOS</h2>
<table id="tablaConteoActivos" class="summary-table">
<thead>
<tr>
<th>Activo</th>
<th>Producidos</th>
<th>Recuperados</th>
<th>Perdidos</th>
</tr>
</thead>
<tbody>
<tr>
<td class="actPersonalCalificado" style="color:black!important; font-weight: bold; text-align: left;">Personal calificado</td>
<td id="conteoProducidosPersonalCalificado">0</td>
<td id="conteoRecuperadosPersonalCalificado">0</td>
<td id="conteoPerdidosPersonalCalificado">0</td>
</tr>
<tr>
<td class="actAnalistas" style="color:black!important; font-weight: bold; text-align: left;">Analistas</td>
<td id="conteoProducidosAnalistas">0</td>
<td id="conteoRecuperadosAnalistas">0</td>
<td id="conteoPerdidosAnalistas">0</td>
</tr>
<tr>
<td class="actFlujoDeEfectivo" style="color:black!important; font-weight: bold; text-align: left;">Flujo de efectivo</td>
<td id="conteoProducidosFlujoDeEfectivo">0</td>
<td id="conteoRecuperadosFlujoDeEfectivo">0</td>
<td id="conteoPerdidosFlujoDeEfectivo">0</td>
</tr>
<tr>
<td class="actCreditoEInversion" style="font-weight: bold; text-align: left;">Crédito e Inversión</td>
<td id="conteoProducidosCreditoEInversion">0</td>
<td id="conteoRecuperadosCreditoEInversion">0</td>
<td id="conteoPerdidosCreditoEInversion">0</td>
</tr>
<tr>
<td class="actTecnologia" style="font-weight: bold; text-align: left;">Tecnología</td>
<td id="conteoProducidosTecnologia">0</td>
<td id="conteoRecuperadosTecnologia">0</td>
<td id="conteoPerdidosTecnologia">0</td>
</tr>
<tr>
<td class="actTransporteYMaquinaria" style="font-weight: bold; text-align: left;">Transporte y Maquinaria</td>
<td id="conteoProducidosTransporteYMaquinaria">0</td>
<td id="conteoRecuperadosTransporteYMaquinaria">0</td>
<td id="conteoPerdidosTransporteYMaquinaria">0</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- =================================================================
@@ -426,6 +477,11 @@
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="capitalCh" class="draggable recurso-item">0</div>
</td>
</tr>
<tr>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioTiempoCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioPersonalCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioCapitalCh"></td>
</tr>
</table>
</td>
</tr>
@@ -465,6 +521,11 @@
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="capitalCh" class="draggable recurso-item">0</div>
</td>
</tr>
<tr>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioTiempoCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioPersonalCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioCapitalCh"></td>
</tr>
</table>
</td>
</tr>
@@ -504,6 +565,11 @@
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="capitalCh" class="draggable recurso-item">0</div>
</td>
</tr>
<tr>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioTiempoCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioPersonalCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioCapitalCh"></td>
</tr>
</table>
</td>
</tr>
@@ -543,6 +609,11 @@
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="capitalCh" class="draggable recurso-item">0</div>
</td>
</tr>
<tr>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioTiempoCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioPersonalCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioCapitalCh"></td>
</tr>
</table>
</td>
</tr>
@@ -582,6 +653,11 @@
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="capitalCh" class="draggable recurso-item">0</div>
</td>
</tr>
<tr>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioTiempoCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioPersonalCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioCapitalCh"></td>
</tr>
</table>
</td>
</tr>
@@ -621,6 +697,11 @@
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="capitalCh" class="draggable recurso-item">0</div>
</td>
</tr>
<tr>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioTiempoCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioPersonalCh"></td>
<td style="text-align:center; font-size:11px; color:#c9302c; font-weight:bold; height:15px; padding: 0;" class="beneficioCapitalCh"></td>
</tr>
</table>
</td>
</tr>
@@ -706,6 +787,32 @@
deptoCard.find('#activoCh1').text(findArrayValue(deptoArr, 'activo1'));
deptoCard.find('#activoCh2').text(findArrayValue(deptoArr, 'activo2'));
// Actualizar beneficios de habilidades acreditadas (-1 T, -1 P, -1 C)
const habTiempo = findArrayValue(deptoArr, 'habilidadTiempo');
const habPersonal = findArrayValue(deptoArr, 'habilidadPersonal');
const habCapital = findArrayValue(deptoArr, 'habilidadCapital');
let txtTiempo = '';
let txtPersonal = '';
let txtCapital = '';
if (habTiempo && habTiempo !== 0) {
const ben = findArrayValue(arreglosCapacitaciones[habTiempo], 'beneficio');
txtTiempo = `${ben} T`;
}
if (habPersonal && habPersonal !== 0) {
const ben = findArrayValue(arreglosCapacitaciones[habPersonal], 'beneficio');
txtPersonal = `${ben} P`;
}
if (habCapital && habCapital !== 0) {
const ben = findArrayValue(arreglosCapacitaciones[habCapital], 'beneficio');
txtCapital = `${ben} C`;
}
deptoCard.find('.beneficioTiempoCh').text(txtTiempo);
deptoCard.find('.beneficioPersonalCh').text(txtPersonal);
deptoCard.find('.beneficioCapitalCh').text(txtCapital);
// Mostrar/Ocultar Habilidad Especial si ya se acreditó
const accionEspecial = findArrayValue(deptoArr, 'accionEspecialQuincenal');
const rowHE = deptoCard.find('.fila-habilidad-especial');
@@ -799,6 +906,87 @@
}
});
// --- 2.5 Contabilización de Activos (Producidos, Recuperados y Perdidos) ---
const statsActivos = {
PersonalCalificado: {
producidos: 0,
recuperados: 0,
perdidos: 0
},
Analistas: {
producidos: 0,
recuperados: 0,
perdidos: 0
},
FlujoDeEfectivo: {
producidos: 0,
recuperados: 0,
perdidos: 0
},
CreditoEInversion: {
producidos: 0,
recuperados: 0,
perdidos: 0
},
Tecnologia: {
producidos: 0,
recuperados: 0,
perdidos: 0
},
TransporteYMaquinaria: {
producidos: 0,
recuperados: 0,
perdidos: 0
}
};
const mapaColoresActivos = {
amarillo: 'PersonalCalificado',
naranjas: 'Analistas',
verdes: 'FlujoDeEfectivo',
azules: 'TransporteYMaquinaria',
rojos: 'Tecnologia',
morados: 'CreditoEInversion'
};
const listaColores = ['amarillo', 'naranjas', 'verdes', 'azules', 'rojos', 'morados'];
proyectos.forEach(p => {
if (p.estatus === 'Completado') {
const coloresConValores = listaColores
.filter(color => p[color] !== null && p[color] > 0)
.map(color => ({
color,
valor: p[color]
}));
coloresConValores.forEach((item, idx) => {
const tipoActivo = mapaColoresActivos[item.color];
const reqOriginal = item.valor;
const asignadoActual = parseInt(p['activoAsignado' + (idx + 1)]) || 0;
// Producidos
statsActivos[tipoActivo].producidos += reqOriginal;
// Recuperados
const recuperados = reqOriginal - asignadoActual;
statsActivos[tipoActivo].recuperados += (recuperados > 0 ? recuperados : 0);
// Perdidos (sólo si pertenece a un trimestre anterior)
if (p.trimestreCompletado < trimestreActual) {
statsActivos[tipoActivo].perdidos += asignadoActual;
}
});
}
});
// Inyectar datos en la tabla HTML (con prefijo conteo)
const tiposActivos = ['PersonalCalificado', 'Analistas', 'FlujoDeEfectivo', 'CreditoEInversion', 'Tecnologia', 'TransporteYMaquinaria'];
tiposActivos.forEach(tipo => {
$(`#conteoProducidos${tipo}`).text(statsActivos[tipo].producidos);
$(`#conteoRecuperados${tipo}`).text(statsActivos[tipo].recuperados);
$(`#conteoPerdidos${tipo}`).text(statsActivos[tipo].perdidos);
});
$('#resumen-proyectos').html(`
<thead><tr><th></th><th>T1</th><th>T2</th><th>T3</th><th>T4</th></tr></thead>
<tbody>