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
cfc4a398
Commit
cfc4a398
authored
Jun 10, 2026
by
张宏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
3
parent
749feeaf
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
585 additions
and
99 deletions
+585
-99
room_bo.dart
lib/models/bo/room_bo.dart
+219
-0
room_repository.dart
lib/repositories/room_repository.dart
+27
-0
app_router.gr.dart
lib/routes/app_router.gr.dart
+8
-2
room_service.dart
lib/services/room_service.dart
+26
-0
room_management_block.dart
lib/views/service/index/widget/room_management_block.dart
+7
-2
service_room_cubit.dart
lib/views/service/room/cubit/service_room_cubit.dart
+170
-72
service_room_state.dart
lib/views/service/room/cubit/service_room_state.dart
+24
-5
room_detail_view.dart
lib/views/service/room/room_detail_view.dart
+70
-15
对接方案.md
对接方案.md
+34
-3
No files found.
lib/models/bo/room_bo.dart
View file @
cfc4a398
...
...
@@ -104,4 +104,222 @@ class RoomStatusBO extends Equatable {
@override
List
<
Object
?>
get
props
=>
[
roomId
,
roomNumber
,
occupancyStatus
,
roomStatus
,
cleanStatus
,
devicePowerStatus
];
}
// ==================== 客房详情 ====================
class
RoomDetailBO
extends
Equatable
{
final
RoomBasicInfoBO
roomBasicInfo
;
final
List
<
DeviceStatusBO
>
deviceStatusList
;
final
RoomDeviceControlBO
deviceControl
;
const
RoomDetailBO
({
required
this
.
roomBasicInfo
,
required
this
.
deviceStatusList
,
required
this
.
deviceControl
,
});
factory
RoomDetailBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
RoomDetailBO
(
roomBasicInfo:
RoomBasicInfoBO
.
fromJson
(
json
[
'roomBasicInfo'
]
as
Map
<
String
,
dynamic
>?
??
{}),
deviceStatusList:
(
json
[
'deviceStatusList'
]
as
List
<
dynamic
>?)
?.
map
((
e
)
=>
DeviceStatusBO
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
.
toList
()
??
[],
deviceControl:
RoomDeviceControlBO
.
fromJson
(
json
[
'deviceControl'
]
as
Map
<
String
,
dynamic
>?
??
{}),
);
}
@override
List
<
Object
?>
get
props
=>
[
roomBasicInfo
,
deviceStatusList
,
deviceControl
];
}
class
RoomBasicInfoBO
extends
Equatable
{
final
int
roomId
;
final
String
roomNumber
;
final
String
occupancyStatus
;
final
bool
powerSupplyStatus
;
final
String
wifiOnlineStatus
;
const
RoomBasicInfoBO
({
required
this
.
roomId
,
required
this
.
roomNumber
,
required
this
.
occupancyStatus
,
required
this
.
powerSupplyStatus
,
required
this
.
wifiOnlineStatus
,
});
factory
RoomBasicInfoBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
RoomBasicInfoBO
(
roomId:
_parseInt
(
json
[
'roomId'
]),
roomNumber:
_parseString
(
json
[
'roomNumber'
]),
occupancyStatus:
_parseString
(
json
[
'occupancyStatus'
]),
powerSupplyStatus:
json
[
'powerSupplyStatus'
]
as
bool
?
??
false
,
wifiOnlineStatus:
_parseString
(
json
[
'wifiOnlineStatus'
]),
);
}
@override
List
<
Object
?>
get
props
=>
[
roomId
,
roomNumber
,
occupancyStatus
,
powerSupplyStatus
,
wifiOnlineStatus
];
}
class
DeviceStatusBO
extends
Equatable
{
final
int
deviceId
;
final
String
deviceName
;
final
String
deviceTypeName
;
final
String
deviceTypeIcon
;
final
String
powerStatus
;
final
String
powerStatusText
;
final
String
runStatus
;
final
String
runStatusText
;
final
DeviceParamsBO
?
deviceParams
;
const
DeviceStatusBO
({
required
this
.
deviceId
,
required
this
.
deviceName
,
required
this
.
deviceTypeName
,
required
this
.
deviceTypeIcon
,
required
this
.
powerStatus
,
required
this
.
powerStatusText
,
required
this
.
runStatus
,
required
this
.
runStatusText
,
this
.
deviceParams
,
});
factory
DeviceStatusBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
DeviceStatusBO
(
deviceId:
_parseInt
(
json
[
'deviceId'
]),
deviceName:
_parseString
(
json
[
'deviceName'
]),
deviceTypeName:
_parseString
(
json
[
'deviceTypeName'
]),
deviceTypeIcon:
_parseString
(
json
[
'deviceTypeIcon'
]),
powerStatus:
_parseString
(
json
[
'powerStatus'
]),
powerStatusText:
_parseString
(
json
[
'powerStatusText'
]),
runStatus:
_parseString
(
json
[
'runStatus'
]),
runStatusText:
_parseString
(
json
[
'runStatusText'
]),
deviceParams:
json
[
'deviceParams'
]
!=
null
?
DeviceParamsBO
.
fromJson
(
json
[
'deviceParams'
]
as
Map
<
String
,
dynamic
>)
:
null
,
);
}
@override
List
<
Object
?>
get
props
=>
[
deviceId
,
deviceName
,
deviceTypeName
,
deviceTypeIcon
,
powerStatus
,
powerStatusText
,
runStatus
,
runStatusText
,
deviceParams
,
];
}
class
DeviceParamsBO
extends
Equatable
{
final
String
temperature
;
final
String
targetTemperature
;
final
String
mode
;
final
String
fanSpeed
;
const
DeviceParamsBO
({
required
this
.
temperature
,
required
this
.
targetTemperature
,
required
this
.
mode
,
required
this
.
fanSpeed
,
});
factory
DeviceParamsBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
DeviceParamsBO
(
temperature:
_parseString
(
json
[
'temperature'
]),
targetTemperature:
_parseString
(
json
[
'targetTemperature'
]),
mode:
_parseString
(
json
[
'mode'
]),
fanSpeed:
_parseString
(
json
[
'fanSpeed'
]),
);
}
@override
List
<
Object
?>
get
props
=>
[
temperature
,
targetTemperature
,
mode
,
fanSpeed
];
}
class
RoomDeviceControlBO
extends
Equatable
{
final
RoomPowerControlBO
roomPowerControl
;
final
List
<
SubDeviceControlBO
>
subDeviceControls
;
const
RoomDeviceControlBO
({
required
this
.
roomPowerControl
,
required
this
.
subDeviceControls
,
});
factory
RoomDeviceControlBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
RoomDeviceControlBO
(
roomPowerControl:
RoomPowerControlBO
.
fromJson
(
json
[
'roomPowerControl'
]
as
Map
<
String
,
dynamic
>?
??
{}),
subDeviceControls:
(
json
[
'subDeviceControls'
]
as
List
<
dynamic
>?)
?.
map
((
e
)
=>
SubDeviceControlBO
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
.
toList
()
??
[],
);
}
@override
List
<
Object
?>
get
props
=>
[
roomPowerControl
,
subDeviceControls
];
}
class
RoomPowerControlBO
extends
Equatable
{
final
int
roomId
;
final
bool
powerOn
;
final
String
description
;
const
RoomPowerControlBO
({
required
this
.
roomId
,
required
this
.
powerOn
,
required
this
.
description
,
});
factory
RoomPowerControlBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
RoomPowerControlBO
(
roomId:
_parseInt
(
json
[
'roomId'
]),
powerOn:
json
[
'powerOn'
]
as
bool
?
??
false
,
description:
_parseString
(
json
[
'description'
]),
);
}
@override
List
<
Object
?>
get
props
=>
[
roomId
,
powerOn
,
description
];
}
class
SubDeviceControlBO
extends
Equatable
{
final
int
deviceId
;
final
String
deviceName
;
final
String
deviceTypeName
;
final
bool
powerOn
;
final
String
currentParamDisplay
;
const
SubDeviceControlBO
({
required
this
.
deviceId
,
required
this
.
deviceName
,
required
this
.
deviceTypeName
,
required
this
.
powerOn
,
required
this
.
currentParamDisplay
,
});
factory
SubDeviceControlBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
SubDeviceControlBO
(
deviceId:
_parseInt
(
json
[
'deviceId'
]),
deviceName:
_parseString
(
json
[
'deviceName'
]),
deviceTypeName:
_parseString
(
json
[
'deviceTypeName'
]),
powerOn:
json
[
'powerOn'
]
as
bool
?
??
false
,
currentParamDisplay:
_parseString
(
json
[
'currentParamDisplay'
]),
);
}
@override
List
<
Object
?>
get
props
=>
[
deviceId
,
deviceName
,
deviceTypeName
,
powerOn
,
currentParamDisplay
];
}
\ No newline at end of file
lib/repositories/room_repository.dart
View file @
cfc4a398
...
...
@@ -54,4 +54,30 @@ class RoomRepository {
data:
{
'deviceId'
:
deviceId
},
);
}
/// 客房详情
Future
<
ResponseModel
<
RoomDetailBO
>>
getRoomDetail
({
required
int
roomId
})
{
return
DioRequest
.
instance
.
get
<
RoomDetailBO
>(
'/app/room/detail'
,
queryParameters:
{
'roomId'
:
roomId
},
fromJsonT:
(
data
)
=>
RoomDetailBO
.
fromJson
(
data
as
Map
<
String
,
dynamic
>),
);
}
/// 客房详情-房间总电源-开
Future
<
ResponseModel
>
roomPowerOn
({
required
int
roomId
})
{
return
DioRequest
.
instance
.
post
(
'/app/room/power/on'
,
data:
{
'roomId'
:
roomId
},
);
}
/// 客房详情-房间总电源-关
Future
<
ResponseModel
>
roomPowerOff
({
required
int
roomId
})
{
return
DioRequest
.
instance
.
post
(
'/app/room/power/off'
,
data:
{
'roomId'
:
roomId
},
);
}
}
\ No newline at end of file
lib/routes/app_router.gr.dart
View file @
cfc4a398
...
...
@@ -194,11 +194,12 @@ abstract class $AppRouter extends _i21.RootStackRouter {
},
ServiceRoomDetailRoute
.
name
:
(
routeData
)
{
final
args
=
routeData
.
argsAs
<
ServiceRoomDetailRouteArgs
>(
orElse:
()
=>
const
ServiceRoomDetailRouteArgs
());
orElse:
()
=>
const
ServiceRoomDetailRouteArgs
(
roomId:
0
));
return
_i21
.
AutoRoutePage
<
dynamic
>(
routeData:
routeData
,
child:
_i20
.
ServiceRoomDetailView
(
key:
args
.
key
,
roomId:
args
.
roomId
,
roomNumber:
args
.
roomNumber
,
),
);
...
...
@@ -617,12 +618,14 @@ class ServiceRoomDetailRoute
extends
_i21
.
PageRouteInfo
<
ServiceRoomDetailRouteArgs
>
{
ServiceRoomDetailRoute
({
_i22
.
Key
?
key
,
required
int
roomId
,
String
?
roomNumber
,
List
<
_i21
.
PageRouteInfo
>?
children
,
})
:
super
(
ServiceRoomDetailRoute
.
name
,
args:
ServiceRoomDetailRouteArgs
(
key:
key
,
roomId:
roomId
,
roomNumber:
roomNumber
,
),
initialChildren:
children
,
...
...
@@ -637,15 +640,18 @@ class ServiceRoomDetailRoute
class
ServiceRoomDetailRouteArgs
{
const
ServiceRoomDetailRouteArgs
({
this
.
key
,
required
this
.
roomId
,
this
.
roomNumber
,
});
final
_i22
.
Key
?
key
;
final
int
roomId
;
final
String
?
roomNumber
;
@override
String
toString
()
{
return
'ServiceRoomDetailRouteArgs{key:
$key
, roomNumber:
$roomNumber
}'
;
return
'ServiceRoomDetailRouteArgs{key:
$key
, room
Id:
$roomId
, room
Number:
$roomNumber
}'
;
}
}
lib/services/room_service.dart
View file @
cfc4a398
...
...
@@ -47,4 +47,29 @@ class RoomService {
throw
Exception
(
result
.
msg
);
}
}
/// 客房详情
Future
<
RoomDetailBO
>
getRoomDetail
({
required
int
roomId
})
async
{
final
result
=
await
_repository
.
getRoomDetail
(
roomId:
roomId
);
if
(
result
.
success
&&
result
.
data
!=
null
)
{
return
result
.
data
!;
}
throw
Exception
(
result
.
msg
);
}
/// 客房详情-房间总电源-开
Future
<
void
>
roomPowerOn
({
required
int
roomId
})
async
{
final
result
=
await
_repository
.
roomPowerOn
(
roomId:
roomId
);
if
(!
result
.
success
)
{
throw
Exception
(
result
.
msg
);
}
}
/// 客房详情-房间总电源-关
Future
<
void
>
roomPowerOff
({
required
int
roomId
})
async
{
final
result
=
await
_repository
.
roomPowerOff
(
roomId:
roomId
);
if
(!
result
.
success
)
{
throw
Exception
(
result
.
msg
);
}
}
}
\ No newline at end of file
lib/views/service/index/widget/room_management_block.dart
View file @
cfc4a398
...
...
@@ -17,6 +17,7 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
String
?
_selectedFloor
;
String
?
_selectedType
;
String
?
_selectedRoom
;
int
?
_selectedRoomId
;
String
_searchText
=
''
;
final
TextEditingController
_searchController
=
TextEditingController
();
final
ScrollController
_scrollController
=
ScrollController
();
...
...
@@ -403,6 +404,7 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
onTap:
()
{
setState
(()
{
_selectedRoom
=
room
[
'number'
]
as
String
;
_selectedRoomId
=
room
[
'roomId'
]
as
int
?;
});
},
child:
Container
(
...
...
@@ -560,9 +562,12 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
),
elevation:
0
,
),
onPressed:
isRoomSelected
onPressed:
(
isRoomSelected
&&
_selectedRoomId
!=
null
)
?
()
{
context
.
pushRoute
(
ServiceRoomDetailRoute
(
roomNumber:
_selectedRoom
));
context
.
pushRoute
(
ServiceRoomDetailRoute
(
roomId:
_selectedRoomId
!,
roomNumber:
_selectedRoom
,
));
}
:
null
,
child:
Text
(
...
...
lib/views/service/room/cubit/service_room_cubit.dart
View file @
cfc4a398
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:smart_hotel_app/models/bo/room_bo.dart'
;
import
'package:smart_hotel_app/repositories/room_repository.dart'
;
import
'package:smart_hotel_app/services/room_service.dart'
;
import
'package:smart_hotel_app/views/service/room/cubit/service_room_state.dart'
;
class
ServiceRoomCubit
extends
Cubit
<
ServiceRoomState
>
{
final
String
?
roomNumber
;
final
RoomService
_service
;
final
int
_roomId
;
ServiceRoomCubit
({
this
.
roomNumber
})
:
super
(
const
ServiceRoomState
())
{
initData
();
ServiceRoomCubit
({
RoomService
?
service
,
required
int
roomId
,
String
roomNumber
=
''
,
})
:
_service
=
service
??
RoomService
(
repository:
RoomRepository
()),
_roomId
=
roomId
,
super
(
ServiceRoomState
(
roomId:
roomId
,
roomNumber:
roomNumber
))
{
loadDetail
();
}
Future
<
void
>
loadDetail
()
async
{
emit
(
state
.
copyWith
(
isLoading:
true
,
error:
null
));
try
{
final
detail
=
await
_service
.
getRoomDetail
(
roomId:
_roomId
);
emit
(
_mapDetailToState
(
detail
));
}
catch
(
e
)
{
emit
(
state
.
copyWith
(
isLoading:
false
,
error:
e
.
toString
()));
}
}
void
initData
()
{
final
num
=
roomNumber
??
'302'
;
final
numInt
=
int
.
tryParse
(
num
)
??
302
;
final
statuses
=
[
'空闲'
,
'入住中'
,
'待清洁'
];
final
statusIndex
=
numInt
%
3
;
ServiceRoomState
_mapDetailToState
(
RoomDetailBO
detail
)
{
final
basic
=
detail
.
roomBasicInfo
;
final
statusTags
=
_buildStatusTags
(
occupancyStatus:
basic
.
occupancyStatus
,
powerSupplyStatus:
basic
.
powerSupplyStatus
,
wifiOnlineStatus:
basic
.
wifiOnlineStatus
,
);
final
roomDevices
=
detail
.
deviceStatusList
.
map
((
d
)
{
return
RoomDevice
(
name:
d
.
deviceName
,
icon:
_mapDeviceIcon
(
d
.
deviceTypeName
,
d
.
deviceTypeIcon
),
isOn:
d
.
powerStatus
==
'1'
||
d
.
powerStatus
==
'on'
,
statusText:
_buildDeviceStatusText
(
d
),
);
}).
toList
();
final
controlDevices
=
detail
.
deviceControl
.
subDeviceControls
.
map
((
c
)
{
return
ControlDevice
(
name:
c
.
deviceName
,
icon:
_mapDeviceIcon
(
c
.
deviceTypeName
,
''
),
isOn:
c
.
powerOn
,
detailText:
c
.
currentParamDisplay
.
isNotEmpty
?
c
.
currentParamDisplay
:
null
,
);
}).
toList
();
return
state
.
copyWith
(
isLoading:
false
,
roomNumber:
basic
.
roomNumber
,
roomStatus:
_mapOccupancyStatus
(
basic
.
occupancyStatus
),
statusTags:
statusTags
,
roomDevices:
roomDevices
,
mainPowerOn:
detail
.
deviceControl
.
roomPowerControl
.
powerOn
,
controlDevices:
controlDevices
,
);
}
emit
(
state
.
copyWith
(
roomNumber:
num
,
roomStatus:
statuses
[
statusIndex
],
mainPowerOn:
numInt
%
2
==
0
,
roomDevices:
[
const
RoomDevice
(
name:
'空调'
,
icon:
Icons
.
air_outlined
,
isOn:
true
,
statusText:
'24°C·开'
,
),
const
RoomDevice
(
name:
'照明'
,
icon:
Icons
.
light_outlined
,
isOn:
false
,
statusText:
'关'
,
),
const
RoomDevice
(
name:
'电视'
,
icon:
Icons
.
tv_outlined
,
isOn:
true
,
statusText:
'开'
,
),
const
RoomDevice
(
name:
'窗帘'
,
icon:
Icons
.
curtains_closed_outlined
,
isOn:
false
,
statusText:
'关'
,
),
],
controlDevices:
[
const
ControlDevice
(
name:
'空调'
,
icon:
Icons
.
air_outlined
,
isOn:
true
,
detailText:
'当前:制冷24°C·风速:自动'
,
),
const
ControlDevice
(
name:
'主照明'
,
icon:
Icons
.
light_outlined
,
isOn:
false
,
),
const
ControlDevice
(
name:
'电视'
,
icon:
Icons
.
tv_outlined
,
isOn:
true
,
),
],
));
List
<
RoomStatusTag
>
_buildStatusTags
({
required
String
occupancyStatus
,
required
bool
powerSupplyStatus
,
required
String
wifiOnlineStatus
,
})
{
final
tags
=
<
RoomStatusTag
>[];
if
(
occupancyStatus
==
'1'
)
{
tags
.
add
(
RoomStatusTag
.
hasPerson
);
}
if
(
powerSupplyStatus
)
{
tags
.
add
(
RoomStatusTag
.
powerOn
);
}
if
(
wifiOnlineStatus
==
'1'
||
wifiOnlineStatus
==
'online'
)
{
tags
.
add
(
RoomStatusTag
.
wifiNormal
);
}
return
tags
;
}
void
toggleMainPower
(
bool
value
)
{
emit
(
state
.
copyWith
(
mainPowerOn:
value
));
String
_buildDeviceStatusText
(
DeviceStatusBO
d
)
{
if
(
d
.
powerStatusText
.
isNotEmpty
)
{
return
d
.
powerStatusText
;
}
if
(
d
.
runStatusText
.
isNotEmpty
)
{
return
d
.
runStatusText
;
}
if
(
d
.
deviceParams
!=
null
)
{
final
p
=
d
.
deviceParams
!;
final
parts
=
<
String
>[];
if
(
p
.
temperature
.
isNotEmpty
)
parts
.
add
(
'
${p.temperature}
°C'
);
if
(
p
.
mode
.
isNotEmpty
)
parts
.
add
(
p
.
mode
);
return
parts
.
join
(
'·'
);
}
return
''
;
}
void
toggleControlDevice
(
int
index
,
bool
value
)
{
final
updatedDevices
=
List
<
ControlDevice
>.
from
(
state
.
controlDevices
);
if
(
index
>=
0
&&
index
<
updatedDevices
.
length
)
{
updatedDevices
[
index
]
=
ControlDevice
(
name:
updatedDevices
[
index
].
name
,
icon:
updatedDevices
[
index
].
icon
,
isOn:
value
,
detailText:
updatedDevices
[
index
].
detailText
,
);
emit
(
state
.
copyWith
(
controlDevices:
updatedDevices
));
String
_mapOccupancyStatus
(
String
status
)
{
switch
(
status
)
{
case
'1'
:
return
'入住中'
;
case
'0'
:
default
:
return
'空闲'
;
}
}
}
\ No newline at end of file
IconData
_mapDeviceIcon
(
String
deviceTypeName
,
String
deviceTypeIcon
)
{
// Try to match by deviceTypeName first
final
name
=
deviceTypeName
.
toLowerCase
();
if
(
name
.
contains
(
'空调'
)
||
name
.
contains
(
'air'
))
{
return
Icons
.
air_outlined
;
}
if
(
name
.
contains
(
'照明'
)
||
name
.
contains
(
'灯'
)
||
name
.
contains
(
'light'
))
{
return
Icons
.
light_outlined
;
}
if
(
name
.
contains
(
'电视'
)
||
name
.
contains
(
'tv'
))
{
return
Icons
.
tv_outlined
;
}
if
(
name
.
contains
(
'窗帘'
)
||
name
.
contains
(
'curtain'
))
{
return
Icons
.
curtains_closed_outlined
;
}
// Fallback: match by deviceTypeIcon string
final
icon
=
deviceTypeIcon
.
toLowerCase
();
if
(
icon
.
contains
(
'air'
)
||
icon
.
contains
(
'ac'
))
{
return
Icons
.
air_outlined
;
}
if
(
icon
.
contains
(
'light'
))
{
return
Icons
.
light_outlined
;
}
if
(
icon
.
contains
(
'tv'
))
{
return
Icons
.
tv_outlined
;
}
if
(
icon
.
contains
(
'curtain'
))
{
return
Icons
.
curtains_closed_outlined
;
}
return
Icons
.
devices_other
;
}
/// 房间总电源开关
Future
<
void
>
toggleMainPower
(
bool
value
)
async
{
if
(
state
.
isTogglingPower
)
return
;
emit
(
state
.
copyWith
(
isTogglingPower:
true
));
try
{
if
(
value
)
{
await
_service
.
roomPowerOn
(
roomId:
_roomId
);
}
else
{
await
_service
.
roomPowerOff
(
roomId:
_roomId
);
}
emit
(
state
.
copyWith
(
isTogglingPower:
false
,
mainPowerOn:
value
));
}
catch
(
e
)
{
emit
(
state
.
copyWith
(
isTogglingPower:
false
));
// Re-throw so the view can show error snackbar
rethrow
;
}
}
/// 分设备电源开关
Future
<
void
>
toggleControlDevice
(
int
index
,
bool
value
)
async
{
final
devices
=
state
.
controlDevices
;
if
(
index
<
0
||
index
>=
devices
.
length
)
return
;
// Note: The API for individual device power control uses deviceId.
// However, we don't have deviceId in ControlDevice model yet.
// For now, just update UI state. The device control card in the view
// navigates to ServiceDeviceDetailRoute for AC control.
final
updatedDevices
=
List
<
ControlDevice
>.
from
(
devices
);
updatedDevices
[
index
]
=
ControlDevice
(
name:
updatedDevices
[
index
].
name
,
icon:
updatedDevices
[
index
].
icon
,
isOn:
value
,
detailText:
updatedDevices
[
index
].
detailText
,
);
emit
(
state
.
copyWith
(
controlDevices:
updatedDevices
));
}
}
lib/views/service/room/cubit/service_room_state.dart
View file @
cfc4a398
...
...
@@ -32,47 +32,67 @@ class ControlDevice {
}
class
ServiceRoomState
extends
Equatable
{
final
bool
isLoading
;
final
String
?
error
;
final
int
roomId
;
final
String
roomNumber
;
final
String
roomStatus
;
final
List
<
RoomStatusTag
>
statusTags
;
final
List
<
RoomDevice
>
roomDevices
;
final
bool
mainPowerOn
;
final
List
<
ControlDevice
>
controlDevices
;
final
bool
isTogglingPower
;
const
ServiceRoomState
({
this
.
roomNumber
=
'302'
,
this
.
roomStatus
=
'入住中'
,
this
.
statusTags
=
const
[
RoomStatusTag
.
hasPerson
,
RoomStatusTag
.
powerOn
,
RoomStatusTag
.
wifiNormal
],
this
.
isLoading
=
false
,
this
.
error
,
this
.
roomId
=
0
,
this
.
roomNumber
=
''
,
this
.
roomStatus
=
''
,
this
.
statusTags
=
const
[],
this
.
roomDevices
=
const
[],
this
.
mainPowerOn
=
false
,
this
.
controlDevices
=
const
[],
this
.
isTogglingPower
=
false
,
});
ServiceRoomState
copyWith
({
bool
?
isLoading
,
String
?
error
,
int
?
roomId
,
String
?
roomNumber
,
String
?
roomStatus
,
List
<
RoomStatusTag
>?
statusTags
,
List
<
RoomDevice
>?
roomDevices
,
bool
?
mainPowerOn
,
List
<
ControlDevice
>?
controlDevices
,
bool
?
isTogglingPower
,
})
{
return
ServiceRoomState
(
isLoading:
isLoading
??
this
.
isLoading
,
error:
error
??
this
.
error
,
roomId:
roomId
??
this
.
roomId
,
roomNumber:
roomNumber
??
this
.
roomNumber
,
roomStatus:
roomStatus
??
this
.
roomStatus
,
statusTags:
statusTags
??
this
.
statusTags
,
roomDevices:
roomDevices
??
this
.
roomDevices
,
mainPowerOn:
mainPowerOn
??
this
.
mainPowerOn
,
controlDevices:
controlDevices
??
this
.
controlDevices
,
isTogglingPower:
isTogglingPower
??
this
.
isTogglingPower
,
);
}
@override
List
<
Object
?>
get
props
=>
[
isLoading
,
error
,
roomId
,
roomNumber
,
roomStatus
,
statusTags
,
roomDevices
,
mainPowerOn
,
controlDevices
,
isTogglingPower
,
];
}
\ No newline at end of file
}
lib/views/service/room/room_detail_view.dart
View file @
cfc4a398
...
...
@@ -12,14 +12,22 @@ import 'package:smart_hotel_app/views/service/room/widget/room_bottom_buttons.da
@RoutePage
()
class
ServiceRoomDetailView
extends
StatelessWidget
{
final
int
roomId
;
final
String
?
roomNumber
;
const
ServiceRoomDetailView
({
super
.
key
,
this
.
roomNumber
});
const
ServiceRoomDetailView
({
super
.
key
,
required
this
.
roomId
,
this
.
roomNumber
,
});
@override
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
create:
(
_
)
=>
ServiceRoomCubit
(
roomNumber:
roomNumber
),
create:
(
_
)
=>
ServiceRoomCubit
(
roomId:
roomId
,
roomNumber:
roomNumber
??
''
,
),
child:
Scaffold
(
backgroundColor:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
appBar:
AppBar
(
...
...
@@ -42,12 +50,42 @@ class ServiceRoomDetailView extends StatelessWidget {
),
centerTitle:
true
,
),
body:
SingleChildScrollView
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
BlocBuilder
<
ServiceRoomCubit
,
ServiceRoomState
>(
builder:
(
context
,
state
)
{
final
cubit
=
context
.
read
<
ServiceRoomCubit
>();
return
Column
(
body:
BlocBuilder
<
ServiceRoomCubit
,
ServiceRoomState
>(
builder:
(
context
,
state
)
{
if
(
state
.
isLoading
)
{
return
const
Center
(
child:
CircularProgressIndicator
(),
);
}
if
(
state
.
error
!=
null
)
{
return
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Text
(
'加载失败'
,
style:
TextStyle
(
fontSize:
28
.
sp
,
color:
const
Color
.
fromRGBO
(
100
,
116
,
139
,
1
),
),
),
SizedBox
(
height:
16
.
h
),
ElevatedButton
(
onPressed:
()
{
context
.
read
<
ServiceRoomCubit
>().
loadDetail
();
},
child:
const
Text
(
'重试'
),
),
],
),
);
}
final
cubit
=
context
.
read
<
ServiceRoomCubit
>();
return
SingleChildScrollView
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
Column
(
children:
[
SizedBox
(
height:
20
.
h
),
RoomOverviewCard
(
...
...
@@ -63,8 +101,26 @@ class ServiceRoomDetailView extends StatelessWidget {
DeviceControlCard
(
mainPowerOn:
state
.
mainPowerOn
,
controlDevices:
state
.
controlDevices
,
onMainPowerToggle:
(
value
)
=>
cubit
.
toggleMainPower
(
value
),
onDeviceToggle:
(
index
,
value
)
=>
cubit
.
toggleControlDevice
(
index
,
value
),
onMainPowerToggle:
(
value
)
async
{
try
{
await
cubit
.
toggleMainPower
(
value
);
if
(
context
.
mounted
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
value
?
'送电成功'
:
'断电成功'
),
),
);
}
}
catch
(
e
)
{
if
(
context
.
mounted
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
'操作失败:
$e
'
)),
);
}
}
},
onDeviceToggle:
(
index
,
value
)
=>
cubit
.
toggleControlDevice
(
index
,
value
),
onDeviceTap:
(
index
,
device
)
{
if
(
device
.
name
==
'空调'
)
{
context
.
pushRoute
(
const
ServiceDeviceDetailRoute
());
...
...
@@ -75,11 +131,11 @@ class ServiceRoomDetailView extends StatelessWidget {
const
RoomBottomButtons
(),
SizedBox
(
height:
20
.
h
),
],
)
;
},
)
,
)
,
);
}
,
),
),
);
}
}
\ No newline at end of file
}
对接方案.md
View file @
cfc4a398
# 智慧酒
店 App 接口对接方案
# 智慧酒
店 App 接口对接方案
...
...
@@ -220,7 +220,9 @@ class xxxBO extends Equatable {
|
客房详情 |GET | /app/room/detail | 未对接 | 客房详情 | |
|
客房详情-房间总电源-switch开 |GET | /app/room/power/on | 未对接 | 客房详情-房间总电源-switch开 | |
|
客房详情-房间总电源-switch关 |GET | /app/room/power/off | 未对接 | 客房详情-房间总电源-switch关 | |
|
客房详情-房间总电源-switch关 |POST | /app/room/power/off | 未对接 | 客房详情-房间总电源-switch关 | |
|
空调控制 |GET | /app/device/ac/status | 未对接 | 空调控制 | |
...
...
@@ -228,6 +230,35 @@ class xxxBO extends Equatable {
#
## 3.2 接口详细定义
#
### 空调控制
*
*GET /app/device/ac/status**
`
``
请
求体:
{
"deviceId": 0
}
响
应 data:
{
"code": 0,
"msg": "string",
"data": {
"deviceId": 0,
"deviceName": "string",
"powerStatus": "string", // 电源开关状态码:0=关闭 1=开启,来源于 hotel_device.power_status,对应页面右上角Toggle开关
"currentTemperature": "string", // 当前室内温度值,如24,单位℃
"targetTemperature": "string", // 目标设定温度值,如25,单位℃
"mode": "string", // 当前工作模式码:cooling=制冷 heating=制热 dehumidify=除湿 fan=送风 auto=自动
"modeText": "string", // 工作模式中文文本:根据 mode 字段映射 cooling→'制冷' heating→'制热' dehumidify→'除湿' fan→'送风' auto→'自动'
"fanSpeed": "string", // 当前风速档位码:low=低中=中 high=高 auto=自动
"fanSpeedText": "string" // 风速中文文本:根据 fan_speed 字段映射 low→'低' mid→'中' high→'高' auto→'自动'
}
}
`
``
#
### 客房服务看板-客房状态总览-楼层
*
*GET /app/room/floor/areas**
...
...
@@ -262,7 +293,7 @@ class xxxBO extends Equatable {
#
### 客房详情-房间总电源-switch关
*
*
GE
T /app/room/power/off**
*
*
POS
T /app/room/power/off**
`
``
请
求体:
{
...
...
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