520 lines
16 KiB
Dart
520 lines
16 KiB
Dart
import 'dart:async';
|
||
import 'dart:convert';
|
||
import 'dart:ffi';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||
import 'package:qhd_prevention/pages/home/danger_auto_scrollList.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/study/study_garden_page.dart';
|
||
import 'package:qhd_prevention/pages/home/userInfo_page.dart';
|
||
import 'package:qhd_prevention/pages/home/work/danger_page.dart';
|
||
import 'package:qhd_prevention/pages/home/work/danger_wait_list_page.dart';
|
||
import 'package:qhd_prevention/pages/home/workSet_page.dart';
|
||
|
||
import '../../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> {
|
||
late int _eight_work_count = 0;
|
||
late int _safetyEnvironmentalInspection = 0;
|
||
late final List<Map<String, dynamic>> buttonInfos;
|
||
|
||
/// 我的工作
|
||
List<Map<String, dynamic>> workInfos = [];
|
||
final 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 Future.delayed(const Duration(seconds: 2));
|
||
// 刷新数据逻辑,如 fetchData()
|
||
setState(() {
|
||
// TODO: 更新数据源
|
||
});
|
||
}
|
||
|
||
@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),
|
||
ListItemFactory.createBuildSimpleSection("隐患播报"),
|
||
const SizedBox(height: 10),
|
||
_buildPCDataSection(),
|
||
SizedBox(height: 50),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
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: [
|
||
ListItemFactory.createBuildSimpleSection("排查数据"),
|
||
...pcData.map(_widgetPCDataItem),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 定义 item 宽度
|
||
double _itemWidth(BuildContext context) {
|
||
final screenW = MediaQuery.of(context).size.width;
|
||
return (screenW - 20) / 4;
|
||
}
|
||
|
||
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,
|
||
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,
|
||
onPressed: () {
|
||
final index = entry.key;
|
||
// 你的导航逻辑
|
||
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(LowPage(), context);
|
||
}
|
||
else if (index == 7) {
|
||
pushPage(StudyGardenPage(), context);
|
||
}
|
||
|
||
},
|
||
);
|
||
}).toList(),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildIconButton({
|
||
required BuildContext context,
|
||
required String iconPath,
|
||
required String label,
|
||
required VoidCallback onPressed,
|
||
int unreadCount = 0,
|
||
}) {
|
||
final w = _itemWidth(context);
|
||
return InkWell(
|
||
onTap: onPressed,
|
||
borderRadius: BorderRadius.circular(8),
|
||
child: SizedBox(
|
||
width: w,
|
||
child: Stack(
|
||
clipBehavior: Clip.none,
|
||
children: [
|
||
/// 中心对齐
|
||
Align(
|
||
alignment: Alignment.topCenter,
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Image.asset(iconPath, width: 40, height: 40),
|
||
const SizedBox(height: 5),
|
||
Text(label, style: const TextStyle(fontSize: 14)),
|
||
],
|
||
),
|
||
),
|
||
if (unreadCount > 0)
|
||
Positioned(
|
||
right: -4,
|
||
top: -4,
|
||
child: Container(
|
||
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: Text(
|
||
unreadCount > 99 ? '99+' : '$unreadCount',
|
||
style: const TextStyle(
|
||
color: Colors.white,
|
||
fontSize: 10,
|
||
height: 1,
|
||
),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
// 排查数据列表 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(), 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,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
void initState() {
|
||
super.initState();
|
||
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": _eight_work_count,
|
||
},
|
||
{
|
||
"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": _safetyEnvironmentalInspection,
|
||
},
|
||
{
|
||
"icon": "assets/icon-apps/home-speEquip.jpg",
|
||
"title": "设备巡检",
|
||
"unreadCount": 0,
|
||
},
|
||
{
|
||
"icon": "assets/icon-apps/safetymeeting.png",
|
||
"title": "安全例会",
|
||
"unreadCount": 0,
|
||
},
|
||
];
|
||
|
||
_fetchData(); // 初始化时请求
|
||
|
||
}
|
||
Future<void> _fetchData() async {
|
||
try {
|
||
// “我的工作” 数量
|
||
final raw = await ApiService.getWork();
|
||
// 如果拿到的是 String,就 decode;如果本来就是 Map,就直接用
|
||
final Map<String, dynamic> data = raw is String
|
||
? json.decode(raw as String) as Map<String, dynamic>
|
||
: raw;
|
||
|
||
final hidCount = data['hidCount'] as Map<String, dynamic>;
|
||
setState(() {
|
||
workInfos = [
|
||
{
|
||
"icon": "assets/icon-apps/jobico1.png",
|
||
"index": 1,
|
||
"detail": "待排查",
|
||
"num": (hidCount['dpc'] ?? 0).toString(),
|
||
},
|
||
{
|
||
"icon": "assets/icon-apps/jobico2.png",
|
||
"index": 2,
|
||
"detail": "待整改",
|
||
"num": (hidCount['dzg'] ?? 0).toString(),
|
||
},
|
||
{
|
||
"icon": "assets/icon-apps/jobico3.png",
|
||
"index": 3,
|
||
"detail": "已超期",
|
||
"num": (hidCount['ycq'] ?? 0).toString(),
|
||
},
|
||
{
|
||
"icon": "assets/icon-apps/jobico4.png",
|
||
"index": 4,
|
||
"detail": "待验收",
|
||
"num": (hidCount['dys'] ?? 0).toString(),
|
||
},
|
||
{
|
||
"icon": "assets/icon-apps/jobico5.png",
|
||
"index": 5,
|
||
"detail": "已验收",
|
||
"num": (hidCount['yys'] ?? 0).toString(),
|
||
},
|
||
];
|
||
|
||
});
|
||
// 安全检查数
|
||
final checkJson =
|
||
await ApiService.getSafetyEnvironmentalInspectionCount();
|
||
setState(() {
|
||
int confirmCount = checkJson['confirmCount']['confirmCount'];
|
||
int repulseCount = checkJson['repulseCount']['repulseCount'];
|
||
int repulseAndCheckCount = checkJson['repulseAndCheckCount']['repulseAndCheckCount'];
|
||
|
||
_safetyEnvironmentalInspection = confirmCount + repulseCount + repulseAndCheckCount;
|
||
});
|
||
|
||
// 特殊作业红点
|
||
final redPointJson = await ApiService.getRedPoint();
|
||
setState(() {
|
||
final countMap = redPointJson['count'] as Map<String, dynamic>;
|
||
for (var item in countMap.values) {
|
||
_eight_work_count += (item ?? 0) as int;
|
||
}
|
||
});
|
||
|
||
|
||
} catch (e) {
|
||
// 出错时可以 Toast 或者在页面上显示错误状态
|
||
print('加载首页数据失败:$e');
|
||
}
|
||
}
|
||
}
|