Initial import
This commit is contained in:
445
ci4app/app/Views/event_reader.php
Normal file
445
ci4app/app/Views/event_reader.php
Normal file
@ -0,0 +1,445 @@
|
||||
<?php
|
||||
$title = "Events";
|
||||
$menu = "menus/men_event_reader";
|
||||
$header = "headers/hea_event_reader";
|
||||
|
||||
$this->setVar('menu', $menu);
|
||||
$this->setVar('header', $header);
|
||||
$this->setVar('title', $title);
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
<?= $this->extend('layouts/default') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="content relative lg:px-4 flex-grow">
|
||||
|
||||
<!--:Prelaoder:-->
|
||||
<div id="preloader" class="absolute inset-0 w-full h-[75vh] flex items-center justify-center z-50">
|
||||
<div class="size-12 bg-white shadow-xl rounded-full flex items-center justify-center">
|
||||
<div class="animate-spin rounded-full size-10 border-b-2 border-primary"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="readers-container" class="px-4 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 mb-4">
|
||||
|
||||
|
||||
</div>
|
||||
<div id="readerstp-container" class="px-4 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 mb-4">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<?php
|
||||
// echo "<pre>";
|
||||
// print_r($config_course);
|
||||
// echo "</pre>";
|
||||
|
||||
// $config_tp['timingpoint'] doit exister
|
||||
$timingPoints = $config_tp['timingpoint'] ?? [];
|
||||
|
||||
// Hauteur fixe visuelle de chaque TP (en px)
|
||||
$tpHeight = 80;
|
||||
$tpGap = 10;
|
||||
// Largeur de chaque colonne d'intervalle (en px)
|
||||
$intervalColWidth = 60;
|
||||
|
||||
// Indexer les TP par tp_id pour les alignements verticaux
|
||||
$tpIndexById = [];
|
||||
foreach ($timingPoints as $index => $tp) {
|
||||
$tpIndexById[$tp['tp_id']] = $index;
|
||||
}
|
||||
|
||||
// Récupérer toutes les lignes d'intervalles (une colonne par intervalle)
|
||||
$intervals = [];
|
||||
foreach ($timingPoints as $tp) {
|
||||
|
||||
// vérifier si la clé existe
|
||||
if (!isset($tp['config_tp_interval']['clef_temp_minimum_read_entre'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// lire toutes les lignes de cet interval
|
||||
foreach ($tp['config_tp_interval']['clef_temp_minimum_read_entre'] as $row) {
|
||||
|
||||
$intervals[] = [
|
||||
'label' => 'clef_temp_minimum_read_entre',
|
||||
'start_id' => isset($row['value2']) ? (int) $row['value2'] : 0, // DÉBUT (tp_id)
|
||||
'end_id' => isset($row['value3']) ? (int) $row['value3'] : 0, // FIN (tp_id)
|
||||
'minimum' => isset($row['value3']) ? (int) $row['value1'] : 0, // FIN (tp_id)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$nbTp = count($timingPoints);
|
||||
// Hauteur totale = toutes les cartes + les espaces entre elles
|
||||
$totalHeight = $nbTp * $tpHeight + max(0, $nbTp - 1) * $tpGap;
|
||||
?>
|
||||
|
||||
<div class="px-4" data-collapse-root>
|
||||
|
||||
<!-- Header du collapse -->
|
||||
<div class="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-t-xl shadow-card">
|
||||
<p class="text-left font-semibold">Config (<?php echo count($timingPoints); ?> timing points)</p>
|
||||
|
||||
<button data-collapse-btn class="text-zinc-700 dark:text-white">
|
||||
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Contenu collapsable -->
|
||||
<div data-collapse-content class="mt-2">
|
||||
|
||||
<div class="lg:col-span-8">
|
||||
<!--:Card:-->
|
||||
<div class="rounded-xl bg-green-300 dark:bg-zinc-900 shadow-card overflow-hidden">
|
||||
<div class="flex items-center justify-between p-4 pb-2">
|
||||
<h1 >Config COURSE</h1>
|
||||
|
||||
</div>
|
||||
<div class="overflow-x-auto px-2">
|
||||
<table class="table-default">
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<?php foreach ($config_course as $cle => $course):
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td class="min-w-64">
|
||||
<div class="flex gap-3.5">
|
||||
<div class="flex-grow">
|
||||
<h6 class="mb-1.5"><?php echo $cle; ?></h6>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td> <?php echo $course[0]['output']; ?></td>
|
||||
<td class="min-w-40">
|
||||
<div class="flex items-center gap-3.5">
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="flex gap-[0px] items-start">
|
||||
|
||||
<!-- COLONNE GAUCHE : TIMING POINTS (~75%) -->
|
||||
<div class="w-4/5">
|
||||
<?php foreach ($timingPoints as $tp):
|
||||
// echo "<pre>";
|
||||
// print_r($tp);
|
||||
// echo "</pre>";
|
||||
?>
|
||||
<div
|
||||
class="rounded-xl bg-blue-300 dark:bg-zinc-900 shadow-card mb-3 flex items-center px-4"
|
||||
style="height: <?php echo $tpHeight; ?>px;"
|
||||
>
|
||||
<!-- Icone + Nom du TP -->
|
||||
<div class="flex items-center gap-3.5 flex-1">
|
||||
<div class="flex items-center justify-center p-4 rounded-lg shrink-0 bg-red-500/10 text-red-500">
|
||||
<span class="icon-[lucide--mouse-pointer-2] text-xl"></span>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<p class="mb-1 font-semibold"><?php echo $tp['tp_name']; ?></p>
|
||||
<p class="mb-1 text-sm text-zinc-600">tp_id : <?php echo $tp['tp_id']; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Temp minimum read -->
|
||||
<div class="flex items-center gap-3.5 flex-1">
|
||||
<div class="flex items-center justify-center p-4 rounded-lg shrink-0 bg-primary/20 text-primary">
|
||||
<i data-lucide="timer" class="w-4 h-4"></i>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<?php $minRead = $tp['config_tp']['clef_temp_read'][0] ?? null; ?>
|
||||
<?php $bbk = $tp['config_tp']['clef_temp_bbk'][0]['value1'] ?? null; ?>
|
||||
<p class="mb-1 text-sm">
|
||||
mode: <?php echo $minRead['value1'] ?? ''; ?><br>
|
||||
bbk:<?php echo $bbk ?? ''; ?><br>
|
||||
</p>
|
||||
<p class="mb-1 text-sm">
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Liste des contrôleurs -->
|
||||
<div class="flex items-center gap-3.5 flex-1">
|
||||
<div class="flex-grow">
|
||||
<?php foreach ($tp['config_tp']['clef_controleur'] ?? [] as $ctrl): ?>
|
||||
<p class="mb-1 text-sm">
|
||||
<?php echo $ctrl['value1']; ?>
|
||||
- (<?php echo $ctrl['value2']; ?>)
|
||||
- (<?php echo $ctrl['value3']; ?>)
|
||||
</p>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Case vide / future config -->
|
||||
<div class="flex items-center gap-3.5">
|
||||
<div class="flex items-center justify-center p-4 rounded-lg shrink-0 bg-yellow-500/20 text-yellow-500">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<!-- COLONNES DROITES : INTERVALLES (~25%) -->
|
||||
|
||||
<?php if (!empty($intervals)): ?>
|
||||
<!-- COLONNES DROITES : INTERVALLES (~25%) -->
|
||||
<div class="overflow-x-auto pt-2 shrink-0" style="width:160px;">
|
||||
|
||||
<div class="flex gap-0">
|
||||
|
||||
|
||||
<?php foreach ($intervals as $interval): ?>
|
||||
|
||||
<?php
|
||||
// Skip si start_id ou end_id n'existent pas dans la map
|
||||
if (!isset($tpIndexById[$interval['start_id']], $tpIndexById[$interval['end_id']])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convertir tp_id → index de ligne
|
||||
$startIndex = $tpIndexById[$interval['start_id']];
|
||||
$endIndex = $tpIndexById[$interval['end_id']];
|
||||
|
||||
// S'assurer startIndex <= endIndex
|
||||
if ($endIndex < $startIndex) {
|
||||
$tmp = $startIndex;
|
||||
$startIndex = $endIndex;
|
||||
$endIndex = $tmp;
|
||||
}
|
||||
|
||||
// Position de départ (index * (hauteur + gap))
|
||||
$top = $startIndex * ($tpHeight + $tpGap);
|
||||
|
||||
// Hauteur du segment = toutes les cartes couvertes + les gaps entre elles
|
||||
$height = ($endIndex - $startIndex + 1) * $tpHeight
|
||||
+ max(0, $endIndex - $startIndex) * $tpGap;
|
||||
|
||||
?>
|
||||
|
||||
<!-- DEBUG propre -->
|
||||
<pre style="font-size:12px;color:#333;">
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<!-- Colonne d’un intervalle -->
|
||||
<div class="relative rounded-xl bg-blue-200"
|
||||
style="width:10px; height:<?= $totalHeight ?>px;">
|
||||
|
||||
<!-- Barre bleue -->
|
||||
<div class="absolute left-1/2 -translate-x-1/2 bg-blue-200 rounded-full shadow"
|
||||
|
||||
style="
|
||||
top: <?= $top ?>px;
|
||||
height: <?= $height ?>px;
|
||||
width: 20px; background-color: #2563eb;
|
||||
">
|
||||
|
||||
|
||||
<!-- TEXTE VERTICAL -->
|
||||
<div style="
|
||||
writing-mode: vertical-rl;
|
||||
transform: rotate(180deg);
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) rotate(180deg);
|
||||
white-space: nowrap;
|
||||
">
|
||||
Minumum <?= $interval['minimum'] ?> sec.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
const DEBUG = <?= (ENVIRONMENT === 'development') ? 'true' : 'false' ?>;
|
||||
|
||||
const conId = <?= json_encode($data['config']['con_id'] ) ?>;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
const container = document.getElementById('readers-container');
|
||||
const eventId = <?= json_encode($id) ?>;
|
||||
|
||||
let refreshRate = 1000; // 1 seconde en ms (sera mis à jour par le JSON)
|
||||
|
||||
async function loadReaders() {
|
||||
try {
|
||||
const response = await fetch('/event/reader-json/' + eventId);
|
||||
const json = await response.json();
|
||||
if (DEBUG) {
|
||||
console.log('JSON complet reçu:', json);
|
||||
console.log('json.readers = ', json.readers);
|
||||
console.log('Array.isArray(json.readers) = ', Array.isArray(json.readers));
|
||||
}
|
||||
// MAJ du rate si tu changes plus tard dans DB
|
||||
refreshRate = json.refreshRate * 1000;
|
||||
|
||||
// Reconstruire les cartes
|
||||
let html = '';
|
||||
const readersRaw = json.readers ?? [];
|
||||
const readers = Array.isArray(readersRaw) ? readersRaw : Object.values(readersRaw);
|
||||
|
||||
readers.forEach(reader => {
|
||||
// Préparer les dates
|
||||
const start = new Date(reader.start_time * 1000)
|
||||
.toISOString().replace('T', ' ').substring(0, 19);
|
||||
|
||||
const end = new Date(reader.end_time * 1000)
|
||||
.toISOString().replace('T', ' ').substring(0, 19);
|
||||
|
||||
html += `
|
||||
<div class="p-4 gap-2.5 rounded-xl shadow-card" style="background-color:${reader.bg_color};">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="size-10 rounded-lg bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center">
|
||||
<span class="icon-[${reader.icon}] text-xl"></span>
|
||||
</div>
|
||||
<h5 class="text-1xl m-0">${reader.location}</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="px-3 py-1 text-sm text-black dark:text-white">Lectures</span>
|
||||
<span class="badge bg-green-500/10 text-sky-950">${reader.count}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="badge bg-green-500/10 text-amber-900">${start}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="badge bg-green-500/10 text-blue-500">${end}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
|
||||
// Injecter dans le DOM
|
||||
container.innerHTML = html;
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erreur AJAX Reader:', err);
|
||||
}
|
||||
|
||||
// Relancer après X secondes
|
||||
setTimeout(loadReaders, refreshRate);
|
||||
}
|
||||
|
||||
// Premier appel
|
||||
loadReaders();
|
||||
loadReaderTP();
|
||||
});
|
||||
|
||||
async function loadReaderTP() {
|
||||
try {
|
||||
const response = await fetch('/event/readertp-json/' + conId );
|
||||
const json = await response.json();
|
||||
|
||||
refreshRate = json.refreshRate * 1000;
|
||||
const process_status = json?.process_status ?? null;
|
||||
const containerTP = document.getElementById('readerstp-container');
|
||||
const listTP = json.readertimingpoint?.timingpoint ?? [];
|
||||
let html = '';
|
||||
|
||||
listTP.forEach(tp => {
|
||||
html += `
|
||||
<div class="p-3 gap-2.5 rounded-xl shadow-card bg-white dark:bg-zinc-900">
|
||||
<div class="flex flex-col">
|
||||
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h5 class="text-1xl m-0">${tp.tp_name}</h5>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="px-3 py-1 text-sm text-black dark:text-white">Lecture valide</span>
|
||||
<span class="badge bg-green-500/10 text-sky-950">${tp.lecture_count}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="px-3 py-1 text-sm text-black dark:text-white">Statut</span>
|
||||
|
||||
<span class="badge bg-green-500/10 text-amber-900">${process_status}</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
containerTP.innerHTML = html;
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erreur AJAX TP:', err);
|
||||
}
|
||||
|
||||
setTimeout(loadReaderTP, refreshRate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user