diff --git a/lib/modules/agent/repositories/agent_repository.dart b/lib/modules/agent/repositories/agent_repository.dart index 6668e77..78e5e1d 100644 --- a/lib/modules/agent/repositories/agent_repository.dart +++ b/lib/modules/agent/repositories/agent_repository.dart @@ -29,13 +29,20 @@ class AgentRepository implements AgentRepositoryContract { int page = 1, int count = 30, }) async { - final response = await _apiClient.get>( + final response = await _apiClient.get( '/api/v1/message/agent/sessions', queryParameters: {'page': page, 'count': count}, ); final data = response.data; - if (data == null || data['success'] != true) { - throw StateError(data?['message']?.toString() ?? '会话列表加载失败'); + if (data is List) { + return data + .whereType() + .map((item) => AgentSession.fromJson(Map.from(item))) + .toList(growable: false); + } + if (data is! Map || data['success'] != true) { + final message = data is Map ? data['message']?.toString() : null; + throw StateError(message ?? '会话列表加载失败'); } final list = data['data']; if (list is! List) return const []; diff --git a/lib/modules/dashboard/controllers/dashboard_controller.dart b/lib/modules/dashboard/controllers/dashboard_controller.dart index 131bf91..6ebeee3 100644 --- a/lib/modules/dashboard/controllers/dashboard_controller.dart +++ b/lib/modules/dashboard/controllers/dashboard_controller.dart @@ -422,14 +422,19 @@ class DashboardController extends GetxController { Future loadMemoryData() async { try { talker.info('开始加载内存数据'); - final response = await apiClient.get>( - '/api/v1/dashboard/memory', - ); + final response = await apiClient.get('/api/v1/dashboard/memory'); if (response.statusCode == 200) { final data = response.data!; - if (data.length >= 2) { - final memoryUsed = data[0] as int; - final memoryUsage = data[1] as int; + int? memoryUsed; + int? memoryUsage; + if (data is Map) { + memoryUsed = (data['used'] as num?)?.toInt(); + memoryUsage = (data['usage'] as num?)?.round(); + } else if (data is List && data.length >= 2) { + memoryUsed = (data[0] as num?)?.toInt(); + memoryUsage = (data[1] as num?)?.round(); + } + if (memoryUsed != null && memoryUsage != null) { memoryData.value = [memoryUsed, memoryUsage]; _appendMemoryChartData(memoryUsage.toDouble()); talker.info('内存数据加载成功: 使用 $memoryUsed 字节, 使用率 $memoryUsage%'); diff --git a/lib/modules/site/controllers/site_detail_controller.dart b/lib/modules/site/controllers/site_detail_controller.dart index 5f573e7..f30ff33 100644 --- a/lib/modules/site/controllers/site_detail_controller.dart +++ b/lib/modules/site/controllers/site_detail_controller.dart @@ -135,17 +135,28 @@ class SiteDetailController extends GetxController { return; } final raw = response.data; - if (raw is! Map) { - historyItems.clear(); - return; - } - final res = SiteUserDataHistoryResponse.fromJson(raw); - if (!res.success) { - errorText.value = res.message ?? '请求失败'; + final List list; + if (raw is List) { + list = raw + .whereType() + .map( + (item) => SiteUserDataHistoryItem.fromJson( + Map.from(item), + ), + ) + .toList(); + } else if (raw is Map) { + final res = SiteUserDataHistoryResponse.fromJson(raw); + if (!res.success) { + errorText.value = res.message ?? '请求失败'; + historyItems.clear(); + return; + } + list = res.data.toList(); + } else { historyItems.clear(); return; } - final list = res.data.toList(); list.sort((a, b) { final da = a.updatedDay; final db = b.updatedDay; diff --git a/lib/services/api_client.dart b/lib/services/api_client.dart index 44c30b2..94a95dd 100644 --- a/lib/services/api_client.dart +++ b/lib/services/api_client.dart @@ -8,6 +8,7 @@ import 'package:moviepilot_mobile/applog/app_log.dart'; import 'package:talker/talker.dart'; import 'package:talker_dio_logger/talker_dio_logger.dart'; import 'package:moviepilot_mobile/services/app_service.dart'; +import 'package:moviepilot_mobile/services/server_api_version_service.dart'; import 'package:moviepilot_mobile/utils/dio_adapter_config_stub.dart' if (dart.library.io) 'package:moviepilot_mobile/utils/dio_adapter_config_io.dart' if (dart.library.js_interop) 'package:moviepilot_mobile/utils/dio_adapter_config_web.dart'; @@ -41,6 +42,8 @@ class ApiHttpException implements Exception { } class ApiClient extends g.GetxController { + static const _skipV3EnvelopeUnwrapKey = 'skipV3EnvelopeUnwrap'; + final _appService = g.Get.find(); final _iosSharedSessionService = g.Get.find(); final _hiveService = g.Get.find(); @@ -191,6 +194,59 @@ class ApiClient extends g.GetxController { ), ); } + _dio.interceptors.add( + InterceptorsWrapper( + onResponse: (response, handler) async { + if (response.requestOptions.extra[_skipV3EnvelopeUnwrapKey] == true || + response.requestOptions.responseType != ResponseType.json) { + handler.next(response); + return; + } + + final envelope = response.data; + if (envelope is! Map || + envelope['success'] is! bool || + !envelope.containsKey('data')) { + handler.next(response); + return; + } + + if (!g.Get.isRegistered()) { + handler.next(response); + return; + } + + try { + final isV3 = await g.Get.find().isV3(); + if (!isV3) { + handler.next(response); + return; + } + } catch (_) { + handler.next(response); + return; + } + + final data = envelope['data']; + if (data == null) { + handler.next(response); + return; + } + if (data is Map) { + // 业务字段优先:仅在原始数据没有同名键时才补 envelope 的字段, + // 避免把接口本身返回的 success / message / data 覆盖掉。 + final merged = Map.from(data); + merged.putIfAbsent('success', () => envelope['success']); + merged.putIfAbsent('message', () => envelope['message']); + merged.putIfAbsent('data', () => data); + response.data = merged; + } else { + response.data = data; + } + handler.next(response); + }, + ), + ); } Future _ensureReady() => _ready; @@ -531,6 +587,7 @@ class ApiClient extends g.GetxController { int? timeout, Map? headers, bool skipUnauthorizedHandling = false, + bool skipV3EnvelopeUnwrap = false, }) async { await _ensureReady(); final authToken = token ?? this.token; @@ -546,7 +603,10 @@ class ApiClient extends g.GetxController { // 允许所有状态码,让调用者自己处理错误 return true; }, - extra: {if (skipUnauthorizedHandling) 'skipUnauthorizedHandling': true}, + extra: { + if (skipUnauthorizedHandling) 'skipUnauthorizedHandling': true, + if (skipV3EnvelopeUnwrap) _skipV3EnvelopeUnwrapKey: true, + }, ); final response = await _dio.get( path, diff --git a/lib/services/server_api_version_service.dart b/lib/services/server_api_version_service.dart index cce6f22..116e5ce 100644 --- a/lib/services/server_api_version_service.dart +++ b/lib/services/server_api_version_service.dart @@ -23,8 +23,15 @@ class ServerApiVersionService extends GetxService { Future _detect(String baseUrl, int generation) async { try { - final response = await _apiClient.get('/api/v1/media/source'); - final result = response.statusCode == 200 && response.data is List; + final response = await _apiClient.get( + '/api/v1/media/source', + skipV3EnvelopeUnwrap: true, + ); + final data = response.data; + final hasSourceList = + data is List || + (data is Map && data.containsKey('data') && data['data'] is List); + final result = response.statusCode == 200 && hasSourceList; if (generation == _generation) { _cache[baseUrl] = result; }