优化
This commit is contained in:
166
client/flutter/lib/models/invite.dart
Normal file
166
client/flutter/lib/models/invite.dart
Normal file
@@ -0,0 +1,166 @@
|
||||
class Invite {
|
||||
final String id;
|
||||
final String code;
|
||||
final String salesId;
|
||||
final String groupId;
|
||||
final String? link;
|
||||
final String? qrCodeUrl;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? expiresAt;
|
||||
final int clickCount;
|
||||
final int scanCount;
|
||||
final int joinCount;
|
||||
final String status;
|
||||
|
||||
Invite({
|
||||
required this.id,
|
||||
required this.code,
|
||||
required this.salesId,
|
||||
required this.groupId,
|
||||
this.link,
|
||||
this.qrCodeUrl,
|
||||
this.createdAt,
|
||||
this.expiresAt,
|
||||
this.clickCount = 0,
|
||||
this.scanCount = 0,
|
||||
this.joinCount = 0,
|
||||
this.status = 'active',
|
||||
});
|
||||
|
||||
factory Invite.fromJson(Map<String, dynamic> json) {
|
||||
return Invite(
|
||||
id: (json['_id'] ?? json['id'] ?? '').toString(),
|
||||
code: json['code'] ?? '',
|
||||
salesId: (json['salesId'] ?? '').toString(),
|
||||
groupId: (json['groupId'] ?? '').toString(),
|
||||
link: json['link'],
|
||||
qrCodeUrl: json['qrCodeUrl'],
|
||||
createdAt: json['createdAt'] != null
|
||||
? DateTime.parse(json['createdAt'].toString())
|
||||
: null,
|
||||
expiresAt: json['expiresAt'] != null
|
||||
? DateTime.parse(json['expiresAt'].toString())
|
||||
: null,
|
||||
clickCount: json['clickCount'] ?? 0,
|
||||
scanCount: json['scanCount'] ?? 0,
|
||||
joinCount: json['joinCount'] ?? 0,
|
||||
status: json['status'] ?? 'active',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'_id': id,
|
||||
'code': code,
|
||||
'salesId': salesId,
|
||||
'groupId': groupId,
|
||||
'link': link,
|
||||
'qrCodeUrl': qrCodeUrl,
|
||||
'createdAt': createdAt?.toIso8601String(),
|
||||
'expiresAt': expiresAt?.toIso8601String(),
|
||||
'clickCount': clickCount,
|
||||
'scanCount': scanCount,
|
||||
'joinCount': joinCount,
|
||||
'status': status,
|
||||
};
|
||||
}
|
||||
|
||||
bool get isExpired =>
|
||||
expiresAt != null && DateTime.now().isAfter(expiresAt!);
|
||||
bool get isActive => status == 'active' && !isExpired;
|
||||
bool get isValid => isActive;
|
||||
}
|
||||
|
||||
/// 单个邀请的统计数据,由 invite.getStats 返回
|
||||
class InviteStats {
|
||||
final String code;
|
||||
final String? link;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? expiresAt;
|
||||
final InviteStatsDetail stats;
|
||||
final List<AccessLog> recentAccess;
|
||||
|
||||
InviteStats({
|
||||
required this.code,
|
||||
this.link,
|
||||
this.createdAt,
|
||||
this.expiresAt,
|
||||
required this.stats,
|
||||
this.recentAccess = const [],
|
||||
});
|
||||
|
||||
factory InviteStats.fromJson(Map<String, dynamic> json) {
|
||||
return InviteStats(
|
||||
code: json['code'] ?? '',
|
||||
link: json['link'],
|
||||
createdAt: json['createdAt'] != null
|
||||
? DateTime.parse(json['createdAt'].toString())
|
||||
: null,
|
||||
expiresAt: json['expiresAt'] != null
|
||||
? DateTime.parse(json['expiresAt'].toString())
|
||||
: null,
|
||||
stats: InviteStatsDetail.fromJson(json['stats'] ?? {}),
|
||||
recentAccess: (json['recentAccess'] as List?)
|
||||
?.map((e) => AccessLog.fromJson(e))
|
||||
.toList() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InviteStatsDetail {
|
||||
final int clicks;
|
||||
final int scans;
|
||||
final int joins;
|
||||
final String conversionRate;
|
||||
|
||||
InviteStatsDetail({
|
||||
this.clicks = 0,
|
||||
this.scans = 0,
|
||||
this.joins = 0,
|
||||
this.conversionRate = '0',
|
||||
});
|
||||
|
||||
factory InviteStatsDetail.fromJson(Map<String, dynamic> json) {
|
||||
return InviteStatsDetail(
|
||||
clicks: json['clicks'] ?? 0,
|
||||
scans: json['scans'] ?? 0,
|
||||
joins: json['joins'] ?? 0,
|
||||
conversionRate: json['conversionRate']?.toString() ?? '0',
|
||||
);
|
||||
}
|
||||
|
||||
double get conversionRateDouble => double.tryParse(conversionRate) ?? 0.0;
|
||||
}
|
||||
|
||||
/// 来自后端的访问日志条目
|
||||
class AccessLog {
|
||||
final String? id;
|
||||
final String inviteCode;
|
||||
final String? visitorId;
|
||||
final String accessType;
|
||||
final DateTime? timestamp;
|
||||
final String? ipAddress;
|
||||
|
||||
AccessLog({
|
||||
this.id,
|
||||
required this.inviteCode,
|
||||
this.visitorId,
|
||||
required this.accessType,
|
||||
this.timestamp,
|
||||
this.ipAddress,
|
||||
});
|
||||
|
||||
factory AccessLog.fromJson(Map<String, dynamic> json) {
|
||||
return AccessLog(
|
||||
id: (json['_id'] ?? json['id'])?.toString(),
|
||||
inviteCode: json['inviteCode'] ?? '',
|
||||
visitorId: json['visitorId']?.toString(),
|
||||
accessType: json['accessType'] ?? '',
|
||||
timestamp: json['timestamp'] != null
|
||||
? DateTime.parse(json['timestamp'].toString())
|
||||
: null,
|
||||
ipAddress: json['ipAddress'],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user