乒乓球口袋教练 HarmonyOS 学习应用(03):练习记录与专项复盘
2026/7/29 22:06:23 网站建设 项目流程

一、复盘数据必须是已完成动作而不是训练计划

训练计划用于安排练习内容和节奏;练习日志只记录已经完成的动作、时长、感受和时间。只有日志才适合参与个人复盘和统计;把课程浏览或计划卡片当成完成事实,会让练习次数失真。为避免计划与事实混在一起,编辑页只将已完成的练习保存到 PracticeLogService。

export interface PracticeLog { id: string; date: string; // YYYY-MM-DD durationMin: number; // 训练时长(分钟) type: string; // 训练类型 content: string; // 描述 rating: number; // 1-5 自评星级 createdAt: number; // Date.now() updatedAt?: number; } export const PRACTICE_TYPES: string[] = [ '投篮训练', '运球训练', '传球配合', '防守脚步', '体能训练', '其他' ];

二、新增与编辑怎样保持同一个日志 id

新增记录生成 id,编辑记录沿用原 id。服务层先读取当前日志列表,再替换或追加对应对象并持久化;列表重新进入时从服务读取,而不是从页面残留数组恢复。这个约束避免用户修改十分钟为二十分钟后出现两条记录。

事实唯一来源页面职责
正常结果模型或服务的回读渲染可观察状态
边界结果明确的缺项或失败分支说明原因并保留入口
重进结果持久化或模型再次解析不复用旧页面变量
} static add(log: PracticeLog): void { const next: PracticeLog[] = PracticeLogService.list().slice(); next.unshift(log); PracticeLogService.save(next); } static update(log: PracticeLog): void { const next: PracticeLog[] = PracticeLogService.list().slice(); const idx: number = next.findIndex(l => l.id === log.id); if (idx >= 0) { next[idx] = log; PracticeLogService.save(next); } } static remove(id: string): void { const cur: PracticeLog[] = PracticeLogService.list(); const next: PracticeLog[] = cur.filter(l => l.id !== id); PracticeLogService.save(next); } static find(id: string): PracticeLog | undefined { return PracticeLogService.list().find(l => l.id === id); } static genId(): string { return 'pl_' + Date.now().toString(36) + '_' + Math.random().toString(36).substring(2, 6); } }

三、持久化失败时页面不能预先报成功

保存失败时最重要的是不制造成功假象。页面应保留输入和错误提示,让用户可以重试;不能在写入完成前跳回列表并让统计增加一次。删除同样必须先作用于持久化集合,随后回读结果,而不是仅把卡片从屏幕上隐藏。

date: this.date, durationMin: this.durationMin, type: this.type, content: this.content, rating: this.rating, createdAt: oldLog?.createdAt ?? now, updatedAt: now } as PracticeLog; if (this.logId.length > 0) { PracticeLogService.update(log); AppToast.show('已更新'); } else { PracticeLogService.add(log); AppToast.show('已保存'); } router.back(); } private todayStr(): string { const d: Date = new Date(); const y: string = d.getFullYear().toString(); const m: string = (d.getMonth() + 1).toString().padStart(2, '0'); const day: string = d.getDate().toString().padStart(2, '0'); return y + '-' + m + '-' + day; } private durationOptions(): DurationOpt[] { return [ { value: 30, label: '30' } as DurationOpt, { value: 60, label: '60' } as DurationOpt, { value: 90, label: '90' } as DurationOpt, { value: 120, label: '120' } as DurationOpt ]; }

四、当前专项类型的真实边界

当前项目的训练类型数组仍保留篮球模板词,这是已知实现边界。可控模拟器已经验证使用“其他”保存并回读记录的路径;本文不把它描述为乒乓球技术点枚举已完整落地。后续专项化应只替换类型数据,不改变日志 id、写入和回读合同。

风险不能采用的做法当前链路的处理
数据不存在用默认对象继续渲染停在可解释的空或失败状态
页面重进复用上一次内存字段重新查询模型或服务
重复动作追加同一业务事实通过稳定 id 或进入标记收敛
export const PRACTICE_TYPES: string[] = [ '投篮训练', '运球训练', '传球配合', '防守脚步', '体能训练', '其他' ];

