216 lines
5.5 KiB
Dart
216 lines
5.5 KiB
Dart
import 'dart:convert';
|
||
|
||
import 'package:yx_tracking_flutter/src/model/device_info.dart';
|
||
import 'package:yx_tracking_flutter/src/model/user_info.dart';
|
||
|
||
/// 统一事件模型。
|
||
class Event {
|
||
/// 创建事件实例。
|
||
const Event({
|
||
required this.systemCode,
|
||
required this.eventType,
|
||
required this.userInfo,
|
||
required this.clientType,
|
||
required this.clientTimestamp,
|
||
required this.timestamp,
|
||
required this.deviceInfo,
|
||
required this.eventParams,
|
||
required this.customTags,
|
||
required this.createTime,
|
||
this.retryCount = 0,
|
||
});
|
||
|
||
/// 从序列化 payload 恢复事件。
|
||
factory Event.fromPayload(
|
||
String payload, {
|
||
required DateTime createTime,
|
||
required int retryCount,
|
||
}) {
|
||
final decoded = jsonDecode(payload);
|
||
if (decoded is! Map<String, dynamic>) {
|
||
throw const FormatException('事件 payload 不是合法的 JSON 对象');
|
||
}
|
||
return Event.fromJson(
|
||
decoded,
|
||
createTime: createTime,
|
||
retryCount: retryCount,
|
||
);
|
||
}
|
||
|
||
/// 从 JSON 恢复事件。
|
||
factory Event.fromJson(
|
||
Map<String, dynamic> json, {
|
||
required DateTime createTime,
|
||
required int retryCount,
|
||
}) {
|
||
final userJson = json['userInfo'];
|
||
final deviceJson = json['deviceInfo'];
|
||
|
||
if (deviceJson is! Map) {
|
||
throw const FormatException('deviceInfo 缺失或格式错误');
|
||
}
|
||
|
||
return Event(
|
||
systemCode: (json['system_code'] ?? '').toString(),
|
||
eventType: (json['eventType'] ?? '').toString(),
|
||
userInfo: userJson is Map
|
||
? UserInfo(
|
||
userId: _toInt(userJson['userId']),
|
||
userName: userJson['userName']?.toString(),
|
||
account: userJson['account']?.toString(),
|
||
)
|
||
: null,
|
||
clientType: _toInt(json['clientType']) ?? 0,
|
||
clientTimestamp: _toInt(json['clientTimestamp']) ?? 0,
|
||
timestamp: (json['timestamp'] ?? '').toString(),
|
||
deviceInfo: DeviceInfo(
|
||
os: deviceJson['os']?.toString() ?? 'unknown',
|
||
model: deviceJson['model']?.toString() ?? 'unknown',
|
||
screenResolution:
|
||
deviceJson['screenResolution']?.toString() ?? 'unknown',
|
||
),
|
||
eventParams: _toMap(json['eventParams']),
|
||
customTags: _toMap(json['customTags']),
|
||
createTime: createTime,
|
||
retryCount: retryCount,
|
||
);
|
||
}
|
||
|
||
/// 系统编码(system_code)。
|
||
final String systemCode;
|
||
|
||
/// 事件类型。
|
||
final String eventType;
|
||
|
||
/// 用户信息。
|
||
final UserInfo? userInfo;
|
||
|
||
/// 客户端类型(client_type)。
|
||
final int clientType;
|
||
|
||
/// 客户端时间戳(秒)。
|
||
final int clientTimestamp;
|
||
|
||
/// 业务时间戳字符串。
|
||
final String timestamp;
|
||
|
||
/// 设备信息。
|
||
final DeviceInfo deviceInfo;
|
||
|
||
/// 事件参数。
|
||
final Map<String, dynamic>? eventParams;
|
||
|
||
/// 自定义标签。
|
||
final Map<String, dynamic>? customTags;
|
||
|
||
/// 事件创建时间。
|
||
final DateTime createTime;
|
||
|
||
/// 当前重试次数。
|
||
final int retryCount;
|
||
|
||
/// 复制事件并覆盖部分字段。
|
||
Event copyWith({
|
||
UserInfo? userInfo,
|
||
DeviceInfo? deviceInfo,
|
||
Map<String, dynamic>? eventParams,
|
||
Map<String, dynamic>? customTags,
|
||
DateTime? createTime,
|
||
int? retryCount,
|
||
}) =>
|
||
Event(
|
||
systemCode: systemCode,
|
||
eventType: eventType,
|
||
userInfo: userInfo ?? this.userInfo,
|
||
clientType: clientType,
|
||
clientTimestamp: clientTimestamp,
|
||
timestamp: timestamp,
|
||
deviceInfo: deviceInfo ?? this.deviceInfo,
|
||
eventParams: eventParams ?? this.eventParams,
|
||
customTags: customTags ?? this.customTags,
|
||
createTime: createTime ?? this.createTime,
|
||
retryCount: retryCount ?? this.retryCount,
|
||
);
|
||
|
||
/// 转换为可序列化的 JSON。
|
||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||
'system_code': systemCode,
|
||
'eventType': eventType,
|
||
'userInfo': userInfo?.toJson(),
|
||
'clientType': clientType,
|
||
'clientTimestamp': clientTimestamp,
|
||
'timestamp': timestamp,
|
||
'deviceInfo': deviceInfo.toJson(),
|
||
'eventParams': eventParams,
|
||
'customTags': customTags,
|
||
};
|
||
|
||
/// 转换为 payload 字符串。
|
||
String toPayload() => jsonEncode(toJson());
|
||
|
||
static int? _toInt(dynamic value) {
|
||
if (value is int) {
|
||
return value;
|
||
}
|
||
if (value is num) {
|
||
return value.toInt();
|
||
}
|
||
if (value is String) {
|
||
return int.tryParse(value);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
static Map<String, dynamic>? _toMap(dynamic value) {
|
||
if (value == null) {
|
||
return null;
|
||
}
|
||
if (value is Map<String, dynamic>) {
|
||
return value;
|
||
}
|
||
if (value is Map) {
|
||
return value.map(
|
||
(key, val) => MapEntry(key.toString(), val),
|
||
);
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// 带本地存储元数据的事件。
|
||
class StoredEvent {
|
||
/// 创建带存储元数据的事件实例。
|
||
const StoredEvent({
|
||
required this.id,
|
||
required this.event,
|
||
required this.retryCount,
|
||
required this.createTime,
|
||
});
|
||
|
||
/// 存储中的自增 ID。
|
||
final int id;
|
||
|
||
/// 事件本体。
|
||
final Event event;
|
||
|
||
/// 当前重试次数。
|
||
final int retryCount;
|
||
|
||
/// 事件创建时间。
|
||
final DateTime createTime;
|
||
|
||
/// 复制对象并覆盖部分字段。
|
||
StoredEvent copyWith({
|
||
int? id,
|
||
Event? event,
|
||
int? retryCount,
|
||
DateTime? createTime,
|
||
}) =>
|
||
StoredEvent(
|
||
id: id ?? this.id,
|
||
event: event ?? this.event,
|
||
retryCount: retryCount ?? this.retryCount,
|
||
createTime: createTime ?? this.createTime,
|
||
);
|
||
}
|