diff options
| author | zwlucas <lucas.fariamo08@gmail.com> | 2026-07-25 21:23:29 +0000 |
|---|---|---|
| committer | zwlucas <lucas.fariamo08@gmail.com> | 2026-07-25 21:23:29 +0000 |
| commit | ef55d9bb24430610b60c1b77821307cd72c08c55 (patch) | |
| tree | e6935a810b34370b0a4c821e55f6397aac50c832 /api/src/modules/stats | |
| download | helpdesk-master.tar.gz helpdesk-master.zip | |
Signed-off-by: zwlucas <lucas.fariamo08@gmail.com>
Diffstat (limited to 'api/src/modules/stats')
| -rw-r--r-- | api/src/modules/stats/stats.controller.ts | 15 | ||||
| -rw-r--r-- | api/src/modules/stats/stats.repository.ts | 41 | ||||
| -rw-r--r-- | api/src/modules/stats/stats.routes.ts | 22 | ||||
| -rw-r--r-- | api/src/modules/stats/stats.schema.ts | 17 |
4 files changed, 95 insertions, 0 deletions
diff --git a/api/src/modules/stats/stats.controller.ts b/api/src/modules/stats/stats.controller.ts new file mode 100644 index 0000000..520f692 --- /dev/null +++ b/api/src/modules/stats/stats.controller.ts @@ -0,0 +1,15 @@ +/** + * stats.controller.ts + * Lógica do dashboard. + */ + +import type { FastifyReply, FastifyRequest } from 'fastify'; +import { getTicketsStats } from './stats.repository.js'; + +export async function getStatsHandler( + request: FastifyRequest, + reply: FastifyReply, +) { + const stats = await getTicketsStats(request.server.db); + return reply.send(stats); +} diff --git a/api/src/modules/stats/stats.repository.ts b/api/src/modules/stats/stats.repository.ts new file mode 100644 index 0000000..d5a543d --- /dev/null +++ b/api/src/modules/stats/stats.repository.ts @@ -0,0 +1,41 @@ +/** + * stats.repository.ts + * Queries para obter os totais agrupados. + */ + +import { sql } from 'drizzle-orm'; +import type { Database } from '@/db/connection.js'; +import { tickets } from '@/db/schema.js'; + +export async function getTicketsStats(db: Database) { + // Uma única query para agrupar as contagens por status + const rows = await db + .select({ + status: tickets.status, + count: sql<number>`count(*)`, + }) + .from(tickets) + .groupBy(tickets.status); + + // Inicializa o mapa com 0 + const stats = { + totalOpen: 0, + totalInProgress: 0, + totalWaiting: 0, + totalResolved: 0, + totalClosed: 0, + }; + + for (const row of rows) { + if (row.status === 'open') stats.totalOpen = row.count; + if (row.status === 'in_progress') stats.totalInProgress = row.count; + if (row.status === 'waiting') stats.totalWaiting = row.count; + if (row.status === 'resolved') stats.totalResolved = row.count; + if (row.status === 'closed') stats.totalClosed = row.count; + } + + return { + ...stats, + totalPending: stats.totalOpen + stats.totalInProgress, + }; +} diff --git a/api/src/modules/stats/stats.routes.ts b/api/src/modules/stats/stats.routes.ts new file mode 100644 index 0000000..cf02c08 --- /dev/null +++ b/api/src/modules/stats/stats.routes.ts @@ -0,0 +1,22 @@ +/** + * stats.routes.ts + * + * GET /api/v1/stats → retorna agregados para o dashboard + */ + +import type { FastifyInstance } from 'fastify'; +import { statsResponseSchema } from './stats.schema.js'; +import { getStatsHandler } from './stats.controller.js'; + +async function statsRoutes(fastify: FastifyInstance): Promise<void> { + fastify.get('/', { + schema: { + tags: ['Dashboard'], + summary: 'Retorna métricas e agregados dos chamados', + }, + preHandler: [fastify.authenticate], + handler: getStatsHandler, + }); +} + +export default statsRoutes; diff --git a/api/src/modules/stats/stats.schema.ts b/api/src/modules/stats/stats.schema.ts new file mode 100644 index 0000000..1616937 --- /dev/null +++ b/api/src/modules/stats/stats.schema.ts @@ -0,0 +1,17 @@ +/** + * stats.schema.ts + * Schemas para o módulo de estatísticas (Dashboard). + */ + +import { z } from 'zod'; + +export const statsResponseSchema = z.object({ + totalOpen: z.number(), + totalInProgress: z.number(), + totalWaiting: z.number(), + totalResolved: z.number(), + totalClosed: z.number(), + totalPending: z.number(), // open + in_progress +}); + +export type StatsResponse = z.infer<typeof statsResponseSchema>; |