跨端: 审计补强 —— 邮件行的「抄送 N」+ 断点差异登记 + 两处"看起来有其实没有"的澄清
继续「全面对齐 WebUI 和鸿蒙」。这一轮做的是**逐页对照审计**(子代理通道被
session daemon 的端口占用堵死,改为自己逐处读源码对照)。
## 一、补上邮件行的「抄送 N」(真缺失)
WebUI `MailList.tsx:350` 行上有「抄送 N」,鸿蒙**完全没有**。而数据一直在:
`cc_list` 服务端确实返回(实测回包字段列表里有),只是鸿蒙的 `MailLike`
接口漏了这个字段 ⇒ 一封抄送给多个人的邮件在列表里看不出任何区别。
修法:接口加 `cc_count`,`MailSummary` 加 `cc_list` + `cc_count`,
收件箱/发件箱两处填充派生值,行上按 WebUI 的位置渲染。
**设备实测**(造了一封带 2 个抄送的真邮件):行上出现「抄送 2」,
位置与 WebUI 一致(主题行下方、灰字)。
★ 接口用**数字**而不是 getter:`MailSummary implements MailLike`,
而 ArkTS 的 interface 里不能声明 getter(编译报 "incorrectly implements interface")。
## 二、有意**不抄**附件标记(发现 WebUI 那段是死代码)
WebUI 行上还有一个 📎 + 数量的标记(`MailList.tsx:351-355`)。但核对服务端
**实测回包**:`GET /me/mail/inbox` 既没有 `attachments` 也没有 `has_attachments`
⇒ `mail.attachments?.length ?? 0` **恒为 0**,那个标记在 WebUI 上**从不出现**。
所以鸿蒙这一轮**有意不抄它** —— 照抄一个不工作的东西,只会多一处
"看起来有、永远不亮"的代码。要做这个功能得先让服务端在列表回包带上附件计数
(一次 JOIN 的事),那是独立的一件事,已登记进 `docs/DEBTS.json`
(`mail-list-attachment-count`)。
★ 这一条与鸿蒙 `MailSummary.has_attachments` 那个字段一起处理掉了:
它还留在那里会误导人(服务端永不返回它 ⇒ 恒 false)。
## 三、两端宽屏断点不同 —— 登记 + 判据(此前**无任何记录**)
审计点名要核实的这条确认成立:
WebUI: `NARROW_QUERY = '(max-width: 1023px)'`
含义 = 「三栏(60 导航 + 320 列表 + ≥520 详情 ≈ 900px,再加余量)放不下就退化单栏」
鸿蒙: `isWide = width >= 768`
含义 = 「要不要显示**侧栏**」(鸿蒙内容区是一个窗格,没有并排三栏)
**含义不同,所以数值不同本身不算错** —— 这与手势阈值同一条口径
(语义各自成立时,数值不必强求一致)。但**用户可见的后果**是:768–1023 宽
(常见竖屏平板、窄窗口)下 WebUI 是单栏+底栏、鸿蒙是侧栏+内容,
同一宽度在两端长得不一样。
处理:① 登记进 `docs/DEBTS.json`(`wide-breakpoint-divergence`,
带三个待定选项);② 加判据 —— 它**不**要求两端取值相同,而是要求
「取值可读 + 含义写清 + 差异被登记」三件事同时成立。
★ 写这条判据时又踩了同一坑:用 `code()` 读注释 ⇒ 永远红。
`criteria-hygiene` 判据的头顶就写着"判代码用 code、判理由用 prose"。
## 四、判据
`run-all.mjs` → `checks=505 pass=505 fail=0 skip=0 red=0 broken=0 unreported=0`
(cross-client-theme 15→16)。`hvigorw assembleHap` 成功。
**未验**:附件标记(有意不做);抄送行在**深色**下的对比度未单独验。
This commit is contained in:
@ -760,3 +760,63 @@ test('★ 手写色清册**跨文件**:全 ets 树里每个 `X: string = \'#RR
|
||||
`${n} 与 CSS 的 ${m[1] === 'DARK' ? '.dark' : ':root'} 段不一致`);
|
||||
}
|
||||
});
|
||||
|
||||
test('★ 断点:两端各是多少、含义是什么、差异被登记(不是"两边必须一样")', () => {
|
||||
/*
|
||||
* 2026-09-19 由审计发现:**两端的宽屏断点不同,而且此前没有任何地方记录过**。
|
||||
*
|
||||
* WebUI: `useIsNarrow.ts` 的 `NARROW_QUERY = '(max-width: 1023px)'`
|
||||
* 含义 = 「三栏(60 导航 + 320 列表 + ≥520 详情 ≈ 900px,再加余量)
|
||||
* 放不下就退化单栏」
|
||||
* 鸿蒙: `MainPage.ets` 的 `isWide = width >= 768`
|
||||
* 含义 = 「要不要显示**侧栏**」(鸿蒙的内容区是一个窗格,没有并排三栏)
|
||||
*
|
||||
* ★ 这条判据**不**要求两端取值相同 —— 那会是错的:它们判的本来就不是同一件事
|
||||
* (一个是"三栏放不下",一个是"要不要侧栏")。这与手势阈值同一个口径:
|
||||
* **语义各自成立时,数值不必强求一致**。
|
||||
*
|
||||
* 它要求的是三件事:
|
||||
* ① 两端的取值能被**读出来**(而不是散落在魔法数字里);
|
||||
* ② 两端的**含义**在注释里说清了(后人不必猜"为什么不一样");
|
||||
* ③ 「两者不同」这个事实被**登记**(`docs/DEBTS.json`),
|
||||
* 否则下一个人只会当成漏改 —— 这正是它被发现时的状态。
|
||||
*/
|
||||
const narrowHook = prose(join(ROOT, 'client/electron/src/hooks/useIsNarrow.ts'));
|
||||
/*
|
||||
* ★ 读**原文**(`prose`)而不是剥注释版:本条要判的正是"理由有没有写在代码旁",
|
||||
* 而理由天然在注释里。用 `code()` 会把注释剥掉 ⇒ 永远红。
|
||||
* (这与 `criteria-hygiene` 那条"判代码用 code、判理由用 prose"是同一条纪律,
|
||||
* 我在本文件里又踩了一次。)
|
||||
*/
|
||||
const mainPage = prose(join(HARMONY_ETS, 'pages/MainPage.ets'));
|
||||
|
||||
/* ① 两端取值可读 */
|
||||
const webMq = /NARROW_QUERY\s*=\s*'\(max-width:\s*(\d+)px\)'/.exec(narrowHook);
|
||||
assert.ok(webMq, 'WebUI 的窄屏断点要能从 `NARROW_QUERY` 读出来');
|
||||
const webMax = Number(webMq[1]);
|
||||
|
||||
const hWide = /this\.isWide\s*=\s*\(newValue\.width as number\)\s*>=\s*(\d+)/.exec(mainPage);
|
||||
assert.ok(hWide, '鸿蒙的宽屏阈值要能从 `onAreaChange` 里读出来');
|
||||
const hMin = Number(hWide[1]);
|
||||
|
||||
assert.ok(webMax > 0 && hMin > 0, '两端断点都应是正数');
|
||||
|
||||
/* ② 含义写清了(这是本条判据的主要价值:把"为什么不同"钉在代码旁) */
|
||||
assert.match(narrowHook, /三栏|导航.*列表.*详情/,
|
||||
'★ WebUI 侧要说明这个断点的**依据**(它是按"三栏放不下"定的)');
|
||||
assert.match(mainPage, /侧栏|宽屏模式/,
|
||||
'★ 鸿蒙侧要说明这个阈值判的是什么(「要不要显示侧栏」)');
|
||||
|
||||
/* ③ 差异被登记 */
|
||||
const debts = prose(join(ROOT, 'docs/DEBTS.json'));
|
||||
assert.match(debts, /wide-breakpoint-divergence/,
|
||||
'★ 「两端断点不同」必须登记在 docs/DEBTS.json —— '
|
||||
+ '它被发现时**没有任何地方记录**,下一个人只会当成漏改');
|
||||
|
||||
/* ④ 反向断言:万一以后有人"统一"了,登记不该变成化石 */
|
||||
if (webMax - 1 === hMin || hMin === 1024) {
|
||||
assert.match(debts, /wide-breakpoint-divergence[\s\S]{0,400}?(已统一|统一到)/,
|
||||
'★ 两端断点看起来已经一致了 —— 那就该在登记里写明"已统一",'
|
||||
+ '否则这条登记会变成没人在核的化石(登记也该跟着事实走)');
|
||||
}
|
||||
});
|
||||
|
||||
@ -68,7 +68,7 @@ const SUITE = [
|
||||
// 「只有通信页深色正常」的回归锁 —— 38 条里后 8 条是这次新增)。
|
||||
['test/theme.test.mjs', [], 38],
|
||||
['test/background.test.mjs', [], 44],
|
||||
['test/cross-client-theme.test.mjs', [], 15],
|
||||
['test/cross-client-theme.test.mjs', [], 16],
|
||||
// 左右滑动翻页的**语义契约**(两端逐项相同、数值各自定)—— 这是
|
||||
// `docs/DEBTS.json` 的 `gesture-semantics` 那条债:它写着「鸿蒙侧出现滑动
|
||||
// 手势代码时**立即建**(此前建 = 只有一端存在的假判据)」。
|
||||
|
||||
Reference in New Issue
Block a user