no message
This commit is contained in:
+36
-168
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user