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.
136 lines
3.3 KiB
136 lines
3.3 KiB
3 weeks ago
|
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;
|
||
|
}
|