【听见课堂 HarmonyOS NEXT 实战系列 36】P05 到 P06:扫描材料与文字复核的双页面状态流
【听见课堂 HarmonyOS NEXT 实战系列 36】P05 到 P06:扫描材料与文字复核的双页面状态流
扫描页负责“从哪里拿图片”,复核页负责“这段文字最终是否可信”。如果拍照、图库、OCR、人工编辑和数据库保存全部堆在一个页面里,任何失败都会同时污染取景状态、文本草稿和持久化结果。
听见课堂把 P05 设计为扫描材料页,把 P06 设计为 OCR 校对页。两页共用一组短生命周期状态,但业务含义清晰分开:P05 选择来源并启动处理,P06 对照、修订和保存。本文按 Index.ets 当前实现拆解完整状态流,也指出它尚未抽成 ViewModel 的维护成本。

一、P05 的职责是获得可信输入
P05 提供系统相机、系统图库和本地示例三个入口。它负责展示等待、正在打开系统 UI、处理图片和失败恢复,不负责决定最终写入数据库的文字。
页面成功拿到 URI 后,把它交给 recognizeSelectedPhoto();用户取消则停留在 P05,不创建任何扫描记录。
二、P06 的职责是做最后确认
P06 同时展示识别文本、原图或示例内容、来源、课堂时间和工具栏。用户可以旋转、重置、复制、切页并编辑,只有点击“完成”且文本非空时才进入保存。
这把自动 OCR 结果定义成草稿,而不是不可修改的事实。
三、scanStatus 描述流程阶段
scanStatus 的值包括“等待扫描”“正在打开系统相机”“正在本机识别图片文字”“真实图片 OCR 成功,请复核后保存”等。
它回答“当前正在发生什么”,不保存图片或文本。流程阶段与业务数据分离后,状态文案变化不会误触数据库。
四、scanImageUri 只保存临时图片句柄
@Local private scanImageUri: string = '';
非空时表示当前复核来自真实图片,P05/P06 用它预览原图;成功保存后立即清空。Repository 不持久化这个临时 URI。
五、scanSourceLabel 记录输入来源
系统相机、系统图库和本地示例分别写入不同来源标签。保存时它会与“Core Vision Kit”或“人工复核”以及课堂时间组合。
来源不仅用于界面提示,还帮助复盘页解释这段板书从哪里得到。
六、ocrText 是用户可编辑草稿
@Local private ocrText: string = '';
OCR 成功时写入识别结果,失败时清空等待人工录入;切换已有扫描页时加载对应 ScanNote.text。它属于页面草稿态,只有保存成功后才通过 Service 进入 Repository。
七、scanError 决定恢复语义
错误状态不只是红色文案。保存时,scanError.length > 0 会让来源标记为“人工复核”,从而与自动 OCR 成功后校正的记录区分开。
页面在每次新扫描开始前清空旧错误,避免上一次失败污染下一张图片。
八、isScanProcessing 防止并发流程
if (this.isScanProcessing) return;
this.isScanProcessing = true;
try {
// Picker 与 OCR
} finally {
this.isScanProcessing = false;
}
按钮同时使用 .enabled(!this.isScanProcessing)。系统 UI 拉起、图片解码和 OCR 期间不会创建第二条并发链路。
九、真实图片成功路径
P05 点击相机/图库
→ 得到 URI
→ 保存临时 URI 与来源
→ Core Vision OCR
→ 写入 ocrText
→ 导航 P06
→ 用户复核并保存
即使 OCR 成功,页面状态仍是“请复核后保存”,不会直接写库。
十、OCR 失败仍然进入 P06
失败分支保留 scanImageUri,清空 ocrText,设置可理解的 scanError,再导航 P06。用户可以看着真实原图手工录入,而不是被迫重选图片。
这是一条完整降级链路,不是把异常吞掉后显示空白页。

十一、取消为何停在 P05
CameraPicker 或 PhotoViewPicker 返回空 URI 时,P05 显示“已取消”,不进入 P06。没有图片、没有示例、没有已有记录时,复核页没有可解释对象。
取消也不会清除数据库中的旧扫描笔记。
十二、保存前的三个门禁
saveOcrReview() 先校验非空文本,再计算来源与课堂时间,最后调用 service.updateScanText()。只有 Repository 返回成功,页面才清理临时状态、刷新快照并进入复盘页。
未影响任何记录时不能显示“保存成功”。
十三、返回路径必须保留用户判断
P06 返回按钮导航到 P05,完成按钮保存后进入 P07 复盘。返回不应自动保存半成品,完成也不能绕过非空校验。
若未来需要“保留草稿”,应新增明确草稿模型,而不是把页面 Local 状态假装成持久化。
十四、手机和大屏共用同一状态
ocrReviewPage() 根据 isLarge 选择紧凑页或大屏页。布局不同,但读取相同的 ocrText、scanImageUri、scanError 和保存函数。
设备适配只改变空间组织,不改变 OCR 成功、人工复核与保存契约。
十五、为什么值得抽成 ViewModel
当前状态和异步方法集中在大型 Index.ets 中,随着批量扫描、取消令牌和草稿恢复增加,页面会越来越难测试。更清晰的结构可以是:
P05/P06 ArkUI
→ ScanReviewViewModel
→ ScanCaptureService
→ ClassroomService
→ Repository
ViewModel 负责页面可消费状态和事件,能力层负责 Picker/OCR,业务层负责保存规则。
十六、已有验证边界
模拟器已验证 P05 本地示例、图库选择器打开/取消、相机不可用降级、P06 编辑保存和时间反显;真实相机、真图 OCR 与页面退出期间的异步回写仍需真机补证。
因此双页面状态流可以记录为已实现并部分运行验证,不能写成所有输入链路全部通过。
十七、总结
P05 和 P06 的分工让“获得图片”与“确认文字”不再互相污染。临时 URI、可编辑文本、错误来源和 Repository 后置条件共同保证:自动能力失败时用户仍能完成任务,保存成功时又有真实写入证据。
下一篇继续拆解多页 OCR:页面索引如何受到保护,以及当前“多页模式”还没有完成哪些批量能力。
参考:项目 scanPage()、recognizeSelectedPhoto()、ocrReviewPage()、saveOcrReview() 与 P05/P06 扫描 OCR 复验报告。
更多推荐



所有评论(0)