Commit 95ab7cfd authored by 张宏's avatar 张宏

.

parent 3978e40d
...@@ -23,5 +23,7 @@ class AppRouter extends $AppRouter { ...@@ -23,5 +23,7 @@ class AppRouter extends $AppRouter {
AutoRoute(page: AbnormalDetailRoute.page), AutoRoute(page: AbnormalDetailRoute.page),
AutoRoute(page:DeviceDetailRoute.page), AutoRoute(page:DeviceDetailRoute.page),
AutoRoute(page: ServiceRoomDetailRoute.page), AutoRoute(page: ServiceRoomDetailRoute.page),
AutoRoute(page: ReportEnergyDetailRoute.page),
AutoRoute(page: ReportRoomDetailRoute.page),
]; ];
} }
This diff is collapsed.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/home/index/controller.dart';
class EquipmentListBlock extends StatefulWidget { class EquipmentListBlock extends StatefulWidget {
const EquipmentListBlock({super.key}); final HomeIndexController controller;
const EquipmentListBlock({super.key, required this.controller});
@override @override
State<EquipmentListBlock> createState() => _EquipmentListBlockState(); State<EquipmentListBlock> createState() => _EquipmentListBlockState();
} }
class _EquipmentListBlockState extends State<EquipmentListBlock> { class _EquipmentListBlockState extends State<EquipmentListBlock> {
final List<Map<String, dynamic>> _equipmentList = [ Widget _buildEquipmentItem(EquipmentItem item) {
{
'icon': Icons.electrical_services,
'title': '空调主机-01',
'subtitle': '位置:A栋3楼机房',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.thermostat,
'title': '温度传感器-02',
'subtitle': '位置:B栋2楼走廊',
'status': '异常',
'statusColor': Color.fromRGBO(246, 158, 11, 1),
},
{
'icon': Icons.water_drop,
'title': '水管阀门-03',
'subtitle': '位置:C栋1楼大厅',
'status': '待检修',
'statusColor': Color.fromRGBO(239, 68, 68, 1),
},
{
'icon': Icons.lightbulb,
'title': '照明系统-04',
'subtitle': '位置:D栋5楼会议室',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.electrical_services,
'title': '空调主机-05',
'subtitle': '位置:A栋3楼机房',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.thermostat,
'title': '温度传感器-06',
'subtitle': '位置:B栋2楼走廊',
'status': '异常',
'statusColor': Color.fromRGBO(246, 158, 11, 1),
},
{
'icon': Icons.water_drop,
'title': '水管阀门-07',
'subtitle': '位置:C栋1楼大厅',
'status': '待检修',
'statusColor': Color.fromRGBO(239, 68, 68, 1),
},
{
'icon': Icons.lightbulb,
'title': '照明系统-08',
'subtitle': '位置:D栋5楼会议室',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.lightbulb,
'title': '照明系统-08',
'subtitle': '位置:D栋5楼会议室',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.lightbulb,
'title': '照明系统-08',
'subtitle': '位置:D栋5楼会议室',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.lightbulb,
'title': '照明系统-08',
'subtitle': '位置:D栋5楼会议室',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
{
'icon': Icons.lightbulb,
'title': '照明系统-08',
'subtitle': '位置:D栋5楼会议室',
'status': '运行中',
'statusColor': Color.fromRGBO(34, 197, 94, 1),
},
];
Widget _buildEquipmentItem(Map<String, dynamic> item) {
return Container( return Container(
padding: EdgeInsets.symmetric(vertical: 8.h), padding: EdgeInsets.symmetric(vertical: 16.h),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
bottom: BorderSide( bottom: BorderSide(
color: Color.fromRGBO(71, 85, 105, 0.3), color: Color.fromRGBO(235, 235, 235, 1.0),
width: 1, width: 1.w,
), ),
), ),
), ),
child: Row( child: Row(
children: [ children: [
Container( Container(
width: 40.w, width: 64.w,
height: 40.h, height: 66.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color.fromRGBO(71, 85, 105, 0.3), color: Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(12.r),
), ),
child: Icon( child: Icon(
item['icon'] as IconData, item.icon,
color: Color.fromRGBO(246, 158, 11, 1), color: Color.fromRGBO(66, 165, 245, 1.0),
size: 20.sp, size: 32.sp,
), ),
), ),
SizedBox(width: 12.w), SizedBox(width: 16.w),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Transform.translate(
item['title'] as String, offset: Offset(0, 2.h),
style: TextStyle( child: Text(
fontSize: 14.sp, item.title,
fontWeight: FontWeight.w500, style: TextStyle(
color: Colors.white, fontSize: 28.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
), ),
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
item['subtitle'] as String, item.subtitle,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 24.sp,
color: Color.fromRGBO(148, 163, 184, 1), color: Color.fromRGBO(100, 116, 139, 1.0),
), ),
), ),
], ],
), ),
), ),
Container( Text(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), item.status,
decoration: BoxDecoration( style: TextStyle(
color: (item['statusColor'] as Color).withOpacity(0.2), fontSize: 24.sp,
borderRadius: BorderRadius.circular(4.r), fontWeight: FontWeight.bold,
), color: item.statusColor,
child: Text(
item['status'] as String,
style: TextStyle(
fontSize: 12.sp,
color: item['statusColor'] as Color,
),
), ),
), ),
], ],
...@@ -167,9 +80,11 @@ class _EquipmentListBlockState extends State<EquipmentListBlock> { ...@@ -167,9 +80,11 @@ class _EquipmentListBlockState extends State<EquipmentListBlock> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final equipmentList = widget.controller.getEquipmentList();
return Container( return Container(
width: double.infinity, width: double.infinity,
margin: EdgeInsets.only(top: 10.h,left: 20.w,right: 20.w), // margin: EdgeInsets.symmetric(horizontal: 14.w, vertical: 24.h),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
...@@ -177,29 +92,38 @@ class _EquipmentListBlockState extends State<EquipmentListBlock> { ...@@ -177,29 +92,38 @@ class _EquipmentListBlockState extends State<EquipmentListBlock> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text('设备巡检',style: TextStyle(fontSize: 14.sp,fontWeight: FontWeight.bold,color: Colors.white),), Text(
Text('查看全部',style: TextStyle(fontSize: 14.sp,fontWeight: FontWeight.bold,color: Colors.white),), '设备巡检',
style: TextStyle(
fontSize: 28.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
Text(
'查看全部>',
style: TextStyle(
fontSize: 28.sp,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(73, 149, 234, 1.0),
),
),
], ],
), ),
SizedBox(height: 12.h), SizedBox(height: 12.h),
Container( Container(
width: double.infinity, width: double.infinity,
padding: EdgeInsets.all(20.w), padding: EdgeInsets.only(top: 20.w,bottom: 20.w,left: 42.w,right: 42.w),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.r), borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(30, 41, 59, 1), color: Colors.white,
border: BoxBorder.all(
color: Color.fromRGBO(246, 158, 11, 1.0),
width: 1.w,
),
), ),
child: Column( child: Column(
children: [ children: [
..._equipmentList.map((item) => _buildEquipmentItem(item)).toList(), ...equipmentList.map((item) => _buildEquipmentItem(item)).toList(),
], ],
), ),
), ),
SizedBox(height: 20.h),
], ],
), ),
); );
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/home/index/controller.dart';
class TaskHeadBlock extends StatefulWidget { class TaskHeadBlock extends StatefulWidget {
const TaskHeadBlock({super.key}); final HomeIndexController controller;
const TaskHeadBlock({super.key, required this.controller});
@override @override
State<TaskHeadBlock> createState() => _TaskHeadBlockState(); State<TaskHeadBlock> createState() => _TaskHeadBlockState();
...@@ -13,51 +16,28 @@ class _TaskHeadBlockState extends State<TaskHeadBlock> { ...@@ -13,51 +16,28 @@ class _TaskHeadBlockState extends State<TaskHeadBlock> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: double.infinity, width: double.infinity,
height: 140.h, // height: 140.h,
padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight,left: 20.w,right: 20.w), padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.blueGrey,
width: 1.w,
),
),
// color: Colors.red,
),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Flex( Text(
direction: Axis.horizontal, '设备告警看板',
mainAxisAlignment: MainAxisAlignment.spaceBetween, style: TextStyle(
children: [ fontSize: 28.sp,
Column( fontWeight: FontWeight.bold,
crossAxisAlignment: CrossAxisAlignment.start, color: Color.fromRGBO(51, 51, 51, 1.0),
children: [ ),
Text('设备告警看板',style: TextStyle(fontSize: 28.sp,fontWeight: FontWeight.bold,color: Colors.white),), ),
Text('工程运维视角 今日xx条待处理',style: TextStyle(fontSize: 24.sp,color: Color.fromRGBO(61, 79, 106, 1.0)),), SizedBox(height: 8.h),
], Text(
), '工程运维视角·今日${widget.controller.getPendingTaskCount()}条待处理',
Container( style: TextStyle(
width: 50.w, fontSize: 16.sp,
height: 50.h, color: Color.fromRGBO(102, 102, 102, 1.0),
decoration: BoxDecoration( ),
borderRadius: BorderRadius.circular(25.r),
color: Colors.grey,
border: Border.all(
color: Colors.blueGrey,
width: 1.w,
),
),
),
],
), ),
], ],
), ),
); );
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/home/index/controller.dart';
class TaskTotalBlock extends StatefulWidget { class TaskTotalBlock extends StatefulWidget {
const TaskTotalBlock({super.key}); final HomeIndexController controller;
const TaskTotalBlock({super.key, required this.controller});
@override @override
State<TaskTotalBlock> createState() => _TaskTotalBlockState(); State<TaskTotalBlock> createState() => _TaskTotalBlockState();
...@@ -13,143 +16,121 @@ class _TaskTotalBlockState extends State<TaskTotalBlock> { ...@@ -13,143 +16,121 @@ class _TaskTotalBlockState extends State<TaskTotalBlock> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: double.infinity, width: double.infinity,
height: 180.h, // height: 180.h,
decoration: BoxDecoration(
// color: Colors.red,
border: Border(
bottom: BorderSide(
width: 1.w,
),
),
),
alignment: Alignment.center,
child: Flex( child: Flex(
direction: Axis.horizontal, direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// 告警待处理 // 高警待处理
Column( Expanded(
mainAxisAlignment: MainAxisAlignment.center, child: Container(
children: [ margin: EdgeInsets.only(right: 10.w),
Container( height: 120.h,
width: 190.w, decoration: BoxDecoration(
height: 120.h, borderRadius: BorderRadius.circular(16.r),
decoration: BoxDecoration( color: Colors.white,
borderRadius: BorderRadius.circular(25.r),
color: Colors.white,
border: Border.all(
color: Colors.blueGrey,
width: 1.w,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('1',style: TextStyle(fontSize: 28.sp,fontWeight: FontWeight.bold,color: Colors.green),),
Text('告警待处理',style: TextStyle(fontSize: 14.sp,fontWeight: FontWeight.bold,color: Colors.grey),),
],
),
), ),
Container( child: Column(
width: 160.w, mainAxisAlignment: MainAxisAlignment.center,
height: 1.h, crossAxisAlignment: CrossAxisAlignment.center,
margin: EdgeInsets.only(top: 5.h), children: [
decoration: BoxDecoration( Text(
color: Colors.white, '${widget.controller.getHighAlarmCount()}',
border: Border(bottom: BorderSide( style: TextStyle(
color: Colors.blueGrey, fontSize: 48.sp,
width: 1.w, fontWeight: FontWeight.bold,
)), color: Color.fromRGBO(255, 77, 79, 1.0),
), ),
),
// SizedBox(height: 5.h),
Transform.translate(
offset: Offset(0, -8.h),
child: Text(
'高警待处理',
style: TextStyle(
fontSize: 24.sp,
color: Color.fromRGBO(100, 116, 139, 1.0),
),
),
),
],
), ),
], ),
), ),
// 中警待处理 // 中警待处理
Column( Expanded(
mainAxisAlignment: MainAxisAlignment.center, child: Container(
children: [ margin: EdgeInsets.symmetric(horizontal: 10.w),
Container( height: 120.h,
width: 190.w, decoration: BoxDecoration(
height: 120.h, borderRadius: BorderRadius.circular(16.r),
decoration: BoxDecoration( color: Colors.white,
borderRadius: BorderRadius.circular(25.r),
color: Colors.white,
border: Border.all(
color: Colors.blueGrey,
width: 1.w,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('12',style: TextStyle(fontSize: 28.sp,fontWeight: FontWeight.bold,color: Colors.green),),
Text('中警待处理',style: TextStyle(fontSize: 14.sp,fontWeight: FontWeight.bold,color: Colors.grey),),
],
),
), ),
Container( child: Column(
width: 160.w, mainAxisAlignment: MainAxisAlignment.center,
height: 1.h, children: [
margin: EdgeInsets.only(top: 5.h), Text(
decoration: BoxDecoration( '${widget.controller.getMediumAlarmCount()}',
color: Colors.white, style: TextStyle(
border: Border(bottom: BorderSide( fontSize: 48.sp,
color: Colors.blueGrey, fontWeight: FontWeight.bold,
width: 1.w, color: Color.fromRGBO(100, 116, 139, 1.0),
)), ),
), ),
// SizedBox(height: 8.h),
Transform.translate(
offset: Offset(0, -8.h),
child: Text(
'中警待处理',
style: TextStyle(
fontSize: 24.sp,
color: Color.fromRGBO(100, 116, 139, 1.0),
),
),
),
],
), ),
], ),
), ),
// 设备在线 // 设备在线
Column( Expanded(
mainAxisAlignment: MainAxisAlignment.center, child: Container(
children: [ margin: EdgeInsets.only(left: 10.w),
Container( height: 120.h,
width: 190.w, decoration: BoxDecoration(
height: 120.h, borderRadius: BorderRadius.circular(16.r),
decoration: BoxDecoration( color: Colors.white,
borderRadius: BorderRadius.circular(25.r),
color: Colors.white,
border: Border.all(
color: Colors.blueGrey,
width: 1.w,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('88',style: TextStyle(fontSize: 28.sp,fontWeight: FontWeight.bold,color: Colors.green),),
Text('设备在线',style: TextStyle(fontSize: 14.sp,fontWeight: FontWeight.bold,color: Colors.grey),),
],
),
), ),
Container( child: Column(
width: 160.w, mainAxisAlignment: MainAxisAlignment.center,
height: 1.h, children: [
margin: EdgeInsets.only(top: 5.h), Text(
decoration: BoxDecoration( '${widget.controller.getOnlineDeviceCount()}',
color: Colors.white, style: TextStyle(
border: Border(bottom: BorderSide( fontSize: 48.sp,
color: Colors.blueGrey, fontWeight: FontWeight.bold,
width: 1.w, color: Color.fromRGBO(26, 188, 156, 1.0),
)), ),
), ),
// SizedBox(height: 8.h),
Transform.translate(
offset: Offset(0, -8.h),
child: Text(
'设备在线',
style: TextStyle(
fontSize: 24.sp,
color: Color.fromRGBO(100, 116, 139, 1.0),
),
),
),
],
), ),
], ),
), ),
], ],
), ),
); );
} }
} }
\ No newline at end of file
...@@ -3,6 +3,22 @@ import 'package:flutter/material.dart'; ...@@ -3,6 +3,22 @@ import 'package:flutter/material.dart';
// import 'package:smart_hotel_app/routes/app_router.dart'; // import 'package:smart_hotel_app/routes/app_router.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
class EquipmentItem {
final IconData icon;
final String title;
final String subtitle;
final String status;
final Color statusColor;
EquipmentItem({
required this.icon,
required this.title,
required this.subtitle,
required this.status,
required this.statusColor,
});
}
class HomeIndexController { class HomeIndexController {
final BuildContext context; final BuildContext context;
HomeIndexController(this.context); HomeIndexController(this.context);
...@@ -10,4 +26,161 @@ class HomeIndexController { ...@@ -10,4 +26,161 @@ class HomeIndexController {
void handleToAbnormalDetail() { void handleToAbnormalDetail() {
context.pushRoute(const AbnormalDetailRoute()); context.pushRoute(const AbnormalDetailRoute());
} }
int getPendingTaskCount() {
return 3;
}
int getHighAlarmCount() {
return 1;
}
int getMediumAlarmCount() {
return 1;
}
int getOnlineDeviceCount() {
return 48;
}
String getTemperatureAlarmTitle() {
return '温度异常告警';
}
String getTemperatureAlarmLocation() {
return '客房301·A-301智能空开';
}
String getCurrentTemperature() {
return '85';
}
String getCurrentVoltage() {
return '220';
}
String getCurrentCurrent() {
return '3.2';
}
String getWaitTime() {
return '2h37m';
}
String getAlarmLevel() {
return '紧急';
}
String getVoltageAlarmTitle() {
return '电压波动告警';
}
String getVoltageAlarmLocation() {
return '会议室2F-01';
}
String getVoltageValue() {
return '248';
}
String getNormalVoltage() {
return '235';
}
String getVoltageWaitTime() {
return '1h19m';
}
String getVoltageAlarmLevel() {
return '中警';
}
List<EquipmentItem> getEquipmentList() {
return [
EquipmentItem(
icon: Icons.power,
title: '客房305空开',
subtitle: '38°C·220V·520W',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.power,
title: '大堂总空开L-01',
subtitle: '380V·42A·28.6kW',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.wifi,
title: '招牌AP-03',
subtitle: '信号弱·RSSI-78dBm',
status: '注意',
statusColor: Color.fromRGBO(255, 193, 7, 1.0),
),
EquipmentItem(
icon: Icons.power,
title: '客房201空开',
subtitle: '25°C·220V·380W',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.power,
title: '水泵控制箱',
subtitle: '运行中·2.2kW',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.thermostat,
title: '冷库温控器',
subtitle: '-18°C·异常波动',
status: '告警',
statusColor: Color.fromRGBO(255, 77, 79, 1.0),
),
EquipmentItem(
icon: Icons.light,
title: '走廊照明回路',
subtitle: '12盏·功率240W',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.wifi,
title: '会议室AP-01',
subtitle: '连接数12·信号强',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.power,
title: '电梯控制柜',
subtitle: '运行中·电压稳定',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
EquipmentItem(
icon: Icons.thermostat,
title: '空调外机',
subtitle: '压力偏高·需检查',
status: '注意',
statusColor: Color.fromRGBO(255, 193, 7, 1.0),
),
EquipmentItem(
icon: Icons.wifi,
title: '楼道AP-05',
subtitle: '离线·需重启',
status: '离线',
statusColor: Color.fromRGBO(102, 102, 102, 1.0),
),
EquipmentItem(
icon: Icons.power,
title: '厨房消毒柜',
subtitle: '消毒中·温度120°C',
status: '正常',
statusColor: Color.fromRGBO(26, 188, 156, 1.0),
),
];
}
} }
\ No newline at end of file
...@@ -39,21 +39,26 @@ class _HomeViewState extends State<HomeView> { ...@@ -39,21 +39,26 @@ class _HomeViewState extends State<HomeView> {
), ),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
color: Color.fromRGBO(15, 23, 42, 1), color: Color.fromRGBO(242, 243, 245, 1),
child: const Column( padding: EdgeInsets.symmetric(horizontal: 28.w),
children: [ child: Column(
TaskHeadBlock(), children: [
TaskTotalBlock(), TaskHeadBlock(controller: _controller),
TemperatureBlock(), SizedBox(height: 20.h),
VoltageOperateBlock(), TaskTotalBlock(controller: _controller),
EquipmentListBlock(), SizedBox(height: 20.h),
TemperatureBlock(controller: _controller),
], SizedBox(height: 20.h),
VoltageOperateBlock(controller: _controller),
SizedBox(height: 20.h),
EquipmentListBlock(controller: _controller),
SizedBox(height: 20.h),
],
),
), ),
), ),
) );
); },
},
); );
} }
} }
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
@RoutePage() @RoutePage()
...@@ -29,17 +30,64 @@ class _DefaultLayoutViewState extends State<DefaultLayoutView> { ...@@ -29,17 +30,64 @@ class _DefaultLayoutViewState extends State<DefaultLayoutView> {
onTap: tabsRouter.setActiveIndex, onTap: tabsRouter.setActiveIndex,
elevation: 0, elevation: 0,
backgroundColor: Colors.white, backgroundColor: Colors.white,
selectedItemColor: Colors.blue, selectedItemColor: const Color(0xFF4995EA),
unselectedItemColor: const Color(0xFF666666), unselectedItemColor: const Color(0xFF666666),
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
selectedFontSize: 12, selectedFontSize: 24.sp,
unselectedFontSize: 12, unselectedFontSize: 24.sp,
items: const [ items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "告警"),
BottomNavigationBarItem(icon: Icon(Icons.new_label), label: "服务"),
BottomNavigationBarItem(icon: Icon(Icons.message), label: "看板"),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.my_location), label: "我的") icon: Image.asset(
'lib/assets/tab/tab1.png',
width: 48.w,
height: 48.h,
),
activeIcon: Image.asset(
'lib/assets/tab/tab1_active.png',
width: 48.w,
height: 48.h,
),
label: "告警",
),
BottomNavigationBarItem(
icon: Image.asset(
'lib/assets/tab/tab2.png',
width: 48.w,
height: 48.h,
),
activeIcon: Image.asset(
'lib/assets/tab/tab2_active.png',
width: 48.w,
height: 48.h,
),
label: "服务",
),
BottomNavigationBarItem(
icon: Image.asset(
'lib/assets/tab/tab3.png',
width: 48.w,
height: 48.h,
),
activeIcon: Image.asset(
'lib/assets/tab/tab3_active.png',
width: 48.w,
height: 48.h,
),
label: "看板",
),
BottomNavigationBarItem(
icon: Image.asset(
'lib/assets/tab/tab4.png',
width: 48.w,
height: 48.h,
),
activeIcon: Image.asset(
'lib/assets/tab/tab4_active.png',
width: 48.w,
height: 48.h,
),
label: "我的",
),
], ],
), ),
); );
......
...@@ -15,10 +15,10 @@ class BtnLogin extends StatelessWidget { ...@@ -15,10 +15,10 @@ class BtnLogin extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: double.infinity, width: double.infinity,
height: 70.h, height: 96.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color.fromRGBO(89, 109, 243, 1), color: Color.fromRGBO(73, 149, 234, 1),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(40.w),
), ),
child: ElevatedButton( child: ElevatedButton(
onPressed: isLoading ? null : onPressed, onPressed: isLoading ? null : onPressed,
...@@ -28,17 +28,21 @@ class BtnLogin extends StatelessWidget { ...@@ -28,17 +28,21 @@ class BtnLogin extends StatelessWidget {
elevation: 0, elevation: 0,
), ),
child: isLoading child: isLoading
? const SizedBox( ? SizedBox(
width: 20, width: 40.w,
height: 20, height: 40.w,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 3.w,
color: Colors.white, color: Colors.white,
), ),
) )
: const Text( : Text(
"提交", "登录",
style: TextStyle(color: Colors.white), style: TextStyle(
color: Colors.white,
fontSize: 32.sp,
fontWeight: FontWeight.bold,
),
), ),
), ),
); );
......
...@@ -28,7 +28,7 @@ class _PasswordFieldState extends State<PasswordField> { ...@@ -28,7 +28,7 @@ class _PasswordFieldState extends State<PasswordField> {
return TextFormField( return TextFormField(
controller: widget.controller, controller: widget.controller,
obscureText: _obscureText, obscureText: _obscureText,
style: const TextStyle(color: Colors.white, fontSize: 14), style: TextStyle(color: Color(0xFF333333), fontSize: 28.sp),
validator: (val) { validator: (val) {
if (val == null || val.isEmpty) { if (val == null || val.isEmpty) {
return "密码不能为空"; return "密码不能为空";
...@@ -37,44 +37,44 @@ class _PasswordFieldState extends State<PasswordField> { ...@@ -37,44 +37,44 @@ class _PasswordFieldState extends State<PasswordField> {
}, },
decoration: InputDecoration( decoration: InputDecoration(
filled: true, filled: true,
hintText: "请输入密码", hintText: "password",
hintStyle: const TextStyle(color: Colors.white70, fontSize: 14), hintStyle: TextStyle(color: Color(0xFF999999), fontSize: 28.sp),
prefixIcon: const Icon(Icons.lock, color: Colors.white, size: 20), prefixIcon: Icon(Icons.lock, color: Color(0xFF999999), size: 40.w),
prefixIconConstraints: const BoxConstraints(minWidth: 40, minHeight: 40), prefixIconConstraints: BoxConstraints(minWidth: 80.w, minHeight: 80.w),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureText ? Icons.visibility_off : Icons.visibility, _obscureText ? Icons.visibility_off : Icons.visibility,
color: Colors.white, color: Color(0xFF999999),
size: 20, size: 40.w,
), ),
onPressed: _toggleVisibility, onPressed: _toggleVisibility,
), ),
suffixIconConstraints: const BoxConstraints(minWidth: 40, minHeight: 40), suffixIconConstraints: BoxConstraints(minWidth: 80.w, minHeight: 80.w),
contentPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), contentPadding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 24.w),
helperText: " ", helperText: " ",
helperStyle: TextStyle(height: 1.1, fontSize: 12.sp), helperStyle: TextStyle(height: 1, fontSize: 24.sp),
errorStyle: TextStyle(color: Colors.red, fontSize: 12.sp, height: 1.1), errorStyle: TextStyle(color: Colors.red, fontSize: 24.sp, height: 1),
errorMaxLines: 1, errorMaxLines: 1,
fillColor: const Color(0xFF1A2B3C), fillColor: Colors.white,
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.white30, width: 1), borderSide: BorderSide.none,
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.white30, width: 1), borderSide: BorderSide(color: Color(0xFFF5F7FA), width: 1),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.white, width: 1.5), borderSide: BorderSide(color: Color(0xFFF5F7FA), width: 1),
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.red, width: 1), borderSide: BorderSide(color: Colors.red, width: 1),
), ),
focusedErrorBorder: OutlineInputBorder( focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.red, width: 1.5), borderSide: BorderSide(color: Colors.red, width: 1.5),
), ),
), ),
); );
......
...@@ -24,42 +24,41 @@ class RememberPasswordRow extends StatelessWidget { ...@@ -24,42 +24,41 @@ class RememberPasswordRow extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( Container(
width: 32, width: 40.w,
height: 32, height: 40.w,
child: Transform.scale( child: Transform.scale(
scale: 0.7, scale: 0.8,
child: Checkbox( child: Checkbox(
value: value, value: value,
onChanged: onChanged, onChanged: onChanged,
activeColor: const Color.fromRGBO(89, 109, 243, 1), activeColor: Color(0xFF4A90E2),
checkColor: Colors.white, checkColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(25.w),
), ),
side: const BorderSide(color: Colors.white30), side: BorderSide(color: Color(0xFF4A90E2)),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
), ),
), ),
), ),
Container( SizedBox(width: 10.w),
margin: EdgeInsets.only(bottom: 2.h), Text(
child: Text( '记住密码',
'记住密码', style: TextStyle(
style: TextStyle(color: Colors.white, fontSize: 18.sp), color: Color(0xFF0A0D14),
fontSize: 24.sp,
), ),
) ),
], ],
), ),
), ),
GestureDetector( GestureDetector(
onTap: onForgotPassword, onTap: onForgotPassword,
child: Text( child: Text(
'忘记密码', '忘记密码?',
style: TextStyle( style: TextStyle(
color: Color.fromRGBO(89, 109, 243, 1), color: Color(0xFF0A0D14),
fontSize: 18.sp, fontSize: 24.sp,
), ),
), ),
), ),
......
...@@ -13,7 +13,7 @@ class UsernameField extends StatelessWidget { ...@@ -13,7 +13,7 @@ class UsernameField extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TextFormField( return TextFormField(
controller: controller, controller: controller,
style: const TextStyle(color: Colors.white, fontSize: 14), style: TextStyle(color: Color(0xFF333333), fontSize: 28.sp),
validator: (val) { validator: (val) {
if (val == null || val.isEmpty) { if (val == null || val.isEmpty) {
return "用户名不能为空哦"; return "用户名不能为空哦";
...@@ -22,35 +22,35 @@ class UsernameField extends StatelessWidget { ...@@ -22,35 +22,35 @@ class UsernameField extends StatelessWidget {
}, },
decoration: InputDecoration( decoration: InputDecoration(
filled: true, filled: true,
hintText: "请输入用户名", hintText: "admin",
hintStyle: const TextStyle(color: Colors.white70, fontSize: 14), hintStyle: TextStyle(color: Color(0xFF999999), fontSize: 28.sp),
prefixIcon: const Icon(Icons.person, color: Colors.white, size: 20), prefixIcon: Icon(Icons.person, color: Color(0xFF999999), size: 40.w),
prefixIconConstraints: const BoxConstraints(minWidth: 40, minHeight: 40), prefixIconConstraints: BoxConstraints(minWidth: 80.w, minHeight: 80.w),
contentPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), contentPadding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 24.w),
helperText: " ", helperText: " ",
helperStyle: TextStyle(height: 1, fontSize: 12.sp), helperStyle: TextStyle(height: 1, fontSize: 24.sp),
errorStyle: TextStyle(color: Colors.red, fontSize: 12.sp, height: 1), errorStyle: TextStyle(color: Colors.red, fontSize: 24.sp, height: 1),
errorMaxLines: 1, errorMaxLines: 1,
fillColor: const Color(0xFF1A2B3C), fillColor: Colors.white,
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.white30, width: 1), borderSide: BorderSide.none,
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.white30, width: 1), borderSide: BorderSide(color: Color(0xFFF5F7FA), width: 1),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.white, width: 1.5), borderSide: BorderSide(color: Color(0xFFF5F7FA), width: 1),
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.red, width: 1), borderSide: BorderSide(color: Colors.red, width: 1),
), ),
focusedErrorBorder: OutlineInputBorder( focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(24.w),
borderSide: const BorderSide(color: Colors.red, width: 1.5), borderSide: BorderSide(color: Colors.red, width: 1),
), ),
), ),
); );
......
...@@ -61,56 +61,86 @@ class _LoginViewState extends State<LoginView> { ...@@ -61,56 +61,86 @@ class _LoginViewState extends State<LoginView> {
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
padding: EdgeInsets.only(left: 50.w, right: 50.w), padding: EdgeInsets.only(left: 50.w, right: 50.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(0xFF1A2B3C), color: Color(0xFFF5F7FA),
), ),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
SizedBox(height: 150.h),
Container( Container(
margin: EdgeInsets.only(top: 150.h, bottom: 150.h), margin: EdgeInsets.only(bottom: 80.h),
child: Column( child: Column(
children: [ children: [
Image.asset( Container(
'lib/assets/znjd_logo.png', width: 160.w,
width: 100, height: 160.w,
height: 100, decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40.w),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFF00C6FF),
Color(0xFF0072FF),
],
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(40.w),
child: Image.asset(
'lib/assets/login/logo@2x.png',
fit: BoxFit.cover,
),
),
),
SizedBox(height: 40.h),
Text(
"智能酒店管理系统",
style: TextStyle(
color: Color(0xFF333333),
fontSize: 36.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 10.h),
Text(
"Intelligent Hotel Management System",
style: TextStyle(
color: Color(0xFF999999),
fontSize: 24.sp,
),
), ),
const SizedBox(height: 10),
Text("智能酒店管理系统", style: TextStyle(color: Colors.white, fontSize: 20.sp),),
Text("Intelligent Hotel Management System", style: TextStyle(color: Colors.white, fontSize: 20.sp),),
], ],
), ),
), ),
Form(
Container( key: _frmGlobalKey,
child: Form( child: Column(
key: _frmGlobalKey, mainAxisAlignment: MainAxisAlignment.center,
child: Column( children: [
mainAxisAlignment: MainAxisAlignment.center, UsernameField(
children: [ controller: _txtUserNameController,
UsernameField( ),
controller: _txtUserNameController, SizedBox(height: 20.h),
), PasswordField(
const SizedBox(height: 10), controller: _txtPwdController,
PasswordField( ),
controller: _txtPwdController, SizedBox(height: 30.h),
), RememberPasswordRow(
// const SizedBox(height: 5), value: _rememberPassword,
RememberPasswordRow( onChanged: (val) {
value: _rememberPassword, setState(() {
onChanged: (val) { _rememberPassword = val ?? false;
setState(() { });
_rememberPassword = val ?? false; },
}); onForgotPassword: _loginController.forgotPwd,
}, ),
onForgotPassword: _loginController.forgotPwd, SizedBox(height: 10.h),
), BlocConsumer<AuthBloc, AuthState>(
const SizedBox(height: 20), listener: (context, state) {
BlocConsumer<AuthBloc, AuthState>( if (state is AuthFailure) {
listener: (context, state) { Fluttertoast.showToast(
if (state is AuthFailure) {
Fluttertoast.showToast(
msg: state.error, msg: state.error,
toastLength: Toast.LENGTH_SHORT, toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER, gravity: ToastGravity.CENTER,
...@@ -118,24 +148,23 @@ class _LoginViewState extends State<LoginView> { ...@@ -118,24 +148,23 @@ class _LoginViewState extends State<LoginView> {
backgroundColor: Colors.red, backgroundColor: Colors.red,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.0); fontSize: 16.0);
} }
},
}, builder: (context, state) {
builder: (context, state) { return BtnLogin(
return BtnLogin( isLoading: state is AuthLoading,
isLoading: state is AuthLoading, onPressed: () => _loginController.login(
onPressed: () => _loginController.login( _frmGlobalKey,
_frmGlobalKey, rememberPassword: _rememberPassword,
rememberPassword: _rememberPassword, ),
), );
); },
}, ),
), ],
], ),
), ),
), ],
), ),
])
), ),
), ),
); );
......
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/energy/controller.dart';
class EnergyStatsCardBlock extends StatelessWidget {
const EnergyStatsCardBlock({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Row(
children: [
Expanded(
child: _buildCard(
'${ReportEnergyController.todayEnergy.toInt()}',
'今日(kWh)',
'${ReportEnergyController.todayEnergyChange.toInt()}%',
true,
),
),
SizedBox(width: 12.w),
Expanded(
child: _buildCard(
'${ReportEnergyController.monthEnergy.toInt()}',
'本月(kWh)',
'${ReportEnergyController.monthEnergyChange.toInt()}%',
true,
),
),
SizedBox(width: 12.w),
Expanded(
child: _buildCard(
${ReportEnergyController.monthBill.toInt()}',
'本月电费预估',
null,
null,
),
),
],
),
);
}
Widget _buildCard(String value, String label, String? change, bool? isDown) {
return Container(
padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 12.w),
decoration: BoxDecoration(
color: const Color.fromRGBO(30, 41, 59, 1),
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
value,
style: TextStyle(
color: Colors.white,
fontSize: 24.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 4.h),
Text(
label,
style: TextStyle(
color: const Color.fromRGBO(148, 163, 184, 1),
fontSize: 12.sp,
),
),
SizedBox(height: 4.h),
if (change != null)
Row(
children: [
Icon(
isDown! ? Icons.arrow_drop_down : Icons.arrow_drop_up,
color: isDown ? const Color.fromRGBO(34, 197, 94, 1) : const Color.fromRGBO(239, 68, 68, 1),
size: 16.sp,
),
Text(
change,
style: TextStyle(
color: isDown ? const Color.fromRGBO(34, 197, 94, 1) : const Color.fromRGBO(239, 68, 68, 1),
fontSize: 12.sp,
),
),
],
)
else
SizedBox(height: 20.h),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:smart_hotel_app/views/report/energy/controller.dart';
class HourlyChartBlock extends StatelessWidget {
const HourlyChartBlock({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: const Color.fromRGBO(30, 41, 59, 1),
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'今日逐时用电',
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16.h),
SizedBox(
height: 200.h,
child: BarChart(
BarChartData(
alignment: BarChartAlignment.spaceBetween,
maxY: 200,
barTouchData: BarTouchData(enabled: false),
titlesData: FlTitlesData(
show: true,
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
if (value % 4 == 0) {
return Text(
'${value.toInt()}',
style: TextStyle(
color: const Color.fromRGBO(148, 163, 184, 1),
fontSize: 10.sp,
),
);
}
return const SizedBox.shrink();
},
reservedSize: 20,
),
),
leftTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
borderData: FlBorderData(show: false),
gridData: const FlGridData(show: false),
barGroups: _buildBarGroups(),
),
),
),
],
),
);
}
List<BarChartGroupData> _buildBarGroups() {
return ReportEnergyController.hourlyData.asMap().entries.map((entry) {
final index = entry.key;
final value = entry.value;
return BarChartGroupData(
x: index,
barRods: [
BarChartRodData(
toY: value,
color: index >= 8 && index <= 12
? const Color.fromRGBO(59, 130, 246, 1)
: const Color.fromRGBO(37, 99, 235, 1),
width: 10.w,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4.r),
topRight: Radius.circular(4.r),
),
),
],
);
}).toList();
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/energy/controller.dart';
class ZoneChartBlock extends StatelessWidget {
const ZoneChartBlock({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: const Color.fromRGBO(30, 41, 59, 1),
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'分区用电占比',
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16.h),
...ReportEnergyController.zoneData.asMap().entries.map((entry) {
final index = entry.key;
final data = entry.value;
return Padding(
padding: EdgeInsets.only(bottom: index < ReportEnergyController.zoneData.length - 1 ? 16.h : 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
data.name,
style: TextStyle(
color: Colors.white,
fontSize: 14.sp,
),
),
Text(
'${data.percentage.toInt()}% (${data.energy.toInt()} kWh)',
style: TextStyle(
color: const Color.fromRGBO(148, 163, 184, 1),
fontSize: 14.sp,
),
),
],
),
SizedBox(height: 8.h),
Stack(
children: [
Container(
height: 12.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(51, 65, 85, 1),
borderRadius: BorderRadius.circular(6.r),
),
),
FractionallySizedBox(
widthFactor: data.percentage / 100,
child: Container(
height: 12.h,
decoration: BoxDecoration(
color: index == 0
? const Color.fromRGBO(59, 130, 246, 1)
: const Color.fromRGBO(71, 85, 105, 1),
borderRadius: BorderRadius.circular(6.r),
),
),
),
],
),
],
),
);
}).toList(),
],
),
);
}
}
class ReportEnergyController {
static const double todayEnergy = 1284;
static const double todayEnergyChange = -8;
static const double monthEnergy = 38420;
static const double monthEnergyChange = -5;
static const double monthBill = 6982;
static const List<double> hourlyData = [
45, 38, 32, 28, 25, 30, 42, 78, 112, 145, 168, 175,
162, 148, 132, 115, 98, 82, 70, 58, 48, 42, 38, 35
];
static const List<ZoneData> zoneData = [
ZoneData(name: '客房区域', percentage: 68, energy: 873),
ZoneData(name: '公共区域', percentage: 18, energy: 231),
ZoneData(name: '餐饮区域', percentage: 10, energy: 128),
ZoneData(name: '其他', percentage: 4, energy: 52),
];
}
class ZoneData {
final String name;
final double percentage;
final double energy;
const ZoneData({
required this.name,
required this.percentage,
required this.energy,
});
}
\ No newline at end of file
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/energy/controller.dart';
import 'package:smart_hotel_app/views/report/energy/child/energy_stats_card_block.dart';
import 'package:smart_hotel_app/views/report/energy/child/hourly_chart_block.dart';
import 'package:smart_hotel_app/views/report/energy/child/zone_chart_block.dart';
@RoutePage()
class ReportEnergyDetailView extends StatefulWidget {
const ReportEnergyDetailView({super.key});
@override
State<ReportEnergyDetailView> createState() => _ReportEnergyDetailViewState();
}
class _ReportEnergyDetailViewState extends State<ReportEnergyDetailView> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(15, 23, 42, 1),
appBar: AppBar(
backgroundColor: Color.fromRGBO(15, 23, 42, 1),
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
context.popRoute();
},
),
title: Text(
'能耗分析',
style: TextStyle(
color: Colors.white,
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
),
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 10.h),
const EnergyStatsCardBlock(),
SizedBox(height: 20.h),
const HourlyChartBlock(),
SizedBox(height: 20.h),
const ZoneChartBlock(),
SizedBox(height: 20.h),
],
),
),
);
}
}
\ No newline at end of file
...@@ -38,6 +38,7 @@ class _ReportMetricsBlockState extends State<ReportMetricsBlock> { ...@@ -38,6 +38,7 @@ class _ReportMetricsBlockState extends State<ReportMetricsBlock> {
changeColor: Color.fromRGBO(34, 197, 94, 1), changeColor: Color.fromRGBO(34, 197, 94, 1),
progress: powerUsage['progress'] as double, progress: powerUsage['progress'] as double,
progressColor: Color.fromRGBO(59, 130, 246, 1), progressColor: Color.fromRGBO(59, 130, 246, 1),
onTap: () => _controller.navigateToEnergyDetail(),
), ),
), ),
SizedBox(width: 16.w), SizedBox(width: 16.w),
...@@ -65,84 +66,88 @@ class _ReportMetricsBlockState extends State<ReportMetricsBlock> { ...@@ -65,84 +66,88 @@ class _ReportMetricsBlockState extends State<ReportMetricsBlock> {
required Color changeColor, required Color changeColor,
required double progress, required double progress,
required Color progressColor, required Color progressColor,
VoidCallback? onTap,
}) { }) {
return Container( return GestureDetector(
padding: EdgeInsets.all(20.w), onTap: onTap,
decoration: BoxDecoration( child: Container(
borderRadius: BorderRadius.circular(20.r), padding: EdgeInsets.all(20.w),
color: Color.fromRGBO(30, 41, 59, 1), decoration: BoxDecoration(
border: Border.all( borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(71, 85, 105, 1), color: Color.fromRGBO(30, 41, 59, 1),
width: 1.w, border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
), ),
), child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Row(
Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
children: [ Text(
Text( title,
title, style: TextStyle(
style: TextStyle( fontSize: 16.sp,
fontSize: 16.sp, color: Colors.grey,
color: Colors.grey, ),
), ),
), Text(
Text( changeText,
changeText, style: TextStyle(
style: TextStyle( fontSize: 14.sp,
fontSize: 14.sp, color: changeColor,
color: changeColor, fontWeight: FontWeight.w500,
fontWeight: FontWeight.w500, ),
),
),
],
),
SizedBox(height: 16.h),
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
value.toString().replaceAllMapped(
RegExp(r'(\d)(?=(\d{3})+(?!\d))'),
(Match match) => '${match[1]},',
), ),
style: TextStyle( ],
fontSize: 36.sp, ),
fontWeight: FontWeight.bold, SizedBox(height: 16.h),
color: Colors.white, Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
value.toString().replaceAllMapped(
RegExp(r'(\d)(?=(\d{3})+(?!\d))'),
(Match match) => '${match[1]},',
),
style: TextStyle(
fontSize: 36.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
), ),
), SizedBox(width: 4.w),
SizedBox(width: 4.w), Text(
Text( unit,
unit, style: TextStyle(
style: TextStyle( fontSize: 16.sp,
fontSize: 16.sp, color: Colors.grey,
color: Colors.grey, ),
), ),
), ],
],
),
SizedBox(height: 16.h),
Container(
height: 8.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r),
color: Color.fromRGBO(51, 65, 85, 1),
), ),
child: FractionallySizedBox( SizedBox(height: 16.h),
widthFactor: progress, Container(
child: Container( height: 8.h,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r), borderRadius: BorderRadius.circular(4.r),
color: progressColor, color: Color.fromRGBO(51, 65, 85, 1),
),
child: FractionallySizedBox(
widthFactor: progress,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r),
color: progressColor,
),
), ),
), ),
), ),
), ],
], ),
), ),
); );
} }
......
...@@ -24,108 +24,111 @@ class _RoomStatusDistributionState extends State<RoomStatusDistribution> { ...@@ -24,108 +24,111 @@ class _RoomStatusDistributionState extends State<RoomStatusDistribution> {
final statuses = distributionData['statuses'] as List<Map<String, dynamic>>; final statuses = distributionData['statuses'] as List<Map<String, dynamic>>;
final totalRooms = distributionData['totalRooms'] as int; final totalRooms = distributionData['totalRooms'] as int;
return Container( return GestureDetector(
width: double.infinity, onTap: () => _controller.navigateToRoomDetail(),
margin: EdgeInsets.symmetric(horizontal: 20.w), child: Container(
padding: EdgeInsets.all(20.w), width: double.infinity,
decoration: BoxDecoration( margin: EdgeInsets.symmetric(horizontal: 20.w),
borderRadius: BorderRadius.circular(20.r), padding: EdgeInsets.all(20.w),
color: Color.fromRGBO(30, 41, 59, 1), decoration: BoxDecoration(
border: Border.all( borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(71, 85, 105, 1), color: Color.fromRGBO(30, 41, 59, 1),
width: 1.w, border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
), ),
), child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Row(
Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
children: [ Text(
Text( distributionData['title'] as String,
distributionData['title'] as String, style: TextStyle(
style: TextStyle( fontSize: 18.sp,
fontSize: 18.sp, fontWeight: FontWeight.bold,
fontWeight: FontWeight.bold, color: Colors.white,
color: Colors.white, ),
), ),
), Text(
Text( '共 $totalRooms 间',
'共 $totalRooms 间', style: TextStyle(
style: TextStyle( fontSize: 14.sp,
fontSize: 14.sp, color: Colors.grey,
color: Colors.grey, ),
), ),
), ],
], ),
), SizedBox(height: 20.h),
SizedBox(height: 20.h), ...statuses.map((status) {
...statuses.map((status) { final count = status['count'] as int;
final count = status['count'] as int; final color = status['color'] as Color;
final color = status['color'] as Color; final percentage = (count / totalRooms * 100).toStringAsFixed(0);
final percentage = (count / totalRooms * 100).toStringAsFixed(0);
return Padding(
return Padding( padding: EdgeInsets.only(bottom: 16.h),
padding: EdgeInsets.only(bottom: 16.h), child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Row(
Row( children: [
children: [ Container(
Container( width: 12.w,
width: 12.w, height: 12.w,
height: 12.w, decoration: BoxDecoration(
decoration: BoxDecoration( color: color,
color: color, borderRadius: BorderRadius.circular(6.r),
borderRadius: BorderRadius.circular(6.r), ),
), ),
), SizedBox(width: 10.w),
SizedBox(width: 10.w), Expanded(
Expanded( child: Text(
child: Text( status['name'] as String,
status['name'] as String, style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
),
),
),
Text(
'$count间 ($percentage%)',
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
color: Colors.white, color: color,
fontWeight: FontWeight.bold,
), ),
), ),
), ],
Text(
'$count间 ($percentage%)',
style: TextStyle(
fontSize: 16.sp,
color: color,
fontWeight: FontWeight.bold,
),
),
],
),
SizedBox(height: 8.h),
Container(
width: double.infinity,
height: 12.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.r),
color: Color.fromRGBO(51, 65, 85, 1),
), ),
child: Align( SizedBox(height: 8.h),
alignment: Alignment.centerLeft, Container(
child: FractionallySizedBox( width: double.infinity,
widthFactor: count / totalRooms, height: 12.h,
child: Container( decoration: BoxDecoration(
decoration: BoxDecoration( borderRadius: BorderRadius.circular(6.r),
borderRadius: BorderRadius.circular(6.r), color: Color.fromRGBO(51, 65, 85, 1),
color: color, ),
child: Align(
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor: count / totalRooms,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.r),
color: color,
),
), ),
), ),
), ),
), ),
), ],
], ),
), );
); }).toList(),
}).toList(), ],
], ),
), ),
); );
} }
......
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart';
class ReportIndexController { class ReportIndexController {
final BuildContext context; final BuildContext context;
...@@ -86,4 +88,12 @@ class ReportIndexController { ...@@ -86,4 +88,12 @@ class ReportIndexController {
], ],
}; };
} }
void navigateToEnergyDetail() {
context.pushRoute(const ReportEnergyDetailRoute());
}
void navigateToRoomDetail() {
context.pushRoute(const ReportRoomDetailRoute());
}
} }
\ No newline at end of file
class ReportRoomController {
}
\ No newline at end of file
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/room/controller.dart';
@RoutePage()
class ReportRoomDetailView extends StatefulWidget {
const ReportRoomDetailView({super.key});
@override
State<ReportRoomDetailView> createState() => _ReportRoomDetailViewState();
}
class _ReportRoomDetailViewState extends State<ReportRoomDetailView> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(15, 23, 42, 1),
appBar: AppBar(
backgroundColor: Color.fromRGBO(15, 23, 42, 1),
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
context.popRoute();
},
),
title: Text(
'能耗分析',
style: TextStyle(
color: Colors.white,
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
),
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 10.h),
],
),
),
);
}
}
\ No newline at end of file
...@@ -72,6 +72,8 @@ flutter: ...@@ -72,6 +72,8 @@ flutter:
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
assets: assets:
- lib/assets/ - lib/assets/
- lib/assets/login/
- lib/assets/tab/
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment