feat: Introduce structured table definitions in convex/tables for various entities and remove the todos example table.
This commit is contained in:
@@ -1,180 +1,180 @@
|
||||
import { v } from "convex/values";
|
||||
import { mutation, query, QueryCtx, MutationCtx } from "./_generated/server";
|
||||
import { Doc, Id } from "./_generated/dataModel";
|
||||
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
|
||||
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(),
|
||||
});
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
});
|
||||
}
|
||||
// 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,
|
||||
};
|
||||
})
|
||||
);
|
||||
// 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;
|
||||
},
|
||||
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;
|
||||
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();
|
||||
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 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 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;
|
||||
});
|
||||
// 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,
|
||||
};
|
||||
},
|
||||
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();
|
||||
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,
|
||||
};
|
||||
})
|
||||
);
|
||||
// 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;
|
||||
},
|
||||
return atividadesComUsuarios;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user