diff --git a/lib/common/models/manage/face_sync_models.dart b/lib/common/models/manage/face_sync_models.dart new file mode 100644 index 0000000..28b52a0 --- /dev/null +++ b/lib/common/models/manage/face_sync_models.dart @@ -0,0 +1,93 @@ +/// 人脸同步的业务范围,所有入口最终映射为部门快照或用户增量。 +enum FaceSyncMode { + /// 本部门及子部门的完整权威快照,用于每日对账和人工同步。 + departmentSnapshot, + + /// 指定用户的最新状态回查,用于 MQ 低延迟增量同步。 + userDelta, + + /// 非生产调试使用的全租户快照,生产界面不会暴露该模式。 + debugAllSnapshot, +} + +/// 一次人脸差异同步的结构化汇总,可直接映射到现有任务日志统计列。 +class FaceSyncSummary { + /// 创建同步汇总;失败样本只保存脱敏标识,不保存姓名、图片地址或特征。 + const FaceSyncSummary({ + required this.mode, + required this.scanned, + required this.added, + required this.updated, + required this.deleted, + required this.skipped, + required this.failed, + required this.maskedFailedSampleIds, + }); + + /// 本次同步模式。 + final FaceSyncMode mode; + + /// 从服务端完整读取并校验的记录数。 + final int scanned; + + /// 新增并成功写入本地数据库及虹软内存库的样本数。 + final int added; + + /// 元数据或图片版本成功更新的样本数。 + final int updated; + + /// 成功从虹软、本地数据库和正式文件范围移除的孤儿样本数。 + final int deleted; + + /// 服务端与本地版本完全一致、未发生下载或虹软写入的样本数。 + final int skipped; + + /// 本次处理失败且保留待下次重试的样本数。 + final int failed; + + /// 失败样本的脱敏编号,最多由同步服务保留有限数量用于现场定位。 + final List maskedFailedSampleIds; + + /// 本次成功新增、更新和删除的变更总数。 + int get changed => added + updated + deleted; + + /// 是否存在需要下次重试的失败样本。 + bool get hasFailures => failed > 0; + + /// 面向任务日志和设置页的简短结果描述。 + String get message { + if (!hasFailures) { + return '扫描 $scanned,新增 $added,更新 $updated,删除 $deleted,跳过 $skipped'; + } + final failedSamples = maskedFailedSampleIds.isEmpty + ? '' + : ',失败样本 ${maskedFailedSampleIds.join(',')}'; + return '扫描 $scanned,新增 $added,更新 $updated,删除 $deleted,失败 $failed$failedSamples'; + } +} + +/// V3 快照不完整、游标倒退或样本标识冲突时抛出的整次同步异常。 +class FaceSyncSnapshotException implements Exception { + /// 使用不包含图片地址和人员信息的安全摘要创建快照异常。 + const FaceSyncSnapshotException(this.message); + + /// 可写入终端任务日志的安全错误摘要。 + final String message; + + /// 返回安全错误摘要。 + @override + String toString() => message; +} + +/// 部分样本失败时交给统一调度器记录统计的异常。 +class FaceSyncPartialFailureException implements Exception { + /// 创建包含脱敏失败样本和完整计数的部分失败异常。 + const FaceSyncPartialFailureException(this.summary); + + /// 已完成的同步统计,失败项均保留旧数据等待下次重试。 + final FaceSyncSummary summary; + + /// 返回面向设置页的汇总描述。 + @override + String toString() => summary.message; +}