Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions lib/modules/agent/repositories/agent_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ class AgentRepository implements AgentRepositoryContract {
int page = 1,
int count = 30,
}) async {
final response = await _apiClient.get<Map<String, dynamic>>(
final response = await _apiClient.get<dynamic>(
'/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>()
.map((item) => AgentSession.fromJson(Map<String, dynamic>.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 [];
Expand Down
17 changes: 11 additions & 6 deletions lib/modules/dashboard/controllers/dashboard_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -422,14 +422,19 @@ class DashboardController extends GetxController {
Future<void> loadMemoryData() async {
try {
talker.info('开始加载内存数据');
final response = await apiClient.get<List<dynamic>>(
'/api/v1/dashboard/memory',
);
final response = await apiClient.get<dynamic>('/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%');
Expand Down
27 changes: 19 additions & 8 deletions lib/modules/site/controllers/site_detail_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,28 @@ class SiteDetailController extends GetxController {
return;
}
final raw = response.data;
if (raw is! Map<String, dynamic>) {
historyItems.clear();
return;
}
final res = SiteUserDataHistoryResponse.fromJson(raw);
if (!res.success) {
errorText.value = res.message ?? '请求失败';
final List<SiteUserDataHistoryItem> list;
if (raw is List) {
list = raw
.whereType<Map>()
.map(
(item) => SiteUserDataHistoryItem.fromJson(
Map<String, dynamic>.from(item),
),
)
.toList();
} else if (raw is Map<String, dynamic>) {
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;
Expand Down
62 changes: 61 additions & 1 deletion lib/services/api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -41,6 +42,8 @@ class ApiHttpException implements Exception {
}

class ApiClient extends g.GetxController {
static const _skipV3EnvelopeUnwrapKey = 'skipV3EnvelopeUnwrap';

final _appService = g.Get.find<AppService>();
final _iosSharedSessionService = g.Get.find<IosSharedSessionService>();
final _hiveService = g.Get.find<HiveService>();
Expand Down Expand Up @@ -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<ServerApiVersionService>()) {
handler.next(response);
return;
}

try {
final isV3 = await g.Get.find<ServerApiVersionService>().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<String, dynamic>.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<void> _ensureReady() => _ready;
Expand Down Expand Up @@ -531,6 +587,7 @@ class ApiClient extends g.GetxController {
int? timeout,
Map<String, dynamic>? headers,
bool skipUnauthorizedHandling = false,
bool skipV3EnvelopeUnwrap = false,
}) async {
await _ensureReady();
final authToken = token ?? this.token;
Expand All @@ -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<T>(
path,
Expand Down
11 changes: 9 additions & 2 deletions lib/services/server_api_version_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ class ServerApiVersionService extends GetxService {

Future<bool> _detect(String baseUrl, int generation) async {
try {
final response = await _apiClient.get<dynamic>('/api/v1/media/source');
final result = response.statusCode == 200 && response.data is List;
final response = await _apiClient.get<dynamic>(
'/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;
}
Expand Down