feat(mobile-app): 添加合同签署 API 详细调试日志
- 为 signContract、lateSignContract、markScrollComplete、acknowledgeContract 添加详细日志 - 记录请求参数(签名图片大小、IP、设备信息、位置) - 记录响应状态码和完整响应数据 - 修复响应解析 bug:正确从 response.data['data'] 提取任务数据 - 增强错误日志,捕获堆栈信息便于调试 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
846bf5b061
commit
accc043ff0
|
|
@ -403,7 +403,8 @@
|
|||
"Bash(frontend/mobile-app/lib/features/contract_signing/ )",
|
||||
"Bash(frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart )",
|
||||
"Bash(git branch:*)",
|
||||
"Bash(echo \"docker exec rwa-planting-service npx prisma db execute --stdin <<< \"\"SELECT template_id, version, title, is_active FROM contract_templates;\"\"\")"
|
||||
"Bash(echo \"docker exec rwa-planting-service npx prisma db execute --stdin <<< \"\"SELECT template_id, version, title, is_active FROM contract_templates;\"\"\")",
|
||||
"Bash(npm uninstall:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -257,20 +257,34 @@ class ContractSigningService {
|
|||
Future<ContractSigningTask> markScrollComplete(String orderNo) async {
|
||||
try {
|
||||
debugPrint('[ContractSigningService] 标记已滚动到底部: $orderNo');
|
||||
debugPrint('[ContractSigningService] 请求 URL: /planting/contract-signing/tasks/$orderNo/scroll-complete');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/contract-signing/tasks/$orderNo/scroll-complete',
|
||||
);
|
||||
|
||||
debugPrint('[ContractSigningService] 响应状态码: ${response.statusCode}');
|
||||
debugPrint('[ContractSigningService] 响应数据: ${response.data}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 滚动标记成功');
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['success'] == true && responseData['data'] != null) {
|
||||
final data = responseData['data'] as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 滚动标记成功,任务状态: ${data['status']}');
|
||||
return ContractSigningTask.fromJson(data);
|
||||
}
|
||||
// 兼容直接返回任务数据的情况
|
||||
if (responseData['orderNo'] != null) {
|
||||
debugPrint('[ContractSigningService] 滚动标记成功(直接返回数据)');
|
||||
return ContractSigningTask.fromJson(responseData);
|
||||
}
|
||||
throw Exception('标记滚动失败: ${responseData['message'] ?? '响应格式错误'}');
|
||||
}
|
||||
|
||||
throw Exception('标记滚动失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[ContractSigningService] 标记滚动失败: $e');
|
||||
debugPrint('[ContractSigningService] 堆栈: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
@ -279,20 +293,34 @@ class ContractSigningService {
|
|||
Future<ContractSigningTask> acknowledgeContract(String orderNo) async {
|
||||
try {
|
||||
debugPrint('[ContractSigningService] 确认法律效力: $orderNo');
|
||||
debugPrint('[ContractSigningService] 请求 URL: /planting/contract-signing/tasks/$orderNo/acknowledge');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/contract-signing/tasks/$orderNo/acknowledge',
|
||||
);
|
||||
|
||||
debugPrint('[ContractSigningService] 响应状态码: ${response.statusCode}');
|
||||
debugPrint('[ContractSigningService] 响应数据: ${response.data}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 确认法律效力成功');
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['success'] == true && responseData['data'] != null) {
|
||||
final data = responseData['data'] as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 确认法律效力成功,任务状态: ${data['status']}');
|
||||
return ContractSigningTask.fromJson(data);
|
||||
}
|
||||
// 兼容直接返回任务数据的情况
|
||||
if (responseData['orderNo'] != null) {
|
||||
debugPrint('[ContractSigningService] 确认法律效力成功(直接返回数据)');
|
||||
return ContractSigningTask.fromJson(responseData);
|
||||
}
|
||||
throw Exception('确认法律效力失败: ${responseData['message'] ?? '响应格式错误'}');
|
||||
}
|
||||
|
||||
throw Exception('确认法律效力失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[ContractSigningService] 确认法律效力失败: $e');
|
||||
debugPrint('[ContractSigningService] 堆栈: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
@ -309,31 +337,51 @@ class ContractSigningService {
|
|||
}) async {
|
||||
try {
|
||||
debugPrint('[ContractSigningService] 签署合同: $orderNo');
|
||||
debugPrint('[ContractSigningService] 签名图片大小: ${signatureImage.length} bytes');
|
||||
debugPrint('[ContractSigningService] IP: $ipAddress, 设备: $deviceInfo');
|
||||
debugPrint('[ContractSigningService] 位置: lat=$latitude, lng=$longitude');
|
||||
|
||||
// 将签名图片转为 base64
|
||||
final signatureBase64 = base64Encode(signatureImage);
|
||||
debugPrint('[ContractSigningService] Base64 长度: ${signatureBase64.length}');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/contract-signing/tasks/$orderNo/sign',
|
||||
data: {
|
||||
final requestData = {
|
||||
'signatureImage': signatureBase64,
|
||||
'ipAddress': ipAddress,
|
||||
'deviceInfo': deviceInfo,
|
||||
'userAgent': userAgent,
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
},
|
||||
};
|
||||
debugPrint('[ContractSigningService] 请求 URL: /planting/contract-signing/tasks/$orderNo/sign');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/contract-signing/tasks/$orderNo/sign',
|
||||
data: requestData,
|
||||
);
|
||||
|
||||
debugPrint('[ContractSigningService] 响应状态码: ${response.statusCode}');
|
||||
debugPrint('[ContractSigningService] 响应数据: ${response.data}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 签署成功');
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['success'] == true && responseData['data'] != null) {
|
||||
final data = responseData['data'] as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 签署成功,任务状态: ${data['status']}');
|
||||
return ContractSigningTask.fromJson(data);
|
||||
}
|
||||
// 兼容直接返回任务数据的情况
|
||||
if (responseData['orderNo'] != null) {
|
||||
debugPrint('[ContractSigningService] 签署成功(直接返回数据)');
|
||||
return ContractSigningTask.fromJson(responseData);
|
||||
}
|
||||
throw Exception('签署合同失败: ${responseData['message'] ?? '响应格式错误'}');
|
||||
}
|
||||
|
||||
throw Exception('签署合同失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[ContractSigningService] 签署合同失败: $e');
|
||||
debugPrint('[ContractSigningService] 堆栈: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
@ -350,30 +398,50 @@ class ContractSigningService {
|
|||
}) async {
|
||||
try {
|
||||
debugPrint('[ContractSigningService] 补签合同: $orderNo');
|
||||
debugPrint('[ContractSigningService] 签名图片大小: ${signatureImage.length} bytes');
|
||||
debugPrint('[ContractSigningService] IP: $ipAddress, 设备: $deviceInfo');
|
||||
debugPrint('[ContractSigningService] 位置: lat=$latitude, lng=$longitude');
|
||||
|
||||
final signatureBase64 = base64Encode(signatureImage);
|
||||
debugPrint('[ContractSigningService] Base64 长度: ${signatureBase64.length}');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/contract-signing/tasks/$orderNo/late-sign',
|
||||
data: {
|
||||
final requestData = {
|
||||
'signatureImage': signatureBase64,
|
||||
'ipAddress': ipAddress,
|
||||
'deviceInfo': deviceInfo,
|
||||
'userAgent': userAgent,
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
},
|
||||
};
|
||||
debugPrint('[ContractSigningService] 请求 URL: /planting/contract-signing/tasks/$orderNo/late-sign');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/contract-signing/tasks/$orderNo/late-sign',
|
||||
data: requestData,
|
||||
);
|
||||
|
||||
debugPrint('[ContractSigningService] 响应状态码: ${response.statusCode}');
|
||||
debugPrint('[ContractSigningService] 响应数据: ${response.data}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 补签成功');
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
if (responseData['success'] == true && responseData['data'] != null) {
|
||||
final data = responseData['data'] as Map<String, dynamic>;
|
||||
debugPrint('[ContractSigningService] 补签成功,任务状态: ${data['status']}');
|
||||
return ContractSigningTask.fromJson(data);
|
||||
}
|
||||
// 兼容直接返回任务数据的情况
|
||||
if (responseData['orderNo'] != null) {
|
||||
debugPrint('[ContractSigningService] 补签成功(直接返回数据)');
|
||||
return ContractSigningTask.fromJson(responseData);
|
||||
}
|
||||
throw Exception('补签合同失败: ${responseData['message'] ?? '响应格式错误'}');
|
||||
}
|
||||
|
||||
throw Exception('补签合同失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[ContractSigningService] 补签合同失败: $e');
|
||||
debugPrint('[ContractSigningService] 堆栈: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import connectivity_plus
|
|||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import flutter_secure_storage_macos
|
||||
import geolocator_apple
|
||||
import local_auth_darwin
|
||||
import mobile_scanner
|
||||
import package_info_plus
|
||||
|
|
@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
|
||||
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <geolocator_windows/geolocator_windows.h>
|
||||
#include <local_auth_windows/local_auth_plugin.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
#include <sentry_flutter/sentry_flutter_plugin.h>
|
||||
|
|
@ -22,6 +23,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
GeolocatorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||
LocalAuthPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
connectivity_plus
|
||||
file_selector_windows
|
||||
flutter_secure_storage_windows
|
||||
geolocator_windows
|
||||
local_auth_windows
|
||||
permission_handler_windows
|
||||
sentry_flutter
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue