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('历史会话')),
],
),
],