From bea26b885a36ae136d9933c9348b050944fb1585 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 21 Sep 2026 21:15:33 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B7=A8=E7=AB=AF:=20=E4=BF=AE=20`harmony-admi?= =?UTF-8?q?n`=20=E7=9A=84**=E9=99=88=E6=97=A7=E5=88=A4=E6=8D=AE**=EF=BC=88?= =?UTF-8?q?=E7=82=B9=E5=90=8D=E4=BA=86=E4=B8=80=E4=B8=AA=E5=B7=B2=E8=A2=AB?= =?UTF-8?q?=E6=8B=86=E6=8E=89=E7=9A=84=20builder=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `harmony-admin` 在我这轮之前就是红的,我之前把它归到"与本轮无关"—— 这次认真看了,它报的是**真问题的一种**,但**报错了对象**: 断言:SecuritySection 必须在 Scroll 内部 实际:SettingsPage.ets 里**已经没有** `SecuritySection` 了 2026-09-21 我按 WebUI `AccountPage` 把 `SecuritySection` 拆成了两段: · `PasswordSection` —— 修改密码 · `LoginSection` —— 登录状态 / 退出登录 两段**都在** Scroll 里(`SettingsPage.ets:637/681/695/699`), 只是名字变了 ⇒ 判据守着一个**历史名字**,与它要守护的东西脱钩了。 ## 改成钉行为,而不是放宽 这条判据当初抓到的危害是具体的:账号列表 `layoutWeight(1)` 占满剩余高度, 后面的 section 被挤出可视区,而「退出登录」正好在最下面 ⇒ **退不出去**。 这个危害跟"那个 builder 叫什么名字"无关 ⇒ 判据应该钉**可滚入口**: ProfileSection / PasswordSection / LoginSection / AdminSection 四类内容各自都要在 Scroll 里 并单独再钉一次 `LoginSection` —— 「退不出去」是这条判据的立身之本, 不该混在四元组里被一次循环顺手覆盖。 ## 变异验证(证明不是放宽) 把 `this.LoginSection()` 从 Scroll 里挪出去(模拟原 bug 的形状): ⇒ `pass 29 / fail 1`,报「★ LoginSection 必须在 Scroll **内部**」 恢复:`pass 30 / fail 0` ★ 教训:判据里的**标识符**是判据的**实现细节**,不是判据的**意图**。 重构改名(拆 builder)不算放宽,但判据必须跟着意图走 —— 否则它就从"守卫"退化成"考古"。 --- client/electron/test/harmony-admin.test.mjs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/client/electron/test/harmony-admin.test.mjs b/client/electron/test/harmony-admin.test.mjs index 1905c70..7560b2e 100644 --- a/client/electron/test/harmony-admin.test.mjs +++ b/client/electron/test/harmony-admin.test.mjs @@ -487,11 +487,27 @@ test('★ 「我的」页整页一个滚动容器(排在 flex-1 之后的 sect } assert.ok(end > start, 'Scroll 的花括号要闭合'); const inside = src.slice(start, end); - for (const sec of ['ProfileSection', 'KeySection', 'SecuritySection', 'AdminSection']) { + /* + * ★★ 2026-09-21 改:`SecuritySection` 已**按 WebUI 拆成两段** + * (`PasswordSection` 改密码 + `LoginSection` 登录状态/退出登录), + * 所以判据不能再点名那个已经不存在的 builder —— 那会变成 + * 「守着一个历史名字」,与它真正要守护的东西(**可滚得到**)脱钩。 + * + * 改成**钉行为**:四类内容各自的可滚入口都要在 Scroll 里。 + * · `ProfileSection` 账号 + * · `PasswordSection` 修改密码(原 SecuritySection 的前半) + * · `LoginSection` 登录状态 + 退出登录(原 SecuritySection 的后半) + * · `AdminSection` 管理入口 + */ + for (const sec of ['ProfileSection', 'PasswordSection', 'LoginSection', 'AdminSection']) { assert.ok(inside.includes(`this.${sec}()`), `★ ${sec} 必须在 Scroll **内部** —— 排在 flex-1 之后会被裁掉且滚不到(WebUI 的注释里就有这个坑)`); } - assert.ok(inside.includes('退出登录') || /SecuritySection/.test(inside), + /* + * 「退不出去」是这条判据当初抓到的**真实危害**(不是"少一段"), + * 所以单独再钉一次:那个动作得真的在可滚动区里。 + */ + assert.ok(inside.includes('this.LoginSection()'), '退出登录要在可滚动区域内(否则退不出去)'); // 滚动容器要挂上下渐隐(与列表同一纪律) assert.match(src, /\.fadingEdge\(true,/, '滚动容器要挂 fadingEdge(WebUI .overflow-y-auto 的 mask-image)');