篮球口袋教练 HarmonyOS 学习应用(07):个人页成就与学习统计
一、统计卡片不能从页面临时变量取数个人页同时展示连续学习、累计时长、课程完成、练习和测验等信息。若每张卡片各自维护一个计数器返回页面、重启应用或在其他页面新增记录后数字很容易彼此矛盾。这里把个人页视为统计结果的消费者而不是新的事实来源。export class AchievementService { static checkAll(): string[] { const unlocked: string[] []; // --- streak --- const streak: number ProgressService.streak(); if (streak 3) unlocked.push(streak_3); if (streak 7) unlocked.push(streak_7); if (streak 14) unlocked.push(streak_14); if (streak 30) unlocked.push(streak_30); // --- study --- const studied: string[] AppStorage.getstring[](StorageKeys.STUDIED) ?? []; if (studied.length 1) unlocked.push(study_1); if (studied.length 5) unlocked.push(study_5); if (studied.length 10) unlocked.push(study_10); const seconds: number AppStorage.getnumber(StorageKeys.LEARN_SECONDS) ?? 0; if (seconds 3600) unlocked.push(time_1h); if (seconds 18000) unlocked.push(time_5h); // --- practice --- const logs: PracticeLog[] AppStorage.getPracticeLog[](StorageKeys.PRACTICE_LOGS) ?? []; if (logs.length 1) unlocked.push(practice_1); if (logs.length 10) unlocked.push(practice_10); if (logs.length 30) unlocked.push(practice_30); for (const log of logs) { if (log.rating 5) { unlocked.push(practice_star); break; } } // --- note --- const notes: NoteItem[] AppStorage.getNoteItem[](StorageKeys.NOTES) ?? []; if (notes.length 1) unlocked.push(note_1); if (notes.length 5) unlocked.push(note_5); // --- explore --- const favs: string[] AppStorage.getstring[](StorageKeys.FAVORITES) ?? []; if (favs.length 1) unlocked.push(fav_1); if (favs.length 10) unlocked.push(fav_10); // --- quiz ---二、成就条件怎样复用已持久化的学习事实AchievementService 会把 ProgressService 的连续学习天数、已学习课程集合、PracticeLogService 的日志、笔记集合以及 QuizService 的结果放到同一次条件检查中。它返回的是已解锁成就 id页面再用该结果筛选徽章不把“显示过的徽章”反向当作用户数据。事实唯一来源页面职责正常结果模型或服务的回读渲染可观察状态边界结果明确的缺项或失败分支说明原因并保留入口重进结果持久化或模型再次解析不复用旧页面变量} static totalSeconds(): number { return AppStorage.getnumber(StorageKeys.LEARN_SECONDS) ?? 0; } // 连续学习天数从今天往前数连续有记录的天数 static streak(): number { const days: string[] AppStorage.getstring[](StorageKeys.LEARN_DAYS) ?? []; if (days.length 0) return 0; const sorted: string[] days.slice().sort(); const today: string dayKey(); // 如果今天没有学习记录从昨天开始算 let cur: Date new Date(); if (sorted.indexOf(today) 0) { cur.setDate(cur.getDate() - 1); } let count: number 0; while (true) { const key: string dayKey(cur); if (sorted.indexOf(key) 0) { count; cur.setDate(cur.getDate() - 1); } else { break; } } return count; } }三、个人页与成就页为何必须各自回读累计学习秒数和连续天数都来自持久化键。记录学习行为后服务先写入 AppStorage 并同步 Preferences个人页下次显示时重新读取因此统计不会依赖此前页面是否仍在内存。这个取舍增加了回读成本却避免了跨页面共享可变数组。StorageLink(user_nick) nick: string ; State achieveCount: number 0; aboutToAppear(): void { this.achieveCount AchievementService.checkAll().length; } build() { Column() { Row() { Text(我的) .fontSize(AppText.fsTitle) .fontWeight(AppText.fwSemi) .fontColor(this.palette.textPrimary) .layoutWeight(1); } .width(100%).height(AppSizes.topBar) .padding({ left: AppSizes.s4, right: AppSizes.s4 }); Scroll() { Column({ space: AppSizes.s4 }) { this.userCard(); this.statsCard(); this.menuList(); Column().height(AppSizes.s8); } .width(100%) .padding({ left: AppSizes.s4, right: AppSizes.s4 }); }四、错误统计最容易发生在什么地方成就阈值的边界必须可解释。例如连续学习三天、完成五个课程、完成一次测验分别是不同事实不能用总点击次数替代。若某项写入失败页面应显示未满足条件而不是预先点亮徽章否则用户会看到无法在重启后复现的“成功”。风险不能采用的做法当前链路的处理数据不存在用默认对象继续渲染停在可解释的空或失败状态页面重进复用上一次内存字段重新查询模型或服务重复动作追加同一业务事实通过稳定 id 或进入标记收敛export class QuizService { static submitResult(moduleId: string, score: number, total: number): void { const results: QuizResult[] QuizService.allResults(); results.push({ moduleId, score, total, ts: Date.now() } as QuizResult); AppStorage.setOrCreatestring(QUIZ_KEY, JSON.stringify(results)); } static allResults(): QuizResult[] { const raw: string AppStorage.getstring(QUIZ_KEY) ?? []; try { return JSON.parse(raw) as QuizResult[]; } catch (e) { return []; } } static bestScore(moduleId: string): number { const results: QuizResult[] QuizService.allResults(); let best: number 0; for (const r of results) { if (r.moduleId moduleId r.score best) { best r.score; } } return best; } static hasCompleted(moduleId: string): boolean { return QuizService.allResults().some(r r.moduleId moduleId); }五、可观察的验收动作验收时先完成一项课程或写入一条练习日志再进入个人页与成就页分别回读。随后强制退出并重新打开比较累计时长、连续天数和解锁数量是否保持一致最后切换测验模块确认某一模块成绩不会改写另一模块的统计。验收阶段操作应观察到的结果建立事实完成一次与主题直接对应的动作服务或模型能回读该事实页面回读进入目标页或结果页标题、数据和状态相互一致重进验证返回、重启或切换模块后再次进入结果不依赖上一页残留六、取舍与后续维护当前实现把业务事实集中到模型与服务页面只负责呈现和触发操作。这样做会多出类型、查询和回读代码却能避免同一份统计或记录在多个页面分叉。需要扩展新课程、新资源或新题目时应先补齐稳定标识与服务合同再补页面入口。ArkTS 的响应式状态机制可参考 HarmonyOS ArkTS 状态管理文档。本文的代码和验收围绕同一个原则可见结果必须能回到对应模型、服务或持久化事实不以邻近页面和控件文字代替主题结果。七、围绕事实来源继续演进篮球口袋教练 HarmonyOS 学习应用07个人页成就与学习统计 关注的不是给页面再增加一层显示逻辑而是让“统计卡片不能从页面临时变量取数”始终能回到唯一的业务事实。模型字段、服务返回值和页面展示应当保持单向关系事实先发生页面随后回读页面不保存第二份能够被误认为真实数据的临时副本。处理“成就条件怎样复用已持久化的学习事实”时新增条件必须先归属到课程模型、资源服务、日志事实或测验结果之一。把条件散落在多个组件里短期看起来省事后续就会出现入口不同、重进不同、统计不同的问题。把规则放回稳定入口页面只根据结果改变可见状态能让同一结论在不同入口被复查。“个人页与成就页为何必须各自回读”说明当前实现选择了页面重建后重新查询而不是把对象和统计快照长期塞进路由参数。读取会增加少量成本却避免课程改名、资源替换、日志编辑或题库切换后继续显示旧内容。学习应用的结果需要能解释不能只追求一次渲染恰好看起来正确。异常分支也应保留语义成就阈值的边界必须可解释。例如连续学习三天、完成五个课程、完成一次测验分别是不同事实不能用总点击次数替代。若某项写入失败页面应显示未满足条件而不是预先点亮徽章否则用户会看到无法在重启后复现的“成功”。 这要求页面区分数据不存在、动作未完成和资源不可用并提供返回选择、补充输入、重新下载或再次答题等对应操作不能把不同原因压缩成同一条模糊的成功或失败提示。最后执行“可观察的验收动作”时至少观察一次主题动作、一次目标页回读和一次重进或切换后的回读。三次观察都指向相同模型或服务结果才说明实现链路没有依赖旧页面残留。面向维护的检查可以沿三个问题展开输入对象的稳定标识是什么哪个服务或模型决定结果页面如何把该结果显示出来。把连续学习、课程进度、练习日志和测验结果汇成成就事实个人页只消费服务回读避免把展示字段当成统计源。 这三个问题分别对应数据合同、调用边界和可见反馈只要其中一层被绕过新增入口就可能产生和原入口不同的事实。对失败路径也要保留同样的追踪能力。先让服务返回清晰的不可用、缺项或未完成状态再由页面提供与原因匹配的操作。这样日志、课程、资源和题目发生变化时回归测试能够看到具体的分歧点而不是只能面对一张没有信息的空白页面。这种组织不会承诺所有后续需求都零成本。新增字段需要同步更新模型、服务与验收但它把变更范围限制在可枚举的位置避免把同一判断复制到首页、详情、个人页和结果页后再分别修补。

相关新闻

突破性Windows网络性能测试方案:iperf3完整指南与下载安装

突破性Windows网络性能测试方案:iperf3完整指南与下载安装

突破性Windows网络性能测试方案:iperf3完整指南与下载安装 【免费下载链接】iperf3-win-builds iperf3 binaries for Windows. Benchmark your network limits. 项目地址: https://gitcode.com/gh_mirrors/ip/iperf3-win-builds 还在为网络速度不稳定而烦恼吗…

2026/7/29 19:29:24阅读更多 →
告别熬夜做PPT✨Paperxie隐藏王牌!一键生成满分学术答辩PPT

告别熬夜做PPT✨Paperxie隐藏王牌!一键生成满分学术答辩PPT

官方直达:https://www.paperxie.cn 写论文有AI辅助,做答辩PPT却还在熬夜抠排版、凑内容?很多同学论文质量很高,最后偏偏输在答辩PPT粗糙、逻辑混乱、重点模糊上! 相比于烂大街的论文写作、降重功能,Paper…

2026/7/29 19:29:24阅读更多 →
在线记事本,不需要登录注册,支持markdown格式

在线记事本,不需要登录注册,支持markdown格式

在日常学习、工作与生活中,我们时常需要临时记录灵感、整理文案、留存资料、编写代码笔记。传统笔记工具大多需要注册账号、绑定信息、登录授权,流程繁琐且占用时间,各类客户端软件还需要下载安装、占用设备内存。而免登录、免注册、原生支持…

2026/7/29 19:29:24阅读更多 →
深入AMD Ryzen硬件底层:SMUDebugTool专业调试工具完全指南

深入AMD Ryzen硬件底层:SMUDebugTool专业调试工具完全指南

深入AMD Ryzen硬件底层:SMUDebugTool专业调试工具完全指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https:…

2026/7/29 20:39:40阅读更多 →
Flutterust常见问题解答:新手入门必知的15个关键问题

Flutterust常见问题解答:新手入门必知的15个关键问题

Flutterust常见问题解答:新手入门必知的15个关键问题 【免费下载链接】flutterust Flutter Rust :heart: 项目地址: https://gitcode.com/gh_mirrors/fl/flutterust Flutterust是一个将Flutter与Rust完美结合的开源项目,它通过Foreign Function…

2026/7/29 20:39:40阅读更多 →
Path of Building:流放之路终极离线构筑模拟器完全指南

Path of Building:流放之路终极离线构筑模拟器完全指南

Path of Building:流放之路终极离线构筑模拟器完全指南 【免费下载链接】PathOfBuilding Offline build planner for Path of Exile. 项目地址: https://gitcode.com/gh_mirrors/pat/PathOfBuilding 想象一下,当你花费数周时间在《流放之路》中打…

2026/7/29 20:39:40阅读更多 →
XiaomiTool V2开发者指南:贡献代码与扩展功能详解

XiaomiTool V2开发者指南:贡献代码与扩展功能详解

XiaomiTool V2开发者指南:贡献代码与扩展功能详解 【免费下载链接】XiaoMiToolV2 XiaomiTool V2 - Modding tool for xiaomi devices 项目地址: https://gitcode.com/gh_mirrors/xia/XiaoMiToolV2 XiaomiTool V2是一款强大的小米设备调制工具,本文…

2026/7/29 20:39:40阅读更多 →
轻松管理Windows和Office激活:KMS智能工具使用指南

轻松管理Windows和Office激活:KMS智能工具使用指南

轻松管理Windows和Office激活:KMS智能工具使用指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 你是否经常遇到Windows系统弹出激活提醒,或是Office文档突然变成只读模…

2026/7/29 20:39:40阅读更多 →
物联网设备安全:SE050芯片与PIC18F57Q43的硬件级防护方案

物联网设备安全:SE050芯片与PIC18F57Q43的硬件级防护方案

1. 为什么物联网设备需要专用安全芯片?在当今的物联网环境中,设备安全已成为最关键的挑战之一。我曾在多个工业物联网项目中亲眼目睹,那些仅依赖软件加密方案的设备是如何被轻易攻破的。传统的MCU(如PIC18F系列)虽然能…

2026/7/29 20:37:40阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/29 9:47:45阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/29 7:00:19阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/29 7:58:51阅读更多 →
28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“! 在构建复杂的 Agent 系统时,我们经常会遇到这样的场景:Agent 正在执行一个多步骤的任务,比如“下单购买商品”,但执行到一半时,我们…

2026/7/29 0:01:46阅读更多 →
自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

近日,国际专注开放式技术研发的声学品牌Nank南卡,正式官宣实力艺人曾舜晞担任品牌代言人。消息一经发出便轰动全网。为什么耳机品牌不选择流量明星、老牌歌手?而且是选择曾舜晞?让我们一起来探索一下!比起短期的流量&a…

2026/7/29 0:01:46阅读更多 →
【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:01:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/29 4:31:51阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/29 14:26:42阅读更多 →