You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.3 KiB
135 lines
3.3 KiB
import 'package:uuid/uuid.dart'; |
|
|
|
class Problem { |
|
final String id; |
|
final String description; |
|
final String location; |
|
final String imageUrl; |
|
final DateTime createdAt; |
|
final DateTime updatedAt; |
|
|
|
static final Uuid _uuid = const Uuid(); |
|
|
|
Problem._({ |
|
required this.id, |
|
required this.description, |
|
required this.location, |
|
required this.imageUrl, |
|
required this.createdAt, |
|
required this.updatedAt, |
|
}); |
|
|
|
// 主工厂构造函数 |
|
factory Problem({ |
|
required String description, |
|
required String location, |
|
required String imageUrl, |
|
String? id, |
|
DateTime? createdAt, |
|
DateTime? updatedAt, |
|
}) { |
|
// 参数验证 |
|
_validateParameters(description, location, imageUrl); |
|
|
|
final now = DateTime.now(); |
|
return Problem._( |
|
id: id ?? _uuid.v4(), |
|
description: description.trim(), |
|
location: location.trim(), |
|
imageUrl: imageUrl, |
|
createdAt: createdAt ?? now, |
|
updatedAt: updatedAt ?? now, |
|
); |
|
} |
|
|
|
// 参数验证 |
|
static void _validateParameters( |
|
String description, |
|
String location, |
|
String imageUrl, |
|
) { |
|
if (description.isEmpty) { |
|
throw ArgumentError('Description cannot be empty'); |
|
} |
|
if (location.isEmpty) { |
|
throw ArgumentError('Location cannot be empty'); |
|
} |
|
if (imageUrl.isEmpty) { |
|
throw ArgumentError('Image URL cannot be empty'); |
|
} |
|
|
|
// 验证 URL 格式(简单验证) |
|
if (!imageUrl.startsWith('http')) { |
|
throw ArgumentError('Image URL must be a valid URL'); |
|
} |
|
} |
|
|
|
// 从 JSON 反序列化 |
|
factory Problem.fromJson(Map<String, dynamic> json) { |
|
return Problem( |
|
id: json['id'], |
|
description: json['description'], |
|
location: json['location'], |
|
imageUrl: json['imageUrl'], |
|
createdAt: json['createdAt'] != null |
|
? DateTime.parse(json['createdAt']) |
|
: null, |
|
updatedAt: json['updatedAt'] != null |
|
? DateTime.parse(json['updatedAt']) |
|
: null, |
|
); |
|
} |
|
|
|
// 转换为 JSON |
|
Map<String, dynamic> toJson() { |
|
return { |
|
'id': id, |
|
'description': description, |
|
'location': location, |
|
'imageUrl': imageUrl, |
|
'createdAt': createdAt.toIso8601String(), |
|
'updatedAt': updatedAt.toIso8601String(), |
|
}; |
|
} |
|
|
|
// 复制方法 |
|
Problem copyWith({ |
|
String? id, |
|
String? description, |
|
String? location, |
|
String? imageUrl, |
|
DateTime? createdAt, |
|
DateTime? updatedAt, |
|
}) { |
|
return Problem( |
|
id: id ?? this.id, |
|
description: description ?? this.description, |
|
location: location ?? this.location, |
|
imageUrl: imageUrl ?? this.imageUrl, |
|
createdAt: createdAt ?? this.createdAt, |
|
updatedAt: updatedAt ?? DateTime.now(), // 更新时间为当前时间 |
|
); |
|
} |
|
|
|
// 检查是否有效 |
|
bool get isValid => description.isNotEmpty && location.isNotEmpty; |
|
|
|
// 获取简短描述 |
|
String get shortDescription { |
|
if (description.length <= 50) return description; |
|
return '${description.substring(0, 47)}...'; |
|
} |
|
|
|
@override |
|
String toString() { |
|
return 'Problem(id: $id, description: $shortDescription, location: $location)'; |
|
} |
|
|
|
@override |
|
bool operator ==(Object other) => |
|
identical(this, other) || |
|
other is Problem && runtimeType == other.runtimeType && id == other.id; |
|
|
|
@override |
|
int get hashCode => id.hashCode; |
|
}
|
|
|