91 lines
2.7 KiB
Dart
91 lines
2.7 KiB
Dart
/// In-site notification fetched from the notification-service backend.
|
|
class InSiteNotification {
|
|
final String id;
|
|
final String title;
|
|
final String content;
|
|
final String type; // SYSTEM | MAINTENANCE | FEATURE | ANNOUNCEMENT | BILLING | SECURITY
|
|
final String priority; // LOW | NORMAL | HIGH | URGENT
|
|
final String? imageUrl;
|
|
final String? linkUrl;
|
|
final bool requiresForceRead;
|
|
final DateTime? publishedAt;
|
|
final bool isRead;
|
|
|
|
const InSiteNotification({
|
|
required this.id,
|
|
required this.title,
|
|
required this.content,
|
|
required this.type,
|
|
required this.priority,
|
|
this.imageUrl,
|
|
this.linkUrl,
|
|
required this.requiresForceRead,
|
|
this.publishedAt,
|
|
required this.isRead,
|
|
});
|
|
|
|
factory InSiteNotification.fromJson(Map<String, dynamic> json) {
|
|
return InSiteNotification(
|
|
id: json['id'] as String,
|
|
title: json['title'] as String? ?? '',
|
|
content: json['content'] as String? ?? '',
|
|
type: json['type'] as String? ?? 'ANNOUNCEMENT',
|
|
priority: json['priority'] as String? ?? 'NORMAL',
|
|
imageUrl: json['imageUrl'] as String?,
|
|
linkUrl: json['linkUrl'] as String?,
|
|
requiresForceRead: json['requiresForceRead'] as bool? ?? false,
|
|
publishedAt: json['publishedAt'] != null
|
|
? DateTime.tryParse(json['publishedAt'] as String)
|
|
: null,
|
|
isRead: json['isRead'] as bool? ?? false,
|
|
);
|
|
}
|
|
|
|
InSiteNotification copyWith({bool? isRead}) => InSiteNotification(
|
|
id: id,
|
|
title: title,
|
|
content: content,
|
|
type: type,
|
|
priority: priority,
|
|
imageUrl: imageUrl,
|
|
linkUrl: linkUrl,
|
|
requiresForceRead: requiresForceRead,
|
|
publishedAt: publishedAt,
|
|
isRead: isRead ?? this.isRead,
|
|
);
|
|
|
|
String get typeLabel {
|
|
const labels = {
|
|
'SYSTEM': '系统通知',
|
|
'MAINTENANCE': '维护通知',
|
|
'FEATURE': '新功能',
|
|
'ANNOUNCEMENT': '公告',
|
|
'BILLING': '账单通知',
|
|
'SECURITY': '安全通知',
|
|
};
|
|
return labels[type] ?? type;
|
|
}
|
|
|
|
String get typeEmoji {
|
|
const emojis = {
|
|
'SYSTEM': '⚙️',
|
|
'MAINTENANCE': '🔧',
|
|
'FEATURE': '✨',
|
|
'ANNOUNCEMENT': '📢',
|
|
'BILLING': '💳',
|
|
'SECURITY': '🔒',
|
|
};
|
|
return emojis[type] ?? '📩';
|
|
}
|
|
|
|
String get relativeTime {
|
|
final ref = publishedAt ?? DateTime.now();
|
|
final diff = DateTime.now().difference(ref);
|
|
if (diff.inMinutes < 1) return '刚刚';
|
|
if (diff.inHours < 1) return '${diff.inMinutes}分钟前';
|
|
if (diff.inDays < 1) return '${diff.inHours}小时前';
|
|
if (diff.inDays < 30) return '${diff.inDays}天前';
|
|
return '${ref.year}-${ref.month.toString().padLeft(2, '0')}-${ref.day.toString().padLeft(2, '0')}';
|
|
}
|
|
}
|