Feat Tabla de Datos Redaccion

- Tabla de Top 2 Conurbano
- Tabla de Top 2 Por Secciones Electorales Bs. As.
This commit is contained in:
2025-10-23 12:31:10 -03:00
parent 3c364ef373
commit 4dbda0da63
18 changed files with 403 additions and 18 deletions

1
.gitignore vendored
View File

@@ -28,6 +28,7 @@ build/
*.userprefs
/bin/
/obj/
/debug/
project.lock.json
project.assets.json
/packages/

View File

@@ -5,7 +5,7 @@ import type {
ApiResponseTablaDetallada, ProyeccionBancas, MunicipioSimple,
TelegramaData, CatalogoItem, CategoriaResumen, ResultadoTicker,
ApiResponseResultadosPorSeccion, PanelElectoralDto, ResumenProvincia,
CategoriaResumenHome
CategoriaResumenHome, ResultadoFila, ResultadoSeccion
} from './types/types';
/**
@@ -337,4 +337,14 @@ export const getHomeResumenNacional = async (eleccionId: number, categoriaId: nu
const url = `/elecciones/home-resumen-nacional?${queryParams.toString()}`;
const { data } = await apiClient.get(url);
return data;
};
export const getTablaConurbano = async (eleccionId: number): Promise<ResultadoFila[]> => {
const { data } = await apiClient.get(`/elecciones/${eleccionId}/tabla-conurbano`);
return data;
};
export const getTablaSecciones = async (eleccionId: number): Promise<ResultadoSeccion[]> => {
const { data } = await apiClient.get(`/elecciones/${eleccionId}/tabla-secciones`);
return data;
};

View File

@@ -6,6 +6,8 @@ import { PanelNacionalWidget } from './nacionales/PanelNacionalWidget';
import { HomeCarouselWidget } from './nacionales/HomeCarouselWidget';
import './DevAppStyle.css'
import { HomeCarouselNacionalWidget } from './nacionales/HomeCarouselNacionalWidget';
import { TablaConurbanoWidget } from './nacionales/TablaConurbanoWidget';
import { TablaSeccionesWidget } from './nacionales/TablaSeccionesWidget';
// --- NUEVO COMPONENTE REUTILIZABLE PARA CONTENIDO COLAPSABLE ---
const CollapsibleWidgetWrapper = ({ children }: { children: React.ReactNode }) => {
@@ -163,7 +165,15 @@ export const DevAppLegislativas = () => {
Uso: <code style={codeStyle}>&lt;ResultadosNacionalesCardsWidget eleccionId={2} focoDistritoId="16" focoCategoriaId={2} cantidadResultados={1} /&gt;</code>
</p>
<ResultadosNacionalesCardsWidget eleccionId={2} focoDistritoId="16" focoCategoriaId={2} cantidadResultados={1} />
<div style={sectionStyle}>
<h2>Widget: Tabla de Resultados del Conurbano</h2>
<TablaConurbanoWidget />
</div>
<div style={sectionStyle}>
<h2>Widget: Tabla de Resultados por Sección Electoral</h2>
<TablaSeccionesWidget />
</div>
</div>
</div>
);

View File

@@ -0,0 +1,53 @@
// src/features/legislativas/nacionales/TablaConurbanoWidget.tsx
import { useQuery } from '@tanstack/react-query';
import { getTablaConurbano } from '../../../apiService';
import styles from './TablaResultadosWidget.module.css';
export const TablaConurbanoWidget = () => {
// CORRECCIÓN: Se elimina el estado y el selector de categoría.
const ELECCION_ID = 2; // Exclusivo para elecciones nacionales
const { data, isLoading, error } = useQuery({
// La queryKey ya no necesita la categoría
queryKey: ['tablaConurbano', ELECCION_ID],
// La llamada a la API ya no necesita la categoría
queryFn: () => getTablaConurbano(ELECCION_ID),
refetchInterval: 60000,
});
const formatPercent = (num: number) => `${num.toFixed(2)}%`;
return (
<div className={styles.widgetContainer}>
<div className={styles.header}>
<h3>Resultados Conurbano - Diputados Nacionales</h3>
</div>
{isLoading && <p>Cargando resultados...</p>}
{error && <p>Error al cargar los datos.</p>}
{data && (
<table className={styles.resultsTable}>
<thead>
<tr>
<th>Distrito</th>
<th>1ra Fuerza</th>
<th>%</th>
<th>2da Fuerza</th>
<th>%</th>
</tr>
</thead>
<tbody>
{data.map((fila, index) => (
<tr key={fila.ambitoId}>
<td className={styles.distritoCell}><span className={styles.distritoIndex}>{index + 1}.</span>{fila.nombre}</td>
<td className={styles.fuerzaCell}>{fila.fuerza1Display}</td>
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza1Porcentaje)}</td>
<td className={styles.fuerzaCell}>{fila.fuerza2Display}</td>
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza2Porcentaje)}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
};

View File

@@ -0,0 +1,76 @@
/* src/features/legislativas/nacionales/TablaResultadosWidget.module.css */
.widgetContainer {
font-family: 'Roboto', sans-serif;
max-width: 900px;
margin: 2rem auto;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 1rem;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid #e0e0e0;
}
.header h3 {
margin: 0;
font-size: 1.5rem;
}
.categoriaSelector {
min-width: 250px;
}
.resultsTable {
width: 100%;
border-collapse: separate;
border-spacing: 0;
}
.resultsTable th,
.resultsTable td {
padding: 0.75rem;
text-align: left;
border-bottom: 1px solid #f0f0f0;
}
.resultsTable th {
font-weight: 700;
font-size: 0.8rem;
text-transform: uppercase;
color: #6c757d;
}
.distritoCell {
font-weight: 500;
}
.fuerzaCell {
color: #212529;
}
.porcentajeCell {
font-weight: 700;
text-align: right;
min-width: 80px;
}
.seccionHeader td {
background-color: #f8f9fa;
font-weight: 700;
font-size: 1.1rem;
color: #007bff;
border-top: 2px solid #007bff;
border-bottom: 2px solid #007bff;
}
.distritoIndex {
font-weight: 400;
color: #6c757d;
padding-right: 0.5rem;
}

