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
168178cd
Commit
168178cd
authored
Jun 11, 2026
by
张宏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
111
parent
a7c9b9f7
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
264 additions
and
41 deletions
+264
-41
auth_bloc.dart
lib/blocs/auth/auth_bloc.dart
+5
-0
alert_dashboard_bo.dart
lib/models/bo/alert_dashboard_bo.dart
+17
-5
room_statistics_bo.dart
lib/models/bo/room_statistics_bo.dart
+30
-0
auth_repository.dart
lib/repositories/auth_repository.dart
+4
-0
room_statistics_repository.dart
lib/repositories/room_statistics_repository.dart
+14
-0
auth_service.dart
lib/services/auth_service.dart
+7
-0
room_statistics_service.dart
lib/services/room_statistics_service.dart
+17
-0
home_index_cubit.dart
lib/views/home/index/cubit/home_index_cubit.dart
+1
-1
profile_state.dart
lib/views/profile/index/cubit/profile_state.dart
+21
-1
index_view.dart
lib/views/profile/index/index_view.dart
+46
-31
profile_menu_block.dart
lib/views/profile/index/widget/profile_menu_block.dart
+5
-1
service_index_cubit.dart
lib/views/service/index/cubit/service_index_cubit.dart
+26
-1
对接方案.md
对接方案.md
+71
-1
No files found.
lib/blocs/auth/auth_bloc.dart
View file @
168178cd
...
@@ -51,6 +51,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
...
@@ -51,6 +51,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthLogoutRequestedEvent
event
,
AuthLogoutRequestedEvent
event
,
Emitter
<
AuthState
>
emit
,
Emitter
<
AuthState
>
emit
,
)
async
{
)
async
{
try
{
await
_authService
.
logout
();
}
catch
(
_
)
{
// 即使接口调用失败也继续执行本地登出
}
await
_storageService
.
deleteToken
();
await
_storageService
.
deleteToken
();
await
_storageService
.
deleteUserInfo
();
await
_storageService
.
deleteUserInfo
();
await
_storageService
.
deleteClientId
();
await
_storageService
.
deleteClientId
();
...
...
lib/models/bo/alert_dashboard_bo.dart
View file @
168178cd
...
@@ -21,11 +21,12 @@ class AlertDashboardBO extends Equatable {
...
@@ -21,11 +21,12 @@ class AlertDashboardBO extends Equatable {
statistics:
AlertDashboardStatisticsBO
.
fromJson
(
statistics:
AlertDashboardStatisticsBO
.
fromJson
(
json
[
'statistics'
]
as
Map
<
String
,
dynamic
>?
??
{},
json
[
'statistics'
]
as
Map
<
String
,
dynamic
>?
??
{},
),
),
alerts:
(
json
[
'alerts'
]
as
List
<
dynamic
>?)
alerts:
_sortedAlerts
(
?.
map
((
e
)
=>
(
json
[
'alerts'
]
as
List
<
dynamic
>?)
AlertItemBO
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
?.
map
((
e
)
=>
.
toList
()
??
AlertItemBO
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
[],
.
toList
()
??
[]),
devices:
(
json
[
'devices'
]
as
List
<
dynamic
>?)
devices:
(
json
[
'devices'
]
as
List
<
dynamic
>?)
?.
map
((
e
)
=>
?.
map
((
e
)
=>
DeviceItemBO
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
DeviceItemBO
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
...
@@ -34,6 +35,17 @@ class AlertDashboardBO extends Equatable {
...
@@ -34,6 +35,17 @@ class AlertDashboardBO extends Equatable {
);
);
}
}
/// 根据 alertLevelText 排序:置顶 > 高警 > 中警 > 一般
static
List
<
AlertItemBO
>
_sortedAlerts
(
List
<
AlertItemBO
>
alerts
)
{
const
order
=
{
'置顶'
:
0
,
'高警'
:
1
,
'中警'
:
2
,
'一般'
:
3
};
return
List
<
AlertItemBO
>.
from
(
alerts
)
..
sort
((
a
,
b
)
{
final
aOrder
=
order
[
a
.
alertLevelText
]
??
4
;
final
bOrder
=
order
[
b
.
alertLevelText
]
??
4
;
return
aOrder
.
compareTo
(
bOrder
);
});
}
@override
@override
List
<
Object
?>
get
props
=>
[
total
,
statistics
,
alerts
,
devices
];
List
<
Object
?>
get
props
=>
[
total
,
statistics
,
alerts
,
devices
];
}
}
...
...
lib/models/bo/room_statistics_bo.dart
0 → 100644
View file @
168178cd
import
'package:equatable/equatable.dart'
;
class
RoomStatisticsBO
extends
Equatable
{
/// 待响应房间数
final
int
pendingResponseCount
;
/// 入住中房间数
final
int
occupiedCount
;
/// 空闲可清洁房间数
final
int
vacantCleanableCount
;
const
RoomStatisticsBO
({
this
.
pendingResponseCount
=
0
,
this
.
occupiedCount
=
0
,
this
.
vacantCleanableCount
=
0
,
});
factory
RoomStatisticsBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
RoomStatisticsBO
(
pendingResponseCount:
json
[
'pendingResponseCount'
]
as
int
?
??
0
,
occupiedCount:
json
[
'occupiedCount'
]
as
int
?
??
0
,
vacantCleanableCount:
json
[
'vacantCleanableCount'
]
as
int
?
??
0
,
);
}
@override
List
<
Object
?>
get
props
=>
[
pendingResponseCount
,
occupiedCount
,
vacantCleanableCount
];
}
lib/repositories/auth_repository.dart
View file @
168178cd
...
@@ -18,4 +18,8 @@ class AuthRepository {
...
@@ -18,4 +18,8 @@ class AuthRepository {
fromJsonT:
(
data
)
=>
UserInfoBO
.
fromJson
(
data
as
Map
<
String
,
dynamic
>),
fromJsonT:
(
data
)
=>
UserInfoBO
.
fromJson
(
data
as
Map
<
String
,
dynamic
>),
);
);
}
}
Future
<
ResponseModel
>
logout
()
{
return
DioRequest
.
instance
.
post
(
'/app/auth/logout'
);
}
}
}
lib/repositories/room_statistics_repository.dart
0 → 100644
View file @
168178cd
import
'../../models/bo/room_statistics_bo.dart'
;
import
'../../utils/http/dio_request.dart'
;
import
'../../utils/http/response_model.dart'
;
class
RoomStatisticsRepository
{
/// GET /app/room/statistics - 客房服务看板-统计
Future
<
ResponseModel
<
RoomStatisticsBO
>>
getStatistics
()
{
return
DioRequest
.
instance
.
get
<
RoomStatisticsBO
>(
'/app/room/statistics'
,
fromJsonT:
(
data
)
=>
RoomStatisticsBO
.
fromJson
(
data
as
Map
<
String
,
dynamic
>),
);
}
}
lib/services/auth_service.dart
View file @
168178cd
...
@@ -50,6 +50,13 @@ class AuthService {
...
@@ -50,6 +50,13 @@ class AuthService {
return
_storageService
.
getUserInfo
();
return
_storageService
.
getUserInfo
();
}
}
Future
<
void
>
logout
()
async
{
final
result
=
await
_authRepository
.
logout
();
if
(!
result
.
success
)
{
throw
Exception
(
result
.
msg
);
}
}
Future
<
bool
>
isTokenExpired
()
async
{
Future
<
bool
>
isTokenExpired
()
async
{
return
_storageService
.
isTokenExpired
();
return
_storageService
.
isTokenExpired
();
}
}
...
...
lib/services/room_statistics_service.dart
0 → 100644
View file @
168178cd
import
'../models/bo/room_statistics_bo.dart'
;
import
'../repositories/room_statistics_repository.dart'
;
class
RoomStatisticsService
{
final
RoomStatisticsRepository
_repository
;
RoomStatisticsService
({
required
RoomStatisticsRepository
repository
})
:
_repository
=
repository
;
Future
<
RoomStatisticsBO
>
getStatistics
()
async
{
final
result
=
await
_repository
.
getStatistics
();
if
(
result
.
success
&&
result
.
data
!=
null
)
{
return
result
.
data
!;
}
throw
Exception
(
result
.
msg
);
}
}
lib/views/home/index/cubit/home_index_cubit.dart
View file @
168178cd
...
@@ -34,7 +34,7 @@ class HomeIndexCubit extends Cubit<HomeIndexState> {
...
@@ -34,7 +34,7 @@ class HomeIndexCubit extends Cubit<HomeIndexState> {
highAlarmCount:
dashboard
.
statistics
.
highAlertCount
,
highAlarmCount:
dashboard
.
statistics
.
highAlertCount
,
mediumAlarmCount:
dashboard
.
statistics
.
mediumAlertCount
,
mediumAlarmCount:
dashboard
.
statistics
.
mediumAlertCount
,
onlineDeviceCount:
dashboard
.
statistics
.
onlineDeviceCount
,
onlineDeviceCount:
dashboard
.
statistics
.
onlineDeviceCount
,
alerts:
dashboard
.
alerts
,
alerts:
dashboard
.
alerts
.
take
(
5
).
toList
()
,
equipmentList:
dashboard
.
devices
equipmentList:
dashboard
.
devices
.
map
((
d
)
=>
_mapDeviceToEquipment
(
d
))
.
map
((
d
)
=>
_mapDeviceToEquipment
(
d
))
.
toList
(),
.
toList
(),
...
...
lib/views/profile/index/cubit/profile_state.dart
View file @
168178cd
...
@@ -17,25 +17,44 @@ class ProfileState extends Equatable {
...
@@ -17,25 +17,44 @@ class ProfileState extends Equatable {
final
String
username
;
final
String
username
;
final
String
welcomeText
;
final
String
welcomeText
;
final
List
<
MenuItem
>
menuList
;
final
List
<
MenuItem
>
menuList
;
final
bool
isLoggingOut
;
final
String
?
logoutError
;
final
bool
logoutSuccess
;
const
ProfileState
({
const
ProfileState
({
this
.
username
=
''
,
this
.
username
=
''
,
this
.
welcomeText
=
''
,
this
.
welcomeText
=
''
,
this
.
menuList
=
const
[],
this
.
menuList
=
const
[],
this
.
isLoggingOut
=
false
,
this
.
logoutError
,
this
.
logoutSuccess
=
false
,
});
});
ProfileState
copyWith
({
ProfileState
copyWith
({
String
?
username
,
String
?
username
,
String
?
welcomeText
,
String
?
welcomeText
,
List
<
MenuItem
>?
menuList
,
List
<
MenuItem
>?
menuList
,
bool
?
isLoggingOut
,
String
?
logoutError
,
bool
?
logoutSuccess
,
})
{
})
{
return
ProfileState
(
return
ProfileState
(
username:
username
??
this
.
username
,
username:
username
??
this
.
username
,
welcomeText:
welcomeText
??
this
.
welcomeText
,
welcomeText:
welcomeText
??
this
.
welcomeText
,
menuList:
menuList
??
this
.
menuList
,
menuList:
menuList
??
this
.
menuList
,
isLoggingOut:
isLoggingOut
??
this
.
isLoggingOut
,
logoutError:
logoutError
??
this
.
logoutError
,
logoutSuccess:
logoutSuccess
??
this
.
logoutSuccess
,
);
);
}
}
@override
@override
List
<
Object
?>
get
props
=>
[
username
,
welcomeText
,
menuList
];
List
<
Object
?>
get
props
=>
[
username
,
welcomeText
,
menuList
,
isLoggingOut
,
logoutError
,
logoutSuccess
,
];
}
}
\ No newline at end of file
lib/views/profile/index/index_view.dart
View file @
168178cd
...
@@ -2,6 +2,8 @@ import 'package:auto_route/auto_route.dart';
...
@@ -2,6 +2,8 @@ import 'package:auto_route/auto_route.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:smart_hotel_app/blocs/auth/auth_bloc.dart'
;
import
'package:smart_hotel_app/blocs/auth/auth_event.dart'
;
import
'package:smart_hotel_app/views/profile/index/cubit/profile_cubit.dart'
;
import
'package:smart_hotel_app/views/profile/index/cubit/profile_cubit.dart'
;
import
'package:smart_hotel_app/views/profile/index/cubit/profile_state.dart'
;
import
'package:smart_hotel_app/views/profile/index/cubit/profile_state.dart'
;
import
'package:smart_hotel_app/views/profile/index/widget/profile_header_block.dart'
;
import
'package:smart_hotel_app/views/profile/index/widget/profile_header_block.dart'
;
...
@@ -15,38 +17,52 @@ class ProfileView extends StatelessWidget {
...
@@ -15,38 +17,52 @@ class ProfileView extends StatelessWidget {
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
return
BlocProvider
(
create:
(
_
)
=>
ProfileCubit
(),
create:
(
_
)
=>
ProfileCubit
(),
child:
LayoutBuilder
(
child:
_ProfileContent
(),
builder:
(
context
,
constraints
)
{
);
return
SingleChildScrollView
(
}
child:
ConstrainedBox
(
}
constraints:
BoxConstraints
(
minHeight:
constraints
.
maxHeight
,
class
_ProfileContent
extends
StatelessWidget
{
),
@override
child:
Container
(
Widget
build
(
BuildContext
context
)
{
width:
double
.
infinity
,
return
BlocBuilder
<
ProfileCubit
,
ProfileState
>(
color:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
builder:
(
context
,
state
)
{
child:
BlocBuilder
<
ProfileCubit
,
ProfileState
>(
return
LayoutBuilder
(
builder:
(
context
,
state
)
{
builder:
(
context
,
constraints
)
{
return
Column
(
return
SingleChildScrollView
(
children:
[
child:
ConstrainedBox
(
ProfileHeaderBlock
(
constraints:
BoxConstraints
(
username:
state
.
username
,
minHeight:
constraints
.
maxHeight
,
welcomeText:
state
.
welcomeText
,
),
),
child:
Container
(
SizedBox
(
height:
10
.
h
),
width:
double
.
infinity
,
Padding
(
color:
const
Color
.
fromRGBO
(
242
,
243
,
245
,
1
),
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
Column
(
child:
ProfileMenuBlock
(
menuList:
state
.
menuList
),
children:
[
ProfileHeaderBlock
(
username:
state
.
username
,
welcomeText:
state
.
welcomeText
,
),
SizedBox
(
height:
10
.
h
),
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
child:
ProfileMenuBlock
(
menuList:
state
.
menuList
,
onLogout:
()
{
context
.
read
<
AuthBloc
>()
.
add
(
const
AuthLogoutRequestedEvent
());
},
),
),
]
,
)
,
);
],
}
,
)
,
),
),
),
),
)
,
)
;
);
},
},
);
)
,
}
,
);
);
}
}
}
}
\ No newline at end of file
lib/views/profile/index/widget/profile_menu_block.dart
View file @
168178cd
...
@@ -6,8 +6,9 @@ import 'package:smart_hotel_app/views/profile/index/cubit/profile_state.dart';
...
@@ -6,8 +6,9 @@ import 'package:smart_hotel_app/views/profile/index/cubit/profile_state.dart';
class
ProfileMenuBlock
extends
StatelessWidget
{
class
ProfileMenuBlock
extends
StatelessWidget
{
final
List
<
MenuItem
>
menuList
;
final
List
<
MenuItem
>
menuList
;
final
VoidCallback
?
onLogout
;
const
ProfileMenuBlock
({
super
.
key
,
required
this
.
menuList
});
const
ProfileMenuBlock
({
super
.
key
,
required
this
.
menuList
,
this
.
onLogout
});
Widget
_buildMenuItem
(
BuildContext
context
,
MenuItem
item
)
{
Widget
_buildMenuItem
(
BuildContext
context
,
MenuItem
item
)
{
return
GestureDetector
(
return
GestureDetector
(
...
@@ -72,6 +73,9 @@ class ProfileMenuBlock extends StatelessWidget {
...
@@ -72,6 +73,9 @@ class ProfileMenuBlock extends StatelessWidget {
case
'告警信息'
:
case
'告警信息'
:
context
.
pushRoute
(
const
AbnormalListRoute
());
context
.
pushRoute
(
const
AbnormalListRoute
());
break
;
break
;
case
'退出登录'
:
onLogout
?.
call
();
break
;
default
:
default
:
break
;
break
;
}
}
...
...
lib/views/service/index/cubit/service_index_cubit.dart
View file @
168178cd
...
@@ -3,20 +3,45 @@ import 'package:smart_hotel_app/views/service/index/cubit/service_index_state.da
...
@@ -3,20 +3,45 @@ import 'package:smart_hotel_app/views/service/index/cubit/service_index_state.da
import
'package:smart_hotel_app/services/room_service.dart'
;
import
'package:smart_hotel_app/services/room_service.dart'
;
import
'package:smart_hotel_app/repositories/room_repository.dart'
;
import
'package:smart_hotel_app/repositories/room_repository.dart'
;
import
'package:smart_hotel_app/models/bo/room_bo.dart'
;
import
'package:smart_hotel_app/models/bo/room_bo.dart'
;
import
'package:smart_hotel_app/services/room_statistics_service.dart'
;
import
'package:smart_hotel_app/repositories/room_statistics_repository.dart'
;
class
ServiceIndexCubit
extends
Cubit
<
ServiceIndexState
>
{
class
ServiceIndexCubit
extends
Cubit
<
ServiceIndexState
>
{
final
RoomService
_roomService
;
final
RoomService
_roomService
;
final
RoomStatisticsService
_statisticsService
;
final
Map
<
String
,
List
<
Map
<
String
,
dynamic
>>>
_roomCache
=
{};
final
Map
<
String
,
List
<
Map
<
String
,
dynamic
>>>
_roomCache
=
{};
List
<
FloorAreaBO
>
_floorAreasCache
=
[];
List
<
FloorAreaBO
>
_floorAreasCache
=
[];
ServiceIndexCubit
()
ServiceIndexCubit
()
:
_roomService
=
RoomService
(
repository:
RoomRepository
()),
:
_roomService
=
RoomService
(
repository:
RoomRepository
()),
_statisticsService
=
RoomStatisticsService
(
repository:
RoomStatisticsRepository
(),
),
super
(
const
ServiceIndexState
())
{
super
(
const
ServiceIndexState
())
{
_init
();
_init
();
}
}
Future
<
void
>
_init
()
async
{
Future
<
void
>
_init
()
async
{
await
loadFloorAndAreas
();
await
Future
.
wait
([
loadStatistics
(),
loadFloorAndAreas
(),
]);
}
/// 加载客房服务看板-统计数据(待响应、入住中、空闲可清洁)
Future
<
void
>
loadStatistics
()
async
{
emit
(
state
.
copyWith
(
isLoading:
true
,
error:
null
));
try
{
final
stats
=
await
_statisticsService
.
getStatistics
();
emit
(
state
.
copyWith
(
isLoading:
false
,
pendingCount:
stats
.
pendingResponseCount
,
occupiedRooms:
stats
.
occupiedCount
,
vacantRooms:
stats
.
vacantCleanableCount
,
));
}
catch
(
e
)
{
emit
(
state
.
copyWith
(
isLoading:
false
,
error:
e
.
toString
()));
}
}
}
/// 加载楼层和区域信息(仅进入页面时调用一次)
/// 加载楼层和区域信息(仅进入页面时调用一次)
...
...
对接方案.md
View file @
168178cd
# 智慧酒
店 App 接口对接方案
# 智慧酒
店 App 接口对接方案
...
@@ -237,10 +237,80 @@ class xxxBO extends Equatable {
...
@@ -237,10 +237,80 @@ class xxxBO extends Equatable {
|
退出登录 |POST | /app/auth/logout | 已对接 | 退出登录 | |
|
客房服务看板-统计 |GET | /app/room/statistics | 已对接 | 客房服务看板-统计 | |
#
## 3.2 接口详细定义
#
## 3.2 接口详细定义
#
### 非客房-相关楼层区域设备
*
*GET /app/room/area/devices**
`
``
请
求体:
{
"floorId":0,// 楼层
"areaType":'', // 区域
}
响
应 data:
{
"code": 0,
"msg": "string",
"data": [
{
"deviceName": "string", // 设备名称
"deviceCode": "string", // 设备编码
"runStatus": "string" // 运行状态:normal=正常 warning=预警 fault=故障 offline=离线
}
]
}
`
``
#
### 客房服务看板-统计
*
*GET /app/room/statistics**
`
``
请
求体:
{
}
响
应 data:
{
"code": 0,
"msg": "string",
"data": {
"pendingResponseCount": 0, // 待响应房间数
"occupiedCount": 0, // 入住中房间数:有人(occupancy_status='1') 或 已入住(sell_status='3')
"vacantCleanableCount": 0 // 空闲可清洁房间数:已退房(checkout_status='1') 且 待清洁(clean_status='0')
}
}
`
``
#
### 退出登录
*
*POST /app/auth/logout**
`
``
请
求体:
{
}
响
应 data:
{
"code": 0,
"msg": "string",
"data": "string"
}
`
``
#
### 联动规则管理-启用/禁用
#
### 联动规则管理-启用/禁用
*
*PUT /app/linkage/rules/toggle**
*
*PUT /app/linkage/rules/toggle**
...
...
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