From 8977020a80c19973b8271b316be7f7a8356c7d74 Mon Sep 17 00:00:00 2001
From: "2569718930@qq.com" <2569718930@qq.com>
Date: Tue, 3 Mar 2026 23:00:06 +0800
Subject: [PATCH] feat: add local time and peak temp time to city list sidebar
---
web/static/app.js | 55 +++++++++++++++++++++++++++++++++-----------
web/static/style.css | 48 ++++++++++++++++++++++++++++++++------
2 files changed, 82 insertions(+), 21 deletions(-)
diff --git a/web/static/app.js b/web/static/app.js
index b51a8f3a..b09bca74 100644
--- a/web/static/app.js
+++ b/web/static/app.js
@@ -119,11 +119,18 @@ function buildCityList(cities) {
sorted.forEach((city) => {
const div = document.createElement("div");
div.className = "city-item";
- div.id = `city-item-${city.name.replace(/\s/g, "-")}`;
+ const cityId = city.name.replace(/\s/g, "-");
+ div.id = `city-item-${cityId}`;
div.innerHTML = `
-
- ${city.display_name}
- —
+
+
+ ${city.display_name}
+ —
+
+
+
+
+
`;
div.addEventListener("click", () => {
loadCityDetail(city.name);
@@ -145,12 +152,32 @@ function setActiveCityItem(cityName) {
}
}
-function updateCityListTemp(cityName, temp, symbol) {
- const id = `temp-${cityName.replace(/\s/g, "-")}`;
- const el = document.getElementById(id);
- if (el) {
- el.textContent = `${temp}${symbol}`;
- el.classList.add("loaded");
+function updateCityListInfo(cityData) {
+ const cityName = cityData.name;
+ const cityId = cityName.replace(/\s/g, "-");
+ const temp =
+ cityData.current?.max_so_far != null &&
+ cityData.current.max_so_far >= (cityData.current.temp || -999)
+ ? cityData.current.max_so_far
+ : cityData.current.temp;
+
+ // Update Temperature
+ const tempEl = document.getElementById(`temp-${cityId}`);
+ if (tempEl && temp != null) {
+ tempEl.textContent = `${temp}${cityData.temp_symbol}`;
+ tempEl.classList.add("loaded");
+ }
+
+ // Update Local Time
+ const timeEl = document.getElementById(`time-${cityId}`);
+ if (timeEl && cityData.local_time) {
+ timeEl.textContent = `🕐 ${cityData.local_time}`;
+ }
+
+ // Update Max Temp Time
+ const maxEl = document.getElementById(`max-${cityId}`);
+ if (maxEl && cityData.current?.max_temp_time) {
+ maxEl.textContent = `峰值 @${cityData.current.max_temp_time}`;
}
}
@@ -188,7 +215,7 @@ async function loadCityDetail(cityName) {
const data = await fetchCityDetail(cityName);
cityDataCache[cityName] = data;
renderPanel(data);
- // Update marker temperature
+ // Update marker and list
if (data.current?.temp != null) {
const displayTemp =
data.current.max_so_far != null &&
@@ -196,7 +223,7 @@ async function loadCityDetail(cityName) {
? data.current.max_so_far
: data.current.temp;
updateMarkerTemp(cityName, displayTemp);
- updateCityListTemp(cityName, displayTemp, data.temp_symbol);
+ updateCityListInfo(data);
}
} catch (e) {
console.error(`Failed to load ${cityName}:`, e);
@@ -695,7 +722,7 @@ function startAutoRefresh() {
? data.current.max_so_far
: data.current.temp;
updateMarkerTemp(selectedCity, displayTemp);
- updateCityListTemp(selectedCity, displayTemp, data.temp_symbol);
+ updateCityListInfo(data);
}
flashLiveBadge();
} catch (e) {
@@ -738,7 +765,7 @@ async function loadAllCitiesProgressively(cities) {
? data.current.max_so_far
: data.current.temp;
updateMarkerTemp(city.name, displayTemp);
- updateCityListTemp(city.name, displayTemp, data.temp_symbol);
+ updateCityListInfo(data);
}
// 如果恰好在这个时候用户选中了这个城市,顺便刷新面板
diff --git a/web/static/style.css b/web/static/style.css
index 7a491ad2..03299415 100644
--- a/web/static/style.css
+++ b/web/static/style.css
@@ -281,28 +281,62 @@ body {
.city-item {
display: flex;
- align-items: center;
- gap: 8px;
+ flex-direction: column;
+ gap: 4px;
padding: 10px 12px;
border-radius: 10px;
cursor: pointer;
transition: var(--transition);
- font-size: 13px;
- font-weight: 500;
- color: var(--text-secondary);
border: 1px solid transparent;
}
.city-item:hover {
background: rgba(99, 102, 241, 0.08);
- color: var(--text-primary);
border-color: var(--border-glass);
}
.city-item.active {
background: rgba(99, 102, 241, 0.15);
- color: var(--text-primary);
border-color: var(--accent-blue);
}
+.city-item-main {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+}
+
+.city-item .city-name-text {
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--text-primary);
+}
+
+.city-item .city-temp {
+ margin-left: auto;
+ font-size: 13px;
+ font-weight: 700;
+ color: var(--accent-cyan);
+ opacity: 0;
+ transition: var(--transition);
+}
+.city-item .city-temp.loaded {
+ opacity: 1;
+}
+
+.city-item-info {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-left: 16px; /* Align with name text, after the dot */
+ font-size: 10px;
+ color: var(--text-muted);
+}
+
+.city-item .city-max-info {
+ color: var(--accent-blue);
+ font-weight: 500;
+}
+
.city-item .risk-dot {
width: 8px;
height: 8px;