View File

@@ -0,0 +1,58 @@
// src/features/legislativas/nacionales/TablaSeccionesWidget.tsx
import React from 'react'; // Importar React para React.Fragment
import { useQuery } from '@tanstack/react-query';
import { getTablaSecciones } from '../../../apiService';
import styles from './TablaResultadosWidget.module.css';
export const TablaSeccionesWidget = () => {
const ELECCION_ID = 2;
const { data, isLoading, error } = useQuery({
queryKey: ['tablaSecciones', ELECCION_ID],
queryFn: () => getTablaSecciones(ELECCION_ID),
refetchInterval: 60000,
});
const formatPercent = (num: number) => `${num.toFixed(2)}%`;
return (
<div className={styles.widgetContainer}>
<div className={styles.header}>
<h3>Resultados por Sección - Diputados Nacionales</h3>
</div>
{isLoading && <p>Cargando resultados...</p>}
{error && <p>Error al cargar los datos.</p>}
{data && (
<table className={styles.resultsTable}>
<thead>
<tr>
<th>Municipio</th>
<th>1ra Fuerza</th>
<th>%</th>
<th>2da Fuerza</th>
<th>%</th>
</tr>
</thead>
<tbody>
{data.map((seccion) => (
<React.Fragment key={seccion.seccionId}>
<tr className={styles.seccionHeader}>
<td colSpan={5}>{seccion.nombre}</td>
</tr>
{seccion.municipios.map((fila, index) => (
<tr key={fila.ambitoId}>
<td className={styles.distritoCell}><span className={styles.distritoIndex}>{index + 1}.</span>{fila.nombre}</td>
<td className={styles.fuerzaCell}>{fila.fuerza1Display}</td>
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza1Porcentaje)}</td>
<td className={styles.fuerzaCell}>{fila.fuerza2Display}</td>
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza2Porcentaje)}</td>
</tr>
))}
</React.Fragment>
))}
</tbody>
</table>
)}
</div>
);
};

View File

@@ -152,7 +152,7 @@ export interface ResultadoCandidato {
color: string | null;
porcentaje: number;
votos: number;
bancasObtenidas?: number;
bancasObtenidas?: number;
}
// Definición para una categoría.
@@ -171,12 +171,29 @@ export interface ResumenProvincia {
}
export interface CategoriaResumenHome {
categoriaId: number;
categoriaNombre: string;
estadoRecuento: EstadoRecuentoDto | null;
resultados: ResultadoCandidato[];
votosEnBlanco: number;
votosEnBlancoPorcentaje: number;
votosTotales: number;
ultimaActualizacion: string;
categoriaId: number;
categoriaNombre: string;
estadoRecuento: EstadoRecuentoDto | null;
resultados: ResultadoCandidato[];
votosEnBlanco: number;
votosEnBlancoPorcentaje: number;
votosTotales: number;
ultimaActualizacion: string;
}
// --- TIPOS PARA WIDGETS DE TABLAS ---
export interface ResultadoFila {
ambitoId: number;
nombre: string;
orden: number;
fuerza1Display: string;
fuerza1Porcentaje: number;
fuerza2Display: string;
fuerza2Porcentaje: number;
}
export interface ResultadoSeccion {
seccionId: string;
nombre: string;
municipios: ResultadoFila[];
}

