import 'package:common_utils/common_utils.dart'; import 'package:get/get.dart'; import 'package:pj_supermarket_cloud/common/index.dart'; /// 新终端侧边栏的统一导航守卫。 /// /// 统一终端导航仍需保留设备绑定、联网限制和设置密码校验, /// 否则视觉重构会意外放开原有业务入口。 abstract final class TerminalNavigationTool { /// 终端工作区使用独立导航栈,避免切换菜单时重建顶部状态栏和侧边栏。 static const navigatorId = 1; static bool _verificationInProgress = false; static Future open(String route) async { if (_requiresAdminUnlock(route)) { if (!await _verifyAdminSession(actionLabel: '进入设置')) return; _replaceWorkspace(route); return; } if (!await _checkIsBind()) return; if (_requiresNetwork(route) && !AppNetworkTool.isAutoNetwork()) { Toast.error(msg: '请先连接网络'); return; } _replaceWorkspace(route); } /// 仅替换终端二级页面,保留一级外壳及应用级资源。 static void replaceWorkspace(String route) => _replaceWorkspace(route); static void _replaceWorkspace(String route) { Get.offAllNamed(route, id: navigatorId); } /// 退出前统一执行管理密码校验,避免侧栏与顶栏出口出现不同的安全规则。 static Future logout() async { if (!await _verifyAdminSession(actionLabel: '退出登录')) return; Get.find().lock(); if (AppNetworkTool.isAutoNetwork()) { // await AppSettingTool.setUserSetting(UserSetting()); } Get.offAllNamed(RouteNames.login); } /// 顶栏锁状态可主动发起验证,不需要先进入设置或退出流程。 static Future unlockAdminSession() async { await _verifyAdminSession(actionLabel: '解锁管理操作'); } static Future _verifyAdminSession({ required String actionLabel, }) async { final session = Get.find(); if (session.isUnlocked) return true; session.lock(); // 快速连续点击设置与退出时只允许存在一个密码弹层,避免重复 Overlay 和 GlobalKey。 if (_verificationInProgress) return false; final context = Get.context; if (context == null) return false; _verificationInProgress = true; try { final verified = await terminalAdminPasswordDialog( context, actionLabel: actionLabel, ); // 弹层取消与验证成功都要等退场结束,避免快速再次点击叠加两个 Overlay。 await Future.delayed(const Duration(milliseconds: 200)); if (!verified) return false; session.unlock(); return true; } finally { _verificationInProgress = false; } } /// 查询菜单是学生本人自助入口,不纳入管理密码校验。 static bool _requiresAdminUnlock(String route) { return route == RouteNames.setting; } static bool _requiresNetwork(String route) { return route == RouteNames.menuQuery || route == RouteNames.canteenReserve || route == RouteNames.takeFood || route == RouteNames.canteenOrderTotal; } static Future _checkIsBind() async { final setting = await AppSettingTool.getSysSetting(); if (ObjectUtil.isEmpty(setting.serviceMerchantId)) { Toast.error(msg: '请前往设置绑定设备'); return false; } return true; } }