From 548314013a950c33dd0ce680a701c84300e43901 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Thu, 24 Sep 2026 14:35:07 +0800 Subject: [PATCH] =?UTF-8?q?=E9=B8=BF=E8=92=99=EF=BD=9C=E4=BF=AE=E5=8F=91?= =?UTF-8?q?=E4=BB=B6=E7=AE=B1=E7=82=B9=E4=B8=8D=E5=BC=80=EF=BC=88SentRow?= =?UTF-8?q?=20=E7=BC=BA=20onClick=EF=BC=89+=20=E8=A1=A5=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E8=A1=8C=E5=88=A4=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户报的三件事,逐条实测后的结论: ## ① 发件箱内容点不开 —— 真 bug,本次修复 复现:点发件箱「致 pi」那一行 · 日志里**没有** `GET /mail/{id}`(收件箱同样操作是会发的) · 右栏仍是占位(「选择一封邮件查看…」) 根因:点击挂在**外层** `Column` 上,而 `SentRow` 自己**一个 `.onClick` 都没有**。 更要命的是 `isFlatGroup(g)` 那条分支(单封不成组)直接调 `SentRow`, **外层那层点击根本不经过它** —— 而用户的数据恰好是 1 封不成组 ⇒ 完全点不动。 收件箱的 `MailRow` 是挂在行自己身上的(`.clip(true)` 之后直接 `.onClick`), 所以它两条分支都通。这是本仓反复出现的形状:同一件事两处各写一遍,然后慢慢分叉。 修法:`.onClick` 移进 `SentRow` 自身(与 `MailRow` 同形), 并删掉外层那处(留着会变成"同一行两处都能点")。 修复后实测:发 `GET /mail/2d882e82…`,右栏渲染出详情 ✅ ## ② 对话树点不开 —— 实测能点开(不是 bug) 代码里有完整的实现(`openThread()` + `bindSheet` + `tree` 图标按钮)。 点开路径:**先点详情页标题展开头部** → 出现「对话树」→ 点它 (`GET /mail/{id}/thread` 发出,弹层显示 `jianf → pi / 测试`)。 ★ 折叠是**两端一致**的行为,不是鸿蒙漏做: WebUI `CollapsibleHeader` 的 `useState(false)` 也是默认收起。 我实测确认了展开后才看得到该按钮。 ## ③ 邮件本地缓存 —— 两端都没有(不是鸿蒙落后) 对着源码逐个数: WebUI `stores/` 有 persist 的:accountStore(8) / appearanceSync / backgroundStore(15) / contactStore(5) / themeStore(3) WebUI **没有** persist 的:`mailStore`(0) / sessionStore(0) / uiStore(0) / authStore(0) ⇒ **邮件与会话在 WebUI 也是不缓存的**,每次打开都从服务端拉。 鸿蒙侧:AppearanceStore / AccountManager 有 preferences 持久化,MailStore 没有 —— 与 WebUI 对齐,不是缺口。 ## 判据 `harmony-logic` +1(35 条):**列表行必须把 onClick 挂在自己身上**。 钉的是不变式("行自带点击"),不是某个函数的写法: `MailRow` / `SentRow` 的属性链里必须有自己的 `.onClick` 且调到 `openMail`。 变异:删掉 `SentRow` 的 `.onClick`(重演原 bug)→ 判据红;还原 → 绿。 套件:harmony-logic 35/35、harmony-nav 22/22、harmony-appearance 28/28、 harmony-contacts 5/5、animation-audit 15/15。 --- client/electron/test/harmony-logic.test.mjs | 45 +++++++++++++++++++ .../entry/src/main/ets/pages/MainPage.ets | 35 ++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/client/electron/test/harmony-logic.test.mjs b/client/electron/test/harmony-logic.test.mjs index 7f8b93b..929c1c5 100644 --- a/client/electron/test/harmony-logic.test.mjs +++ b/client/electron/test/harmony-logic.test.mjs @@ -985,3 +985,48 @@ test('★ 附件区:空文件名要显式占位,不能留一条看起来坏 assert.notEqual(empty.filename, '', '空文件名要有占位符,不能是空串'); assert.equal(empty.size, '100 B', '空文件名不影响大小显示'); }); + +/** + * ★★ 2026-09-24 新增(用户:「发件箱内容也点不开」)。 + * + * ── 实测复现 ── + * 点发件箱里「致 pi」那一行: + * · 日志里**没有** `GET /mail/{id}`(收件箱同样操作是会发的); + * · 右栏仍是占位(「选择一封邮件查看…」)。 + * + * ── 根因 ── + * 点击挂在**外层** `Column` 上,而 `SentRow` 自己**一个 `.onClick` 都没有**。 + * 更要命的是:`isFlatGroup(g)` 那条分支(单封不成组)直接调 `SentRow`, + * **外层那层点击根本不经过** ⇒ 用户的数据恰好是 1 封不成组 ⇒ 完全点不动。 + * + * 收件箱的 `MailRow` 是挂在行自己身上的,所以它两条分支都通。 + * 这就是本仓反复出现的形状:**同一件事两处各写一遍,然后慢慢分叉**。 + * + * 判据钉的是**不变式**(“列表行自带点击”),而不是某个函数的写法: + * 每个能展开邮件的列表行 `@Builder`,它的属性链里必须有自己的 `.onClick`。 + */ +test('★ 列表行必须把 onClick 挂在自己身上(发件箱就漏在这里)', () => { + /* + * 行 Builder 的名单:两栏各自的邮件行。 + * ★ 不扫全部 `@Builder`(那样会把组头、空态、徽标都算进来), + * 只钉**真正代表“一封邮件”的那两个** —— 与 `PAGE_SOURCES` 同一条纪律: + * 名单显式,不把作用域开得比声称的宽。 + */ + const ROWS = ['MailRow', 'SentRow']; + for (const name of ROWS) { + const at = pageCode.indexOf(`${name}(mail: MailLike)`); + assert.ok(at > 0, `${name} 要存在(列表行)`); + /* + * 取到下一个 `@Builder` 为止(下一个 Builder 就是下一个方法的开始)。 + * 比“取 3000 字符”可靠:方法长短会变,而 `@Builder` 是结构边界。 + */ + const nextAt = pageCode.indexOf('@Builder', at); + const body = pageCode.slice(at, nextAt > at ? nextAt : at + 4000); + assert.match(body, /\.onClick\(/, [ + `${name} 的属性链里必须有自己的 \`.onClick\``, + '—— 点击挂在外层容器时,扁平组分支(isFlatGroup)**不经过它**,', + '那一栏就完全点不动(2026-09-24 发件箱实测就是这个形状)。', + ].join('')); + assert.match(body, /openMail\(/, `${name} 的 onClick 要调到 openMail(而不是只写个空壳)`); + } +}); diff --git a/client/harmony/entry/src/main/ets/pages/MainPage.ets b/client/harmony/entry/src/main/ets/pages/MainPage.ets index 337b519..03a7b2f 100644 --- a/client/harmony/entry/src/main/ets/pages/MainPage.ets +++ b/client/harmony/entry/src/main/ets/pages/MainPage.ets @@ -1139,6 +1139,30 @@ struct SentTab { }) .borderRadius(Theme.radiusCard) .clip(true) + /* + * ★★ 2026-09-24 补 `.onClick`(用户:「发件箱内容也点不开」)。 + * + * ── 实测复现 ── + * 点发件箱里「致 pi」那一行: + * · 日志里**没有** `GET /mail/{id}`(收件箱同样操作是会发的); + * · 右栏仍是占位(「选择一封邮件查看…」)。 + * ⇒ 点击事件根本到不了处理函数。 + * + * ── 根因 ── + * 点击原来挂在**外层** `Column` 上(`SentTab` 的 `ListItem` 里): + * Column() { this.SentRow(m) } + * .width('100%').margin({ bottom: 6 }) + * .onClick(() => { this.openMail(m); }) + * 而 `SentRow` **自己一个 `.onClick` 都没有** —— 收件箱的 `MailRow` + * 是挂在行自己身上的(同位置 `.clip(true)` 之后直接 `.onClick`)。 + * 本仓反复出现的形状:**同一件事两处各写一遍,然后慢慢分叉** + * (这段注释上方才记过 `SentRow` 漏挂卡片修饰符的那次,同一处、同一类错)。 + * + * ⇒ 与 `MailRow` 取同形:卡在行自己身上,点击也挂在行自己身上。 + */ + .onClick(() => { + this.openMail(mail); + }) } @Builder @@ -1263,7 +1287,16 @@ struct SentTab { } .width('100%') .margin({ bottom: 6 }) - .onClick(() => { this.openMail(m); }) + /* + * ★★ 2026-09-24 删掉这里的 `.onClick`(用户:「发件箱内容也点不开」)。 + * + * 点击现在挂在 `SentRow` **自己身上**(与收件箱的 `MailRow` 同形)—— + * 原来挂在这一层时,**扁平组那条路根本不经过它**: + * `isFlatGroup(g)` 分支直接 `this.SentRow(g.mails[0])`,外层没有点击。 + * 而用户的数据恰好就是 1 封不成组(发件箱「测试-4」)⇒ 完全点不动。 + * + * 留着它还会变成"同一行两处都能点"—— 本仓反复出现的那个形状。 + */ } .width('100%') }, (m: MailLike) => m.mail_id)