2026.2.28 消息通知
parent
e9644fea24
commit
37651441b2
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
|
|
@ -0,0 +1,69 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/http/HttpManager.dart';
|
||||
|
||||
class NotifApi {
|
||||
|
||||
/// 通知列表
|
||||
static Future<Map<String, dynamic>> getNoticeList(Map data) {
|
||||
return HttpManager().request(
|
||||
'${ApiService.basePath}/appmenu',
|
||||
'/noticeReadRecord/list',
|
||||
method: Method.post,
|
||||
data: {
|
||||
...data ,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 通知详情
|
||||
static Future<Map<String, dynamic>> getNoticeDetail(String noticeId) {
|
||||
return HttpManager().request(
|
||||
'${ApiService.basePath}/appmenu',
|
||||
'/notice/noticeContentInfo/$noticeId',
|
||||
method: Method.get,
|
||||
data: {
|
||||
// ...data ,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 已阅
|
||||
static Future<Map<String, dynamic>> saveReadNoticeDetail(String noticeId) {
|
||||
return HttpManager().request(
|
||||
'${ApiService.basePath}/appmenu',
|
||||
'/noticeReadRecord/save',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"noticeId": noticeId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 回复
|
||||
static Future<Map<String, dynamic>> replyContent(String noticeReadId,String replyContent) {
|
||||
return HttpManager().request(
|
||||
'${ApiService.basePath}/appmenu',
|
||||
'/noticeReadRecord/reply',
|
||||
method: Method.put,
|
||||
data: {
|
||||
"noticeReadId": noticeReadId,
|
||||
"replyContent": replyContent,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 通知数量
|
||||
static Future<Map<String, dynamic>> getNotifRedPoint() {
|
||||
return HttpManager().request(
|
||||
'${ApiService.basePath}/appmenu',
|
||||
'/notice/unreadCount',
|
||||
method: Method.get,
|
||||
data: {
|
||||
// ...data ,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_new_badger/flutter_new_badger.dart';
|
||||
import 'package:qhd_prevention/common/route_service.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/http/modules/notif_api.dart';
|
||||
|
||||
|
||||
/// 优化版 BadgeManager:每个接口超时保护、增量更新、notify 合并、原生角标 debounce
|
||||
class BadgeManager extends ChangeNotifier {
|
||||
BadgeManager._internal();
|
||||
static final BadgeManager _instance = BadgeManager._internal();
|
||||
factory BadgeManager() => _instance;
|
||||
// 添加完整的工作数据存储
|
||||
Map<String, dynamic> _workData = {};
|
||||
Map<String, dynamic> get workData => _workData;
|
||||
// 各模块未读
|
||||
int _notifCount = 0;
|
||||
|
||||
|
||||
// 读取接口值的公开 getter
|
||||
int get count => _notifCount ;
|
||||
int get notifCount => _notifCount;
|
||||
|
||||
|
||||
|
||||
// 通知合并控制(短时间内多次更新只触发一次 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 fNotif = _safe<Map<String, dynamic>>(
|
||||
NotifApi.getNotifRedPoint().then((r) => r as Map<String, dynamic>),
|
||||
<String, dynamic>{},
|
||||
timeout: const Duration(seconds: 4),
|
||||
);
|
||||
|
||||
|
||||
fNotif.then((notifJson) {
|
||||
try {
|
||||
_notifCount = ((notifJson['data'] as int?) ?? 0);
|
||||
} catch (e, st) {
|
||||
debugPrint('BadgeManager.parse notifJson error: $e\n$st');
|
||||
}
|
||||
_scheduleNotify();
|
||||
_syncNativeDebounced();
|
||||
});
|
||||
|
||||
|
||||
} catch (e, st) {
|
||||
debugPrint('BadgeManager.initAllModules unexpected error: $e\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
// 下面的 updateX 方法也做了超时保护并使用 _onModuleChanged 合并通知
|
||||
|
||||
void updateNotifCount() async {
|
||||
try {
|
||||
final notifJson = await _safe<Map<String, dynamic>>(
|
||||
NotifApi.getNotifRedPoint().then((r) => r as Map<String, dynamic>),
|
||||
<String, dynamic>{},
|
||||
timeout: const Duration(seconds: 4),
|
||||
);
|
||||
_notifCount = (notifJson['data'] as int?) ?? 0;
|
||||
_onModuleChanged();
|
||||
} catch (e) {
|
||||
debugPrint('updateNotifCount error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clearAll() {
|
||||
_syncNativeDebounced();
|
||||
_scheduleNotify();
|
||||
}
|
||||
|
||||
void _onModuleChanged() {
|
||||
_syncNativeDebounced();
|
||||
_scheduleNotify();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/pages/badge_manager.dart';
|
||||
import 'package:qhd_prevention/pages/home/home_page.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/notif/notif_page.dart';
|
||||
import 'package:qhd_prevention/services/heartbeat_service.dart';
|
||||
|
||||
/// 用于向子树公布当前 tab 索引
|
||||
|
|
@ -35,21 +37,33 @@ class MainPage extends StatefulWidget {
|
|||
class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
||||
int _currentIndex = 0;
|
||||
final GlobalKey<HomePageState> _homeKey = GlobalKey<HomePageState>();
|
||||
|
||||
final GlobalKey<NotifPageState> _notifKey = GlobalKey<NotifPageState>();
|
||||
// final GlobalKey<ApplicationPageTwoState> _appKey = GlobalKey<ApplicationPageTwoState>();
|
||||
final GlobalKey<MinePageState> _mineKey = GlobalKey<MinePageState>();
|
||||
late List<Widget> _pages;
|
||||
late List<bool> _tabVisibility; // 存储每个Tab的显示状态
|
||||
|
||||
// 添加 BadgeManager 实例
|
||||
late final BadgeManager _badgeManager;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// 初始化 BadgeManager
|
||||
_badgeManager = BadgeManager();
|
||||
_badgeManager.initAllModules();
|
||||
|
||||
// 监听 BadgeManager 的变化
|
||||
_badgeManager.addListener(_onBadgeChanged);
|
||||
|
||||
// 注册生命周期监听
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
// 初始化所有Tab
|
||||
_tabVisibility = [true, true, true];
|
||||
_pages = <Widget>[
|
||||
HomePage(key: _homeKey, isChooseFirm: widget.isChooseFirm),
|
||||
NotifPage(key: _notifKey),
|
||||
MinePage(key: _mineKey, isChooseFirm: widget.isChooseFirm),
|
||||
];
|
||||
// 启动心跳服务
|
||||
|
|
@ -58,7 +72,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
// BadgeManager().removeListener(_onBadgeChanged);
|
||||
_badgeManager.removeListener(_onBadgeChanged);
|
||||
// 移除生命周期监听
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
|
||||
|
|
@ -122,7 +136,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final bm = BadgeManager();
|
||||
final bm = _badgeManager;
|
||||
|
||||
// 构建可见的底部导航项
|
||||
final List<BottomNavigationBarItem> visibleItems = [];
|
||||
|
|
@ -150,6 +164,20 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||
visiblePages.add(_pages[i]);
|
||||
break;
|
||||
case 1:
|
||||
visibleItems.add(BottomNavigationBarItem(
|
||||
icon: _buildIconWithBadge(
|
||||
icon: Image.asset('assets/tabbar/works.png', width: 24, height: 24),
|
||||
badgeCount: bm.notifCount,
|
||||
),
|
||||
activeIcon: _buildIconWithBadge(
|
||||
icon: Image.asset('assets/tabbar/works_cur.png', width: 24, height: 24),
|
||||
badgeCount: bm.notifCount,
|
||||
),
|
||||
label: '通知',
|
||||
));
|
||||
visiblePages.add(_pages[i]);
|
||||
break;
|
||||
case 2:
|
||||
visibleItems.add(
|
||||
BottomNavigationBarItem(
|
||||
icon: Image.asset(
|
||||
|
|
@ -167,7 +195,6 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||
);
|
||||
visiblePages.add(_pages[i]);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,4 +245,16 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void _onBadgeChanged() {
|
||||
// 当角标数据变化时,只更新需要重建的部分
|
||||
// 但这里我们只需要触发 build 来更新底部导航栏的角标
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
// 只触发重建,不改变数据
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,189 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/http/modules/notif_api.dart';
|
||||
import 'package:qhd_prevention/pages/mine/webViewPage.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
import '../../http/ApiService.dart';
|
||||
|
||||
|
||||
class NotifDetailPage extends StatefulWidget {
|
||||
const NotifDetailPage(this.item, this.selectedTab, {super.key,required this.onClose});
|
||||
|
||||
final Function(String) onClose; // 回调函数
|
||||
final dynamic item;
|
||||
final int selectedTab;
|
||||
|
||||
@override
|
||||
State<NotifDetailPage> createState() => _NotifDetailPageState(item,selectedTab,onClose);
|
||||
}
|
||||
|
||||
class _NotifDetailPageState extends State<NotifDetailPage> {
|
||||
_NotifDetailPageState(this.item, this.selectedTab,this.onClose);
|
||||
|
||||
final Function(String) onClose; // 回调函数
|
||||
final dynamic item;
|
||||
final int selectedTab;
|
||||
String title="";
|
||||
String time="";
|
||||
String text="";
|
||||
bool isShowReply=false;
|
||||
String replyText="";
|
||||
String noticeReadId='';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if(0==selectedTab){
|
||||
_getNotifDetail();
|
||||
}else{
|
||||
_getNotifEnterpriseDetail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Future<void> _getNotifDetail() async {
|
||||
// LoadingDialogHelper.show();
|
||||
try {
|
||||
final result = await NotifApi.getNoticeDetail(item['noticeId']);
|
||||
if (result['success']) {
|
||||
final dynamic newList = result['data'] ;
|
||||
setState(() {
|
||||
title= newList['title']??'';
|
||||
time= newList['publishTime']??'';
|
||||
text= newList['content']??'';
|
||||
isShowReply=newList['requireReply']==1?true:false;
|
||||
noticeReadId=newList['noticeReadId']??'';
|
||||
replyText=newList['replyContent']??'';
|
||||
});
|
||||
if(newList['readStatus']!='1'){
|
||||
final resultTwo = await NotifApi.saveReadNoticeDetail(item['noticeId']);
|
||||
if (result['success']) {
|
||||
noticeReadId = resultTwo['data'] ?? '';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('加载出错: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getNotifEnterpriseDetail() async {
|
||||
// LoadingDialogHelper.show();
|
||||
try {
|
||||
// final result = await HiddenDangerApi.getNotifEnterpriseDetail(item['NOTICECORPUSERID_ID']);
|
||||
// if (result['result'] == 'success') {
|
||||
// final dynamic newList = result['pd'] ;
|
||||
// setState(() {
|
||||
// title= newList['SYNOPSIS'];
|
||||
// time= newList['CREATTIME'];
|
||||
// text= newList['CONTENT'];
|
||||
// });
|
||||
// }
|
||||
} catch (e) {
|
||||
print('加载出错: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: "通知详情"),
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
// color: Colors.white,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Card(
|
||||
child: Container(
|
||||
width: double.infinity, // 铺满父容器
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start, // 左对齐
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10,right: 10),
|
||||
child: Text(title,style: TextStyle(color: Colors.black,fontSize: 16,fontWeight: FontWeight.bold),),
|
||||
),
|
||||
|
||||
SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10,right: 10),
|
||||
child: Text(time,),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Html(
|
||||
data: text,
|
||||
),
|
||||
|
||||
SizedBox(height: 8),
|
||||
if(isShowReply&&replyText.isEmpty)
|
||||
CustomButton(
|
||||
height: 35,
|
||||
margin: EdgeInsets.only(right: 10),
|
||||
onPressed: () async {
|
||||
final confirmed = await CustomAlertDialog.showInput(
|
||||
context,
|
||||
title: "回复",
|
||||
hintText: '输入内容',
|
||||
cancelText: '关闭',
|
||||
confirmText: '确定',
|
||||
);
|
||||
if (confirmed != null&&confirmed.isNotEmpty) {
|
||||
//确定回复
|
||||
// ToastUtil.showNormal(context, confirmed);
|
||||
_replyContent(confirmed);
|
||||
}
|
||||
},
|
||||
backgroundColor: h_AppBarColor(),
|
||||
textStyle: const TextStyle(color: Colors.white),
|
||||
buttonStyle: ButtonStyleType.primary,
|
||||
text: '回复',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
onClose('关闭详情'); // 触发回调
|
||||
}
|
||||
|
||||
|
||||
Future<void> _replyContent(String content) async {
|
||||
try {
|
||||
LoadingDialogHelper.show();
|
||||
final result = await NotifApi.replyContent(noticeReadId,content);
|
||||
LoadingDialogHelper.hide();
|
||||
if (result['success']) {
|
||||
ToastUtil.showNormal(context, '回复成功');
|
||||
Navigator.pop(context);
|
||||
// onClose('关闭详情'); // 触发回调
|
||||
}
|
||||
} catch (e) {
|
||||
print('加载出错: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,497 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:qhd_prevention/common/route_aware_state.dart';
|
||||
import 'package:qhd_prevention/common/route_service.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/http/modules/notif_api.dart';
|
||||
import 'package:qhd_prevention/pages/badge_manager.dart';
|
||||
import 'package:qhd_prevention/pages/main_tab.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
|
||||
import 'package:qhd_prevention/pages/notif/notif_detail_page.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import '../../http/ApiService.dart';
|
||||
|
||||
class NotifPage extends StatefulWidget {
|
||||
const NotifPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
NotifPageState createState() => NotifPageState();
|
||||
}
|
||||
|
||||
class NotifPageState extends RouteAwareState<NotifPage>
|
||||
with TickerProviderStateMixin, WidgetsBindingObserver {
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
late List<dynamic> _list = [];
|
||||
|
||||
|
||||
late TabController _tabController;
|
||||
late TabController _tabControllerTwo;
|
||||
int _selectedTab = 0;
|
||||
int _selectedTabTwo = 0;
|
||||
int pageNum = 1;
|
||||
int _totalPage=1;
|
||||
String keyWord = "";
|
||||
|
||||
// 控制Tab显示状态
|
||||
bool _showPlatformAnnouncement = true;
|
||||
bool _showEnterpriseAnnouncement = true;
|
||||
|
||||
// 标记是否已初始化
|
||||
bool _isInitialized = false;
|
||||
bool _isLoading = false;
|
||||
bool _hasMore = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
// 初始化显示状态
|
||||
_initializeVisibility();
|
||||
|
||||
// 初始化TabController
|
||||
_initializeTabControllers();
|
||||
|
||||
_getListData(false);
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
void _initializeVisibility() {
|
||||
_showPlatformAnnouncement = true;
|
||||
_showEnterpriseAnnouncement = true;
|
||||
}
|
||||
|
||||
void _initializeTabControllers() {
|
||||
final visibleTabsCount =
|
||||
(_showPlatformAnnouncement ? 1 : 0) +
|
||||
(_showEnterpriseAnnouncement ? 1 : 0);
|
||||
|
||||
_tabController = TabController(length: visibleTabsCount, vsync: this);
|
||||
_tabController.addListener(() {
|
||||
if (_tabController.indexIsChanging) {
|
||||
setState(() => _selectedTab = _tabController.index);
|
||||
print('切换到标签:${_tabController.index}');
|
||||
searchController.text = "";
|
||||
keyWord = "";
|
||||
reRefreshData();
|
||||
}
|
||||
});
|
||||
|
||||
_tabControllerTwo = TabController(length: 2, vsync: this);
|
||||
_tabControllerTwo.addListener(() {
|
||||
if (_tabControllerTwo.indexIsChanging) {
|
||||
setState(() => _selectedTabTwo = _tabControllerTwo.index);
|
||||
print('切换到标签:${_tabControllerTwo.index}');
|
||||
|
||||
searchController.text = "";
|
||||
keyWord = "";
|
||||
reRefreshData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _updateNotifVisibility() {
|
||||
final routeService = RouteService();
|
||||
final notifRoutes =
|
||||
routeService.mainTabs.isNotEmpty
|
||||
? routeService.getRoutesForTab(routeService.mainTabs[2])
|
||||
: [];
|
||||
|
||||
bool newPlatformAnnouncement = false;
|
||||
bool newEnterpriseAnnouncement = false;
|
||||
|
||||
// 根据路由标题匹配并设置显示状态
|
||||
for (final route in notifRoutes) {
|
||||
final routeTitle = route.title;
|
||||
|
||||
switch (routeTitle) {
|
||||
case '公告':
|
||||
newPlatformAnnouncement = route.hasMenu;
|
||||
break;
|
||||
case '通知':
|
||||
newEnterpriseAnnouncement = route.hasMenu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 只有当显示状态确实发生变化时才更新
|
||||
if (newPlatformAnnouncement != _showPlatformAnnouncement ||
|
||||
newEnterpriseAnnouncement != _showEnterpriseAnnouncement) {
|
||||
setState(() {
|
||||
_showPlatformAnnouncement = newPlatformAnnouncement;
|
||||
_showEnterpriseAnnouncement = newEnterpriseAnnouncement;
|
||||
|
||||
// 重新初始化TabController
|
||||
_disposeTabControllers();
|
||||
_initializeTabControllers();
|
||||
|
||||
// 重置选中状态
|
||||
_selectedTab = 0;
|
||||
_selectedTabTwo = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _disposeTabControllers() {
|
||||
_tabController.dispose();
|
||||
_tabControllerTwo.dispose();
|
||||
}
|
||||
|
||||
void onRouteConfigLoaded() {
|
||||
if (mounted && _isInitialized) {
|
||||
_updateNotifVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
void reRefreshData() {
|
||||
pageNum = 1;
|
||||
_list.clear();
|
||||
_getListData(false);
|
||||
// if (0 == _selectedTab) {
|
||||
//
|
||||
// _getNotifList();
|
||||
// } else {
|
||||
// _getNotifEnterprise();
|
||||
// }
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onVisible() async {
|
||||
final current = CurrentTabNotifier.of(context)?.currentIndex ?? 0;
|
||||
const myIndex = 2;
|
||||
if (current != myIndex) {
|
||||
return;
|
||||
}
|
||||
// BadgeManager().updateNotifCount();
|
||||
}
|
||||
|
||||
Future<void> _getListData(bool loadMore) async {
|
||||
try {
|
||||
if (_isLoading) return;
|
||||
_isLoading = true;
|
||||
|
||||
LoadingDialogHelper.show();
|
||||
|
||||
final Map<String, dynamic> result;
|
||||
|
||||
final data = {
|
||||
"pageSize": 20,
|
||||
"pageIndex": pageNum,
|
||||
};
|
||||
|
||||
if(_selectedTab==0){
|
||||
result = await NotifApi.getNoticeList(data);
|
||||
}else{
|
||||
result = await NotifApi.getNoticeList(data);
|
||||
}
|
||||
BadgeManager().updateNotifCount();
|
||||
LoadingDialogHelper.hide();
|
||||
if(_selectedTab==0){
|
||||
if (result['success']) {
|
||||
_totalPage =result['totalPages'] ?? 1;
|
||||
final List<dynamic> newList = result['data'] ?? [];
|
||||
// setState(() {
|
||||
// _list.addAll(newList);
|
||||
// });
|
||||
|
||||
setState(() {
|
||||
if (loadMore) {
|
||||
_list.addAll(newList);
|
||||
} else {
|
||||
_list = newList;
|
||||
}
|
||||
_hasMore = pageNum < _totalPage;
|
||||
// if (_hasMore) _page++;
|
||||
});
|
||||
|
||||
}else{
|
||||
ToastUtil.showNormal(context, "加载数据失败");
|
||||
// _showMessage('加载数据失败');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (e) {
|
||||
LoadingDialogHelper.hide();
|
||||
// 出错时可以 Toast 或者在页面上显示错误状态
|
||||
print('加载数据失败:$e');
|
||||
} finally {
|
||||
// if (!loadMore) LoadingDialogHelper.hide();
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
_disposeTabControllers();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 构建可见的Tab列表
|
||||
final List<Widget> visibleTabs = [];
|
||||
if (_showPlatformAnnouncement) {
|
||||
visibleTabs.add(const Tab(text: '公告'));
|
||||
}
|
||||
if (_showEnterpriseAnnouncement) {
|
||||
visibleTabs.add(const Tab(text: '通知'));
|
||||
}
|
||||
|
||||
// 如果没有可见的Tab,显示空页面
|
||||
if (visibleTabs.isEmpty) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: '通知', isBack: false),
|
||||
body: Center(
|
||||
child: Text(
|
||||
'暂无通知权限',
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: '通知', isBack: false),
|
||||
body: GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Scaffold(
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
// Tab bar
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: TabBar(
|
||||
controller: _tabController,
|
||||
labelStyle: const TextStyle(fontSize: 16),
|
||||
indicator: const UnderlineTabIndicator(
|
||||
borderSide: BorderSide(
|
||||
width: 4.0,
|
||||
color: const Color(0xFF1C61FF),
|
||||
),
|
||||
insets: EdgeInsets.symmetric(horizontal: 35.0),
|
||||
),
|
||||
labelColor: const Color(0xFF1C61FF),
|
||||
unselectedLabelColor: Colors.grey,
|
||||
tabs: visibleTabs,
|
||||
),
|
||||
),
|
||||
|
||||
NotificationListener<ScrollNotification>(
|
||||
onNotification: _onScroll,
|
||||
child: // List
|
||||
Expanded(
|
||||
child:
|
||||
_list.isEmpty
|
||||
? NoDataWidget.show()
|
||||
: ListView.builder(
|
||||
itemCount: _list.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _itemCellTwo(_list[index]);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool _onScroll(ScrollNotification n) {
|
||||
if (n.metrics.pixels > n.metrics.maxScrollExtent - 100 &&
|
||||
_hasMore &&
|
||||
!_isLoading) {
|
||||
pageNum++;
|
||||
_getListData(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Widget _itemCellTwo(final item) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => NotifDetailPage(
|
||||
item,
|
||||
_selectedTab,
|
||||
onClose: (result) {
|
||||
print('详情页面已关闭,返回结果: $result');
|
||||
reRefreshData();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Card(
|
||||
margin: EdgeInsets.all(8.0),
|
||||
color: Colors.white,
|
||||
elevation: 2.0,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题
|
||||
Text(
|
||||
item['title']??'',
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 8.0),
|
||||
|
||||
Text(
|
||||
'发布时间:${item['publishTime']??''}',
|
||||
style: TextStyle(fontSize: 14.0, color: Colors.grey[500]),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 8.0),
|
||||
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
item['readStatus']=='1'?'已阅':'待阅',
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6.0),
|
||||
Image.asset(
|
||||
item['readStatus']=='1'?'assets/icon-apps/read_message.png':'assets/icon-apps/unread_message.png',
|
||||
width: 25,
|
||||
height: 25,
|
||||
),
|
||||
const SizedBox(width: 6.0),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Widget _itemCell(final item) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => NotifDetailPage(
|
||||
item,
|
||||
_selectedTab,
|
||||
onClose: (result) {
|
||||
print('详情页面已关闭,返回结果: $result');
|
||||
reRefreshData();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 10,
|
||||
),
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: Text(item['SYNOPSIS'], style: const TextStyle(fontSize: 14)),
|
||||
),
|
||||
subtitle: Text(
|
||||
item['CREATTIME'],
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
trailing: Container(
|
||||
constraints: const BoxConstraints(minHeight: 100),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
if (0 != _selectedTab)
|
||||
Text(
|
||||
item['TYPE'] == 1 ? '已读' : '未读',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: item['TYPE'] == 1 ? Colors.grey : Colors.red,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
if (0 != _selectedTab && item['TYPE'] == 1)
|
||||
SizedBox(
|
||||
height: 24,
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
final ok = await CustomAlertDialog.showConfirm(
|
||||
context,
|
||||
title: '确认删除',
|
||||
content: '确定要删除这条通知吗?',
|
||||
cancelText: '取消',
|
||||
);
|
||||
// if (ok) {
|
||||
// _deleteNotif(item['NOTICECORPUSERID_ID']);
|
||||
// }
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
backgroundColor: Colors.red,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'删除',
|
||||
style: TextStyle(fontSize: 13, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(height: 1, color: Colors.black12),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue