asdsad
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
const settings = page.settings || {};
|
||||
const nodes = {
|
||||
ratesBody: root.querySelector('[data-bind="rates-body"]'),
|
||||
historyHead: root.querySelector('[data-bind="history-head"]'),
|
||||
historyBody: root.querySelector('[data-bind="history-body"]'),
|
||||
fetchesBody: root.querySelector('[data-bind="fetches-body"]'),
|
||||
convertResult: root.querySelector('[data-bind="convert-result"]'),
|
||||
convertFrom: root.querySelector('select[name="convert_from"]'),
|
||||
@@ -59,6 +61,45 @@
|
||||
`).join('');
|
||||
};
|
||||
|
||||
const renderHistory = (rows, currencies) => {
|
||||
if (!nodes.historyHead || !nodes.historyBody) {
|
||||
return;
|
||||
}
|
||||
|
||||
const series = Array.isArray(currencies) ? currencies : [];
|
||||
if (!series.length) {
|
||||
nodes.historyHead.innerHTML = '<tr><th>Datum</th><th>Kurse</th></tr>';
|
||||
nodes.historyBody.innerHTML = '<tr><td colspan="2">Keine bevorzugten Waehrungen fuer den Verlauf vorhanden.</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
nodes.historyHead.innerHTML = `
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
${series.map((currency) => `<th>${currency}</th>`).join('')}
|
||||
</tr>
|
||||
`;
|
||||
|
||||
const entries = Array.isArray(rows) ? rows : [];
|
||||
if (!entries.length) {
|
||||
nodes.historyBody.innerHTML = `<tr><td colspan="${series.length + 1}">Noch keine Verlaufsdaten vorhanden.</td></tr>`;
|
||||
return;
|
||||
}
|
||||
|
||||
nodes.historyBody.innerHTML = entries.map((entry) => `
|
||||
<tr>
|
||||
<td>${entry.label}</td>
|
||||
${series.map((currency) => {
|
||||
const value = entry.rates?.[currency];
|
||||
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
||||
return '<td>–</td>';
|
||||
}
|
||||
return `<td>${value.toLocaleString('de-DE', { maximumFractionDigits: 8 })}</td>`;
|
||||
}).join('')}
|
||||
</tr>
|
||||
`).join('');
|
||||
};
|
||||
|
||||
const request = async (path, options = {}) => {
|
||||
const response = await fetch(`${apiBase}${path}`, {
|
||||
credentials: 'same-origin',
|
||||
@@ -91,6 +132,50 @@
|
||||
return data;
|
||||
};
|
||||
|
||||
const loadHistory = async () => {
|
||||
const base = String(
|
||||
settings.display_base_currency || settings.default_base_currency || 'EUR'
|
||||
).trim().toUpperCase();
|
||||
const historyCurrencies = preferredCurrencies.filter((currency) => currency !== base);
|
||||
|
||||
if (!historyCurrencies.length) {
|
||||
renderHistory([], []);
|
||||
return;
|
||||
}
|
||||
|
||||
const histories = await Promise.all(historyCurrencies.map(async (currency) => {
|
||||
const query = new URLSearchParams({ from: base, to: currency, limit: '20' });
|
||||
const rows = await request(`/history?${query.toString()}`);
|
||||
return { currency, rows: Array.isArray(rows) ? rows : [] };
|
||||
}));
|
||||
|
||||
const byDate = new Map();
|
||||
histories.forEach(({ currency, rows }) => {
|
||||
rows.forEach((row) => {
|
||||
const key = String(row?.fetched_at || row?.rate_date || '').trim();
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
if (!byDate.has(key)) {
|
||||
byDate.set(key, {
|
||||
sortKey: key,
|
||||
label: row?.fetched_at_display || row?.fetched_at || row?.rate_date || key,
|
||||
rates: {},
|
||||
});
|
||||
}
|
||||
const entry = byDate.get(key);
|
||||
if (entry && typeof row?.rate === 'number' && Number.isFinite(row.rate)) {
|
||||
entry.rates[currency] = row.rate;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const mergedRows = Array.from(byDate.values())
|
||||
.sort((left, right) => String(left.sortKey).localeCompare(String(right.sortKey)));
|
||||
|
||||
renderHistory(mergedRows, historyCurrencies);
|
||||
};
|
||||
|
||||
const calculateConversion = async () => {
|
||||
if (!nodes.convertFrom || !nodes.convertTo || !nodes.convertAmount || !nodes.convertResult) {
|
||||
return;
|
||||
@@ -136,5 +221,10 @@
|
||||
renderFetches(page.recent_fetches || []);
|
||||
|
||||
loadLatest().catch(() => {});
|
||||
loadHistory().catch(() => {
|
||||
renderHistory([], preferredCurrencies.filter((currency) => currency !== String(
|
||||
settings.display_base_currency || settings.default_base_currency || 'EUR'
|
||||
).trim().toUpperCase()));
|
||||
});
|
||||
calculateConversion().catch(() => {});
|
||||
})();
|
||||
|
||||
@@ -87,11 +87,12 @@ $pageData = json_encode([
|
||||
<div class="fx-card-head">
|
||||
<div>
|
||||
<h2>Letzte Kurse</h2>
|
||||
<p>Letzter gespeicherter Snapshot fuer <?= e((string) ($settings['display_base_currency'] ?? $settings['default_base_currency'] ?? 'EUR')) ?>.</p>
|
||||
<p>Letzter gespeicherter Snapshot, umgerechnet auf <?= e((string) ($settings['display_base_currency'] ?? $settings['default_base_currency'] ?? 'EUR')) ?>.</p>
|
||||
</div>
|
||||
<div class="fx-card-meta">
|
||||
<div><strong>Letzter Abruf:</strong> <?= e((string) ($latest['fetched_at_display'] ?? $latest['fetched_at'] ?? 'noch keiner')) ?></div>
|
||||
<div><strong>Basis:</strong> <?= e((string) ($latest['base_currency'] ?? $settings['default_base_currency'] ?? '')) ?></div>
|
||||
<div><strong>Anzeige-Basis:</strong> <?= e((string) ($settings['display_base_currency'] ?? $settings['default_base_currency'] ?? '')) ?></div>
|
||||
<div><strong>Snapshot-Basis:</strong> <?= e((string) ($latest['base_currency'] ?? '')) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fx-table-wrap">
|
||||
@@ -109,6 +110,24 @@ $pageData = json_encode([
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fx-card">
|
||||
<h2>Kursverlauf</h2>
|
||||
<p>Chronologischer Verlauf der bevorzugten Waehrungen relativ zur Anzeige-Basiswaehrung.</p>
|
||||
<div class="fx-table-wrap">
|
||||
<table class="fx-table">
|
||||
<thead data-bind="history-head">
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Kurse</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-bind="history-body">
|
||||
<tr><td colspan="2">Noch keine Verlaufsdaten geladen.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fx-card">
|
||||
<h2>Letzte Abrufe</h2>
|
||||
<div class="fx-table-wrap">
|
||||
|
||||
Reference in New Issue
Block a user