做一个鸿蒙倒班应用时,我踩过的 4 个“看起来很简单”坑

利益相关:我是《班妥了》的开发者。本文不是把"做个日历"包装成技术难题,而是复盘真实实现里最容易算错、丢历史和不同步的部分。

排班应用第一眼很像 CRUD:定义几个班次、生成一个月历、允许用户修改某一天。真正写下去才发现,它同时碰到了日期算法、跨日时间、历史状态、关系型数据和鸿蒙 Form 卡片生命周期。下面选四个对同类应用也有参考价值的坑。

1. 循环排班不能只存"当前模板"

最直观的做法,是保存一个起始日和一个序列,例如"白白夜夜休休",再用日期差取模:

ts 复制代码
function cycleIndex(days: number, length: number): number {
  return ((days % length) + length) % length;
}

这里必须用正模,否则查看起始日前的日期时,负数余数会把索引带出数组。

更大的坑是:用户今天切换了一套循环,不代表过去的班表也应该被重算。因此我最终没有只保存"当前循环",而是保存循环分段:

  • startKey:这段循环从哪天开始;
  • endKey:哪天结束,空值代表当前仍生效;
  • templateIndex:使用哪套循环模板。

关闭循环时只封存当前分段;重新开启时创建新分段。这样月度和年度统计不会因为一次改模板,把几个月前的数据全部改写。

单日换班则是另一层数据:人工覆盖优先于循环。用户点"恢复循环"时,只删除当天覆盖记录,不需要重写后面的每一天。这种分层比把整个月 42 个格子都持久化更稳,也更容易解释。

2. 夜班不是同一天内的两个时间点

如果班次是 20:00 到次日 08:00,直接做 end - start 会得到负数。实现时需要先判断结束分钟是否小于或等于开始分钟;若是,就给结束时间加 24 小时,再扣除休息分钟。

提醒也有相同问题:

  • 班前提醒按"开始时间 - 提前量"计算;
  • 下班前提醒如果跨午夜,触发日应落到第二天;
  • 排班一旦临时调整,未来提醒必须重算。

鸿蒙侧使用系统代理提醒后,还要考虑单应用提醒配额。我这里会规划未来 31 天,但按触发时间只注册最近 30 条;首条注册失败就终止本轮,避免权限或额度未就绪时连续制造失败调用。

3. 本地优先不等于把所有数据塞进一个 JSON

《班妥了》不要求登录,核心数据保存在本地关系型数据库 rotaday.db。早期把设置放 JSON 很方便,但团队成员、逐日排班和长期单日覆盖持续增长后,继续堆 JSON 会让更新、迁移和统计都变得笨重。

目前主要拆成几张表:

  • shift_assignment:个人单日覆盖,日期为主键;
  • team_member:团队成员;
  • team_assignment:日期 + 成员复合主键;
  • app_setting:主题、循环分段、提醒等轻量设置;
  • form_instance:已添加的桌面卡片实例。

一次保存会放在事务里:设置、个人排班、成员与团队排班任何一步失败都回滚。版本迁移时则先读取旧设置和旧关系表,再升级到新 schema,避免"升级成功但历史班表消失"这种最伤信任的问题。

4. 桌面卡片最怕"主页面是新的,卡片还是旧的"

鸿蒙版提供 2×2 和 2×4 两种今日班次卡片。这里我踩到的关键点有两个。

第一,FormExtensionAbility 创建卡片时,先同步返回一份可理解的默认数据,再异步读取数据库并更新。否则添加卡片过程等数据库,容易触发超时。

第二,主页面保存排班后,不只更新内存状态,还要读取已注册的 formId,统一调用 updateForm。失效的 formId 会从本地表清理,避免以后每次保存都重复报错。

卡片计算今日班次时复用与主页面相同的规则:个人版按"单日覆盖 > 循环",团队版读取标记为"我"的成员实际排班。业务规则只保留一份,才能避免 App 显示白班、桌面卡片却显示夜班。

从技术边界反推产品边界

这些实现最后落在《班妥了》的两种模式里:个人版负责循环排班、临时改单日、三类提醒和月度/年度统计;团队版负责成员、岗位和逐日排班,让负责人从月历里快速看出当天谁在岗。它不是考勤、薪资或劳动合规一体化 HR 系统,定位仍然是轻量排班工具。

目前有鸿蒙版本和微信小程序版本。鸿蒙版适合长期使用,支持桌面卡片,免费、无广告、无需登录,本地保存;小程序不需要安装,适合临时查班或帮家人排一段时间。

如果你也做过日历、值班、提醒或 Form 卡片类应用,欢迎交流你遇到过的日期边界。最后放一张当前的个人排班界面:

相关推荐
lnix6 小时前
你的代码 3 年后会被 AI 替代,但 FDE 不会:8 个你看不到的底层原因
程序员·aigc
赚点小钱9 小时前
从零开发 AIDataReport 智能数据报表工具|工程脚手架
程序员
小流苏生12 小时前
“《关于我妈说我又老又丑又穷已经没有女生会看得上我了这件事情》”
程序员
CodeSheep21 小时前
稚晖君公司人事大变动,来了!
前端·后端·程序员
程序员cxuan1 天前
Pi + DeepSeek-v4-Flash,这用着也太爽了。
人工智能·后端·程序员
程序员cxuan1 天前
Claude Opus 5 的系统提示词被扒出来了
人工智能·后端·程序员
AskHarries1 天前
为什么产品没人用
程序员
Patrick_Wilson2 天前
代码重构中的蚕食方式是什么
程序员·架构·代码规范
Patrick_Wilson2 天前
你知道 git check 的故事吗
git·程序员·命令行