云计算百科
云计算领域专业知识百科平台

篮球口袋教练 HarmonyOS 学习应用(06):测验结果页的解释型反馈

测验页面的价值不止是给出分数。对于学习者,知道“这一题错了”还不够,还要能看到正确选项和解释;完成一组题后,结果页还应给出本次成绩与历史最佳成绩。篮球口袋教练把逐题反馈和结果汇总分为两个阶段,避免在答题过程中丢失题目上下文。

篮球口袋教练 HarmonyOS 学习应用(06):测验结果页的解释型反馈运行回读

一、单题反馈保存题目上下文

用户选择选项后,页面根据当前题的正确答案计算对错,并展示正确选项与解释文本。解释来自题目模型,不是页面临时拼接的通用提示,因此不同知识点可以保留各自的学习原因。

const correct = question.options[selectedIndex] === question.answer
this.feedback = correct ? '回答正确' : '答案不正确'
this.explanation = question.explanation

题目、用户选择、正确答案和解释要在当前题切换前一起保留。否则页面一进入下一题,用户只能看到结果颜色,无法知道自己在哪个概念上出现偏差。

二、完成结果以模块为单位归档

答完后,服务记录模块 id、得分、题目总数与时间。历史最佳成绩从同一模块的结果集合中计算,因此体能训练的成绩不会覆盖战术策略的成绩。

static bestScore(moduleId: string): number {
return QuizService.allResults()
.filter(item => item.moduleId === moduleId)
.reduce((best, item) => Math.max(best, item.score), 0)
}

页面阶段关注信息用户能得到什么
作答中 当前题、所选答案、解释 立即理解对错原因
提交后 得分、总题数、正确率 了解本次完成度
再次进入 模块历史最佳 判断是否超过过去表现

三、运行回读结果

模拟器中逐题选择答案后,页面回读到正确选项、对错反馈和当前题解释。完成体能训练模块 6 道题后,结果页显示 6/6、100%、“满分”和“历史最高:6/6”。这证明解释反馈与结果汇总都在真实答题动作链中出现。

四、解释型反馈的边界

解释型反馈不等于给用户直接公布所有题目的答案。正确的顺序是先接受用户选择,再显示该题的判定与解释;结果页只汇总已经完成的题目。若题目集合为空,页面应阻止进入作答并提示暂无内容,而不是生成 0 分的伪结果。

五、后续扩展的切入点

当前模型已经以模块 id 分隔成绩,后续可以在不改变题目反馈逻辑的前提下增加错题回练、按知识点统计和阶段性复习。关键是继续让题目解释、作答过程和成绩持久化各自承担单一职责,避免把所有规则堆进结果页。

分数之外为什么还要保留错因

解释型反馈的关键是把题目、用户选择、正确答案和 explanation 在切题前保留下来。只有颜色变化不能帮助学习者建立概念;例如挡拆、空间或退防的题目需要把正确选择与原因连在一起,才能把一次答错转成下一次训练的依据。

提交阶段保存 moduleId、score、total 和时间,历史最佳从同模块记录中归约得到。这个范围限制很重要:不同主题的题目数量与难度不同,不能让一次体能小测的分数覆盖战术模块的学习轨迹。

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.setOrCreate<string>(QUIZ_KEY, JSON.stringify(results));
}

static allResults(): QuizResult[] {
const raw: string = AppStorage.get<string>(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);
}

static completedModuleCount(): number {
const done: Set<string> = new Set<string>();
for (const r of QuizService.allResults()) {
done.add(r.moduleId);

提交结果如何按模块归档

结果页的保存应有幂等边界。页面重新显示时可以回读已保存结果和最佳分,但不应因为组件再次出现又插入一条相同记录;空题库则应终止提交并给出返回路径,而不是写入 0/0 的假成绩。

}

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);
}

static completedModuleCount(): number {
const done: Set<string> = new Set<string>();
for (const r of QuizService.allResults()) {
done.add(r.moduleId);
}
return done.size;
}

static hasPerfect(): boolean {
return QuizService.allResults().some(r => r.score === r.total);
}
}

