FUSIOONNNNN #1
@@ -5,7 +5,7 @@ body::before {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: url("../image/camera-image");
|
background-image: url("../image/camera-image.png");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
filter: blur(1px) brightness(0.3);
|
filter: blur(1px) brightness(0.3);
|
||||||
@@ -443,4 +443,30 @@ footer {
|
|||||||
.global_title_h1 {
|
.global_title_h1 {
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 10vh;
|
font-size: 10vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles pour les statuts des projets dans le carrousel */
|
||||||
|
.status-draft {
|
||||||
|
color: #6B8E23; /* Vert haricot/marron pour les brouillons */
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-capturing {
|
||||||
|
color: #87CEEB; /* Bleu ciel pour les projets en capture/en cours */
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-idle {
|
||||||
|
color: #32CD32; /* Vert vif pour les projets terminés */
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-stopping {
|
||||||
|
color: #FF4500; /* Orange rougeâtre pour les projets arrêtés */
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-unknown {
|
||||||
|
color: #cccccc; /* Gris pour les statuts inconnus */
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 285 KiB |
@@ -197,8 +197,10 @@ async function start_timelapse(id,frequency,nbimages){
|
|||||||
data: mydata
|
data: mydata
|
||||||
});
|
});
|
||||||
|
|
||||||
alert("data retrieval started:", response);
|
alert("Configuration de la caméra réussie");
|
||||||
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
alert("Erreur lors de la configuration de la caméra: " + error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,9 +218,36 @@ async function stopCamera(id){
|
|||||||
data: mydata
|
data: mydata
|
||||||
});
|
});
|
||||||
|
|
||||||
alert("Camera stopped succesfully :", response);
|
alert("La caméra a été arrêtée avec succès");
|
||||||
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert("Error stopping the camera :", error);
|
alert("Erreur lors de l'arrêt de la caméra : " + error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function manualUpload(imageFile, projectId, timestamp, temperature, humidity) {
|
||||||
|
try {
|
||||||
|
// Create FormData to send the file and metadata
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('image', imageFile);
|
||||||
|
formData.append('projectId', projectId);
|
||||||
|
formData.append('timestamp', timestamp);
|
||||||
|
formData.append('temperature', temperature);
|
||||||
|
formData.append('humidity', humidity);
|
||||||
|
|
||||||
|
const response = await $.ajax({
|
||||||
|
url: api_url.concat("/camera/upload"),
|
||||||
|
method: "POST",
|
||||||
|
data: formData,
|
||||||
|
processData: false, // Prevents jQuery from converting FormData to string
|
||||||
|
contentType: false, // Lets browser set the content type with boundary
|
||||||
|
});
|
||||||
|
|
||||||
|
alert("Image uploaded successfully");
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
alert("Error uploading image: " + error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,18 +9,57 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function formatDateToFrench(dateString) {
|
||||||
|
const options = {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
};
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString('fr-FR', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatStatusWithColor(status) {
|
||||||
|
let statusText = "";
|
||||||
|
let colorClass = "";
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 0:
|
||||||
|
statusText = "Brouillon";
|
||||||
|
colorClass = "status-draft";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
statusText = "En capture";
|
||||||
|
colorClass = "status-capturing";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
statusText = "Terminé";
|
||||||
|
colorClass = "status-idle";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
statusText = "En cours d\'arrêt";
|
||||||
|
colorClass = "status-stopping";
|
||||||
|
break; // Ajout du break manquant ici
|
||||||
|
default:
|
||||||
|
statusText = "Inconnu";
|
||||||
|
colorClass = "status-unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<span class="${colorClass}">${statusText}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
function formatStatus(status) {
|
function formatStatus(status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
return "brouillon";
|
return "Brouillon"; // Projet à peine créé, vide sans config
|
||||||
case 1:
|
case 1:
|
||||||
return "en cours";
|
return "En capture"; // Projet en cours de capture
|
||||||
case 2:
|
case 2:
|
||||||
return "terminé";
|
return "En pause"; // Projet en pause ou inactif
|
||||||
case 3:
|
case 3:
|
||||||
return "En cours de génération";
|
return "En cours d\'arrêt"; // Projet en cours d'arrêt
|
||||||
default:
|
default:
|
||||||
return "inconnu";
|
return "Inconnu";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,10 +130,10 @@ function setupCarousel(global_project_list) {
|
|||||||
projectDiv.classList.add(letter[index]);
|
projectDiv.classList.add(letter[index]);
|
||||||
projectDiv.innerHTML = `
|
projectDiv.innerHTML = `
|
||||||
<h2>${project.name}</h2>
|
<h2>${project.name}</h2>
|
||||||
<p>${formatDate(project.start_date)}</p>
|
<p><strong>Date de début :</strong> ${formatDateToFrench(project.start_date)}</p>
|
||||||
<p>Status : ${formatStatus(parseInt(project.status))}</p>
|
<p><strong>Statut :</strong> ${formatStatusWithColor(parseInt(project.status))}</p>
|
||||||
<div class="project_buttons">
|
<div class="project_buttons">
|
||||||
<button class="default-access-button">détails de ${project.name}</button>
|
<button class="default-access-button">Voir les détails</button>
|
||||||
<button class="default-delete-button">Supprimer</button>
|
<button class="default-delete-button">Supprimer</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -111,6 +150,14 @@ function setupCarousel(global_project_list) {
|
|||||||
deleteButton.addEventListener('click', (event) => {
|
deleteButton.addEventListener('click', (event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const projectName = project.name;
|
const projectName = project.name;
|
||||||
|
const projectStatus = parseInt(project.status);
|
||||||
|
|
||||||
|
// Vérifier si le projet est en cours de capture (statut 1) ou en cours d'arrêt (statut 3)
|
||||||
|
if (projectStatus === 1 || projectStatus === 3) {
|
||||||
|
alert(`Impossible de supprimer "${projectName}" car sa capture est ${projectStatus === 1 ? 'en cours' : 'en cours d\'arrêt'}.\nVeuillez d'abord arrêter la procédure de capture.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('alertMessage').textContent = `Veux-tu vraiment supprimer le projet : ${projectName} ?`;
|
document.getElementById('alertMessage').textContent = `Veux-tu vraiment supprimer le projet : ${projectName} ?`;
|
||||||
document.getElementById('customAlert').style.display = 'block';
|
document.getElementById('customAlert').style.display = 'block';
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,40 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
const firstInput = document.getElementById("first");
|
const firstInput = document.getElementById("first");
|
||||||
const lastInput = document.getElementById("last");
|
const lastInput = document.getElementById("last");
|
||||||
|
|
||||||
|
const formContainerUpload = document.getElementById("form-container-upload");
|
||||||
|
const showFormButtonUpload = document.getElementById("show-form-button-upload");
|
||||||
|
const closeFormButtonUpload = document.getElementById("close-form-button-upload");
|
||||||
|
const manualUploadForm = document.getElementById("manual-upload-form");
|
||||||
|
|
||||||
|
if (formContainerUpload && showFormButtonUpload && closeFormButtonUpload && manualUploadForm) {
|
||||||
|
showFormButtonUpload.addEventListener("click", () => {
|
||||||
|
formContainerUpload.style.display = "flex";
|
||||||
|
});
|
||||||
|
|
||||||
|
closeFormButtonUpload.addEventListener("click", () => {
|
||||||
|
formContainerUpload.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
manualUploadForm.addEventListener("submit", async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const imageFile = document.getElementById("imageFile").files[0];
|
||||||
|
const temperature = document.getElementById("temperature").value;
|
||||||
|
const humidity = document.getElementById("humidity").value;
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await manualUpload(imageFile, projectId, timestamp, temperature, humidity);
|
||||||
|
alert("Image uploadée avec succès !");
|
||||||
|
formContainerUpload.style.display = "none";
|
||||||
|
} catch (error) {
|
||||||
|
alert("Erreur lors de l'upload de l'image : " + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Un ou plusieurs éléments du formulaire d'upload manuel sont introuvables.");
|
||||||
|
}
|
||||||
|
|
||||||
let selectedNumbers = [];
|
let selectedNumbers = [];
|
||||||
|
|
||||||
populateTimelapseLogic(start_timelapse_button, projectId).then(() => {
|
populateTimelapseLogic(start_timelapse_button, projectId).then(() => {
|
||||||
@@ -51,10 +85,14 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
const minutes = document.getElementById("minutes").value;
|
const minutes = document.getElementById("minutes").value;
|
||||||
const frequency = days * 1440 + hours * 60 + minutes;
|
const frequency = days * 1440 + hours * 60 + minutes;
|
||||||
if(frequency >= 3) {
|
if(frequency >= 3) {
|
||||||
const nbrimages = document.getElementById("totalImages").value;
|
const nbrimages = document.getElementById("totalImages").value;
|
||||||
start_timelapse(projectId, frequency, nbrimages).then(() => {
|
try {
|
||||||
|
// Attendre que la requête API soit terminée avant de recharger la page
|
||||||
|
await start_timelapse(projectId, frequency, nbrimages);
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
} catch (error) {
|
||||||
|
console.error("Erreur lors du démarrage du timelapse:", error);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert("La fréquence doit être supérieure à 3 minutes !");
|
alert("La fréquence doit être supérieure à 3 minutes !");
|
||||||
}
|
}
|
||||||
@@ -64,8 +102,13 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
document
|
document
|
||||||
.getElementById("stop-camera")
|
.getElementById("stop-camera")
|
||||||
.addEventListener("click", async () => {
|
.addEventListener("click", async () => {
|
||||||
stopCamera(projectId);
|
try {
|
||||||
location.reload();
|
// Attendre que la requête API soit terminée avant de recharger la page
|
||||||
|
await stopCamera(projectId);
|
||||||
|
location.reload();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de l'arrêt de la caméra:", error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -345,24 +388,44 @@ async function generateViewMetric(projectId) {
|
|||||||
if (measurements != 404) {
|
if (measurements != 404) {
|
||||||
let samples;
|
let samples;
|
||||||
if (videoId != -1) {
|
if (videoId != -1) {
|
||||||
currentVideoDatas = await getDataVideoFromApi(videoId);
|
try {
|
||||||
samples = JSON.parse(currentVideoDatas[0]["measurement_ids"]);
|
console.log("videoId", videoId);
|
||||||
if (currentVideoDatas[0].status != 0) {
|
currentVideoDatas = await getDataVideoFromApi(videoId);
|
||||||
videoPlaceHolder.innerHTML = `
|
console.log("currentVideoDatas", currentVideoDatas);
|
||||||
<video class="video" controls>
|
// Vérifier que currentVideoDatas existe et contient au moins un élément
|
||||||
<source src="${api_url}/videos/file/${videoId}" type="video/mp4">
|
if (currentVideoDatas) {
|
||||||
Your browser does not support the video tag.
|
samples = JSON.parse(currentVideoDatas["measurement_ids"]);
|
||||||
</video>`;
|
if (currentVideoDatas.status != 0) {
|
||||||
} else {
|
videoPlaceHolder.innerHTML = `
|
||||||
videoPlaceHolder.innerHTML = `<h2>La vidéo n'a pas été rendered</h2>`;
|
<video class="video" controls>
|
||||||
|
<source src="${api_url}/videos/file/${videoId}" type="video/mp4">
|
||||||
|
Your browser does not support the video tag.
|
||||||
|
</video>`;
|
||||||
|
} else {
|
||||||
|
videoPlaceHolder.innerHTML = `<h2>La vidéo n'a pas été rendered</h2>`;
|
||||||
|
}
|
||||||
|
deletePlaceHolder.innerHTML = `
|
||||||
|
<button id="delete-video" class="default-delete-button" data-video-id="${videoId}">Delete Video</button>
|
||||||
|
`;
|
||||||
|
document.getElementById("delete-video").addEventListener("click", () => {
|
||||||
|
showConfirmationAlert(videoId);
|
||||||
|
});
|
||||||
|
tempoMeasure = filterAndSortMeasurementsByNumber(measurements, samples);
|
||||||
|
} else {
|
||||||
|
// Si aucune donnée n'est disponible pour cette vidéo
|
||||||
|
console.warn("Aucune donnée disponible pour la vidéo sélectionnée");
|
||||||
|
deletePlaceHolder.innerHTML = "";
|
||||||
|
videoPlaceHolder.innerHTML = `<h2>Données de vidéo non disponibles</h2>`;
|
||||||
|
samples = measurements.map((measurement) => measurement.id);
|
||||||
|
tempoMeasure = filterAndSortMeasurementsByIds(measurements, samples);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la récupération des données vidéo:", error);
|
||||||
|
deletePlaceHolder.innerHTML = "";
|
||||||
|
videoPlaceHolder.innerHTML = `<h2>Erreur lors de la récupération des données vidéo</h2>`;
|
||||||
|
samples = measurements.map((measurement) => measurement.id);
|
||||||
|
tempoMeasure = filterAndSortMeasurementsByIds(measurements, samples);
|
||||||
}
|
}
|
||||||
deletePlaceHolder.innerHTML = `
|
|
||||||
<button id="delete-video" class="default-delete-button" data-video-id="${videoId}">Delete Video</button>
|
|
||||||
`;
|
|
||||||
document.getElementById("delete-video").addEventListener("click", () => {
|
|
||||||
showConfirmationAlert(videoId);
|
|
||||||
});
|
|
||||||
tempoMeasure = filterAndSortMeasurementsByNumber(measurements, samples);
|
|
||||||
} else {
|
} else {
|
||||||
deletePlaceHolder.innerHTML = "";
|
deletePlaceHolder.innerHTML = "";
|
||||||
videoPlaceHolder.innerHTML = "";
|
videoPlaceHolder.innerHTML = "";
|
||||||
@@ -496,10 +559,19 @@ function filterAndSortMeasurementsByNumber(measurements, Numbers) {
|
|||||||
|
|
||||||
function checkVideoPath(videos, name) {
|
function checkVideoPath(videos, name) {
|
||||||
let res = true;
|
let res = true;
|
||||||
videos.forEach((video) => {
|
|
||||||
const videoName = video.name;
|
// Vérifier si videos est un tableau et s'il a une méthode forEach
|
||||||
if (videoName == name) res = false;
|
if (videos && Array.isArray(videos) && videos.length > 0) {
|
||||||
});
|
videos.forEach((video) => {
|
||||||
|
const videoName = video.name;
|
||||||
|
if (videoName == name) res = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Si videos n'est pas un tableau valide, on considère qu'aucune vidéo n'existe
|
||||||
|
// et donc n'importe quel nom est valide
|
||||||
|
console.log("Aucune vidéo existante détectée");
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,6 +612,16 @@ async function populateTimelapseLogic(placeholder, id) {
|
|||||||
placeholder.innerHTML = `<button class="default-delete-button" id="stop-camera">
|
placeholder.innerHTML = `<button class="default-delete-button" id="stop-camera">
|
||||||
<span> Stopper la prise d'images </span>
|
<span> Stopper la prise d'images </span>
|
||||||
</button>`;
|
</button>`;
|
||||||
|
} else if (data.status == 2) {
|
||||||
|
// Ajout de la possibilité de configurer la caméra pour un projet avec statut "terminé"
|
||||||
|
placeholder.innerHTML = `<button class="default-button" id="show-form-button-project">
|
||||||
|
<span> Reconfigurer la caméra </span>
|
||||||
|
</button>`;
|
||||||
|
} else if (data.status == 3) {
|
||||||
|
// Affichage d'un message pour indiquer que l'arrêt est en cours
|
||||||
|
placeholder.innerHTML = `<button class="default-button" disabled>
|
||||||
|
<span> Arrêt en cours... </span>
|
||||||
|
</button>`;
|
||||||
} else {
|
} else {
|
||||||
placeholder.innerHTML = ``;
|
placeholder.innerHTML = ``;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,27 @@
|
|||||||
<button id="commencer" class="default-access-button">Lancer</button>
|
<button id="commencer" class="default-access-button">Lancer</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Formulaire pour l'upload manuel d'une image -->
|
||||||
|
<div id="form-container-upload" class="form-container" style="display: none">
|
||||||
|
<div class="form-content">
|
||||||
|
<div class="form-header">
|
||||||
|
<button id="close-form-button-upload" class="default-delete-button">✕</button>
|
||||||
|
</div>
|
||||||
|
<h1>Upload Manuel</h1>
|
||||||
|
<form id="manual-upload-form">
|
||||||
|
<label for="imageFile">Fichier image :</label>
|
||||||
|
<input type="file" id="imageFile" name="imageFile" accept="image/*" required />
|
||||||
|
<br /><br />
|
||||||
|
<label for="temperature">Température :</label>
|
||||||
|
<input type="number" id="temperature" name="temperature" step="0.1" required />
|
||||||
|
<br /><br />
|
||||||
|
<label for="humidity">Humidité :</label>
|
||||||
|
<input type="number" id="humidity" name="humidity" step="0.1" required />
|
||||||
|
<br /><br />
|
||||||
|
<button type="submit" class="default-access-button">Uploader</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- page classique -->
|
<!-- page classique -->
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@@ -118,6 +139,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="start-timelapse"></div>
|
<div id="start-timelapse"></div>
|
||||||
<button class="default-access-button" id="show-form-button-camera">+</button>
|
<button class="default-access-button" id="show-form-button-camera">+</button>
|
||||||
|
<button class="default-access-button" id="show-form-button-upload">Upload Manuel</button>
|
||||||
<div id="delete-placeholder"></div>
|
<div id="delete-placeholder"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user