import '../../../core/utils/avatar_urls.dart'; /// 交易员(跟单广场列表项) class Trader { final String id; final String name; final String avatarLetter; final String? avatarUrl; // 真实头像 URL(来自 API) final int followers; final int? maxFollowers; // 最大跟随人数 final double roi30d; // 近14日收益率 % final double profit30d; // 近30日收益 USDT final double profitShare; // 分润比例 %(来自 dividendPercent) final double winRate; // 近14日胜率 % final bool isNoLoss; // 是否无损跟单 final bool isFollowing; // 是否已跟随 /// 当前用户是否已收藏(跟单广场「我的收藏」与列表星标) final bool isFavorited; final List trendData; // 走势迷你图数据 final String? levelName; // 交易员等级名称(如 L3、L5) // ── 我的交易员 tab 额外字段 ────────────────────────────── final String? description; // 个人介绍 final List tags; // 标签列表(如超短、中长、稳健型) final double profitAmount; // 累计收益 USDT(对跟单员是从该交易员获得的收益) final int tradingDays; // 累计交易天数 final int followCustomer; // 累计跟单人数(总人数,非当前) const Trader({ required this.id, required this.name, required this.avatarLetter, this.avatarUrl, required this.followers, this.maxFollowers, required this.roi30d, required this.profit30d, required this.profitShare, required this.winRate, this.isNoLoss = false, this.isFollowing = false, this.isFavorited = false, this.trendData = const [], this.levelName, this.description, this.tags = const [], this.profitAmount = 0, this.tradingDays = 0, this.followCustomer = 0, }); /// 是否与 Web 一致的布尔解析(支持 1/true/"true")。 static bool parseFavoriteFlag(dynamic value) { if (value == null) { return false; } if (value is bool) { return value; } if (value is num) { return value != 0; } final s = value.toString().trim().toLowerCase(); if (s.isEmpty || s == '0' || s == 'false') { return false; } if (s == '1' || s == 'true' || s == 'yes') { return true; } return false; } Trader copyWith({ bool? isFavorited, bool? isFollowing, }) { return Trader( id: id, name: name, avatarLetter: avatarLetter, avatarUrl: avatarUrl, followers: followers, maxFollowers: maxFollowers, roi30d: roi30d, profit30d: profit30d, profitShare: profitShare, winRate: winRate, isNoLoss: isNoLoss, isFollowing: isFollowing ?? this.isFollowing, isFavorited: isFavorited ?? this.isFavorited, trendData: trendData, levelName: levelName, description: description, tags: tags, profitAmount: profitAmount, tradingDays: tradingDays, followCustomer: followCustomer, ); } /// 从 API 返回的 FollowTrader / TraderVo Map 构建 factory Trader.fromApi( Map json, { bool isNoLoss = false, bool? isFavoritedOverride, }) { final nickname = (json['nickname'] ?? json['nickName'])?.toString().trim() ?? ''; final letter = nickname.isNotEmpty ? nickname[0].toUpperCase() : '?'; // 将 yield14List 数组转为 double 列表(用于走势图) List trendData = []; final yields = json['yield14List']; if (yields is List) { trendData = yields .map((e) { if (e is Map) { // 安卓 Yield14 model: @SerializedName("dayYield14") final v = e['dayYield14'] ?? e['yield'] ?? e['rate'] ?? e['value'] ?? 0; return (v is num) ? v.toDouble() : double.tryParse(v.toString()) ?? 0.0; } return (e is num) ? e.toDouble() : double.tryParse(e.toString()) ?? 0.0; }) .toList() .reversed // 后台按 date DESC 返回(最新在前),翻转为时间正序(旧→新,左→右) .toList(); } double _d(String key) => double.tryParse((json[key] ?? '0').toString()) ?? 0.0; int _i(String key) => int.tryParse((json[key] ?? '0').toString()) ?? 0; // 解析标签列表(可能是 List 或 List) List tags = []; final rawTags = json['tags']; if (rawTags is List) { tags = rawTags .map((e) { if (e is String) return e; if (e is Map) return (e['name'] ?? '').toString(); return ''; }) .where((s) => s.isNotEmpty) .toList(); } // 分润比例:不同接口可能用不同字段名 double resolvedProfitShare = 0.0; for (final key in [ 'dividendPercent', 'profitRatio', 'dividendRatio', 'sharePercent', 'profitPercent' ]) { final v = double.tryParse((json[key] ?? '').toString()); if (v != null && v != 0.0) { resolvedProfitShare = v; break; } } return Trader( id: json['id']?.toString() ?? '', name: nickname, avatarLetter: letter, avatarUrl: resolvedAvatarUrlFromRecord(json), followers: _i('following'), maxFollowers: json['maxFollow'] != null ? _i('maxFollow') : null, roi30d: _d('dayYield14'), profit30d: _d('profitAmount'), profitShare: resolvedProfitShare, winRate: _d('winRate14'), isNoLoss: isNoLoss || json['specialTrader'] == true, isFollowing: parseFavoriteFlag(json['isFollow'] ?? json['follow']), isFavorited: isFavoritedOverride ?? parseFavoriteFlag( json['isFavorite'] ?? json['isFavorited'] ?? json['favorite']), trendData: trendData, levelName: json['levelName'] as String?, description: json['description'] as String?, tags: tags, profitAmount: _d('profitAmount'), tradingDays: _i('tradingDays'), followCustomer: _i('defaultFollowCustomer') + _i('followCustomer'), ); } }