Commit 2421f3e8 authored by 张宏's avatar 张宏

.

parent 1bfb3cc9
......@@ -15,7 +15,7 @@ class AppRouter extends $AppRouter {
children: [
AutoRoute(page: HomeRoute.page, initial: true),
AutoRoute(page: ServiceIndexRoute.page),
AutoRoute(page: MessageRoute.page),
AutoRoute(page: ReportIndexRoute.page),
AutoRoute(page: ProfileRoute.page),
],
),
......
......@@ -17,8 +17,8 @@ import 'package:smart_hotel_app/views/home/device/device_detail_view.dart'
import 'package:smart_hotel_app/views/home/index/index_view.dart' as _i4;
import 'package:smart_hotel_app/views/layout/default_view.dart' as _i2;
import 'package:smart_hotel_app/views/login/login_view.dart' as _i5;
import 'package:smart_hotel_app/views/message/index_view.dart' as _i6;
import 'package:smart_hotel_app/views/profile/index_view.dart' as _i7;
import 'package:smart_hotel_app/views/profile/index_view.dart' as _i6;
import 'package:smart_hotel_app/views/report/index/index_view.dart' as _i7;
import 'package:smart_hotel_app/views/search/index_view.dart' as _i8;
import 'package:smart_hotel_app/views/service/index/index_view.dart' as _i9;
import 'package:smart_hotel_app/views/service/room/room_detail_view.dart'
......@@ -59,16 +59,16 @@ abstract class $AppRouter extends _i11.RootStackRouter {
child: const _i5.LoginView(),
);
},
MessageRoute.name: (routeData) {
ProfileRoute.name: (routeData) {
return _i11.AutoRoutePage<dynamic>(
routeData: routeData,
child: const _i6.MessageView(),
child: const _i6.ProfileView(),
);
},
ProfileRoute.name: (routeData) {
ReportIndexRoute.name: (routeData) {
return _i11.AutoRoutePage<dynamic>(
routeData: routeData,
child: const _i7.ProfileView(),
child: const _i7.ReportIndexView(),
);
},
SearchRoute.name: (routeData) {
......@@ -173,29 +173,29 @@ class LoginRoute extends _i11.PageRouteInfo<void> {
}
/// generated route for
/// [_i6.MessageView]
class MessageRoute extends _i11.PageRouteInfo<void> {
const MessageRoute({List<_i11.PageRouteInfo>? children})
/// [_i6.ProfileView]
class ProfileRoute extends _i11.PageRouteInfo<void> {
const ProfileRoute({List<_i11.PageRouteInfo>? children})
: super(
MessageRoute.name,
ProfileRoute.name,
initialChildren: children,
);
static const String name = 'MessageRoute';
static const String name = 'ProfileRoute';
static const _i11.PageInfo<void> page = _i11.PageInfo<void>(name);
}
/// generated route for
/// [_i7.ProfileView]
class ProfileRoute extends _i11.PageRouteInfo<void> {
const ProfileRoute({List<_i11.PageRouteInfo>? children})
/// [_i7.ReportIndexView]
class ReportIndexRoute extends _i11.PageRouteInfo<void> {
const ReportIndexRoute({List<_i11.PageRouteInfo>? children})
: super(
ProfileRoute.name,
ReportIndexRoute.name,
initialChildren: children,
);
static const String name = 'ProfileRoute';
static const String name = 'ReportIndexRoute';
static const _i11.PageInfo<void> page = _i11.PageInfo<void>(name);
}
......
......@@ -14,7 +14,7 @@ class _DefaultLayoutViewState extends State<DefaultLayoutView> {
@override
Widget build(BuildContext context) {
return AutoTabsScaffold(
routes: const [HomeRoute(), ServiceIndexRoute(), MessageRoute(), ProfileRoute()],
routes: const [HomeRoute(), ServiceIndexRoute(), ReportIndexRoute(), ProfileRoute()],
transitionBuilder: (context, child, animation) => child,
bottomNavigationBuilder: (context, tabsRouter) {
return Container(
......
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
@RoutePage()
class MessageView extends StatefulWidget {
const MessageView({super.key});
@override
State<MessageView> createState() => _MessageViewState();
}
class _MessageViewState extends State<MessageView> {
@override
Widget build(BuildContext context) {
return const Center(
child: Text('MessageView'),
);
}
}
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/index/controller.dart';
class DeviceOnlineRate extends StatefulWidget {
const DeviceOnlineRate({super.key});
@override
State<DeviceOnlineRate> createState() => _DeviceOnlineRateState();
}
class _DeviceOnlineRateState extends State<DeviceOnlineRate> {
late final ReportIndexController _controller;
@override
void initState() {
super.initState();
_controller = ReportIndexController(context);
}
@override
Widget build(BuildContext context) {
final rateData = _controller.getDeviceOnlineRate();
final devices = rateData['devices'] as List<Map<String, dynamic>>;
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 20.w),
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(30, 41, 59, 1),
border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
rateData['title'] as String,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
rateData['rateText'] as String,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(34, 197, 94, 1),
),
),
],
),
SizedBox(height: 20.h),
Row(
children: [
SizedBox(
height: 150.w,
child: Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: 150.w,
height: 150.w,
child: PieChart(
PieChartData(
sections: [
PieChartSectionData(
value: rateData['rate'] as double,
color: Color.fromRGBO(34, 197, 94, 1),
radius: 15,
),
PieChartSectionData(
value: 1 - (rateData['rate'] as double),
color: Color.fromRGBO(51, 65, 85, 1),
radius: 15,
),
],
centerSpaceRadius: 50.w,
sectionsSpace: 0,
startDegreeOffset: -90,
),
),
),
Text(
rateData['rateText'].toString().replaceAll('%', ''),
style: TextStyle(
fontSize: 32.sp,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(34, 197, 94, 1),
),
),
],
),
),
SizedBox(width: 30.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...devices.map((device) {
return Padding(
padding: EdgeInsets.only(bottom: 12.h),
child: Text(
'${device['name']} ${device['count']} 台',
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
),
),
);
}).toList(),
],
),
),
],
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/index/controller.dart';
class QuickActionsBlock extends StatefulWidget {
const QuickActionsBlock({super.key});
@override
State<QuickActionsBlock> createState() => _QuickActionsBlockState();
}
class _QuickActionsBlockState extends State<QuickActionsBlock> {
late final ReportIndexController _controller;
@override
void initState() {
super.initState();
_controller = ReportIndexController(context);
}
@override
Widget build(BuildContext context) {
final actionsData = _controller.getQuickActions();
final actions = actionsData['actions'] as List<Map<String, dynamic>>;
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 20.w),
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(30, 41, 59, 1),
border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
actionsData['title'] as String,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 20.h),
Row(
children: actions.map((action) {
return Expanded(
child: Column(
children: [
Container(
width: 80.w,
height: 80.w,
decoration: BoxDecoration(
color: action['backgroundColor'] as Color,
borderRadius: BorderRadius.circular(40.r),
),
child: Icon(
action['icon'] as IconData,
color: action['iconColor'] as Color,
size: 36.sp,
),
),
SizedBox(height: 12.h),
Text(
action['name'] as String,
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
),
),
],
),
);
}).toList(),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/index/controller.dart';
class ReportHeaderBlock extends StatefulWidget {
const ReportHeaderBlock({super.key});
@override
State<ReportHeaderBlock> createState() => _ReportHeaderBlockState();
}
class _ReportHeaderBlockState extends State<ReportHeaderBlock> {
late final ReportIndexController _controller;
@override
void initState() {
super.initState();
_controller = ReportIndexController(context);
}
@override
Widget build(BuildContext context) {
final headerData = _controller.getReportHeader();
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 24.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
headerData['title'] as String,
style: TextStyle(
fontSize: 28.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 8.h),
Text(
headerData['subtitle'] as String,
style: TextStyle(
fontSize: 16.sp,
color: Colors.grey,
),
),
],
),
),
Container(
width: 56.w,
height: 56.w,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color.fromRGBO(51, 65, 85, 1),
),
child: Icon(
Icons.star,
color: Color.fromRGBO(251, 191, 36, 1),
size: 28.sp,
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/index/controller.dart';
class ReportMetricsBlock extends StatefulWidget {
const ReportMetricsBlock({super.key});
@override
State<ReportMetricsBlock> createState() => _ReportMetricsBlockState();
}
class _ReportMetricsBlockState extends State<ReportMetricsBlock> {
late final ReportIndexController _controller;
@override
void initState() {
super.initState();
_controller = ReportIndexController(context);
}
@override
Widget build(BuildContext context) {
final metricsData = _controller.getReportMetrics();
final powerUsage = metricsData['powerUsage'] as Map<String, dynamic>;
final pendingAlerts = metricsData['pendingAlerts'] as Map<String, dynamic>;
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Row(
children: [
Expanded(
child: _buildMetricCard(
title: '今日用电',
value: powerUsage['value'],
unit: powerUsage['unit'] as String,
changeText: powerUsage['changeText'] as String,
changeColor: Color.fromRGBO(34, 197, 94, 1),
progress: powerUsage['progress'] as double,
progressColor: Color.fromRGBO(59, 130, 246, 1),
),
),
SizedBox(width: 16.w),
Expanded(
child: _buildMetricCard(
title: '待处理告警',
value: pendingAlerts['value'],
unit: pendingAlerts['unit'] as String,
changeText: pendingAlerts['changeText'] as String,
changeColor: Color.fromRGBO(246, 158, 11, 1),
progress: pendingAlerts['progress'] as double,
progressColor: Color.fromRGBO(249, 115, 22, 1),
),
),
],
),
);
}
Widget _buildMetricCard({
required String title,
required num value,
required String unit,
required String changeText,
required Color changeColor,
required double progress,
required Color progressColor,
}) {
return Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(30, 41, 59, 1),
border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
color: Colors.grey,
),
),
Text(
changeText,
style: TextStyle(
fontSize: 14.sp,
color: changeColor,
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,
color: Colors.white,
),
),
SizedBox(width: 4.w),
Text(
unit,
style: TextStyle(
fontSize: 16.sp,
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(
widthFactor: progress,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r),
color: progressColor,
),
),
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/report/index/controller.dart';
class RoomStatusDistribution extends StatefulWidget {
const RoomStatusDistribution({super.key});
@override
State<RoomStatusDistribution> createState() => _RoomStatusDistributionState();
}
class _RoomStatusDistributionState extends State<RoomStatusDistribution> {
late final ReportIndexController _controller;
@override
void initState() {
super.initState();
_controller = ReportIndexController(context);
}
@override
Widget build(BuildContext context) {
final distributionData = _controller.getRoomStatusDistribution();
final statuses = distributionData['statuses'] as List<Map<String, dynamic>>;
final totalRooms = distributionData['totalRooms'] as int;
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 20.w),
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(30, 41, 59, 1),
border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
distributionData['title'] as String,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'共 $totalRooms 间',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey,
),
),
],
),
SizedBox(height: 20.h),
...statuses.map((status) {
final count = status['count'] as int;
final color = status['color'] as Color;
final percentage = (count / totalRooms * 100).toStringAsFixed(0);
return Padding(
padding: EdgeInsets.only(bottom: 16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 12.w,
height: 12.w,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6.r),
),
),
SizedBox(width: 10.w),
Expanded(
child: Text(
status['name'] as String,
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
),
),
),
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(
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor: count / totalRooms,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.r),
color: color,
),
),
),
),
),
],
),
);
}).toList(),
],
),
);
}
}
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/index/controller.dart';
class WeeklyPowerChart extends StatefulWidget {
const WeeklyPowerChart({super.key});
@override
State<WeeklyPowerChart> createState() => _WeeklyPowerChartState();
}
class _WeeklyPowerChartState extends State<WeeklyPowerChart> {
late final ReportIndexController _controller;
@override
void initState() {
super.initState();
_controller = ReportIndexController(context);
}
@override
Widget build(BuildContext context) {
final chartData = _controller.getWeeklyPowerUsage();
final data = chartData['data'] as List<Map<String, dynamic>>;
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 20.w),
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.r),
color: Color.fromRGBO(30, 41, 59, 1),
border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${chartData['title']} (${chartData['unit']})',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
chartData['dateRange'] as String,
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey,
),
),
],
),
SizedBox(height: 20.h),
SizedBox(
height: 200.h,
child: LineChart(
LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: false,
drawHorizontalLine: true,
getDrawingHorizontalLine: (value) {
return FlLine(
color: Color.fromRGBO(71, 85, 105, 1),
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
final index = value.toInt();
if (index >= 0 && index < data.length) {
return Padding(
padding: EdgeInsets.only(top: 8.h),
child: Text(
data[index]['day'] as String,
style: TextStyle(
color: Colors.grey,
fontSize: 14.sp,
),
),
);
}
return const SizedBox.shrink();
},
reservedSize: 30.h,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
borderData: FlBorderData(
show: false,
),
minX: 0,
maxX: (data.length - 1).toDouble(),
minY: 0,
maxY: 300,
lineBarsData: [
LineChartBarData(
spots: data.asMap().entries.map((entry) {
final index = entry.key;
final item = entry.value;
return FlSpot(
index.toDouble(),
(item['value'] as num).toDouble(),
);
}).toList(),
isCurved: true,
color: Color.fromRGBO(59, 130, 246, 1),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: Color.fromRGBO(59, 130, 246, 1),
strokeWidth: 2,
strokeColor: Colors.white,
);
},
),
belowBarData: BarAreaData(
show: true,
color: Color.fromRGBO(59, 130, 246, 0.2),
),
),
],
),
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
class ReportIndexController {
final BuildContext context;
ReportIndexController(this.context);
Map<String, dynamic> getReportHeader() {
return {
'title': '经营概览看板',
'subtitle': '管理层视角 · 关键指标一览',
};
}
Map<String, dynamic> getReportMetrics() {
return {
'powerUsage': {
'value': 1284,
'unit': 'kWh',
'change': -8,
'changeText': '↓ 8%',
'progress': 0.6,
},
'pendingAlerts': {
'value': 3,
'unit': '条',
'change': null,
'changeText': '需关注',
'progress': 0.3,
},
};
}
Map<String, dynamic> getWeeklyPowerUsage() {
return {
'title': '本周用电趋势',
'unit': 'kWh',
'dateRange': '5.7 - 5.13',
'data': [
{'day': '一', 'value': 120},
{'day': '二', 'value': 180},
{'day': '三', 'value': 150},
{'day': '四', 'value': 200},
{'day': '五', 'value': 250},
{'day': '六', 'value': 220},
{'day': '日', 'value': 164},
],
};
}
Map<String, dynamic> getRoomStatusDistribution() {
return {
'title': '客房状态分布',
'totalRooms': 52,
'statuses': [
{'name': '入住中', 'count': 45, 'color': Color.fromRGBO(59, 130, 246, 1)},
{'name': '空闲', 'count': 7, 'color': Color.fromRGBO(148, 163, 184, 1)},
{'name': '已预订', 'count': 5, 'color': Color.fromRGBO(96, 165, 250, 1)},
{'name': '设备告警', 'count': 3, 'color': Color.fromRGBO(249, 115, 22, 1)},
],
};
}
Map<String, dynamic> getDeviceOnlineRate() {
return {
'title': '设备在线率',
'rate': 1.0,
'rateText': '100%',
'devices': [
{'name': '智能空开', 'count': 16},
{'name': '客控设备', 'count': 24},
{'name': '网络设备', 'count': 8},
],
};
}
Map<String, dynamic> getQuickActions() {
return {
'title': '快捷操作',
'actions': [
{
'name': '告警记录',
'icon': Icons.warning_amber,
'backgroundColor': Color.fromRGBO(125, 96, 87, 1),
'iconColor': Color.fromRGBO(255, 152, 0, 1),
},
{
'name': '联动规则',
'icon': Icons.account_tree,
'backgroundColor': Color.fromRGBO(68, 109, 98, 1),
'iconColor': Color.fromRGBO(76, 175, 80, 1),
},
],
};
}
}
\ 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/index/child/report_header_block.dart';
import 'package:smart_hotel_app/views/report/index/child/report_metrics_block.dart';
import 'package:smart_hotel_app/views/report/index/child/weekly_power_chart.dart';
import 'package:smart_hotel_app/views/report/index/child/room_status_distribution.dart';
import 'package:smart_hotel_app/views/report/index/child/device_online_rate.dart';
import 'package:smart_hotel_app/views/report/index/child/quick_actions_block.dart';
@RoutePage()
class ReportIndexView extends StatefulWidget {
const ReportIndexView({super.key});
@override
State<ReportIndexView> createState() => _ReportIndexViewState();
}
class _ReportIndexViewState extends State<ReportIndexView> {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: Container(
width: double.infinity,
color: Color.fromRGBO(15, 23, 42, 1),
child: Column(
children: [
ReportHeaderBlock(),
SizedBox(height: 10.h),
ReportMetricsBlock(),
SizedBox(height: 10.h),
WeeklyPowerChart(),
SizedBox(height: 10.h),
RoomStatusDistribution(),
SizedBox(height: 10.h),
DeviceOnlineRate(),
SizedBox(height: 10.h),
QuickActionsBlock(),
SizedBox(height: 10.h),
],
),
),
),
);
},
);
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/views/service/room/controller.dart';
class RoomStatusBlock extends StatefulWidget {
final ServiceRoomController controller;
const RoomStatusBlock({
super.key,
required this.controller,
});
@override
State<RoomStatusBlock> createState() => _RoomStatusBlockState();
}
class _RoomStatusBlockState extends State<RoomStatusBlock> {
@override
Widget build(BuildContext context) {
final roomStatus = widget.controller.getRoomStatus();
final hasGuest = roomStatus['hasGuest'] as bool;
final guestRefreshTime = roomStatus['guestRefreshTime'] as String;
final powerOn = roomStatus['powerOn'] as bool;
final currentPower = roomStatus['currentPower'] as String;
final wifiNormal = roomStatus['wifiNormal'] as bool;
final wifiSignal = roomStatus['wifiSignal'] as String;
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
children: [
SizedBox(height: 20.h),
Row(
children: [
Expanded(
child: _buildStatusCard(
icon: Icons.person_outline,
title: '有客人',
subtitle: hasGuest ? '有人在房内' : '无人在房内',
extraInfo: '感应器刷新 · $guestRefreshTime',
isActive: hasGuest,
),
),
SizedBox(width: 12.w),
Expanded(
child: _buildStatusCard(
icon: Icons.flash_on,
title: '没有电',
subtitle: powerOn ? '通电运行中' : '断电中',
extraInfo: '当前功率 $currentPower',
isActive: powerOn,
),
),
],
),
SizedBox(height: 12.h),
Row(
children: [
Expanded(
child: _buildStatusCard(
icon: Icons.wifi,
title: '没有网',
subtitle: wifiNormal ? 'WiFi正常' : 'WiFi异常',
extraInfo: '信号强度 $wifiSignal',
isActive: wifiNormal,
),
),
SizedBox(width: 12.w),
Expanded(child: Container()),
],
),
],
),
);
}
Widget _buildStatusCard({
required IconData icon,
required String title,
required String subtitle,
required String extraInfo,
required bool isActive,
}) {
final activeColor = Color.fromRGBO(34, 197, 94, 1);
final inactiveColor = Color.fromRGBO(148, 163, 184, 1);
final bgColor = isActive
? Color.fromRGBO(34, 197, 94, 0.1)
: Color.fromRGBO(51, 65, 85, 1);
final color = isActive ? activeColor : inactiveColor;
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.r),
color: Color.fromRGBO(30, 41, 59, 1),
border: Border.all(
color: Color.fromRGBO(71, 85, 105, 1),
width: 1.w,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, color: color, size: 20.sp),
SizedBox(width: 8.w),
Text(
title,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
),
),
],
),
SizedBox(height: 12.h),
Row(
children: [
Icon(
isActive ? Icons.check_circle : Icons.cancel,
color: color,
size: 18.sp,
),
SizedBox(width: 6.w),
Text(
subtitle,
style: TextStyle(
fontSize: 14.sp,
color: color,
fontWeight: FontWeight.w500,
),
),
],
),
SizedBox(height: 8.h),
Text(
extraInfo,
style: TextStyle(
fontSize: 11.sp,
color: Colors.grey,
),
),
],
),
);
}
}
......@@ -28,4 +28,24 @@ class ServiceRoomController {
'roomType': roomTypes[typeIndex],
};
}
Map<String, dynamic> getRoomStatus() {
final num = roomNumber ?? '302';
final numInt = int.tryParse(num) ?? 302;
final hasGuest = numInt % 2 == 0;
final powerOn = true;
final wifiNormal = true;
final now = DateTime.now();
final refreshTime = '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}';
return {
'hasGuest': hasGuest,
'guestRefreshTime': refreshTime,
'powerOn': powerOn,
'currentPower': '1.24kW',
'wifiNormal': wifiNormal,
'wifiSignal': '-45dBm',
};
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ 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/service/room/child/room_info_block.dart';
import 'package:smart_hotel_app/views/service/room/child/room_status_block.dart';
import 'package:smart_hotel_app/views/service/room/controller.dart';
@RoutePage()
......@@ -52,6 +53,7 @@ class _ServiceRoomDetailViewState extends State<ServiceRoomDetailView> {
children: [
SizedBox(height: 20.h),
RoomInfoBlock(controller: _controller),
RoomStatusBlock(controller: _controller),
],
),
),
......
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