View File

@@ -1676,7 +1676,6 @@ List<CandidatoOverride> overrides, string agrupacionId, int categoriaId, int? am
var todosLosLogos = await _dbContext.LogosAgrupacionesCategorias.AsNoTracking().Where(l => l.EleccionId == eleccionId || l.EleccionId == 0).ToListAsync();
var categoriaInfo = await _dbContext.CategoriasElectorales.AsNoTracking().FirstOrDefaultAsync(c => c.Id == categoriaId);
// Calculamos los totales nacionales sumando los datos de todas las provincias (NivelId = 10).
var totalesProvincialesAgregados = await _dbContext.EstadosRecuentosGenerales
.AsNoTracking()
.Where(e => e.EleccionId == eleccionId && e.CategoriaId == categoriaId && e.AmbitoGeografico.NivelId == 10)
@@ -1687,7 +1686,7 @@ List<CandidatoOverride> overrides, string agrupacionId, int categoriaId, int? am
TotalElectores = g.Sum(e => e.CantidadElectores),
TotalMesasTotalizadas = g.Sum(e => e.MesasTotalizadas),
TotalMesasEsperadas = g.Sum(e => e.MesasEsperadas),
UltimaFecha = g.Max(e => e.FechaTotalizacion) // También obtenemos la fecha más reciente.
UltimaFecha = g.Max(e => e.FechaTotalizacion)
})
.FirstOrDefaultAsync();
@@ -1748,4 +1747,128 @@ List<CandidatoOverride> overrides, string agrupacionId, int categoriaId, int? am
return Ok(respuesta);
}
[HttpGet("tabla-conurbano")]
public async Task<IActionResult> GetTablaConurbano([FromRoute] int eleccionId)
{
const int categoriaId = 3; // Diputados Nacionales
var municipiosConurbano = await (
from conurbano in _dbContext.Conurbano
join ambito in _dbContext.AmbitosGeograficos on conurbano.AmbitoGeograficoId equals ambito.Id
orderby conurbano.Orden
select new
{
conurbano.AmbitoGeograficoId,
conurbano.Orden,
ambito.Nombre
})
.AsNoTracking()
.ToListAsync();
var idsMunicipios = municipiosConurbano.Select(m => m.AmbitoGeograficoId).ToList();
var todosLosVotos = await _dbContext.ResultadosVotos
.AsNoTracking()
.Include(rv => rv.AgrupacionPolitica)
.Where(rv => rv.EleccionId == eleccionId && rv.CategoriaId == categoriaId && idsMunicipios.Contains(rv.AmbitoGeograficoId))
.ToListAsync();
var resultadosFinales = new List<Elecciones.Core.DTOs.ApiResponses.Tablas.ResultadoFilaDto>();
foreach (var municipio in municipiosConurbano)
{
var votosMunicipio = todosLosVotos.Where(v => v.AmbitoGeograficoId == municipio.AmbitoGeograficoId).ToList();
var totalVotos = (decimal)votosMunicipio.Sum(v => v.CantidadVotos);
var top2 = votosMunicipio.OrderByDescending(v => v.CantidadVotos).Take(2).ToList();
string GetDisplayName(ResultadoVoto? voto)
{
if (voto == null) return "N/D";
return voto.AgrupacionPolitica.NombreCorto ?? voto.AgrupacionPolitica.Nombre;
}
var fila = new Elecciones.Core.DTOs.ApiResponses.Tablas.ResultadoFilaDto
{
AmbitoId = municipio.AmbitoGeograficoId,
Nombre = municipio.Nombre,
Orden = municipio.Orden,
Fuerza1Display = GetDisplayName(top2.FirstOrDefault()),
Fuerza1Porcentaje = top2.Count > 0 && totalVotos > 0 ? (top2[0].CantidadVotos / totalVotos) * 100 : 0,
Fuerza2Display = GetDisplayName(top2.Skip(1).FirstOrDefault()),
Fuerza2Porcentaje = top2.Count > 1 && totalVotos > 0 ? (top2[1].CantidadVotos / totalVotos) * 100 : 0,
};
resultadosFinales.Add(fila);
}
return Ok(resultadosFinales);
}
[HttpGet("tabla-secciones")]
public async Task<IActionResult> GetTablaSecciones([FromRoute] int eleccionId)
{
const int categoriaId = 3;
var provinciaBA = await _dbContext.AmbitosGeograficos.AsNoTracking().FirstOrDefaultAsync(a => a.DistritoId == "02" && a.NivelId == 10);
if (provinciaBA == null) return NotFound("No se encontró el ámbito de la Provincia de Buenos Aires.");
var secciones = await _dbContext.AmbitosGeograficos
.AsNoTracking()
.Where(a => a.NivelId == 20 && a.DistritoId == "02" && a.SeccionProvincialId != null)
.OrderBy(a => a.SeccionProvincialId)
.ToListAsync();
var idsSecciones = secciones.Select(s => s.SeccionProvincialId).ToList();
var municipiosDeSecciones = await _dbContext.AmbitosGeograficos.AsNoTracking()
.Where(a => a.NivelId == 30 && a.DistritoId == "02" && idsSecciones.Contains(a.SeccionProvincialId)).ToListAsync();
var idsMunicipios = municipiosDeSecciones.Select(m => m.Id).ToList();
var todosLosVotos = await _dbContext.ResultadosVotos.AsNoTracking()
.Include(rv => rv.AgrupacionPolitica)
.Where(rv => rv.EleccionId == eleccionId && rv.CategoriaId == categoriaId && idsMunicipios.Contains(rv.AmbitoGeograficoId)).ToListAsync();
var todosLosCandidatos = await _dbContext.CandidatosOverrides.AsNoTracking()
.Where(c => (c.EleccionId == eleccionId || c.EleccionId == 0) && c.CategoriaId == categoriaId).ToListAsync();
var resultadosFinales = new List<Elecciones.Core.DTOs.ApiResponses.Tablas.ResultadoSeccionDto>();
foreach (var seccion in secciones)
{
var seccionDto = new Elecciones.Core.DTOs.ApiResponses.Tablas.ResultadoSeccionDto { SeccionId = seccion.SeccionProvincialId!, Nombre = seccion.Nombre };
var municipiosDeEstaSeccion = municipiosDeSecciones.Where(m => m.SeccionProvincialId == seccion.SeccionProvincialId).OrderBy(m => m.Nombre);
foreach (var municipio in municipiosDeEstaSeccion)
{
var votosMunicipio = todosLosVotos.Where(v => v.AmbitoGeograficoId == municipio.Id).ToList();
var totalVotos = (decimal)votosMunicipio.Sum(v => v.CantidadVotos);
var top2 = votosMunicipio.OrderByDescending(v => v.CantidadVotos).Take(2).ToList();
string GetDisplayName(ResultadoVoto? voto)
{
if (voto == null) return "N/D";
var candidato = todosLosCandidatos.FirstOrDefault(c => c.AgrupacionPoliticaId == voto.AgrupacionPoliticaId && c.AmbitoGeograficoId == voto.AmbitoGeograficoId)
?? todosLosCandidatos.FirstOrDefault(c => c.AgrupacionPoliticaId == voto.AgrupacionPoliticaId && c.AmbitoGeograficoId == provinciaBA.Id)
?? todosLosCandidatos.FirstOrDefault(c => c.AgrupacionPoliticaId == voto.AgrupacionPoliticaId && c.AmbitoGeograficoId == null);
return candidato?.NombreCandidato ?? voto.AgrupacionPolitica.NombreCorto ?? voto.AgrupacionPolitica.Nombre;
}
seccionDto.Municipios.Add(new Elecciones.Core.DTOs.ApiResponses.Tablas.ResultadoFilaDto
{
AmbitoId = municipio.Id,
Nombre = municipio.Nombre,
Orden = municipio.Id,
Fuerza1Display = GetDisplayName(top2.FirstOrDefault()),
Fuerza1Porcentaje = top2.Count > 0 && totalVotos > 0 ? (top2[0].CantidadVotos / totalVotos) * 100 : 0,
Fuerza2Display = GetDisplayName(top2.Skip(1).FirstOrDefault()),
Fuerza2Porcentaje = top2.Count > 1 && totalVotos > 0 ? (top2[1].CantidadVotos / totalVotos) * 100 : 0,
});
}
resultadosFinales.Add(seccionDto);
}
return Ok(resultadosFinales);
}
}

