做一个鸿蒙倒班应用时,我踩过的 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 卡片类应用,欢迎交流你遇到过的日期边界。最后放一张当前的个人排班界面:

相关推荐
Sam_Deep_Thinking11 小时前
new Thread()之后发生了什么?
java·后端·面试·程序员
一拳不是超人17 小时前
之前用 AI 两小时写的塔罗网站,我真把它做上线了,然后呢?
前端·人工智能·程序员
人邮异步社区1 天前
学习Python的最佳学习路径是什么?
python·程序员
kyriewen1 天前
我删掉了 29 个 AI Skill 里的 23 个:留下的 6 个都有同一个特点
人工智能·程序员·ai编程
她的男孩2 天前
做了"异步导出",用户点了还是卡 3 分钟:扒完 4223 行源码,@Async 压根没生效
人工智能·后端·程序员
IamZJT_2 天前
Agent 系统工程 01|模型之外,Harness 到底该负责什么?
人工智能·python·程序员
爱勇宝2 天前
用了一个月 WorkBuddy,聊聊我的真实感受
前端·后端·程序员
无限压榨切图仔2 天前
加了“去 AI 味”Skill,水稿还是水:AI 写作流程缺的不是润色
人工智能·程序员
codigger2 天前
CLI 还是 MCP?一场关于 Agent 工具接口的再思考
程序员·编程·#人工智能·#agent
six_2 天前
RiverPlusCOM Web:不用安装的在线串口调试助手
vue.js·程序员