Files
CloudHome-Ops/lib/models/marquee_message.dart

212 lines
7.0 KiB
Dart
Raw Normal View History

/// 滚动字幕消息模型。
///
/// 对应 Web 后台「滚动字幕」表(tv_scrolling_text / theme_scrolling_text)
/// 以及管理模块「滚动字幕管理」中的单条字幕记录。
///
/// 字段映射:
/// - Web 端返回 `orgId` / `orgName`,本模型内部使用 `storeId` / `storeName`。
/// - Web 端返回 `scrollSpeed`,本模型内部使用 `speed`。
/// - Web 端返回 `bgColor`,本模型内部使用 `backgroundColor`。
/// - `status` 沿用 Web 端语义:`1=启用`,`0=禁用`。
class MarqueeMessage {
const MarqueeMessage({
required this.id,
required this.storeId,
required this.storeName,
required this.content,
required this.status,
required this.speed,
required this.createTime,
required this.updateTime,
this.fontColor,
this.backgroundColor,
this.fontSize,
this.level,
this.startTime,
this.endTime,
});
/// 字幕 ID。
final String id;
/// 所属门店 ID(对应 Web 端 orgId)。
final String storeId;
/// 所属门店名称(对应 Web 端 orgName)。
final String storeName;
/// 字幕内容。
final String content;
/// 状态:`1=启用`,`0=禁用`。
final int status;
/// 滚动速度(对应 Web 端 scrollSpeed,单位 ms/像素,越小越快)。
///
/// 档位映射:慢=200 / 较慢=100 / 中=50 / 较快=30 / 快=10。
final int speed;
/// 字体颜色(Hex,如 `#FFFFFF`)。
final String? fontColor;
/// 背景颜色(Hex,如 `#3B82F6`,对应 Web 端 bgColor)。
final String? backgroundColor;
/// 字体大小(px,如 32)。
final int? fontSize;
/// 字幕级别/优先级。
final int? level;
/// 开始生效时间(Web 端为 `HH:mm:ss` 字符串,本地存为时间)。
final DateTime? startTime;
/// 结束生效时间(Web 端为 `HH:mm:ss` 字符串,本地存为时间)。
final DateTime? endTime;
/// 创建时间。
final DateTime? createTime;
/// 更新时间。
final DateTime? updateTime;
bool get isEnabled => status == 1;
bool get isDisabled => status == 0;
factory MarqueeMessage.fromJson(Map<String, dynamic> json) {
return MarqueeMessage(
id: (json['id'] ?? json['marqueeId'])?.toString() ?? '',
storeId: json['storeId']?.toString() ??
json['orgId']?.toString() ??
json['org_id']?.toString() ??
'',
storeName: json['storeName']?.toString() ??
json['orgName']?.toString() ??
json['org_name']?.toString() ??
'',
content: json['content']?.toString() ?? '',
status: _parseInt(json['status'], fallback: 0) ?? 0,
speed: _parseInt(json['speed'], fallback: 50) ??
_parseInt(json['scrollSpeed'], fallback: 50) ??
_parseInt(json['scroll_speed'], fallback: 50) ??
50,
fontColor: json['fontColor']?.toString() ?? json['font_color']?.toString(),
backgroundColor: json['backgroundColor']?.toString() ??
json['bgColor']?.toString() ??
json['bg_color']?.toString(),
fontSize: _parseInt(json['fontSize'] ?? json['font_size']),
level: _parseInt(json['level']),
startTime: _parseDateTime(json['startTime'] ?? json['start_time']),
endTime: _parseDateTime(json['endTime'] ?? json['end_time']),
createTime: _parseDateTime(json['createTime'] ?? json['create_time']),
updateTime: _parseDateTime(json['updateTime'] ?? json['update_time']),
);
}
/// 转换为本地缓存使用的 JSON。
Map<String, dynamic> toJson() {
return {
'id': id,
'storeId': storeId,
'storeName': storeName,
'content': content,
'status': status,
'speed': speed,
if (fontColor != null) 'fontColor': fontColor,
if (backgroundColor != null) 'backgroundColor': backgroundColor,
if (fontSize != null) 'fontSize': fontSize,
if (level != null) 'level': level,
if (startTime != null) 'startTime': _formatTime(startTime!),
if (endTime != null) 'endTime': _formatTime(endTime!),
'createTime': createTime?.toIso8601String(),
'updateTime': updateTime?.toIso8601String(),
};
}
/// 转换为 Web 后台可接收的字段名(用于新增/编辑请求)。
Map<String, dynamic> toWebJson() {
return {
if (id.isNotEmpty) 'id': int.tryParse(id),
'orgId': int.tryParse(storeId) ?? storeId,
'orgName': storeName,
'content': content,
'scrollSpeed': speed,
if (fontColor != null) 'fontColor': fontColor,
if (backgroundColor != null) 'bgColor': backgroundColor,
if (fontSize != null) 'fontSize': fontSize,
if (level != null) 'level': level,
'status': status,
if (startTime != null) 'startTime': _formatTime(startTime!),
if (endTime != null) 'endTime': _formatTime(endTime!),
};
}
MarqueeMessage copyWith({
String? id,
String? storeId,
String? storeName,
String? content,
int? status,
int? speed,
String? fontColor,
String? backgroundColor,
int? fontSize,
int? level,
DateTime? startTime,
DateTime? endTime,
DateTime? createTime,
DateTime? updateTime,
}) {
return MarqueeMessage(
id: id ?? this.id,
storeId: storeId ?? this.storeId,
storeName: storeName ?? this.storeName,
content: content ?? this.content,
status: status ?? this.status,
speed: speed ?? this.speed,
fontColor: fontColor ?? this.fontColor,
backgroundColor: backgroundColor ?? this.backgroundColor,
fontSize: fontSize ?? this.fontSize,
level: level ?? this.level,
startTime: startTime ?? this.startTime,
endTime: endTime ?? this.endTime,
createTime: createTime ?? this.createTime,
updateTime: updateTime ?? this.updateTime,
);
}
/// 颜色字段兜底:当 Web 端未返回颜色时返回默认半透明色。
static const String defaultFontColor = '#FFFFFF';
static const String defaultBackgroundColor = '#3B82F6';
/// 兼容 `yyyy-MM-dd HH:mm:ss`、ISO 8601 以及纯 `HH:mm:ss` 时间字符串。
static DateTime? _parseDateTime(dynamic value) {
if (value == null) return null;
final text = value.toString().trim();
if (text.isEmpty) return null;
// 纯时间:补齐一个固定日期用于本地 DateTime 存储。
if (RegExp(r'^\d{2}:\d{2}:\d{2}$').hasMatch(text)) {
return DateTime.tryParse('2000-01-01 $text');
}
return DateTime.tryParse(text) ??
DateTime.tryParse(text.replaceFirst(' ', 'T'));
}
/// 时间字段序列化为 `HH:mm:ss`,与 Web 后台保持一致。
static String _formatTime(DateTime value) {
return '${value.hour.toString().padLeft(2, '0')}:'
'${value.minute.toString().padLeft(2, '0')}:'
'${value.second.toString().padLeft(2, '0')}';
}
/// 解析整数字段,兼容 int / String / null。
static int? _parseInt(dynamic value, {int? fallback}) {
if (value == null) return fallback;
if (value is int) return value;
if (value is String) return int.tryParse(value.trim()) ?? fallback;
return fallback;
}
}