From 1bbcd451daacf6f16b5c47d447bc7d5cb17f50dd Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Wed, 4 Mar 2026 10:22:12 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=89=AB=E7=A0=81?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E7=9A=84cubit=E5=B1=82=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=89=AB=E7=A0=81=E4=BE=9D=E8=B5=96=E7=9A=84=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=92=8C=E6=9D=83=E9=99=90=E9=85=8D=E7=BD=AE=20=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E6=89=AB=E7=A0=81=E7=BB=91=E5=AE=9A=E8=AE=BE=E5=A4=87?= =?UTF-8?q?-=E5=88=9D=E6=AD=A5=E6=B5=8B=E8=AF=95=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E6=89=AB=E7=A0=81=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 4 + ios/Runner/Info.plist | 3 +- lib/core/di/injection.dart | 4 +- .../presentation/bloc/device_status_bloc.dart | 2 +- .../presentation/bloc/devices_cubit.dart | 39 +++++++++- .../my/presentation/pages/my_page.dart | 1 + .../web_view/user_info_pages.dart | 75 ++++++++++++++++++- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 8 ++ pubspec.yaml | 2 + 10 files changed, 134 insertions(+), 6 deletions(-) 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 From 3effece0f5f4bc07fb99942e6a3afdd10062f2dd Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Wed, 4 Mar 2026 10:28:26 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=89=AB=E7=A0=81=E7=BB=91=E5=AE=9A=E8=AE=BE=E5=A4=87=E7=9A=84?= =?UTF-8?q?=E9=BB=91=E5=B1=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/features/my/presentation/web_view/user_info_pages.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1927c817..a78d8891 100644 --- a/lib/features/my/presentation/web_view/user_info_pages.dart +++ b/lib/features/my/presentation/web_view/user_info_pages.dart @@ -66,7 +66,7 @@ class UserInfoCard extends StatelessWidget { if (code != null && code.isNotEmpty) { // 识别成功,立即返回结果并关闭页面 debugPrint('扫码成功,识别到的数据: $code'); - Navigator.pop(context, code); + // Navigator.pop(context, code); } } }, From 8ea6bace6a714fa1d2d64e6e75c0edc420be86c3 Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Wed, 4 Mar 2026 10:43:18 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=89=AB=E7=A0=81=E7=BB=91=E5=AE=9A=E8=AE=BE=E5=A4=87=E7=9A=84?= =?UTF-8?q?=E9=BB=91=E5=B1=8Fbug=20AI=E6=99=BA=E8=83=BD=E4=BD=93=E7=9A=84?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E7=9A=84=E5=8F=8B=E5=A5=BD=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/features/ai/presentation/bloc/ai_cubit.dart | 2 +- lib/features/ai/presentation/pages/ai_page.dart | 2 +- lib/features/my/presentation/web_view/user_info_pages.dart | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/features/ai/presentation/bloc/ai_cubit.dart b/lib/features/ai/presentation/bloc/ai_cubit.dart index bff6cd00..5fb7e71f 100644 --- a/lib/features/ai/presentation/bloc/ai_cubit.dart +++ b/lib/features/ai/presentation/bloc/ai_cubit.dart @@ -35,7 +35,7 @@ class AiCubit extends Cubit { void createNewSession() { emit(AiState( sessionId: DateTime.now().millisecondsSinceEpoch.toString(), - messages: [ChatMessage(text: "Welcome to the AI chat!", isUserMessage: false)], + messages: [ChatMessage(text: "快来和我一起探讨吧!", isUserMessage: false)], status: AiStatus.initial, selectedImageFile: null, // Explicitly set to null sessions: state.sessions, // Preserve existing sessions diff --git a/lib/features/ai/presentation/pages/ai_page.dart b/lib/features/ai/presentation/pages/ai_page.dart index 6452d19d..044011c4 100644 --- a/lib/features/ai/presentation/pages/ai_page.dart +++ b/lib/features/ai/presentation/pages/ai_page.dart @@ -238,7 +238,7 @@ class _AiViewState extends State { controller: _textController, enabled: state.status != AiStatus.loading, decoration: InputDecoration( - hintText: state.status == AiStatus.loading ? 'AI is thinking...' : 'Enter a message...', + hintText: state.status == AiStatus.loading ? 'AI正在思考中...' : '输入你的想法...', border: OutlineInputBorder( borderRadius: BorderRadius.circular(30.0), borderSide: const BorderSide(width: 0, style: BorderStyle.none), 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 a78d8891..184b07d3 100644 --- a/lib/features/my/presentation/web_view/user_info_pages.dart +++ b/lib/features/my/presentation/web_view/user_info_pages.dart @@ -88,10 +88,9 @@ class UserInfoCard extends StatelessWidget { try { // 5. 获取 Cubit 实例并调用绑定接口 - // 假设 AuthCubit 中已定义 bindDeviceByQr 方法 final Cubit = GetIt.I(); - // 执行绑定逻辑 (请确保 Cubit 层已实现此方法) + // 执行绑定逻辑 //await Cubit.bindDevice(qrCode); // 关闭加载框 From 027b71a4827580f92efd3395a63d95824607b7fd Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Wed, 4 Mar 2026 10:46:32 +0800 Subject: [PATCH 4/4] =?UTF-8?q?AI=E6=99=BA=E8=83=BD=E4=BD=93=E7=9A=84?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E6=96=B0=E7=9A=84=E4=BC=9A=E8=AF=9D=E5=92=8C?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E4=BC=9A=E8=AF=9D=E7=9A=84=E4=B8=AD=E6=96=87?= =?UTF-8?q?=E7=9A=84=E5=8F=8B=E5=A5=BD=E6=8F=90=E7=A4=BA=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/features/ai/presentation/pages/ai_page.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/features/ai/presentation/pages/ai_page.dart b/lib/features/ai/presentation/pages/ai_page.dart index 044011c4..a4fcdfa2 100644 --- a/lib/features/ai/presentation/pages/ai_page.dart +++ b/lib/features/ai/presentation/pages/ai_page.dart @@ -49,7 +49,7 @@ class _AiViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('AI'), + title: const Text('AI智能体'), actions: [ PopupMenuButton( onSelected: (value) { @@ -60,8 +60,8 @@ class _AiViewState extends State { } }, itemBuilder: (BuildContext context) => >[ - const PopupMenuItem(value: 'new_session', child: Text('New Session')), - const PopupMenuItem(value: 'history', child: Text('History')), + const PopupMenuItem(value: 'new_session', child: Text('开启新的会话')), + const PopupMenuItem(value: 'history', child: Text('历史会话')), ], ), ],