归档、恢复还是删除?HarmonyOS 习惯数据生命周期设计

📅 2026/8/25 22:17:08
归档、恢复还是删除?HarmonyOS 习惯数据生命周期设计
为什么习惯不能只有一个删除按钮用户不再继续“每天阅读”时可能有两种完全不同的意图暂时不做了但想保留历史适合归档。这个习惯建错了希望连历史一起删除适合删除。如果产品只有删除用户为了整理今日列表就必须牺牲历史如果所谓归档只是隐藏 UI但统计仍持续把未来日期算进分母数据又会越来越失真。一、Habit 模型需要表达生命周期exportinterfaceHabit{id:string;name:string;icon:string;color:string;isActive:boolean;createdAtMillis:number;updatedAtMillis:number;archivedAtMillis:number;}其中isActive当前是否显示在今日打卡createdAtMillis从哪天开始参与统计archivedAtMillis从哪天停止参与updatedAtMillis列表刷新和审计使用。二、今日页只关心 activeHabitsprivateactiveHabits():Habit[]{returnthis.habits.filter((habit:Habit)habit.isActive);}归档列表则相反privatearchivedHabits():Habit[]{returnthis.habits.filter((habit:Habit)!habit.isActive);}归档改变的是“当前是否继续参与”不是删除实体。三、归档时要记录发生日期privatesetHabitActive(habitId:string,active:boolean):void{constnow:numberDate.now();this.habitsthis.habits.map((habit:Habit){if(habit.id!habitId){returnhabit;}return{id:habit.id,name:habit.name,icon:habit.icon,color:habit.color,isActive:active,createdAtMillis:habit.createdAtMillis,updatedAtMillis:now,archivedAtMillis:active?0:now};});this.persist();this.refreshUi();}归档isActive false archivedAtMillis now恢复isActive true archivedAtMillis 0四、历史打卡为什么不能随归档删除HabitCompletion 独立保存exportinterfaceHabitCompletion{id:string;habitId:string;dayIdentifier:string;isCompleted:boolean;// 时间字段}归档时不修改habitCompletions因此历史月历和最近记录仍能找到过去的完成情况。这是归档的核心承诺停止未来展示保留过去事实五、统计分母只计算有效生命周期假设一个习惯 8 月 10 日创建8 月 15 日归档。查看最近 30 天时不应该把 30 天全部当作可完成天数。项目逐日构造可参与日期if(dayStartcreatedStart(archivedStart0||dayStartarchivedStart)){identifiers.push(dayIdentifier(day));}因此分母只包含创建日 ≤ 日期 ≤ 归档日新建习惯不会为创建前的日期得到大量“未完成”归档后也不会继续拉低完成率。六、恢复后单个 archivedAtMillis 有什么局限当前模型恢复时把archivedAtMillis清零。如果一个习惯经历创建 → 归档 10 天 → 恢复恢复后模型无法再知道中间曾暂停 10 天。统计会把整个创建日至今都视为有效期。对于第一版轻量习惯模型这个取舍可以接受如果产品支持频繁暂停/恢复就需要更完整的区间模型interfaceHabitActivePeriod{habitId:string;startDay:string;endDay:string;}或者保存状态变更事件ACTIVATED ARCHIVED RESTORED统计时根据事件重建有效区间。这说明时间字段设计要与产品承诺匹配。只存最后一次归档时间不能支持无限复杂的历史解释。七、删除必须级联清理关联打卡删除实现privatedeleteHabit(habitId:string):void{this.habitsthis.habits.filter((habit:Habit)habit.id!habitId);this.completionsthis.completions.filter((completion:HabitCompletion)completion.habitId!habitId);this.showDeleteHabitId;this.persist();this.refreshUi();}如果只删除 Habit会留下孤儿 Completion历史日期仍可能出现打卡数量统计可能计算一个不存在的习惯JSON 导出包含无法解释的 habitId以后导入数据库时破坏引用完整性。本地数组模型没有数据库外键因此级联规则必须由 Repository 或业务层主动保证。八、删除前为什么要二次确认归档可恢复删除不可恢复交互强度应不同。删除确认文案需要说明影响范围习惯及相关打卡会永久删除如果以后可能继续建议选择归档。它比“确定删除吗”提供了更有价值的信息告诉用户会删除关联打卡提醒存在更温和的归档选项让不可逆操作不容易误触。九、删除全部数据与删除单个习惯不同删除全部数据会清空this.moodEntries[];this.habits[];this.completions[];并保持“默认习惯已经初始化过”的标志避免重启后自动复活。删除单个习惯只影响该 Habit 和关联 Completion不应该删除当天的心情日记或其他习惯。不同删除范围必须在函数和文案中分开不要复用一个含糊的clear()。十、什么时候应该提供撤销如果用户误删成本高可以考虑软删除增加deletedAtMillis一段时间后物理清理。操作后撤销短时间保留被删除对象和关联打卡Toast 提供“撤销”。导出后删除删除全部数据前提示先导出 JSON。但不要只在 UI 隐藏记录却在隐私文案中声称已经永久删除。产品语义、磁盘状态和用户承诺必须一致。十一、生命周期测试清单归档今日页立即消失历史打卡仍存在归档列表出现统计截止到归档日杀进程后仍归档。恢复今日页重新出现历史打卡仍存在新打卡可以创建统计口径符合当前模型定义。删除二次确认可取消Habit 删除关联 Completion 全部删除其他习惯不受影响历史日期和统计同步刷新导出 JSON 不再含孤儿引用。总结归档、恢复和删除的区别可以归纳为操作今日展示历史打卡统计未来分母可恢复归档移除保留停止计入是恢复恢复保留重新计入—删除移除删除不再存在否只有当数据模型、统计口径和交互文案同时遵守这张表习惯生命周期才真正一致。本文案例来自“心晴手记MoodMemoir”HarmonyOS 版的习惯管理与统计实现。