mirror of
https://github.com/cheveguerra/Colaborando.git
synced 2026-08-18 16:36:39 +00:00
1ac6233e3c
- Ocultar dinámicamente contenedores vacíos de activos asignados en tarjetas de proyectos (.pm-card :empty). - Ajustar estilos del temporizador (.timer-face) y actualizar enlace de navegación a resumen3.php. - Actualizar CONTEXT.md con el resumen de arquitectura y estado del proyecto.
2151 lines
111 KiB
PHP
2151 lines
111 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="es">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Resumen de Colaborando</title>
|
|
<!-- Estilos y scripts base de colaborando3.php -->
|
|
<link rel="stylesheet" href="js/jquery-ui.min.css">
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Ubuntu&display=swap');
|
|
|
|
body,
|
|
input,
|
|
button {
|
|
font-family: 'Ubuntu', sans-serif;
|
|
font-size: 14px;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.draggable {
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* --- Estilos para la nueva maqueta --- */
|
|
.dashboard-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
padding: 8px;
|
|
}
|
|
|
|
.top-row {
|
|
display: flex;
|
|
gap: 8px;
|
|
width: 100%;
|
|
}
|
|
|
|
.top-row>.card {
|
|
flex: 1 1 0px;
|
|
margin: 0;
|
|
min-width: 0;
|
|
padding: 4px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.main-container {
|
|
display: flex;
|
|
gap: 8px;
|
|
width: 100%;
|
|
}
|
|
|
|
.column {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 5px;
|
|
}
|
|
|
|
.column-depts {
|
|
flex: 1 1 0px;
|
|
min-width: 0;
|
|
/* 1/5 del ancho (20%) */
|
|
}
|
|
|
|
.column-completed {
|
|
flex: 2 1 0px;
|
|
min-width: 0;
|
|
/* 2/5 del ancho (40%) */
|
|
}
|
|
|
|
.column-active {
|
|
flex: 2 1 0px;
|
|
min-width: 0;
|
|
/* 2/5 del ancho (40%) */
|
|
}
|
|
|
|
.card {
|
|
border: 2px solid #ccc;
|
|
border-radius: 5px;
|
|
padding: 6px;
|
|
background-color: #f9f9f9;
|
|
}
|
|
|
|
h2 {
|
|
text-align: center;
|
|
margin-top: 0;
|
|
margin-bottom: 6px;
|
|
font-size: 1.25em;
|
|
background-color: gray;
|
|
color: white;
|
|
padding: 5px;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/* Estilos para las tablas de resumen */
|
|
.summary-table {
|
|
font-size: 13px;
|
|
}
|
|
|
|
.summary-table th,
|
|
.summary-table td {
|
|
border: 1px solid #ddd;
|
|
padding: 4px 6px;
|
|
text-align: center;
|
|
}
|
|
|
|
.summary-table th {
|
|
background-color: #e9e9e9;
|
|
}
|
|
|
|
/* Estilos para los departamentos en una columna */
|
|
/* Se ajusta el selector para que apunte a los .card dentro de la columna de departamentos,
|
|
restaurando el borde gris y eliminando el padding para que la tabla se ajuste. */
|
|
.column-depts .card {
|
|
padding: 0;
|
|
border: solid 3px gray;
|
|
}
|
|
|
|
.departamentos #nombreDeptoCh {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.departamentos td {
|
|
padding: 2px 5px;
|
|
}
|
|
|
|
/* Estilos para los proyectos (activos y completados) */
|
|
.project-card {
|
|
border: 2px solid gray;
|
|
font-size: 12px;
|
|
background-color: white;
|
|
}
|
|
|
|
.project-card.completado {
|
|
background-color: lightgray;
|
|
}
|
|
|
|
.project-header {
|
|
font-weight: bold;
|
|
text-align: center;
|
|
padding: 4px;
|
|
border-bottom: 1px solid gray;
|
|
}
|
|
|
|
.project-body {
|
|
padding: 5px;
|
|
text-align: center;
|
|
}
|
|
|
|
.project-assets-req,
|
|
.project-assets-asig {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 5px;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.project-assets-req span,
|
|
.project-assets-asig span {
|
|
padding: 4px;
|
|
color: white;
|
|
border-radius: 3px;
|
|
min-width: 30px;
|
|
text-align: center;
|
|
}
|
|
|
|
.project-footer {
|
|
background-color: silver;
|
|
text-align: center;
|
|
padding: 3px;
|
|
font-size: 11px;
|
|
border-top: 1px solid gray;
|
|
}
|
|
|
|
/* Clases de activos (copiadas de colaborando3.php) */
|
|
.actNinguno {
|
|
background-color: white;
|
|
color: black !important;
|
|
border: 1px solid #ccc;
|
|
}
|
|
|
|
.actPersonalCalificado {
|
|
background-color: yellow;
|
|
color: black !important;
|
|
}
|
|
|
|
.actAnalistas {
|
|
background-color: orange;
|
|
color: black !important;
|
|
}
|
|
|
|
.actFlujoDeEfectivo {
|
|
background-color: limegreen;
|
|
color: black !important;
|
|
}
|
|
|
|
.actCreditoEInversion {
|
|
background-color: blueviolet;
|
|
color: white !important;
|
|
}
|
|
|
|
.actTecnologia {
|
|
background-color: red;
|
|
color: white !important;
|
|
}
|
|
|
|
.actTransporteYMaquinaria {
|
|
background-color: blue;
|
|
color: white !important;
|
|
}
|
|
|
|
/* Estilo para drag-drop de recuperación */
|
|
.asset-recover {
|
|
cursor: grab;
|
|
}
|
|
|
|
.nav-button {
|
|
display: inline-block;
|
|
padding: 6px 10px;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
color: #fff !important;
|
|
background-color: #007bff;
|
|
border-radius: 4px;
|
|
text-decoration: none;
|
|
text-align: center;
|
|
}
|
|
|
|
.nav-button:hover {
|
|
background-color: #0056b3;
|
|
}
|
|
|
|
/* Estilos para que los diálogos/alertas jQuery UI se muestren de color rojo (carmesí) */
|
|
.ui-dialog-titlebar {
|
|
background-color: crimson;
|
|
color: white;
|
|
}
|
|
|
|
.ui-widget.ui-widget-content {
|
|
border-color: crimson;
|
|
border-width: 5px;
|
|
}
|
|
|
|
.ui-dialog .ui-dialog-content {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
}
|
|
|
|
.ui-dialog .ui-dialog-buttonpane button {
|
|
font-size: 17px;
|
|
}
|
|
</style>
|
|
<!-- Scripts base -->
|
|
<script src="js/jquery-3.5.1.min.js"></script>
|
|
<script src="js/jquery-ui.min.js"></script>
|
|
<script src="colaborando_arreglos.js?v=<?php echo filemtime('colaborando_arreglos.js'); ?>"></script>
|
|
<script src="manejoDeSesiones.js?v=<?php echo filemtime('manejoDeSesiones.js'); ?>"></script>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="dashboard-wrapper">
|
|
<!-- =================================================================
|
|
FILA SUPERIOR: 5 BLOQUES INFORMATIVOS / COLUMNAS HORIZONTALES
|
|
================================================================== -->
|
|
<div class="top-row">
|
|
|
|
<!-- BLOQUE 1: INFORMACIÓN DE SESIÓN Y TIMER -->
|
|
<div class="card">
|
|
<div style="text-align: center; margin-bottom: 4px;">
|
|
<img id="logo" src="img/logoColaborando-tablero.png" style="max-height: 40px; width: auto;">
|
|
</div>
|
|
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0 4px; margin-bottom: 6px;">
|
|
<div id="nombreSesion" style="font-weight: bold; font-size: 15px; color: #555;"></div>
|
|
<div style="display: flex; gap: 5px;">
|
|
<button id="btnFullscreen" onclick="toggleFullscreen()" class="nav-button" style="border: none; cursor: pointer; text-align: center; line-height: 1.1; padding: 4px 8px; font-size: 12px;">Pantalla<br>Completa</button>
|
|
<a href="colaborando3.php?n=<?php echo htmlspecialchars($_GET['n'] ?? $_GET['nombre'] ?? ''); ?>" class="nav-button" style="text-align: center; line-height: 1.1; padding: 4px 8px; font-size: 12px;">Ir al<br>Tablero</a>
|
|
</div>
|
|
</div>
|
|
<div style="border-top: 1px solid #ddd; padding-top: 6px;">
|
|
<table style="width:100%; text-align:center; vertical-align: middle;">
|
|
<tr>
|
|
<td style="width:35%; vertical-align: middle;">
|
|
<span id="resumenTrimestre" style="font-size:1.6em; font-weight:bold; color: #007bff;"></span>
|
|
<br>
|
|
<span id="resumenQuincena" style="font-size:1.6em; font-weight:bold; color: #007bff;"></span>
|
|
</td>
|
|
<td style="width:65%; vertical-align: middle;">
|
|
<div id="timer" style="margin-bottom: 3px;"><span id="time" style="font-size:22px; font-weight:bold;">2:00</span></div>
|
|
<div class="button-container" style="display: flex; justify-content: center; gap: 5px; margin-bottom: 4px;">
|
|
<button id="relojStartPauseButton" onclick="relojToggleTimer()" style="font-size: 12px; padding: 3px 8px; font-weight: bold;">Iniciar</button>
|
|
<button onclick="relojResumeTimer()" style="font-size: 12px; padding: 3px 8px; font-weight: bold;">Continuar</button>
|
|
</div>
|
|
<input type="range" id="timeRange" min="1" max="3" value="1" step="1" oninput="relojUpdateTime()" style="width: 85%; margin: 2px 0;">
|
|
<div id="rangeValue" style="font-weight: bold; font-size: 12px; line-height: 1.2;">2 min</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<!-- Hidden elements to keep jsCode.js and other logic working -->
|
|
<div style="display:none;">
|
|
<div id="trimestre">
|
|
<table>
|
|
<tr>
|
|
<td id="T1">1</td>
|
|
<td id="T2">2</td>
|
|
<td id="T3">3</td>
|
|
<td id="T4">4</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div id="quincena">
|
|
<table id="tablaQuincena">
|
|
<tr>
|
|
<td><button id="bMenos"></button></td>
|
|
<td><input id="etQuincena" type="text" value="1"></td>
|
|
<td><button id="bMas"></button></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- BLOQUE 2: TABLA DE ACTIVOS (PRODUCCIÓN Y RECUPERACIÓN) -->
|
|
<div class="card">
|
|
<table id="tablaActivos" class="summary-table">
|
|
<thead>
|
|
<tr>
|
|
<th colspan="2">ACTIVOS</th>
|
|
<th>Producción</th>
|
|
<th>Recuperación</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" class="actPersonalCalificado" style="color:black!important; font-weight:bold;">Personal calificado</td>
|
|
<td id="activosPersonalCalificado"></td>
|
|
<td id="recuperacionPersonalCalificado"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2" class="actAnalistas" style="color:black!important; font-weight:bold;">Analistas</td>
|
|
<td id="activosAnalistas"></td>
|
|
<td id="recuperacionAnalistas"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2" class="actFlujoDeEfectivo" style="color:black!important; font-weight:bold;">Flujo de efectivo</td>
|
|
<td id="activosFlujoDeEfectivo"></td>
|
|
<td id="recuperacionFlujoDeEfectivo"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2" class="actCreditoEInversion" style="font-weight:bold;">Crédito e Inversión</td>
|
|
<td id="activosCreditoEInversion"></td>
|
|
<td id="recuperacionCreditoEInversion"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2" class="actTecnologia" style="font-weight:bold;">Tecnología</td>
|
|
<td id="activosTecnologia"></td>
|
|
<td id="recuperacionTecnologia"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2" class="actTransporteYMaquinaria" style="font-weight:bold;">Transporte y Maquinaria</td>
|
|
<td id="activosTransporteYMaquinaria"></td>
|
|
<td id="recuperacionTransporteYMaquinaria"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- BLOQUE 3: PROGRESIÓN Y ACUMULADOS -->
|
|
<div class="card">
|
|
<h2>PROGRESIÓN</h2>
|
|
<table class="summary-table">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>T1</th>
|
|
<th>T2</th>
|
|
<th>T3</th>
|
|
<th>T4</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td style="font-weight:bold;">Ingreso</td>
|
|
<td id="ingresoT1">$0</td>
|
|
<td id="ingresoT2">$0</td>
|
|
<td id="ingresoT3">$0</td>
|
|
<td id="ingresoT4">$0</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="font-weight:bold;">Acumulado</td>
|
|
<td id="acumuladoT1">$0</td>
|
|
<td id="acumuladoT2">$0</td>
|
|
<td id="acumuladoT3">$0</td>
|
|
<td id="acumuladoT4">$0</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<div id="grafico-progresion-container" style="position: relative; margin-top: 4px; text-align: center; cursor: pointer;">
|
|
<canvas id="grafico-progresion-canvas" style="width: 100%; height: 75px; display: block;"></canvas>
|
|
<div id="grafico-progresion-popover" style="display: none; position: absolute; top: -90px; left: -150px; width: 560px; background: #ffffff; border: 2.5px solid #007bff; border-radius: 10px; box-shadow: 0 12px 30px rgba(0,0,0,0.4); padding: 10px; z-index: 10000; pointer-events: none;">
|
|
<div style="font-weight: bold; font-size: 14px; color: #007bff; margin-bottom: 5px; border-bottom: 1px solid #e0e0e0; padding-bottom: 4px; text-align: center;">PROGRESIÓN TRIMESTRAL</div>
|
|
<canvas id="grafico-progresion-canvas-popover" style="width: 100%; height: 185px; display: block;"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- BLOQUE 4: PROYECTOS E INCIDENCIAS (UNIFICADO COMPACTO) -->
|
|
<div class="card">
|
|
<h2>PROYECTOS E INCIDENCIAS</h2>
|
|
<table id="resumen-proyectos" class="summary-table">
|
|
<!-- Contenido unificado se llenará con JS -->
|
|
</table>
|
|
<table id="resumen-incidencias" class="summary-table" style="display:none;"></table>
|
|
</div>
|
|
|
|
<!-- BLOQUE 5: CONTABILIZACIÓN DE ACTIVOS -->
|
|
<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>
|
|
|
|
<!-- =================================================================
|
|
FILA INFERIOR: CONTENIDO PRINCIPAL (DEPARTAMENTOS, PROYECTOS TERMINADOS Y ACTIVOS)
|
|
================================================================== -->
|
|
<div class="main-container">
|
|
|
|
<!-- COLUMNA 1 (20%): DEPARTAMENTOS -->
|
|
<div class="column column-depts">
|
|
<h2>DEPARTAMENTOS</h2>
|
|
|
|
<!-- MarketingYVentas -->
|
|
<div class="card">
|
|
<table style="width:100%;" class="departamentos droppableRecursos droppable-asset-recovery" id="MarketingYVentas">
|
|
<tr style="border-bottom: 1px solid gray; height: 35px;">
|
|
<td style="width: 70%;"><span id="nombreDeptoCh">MARKETING Y VENTAS</span></td>
|
|
<td style="text-align:right;" colspan="2">
|
|
<span style="border:1px solid black;padding:5px;" class="actPersonalCalificado draggable activo-item" id="activoCh1">0</span>
|
|
<span style="border:1px solid black;padding:5px;" class="actFlujoDeEfectivo draggable activo-item" id="activoCh2">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align:middle;">
|
|
<td colspan=3>
|
|
<table>
|
|
<tr>
|
|
<td style="text-align:center;">
|
|
<img src="img/tiempoCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="tiempoCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/personalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="personalCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/capitalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<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>
|
|
<!-- Fila de Habilidad Especial -->
|
|
<tr class="fila-habilidad-especial" style="display: none; background-color: #f0f0f0; border-top: 1px solid gray;">
|
|
<td colspan="3" style="text-align: center; font-size: 16px; padding: 4px; font-weight: bold; color: #444;">
|
|
HE: <span class="texto-habilidad-especial"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Finanzas -->
|
|
<div class="card">
|
|
<table style="width:100%;" class="departamentos droppableRecursos droppable-asset-recovery" id="Finanzas">
|
|
<tr style="border-bottom: 1px solid gray; height: 35px;">
|
|
<td style="width: 70%;"><span id="nombreDeptoCh">FINANZAS</span></td>
|
|
<td style="text-align:right;" colspan="2">
|
|
<span style="border:1px solid black;padding:5px;" class="actFlujoDeEfectivo draggable activo-item" id="activoCh1">0</span>
|
|
<span style="border:1px solid black;padding:5px;" class="actCreditoEInversion draggable activo-item" id="activoCh2">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align:middle;">
|
|
<td colspan=3>
|
|
<table>
|
|
<tr>
|
|
<td style="text-align:center;">
|
|
<img src="img/tiempoCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="tiempoCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/personalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="personalCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/capitalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<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>
|
|
<!-- Fila de Habilidad Especial -->
|
|
<tr class="fila-habilidad-especial" style="display: none; background-color: #f0f0f0; border-top: 1px solid gray;">
|
|
<td colspan="3" style="text-align: center; font-size: 16px; padding: 4px; font-weight: bold; color: #444;">
|
|
HE: <span class="texto-habilidad-especial"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- InvestigacionYDesarrollo -->
|
|
<div class="card">
|
|
<table style="width:100%;" class="departamentos droppableRecursos droppable-asset-recovery" id="InvestigacionYDesarrollo">
|
|
<tr style="border-bottom: 1px solid gray; height: 35px;">
|
|
<td style="width: 70%;"><span id="nombreDeptoCh">INVESTIGACIÓN Y DESARROLLO</span></td>
|
|
<td style="text-align:right;" colspan="2">
|
|
<span style="border:1px solid black;padding:5px;" class="actCreditoEInversion draggable activo-item" id="activoCh1">0</span>
|
|
<span style="border:1px solid black;padding:5px;" class="actTecnologia draggable activo-item" id="activoCh2">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align:middle;">
|
|
<td colspan=3>
|
|
<table>
|
|
<tr>
|
|
<td style="text-align:center;">
|
|
<img src="img/tiempoCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="tiempoCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/personalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="personalCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/capitalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<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>
|
|
<!-- Fila de Habilidad Especial -->
|
|
<tr class="fila-habilidad-especial" style="display: none; background-color: #f0f0f0; border-top: 1px solid gray;">
|
|
<td colspan="3" style="text-align: center; font-size: 16px; padding: 4px; font-weight: bold; color: #444;">
|
|
HE: <span class="texto-habilidad-especial"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- LogisticaYSistemas -->
|
|
<div class="card">
|
|
<table style="width:100%;" class="departamentos droppableRecursos droppable-asset-recovery" id="LogisticaYSistemas">
|
|
<tr style="border-bottom: 1px solid gray; height: 35px;">
|
|
<td style="width: 70%;"><span id="nombreDeptoCh">LOGÍSTICA Y SISTEMAS</span></td>
|
|
<td style="text-align:right;" colspan="2">
|
|
<span style="border:1px solid black;padding:5px;" class="actTecnologia draggable activo-item" id="activoCh1">0</span>
|
|
<span style="border:1px solid black;padding:5px;" class="actTransporteYMaquinaria draggable activo-item" id="activoCh2">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align:middle;">
|
|
<td colspan=3>
|
|
<table>
|
|
<tr>
|
|
<td style="text-align:center;">
|
|
<img src="img/tiempoCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="tiempoCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/personalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="personalCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/capitalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<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>
|
|
<!-- Fila de Habilidad Especial -->
|
|
<tr class="fila-habilidad-especial" style="display: none; background-color: #f0f0f0; border-top: 1px solid gray;">
|
|
<td colspan="3" style="text-align: center; font-size: 16px; padding: 4px; font-weight: bold; color: #444;">
|
|
HE: <span class="texto-habilidad-especial"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Operaciones -->
|
|
<div class="card">
|
|
<table style="width:100%;" class="departamentos droppableRecursos droppable-asset-recovery" id="Operaciones">
|
|
<tr style="border-bottom: 1px solid gray; height: 35px;">
|
|
<td style="width: 70%;"><span id="nombreDeptoCh">OPERACIONES</span></td>
|
|
<td style="text-align:right;" colspan="2">
|
|
<span style="border:1px solid black;padding:5px;" class="actTransporteYMaquinaria draggable activo-item" id="activoCh1">0</span>
|
|
<span style="border:1px solid black;padding:5px;" class="actAnalistas draggable activo-item" id="activoCh2">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align:middle;">
|
|
<td colspan=3>
|
|
<table>
|
|
<tr>
|
|
<td style="text-align:center;">
|
|
<img src="img/tiempoCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="tiempoCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/personalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="personalCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/capitalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<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>
|
|
<!-- Fila de Habilidad Especial -->
|
|
<tr class="fila-habilidad-especial" style="display: none; background-color: #f0f0f0; border-top: 1px solid gray;">
|
|
<td colspan="3" style="text-align: center; font-size: 16px; padding: 4px; font-weight: bold; color: #444;">
|
|
HE: <span class="texto-habilidad-especial"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- RecursosHumanos -->
|
|
<div class="card">
|
|
<table style="width:100%;" class="departamentos droppableRecursos droppable-asset-recovery" id="RecursosHumanos">
|
|
<tr style="border-bottom: 1px solid gray; height: 35px;">
|
|
<td style="width: 70%;"><span id="nombreDeptoCh">RECURSOS HUMANOS</span></td>
|
|
<td style="text-align:right;" colspan="2">
|
|
<span style="border:1px solid black;padding:5px;" class="actAnalistas draggable activo-item" id="activoCh1">0</span>
|
|
<span style="border:1px solid black;padding:5px;" class="actPersonalCalificado draggable activo-item" id="activoCh2">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr style="vertical-align:middle;">
|
|
<td colspan=3>
|
|
<table>
|
|
<tr>
|
|
<td style="text-align:center;">
|
|
<img src="img/tiempoCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="tiempoCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/personalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<div style="vertical-align:middle; display:inline-block; font-weight:bold; font-size:16px;" id="personalCh" class="draggable recurso-item">0</div>
|
|
</td>
|
|
<td style="text-align:center;">
|
|
<img src="img/capitalCH.png" style="width: 30px; height: 30px; vertical-align: middle;">
|
|
<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>
|
|
<!-- Fila de Habilidad Especial -->
|
|
<tr class="fila-habilidad-especial" style="display: none; background-color: #f0f0f0; border-top: 1px solid gray;">
|
|
<td colspan="3" style="text-align: center; font-size: 16px; padding: 4px; font-weight: bold; color: #444;">
|
|
HE: <span class="texto-habilidad-especial"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- BOTON DE HABILIDAD ESPECIAL -->
|
|
<div class="card" style="padding: 5px; margin-top: 10px;">
|
|
<button id="resumenAccionHabilidadEspecial" class="nav-button" style="width: 100%;">
|
|
Utilizar Habilidad Especial
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- COLUMNAS 2 Y 3 (40%): PROYECTOS TERMINADOS -->
|
|
<div class="column column-completed">
|
|
<h2>PROYECTOS TERMINADOS (T)</h2>
|
|
<div id="completed-projects-container" style="display: flex; flex-wrap: wrap; gap: 10px; align-content: flex-start;">
|
|
<!-- Los proyectos completados del trimestre se insertan aquí por JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- COLUMNAS 4 Y 5 (40%): PROYECTOS ACTIVOS -->
|
|
<div class="column column-active">
|
|
<h2>PROYECTOS ACTIVOS</h2>
|
|
<div id="active-projects-container" style="display: flex; flex-wrap: wrap; gap: 10px; align-content: flex-start;">
|
|
<!-- Los proyectos activos se insertan aquí por JS -->
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- =================================================================
|
|
JAVASCRIPT
|
|
================================================================== -->
|
|
<script src="jsCode.js?v=<?php echo filemtime('jsCode.js'); ?>"></script>
|
|
|
|
<script>
|
|
// Sobreescribimos 'continuamos' para añadir la lógica de esta pantalla
|
|
const originalContinuamos = continuamos;
|
|
continuamos = function() {
|
|
originalContinuamos();
|
|
actualizarResumenUI();
|
|
};
|
|
|
|
// YA NO SE NECESITA la función local `llenaDepartamentoGde` porque ahora usamos la de jsCode.js
|
|
|
|
function formatCurrency(value) {
|
|
return new Intl.NumberFormat('es-MX', {
|
|
style: 'currency',
|
|
currency: 'MXN',
|
|
minimumFractionDigits: 0,
|
|
maximumFractionDigits: 0,
|
|
}).format(value);
|
|
}
|
|
|
|
/**
|
|
* Actualiza la UI de una tarjeta de departamento en la pantalla de resumen.
|
|
* Usa IDs porque ahora la estructura es como en colaborando3.php
|
|
*/
|
|
function actualizarTarjetaDepto(deptoId) {
|
|
const deptoArr = arreglosDeptos['arr' + deptoId];
|
|
const deptoCard = $('#' + deptoId);
|
|
|
|
if (!deptoArr || !deptoCard.length) return;
|
|
|
|
// Actualizar recursos (con selector flexible para soportar el deptoActual con IDs renombrados)
|
|
const tiempoElem = deptoCard.find('#tiempoCh').length ? deptoCard.find('#tiempoCh') : deptoCard.find('#recursoDispTiempoGde');
|
|
const personalElem = deptoCard.find('#personalCh').length ? deptoCard.find('#personalCh') : deptoCard.find('#recursoDispPersonalGde');
|
|
const capitalElem = deptoCard.find('#capitalCh').length ? deptoCard.find('#capitalCh') : deptoCard.find('#recursoDispCapitalGde');
|
|
|
|
tiempoElem.text(findArrayValue(deptoArr, 'recursoTiempo'));
|
|
personalElem.text(findArrayValue(deptoArr, 'recursoPersonal'));
|
|
capitalElem.text(findArrayValue(deptoArr, 'recursoCapital'));
|
|
|
|
// Actualizar activos
|
|
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');
|
|
if (accionEspecial && accionEspecial !== '') {
|
|
rowHE.find('.texto-habilidad-especial').text(accionEspecial);
|
|
rowHE.show();
|
|
} else {
|
|
rowHE.hide();
|
|
}
|
|
}
|
|
|
|
function actualizarResumenUI() {
|
|
console.log("Actualizando UI de Resumen...");
|
|
|
|
const quincena = parseInt($('#etQuincena').val()) || 1;
|
|
const trimestreActual = Math.floor((quincena - 1) / 6) + 1;
|
|
|
|
$('#resumenTrimestre').text(`T${trimestreActual}`);
|
|
$('#resumenQuincena').text(`Q${quincena}`);
|
|
|
|
// --- 1. Actualizar Progresión ---
|
|
$('#ingresoT1').text(formatCurrency(arregloGeneral.trimestre1 || 0));
|
|
$('#ingresoT2').text(formatCurrency(arregloGeneral.trimestre2 || 0));
|
|
$('#ingresoT3').text(formatCurrency(arregloGeneral.trimestre3 || 0));
|
|
$('#ingresoT4').text(formatCurrency(arregloGeneral.trimestre4 || 0));
|
|
|
|
let acumulado = 0;
|
|
acumulado += (arregloGeneral.trimestre1 || 0);
|
|
$('#acumuladoT1').text(formatCurrency(acumulado));
|
|
acumulado += (arregloGeneral.trimestre2 || 0);
|
|
$('#acumuladoT2').text(formatCurrency(acumulado));
|
|
acumulado += (arregloGeneral.trimestre3 || 0);
|
|
$('#acumuladoT3').text(formatCurrency(acumulado));
|
|
acumulado += (arregloGeneral.trimestre4 || 0);
|
|
$('#acumuladoT4').text(formatCurrency(acumulado));
|
|
|
|
// --- 2. Contar y mostrar resumen de Proyectos e Incidencias ---
|
|
let conteoProyectos = {
|
|
1: {
|
|
concretados: 0
|
|
},
|
|
2: {
|
|
concretados: 0
|
|
},
|
|
3: {
|
|
concretados: 0
|
|
},
|
|
4: {
|
|
concretados: 0
|
|
}
|
|
};
|
|
let conteoIncidencias = {
|
|
1: {
|
|
resueltos: 0
|
|
},
|
|
2: {
|
|
resueltos: 0
|
|
},
|
|
3: {
|
|
resueltos: 0
|
|
},
|
|
4: {
|
|
resueltos: 0
|
|
}
|
|
};
|
|
let proyectosEnProceso = 0;
|
|
let incidenciasEnProceso = 0;
|
|
|
|
proyectos.forEach(p => {
|
|
const esIncidencia = p.dificultad === 'Incidencia';
|
|
const trimestreCompletado = p.trimestreCompletado;
|
|
|
|
if (p.estatus === 'Completado') {
|
|
if (esIncidencia) {
|
|
if (!conteoIncidencias[trimestreCompletado]) conteoIncidencias[trimestreCompletado] = {
|
|
resueltos: 0
|
|
};
|
|
conteoIncidencias[trimestreCompletado].resueltos++;
|
|
} else {
|
|
if (!conteoProyectos[trimestreCompletado]) conteoProyectos[trimestreCompletado] = {
|
|
concretados: 0
|
|
};
|
|
conteoProyectos[trimestreCompletado].concretados++;
|
|
}
|
|
} else if (p.estatus === 'En proceso') {
|
|
if (esIncidencia) {
|
|
incidenciasEnProceso++;
|
|
} else {
|
|
proyectosEnProceso++;
|
|
}
|
|
}
|
|
});
|
|
|
|
// --- 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>
|
|
<tr><td style="font-weight:bold; text-align:left;">Proyectos En Proceso</td><td colspan="4">${proyectosEnProceso}</td></tr>
|
|
<tr><td style="font-weight:bold; text-align:left;">Proyectos Concretados</td><td>${conteoProyectos[1].concretados}</td><td>${conteoProyectos[2].concretados}</td><td>${conteoProyectos[3].concretados}</td><td>${conteoProyectos[4].concretados}</td></tr>
|
|
<tr><td style="font-weight:bold; text-align:left;">Incidencias En Proceso</td><td colspan="4">${incidenciasEnProceso}</td></tr>
|
|
<tr><td style="font-weight:bold; text-align:left;">Incidencias Resueltas</td><td>${conteoIncidencias[1].resueltos}</td><td>${conteoIncidencias[2].resueltos}</td><td>${conteoIncidencias[3].resueltos}</td><td>${conteoIncidencias[4].resueltos}</td></tr>
|
|
</tbody>
|
|
`);
|
|
$('#resumen-incidencias').empty();
|
|
|
|
// --- 3. Llenar columnas de proyectos ---
|
|
const completedContainer = $('#completed-projects-container');
|
|
const activeContainer = $('#active-projects-container');
|
|
completedContainer.empty();
|
|
activeContainer.empty();
|
|
|
|
$('.column-completed h2').text(`PROYECTOS TERMINADOS (T${trimestreActual})`);
|
|
|
|
proyectos.forEach(p => {
|
|
if (p.estatus === 'Completado' && p.trimestreCompletado === trimestreActual) {
|
|
completedContainer.append(crearTarjetaProyecto(p, true));
|
|
} else if (p.estatus === 'En proceso') {
|
|
activeContainer.append(crearTarjetaProyecto(p, false));
|
|
}
|
|
});
|
|
|
|
// --- 4. Actualizar todas las tarjetas de departamento con los datos cargados ---
|
|
const deptoIds = ["MarketingYVentas", "Finanzas", "InvestigacionYDesarrollo", "LogisticaYSistemas", "Operaciones", "RecursosHumanos"];
|
|
deptoIds.forEach(deptoId => {
|
|
actualizarTarjetaDepto(deptoId);
|
|
});
|
|
|
|
// --- 5. Dibujar gráfica de progresión (barras de objetivos $100k + línea de ingresos) ---
|
|
dibujarGraficaProgresion();
|
|
|
|
// --- 6. Inicializar todas las interacciones de Drag & Drop ---
|
|
inicializarInteraccionesDragDrop();
|
|
}
|
|
|
|
$(window).on('resize', function() {
|
|
dibujarGraficaProgresion();
|
|
});
|
|
|
|
$(document).on('mouseenter', '#grafico-progresion-container', function() {
|
|
const popover = $('#grafico-progresion-popover');
|
|
|
|
// Posicionamiento dinámico para evitar salirse por arriba de la pantalla
|
|
const containerOffset = $(this).offset();
|
|
const scrollTop = $(window).scrollTop();
|
|
const desiredTop = -90; // Posición más baja centrada sobre el bloque 3
|
|
|
|
if (containerOffset.top + desiredTop < scrollTop + 10) {
|
|
const safeTop = Math.max(-20, (scrollTop + 10) - containerOffset.top);
|
|
popover.css('top', safeTop + 'px');
|
|
} else {
|
|
popover.css('top', desiredTop + 'px');
|
|
}
|
|
|
|
popover.stop(true, true).fadeIn(150);
|
|
dibujarGraficaProgresionCanvas('grafico-progresion-canvas-popover', true);
|
|
});
|
|
|
|
$(document).on('mouseleave', '#grafico-progresion-container', function() {
|
|
$('#grafico-progresion-popover').stop(true, true).fadeOut(150);
|
|
});
|
|
|
|
function dibujarGraficaProgresion() {
|
|
dibujarGraficaProgresionCanvas('grafico-progresion-canvas', false);
|
|
}
|
|
|
|
function dibujarGraficaProgresionCanvas(canvasId, isExpanded) {
|
|
const canvas = document.getElementById(canvasId);
|
|
if (!canvas) return;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
const rect = canvas.getBoundingClientRect();
|
|
const width = rect.width || canvas.clientWidth || (isExpanded ? 560 : 220);
|
|
const height = isExpanded ? 185 : 75;
|
|
|
|
const dpr = window.devicePixelRatio || 1;
|
|
canvas.width = width * dpr;
|
|
canvas.height = height * dpr;
|
|
ctx.scale(dpr, dpr);
|
|
|
|
ctx.clearRect(0, 0, width, height);
|
|
|
|
// Datos guardados de Objetivos e Ingresos de la sesión
|
|
const objetivos = [
|
|
parseInt(arregloGeneral.objetivoT1) || 100000,
|
|
parseInt(arregloGeneral.objetivoT2) || 100000,
|
|
parseInt(arregloGeneral.objetivoT3) || 100000,
|
|
parseInt(arregloGeneral.objetivoT4) || 100000
|
|
];
|
|
const ingresos = [
|
|
arregloGeneral.trimestre1 || 0,
|
|
arregloGeneral.trimestre2 || 0,
|
|
arregloGeneral.trimestre3 || 0,
|
|
arregloGeneral.trimestre4 || 0
|
|
];
|
|
|
|
const maxVal = Math.max(120000, ...ingresos, ...objetivos) * 1.18;
|
|
|
|
const marginTop = isExpanded ? 28 : 14;
|
|
const marginBottom = isExpanded ? 24 : 14;
|
|
const marginLeft = isExpanded ? 55 : 32;
|
|
const marginRight = isExpanded ? 15 : 8;
|
|
const chartWidth = width - marginLeft - marginRight;
|
|
const chartHeight = height - marginTop - marginBottom;
|
|
|
|
// 1. Líneas de cuadrícula horizontales
|
|
ctx.strokeStyle = '#e6e6e6';
|
|
ctx.lineWidth = 1;
|
|
ctx.fillStyle = '#666';
|
|
ctx.font = isExpanded ? '12px Arial' : '9px Arial';
|
|
ctx.textAlign = 'right';
|
|
ctx.textBaseline = 'middle';
|
|
|
|
const steps = isExpanded ? 3 : 2;
|
|
for (let i = 0; i <= steps; i++) {
|
|
const val = (maxVal / steps) * i;
|
|
const y = height - marginBottom - (chartHeight / steps) * i;
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(marginLeft, y);
|
|
ctx.lineTo(width - marginRight, y);
|
|
ctx.stroke();
|
|
|
|
let label = '$' + (val >= 1000 ? Math.round(val / 1000) + 'k' : Math.round(val));
|
|
ctx.fillText(label, marginLeft - (isExpanded ? 6 : 3), y);
|
|
}
|
|
|
|
const colStep = chartWidth / 4;
|
|
const barWidth = Math.min(isExpanded ? 48 : 22, colStep * 0.45);
|
|
|
|
// 2. Dibujar Barras (Objetivos del Trimestre guardados)
|
|
for (let i = 0; i < 4; i++) {
|
|
const xCenter = marginLeft + colStep * i + colStep / 2;
|
|
const xBar = xCenter - barWidth / 2;
|
|
const barH = (objetivos[i] / maxVal) * chartHeight;
|
|
const yBar = height - marginBottom - barH;
|
|
|
|
ctx.fillStyle = '#5c9ecc';
|
|
ctx.fillRect(xBar, yBar, barWidth, barH);
|
|
ctx.strokeStyle = '#3b7bb2';
|
|
ctx.lineWidth = 1.2;
|
|
ctx.strokeRect(xBar, yBar, barWidth, barH);
|
|
|
|
ctx.fillStyle = '#333';
|
|
ctx.font = isExpanded ? 'bold 12px Arial' : 'bold 9px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'top';
|
|
ctx.fillText('T' + (i + 1), xCenter, height - marginBottom + (isExpanded ? 5 : 3));
|
|
|
|
if (isExpanded) {
|
|
ctx.fillStyle = '#1b4f72';
|
|
ctx.font = '11px Arial';
|
|
let formattedObj = '$' + Math.round(objetivos[i] / 1000) + 'k';
|
|
ctx.fillText('Obj: ' + formattedObj, xCenter, yBar - 14);
|
|
}
|
|
}
|
|
|
|
// 3. Dibujar Línea + Puntos (Ingresos del Trimestre)
|
|
const linePoints = [];
|
|
for (let i = 0; i < 4; i++) {
|
|
const xCenter = marginLeft + colStep * i + colStep / 2;
|
|
const valY = (ingresos[i] / maxVal) * chartHeight;
|
|
const yLine = height - marginBottom - valY;
|
|
linePoints.push({
|
|
x: xCenter,
|
|
y: yLine,
|
|
val: ingresos[i]
|
|
});
|
|
}
|
|
|
|
// Trazar línea conectora
|
|
ctx.strokeStyle = '#d9534f';
|
|
ctx.lineWidth = isExpanded ? 3.5 : 2;
|
|
ctx.beginPath();
|
|
linePoints.forEach((pt, idx) => {
|
|
if (idx === 0) ctx.moveTo(pt.x, pt.y);
|
|
else ctx.lineTo(pt.x, pt.y);
|
|
});
|
|
ctx.stroke();
|
|
|
|
// Puntos y valores
|
|
linePoints.forEach((pt) => {
|
|
ctx.fillStyle = '#d9534f';
|
|
ctx.beginPath();
|
|
ctx.arc(pt.x, pt.y, isExpanded ? 6 : 3.5, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
ctx.strokeStyle = '#ffffff';
|
|
ctx.lineWidth = isExpanded ? 2.5 : 1.5;
|
|
ctx.stroke();
|
|
|
|
if (pt.val > 0) {
|
|
ctx.fillStyle = '#a94442';
|
|
ctx.font = isExpanded ? 'bold 12px Arial' : 'bold 8px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'bottom';
|
|
let formattedVal = isExpanded ? formatCurrency(pt.val) : ('$' + (pt.val >= 1000 ? Math.round(pt.val / 1000) + 'k' : pt.val));
|
|
ctx.fillText(formattedVal, pt.x, pt.y - (isExpanded ? 7 : 3));
|
|
}
|
|
});
|
|
|
|
// 4. Leyenda en la esquina superior derecha
|
|
ctx.font = isExpanded ? '11px Arial' : '8px Arial';
|
|
ctx.textAlign = 'left';
|
|
ctx.textBaseline = 'top';
|
|
|
|
const legY = isExpanded ? 4 : 1;
|
|
|
|
if (isExpanded) {
|
|
// Leyenda amplia (2.5X)
|
|
const item1SquareX = width - 230;
|
|
const item1TextX = width - 213;
|
|
const item2CircleX = width - 95;
|
|
const item2TextX = width - 85;
|
|
|
|
// 🟦 Cuadro azul + Texto Objetivo
|
|
ctx.fillStyle = '#5c9ecc';
|
|
ctx.fillRect(item1SquareX, legY, 12, 12);
|
|
ctx.strokeStyle = '#3b7bb2';
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(item1SquareX, legY, 12, 12);
|
|
ctx.fillStyle = '#444';
|
|
ctx.fillText('Objetivo Trimestre', item1TextX, legY);
|
|
|
|
// 🔴 Círculo rojo + Texto Ingreso
|
|
ctx.fillStyle = '#d9534f';
|
|
ctx.beginPath();
|
|
ctx.arc(item2CircleX, legY + 6, 4.5, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
ctx.strokeStyle = '#ffffff';
|
|
ctx.lineWidth = 1;
|
|
ctx.stroke();
|
|
ctx.fillStyle = '#444';
|
|
ctx.fillText('Ingreso Real', item2TextX, legY);
|
|
} else {
|
|
// Leyenda compacta
|
|
const item1SquareX = width - 118;
|
|
const item1TextX = width - 108;
|
|
const item2CircleX = width - 42;
|
|
const item2TextX = width - 35;
|
|
|
|
// 🟦 Cuadro azul + Texto Obj.
|
|
ctx.fillStyle = '#5c9ecc';
|
|
ctx.fillRect(item1SquareX, legY, 7, 7);
|
|
ctx.fillStyle = '#444';
|
|
ctx.fillText('Obj. ($100k)', item1TextX, legY);
|
|
|
|
// 🔴 Círculo rojo + Texto Ingreso
|
|
ctx.fillStyle = '#d9534f';
|
|
ctx.beginPath();
|
|
ctx.arc(item2CircleX, legY + 3.5, 3, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
ctx.fillStyle = '#444';
|
|
ctx.fillText('Ingreso', item2TextX, legY);
|
|
}
|
|
}
|
|
|
|
function crearTarjetaProyecto(proyecto, esCompletado) {
|
|
const colores = ['amarillo', 'naranjas', 'verdes', 'azules', 'rojos', 'morados'];
|
|
let activosReqHtml = '';
|
|
let activosAsigHtml = '';
|
|
|
|
const coloresConValores = colores
|
|
.filter(color => proyecto[color] !== null && proyecto[color] > 0)
|
|
.map(color => ({
|
|
color,
|
|
valor: proyecto[color]
|
|
}));
|
|
|
|
let laClase = '';
|
|
for (let i = 0; i < 3; i++) {
|
|
if (i < coloresConValores.length) {
|
|
const activo = coloresConValores[i];
|
|
const claseActivo = 'act' + getClassNameFromColor(activo.color);
|
|
activosReqHtml += `<span class="${claseActivo}">${activo.valor}</span>`;
|
|
|
|
const draggableClass = esCompletado ? 'asset-recover' : '';
|
|
const assetId = `asset-${proyecto.id}-${i}`;
|
|
activosAsigHtml += `<span id="${assetId}" class="${claseActivo} ${draggableClass}" data-asset-type="${getClassNameFromColor(activo.color)}">${proyecto['activoAsignado' + (i + 1)]}</span>`;
|
|
} else {
|
|
activosReqHtml += `<span class="actNinguno"></span>`;
|
|
activosAsigHtml += `<span class="actNinguno"></span>`;
|
|
}
|
|
}
|
|
|
|
const completadoClass = esCompletado ? 'completado' : '';
|
|
|
|
const quincena = parseInt($('#etQuincena').val()) || 1;
|
|
const trimestreActual = Math.floor((quincena - 1) / 6) + 1;
|
|
const esFinTrimestre = (quincena % 6 === 0);
|
|
const yaResolvioManto = (proyecto.mantenimientoPagadoEnTrimestre === trimestreActual);
|
|
|
|
let actionButtonsHtml = '';
|
|
if (!esCompletado && esFinTrimestre) {
|
|
const showPay = (proyecto.dificultad !== 'Incidencia' && proyecto.mantenimiento !== 'N/A');
|
|
const penalizacionFormateada = formatCurrency(proyecto.penalizacion || 0);
|
|
|
|
let buttonManto = '';
|
|
let buttonPenalizar = '';
|
|
|
|
if (yaResolvioManto) {
|
|
buttonManto = showPay ?
|
|
`<button disabled class="nav-button btn-pagar-mantenimiento" data-id="${proyecto.id}" style="background-color: #6c757d; border: none; font-size: 11px; padding: 5px 8px; cursor: not-allowed; flex: 1;">Pagar Manto</button>` : '';
|
|
buttonPenalizar = `<button disabled class="nav-button btn-penalizar-proyecto" data-id="${proyecto.id}" style="background-color: #6c757d; border: none; font-size: 11px; padding: 5px 8px; cursor: not-allowed; flex: 1;">Penalizar</button>`;
|
|
} else {
|
|
buttonManto = showPay ?
|
|
`<button class="nav-button btn-pagar-mantenimiento" data-id="${proyecto.id}" style="background-color: #28a745; border: none; font-size: 11px; padding: 5px 8px; cursor: pointer; flex: 1;">Pagar Manto</button>` : '';
|
|
buttonPenalizar = `<button class="nav-button btn-penalizar-proyecto" data-id="${proyecto.id}" style="background-color: #dc3545; border: none; font-size: 11px; padding: 5px 8px; cursor: pointer; flex: 1;">Penalizar</button>`;
|
|
}
|
|
|
|
actionButtonsHtml = `
|
|
<div class="project-actions" style="display: flex; gap: 8px; margin-top: 10px; width: 100%;">
|
|
${buttonManto}
|
|
${buttonPenalizar}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
let infoAdicionalHtml = '';
|
|
if (!esCompletado) {
|
|
const penalizacionFormateada = formatCurrency(proyecto.penalizacion || 0);
|
|
const potencialVal = proyecto.potencial || 'N/A';
|
|
infoAdicionalHtml = `
|
|
<div class="project-info-adicional" style="font-size: 1.2em; color: #444; margin-top: 8px; border-top: 1px dashed #ccc; padding-top: 5px; text-align: left; display: flex; justify-content: space-between;">
|
|
<span><b>Potencial:</b> ${potencialVal}</span>
|
|
<span><b>Penalización:</b> ${penalizacionFormateada}</span>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
return `
|
|
<div class="project-card ${completadoClass}" style="flex-basis: 48%; display: flex; flex-direction: column; justify-content: space-between; min-height: 180px; box-sizing: border-box; padding: 10px; ${yaResolvioManto ? 'background-color: #e9e9e9; opacity: 0.75; border-color: #aaa;' : ''}">
|
|
<div>
|
|
<div class="project-header" style="font-weight: bold; margin-bottom: 5px; text-align: center; border-bottom: 1px solid gray; padding-bottom: 4px;">${proyecto.nombreProyecto.toUpperCase()}</div>
|
|
<div class="project-body" style="padding: 5px; text-align: center;">
|
|
<i style="font-size: 0.9em; color: #555;">${proyecto.descripcion}</i>
|
|
<div class="project-assets-req" style="margin-top: 5px; display: flex; justify-content: center; gap: 2px;">${activosReqHtml}</div>
|
|
<div class="project-assets-asig" style="margin-top: 5px; display: flex; justify-content: center; gap: 2px;">${activosAsigHtml}</div>
|
|
${infoAdicionalHtml}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="project-footer" style="font-size: 0.9em; margin-top: 8px; font-weight: bold; border-top: 1px solid #ddd; padding-top: 5px; text-align: center;">MANTENIMIENTO: ${proyecto.mantenimiento}</div>
|
|
${actionButtonsHtml}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function getClassNameFromColor(color) {
|
|
switch (color) {
|
|
case 'amarillo':
|
|
return 'PersonalCalificado';
|
|
case 'naranjas':
|
|
return 'Analistas';
|
|
case 'verdes':
|
|
return 'FlujoDeEfectivo';
|
|
case 'azules':
|
|
return 'TransporteYMaquinaria';
|
|
case 'rojos':
|
|
return 'Tecnologia';
|
|
case 'morados':
|
|
return 'CreditoEInversion';
|
|
default:
|
|
return 'Ninguno';
|
|
}
|
|
}
|
|
|
|
function inicializarInteraccionesDragDrop() {
|
|
console.log("[RESUMEN] Inicializando interacciones de Drag & Drop...");
|
|
|
|
// 1. DRAGGABLE: Hacemos arrastrables los activos de proyectos terminados.
|
|
$('.asset-recover').draggable({
|
|
revert: "invalid",
|
|
helper: "clone",
|
|
start: function(event, ui) {
|
|
if (parseInt($(this).text()) === 0) {
|
|
return false;
|
|
}
|
|
ui.helper.css('z-index', 100);
|
|
}
|
|
});
|
|
|
|
// La lógica DRAGGABLE para los recursos del departamento activo ya está en jsCode.js.
|
|
|
|
// 2. DROPPABLE: Se crea UN SOLO manejador para las tablas de departamento,
|
|
// que acepta tanto recursos como activos, evitando que una inicialización
|
|
// sobrescriba a la otra.
|
|
$('.departamentos.droppableRecursos').droppable({
|
|
accept: ".recurso-item, .asset-recover", // Acepta ambos tipos de elementos.
|
|
drop: function(event, ui) {
|
|
console.log(`[DROP EVENT] -> Elemento soltado en: ${this.id}. Elemento arrastrado:`, ui.draggable[0]);
|
|
|
|
// LÓGICA PARA RECURSOS (adaptada de jsCode.js)
|
|
if (ui.draggable.hasClass('recurso-item')) {
|
|
console.log("[DROP EVENT] -> Es un 'recurso-item'. Ejecutando lógica de intercambio.");
|
|
|
|
var droppedText = ui.draggable.text();
|
|
var originalValue = parseInt(droppedText) || 0;
|
|
|
|
// <<<< LÍNEA CLAVE: Regresa el elemento a su posición original >>>>
|
|
ui.draggable.css({
|
|
top: originalPosition.top,
|
|
left: originalPosition.left
|
|
});
|
|
|
|
if (originalValue === 0) {
|
|
console.log("[DROP EVENT] -> Recurso de origen tiene 0. Cancelando.");
|
|
return;
|
|
}
|
|
|
|
var newValue = originalValue - 1;
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
|
|
// Actualiza el texto del elemento original que se está arrastrando
|
|
ui.draggable.text(newValue);
|
|
|
|
// Determina qué tipo de recurso es y actualiza los arreglos y la UI
|
|
if (ui.draggable.attr("id") == 'recursoDispTiempoGde') {
|
|
$('#' + this.id + ' #tiempoCh').text(parseInt($('#' + this.id + ' #tiempoCh').text()) + 1);
|
|
setArrayValue(arreglosDeptos['arr' + this.id], 'recursoTiempo', parseInt($('#' + this.id + ' #tiempoCh').text()));
|
|
setArrayValue(arreglosDeptos['arr' + deptoActual], 'recursoTiempo', newValue);
|
|
$('#' + deptoActual + ' #tiempoCh').text(newValue);
|
|
} else if (ui.draggable.attr("id") == 'recursoDispPersonalGde') {
|
|
$('#' + this.id + ' #personalCh').text(parseInt($('#' + this.id + ' #personalCh').text()) + 1);
|
|
setArrayValue(arreglosDeptos['arr' + this.id], 'recursoPersonal', parseInt($('#' + this.id + ' #personalCh').text()));
|
|
setArrayValue(arreglosDeptos['arr' + deptoActual], 'recursoPersonal', newValue);
|
|
$('#' + deptoActual + ' #personalCh').text(newValue);
|
|
} else if (ui.draggable.attr("id") == 'recursoDispCapitalGde') {
|
|
$('#' + this.id + ' #capitalCh').text(parseInt($('#' + this.id + ' #capitalCh').text()) + 1);
|
|
setArrayValue(arreglosDeptos['arr' + this.id], 'recursoCapital', parseInt($('#' + this.id + ' #capitalCh').text()));
|
|
setArrayValue(arreglosDeptos['arr' + deptoActual], 'recursoCapital', newValue);
|
|
$('#' + deptoActual + ' #capitalCh').text(newValue);
|
|
}
|
|
|
|
}
|
|
// LÓGICA PARA ACTIVOS (la que ya estaba en resumen.php)
|
|
else if (ui.draggable.hasClass('asset-recover')) {
|
|
console.log("[DROP EVENT] -> Es un 'asset-recover'. Ejecutando lógica de recuperación.");
|
|
|
|
const deptoId = $(this).attr('id');
|
|
const assetType = ui.draggable.data('asset-type');
|
|
const assetElementId = ui.draggable.attr('id');
|
|
|
|
const costoRecuperacion = arreglosActivos['arr' + assetType];
|
|
const costoT = findArrayValue(costoRecuperacion, 'recuperacionTiempo');
|
|
const costoP = findArrayValue(costoRecuperacion, 'recuperacionPersonal');
|
|
const costoC = findArrayValue(costoRecuperacion, 'recuperacionCapital');
|
|
|
|
const deptoArr = arreglosDeptos['arr' + deptoId];
|
|
const recT = findArrayValue(deptoArr, 'recursoTiempo');
|
|
const recP = findArrayValue(deptoArr, 'recursoPersonal');
|
|
const recC = findArrayValue(deptoArr, 'recursoCapital');
|
|
|
|
if (recT >= costoT && recP >= costoP && recC >= costoC) {
|
|
setArrayValue(deptoArr, 'recursoTiempo', recT - costoT);
|
|
setArrayValue(deptoArr, 'recursoPersonal', recP - costoP);
|
|
setArrayValue(deptoArr, 'recursoCapital', recC - costoC);
|
|
|
|
let activoSlot = '';
|
|
if (findArrayValue(deptoArr, 'activo1Tipo') === assetType) activoSlot = 'activo1';
|
|
else if (findArrayValue(deptoArr, 'activo2Tipo') === assetType) activoSlot = 'activo2';
|
|
|
|
if (activoSlot) {
|
|
const valorActualActivo = findArrayValue(deptoArr, activoSlot);
|
|
setArrayValue(deptoArr, activoSlot, valorActualActivo + 1);
|
|
|
|
const assetElement = $(`#${assetElementId}`);
|
|
const currentCount = parseInt(assetElement.text());
|
|
assetElement.text(currentCount - 1);
|
|
|
|
const assetIdParts = assetElementId.split('-');
|
|
const projectId = parseInt(assetIdParts[1]);
|
|
const assetIndex = parseInt(assetIdParts[2]);
|
|
|
|
const projectToUpdate = proyectos.find(p => p.id === projectId);
|
|
if (projectToUpdate) {
|
|
const assetSlotName = `activoAsignado${assetIndex + 1}`;
|
|
if (projectToUpdate[assetSlotName] > 0) {
|
|
projectToUpdate[assetSlotName]--;
|
|
}
|
|
}
|
|
actualizarTarjetaDepto(deptoId);
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
} else {
|
|
alert(`El departamento ${deptoId} no puede almacenar activos de tipo ${assetType}.`);
|
|
setArrayValue(deptoArr, 'recursoTiempo', recT);
|
|
setArrayValue(deptoArr, 'recursoPersonal', recP);
|
|
setArrayValue(deptoArr, 'recursoCapital', recC);
|
|
}
|
|
} else {
|
|
alert("Recursos insuficientes en el departamento para recuperar este activo.");
|
|
}
|
|
}
|
|
},
|
|
over: function(event, ui) {
|
|
// Lógica combinada para el 'over'
|
|
if (ui.draggable.hasClass('recurso-item') && $(this).attr('id') !== deptoActual) {
|
|
$(this).parent().css('background-color', '#e9f5e9'); // Pinta el div.card
|
|
} else if (ui.draggable.hasClass('asset-recover')) {
|
|
$(this).parent().css('background-color', '#e9f5e9'); // Pinta el div.card
|
|
}
|
|
},
|
|
out: function(event, ui) {
|
|
$(this).parent().css('background-color', ''); // Limpia el color del div.card
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
// Listener para los botones de quincena para actualizar la UI
|
|
$('#bMas, #bMenos').on('click', function() {
|
|
setTimeout(actualizarResumenUI, 100);
|
|
});
|
|
|
|
$('#resumenAccionHabilidadEspecial').click(function() {
|
|
if (typeof deptoActual === 'undefined' || !deptoActual) {
|
|
alert('Primero selecciona un departamento haciendo clic en él.');
|
|
return;
|
|
}
|
|
|
|
let elArreglo = arreglosDeptos['arr' + deptoActual];
|
|
let accionQuincenal = findArrayValue(elArreglo, 'accionEspecialQuincenal');
|
|
|
|
if (!accionQuincenal || accionQuincenal === '') {
|
|
alert('El departamento seleccionado no tiene una habilidad especial disponible (requiere comprar sus 3 habilidades).');
|
|
return;
|
|
}
|
|
|
|
if (deptoActual === 'Finanzas') {
|
|
window.alert(
|
|
'La habilidad especial de Finanzas (Tener 1 recurso extra) ya está activa y se aplica automáticamente al generar recursos aleatorios.'
|
|
);
|
|
return;
|
|
}
|
|
|
|
let lastUsed = parseInt(findArrayValue(elArreglo, 'accionEspecialLastUsed')) || 0;
|
|
let periodicidad = parseInt(findArrayValue(elArreglo, 'accionEspecialPeriodicidad')) || 2;
|
|
let quincenaActual = parseInt($('#etQuincena').val()) || 1;
|
|
|
|
let puedeUsar = false;
|
|
if (lastUsed === 0) {
|
|
puedeUsar = true;
|
|
} else if (quincenaActual >= lastUsed + periodicidad) {
|
|
puedeUsar = true;
|
|
}
|
|
|
|
if (puedeUsar) {
|
|
let proximoUso = quincenaActual + periodicidad;
|
|
let nombreDepto = findArrayValue(elArreglo, 'nombre').toLowerCase().replace(/(?:^|\s)\S/g, function(a) {
|
|
return a.toUpperCase();
|
|
});
|
|
let textoConfirmacion =
|
|
'¿Quieres utilizar la acción especial del departamento "' +
|
|
nombreDepto +
|
|
'"?<br><br>' +
|
|
'Acción: <b>' +
|
|
accionQuincenal +
|
|
'</b><br><br>' +
|
|
'<small><i>Periodicidad: Cada ' +
|
|
periodicidad +
|
|
' quincenas.</i><br>' +
|
|
'<i>Si la usas ahora, podrás usarla de nuevo en la quincena <b>' +
|
|
proximoUso +
|
|
'</b>.</i></small>';
|
|
|
|
confirm(textoConfirmacion, function(result) {
|
|
if (result) {
|
|
console.log('Se activa la accion especial: ' + accionQuincenal);
|
|
|
|
if (accionQuincenal === 'Generar un activo sin costo') {
|
|
let tipoActivo1 = findArrayValue(elArreglo, 'activo1Tipo');
|
|
let tipoActivo2 = findArrayValue(elArreglo, 'activo2Tipo');
|
|
|
|
$('<div>¿Qué activo deseas generar sin costo?</div>').dialog({
|
|
modal: true,
|
|
title: 'Generar Activo',
|
|
width: 450,
|
|
open: function() {
|
|
var $btnset = $(this).closest('.ui-dialog').find('.ui-dialog-buttonset');
|
|
$btnset.css({
|
|
display: 'flex',
|
|
'flex-wrap': 'wrap',
|
|
'justify-content': 'center',
|
|
width: '100%',
|
|
float: 'none',
|
|
});
|
|
$btnset.find('button:contains("Cancelar")').before('<div style="flex-basis: 100%; height: 15px;"></div>');
|
|
|
|
var coloresMapa = {
|
|
PersonalCalificado: 'yellow',
|
|
Analistas: 'orange',
|
|
FlujoDeEfectivo: 'green',
|
|
TransporteYMaquinaria: 'blue',
|
|
Tecnologia: 'red',
|
|
CreditoEInversion: 'purple',
|
|
};
|
|
|
|
$btnset.find('.act' + tipoActivo1).css({
|
|
width: 'auto',
|
|
padding: '10px 20px',
|
|
background: coloresMapa[tipoActivo1] || '',
|
|
color: tipoActivo1 === 'PersonalCalificado' || tipoActivo1 === 'FlujoDeEfectivo' ? 'black' : 'white',
|
|
});
|
|
$btnset.find('.act' + tipoActivo2).css({
|
|
width: 'auto',
|
|
padding: '10px 20px',
|
|
background: coloresMapa[tipoActivo2] || '',
|
|
color: tipoActivo2 === 'PersonalCalificado' || tipoActivo2 === 'FlujoDeEfectivo' ? 'black' : 'white',
|
|
});
|
|
},
|
|
buttons: [{
|
|
text: tipoActivo1,
|
|
class: 'act' + tipoActivo1,
|
|
click: function() {
|
|
$(this).dialog('close');
|
|
generarActivo(1);
|
|
},
|
|
}, {
|
|
text: tipoActivo2,
|
|
class: 'act' + tipoActivo2,
|
|
click: function() {
|
|
$(this).dialog('close');
|
|
generarActivo(2);
|
|
},
|
|
}, {
|
|
text: 'Cancelar',
|
|
click: function() {
|
|
$(this).dialog('close');
|
|
},
|
|
}, ],
|
|
});
|
|
|
|
function generarActivo(num) {
|
|
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual);
|
|
let activoKey = 'activo' + num;
|
|
let valorActual = parseInt(findArrayValue(elArreglo, activoKey)) || 0;
|
|
let nuevoValor = valorActual + 1;
|
|
setArrayValue(elArreglo, activoKey, nuevoValor);
|
|
actualizarTarjetaDepto(deptoActual); // Actualiza la tarjeta del depto en la UI de resumen
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
window.alert('¡Activo generado con éxito!');
|
|
if (typeof guardaSesion === 'function') {
|
|
guardaSesion();
|
|
}
|
|
}
|
|
} else if (accionQuincenal === 'Descartar un proyecto') {
|
|
const proyectosEnProceso = proyectos.filter(p => p.estatus === 'En proceso');
|
|
if (proyectosEnProceso.length === 0) {
|
|
alert('No hay proyectos en proceso para descartar.');
|
|
return;
|
|
}
|
|
|
|
let dialogContent = $('<div><p>Selecciona el proyecto a descartar:</p></div>');
|
|
let projectList = $('<form>');
|
|
proyectosEnProceso.forEach((p) => {
|
|
let labelText = p.nombreProyecto;
|
|
if (p.dificultad === 'Incidencia') {
|
|
const shortDesc = p.descripcion.length > 35 ? p.descripcion.substring(0, 35) + '...' : p.descripcion;
|
|
labelText = `${p.nombreProyecto} (${shortDesc})`;
|
|
}
|
|
projectList.append(
|
|
`<div style="display: flex; align-items: flex-start; margin: 8px 0; text-align: left;">
|
|
<input type="radio" id="proj-discard-${p.id}" name="proyectoADescartar" value="${p.id}" style="margin-top: 2px; flex-shrink: 0;">
|
|
<label for="proj-discard-${p.id}" style="margin-left: 8px; cursor: pointer;">
|
|
${labelText}
|
|
</label>
|
|
</div>`
|
|
);
|
|
});
|
|
dialogContent.append(projectList);
|
|
|
|
dialogContent.dialog({
|
|
modal: true,
|
|
title: 'Descartar Proyecto',
|
|
width: 450,
|
|
buttons: {
|
|
Descartar: function() {
|
|
const selectedProjectId = $('input[name="proyectoADescartar"]:checked').val();
|
|
if (!selectedProjectId) {
|
|
alert('Por favor, selecciona un proyecto.');
|
|
return;
|
|
}
|
|
const proyectoADescartar = proyectos.find(p => p.id == selectedProjectId);
|
|
if (proyectoADescartar) {
|
|
proyectoADescartar.estatus = 'descartado';
|
|
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual);
|
|
actualizarResumenUI(); // <--- Cambio clave: refresca la UI de resumen
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
alert('¡Proyecto descartado con éxito!');
|
|
if (typeof guardaSesion === 'function') {
|
|
guardaSesion();
|
|
}
|
|
}
|
|
$(this).dialog('close');
|
|
},
|
|
Cancelar: function() {
|
|
$(this).dialog('close');
|
|
},
|
|
},
|
|
close: function() {
|
|
$(this).dialog('destroy').remove();
|
|
},
|
|
});
|
|
} else if (accionQuincenal === 'Omitir un mantenimiento') {
|
|
const esFinTrimestre = (quincenaActual % 6 === 0);
|
|
const trimestreActual = Math.floor((quincenaActual - 1) / 6) + 1;
|
|
if (!esFinTrimestre) {
|
|
alert('Esta Habilidad Especial solo se puede utilizar en el cierre de un trimestre (quincenas 6, 12, 18 y 24).');
|
|
return;
|
|
}
|
|
const proyectosPendientes = proyectos.filter(p =>
|
|
p.estatus === 'En proceso' &&
|
|
p.mantenimiento !== 'N/A' &&
|
|
p.mantenimientoPagadoEnTrimestre !== trimestreActual
|
|
);
|
|
|
|
if (proyectosPendientes.length === 0) {
|
|
alert('No hay proyectos activos con mantenimiento pendiente en este trimestre.');
|
|
return;
|
|
}
|
|
|
|
let dialogContent = $('<div><p>Selecciona el proyecto al que deseas omitir el costo de mantenimiento:</p></div>');
|
|
let projectList = $('<form>');
|
|
proyectosPendientes.forEach((p) => {
|
|
projectList.append(
|
|
`<div style="display: flex; align-items: flex-start; margin: 8px 0; text-align: left;">
|
|
<input type="radio" id="proj-omit-${p.id}" name="proyectoAOmitir" value="${p.id}" style="margin-top: 2px; flex-shrink: 0;">
|
|
<label for="proj-omit-${p.id}" style="margin-left: 8px; cursor: pointer;">
|
|
${p.nombreProyecto} <span style="color: #555; font-size: 0.9em;">(Costo: ${p.mantenimiento})</span>
|
|
</label>
|
|
</div>`
|
|
);
|
|
});
|
|
dialogContent.append(projectList);
|
|
|
|
dialogContent.dialog({
|
|
modal: true,
|
|
title: 'Omitir Mantenimiento - Logística y Sistemas',
|
|
width: 450,
|
|
buttons: {
|
|
"Omitir Costo": function() {
|
|
const selectedProjectId = $('input[name="proyectoAOmitir"]:checked').val();
|
|
if (!selectedProjectId) {
|
|
alert('Por favor, selecciona un proyecto.');
|
|
return;
|
|
}
|
|
const proyectoAOmitir = proyectos.find(p => p.id == selectedProjectId);
|
|
if (proyectoAOmitir) {
|
|
proyectoAOmitir.mantenimientoPagadoEnTrimestre = trimestreActual;
|
|
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual);
|
|
actualizarResumenUI();
|
|
actualizarTarjetaDepto('LogisticaYSistemas');
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
alert(`¡El mantenimiento del proyecto "${proyectoAOmitir.nombreProyecto}" ha sido omitido con éxito sin costo!`);
|
|
if (typeof guardaSesion === 'function') {
|
|
guardaSesion();
|
|
} else if (typeof guardarDatosEnServidor === 'function') {
|
|
guardarDatosEnServidor();
|
|
}
|
|
}
|
|
$(this).dialog('close');
|
|
},
|
|
"Cancelar": function() {
|
|
$(this).dialog('close');
|
|
}
|
|
},
|
|
close: function() {
|
|
$(this).dialog('destroy').remove();
|
|
}
|
|
});
|
|
} else if (accionQuincenal === 'Ordenar los próximos 5 proyectos') {
|
|
alert('Esta habilidad especial solo se puede utilizar desde el tablero de juego.');
|
|
return;
|
|
} else {
|
|
// Para las demás habilidades que solo muestran un mensaje
|
|
setArrayValue(elArreglo, 'accionEspecialLastUsed', quincenaActual);
|
|
window.alert(`¡Acción especial '${accionQuincenal}' activada!`);
|
|
if (typeof guardaSesion === 'function') {
|
|
guardaSesion();
|
|
}
|
|
}
|
|
}
|
|
}, 450);
|
|
} else {
|
|
let quincenasRestantes = lastUsed + periodicidad - quincenaActual;
|
|
window.alert('Aún no puedes usar la habilidad especial. Debes esperar ' + quincenasRestantes + ' quincena(s) más.');
|
|
}
|
|
});
|
|
|
|
function parseMantenimiento(mantenimientoStr) {
|
|
let t = 0,
|
|
p = 0,
|
|
c = 0;
|
|
if (mantenimientoStr && mantenimientoStr !== 'N/A') {
|
|
const matchesT = mantenimientoStr.match(/(\d+)T/i);
|
|
const matchesP = mantenimientoStr.match(/(\d+)P/i);
|
|
const matchesC = mantenimientoStr.match(/(\d+)C/i);
|
|
if (matchesT) t = parseInt(matchesT[1]);
|
|
if (matchesP) p = parseInt(matchesP[1]);
|
|
if (matchesC) c = parseInt(matchesC[1]);
|
|
}
|
|
return {
|
|
t,
|
|
p,
|
|
c
|
|
};
|
|
}
|
|
|
|
function pagarMantenimientoProyecto(projectId) {
|
|
console.log("[PagarManto] Iniciando pago para proyecto ID:", projectId);
|
|
if (typeof deptoActual === 'undefined' || !deptoActual) {
|
|
alert('Por favor, selecciona primero un departamento haciendo clic en él.');
|
|
return;
|
|
}
|
|
|
|
const proyecto = proyectos.find(p => p.id == projectId);
|
|
if (!proyecto) {
|
|
alert('No se encontró el proyecto.');
|
|
console.error("[PagarManto] Proyecto no encontrado con ID:", projectId);
|
|
return;
|
|
}
|
|
console.log("[PagarManto] Proyecto encontrado:", proyecto.nombreProyecto);
|
|
|
|
// Parse maintenance cost
|
|
const cost = parseMantenimiento(proyecto.mantenimiento);
|
|
console.log("[PagarManto] Costo parsed:", cost);
|
|
|
|
// Get department resources
|
|
const deptoArr = arreglosDeptos['arr' + deptoActual];
|
|
const recT = parseInt(findArrayValue(deptoArr, 'recursoTiempo')) || 0;
|
|
const recP = parseInt(findArrayValue(deptoArr, 'recursoPersonal')) || 0;
|
|
const recC = parseInt(findArrayValue(deptoArr, 'recursoCapital')) || 0;
|
|
|
|
// Get department skills discounts
|
|
const habTiempo = findArrayValue(deptoArr, 'habilidadTiempo');
|
|
const habPersonal = findArrayValue(deptoArr, 'habilidadPersonal');
|
|
const habCapital = findArrayValue(deptoArr, 'habilidadCapital');
|
|
|
|
const discountT = (habTiempo && habTiempo !== 0) ? parseInt(findArrayValue(arreglosCapacitaciones[habTiempo], 'beneficio')) || 0 : 0;
|
|
const discountP = (habPersonal && habPersonal !== 0) ? parseInt(findArrayValue(arreglosCapacitaciones[habPersonal], 'beneficio')) || 0 : 0;
|
|
const discountC = (habCapital && habCapital !== 0) ? parseInt(findArrayValue(arreglosCapacitaciones[habCapital], 'beneficio')) || 0 : 0;
|
|
|
|
const finalCostT = Math.max(0, cost.t + discountT);
|
|
const finalCostP = Math.max(0, cost.p + discountP);
|
|
const finalCostC = Math.max(0, cost.c + discountC);
|
|
|
|
console.log("[PagarManto] Recursos depto actual:", {
|
|
recT,
|
|
recP,
|
|
recC
|
|
});
|
|
console.log("[PagarManto] Descuentos:", {
|
|
discountT,
|
|
discountP,
|
|
discountC
|
|
});
|
|
console.log("[PagarManto] Costo final con descuento:", {
|
|
finalCostT,
|
|
finalCostP,
|
|
finalCostC
|
|
});
|
|
|
|
// Verificar si LogisticaYSistemas tiene comprada y disponible su habilidad especial
|
|
let logisticaHabilidadEspecialDisponible = false;
|
|
let elArregloLogistica = null;
|
|
const quincena = parseInt($('#etQuincena').val()) || 1;
|
|
const trimestreActual = Math.floor((quincena - 1) / 6) + 1;
|
|
|
|
if (typeof deptoActual !== 'undefined' && deptoActual === 'LogisticaYSistemas') {
|
|
elArregloLogistica = arreglosDeptos['arrLogisticaYSistemas'];
|
|
if (elArregloLogistica) {
|
|
const accionQuincenal = findArrayValue(elArregloLogistica, 'accionEspecialQuincenal');
|
|
if (accionQuincenal && accionQuincenal !== '') {
|
|
const lastUsed = parseInt(findArrayValue(elArregloLogistica, 'accionEspecialLastUsed')) || 0;
|
|
const periodicidad = parseInt(findArrayValue(elArregloLogistica, 'accionEspecialPeriodicidad')) || 2;
|
|
if (lastUsed === 0 || quincena >= lastUsed + periodicidad) {
|
|
logisticaHabilidadEspecialDisponible = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const deptoNombre = findArrayValue(deptoArr, 'nombre');
|
|
|
|
if (logisticaHabilidadEspecialDisponible) {
|
|
const dialogMsg = `El departamento de Logística y Sistemas tiene disponible la Habilidad Especial para omitir un mantenimiento sin costo.<br><br>` +
|
|
`¿Deseas usar la Habilidad Especial para omitir el mantenimiento del proyecto "${proyecto.nombreProyecto}" <b>sin gastar recursos</b>,<br>` +
|
|
`o prefieres realizar un pago normal gastando recursos (${proyecto.mantenimiento})?`;
|
|
|
|
$('<div></div>')
|
|
.html(dialogMsg)
|
|
.dialog({
|
|
modal: true,
|
|
title: 'Pagar Mantenimiento - Logística y Sistemas',
|
|
width: 480,
|
|
buttons: {
|
|
"Usar Habilidad (Sin costo)": function() {
|
|
$(this).dialog('close');
|
|
// Mark project maintenance as paid in the current trimester
|
|
proyecto.mantenimientoPagadoEnTrimestre = trimestreActual;
|
|
|
|
// Update skill cooldown
|
|
setArrayValue(elArregloLogistica, 'accionEspecialLastUsed', quincena);
|
|
|
|
// Save and update UI
|
|
actualizarResumenUI();
|
|
actualizarTarjetaDepto('LogisticaYSistemas'); // Refresca la tarjeta en la UI
|
|
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
|
|
alert(`Se ha omitido el mantenimiento del proyecto "${proyecto.nombreProyecto}" sin costo utilizando la Habilidad Especial de Logística y Sistemas.`);
|
|
|
|
if (typeof guardarDatosEnServidor === 'function') {
|
|
guardarDatosEnServidor();
|
|
}
|
|
},
|
|
"Pagar Normal (Con costo)": function() {
|
|
$(this).dialog('close');
|
|
ejecutarPagoNormal(proyecto, deptoArr, recT, recP, recC, deptoNombre, trimestreActual, finalCostT, finalCostP, finalCostC);
|
|
},
|
|
"Cancelar": function() {
|
|
$(this).dialog('close');
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
ejecutarPagoNormal(proyecto, deptoArr, recT, recP, recC, deptoNombre, trimestreActual, finalCostT, finalCostP, finalCostC);
|
|
}
|
|
}
|
|
|
|
function ejecutarPagoNormal(proyecto, deptoArr, recT, recP, recC, deptoNombre, trimestreActual, finalCostT, finalCostP, finalCostC) {
|
|
if (recT < finalCostT || recP < finalCostP || recC < finalCostC) {
|
|
alert(`El departamento seleccionado (${deptoNombre}) NO tiene suficientes recursos para pagar el mantenimiento del proyecto "${proyecto.nombreProyecto}".\n` +
|
|
`Costo requerido (con descuento): ${finalCostT}T ${finalCostP}P ${finalCostC}C\n` +
|
|
`Recursos actuales: Tiempo: ${recT}, Personal: ${recP}, Capital: ${recC}`);
|
|
return;
|
|
}
|
|
|
|
const confirmMessage = `¿Estás seguro de que deseas pagar el mantenimiento para el proyecto "${proyecto.nombreProyecto}" desde el departamento <b>${deptoNombre}</b>?<br>` +
|
|
`Costo original: <b>${proyecto.mantenimiento}</b><br>` +
|
|
`Costo final con descuento aplicado: <b>${finalCostT}T ${finalCostP}P ${finalCostC}C</b>`;
|
|
|
|
confirm(confirmMessage, function(confirmed) {
|
|
if (confirmed) {
|
|
// Deduct resources
|
|
setArrayValue(deptoArr, 'recursoTiempo', recT - finalCostT);
|
|
setArrayValue(deptoArr, 'recursoPersonal', recP - finalCostP);
|
|
setArrayValue(deptoArr, 'recursoCapital', recC - finalCostC);
|
|
|
|
// Mark project maintenance as paid in the current trimester
|
|
proyecto.mantenimientoPagadoEnTrimestre = trimestreActual;
|
|
console.log("[PagarManto] Asignado mantenimientoPagadoEnTrimestre a:", trimestreActual);
|
|
|
|
// Save and update UI
|
|
actualizarTarjetaDepto(deptoActual);
|
|
console.log("[PagarManto] Tarjeta departamento actualizada.");
|
|
|
|
actualizarResumenUI();
|
|
console.log("[PagarManto] UI de resumen actualizada.");
|
|
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
|
|
alert(`Mantenimiento pagado con éxito para el proyecto "${proyecto.nombreProyecto}" desde el departamento ${deptoNombre}. El proyecto continuará en proceso en el siguiente trimestre.`);
|
|
|
|
if (typeof guardarDatosEnServidor === 'function') {
|
|
console.log("[PagarManto] Guardando sesión en el servidor...");
|
|
guardarDatosEnServidor();
|
|
}
|
|
}
|
|
}, 450);
|
|
}
|
|
|
|
function penalizarProyecto(projectId) {
|
|
const proyecto = proyectos.find(p => p.id == projectId);
|
|
if (!proyecto) {
|
|
alert('No se encontró el proyecto.');
|
|
return;
|
|
}
|
|
|
|
const penalizacionVal = parseInt(proyecto.penalizacion) || 0;
|
|
const penalizacionFormateada = formatCurrency(penalizacionVal);
|
|
|
|
const quincena = parseInt($('#etQuincena').val()) || 1;
|
|
const trimestreActual = Math.floor((quincena - 1) / 6) + 1;
|
|
|
|
// Verificar si Operaciones tiene comprada y disponible su habilidad especial
|
|
let operacionesHabilidadEspecialDisponible = false;
|
|
let elArregloOperaciones = null;
|
|
if (typeof deptoActual !== 'undefined' && deptoActual === 'Operaciones') {
|
|
elArregloOperaciones = arreglosDeptos['arrOperaciones'];
|
|
if (elArregloOperaciones) {
|
|
const accionQuincenal = findArrayValue(elArregloOperaciones, 'accionEspecialQuincenal');
|
|
if (accionQuincenal && accionQuincenal !== '') {
|
|
const lastUsed = parseInt(findArrayValue(elArregloOperaciones, 'accionEspecialLastUsed')) || 0;
|
|
const periodicidad = parseInt(findArrayValue(elArregloOperaciones, 'accionEspecialPeriodicidad')) || 2;
|
|
if (lastUsed === 0 || quincena >= lastUsed + periodicidad) {
|
|
operacionesHabilidadEspecialDisponible = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (operacionesHabilidadEspecialDisponible) {
|
|
const dialogMsg = `El departamento de Operaciones tiene disponible la Habilidad Especial para exentar de penalización a un proyecto.<br><br>` +
|
|
`¿Deseas usar la Habilidad Especial para el proyecto "${proyecto.nombreProyecto}" <b>sin pagar la penalización</b>,<br>` +
|
|
`o prefieres pagar la penalización de <b>${penalizacionFormateada}</b> de manera normal?`;
|
|
|
|
$('<div></div>')
|
|
.html(dialogMsg)
|
|
.dialog({
|
|
modal: true,
|
|
title: 'Penalizar Proyecto - Operaciones',
|
|
width: 480,
|
|
buttons: {
|
|
"Usar Habilidad (Sin costo)": function() {
|
|
$(this).dialog('close');
|
|
// Mantiene el estatus 'En proceso' pero marca el mantenimiento resuelto en este trimestre
|
|
proyecto.mantenimientoPagadoEnTrimestre = trimestreActual;
|
|
|
|
// Cooldown de la habilidad
|
|
setArrayValue(elArregloOperaciones, 'accionEspecialLastUsed', quincena);
|
|
|
|
actualizarResumenUI();
|
|
actualizarTarjetaDepto('Operaciones');
|
|
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
|
|
alert(`El proyecto "${proyecto.nombreProyecto}" ha sido exentado de la penalización utilizando la Habilidad Especial de Operaciones.`);
|
|
|
|
if (typeof guardarDatosEnServidor === 'function') {
|
|
guardarDatosEnServidor();
|
|
}
|
|
},
|
|
"Pagar Penalización (Con costo)": function() {
|
|
$(this).dialog('close');
|
|
ejecutarPenalizacionNormal(proyecto, penalizacionVal, penalizacionFormateada, trimestreActual);
|
|
},
|
|
"Cancelar": function() {
|
|
$(this).dialog('close');
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
ejecutarPenalizacionNormal(proyecto, penalizacionVal, penalizacionFormateada, trimestreActual);
|
|
}
|
|
}
|
|
|
|
function ejecutarPenalizacionNormal(proyecto, penalizacionVal, penalizacionFormateada, trimestreActual) {
|
|
let acumuladoDisponible = 0;
|
|
for (let t = 1; t <= trimestreActual; t++) {
|
|
acumuladoDisponible += (arregloGeneral['trimestre' + t] || 0);
|
|
}
|
|
|
|
if (acumuladoDisponible < penalizacionVal) {
|
|
alert(`No puedes penalizar el proyecto "${proyecto.nombreProyecto}" porque no hay acumulado general suficiente.\n` +
|
|
`Penalización requerida: ${penalizacionFormateada}\n` +
|
|
`Acumulado general disponible: ${formatCurrency(acumuladoDisponible)}`);
|
|
return;
|
|
}
|
|
|
|
const confirmMessage = `¿Estás seguro de que quieres pagar la penalización del proyecto "${proyecto.nombreProyecto}"?<br>` +
|
|
`Se aplicará una penalización de <b>${penalizacionFormateada}</b> del acumulado general.`;
|
|
|
|
confirm(confirmMessage, function(confirmed) {
|
|
if (confirmed) {
|
|
const trimestreKey = 'trimestre' + trimestreActual;
|
|
if (typeof arregloGeneral[trimestreKey] === 'undefined') {
|
|
arregloGeneral[trimestreKey] = 0;
|
|
}
|
|
arregloGeneral[trimestreKey] -= penalizacionVal;
|
|
|
|
// Mantiene el estatus 'En proceso' pero marca el mantenimiento resuelto en este trimestre
|
|
proyecto.mantenimientoPagadoEnTrimestre = trimestreActual;
|
|
|
|
actualizarResumenUI();
|
|
|
|
var audio = new Audio('./Microwave_bell.wav');
|
|
audio.play();
|
|
|
|
alert(`El proyecto "${proyecto.nombreProyecto}" ha sido penalizado. Se aplicó una penalización de ${penalizacionFormateada}.`);
|
|
|
|
if (typeof guardarDatosEnServidor === 'function') {
|
|
guardarDatosEnServidor();
|
|
}
|
|
}
|
|
}, 450);
|
|
}
|
|
|
|
// Delegación de eventos para los botones de pagar y penalizar
|
|
$(document).on('click', '.btn-pagar-mantenimiento', function() {
|
|
const id = $(this).data('id');
|
|
pagarMantenimientoProyecto(id);
|
|
});
|
|
|
|
$(document).on('click', '.btn-penalizar-proyecto', function() {
|
|
const id = $(this).data('id');
|
|
penalizarProyecto(id);
|
|
});
|
|
|
|
// El listener para el click en .departamentos ya está en jsCode.js y funcionará ahora
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
|
|
</html> |