检查对象事实来源页面应表现
正常路径 题目模型保留正确答案与 explanation,QuizService 按 moduleId 保存结果并在同一模块集合中计算 bestScore。 显示与真实数据一致的结果
边界条件 结果页重建、重复进入、空题库和不同模块切换不能重复写分或混淆历史最佳。 不给出假成功,保留可恢复入口
回读验证 完成一个模块测验、回读解释与本次得分,重进结果页核对历史最佳,再切换另一模块确认成绩独立。 跨页面或重进后结果一致

历史最佳怎样避免跨模块串分

验收要覆盖完成、重进和切模块三个时刻:本次结果页显示解释,重进后最佳分保持,另一个模块的最佳分不受影响。这样验证的是结果模型和数据范围,而不是一次偶然的按钮文案。

if (params !== undefined && params !== null) {
this.moduleId = params.moduleId;
this.score = params.score;
this.total = params.total;
const m: LearnModule | undefined = findModule(this.moduleId);
this.moduleTitle = m !== undefined ? m.title : '测验';

if (!this.saved) {
QuizService.submitResult(this.moduleId, this.score, this.total);
this.saved = true;
}
}
}

build() {
Column() {
TopBar({ title: '测验结果' });

Scroll() {
Column({ space: AppSizes.s5 }) {
Column().height(AppSizes.s5);

// 分数圆环
Stack({ alignContent: Alignment.Center }) {
Column()
.width(160).height(160)
.borderRadius(80)
.border({ width: 8, color: this.palette.bgElevated });
Column()
.width(160).height(160)
.borderRadius(80)
.border({ width: 8, color: this.ringColor() })
.opacity(1);
Column({ space: AppSizes.s1 }) {

上述代码片段来自当前实现的连续调用点:它们分别回答“谁提供事实”“谁消费结果”“异常时在哪里停止”。读者排查同类问题时,应先验证这三个边界,而不是只根据按钮颜色判断业务是否完成。

结果页的重进与重复提交

完成一个模块测验、回读解释与本次得分,重进结果页核对历史最佳,再切换另一模块确认成绩独立。

定位这类问题时,第一步应回到实际风险:只显示本次分数会让学习者不知道错在哪;若结果未按模块归档,战术测验可能覆盖体能测验的历史最佳。。先确认输入是否已经被模型或服务拒绝,再检查页面是否把该结果展示出来;如果先从视觉现象倒推,往往会把偶然残留的控件状态误判成业务完成。

当前实现选择的是:题目模型保留正确答案与 explanation,QuizService 按 moduleId 保存结果并在同一模块集合中计算 bestScore。。这意味着每个页面不必重复实现同一份判断,却也要求任何新增入口都调用相同的服务或模型;绕过该入口虽然能暂时缩短页面代码,却会让后续回读失去一致性。

需要单独保住的边界是:结果页重建、重复进入、空题库和不同模块切换不能重复写分或混淆历史最佳。。边界出现时,页面应当保留原因和下一步操作,而不是把错误状态压成空白或成功提示。读者据此可以区分“没有数据”“资源不可用”和“动作尚未完成”。

把这条边界写进文章还有一个维护价值:当课程内容、页面布局或资源形式变化时,验收仍可以围绕同一个事实来源进行,而不必依赖某张旧截图或某个控件曾经显示过的文字。这样得到的结论能被下一次修改复查。

排查顺序应先确认的事实不应采用的替代做法
输入 课程、记录或题目是否有稳定标识 从页面文本推断业务对象
服务 判断或写入是否经过唯一入口 在多个页面复制同一段临时逻辑
回读 重进后是否从持久化或模型得到同一结果 只凭一次按钮变化判定成功

ArkTS 响应式状态的基础机制可参考 HarmonyOS ArkTS 状态管理文档。这里的重点不是堆叠状态字段,而是让页面在每次进入时都从同一业务事实重新得到可见结果。

当需求继续扩展时,应把新增条件加入现有服务或模型的明确入口,并为该条件补充可观察的回读动作。这样课程内容、页面交互和持久化数据仍可沿同一条链路解释,而不会在不同入口形成互相矛盾的结论。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 篮球口袋教练 HarmonyOS 学习应用(06):测验结果页的解释型反馈
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!