4 pages de détail avec courbe (Canvas), navigation depuis home.qml, sélecteurs de variable pour circuits/batteries
@@ -2,7 +2,6 @@
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
@@ -10,51 +9,90 @@ DataProvider::DataProvider(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DataProvider::signalerSucces()
|
||||
{
|
||||
m_connecte = true;
|
||||
m_derniereConnexionReussie = QDateTime::currentDateTime();
|
||||
emit etatConnexionChange();
|
||||
}
|
||||
|
||||
void DataProvider::signalerEchec()
|
||||
{
|
||||
if (m_connecte) {
|
||||
m_connecte = false;
|
||||
emit etatConnexionChange();
|
||||
}
|
||||
}
|
||||
|
||||
void DataProvider::get_familles(const QString &type)
|
||||
{
|
||||
if (m_replyFamillesEnCours) m_replyFamillesEnCours->abort();
|
||||
|
||||
QUrl url(m_baseUrl + "/elements/familles");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("type", type);
|
||||
url.setQuery(query);
|
||||
|
||||
auto reply = m_manager.get(QNetworkRequest(url));
|
||||
QNetworkRequest request(url);
|
||||
request.setTransferTimeout(5000);
|
||||
|
||||
auto reply = m_manager.get(request);
|
||||
m_replyFamillesEnCours = reply;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, type]() {
|
||||
reply->deleteLater();
|
||||
if (m_replyFamillesEnCours == reply) m_replyFamillesEnCours = nullptr;
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError) return;
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
return;
|
||||
}
|
||||
const auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
const auto obj = doc.object();
|
||||
if (obj["status"].toString() != "ok") {
|
||||
signalerEchec();
|
||||
emit erreur(obj["message"].toString());
|
||||
return;
|
||||
}
|
||||
signalerSucces();
|
||||
emit famillesRecues(type, obj["familles"].toArray());
|
||||
});
|
||||
}
|
||||
|
||||
void DataProvider::get_elements(const QString &type, int famille)
|
||||
{
|
||||
if (m_replyElementsEnCours) m_replyElementsEnCours->abort();
|
||||
|
||||
QUrl url(m_baseUrl + "/elements");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("type", type);
|
||||
query.addQueryItem("famille", QString::number(famille));
|
||||
url.setQuery(query);
|
||||
|
||||
auto reply = m_manager.get(QNetworkRequest(url));
|
||||
QNetworkRequest request(url);
|
||||
request.setTransferTimeout(5000);
|
||||
|
||||
auto reply = m_manager.get(request);
|
||||
m_replyElementsEnCours = reply;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, type, famille]() {
|
||||
reply->deleteLater();
|
||||
if (m_replyElementsEnCours == reply) m_replyElementsEnCours = nullptr;
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError) return;
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
return;
|
||||
}
|
||||
const auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
const auto obj = doc.object();
|
||||
if (obj["status"].toString() != "ok") {
|
||||
signalerEchec();
|
||||
emit erreur(obj["message"].toString());
|
||||
return;
|
||||
}
|
||||
signalerSucces();
|
||||
emit elementsRecus(type, famille, obj["elements"].toArray());
|
||||
});
|
||||
}
|
||||
@@ -64,6 +102,7 @@ void DataProvider::set_circuit(int id, int consigne)
|
||||
QUrl url(m_baseUrl + "/elements/circuit/" + QString::number(id));
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setTransferTimeout(5000);
|
||||
|
||||
QJsonObject body;
|
||||
body["consigne"] = consigne;
|
||||
@@ -73,7 +112,50 @@ void DataProvider::set_circuit(int id, int consigne)
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, id]() {
|
||||
reply->deleteLater();
|
||||
const bool succes = (reply->error() == QNetworkReply::NoError);
|
||||
if (!succes) emit erreur(reply->errorString());
|
||||
if (succes) signalerSucces();
|
||||
else {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
}
|
||||
emit circuitModifie(id, succes);
|
||||
});
|
||||
}
|
||||
|
||||
void DataProvider::get_mesures(const QString &type, int id, int periode, const QString &variable)
|
||||
{
|
||||
if (m_replyMesuresEnCours) m_replyMesuresEnCours->abort();
|
||||
|
||||
QUrl url(m_baseUrl + "/mesures");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("type", type);
|
||||
query.addQueryItem("id", QString::number(id));
|
||||
query.addQueryItem("periode", QString::number(periode));
|
||||
if (!variable.isEmpty()) query.addQueryItem("variable", variable);
|
||||
url.setQuery(query);
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setTransferTimeout(8000); // Requête potentiellement plus lourde (jusqu'à 200 points) qu'un simple /elements - délai un peu plus généreux.
|
||||
|
||||
auto reply = m_manager.get(request);
|
||||
m_replyMesuresEnCours = reply;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, type, id, periode, variable]() {
|
||||
reply->deleteLater();
|
||||
if (m_replyMesuresEnCours == reply) m_replyMesuresEnCours = nullptr;
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError) return;
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
return;
|
||||
}
|
||||
const auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
const auto obj = doc.object();
|
||||
if (obj["status"].toString() != "ok") {
|
||||
signalerEchec();
|
||||
emit erreur(obj["message"].toString());
|
||||
return;
|
||||
}
|
||||
signalerSucces();
|
||||
emit mesuresRecues(type, id, periode, variable, obj);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QDateTime>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
// ============================================================================
|
||||
// DataProvider - couche d'accès aux données du client WASM (cas 2/3).
|
||||
@@ -11,13 +15,23 @@
|
||||
// HTTP/JSON est encapsulée ici - le QML ne voit que des signaux avec des
|
||||
// tableaux déjà prêts à l'emploi.
|
||||
//
|
||||
// Portée actuelle : les 4 domaines (circuit, batterie, capteur, reservoir)
|
||||
// en lecture, écriture (consigne/mode auto) sur circuit uniquement.
|
||||
// Portée actuelle : les 4 domaines (circuits, batteries, capteurs, reservoirs)
|
||||
// en lecture, écriture (consigne/mode auto) sur circuits uniquement, et
|
||||
// désormais l'historique/courbe (capteurs uniquement pour l'instant, cf
|
||||
// GET /mesures côté API).
|
||||
//
|
||||
// Suit également l'état de connexion (succès/échec de chaque requête) pour
|
||||
// permettre à l'UI d'afficher un état "hors ligne" explicite plutôt que de
|
||||
// laisser les listes silencieusement vides ou figées.
|
||||
// ============================================================================
|
||||
class DataProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool connecte READ connecte NOTIFY etatConnexionChange)
|
||||
Q_PROPERTY(bool aDejaEteConnecte READ aDejaEteConnecte NOTIFY etatConnexionChange)
|
||||
Q_PROPERTY(QDateTime derniereConnexionReussie READ derniereConnexionReussie NOTIFY etatConnexionChange)
|
||||
|
||||
public:
|
||||
explicit DataProvider(QObject *parent = nullptr);
|
||||
|
||||
@@ -30,16 +44,34 @@ public:
|
||||
// Écriture rapide sur un circuit (bouton d'accueil) - PATCH /elements/circuit/<id>.
|
||||
Q_INVOKABLE void set_circuit(int id, int consigne);
|
||||
|
||||
// Historique/courbe pour la page de détail - GET /mesures.
|
||||
// periode : 0=1h, 1=24h, 2=7j, 3=30j (même convention que le natif).
|
||||
// variable : requis pour circuits/batteries (sélecteur de variable côté
|
||||
// client), ignoré pour capteurs/reservoirs (variable fixe côté serveur).
|
||||
Q_INVOKABLE void get_mesures(const QString &type, int id, int periode, const QString &variable = QString());
|
||||
|
||||
bool connecte() const { return m_connecte; }
|
||||
bool aDejaEteConnecte() const { return m_derniereConnexionReussie.isValid(); }
|
||||
QDateTime derniereConnexionReussie() const { return m_derniereConnexionReussie; }
|
||||
|
||||
signals:
|
||||
// Le type (et, pour les éléments, la famille) sont désormais inclus dans
|
||||
// chaque signal - indispensable avec plusieurs domaines actifs en
|
||||
// parallèle, pour que le QML sache à quelle réponse il a affaire.
|
||||
void famillesRecues(const QString &type, const QJsonArray &familles);
|
||||
void elementsRecus(const QString &type, int famille, const QJsonArray &elements);
|
||||
void circuitModifie(int id, bool succes);
|
||||
void mesuresRecues(const QString &type, int id, int periode, const QString &variable, const QJsonObject &donnees);
|
||||
void erreur(const QString &message);
|
||||
void etatConnexionChange();
|
||||
|
||||
private:
|
||||
void signalerSucces();
|
||||
void signalerEchec();
|
||||
|
||||
QNetworkAccessManager m_manager;
|
||||
QString m_baseUrl = QStringLiteral("https://api.ship2net.fr");
|
||||
bool m_connecte = false;
|
||||
QDateTime m_derniereConnexionReussie;
|
||||
|
||||
QNetworkReply *m_replyFamillesEnCours = nullptr;
|
||||
QNetworkReply *m_replyElementsEnCours = nullptr;
|
||||
QNetworkReply *m_replyMesuresEnCours = nullptr;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "dataprovider.h"
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
DataProvider::DataProvider(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DataProvider::signalerSucces()
|
||||
{
|
||||
m_connecte = true;
|
||||
m_derniereConnexionReussie = QDateTime::currentDateTime();
|
||||
emit etatConnexionChange();
|
||||
}
|
||||
|
||||
void DataProvider::signalerEchec()
|
||||
{
|
||||
// Ne touche JAMAIS m_derniereConnexionReussie ici : on veut garder la
|
||||
// trace du dernier succès réel, pas la remplacer par l'instant de l'échec.
|
||||
if (m_connecte) {
|
||||
m_connecte = false;
|
||||
emit etatConnexionChange();
|
||||
}
|
||||
}
|
||||
|
||||
void DataProvider::get_familles(const QString &type)
|
||||
{
|
||||
if (m_replyFamillesEnCours) {
|
||||
m_replyFamillesEnCours->abort(); // Requête précédente encore en attente : remplacée par celle-ci
|
||||
}
|
||||
|
||||
QUrl url(m_baseUrl + "/elements/familles");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("type", type);
|
||||
url.setQuery(query);
|
||||
|
||||
QNetworkRequest request(url);
|
||||
// Sans délai explicite, une requête vers un CM5 devenu injoignable peut
|
||||
// rester en attente indéfiniment côté navigateur (ni succès ni échec) -
|
||||
// 'finished' ne se déclencherait alors jamais, empêchant toute détection
|
||||
// de perte de connexion.
|
||||
request.setTransferTimeout(TIME_OUT_TRANSFER_DATA);
|
||||
|
||||
auto reply = m_manager.get(request);
|
||||
m_replyFamillesEnCours = reply;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, type]() {
|
||||
reply->deleteLater();
|
||||
if (m_replyFamillesEnCours == reply) m_replyFamillesEnCours = nullptr;
|
||||
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError) {
|
||||
return; // Annulée volontairement (remplacée par une requête plus récente) - pas un vrai échec réseau
|
||||
}
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
return;
|
||||
}
|
||||
const auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
const auto obj = doc.object();
|
||||
if (obj["status"].toString() != "ok") {
|
||||
signalerEchec();
|
||||
emit erreur(obj["message"].toString());
|
||||
return;
|
||||
}
|
||||
signalerSucces();
|
||||
emit famillesRecues(type, obj["familles"].toArray());
|
||||
});
|
||||
}
|
||||
|
||||
void DataProvider::get_elements(const QString &type, int famille)
|
||||
{
|
||||
if (m_replyElementsEnCours) {
|
||||
m_replyElementsEnCours->abort();
|
||||
}
|
||||
|
||||
QUrl url(m_baseUrl + "/elements");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("type", type);
|
||||
query.addQueryItem("famille", QString::number(famille));
|
||||
url.setQuery(query);
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setTransferTimeout(TIME_OUT_TRANSFER_DATA);
|
||||
|
||||
auto reply = m_manager.get(request);
|
||||
m_replyElementsEnCours = reply;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, type, famille]() {
|
||||
reply->deleteLater();
|
||||
if (m_replyElementsEnCours == reply) m_replyElementsEnCours = nullptr;
|
||||
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError) {
|
||||
return;
|
||||
}
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
return;
|
||||
}
|
||||
const auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
const auto obj = doc.object();
|
||||
if (obj["status"].toString() != "ok") {
|
||||
signalerEchec();
|
||||
emit erreur(obj["message"].toString());
|
||||
return;
|
||||
}
|
||||
signalerSucces();
|
||||
emit elementsRecus(type, famille, obj["elements"].toArray());
|
||||
});
|
||||
}
|
||||
|
||||
void DataProvider::set_circuit(int id, int consigne)
|
||||
{
|
||||
QUrl url(m_baseUrl + "/elements/circuit/" + QString::number(id));
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setTransferTimeout(TIME_OUT_TRANSFER_DATA);
|
||||
|
||||
QJsonObject body;
|
||||
body["consigne"] = consigne;
|
||||
const QByteArray data = QJsonDocument(body).toJson();
|
||||
|
||||
auto reply = m_manager.sendCustomRequest(request, "PATCH", data);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, id]() {
|
||||
reply->deleteLater();
|
||||
const bool succes = (reply->error() == QNetworkReply::NoError);
|
||||
if (succes) signalerSucces();
|
||||
else {
|
||||
signalerEchec();
|
||||
emit erreur(reply->errorString());
|
||||
}
|
||||
emit circuitModifie(id, succes);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QJsonArray>
|
||||
#include <QDateTime>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
// ============================================================================
|
||||
// DataProvider - couche d'accès aux données du client WASM (cas 2/3).
|
||||
// ----------------------------------------------------------------------------
|
||||
// Remplace, pour les domaines déjà portés, les appels bdd.* directs du cas 1
|
||||
// (qui reste inchangé, cf décision §21.1 de la synthèse). Toute la logique
|
||||
// HTTP/JSON est encapsulée ici - le QML ne voit que des signaux avec des
|
||||
// tableaux déjà prêts à l'emploi.
|
||||
//
|
||||
// Portée actuelle : les 4 domaines (circuit, batterie, capteur, reservoir)
|
||||
// en lecture, écriture (consigne/mode auto) sur circuit uniquement.
|
||||
//
|
||||
// Suit également l'état de connexion (succès/échec de chaque requête) pour
|
||||
// permettre à l'UI d'afficher un état "hors ligne" explicite plutôt que de
|
||||
// laisser les listes silencieusement vides ou figées (cf synthèse, gestion
|
||||
// du hors-ligne).
|
||||
// ============================================================================
|
||||
|
||||
#define TIME_OUT_TRANSFER_DATA 5000 // En ms
|
||||
|
||||
|
||||
class DataProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool connecte READ connecte NOTIFY etatConnexionChange)
|
||||
Q_PROPERTY(bool aDejaEteConnecte READ aDejaEteConnecte NOTIFY etatConnexionChange)
|
||||
Q_PROPERTY(QDateTime derniereConnexionReussie READ derniereConnexionReussie NOTIFY etatConnexionChange)
|
||||
|
||||
public:
|
||||
explicit DataProvider(QObject *parent = nullptr);
|
||||
|
||||
// TODO : rendre l'adresse de base configurable (IP locale du CM5 en cas 2,
|
||||
// domaine VPS en cas 3 - cf QR code d'accès, §"Architecture cible"/Cas 2-3
|
||||
// de la synthèse) - en dur sur le relais VPS pour cette étape.
|
||||
Q_INVOKABLE void get_familles(const QString &type);
|
||||
Q_INVOKABLE void get_elements(const QString &type, int famille);
|
||||
|
||||
// Écriture rapide sur un circuit (bouton d'accueil) - PATCH /elements/circuit/<id>.
|
||||
Q_INVOKABLE void set_circuit(int id, int consigne);
|
||||
|
||||
bool connecte() const { return m_connecte; }
|
||||
bool aDejaEteConnecte() const { return m_derniereConnexionReussie.isValid(); }
|
||||
QDateTime derniereConnexionReussie() const { return m_derniereConnexionReussie; }
|
||||
|
||||
signals:
|
||||
// Le type (et, pour les éléments, la famille) sont désormais inclus dans
|
||||
// chaque signal - indispensable avec plusieurs domaines actifs en
|
||||
// parallèle, pour que le QML sache à quelle réponse il a affaire.
|
||||
void famillesRecues(const QString &type, const QJsonArray &familles);
|
||||
void elementsRecus(const QString &type, int famille, const QJsonArray &elements);
|
||||
void circuitModifie(int id, bool succes);
|
||||
void erreur(const QString &message);
|
||||
void etatConnexionChange();
|
||||
|
||||
private:
|
||||
void signalerSucces();
|
||||
void signalerEchec();
|
||||
|
||||
QNetworkAccessManager m_manager;
|
||||
QString m_baseUrl = QStringLiteral("https://api.ship2net.fr");
|
||||
bool m_connecte = false;
|
||||
QDateTime m_derniereConnexionReussie; // invalide (isValid()==false) tant qu'aucun succès n'a jamais eu lieu
|
||||
|
||||
// Requête en cours par type d'appel (familles/éléments) - permet d'annuler
|
||||
// une requête encore en vol avant d'en émettre une nouvelle, pour éviter
|
||||
// qu'une réponse "en retard" (envoyée pendant une coupure, résolue après
|
||||
// qu'une requête plus récente ait déjà réussi) ne fasse clignoter l'état
|
||||
// de connexion après une reconnexion.
|
||||
QNetworkReply *m_replyFamillesEnCours = nullptr;
|
||||
QNetworkReply *m_replyElementsEnCours = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
powershell -ExecutionPolicy Bypass -File "%~dp0deploy_wasm.ps1"
|
||||
|
||||
@@ -11,12 +11,10 @@
|
||||
# ============================================================================
|
||||
|
||||
param(
|
||||
[string]$BuildDir = "O:\Technique\Projets_Qt\koriolan\shipheart_wasm\build\WebAssembly_Qt_6_8_3_Release",
|
||||
[string]$AssetsDir = "O:\Technique\Projets_Qt\koriolan\shipheart_wasm\deploy", # manifest.json, icônes, sw.js "modèle" (CACHE_NAME sans version)
|
||||
[string]$CM5Host = "192.168.1.220",
|
||||
[int]$CM5Port = 2022,
|
||||
[string]$CM5User = "koriolan",
|
||||
[string]$CM5Path = "/var/www/shipheart-poc-wasm/"
|
||||
[string]$BuildDir = "C:\Users\pierr\KORIOLAN\Koriolan - Documents\Technique\Projets_Qt\koriolan\shipheart_wasm\build\WebAssembly_Qt_6_8_3_Release",
|
||||
[string]$AssetsDir = "C:\Users\pierr\KORIOLAN\Koriolan - Documents\Technique\Projets_Qt\koriolan\shipheart_wasm\deploy",
|
||||
[string]$CM5Alias = "cm5", # alias défini dans %USERPROFILE%\.ssh\config
|
||||
[string]$CM5Path = "/var/www/shipheart-wasm/"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
@@ -44,6 +42,32 @@ if ('serviceWorker' in navigator) {
|
||||
"@
|
||||
Set-Content "$BuildDir\index.html" $html -NoNewline
|
||||
|
||||
# --- 2bis. Remplacer l'écran de chargement Qt par défaut (logo Qt + texte
|
||||
# technique "Qt for WebAssembly: ...") par un écran plus sobre, réutilisant
|
||||
# l'icône de l'app déjà déployée. Fait ici plutôt que via une configuration
|
||||
# CMake dédiée : plusieurs retours d'expérience Qt confirment que Qt Creator
|
||||
# régénère de toute façon le HTML par défaut au build, quelle que soit la
|
||||
# tentative de template personnalisé côté CMake - rester sur ce mécanisme de
|
||||
# post-traitement, déjà fiable pour le manifest/service-worker, est plus sûr.
|
||||
$html = Get-Content "$BuildDir\index.html" -Raw
|
||||
$ancienSpinner = '(?s)<figure[^>]*id="qtspinner">.*?</figure>'
|
||||
$nouveauSpinner = @"
|
||||
<figure style="overflow:visible;" id="qtspinner">
|
||||
<center style="margin-top:1.5em; line-height:150%; font-family: sans-serif; color: rgb(0 118 154);">
|
||||
<img src="icon-512.png" style="display:block; margin:0 auto; max-width:55vw; max-height:55vh; width:auto; height:auto;">
|
||||
<p style="margin-bottom: 5%;">
|
||||
<strong>ShipHeart™</strong>
|
||||
<br />
|
||||
by Koriolan
|
||||
</p>
|
||||
<div id="qtstatus"></div>
|
||||
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
|
||||
</center>
|
||||
</figure>
|
||||
"@
|
||||
$html = $html -replace $ancienSpinner, $nouveauSpinner
|
||||
Set-Content "$BuildDir\index.html" $html -NoNewline
|
||||
|
||||
# --- 3. Versionner sw.js (change le CACHE_NAME à chaque déploiement) ---
|
||||
# Le fichier "modèle" (CACHE_NAME générique) vit dans $AssetsDir, sous
|
||||
# contrôle de version - on ne le modifie jamais sur place, on écrit la
|
||||
@@ -60,7 +84,7 @@ Copy-Item "$AssetsDir\icon-512.png" "$BuildDir\icon-512.png" -Force
|
||||
|
||||
$fichiers = "index.html","qtloader.js","qtlogo.svg","shipheart_wasm.js","shipheart_wasm.wasm","shipheart_wasm.worker.js","sw.js","manifest.json","icon-192.png","icon-512.png"
|
||||
foreach ($f in $fichiers) {
|
||||
scp -P $CM5Port "$BuildDir\$f" "${CM5User}@${CM5Host}:${CM5Path}"
|
||||
scp "$BuildDir\$f" "${CM5Alias}:${CM5Path}"
|
||||
}
|
||||
|
||||
Write-Host "Déploiement terminé - version $version"
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 23 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ShipHeart (POC WASM)",
|
||||
"short_name": "ShipHeart POC",
|
||||
"description": "POC d'accès à ShipHeart via WebAssembly - jusqu'à home_accueil.qml",
|
||||
"name": "ShipHeart",
|
||||
"short_name": "ShipHeart",
|
||||
"description": "Accès à distance à ShipHeart",
|
||||
"start_url": "./index.html",
|
||||
"display": "fullscreen",
|
||||
"orientation": "landscape",
|
||||
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 596 B |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.1 KiB |