Files
MailUI4Agents/client/harmony/entry/src/main/ets/model/NavItems.ts
pi 94ba4b9c58 跨端: 鸿蒙端功能同步第一步——日历(只读月视图)上架,入口进底部导航
用户:「要给鸿蒙端做功能同步」。按 API 面盘点(WebUI 62 个 API 函数 vs 鸿蒙 38 个),
最大的用户面缺口是**日历**:纯逻辑(model/Calendar.ts)与判据早就在,一直没页面。

新增:
- api/CalendarApi.ets:GET /calendar/events?from=&to=(与 WebUI 同参;区间按**网格**取,
  不是月首月末 —— 首尾格子会显示邻月,只查当月会让那些格子永远空着)
- pages/CalendarPage.ets:月网格(翻月/回今天)、点某天看当天日程、事件点、今天/选中两态、
  加载失败说出来。**没做**:写侧(增删改)、农历重复、.ics、滑动翻页 —— 逐条写在文件头
- model/Calendar.ts:补 localIsoOf / hhmmAtOffset / deviceOffsetMinutes(偏移是入参 ⇒ 三时区可真跑)
- model/Models.ets:CalendarEvent / CalendarListResponse(字段对齐服务端 JSON)
- NavItems:加「日历」,底部成为 通信/日历/联系人 三项(与 WebUI 同序)
- MainPage:日历是**常驻 pane**(visibility 控制),首次可见才拉数据;today 走
  @Prop @Watch(visible) 在 pane 变可见时重算 ⇒ 结算欠账 calendar-today-recompute
  (DEBTS 15 笔 → 14 笔,余额里不再计这一笔)

判据:harmony-calendar 新增 6 条(网格/表头同源、事件归日走 localIsoOf、三时区钟点、
today 重算路径、翻月走 addMonths、变异自检);harmony-nav ② 分派与 ④ 让位跟着改成结构性判据
(④ 原来那个 400 字符窗口一加 pane 就红 —— 窗口式判据的又一次现身);harmony-logic 两处
「只剩两个平级页签」跟着改成三项。

真机实测(harmony-emu + hvigorw assembleHap + hdc install + uitest click + dumpLayout):
9 月网格星期对齐(周一起始,2026-09-01 落在「二」列)、事件点恰好在有日程的那 6 天
(11/17/18/24/25/30)、点 09-17 列出当天两条日程且钟点是本地时间(DB 里 02:20Z/08:30Z
→ 界面 10:20/16:30)。
2026-09-14 18:38:51 +08:00

92 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 底部导航(P5:悬浮玻璃条)的**清单与尺寸**。
*
* 为什么数据放在 `.ts` 而不是写在 `MainPage.ets` 里:
* - 判据可以直接 `import` 它(`node --experimental-strip-types` 能跑纯逻辑 `.ts`),
* 于是"命中区 ≥44vp"这类要求判的是**数值本身**,而不是拿正则去源码里猜;
* - 「通信 → 联系人」的顺序与文案是信息架构,和 CommTabs 一样属于跨端要对齐的东西
* (WebUI 侧同样是两项,撤掉会话 tab 的时机见计划文档 §7.15)。
*/
/** 一个底部导航项。字段与 WebUI `Sidebar.tsx` 的项一一对应 */
export interface NavItem {
/** 稳定键(ForEach 的 key,也是判据认的名字) */
key: string;
/** 显示文案(与 WebUI 逐字一致) */
label: string;
/** 图标字形(鸿蒙侧用文本字形,不用猜 sys.media 名字) */
icon: string;
}
/**
* 平级导航项。**三项**:通信(内部三栏:收件箱/发件箱/授权)、日历、联系人。
*
* 「会话」原先是个平级 tab,已撤 —— 它不是第三个地方,而是"同一批数据的另一种看法"
* (收件箱按会话折叠、联系人卡片视图就是会话的进度视角)。理由见 `MainPage.build()` 的注释。
*
* 「日历」原来写着"等 P6 内容做完再上入口 —— 不留点进去空着的页签"。P6 第一步
* (只读月视图:`pages/CalendarPage.ets`)已经做完,所以入口**现在**上:
* 空页签那条理由不再成立,而日历的纯逻辑(`model/Calendar.ts`)本来就是照着
* 「顶层是 通信/日历/联系人 三个平级 pane」写判据的。
*/
export const NAV_ITEMS: NavItem[] = [
{ key: 'comm', label: '通信', icon: '✉️' },
{ key: 'calendar', label: '日历', icon: '📅' },
{ key: 'contacts', label: '联系人', icon: '👤' }
];
/** 命中区下限(vp)。**44 是可点区域的下限**,不是"看起来够大"的估计 */
export const NAV_ITEM_MIN_HIT: number = 44;
/** 浮动条自身高度(vp)。≥ NAV_ITEM_MIN_HIT,否则命中区内边距会互相挤压 */
export const NAV_BAR_HEIGHT: number = 56;
/** 悬浮:左右留白(vp)—— 贴边就不是"悬浮"了,WebUI 的底栏同样浮在内容之上 */
export const NAV_BAR_SIDE: number = 16;
/** 悬浮:离屏幕底部的留白(vp) */
export const NAV_BAR_BOTTOM: number = 12;
/** 圆角(vp)。用"胶囊"半径(= 高度一半),与 WebUI 的 `rounded-2xl` 观感一致 */
export const NAV_BAR_RADIUS: number = 28;
/**
* 内容与浮动条之间的余量(vp)。
*
* 单独起名而不是把 `8` 埋在算式里:它是这一族里**唯一**还需要人判断的数
* (条离底 12 + 条高 56 + 余量 8),命名之后"内容到底让多少"只剩一个数可争,
* 其余全部派生。pi 2026-09-14 提的"让位高度应从条高派生,不要写成并列常量",
* 落实在这两行上。
*/
export const NAV_CONTENT_GAP: number = 8;
/**
* 内容底部要让出的高度(vp):条高 + 离底留白 + 一点余量。
*
* **这是"点得到"的问题,不是美观问题**:条是浮在内容之上的,不让出这段高度,
* 列表最后一行就永远压在玻璃条底下 —— 看得见、点不到。
*
* **派生,不并列**:上面三个常量任何一个变大,这里自动跟着变;写死一个数(例如 76)
* 就会在改条高的那天悄悄失配。判据 `harmony-nav.test.mjs` 同时钉"派生关系"与
* "在算式中出现",防它退回字面量。
*/
export const NAV_CONTENT_RESERVE: number = NAV_BAR_HEIGHT + NAV_BAR_BOTTOM + NAV_CONTENT_GAP;
/** 把任意下标归一化到合法范围(点击/外部传值都过这里,别直接赋值) */
export function normalizeNavIndex(index: number): number {
if (index >= 0 && index < NAV_ITEMS.length) {
return index;
}
return 0;
}
/** 第 index 项的键(内容按它挂载,判据也认它) */
export function navKeyAt(index: number): string {
return NAV_ITEMS[normalizeNavIndex(index)].key;
}
/** 第 index 项的标签(给判据与无障碍文案用) */
export function navLabelAt(index: number): string {
return NAV_ITEMS[normalizeNavIndex(index)].label;
}