Call audio video jitsi #40
@@ -404,6 +404,70 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Função para calcular saldo diário como diferença entre saída e entrada
|
// Função para calcular saldo diário como diferença entre saída e entrada
|
||||||
|
/**
|
||||||
|
* Calcula saldos parciais entre cada par entrada/saída
|
||||||
|
* Retorna um mapa com o índice do registro e seu saldo parcial
|
||||||
|
*/
|
||||||
|
function calcularSaldosParciais(registros: Array<{ tipo: string; hora: number; minuto: number; _id?: any }>): Map<number, { saldoMinutos: number; horas: number; minutos: number; positivo: boolean; parNumero: number }> {
|
||||||
|
const saldos = new Map<number, { saldoMinutos: number; horas: number; minutos: number; positivo: boolean; parNumero: number }>();
|
||||||
|
if (registros.length === 0) return saldos;
|
||||||
|
|
||||||
|
// Criar array com índices originais
|
||||||
|
const registrosComIndice = registros.map((r, idx) => ({ ...r, originalIndex: idx }));
|
||||||
|
|
||||||
|
// Ordenar registros por hora e minuto para processar em ordem cronológica
|
||||||
|
const registrosOrdenados = [...registrosComIndice].sort((a, b) => {
|
||||||
|
if (a.hora !== b.hora) {
|
||||||
|
return a.hora - b.hora;
|
||||||
|
}
|
||||||
|
return a.minuto - b.minuto;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Identificar pares entrada/saída
|
||||||
|
// Par 1: entrada -> saida_almoco
|
||||||
|
// Par 2: retorno_almoco -> saida
|
||||||
|
let entradaAtual: typeof registrosComIndice[0] | null = null;
|
||||||
|
let parNumero = 1;
|
||||||
|
|
||||||
|
for (let i = 0; i < registrosOrdenados.length; i++) {
|
||||||
|
const registro = registrosOrdenados[i];
|
||||||
|
|
||||||
|
// Considerar entrada ou retorno_almoco como início de um período
|
||||||
|
if (registro.tipo === 'entrada' || registro.tipo === 'retorno_almoco') {
|
||||||
|
entradaAtual = registro;
|
||||||
|
} else if (entradaAtual) {
|
||||||
|
// Qualquer saída (saida_almoco ou saida) fecha o período atual
|
||||||
|
if (registro.tipo === 'saida_almoco' || registro.tipo === 'saida') {
|
||||||
|
// Calcular diferença entre saída e entrada
|
||||||
|
const minutosEntrada = entradaAtual.hora * 60 + entradaAtual.minuto;
|
||||||
|
const minutosSaida = registro.hora * 60 + registro.minuto;
|
||||||
|
|
||||||
|
let saldoMinutos = minutosSaida - minutosEntrada;
|
||||||
|
if (saldoMinutos < 0) {
|
||||||
|
saldoMinutos += 24 * 60; // Adicionar um dia em minutos
|
||||||
|
}
|
||||||
|
|
||||||
|
const horas = Math.floor(saldoMinutos / 60);
|
||||||
|
const minutos = saldoMinutos % 60;
|
||||||
|
|
||||||
|
// Salvar saldo no índice original do registro de saída
|
||||||
|
saldos.set(registro.originalIndex, {
|
||||||
|
saldoMinutos,
|
||||||
|
horas,
|
||||||
|
minutos,
|
||||||
|
positivo: true,
|
||||||
|
parNumero
|
||||||
|
});
|
||||||
|
|
||||||
|
entradaAtual = null; // Resetar para próximo par
|
||||||
|
parNumero++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return saldos;
|
||||||
|
}
|
||||||
|
|
||||||
function calcularSaldoDiario(registros: Array<{ tipo: string; hora: number; minuto: number }>): { saldoMinutos: number; horas: number; minutos: number; positivo: boolean } | null {
|
function calcularSaldoDiario(registros: Array<{ tipo: string; hora: number; minuto: number }>): { saldoMinutos: number; horas: number; minutos: number; positivo: boolean } | null {
|
||||||
if (registros.length === 0) return null;
|
if (registros.length === 0) return null;
|
||||||
|
|
||||||
@@ -2173,27 +2237,31 @@
|
|||||||
{#each registrosAgrupados as grupo}
|
{#each registrosAgrupados as grupo}
|
||||||
<div class="card bg-gradient-to-br from-base-100 to-base-200/50 border border-base-300 shadow-lg hover:shadow-xl transition-all duration-300">
|
<div class="card bg-gradient-to-br from-base-100 to-base-200/50 border border-base-300 shadow-lg hover:shadow-xl transition-all duration-300">
|
||||||
<div class="card-body p-6">
|
<div class="card-body p-6">
|
||||||
<div class="flex flex-col lg:flex-row items-start lg:items-center justify-between gap-4 mb-6">
|
<!-- Cabeçalho melhorado -->
|
||||||
<div class="flex-1">
|
<div class="mb-6 pb-4 border-b border-base-300">
|
||||||
<div class="flex items-center gap-3 mb-2">
|
<div class="flex flex-col lg:flex-row items-start lg:items-center justify-between gap-4">
|
||||||
<div class="p-2 bg-primary/10 rounded-lg">
|
<div class="flex-1">
|
||||||
<Users class="h-5 w-5 text-primary" strokeWidth={2.5} />
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<div class="p-2 bg-primary/10 rounded-lg">
|
||||||
|
<Users class="h-5 w-5 text-primary" strokeWidth={2.5} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-bold text-xl text-base-content">
|
||||||
|
{grupo.funcionario?.nome || 'Funcionário não encontrado'}
|
||||||
|
</h3>
|
||||||
|
{#if grupo.funcionario?.matricula}
|
||||||
|
<p class="text-sm text-base-content/70 mt-1">
|
||||||
|
Matrícula: <span class="font-semibold">{grupo.funcionario.matricula}</span>
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="font-bold text-xl text-base-content">
|
{#if grupo.funcionario?.descricaoCargo}
|
||||||
{grupo.funcionario?.nome || 'Funcionário não encontrado'}
|
<p class="text-sm text-base-content/60 ml-11">
|
||||||
</h3>
|
{grupo.funcionario.descricaoCargo}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if grupo.funcionario?.matricula}
|
|
||||||
<p class="text-sm text-base-content/70 ml-11">
|
|
||||||
Matrícula: <span class="font-semibold">{grupo.funcionario.matricula}</span>
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
{#if grupo.funcionario?.descricaoCargo}
|
|
||||||
<p class="text-sm text-base-content/60 ml-11">
|
|
||||||
{grupo.funcionario.descricaoCargo}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-3 flex-wrap">
|
<div class="flex items-center gap-3 flex-wrap">
|
||||||
<!-- Banco de Horas -->
|
<!-- Banco de Horas -->
|
||||||
@@ -2244,6 +2312,7 @@
|
|||||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Data</th>
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Data</th>
|
||||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Tipo</th>
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Tipo</th>
|
||||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Horário</th>
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Horário</th>
|
||||||
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Saldo Parcial</th>
|
||||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Saldo Diário</th>
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Saldo Diário</th>
|
||||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Localização</th>
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Localização</th>
|
||||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Status</th>
|
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Status</th>
|
||||||
@@ -2254,7 +2323,9 @@
|
|||||||
{#each Object.values(grupo.registrosPorData) as grupoData}
|
{#each Object.values(grupo.registrosPorData) as grupoData}
|
||||||
{@const totalRegistros = grupoData.registros.length}
|
{@const totalRegistros = grupoData.registros.length}
|
||||||
{@const dataFormatada = formatarDataDDMMAAAA(grupoData.data)}
|
{@const dataFormatada = formatarDataDDMMAAAA(grupoData.data)}
|
||||||
|
{@const saldosParciais = calcularSaldosParciais(grupoData.registros)}
|
||||||
{#each grupoData.registros as registro, index}
|
{#each grupoData.registros as registro, index}
|
||||||
|
{@const saldoParcial = saldosParciais.get(index)}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="whitespace-nowrap">{dataFormatada}</td>
|
<td class="whitespace-nowrap">{dataFormatada}</td>
|
||||||
<td class="whitespace-nowrap">
|
<td class="whitespace-nowrap">
|
||||||
@@ -2268,6 +2339,15 @@
|
|||||||
: getTipoRegistroLabel(registro.tipo)}
|
: getTipoRegistroLabel(registro.tipo)}
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap">{formatarHoraPonto(registro.hora, registro.minuto)}</td>
|
<td class="whitespace-nowrap">{formatarHoraPonto(registro.hora, registro.minuto)}</td>
|
||||||
|
<td class="whitespace-nowrap">
|
||||||
|
{#if saldoParcial}
|
||||||
|
<span class="badge badge-info badge-sm font-semibold">
|
||||||
|
Par {saldoParcial.parNumero}: +{saldoParcial.horas}h {saldoParcial.minutos}min
|
||||||
|
</span>
|
||||||
|
{:else}
|
||||||
|
<span class="text-base-content/40">-</span>
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
{#if index === 0}
|
{#if index === 0}
|
||||||
<td class="whitespace-nowrap" rowspan={totalRegistros}>
|
<td class="whitespace-nowrap" rowspan={totalRegistros}>
|
||||||
<SaldoDiarioBadge saldo={grupoData.saldoDiario} size="md" />
|
<SaldoDiarioBadge saldo={grupoData.saldoDiario} size="md" />
|
||||||
|
|||||||
Reference in New Issue
Block a user