qhd-prevention-flutter/lib/pages/home/home_page.dart

497 lines
16 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:async';
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/pages/app/Danger_paicha/danger_page.dart';
import 'package:qhd_prevention/pages/badge_manager.dart';
import 'package:qhd_prevention/pages/home/hidden_roll_widget.dart';
import 'package:qhd_prevention/pages/home/low_page.dart';
import 'package:qhd_prevention/pages/home/risk/riskControl_page.dart';
import 'package:qhd_prevention/pages/home/userInfo_page.dart';
import 'package:qhd_prevention/pages/app/hidden_danger_management/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/home/workSet_page.dart';
import 'package:qhd_prevention/pages/http/ApiService.dart';
import '../../tools/tools.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _eight_work_count = 0;
int _safetyEnvironmentalInspection = 0;
/// 隐患播报列表及状态
List<Map<String, dynamic>> hiddenList = [];
bool _initialLoadingHidden = true;
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 '';
}
}
late List<Map<String, String>> buttonInfos = [
{"icon": "assets/icon-apps/home-base.png", "title": "人员信息"},
{"icon": "assets/icon-apps/home-rili.png", "title": "工作安排"},
{"icon": "assets/icon-apps/home-risk.png", "title": "风险布控"},
{"icon": "assets/icon-apps/home-fl.png", "title": "法律法规"},
];
late List<Map<String, dynamic>> workInfos = [
{
"icon": "assets/icon-apps/jobico1.png",
"num": "0",
"detail": "待排查",
"index": 1,
},
{
"icon": "assets/icon-apps/jobico2.png",
"num": "0",
"detail": "待整改",
"index": 2,
},
{
"icon": "assets/icon-apps/jobico3.png",
"num": "0",
"detail": "已超期",
"index": 3,
},
{
"icon": "assets/icon-apps/jobico4.png",
"num": "0",
"detail": "待验收",
"index": 4,
},
{
"icon": "assets/icon-apps/jobico5.png",
"num": "0",
"detail": "已验收",
"index": 5,
},
];
late List<Map<String, dynamic>> pcData = [
{
"index": 1,
"detail": {"jiancha": "2", "yinhuan": "20", "yanshou": "4"},
},
{
"index": 2,
"detail": {"jiancha": "4", "yinhuan": "10", "yanshou": "5"},
},
{
"index": 3,
"detail": {"jiancha": "3", "yinhuan": "23", "yanshou": "3"},
},
];
final List<List<String>> tagLabels = [
['', ''],
['', ''],
['', ''],
];
Future<void> _onRefresh() async {
await BadgeManager().initAllModules();
await Future.wait([
_fetchData(),
_fetchHiddenList(showLoading: false),
]);
}
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 {
// “我的工作”数据
final data = await ApiService.getWork();
final hidCount = data['hidCount'] as Map<String, dynamic>? ?? {};
// 告知BadgeManager去更新“安全巡检”和“八项作业”角标
BadgeManager().updateEnvInspectCount();
BadgeManager().updateEightWorkCount();
// 拉取其他数据
final results = await Future.wait([
ApiService.getUserData(),
ApiService.getDeptData(),
ApiService.getSuperviseDeptData(),
]);
final myData = results[0];
final deptData = results[1];
final superDeptData= results[2];
//更新页面状态
setState(() {
// ———— 更新 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();
// ———— 从 BadgeManager 拿最新的本页角标 ————
_safetyEnvironmentalInspection = BadgeManager().envInspectCount;
_eight_work_count = BadgeManager().eightWorkCount;
// ———— 更新 buttonInfos 中两个角标位置 ————
buttonInfos = buttonInfos.map((info) {
switch (info['title'] as String) {
case '特殊作业':
info['unreadCount'] = _eight_work_count as String;
break;
case '安全检查':
info['unreadCount'] = _safetyEnvironmentalInspection as String;
break;
default:
// 其它保持原样
break;
}
return info;
}).toList();
// ———— 更新排查数据 pcData ————
pcData = [
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();
});
} catch (e) {
debugPrint('加载首页数据失败:$e');
}
}
@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),
Container(
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),
],
)
),
const SizedBox(height: 10),
_buildPCDataSection(),
SizedBox(height: 50),
],
),
),
);
}
Widget _buildIconSection(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:
buttonInfos.asMap().entries.map((entry) {
final index = entry.key; // 获取当前索引
final btnInfo = entry.value; // 获取按钮信息
return _buildIconButton(
icon: Image.asset(btnInfo["icon"]!, width: 40, height: 40),
label: btnInfo["title"]!,
onPressed: () {
// 使用索引判断点击的是哪个按钮
print("点击了第 $index 个按钮");
if (index == 0) {
pushPage(UserinfoPage(), context);
} else if (index == 1) {
pushPage(WorkSetPage(), context);
} else if (index == 2) {
pushPage(RiskControlPage(), context);
} else if (index == 3) {
pushPage(LawsRegulationsPage(), context);
}
},
);
}).toList(),
),
);
}
Widget _buildWorkSection(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// _widgetTopTip(title: "我的工作"),
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,
children:
workInfos.map((info) {
return SizedBox(
width: itemWidth,
child: _buildGridItem(
context,
icon: info["icon"]!,
title: info["num"]!,
subtitle: info["detail"]!,
index: info["index"]!,
),
);
}).toList(),
);
},
),
),
],
),
);
}
Widget _buildPCDataSection() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// _widgetTopTip(title: "排查数据"),
ListItemFactory.createBuildSimpleSection("排查数据"),
...pcData.map(_widgetPCDataItem),
],
),
);
}
// 构建图标按钮:图上文字下
Widget _buildIconButton({
required Widget icon,
required String label,
required VoidCallback onPressed, // 添加点击回调参数
}) {
return InkWell(
onTap: onPressed, // 处理点击事件
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
icon,
const SizedBox(height: 5),
Text(label, style: const TextStyle(fontSize: 14)),
],
),
),
);
}
// 排查数据列表 item
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)];
final int idx = int.tryParse(item["index"].toString())! - 1;
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: [
Text(
values[i],
style: TextStyle(
color: colors[i],
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
labels[i],
style: TextStyle(color: Colors.black38, fontSize: 15),
),
],
),
Container(
color: idx == 0 ? Colors.red : Colors.blue,
width: 20,
height: 40,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
tagLabels[idx][0],
style: TextStyle(color: Colors.white, fontSize: 12),
),
Text(
tagLabels[idx][1],
style: TextStyle(color: Colors.white, fontSize: 12),
),
],
),
),
],
),
SizedBox(height: 10),
Divider(height: 1, color: Colors.black12),
],
),
);
}
// 构建灰色网格项
Widget _buildGridItem(
BuildContext context, {
required String icon,
required String title,
required String subtitle,
required int index,
}) {
return GestureDetector(
onTap: () {
if (index == 1) {
pushPage(DangerPage(1), context);
} else if (index == 2) {
pushPage(DangerWaitListPage(DangerType.wait, 2), context);
} else if (index == 3) {
pushPage(DangerWaitListPage(DangerType.expired, 3), context);
} else if (index == 4) {
pushPage(DangerWaitListPage(DangerType.waitAcceptance, 4), context);
} else if (index == 5) {
pushPage(DangerWaitListPage(DangerType.acceptance, 5), context);
}
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xfbf9f9ff),
borderRadius: BorderRadius.circular(6),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(icon, width: 35, height: 35),
const SizedBox(width: 15),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
subtitle,
style: const TextStyle(fontSize: 14, color: Colors.black),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
);
}
}