Upload-Serie: Screen-Aus bricht nicht mehr ab, Duplikate erkannt [deploy]
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 16s
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 16s
Schaltet sich das Display waehrend einer Foto-Serie ab, friert der Browser die laufenden fetch-Aufrufe ein — die halbe Serie blieb liegen, der zweite Anlauf erzeugte Duplikate (28.08.2026, Auftrag PROV105: 11 doppelte Fotos). - Wake Lock waehrend syncQueue(), inkl. Neuanforderung nach App-Wechsel (visibilitychange). Scheitert die Anforderung, laeuft der Sync unveraendert weiter — die Queue faengt Abbrueche ohnehin ab - duplicate:true aus der Server-Antwort wandert durch das photo-uploaded-Event; die Miniatur zeigt dann „War schon hochgeladen" statt eines zweiten Fotos - api.js: Kommentar auf den neuen Server-Vertrag gebracht (Bericht 1.6.0 legt identische Dateien nicht erneut ab, at-least-once bleibt Rueckfallebene) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
10d5f915df
commit
65bc09d9f1
3 changed files with 38 additions and 3 deletions
2
app.js
2
app.js
|
|
@ -3117,6 +3117,8 @@ async function openCameraModal(orderId) {
|
|||
if (d.relpath) thumb.dataset.relpath = d.relpath;
|
||||
thumb.classList.remove('pending', 'saving');
|
||||
thumb.classList.add('done');
|
||||
// Server hatte das Bild schon (Wiederholung nach Abbruch): kein Fehler, nur Hinweis
|
||||
if (d.duplicate) thumb.title = 'War schon hochgeladen';
|
||||
}
|
||||
window.addEventListener('photo-uploaded', onUploaded);
|
||||
|
||||
|
|
|
|||
|
|
@ -113,9 +113,11 @@
|
|||
|
||||
// Semantik: at-least-once. Geht die Server-Antwort NACH dem Speichern verloren
|
||||
// (z.B. Netz-Abbruch, Proxy-2xx-HTML), gilt der Upload als unbestätigt und wird
|
||||
// wiederholt → das Foto kann dadurch doppelt auf dem Server landen (der Dateiname
|
||||
// enthält uniqid(), es wird also nicht überschrieben). Bewusst gewählt: lieber ein
|
||||
// löschbares Duplikat als ein verlorenes Foto.
|
||||
// wiederholt. Der Server vergleicht seit Bericht 1.6.0 den Inhalt (md5) gegen die
|
||||
// Dateien im Auftragsordner und legt eine identische Datei kein zweites Mal ab —
|
||||
// er antwortet dann mit duplicate:true und dem relpath der vorhandenen Datei.
|
||||
// Die Wiederholung ist damit idempotent statt duplikaterzeugend; die Regel „lieber
|
||||
// ein Duplikat als ein verlorenes Foto" gilt weiterhin als Rückfallebene.
|
||||
async function uploadOrderPhoto(orderId, fileBlob, filename) {
|
||||
const fd = new FormData();
|
||||
fd.append('file', fileBlob, filename || 'photo.jpg');
|
||||
|
|
|
|||
|
|
@ -51,12 +51,41 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
// Screen wachhalten, solange Uploads laufen. Schaltet sich das Display waehrend einer
|
||||
// Foto-Serie ab, friert der Browser die laufenden fetch-Aufrufe ein und der Rest der
|
||||
// Serie bleibt liegen (real am 28.08.2026: halbe Serie kam nicht an, der zweite Anlauf
|
||||
// erzeugte dann Duplikate). Scheitert die Anforderung (Akkusparmodus, alter Browser),
|
||||
// laeuft der Sync unveraendert weiter — die Queue faengt den Abbruch ohnehin ab.
|
||||
let wakeLock = null;
|
||||
|
||||
async function acquireWakeLock() {
|
||||
try {
|
||||
if (!navigator.wakeLock || wakeLock) return;
|
||||
wakeLock = await navigator.wakeLock.request('screen');
|
||||
wakeLock.addEventListener('release', function () { wakeLock = null; });
|
||||
} catch (_) { wakeLock = null; }
|
||||
}
|
||||
|
||||
function releaseWakeLock() {
|
||||
try { if (wakeLock) wakeLock.release(); } catch (_) {}
|
||||
wakeLock = null;
|
||||
}
|
||||
|
||||
// Ein Wake Lock geht verloren, sobald die Seite in den Hintergrund geht (Anruf,
|
||||
// App-Wechsel). Kommt sie zurueck und laeuft noch ein Sync, neu anfordern.
|
||||
try {
|
||||
document.addEventListener('visibilitychange', function () {
|
||||
if (document.visibilityState === 'visible' && syncing) acquireWakeLock();
|
||||
});
|
||||
} catch (_) {}
|
||||
|
||||
async function syncQueue() {
|
||||
// Läuft schon einer? Dann nur merken, dass danach nochmal geprüft werden soll
|
||||
// (so werden Fotos erfasst, die während eines laufenden Syncs neu dazukamen).
|
||||
if (syncing) { syncAgain = true; return; }
|
||||
if (!navigator.onLine) return;
|
||||
syncing = true;
|
||||
await acquireWakeLock();
|
||||
try {
|
||||
do {
|
||||
syncAgain = false;
|
||||
|
|
@ -74,6 +103,7 @@
|
|||
detail: {
|
||||
queueId: it.id,
|
||||
relpath: res && res.relpath,
|
||||
duplicate: !!(res && res.duplicate),
|
||||
orderId: it.order_id,
|
||||
filename: it.filename,
|
||||
},
|
||||
|
|
@ -98,6 +128,7 @@
|
|||
} while (syncAgain);
|
||||
} finally {
|
||||
syncing = false;
|
||||
releaseWakeLock();
|
||||
await updateBadge();
|
||||
emitChange();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue