优化扫码页 UI

This commit is contained in:
2026-07-28 18:50:14 +08:00
parent 8e599f5a86
commit f7f7413b55
8 changed files with 157 additions and 52 deletions
+17 -3
View File
@@ -38,11 +38,15 @@ class ApiClient {
return _parseData<T>(raw, parser);
}
if (raw is! Map<String, dynamic>) {
final payload = raw is Map ? Map<String, dynamic>.from(raw) : null;
if (payload == null ||
!(payload.containsKey('code') || payload.containsKey('message'))) {
return _parseData<T>(raw, parser);
}
final wrapped = ApiResponse<T>.fromJson(raw, fromJsonT: parser);
// 先按 {code,message,data} 解包,再用业务 parser 解析 data
// 避免把 Map 直接强转成业务模型。
final wrapped = ApiResponse<dynamic>.fromJson(payload);
if (!wrapped.isSuccess) {
throw ApiException(
code: wrapped.code,
@@ -52,7 +56,17 @@ class ApiClient {
);
}
return wrapped.data as T;
if (wrapped.data == null) {
if (null is T) return null as T;
throw ApiException(
code: wrapped.code,
statusCode: response.statusCode,
message: '响应 data 为空',
details: raw,
);
}
return _parseData<T>(wrapped.data, parser);
} on DioException catch (error) {
throw _mapDioException(error);
}
+17 -1
View File
@@ -11,10 +11,26 @@ class ApiResponse<T> {
Map<String, dynamic> json, {
T Function(dynamic json)? fromJsonT,
}) {
final rawData = json['data'];
T? data;
if (rawData != null && fromJsonT != null) {
data = fromJsonT(rawData);
} else if (rawData != null && fromJsonT == null) {
// 无 parser 时仅在类型已匹配时接收,避免 Map 被强转为业务模型。
if (rawData is T) {
data = rawData;
} else {
throw FormatException(
'ApiResponse data 类型不匹配,且未提供 fromJsonT;'
'期望 $T,实际 ${rawData.runtimeType}',
);
}
}
return ApiResponse<T>(
code: (json['code'] as num?)?.toInt() ?? 200,
message: (json['message'] ?? json['msg'] ?? '').toString(),
data: fromJsonT == null ? json['data'] as T? : fromJsonT(json['data']),
data: data,
);
}
}