用户:「要给鸿蒙端做功能同步」。按 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)。
92 lines
4.2 KiB
TypeScript
92 lines
4.2 KiB
TypeScript
/*
|
||
* 底部导航(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;
|
||
}
|