no message

This commit is contained in:
belevo\mh
2025-12-18 10:51:21 +01:00
parent 3f86c5583a
commit f5d6ad2a72

View File

@@ -12,38 +12,14 @@
</select>
</label>
<!-- Datum: sichtbares Feld + unsichtbare Picker als Overlay -->
<label id="dateWrap" style="display:flex;gap:6px;align-items:center; position:relative;">
<label style="display:flex;gap:6px;align-items:center;">
<span>Datum</span>
<!-- 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>
<input id="date" type="date" />
</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="today" type="button">Heute</button>
<button id="next" type="button"></button>
@@ -138,6 +114,9 @@
<script>
(function () {
const elRange = document.getElementById('range');
const elDate = document.getElementById('date');
const elDateLbl = document.getElementById('dateLabel');
const elPrev = document.getElementById('prev');
const elToday = document.getElementById('today');
const elNext = document.getElementById('next');
@@ -147,16 +126,9 @@
const elGrid = document.getElementById('grid');
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>';
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 clamp01(x){ return (!Number.isFinite(x)) ? 0 : (x<0?0:(x>1?1:x)); }
function escapeHtml(s){
@@ -179,24 +151,6 @@
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){
const msg = (e && e.message) ? e.message : String(e);
elErr.textContent = 'JS-Fehler: ' + msg;
@@ -226,69 +180,30 @@
}
function safeRefreshSoon(){ setTimeout(() => safeRequestAction('Refresh', 1), 150); }
// aktiven Picker anzeigen
function setActivePicker(range){
elDate.style.display = 'none';
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; }
// Label rechts vom Datum (immer aus dem gewählten Tag berechnet)
function setDateLabel(range, ymd){
if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) { elDateLbl.textContent = ''; return; }
const d = new Date(ymd + 'T00:00:00');
if (range === 'day'){
elDateText.value = `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`;
} else if (range === 'week'){
const iso = getISOWeekYear(d);
elDateText.value = `Woche ${iso.week}: ${iso.year}`;
} else if (range === 'month'){
elDateText.value = `${monthNameDe(d.getMonth())} ${d.getFullYear()}`;
} else if (range === 'year'){
elDateText.value = `${d.getFullYear()}`;
} else {
elDateText.value = '';
}
if (range === 'total') { elDateLbl.textContent = 'Gesamt'; return; }
if (range === 'day') { elDateLbl.textContent = `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`; return; }
if (range === 'week') { const iso = getISOWeekYear(d); elDateLbl.textContent = `Woche ${iso.week}: ${iso.year}`; return; }
if (range === 'month') { elDateLbl.textContent = `${monthNameDe(d.getMonth())} ${d.getFullYear()}`; return; }
if (range === 'year') { elDateLbl.textContent = String(d.getFullYear()); return; }
elDateLbl.textContent = '';
}
// 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){
if (!tStart || !tEnd) return '';
if (range === 'total') return 'Zeitraum: Gesamt';
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()}`;
return `Zeitraum: ${dmy(s)} - ${dmy(e)}`;
}
// Donut (ohne Box/Rand)
function donutCard({ title, percent, subtitle, color }){
const share = clamp01(percent / 100);
const r = 56;
@@ -340,34 +255,12 @@
const autark = (cons > 0) ? (eigenClamped / cons * 100) : 0;
if (data?.range) elRange.value = data.range;
if (data?.date) elDate.value = data.date;
// Basisdatum (immer YYYY-MM-DD vom Backend)
const ymd = data?.date || '';
if (ymd && /^\d{4}-\d{2}-\d{2}$/.test(ymd)) elDate.value = ymd;
elDate.disabled = (data?.range === 'total');
// aktiven Picker setzen
setActivePicker(elRange.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);
// Datum-Label (Tag bleibt im Picker!)
setDateLabel(elRange.value, elDate.value);
// Zeitraum-Spanne
elPeriod.textContent = (data?.tStart && data?.tEnd)
@@ -423,48 +316,23 @@
render(data);
};
// ---------- UI EVENTS ----------
// UI events
elRange.addEventListener('change', () => {
const r = elRange.value;
setActivePicker(r);
safeRequestAction('SetRange', r);
// kein direktes SetDate hier nötig; der Nutzer wählt danach passend (Week/Month/Year)
safeRequestAction('SetRange', elRange.value);
// Label sofort updaten (Backend kommt dann eh gleich nach)
setDateLabel(elRange.value, elDate.value);
});
// Tag
elDate.addEventListener('change', () => {
const ymd = elDate.value;
setDateText('day', ymd);
safeRequestAction('SetDate', ymd);
});
// Woche
elWeek.addEventListener('change', () => {
const mondayYmd = isoWeekToMondayYmd(elWeek.value);
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);
});
let dateTimer = null;
function pushDateNow(){
if (dateTimer) clearTimeout(dateTimer);
dateTimer = setTimeout(() => {
setDateLabel(elRange.value, elDate.value);
safeRequestAction('SetDate', elDate.value);
}, 80);
}
elDate.addEventListener('input', pushDateNow);
elDate.addEventListener('change', pushDateNow);
elPrev.addEventListener('click', () => safeRequestAction('Prev', 1));
elToday.addEventListener('click', () => safeRequestAction('Today', 1));