flutter_integrated_whb/lib/pages/home/home_page.dart

496 lines
17 KiB
Dart
Raw Normal View History

2025-07-11 11:03:21 +08:00
import 'dart:async';
2025-07-24 09:38:06 +08:00
2025-07-11 11:03:21 +08:00
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
2025-08-12 10:57:07 +08:00
import 'package:qhd_prevention/pages/KeyProjects/keyProjects_tab_list.dart';
2025-08-07 17:33:16 +08:00
import 'package:qhd_prevention/pages/badge_manager.dart';
2025-07-30 10:51:07 +08:00
import 'package:qhd_prevention/pages/home/NFC/home_nfc_list_page.dart';
2025-08-14 15:05:48 +08:00
import 'package:qhd_prevention/pages/home/SafeCheck/safeCheck_tab_list.dart';
import 'package:qhd_prevention/pages/home/home_danger_page.dart';
2025-07-11 11:03:21 +08:00
import 'package:qhd_prevention/pages/home/low_page.dart';
import 'package:qhd_prevention/pages/home/risk/riskControl_page.dart';
2025-07-16 08:37:08 +08:00
import 'package:qhd_prevention/pages/home/study/study_garden_page.dart';
2025-07-24 09:38:06 +08:00
import 'package:qhd_prevention/pages/home/tap/tabList/work_tab_list_page.dart';
2025-07-11 11:03:21 +08:00
import 'package:qhd_prevention/pages/home/userInfo_page.dart';
import 'package:qhd_prevention/pages/home/work/danger_page.dart';
import 'package:qhd_prevention/pages/app/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/home/work/laws_regulations_page.dart';
2025-07-11 11:03:21 +08:00
import 'package:qhd_prevention/pages/home/workSet_page.dart';
2025-08-08 10:51:48 +08:00
import 'Safetymeeting/safety_meeting_list_page.dart';
2025-07-28 14:22:07 +08:00
import 'hidden_roll_widget.dart';
2025-07-15 08:32:50 +08:00
import '../../http/ApiService.dart';
2025-07-11 11:03:21 +08:00
import '../../tools/tools.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
2025-08-06 13:43:22 +08:00
int _eight_work_count = 0;
int _safetyEnvironmentalInspection = 0;
2025-08-07 17:33:16 +08:00
String _workKey(int idx) {
switch (idx) {
case 1:
return 'dpc'; // 待排查
case 2:
return 'dzg'; // 待整改
case 3:
return 'ycq'; // 已超期
case 4:
return 'dys'; // 待验收
case 5:
return 'yys'; // 已验收
default:
return '';
}
}
2025-08-06 13:43:22 +08:00
/// 按钮信息
List<Map<String, dynamic>> buttonInfos = [
{"icon": "assets/icon-apps/home-base.png", "title": "人员信息", "unreadCount": 0},
{"icon": "assets/icon-apps/home-rili.png", "title": "工作安排", "unreadCount": 0},
{"icon": "assets/icon-apps/home-risk.png", "title": "风险布控", "unreadCount": 0},
{"icon": "assets/icon-apps/home-fl.png", "title": "法律法规", "unreadCount": 0},
{"icon": "assets/icon-apps/home-gw.png", "title": "特殊作业", "unreadCount": 0},
{"icon": "assets/icon-apps/home-zdgcgl.jpg", "title": "重点工程管理", "unreadCount": 0},
{"icon": "assets/icon-apps/home-cns.png", "title": "安全承诺", "unreadCount": 0},
{"icon": "assets/icon-apps/home-study.png", "title": "学习园地", "unreadCount": 0},
{"icon": "assets/icon-apps/home-base.png", "title": "安全检查", "unreadCount": 0},
{"icon": "assets/icon-apps/home-speEquip.jpg", "title": "设备巡检", "unreadCount": 0},
{"icon": "assets/icon-apps/safetymeeting.png", "title": "安全例会", "unreadCount": 0},
{"icon": "assets/icon-apps/home-xj.png", "title": "燃气巡检", "unreadCount": 0},
];
2025-07-15 08:32:50 +08:00
/// 我的工作
2025-08-06 13:43:22 +08:00
List<Map<String, dynamic>> workInfos = [
{"icon": "assets/icon-apps/jobico1.png", "index": 1, "detail": "待排查", "num": '0'},
{"icon": "assets/icon-apps/jobico2.png", "index": 2, "detail": "待整改", "num": '0'},
{"icon": "assets/icon-apps/jobico3.png", "index": 3, "detail": "已超期", "num": '0'},
{"icon": "assets/icon-apps/jobico4.png", "index": 4, "detail": "待验收", "num": '0'},
{"icon": "assets/icon-apps/jobico5.png", "index": 5, "detail": "已验收", "num": '0'},
];
2025-07-24 09:38:06 +08:00
/// 排查数据
2025-08-06 13:43:22 +08:00
List<Map<String, dynamic>> pcData = [
{"index": 1, "detail": {"jiancha": '0', "yinhuan": '0', "yanshou": '0'}},
{"index": 2, "detail": {"jiancha": '0', "yinhuan": '0', "yanshou": '0'}},
{"index": 3, "detail": {"jiancha": '0', "yinhuan": '0', "yanshou": '0'}},
];
/// 隐患播报列表及状态
List<Map<String, dynamic>> hiddenList = [];
bool _initialLoadingHidden = true;
2025-07-11 11:03:21 +08:00
final List<List<String>> tagLabels = [
['', ''],
['', ''],
['', ''],
];
2025-08-06 13:43:22 +08:00
@override
void initState() {
super.initState();
2025-08-07 17:33:16 +08:00
2025-08-06 13:43:22 +08:00
_onRefresh();
}
2025-07-11 11:03:21 +08:00
Future<void> _onRefresh() async {
2025-08-07 17:33:16 +08:00
await BadgeManager().initAllModules();
2025-08-06 13:43:22 +08:00
await Future.wait([
_fetchData(),
_fetchHiddenList(showLoading: false),
]);
}
2025-08-07 17:33:16 +08:00
2025-08-06 13:43:22 +08:00
Future<void> _fetchHiddenList({bool showLoading = true}) async {
// 保留已有列表仅首次显示loading
if (showLoading && hiddenList.isEmpty) setState(() {});
try {
final res = await ApiService.getHiddenRoll().timeout(Duration(seconds: 10));
final list = (res['hiddenList'] as List).cast<Map<String, dynamic>>();
setState(() {
hiddenList = list;
_initialLoadingHidden = false;
});
} catch (e) {
// 超时或失败且已有数据,则不处理
if (hiddenList.isEmpty) {
setState(() {
_initialLoadingHidden = false;
});
}
}
}
Future<void> _fetchData() async {
try {
2025-08-07 17:33:16 +08:00
// “我的工作”数据
2025-08-06 13:43:22 +08:00
final data = await ApiService.getWork();
final hidCount = data['hidCount'] as Map<String, dynamic>? ?? {};
2025-08-07 17:33:16 +08:00
// 告知BadgeManager去更新“安全巡检”和“八项作业”角标
BadgeManager().updateEnvInspectCount();
BadgeManager().updateEightWorkCount();
// 拉取其他数据
2025-08-06 13:43:22 +08:00
final results = await Future.wait([
ApiService.getUserData(),
ApiService.getDeptData(),
ApiService.getSuperviseDeptData(),
]);
2025-08-07 17:33:16 +08:00
final myData = results[0];
final deptData = results[1];
final superDeptData= results[2];
2025-08-06 13:43:22 +08:00
2025-08-07 17:33:16 +08:00
//更新页面状态
2025-08-06 13:43:22 +08:00
setState(() {
2025-08-07 17:33:16 +08:00
// ———— 更新 workInfos ————
workInfos = workInfos.map((info) {
final idx = info['index'] as int;
final key = _workKey(idx);
final num = (hidCount[key] ?? 0).toString();
return {...info, 'num': num};
}).toList();
2025-08-06 13:43:22 +08:00
2025-08-07 17:33:16 +08:00
// ———— 从 BadgeManager 拿最新的本页角标 ————
_safetyEnvironmentalInspection = BadgeManager().envInspectCount;
_eight_work_count = BadgeManager().eightWorkCount;
2025-08-06 13:43:22 +08:00
2025-08-07 17:33:16 +08:00
// ———— 更新 buttonInfos 中两个角标位置 ————
buttonInfos = buttonInfos.map((info) {
switch (info['title'] as String) {
case '特殊作业':
info['unreadCount'] = _eight_work_count;
break;
case '安全检查':
info['unreadCount'] = _safetyEnvironmentalInspection;
break;
default:
// 其它保持原样
break;
}
return info;
}).toList();
2025-08-06 13:43:22 +08:00
2025-08-07 17:33:16 +08:00
// ———— 更新排查数据 pcData ————
2025-08-06 13:43:22 +08:00
pcData = [
2025-08-07 17:33:16 +08:00
myData,
deptData,
superDeptData,
].asMap().entries.map((entry) {
final idx = entry.key;
final pdMap = (entry.value['pd'] as Map<String, dynamic>? ) ?? {};
return {
'index': idx + 1,
'detail': {
'jiancha': pdMap['check_count']?.toString() ?? '0',
'yinhuan': pdMap['hidden_count']?.toString() ?? '0',
'yanshou': pdMap['rectify_count']?.toString() ?? '0',
},
};
}).toList();
2025-08-06 13:43:22 +08:00
});
} catch (e) {
2025-08-07 17:33:16 +08:00
debugPrint('加载首页数据失败:$e');
2025-08-06 13:43:22 +08:00
}
2025-07-11 11:03:21 +08:00
}
2025-08-07 17:33:16 +08:00
2025-07-11 11:03:21 +08:00
@override
Widget build(BuildContext context) {
return Scaffold(
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(10),
children: [
ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.asset('assets/images/banner.jpg', fit: BoxFit.cover),
),
const SizedBox(height: 10),
_buildIconSection(context),
const SizedBox(height: 10),
_buildWorkSection(context),
const SizedBox(height: 10),
2025-07-22 13:34:34 +08:00
Container(
2025-08-08 10:52:15 +08:00
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: Column(
children: [
ListItemFactory.createBuildSimpleSection("隐患播报"),
_initialLoadingHidden && hiddenList.isEmpty
? SizedBox(
height: 150,
child: Center(child: CircularProgressIndicator()),
)
: HiddenRollWidget(hiddenList: hiddenList),
],
2025-08-06 13:43:22 +08:00
)
2025-07-22 13:34:34 +08:00
),
2025-07-11 11:03:21 +08:00
const SizedBox(height: 10),
_buildPCDataSection(),
2025-07-22 13:34:34 +08:00
SizedBox(height: 20),
2025-07-11 11:03:21 +08:00
],
),
),
);
}
Widget _buildWorkSection(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ListItemFactory.createBuildSimpleSection("我的工作"),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 10),
child: LayoutBuilder(
builder: (context, constraints) {
const spacing = 10.0;
final totalWidth = constraints.maxWidth;
final itemWidth = (totalWidth - spacing * 2) / 3;
return Wrap(
spacing: spacing,
runSpacing: spacing,
2025-08-06 13:43:22 +08:00
children: workInfos.map((info) {
return SizedBox(
width: itemWidth,
child: _buildGridItem(
context,
icon: info["icon"]!,
title: info["num"]!,
subtitle: info["detail"]!,
index: info["index"]!,
),
);
}).toList(),
2025-07-11 11:03:21 +08:00
);
},
),
),
],
),
);
}
Widget _buildPCDataSection() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ListItemFactory.createBuildSimpleSection("排查数据"),
...pcData.map(_widgetPCDataItem),
],
),
);
}
2025-08-06 13:43:22 +08:00
double _itemWidth(BuildContext context) => (MediaQuery.of(context).size.width - 20) / 4;
2025-07-15 08:32:50 +08:00
Widget _buildIconSection(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Wrap(
runSpacing: 16,
2025-08-06 13:43:22 +08:00
children: buttonInfos.asMap().entries.map((entry) {
final idx = entry.key;
final info = entry.value;
return _buildIconButton(
context: context,
iconPath: info["icon"] as String,
label: info["title"] as String,
unreadCount: info["unreadCount"] as int,
2025-08-07 17:33:16 +08:00
onPressed: () async {
2025-08-06 13:43:22 +08:00
switch (idx) {
2025-08-12 10:57:07 +08:00
case 0:// 人员信息
2025-08-06 13:43:22 +08:00
pushPage(UserinfoPage(), context);
break;
2025-08-12 10:57:07 +08:00
case 1:// 法律法规
2025-08-06 13:43:22 +08:00
pushPage(WorkSetPage(), context);
break;
2025-08-12 10:57:07 +08:00
case 2:// 风险布控
2025-08-06 13:43:22 +08:00
pushPage(RiskControlPage(), context);
break;
2025-08-12 10:57:07 +08:00
case 3:// 法律法规
2025-08-06 13:43:22 +08:00
pushPage(LawsRegulationsPage(), context);
break;
2025-08-12 10:57:07 +08:00
case 4:// 八项作业
2025-08-07 17:33:16 +08:00
await pushPage(WorkTabListPage(), context);
2025-08-06 13:43:22 +08:00
break;
2025-08-12 10:57:07 +08:00
case 5: // 重点工程管理
await pushPage(KeyprojectsTabList(), context);
break;
2025-08-06 13:43:22 +08:00
case 7:
pushPage(StudyGardenPage(), context);
break;
2025-08-14 15:05:48 +08:00
case 8: // 安全检查
await pushPage(SafecheckTabList(), context);
break;
2025-08-08 10:51:48 +08:00
case 10:
pushPage(SafetyMeetingListPage(), context);
break;
2025-08-06 13:43:22 +08:00
case 11:
pushPage(HomeNfcListPage(), context);
break;
}
2025-08-07 17:33:16 +08:00
_onRefresh();
2025-08-06 13:43:22 +08:00
},
);
}).toList(),
2025-07-15 08:32:50 +08:00
),
);
}
2025-07-11 11:03:21 +08:00
Widget _buildIconButton({
2025-07-15 08:32:50 +08:00
required BuildContext context,
required String iconPath,
2025-07-11 11:03:21 +08:00
required String label,
2025-07-15 08:32:50 +08:00
required VoidCallback onPressed,
int unreadCount = 0,
2025-07-11 11:03:21 +08:00
}) {
2025-07-15 08:32:50 +08:00
final w = _itemWidth(context);
2025-07-11 11:03:21 +08:00
return InkWell(
2025-07-15 08:32:50 +08:00
onTap: onPressed,
2025-07-11 11:03:21 +08:00
borderRadius: BorderRadius.circular(8),
2025-07-15 08:32:50 +08:00
child: SizedBox(
width: w,
child: Stack(
clipBehavior: Clip.none,
2025-07-11 11:03:21 +08:00
children: [
2025-07-15 08:32:50 +08:00
Align(
alignment: Alignment.topCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset(iconPath, width: 40, height: 40),
const SizedBox(height: 5),
Text(label, style: const TextStyle(fontSize: 14)),
],
),
),
if (unreadCount > 0)
Positioned(
2025-07-24 09:38:06 +08:00
right: 20,
top: -5,
2025-07-15 08:32:50 +08:00
child: Container(
2025-08-06 13:43:22 +08:00
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(10)),
constraints: const BoxConstraints(minWidth: 16, minHeight: 16),
child: Center(
child: Text(
unreadCount > 99 ? '99+' : '$unreadCount',
style: const TextStyle(color: Colors.white, fontSize: 11, height: 1),
textAlign: TextAlign.center,
2025-07-15 08:32:50 +08:00
),
2025-08-06 13:43:22 +08:00
)
2025-07-15 08:32:50 +08:00
),
),
2025-07-11 11:03:21 +08:00
],
),
),
);
}
Widget _widgetPCDataItem(Map<String, dynamic> item) {
final detail = item["detail"] as Map<String, String>;
final values = [detail["jiancha"]!, detail["yinhuan"]!, detail["yanshou"]!];
const labels = ["检查数", "发现隐患数", "已验收隐患数"];
const colors = [Color(0xFF3283FF), Color(0xFFF37B1D), Color(0xFF41B852)];
2025-08-06 13:43:22 +08:00
final idx = int.tryParse(item["index"].toString())! - 1;
2025-07-11 11:03:21 +08:00
return Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 10, 15),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (var i = 0; i < 3; i++)
Column(
children: [
2025-08-06 13:43:22 +08:00
Text(values[i], style: TextStyle(color: colors[i], fontSize: 18, fontWeight: FontWeight.bold)),
2025-07-11 11:03:21 +08:00
const SizedBox(height: 4),
2025-08-06 13:43:22 +08:00
Text(labels[i], style: TextStyle(color: Colors.black38, fontSize: 15)),
2025-07-11 11:03:21 +08:00
],
),
Container(
color: idx == 0 ? Colors.red : Colors.blue,
width: 20,
height: 40,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
2025-08-06 13:43:22 +08:00
Text(tagLabels[idx][0], style: TextStyle(color: Colors.white, fontSize: 12)),
Text(tagLabels[idx][1], style: TextStyle(color: Colors.white, fontSize: 12)),
2025-07-11 11:03:21 +08:00
],
),
),
],
),
SizedBox(height: 10),
Divider(height: 1, color: Colors.black12),
],
),
);
}
2025-08-06 13:43:22 +08:00
Widget _buildGridItem(BuildContext context, {required String icon, required String title, required String subtitle, required int index}) {
2025-07-11 11:03:21 +08:00
return GestureDetector(
onTap: () {
if (index == 1) {
pushPage(HomeDangerPage(), context);
2025-07-11 11:03:21 +08:00
} else if (index == 2) {
2025-07-22 13:34:34 +08:00
pushPage(DangerWaitListPage(DangerType.wait, 2), context);
2025-07-11 11:03:21 +08:00
} else if (index == 3) {
2025-07-22 13:34:34 +08:00
pushPage(DangerWaitListPage(DangerType.expired, 3), context);
2025-07-15 08:32:50 +08:00
} else if (index == 4) {
2025-07-22 13:34:34 +08:00
pushPage(DangerWaitListPage(DangerType.waitAcceptance, 4), context);
2025-07-15 08:32:50 +08:00
} else if (index == 5) {
2025-07-22 13:34:34 +08:00
pushPage(DangerWaitListPage(DangerType.acceptance, 5), context);
2025-07-11 11:03:21 +08:00
}
},
child: Container(
padding: const EdgeInsets.all(8),
2025-08-06 13:43:22 +08:00
decoration: BoxDecoration(color: const Color(0xfbf9f9ff), borderRadius: BorderRadius.circular(6)),
2025-07-11 11:03:21 +08:00
child: Row(
children: [
Image.asset(icon, width: 35, height: 35),
2025-07-28 14:22:07 +08:00
const SizedBox(width: 5),
2025-07-11 11:03:21 +08:00
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
2025-08-06 13:43:22 +08:00
Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis),
2025-07-11 11:03:21 +08:00
const SizedBox(height: 4),
2025-08-06 13:43:22 +08:00
Text(subtitle, style: const TextStyle(fontSize: 14, color: Colors.black), maxLines: 1, overflow: TextOverflow.ellipsis),
2025-07-11 11:03:21 +08:00
],
),
),
],
),
),
);
}
}