Commit cfc4a398 authored by 张宏's avatar 张宏

3

parent 749feeaf
...@@ -104,4 +104,222 @@ class RoomStatusBO extends Equatable { ...@@ -104,4 +104,222 @@ class RoomStatusBO extends Equatable {
@override @override
List<Object?> get props => List<Object?> get props =>
[roomId, roomNumber, occupancyStatus, roomStatus, cleanStatus, devicePowerStatus]; [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
...@@ -54,4 +54,30 @@ class RoomRepository { ...@@ -54,4 +54,30 @@ class RoomRepository {
data: {'deviceId': deviceId}, 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
...@@ -194,11 +194,12 @@ abstract class $AppRouter extends _i21.RootStackRouter { ...@@ -194,11 +194,12 @@ abstract class $AppRouter extends _i21.RootStackRouter {
}, },
ServiceRoomDetailRoute.name: (routeData) { ServiceRoomDetailRoute.name: (routeData) {
final args = routeData.argsAs<ServiceRoomDetailRouteArgs>( final args = routeData.argsAs<ServiceRoomDetailRouteArgs>(
orElse: () => const ServiceRoomDetailRouteArgs()); orElse: () => const ServiceRoomDetailRouteArgs(roomId: 0));
return _i21.AutoRoutePage<dynamic>( return _i21.AutoRoutePage<dynamic>(
routeData: routeData, routeData: routeData,
child: _i20.ServiceRoomDetailView( child: _i20.ServiceRoomDetailView(
key: args.key, key: args.key,
roomId: args.roomId,
roomNumber: args.roomNumber, roomNumber: args.roomNumber,
), ),
); );
...@@ -617,12 +618,14 @@ class ServiceRoomDetailRoute ...@@ -617,12 +618,14 @@ class ServiceRoomDetailRoute
extends _i21.PageRouteInfo<ServiceRoomDetailRouteArgs> { extends _i21.PageRouteInfo<ServiceRoomDetailRouteArgs> {
ServiceRoomDetailRoute({ ServiceRoomDetailRoute({
_i22.Key? key, _i22.Key? key,
required int roomId,
String? roomNumber, String? roomNumber,
List<_i21.PageRouteInfo>? children, List<_i21.PageRouteInfo>? children,
}) : super( }) : super(
ServiceRoomDetailRoute.name, ServiceRoomDetailRoute.name,
args: ServiceRoomDetailRouteArgs( args: ServiceRoomDetailRouteArgs(
key: key, key: key,
roomId: roomId,
roomNumber: roomNumber, roomNumber: roomNumber,
), ),
initialChildren: children, initialChildren: children,
...@@ -637,15 +640,18 @@ class ServiceRoomDetailRoute ...@@ -637,15 +640,18 @@ class ServiceRoomDetailRoute
class ServiceRoomDetailRouteArgs { class ServiceRoomDetailRouteArgs {
const ServiceRoomDetailRouteArgs({ const ServiceRoomDetailRouteArgs({
this.key, this.key,
required this.roomId,
this.roomNumber, this.roomNumber,
}); });
final _i22.Key? key; final _i22.Key? key;
final int roomId;
final String? roomNumber; final String? roomNumber;
@override @override
String toString() { String toString() {
return 'ServiceRoomDetailRouteArgs{key: $key, roomNumber: $roomNumber}'; return 'ServiceRoomDetailRouteArgs{key: $key, roomId: $roomId, roomNumber: $roomNumber}';
} }
} }
...@@ -47,4 +47,29 @@ class RoomService { ...@@ -47,4 +47,29 @@ class RoomService {
throw Exception(result.msg); 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
...@@ -17,6 +17,7 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> { ...@@ -17,6 +17,7 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
String? _selectedFloor; String? _selectedFloor;
String? _selectedType; String? _selectedType;
String? _selectedRoom; String? _selectedRoom;
int? _selectedRoomId;
String _searchText = ''; String _searchText = '';
final TextEditingController _searchController = TextEditingController(); final TextEditingController _searchController = TextEditingController();
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
...@@ -403,6 +404,7 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> { ...@@ -403,6 +404,7 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
onTap: () { onTap: () {
setState(() { setState(() {
_selectedRoom = room['number'] as String; _selectedRoom = room['number'] as String;
_selectedRoomId = room['roomId'] as int?;
}); });
}, },
child: Container( child: Container(
...@@ -560,9 +562,12 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> { ...@@ -560,9 +562,12 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
), ),
elevation: 0, elevation: 0,
), ),
onPressed: isRoomSelected onPressed: (isRoomSelected && _selectedRoomId != null)
? () { ? () {
context.pushRoute(ServiceRoomDetailRoute(roomNumber: _selectedRoom)); context.pushRoute(ServiceRoomDetailRoute(
roomId: _selectedRoomId!,
roomNumber: _selectedRoom,
));
} }
: null, : null,
child: Text( child: Text(
......
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.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'; import 'package:smart_hotel_app/views/service/room/cubit/service_room_state.dart';
class ServiceRoomCubit extends Cubit<ServiceRoomState> { class ServiceRoomCubit extends Cubit<ServiceRoomState> {
final String? roomNumber; final RoomService _service;
final int _roomId;
ServiceRoomCubit({this.roomNumber}) : super(const ServiceRoomState()) { ServiceRoomCubit({
initData(); 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() { ServiceRoomState _mapDetailToState(RoomDetailBO detail) {
final num = roomNumber ?? '302'; final basic = detail.roomBasicInfo;
final numInt = int.tryParse(num) ?? 302; final statusTags = _buildStatusTags(
final statuses = ['空闲', '入住中', '待清洁']; occupancyStatus: basic.occupancyStatus,
final statusIndex = numInt % 3; 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( List<RoomStatusTag> _buildStatusTags({
roomNumber: num, required String occupancyStatus,
roomStatus: statuses[statusIndex], required bool powerSupplyStatus,
mainPowerOn: numInt % 2 == 0, required String wifiOnlineStatus,
roomDevices: [ }) {
const RoomDevice( final tags = <RoomStatusTag>[];
name: '空调', if (occupancyStatus == '1') {
icon: Icons.air_outlined, tags.add(RoomStatusTag.hasPerson);
isOn: true, }
statusText: '24°C·开', if (powerSupplyStatus) {
), tags.add(RoomStatusTag.powerOn);
const RoomDevice( }
name: '照明', if (wifiOnlineStatus == '1' || wifiOnlineStatus == 'online') {
icon: Icons.light_outlined, tags.add(RoomStatusTag.wifiNormal);
isOn: false, }
statusText: '关', return tags;
),
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,
),
],
));
} }
void toggleMainPower(bool value) { String _buildDeviceStatusText(DeviceStatusBO d) {
emit(state.copyWith(mainPowerOn: value)); 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) { String _mapOccupancyStatus(String status) {
final updatedDevices = List<ControlDevice>.from(state.controlDevices); switch (status) {
if (index >= 0 && index < updatedDevices.length) { case '1':
updatedDevices[index] = ControlDevice( return '入住中';
name: updatedDevices[index].name, case '0':
icon: updatedDevices[index].icon, default:
isOn: value, return '空闲';
detailText: updatedDevices[index].detailText,
);
emit(state.copyWith(controlDevices: updatedDevices));
} }
} }
}
\ 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));
}
}
...@@ -32,47 +32,67 @@ class ControlDevice { ...@@ -32,47 +32,67 @@ class ControlDevice {
} }
class ServiceRoomState extends Equatable { class ServiceRoomState extends Equatable {
final bool isLoading;
final String? error;
final int roomId;
final String roomNumber; final String roomNumber;
final String roomStatus; final String roomStatus;
final List<RoomStatusTag> statusTags; final List<RoomStatusTag> statusTags;
final List<RoomDevice> roomDevices; final List<RoomDevice> roomDevices;
final bool mainPowerOn; final bool mainPowerOn;
final List<ControlDevice> controlDevices; final List<ControlDevice> controlDevices;
final bool isTogglingPower;
const ServiceRoomState({ const ServiceRoomState({
this.roomNumber = '302', this.isLoading = false,
this.roomStatus = '入住中', this.error,
this.statusTags = const [RoomStatusTag.hasPerson, RoomStatusTag.powerOn, RoomStatusTag.wifiNormal], this.roomId = 0,
this.roomNumber = '',
this.roomStatus = '',
this.statusTags = const [],
this.roomDevices = const [], this.roomDevices = const [],
this.mainPowerOn = false, this.mainPowerOn = false,
this.controlDevices = const [], this.controlDevices = const [],
this.isTogglingPower = false,
}); });
ServiceRoomState copyWith({ ServiceRoomState copyWith({
bool? isLoading,
String? error,
int? roomId,
String? roomNumber, String? roomNumber,
String? roomStatus, String? roomStatus,
List<RoomStatusTag>? statusTags, List<RoomStatusTag>? statusTags,
List<RoomDevice>? roomDevices, List<RoomDevice>? roomDevices,
bool? mainPowerOn, bool? mainPowerOn,
List<ControlDevice>? controlDevices, List<ControlDevice>? controlDevices,
bool? isTogglingPower,
}) { }) {
return ServiceRoomState( return ServiceRoomState(
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
roomId: roomId ?? this.roomId,
roomNumber: roomNumber ?? this.roomNumber, roomNumber: roomNumber ?? this.roomNumber,
roomStatus: roomStatus ?? this.roomStatus, roomStatus: roomStatus ?? this.roomStatus,
statusTags: statusTags ?? this.statusTags, statusTags: statusTags ?? this.statusTags,
roomDevices: roomDevices ?? this.roomDevices, roomDevices: roomDevices ?? this.roomDevices,
mainPowerOn: mainPowerOn ?? this.mainPowerOn, mainPowerOn: mainPowerOn ?? this.mainPowerOn,
controlDevices: controlDevices ?? this.controlDevices, controlDevices: controlDevices ?? this.controlDevices,
isTogglingPower: isTogglingPower ?? this.isTogglingPower,
); );
} }
@override @override
List<Object?> get props => [ List<Object?> get props => [
isLoading,
error,
roomId,
roomNumber, roomNumber,
roomStatus, roomStatus,
statusTags, statusTags,
roomDevices, roomDevices,
mainPowerOn, mainPowerOn,
controlDevices, controlDevices,
isTogglingPower,
]; ];
} }
\ No newline at end of file
...@@ -12,14 +12,22 @@ import 'package:smart_hotel_app/views/service/room/widget/room_bottom_buttons.da ...@@ -12,14 +12,22 @@ import 'package:smart_hotel_app/views/service/room/widget/room_bottom_buttons.da
@RoutePage() @RoutePage()
class ServiceRoomDetailView extends StatelessWidget { class ServiceRoomDetailView extends StatelessWidget {
final int roomId;
final String? roomNumber; final String? roomNumber;
const ServiceRoomDetailView({super.key, this.roomNumber}); const ServiceRoomDetailView({
super.key,
required this.roomId,
this.roomNumber,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (_) => ServiceRoomCubit(roomNumber: roomNumber), create: (_) => ServiceRoomCubit(
roomId: roomId,
roomNumber: roomNumber ?? '',
),
child: Scaffold( child: Scaffold(
backgroundColor: const Color.fromRGBO(242, 243, 245, 1), backgroundColor: const Color.fromRGBO(242, 243, 245, 1),
appBar: AppBar( appBar: AppBar(
...@@ -42,12 +50,42 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -42,12 +50,42 @@ class ServiceRoomDetailView extends StatelessWidget {
), ),
centerTitle: true, centerTitle: true,
), ),
body: SingleChildScrollView( body: BlocBuilder<ServiceRoomCubit, ServiceRoomState>(
padding: EdgeInsets.symmetric(horizontal: 28.w), builder: (context, state) {
child: BlocBuilder<ServiceRoomCubit, ServiceRoomState>( if (state.isLoading) {
builder: (context, state) { return const Center(
final cubit = context.read<ServiceRoomCubit>(); child: CircularProgressIndicator(),
return Column( );
}
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: [ children: [
SizedBox(height: 20.h), SizedBox(height: 20.h),
RoomOverviewCard( RoomOverviewCard(
...@@ -63,8 +101,26 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -63,8 +101,26 @@ class ServiceRoomDetailView extends StatelessWidget {
DeviceControlCard( DeviceControlCard(
mainPowerOn: state.mainPowerOn, mainPowerOn: state.mainPowerOn,
controlDevices: state.controlDevices, controlDevices: state.controlDevices,
onMainPowerToggle: (value) => cubit.toggleMainPower(value), onMainPowerToggle: (value) async {
onDeviceToggle: (index, value) => cubit.toggleControlDevice(index, value), 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) { onDeviceTap: (index, device) {
if (device.name == '空调') { if (device.name == '空调') {
context.pushRoute(const ServiceDeviceDetailRoute()); context.pushRoute(const ServiceDeviceDetailRoute());
...@@ -75,11 +131,11 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -75,11 +131,11 @@ class ServiceRoomDetailView extends StatelessWidget {
const RoomBottomButtons(), const RoomBottomButtons(),
SizedBox(height: 20.h), SizedBox(height: 20.h),
], ],
); ),
}, );
), },
), ),
), ),
); );
} }
} }
\ No newline at end of file
# 智慧酒店 App 接口对接方案 # 智慧酒店 App 接口对接方案
...@@ -220,7 +220,9 @@ class xxxBO extends Equatable { ...@@ -220,7 +220,9 @@ class xxxBO extends Equatable {
| 客房详情 |GET | /app/room/detail | 未对接 | 客房详情 | | | 客房详情 |GET | /app/room/detail | 未对接 | 客房详情 | |
| 客房详情-房间总电源-switch开 |GET | /app/room/power/on | 未对接 | 客房详情-房间总电源-switch开 | | | 客房详情-房间总电源-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 { ...@@ -228,6 +230,35 @@ class xxxBO extends Equatable {
### 3.2 接口详细定义 ### 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** **GET /app/room/floor/areas**
...@@ -262,7 +293,7 @@ class xxxBO extends Equatable { ...@@ -262,7 +293,7 @@ class xxxBO extends Equatable {
#### 客房详情-房间总电源-switch关 #### 客房详情-房间总电源-switch关
**GET /app/room/power/off** **POST /app/room/power/off**
``` ```
求体: 求体:
{ {
......
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