HarmonyOS 7 DatePickerComponent实战:2月29日年度复查怎么跨闰年
康复计划里常有“每年这个时候复查一次”。用户滚到一个日子,看起来只是挑了个日期,但落到每一年,它可能是三个不同的结果。选择 2 月 29 日就是最典型的例子:2028 年有这一天,2027 和 2029 年没有。
分析:组件只交出月日,跨年的事得自己算
DatePickerComponent 从 API 26.0.0 起提供,属于 Stage 模型组件。把 displayMode 设为 DisplayMode.DATE、dateOptions.mode 设为 DateMode.MONTH_AND_DAY,界面就只显示两列滚轮:月和日。
SDK 声明里写得很清楚:这个模式下,月份从 12 月滚到 1 月时年份不增加,从 1 月滚到 12 月时年份也不减少,年份保持在当前设定值。换句话说,用户选中的是一个“月日”,组件并没有替业务回答“明年这一天是哪天”。
这就带来第一个决策点:2 月 29 日在平年不存在,应用不能悄悄改成 2 月 28 日或 3 月 1 日。提前一天还是顺延一天,会改变复查间隔,也会影响医生排班和用户预期,必须来自门诊的明确规则,而不是代码里的顺手兜底。
第二个决策点更容易被忽略:年度复查只是提醒锚点,不是真实预约。号源、停诊、院区安排每年都会变,一次选择不应该被理解成永久占位。页面能做的,是把“每年哪一天提醒”记清楚,把“那一年具体约到哪天”留给预约服务逐年确认。

· 年度复查的三层数据——选中的月日、门诊规则、逐年投影各管一段。
功能描述:锚点、门诊规则、年度投影分开存
康复随行的年度功能复查页把数据拆成三层。第一层是锚点,只记月和日;第二层是门诊规则,说明平年怎么落;第三层是年度投影,把锚点按规则展开成未来三年。
页面进来先看门诊规则是否同步。没同步时,三次预览一律显示“待门诊确认”,保存按钮置灰,说明文字写“同步门诊规则后,才知道平年落在哪一天”。这里没有拿 2 月 28 日先顶上,也没有把 3 月 1 日当成默认值。
同步之后,2 月 29 日的锚点展开成:2027 年 2 月 28 日、2028 年 2 月 29 日、2029 年 2 月 28 日。平年那两年标注“平年 · 二月末”,闰年保持原样。用户看到的是三个具体日期,不是一句“按规则处理”。
保存是单向的。函数里先查两件事:2 月 29 日的锚点是否已有门诊规则、当前锚点是否已经保存过。两个条件都通过才写入,按钮文案同时变成“已保存”并禁用。这个禁用只是视觉门,函数内会再查一遍,别的入口直接调用也写不进去。
改日期会让已保存状态立即失效。用户把锚点从 2 月 29 日换到 2 月 28 日,页面马上提示“换成 2 月 28 日了,这个日子每年都有”,保存按钮重新可点,预览也不再需要平年规则。旧锚点的保存状态没有被带到新日期上。
组件结果里的月份是零基的,0 表示 1 月。业务侧如果一处加 1、一处不加,就会出现“选了 2 月、存成 3 月”的错位。页面统一用 anchorText() 转换,其他函数只拿转换后的文本,避免两边各写一套。
案例:从“还没同步”到保存两次
进入页面时,门诊规则是“还没同步”,日期滚轮停在 2 月 29 日,三次复查全部写着“待门诊确认”,保存按钮是灰的。此时的反馈是“先同步门诊规则,才能确认平年怎么安排”。
点一下“同步门诊规则”,状态变成“已同步”,三次复查立刻展开成 2027 年 2 月 28 日、2028 年 2 月 29 日、2029 年 2 月 28 日,说明改成“平年没有 2 月 29 日,门诊规则把这一天落到二月末”。保存按钮这时才亮起来。
点“保存复查日期”,按钮变成“已保存”并禁用,反馈写“已保存:每年 2 月 29 日提醒你复查”。这一步只写入了提醒锚点,页面底部那句“这里设的是提醒日期,不会直接占用号源”始终在。
接着把日期从 29 日改到 28 日。三次复查变成清一色的 2 月 28 日,说明换成“这个日子每年都有,不需要平年规则”,已保存状态被清掉,按钮回到“保存复查日期”可点状态。这一步是故意的:换了锚点,旧保存就不该继续生效。
再保存一次,反馈变成“已保存:每年 2 月 28 日提醒你复查”,按钮重新变灰。整个过程里,组件只负责把月日滚出来,哪一年是哪天、平年怎么落、保存过没有,全部由页面判断。
边界都落在状态上:规则没同步时保存不可点;保存之后按钮禁用;改日期才恢复可点。如果用户在规则缺失时通过别的入口调用保存,函数里的第一道检查仍然会拒绝,不会写出一条“2 月 29 日、平年未知”的提醒。
运行截图

· 门诊规则未同步时三次复查全部待确认——保存按钮保持灰色。

· 同步门诊规则后展开三年日期——2027、2029 落到二月末,2028 保持 2 月 29 日。

· 保存 2 月 29 日锚点后按钮锁定——“已保存”不可再点。

· 改到 2 月 28 日后旧保存失效——说明改成“不需要平年规则”。

· 2 月 28 日再次保存成功——每年都有这一天,平年规则退出计算。
代码片段:滚轮只给月日,投影自己算
组件配置只负责月日输入和稳定结果回调:
DatePickerComponent({
options: {
displayMode: DisplayMode.DATE,
dateOptions: {
mode: DateMode.MONTH_AND_DAY,
selected: new Date(2028, this.selectedMonth, this.selectedDay),
enableHapticFeedback: false,
onScrollStop: (result: DatePickerComponentResult) => {
this.onDateSettled(result);
}
}
}
})
逐年投影不猜,按门诊规则分开处理:
private resolveForYear(year: number): string {
if (!this.isLeapDay()) {
return this.anchorText();
}
if (!this.clinicSynced) {
return '待门诊确认';
}
return this.isLeapYear(year)
? '2月29日'
: '2月28日(平年 · 二月末)';
}
保存先查规则和重复,再落下状态:
private saveRule(): void {
if (this.needsClinicRule()) {
this.feedback = '门诊规则还没同步,2 月 29 日先不保存。';
return;
}
if (this.savedAnchor === this.anchorKey()) {
this.feedback = '这个日子已经保存过,不用重复保存。';
return;
}
this.savedAnchor = this.anchorKey();
this.feedback = `已保存:每年${this.anchorText()}提醒你复查。`;
}
三段代码的分工同样清楚:组件交出月日,resolveForYear() 决定平年落点,saveRule() 管住写入时机。任何一段都不需要知道另外两段之外的东西。
总结
MONTH_AND_DAY 解决的是“怎么让用户选出 2 月 29 日”,不是“每年 2 月 29 日怎么办”。组件明确保持年份不变,跨年解析就必然落在业务层。
这个页面把月日锚点、门诊规则和年度投影拆开:规则没同步时不显示具体日期,保存前再查一次,改日期让旧保存失效。页面已构建并安装到模拟器,五种状态都实际点过;真实门诊规则服务、时区与节假日处理、号源确认和持久化还没接,界面状态不等于预约成功。
官方资料
更多推荐



所有评论(0)