feat:消费机更新

feat:人员调用钱包部门不调动的bug
This commit is contained in:
dzc committed 2026-09-09 11:56:19 +08:00
1 parent 842402e364
commit 60d9380a65
144 files changed
+27832 -1666

No files matched your search

@@ -41,6 +41,18 @@ class FaceEntity extends Equatable {
/// 同步时间
DateTime? updateTime;
/// 最近一次在库图片质量分,范围为0到1;未检测或检测失败时为空。
double? qualityScore;
/// 质量检测状态,持久化值为pending、detected或failed。
String qualityStatus;
/// 最近一次质量检测完成时间;从未检测时为空。
DateTime? qualityCheckedAt;
/// 最近一次质量检测的虹软或插件错误码;成功时为空。
int? qualityErrorCode;
FaceEntity({
this.id,
required this.userId,
@@ -53,6 +65,10 @@ class FaceEntity extends Equatable {
this.faceModel,
this.createTime,
this.updateTime,
this.qualityScore,
this.qualityStatus = 'pending',
this.qualityCheckedAt,
this.qualityErrorCode,
});
factory FaceEntity.fromJson(Map<String, dynamic> json) =>
@@ -22,6 +22,12 @@ FaceEntity _$FaceEntityFromJson(Map<String, dynamic> json) => FaceEntity(
updateTime: json['updateTime'] == null
? null
: DateTime.parse(json['updateTime'] as String),
qualityScore: (json['qualityScore'] as num?)?.toDouble(),
qualityStatus: json['qualityStatus'] as String? ?? 'pending',
qualityCheckedAt: json['qualityCheckedAt'] == null
? null
: DateTime.parse(json['qualityCheckedAt'] as String),
qualityErrorCode: (json['qualityErrorCode'] as num?)?.toInt(),
);
Map<String, dynamic> _$FaceEntityToJson(FaceEntity instance) =>
@@ -37,4 +43,8 @@ Map<String, dynamic> _$FaceEntityToJson(FaceEntity instance) =>
'faceModel': instance.faceModel,
'createTime': instance.createTime?.toIso8601String(),
'updateTime': instance.updateTime?.toIso8601String(),
'qualityScore': instance.qualityScore,
'qualityStatus': instance.qualityStatus,
'qualityCheckedAt': instance.qualityCheckedAt?.toIso8601String(),
'qualityErrorCode': instance.qualityErrorCode,
};
@@ -0,0 +1,97 @@
import 'package:floor/floor.dart';
import 'package:json_annotation/json_annotation.dart';
part 'file_upload_record_entity.g.dart';
/// 本机文件上传记录。
///
/// 目前 [bizType] 使用 `terminal_log`,保留业务类型后可复用到数据库备份等文件任务。
@JsonSerializable()
@Entity(
tableName: 'file_upload_record',
indices: [
Index(value: ['hardId', 'bizType', 'relativePath'], unique: true),
Index(value: ['bizType', 'status', 'updateTime']),
],
)
class FileUploadRecordEntity {
/// SQLite 自增主键;首次保存前为空。
@PrimaryKey(autoGenerate: true)
final int? id;
/// 终端绑定的设备 ID,用于隔离设备重新绑定前后的文件状态。
final String hardId;
/// 文件业务类型;终端日志固定使用 `terminal_log`。
final String bizType;
/// 文件在业务根目录下使用正斜杠的相对路径。
final String relativePath;
/// 原始文件名,不包含目录。
final String originalName;
/// 生成脱敏副本时读取的原文件快照大小,单位为字节。
final int sourceSize;
/// 生成脱敏副本时原文件的最后修改时间。
final DateTime sourceModifiedTime;
/// 脱敏后文件内容的 MD5 哈希;首次尝试尚未完成脱敏时可为空字符串。
final String sanitizedHash;
/// 脱敏后文件大小,单位为字节;尚未完成脱敏时为零。
final int sanitizedSize;
/// 最近一次上传尝试状态,保存 [FileUploadStatus.name]。
final String status;
/// 后端 hard_terminal_log_file 记录 ID;预检判定无需上传且本机无旧记录时可为空。
final String? serverFileId;
/// 对该路径发起过的上传尝试次数,预检前即递增。
final int attemptCount;
/// 最近一次开始上传尝试的本地时间;从未尝试时为空。
final DateTime? lastAttemptAt;
/// 最近一次被服务端确认成功或无需上传的本地时间。
final DateTime? uploadedAt;
/// 最近一次失败的截断错误摘要;成功记录为空。
final String? lastError;
/// 当前设备与业务类型下首次创建该路径记录的本地时间。
final DateTime createTime;
/// 状态、快照或服务端 ID 最近一次更新的本地时间。
final DateTime updateTime;
/// 创建一条文件上传状态记录。
const FileUploadRecordEntity({
this.id,
required this.hardId,
required this.bizType,
required this.relativePath,
required this.originalName,
required this.sourceSize,
required this.sourceModifiedTime,
required this.sanitizedHash,
required this.sanitizedSize,
required this.status,
this.serverFileId,
this.attemptCount = 0,
this.lastAttemptAt,
this.uploadedAt,
this.lastError,
required this.createTime,
required this.updateTime,
});
/// 从 JSON 数据恢复上传记录,仅供调试序列化使用。
factory FileUploadRecordEntity.fromJson(Map<String, dynamic> json) =>
_$FileUploadRecordEntityFromJson(json);
/// 将上传记录转换为 JSON,仅供调试序列化使用。
Map<String, dynamic> toJson() => _$FileUploadRecordEntityToJson(this);
}
@@ -0,0 +1,55 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'file_upload_record_entity.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
FileUploadRecordEntity _$FileUploadRecordEntityFromJson(
Map<String, dynamic> json) =>
FileUploadRecordEntity(
id: (json['id'] as num?)?.toInt(),
hardId: json['hardId'] as String,
bizType: json['bizType'] as String,
relativePath: json['relativePath'] as String,
originalName: json['originalName'] as String,
sourceSize: (json['sourceSize'] as num).toInt(),
sourceModifiedTime: DateTime.parse(json['sourceModifiedTime'] as String),
sanitizedHash: json['sanitizedHash'] as String,
sanitizedSize: (json['sanitizedSize'] as num).toInt(),
status: json['status'] as String,
serverFileId: json['serverFileId'] as String?,
attemptCount: (json['attemptCount'] as num?)?.toInt() ?? 0,
lastAttemptAt: json['lastAttemptAt'] == null
? null
: DateTime.parse(json['lastAttemptAt'] as String),
uploadedAt: json['uploadedAt'] == null
? null
: DateTime.parse(json['uploadedAt'] as String),
lastError: json['lastError'] as String?,
createTime: DateTime.parse(json['createTime'] as String),
updateTime: DateTime.parse(json['updateTime'] as String),
);
Map<String, dynamic> _$FileUploadRecordEntityToJson(
FileUploadRecordEntity instance) =>
<String, dynamic>{
'id': instance.id,
'hardId': instance.hardId,
'bizType': instance.bizType,
'relativePath': instance.relativePath,
'originalName': instance.originalName,
'sourceSize': instance.sourceSize,
'sourceModifiedTime': instance.sourceModifiedTime.toIso8601String(),
'sanitizedHash': instance.sanitizedHash,
'sanitizedSize': instance.sanitizedSize,
'status': instance.status,
'serverFileId': instance.serverFileId,
'attemptCount': instance.attemptCount,
'lastAttemptAt': instance.lastAttemptAt?.toIso8601String(),
'uploadedAt': instance.uploadedAt?.toIso8601String(),
'lastError': instance.lastError,
'createTime': instance.createTime.toIso8601String(),
'updateTime': instance.updateTime.toIso8601String(),
};
@@ -82,6 +82,7 @@ const _$OrderPayTypeEnumMap = {
OrderPayType.WALLET_DEFAULT: 'WALLET_DEFAULT',
OrderPayType.WALLET_QR_CODE: 'WALLET_QR_CODE',
OrderPayType.WALLET_QR_CODE_SCAN: 'WALLET_QR_CODE_SCAN',
OrderPayType.AGGREGATE_ORDER_PAY: 'AGGREGATE_ORDER_PAY',
OrderPayType.WALLET_CARD: 'WALLET_CARD',
OrderPayType.FACE: 'FACE',
OrderPayType.STRIDE_DEPT_QR_CODE: 'STRIDE_DEPT_QR_CODE',
@@ -0,0 +1,211 @@
import 'package:floor/floor.dart';
/// 终端订单识别证据补传任务。
///
/// 本表是断网、崩溃和接口超时后的本地待办队列,不是最终证据库。服务端确认成功后立即删除
/// [localFilePath] 对应的现场图片;失败图片最多保留 30 天,任务终态元数据按业务规则保留。
@Entity(
tableName: 'order_evidence_upload_task',
indices: [
Index(
value: [
'androidOrderCode',
'evidenceType',
'evidenceRole',
'sequenceNo',
],
unique: true,
),
Index(value: ['status', 'nextRetryAt', 'createTime']),
],
)
class OrderEvidenceUploadTaskEntity {
/// SQLite 自增主键,首次保存前为空。
@PrimaryKey(autoGenerate: true)
final int? id;
/// 终端生成的稳定订单号,用于响应超时后与服务端对账。
final String? androidOrderCode;
/// 对账成功后的服务端订单主键;尚未落单或请求结果不确定时为空。
final String? serverOrderId;
/// 产生现场图片的人脸识别业务会话编号,用于诊断但不作为服务端幂等键。
final String recognitionSessionId;
/// 证据类型,保存 `OrderEvidenceType.code`。
final String evidenceType;
/// 图片角色,保存 `OrderEvidenceRole.code`。
final String evidenceRole;
/// 同一订单、类型和角色下的稳定序号,从 0 开始。
final int sequenceNo;
/// 识别用户主键快照,来源于最终用于下单的人员。
final String userId;
/// 虹软样本编号快照;非人脸证据允许为空。
final String? faceSampleId;
/// 识别时本地人脸记录保存的后台参考图片地址,仅由服务端校验和复制。
final String? referenceImageUrl;
/// 识别时参考图片的版本摘要,当前使用本地人脸记录更新时间 ISO 字符串。
final String? referenceImageVersion;
/// 终端私有目录中的现场 JPEG 路径;参考图、已成功或图片到期任务为空。
final String? localFilePath;
/// 现场图片或已知参考图内容的 SHA-256;参考图未知内容时允许为空。
final String? imageHash;
/// 现场图片大小,单位字节;参考图未下载时允许为空。
final int? imageSize;
/// 现场图片宽度,单位像素;参考图未下载时允许为空。
final int? imageWidth;
/// 现场图片高度,单位像素;参考图未下载时允许为空。
final int? imageHeight;
/// 人脸比对相似度快照,范围 0 到 1;菜谱识别允许为空。
final double? similarity;
/// 人脸比对通过时使用的阈值快照,范围 0 到 1;菜谱识别允许为空。
final double? similarityThreshold;
/// 真正比对成功帧的终端采集时间。
final DateTime capturedAt;
/// 产生证据时的终端应用展示版本与内部版本组合。
final String appVersion;
/// 当前任务状态,保存 `OrderEvidenceTaskStatus.code`。
final String status;
/// 已发起的服务端对账、提交或上传尝试次数,用于计算退避间隔。
final int attemptCount;
/// 下一次允许自动处理的本地时间;立即可处理时为空。
final DateTime? nextRetryAt;
/// 服务端证据记录主键;尚未创建或永久缺失上报未返回时为空。
final String? serverEvidenceId;
/// 服务端最终证据图片地址;非 AVAILABLE 或参考复制失败时为空。
final String? serverImageUrl;
/// 最近一次失败的单行截断摘要,不包含 Token、原始帧、完整路径或图片内容。
final String? lastError;
/// 终端已向服务端成功报告 UNAVAILABLE 的时间;未报告或无订单时为空。
final DateTime? unavailableReportedAt;
/// 服务端确认 AVAILABLE 的完成时间;其他状态为空。
final DateTime? completedAt;
/// 任务首次创建时间,用于 24 小时未绑定订单和终态保留策略。
final DateTime createTime;
/// 状态、重试时间或服务端结果最近一次更新时间。
final DateTime updateTime;
/// 当前图片或未绑定任务的本地到期时间;绑定订单后延长为现场图片 30 天。
final DateTime expiresAt;
/// 创建一条可持久化的订单证据补传任务。
const OrderEvidenceUploadTaskEntity({
this.id,
this.androidOrderCode,
this.serverOrderId,
required this.recognitionSessionId,
required this.evidenceType,
required this.evidenceRole,
required this.sequenceNo,
required this.userId,
this.faceSampleId,
this.referenceImageUrl,
this.referenceImageVersion,
this.localFilePath,
this.imageHash,
this.imageSize,
this.imageWidth,
this.imageHeight,
this.similarity,
this.similarityThreshold,
required this.capturedAt,
required this.appVersion,
required this.status,
this.attemptCount = 0,
this.nextRetryAt,
this.serverEvidenceId,
this.serverImageUrl,
this.lastError,
this.unavailableReportedAt,
this.completedAt,
required this.createTime,
required this.updateTime,
required this.expiresAt,
});
/// 保留证据位置和识别快照,生成包含指定状态变化的新任务。
OrderEvidenceUploadTaskEntity copyWith({
String? androidOrderCode,
String? serverOrderId,
String? localFilePath,
bool clearLocalFilePath = false,
String? imageHash,
int? imageSize,
int? imageWidth,
int? imageHeight,
String? status,
int? attemptCount,
DateTime? nextRetryAt,
bool clearNextRetryAt = false,
String? serverEvidenceId,
String? serverImageUrl,
String? lastError,
bool clearLastError = false,
DateTime? unavailableReportedAt,
DateTime? completedAt,
DateTime? updateTime,
DateTime? expiresAt,
}) {
return OrderEvidenceUploadTaskEntity(
id: id,
androidOrderCode: androidOrderCode ?? this.androidOrderCode,
serverOrderId: serverOrderId ?? this.serverOrderId,
recognitionSessionId: recognitionSessionId,
evidenceType: evidenceType,
evidenceRole: evidenceRole,
sequenceNo: sequenceNo,
userId: userId,
faceSampleId: faceSampleId,
referenceImageUrl: referenceImageUrl,
referenceImageVersion: referenceImageVersion,
localFilePath:
clearLocalFilePath ? null : localFilePath ?? this.localFilePath,
imageHash: imageHash ?? this.imageHash,
imageSize: imageSize ?? this.imageSize,
imageWidth: imageWidth ?? this.imageWidth,
imageHeight: imageHeight ?? this.imageHeight,
similarity: similarity,
similarityThreshold: similarityThreshold,
capturedAt: capturedAt,
appVersion: appVersion,
status: status ?? this.status,
attemptCount: attemptCount ?? this.attemptCount,
nextRetryAt: clearNextRetryAt ? null : nextRetryAt ?? this.nextRetryAt,
serverEvidenceId: serverEvidenceId ?? this.serverEvidenceId,
serverImageUrl: serverImageUrl ?? this.serverImageUrl,
lastError: clearLastError ? null : lastError ?? this.lastError,
unavailableReportedAt:
unavailableReportedAt ?? this.unavailableReportedAt,
completedAt: completedAt ?? this.completedAt,
createTime: createTime,
updateTime: updateTime ?? this.updateTime,
expiresAt: expiresAt ?? this.expiresAt,
);
}
}
@@ -6,7 +6,12 @@ import 'package:pj_supermarket_cloud/common/index.dart';
part 'print_history_entity.g.dart';
@JsonSerializable()
@Entity(tableName: "print_history")
@Entity(
tableName: "print_history",
indices: [
Index(value: ['servicePrintId'], unique: true)
],
)
class PrintHistoryEntity {
/// 自增ID
@PrimaryKey(autoGenerate: true)
@@ -24,6 +29,18 @@ class PrintHistoryEntity {
/// 发票图片地址
String invoiceUrl;
/// 服务端凭证类型、打印序号与重试版本。
String printType;
int printNo;
int retryVersion;
/// 当前重试版本实际执行的 USB 尝试次数和最近错误。
int attemptCount;
String? lastError;
/// 打印结果尚未可靠提交到服务端时保持为 true,网络恢复后继续补报。
bool resultPending;
/// 打印状态
PrintStatus status;
@@ -42,6 +59,12 @@ class PrintHistoryEntity {
required this.serviceOrderId,
required this.servicePrintId,
required this.invoiceUrl,
this.printType = '1',
this.printNo = 1,
this.retryVersion = 0,
this.attemptCount = 0,
this.lastError,
this.resultPending = false,
required this.status,
this.printTime,
this.syncTime,
@@ -13,6 +13,12 @@ PrintHistoryEntity _$PrintHistoryEntityFromJson(Map<String, dynamic> json) =>
serviceOrderId: json['serviceOrderId'] as String,
servicePrintId: json['servicePrintId'] as String,
invoiceUrl: json['invoiceUrl'] as String,
printType: json['printType'] as String? ?? '1',
printNo: (json['printNo'] as num?)?.toInt() ?? 1,
retryVersion: (json['retryVersion'] as num?)?.toInt() ?? 0,
attemptCount: (json['attemptCount'] as num?)?.toInt() ?? 0,
lastError: json['lastError'] as String?,
resultPending: json['resultPending'] as bool? ?? false,
status: $enumDecode(_$PrintStatusEnumMap, json['status']),
printTime: json['printTime'] as String?,
syncTime: json['syncTime'] == null
@@ -28,6 +34,12 @@ Map<String, dynamic> _$PrintHistoryEntityToJson(PrintHistoryEntity instance) =>
'serviceOrderId': instance.serviceOrderId,
'servicePrintId': instance.servicePrintId,
'invoiceUrl': instance.invoiceUrl,
'printType': instance.printType,
'printNo': instance.printNo,
'retryVersion': instance.retryVersion,
'attemptCount': instance.attemptCount,
'lastError': instance.lastError,
'resultPending': instance.resultPending,
'status': _$PrintStatusEnumMap[instance.status]!,
'printTime': instance.printTime,
'syncTime': instance.syncTime?.toIso8601String(),
@@ -0,0 +1,87 @@
import 'package:floor/floor.dart';
import 'package:json_annotation/json_annotation.dart';
part 'scheduled_task_entity.g.dart';
/// 终端定时任务配置及最近一次执行快照。
///
/// [taskCode] 使用代码枚举名作为稳定主键,界面文案调整时不会产生重复任务。
@JsonSerializable()
@Entity(tableName: 'scheduled_task')
class ScheduledTaskEntity {
/// 稳定任务编码,取 [ScheduledTaskType.name],作为表主键且不能随展示文案变化。
@PrimaryKey()
final String taskCode;
/// 是否启用 Cron 自动调度;关闭时仍可通过设置页手动触发。
final bool enabled;
/// cron 0.6.2 使用的六段表达式,字段顺序为秒、分、时、日、月、周。
final String cronExpression;
/// 自动任务是否必须等待连续 60 秒无人操作的完整空闲窗口。
final bool idleOnly;
/// 最近一次任务开始执行的本地时间;从未执行时为空。
final DateTime? lastRunAt;
/// 最近一次成功完成的本地时间;尚无成功记录时为空。
final DateTime? lastSuccessAt;
/// 最近一次运行状态,保存 [ScheduledTaskRunStatus.name]。
final String lastStatus;
/// 最近一次运行结果的简短中文摘要。
final String lastMessage;
/// 任务配置首次写入 SQLite 的本地时间。
final DateTime createTime;
/// 配置或执行快照最近一次更新的本地时间。
final DateTime updateTime;
/// 创建一条定时任务配置与最近执行快照。
const ScheduledTaskEntity({
required this.taskCode,
required this.enabled,
required this.cronExpression,
required this.idleOnly,
this.lastRunAt,
this.lastSuccessAt,
required this.lastStatus,
required this.lastMessage,
required this.createTime,
required this.updateTime,
});
/// 从 JSON 数据恢复实体,仅供兼容迁移和调试序列化使用。
factory ScheduledTaskEntity.fromJson(Map<String, dynamic> json) =>
_$ScheduledTaskEntityFromJson(json);
/// 将实体转换为 JSON,仅供兼容迁移和调试序列化使用。
Map<String, dynamic> toJson() => _$ScheduledTaskEntityToJson(this);
/// 保留主键与创建时间,生成包含配置或最近执行结果变更的新实体。
ScheduledTaskEntity copyWith({
bool? enabled,
String? cronExpression,
bool? idleOnly,
DateTime? lastRunAt,
DateTime? lastSuccessAt,
String? lastStatus,
String? lastMessage,
DateTime? updateTime,
}) =>
ScheduledTaskEntity(
taskCode: taskCode,
enabled: enabled ?? this.enabled,
cronExpression: cronExpression ?? this.cronExpression,
idleOnly: idleOnly ?? this.idleOnly,
lastRunAt: lastRunAt ?? this.lastRunAt,
lastSuccessAt: lastSuccessAt ?? this.lastSuccessAt,
lastStatus: lastStatus ?? this.lastStatus,
lastMessage: lastMessage ?? this.lastMessage,
createTime: createTime,
updateTime: updateTime ?? this.updateTime,
);
}
@@ -0,0 +1,40 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'scheduled_task_entity.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ScheduledTaskEntity _$ScheduledTaskEntityFromJson(Map<String, dynamic> json) =>
ScheduledTaskEntity(
taskCode: json['taskCode'] as String,
enabled: json['enabled'] as bool,
cronExpression: json['cronExpression'] as String,
idleOnly: json['idleOnly'] as bool,
lastRunAt: json['lastRunAt'] == null
? null
: DateTime.parse(json['lastRunAt'] as String),
lastSuccessAt: json['lastSuccessAt'] == null
? null
: DateTime.parse(json['lastSuccessAt'] as String),
lastStatus: json['lastStatus'] as String,
lastMessage: json['lastMessage'] as String,
createTime: DateTime.parse(json['createTime'] as String),
updateTime: DateTime.parse(json['updateTime'] as String),
);
Map<String, dynamic> _$ScheduledTaskEntityToJson(
ScheduledTaskEntity instance) =>
<String, dynamic>{
'taskCode': instance.taskCode,
'enabled': instance.enabled,
'cronExpression': instance.cronExpression,
'idleOnly': instance.idleOnly,
'lastRunAt': instance.lastRunAt?.toIso8601String(),
'lastSuccessAt': instance.lastSuccessAt?.toIso8601String(),
'lastStatus': instance.lastStatus,
'lastMessage': instance.lastMessage,
'createTime': instance.createTime.toIso8601String(),
'updateTime': instance.updateTime.toIso8601String(),
};
@@ -0,0 +1,135 @@
import 'package:floor/floor.dart';
import 'package:json_annotation/json_annotation.dart';
part 'scheduled_task_log_entity.g.dart';
/// 定时任务的结构化执行日志。
///
/// 来源、触发方式、状态和统计值使用独立列,日志页面无需解析拼接文本即可筛选。
@JsonSerializable()
@Entity(
tableName: 'scheduled_task_log',
indices: [
Index(value: ['taskCode', 'startedAt']),
Index(value: ['sourceType', 'status', 'startedAt']),
],
)
class ScheduledTaskLogEntity {
/// SQLite 自增主键;日志尚未插入数据库时为空。
@PrimaryKey(autoGenerate: true)
final int? id;
/// 任务稳定编码,关联 scheduled_task.taskCode,但不建立外键以兼容任务版本演进。
final String taskCode;
/// 执行发生时的任务展示名称快照。
final String taskName;
/// 触发来源,保存 [ScheduledTaskTriggerType.name]。
final String triggerType;
/// 主要依赖类型,保存 [ScheduledTaskSourceType.name]。
final String sourceType;
/// 执行发生时的依赖名称快照,例如 MQTT 消息服务或 HTTP 商品接口。
final String sourceName;
/// 本次执行状态,保存 [ScheduledTaskRunStatus.name]。
final String status;
/// 本次执行结果的简短中文摘要。
final String message;
/// 异常运行时的 Dart 异常类型;成功或跳过时为空。
final String? errorType;
/// 截断并脱敏后的异常摘要;成功或跳过时为空。
final String? errorMessage;
/// 截断后的异常堆栈,最多保存调度器允许的诊断长度。
final String? errorStack;
/// 任务开始执行的本地时间。
final DateTime startedAt;
/// 任务结束的本地时间;执行中日志为空。
final DateTime? finishedAt;
/// 从开始到结束的耗时,单位为毫秒;执行中默认为零。
final int durationMs;
/// 文件类任务扫描到的文件数量;不适用的任务为空。
final int? scannedCount;
/// 文件类任务因未变化或服务端已存在而跳过的数量;不适用时为空。
final int? skippedCount;
/// 文件类任务实际上传成功的数量;不适用时为空。
final int? successCount;
/// 文件类任务处理失败的数量;不适用时为空。
final int? failureCount;
/// 创建一条任务执行日志;开始记录尚未结束时不填写结束信息。
const ScheduledTaskLogEntity({
this.id,
required this.taskCode,
required this.taskName,
required this.triggerType,
required this.sourceType,
required this.sourceName,
required this.status,
required this.message,
this.errorType,
this.errorMessage,
this.errorStack,
required this.startedAt,
this.finishedAt,
this.durationMs = 0,
this.scannedCount,
this.skippedCount,
this.successCount,
this.failureCount,
});
/// 从 JSON 数据恢复任务日志,仅供调试序列化使用。
factory ScheduledTaskLogEntity.fromJson(Map<String, dynamic> json) =>
_$ScheduledTaskLogEntityFromJson(json);
/// 将任务日志转换为 JSON,仅供调试序列化使用。
Map<String, dynamic> toJson() => _$ScheduledTaskLogEntityToJson(this);
/// 使用最终状态、错误和统计值生成同一条日志的完成快照。
ScheduledTaskLogEntity finish({
required String nextStatus,
required String nextMessage,
required DateTime at,
String? nextErrorType,
String? nextErrorMessage,
String? nextErrorStack,
int? scanned,
int? skipped,
int? succeeded,
int? failed,
}) =>
ScheduledTaskLogEntity(
id: id,
taskCode: taskCode,
taskName: taskName,
triggerType: triggerType,
sourceType: sourceType,
sourceName: sourceName,
status: nextStatus,
message: nextMessage,
errorType: nextErrorType,
errorMessage: nextErrorMessage,
errorStack: nextErrorStack,
startedAt: startedAt,
finishedAt: at,
durationMs: at.difference(startedAt).inMilliseconds,
scannedCount: scanned,
skippedCount: skipped,
successCount: succeeded,
failureCount: failed,
);
}
@@ -0,0 +1,55 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'scheduled_task_log_entity.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ScheduledTaskLogEntity _$ScheduledTaskLogEntityFromJson(
Map<String, dynamic> json) =>
ScheduledTaskLogEntity(
id: (json['id'] as num?)?.toInt(),
taskCode: json['taskCode'] as String,
taskName: json['taskName'] as String,
triggerType: json['triggerType'] as String,
sourceType: json['sourceType'] as String,
sourceName: json['sourceName'] as String,
status: json['status'] as String,
message: json['message'] as String,
errorType: json['errorType'] as String?,
errorMessage: json['errorMessage'] as String?,
errorStack: json['errorStack'] as String?,
startedAt: DateTime.parse(json['startedAt'] as String),
finishedAt: json['finishedAt'] == null
? null
: DateTime.parse(json['finishedAt'] as String),
durationMs: (json['durationMs'] as num?)?.toInt() ?? 0,
scannedCount: (json['scannedCount'] as num?)?.toInt(),
skippedCount: (json['skippedCount'] as num?)?.toInt(),
successCount: (json['successCount'] as num?)?.toInt(),
failureCount: (json['failureCount'] as num?)?.toInt(),
);
Map<String, dynamic> _$ScheduledTaskLogEntityToJson(
ScheduledTaskLogEntity instance) =>
<String, dynamic>{
'id': instance.id,
'taskCode': instance.taskCode,
'taskName': instance.taskName,
'triggerType': instance.triggerType,
'sourceType': instance.sourceType,
'sourceName': instance.sourceName,
'status': instance.status,
'message': instance.message,
'errorType': instance.errorType,
'errorMessage': instance.errorMessage,
'errorStack': instance.errorStack,
'startedAt': instance.startedAt.toIso8601String(),
'finishedAt': instance.finishedAt?.toIso8601String(),
'durationMs': instance.durationMs,
'scannedCount': instance.scannedCount,
'skippedCount': instance.skippedCount,
'successCount': instance.successCount,
'failureCount': instance.failureCount,
};