estadisticas por estado, municipio y parroquia agregadas
This commit is contained in:
@@ -4,7 +4,7 @@ import { and, eq, gte, ilike, lte, or, SQL, sql } from 'drizzle-orm';
|
|||||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||||
import { DRIZZLE_PROVIDER } from 'src/database/drizzle-provider';
|
import { DRIZZLE_PROVIDER } from 'src/database/drizzle-provider';
|
||||||
import * as schema from 'src/database/index';
|
import * as schema from 'src/database/index';
|
||||||
import { states, trainingSurveys } from 'src/database/index';
|
import { municipalities, parishes, states, trainingSurveys } from 'src/database/index';
|
||||||
|
|
||||||
import { PaginationDto } from '../../common/dto/pagination.dto';
|
import { PaginationDto } from '../../common/dto/pagination.dto';
|
||||||
import { CreateTrainingDto } from './dto/create-training.dto';
|
import { CreateTrainingDto } from './dto/create-training.dto';
|
||||||
@@ -120,6 +120,8 @@ export class TrainingService {
|
|||||||
isOpenSpaceDistribution,
|
isOpenSpaceDistribution,
|
||||||
hasTransportDistribution,
|
hasTransportDistribution,
|
||||||
genderResult,
|
genderResult,
|
||||||
|
municipalityDistribution,
|
||||||
|
parishDistribution,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
// 1. Total OSPs
|
// 1. Total OSPs
|
||||||
this.drizzle
|
this.drizzle
|
||||||
@@ -275,6 +277,31 @@ export class TrainingService {
|
|||||||
})
|
})
|
||||||
.from(trainingSurveys)
|
.from(trainingSurveys)
|
||||||
.where(whereCondition),
|
.where(whereCondition),
|
||||||
|
|
||||||
|
// 17. Distribución por Municipio
|
||||||
|
this.drizzle
|
||||||
|
.select({
|
||||||
|
name: sql<string>`COALESCE(${municipalities.name}, 'Sin Asignar')`,
|
||||||
|
value: sql<number>`count(${trainingSurveys.id})`,
|
||||||
|
})
|
||||||
|
.from(trainingSurveys)
|
||||||
|
.leftJoin(
|
||||||
|
municipalities,
|
||||||
|
eq(trainingSurveys.municipality, municipalities.id),
|
||||||
|
)
|
||||||
|
.where(whereCondition)
|
||||||
|
.groupBy(municipalities.name),
|
||||||
|
|
||||||
|
// 18. Distribución por Parroquia
|
||||||
|
this.drizzle
|
||||||
|
.select({
|
||||||
|
name: sql<string>`COALESCE(${parishes.name}, 'Sin Asignar')`,
|
||||||
|
value: sql<number>`count(${trainingSurveys.id})`,
|
||||||
|
})
|
||||||
|
.from(trainingSurveys)
|
||||||
|
.leftJoin(parishes, eq(trainingSurveys.parish, parishes.id))
|
||||||
|
.where(whereCondition)
|
||||||
|
.groupBy(parishes.name),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -334,6 +361,14 @@ export class TrainingService {
|
|||||||
{ name: 'Mujeres', value: Number(genderResult[0]?.women || 0) },
|
{ name: 'Mujeres', value: Number(genderResult[0]?.women || 0) },
|
||||||
{ name: 'Hombres', value: Number(genderResult[0]?.men || 0) },
|
{ name: 'Hombres', value: Number(genderResult[0]?.men || 0) },
|
||||||
],
|
],
|
||||||
|
municipalityDistribution: municipalityDistribution.map((item) => ({
|
||||||
|
...item,
|
||||||
|
value: Number(item.value),
|
||||||
|
})),
|
||||||
|
parishDistribution: parishDistribution.map((item) => ({
|
||||||
|
...item,
|
||||||
|
value: Number(item.value),
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ export function TrainingStatistics() {
|
|||||||
isOpenSpaceDistribution,
|
isOpenSpaceDistribution,
|
||||||
hasTransportDistribution,
|
hasTransportDistribution,
|
||||||
genderDistribution,
|
genderDistribution,
|
||||||
|
municipalityDistribution,
|
||||||
|
parishDistribution,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
@@ -279,8 +281,8 @@ export function TrainingStatistics() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* State Distribution */}
|
{/* Location Distribution (Dynamic) */}
|
||||||
{/* <Card className="col-span-full">
|
<Card className="col-span-full">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Distribución por Estado</CardTitle>
|
<CardTitle>Distribución por Estado</CardTitle>
|
||||||
<CardDescription>OSP registradas por estado</CardDescription>
|
<CardDescription>OSP registradas por estado</CardDescription>
|
||||||
@@ -300,7 +302,69 @@ export function TrainingStatistics() {
|
|||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card> */}
|
</Card>
|
||||||
|
|
||||||
|
{stateId > 0 ? (
|
||||||
|
<Card className="col-span-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Distribución por Municipio</CardTitle>
|
||||||
|
<CardDescription>OSP registradas en este estado</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="h-[400px]">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<BarChart
|
||||||
|
data={municipalityDistribution}
|
||||||
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="name" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
||||||
|
<Legend />
|
||||||
|
<Bar dataKey="value" fill="#0088FE" name="Cantidad" />
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<Card className="col-span-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Distribución por Municipio</CardTitle>
|
||||||
|
<CardDescription>Seleccione un estado</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{municipalityId > 0 ? (
|
||||||
|
<Card className="col-span-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Distribución por Parroquia</CardTitle>
|
||||||
|
<CardDescription>OSP registradas en este municipio</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="h-[400px]">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<BarChart
|
||||||
|
data={parishDistribution}
|
||||||
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="name" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
||||||
|
<Legend />
|
||||||
|
<Bar dataKey="value" fill="#FFBB28" name="Cantidad" />
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<Card className="col-span-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Distribución por Parroquia</CardTitle>
|
||||||
|
<CardDescription>Seleccione un municipio</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Year Distribution */}
|
{/* Year Distribution */}
|
||||||
<Card className="col-span-full lg:col-span-1">
|
<Card className="col-span-full lg:col-span-1">
|
||||||
@@ -483,7 +547,7 @@ export function TrainingStatistics() {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* STRUCTURE TYPE DISTRIBUTION */}
|
{/* STRUCTURE TYPE DISTRIBUTION */}
|
||||||
<Card className="col-span-full lg:col-span-1">
|
<Card className="col-span-full lg:col-span-2">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Tipo de Estructura</CardTitle>
|
<CardTitle>Tipo de Estructura</CardTitle>
|
||||||
<CardDescription>Distribución física</CardDescription>
|
<CardDescription>Distribución física</CardDescription>
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export const trainingStatisticsSchema = z.object({
|
|||||||
isOpenSpaceDistribution: z.array(statisticsItemSchema),
|
isOpenSpaceDistribution: z.array(statisticsItemSchema),
|
||||||
hasTransportDistribution: z.array(statisticsItemSchema),
|
hasTransportDistribution: z.array(statisticsItemSchema),
|
||||||
genderDistribution: z.array(statisticsItemSchema),
|
genderDistribution: z.array(statisticsItemSchema),
|
||||||
|
municipalityDistribution: z.array(statisticsItemSchema),
|
||||||
|
parishDistribution: z.array(statisticsItemSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TrainingStatisticsData = z.infer<typeof trainingStatisticsSchema>;
|
export type TrainingStatisticsData = z.infer<typeof trainingStatisticsSchema>;
|
||||||
|
|||||||
Reference in New Issue
Block a user