498 lines
14 KiB
Dart
498 lines
14 KiB
Dart
|
|
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),
|
|||
|
|
],
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|