Commit daa14c60 authored by 张宏's avatar 张宏

2222

parent faf44368
......@@ -71,6 +71,31 @@ class FloorRoomSimpleBO extends Equatable {
List<Object?> get props => [roomId, roomName];
}
// ==================== 非客房-相关楼层区域设备 ====================
class AreaDeviceBO extends Equatable {
final String deviceName;
final String deviceCode;
final String runStatus; // normal=正常 warning=预警 fault=故障 offline=离线
const AreaDeviceBO({
required this.deviceName,
required this.deviceCode,
required this.runStatus,
});
factory AreaDeviceBO.fromJson(Map<String, dynamic> json) {
return AreaDeviceBO(
deviceName: _parseString(json['deviceName']),
deviceCode: _parseString(json['deviceCode']),
runStatus: _parseString(json['runStatus']),
);
}
@override
List<Object?> get props => [deviceName, deviceCode, runStatus];
}
// ==================== 客房服务看板-客房状态总览-房间list ====================
class RoomStatusBO extends Equatable {
......
......@@ -80,4 +80,24 @@ class RoomRepository {
data: {'roomId': roomId},
);
}
/// 非客房-相关楼层区域设备
Future<ResponseModel<List<AreaDeviceBO>>> getAreaDevices({
required int floorId,
required String areaType,
}) {
return DioRequest.instance.get<List<AreaDeviceBO>>(
'/app/room/area/devices',
queryParameters: {
'floorId': floorId.toString(),
'areaType': areaType,
},
fromJsonT: (data) {
final list = data as List<dynamic>;
return list
.map((e) => AreaDeviceBO.fromJson(e as Map<String, dynamic>))
.toList();
},
);
}
}
\ No newline at end of file
......@@ -72,4 +72,19 @@ class RoomService {
throw Exception(result.msg);
}
}
/// 非客房-相关楼层区域设备
Future<List<AreaDeviceBO>> getAreaDevices({
required int floorId,
required String areaType,
}) async {
final result = await _repository.getAreaDevices(
floorId: floorId,
areaType: areaType,
);
if (result.success && result.data != null) {
return result.data!;
}
throw Exception(result.msg);
}
}
\ No newline at end of file
......@@ -187,6 +187,29 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
emit(state.copyWith(selectedType: type));
}
/// 加载非客房-相关楼层区域设备
Future<void> loadAreaDevices({
required int floorId,
required String areaType,
}) async {
emit(state.copyWith(isLoadingAreaDevices: true, error: null));
try {
final devices = await _roomService.getAreaDevices(
floorId: floorId,
areaType: areaType,
);
emit(state.copyWith(
isLoadingAreaDevices: false,
areaDevices: devices,
));
} catch (e) {
emit(state.copyWith(
isLoadingAreaDevices: false,
error: e.toString(),
));
}
}
void selectRoom(String? room) {
emit(state.copyWith(selectedRoom: room));
}
......
import 'package:equatable/equatable.dart';
import 'package:smart_hotel_app/models/bo/room_bo.dart';
class ServiceIndexState extends Equatable {
final int pendingCount;
......@@ -12,7 +13,9 @@ class ServiceIndexState extends Equatable {
final String? selectedRoom;
final String searchText;
final List<Map<String, dynamic>> rooms;
final List<AreaDeviceBO> areaDevices;
final bool isLoading;
final bool isLoadingAreaDevices;
final String? error;
final bool isPoweringOn;
final bool isPoweringOff;
......@@ -28,7 +31,9 @@ class ServiceIndexState extends Equatable {
this.selectedRoom,
this.searchText = '',
this.rooms = const [],
this.areaDevices = const [],
this.isLoading = false,
this.isLoadingAreaDevices = false,
this.error,
this.isPoweringOn = false,
this.isPoweringOff = false,
......@@ -46,7 +51,9 @@ class ServiceIndexState extends Equatable {
String? selectedRoom,
String? searchText,
List<Map<String, dynamic>>? rooms,
List<AreaDeviceBO>? areaDevices,
bool? isLoading,
bool? isLoadingAreaDevices,
String? error,
bool? isPoweringOn,
bool? isPoweringOff,
......@@ -62,7 +69,9 @@ class ServiceIndexState extends Equatable {
selectedRoom: selectedRoom ?? this.selectedRoom,
searchText: searchText ?? this.searchText,
rooms: rooms ?? this.rooms,
areaDevices: areaDevices ?? this.areaDevices,
isLoading: isLoading ?? this.isLoading,
isLoadingAreaDevices: isLoadingAreaDevices ?? this.isLoadingAreaDevices,
error: error ?? this.error,
isPoweringOn: isPoweringOn ?? this.isPoweringOn,
isPoweringOff: isPoweringOff ?? this.isPoweringOff,
......@@ -81,7 +90,9 @@ class ServiceIndexState extends Equatable {
selectedRoom,
searchText,
rooms,
areaDevices,
isLoading,
isLoadingAreaDevices,
error,
isPoweringOn,
isPoweringOff,
......
......@@ -65,6 +65,7 @@ class _ServiceIndexViewState extends State<ServiceIndexView> with AutoRouteAware
vacantCount: state.vacantRooms,
),
RoomManagementBlock(),
SizedBox(height: 18.h),
],
);
},
......
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/models/bo/room_bo.dart';
/// 非客房-相关楼层区域设备列表组件
class AreaDeviceList extends StatelessWidget {
final List<AreaDeviceBO> devices;
final bool isLoading;
const AreaDeviceList({
super.key,
required this.devices,
this.isLoading = false,
});
/// 根据运行状态获取显示颜色
Color _statusColor(String runStatus) {
switch (runStatus) {
case 'normal':
return const Color.fromRGBO(82, 196, 26, 1);
case 'warning':
return const Color.fromRGBO(250, 173, 20, 1);
case 'fault':
return const Color.fromRGBO(245, 34, 45, 1);
case 'offline':
default:
return const Color.fromRGBO(153, 153, 153, 1);
}
}
/// 根据运行状态获取显示文字
String _statusText(String runStatus) {
switch (runStatus) {
case 'normal':
return '正常';
case 'warning':
return '预警';
case 'fault':
return '故障';
case 'offline':
return '离线';
default:
return '未知';
}
}
@override
Widget build(BuildContext context) {
if (isLoading) {
return const Center(
child: Padding(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(),
),
);
}
if (devices.isEmpty) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 40.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.r),
color: const Color.fromRGBO(245, 245, 245, 1),
),
child: Center(
child: Text(
'暂无设备数据',
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(153, 153, 153, 1),
),
),
),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: Text(
'区域设备(共${devices.length}个)',
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
),
...devices.map((device) => _buildDeviceItem(device)),
],
);
}
Widget _buildDeviceItem(AreaDeviceBO device) {
final color = _statusColor(device.runStatus);
return Container(
width: double.infinity,
margin: EdgeInsets.only(bottom: 8.h),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.r),
color: Colors.white,
border: Border.all(
color: const Color.fromRGBO(238, 238, 238, 1),
width: 1.w,
),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
device.deviceName,
style: TextStyle(
fontSize: 26.sp,
fontWeight: FontWeight.w500,
color: const Color.fromRGBO(51, 51, 51, 1),
),
),
SizedBox(height: 4.h),
Text(
'编码:${device.deviceCode}',
style: TextStyle(
fontSize: 22.sp,
color: const Color.fromRGBO(153, 153, 153, 1),
),
),
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r),
color: color.withValues(alpha: 0.1),
),
child: Text(
_statusText(device.runStatus),
style: TextStyle(
fontSize: 22.sp,
color: color,
fontWeight: FontWeight.w500,
),
),
),
],
),
);
}
}
......@@ -5,6 +5,7 @@ import 'package:smart_hotel_app/views/service/index/cubit/service_index_cubit.da
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart';
import 'package:smart_hotel_app/views/service/index/cubit/service_index_state.dart';
import 'package:smart_hotel_app/views/service/index/widget/area_device_list.dart';
class RoomManagementBlock extends StatefulWidget {
const RoomManagementBlock({super.key});
......@@ -50,6 +51,21 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
return filtered;
}
/// 加载非客房区域设备
void _loadAreaDevices(ServiceIndexCubit cubit) {
if (_selectedFloor == null) return;
// 从 floors 中找对应 floorId
int? floorId;
for (final floorMap in (cubit.state.floors ?? [])) {
if (floorMap.values.first == _selectedFloor) {
floorId = floorMap.keys.first;
break;
}
}
if (floorId == null) return;
cubit.loadAreaDevices(floorId: floorId, areaType: _selectedType!);
}
@override
Widget build(BuildContext context) {
final cubit = context.read<ServiceIndexCubit>();
......@@ -82,26 +98,38 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
SizedBox(height: 18.h),
_buildTypeSelector(),
SizedBox(height: 18.h),
_buildSearchBox(),
SizedBox(height: 32.h),
_buildLine(),
SizedBox(height: 18.h),
_buildRoomGrid(cubit),
SizedBox(height: 20.h),
if (_selectedRoom != null)
Padding(
padding: EdgeInsets.only(bottom: 15.h),
child: Text(
'已选:$_selectedRoom号房',
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1),
if (_selectedType == null || _selectedType == '客房') ...[
_buildSearchBox(),
SizedBox(height: 32.h),
_buildLine(),
SizedBox(height: 18.h),
_buildRoomGrid(cubit),
SizedBox(height: 20.h),
if (_selectedRoom != null)
Padding(
padding: EdgeInsets.only(bottom: 15.h),
child: Text(
'已选:$_selectedRoom号房',
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
),
BlocBuilder<ServiceIndexCubit, ServiceIndexState>(
builder: (context, state) => _buildBottomButtons(cubit),
),
BlocBuilder<ServiceIndexCubit, ServiceIndexState>(
builder: (context, state) => _buildBottomButtons(cubit),
),
] else ...[
_buildLine(),
SizedBox(height: 18.h),
BlocBuilder<ServiceIndexCubit, ServiceIndexState>(
builder: (context, state) => AreaDeviceList(
devices: state.areaDevices,
isLoading: state.isLoadingAreaDevices,
),
),
],
],
),
),
......@@ -194,7 +222,13 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
} else {
_selectedType = type;
}
_selectedRoom = null;
_selectedRoomId = null;
});
// 非客房类型时,加载区域设备数据
if (_selectedType != null && _selectedType != '客房') {
_loadAreaDevices(cubit);
}
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 8.h),
......
# 智慧酒店 App 接口对接方案
# 智慧酒店 App 接口对接方案
......@@ -241,6 +241,7 @@ class xxxBO extends Equatable {
| 客房服务看板-统计 |GET | /app/room/statistics | 已对接 | 客房服务看板-统计 | |
| 非客房-相关楼层区域设备 |GET | /app/room/area/devices | 未对接 | 非客房-相关楼层区域设备 | |
......@@ -253,8 +254,8 @@ class xxxBO extends Equatable {
```
求体:
{
"floorId":0,// 楼层
"areaType":'', // 区域
"floorId":0,// 楼层 必传
"areaType":'', // 区域 必传
}
应 data:
{
......
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