From 7ebd28f177ac44e2ac67b37d8660fa4419232c53 Mon Sep 17 00:00:00 2001 From: hs <873121290@qq.com> Date: Wed, 3 Jun 2026 16:51:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B2=A1=E6=9C=89=E4=BC=81=E4=B8=9A=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=80=BB=E8=BE=91=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/home/home_page.dart | 10 +++- lib/pages/main_tab.dart | 50 ++++++++-------- lib/tools/click_util.dart | 106 ++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 26 deletions(-) create mode 100644 lib/tools/click_util.dart diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index fcdec67..646833a 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -166,10 +166,11 @@ class HomePageState extends RouteAwareState _scrollController.addListener(_onScroll); WidgetsBinding.instance.addObserver(this); RouteService().addListener(onRouteConfigLoaded); - Future.microtask(() { - _updateModuleAndButtonVisibility(); - }); + if (_isShowCheckLogin) { + Future.microtask(() { + _updateModuleAndButtonVisibility(); + }); _getToDoWorkList(pcType); } } @@ -1105,6 +1106,9 @@ class HomePageState extends RouteAwareState // 获取待办事项 void _getToDoWorkList(int type) async { + if (!_isShowCheckLogin) { + return; + } Map data = { "eqAppFlag": type == 1 ? "1" : "", "eqPcFlag": type == 1 ? "" : "1", diff --git a/lib/pages/main_tab.dart b/lib/pages/main_tab.dart index bcd3669..0b99a85 100644 --- a/lib/pages/main_tab.dart +++ b/lib/pages/main_tab.dart @@ -94,30 +94,34 @@ class _MainPageState extends State with WidgetsBindingObserver { Future _getRoute() async { try { Map? route; - // 接口获取 - try { - LoadingDialogHelper.show(message: '加载中...'); - final roleId = SessionService.instance.roleId; - final res = await AppMenuApi.getAppMenu({'roleId': roleId}); - LoadingDialogHelper.hide(); - if (res['success'] == true) { - route = res; - printLongString(jsonEncode(route)); - } else {} - } catch (e) { - debugPrint( - 'AppMenuApi.getAppMenu error: $e -> fallback to local assets.', - ); + if (widget.isChooseFirm) { + // 接口获取 + try { + LoadingDialogHelper.show(message: '加载中...'); + final roleId = SessionService.instance.roleId; + final res = await AppMenuApi.getAppMenu({'roleId': roleId}); + LoadingDialogHelper.hide(); + if (res['success'] == true) { + route = res; + printLongString(jsonEncode(route)); + } else {} + } catch (e) { + debugPrint( + 'AppMenuApi.getAppMenu error: $e -> fallback to local assets.', + ); + } + }else{ + // 本地获取 + try { + final routeString = await loadFromAssets(); + route = jsonDecode(routeString) as Map; + } catch (e) { + debugPrint('loadFromAssets error: $e'); + } + final data = route?['data'] ?? []; + RouteService().initializeRoutes(data); } - // 本地获取 - // try { - // final routeString = await loadFromAssets(); - // route = jsonDecode(routeString) as Map; - // } catch (e) { - // debugPrint('loadFromAssets error: $e'); - // } - final data = route?['data'] ?? []; - RouteService().initializeRoutes(data); + } catch (e) { debugPrint('获取路由配置失败: $e'); } finally { diff --git a/lib/tools/click_util.dart b/lib/tools/click_util.dart new file mode 100644 index 0000000..6bf08f3 --- /dev/null +++ b/lib/tools/click_util.dart @@ -0,0 +1,106 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; + +typedef GuardedTapCallback = FutureOr Function(); + +/// 通用防连点工具。 +/// +/// 适用于 `TextButton`、`IconButton`、`GestureDetector`、`InkWell` 等 +/// 任意需要点击防抖的场景。 +class ClickUtil { + ClickUtil._(); + + static const int defaultDelayMs = 800; + + static final Map _lastTriggerTimes = {}; + static final Set _runningKeys = {}; + static final Object _globalKey = Object(); + + /// 运行一个带防连点保护的点击事件。 + /// + /// `key` 相同的点击事件会共用一把锁; + /// `delayMs` 内重复点击会被忽略; + /// `lockDuringExecution` 为 true 时,异步执行期间也会被锁住。 + static Future run( + GuardedTapCallback action, { + Object? key, + int delayMs = defaultDelayMs, + bool lockDuringExecution = true, + }) async { + final Object guardKey = key ?? action; + final DateTime now = DateTime.now(); + final DateTime? lastTriggerTime = _lastTriggerTimes[guardKey]; + + if (lastTriggerTime != null && + now.difference(lastTriggerTime).inMilliseconds < delayMs) { + debugPrint('请稍后点击'); + return; + } + + if (lockDuringExecution && _runningKeys.contains(guardKey)) { + debugPrint('操作进行中,请稍后'); + return; + } + + _lastTriggerTimes[guardKey] = now; + if (lockDuringExecution) { + _runningKeys.add(guardKey); + } + + try { + await action(); + } finally { + if (lockDuringExecution) { + final int elapsedMs = DateTime.now().difference(now).inMilliseconds; + final int remainingMs = delayMs - elapsedMs; + if (remainingMs > 0) { + await Future.delayed(Duration(milliseconds: remainingMs)); + } + _runningKeys.remove(guardKey); + } + } + } + + /// 直接包装成可绑定给按钮的回调。 + /// + /// 对于会在 `build` 中频繁新建的匿名函数,推荐显式传入 `key`。 + static VoidCallback? wrap( + GuardedTapCallback? action, { + Object? key, + int delayMs = defaultDelayMs, + bool lockDuringExecution = true, + }) { + if (action == null) return null; + + return () { + unawaited( + run( + action, + key: key, + delayMs: delayMs, + lockDuringExecution: lockDuringExecution, + ), + ); + }; + } + + /// 兼容旧调用方式:全局共用一把锁。 + static Future noMultipleClicks( + GuardedTapCallback action, { + int delayMs = 2000, + }) { + return run(action, key: _globalKey, delayMs: delayMs); + } + + static void reset([Object? key]) { + if (key == null) { + _lastTriggerTimes.clear(); + _runningKeys.clear(); + return; + } + + _lastTriggerTimes.remove(key); + _runningKeys.remove(key); + } +}