246 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			246 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:async';
 | ||
| import 'package:flutter/foundation.dart';
 | ||
| import 'package:flutter_new_badger/flutter_new_badger.dart';
 | ||
| import 'package:qhd_prevention/http/ApiService.dart';
 | ||
| import 'package:flutter/material.dart';
 | ||
| 
 | ||
| /// 优化版 BadgeManager:每个接口超时保护、增量更新、notify 合并、原生角标 debounce
 | ||
| class BadgeManager extends ChangeNotifier {
 | ||
|   BadgeManager._internal();
 | ||
|   static final BadgeManager _instance = BadgeManager._internal();
 | ||
|   factory BadgeManager() => _instance;
 | ||
| 
 | ||
|   // 各模块未读
 | ||
|   int _appCount = 0;
 | ||
|   int _appDysCount = 0;
 | ||
|   int _appDzgCount = 0;
 | ||
|   int _notifCount = 0;
 | ||
|   int _envInspectCount = 0;
 | ||
|   int _eightWorkCount = 0;
 | ||
| 
 | ||
|   // 读取接口值的公开 getter
 | ||
|   int get count => _appCount + _notifCount + _envInspectCount + _eightWorkCount;
 | ||
|   int get appCount => _appCount;
 | ||
|   int get appDysCount => _appDysCount;
 | ||
|   int get appDzgCount => _appDzgCount;
 | ||
|   int get notifCount => _notifCount;
 | ||
|   int get envInspectCount => _envInspectCount;
 | ||
|   int get eightWorkCount => _eightWorkCount;
 | ||
| 
 | ||
|   // 通知合并控制(短时间内多次更新只触发一次 notify)
 | ||
|   Timer? _notifyTimer;
 | ||
|   Duration _notifyDelay = const Duration(milliseconds: 180);
 | ||
|   void _scheduleNotify() {
 | ||
|     // 如果已有计划,不需要再立即计划(合并)
 | ||
|     _notifyTimer?.cancel();
 | ||
|     _notifyTimer = Timer(_notifyDelay, () {
 | ||
|       try {
 | ||
|         notifyListeners();
 | ||
|       } catch (e) {
 | ||
|         debugPrint('BadgeManager.notifyListeners error: $e');
 | ||
|       }
 | ||
|       _notifyTimer = null;
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   // 原生角标同步 debounce(防止短时间内频繁调用)
 | ||
|   Timer? _syncTimer;
 | ||
|   Duration _syncDelay = const Duration(milliseconds: 250);
 | ||
|   void _syncNativeDebounced() {
 | ||
|     _syncTimer?.cancel();
 | ||
|     _syncTimer = Timer(_syncDelay, () {
 | ||
|       try {
 | ||
|         final total = count;
 | ||
|         if (total > 0) {
 | ||
|           FlutterNewBadger.setBadge(total);
 | ||
|         } else {
 | ||
|           FlutterNewBadger.removeBadge();
 | ||
|         }
 | ||
|       } catch (e) {
 | ||
|         debugPrint('BadgeManager._syncNativeDebounced error: $e');
 | ||
|       }
 | ||
|       _syncTimer = null;
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   // safe wrapper: 给单个 future 加超时与兜底返回
 | ||
|   Future<T> _safe<T>(Future<T> future, T fallback, {Duration timeout = const Duration(seconds: 5)}) async {
 | ||
|     try {
 | ||
|       return await future.timeout(timeout);
 | ||
|     } catch (e, st) {
 | ||
|       // 报错不抛出到外层,记录并返回 fallback
 | ||
|       debugPrint('BadgeManager._safe error: $e\n$st');
 | ||
|       return fallback;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   /// 初始化所有模块(并行发起,但每个接口独立 timeout & 提交结果)
 | ||
|   Future<void> initAllModules() async {
 | ||
|     // 不 await 整个 Future.wait,使调用方不会因为单个慢接口阻塞
 | ||
|     try {
 | ||
|       // 每个请求都通过 _safe 包裹,设置超时与兜底
 | ||
|       final fWork = _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getWork().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 6),
 | ||
|       );
 | ||
|       final fNotif = _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getNotifRedPoint().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 4),
 | ||
|       );
 | ||
|       final fCheck = _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getSafetyEnvironmentalInspectionCount().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 5),
 | ||
|       );
 | ||
|       final fRed = _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getRedPoint().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 5),
 | ||
|       );
 | ||
| 
 | ||
|       // 按接口独立处理:完成即更新并合并通知(progressive update)
 | ||
|       fWork.then((workJson) {
 | ||
|         try {
 | ||
|           final hid = (workJson['hidCount'] as Map<String, dynamic>?) ?? {};
 | ||
|           _appDysCount = (hid['dys'] ?? 0) as int? ?? 0;
 | ||
|           _appDzgCount = (hid['dzg'] ?? 0) as int? ?? 0;
 | ||
|           _appCount = _appDysCount + _appDzgCount;
 | ||
|         } catch (e, st) {
 | ||
|           debugPrint('BadgeManager.parse workJson error: $e\n$st');
 | ||
|         }
 | ||
|         _scheduleNotify();
 | ||
|         _syncNativeDebounced();
 | ||
|       });
 | ||
| 
 | ||
|       fNotif.then((notifJson) {
 | ||
|         try {
 | ||
|           _notifCount = (notifJson['count'] as int?) ?? 0;
 | ||
|         } catch (e, st) {
 | ||
|           debugPrint('BadgeManager.parse notifJson error: $e\n$st');
 | ||
|         }
 | ||
|         _scheduleNotify();
 | ||
|         _syncNativeDebounced();
 | ||
|       });
 | ||
| 
 | ||
|       fCheck.then((checkJson) {
 | ||
|         try {
 | ||
|           // 兼容不同返回结构,防止空指针
 | ||
|           int checkedCount = 0, repulseAndCheckCount = 0, confirmCount = 0, repulseCount = 0;
 | ||
|           if (checkJson['checkedCount'] is Map) checkedCount = (checkJson['checkedCount']['checkedCount'] ?? 0) as int? ?? 0;
 | ||
|           if (checkJson['repulseAndCheckCount'] is Map) repulseAndCheckCount = (checkJson['repulseAndCheckCount']['repulseAndCheckCount'] ?? 0) as int? ?? 0;
 | ||
|           if (checkJson['confirmCount'] is Map) confirmCount = (checkJson['confirmCount']['confirmCount'] ?? 0) as int? ?? 0;
 | ||
|           if (checkJson['repulseCount'] is Map) repulseCount = (checkJson['repulseCount']['repulseCount'] ?? 0) as int? ?? 0;
 | ||
|           _envInspectCount = checkedCount + repulseAndCheckCount + confirmCount + repulseCount;
 | ||
|         } catch (e, st) {
 | ||
|           debugPrint('BadgeManager.parse checkJson error: $e\n$st');
 | ||
|         }
 | ||
|         _scheduleNotify();
 | ||
|         _syncNativeDebounced();
 | ||
|       });
 | ||
| 
 | ||
|       fRed.then((redPointJson) {
 | ||
|         try {
 | ||
|           _eightWorkCount = 0;
 | ||
|           final m = (redPointJson['count'] as Map<String, dynamic>?) ?? {};
 | ||
|           for (final v in m.values) {
 | ||
|             _eightWorkCount += (v ?? 0) as int? ?? 0;
 | ||
|           }
 | ||
|         } catch (e, st) {
 | ||
|           debugPrint('BadgeManager.parse redPointJson error: $e\n$st');
 | ||
|         }
 | ||
|         _scheduleNotify();
 | ||
|         _syncNativeDebounced();
 | ||
|       });
 | ||
| 
 | ||
|       // 可选:等待所有结束(不阻塞调用方),用于 debug 或需要最终一致性的场景
 | ||
|       unawaited(Future.wait([fWork, fNotif, fCheck, fRed]).then((_) {
 | ||
|         debugPrint('BadgeManager.initAllModules: all done at ${DateTime.now()}');
 | ||
|       }));
 | ||
|     } catch (e, st) {
 | ||
|       debugPrint('BadgeManager.initAllModules unexpected error: $e\n$st');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // 下面的 updateX 方法也做了超时保护并使用 _onModuleChanged 合并通知
 | ||
|   void updateAppCount() async {
 | ||
|     try {
 | ||
|       final workJson = await _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getWork().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 5),
 | ||
|       );
 | ||
|       final hid = (workJson['hidCount'] as Map<String, dynamic>?) ?? {};
 | ||
|       _appDysCount = (hid['dys'] ?? 0) as int? ?? 0;
 | ||
|       _appDzgCount = (hid['dzg'] ?? 0) as int? ?? 0;
 | ||
|       _appCount = _appDysCount + _appDzgCount;
 | ||
|       _onModuleChanged();
 | ||
|     } catch (e) {
 | ||
|       debugPrint('updateAppCount error: $e');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   void updateNotifCount() async {
 | ||
|     try {
 | ||
|       final notifJson = await _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getNotifRedPoint().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 4),
 | ||
|       );
 | ||
|       _notifCount = (notifJson['count'] as int?) ?? 0;
 | ||
|       _onModuleChanged();
 | ||
|     } catch (e) {
 | ||
|       debugPrint('updateNotifCount error: $e');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   void updateEnvInspectCount() async {
 | ||
|     try {
 | ||
|       final checkJson = await _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getSafetyEnvironmentalInspectionCount().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 5),
 | ||
|       );
 | ||
|       int checkedCount = 0, repulseAndCheckCount = 0, confirmCount = 0, repulseCount = 0;
 | ||
|       if (checkJson['checkedCount'] is Map) checkedCount = (checkJson['checkedCount']['checkedCount'] ?? 0) as int? ?? 0;
 | ||
|       if (checkJson['repulseAndCheckCount'] is Map) repulseAndCheckCount = (checkJson['repulseAndCheckCount']['repulseAndCheckCount'] ?? 0) as int? ?? 0;
 | ||
|       if (checkJson['confirmCount'] is Map) confirmCount = (checkJson['confirmCount']['confirmCount'] ?? 0) as int? ?? 0;
 | ||
|       if (checkJson['repulseCount'] is Map) repulseCount = (checkJson['repulseCount']['repulseCount'] ?? 0) as int? ?? 0;
 | ||
|       _envInspectCount = checkedCount + repulseAndCheckCount + confirmCount + repulseCount;
 | ||
|       _onModuleChanged();
 | ||
|     } catch (e) {
 | ||
|       debugPrint('updateEnvInspectCount error: $e');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   void updateEightWorkCount() async {
 | ||
|     try {
 | ||
|       final redPointJson = await _safe<Map<String, dynamic>>(
 | ||
|         ApiService.getRedPoint().then((r) => r as Map<String, dynamic>),
 | ||
|         <String, dynamic>{},
 | ||
|         timeout: const Duration(seconds: 5),
 | ||
|       );
 | ||
|       int sum = 0;
 | ||
|       final m = (redPointJson['count'] as Map<String, dynamic>?) ?? {};
 | ||
|       for (final v in m.values) sum += (v ?? 0) as int? ?? 0;
 | ||
|       _eightWorkCount = sum;
 | ||
|       _onModuleChanged();
 | ||
|     } catch (e) {
 | ||
|       debugPrint('updateEightWorkCount error: $e');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   void clearAll() {
 | ||
|     _appCount = _notifCount = _envInspectCount = _eightWorkCount = 0;
 | ||
|     _appDysCount = _appDzgCount = 0;
 | ||
|     _syncNativeDebounced();
 | ||
|     _scheduleNotify();
 | ||
|   }
 | ||
| 
 | ||
|   void _onModuleChanged() {
 | ||
|     _syncNativeDebounced();
 | ||
|     _scheduleNotify();
 | ||
|   }
 | ||
| }
 |