UI 新增資料更新時間 badge
在地圖右下角顯示後端 /scan response 新增的 generated_at 欄位, 以中文相對時間呈現(剛剛 / N 分鐘前 / N 小時前 / 絕對日期), 每 10 秒自動重算顯示,資料空或缺欄位時保留上次值。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
70
index.html
70
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; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<div id="updated-badge" hidden></div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
Reference in New Issue
Block a user