View File

@@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+814b24cefbaf491f4b43e55a0ded7431f679486d")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3c364ef373330eaa052fa0d2aad92e71d0bfd7df")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","ZxPpBx5gkHuilHLcg/vcjvaXswvTqiUM0YaAEwbNSLI=","zSbNtRd32h6wCMWjU5ecl5a3ECd\u002BVBstFC3etkdk4s0=","oncJIM8bHl6Y6SOcfvvBEQqLSQ06eswRhLoWIZejO5w=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","8MmMrEQZa7r\u002B8J2r9WqeQZOEj806afRSF6ducpDWGG0="],"CachedAssets":{},"CachedCopyCandidates":{}}
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","ZxPpBx5gkHuilHLcg/vcjvaXswvTqiUM0YaAEwbNSLI=","zSbNtRd32h6wCMWjU5ecl5a3ECd\u002BVBstFC3etkdk4s0=","urIQ/RlknPjR8\u002BeAcCsDIPiRjQGFfUdIC\u002BoT3wYB2dU=","0GIIj19uQyjDIXFgf3aZC3MWTTr0ockrC95FYCZEyN4=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","YscOvhINdry\u002BI95UO\u002BBCycn6KSJEZQzHtH6Q7oRYqCI="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","ZxPpBx5gkHuilHLcg/vcjvaXswvTqiUM0YaAEwbNSLI=","zSbNtRd32h6wCMWjU5ecl5a3ECd\u002BVBstFC3etkdk4s0=","oncJIM8bHl6Y6SOcfvvBEQqLSQ06eswRhLoWIZejO5w=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","8MmMrEQZa7r\u002B8J2r9WqeQZOEj806afRSF6ducpDWGG0="],"CachedAssets":{},"CachedCopyCandidates":{}}
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","ZxPpBx5gkHuilHLcg/vcjvaXswvTqiUM0YaAEwbNSLI=","zSbNtRd32h6wCMWjU5ecl5a3ECd\u002BVBstFC3etkdk4s0=","urIQ/RlknPjR8\u002BeAcCsDIPiRjQGFfUdIC\u002BoT3wYB2dU=","0GIIj19uQyjDIXFgf3aZC3MWTTr0ockrC95FYCZEyN4=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","YscOvhINdry\u002BI95UO\u002BBCycn6KSJEZQzHtH6Q7oRYqCI="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -0,0 +1,13 @@
// src/Elecciones.Core/DTOs/ApiResponses/Tablas/ResultadoFilaDto.cs
namespace Elecciones.Core.DTOs.ApiResponses.Tablas;
public class ResultadoFilaDto
{
public int AmbitoId { get; set; }
public string Nombre { get; set; } = string.Empty;
public int Orden { get; set; }
public string? Fuerza1Display { get; set; }
public decimal Fuerza1Porcentaje { get; set; }
public string? Fuerza2Display { get; set; }
public decimal Fuerza2Porcentaje { get; set; }
}

