From 06b1e1b9fe9b921d5f98db889a590ff6118c06b3 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Mon, 23 Mar 2026 17:54:14 +0800 Subject: [PATCH] Release v1.5.1 and improve mobile dashboard layouts --- CHANGELOG.md | 20 +- FRONTEND_REDESIGN_REPORT.md | 2 +- README.md | 2 +- README_ZH.md | 2 +- VERSION | 2 +- docs/API_ZH.md | 2 +- docs/SUPABASE_SETUP_ZH.md | 2 +- docs/TECH_DEBT.md | 2 +- docs/TECH_DEBT_ZH.md | 2 +- docs/payments/POLYGONSCAN_VERIFY.md | 2 +- .../account/AccountCenter.module.css | 73 +++++ .../components/dashboard/Dashboard.module.css | 289 +++++++++++++++++- frontend/components/ops/OpsDashboard.tsx | 149 ++++++--- frontend/package.json | 2 +- 14 files changed, 492 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d13ec5ea..cada395d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,23 @@ # Changelog -## Unreleased +## 1.5.1 - 2026-03-23 -- 新增 `/ops` 轻量运营后台,支持系统状态、会员列表、用户查询、周榜、手动补分 -- `/ops` 新增支付异常单,支持按原因筛选并手动标记“已处理” -- 会员列表支持按 `user_id` 去重,并回补 Supabase Auth 邮箱/注册时间 +- `/ops` 页面增加管理员守卫,前后端双层限制管理员访问 +- `/ops` 支持会员列表、支付异常单、用户查询、周榜和手动补分 +- `/ops` 支付异常单支持按原因筛选、标记已处理,并补充支付异常审计视图 +- 会员列表支持按 `user_id` 去重,并优先回补 Supabase Auth 邮箱/注册时间 - 新增按邮箱补跑订阅恢复脚本 `scripts/reconcile_subscription_by_email.py` - 支付确认失败(如 `receiver_mismatch`)现在会明确落 `failed`,并写入 SQLite 审计事件 -- 账户页支付前强制重新拉取 `/api/payments/config`,并对 `tx_payload.to` 做最新地址校验 +- 支付前强制重新拉取 `/api/payments/config`,并校验最新地址、允许域名和当前支付上下文 +- 浏览器钱包选择补齐 EIP-6963 发现、稳定去重和绑定后账户状态即时刷新 - 城市详情页新增 `官方参考 / Official Sources` 区块,覆盖主要城市的官方机构/机场/METAR 链接 -- 前端钱包选择补齐 EIP-6963 发现、稳定去重和绑定后账户状态即时刷新 +- “今日日内分析”结构解读改为后端同源动态短评,并统一网页与 Bot 解释口径 +- 台北主结算源切换到 `NOAA RCTP`,按最终质控后的最高整度摄氏值展示和说明 +- 浏览器插件同步台北 `NOAA RCTP` 结算参考标签和说明 +- `/ops` 手机端收口为卡片化视图,保留桌面表格 + + +## Unreleased ## 1.5.0 - 2026-03-21 diff --git a/FRONTEND_REDESIGN_REPORT.md b/FRONTEND_REDESIGN_REPORT.md index 4ae77275..98d1b1e4 100644 --- a/FRONTEND_REDESIGN_REPORT.md +++ b/FRONTEND_REDESIGN_REPORT.md @@ -1,4 +1,4 @@ -# 前端交付与重构报告(v1.5.0) +# 前端交付与重构报告(v1.5.1) 最后更新:`2026-03-14` diff --git a/README.md b/README.md index e7f80b76..407f03f7 100644 --- a/README.md +++ b/README.md @@ -162,5 +162,5 @@ docker compose logs -f polyweather | egrep "polymarket wallet activity watcher s ## Version -- Version: `v1.5.0` +- Version: `v1.5.1` - Last Updated: `2026-03-21` diff --git a/README_ZH.md b/README_ZH.md index 4686dbe1..cd6c0234 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -177,5 +177,5 @@ docker compose logs -f polyweather | egrep "polymarket wallet activity watcher s ## 当前版本 -- 版本:`v1.5.0` +- 版本:`v1.5.1` - 文档最后更新:`2026-03-21` diff --git a/VERSION b/VERSION index bc80560f..26ca5946 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.0 +1.5.1 diff --git a/docs/API_ZH.md b/docs/API_ZH.md index 844dc7b8..e4780cc4 100644 --- a/docs/API_ZH.md +++ b/docs/API_ZH.md @@ -1,4 +1,4 @@ -# PolyWeather API 文档(v1.5.0) +# PolyWeather API 文档(v1.5.1) 最后更新:`2026-03-21` diff --git a/docs/SUPABASE_SETUP_ZH.md b/docs/SUPABASE_SETUP_ZH.md index 0f0d244a..f425d5ef 100644 --- a/docs/SUPABASE_SETUP_ZH.md +++ b/docs/SUPABASE_SETUP_ZH.md @@ -1,4 +1,4 @@ -# Supabase + 登录 + 支付接入说明(v1.5.0) +# Supabase + 登录 + 支付接入说明(v1.5.1) 最后更新:`2026-03-14` diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md index 0f522cdc..e90ad8da 100644 --- a/docs/TECH_DEBT.md +++ b/docs/TECH_DEBT.md @@ -1,4 +1,4 @@ -# 技术债与工程待办(v1.5.0) +# 技术债与工程待办(v1.5.1) 最后更新:`2026-03-20` diff --git a/docs/TECH_DEBT_ZH.md b/docs/TECH_DEBT_ZH.md index 0f522cdc..e90ad8da 100644 --- a/docs/TECH_DEBT_ZH.md +++ b/docs/TECH_DEBT_ZH.md @@ -1,4 +1,4 @@ -# 技术债与工程待办(v1.5.0) +# 技术债与工程待办(v1.5.1) 最后更新:`2026-03-20` diff --git a/docs/payments/POLYGONSCAN_VERIFY.md b/docs/payments/POLYGONSCAN_VERIFY.md index 3756bdac..e06bfec7 100644 --- a/docs/payments/POLYGONSCAN_VERIFY.md +++ b/docs/payments/POLYGONSCAN_VERIFY.md @@ -1,4 +1,4 @@ -# PolyWeatherCheckout PolygonScan 验证(v1.5.0) +# PolyWeatherCheckout PolygonScan 验证(v1.5.1) 最后更新:`2026-03-20` diff --git a/frontend/components/account/AccountCenter.module.css b/frontend/components/account/AccountCenter.module.css index c5ad7174..5143ba96 100644 --- a/frontend/components/account/AccountCenter.module.css +++ b/frontend/components/account/AccountCenter.module.css @@ -390,6 +390,10 @@ .cards { grid-template-columns: 1fr; } + + .metaList dd { + max-width: 56%; + } } @media (max-width: 560px) { @@ -414,5 +418,74 @@ flex-direction: column; align-items: stretch; } + + .ghostBtn, + .primaryBtn { + min-height: 40px; + justify-content: center; + } + + .title { + font-size: 22px; + } + + .subtitle { + font-size: 12px; + } + + .heroCard { + grid-template-columns: 1fr; + gap: 12px; + } + + .avatar { + width: 56px; + height: 56px; + border-radius: 16px; + font-size: 20px; + } + + .heroMain h2 { + font-size: 22px; + } + + .updatedText { + text-align: left; + } + + .metaList > div { + flex-direction: column; + align-items: flex-start; + gap: 4px; + } + + .metaList dd { + max-width: 100%; + text-align: left; + } + + .commandRow { + flex-direction: column; + align-items: stretch; + } + + .command { + flex: 1 1 auto; + width: 100%; + min-height: 48px; + padding: 10px 12px; + } + + .copyBtn { + width: 100%; + justify-content: center; + } + + .noticeRow, + .errorRow { + width: 100%; + align-items: flex-start; + line-height: 1.5; + } } diff --git a/frontend/components/dashboard/Dashboard.module.css b/frontend/components/dashboard/Dashboard.module.css index e9441acb..ab3241aa 100644 --- a/frontend/components/dashboard/Dashboard.module.css +++ b/frontend/components/dashboard/Dashboard.module.css @@ -1392,8 +1392,58 @@ } @media (max-width: 768px) { + .root :global(.header) { + height: auto; + min-height: var(--header-height); + align-items: flex-start; + gap: 10px; + padding: 10px 12px; + } + + .root :global(.brand) { + align-items: flex-start; + gap: 8px; + min-width: 0; + } + + .root :global(.header-right) { + flex: 1 1 auto; + justify-content: flex-end; + flex-wrap: wrap; + gap: 8px; + min-width: 0; + } + + .root :global(.lang-switch) { + order: 1; + } + + .root :global(.account-btn), + .root :global(.info-btn) { + padding: 6px 10px; + font-size: 12px; + } + + .root :global(.live-badge) { + order: 4; + padding: 4px 10px; + white-space: nowrap; + } + + .root :global(.refresh-btn) { + order: 5; + } + .root :global(.city-list) { - display: none; + display: flex; + top: auto; + left: 8px; + right: 8px; + bottom: 8px; + width: auto; + max-height: min(36vh, 320px); + border-radius: 14px; + z-index: 920; } .root :global(.detail-panel) { width: 100%; @@ -1401,15 +1451,97 @@ .root { --panel-width: 100%; } + + .root :global(.city-list-header) { + padding: 12px 14px; + font-size: 14px; + } + + .root :global(.city-list-items) { + padding: 6px; + } + + .root :global(.city-group-header) { + padding: 8px 9px; + } + + .root :global(.city-item) { + padding: 8px 9px; + } + + .root :global(.city-item .city-name-text), + .root :global(.city-item .city-temp) { + font-size: 12px; + } + + .root :global(.city-item-info) { + padding-left: 18px; + flex-wrap: wrap; + row-gap: 4px; + } + + .root :global(.panel-header) { + padding: 16px 16px 14px; + } } @media (max-width: 600px) { + .root :global(.header) { + flex-direction: column; + align-items: stretch; + gap: 8px; + padding: 8px 10px; + } + + .root :global(.brand) { + justify-content: space-between; + width: 100%; + } + .root :global(.subtitle) { display: none; } .root :global(.brand h1) { font-size: 16px; } + + .root :global(.header-right) { + width: 100%; + justify-content: flex-start; + gap: 6px; + } + + .root :global(.lang-switch) { + margin-right: auto; + } + + .root :global(.account-btn), + .root :global(.info-btn) { + min-height: 34px; + padding: 6px 9px; + font-size: 11px; + } + + .root :global(.account-btn span), + .root :global(.info-btn span) { + max-width: 88px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .root :global(.live-badge) { + padding: 4px 8px; + font-size: 10px; + letter-spacing: 0.6px; + } + + .root :global(.refresh-btn) { + width: 34px; + height: 34px; + font-size: 16px; + } + .root :global(.hero-value) { font-size: 42px; } @@ -1420,6 +1552,47 @@ .root :global(.hero-item .value) { font-size: 14px; } + + .root :global(.city-list) { + left: 6px; + right: 6px; + bottom: 6px; + max-height: min(40vh, 300px); + } + + .root :global(.city-list-header) { + padding: 10px 12px; + } + + .root :global(.city-group-title) { + font-size: 11px; + } + + .root :global(.city-item-main) { + gap: 6px; + } + + .root :global(.city-item-info) { + font-size: 9px; + } + + .root :global(.panel-header) { + padding: 14px 14px 12px; + } + + .root :global(.city-marker:hover) { + transform: none; + } + + .root :global(.marker-bubble) { + min-width: 48px; + min-height: 32px; + padding: 6px 10px; + } + + .root :global(.marker-name) { + font-size: 11px; + } } /* ── History Modal ── */ @@ -1490,6 +1663,7 @@ font-weight: 600; color: var(--text-primary); margin: 0; + min-width: 0; } .root :global(.future-modal-title-with-actions) { display: flex; @@ -1658,6 +1832,32 @@ } @media (max-width: 640px) { + .root :global(.modal-content) { + border-radius: 14px; + max-height: calc(100vh - 16px); + } + + .root :global(.modal-content.history-modal), + .root :global(.modal-content.large.future-modal) { + width: min(100vw - 12px, 100%); + max-width: none; + } + + .root :global(.modal-header) { + padding: 14px 14px 12px; + align-items: flex-start; + gap: 12px; + } + + .root :global(.modal-header h2) { + font-size: 15px; + line-height: 1.35; + } + + .root :global(.modal-body) { + padding: 14px; + } + .root :global(.history-modal .history-stats) { grid-template-columns: 1fr; } @@ -2195,6 +2395,93 @@ } } +@media (max-width: 640px) { + .root :global(.future-modal-body) { + gap: 12px; + padding-right: 0; + } + + .root :global(.future-v2-card), + .root :global(.future-modal-section) { + border-radius: 12px; + padding: 12px; + } + + .root :global(.future-v2-hero-main) { + align-items: flex-start; + gap: 12px; + } + + .root :global(.future-v2-hero-temp) { + font-size: 44px; + } + + .root :global(.future-v2-hero-divider) { + height: 44px; + } + + .root :global(.future-v2-hero-obs) { + font-size: 18px; + } + + .root :global(.future-v2-mini-grid) { + grid-template-columns: 1fr; + } + + .root :global(.future-v2-mini-item strong) { + font-size: 20px; + } + + .root :global(.future-v2-main-chart) { + min-height: 280px; + } + + .root :global(.future-chart-wrapper) { + height: 190px; + } + + .root :global(.future-trend-card) { + padding: 10px; + } + + .root :global(.future-trend-value) { + font-size: 16px; + } + + .root :global(.future-trend-note), + .root :global(.future-text-block) { + font-size: 12px; + line-height: 1.6; + } + + .root :global(.future-front-meta) { + gap: 8px; + } + + .root :global(.future-front-pill) { + width: 100%; + justify-content: center; + } + + .root :global(.detail-grid) { + grid-template-columns: 1fr; + } + + .root :global(.detail-mini-chart) { + height: 170px; + } + + .root :global(.detail-source-link) { + padding: 10px 12px; + align-items: flex-start; + flex-direction: column; + } + + .root :global(.detail-source-label) { + text-align: left; + } +} + @media (max-width: 1200px) { .root :global(.future-trend-grid) { grid-template-columns: repeat(2, minmax(0, 1fr)); diff --git a/frontend/components/ops/OpsDashboard.tsx b/frontend/components/ops/OpsDashboard.tsx index d2d73c51..08b8683a 100644 --- a/frontend/components/ops/OpsDashboard.tsx +++ b/frontend/components/ops/OpsDashboard.tsx @@ -142,6 +142,23 @@ async function readJson(url: string): Promise { return response.json() as Promise; } +function MobileField({ + label, + value, + mono = false, +}: { + label: string; + value: string; + mono?: boolean; +}) { + return ( +
+
{label}
+
{value}
+
+ ); +} + export function OpsDashboard() { const [health, setHealth] = useState(null); const [status, setStatus] = useState(null); @@ -328,9 +345,9 @@ export function OpsDashboard() { }, [grantEmail, grantPoints, incidentReasonFilter, loadLeaderboard, loadMemberships, loadPaymentIncidents, loadUsers, searchQuery]); return ( -
-
-
+
+
+
Ops @@ -344,20 +361,20 @@ export function OpsDashboard() { EMOS {rolloutDecision?.decision || "hold"}
-
-

PolyWeather Ops

-

- 直接挂在现有域名下的轻量运营页。先做只读运维视图,把系统状态、支付运行态和当前登录态聚合起来。 -

+
+

PolyWeather Ops

+

+ 直接挂在现有域名下的轻量运营页。先做只读运维视图,把系统状态、支付运行态和当前登录态聚合起来。 +

+
+
+
+ 刷新时间: {formatDateTime(refreshedAt)} +
-
-
- 刷新时间: {formatDateTime(refreshedAt)} - -
{error ? ( @@ -507,17 +524,17 @@ export function OpsDashboard() { -
-
- 支付异常单 - 只显示已明确标记失败的支付确认事故。 -
-
- { + const next = event.target.value; setIncidentReasonFilter(next); void loadPaymentIncidents(next); }} @@ -528,15 +545,46 @@ export function OpsDashboard() { - + +
-
- - -
- + + +
+ {paymentIncidents.map((item) => ( +
+
+
+
{item.payload?.reason || "-"}
+
{formatDateTime(item.created_at)}
+
+ +
+
+ + + + +
+
+ ))} + {!paymentIncidents.length ? ( +
+ 暂无支付异常单 +
+ ) : null} +
+
+
@@ -588,15 +636,32 @@ export function OpsDashboard() { 当前有效订阅用户、注册时间和到期时间。 -
-
- 当前有效会员数:{memberships.length} -
-
-
+
+ {memberships.map((item) => ( +
+
{item.email || "-"}
+
{item.username || "-"}
+
+ + +
+
+ ))} + {!memberships.length ? ( +
+ 暂无有效会员 +
+ ) : null} +
+
时间
@@ -642,7 +707,7 @@ export function OpsDashboard() { placeholder="telegram id / username / email" className="h-10 flex-1 rounded-xl border border-slate-800 bg-slate-950 px-3 text-sm text-slate-100 outline-none ring-0" /> - diff --git a/frontend/package.json b/frontend/package.json index 84c9fab1..11d097b7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "polyweather-frontend", - "version": "1.5.0", + "version": "1.5.1", "private": true, "scripts": { "dev": "next dev",