From b87ba3f8f41dc727fa342805f123644b57dc9f4b Mon Sep 17 00:00:00 2001 From: sloop Date: Mon, 20 Jul 2026 02:53:19 +0800 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20=E8=AE=B0=E5=BD=95=E5=BB=B6?= =?UTF-8?q?=E8=BF=9F=E5=8D=A1=E7=89=87=E5=8F=91=E5=B8=83=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...2026-07-20-stats-latency-seconds-design.md | 13 +++ .../plans/2026-07-20-stats-latency-seconds.md | 94 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 docs/plans/2026-07-20-stats-latency-seconds-design.md create mode 100644 docs/plans/2026-07-20-stats-latency-seconds.md diff --git a/docs/plans/2026-07-20-stats-latency-seconds-design.md b/docs/plans/2026-07-20-stats-latency-seconds-design.md new file mode 100644 index 0000000..21d1d36 --- /dev/null +++ b/docs/plans/2026-07-20-stats-latency-seconds-design.md @@ -0,0 +1,13 @@ +# 统计延迟卡片秒数展示设计 + +## 目标 + +统计页红框中的平均延迟、P95 延迟、P99 延迟和最大 / 最小延迟卡片统一以秒为单位展示,并固定保留 1 位小数。最近记录列表中的延迟展示保持现状,不纳入本次改动。 + +## 方案 + +复用 `frontend/src/features/stats/StatsPage.tsx` 现有的 `formatLatency` helper:将后端返回的毫秒值除以 1000,再使用 `Intl.NumberFormat` 配置 `minimumFractionDigits: 1` 和 `maximumFractionDigits: 1`,最后追加 `s` 单位。四张质量卡片继续通过同一个 helper 渲染,确保单值和最大 / 最小组合一致。 + +## 测试与发布 + +在 `StatsPage.test.tsx` 中补充卡片展示断言,覆盖毫秒到秒的换算、固定 1 位小数和最大 / 最小组合,同时确认最近记录仍显示毫秒。发布前运行前端测试、生产构建、发布脚本 harness,以及 `release_no_apple_signing_test.sh`,确认 GitHub Actions CI 没有 Apple 账号签名、公证或证书导入逻辑。Apple 签名辅助脚本仅供本地 macOS 打包使用,不属于本次 CI 变更范围。 diff --git a/docs/plans/2026-07-20-stats-latency-seconds.md b/docs/plans/2026-07-20-stats-latency-seconds.md new file mode 100644 index 0000000..ca9e522 --- /dev/null +++ b/docs/plans/2026-07-20-stats-latency-seconds.md @@ -0,0 +1,94 @@ +# 统计延迟卡片秒数展示实施计划 + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** 将统计页四张请求质量卡片的延迟从毫秒改为秒,并固定保留 1 位小数,同时完成软件发布闭环。 + +**Architecture:** 保留后端毫秒数据协议,仅在统计页的卡片展示 helper 中进行单位转换和格式化。最近记录列表继续显示整数毫秒。发布前通过既有的无 Apple 签名 CI harness 审计 GitHub Actions 工作流,不改动仅供本地 macOS 使用的签名脚本。 + +**Tech Stack:** React 19、Ant Design、Vitest、Vite、GitHub Actions、GitHub CLI。 + +--- + +### Task 1:为延迟卡片补充失败回归测试 + +**Files:** +- Modify: `frontend/src/features/stats/StatsPage.test.tsx` +- Test: `frontend/src/features/stats/StatsPage.test.tsx` + +**Step 1: Write the failing test** + +在现有统计页测试中断言:321.4 毫秒显示为 `0.3 s`,880 毫秒显示为 `0.9 s`,1200 毫秒显示为 `1.2 s`,最大 / 最小显示为 `1.5 s / 0.1 s`;同时断言最近记录仍显示 `321 ms`。 + +**Step 2: Run test to verify it fails** + +Run: `npm --prefix frontend test -- --run src/features/stats/StatsPage.test.tsx` + +Expected: FAIL because the cards currently display integer millisecond values. + +### Task 2:实现卡片延迟秒数格式化 + +**Files:** +- Modify: `frontend/src/features/stats/StatsPage.tsx:52-54` + +**Step 1: Write minimal implementation** + +将 `formatLatency` 的输入毫秒值除以 1000,使用本地化数字格式固定 1 位小数,并将单位从 `ms` 改为 `s`。不修改最近记录的渲染逻辑。 + +**Step 2: Run test to verify it passes** + +Run: `npm --prefix frontend test -- --run src/features/stats/StatsPage.test.tsx` + +Expected: PASS。 + +### Task 3:验证前端和发布脚本 + +**Files:** +- Check: `frontend/src/features/stats/StatsPage.tsx` +- Check: `frontend/src/features/stats/StatsPage.test.tsx` +- Check: `.github/workflows/release.yml` +- Check: `.github/workflows/dev-ci.yml` + +**Step 1: Run focused and full frontend harnesses** + +Run: `npm --prefix frontend test -- --run src/features/stats/StatsPage.test.tsx` + +Run: `npm --prefix frontend test` + +Run: `npm --prefix frontend run build` + +**Step 2: Run CI/release harnesses** + +Run: `bash scripts/test/release_no_apple_signing_test.sh` + +Run: `bash scripts/test/release_updater_signing_key_test.sh` + +Run: `bash scripts/test/release_version_helpers_test.sh && bash scripts/test/sync_release_metadata_test.sh && bash scripts/test/collect_release_assets_test.sh && bash scripts/test/release_updater_manifest_test.sh && bash scripts/test/package_local_release_test.sh && bash scripts/test/release_msvc_spub_test.sh` + +**Step 3: Check diff hygiene** + +Run: `git diff --check` + +### Task 4:提交并执行软件发布闭环 + +**Files:** +- Commit: `docs/plans/2026-07-20-stats-latency-seconds-design.md` +- Commit: `docs/plans/2026-07-20-stats-latency-seconds.md` +- Commit: `frontend/src/features/stats/StatsPage.test.tsx` +- Commit: `frontend/src/features/stats/StatsPage.tsx` + +**Step 1: Create scoped commits** + +只暂存本次任务文件,使用中文提交信息;不带入工作区已有的后端、账户页和图片改动。 + +**Step 2: Rebase and push** + +拉取 `origin/main` 和 tags,将工作分支 rebase 到最新 `origin/main`,重新运行本地验证后推送 `codex/stats-latency-seconds`。 + +**Step 3: Monitor CI and merge PR** + +只监控本次推送触发的 workflow,成功后创建并以 rebase 方式合并 PR;若 CI 失败,先定位具体 job 和步骤,做最小修复后从最新 `origin/main` 重新开始。 + +**Step 4: Tag and monitor release** + +在合并后的最新 `main` 上使用下一个版本 tag `v1.6.7`,推送 tag,并监控 release workflow 到终态;若失败,按发布闭环从最新 `main` 新建修复分支处理。 From 6d0fb134e4ff73fd8b77bd38cc65604a6af05cf3 Mon Sep 17 00:00:00 2001 From: sloop Date: Mon, 20 Jul 2026 02:53:44 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=B0=86=E5=BB=B6=E8=BF=9F?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=94=B9=E4=B8=BA=E7=A7=92=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/stats/StatsPage.test.tsx | 5 +++++ frontend/src/features/stats/StatsPage.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/features/stats/StatsPage.test.tsx b/frontend/src/features/stats/StatsPage.test.tsx index 8304087..104e24d 100644 --- a/frontend/src/features/stats/StatsPage.test.tsx +++ b/frontend/src/features/stats/StatsPage.test.tsx @@ -102,6 +102,11 @@ describe("StatsPage", () => { expect(screen.getByText("P95 延迟")).toBeInTheDocument(); expect(screen.getByText("P99 延迟")).toBeInTheDocument(); expect(screen.getByText("最大 / 最小延迟")).toBeInTheDocument(); + expect(screen.getByText("0.3 s")).toBeInTheDocument(); + expect(screen.getByText("0.9 s")).toBeInTheDocument(); + expect(screen.getByText("1.2 s")).toBeInTheDocument(); + expect(screen.getByText("1.5 s / 0.1 s")).toBeInTheDocument(); + expect(screen.getByText("321 ms")).toBeInTheDocument(); expect(screen.queryByText("余额变化")).not.toBeInTheDocument(); expect(screen.getByText("US$1.23")).toBeInTheDocument(); expect(screen.queryByText("总 Token")).not.toBeInTheDocument(); diff --git a/frontend/src/features/stats/StatsPage.tsx b/frontend/src/features/stats/StatsPage.tsx index ba1e9af..df0cd2b 100644 --- a/frontend/src/features/stats/StatsPage.tsx +++ b/frontend/src/features/stats/StatsPage.tsx @@ -51,7 +51,7 @@ function formatCurrency(language: AppLanguage, value: number): string { } function formatLatency(language: AppLanguage, value: number): string { - return `${new Intl.NumberFormat(language, { maximumFractionDigits: 0 }).format(value)} ms`; + return `${new Intl.NumberFormat(language, { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(value / 1000)} s`; } function eventStatusColor(status: string): string {