feat: enhance call and point registration features with sensor data integration

- Updated the CallWindow component to include connection quality states and reconnection attempts, improving user experience during calls.
- Enhanced the ChatWindow to allow starting audio and video calls in a new window, providing users with more flexibility.
- Integrated accelerometer and gyroscope data collection in the RegistroPonto component, enabling validation of point registration authenticity.
- Improved error handling and user feedback for sensor permissions and data validation, ensuring a smoother registration process.
- Updated backend logic to validate sensor data and adjust confidence scores for point registration, enhancing security against spoofing.
This commit is contained in:
2025-11-22 20:49:52 -03:00
parent fc4b5c5ba5
commit f818756efc
15 changed files with 2100 additions and 275 deletions

View File

@@ -9,6 +9,7 @@
import AreaChart from './charts/AreaChart.svelte';
import DoughnutChart from './charts/DoughnutChart.svelte';
import BarChart from './charts/BarChart.svelte';
import { obterInformacoesDispositivo } from '$lib/utils/deviceInfo';
const client = useConvexClient();
@@ -45,6 +46,18 @@
serviceWorkerStatus: string;
domNodes: number;
jsHeapSize: number;
// GPS
latitude?: number;
longitude?: number;
gpsPrecision?: number;
gpsConfidence?: number;
// Acelerômetro
accelerometerX?: number;
accelerometerY?: number;
accelerometerZ?: number;
movementDetected?: boolean;
movementMagnitude?: number;
sensorAvailable?: boolean;
};
type NetworkInformationEx = {
@@ -548,7 +561,8 @@
usuariosOnline,
tempoRespostaMedio,
batteryInfo,
indexedDBSize
indexedDBSize,
deviceInfo
] = await Promise.all([
estimateCPU(),
Promise.resolve(getMemoryUsage()),
@@ -557,14 +571,15 @@
getUsuariosOnline(),
getResponseTime(),
getBatteryInfo(),
getIndexedDBSize()
getIndexedDBSize(),
obterInformacoesDispositivo().catch(() => ({}) as Record<string, unknown>) // Capturar erro se falhar
]);
const browserInfo = getBrowserInfo();
const networkInfo = getNetworkInfo();
const wsInfo = getWebSocketStatus();
const newMetrics = {
const newMetrics: Metrics = {
timestamp: Date.now(),
cpuUsage,
memoryUsage,
@@ -594,7 +609,19 @@
indexedDBSize,
serviceWorkerStatus: getServiceWorkerStatus(),
domNodes: getDOMNodeCount(),
jsHeapSize: getJSHeapSize()
jsHeapSize: getJSHeapSize(),
// GPS
latitude: deviceInfo.latitude,
longitude: deviceInfo.longitude,
gpsPrecision: deviceInfo.precisao,
gpsConfidence: deviceInfo.confiabilidadeGPS,
// Acelerômetro
accelerometerX: deviceInfo.acelerometro?.x,
accelerometerY: deviceInfo.acelerometro?.y,
accelerometerZ: deviceInfo.acelerometro?.z,
movementDetected: deviceInfo.acelerometro?.movimentoDetectado,
movementMagnitude: deviceInfo.acelerometro?.magnitude,
sensorAvailable: deviceInfo.sensorDisponivel
};
// Resetar contadores
@@ -1445,6 +1472,181 @@
</div>
</div>
<!-- Seção de GPS e Sensores -->
<div class="mt-8">
<div class="divider">
<h2 class="text-primary flex items-center gap-3 text-2xl font-bold">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
GPS e Sensores
</h2>
</div>
<div class="mt-6 grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<!-- Latitude -->
{#if metrics.latitude !== undefined}
<div
class="stat bg-base-100 border-primary/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Latitude</div>
<div class="stat-value text-primary text-2xl">{metrics.latitude.toFixed(6)}</div>
<div class="stat-desc mt-2">
<div class="badge badge-primary badge-sm">GPS</div>
</div>
</div>
{/if}
<!-- Longitude -->
{#if metrics.longitude !== undefined}
<div
class="stat bg-base-100 border-primary/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Longitude</div>
<div class="stat-value text-primary text-2xl">{metrics.longitude.toFixed(6)}</div>
<div class="stat-desc mt-2">
<div class="badge badge-primary badge-sm">GPS</div>
</div>
</div>
{/if}
<!-- Precisão GPS -->
{#if metrics.gpsPrecision !== undefined}
<div
class="stat bg-base-100 border-info/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Precisão GPS</div>
<div class="stat-value text-info text-2xl">{metrics.gpsPrecision.toFixed(2)}m</div>
<div class="stat-desc mt-2">
<div class="badge badge-info badge-sm">Precisão</div>
</div>
</div>
{/if}
<!-- Confiança GPS -->
{#if metrics.gpsConfidence !== undefined}
<div
class="stat bg-base-100 border-success/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Confiança GPS</div>
<div class="stat-value text-success text-2xl">
{(metrics.gpsConfidence * 100).toFixed(1)}%
</div>
<div class="stat-desc mt-2">
<div class="badge badge-success badge-sm">Confiança</div>
</div>
</div>
{/if}
<!-- Acelerômetro X -->
{#if metrics.accelerometerX !== undefined}
<div
class="stat bg-base-100 border-warning/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Acelerômetro X</div>
<div class="stat-value text-warning text-2xl">{metrics.accelerometerX.toFixed(3)}</div>
<div class="stat-desc mt-2">
<div class="badge badge-warning badge-sm">m/s²</div>
</div>
</div>
{/if}
<!-- Acelerômetro Y -->
{#if metrics.accelerometerY !== undefined}
<div
class="stat bg-base-100 border-warning/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Acelerômetro Y</div>
<div class="stat-value text-warning text-2xl">{metrics.accelerometerY.toFixed(3)}</div>
<div class="stat-desc mt-2">
<div class="badge badge-warning badge-sm">m/s²</div>
</div>
</div>
{/if}
<!-- Acelerômetro Z -->
{#if metrics.accelerometerZ !== undefined}
<div
class="stat bg-base-100 border-warning/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Acelerômetro Z</div>
<div class="stat-value text-warning text-2xl">{metrics.accelerometerZ.toFixed(3)}</div>
<div class="stat-desc mt-2">
<div class="badge badge-warning badge-sm">m/s²</div>
</div>
</div>
{/if}
<!-- Magnitude de Movimento -->
{#if metrics.movementMagnitude !== undefined}
<div
class="stat bg-base-100 border-error/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Magnitude de Movimento</div>
<div class="stat-value text-error text-2xl">{metrics.movementMagnitude.toFixed(3)}</div>
<div class="stat-desc mt-2">
<div class="badge badge-error badge-sm">m/s²</div>
</div>
</div>
{/if}
<!-- Movimento Detectado -->
{#if metrics.movementDetected !== undefined}
<div
class="stat bg-base-100 border-accent/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Movimento Detectado</div>
<div class="stat-value text-accent text-3xl">
{metrics.movementDetected ? 'Sim' : 'Não'}
</div>
<div class="stat-desc mt-2">
<div
class="badge {metrics.movementDetected ? 'badge-success' : 'badge-warning'} badge-sm"
>
{metrics.movementDetected ? 'Ativo' : 'Inativo'}
</div>
</div>
</div>
{/if}
<!-- Status do Sensor -->
{#if metrics.sensorAvailable !== undefined}
<div
class="stat bg-base-100 border-secondary/10 rounded-2xl border shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl"
>
<div class="stat-title font-semibold">Sensor Disponível</div>
<div class="stat-value text-secondary text-3xl">
{metrics.sensorAvailable ? 'Sim' : 'Não'}
</div>
<div class="stat-desc mt-2">
<div
class="badge {metrics.sensorAvailable ? 'badge-success' : 'badge-ghost'} badge-sm"
>
{metrics.sensorAvailable ? 'Disponível' : 'Indisponível'}
</div>
</div>
</div>
{/if}
</div>
</div>
<!-- Seção de Gráficos Interativos -->
{#if metricsHistory.length > 5}
<div class="mt-8">
@@ -1608,14 +1810,16 @@
</svg>
<div>
<h3 class="font-bold">
Monitoramento Ativo (Modo Local) - 23 Métricas Técnicas + 4 Gráficos Interativos
Monitoramento Ativo (Modo Local) - Métricas Técnicas + GPS + Sensores + 4 Gráficos Interativos
</h3>
<div class="text-xs">
<strong>Sistema:</strong> CPU, RAM, Latência, Storage |
<strong>Aplicação:</strong> Usuários, Mensagens, Tempo Resposta, Erros, HTTP Requests |
<strong>Performance:</strong> FPS, Conexão, Navegador, Tela |
<strong>Hardware:</strong> RAM Física, Núcleos CPU, Cache, Bateria, Uptime |
<strong>Avançado:</strong> WebSocket, IndexedDB, Service Worker, DOM Nodes, JS Heap
<strong>Avançado:</strong> WebSocket, IndexedDB, Service Worker, DOM Nodes, JS Heap |
<strong>GPS:</strong> Latitude, Longitude, Precisão, Confiança |
<strong>Sensores:</strong> Acelerômetro (X, Y, Z), Magnitude, Movimento Detectado
<br />
<strong>Gráficos:</strong> Linha (Recursos), Área (Atividade), Donut (Distribuição),
Barras (Métricas)