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) { throw const FormatException('事件 payload 不是合法的 JSON 对象'); } return Event.fromJson( decoded, createTime: createTime, retryCount: retryCount, ); } /// 从 JSON 恢复事件。 factory Event.fromJson( Map 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? eventParams; /// 自定义标签。 final Map? customTags; /// 事件创建时间。 final DateTime createTime; /// 当前重试次数。 final int retryCount; /// 复制事件并覆盖部分字段。 Event copyWith({ UserInfo? userInfo, DeviceInfo? deviceInfo, Map? eventParams, Map? 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 toJson() => { '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? _toMap(dynamic value) { if (value == null) { return null; } if (value is Map) { 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, ); }