diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 67dc4a4f..f282b750 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -12,6 +12,10 @@
+
+
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 49eff797..c51b485c 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -49,7 +49,8 @@
需要访问您的位置以显示地图
NSCameraUsageDescription
- 需要访问相机以扫描二维码
+ 我们需要访问您的摄像头以扫描二维码绑定设备
+
diff --git a/lib/core/di/injection.dart b/lib/core/di/injection.dart
index e014f110..85a19f28 100644
--- a/lib/core/di/injection.dart
+++ b/lib/core/di/injection.dart
@@ -35,6 +35,7 @@ import '../../features/devices/data/repositories/route_planning_repository_impl.
import '../../features/devices/domain/repositories/device_hostrity_work_repository.dart';
import '../../features/devices/domain/repositories/path_repository.dart';
import '../../features/devices/domain/repositories/route_planning_repository.dart';
+import '../../features/devices/domain/usecases/bind_device_usecase.dart';
import '../../features/devices/domain/usecases/delete_work_record_usecase.dart';
import '../../features/devices/domain/usecases/device_work_hostrirty_usecase.dart';
import '../../features/devices/domain/usecases/generate_path_usecase.dart';
@@ -130,6 +131,7 @@ Future init() async {
sl.registerLazySingleton(() => DeviceWorkHostrirty(sl()));
sl.registerLazySingleton(() => SelectWorkRecordUseCase(sl()));
sl.registerLazySingleton(() => UnbindDeviceUseCase(sl()));
+ sl.registerLazySingleton(() => BindDeviceUseCase(sl()));
sl.registerLazySingleton(() => UpdateDevicenameUsecase(sl()));
sl.registerLazySingleton(() => SaveWorkRecordUseCase(sl()));
sl.registerLazySingleton(() => SwitchDeviceUseCase(sl()));
@@ -148,7 +150,7 @@ Future init() async {
sl.registerLazySingleton(() => AppUserCubit()); // AuthCubit 依赖它,必须先注册
sl.registerLazySingleton(() => GetDeviceLocationUseCase(sl()));
sl.registerLazySingleton(
- () => DevicesCubit(sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(),sl(),sl()),
+ () => DevicesCubit(sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(),sl(),sl(), sl()),
);
sl.registerFactory(() => RemoteControlCubit(sl()));
/* // 工厂模式(留存,每次获取新实例)
diff --git a/lib/features/devices/presentation/bloc/device_status_bloc.dart b/lib/features/devices/presentation/bloc/device_status_bloc.dart
index b78b0b13..2ad34136 100644
--- a/lib/features/devices/presentation/bloc/device_status_bloc.dart
+++ b/lib/features/devices/presentation/bloc/device_status_bloc.dart
@@ -30,7 +30,7 @@ class DeviceStatusBloc extends Bloc {
// 🔥 新增:模拟测试数据(调试用)
- _testMockData();
+ // _testMockData();
}
void _testMockData() {
// 用户提供的真实指令数据(字节数组)
diff --git a/lib/features/devices/presentation/bloc/devices_cubit.dart b/lib/features/devices/presentation/bloc/devices_cubit.dart
index dee10ce7..96482e2b 100644
--- a/lib/features/devices/presentation/bloc/devices_cubit.dart
+++ b/lib/features/devices/presentation/bloc/devices_cubit.dart
@@ -13,6 +13,7 @@ import 'package:maibu_satabot_v2/features/devices/domain/usecases/update_devicen
import '../../data/models/device_add_path_point_model.dart';
import '../../data/models/device_work_area_param_model.dart';
+import '../../domain/usecases/bind_device_usecase.dart';
import '../../domain/usecases/delete_work_record_usecase.dart';
import '../../domain/usecases/get_device_location_usecase.dart';
import '../../domain/usecases/get_work_record_usecase.dart';
@@ -25,6 +26,7 @@ class DevicesCubit extends Cubit {
final DeviceRepository repository;
final GetWorkRecordUseCase _getWorkRecordUseCase;
final DeleteWorkRecordUseCase _deleteWorkRecordUseCase;
+ final BindDeviceUseCase _bindDeviceUseCase;
final UnbindDeviceUseCase _unbindDeviceUseCase;
final UpdateDevicenameUsecase _updateDevicename;
final SelectWorkRecordUseCase _selectWorkRecordUseCase;
@@ -43,7 +45,7 @@ class DevicesCubit extends Cubit {
this._selectWorkRecordUseCase,
this._saveWorkRecordUseCase,
this._generatePathUseCase,
- this._routePlanningUseCase
+ this._routePlanningUseCase, this._bindDeviceUseCase
) : super(const DevicesState());
Future unbindDevice(String deviceId, String deviceName) async {
@@ -176,6 +178,41 @@ class DevicesCubit extends Cubit {
selectDevice(device);
}, (r) => emit(state.copyWith(isLoading: false, selectedDevice: device)));
}
+ /// 绑定设备
+ Future 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 ?? '绑定设备失败',
+ )),
+ // 成功处理(返回 int 状态码)
+ (successCode) {
+ if (successCode == 1) {
+ emit(state.copyWith(isLoading: false, errorMessage: ''));
+ // 绑定成功后刷新设备列表
+ //fetchAllDevices(state.?.username ?? '');
+ } else {
+ emit(state.copyWith(
+ isLoading: false,
+ errorMessage: '绑定失败:状态码 $successCode',
+ ));
+ }
+ },
+ );
+ } catch (e) {
+ emit(state.copyWith(
+ isLoading: false,
+ errorMessage: '绑定异常:${e.toString()}',
+ ));
+ }
+ }
+
+
/// 获取设备位置
Future getDeviceLocation(DeviceEntity device) async {
diff --git a/lib/features/my/presentation/pages/my_page.dart b/lib/features/my/presentation/pages/my_page.dart
index a515434d..de81b3dc 100644
--- a/lib/features/my/presentation/pages/my_page.dart
+++ b/lib/features/my/presentation/pages/my_page.dart
@@ -10,6 +10,7 @@ import '../../../auth/presentation/bloc/auth_state.dart';
import '../../../auth/presentation/pages/login_page.dart';
import '../../../web_view/web_view_page.dart';
import '../web_view/user_info_pages.dart';
+import 'package:mobile_scanner/mobile_scanner.dart';
class MyPage extends StatelessWidget {
const MyPage({super.key});
diff --git a/lib/features/my/presentation/web_view/user_info_pages.dart b/lib/features/my/presentation/web_view/user_info_pages.dart
index de7a44a5..1927c817 100644
--- a/lib/features/my/presentation/web_view/user_info_pages.dart
+++ b/lib/features/my/presentation/web_view/user_info_pages.dart
@@ -1,5 +1,10 @@
// user_info_card.dart
import 'package:flutter/material.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';
class UserInfoCard extends StatelessWidget {
final String userName;
@@ -28,7 +33,7 @@ class UserInfoCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(userName, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
- Text('用户id:$userId', style: TextStyle(fontSize: 12, color: Colors.grey)),
+ Text('用户 id:$userId', style: TextStyle(fontSize: 12, color: Colors.grey)),
],
),
),
@@ -39,9 +44,75 @@ class UserInfoCard extends StatelessWidget {
Spacer(),
IconButton(
icon: Icon(Icons.add),
- onPressed: () {},
+ // 3. 绑定点击事件
+ onPressed: () => _handleScanAndBind(context),
),
],
);
}
+
+ // 4. 定义扫码与绑定逻辑
+ Future _handleScanAndBind(BuildContext context) async {
+ // 跳转到扫码页面
+ final String? qrCode = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => MobileScanner(
+ onDetect: (capture) {
+ final List 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);
+ }
+ }
+ },
+ ),
+ ),
+ );
+
+ // 如果用户取消或未扫到码,直接返回
+ if (qrCode == null || qrCode.isEmpty) {
+ return;
+ }
+
+ // 显示加载对话框
+ showDialog(
+ context: context,
+ barrierDismissible: false,
+ builder: (context) => Center(child: CircularProgressIndicator()),
+ );
+
+ try {
+ // 5. 获取 Cubit 实例并调用绑定接口
+ // 假设 AuthCubit 中已定义 bindDeviceByQr 方法
+ final Cubit = GetIt.I();
+
+ // 执行绑定逻辑 (请确保 Cubit 层已实现此方法)
+ //await Cubit.bindDevice(qrCode);
+
+ // 关闭加载框
+ if (context.mounted) Navigator.pop(context);
+
+ // 成功提示
+ if (context.mounted) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green),
+ );
+ }
+ } catch (e) {
+ // 关闭加载框
+ if (context.mounted) Navigator.pop(context);
+
+ // 失败提示
+ if (context.mounted) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text('绑定失败:$e'), backgroundColor: Colors.red),
+ );
+ }
+ }
+ }
}
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index 291d5749..bf451370 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -10,6 +10,7 @@ import file_selector_macos
import flutter_webrtc
import geolocator_apple
import isar_community_flutter_libs
+import mobile_scanner
import package_info_plus
import sentry_flutter
import shared_preferences_foundation
@@ -21,6 +22,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))
+ MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
diff --git a/pubspec.lock b/pubspec.lock
index 6d50973f..7d8e3187 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -799,6 +799,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
+ mobile_scanner:
+ dependency: "direct dev"
+ description:
+ name: mobile_scanner
+ sha256: "1b60b8f9d4ce0cb0e7d7bc223c955d083a0737bee66fa1fcfe5de48225e0d5b3"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.5.7"
native_toolchain_c:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 0c7a5fdb..96c3df36 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -140,6 +140,8 @@ dev_dependencies:
flutter_launcher_icons: ^0.13.1
+ mobile_scanner: ^3.4.1 # 请根据实际需求选择最新版本
+
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec