Files
sgse-app/packages/backend/convex/logsAtividades.ts

181 lines
4.5 KiB
TypeScript

import { v } from 'convex/values';
import { MutationCtx, query } from './_generated/server';
import { Id } from './_generated/dataModel';
/**
* Helper function para registrar atividades no sistema
* Use em todas as mutations que modificam dados
*/
export async function registrarAtividade(
ctx: MutationCtx,
usuarioId: Id<'usuarios'>,
acao: string,
recurso: string,
detalhes?: string,
recursoId?: string
) {
await ctx.db.insert('logsAtividades', {
usuarioId,
acao,
recurso,
recursoId,
detalhes,
timestamp: Date.now()
});
}
/**
* Lista atividades com filtros
*/
export const listarAtividades = query({
args: {
usuarioId: v.optional(v.id('usuarios')),
acao: v.optional(v.string()),
recurso: v.optional(v.string()),
dataInicio: v.optional(v.number()),
dataFim: v.optional(v.number()),
limite: v.optional(v.number())
},
handler: async (ctx, args) => {
let atividades;
if (args.usuarioId) {
atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_usuario', (q) => q.eq('usuarioId', args.usuarioId!))
.order('desc')
.take(args.limite || 100);
} else if (args.acao) {
atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_acao', (q) => q.eq('acao', args.acao!))
.order('desc')
.take(args.limite || 100);
} else if (args.recurso) {
atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_recurso', (q) => q.eq('recurso', args.recurso!))
.order('desc')
.take(args.limite || 100);
} else {
atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_timestamp')
.order('desc')
.take(args.limite || 100);
}
// Filtrar por range de datas se fornecido
if (args.dataInicio || args.dataFim) {
atividades = atividades.filter((log) => {
if (args.dataInicio && log.timestamp < args.dataInicio) return false;
if (args.dataFim && log.timestamp > args.dataFim) return false;
return true;
});
}
// Buscar informações dos usuários
const atividadesComUsuarios = await Promise.all(
atividades.map(async (atividade) => {
const usuario = await ctx.db.get(atividade.usuarioId);
let matricula = 'N/A';
if (usuario?.funcionarioId) {
const funcionario = await ctx.db.get(usuario.funcionarioId);
matricula = funcionario?.matricula || 'N/A';
}
return {
...atividade,
usuarioNome: usuario?.nome || 'Usuário Desconhecido',
usuarioMatricula: matricula
};
})
);
return atividadesComUsuarios;
}
});
/**
* Obtém estatísticas de atividades
*/
export const obterEstatisticasAtividades = query({
args: {
periodo: v.optional(v.number()) // dias (ex: 7, 30)
},
handler: async (ctx, args) => {
const periodo = args.periodo || 30;
const dataInicio = Date.now() - periodo * 24 * 60 * 60 * 1000;
const atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_timestamp')
.filter((q) => q.gte(q.field('timestamp'), dataInicio))
.collect();
// Agrupar por ação
const porAcao: Record<string, number> = {};
atividades.forEach((ativ) => {
porAcao[ativ.acao] = (porAcao[ativ.acao] || 0) + 1;
});
// Agrupar por recurso
const porRecurso: Record<string, number> = {};
atividades.forEach((ativ) => {
porRecurso[ativ.recurso] = (porRecurso[ativ.recurso] || 0) + 1;
});
// Agrupar por dia
const porDia: Record<string, number> = {};
atividades.forEach((ativ) => {
const data = new Date(ativ.timestamp);
const dia = data.toISOString().split('T')[0];
porDia[dia] = (porDia[dia] || 0) + 1;
});
return {
total: atividades.length,
porAcao,
porRecurso,
porDia
};
}
});
/**
* Obtém histórico de atividades de um recurso específico
*/
export const obterHistoricoRecurso = query({
args: {
recurso: v.string(),
recursoId: v.string()
},
handler: async (ctx, args) => {
const atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_recurso_id', (q) =>
q.eq('recurso', args.recurso).eq('recursoId', args.recursoId)
)
.order('desc')
.collect();
// Buscar informações dos usuários
const atividadesComUsuarios = await Promise.all(
atividades.map(async (atividade) => {
const usuario = await ctx.db.get(atividade.usuarioId);
let matricula = 'N/A';
if (usuario?.funcionarioId) {
const funcionario = await ctx.db.get(usuario.funcionarioId);
matricula = funcionario?.matricula || 'N/A';
}
return {
...atividade,
usuarioNome: usuario?.nome || 'Usuário Desconhecido',
usuarioMatricula: matricula
};
})
);
return atividadesComUsuarios;
}
});