no message

This commit is contained in:
mh
2025-12-18 10:51:21 +01:00
parent 3f86c5583a
commit f5d6ad2a72
+36 -168
View File
@@ -12,38 +12,14 @@
</select> </select>
</label> </label>
<!-- Datum: sichtbares Feld + unsichtbare Picker als Overlay --> <label style="display:flex;gap:6px;align-items:center;">
<label id="dateWrap" style="display:flex;gap:6px;align-items:center; position:relative;">
<span>Datum</span> <span>Datum</span>
<input id="date" type="date" />
<!-- Sichtbar -->
<input id="dateText" type="text" readonly
style="width:210px; padding:4px 10px; font-weight:900; font-size:14px;
opacity:.95; cursor:pointer; border:1px solid rgba(255,255,255,.25);
border-radius:6px; background:rgba(0,0,0,.18); color:#fff;" />
<!-- Overlay Picker (transparent, exakt über dateText) -->
<input id="date" type="date" aria-label="Datum"
style="position:absolute; left:52px; top:0; height:100%;
width:210px; opacity:0; cursor:pointer; display:none;" />
<input id="week" type="week" aria-label="Woche"
style="position:absolute; left:52px; top:0; height:100%;
width:210px; opacity:0; cursor:pointer; display:none;" />
<input id="month" type="month" aria-label="Monat"
style="position:absolute; left:52px; top:0; height:100%;
width:210px; opacity:0; cursor:pointer; display:none;" />
<!-- Jahr: nativer Picker existiert nicht -> Select -->
<select id="yearSel"
style="position:absolute; left:52px; top:0; height:100%;
width:210px; font-weight:900; display:none;
border:1px solid rgba(255,255,255,.25);
border-radius:6px; background:rgba(0,0,0,.35); color:#fff;">
</select>
</label> </label>
<!-- Label rechts neben Date-Picker -->
<div id="dateLabel" style="font-weight:900;opacity:.95;min-width:140px;"></div>
<button id="prev" type="button"></button> <button id="prev" type="button"></button>
<button id="today" type="button">Heute</button> <button id="today" type="button">Heute</button>
<button id="next" type="button"></button> <button id="next" type="button"></button>
@@ -138,6 +114,9 @@
<script> <script>
(function () { (function () {
const elRange = document.getElementById('range'); const elRange = document.getElementById('range');
const elDate = document.getElementById('date');
const elDateLbl = document.getElementById('dateLabel');
const elPrev = document.getElementById('prev'); const elPrev = document.getElementById('prev');
const elToday = document.getElementById('today'); const elToday = document.getElementById('today');
const elNext = document.getElementById('next'); const elNext = document.getElementById('next');
@@ -147,16 +126,9 @@
const elGrid = document.getElementById('grid'); const elGrid = document.getElementById('grid');
const elErr = document.getElementById('err'); const elErr = document.getElementById('err');
const elDateText = document.getElementById('dateText');
const elDate = document.getElementById('date');
const elWeek = document.getElementById('week');
const elMonth = document.getElementById('month');
const elYearSel = document.getElementById('yearSel');
elGrid.innerHTML = '<div style="opacity:.75;padding:12px;">Lade Daten…</div>'; elGrid.innerHTML = '<div style="opacity:.75;padding:12px;">Lade Daten…</div>';
const pad2 = (n) => String(n).padStart(2,'0'); const pad2 = (n) => String(n).padStart(2,'0');
function toYmd(d){ return `${d.getFullYear()}-${pad2(d.getMonth()+1)}-${pad2(d.getDate())}`; }
function toNum(x){ const n = Number(x); return Number.isFinite(n) ? n : 0; } function toNum(x){ const n = Number(x); return Number.isFinite(n) ? n : 0; }
function clamp01(x){ return (!Number.isFinite(x)) ? 0 : (x<0?0:(x>1?1:x)); } function clamp01(x){ return (!Number.isFinite(x)) ? 0 : (x<0?0:(x>1?1:x)); }
function escapeHtml(s){ function escapeHtml(s){
@@ -179,24 +151,6 @@
return { week: weekNo, year: isoYear }; return { week: weekNo, year: isoYear };
} }
// YYYY-Www -> Montag YYYY-MM-DD
function isoWeekToMondayYmd(isoWeekStr){
const m = /^(\d{4})-W(\d{2})$/.exec(isoWeekStr || '');
if (!m) return '';
const year = parseInt(m[1],10);
const week = parseInt(m[2],10);
const jan4 = new Date(Date.UTC(year,0,4));
const jan4Dow = jan4.getUTCDay() || 7;
const mondayWeek1 = new Date(jan4);
mondayWeek1.setUTCDate(jan4.getUTCDate() - (jan4Dow - 1));
const monday = new Date(mondayWeek1);
monday.setUTCDate(mondayWeek1.getUTCDate() + (week-1)*7);
return `${monday.getUTCFullYear()}-${pad2(monday.getUTCMonth()+1)}-${pad2(monday.getUTCDate())}`;
}
function showErr(e){ function showErr(e){
const msg = (e && e.message) ? e.message : String(e); const msg = (e && e.message) ? e.message : String(e);
elErr.textContent = 'JS-Fehler: ' + msg; elErr.textContent = 'JS-Fehler: ' + msg;
@@ -226,69 +180,30 @@
} }
function safeRefreshSoon(){ setTimeout(() => safeRequestAction('Refresh', 1), 150); } function safeRefreshSoon(){ setTimeout(() => safeRequestAction('Refresh', 1), 150); }
// aktiven Picker anzeigen // Label rechts vom Datum (immer aus dem gewählten Tag berechnet)
function setActivePicker(range){ function setDateLabel(range, ymd){
elDate.style.display = 'none'; if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) { elDateLbl.textContent = ''; return; }
elWeek.style.display = 'none';
elMonth.style.display = 'none';
elYearSel.style.display = 'none';
if (range === 'total') return;
if (range === 'day') elDate.style.display = 'block';
if (range === 'week') elWeek.style.display = 'block';
if (range === 'month') elMonth.style.display = 'block';
if (range === 'year') elYearSel.style.display = 'block';
}
// dateText setzen
function setDateText(range, ymd){
if (range === 'total'){ elDateText.value = 'Gesamt'; return; }
if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) { elDateText.value = ''; return; }
const d = new Date(ymd + 'T00:00:00'); const d = new Date(ymd + 'T00:00:00');
if (range === 'day'){ if (range === 'total') { elDateLbl.textContent = 'Gesamt'; return; }
elDateText.value = `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`; if (range === 'day') { elDateLbl.textContent = `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`; return; }
} else if (range === 'week'){ if (range === 'week') { const iso = getISOWeekYear(d); elDateLbl.textContent = `Woche ${iso.week}: ${iso.year}`; return; }
const iso = getISOWeekYear(d); if (range === 'month') { elDateLbl.textContent = `${monthNameDe(d.getMonth())} ${d.getFullYear()}`; return; }
elDateText.value = `Woche ${iso.week}: ${iso.year}`; if (range === 'year') { elDateLbl.textContent = String(d.getFullYear()); return; }
} else if (range === 'month'){ elDateLbl.textContent = '';
elDateText.value = `${monthNameDe(d.getMonth())} ${d.getFullYear()}`;
} else if (range === 'year'){
elDateText.value = `${d.getFullYear()}`;
} else {
elDateText.value = '';
}
} }
// Jahr-Select bauen
function buildYearOptions(baseYmd){
const base = (baseYmd && /^\d{4}-\d{2}-\d{2}$/.test(baseYmd)) ? new Date(baseYmd+'T00:00:00') : new Date();
const y0 = base.getFullYear();
const from = y0 - 15;
const to = y0 + 1;
elYearSel.innerHTML = '';
for (let y = to; y >= from; y--){
const opt = document.createElement('option');
opt.value = String(y);
opt.textContent = String(y);
elYearSel.appendChild(opt);
}
}
// Zeitraum-Spanne
function fmtRangeSpan(range, tStart, tEnd){ function fmtRangeSpan(range, tStart, tEnd){
if (!tStart || !tEnd) return ''; if (!tStart || !tEnd) return '';
if (range === 'total') return 'Zeitraum: Gesamt'; if (range === 'total') return 'Zeitraum: Gesamt';
const s = new Date(tStart * 1000); const s = new Date(tStart * 1000);
const e = new Date((tEnd * 1000) - 1000); // tEnd exklusiv -> -1s const e = new Date((tEnd * 1000) - 1000);
const dmy = (d) => `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`; const dmy = (d) => `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`;
return `Zeitraum: ${dmy(s)} - ${dmy(e)}`; return `Zeitraum: ${dmy(s)} - ${dmy(e)}`;
} }
// Donut (ohne Box/Rand)
function donutCard({ title, percent, subtitle, color }){ function donutCard({ title, percent, subtitle, color }){
const share = clamp01(percent / 100); const share = clamp01(percent / 100);
const r = 56; const r = 56;
@@ -340,34 +255,12 @@
const autark = (cons > 0) ? (eigenClamped / cons * 100) : 0; const autark = (cons > 0) ? (eigenClamped / cons * 100) : 0;
if (data?.range) elRange.value = data.range; if (data?.range) elRange.value = data.range;
if (data?.date) elDate.value = data.date;
// Basisdatum (immer YYYY-MM-DD vom Backend) elDate.disabled = (data?.range === 'total');
const ymd = data?.date || '';
if (ymd && /^\d{4}-\d{2}-\d{2}$/.test(ymd)) elDate.value = ymd;
// aktiven Picker setzen // Datum-Label (Tag bleibt im Picker!)
setActivePicker(elRange.value); setDateLabel(elRange.value, elDate.value);
// Jahr-Select vorbereiten
buildYearOptions(ymd);
// Picker synchronisieren
if (elRange.value === 'week' && ymd){
const d = new Date(ymd + 'T00:00:00');
const iso = getISOWeekYear(d);
elWeek.value = `${iso.year}-W${pad2(iso.week)}`;
}
if (elRange.value === 'month' && ymd){
const d = new Date(ymd + 'T00:00:00');
elMonth.value = `${d.getFullYear()}-${pad2(d.getMonth()+1)}`;
}
if (elRange.value === 'year' && ymd){
const d = new Date(ymd + 'T00:00:00');
elYearSel.value = String(d.getFullYear());
}
// sichtbares Datumsfeld
setDateText(elRange.value, ymd);
// Zeitraum-Spanne // Zeitraum-Spanne
elPeriod.textContent = (data?.tStart && data?.tEnd) elPeriod.textContent = (data?.tStart && data?.tEnd)
@@ -423,48 +316,23 @@
render(data); render(data);
}; };
// ---------- UI EVENTS ---------- // UI events
elRange.addEventListener('change', () => { elRange.addEventListener('change', () => {
const r = elRange.value; safeRequestAction('SetRange', elRange.value);
setActivePicker(r); // Label sofort updaten (Backend kommt dann eh gleich nach)
safeRequestAction('SetRange', r); setDateLabel(elRange.value, elDate.value);
// kein direktes SetDate hier nötig; der Nutzer wählt danach passend (Week/Month/Year)
}); });
// Tag let dateTimer = null;
elDate.addEventListener('change', () => { function pushDateNow(){
const ymd = elDate.value; if (dateTimer) clearTimeout(dateTimer);
setDateText('day', ymd); dateTimer = setTimeout(() => {
safeRequestAction('SetDate', ymd); setDateLabel(elRange.value, elDate.value);
}); safeRequestAction('SetDate', elDate.value);
}, 80);
// Woche }
elWeek.addEventListener('change', () => { elDate.addEventListener('input', pushDateNow);
const mondayYmd = isoWeekToMondayYmd(elWeek.value); elDate.addEventListener('change', pushDateNow);
if (!mondayYmd) return;
elDate.value = mondayYmd;
setDateText('week', mondayYmd);
safeRequestAction('SetDate', mondayYmd);
});
// Monat
elMonth.addEventListener('change', () => {
const v = elMonth.value; // YYYY-MM
if (!/^\d{4}-\d{2}$/.test(v)) return;
const ymd = `${v}-01`;
elDate.value = ymd;
setDateText('month', ymd);
safeRequestAction('SetDate', ymd);
});
// Jahr
elYearSel.addEventListener('change', () => {
const y = elYearSel.value;
const ymd = `${y}-01-01`;
elDate.value = ymd;
setDateText('year', ymd);
safeRequestAction('SetDate', ymd);
});
elPrev.addEventListener('click', () => safeRequestAction('Prev', 1)); elPrev.addEventListener('click', () => safeRequestAction('Prev', 1));
elToday.addEventListener('click', () => safeRequestAction('Today', 1)); elToday.addEventListener('click', () => safeRequestAction('Today', 1));