diff --git a/index.html b/index.html index 9c4861b..6c94dcc 100644 --- a/index.html +++ b/index.html @@ -200,10 +200,30 @@ 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } + + /* 右下角資料更新時間 badge:半透明深色、小字、不搶視覺 */ + #updated-badge { + position: absolute; + right: 12px; + bottom: 12px; + z-index: 500; + padding: 6px 10px; + background: rgba(15, 23, 42, 0.72); + color: #f1f5f9; + font-size: 12px; + line-height: 1.3; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18); + pointer-events: none; + font-variant-numeric: tabular-nums; + letter-spacing: 0.02em; + } + #updated-badge[hidden] { display: none; }
+ @@ -439,6 +459,55 @@ // 頁面關閉/離開時清 timer,避免 leak window.addEventListener('beforeunload', clearRetry); + // ---- 資料更新時間 badge ---- + const updatedBadgeEl = document.getElementById('updated-badge'); + let lastGeneratedAtMs = null; // 暫存 ISO parsed 後的 ms,供每 10s tick 重算相對時間 + + // 中文相對時間:<30s 剛剛;<60m N 分鐘前;<24h N 小時前;否則絕對日期 + function formatRelativeTime(isoString) { + const ms = Date.parse(isoString); + if (!Number.isFinite(ms)) return null; + const diffSec = Math.max(0, Math.floor((Date.now() - ms) / 1000)); + if (diffSec < 30) return '剛剛'; + if (diffSec < 3600) return `${Math.floor(diffSec / 60)} 分鐘前`; + if (diffSec < 86400) return `${Math.floor(diffSec / 3600)} 小時前`; + const d = new Date(ms); + const pad = n => String(n).padStart(2, '0'); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; + } + + function renderUpdatedBadge() { + if (lastGeneratedAtMs === null) { + updatedBadgeEl.hidden = true; + return; + } + const iso = new Date(lastGeneratedAtMs).toISOString(); + const rel = formatRelativeTime(iso); + if (rel === null) { + updatedBadgeEl.hidden = true; + return; + } + const d = new Date(lastGeneratedAtMs); + const pad = n => String(n).padStart(2, '0'); + const hhmmss = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; + updatedBadgeEl.textContent = `資料更新於 ${hhmmss}(${rel})`; + updatedBadgeEl.hidden = false; + } + + function updateGeneratedAt(iso) { + if (!iso) { + // 保留上次值即可,不主動清;若從未設過則維持隱藏 + return; + } + const ms = Date.parse(iso); + if (!Number.isFinite(ms)) return; + lastGeneratedAtMs = ms; + renderUpdatedBadge(); + } + + // 每 10 秒重算一次相對時間(不重打 API) + setInterval(renderUpdatedBadge, 10000); + function renderItems(list) { const markers = []; for (const item of list) { @@ -531,6 +600,7 @@ clearRetry(); clearStatus(); retryCount = 0; + updateGeneratedAt(json.generated_at); renderItems(list); }) .catch(err => {