Merge branch 'feature/my' of http://1.95.137.212:57001/APP/FlutterApp into feature/my

This commit is contained in:
mmc
2026-03-04 14:56:25 +08:00
12 changed files with 138 additions and 11 deletions

View File

@@ -12,6 +12,10 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <!-- 关键! -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 如果还需要扫描闪光灯控制,可选添加 -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />

View File

@@ -49,7 +49,8 @@
<string>需要访问您的位置以显示地图</string>
<key>NSCameraUsageDescription</key>
<string>需要访问相机以扫描二维码</string>
<string>我们需要访问您的摄像头以扫描二维码绑定设备</string>
</dict>
</plist>

View File

@@ -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<void> init() async {
sl.registerLazySingleton(() => DeviceWorkHostrirty(sl()));
sl.registerLazySingleton<SelectWorkRecordUseCase>(() => SelectWorkRecordUseCase(sl<PathRepository>()));
sl.registerLazySingleton(() => UnbindDeviceUseCase(sl()));
sl.registerLazySingleton(() => BindDeviceUseCase(sl()));
sl.registerLazySingleton(() => UpdateDevicenameUsecase(sl()));
sl.registerLazySingleton<SaveWorkRecordUseCase>(() => SaveWorkRecordUseCase(sl<PathRepository>()));
sl.registerLazySingleton<SwitchDeviceUseCase>(() => SwitchDeviceUseCase(sl()));
@@ -148,7 +150,7 @@ Future<void> 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()));
/* // 工厂模式(留存,每次获取新实例)

View File

@@ -35,7 +35,7 @@ class AiCubit extends Cubit<AiState> {
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

View File

@@ -49,7 +49,7 @@ class _AiViewState extends State<AiView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AI'),
title: const Text('AI智能体'),
actions: [
PopupMenuButton<String>(
onSelected: (value) {
@@ -60,8 +60,8 @@ class _AiViewState extends State<AiView> {
}
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
const PopupMenuItem<String>(value: 'new_session', child: Text('New Session')),
const PopupMenuItem<String>(value: 'history', child: Text('History')),
const PopupMenuItem<String>(value: 'new_session', child: Text('开启新的会话')),
const PopupMenuItem<String>(value: 'history', child: Text('历史会话')),
],
),
],
@@ -238,7 +238,7 @@ class _AiViewState extends State<AiView> {
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),

View File

@@ -30,7 +30,7 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
// 🔥 新增:模拟测试数据(调试用)
_testMockData();
// _testMockData();
}
void _testMockData() {
// 用户提供的真实指令数据(字节数组)

View File

@@ -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<DevicesState> {
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<DevicesState> {
this._selectWorkRecordUseCase,
this._saveWorkRecordUseCase,
this._generatePathUseCase,
this._routePlanningUseCase
this._routePlanningUseCase, this._bindDeviceUseCase
) : super(const DevicesState());
Future<void> unbindDevice(String deviceId, String deviceName) async {
@@ -176,6 +178,41 @@ class DevicesCubit extends Cubit<DevicesState> {
selectDevice(device);
}, (r) => emit(state.copyWith(isLoading: false, selectedDevice: device)));
}
/// 绑定设备
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 ?? '绑定设备失败',
)),
// 成功处理(返回 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<void> getDeviceLocation(DeviceEntity device) async {

View File

@@ -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});

View File

@@ -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,74 @@ class UserInfoCard extends StatelessWidget {
Spacer(),
IconButton(
icon: Icon(Icons.add),
onPressed: () {},
// 3. 绑定点击事件
onPressed: () => _handleScanAndBind(context),
),
],
);
}
// 4. 定义扫码与绑定逻辑
Future<void> _handleScanAndBind(BuildContext context) async {
// 跳转到扫码页面
final String? qrCode = 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);
}
}
},
),
),
);
// 如果用户取消或未扫到码,直接返回
if (qrCode == null || qrCode.isEmpty) {
return;
}
// 显示加载对话框
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => Center(child: CircularProgressIndicator()),
);
try {
// 5. 获取 Cubit 实例并调用绑定接口
final Cubit = GetIt.I<DevicesCubit>();
// 执行绑定逻辑
//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),
);
}
}
}
}

View File

@@ -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"))

View File

@@ -807,6 +807,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:

View File

@@ -143,6 +143,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