View File

@@ -0,0 +1,9 @@
// src/Elecciones.Core/DTOs/ApiResponses/Tablas/ResultadoSeccionDto.cs
namespace Elecciones.Core.DTOs.ApiResponses.Tablas;
public class ResultadoSeccionDto
{
public string SeccionId { get; set; } = string.Empty;
public string Nombre { get; set; } = string.Empty;
public List<ResultadoFilaDto> Municipios { get; set; } = new();
}

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ee092d6edd7454ee43318dc4c7e3d6f5348bff1")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3c364ef373330eaa052fa0d2aad92e71d0bfd7df")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -23,6 +23,7 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options)
public DbSet<CandidatoOverride> CandidatosOverrides { get; set; }
public DbSet<Eleccion> Elecciones { get; set; }
public DbSet<BancaPrevia> BancasPrevias { get; set; }
public DbSet<Conurbano> Conurbano { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{

View File

@@ -0,0 +1,14 @@
// src/Elecciones.Database/Entities/Conurbano.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Elecciones.Database.Entities;
[Table("Conurbano")]
public class Conurbano
{
[Key]
public int AmbitoGeograficoId { get; set; }
public int Orden { get; set; }
}

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ee092d6edd7454ee43318dc4c7e3d6f5348bff1")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3c364ef373330eaa052fa0d2aad92e71d0bfd7df")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ee092d6edd7454ee43318dc4c7e3d6f5348bff1")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3c364ef373330eaa052fa0d2aad92e71d0bfd7df")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]