import 'dart:convert'; /// 服务节点(线路) class ServiceNode { final int id; final String name; final String apiHost; final String wsHost; final int status; const ServiceNode({ required this.id, required this.name, required this.apiHost, required this.wsHost, this.status = 0, }); factory ServiceNode.fromJson(Map json) { return ServiceNode( id: json['id'] as int? ?? 0, name: json['name'] as String? ?? '', apiHost: json['apiHost'] as String? ?? '', wsHost: json['wsHost'] as String? ?? '', status: json['status'] as int? ?? 0, ); } Map toJson() => { 'id': id, 'name': name, 'apiHost': apiHost, 'wsHost': wsHost, 'status': status, }; /// apiHost 是否为有效 URL bool get isValid => apiHost.startsWith('http') && wsHost.startsWith('ws'); /// 归一化 API Host:确保以 / 结尾,以便 Dio 正确拼接相对路径 /// 例如 "https://xxx.top/api" → "https://xxx.top/api/" String get normalizedApiHost { var host = apiHost; if (!host.endsWith('/')) host = '$host/'; return host; } /// 归一化 WS Host:补全 /ws/market 后缀 /// 例如 "ws://xxx.top/api/market-new" → "ws://xxx.top/api/market-new/ws/market" String get normalizedWsHost { var host = wsHost; if (!host.endsWith('/ws/market')) { if (host.endsWith('/')) host = host.substring(0, host.length - 1); host = '$host/ws/market'; } return host; } /// 从 JSON 字符串列表反序列化 static List listFromJson(String jsonStr) { final list = jsonDecode(jsonStr) as List; return list .map((e) => ServiceNode.fromJson(e as Map)) .toList(); } /// 序列化列表为 JSON 字符串 static String listToJson(List nodes) { return jsonEncode(nodes.map((e) => e.toJson()).toList()); } }