212 lines
7.0 KiB
Dart
212 lines
7.0 KiB
Dart
/// 滚动字幕消息模型。
|
||
///
|
||
/// 对应 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;
|
||
}
|
||
}
|