【听见课堂 HarmonyOS NEXT 实战系列 43】拒绝、撤销拒绝、稍后处理:任务候选的非破坏性交互
课堂里的自动候选不可能每一条都准确。如果“不是任务”直接等同于数据库删除,用户误触后将失去来源证据,也无法区分“这次不想处理”和“永远不要再出现”。对尚未验证准确率的规则或模型来说,破坏性拒绝尤其危险。
听见课堂当前把拒绝和稍后处理设计为页面内隐藏:正式任务不会增加,底层候选也不会删除,用户可以立即撤销。这个方案适合演示和低风险验证,但它还不是完整的持久化候选状态机。本文把已实现行为和后续演进边界分开说明。
一、“不是任务”为什么不能直接 delete
候选可能来自误识别,也可能只是用户暂时不想处理。直接删除会丢失判断依据,还可能让同一条规则在下次刷新时重新生成,形成“删了又来”的循环。
非破坏性操作先改变可见性,给用户保留撤销机会,也为后续分析候选质量留下空间。
二、当前拒绝集合保存在页面状态
P08 使用hiddenCandidateTaskIds记录本次被隐藏的任务 ID。拒绝函数只向数组追加 ID,并清理当前选择:
privaterejectCandidateTask(taskId:string):void{if(!this.hiddenCandidateTaskIds.includes(taskId)){this.hiddenCandidateTaskIds=[...this.hiddenCandidateTaskIds,taskId];}if(this.selectedCandidateTaskId===taskId){this.selectedCandidateTaskId='';}this.notice='候选任务已暂不加入;本次演示可立即撤销。';}这里没有 Repository 调用,所以数据库记录保持不变。
三、visibleCandidateTasks 负责展示过滤
候选原始集合来自 Service,页面只在渲染前过滤隐藏 ID:
returnthis.candidateTasks.filter((task:TaskItem)=>!this.hiddenCandidateTaskIds.includes(task.id));显示集合和 canonical data 分开后,撤销只需恢复过滤状态,不需要重新插入一条任务。
四、撤销拒绝为什么成本很低
undoRejectedCandidates()将隐藏 ID 数组清空,并显示“候选任务重新显示”。因为原记录从未被删除,撤销不涉及数据库恢复、主键重建或来源补写。
这是可逆交互最直接的工程收益。
五、全部稍后处理不是批量删除
deferAllCandidateTasks()把当前候选 ID 全部写入隐藏数组,同时清空选中项和编辑项。页面明确提示“未写入正式任务”。
它表达的是“这批先不处理”,不是“这些候选无效”。用户仍可点击“撤销稍后处理”恢复。
六、逐项拒绝与批量稍后处理语义不同
逐项“不是任务”表示用户对某条候选做了负向判断;“全部稍后处理”更接近延迟决策。当前两者都落到同一个隐藏数组,交互可用,但业务语义尚未持久化区分。
如果未来要评估规则质量,必须记录不同原因,而不能只看到“不可见”。
七、确认操作才会修改正式数据状态
“确认加入”调用 Service 和 Repository,把confirmed更新为真;拒绝与稍后处理都不改confirmed。因此 P09 正式任务中心只会新增经过人工确认的记录。
这保证了隐藏候选不会因为页面操作失误进入待办统计。
八、AI 建议开关是另一层可见性控制
当aiSuggestionsEnabled关闭时,visibleCandidateTasks()直接返回空数组,但候选数据仍在本机。开关控制是否展示建议,不应被理解为清空数据库。
重新开启后,未确认且未被本次页面状态隐藏的候选可以继续复核。
九、页面刷新和应用重启的边界
refreshData()会重新读取候选,但不会主动清空当前页面的隐藏 ID,因此同一页面生命周期内的隐藏通常仍然有效。应用进程重启后,短生命周期数组会恢复默认值,候选可能重新出现。
文章必须明确:当前是可演示的临时撤销机制,不是已经持久化的拒绝历史。
十、为什么当前方案仍有产品价值
在候选生成能力尚处于规则模拟阶段,先验证“用户不会被迫接受”“可以撤销”“正式数据不被污染”比急着设计复杂拒绝表更重要。
它以较小实现成本建立了正确的权限方向,并为后续 schema 演进保留空间。
十一、后续 schema 可以怎样演进
可以为任务增加candidate_status,取值如pending、confirmed、rejected、deferred;再增加decision_at、decision_reason和可选的生成器版本。
正式任务的confirmed仍可保留,或在迁移后由状态字段统一表达。迁移必须兼容已有记录与内存降级实现。
十二、拒绝记录不等于训练数据授权
即使持久化用户的拒绝原因,也不能默认把这些数据上传用于模型训练。课堂字幕、任务标题和来源可能含个人信息或课程隐私。
若将来要做质量分析,应先定义本机统计、匿名化范围、用户选择和删除机制。
十三、批量操作需要稳定快照
当前“全部稍后处理”从candidateTasks直接提取所有 ID。如果未来候选在后台异步更新,批量操作应基于用户点击时的可见快照,并记录实际影响数量。
这样新增候选不会被一次旧操作意外隐藏。
十四、错误恢复应区分本地态和存储态
页面隐藏操作本身不会失败,但未来持久化后可能遇到写入异常。界面应明确“仅本次隐藏”还是“已保存决定”,不能在保存失败时仍展示永久成功文案。
最安全的做法是先写 Repository,成功后再更新可见集合;失败则保留候选并提供重试。
十五、验收清单
至少验证:单条拒绝立即隐藏、撤销后恢复、全部稍后处理不进入任务中心、撤销批量操作恢复、确认任务不再出现在候选、AI 开关不删除数据、页面重启后临时隐藏状态按设计恢复。
如果引入持久化,还要补迁移、重复点击、并发更新、清除数据和隐私导出检查。
十六、总结
候选任务的“拒绝”首先应该保护用户,而不是保护算法输出。听见课堂当前用页面隐藏实现低风险、可撤销、不污染正式待办的交互,并明确它只在短生命周期内有效。
下一篇转向截止时间:如何把“今晚”“明天 20:00”“本周五”等中文表达解析为可排序、可判断过期的本地时间,同时避免夸大规则解析能力。