【听见课堂 HarmonyOS NEXT 实战系列 41】任务候选不能直接进待办:confirmed 字段的产品与数据意义
从课堂字幕里发现“周五提交实验报告”,只是得到一条可能的任务线索,并不等于用户已经同意把它加入正式待办。如果应用把规则或模型生成的候选直接写进任务中心,误识别、断句错误和上下文缺失都会变成正式数据,最终让用户不再信任自动整理功能。
听见课堂在TaskItem中使用confirmed把“待人工确认的候选”与“正式任务”分开。当前任务提取仍是明确标注的规则模拟,不是已经验证的真实 AI 模型。本文从领域模型、Service 过滤、Repository 写入和页面反馈四层拆解这条人工确认边界。
一、同一条任务为什么需要两种身份
候选区回答的是“系统认为这句话可能是一项任务吗”,任务中心回答的是“用户是否认可并愿意管理这项任务”。二者的责任不同,不能只靠页面位置区分。
confirmed=false表示候选,confirmed=true表示正式任务。字段进入领域模型和数据库后,即使页面重构、路由变化或设备宽度变化,业务语义仍然一致。
二、TaskItem 的最小状态集合
项目中的任务模型包含标题、截止时间原文、来源、确认状态、完成状态和规范化截止时间:
exportclassTaskItem{id:string;title:string;dueText:string;source:string;confirmed:boolean;completed:boolean;dueAtMillis:number;}confirmed控制是否进入正式管理链路,completed只对正式任务有意义,source则保留它从哪段课堂证据产生。
三、Service 用过滤规则生成两种视图
页面不直接对数据库结果散写过滤条件。ClassroomService分别暴露:
asyncgetCandidateTasks():Promise<Array<TaskItem>>{consttasks=awaitthis.repository.getTasks();returntasks.filter((item:TaskItem)=>!item.confirmed);}asyncgetConfirmedTasks():Promise<Array<TaskItem>>{consttasks=awaitthis.repository.getTasks();returntasks.filter((item:TaskItem)=>item.confirmed);}这样 P08 候选确认页与 P09 任务中心消费的是同一份 canonical data,只是业务视图不同。
四、任务中心再次执行 confirmed 门禁
getTaskCenterSnapshot()会读取全部任务,但第一步就是.filter(task => task.confirmed)。统计、周历、过期判断和完成切换都只在正式任务集合上进行。
这道二次门禁很重要:即使某个页面误把候选传给任务中心组件,Service 仍不会把未确认数据计入待办总数。
五、确认动作只修改一个业务事实
页面点击“确认加入”后调用confirmCandidateTask(),再由 Service 转交 Repository:
asyncconfirmTask(taskId:string):Promise<boolean>{constvalues:ValuesBucket={confirmed:1};returnthis.updateById(TABLE_TASKS,taskId,values);}确认不会重新生成标题,也不会丢掉来源。它只改变“用户是否认可”这一事实,然后页面重新读取候选、正式任务和聚合快照。
六、写后刷新比手工搬卡片可靠
确认成功后,页面没有把卡片从数组 A 手工移动到数组 B,而是调用refreshData()。候选列表、正式任务列表、复盘指标和任务中心统计都会从 Repository 重新计算。
这避免了页面局部状态和数据库状态不一致,也让 RelationalStore 与内存降级实现遵循同一条刷新路径。
七、撤销确认为什么要同时清理 completed
项目允许在确认成功后立即撤销。Repository 的unconfirmTask()会把confirmed和completed都重置为 0。
原因是:一条重新回到候选区的记录不应该继续携带“已完成”身份。否则再次确认时,它会绕过用户的待办阶段,直接出现在已完成列表。
八、候选、正式任务与历史证据不是一回事
候选区用于人工判断,任务中心用于状态管理,复盘与历史页用于解释来源。历史时间线可以展示任务证据,并根据confirmed标注“待人工确认”或“已人工确认”。
因此确认状态既影响操作权限,也影响证据解释,但不会删除原始课堂来源。
九、来源字段让确认决定可追溯
用户确认任务时需要看到标题之外的信息,例如来源字幕、课堂时间或板书上下文。当前source与reviewSourceTime()支撑基本跳转,P08 也能打开对应复盘节点。
这种设计比只保存一个标题更可靠,但当前来源时间仍有字符串解析成分,后续应演进为结构化证据 ID 和时间字段。
十、当前“智能提取”必须按规则模拟表述
getCapabilityStatus()明确把“任务智能提取”标为未完成,来源为“规则模拟”,说明文字是依据时间和关键词生成候选任务。
所以文章可以验证候选—确认—任务中心的业务闭环,不能据此声称已经接入大模型、具备真实语义理解或达到某个提取准确率。
十一、为什么不能让模型直接写 confirmed=true
模型输出天然存在误判。若远端 AI、规则引擎或本地模型拥有直接写正式数据的权限,一次错误就可能创建虚假截止时间、重复任务,甚至触发后续提醒。
更安全的架构是:生成器只产出候选 DTO,业务 Service 保存为confirmed=false,只有明确的用户动作才能提升为正式任务。
十二、完成状态也有 Repository 门禁
setTaskCompleted()会先查找任务,并拒绝不存在或尚未确认的记录。这样候选任务无法绕过确认流程直接变成“已完成”。
页面按钮是否隐藏只是体验层保护,Repository 的状态检查才是最终数据边界。
十三、AI 建议开关不会删除候选
页面的visibleCandidateTasks()在“智能整理”关闭时返回空数组,但底层候选仍保留。重新开启后,未确认记录可以再次出现。
开关控制的是展示与建议能力,不应静默删除用户可能需要复核的数据。
十四、当前实现仍需补强哪些校验
confirmTask()当前直接按 ID 更新,没有先检查记录是否已确认;重复点击主要依赖页面状态和刷新避免。后续可以增加旧值条件,例如只允许confirmed=0的一行更新,并要求影响行数恰好为 1。
如果将来加入多设备同步,还需要版本号或乐观锁,防止两个设备同时确认、撤销造成覆盖。
十五、验收应覆盖完整状态闭环
至少验证:候选初始不进入任务中心、确认后候选消失且任务中心出现、统计同步变化、撤销后回到候选、完成状态被清理、来源证据仍可打开、重启后 RelationalStore 状态保持。
项目既有 P08/P09 证据覆盖确认、撤销和任务中心刷新;这不等于真实 AI 候选质量已经验收。
十六、总结
confirmed不是一个为了方便筛选的布尔值,而是自动建议与用户正式数据之间的权限边界。听见课堂让规则或未来模型只能提出候选,让用户决定是否进入待办,再通过 Repository 门禁和写后刷新保持数据一致。
下一篇继续分析:为什么候选标题和截止时间只能在确认前编辑,以及这条限制如何由页面、Service 和 Repository 共同执行。