Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
smart_hotel_app
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张宏
smart_hotel_app
Commits
3c72b94e
Commit
3c72b94e
authored
Jun 04, 2026
by
张宏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
。
parent
7e849e9f
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1667 additions
and
39 deletions
+1667
-39
settings.gradle
android/settings.gradle
+0
-29
abnormal_list_cubit.dart
lib/views/home/abnormal_list/cubit/abnormal_list_cubit.dart
+49
-0
abnormal_list_state.dart
lib/views/home/abnormal_list/cubit/abnormal_list_state.dart
+50
-0
index_view.dart
lib/views/home/abnormal_list/index_view.dart
+66
-0
alarm_list_item.dart
lib/views/home/abnormal_list/widget/alarm_list_item.dart
+200
-0
filter_tab_block.dart
lib/views/home/abnormal_list/widget/filter_tab_block.dart
+57
-0
device_list_cubit.dart
lib/views/report/device/cubit/device_list_cubit.dart
+91
-0
device_list_state.dart
lib/views/report/device/cubit/device_list_state.dart
+78
-0
device_detail_view.dart
lib/views/report/device/device_detail_view.dart
+0
-0
device_list_view.dart
lib/views/report/device/device_list_view.dart
+34
-10
device_card.dart
lib/views/report/device/widget/device_card.dart
+148
-0
device_filter_tab.dart
lib/views/report/device/widget/device_filter_tab.dart
+59
-0
room_detail_view.dart
lib/views/report/room/room_detail_view.dart
+94
-0
floor_selector.dart
lib/views/report/room/widget/floor_selector.dart
+66
-0
room_detail_card.dart
lib/views/report/room/widget/room_detail_card.dart
+222
-0
room_grid.dart
lib/views/report/room/widget/room_grid.dart
+108
-0
status_stats.dart
lib/views/report/room/widget/status_stats.dart
+55
-0
rule_management_cubit.dart
lib/views/report/rule/cubit/rule_management_cubit.dart
+72
-0
rule_management_state.dart
lib/views/report/rule/cubit/rule_management_state.dart
+61
-0
rule_management_view.dart
lib/views/report/rule/rule_management_view.dart
+75
-0
rule_card.dart
lib/views/report/rule/widget/rule_card.dart
+82
-0
No files found.
android/settings.gradle
deleted
100644 → 0
View file @
7e849e9f
pluginManagement
{
def
flutterSdkPath
=
{
def
properties
=
new
Properties
()
file
(
"local.properties"
).
withInputStream
{
properties
.
load
(
it
)
}
def
flutterSdkPath
=
properties
.
getProperty
(
"flutter.sdk"
)
assert
flutterSdkPath
!=
null
,
"flutter.sdk not set in local.properties"
return
flutterSdkPath
}
settings
.
ext
.
flutterSdkPath
=
flutterSdkPath
()
includeBuild
(
"${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle"
)
repositories
{
google
()
mavenCentral
()
gradlePluginPortal
()
}
plugins
{
id
"dev.flutter.flutter-gradle-plugin"
version
"1.0.0"
apply
false
}
}
plugins
{
id
"dev.flutter.flutter-plugin-loader"
version
"1.0.0"
id
"com.android.application"
version
"8.7.2"
apply
false
}
include
":app"
lib/views/home/abnormal_list/cubit/abnormal_list_cubit.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/cubit/abnormal_list_state.dart'
;
class
AbnormalListCubit
extends
Cubit
<
AbnormalListState
>
{
AbnormalListCubit
()
:
super
(
AbnormalListState
(
currentFilter:
AlarmStatus
.
all
,
alarmList:
_getAlarmList
()));
static
List
<
AlarmItem
>
_getAlarmList
()
{
return
[
const
AlarmItem
(
id:
'1'
,
title:
'温度异常告警'
,
deviceInfo:
'A-301智能空开·客房301'
,
alarmTime:
'2026-5-30 16:32:31'
,
processTime:
'2026-5-30 16:32:31'
,
status:
AlarmStatus
.
pending
,
level:
'高警'
,
urgency:
'紧急'
,
),
const
AlarmItem
(
id:
'2'
,
title:
'温度异常告警'
,
deviceInfo:
'A-301智能空开·客房301'
,
alarmTime:
'2026-5-30 16:32:31'
,
processTime:
'2026-5-30 16:32:31'
,
status:
AlarmStatus
.
processed
,
level:
'高警'
,
urgency:
'紧急'
,
),
const
AlarmItem
(
id:
'3'
,
title:
'温度异常告警'
,
deviceInfo:
'A-301智能空开·客房301'
,
alarmTime:
'2026-5-30 16:32:31'
,
processTime:
'2026-5-30 16:32:31'
,
status:
AlarmStatus
.
falseAlarm
,
level:
'高警'
,
urgency:
'紧急'
,
),
];
}
void
setFilter
(
AlarmStatus
filter
)
{
emit
(
state
.
copyWith
(
currentFilter:
filter
));
}
void
onAlarmItemTap
(
AlarmItem
item
)
{
print
(
'点击告警:
${item.title}
'
);
}
}
lib/views/home/abnormal_list/cubit/abnormal_list_state.dart
0 → 100644
View file @
3c72b94e
enum
AlarmStatus
{
all
,
pending
,
processed
,
falseAlarm
}
class
AlarmItem
{
final
String
id
;
final
String
title
;
final
String
deviceInfo
;
final
String
alarmTime
;
final
String
processTime
;
final
AlarmStatus
status
;
final
String
level
;
final
String
urgency
;
const
AlarmItem
({
required
this
.
id
,
required
this
.
title
,
required
this
.
deviceInfo
,
required
this
.
alarmTime
,
required
this
.
processTime
,
required
this
.
status
,
required
this
.
level
,
required
this
.
urgency
,
});
}
class
AbnormalListState
{
final
AlarmStatus
currentFilter
;
final
List
<
AlarmItem
>
alarmList
;
const
AbnormalListState
({
required
this
.
currentFilter
,
required
this
.
alarmList
,
});
AbnormalListState
copyWith
({
AlarmStatus
?
currentFilter
,
List
<
AlarmItem
>?
alarmList
,
})
{
return
AbnormalListState
(
currentFilter:
currentFilter
??
this
.
currentFilter
,
alarmList:
alarmList
??
this
.
alarmList
,
);
}
List
<
AlarmItem
>
get
filteredList
{
if
(
currentFilter
==
AlarmStatus
.
all
)
{
return
alarmList
;
}
return
alarmList
.
where
((
item
)
=>
item
.
status
==
currentFilter
).
toList
();
}
}
lib/views/home/abnormal_list/index_view.dart
0 → 100644
View file @
3c72b94e
import
'package:auto_route/auto_route.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/cubit/abnormal_list_cubit.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/cubit/abnormal_list_state.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/widget/alarm_list_item.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/widget/filter_tab_block.dart'
;
@RoutePage
()
class
AbnormalListView
extends
StatelessWidget
{
const
AbnormalListView
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
create:
(
_
)
=>
AbnormalListCubit
(),
child:
Scaffold
(
backgroundColor:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
appBar:
AppBar
(
backgroundColor:
Colors
.
white
,
elevation:
0
,
leading:
IconButton
(
icon:
const
Icon
(
Icons
.
arrow_back_ios
,
color:
Color
.
fromRGBO
(
100
,
116
,
139
,
1
)),
onPressed:
()
{
context
.
popRoute
();
},
),
title:
Text
(
'告警信息'
,
style:
TextStyle
(
color:
const
Color
.
fromRGBO
(
10
,
13
,
20
,
1
),
fontSize:
32
.
sp
,
fontWeight:
FontWeight
.
w200
,
),
),
centerTitle:
true
,
),
body:
BlocBuilder
<
AbnormalListCubit
,
AbnormalListState
>(
builder:
(
context
,
state
)
{
final
cubit
=
context
.
read
<
AbnormalListCubit
>();
return
SingleChildScrollView
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
Column
(
children:
[
FilterTabBlock
(
currentFilter:
state
.
currentFilter
,
onFilterChanged:
cubit
.
setFilter
,
),
SizedBox
(
height:
10
.
h
),
...
state
.
filteredList
.
map
((
item
)
{
return
AlarmListItem
(
item:
item
,
onTap:
cubit
.
onAlarmItemTap
,
);
}).
toList
(),
SizedBox
(
height:
30
.
h
),
],
),
);
},
),
),
);
}
}
lib/views/home/abnormal_list/widget/alarm_list_item.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/cubit/abnormal_list_state.dart'
;
class
AlarmListItem
extends
StatelessWidget
{
final
AlarmItem
item
;
final
Function
(
AlarmItem
)
onTap
;
const
AlarmListItem
({
super
.
key
,
required
this
.
item
,
required
this
.
onTap
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
=>
onTap
(
item
),
child:
Container
(
width:
double
.
infinity
,
margin:
EdgeInsets
.
only
(
top:
20
.
h
),
padding:
EdgeInsets
.
all
(
25
.
w
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
25
.
r
),
color:
Colors
.
white
,
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
_buildIcon
(),
SizedBox
(
width:
20
.
w
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
_buildTitleRow
(),
SizedBox
(
height:
15
.
h
),
Text
(
item
.
deviceInfo
,
style:
TextStyle
(
fontSize:
24
.
sp
,
color:
const
Color
.
fromRGBO
(
100
,
116
,
139
,
1
),
),
),
SizedBox
(
height:
10
.
h
),
Text
(
'告警时间:
${item.alarmTime}
'
,
style:
TextStyle
(
fontSize:
24
.
sp
,
color:
const
Color
.
fromRGBO
(
100
,
116
,
139
,
1
),
),
),
SizedBox
(
height:
10
.
h
),
Text
(
'处理时间:
${item.processTime}
'
,
style:
TextStyle
(
fontSize:
24
.
sp
,
color:
const
Color
.
fromRGBO
(
100
,
116
,
139
,
1
),
),
),
],
),
),
],
),
),
);
}
Widget
_buildIcon
()
{
return
Container
(
width:
96
.
w
,
height:
96
.
w
,
decoration:
BoxDecoration
(
color:
const
Color
.
fromRGBO
(
237
,
245
,
255
,
1
),
borderRadius:
BorderRadius
.
circular
(
16
.
r
),
),
child:
Icon
(
Icons
.
thermostat
,
size:
48
.
w
,
color:
const
Color
.
fromRGBO
(
73
,
149
,
234
,
1
),
),
);
}
Widget
_buildTitleRow
()
{
return
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
item
.
title
,
style:
TextStyle
(
fontSize:
28
.
sp
,
color:
Colors
.
black
,
fontWeight:
FontWeight
.
bold
,
),
),
Row
(
children:
[
_buildStatusBadge
(),
SizedBox
(
width:
12
.
w
),
_buildLevelBadge
(),
SizedBox
(
width:
8
.
w
),
_buildUrgencyBadge
(),
],
),
],
);
}
Widget
_buildStatusBadge
()
{
Color
bgColor
;
Color
textColor
;
String
text
;
IconData
?
icon
;
switch
(
item
.
status
)
{
case
AlarmStatus
.
pending
:
bgColor
=
const
Color
.
fromRGBO
(
250
,
204
,
21
,
0.15
);
textColor
=
const
Color
.
fromRGBO
(
250
,
204
,
21
,
1
);
text
=
'待处理'
;
icon
=
Icons
.
error_outline
;
break
;
case
AlarmStatus
.
processed
:
bgColor
=
const
Color
.
fromRGBO
(
84
,
214
,
120
,
0.15
);
textColor
=
const
Color
.
fromRGBO
(
84
,
214
,
120
,
1
);
text
=
'已处理'
;
icon
=
Icons
.
check_circle_outline
;
break
;
case
AlarmStatus
.
falseAlarm
:
bgColor
=
const
Color
.
fromRGBO
(
255
,
100
,
101
,
0.15
);
textColor
=
const
Color
.
fromRGBO
(
255
,
100
,
101
,
1
);
text
=
'误报'
;
icon
=
Icons
.
cancel_outlined
;
break
;
default
:
bgColor
=
const
Color
.
fromRGBO
(
100
,
116
,
139
,
0.15
);
textColor
=
const
Color
.
fromRGBO
(
100
,
116
,
139
,
1
);
text
=
''
;
}
return
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
16
.
w
,
vertical:
8
.
h
),
decoration:
BoxDecoration
(
color:
bgColor
,
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
),
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
if
(
icon
!=
null
)
...[
Icon
(
icon
,
size:
20
.
w
,
color:
textColor
),
SizedBox
(
width:
6
.
w
),
],
Text
(
text
,
style:
TextStyle
(
fontSize:
22
.
sp
,
color:
textColor
,
),
),
],
),
);
}
Widget
_buildLevelBadge
()
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
16
.
w
,
vertical:
8
.
h
),
decoration:
BoxDecoration
(
color:
const
Color
.
fromRGBO
(
255
,
100
,
101
,
0.15
),
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
),
child:
Text
(
item
.
level
,
style:
TextStyle
(
fontSize:
22
.
sp
,
color:
const
Color
.
fromRGBO
(
255
,
100
,
101
,
1
),
),
),
);
}
Widget
_buildUrgencyBadge
()
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
16
.
w
,
vertical:
8
.
h
),
decoration:
BoxDecoration
(
color:
const
Color
.
fromRGBO
(
255
,
100
,
101
,
0.15
),
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
),
child:
Text
(
item
.
urgency
,
style:
TextStyle
(
fontSize:
22
.
sp
,
color:
const
Color
.
fromRGBO
(
255
,
100
,
101
,
1
),
),
),
);
}
}
lib/views/home/abnormal_list/widget/filter_tab_block.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/home/abnormal_list/cubit/abnormal_list_state.dart'
;
class
FilterTabBlock
extends
StatelessWidget
{
final
AlarmStatus
currentFilter
;
final
Function
(
AlarmStatus
)
onFilterChanged
;
const
FilterTabBlock
({
super
.
key
,
required
this
.
currentFilter
,
required
this
.
onFilterChanged
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
width:
double
.
infinity
,
margin:
EdgeInsets
.
only
(
top:
10
.
h
),
child:
Row
(
children:
[
_buildTab
(
'全部'
,
AlarmStatus
.
all
),
SizedBox
(
width:
20
.
w
),
_buildTab
(
'待处理'
,
AlarmStatus
.
pending
),
SizedBox
(
width:
20
.
w
),
_buildTab
(
'已处理'
,
AlarmStatus
.
processed
),
SizedBox
(
width:
20
.
w
),
_buildTab
(
'误报'
,
AlarmStatus
.
falseAlarm
),
],
),
);
}
Widget
_buildTab
(
String
label
,
AlarmStatus
status
)
{
final
isSelected
=
currentFilter
==
status
;
return
Expanded
(
child:
GestureDetector
(
onTap:
()
=>
onFilterChanged
(
status
),
child:
Container
(
height:
72
.
h
,
decoration:
BoxDecoration
(
color:
isSelected
?
const
Color
.
fromRGBO
(
73
,
149
,
234
,
1
)
:
const
Color
.
fromRGBO
(
100
,
116
,
139
,
0.1
),
borderRadius:
BorderRadius
.
circular
(
16
.
r
),
),
alignment:
Alignment
.
center
,
child:
Text
(
label
,
style:
TextStyle
(
fontSize:
26
.
sp
,
color:
isSelected
?
Colors
.
white
:
const
Color
.
fromRGBO
(
100
,
116
,
139
,
1
),
),
),
),
),
);
}
}
lib/views/report/device/cubit/device_list_cubit.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:smart_hotel_app/views/report/device/cubit/device_list_state.dart'
;
class
DeviceListCubit
extends
Cubit
<
DeviceListState
>
{
DeviceListCubit
()
:
super
(
const
DeviceListState
())
{
_initData
();
}
void
_initData
()
{
final
devices
=
[
const
DeviceInfo
(
id:
'1'
,
name:
'智能空开 1F-01'
,
room:
'101'
,
type:
DeviceTypeEnum
.
smartBreaker
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:30'
,
),
const
DeviceInfo
(
id:
'2'
,
name:
'客控设备 1F-01'
,
room:
'101'
,
type:
DeviceTypeEnum
.
guestControl
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:32'
,
),
const
DeviceInfo
(
id:
'3'
,
name:
'网络设备 1F'
,
room:
'一楼'
,
type:
DeviceTypeEnum
.
network
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:28'
,
),
const
DeviceInfo
(
id:
'4'
,
name:
'智能空开 2F-01'
,
room:
'201'
,
type:
DeviceTypeEnum
.
smartBreaker
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:25'
,
),
const
DeviceInfo
(
id:
'5'
,
name:
'客控设备 2F-01'
,
room:
'201'
,
type:
DeviceTypeEnum
.
guestControl
,
online:
false
,
status:
'离线'
,
lastUpdate:
'09:15'
,
),
const
DeviceInfo
(
id:
'6'
,
name:
'智能空开 3F-01'
,
room:
'301'
,
type:
DeviceTypeEnum
.
smartBreaker
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:30'
,
),
const
DeviceInfo
(
id:
'7'
,
name:
'客控设备 3F-01'
,
room:
'301'
,
type:
DeviceTypeEnum
.
guestControl
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:30'
,
),
const
DeviceInfo
(
id:
'8'
,
name:
'网络设备 2F'
,
room:
'二楼'
,
type:
DeviceTypeEnum
.
network
,
online:
true
,
status:
'正常'
,
lastUpdate:
'10:30'
,
),
];
emit
(
state
.
copyWith
(
devices:
devices
));
}
void
selectType
(
DeviceTypeEnum
type
)
{
emit
(
state
.
copyWith
(
selectedType:
type
));
}
}
lib/views/report/device/cubit/device_list_state.dart
0 → 100644
View file @
3c72b94e
import
'package:equatable/equatable.dart'
;
enum
DeviceTypeEnum
{
all
,
smartBreaker
,
guestControl
,
network
,
}
class
DeviceInfo
{
final
String
id
;
final
String
name
;
final
String
room
;
final
DeviceTypeEnum
type
;
final
bool
online
;
final
String
status
;
final
String
lastUpdate
;
const
DeviceInfo
({
required
this
.
id
,
required
this
.
name
,
required
this
.
room
,
required
this
.
type
,
required
this
.
online
,
required
this
.
status
,
required
this
.
lastUpdate
,
});
DeviceInfo
copyWith
({
String
?
id
,
String
?
name
,
String
?
room
,
DeviceTypeEnum
?
type
,
bool
?
online
,
String
?
status
,
String
?
lastUpdate
,
})
{
return
DeviceInfo
(
id:
id
??
this
.
id
,
name:
name
??
this
.
name
,
room:
room
??
this
.
room
,
type:
type
??
this
.
type
,
online:
online
??
this
.
online
,
status:
status
??
this
.
status
,
lastUpdate:
lastUpdate
??
this
.
lastUpdate
,
);
}
}
class
DeviceListState
extends
Equatable
{
final
List
<
DeviceInfo
>
devices
;
final
DeviceTypeEnum
selectedType
;
const
DeviceListState
({
this
.
devices
=
const
[],
this
.
selectedType
=
DeviceTypeEnum
.
all
,
});
DeviceListState
copyWith
({
List
<
DeviceInfo
>?
devices
,
DeviceTypeEnum
?
selectedType
,
})
{
return
DeviceListState
(
devices:
devices
??
this
.
devices
,
selectedType:
selectedType
??
this
.
selectedType
,
);
}
List
<
DeviceInfo
>
get
filteredDevices
{
if
(
selectedType
==
DeviceTypeEnum
.
all
)
{
return
devices
;
}
return
devices
.
where
((
device
)
=>
device
.
type
==
selectedType
).
toList
();
}
@override
List
<
Object
?>
get
props
=>
[
devices
,
selectedType
];
}
lib/views/report/device/device_detail_view.dart
0 → 100644
View file @
3c72b94e
lib/views/report/
room/room_detail
.dart
→
lib/views/report/
device/device_list_view
.dart
View file @
3c72b94e
...
...
@@ -2,31 +2,36 @@ import 'package:auto_route/auto_route.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_cubit.dart'
;
import
'package:smart_hotel_app/views/report/device/cubit/device_list_cubit.dart'
;
import
'package:smart_hotel_app/views/report/device/cubit/device_list_state.dart'
;
import
'package:smart_hotel_app/views/report/device/widget/device_card.dart'
;
import
'package:smart_hotel_app/views/report/device/widget/device_filter_tab.dart'
;
@RoutePage
()
class
Report
RoomDetail
View
extends
StatelessWidget
{
const
Report
RoomDetail
View
({
super
.
key
});
class
Report
DeviceList
View
extends
StatelessWidget
{
const
Report
DeviceList
View
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
create:
(
_
)
=>
RoomReportCubit
(),
child:
Scaffold
(
backgroundColor:
const
Color
.
fromRGBO
(
15
,
23
,
42
,
1
),
create:
(
_
)
=>
DeviceListCubit
(),
child:
BlocBuilder
<
DeviceListCubit
,
DeviceListState
>(
builder:
(
context
,
state
)
{
return
Scaffold
(
backgroundColor:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
appBar:
AppBar
(
backgroundColor:
const
Color
.
fromRGBO
(
15
,
23
,
42
,
1
)
,
backgroundColor:
Colors
.
white
,
elevation:
0
,
leading:
IconButton
(
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
white
),
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
black
),
onPressed:
()
{
context
.
popRoute
();
},
),
title:
Text
(
'能耗分析
'
,
'全部设备
'
,
style:
TextStyle
(
color:
Colors
.
white
,
color:
Colors
.
black
,
fontSize:
18
.
sp
,
fontWeight:
FontWeight
.
bold
,
),
...
...
@@ -34,13 +39,32 @@ class ReportRoomDetailView extends StatelessWidget {
centerTitle:
true
,
),
body:
SingleChildScrollView
(
child:
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
Column
(
children:
[
SizedBox
(
height:
10
.
h
),
DeviceFilterTab
(
selectedType:
state
.
selectedType
,
onSelect:
(
type
)
{
context
.
read
<
DeviceListCubit
>().
selectType
(
type
);
},
),
SizedBox
(
height:
10
.
h
),
...
state
.
filteredDevices
.
map
((
device
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
10
.
h
),
child:
DeviceCard
(
device:
device
),
);
}).
toList
(),
SizedBox
(
height:
10
.
h
),
],
),
),
),
);
},
),
);
}
}
lib/views/report/device/widget/device_card.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/device/cubit/device_list_state.dart'
;
class
DeviceCard
extends
StatelessWidget
{
final
DeviceInfo
device
;
const
DeviceCard
({
super
.
key
,
required
this
.
device
,
});
IconData
_getIconForType
(
DeviceTypeEnum
type
)
{
switch
(
type
)
{
case
DeviceTypeEnum
.
smartBreaker
:
return
Icons
.
power
;
case
DeviceTypeEnum
.
guestControl
:
return
Icons
.
settings_remote
;
case
DeviceTypeEnum
.
network
:
return
Icons
.
wifi
;
default
:
return
Icons
.
devices
;
}
}
Color
_getIconColor
(
DeviceTypeEnum
type
)
{
switch
(
type
)
{
case
DeviceTypeEnum
.
smartBreaker
:
return
const
Color
.
fromRGBO
(
245
,
158
,
11
,
1
);
case
DeviceTypeEnum
.
guestControl
:
return
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
);
case
DeviceTypeEnum
.
network
:
return
const
Color
.
fromRGBO
(
16
,
185
,
129
,
1
);
default
:
return
const
Color
.
fromRGBO
(
107
,
114
,
128
,
1
);
}
}
String
_getTypeLabel
(
DeviceTypeEnum
type
)
{
switch
(
type
)
{
case
DeviceTypeEnum
.
smartBreaker
:
return
'智能空开'
;
case
DeviceTypeEnum
.
guestControl
:
return
'客控设备'
;
case
DeviceTypeEnum
.
network
:
return
'网络设备'
;
default
:
return
'其他'
;
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
width:
double
.
infinity
,
padding:
EdgeInsets
.
all
(
28
.
w
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
24
.
r
),
color:
Colors
.
white
,
),
child:
Row
(
children:
[
Container
(
width:
80
.
w
,
height:
80
.
h
,
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
16
.
r
),
color:
_getIconColor
(
device
.
type
).
withOpacity
(
0.1
),
),
child:
Icon
(
_getIconForType
(
device
.
type
),
color:
_getIconColor
(
device
.
type
),
size:
36
.
sp
,
),
),
SizedBox
(
width:
20
.
w
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
device
.
name
,
style:
TextStyle
(
fontSize:
26
.
sp
,
fontWeight:
FontWeight
.
bold
,
color:
const
Color
.
fromRGBO
(
31
,
41
,
55
,
1
),
),
),
SizedBox
(
height:
8
.
h
),
Row
(
children:
[
Text
(
_getTypeLabel
(
device
.
type
),
style:
TextStyle
(
fontSize:
20
.
sp
,
color:
const
Color
.
fromRGBO
(
107
,
114
,
128
,
1
),
),
),
SizedBox
(
width:
16
.
w
),
Text
(
'房间
${device.room}
'
,
style:
TextStyle
(
fontSize:
20
.
sp
,
color:
const
Color
.
fromRGBO
(
107
,
114
,
128
,
1
),
),
),
],
),
],
),
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
16
.
w
,
vertical:
8
.
h
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
color:
device
.
online
?
const
Color
.
fromRGBO
(
220
,
252
,
231
,
1
)
:
const
Color
.
fromRGBO
(
254
,
226
,
226
,
1
),
),
child:
Text
(
device
.
status
,
style:
TextStyle
(
fontSize:
20
.
sp
,
color:
device
.
online
?
const
Color
.
fromRGBO
(
21
,
128
,
61
,
1
)
:
const
Color
.
fromRGBO
(
220
,
38
,
38
,
1
),
fontWeight:
FontWeight
.
bold
,
),
),
),
SizedBox
(
height:
8
.
h
),
Text
(
device
.
lastUpdate
,
style:
TextStyle
(
fontSize:
18
.
sp
,
color:
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
),
),
),
],
),
],
),
);
}
}
lib/views/report/device/widget/device_filter_tab.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/device/cubit/device_list_state.dart'
;
class
DeviceFilterTab
extends
StatelessWidget
{
final
DeviceTypeEnum
selectedType
;
final
Function
(
DeviceTypeEnum
)
onSelect
;
const
DeviceFilterTab
({
super
.
key
,
required
this
.
selectedType
,
required
this
.
onSelect
,
});
@override
Widget
build
(
BuildContext
context
)
{
final
tabs
=
[
{
'type'
:
DeviceTypeEnum
.
all
,
'label'
:
'全部'
},
{
'type'
:
DeviceTypeEnum
.
smartBreaker
,
'label'
:
'空开'
},
{
'type'
:
DeviceTypeEnum
.
guestControl
,
'label'
:
'客控'
},
{
'type'
:
DeviceTypeEnum
.
network
,
'label'
:
'网络'
},
];
return
Container
(
width:
double
.
infinity
,
padding:
EdgeInsets
.
all
(
20
.
w
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
24
.
r
),
color:
Colors
.
white
,
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
tabs
.
map
((
tab
)
{
final
isSelected
=
selectedType
==
tab
[
'type'
];
return
GestureDetector
(
onTap:
()
=>
onSelect
(
tab
[
'type'
]
as
DeviceTypeEnum
),
child:
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
24
.
w
,
vertical:
12
.
h
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
16
.
r
),
color:
isSelected
?
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
)
:
const
Color
.
fromRGBO
(
243
,
244
,
246
,
1
),
),
child:
Text
(
tab
[
'label'
]
as
String
,
style:
TextStyle
(
fontSize:
24
.
sp
,
color:
isSelected
?
Colors
.
white
:
const
Color
.
fromRGBO
(
107
,
114
,
128
,
1
),
fontWeight:
isSelected
?
FontWeight
.
bold
:
FontWeight
.
normal
,
),
),
),
);
}).
toList
(),
),
);
}
}
lib/views/report/room/room_detail_view.dart
0 → 100644
View file @
3c72b94e
import
'package:auto_route/auto_route.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_cubit.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_state.dart'
;
import
'package:smart_hotel_app/views/report/room/widget/floor_selector.dart'
;
import
'package:smart_hotel_app/views/report/room/widget/room_grid.dart'
;
import
'package:smart_hotel_app/views/report/room/widget/status_stats.dart'
;
import
'package:smart_hotel_app/views/report/room/widget/room_detail_card.dart'
;
@RoutePage
()
class
ReportRoomDetailView
extends
StatelessWidget
{
const
ReportRoomDetailView
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
create:
(
_
)
=>
RoomReportCubit
(),
child:
BlocBuilder
<
RoomReportCubit
,
RoomReportState
>(
builder:
(
context
,
state
)
{
return
Scaffold
(
backgroundColor:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
appBar:
AppBar
(
backgroundColor:
Colors
.
white
,
elevation:
0
,
leading:
IconButton
(
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
black
),
onPressed:
()
{
context
.
popRoute
();
},
),
title:
Text
(
'客房详情'
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
32
.
sp
,
fontWeight:
FontWeight
.
bold
,
),
),
centerTitle:
true
,
),
body:
SingleChildScrollView
(
child:
Column
(
children:
[
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
Column
(
children:
[
SizedBox
(
height:
10
.
h
),
if
(
state
.
floors
.
isNotEmpty
)
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
24
.
r
)),
),
child:
FloorSelector
(
floorNames:
state
.
floors
.
map
((
f
)
=>
f
.
floorName
).
toList
(),
selectedIndex:
state
.
selectedFloorIndex
,
),
),
if
(
state
.
floors
.
isNotEmpty
&&
state
.
selectedFloorIndex
<
state
.
floors
.
length
)
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
vertical
(
bottom:
Radius
.
circular
(
24
.
r
)),
),
padding:
EdgeInsets
.
only
(
bottom:
28
.
w
),
child:
RoomGrid
(
rooms:
state
.
floors
[
state
.
selectedFloorIndex
].
rooms
),
),
SizedBox
(
height:
10
.
h
),
if
(
state
.
statusStats
.
isNotEmpty
)
StatusStats
(
stats:
state
.
statusStats
),
SizedBox
(
height:
10
.
h
),
...
state
.
detailRooms
.
map
((
room
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
10
.
h
),
child:
RoomDetailCard
(
room:
room
),
);
}).
toList
(),
SizedBox
(
height:
10
.
h
),
],
),
),
],
),
),
);
},
),
);
}
}
\ No newline at end of file
lib/views/report/room/widget/floor_selector.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_cubit.dart'
;
class
FloorSelector
extends
StatelessWidget
{
final
List
<
String
>
floorNames
;
final
int
selectedIndex
;
const
FloorSelector
({
super
.
key
,
required
this
.
floorNames
,
required
this
.
selectedIndex
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
width:
double
.
infinity
,
child:
SingleChildScrollView
(
scrollDirection:
Axis
.
horizontal
,
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
,
vertical:
16
.
h
),
child:
Row
(
children:
floorNames
.
asMap
().
entries
.
map
((
entry
)
{
final
index
=
entry
.
key
;
final
name
=
entry
.
value
;
final
isSelected
=
index
==
selectedIndex
;
return
Padding
(
padding:
EdgeInsets
.
only
(
right:
32
.
w
),
child:
GestureDetector
(
onTap:
()
{
context
.
read
<
RoomReportCubit
>().
selectFloor
(
index
);
},
child:
Column
(
children:
[
Text
(
name
,
style:
TextStyle
(
fontSize:
28
.
sp
,
color:
isSelected
?
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
)
:
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
),
fontWeight:
isSelected
?
FontWeight
.
bold
:
FontWeight
.
normal
,
),
),
SizedBox
(
height:
4
.
h
),
Container
(
width:
40
.
w
,
height:
3
.
h
,
decoration:
BoxDecoration
(
color:
isSelected
?
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
)
:
Colors
.
transparent
,
borderRadius:
BorderRadius
.
circular
(
2
.
r
),
),
),
],
),
),
);
}).
toList
(),
),
),
);
}
}
lib/views/report/room/widget/room_detail_card.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_state.dart'
;
class
RoomDetailCard
extends
StatelessWidget
{
final
RoomInfo
room
;
const
RoomDetailCard
({
super
.
key
,
required
this
.
room
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
width:
double
.
infinity
,
padding:
EdgeInsets
.
all
(
28
.
w
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
24
.
r
),
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
children:
[
Container
(
width:
60
.
w
,
height:
60
.
h
,
decoration:
BoxDecoration
(
color:
const
Color
.
fromRGBO
(
219
,
234
,
254
,
1
),
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
),
child:
Icon
(
Icons
.
meeting_room_outlined
,
color:
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
),
size:
32
.
sp
,
),
),
SizedBox
(
width:
16
.
w
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
children:
[
Text
(
room
.
roomNumber
,
style:
TextStyle
(
fontSize:
36
.
sp
,
fontWeight:
FontWeight
.
bold
,
color:
const
Color
.
fromRGBO
(
31
,
41
,
55
,
1
),
),
),
SizedBox
(
width:
16
.
w
),
Text
(
'入住中'
,
style:
TextStyle
(
fontSize:
28
.
sp
,
color:
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
),
),
),
],
),
SizedBox
(
height:
12
.
h
),
Row
(
children:
[
_StatusTag
(
label:
'有人'
,
isActive:
room
.
deviceStatus
.
hasPerson
,
),
SizedBox
(
width:
12
.
w
),
_StatusTag
(
label:
'通电中'
,
isActive:
room
.
deviceStatus
.
powerOn
,
),
SizedBox
(
width:
12
.
w
),
_StatusTag
(
label:
'wifi正常'
,
isActive:
room
.
deviceStatus
.
wifiNormal
,
),
],
),
],
),
],
),
SizedBox
(
height:
24
.
h
),
Divider
(
height:
1
.
h
,
color:
const
Color
.
fromRGBO
(
229
,
231
,
235
,
1
),
),
SizedBox
(
height:
24
.
h
),
GridView
.
count
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
crossAxisCount:
2
,
mainAxisSpacing:
16
.
h
,
crossAxisSpacing:
16
.
w
,
children:
[
_DeviceControl
(
icon:
Icons
.
air_outlined
,
label:
'空调'
,
value:
'
${room.deviceStatus.acTemperature}
°C·
${room.deviceStatus.acOn ? '开' : '关'}
'
,
isOn:
room
.
deviceStatus
.
acOn
,
),
_DeviceControl
(
icon:
Icons
.
light_outlined
,
label:
'照明'
,
value:
room
.
deviceStatus
.
lightOn
?
'开'
:
'关'
,
isOn:
room
.
deviceStatus
.
lightOn
,
),
_DeviceControl
(
icon:
Icons
.
tv_outlined
,
label:
'电视'
,
value:
room
.
deviceStatus
.
tvOn
?
'开'
:
'关'
,
isOn:
room
.
deviceStatus
.
tvOn
,
),
_DeviceControl
(
icon:
Icons
.
curtains_outlined
,
label:
'窗帘'
,
value:
room
.
deviceStatus
.
curtainOn
?
'开'
:
'关'
,
isOn:
room
.
deviceStatus
.
curtainOn
,
),
],
),
],
),
);
}
}
class
_StatusTag
extends
StatelessWidget
{
final
String
label
;
final
bool
isActive
;
const
_StatusTag
({
required
this
.
label
,
required
this
.
isActive
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
12
.
w
,
vertical:
8
.
h
),
decoration:
BoxDecoration
(
color:
isActive
?
const
Color
.
fromRGBO
(
167
,
243
,
208
,
1
)
:
const
Color
.
fromRGBO
(
229
,
231
,
235
,
1
),
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
),
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
if
(
isActive
)
Icon
(
Icons
.
check
,
size:
20
.
sp
,
color:
const
Color
.
fromRGBO
(
16
,
185
,
129
,
1
),
),
if
(
isActive
)
SizedBox
(
width:
4
.
w
),
Text
(
label
,
style:
TextStyle
(
fontSize:
22
.
sp
,
color:
isActive
?
const
Color
.
fromRGBO
(
16
,
185
,
129
,
1
)
:
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
),
),
),
],
),
);
}
}
class
_DeviceControl
extends
StatelessWidget
{
final
IconData
icon
;
final
String
label
;
final
String
value
;
final
bool
isOn
;
const
_DeviceControl
({
required
this
.
icon
,
required
this
.
label
,
required
this
.
value
,
required
this
.
isOn
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
24
.
w
,
vertical:
24
.
h
),
decoration:
BoxDecoration
(
color:
const
Color
.
fromRGBO
(
239
,
246
,
255
,
1
),
borderRadius:
BorderRadius
.
circular
(
24
.
r
),
),
child:
Row
(
children:
[
Icon
(
icon
,
color:
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
),
size:
40
.
sp
,
),
SizedBox
(
width:
16
.
w
),
Text
(
label
,
style:
TextStyle
(
fontSize:
28
.
sp
,
color:
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
),
fontWeight:
FontWeight
.
w500
,
),
),
const
Spacer
(),
Text
(
value
,
style:
TextStyle
(
fontSize:
26
.
sp
,
color:
isOn
?
const
Color
.
fromRGBO
(
16
,
185
,
129
,
1
)
:
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
),
),
),
],
),
);
}
}
lib/views/report/room/widget/room_grid.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_state.dart'
;
class
RoomGrid
extends
StatelessWidget
{
final
List
<
RoomInfo
>
rooms
;
const
RoomGrid
({
super
.
key
,
required
this
.
rooms
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
width:
double
.
infinity
,
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
GridView
.
count
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
crossAxisCount:
5
,
mainAxisSpacing:
20
.
h
,
crossAxisSpacing:
16
.
w
,
children:
rooms
.
map
((
room
)
=>
RoomItem
(
room:
room
)).
toList
(),
),
);
}
}
class
RoomItem
extends
StatelessWidget
{
final
RoomInfo
room
;
const
RoomItem
({
super
.
key
,
required
this
.
room
});
Color
get
_bgColor
{
switch
(
room
.
status
)
{
case
RoomStatus
.
vacant
:
return
const
Color
.
fromRGBO
(
229
,
231
,
235
,
1
);
case
RoomStatus
.
occupied
:
case
RoomStatus
.
reserved
:
return
const
Color
.
fromRGBO
(
219
,
234
,
254
,
1
);
case
RoomStatus
.
warning
:
case
RoomStatus
.
temperature
:
return
const
Color
.
fromRGBO
(
254
,
243
,
199
,
1
);
}
}
Color
get
_textColor
{
switch
(
room
.
status
)
{
case
RoomStatus
.
vacant
:
return
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
);
case
RoomStatus
.
occupied
:
case
RoomStatus
.
reserved
:
return
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
);
case
RoomStatus
.
warning
:
case
RoomStatus
.
temperature
:
return
const
Color
.
fromRGBO
(
245
,
158
,
11
,
1
);
}
}
Color
?
get
_borderColor
{
switch
(
room
.
status
)
{
case
RoomStatus
.
vacant
:
return
null
;
case
RoomStatus
.
occupied
:
case
RoomStatus
.
reserved
:
return
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
);
case
RoomStatus
.
warning
:
case
RoomStatus
.
temperature
:
return
const
Color
.
fromRGBO
(
245
,
158
,
11
,
1
);
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
vertical:
12
.
h
,
horizontal:
8
.
w
),
decoration:
BoxDecoration
(
color:
_bgColor
,
borderRadius:
BorderRadius
.
circular
(
16
.
r
),
border:
_borderColor
!=
null
?
Border
.
all
(
color:
_borderColor
!,
width:
2
.
w
)
:
null
,
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Text
(
room
.
roomNumber
,
style:
TextStyle
(
fontSize:
28
.
sp
,
fontWeight:
FontWeight
.
bold
,
color:
_textColor
,
),
),
SizedBox
(
height:
4
.
h
),
if
(
room
.
status
==
RoomStatus
.
warning
||
room
.
status
==
RoomStatus
.
temperature
)
Icon
(
Icons
.
warning_amber_outlined
,
color:
_textColor
,
size:
20
.
sp
),
if
(
room
.
status
!=
RoomStatus
.
warning
&&
room
.
status
!=
RoomStatus
.
temperature
)
Text
(
room
.
statusText
,
style:
TextStyle
(
fontSize:
20
.
sp
,
color:
_textColor
,
),
),
],
),
);
}
}
lib/views/report/room/widget/status_stats.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/room/cubit/room_report_state.dart'
;
class
StatusStats
extends
StatelessWidget
{
final
List
<
StatusStat
>
stats
;
const
StatusStats
({
super
.
key
,
required
this
.
stats
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
width:
double
.
infinity
,
padding:
EdgeInsets
.
all
(
28
.
w
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
24
.
r
),
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
stats
.
map
((
stat
)
=>
StatItem
(
stat:
stat
)).
toList
(),
),
);
}
}
class
StatItem
extends
StatelessWidget
{
final
StatusStat
stat
;
const
StatItem
({
super
.
key
,
required
this
.
stat
});
@override
Widget
build
(
BuildContext
context
)
{
return
Column
(
children:
[
Text
(
stat
.
count
.
toString
(),
style:
TextStyle
(
fontSize:
40
.
sp
,
fontWeight:
FontWeight
.
bold
,
color:
stat
.
color
,
),
),
SizedBox
(
height:
4
.
h
),
Text
(
stat
.
label
,
style:
TextStyle
(
fontSize:
24
.
sp
,
color:
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
),
),
),
],
);
}
}
lib/views/report/rule/cubit/rule_management_cubit.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:smart_hotel_app/views/report/rule/cubit/rule_management_state.dart'
;
class
RuleManagementCubit
extends
Cubit
<
RuleManagementState
>
{
RuleManagementCubit
()
:
super
(
const
RuleManagementState
())
{
_initData
();
}
void
_initData
()
{
final
rules
=
[
const
RuleInfo
(
id:
'1'
,
name:
'退房自动断电'
,
description:
'酒管系统—酒度状态'
,
enabled:
true
,
triggerCondition:
'酒管系统—酒度状态'
,
action:
'断电'
,
icon:
Icons
.
logout_outlined
,
),
const
RuleInfo
(
id:
'2'
,
name:
'清洁中请自动开灯'
,
description:
'服务彩忧消洁中调'
,
enabled:
true
,
triggerCondition:
'服务彩忧消洁中调'
,
action:
'开灯'
,
icon:
Icons
.
cleaning_services_outlined
,
),
const
RuleInfo
(
id:
'3'
,
name:
'温度过高自动保护'
,
description:
'温度·80°C—断电+告管'
,
enabled:
true
,
triggerCondition:
'温度·80°C'
,
action:
'断电+告管'
,
icon:
Icons
.
thermostat_outlined
,
),
const
RuleInfo
(
id:
'4'
,
name:
'深夜低功事休眠'
,
description:
'23:00-06:00 平<50W'
,
enabled:
false
,
triggerCondition:
'23:00-06:00 平<50W'
,
action:
'休眠'
,
icon:
Icons
.
nightlight_outlined
,
),
const
RuleInfo
(
id:
'5'
,
name:
'定时全楼巡检提醒'
,
description:
'国日 09:00/15.00'
,
enabled:
true
,
triggerCondition:
'国日 09:00/15.00'
,
action:
'提醒'
,
icon:
Icons
.
access_time_outlined
,
),
];
emit
(
state
.
copyWith
(
rules:
rules
));
}
void
toggleRule
(
String
id
)
{
final
updatedRules
=
state
.
rules
.
map
((
rule
)
{
if
(
rule
.
id
==
id
)
{
return
rule
.
copyWith
(
enabled:
!
rule
.
enabled
);
}
return
rule
;
}).
toList
();
emit
(
state
.
copyWith
(
rules:
updatedRules
));
}
}
lib/views/report/rule/cubit/rule_management_state.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:equatable/equatable.dart'
;
class
RuleInfo
{
final
String
id
;
final
String
name
;
final
String
description
;
final
bool
enabled
;
final
String
triggerCondition
;
final
String
action
;
final
IconData
icon
;
const
RuleInfo
({
required
this
.
id
,
required
this
.
name
,
required
this
.
description
,
required
this
.
enabled
,
required
this
.
triggerCondition
,
required
this
.
action
,
required
this
.
icon
,
});
RuleInfo
copyWith
({
String
?
id
,
String
?
name
,
String
?
description
,
bool
?
enabled
,
String
?
triggerCondition
,
String
?
action
,
IconData
?
icon
,
})
{
return
RuleInfo
(
id:
id
??
this
.
id
,
name:
name
??
this
.
name
,
description:
description
??
this
.
description
,
enabled:
enabled
??
this
.
enabled
,
triggerCondition:
triggerCondition
??
this
.
triggerCondition
,
action:
action
??
this
.
action
,
icon:
icon
??
this
.
icon
,
);
}
}
class
RuleManagementState
extends
Equatable
{
final
List
<
RuleInfo
>
rules
;
const
RuleManagementState
({
this
.
rules
=
const
[],
});
RuleManagementState
copyWith
({
List
<
RuleInfo
>?
rules
,
})
{
return
RuleManagementState
(
rules:
rules
??
this
.
rules
,
);
}
@override
List
<
Object
?>
get
props
=>
[
rules
];
}
lib/views/report/rule/rule_management_view.dart
0 → 100644
View file @
3c72b94e
import
'package:auto_route/auto_route.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/views/report/rule/cubit/rule_management_cubit.dart'
;
import
'package:smart_hotel_app/views/report/rule/cubit/rule_management_state.dart'
;
import
'package:smart_hotel_app/views/report/rule/widget/rule_card.dart'
;
@RoutePage
()
class
ReportRuleManagementView
extends
StatelessWidget
{
const
ReportRuleManagementView
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
create:
(
_
)
=>
RuleManagementCubit
(),
child:
BlocBuilder
<
RuleManagementCubit
,
RuleManagementState
>(
builder:
(
context
,
state
)
{
return
Scaffold
(
backgroundColor:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
appBar:
AppBar
(
backgroundColor:
Colors
.
white
,
elevation:
0
,
leading:
IconButton
(
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
black
),
onPressed:
()
{
context
.
popRoute
();
},
),
title:
Text
(
'联动规则管理'
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
32
.
sp
,
fontWeight:
FontWeight
.
bold
,
),
),
centerTitle:
true
,
),
body:
SingleChildScrollView
(
child:
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
,
vertical:
20
.
h
),
child:
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
24
.
r
),
),
child:
ListView
.
separated
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
itemCount:
state
.
rules
.
length
,
separatorBuilder:
(
context
,
index
)
=>
Divider
(
height:
1
.
h
,
color:
const
Color
.
fromRGBO
(
229
,
231
,
235
,
1
),
indent:
28
.
w
,
endIndent:
28
.
w
,
),
itemBuilder:
(
context
,
index
)
{
return
RuleCard
(
rule:
state
.
rules
[
index
],
onToggle:
(
id
)
{
context
.
read
<
RuleManagementCubit
>().
toggleRule
(
id
);
},
);
},
),
),
),
),
);
},
),
);
}
}
lib/views/report/rule/widget/rule_card.dart
0 → 100644
View file @
3c72b94e
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:flutter_switch/flutter_switch.dart'
;
import
'package:smart_hotel_app/views/report/rule/cubit/rule_management_state.dart'
;
class
RuleCard
extends
StatelessWidget
{
final
RuleInfo
rule
;
final
Function
(
String
)
onToggle
;
const
RuleCard
({
super
.
key
,
required
this
.
rule
,
required
this
.
onToggle
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
vertical:
24
.
h
,
horizontal:
28
.
w
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
),
child:
Column
(
children:
[
Row
(
children:
[
Container
(
width:
72
.
w
,
height:
72
.
h
,
decoration:
BoxDecoration
(
color:
const
Color
.
fromRGBO
(
219
,
234
,
254
,
1
),
borderRadius:
BorderRadius
.
circular
(
12
.
r
),
),
child:
Icon
(
rule
.
icon
,
size:
36
.
sp
,
color:
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
),
),
),
SizedBox
(
width:
20
.
w
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
rule
.
name
,
style:
TextStyle
(
fontSize:
32
.
sp
,
fontWeight:
FontWeight
.
bold
,
color:
const
Color
.
fromRGBO
(
31
,
41
,
55
,
1
),
),
),
SizedBox
(
height:
8
.
h
),
Text
(
rule
.
description
,
style:
TextStyle
(
fontSize:
26
.
sp
,
color:
const
Color
.
fromRGBO
(
156
,
163
,
175
,
1
),
),
),
],
),
),
FlutterSwitch
(
width:
88
.
w
,
height:
48
.
h
,
valueFontSize:
20
.
sp
,
toggleSize:
40
.
h
,
value:
rule
.
enabled
,
borderRadius:
24
.
r
,
padding:
4
.
w
,
activeColor:
const
Color
.
fromRGBO
(
59
,
130
,
246
,
1
),
inactiveColor:
const
Color
.
fromRGBO
(
209
,
213
,
219
,
1
),
onToggle:
(
_
)
=>
onToggle
(
rule
.
id
),
),
],
),
],
),
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment