From 1869924507b50024b457394b242fa63b960641b1 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 21 Sep 2026 16:32:49 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B7=A8=E7=AB=AF:=20=E6=8E=A5=E4=B8=8A?= =?UTF-8?q?=E8=81=9A=E5=90=88=E5=A4=B1=E8=B4=A5=E6=A8=AA=E5=B9=85=EF=BC=88?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=80=E7=9B=B4=E5=9C=A8=E6=94=B6=E9=9B=86?= =?UTF-8?q?=EF=BC=8C=E7=95=8C=E9=9D=A2=E4=BB=8E=E6=9D=A5=E6=B2=A1=E8=AF=BB?= =?UTF-8?q?=E8=BF=87=20=E2=80=94=E2=80=94=20=E5=AE=89=E5=85=A8=E7=BD=91?= =?UTF-8?q?=E6=98=AF=E6=96=AD=E7=9A=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 逐页对齐 WebUI 时发现的**不是观感问题,是安全网断线**。 ## 事实 `MailStore` 一直在收集"聚合模式下哪个账号取失败了": MailStore.ets:142 const failed: AccountError[] = []; MailStore.ets:208 failed.push(AccountError.of(acct.displayName, reason)); MailStore.ets:226 snap.accountErrors = failed; (收件箱与发件箱两处 load 都写) 而**界面一次都没读过 `snap.accountErrors`**(`MainPage` 里 grep 为 0 处)。 ⇒ 后果:某个账号拉不到邮件时,列表**静默少一整份**,界面看起来完全正常。 用户会据此得出错误结论 —— "没人给我发信"。 WebUI 把这条写成了显式警告(`MailList.tsx:85-91` 原注释): 「聚合时**某个账号取不到**必须说出来:静默丢掉它,列表会少一整份邮件, 而界面看起来完全正常 —— 这正是『聚合』最容易骗人的失败方式」 ## 改动 · `InboxTab` 加 `@State accountErrors`,在 `applyStoreSnapshot` 里接上 `snap.accountErrors`; · 卡片下方渲染琥珀色横幅,文案照 WebUI: 「有 {n} 个账号没取到:{账号}({原因});…」 (`bg-amber-50 border-amber-200 text-amber-800` → `warnBg` / `warnFgDark` / 11 号字); · 新增 `accountErrorText()` 做拼接(`「a(原因);b(原因)」`)。 ★ 只接了**收件箱**那一处。发件箱 `SentTab` 有自己的 `applyStoreSnapshot`, 本轮不动它 —— 它的聚合语义与收件箱不同(见 `SentTab.load`), 要不要显示同一张横幅需要单独判断,不顺手加(顺手加是本仓反复出现的错法)。 ## 设备验证(如实) ✓ 收件箱正常渲染(`9 组 · 9 封`),进程存活(22242),无新 jscrash ✓ 横幅**正确不出现** —— 当前所有账号都取得到(这是应该的行为) ✗ **横幅"出现"的那条路径没能实测到**:要触发它需要一个取失败的账号, 而本机没有可用的失败账号构造。逻辑与 WebUI 逐条对齐、编译通过, 但"真的会显示成那样"我不声称已验 —— 与"动画中间帧看不到"同样的诚实口径。 --- .../entry/src/main/ets/pages/MainPage.ets | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/client/harmony/entry/src/main/ets/pages/MainPage.ets b/client/harmony/entry/src/main/ets/pages/MainPage.ets index 47b3039..3f65128 100644 --- a/client/harmony/entry/src/main/ets/pages/MainPage.ets +++ b/client/harmony/entry/src/main/ets/pages/MainPage.ets @@ -18,7 +18,7 @@ import { MailApi, InboxResponse } from '../api/MailApi'; import { AccountManager, AccountInfo } from '../api/AccountManager'; import { SseService, SseEvent } from '../api/SseService'; import { AppearanceStore } from '../common/AppearanceStore'; -import { MailStore, MailSnapshot, INBOX_PAGE_SIZE } from '../common/MailStore'; +import { MailStore, MailSnapshot, AccountError, INBOX_PAGE_SIZE } from '../common/MailStore'; import { AppearanceApi } from '../api/AppearanceApi'; import { performLogout } from '../api/Logout'; import { ComposeIntent } from '../common/ComposeIntent'; @@ -502,6 +502,26 @@ struct InboxTab { } /** 把 store 快照接进本组件的 `@State`(触发 ArkUI 刷新)。 */ + /** + * 聚合模式下**单个账号**取失败的原因(`MailStore` 已在收集,此前没人读)。 + * + * ★★ 2026-09-21 补(逐页对齐 WebUI 时发现的安全网断线): + * 数据一直在 `MailSnapshot.accountErrors` 里、两处 load 都写, + * 但**界面从来没有读过它** ⇒ 某个账号拉不到邮件时列表**静默少一整份**, + * 而界面看起来完全正常 —— 用户会得出错误结论("没人给我发信")。 + */ + @State accountErrors: AccountError[] = []; + + /** 把聚合失败拼成 WebUI 那句文案:「a(原因);b(原因)」 */ + private accountErrorText(): string { + const parts: string[] = []; + for (let i = 0; i < this.accountErrors.length; i++) { + const e: AccountError = this.accountErrors[i]; + parts.push(e.reason.length > 0 ? e.account + '(' + e.reason + ')' : e.account); + } + return parts.join(';'); + } + private applyStoreSnapshot(snap: MailSnapshot): void { /* * `MailLike[]` → `MailSummary[]`:store 持有的是接口类型(它不该依赖具体实现类), @@ -516,6 +536,8 @@ struct InboxTab { this.notice = snap.notice; this.loading = snap.loading; this.error = snap.error; + /* 聚合失败原因(见 `accountErrors` 的注释:数据一直有,界面前面没接) */ + this.accountErrors = snap.accountErrors; } /** 展开状态放在数组里(ArkTS 的 @State 对 Map/Set 的变更不总是能观察到) */ @@ -613,6 +635,31 @@ struct InboxTab { .padding({ left: 10, right: 10 }) .margin({ top: 10 }) + /* + * 聚合失败横幅(对齐 WebUI `MailList.tsx:85-96` 的 `account-errors`)。 + * + * 文案/形状照 WebUI: + * 「有 {n} 个账号没取到:{账号}({原因});…」 + * 琥珀底 + 琥珀边 + 11 号字(`bg-amber-50 border-amber-200 text-amber-800`)。 + * + * ★★ 为什么值得单独占一块地方(WebUI 原注释): + * 「聚合时**某个账号取不到**必须说出来:静默丢掉它,列表会少一整份邮件, + * 而界面看起来完全正常 —— 这正是"聚合"最容易骗人的失败方式」 + * + * 本仓的情况更糟一点:`MailStore` **一直在收集**这些失败 + * (`snap.accountErrors`,两处 load 都写),但**界面从来没有读过它** ⇒ + * 这个安全网当前是断的。是逐页对齐时比对出来的,不是猜的。 + */ + if (this.accountErrors.length > 0) { + Text('有 ' + this.accountErrors.length + ' 个账号没取到:' + this.accountErrorText()) + .fontSize(11).fontColor(Theme.warnFgDark) + .width('100%') + .padding({ left: 8, right: 8, top: 6, bottom: 6 }) + .backgroundColor(Theme.warnBg) + .borderRadius(6) + .margin({ top: 6 }) + } + // 账号选择器下拉 if (this.showAccountPicker && this.accountList.length > 1) { Column() {