feat: implement sub-steps management in workflow editor
- Added functionality for creating, updating, and deleting sub-steps within the workflow editor. - Introduced a modal for adding new sub-steps, including fields for name and description. - Enhanced the UI to display sub-steps with status indicators and options for updating their status. - Updated navigation links to reflect changes in the workflow structure, ensuring consistency across the application. - Refactored related components to accommodate the new sub-steps feature, improving overall workflow management.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -163,6 +163,16 @@ export default defineSchema({
|
||||
.index("by_nome", ["nome"])
|
||||
.index("by_sigla", ["sigla"]),
|
||||
|
||||
// Relação muitos-para-muitos entre funcionários e setores
|
||||
funcionarioSetores: defineTable({
|
||||
funcionarioId: v.id("funcionarios"),
|
||||
setorId: v.id("setores"),
|
||||
createdAt: v.number(),
|
||||
})
|
||||
.index("by_funcionarioId", ["funcionarioId"])
|
||||
.index("by_setorId", ["setorId"])
|
||||
.index("by_funcionarioId_and_setorId", ["funcionarioId", "setorId"]),
|
||||
|
||||
// Templates de fluxo
|
||||
flowTemplates: defineTable({
|
||||
name: v.string(),
|
||||
@@ -191,8 +201,7 @@ export default defineSchema({
|
||||
// Instâncias de fluxo
|
||||
flowInstances: defineTable({
|
||||
flowTemplateId: v.id("flowTemplates"),
|
||||
targetType: v.string(), // ex: 'contrato', 'projeto'
|
||||
targetId: v.string(), // ID genérico do alvo
|
||||
contratoId: v.optional(v.id("contratos")),
|
||||
managerId: v.id("usuarios"),
|
||||
status: flowInstanceStatus,
|
||||
startedAt: v.number(),
|
||||
@@ -200,7 +209,7 @@ export default defineSchema({
|
||||
currentStepId: v.optional(v.id("flowInstanceSteps")),
|
||||
})
|
||||
.index("by_flowTemplateId", ["flowTemplateId"])
|
||||
.index("by_targetType_and_targetId", ["targetType", "targetId"])
|
||||
.index("by_contratoId", ["contratoId"])
|
||||
.index("by_managerId", ["managerId"])
|
||||
.index("by_status", ["status"]),
|
||||
|
||||
@@ -214,6 +223,8 @@ export default defineSchema({
|
||||
startedAt: v.optional(v.number()),
|
||||
finishedAt: v.optional(v.number()),
|
||||
notes: v.optional(v.string()),
|
||||
notesUpdatedBy: v.optional(v.id("usuarios")),
|
||||
notesUpdatedAt: v.optional(v.number()),
|
||||
dueDate: v.optional(v.number()),
|
||||
})
|
||||
.index("by_flowInstanceId", ["flowInstanceId"])
|
||||
@@ -232,6 +243,39 @@ export default defineSchema({
|
||||
.index("by_flowInstanceStepId", ["flowInstanceStepId"])
|
||||
.index("by_uploadedById", ["uploadedById"]),
|
||||
|
||||
// Sub-etapas de fluxo (para templates e instâncias)
|
||||
flowSubSteps: defineTable({
|
||||
flowStepId: v.optional(v.id("flowSteps")), // Para templates
|
||||
flowInstanceStepId: v.optional(v.id("flowInstanceSteps")), // Para instâncias
|
||||
name: v.string(),
|
||||
description: v.optional(v.string()),
|
||||
status: v.union(
|
||||
v.literal("pending"),
|
||||
v.literal("in_progress"),
|
||||
v.literal("completed"),
|
||||
v.literal("blocked")
|
||||
),
|
||||
position: v.number(),
|
||||
createdBy: v.id("usuarios"),
|
||||
createdAt: v.number(),
|
||||
})
|
||||
.index("by_flowStepId", ["flowStepId"])
|
||||
.index("by_flowInstanceStepId", ["flowInstanceStepId"]),
|
||||
|
||||
// Notas de steps e sub-etapas
|
||||
flowStepNotes: defineTable({
|
||||
flowStepId: v.optional(v.id("flowSteps")),
|
||||
flowInstanceStepId: v.optional(v.id("flowInstanceSteps")),
|
||||
flowSubStepId: v.optional(v.id("flowSubSteps")),
|
||||
texto: v.string(),
|
||||
criadoPor: v.id("usuarios"),
|
||||
criadoEm: v.number(),
|
||||
arquivos: v.array(v.id("_storage")),
|
||||
})
|
||||
.index("by_flowStepId", ["flowStepId"])
|
||||
.index("by_flowInstanceStepId", ["flowInstanceStepId"])
|
||||
.index("by_flowSubStepId", ["flowSubStepId"]),
|
||||
|
||||
contratos: defineTable({
|
||||
contratadaId: v.id("empresas"),
|
||||
objeto: v.string(),
|
||||
@@ -314,7 +358,6 @@ export default defineSchema({
|
||||
simboloId: v.id("simbolos"),
|
||||
simboloTipo: simboloTipo,
|
||||
gestorId: v.optional(v.id("usuarios")),
|
||||
setorId: v.optional(v.id("setores")), // Setor do funcionário
|
||||
statusFerias: v.optional(
|
||||
v.union(v.literal("ativo"), v.literal("em_ferias"))
|
||||
),
|
||||
@@ -454,8 +497,7 @@ export default defineSchema({
|
||||
.index("by_simboloTipo", ["simboloTipo"])
|
||||
.index("by_cpf", ["cpf"])
|
||||
.index("by_rg", ["rg"])
|
||||
.index("by_gestor", ["gestorId"])
|
||||
.index("by_setor", ["setorId"]),
|
||||
.index("by_gestor", ["gestorId"]),
|
||||
|
||||
atestados: defineTable({
|
||||
funcionarioId: v.id("funcionarios"),
|
||||
@@ -1003,7 +1045,8 @@ export default defineSchema({
|
||||
v.literal("mencao"),
|
||||
v.literal("grupo_criado"),
|
||||
v.literal("adicionado_grupo"),
|
||||
v.literal("alerta_seguranca")
|
||||
v.literal("alerta_seguranca"),
|
||||
v.literal("etapa_fluxo_concluida")
|
||||
),
|
||||
conversaId: v.optional(v.id("conversas")),
|
||||
mensagemId: v.optional(v.id("mensagens")),
|
||||
|
||||
@@ -136,6 +136,146 @@ export const update = mutation({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Obter funcionários de um setor específico
|
||||
*/
|
||||
export const getFuncionariosBySetor = query({
|
||||
args: { setorId: v.id('setores') },
|
||||
returns: v.array(
|
||||
v.object({
|
||||
_id: v.id('funcionarios'),
|
||||
_creationTime: v.number(),
|
||||
nome: v.string(),
|
||||
matricula: v.optional(v.string()),
|
||||
email: v.string(),
|
||||
cpf: v.string()
|
||||
})
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Buscar todas as relações funcionarioSetores para este setor
|
||||
const funcionarioSetores = await ctx.db
|
||||
.query('funcionarioSetores')
|
||||
.withIndex('by_setorId', (q) => q.eq('setorId', args.setorId))
|
||||
.collect();
|
||||
|
||||
// Buscar os funcionários correspondentes
|
||||
const funcionarios = [];
|
||||
for (const relacao of funcionarioSetores) {
|
||||
const funcionario = await ctx.db.get(relacao.funcionarioId);
|
||||
if (funcionario) {
|
||||
funcionarios.push({
|
||||
_id: funcionario._id,
|
||||
_creationTime: funcionario._creationTime,
|
||||
nome: funcionario.nome,
|
||||
matricula: funcionario.matricula,
|
||||
email: funcionario.email,
|
||||
cpf: funcionario.cpf
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return funcionarios;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Obter setores de um funcionário
|
||||
*/
|
||||
export const getSetoresByFuncionario = query({
|
||||
args: { funcionarioId: v.id('funcionarios') },
|
||||
returns: v.array(
|
||||
v.object({
|
||||
_id: v.id('setores'),
|
||||
_creationTime: v.number(),
|
||||
nome: v.string(),
|
||||
sigla: v.string(),
|
||||
criadoPor: v.id('usuarios'),
|
||||
createdAt: v.number()
|
||||
})
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Buscar todas as relações funcionarioSetores para este funcionário
|
||||
const funcionarioSetores = await ctx.db
|
||||
.query('funcionarioSetores')
|
||||
.withIndex('by_funcionarioId', (q) => q.eq('funcionarioId', args.funcionarioId))
|
||||
.collect();
|
||||
|
||||
// Buscar os setores correspondentes
|
||||
const setores = [];
|
||||
for (const relacao of funcionarioSetores) {
|
||||
const setor = await ctx.db.get(relacao.setorId);
|
||||
if (setor) {
|
||||
setores.push(setor);
|
||||
}
|
||||
}
|
||||
|
||||
return setores;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Atualizar setores de um funcionário
|
||||
*/
|
||||
export const atualizarSetoresFuncionario = mutation({
|
||||
args: {
|
||||
funcionarioId: v.id('funcionarios'),
|
||||
setorIds: v.array(v.id('setores'))
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const usuario = await getCurrentUserFunction(ctx);
|
||||
if (!usuario) {
|
||||
throw new Error('Usuário não autenticado');
|
||||
}
|
||||
|
||||
// Verificar se o funcionário existe
|
||||
const funcionario = await ctx.db.get(args.funcionarioId);
|
||||
if (!funcionario) {
|
||||
throw new Error('Funcionário não encontrado');
|
||||
}
|
||||
|
||||
// Verificar se todos os setores existem
|
||||
for (const setorId of args.setorIds) {
|
||||
const setor = await ctx.db.get(setorId);
|
||||
if (!setor) {
|
||||
throw new Error(`Setor ${setorId} não encontrado`);
|
||||
}
|
||||
}
|
||||
|
||||
// Remover todas as relações existentes do funcionário
|
||||
const funcionarioSetoresExistentes = await ctx.db
|
||||
.query('funcionarioSetores')
|
||||
.withIndex('by_funcionarioId', (q) => q.eq('funcionarioId', args.funcionarioId))
|
||||
.collect();
|
||||
|
||||
for (const relacao of funcionarioSetoresExistentes) {
|
||||
await ctx.db.delete(relacao._id);
|
||||
}
|
||||
|
||||
// Criar novas relações para os setores selecionados
|
||||
const now = Date.now();
|
||||
for (const setorId of args.setorIds) {
|
||||
// Verificar se já existe relação (evitar duplicatas)
|
||||
const existe = await ctx.db
|
||||
.query('funcionarioSetores')
|
||||
.withIndex('by_funcionarioId_and_setorId', (q) =>
|
||||
q.eq('funcionarioId', args.funcionarioId).eq('setorId', setorId)
|
||||
)
|
||||
.first();
|
||||
|
||||
if (!existe) {
|
||||
await ctx.db.insert('funcionarioSetores', {
|
||||
funcionarioId: args.funcionarioId,
|
||||
setorId,
|
||||
createdAt: now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Excluir um setor
|
||||
*/
|
||||
@@ -155,8 +295,8 @@ export const remove = mutation({
|
||||
|
||||
// Verificar se há funcionários vinculados
|
||||
const funcionariosVinculados = await ctx.db
|
||||
.query('funcionarios')
|
||||
.withIndex('by_setor', (q) => q.eq('setorId', args.id))
|
||||
.query('funcionarioSetores')
|
||||
.withIndex('by_setorId', (q) => q.eq('setorId', args.id))
|
||||
.first();
|
||||
if (funcionariosVinculados) {
|
||||
throw new Error('Não é possível excluir um setor com funcionários vinculados');
|
||||
|
||||
Reference in New Issue
Block a user