Ueberschrittene Servicetermine werden markiert
Wunsch des Eigentuemers: faellige oder ueberschrittene Termine dezent
gelb/orange hinterlegen und mit "ueberschritten" markieren - Service-Seite und
Mein Audi; auf der Uebersicht zusaetzlich die Kennzahl im Warnton.
Erkannt wird am DATUM, nicht an den Restkilometern. Gemessen: die Sensoren
melden -28600 bzw. -22000 bei Faelligkeit 2028 bzw. 2027, negativ heisst hier
also "noch so weit hin". Welches Vorzeichen ein tatsaechlich ueberschrittener
Wert traegt, ist an den vorliegenden Daten nicht beobachtbar - geraten wird es
nicht. Der km-Fall faellt ohnehin unter die Datumsregel: servicePrognose()
setzt datum auf heute, sobald restKm auf 0 laeuft. Der Faelligkeitstag zaehlt
mit ("bereits faellig bzw. ueberschritten").
Dabei eine Luecke im Panel gefunden, vom Test und nicht im Betrieb:
datumAusText() ist verankert und nimmt keine vollen Zeitstempel - die
Fahrzeugmeldung ist aber genau das und bei Oelwechsel und Inspektion die
Hauptquelle. Sie waere still nie als ueberschritten erkannt worden.
zeitstempelAlsDatum() schliesst sie; die App hatte die Luecke nie.
Farbe nach Rolle geteilt wie --bad/--bad-flaeche: --warn ist die Flaeche,
--warn-text die Schrift. Grund: #FF9F0A als Text auf Weiss sind 2.06:1. Auf dem
12% hinterlegten Grund misst --warn-text 4.90:1 (Tag, #A15800) bzw. 9.30:1
(Nacht).
Geprueft: 15 Faelle gegen die echten Panel-Funktionen, 7 in der App, 14
Paritaetsfaelle Panel gegen App, 3 Rendertests ueber alle drei Anzeigestellen.
Gegenprobe: mit ausgehaengter Entscheidung fallen 9 Tests. 327/327, tsc sauber,
Panel als Modul geparst, Manifest und Buendel auf 2026.9.6.6, Container sauber
gestartet.
Offen: optisch nicht gesehen - der Testbestand enthaelt keinen ueberschrittenen
Termin. In OFFEN.md vermerkt.
This commit is contained in:
@@ -1 +1 @@
|
||||
{"version":"2026.9.6.5","sha256":"d7373ee38b4b6e97f5d20e5225bca6981d21f60fc34d7b2658b8571650b52726","bytes":378720,"gebaut":"2026-09-06T21:29:15Z"}
|
||||
{"version":"2026.9.6.6","sha256":"c9e3d8f25998f38b70e38441a8c0e09d76bbe340845575e9ae769fe12c2fc45e","bytes":379100,"gebaut":"2026-09-07T11:37:53Z"}
|
||||
Binary file not shown.
@@ -741,6 +741,52 @@ function datumAusText(wert) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Ist dieser Servicetermin bereits faellig oder ueberschritten? Der
|
||||
Faelligkeitstag selbst zaehlt mit ("bereits faellig bzw. ueberschritten",
|
||||
Ansage des Eigentuemers 07.09.2026).
|
||||
|
||||
Entschieden wird am DATUM, nicht an den Restkilometern - und das ist keine
|
||||
Bequemlichkeit. Die Kilometerseite traegt je nach Quelle ein anderes
|
||||
Vorzeichen: die Sensoren des Fahrzeugs melden negativ, solange noch Strecke
|
||||
bleibt (am 07.09.2026 gemessen: oil_change_distance -28600 bei Faelligkeit
|
||||
2028), und servicePrognose() klemmt ihre Restkilometer ohnehin mit
|
||||
Math.max(0, ...). Welches Vorzeichen ein ueberschrittener Fahrzeugwert
|
||||
traegt, laesst sich an den vorliegenden Daten nicht beobachten - geraten wird
|
||||
es nicht. Der km-Fall faellt ohnehin unter die Datumsregel: servicePrognose()
|
||||
setzt datum auf heute, sobald restKm auf 0 laeuft.
|
||||
|
||||
Genommen wird das ERSTE lesbare Datum der uebergebenen Kandidaten - also das,
|
||||
das an dieser Stelle auch angezeigt wird. So kann die Markierung nicht von
|
||||
dem abweichen, was daneben steht. */
|
||||
/* Ein voller ISO-Zeitstempel ("2027-10-21T00:00:00+00:00"), wie ihn die
|
||||
Sensoren des Fahrzeugs liefern. Bewusst eng gefasst statt einem allgemeinen
|
||||
new Date(): sonst deutete der Rueckfall auch Zeichenketten, die
|
||||
datumAusText() gerade abgelehnt hat. */
|
||||
const DATUM_ZEITSTEMPEL = /^\d{4}-\d{2}-\d{2}T/;
|
||||
function zeitstempelAlsDatum(wert) {
|
||||
if (typeof wert !== "string" || !DATUM_ZEITSTEMPEL.test(wert)) return null;
|
||||
const d = new Date(wert);
|
||||
return gueltigesDatum(d) ? { zeit: d, genau: "tag" } : null;
|
||||
}
|
||||
|
||||
function terminUeberschritten(...kandidaten) {
|
||||
for (const kandidat of kandidaten) {
|
||||
if (kandidat == null || kandidat === "") continue;
|
||||
// datumAusText() ist verankert und nimmt bewusst keine Zeitstempel - die
|
||||
// Fahrzeugmeldung (fm.ts) ist aber genau das, und sie ist bei Oelwechsel
|
||||
// und Inspektion die Hauptquelle. Ohne diesen Zweig gaelte sie stillschweigend
|
||||
// nie als ueberschritten; am 07.09.2026 vom Test gefangen, nicht im Betrieb.
|
||||
const d = datumAusText(kandidat) || zeitstempelAlsDatum(kandidat);
|
||||
if (!d) continue;
|
||||
const z = d.zeit, h = new Date();
|
||||
return new Date(z.getFullYear(), z.getMonth(), z.getDate()).getTime()
|
||||
<= new Date(h.getFullYear(), h.getMonth(), h.getDate()).getTime();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const UEBERSCHRITTEN_MARKE = '<span class="ueberschritten-marke">überschritten</span>';
|
||||
|
||||
/* Zeigt eine monatsgenaue Angabe als Monat statt als erfundenen Ersten. */
|
||||
const demonat = (d) => (gueltigesDatum(d)
|
||||
? d.toLocaleDateString("de-DE", { month: "long", year: "numeric" })
|
||||
@@ -2434,11 +2480,15 @@ function vHome() {
|
||||
const figMarkup = artIcon
|
||||
? `<div class="fig-zeile">${ciSVG(artIcon, 31)}<div class="fig" style="font-size:${zahlGroesse}px">${hauptwert}</div></div>`
|
||||
: `<div class="fig" style="font-size:${zahlGroesse}px;margin-top:8px">${hauptwert}</div>`;
|
||||
// Auf der Uebersicht wechselt zusaetzlich die Kennzahl selbst die Farbe -
|
||||
// sie ist hier die Aussage, nicht nur ihr Rahmen (Ansage des Eigentuemers).
|
||||
const ueber = terminUeberschritten(datum, t.datum);
|
||||
return `<div class="tile" style="margin-bottom:22px">
|
||||
<button class="serviceblock" data-go="service:x">
|
||||
<button class="serviceblock${ueber ? " ueberschritten" : ""}" data-go="service:x">
|
||||
<span class="label">Nächster Service:</span>
|
||||
<svg class="go" viewBox="0 0 6 10"><polyline points="1,1 5,5 1,9"/></svg>
|
||||
${figMarkup}
|
||||
${ueber ? `<div class="servicemarke">${UEBERSCHRITTEN_MARKE}</div>` : ""}
|
||||
<span class="label" style="margin-top:8px">${nebenzeile}</span>
|
||||
</button>
|
||||
${kmZeile}
|
||||
@@ -2610,15 +2660,17 @@ function vAudi() {
|
||||
const eigen = prognoseZeile(t.art);
|
||||
if (fm.ts == null && fm.km == null) {
|
||||
const x = terminText(t);
|
||||
const ueber = terminUeberschritten(t.ziel, t.datum);
|
||||
return `<div class="row" ${letzte}>
|
||||
<dt>${t.art}${t.art === "Inspektion" ? eigen : ""}</dt>
|
||||
<dd>${x.haupt}${x.neben ? `<small style="text-align:left">${x.neben}</small>` : ""}</dd></div>`;
|
||||
<dd>${x.haupt}${ueber ? UEBERSCHRITTEN_MARKE : ""}${x.neben ? `<small style="text-align:left">${x.neben}</small>` : ""}</dd></div>`;
|
||||
}
|
||||
const haupt = fm.ts ? dedat(new Date(fm.ts)) : "";
|
||||
const neben = fm.km != null ? "in " + de(fm.km) + " km" : "";
|
||||
const ueber = terminUeberschritten(fm.ts, t.ziel, t.datum);
|
||||
return `<div class="row" ${letzte}>
|
||||
<dt>${t.art}${eigen}</dt>
|
||||
<dd>${haupt}${neben ? `<span style="display:block">${neben}</span>` : ""}</dd></div>`;
|
||||
<dd>${haupt}${ueber ? UEBERSCHRITTEN_MARKE : ""}${neben ? `<span style="display:block">${neben}</span>` : ""}</dd></div>`;
|
||||
}).join("")}
|
||||
</dl></button>
|
||||
<button class="tile tilebtn" data-go="vers:x">
|
||||
@@ -3024,10 +3076,13 @@ function vService() {
|
||||
Wartungsplan" gezeigt, waehrend die Uebersicht denselben Termin
|
||||
auswies - gemeldet vom Eigentuemer, zwei Bildschirme, zwei
|
||||
Antworten. */
|
||||
if (!iv && !hatMeldung && t.datum) return `<div class="termingruppe">
|
||||
<div class="tg-kopf">${kopf}</div>
|
||||
if (!iv && !hatMeldung && t.datum) {
|
||||
const ueber = terminUeberschritten(t.datum);
|
||||
return `<div class="termingruppe${ueber ? " ueberschritten" : ""}">
|
||||
<div class="tg-kopf">${kopf}${ueber ? UEBERSCHRITTEN_MARKE : ""}</div>
|
||||
<div class="tg-wert">${datumText(t.datum, t.genau)}</div>
|
||||
</div>`;
|
||||
}
|
||||
if (!iv && !hatMeldung) return `<div class="termingruppe">
|
||||
<div class="tg-kopf">${kopf}</div>
|
||||
<div class="tg-wert leer">kein Eintrag im Wartungsplan</div>
|
||||
@@ -3074,9 +3129,13 @@ function vService() {
|
||||
// als Herstellervorgabe; nur der App-eigene Eigen-Intervall-Fallback
|
||||
// (anzeige.eigen/eigenOel bei modus "eigen") ist es nicht.
|
||||
const herstellervorgabe = hatMeldung || (iv && iv.hersteller);
|
||||
return `<div class="termingruppe">
|
||||
// Dasselbe Datum, das gleich als `wert` erscheint - siehe
|
||||
// terminUeberschritten().
|
||||
const ueber = terminUeberschritten(
|
||||
hatMeldung ? fm.ts : (eigenOel ? eigenOel.datum : (anzeige ? anzeige.datum : null)));
|
||||
return `<div class="termingruppe${ueber ? " ueberschritten" : ""}">
|
||||
<div class="tg-kopf">
|
||||
${kopf}
|
||||
${kopf}${ueber ? UEBERSCHRITTEN_MARKE : ""}
|
||||
</div>
|
||||
${herstellervorgabe ? `<div class="tg-vorgabe">Herstellervorgabe</div>` : ""}
|
||||
<div class="tg-wert">${wert}</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
--line:rgba(255,255,255,.13);
|
||||
--line-strong:rgba(255,255,255,.24);
|
||||
--fg:#FFFFFF; --fg2:#BFC4CC; --fg3:#8E8E93;
|
||||
--ok:#30D158; --warn:#FFD60A; --bad:#FF453A; --bad-flaeche:#D70015;
|
||||
--ok:#30D158; --warn:#FFD60A; --bad:#FF453A; --bad-flaeche:#D70015; --warn-text:#FFD60A;
|
||||
/* Ohne diese Angabe rendert der Browser native Steuerelemente (Dropdown-
|
||||
Aufklapp-Liste bei <select>, Scrollbars) in seiner Standard-Hellansicht,
|
||||
egal wie dunkel die App selbst ist - das liess z. B. "Modell" beim
|
||||
@@ -45,7 +45,7 @@
|
||||
auf 4,75:1 bzw. 5,30:1, ohne den ruhigen Gesamteindruck zu aendern.
|
||||
Der Nachtwert bleibt #8E8E93 - dort sind es ohnehin 5,86:1. */
|
||||
--fg:#000000; --fg2:#3C3C43; --fg3:#6B6B70;
|
||||
--ok:#34C759; --warn:#FF9F0A; --bad:#D70015; --bad-flaeche:#D70015;
|
||||
--ok:#34C759; --warn:#FF9F0A; --bad:#D70015; --bad-flaeche:#D70015; --warn-text:#A15800;
|
||||
--ios-sep:rgba(60,60,67,.16);
|
||||
--ios-fill:rgba(120,120,128,.16);
|
||||
--tile-deckend:#FFFFFF;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
--fg3: #8a94a3;
|
||||
--ok: #15da15;
|
||||
--warn: #ffaa00;
|
||||
--warn-text: #ffaa00;
|
||||
--bad: #fd2c4e;
|
||||
--shade: rgba(255,255,255,.05);
|
||||
--font-stack: "Audi Type", Helvetica, Arial, sans-serif;
|
||||
@@ -50,6 +51,7 @@
|
||||
--fg3: #666666;
|
||||
--ok: #0DA20D;
|
||||
--warn: #ffaa00;
|
||||
--warn-text: #ffaa00;
|
||||
--bad: #eb0d3f;
|
||||
--shade: rgba(0,0,0,.04);
|
||||
}
|
||||
@@ -653,6 +655,32 @@ button.leaf:active { background: var(--tile-2); }
|
||||
.tg-wert.leer { font-family: var(--font-stack); font-weight: 400; font-size: 15px; color: var(--fg3); margin-top: 8px; }
|
||||
.tg-prognose { font-size: 12.5px; color: var(--fg2); margin-top: 6px; }
|
||||
|
||||
/* Ueberschrittene Servicetermine: dezent hinterlegt statt umgefaerbt, damit die
|
||||
Zeile lesbar bleibt und der Hinweis trotzdem auffaellt (Ansage des
|
||||
Eigentuemers 07.09.2026). --warn ist die Flaeche, --warn-text die Schrift -
|
||||
dieselbe Rollenteilung wie bei --bad/--bad-flaeche, und aus demselben Grund:
|
||||
#FF9F0A als Text auf Weiss sind 2.06:1. Auf dem hier hinterlegten Grund
|
||||
(#FFF3E2 tags, #33311E nachts) misst --warn-text 4.90:1 bzw. 9.30:1. */
|
||||
.termingruppe.ueberschritten {
|
||||
background: color-mix(in srgb, var(--warn) 12%, transparent);
|
||||
border-radius: var(--r-tile); padding-left: 12px; padding-right: 12px;
|
||||
margin-left: -12px; margin-right: -12px;
|
||||
}
|
||||
/* Die Trennlinie zur Vorgaengerzeile wuerde ueber die abgerundete Flaeche
|
||||
laufen - die uebernimmt hier die Abgrenzung. */
|
||||
.termingruppe.ueberschritten, .termingruppe.ueberschritten + .termingruppe { border-top: 0; }
|
||||
.ueberschritten-marke {
|
||||
font-size: 10.5px; color: var(--warn-text);
|
||||
border: 1px solid var(--warn-text); border-radius: var(--r-pill);
|
||||
padding: 3px 8px; white-space: nowrap; flex: 0 0 auto;
|
||||
}
|
||||
/* Auf der Uebersicht wechselt zusaetzlich die Schrift der Kennzahl - dort ist
|
||||
sie die Aussage, nicht nur ihr Rahmen. */
|
||||
.serviceblock.ueberschritten .fig, .serviceblock.ueberschritten .fig .unit { color: var(--warn-text); }
|
||||
.servicemarke { display: inline-flex; margin-top: 8px; }
|
||||
/* In der Zeilenliste von "Mein Audi" reicht die Marke neben dem Wert. */
|
||||
.row .ueberschritten-marke { margin-left: 8px; vertical-align: middle; }
|
||||
|
||||
.badge { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
||||
.badge img { height: 18px; width: auto; display: none; }
|
||||
:host([data-theme=nacht]) .badge img.negative { display: block; }
|
||||
|
||||
Reference in New Issue
Block a user