// 功能描述:银行卡与提现申请的严格领域模型;版本:1.0.0。 /// 本人已绑定银行卡只保留服务端返回的脱敏字段。 class WalletBank { const WalletBank({ required this.identity, required this.maskedNumber, required this.bankName, required this.owner, required this.type, required this.isDefault, }); final String identity, maskedNumber, bankName, owner, type; final bool isDefault; factory WalletBank.fromJson(Map json) { final identity = json['identity'], number = json['card_no_masked']; if (identity is! String || identity.isEmpty || number is! String || number.isEmpty) { throw const FormatException('银行卡数据不完整'); } return WalletBank( identity: identity, maskedNumber: number, bankName: json['bank_name'] as String? ?? '银行卡', owner: json['card_owner'] as String? ?? '', type: json['bank_type'] as String? ?? '', isDefault: json['is_default'] == true, ); } String get typeName => switch (type) { 'debit' || 'saving' => '储蓄卡', 'credit' => '信用卡', _ => type, }; } /// 提现状态必须来自服务端,申请成功只表示进入审核流程。 class WalletWithdrawal { const WalletWithdrawal({ required this.identity, required this.number, required this.amount, required this.fee, required this.status, required this.createdAt, }); final String identity, number; final int amount, fee, status; final DateTime createdAt; factory WalletWithdrawal.fromJson(Map json) { final identity = json['identity'], amount = json['amount'], fee = json['fee']; final createdAt = DateTime.tryParse(json['created_at'] as String? ?? ''); if (identity is! String || identity.isEmpty || amount is! int || amount <= 0 || fee is! int || fee < 0 || json['apply_status'] is! int || createdAt == null) { throw const FormatException('提现记录数据不完整'); } return WalletWithdrawal( identity: identity, number: json['cash_no'] as String? ?? '', amount: amount, fee: fee, status: json['apply_status'] as int, createdAt: createdAt.toLocal(), ); } String get statusName => switch (status) { 10 => '待审核', 18 => '处理中', 23 => '已到账', 30 => '已拒绝', 31 => '已退回', _ => '状态待确认', }; } /// 金额文本直接转整数分,禁止浮点舍入和指数格式。 int? parseWithdrawalAmount(String value) { final text = value.trim(); if (!RegExp(r'^\d{1,9}(\.\d{1,2})?$').hasMatch(text)) return null; final parts = text.split('.'); return int.parse(parts[0]) * 100 + (parts.length == 1 ? 0 : int.parse(parts[1].padRight(2, '0'))); }