import 'package:networks_sdk/networks_sdk.dart'; import 'package:im_app/core/foundation/api_paths.dart'; // ── 发送红包 ────────────────────────────────────────────────────────────────── /// 发送红包响应 class SendRpData { final String rpId; const SendRpData({required this.rpId}); factory SendRpData.fromJson(Map json) { return SendRpData( rpId: (json['rpID'] ?? json['rp_id'] ?? '').toString(), ); } } /// 发送红包请求 /// /// 对应 Gitea issue #19 + #22 + #30 /// /// ## currencyType 规则(#19 bug fix) /// /// iOS 硬编码 `"PEA"` → `code=150001` 错误(workspace 群使用 USDT)。 /// Flutter 修复:`currencyType` 由调用方传入,UseCase 层根据 workspaceId 动态决定: /// - workspaceId > 0 → 从 `/workspace/workspace/get` 取 workspace.currency /// - workspaceId == 0 → 默认 `"PEA"` /// /// ## mineAmount(#30 MINE_RP) /// /// 地雷红包时附带 `mineAmount` 参数,null 时不传。 class SendRpRequest extends ApiRequestable { final String amount; final String currencyType; final int chatId; final int chatType; final String rpType; final List recipientIds; final int rpNum; final String remark; final int msgSendTime; final String? mineAmount; const SendRpRequest({ required this.amount, required this.currencyType, required this.chatId, required this.chatType, required this.rpType, required this.recipientIds, required this.rpNum, required this.remark, required this.msgSendTime, this.mineAmount, }); @override String get path => ApiPaths.rpSend; @override HttpMethod get method => HttpMethod.post; @override Map get parameters => { 'amount': amount, 'currencyType': currencyType, 'chatID': chatId, 'chatType': chatType, 'rpType': rpType, 'recipientIDs': recipientIds, 'rpNum': rpNum, 'remark': remark, 'msgSendTime': msgSendTime, if (mineAmount != null && mineAmount!.isNotEmpty) 'mineAmount': mineAmount, }; @override SendRpData? decodeResponse(dynamic response) { final data = (response as dynamic).data; if (data is! Map) return null; return SendRpData.fromJson(data); } } // ── 领取红包 ────────────────────────────────────────────────────────────────── /// 领取红包响应 class ReceiveRpData { final bool grabFlag; final String amount; final int rpStatus; const ReceiveRpData({ required this.grabFlag, required this.amount, required this.rpStatus, }); factory ReceiveRpData.fromJson(Map json) { return ReceiveRpData( grabFlag: json['grabFlag'] as bool? ?? false, amount: (json['amount'] ?? '0').toString(), rpStatus: json['rpStatus'] as int? ?? 0, ); } } /// 领取红包请求 /// /// 对应 Gitea issue #21 /// /// ⚠️ 必须 JSON typed body(非 form 字符串),否则 server 返回 code=30007。 /// `supportMask: true` + `supportHideTail: true` 为必填标志位。 class ReceiveRpRequest extends ApiRequestable { final String rpId; final int chatId; final String rpType; final int sendRpMsgId; const ReceiveRpRequest({ required this.rpId, required this.chatId, required this.rpType, required this.sendRpMsgId, }); @override String get path => ApiPaths.rpReceive; @override HttpMethod get method => HttpMethod.post; @override Map get parameters => { 'rpID': rpId, 'chatID': chatId, 'rpType': rpType, 'sendRpMsgID': sendRpMsgId, 'supportMask': true, 'supportHideTail': true, }; @override ReceiveRpData? decodeResponse(dynamic response) { final data = (response as dynamic).data; if (data is! Map) return null; return ReceiveRpData.fromJson(data); } } // ── 游戏横幅 ────────────────────────────────────────────────────────────────── /// 游戏横幅响应 class GameBannerData { final String gameId; final String gameName; final String? appId; final GameCurrentRound? currentRound; final GameLastRound? lastRound; const GameBannerData({ required this.gameId, required this.gameName, this.appId, this.currentRound, this.lastRound, }); factory GameBannerData.fromJson(Map json) { return GameBannerData( gameId: json['gameId'] as String? ?? '', gameName: json['gameName'] as String? ?? '', appId: json['appid'] as String?, currentRound: json['currentRound'] is Map ? GameCurrentRound.fromJson(json['currentRound'] as Map) : null, lastRound: json['lastCompletedRound'] is Map ? GameLastRound.fromJson(json['lastCompletedRound'] as Map) : null, ); } } class GameCurrentRound { final String round; final int? startTime; final int? closureTime; final int? drawTime; final int? serverTime; const GameCurrentRound({ required this.round, this.startTime, this.closureTime, this.drawTime, this.serverTime, }); factory GameCurrentRound.fromJson(Map json) { return GameCurrentRound( round: json['round'] as String? ?? '', startTime: json['startTime'] as int?, closureTime: json['closureTime'] as int?, drawTime: json['drawTime'] as int?, serverTime: json['serverTime'] as int?, ); } } class GameLastRound { final String round; final String result; final String? simple; const GameLastRound({ required this.round, required this.result, this.simple, }); factory GameLastRound.fromJson(Map json) { return GameLastRound( round: json['round'] as String? ?? '', result: json['result'] as String? ?? '', simple: json['simple'] as String?, ); } } /// 获取游戏横幅请求 class FetchBannerRequest extends ApiRequestable { final String gameId; const FetchBannerRequest({required this.gameId}); @override String get path => ApiPaths.bannerGet; @override HttpMethod get method => HttpMethod.post; @override Map get parameters => {'game_id': gameId}; @override GameBannerData? decodeResponse(dynamic response) { final data = (response as dynamic).data; if (data is! Map) return null; return GameBannerData.fromJson(data); } } // ── Workspace ───────────────────────────────────────────────────────────────── /// Workspace 信息响应(用于获取 currency) class WorkspaceData { final int id; final String currency; final String name; const WorkspaceData({ required this.id, required this.currency, required this.name, }); factory WorkspaceData.fromJson(Map json) { final ws = json['workspace'] as Map? ?? json; return WorkspaceData( id: ws['id'] as int? ?? 0, currency: ws['currency'] as String? ?? 'PEA', name: ws['name'] as String? ?? '', ); } } // ── 红包领取详情 ─────────────────────────────────────────────────────────────── /// 单条领取记录 class RpRecordItem { final int userId; final String nickname; final String avatarUrl; final String amount; final int grabTime; const RpRecordItem({ required this.userId, required this.nickname, required this.avatarUrl, required this.amount, required this.grabTime, }); factory RpRecordItem.fromJson(Map json) { return RpRecordItem( userId: json['userId'] as int? ?? 0, nickname: json['nickname'] as String? ?? '', avatarUrl: json['avatarUrl'] as String? ?? '', amount: (json['amount'] ?? '0').toString(), grabTime: json['grabTime'] as int? ?? 0, ); } } /// 红包领取详情响应 /// /// 对应 Gitea issue #29 class RpDetailData { final String rpId; final String rpType; final String remark; final String totalAmount; final int totalNum; final String receivedAmount; final int receivedNum; final int status; final List records; const RpDetailData({ required this.rpId, required this.rpType, required this.remark, required this.totalAmount, required this.totalNum, required this.receivedAmount, required this.receivedNum, required this.status, required this.records, }); factory RpDetailData.fromJson(Map json) { final raw = json['records']; final records = raw is List ? raw.whereType>().map(RpRecordItem.fromJson).toList() : []; return RpDetailData( rpId: json['rpId'] as String? ?? '', rpType: json['rpType'] as String? ?? '', remark: json['remark'] as String? ?? '恭喜发财', totalAmount: (json['totalAmount'] ?? '0').toString(), totalNum: json['totalNum'] as int? ?? 0, receivedAmount: (json['receivedAmount'] ?? '0').toString(), receivedNum: json['receivedNum'] as int? ?? 0, status: json['status'] as int? ?? 0, records: records, ); } } /// 获取红包领取详情请求 /// /// GET /payment/rp/detail?rpId=xxx class GetRpDetailRequest extends ApiRequestable { final String rpId; const GetRpDetailRequest({required this.rpId}); @override String get path => ApiPaths.rpDetail; @override HttpMethod get method => HttpMethod.get; @override Map get parameters => {'rpId': rpId}; @override RpDetailData? decodeResponse(dynamic response) { final data = (response as dynamic).data; if (data is! Map) return null; return RpDetailData.fromJson(data); } } // ── Workspace ───────────────────────────────────────────────────────────────── /// 获取 Workspace 信息请求 class GetWorkspaceRequest extends ApiRequestable { final int workspaceId; const GetWorkspaceRequest({required this.workspaceId}); @override String get path => ApiPaths.workspaceGet; @override HttpMethod get method => HttpMethod.get; @override Map get parameters => {'id': workspaceId.toString()}; @override WorkspaceData? decodeResponse(dynamic response) { final data = (response as dynamic).data; if (data is! Map) return null; return WorkspaceData.fromJson(data); } }