From b97d7006b34adc52e1d28bbaaca26c3abdcfd5c8 Mon Sep 17 00:00:00 2001 From: sky_min Date: Wed, 19 Nov 2025 12:00:25 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BC=98=E5=8C=96=E6=B3=A8=E5=86=8C=E5=88=87?= =?UTF-8?q?=E5=87=BA=E5=8E=BB=E5=86=8D=E5=9B=9E=E6=9D=A5=E9=97=AE=E9=A2=98?= =?UTF-8?q?=202.=E8=A7=86=E9=A2=91=E5=AF=B9=E8=AE=B2=E4=BC=98=E5=8C=96=203?= =?UTF-8?q?.=E5=9B=BE=E4=BC=A0-=E8=A7=86=E9=A2=91=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E5=88=87=E5=87=BA=E5=8E=BB=E5=86=8D=E5=9B=9E=E6=9D=A5=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=8E=A5=E5=90=AC=204.=E4=BC=98=E5=8C=96=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E5=BC=80=E9=94=81--=E4=BD=BF=E7=94=A8=E8=93=9D?= =?UTF-8?q?=E7=89=99=E9=80=8F=E4=BC=A0--=E5=88=A4=E6=96=AD=E8=93=9D?= =?UTF-8?q?=E7=89=99=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/login/login/starLock_login_page.dart | 9 +- .../register/starLock_register_logic.dart | 30 ++- .../register/starLock_register_page.dart | 10 + .../lockDetail/lockDetail_logic.dart | 189 ++++++++++++++++++ lib/talk/starChart/star_chart_manage.dart | 36 +++- .../status/appLifecycle_observer.dart | 5 +- 6 files changed, 262 insertions(+), 17 deletions(-) diff --git a/lib/login/login/starLock_login_page.dart b/lib/login/login/starLock_login_page.dart index 22ac6540..dcee7e22 100755 --- a/lib/login/login/starLock_login_page.dart +++ b/lib/login/login/starLock_login_page.dart @@ -1,13 +1,8 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:star_lock/flavors.dart'; import 'package:star_lock/login/login/starLock_login_state.dart'; -import 'package:star_lock/talk/starChart/handle/impl/udp_talk_ping_handler.dart'; -import 'package:star_lock/talk/starChart/star_chart_manage.dart'; import 'package:star_lock/tools/appFirstEnterHandle.dart'; import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/wechat/customer_tool.dart'; @@ -16,7 +11,6 @@ import '../../appRouters.dart'; import '../../app_settings/app_colors.dart'; import '../../common/XSConstantMacro/XSConstantMacro.dart'; import '../../tools/commonItem.dart'; -import '../../tools/jverify_one_click_login.dart'; import '../../tools/submitBtn.dart'; import '../../tools/tf_loginInput.dart'; import '../../tools/titleAppBar.dart'; @@ -193,6 +187,7 @@ class _StarLockLoginPageState extends State { inputFormatters: [ LengthLimitingTextInputFormatter(20), ]), + _agreentWidget(), SizedBox(height: 50.w), Obx(() => SubmitBtn( btnName: '登录'.tr, @@ -234,7 +229,7 @@ class _StarLockLoginPageState extends State { Widget _agreentWidget() { return Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ Obx(() => GestureDetector( onTap: () { diff --git a/lib/login/register/starLock_register_logic.dart b/lib/login/register/starLock_register_logic.dart index ff7cc21a..31338062 100755 --- a/lib/login/register/starLock_register_logic.dart +++ b/lib/login/register/starLock_register_logic.dart @@ -25,10 +25,10 @@ import 'starLock_register_state.dart'; class StarLockRegisterLogic extends BaseGetXController { final StarLockRegisterState state = StarLockRegisterState(); - late Timer _timer; + Timer? _timer; void _startTimer() { - _timer = Timer.periodic(1.seconds, (Timer timer) { + _timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { if (state.currentSecond > 1) { state.currentSecond--; } else { @@ -40,7 +40,8 @@ class StarLockRegisterLogic extends BaseGetXController { } void _cancelTimer() { - _timer.cancel(); + _timer?.cancel(); + _timer = null; // _timer = null; } @@ -162,4 +163,27 @@ class StarLockRegisterLogic extends BaseGetXController { await checkIpAction(); } + + void clearInputData() { + // 清除手机号/邮箱输入框 + state.phoneOrEmailController.clear(); + state.phoneOrEmailStr.value = ''; + + // 清除密码输入框 + state.pwdController.clear(); + state.pwd.value = ''; + + // 清除确认密码输入框 + state.sureController.clear(); + state.surePwd.value = ''; + + // 清除验证码输入框 + state.codeController.clear(); + state.verificationCode.value = ''; + + // 安全地重置验证码倒计时 + _cancelTimer(); + state.currentSecond = state.totalSeconds; + state.resetResend(); + } } diff --git a/lib/login/register/starLock_register_page.dart b/lib/login/register/starLock_register_page.dart index 10980ed2..b81ac86e 100755 --- a/lib/login/register/starLock_register_page.dart +++ b/lib/login/register/starLock_register_page.dart @@ -89,7 +89,12 @@ class _StarLockRegisterPageState extends State { children: [ GestureDetector( onTap: () { + // 切换到手机号输入前先清除数据 + if (!state.isIphoneType.value) { + logic.clearInputData(); + } state.isIphoneType.value = true; + FocusScope.of(context).unfocus(); }, child: Obx( () => Container( @@ -113,6 +118,11 @@ class _StarLockRegisterPageState extends State { Expanded( child: GestureDetector( onTap: () { + // 切换到邮箱输入前先清除数据 + if (state.isIphoneType.value) { + logic.clearInputData(); + FocusScope.of(context).unfocus(); + } state.isIphoneType.value = false; }, child: Obx( diff --git a/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index 7d62d6bc..cb5c3072 100755 --- a/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -696,6 +696,18 @@ class LockDetailLogic extends BaseGetXController { final lockPeerId = StartChartManage().lockPeerId; final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData(); + + //检查蓝牙连接状态 + final connectedDevices = await FlutterBluePlus.connectedDevices; + final isDeviceConnected = connectedDevices.any((device) => + device.remoteId.str == BlueManage().connectDeviceName); + + if (!isDeviceConnected) { + AppLog.log('蓝牙已断开,尝试重新连接'); + // 蓝牙断开,需要重新连接并获取新的token + await _reconnectAndRefreshToken(); + } + if (lockListInfoGroupEntity != null) { lockListInfoGroupEntity!.groupList?.forEach((element) { final lockList = element.lockList; @@ -712,7 +724,11 @@ class LockDetailLogic extends BaseGetXController { } }); } + if (remoteUnlock == 1) { + // 发送蓝牙透传开锁 + await _sendUnlockViaBluetooth(); + // 发送远程开锁api final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60); if (entity.errorCode!.codeIsSuccessful) { showToast('已开锁'.tr); @@ -721,6 +737,179 @@ class LockDetailLogic extends BaseGetXController { } } + // 新增方法:通过蓝牙透传发送开锁命令 + Future _sendUnlockViaBluetooth() async { + try { + // 获取必要的密钥信息 + final List? privateKey = await Storage.getStringList(saveBluePrivateKey); + final List privateKeyList = changeStringListToIntList(privateKey!); + + final List? signKey = await Storage.getStringList(saveBlueSignKey); + final List signKeyList = changeStringListToIntList(signKey!); + + final List? token = await Storage.getStringList(saveBlueToken); + final List tokenList = changeStringListToIntList(token!); + + // 构建开锁命令 + final OpenLockCommand openLockCommand = OpenLockCommand( + lockID: BlueManage().connectDeviceName, + userID: await Storage.getUid(), + openMode: state.openDoorModel, + openTime: getUTCNetTime(), + onlineToken: state.lockNetToken, + token: tokenList, + needAuthor: 1, + signKey: signKeyList, + privateKey: privateKeyList, + ); + + // 包装命令数据 + final List messageDetail = openLockCommand.packageData(); + + // 通过蓝牙透传发送开锁命令 + StartChartManage().sendRemoteUnLockMessage( + bluetoothDeviceName: BlueManage().connectDeviceName, + openLockCommand: messageDetail, + ); + + AppLog.log('通过蓝牙透传发送远程开锁命令'); + + // 监听开锁结果,处理token不一致的情况 + _listenForOpenLockReply(tokenList); + } catch (e) { + AppLog.log('蓝牙透传开锁异常: $e'); + showToast('蓝牙透传开锁失败'.tr); + } + } + + // 监听开锁回复,处理token验证 + void _listenForOpenLockReply(List originalToken) { + StreamSubscription? subscription; + // 设置监听器处理开锁回复 + subscription = EventBusManager().eventBus!.on().listen((Reply reply) async { + if (reply is OpenDoorReply) { + final int status = reply.data[6]; + + // 如果是token不一致的情况(状态码0x06) + if (status == 0x06) { + AppLog.log('token不一致,使用新token重新开锁'); + + // 提取新的token + final List newToken = reply.data.sublist(2, 6); + + // 保存新token到存储 + final List saveStrList = changeIntListToStringList(newToken); + Storage.setStringList(saveBlueToken, saveStrList); + + // 使用新token重新发送开锁命令 + await _reSendUnlockWithNewToken(newToken); + } + + // 取消监听 + subscription?.cancel(); + } + }); + + // 设置超时机制,避免监听器一直存在 + Timer(const Duration(seconds: 10), () { + subscription?.cancel(); + }); + } + + // 使用新token重新发送开锁命令 + Future _reSendUnlockWithNewToken(List newToken) async { + try { + // 获取必要的密钥信息 + final List? privateKey = await Storage.getStringList(saveBluePrivateKey); + final List privateKeyList = changeStringListToIntList(privateKey!); + + final List? signKey = await Storage.getStringList(saveBlueSignKey); + final List signKeyList = changeStringListToIntList(signKey!); + + // 构建新的开锁命令 + final OpenLockCommand openLockCommand = OpenLockCommand( + lockID: BlueManage().connectDeviceName, + userID: await Storage.getUid(), + openMode: state.openDoorModel, + openTime: getUTCNetTime(), + onlineToken: state.lockNetToken, + token: newToken, + needAuthor: 1, + signKey: signKeyList, + privateKey: privateKeyList, + ); + + // 包装命令数据 + final List messageDetail = openLockCommand.packageData(); + + // 通过蓝牙透传发送开锁命令 + StartChartManage().sendRemoteUnLockMessage( + bluetoothDeviceName: BlueManage().connectDeviceName, + openLockCommand: messageDetail, + ); + + AppLog.log('使用新token重新发送开锁命令'); + } catch (e) { + AppLog.log('使用新token重新开锁异常: $e'); + showToast('重新开锁失败'.tr); + } + } + + // 新增方法:重新连接蓝牙并刷新token + Future _reconnectAndRefreshToken() async { + try { + // 重新连接蓝牙 + await BlueManage().blueSendData( + state.keyInfos.value.bluetooth!.bluetoothDeviceName!, + (BluetoothConnectionState deviceConnectionState) async { + if (deviceConnectionState == BluetoothConnectionState.connected) { + AppLog.log('蓝牙重新连接成功'); + // 获取新的token + await _refreshLockToken(); + } else if (deviceConnectionState == BluetoothConnectionState.disconnected) { + AppLog.log('蓝牙重新连接失败'); + showToast('蓝牙连接失败,请重试'.tr); + } + }, + ); + } catch (e) { + AppLog.log('蓝牙重连异常: $e'); + showToast('蓝牙连接异常,请重试'.tr); + } + } + + // 新增方法:刷新锁token + Future _refreshLockToken() async { + try { + final List? token = await Storage.getStringList(saveBlueToken); + final List tokenList = changeStringListToIntList(token!); + + final List? privateKey = await Storage.getStringList(saveBluePrivateKey); + final List privateKeyList = changeStringListToIntList(privateKey!); + + final List? signKey = await Storage.getStringList(saveBlueSignKey); + final List signKeyList = changeStringListToIntList(signKey!); + + // 发送获取新token的命令 + IoSenderManage.senderOpenLock( + lockID: BlueManage().connectDeviceName, + userID: await Storage.getUid(), + openMode: state.openDoorModel, + openTime: getUTCNetTime(), + onlineToken: state.lockNetToken, + token: tokenList, + needAuthor: 1, + signKey: signKeyList, + privateKey: privateKeyList, + ); + + // 等待一段时间让token更新完成 + await Future.delayed(Duration(milliseconds: 500)); + } catch (e) { + AppLog.log('刷新token异常: $e'); + } + } + /// 锁设置里面开启关闭考勤刷新锁详情 void initLockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceAction() { // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus diff --git a/lib/talk/starChart/star_chart_manage.dart b/lib/talk/starChart/star_chart_manage.dart index 057363b6..555f90f5 100644 --- a/lib/talk/starChart/star_chart_manage.dart +++ b/lib/talk/starChart/star_chart_manage.dart @@ -161,6 +161,18 @@ class StartChartManage { await reportInformation(); } + // 优化连接建立 + Future establishConnection({required String ToPeerId}) async { + // 提前预加载必要资源 + await init(); // 确保基础服务已初始化 + + // 并行执行地址交换和打洞 + await Future.wait([ + startSendingRbcuInfoMessages(ToPeerId: ToPeerId), + startSendingRbcuProbeTMessages(), + ] as Iterable); + } + /// 客户端注册 Future _clientRegister(LoginData? loginData) async { if (loginData?.starchart?.starchartId != null) { @@ -457,7 +469,7 @@ class StartChartManage { // 启动定时器持续发送对讲请求 talkRequestTimer ??= Timer.periodic( Duration( - seconds: _defaultIntervalTime, + milliseconds: 500, ), (Timer timer) async { AppLog.log('发送对讲请求:${ToPeerId}'); @@ -719,7 +731,14 @@ class StartChartManage { FromPeerId: FromPeerId, MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true), ); - await _sendMessage(message: message); + try { + await _sendMessage(message: message); + } catch (e) { + // 记录日志但不中断程序执行 + AppLog.log('发送挂断消息失败: $e'); + // 不抛出异常,避免应用崩溃 + } + } // 发送通话中挂断消息 @@ -800,9 +819,16 @@ class StartChartManage { // 发送消息 Future _sendMessage({required List message}) async { var result = await _udpSocket?.send(message, InternetAddress(remoteHost), remotePort); - if (result != message.length) { - throw StartChartMessageException('❌Udp send data error----> $result ${message.length}'); - // _udpSocket = null; + // 在对讲管理类中完善异常处理 + try { + // UDP发送逻辑 + } catch (e) { + // 记录错误但不影响主流程 + if (result != message.length) { + throw StartChartMessageException('❌Udp send data error----> $result ${message.length}'); + // _udpSocket = null; + } + print('对讲消息发送失败: $e'); } //ToDo: 增加对讲调试、正式可删除 diff --git a/lib/talk/starChart/status/appLifecycle_observer.dart b/lib/talk/starChart/status/appLifecycle_observer.dart index 678c04c6..042740f5 100644 --- a/lib/talk/starChart/status/appLifecycle_observer.dart +++ b/lib/talk/starChart/status/appLifecycle_observer.dart @@ -68,9 +68,10 @@ class AppLifecycleObserver extends WidgetsBindingObserver { status == TalkStatus.proactivelyCallWaitingAnswer || status == TalkStatus.answeredSuccessfully || status == TalkStatus.uninitialized) { - Get.back(); + // Get.back(); // 避免返回上一页的操作,避免影响注册页 } - StartChartManage().destruction(); + // 不进行对讲资源清理,避免切出去回来无法接听 + // StartChartManage().destruction(); _readMessageRefreshUIEvent?.cancel(); }