142 lines
3.7 KiB
Dart
142 lines
3.7 KiB
Dart
import '../../../common/domain/metal_type.dart';
|
|
|
|
enum AssetCategory {
|
|
bar('金条'),
|
|
necklace('项链'),
|
|
ring('戒指'),
|
|
bracelet('手镯'),
|
|
bean('金豆'),
|
|
earring('耳环'),
|
|
silverware('银饰'),
|
|
platinumPiece('铂金件');
|
|
|
|
const AssetCategory(this.label);
|
|
|
|
final String label;
|
|
}
|
|
|
|
enum HoldingStatus { active, sold, gifted }
|
|
|
|
class GoldAssetHolding {
|
|
const GoldAssetHolding({
|
|
required this.id,
|
|
required this.name,
|
|
required this.metal,
|
|
required this.category,
|
|
required this.purity,
|
|
required this.purityLabel,
|
|
required this.weightGram,
|
|
required this.createdAt,
|
|
required this.updatedAt,
|
|
this.costAmount,
|
|
this.purchaseDate,
|
|
this.channel,
|
|
this.note,
|
|
this.status = HoldingStatus.active,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final MetalType metal;
|
|
final AssetCategory category;
|
|
final double purity;
|
|
final String purityLabel;
|
|
final double weightGram;
|
|
final double? costAmount;
|
|
final DateTime? purchaseDate;
|
|
final String? channel;
|
|
final String? note;
|
|
final DateTime createdAt;
|
|
final DateTime updatedAt;
|
|
final HoldingStatus status;
|
|
|
|
double materialValue(double spotPrice) => weightGram * purity * spotPrice;
|
|
|
|
Map<String, Object?> toJson() => {
|
|
'id': id,
|
|
'name': name,
|
|
'metal': metal.name,
|
|
'category': category.name,
|
|
'purity': purity,
|
|
'purityLabel': purityLabel,
|
|
'weightGram': weightGram,
|
|
'costAmount': costAmount,
|
|
'purchaseDate': purchaseDate?.toIso8601String(),
|
|
'channel': channel,
|
|
'note': note,
|
|
'createdAt': createdAt.toIso8601String(),
|
|
'updatedAt': updatedAt.toIso8601String(),
|
|
'status': status.name,
|
|
};
|
|
|
|
factory GoldAssetHolding.fromJson(Map<String, Object?> json) {
|
|
return GoldAssetHolding(
|
|
id: json['id']! as String,
|
|
name: json['name']! as String,
|
|
metal: MetalType.values.byName(json['metal']! as String),
|
|
category: AssetCategory.values.byName(json['category']! as String),
|
|
purity: (json['purity']! as num).toDouble(),
|
|
purityLabel: json['purityLabel']! as String,
|
|
weightGram: (json['weightGram']! as num).toDouble(),
|
|
costAmount: (json['costAmount'] as num?)?.toDouble(),
|
|
purchaseDate: switch (json['purchaseDate']) {
|
|
final String value when value.isNotEmpty => DateTime.parse(value),
|
|
_ => null,
|
|
},
|
|
channel: json['channel'] as String?,
|
|
note: json['note'] as String?,
|
|
createdAt: DateTime.parse(json['createdAt']! as String),
|
|
updatedAt: DateTime.parse(json['updatedAt']! as String),
|
|
status: HoldingStatus.values.byName(json['status']! as String),
|
|
);
|
|
}
|
|
}
|
|
|
|
class HoldingValuation {
|
|
const HoldingValuation({
|
|
required this.holding,
|
|
required this.materialValue,
|
|
required this.todayChange,
|
|
});
|
|
|
|
final GoldAssetHolding holding;
|
|
final double materialValue;
|
|
final double todayChange;
|
|
}
|
|
|
|
class MetalBreakdown {
|
|
const MetalBreakdown({
|
|
required this.metal,
|
|
required this.value,
|
|
required this.weightGram,
|
|
required this.count,
|
|
});
|
|
|
|
final MetalType metal;
|
|
final double value;
|
|
final double weightGram;
|
|
final int count;
|
|
}
|
|
|
|
class PortfolioSummary {
|
|
const PortfolioSummary({
|
|
required this.totalValue,
|
|
required this.todayChangeAmount,
|
|
required this.todayChangePercent,
|
|
required this.totalCost,
|
|
required this.totalWeightGram,
|
|
required this.recycleReferenceValue,
|
|
required this.breakdowns,
|
|
required this.holdings,
|
|
});
|
|
|
|
final double totalValue;
|
|
final double todayChangeAmount;
|
|
final double todayChangePercent;
|
|
final double totalCost;
|
|
final double totalWeightGram;
|
|
final double recycleReferenceValue;
|
|
final List<MetalBreakdown> breakdowns;
|
|
final List<HoldingValuation> holdings;
|
|
}
|