五、练习日志的回读验收

验收先用“其他”创建一条可识别记录,回到列表检查时间和时长,再进入编辑页修改并回读。最后删除这条记录并重启页面,确认它不会重新出现;同时确认没有借由旧篮球类型文字宣称专项选择已经完成。

验收阶段操作应观察到的结果
建立事实完成一次与主题直接对应的动作服务或模型能回读该事实
页面回读进入目标页或结果页标题、数据和状态相互一致
重进验证返回、重启或切换模块后再次进入结果不依赖上一页残留

六、取舍与后续维护

当前实现把业务事实集中到模型与服务,页面只负责呈现和触发操作。这样做会多出类型、查询和回读代码,却能避免同一份统计或记录在多个页面分叉。需要扩展新课程、新资源或新题目时,应先补齐稳定标识与服务合同,再补页面入口。

ArkTS 的响应式状态机制可参考 HarmonyOS ArkTS 状态管理文档。本文的代码和验收围绕同一个原则:可见结果必须能回到对应模型、服务或持久化事实,不以邻近页面和控件文字代替主题结果。

七、围绕事实来源继续演进

乒乓球口袋教练 HarmonyOS 学习应用(03):练习记录与专项复盘 关注的不是给页面再增加一层显示逻辑,而是让“复盘数据必须是已完成动作而不是训练计划”始终能回到唯一的业务事实。模型字段、服务返回值和页面展示应当保持单向关系:事实先发生,页面随后回读;页面不保存第二份能够被误认为真实数据的临时副本。

处理“新增与编辑怎样保持同一个日志 id”时,新增条件必须先归属到课程模型、资源服务、日志事实或测验结果之一。把条件散落在多个组件里,短期看起来省事,后续就会出现入口不同、重进不同、统计不同的问题。把规则放回稳定入口,页面只根据结果改变可见状态,能让同一结论在不同入口被复查。

“持久化失败时页面不能预先报成功”说明当前实现选择了页面重建后重新查询,而不是把对象和统计快照长期塞进路由参数。读取会增加少量成本,却避免课程改名、资源替换、日志编辑或题库切换后继续显示旧内容。学习应用的结果需要能解释,不能只追求一次渲染恰好看起来正确。

异常分支也应保留语义:当前项目的训练类型数组仍保留篮球模板词,这是已知实现边界。可控模拟器已经验证使用“其他”保存并回读记录的路径;本文不把它描述为乒乓球技术点枚举已完整落地。后续专项化应只替换类型数据,不改变日志 id、写入和回读合同。 这要求页面区分数据不存在、动作未完成和资源不可用,并提供返回选择、补充输入、重新下载或再次答题等对应操作;不能把不同原因压缩成同一条模糊的成功或失败提示。

最后执行“练习日志的回读验收”时,至少观察一次主题动作、一次目标页回读和一次重进或切换后的回读。三次观察都指向相同模型或服务结果,才说明实现链路没有依赖旧页面残留。 最后执行“练习日志的回读验收”时,至少观察一次主题动作、一次目标页回读和一次重进或切换后的回读。三次观察都指向相同模型或服务结果,才说明实现链路没有依赖旧页面残留。

面向维护的检查可以沿三个问题展开:输入对象的稳定标识是什么,哪个服务或模型决定结果,页面如何把该结果显示出来。练习编辑页通过 PracticeLogService 写入、更新和回读日志;当前类型选项仍含旧篮球词,文章只讨论“其他”记录链路,不把该瑕疵伪装成已完成的乒乓球专项枚举。 这三个问题分别对应数据合同、调用边界和可见反馈;只要其中一层被绕过,新增入口就可能产生和原入口不同的事实。

对失败路径也要保留同样的追踪能力。先让服务返回清晰的不可用、缺项或未完成状态,再由页面提供与原因匹配的操作。这样日志、课程、资源和题目发生变化时,回归测试能够看到具体的分歧点,而不是只能面对一张没有信息的空白页面。

这种组织不会承诺所有后续需求都零成本。新增字段需要同步更新模型、服务与验收;但它把变更范围限制在可枚举的位置,避免把同一判断复制到首页、详情、个人页和结果页后再分别修补。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询