完成扫码绑定设备-初步测试正确完成
This commit is contained in:
@@ -26,17 +26,43 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource {
|
||||
|
||||
@override
|
||||
Future<int> bindDevice(String deviceId, String deviceAlias) async {
|
||||
final logger = GetIt.I<ILoggerService>() as SentryLoggerImpl;
|
||||
logger.logWithLevel('用户点击bindDevice方法开始触发', level: 'INFO');
|
||||
logger.logWithLevel(
|
||||
'用户点击bindDevice方法API 请求开始',
|
||||
level: 'INFO',
|
||||
data: {'url': 'https://serviceri.satabot.com/iot/device/bindDevice'}
|
||||
);
|
||||
var response = await dio.post(
|
||||
HttpApiConsts.bindDevice,
|
||||
data: {'deviceId': deviceId, 'deviceAlias': deviceAlias},
|
||||
);
|
||||
logger.logWithLevel(
|
||||
'请求详细参数',
|
||||
level: 'DEBUG',
|
||||
data: {
|
||||
'url': 'https://serviceri.satabot.com/iot/device/bindDevice',
|
||||
'deviceId': deviceId,
|
||||
'deviceAlias': deviceAlias
|
||||
}
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
logger.logWithLevel(
|
||||
'API 响应失败',
|
||||
level: 'ERROR',
|
||||
data: {'statusCode': response.statusCode, 'data': response.data}
|
||||
);
|
||||
throw Exception('网络请求失败:${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseData = response.data;
|
||||
|
||||
if (responseData['code'] != 200 || responseData['data'] != true) {
|
||||
logger.logWithLevel(
|
||||
'API 响应失败',
|
||||
level: 'ERROR',
|
||||
data: {'statusCode': response.statusCode, 'data': response.data}
|
||||
);
|
||||
throw Exception(responseData['msg'] ?? '业务异常');
|
||||
}
|
||||
|
||||
|
||||
@@ -180,16 +180,21 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
}
|
||||
/// 绑定设备
|
||||
Future<void> bindDevice(String deviceId, String deviceAlias) async {
|
||||
|
||||
emit(state.copyWith(isLoading: true, errorMessage: ''));
|
||||
try {
|
||||
final params = BindDeviceParams(deviceId, deviceAlias);
|
||||
final result = await _bindDeviceUseCase.call(params);
|
||||
result.fold(
|
||||
// 失败处理
|
||||
(failure) => emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: failure.message ?? '绑定设备失败',
|
||||
)),
|
||||
(failure) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: failure.message ?? '绑定设备失败',
|
||||
));
|
||||
// 抛出异常,携带后端返回的错误消息(如“设备不存在”)
|
||||
throw Exception(failure.message ?? '绑定设备失败');
|
||||
},
|
||||
// 成功处理(返回 int 状态码)
|
||||
(successCode) {
|
||||
if (successCode == 1) {
|
||||
@@ -201,14 +206,17 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
isLoading: false,
|
||||
errorMessage: '绑定失败:状态码 $successCode',
|
||||
));
|
||||
throw Exception('绑定失败:状态码 $successCode');
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '绑定异常:${e.toString()}',
|
||||
));
|
||||
// emit(state.copyWith(
|
||||
// isLoading: false,
|
||||
// errorMessage: '绑定异常:${e.toString()}',
|
||||
// ));
|
||||
// 🔥 重新抛出,传递给 UI
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// user_info_card.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart'; // 1. 导入扫码库
|
||||
import 'package:get_it/get_it.dart'; // 用于获取 Cubit 实例
|
||||
// 2. 导入你的 Cubit 文件,请根据实际路径调整
|
||||
import '../../../auth/presentation/bloc/auth_cubit.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
// 其他导入保持不变...
|
||||
|
||||
class UserInfoCard extends StatelessWidget {
|
||||
final String userName;
|
||||
@@ -27,91 +26,157 @@ class UserInfoCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(userName, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
Text('用户 id:$userId', style: TextStyle(fontSize: 12, color: Colors.grey)),
|
||||
Text(userName, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
Text('用户 id:$userId', style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () {},
|
||||
),
|
||||
Spacer(),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
icon: Icon(Icons.add),
|
||||
// 3. 绑定点击事件
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () => _handleScanAndBind(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// 4. 定义扫码与绑定逻辑
|
||||
Future<void> _handleScanAndBind(BuildContext context) async {
|
||||
// 跳转到扫码页面
|
||||
final String? qrCode = await Navigator.push<String>(
|
||||
bool isScanned = false;
|
||||
|
||||
// 1. 扫码逻辑 (保持不变)
|
||||
final String? deviceCode = await Navigator.push<String>(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MobileScanner(
|
||||
onDetect: (capture) {
|
||||
final List<Barcode> barcodes = capture.barcodes;
|
||||
if (barcodes.isNotEmpty) {
|
||||
debugPrint('识别到的数据: $barcodes');
|
||||
final String? code = barcodes.first.rawValue;
|
||||
if (code != null && code.isNotEmpty) {
|
||||
// 识别成功,立即返回结果并关闭页面
|
||||
debugPrint('扫码成功,识别到的数据: $code');
|
||||
// Navigator.pop(context, code);
|
||||
builder: (context) => Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: AppBar(
|
||||
title: const Text('扫码绑定设备'),
|
||||
backgroundColor: Colors.black54,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
body: MobileScanner(
|
||||
onDetect: (BarcodeCapture capture) {
|
||||
if (isScanned) return;
|
||||
final List<Barcode> barcodes = capture.barcodes;
|
||||
if (barcodes.isNotEmpty) {
|
||||
final String? code = barcodes.first.rawValue;
|
||||
if (code != null && code.isNotEmpty) {
|
||||
isScanned = true;
|
||||
// 使用 addPostFrameCallback 确保在帧渲染后执行,避免锁死
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (context.mounted && Navigator.canPop(context)) {
|
||||
Navigator.pop(context, code);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// 如果用户取消或未扫到码,直接返回
|
||||
if (qrCode == null || qrCode.isEmpty) {
|
||||
if (deviceCode == null || deviceCode.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载对话框
|
||||
// 2. 确认对话框 (保持不变)
|
||||
final bool? confirmBind = await showDialog<bool>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('确认绑定设备'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('设备信息:'),
|
||||
const SizedBox(height: 8),
|
||||
Text('设备编码:$deviceCode'),
|
||||
const Text('设备状态:未绑定'),
|
||||
const Text('设备类型:智能设备'),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
child: const Text('取消'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text('确定绑定'),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirmBind != true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 显示加载框
|
||||
// 保存 BuildContext 引用,防止后续 context 变化导致找不到正确的 Navigator
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Center(child: CircularProgressIndicator()),
|
||||
builder: (loadingContext) => const Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
|
||||
try {
|
||||
// 5. 获取 Cubit 实例并调用绑定接口
|
||||
final Cubit = GetIt.I<DevicesCubit>();
|
||||
final devicesCubit = GetIt.I<DevicesCubit>();
|
||||
await devicesCubit.bindDevice(deviceCode, '');
|
||||
|
||||
// 执行绑定逻辑
|
||||
//await Cubit.bindDevice(qrCode);
|
||||
|
||||
// 关闭加载框
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
|
||||
// 成功提示
|
||||
if (context.mounted) {
|
||||
// ✅ 成功:安全关闭加载框
|
||||
if (context.mounted && Navigator.canPop(context)) {
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green),
|
||||
const SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// 关闭加载框
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
// ✅ 失败:安全关闭加载框 (关键修复点)
|
||||
// 即使发生了 Framework 错误,也要尝试关闭弹窗
|
||||
if (context.mounted && Navigator.canPop(context)) {
|
||||
Navigator.pop(context);
|
||||
|
||||
// 失败提示
|
||||
if (context.mounted) {
|
||||
// 显示具体错误信息
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('绑定失败:$e'), backgroundColor: Colors.red),
|
||||
SnackBar(
|
||||
content: Text('绑定失败:${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
duration: const Duration(seconds: 4),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// 极端情况:如果 Navigator 已经锁死无法 pop,尝试用其他方式提示用户
|
||||
// 或者等待下一帧再试
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (context.mounted) {
|
||||
// 尝试再次关闭,或者只显示错误提示
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('绑定失败:${e.toString()} (请手动返回)'),
|
||||
backgroundColor: Colors.orange,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
debugPrint('设备绑定失败详情:$e');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -811,10 +811,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobile_scanner
|
||||
sha256: "1b60b8f9d4ce0cb0e7d7bc223c955d083a0737bee66fa1fcfe5de48225e0d5b3"
|
||||
sha256: "827765afbd4792ff3fd105ad593821ac0f6d8a7d352689013b07ee85be336312"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.5.7"
|
||||
version: "4.0.1"
|
||||
native_toolchain_c:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -143,7 +143,7 @@ dev_dependencies:
|
||||
|
||||
flutter_launcher_icons: ^0.13.1
|
||||
|
||||
mobile_scanner: ^3.4.1 # 请根据实际需求选择最新版本
|
||||
mobile_scanner: ^4.0.1 # 升级到最新稳定版
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
Reference in New Issue
Block a user