Commit 7ba2abc6 authored by 胡曲's avatar 胡曲

fix bugs

parent b57da32b
...@@ -34,11 +34,13 @@ class RoomOverviewSummaryBO extends Equatable { ...@@ -34,11 +34,13 @@ class RoomOverviewSummaryBO extends Equatable {
/// 楼层Tab列表 /// 楼层Tab列表
class RoomFloorBO extends Equatable { class RoomFloorBO extends Equatable {
final int floorId; final int floorId;
final int floorNumber;
final String floorName; final String floorName;
final bool isActive; final bool isActive;
const RoomFloorBO({ const RoomFloorBO({
this.floorId = 0, this.floorId = 0,
this.floorNumber = 0,
this.floorName = '', this.floorName = '',
this.isActive = false, this.isActive = false,
}); });
...@@ -46,18 +48,20 @@ class RoomFloorBO extends Equatable { ...@@ -46,18 +48,20 @@ class RoomFloorBO extends Equatable {
factory RoomFloorBO.fromJson(Map<String, dynamic> json) { factory RoomFloorBO.fromJson(Map<String, dynamic> json) {
return RoomFloorBO( return RoomFloorBO(
floorId: json['floorId'] as int? ?? 0, floorId: json['floorId'] as int? ?? 0,
floorNumber: json['floorNumber'] as int? ?? 0,
floorName: json['floorName'] as String? ?? '', floorName: json['floorName'] as String? ?? '',
isActive: json['isActive'] as bool? ?? false, isActive: json['isActive'] as bool? ?? false,
); );
} }
@override @override
List<Object?> get props => [floorId, floorName, isActive]; List<Object?> get props => [floorId, floorNumber, floorName, isActive];
} }
/// 房间网格(房间卡片网格布局) /// 房间网格(房间卡片网格布局)
class RoomGridBO extends Equatable { class RoomGridBO extends Equatable {
final int roomId; final int roomId;
final int floorNumber;
final String roomNumber; final String roomNumber;
final String statusText; final String statusText;
final String statusColor; final String statusColor;
...@@ -65,6 +69,7 @@ class RoomGridBO extends Equatable { ...@@ -65,6 +69,7 @@ class RoomGridBO extends Equatable {
const RoomGridBO({ const RoomGridBO({
this.roomId = 0, this.roomId = 0,
this.floorNumber = 0,
this.roomNumber = '', this.roomNumber = '',
this.statusText = '', this.statusText = '',
this.statusColor = '', this.statusColor = '',
...@@ -78,11 +83,12 @@ class RoomGridBO extends Equatable { ...@@ -78,11 +83,12 @@ class RoomGridBO extends Equatable {
statusText: json['statusText'] as String? ?? '', statusText: json['statusText'] as String? ?? '',
statusColor: json['statusColor'] as String? ?? '', statusColor: json['statusColor'] as String? ?? '',
hasAlarmIcon: json['hasAlarmIcon'] as bool? ?? false, hasAlarmIcon: json['hasAlarmIcon'] as bool? ?? false,
floorNumber: json['floorNumber'] as int? ?? 0,
); );
} }
@override @override
List<Object?> get props => [roomId, roomNumber, statusText, statusColor, hasAlarmIcon]; List<Object?> get props => [roomId, roomNumber, statusText, statusColor, hasAlarmIcon, floorNumber];
} }
/// 房间基础信息(客房概览统计) /// 房间基础信息(客房概览统计)
...@@ -90,11 +96,13 @@ class RoomOverviewBasicInfoBO extends Equatable { ...@@ -90,11 +96,13 @@ class RoomOverviewBasicInfoBO extends Equatable {
final int roomId; final int roomId;
final String roomNumber; final String roomNumber;
final String roomStatusText; final String roomStatusText;
final int floorNumber;
const RoomOverviewBasicInfoBO({ const RoomOverviewBasicInfoBO({
this.roomId = 0, this.roomId = 0,
this.roomNumber = '', this.roomNumber = '',
this.roomStatusText = '', this.roomStatusText = '',
this.floorNumber = 0,
}); });
factory RoomOverviewBasicInfoBO.fromJson(Map<String, dynamic> json) { factory RoomOverviewBasicInfoBO.fromJson(Map<String, dynamic> json) {
...@@ -102,11 +110,12 @@ class RoomOverviewBasicInfoBO extends Equatable { ...@@ -102,11 +110,12 @@ class RoomOverviewBasicInfoBO extends Equatable {
roomId: json['roomId'] as int? ?? 0, roomId: json['roomId'] as int? ?? 0,
roomNumber: json['roomNumber'] as String? ?? '', roomNumber: json['roomNumber'] as String? ?? '',
roomStatusText: json['roomStatusText'] as String? ?? '', roomStatusText: json['roomStatusText'] as String? ?? '',
floorNumber: json['floorNumber'] as int? ?? 0,
); );
} }
@override @override
List<Object?> get props => [roomId, roomNumber, roomStatusText]; List<Object?> get props => [roomId, roomNumber, roomStatusText, floorNumber];
} }
/// 状态标签 /// 状态标签
...@@ -261,11 +270,15 @@ String _parseString(dynamic value, {String fallback = ''}) { ...@@ -261,11 +270,15 @@ String _parseString(dynamic value, {String fallback = ''}) {
class FloorAreaBO extends Equatable { class FloorAreaBO extends Equatable {
final int floorId; final int floorId;
final int floorNumber;
final String floorName;
final List<String> areas; final List<String> areas;
final List<FloorRoomSimpleBO> rooms; final List<FloorRoomSimpleBO> rooms;
const FloorAreaBO({ const FloorAreaBO({
required this.floorId, required this.floorId,
required this.floorNumber,
required this.floorName,
required this.areas, required this.areas,
required this.rooms, required this.rooms,
}); });
...@@ -273,6 +286,8 @@ class FloorAreaBO extends Equatable { ...@@ -273,6 +286,8 @@ class FloorAreaBO extends Equatable {
factory FloorAreaBO.fromJson(Map<String, dynamic> json) { factory FloorAreaBO.fromJson(Map<String, dynamic> json) {
return FloorAreaBO( return FloorAreaBO(
floorId: _parseInt(json['floorId']), floorId: _parseInt(json['floorId']),
floorNumber: _parseInt(json['floorNumber']),
floorName: json['floorName'] as String? ?? '',
areas: (json['areas'] as List<dynamic>?) areas: (json['areas'] as List<dynamic>?)
?.map((e) => e as String) ?.map((e) => e as String)
.toList() ?? .toList() ??
...@@ -286,9 +301,7 @@ class FloorAreaBO extends Equatable { ...@@ -286,9 +301,7 @@ class FloorAreaBO extends Equatable {
} }
@override @override
List<Object?> get props => [floorId, areas, rooms]; List<Object?> get props => [floorId, floorNumber, floorName, areas, rooms];
String get floorName => '${floorId}楼';
} }
class FloorRoomSimpleBO extends Equatable { class FloorRoomSimpleBO extends Equatable {
......
...@@ -65,27 +65,31 @@ class RoomRepository { ...@@ -65,27 +65,31 @@ class RoomRepository {
); );
} }
/// 客房详情-房间总电源-开 /// 单设备送电
Future<ResponseModel> roomPowerOn({required int roomId}) { Future<ResponseModel> powerSingleOn({required int deviceId}) {
return DioRequest.instance.post( return DioRequest.instance.post<Map<String, dynamic>>(
'/app/room/power/on', '/app/room/device/power/single/on',
data: {'roomId': roomId}, data: {'deviceId': deviceId},
); );
} }
/// 客房详情-房间总电源-关 /// 单设备断电
Future<ResponseModel> roomPowerOff({required int roomId}) { Future<ResponseModel> powerSingleOff({required int deviceId}) {
return DioRequest.instance.post( return DioRequest.instance.post<Map<String, dynamic>>(
'/app/room/power/off', '/app/room/device/power/single/off',
data: {'roomId': roomId}, data: {'deviceId': deviceId},
); );
} }
/// 客房状态总览-客房概览统计 /// 客房状态总览-客房概览统计
Future<ResponseModel<RoomOverviewBO>> getOverview(int? floorId) { Future<ResponseModel<RoomOverviewBO>> getOverview(int? floorId) {
Map<String, dynamic> param = {};
if (floorId != null && floorId != 0) {
param['floorId'] = floorId;
}
return DioRequest.instance.get<RoomOverviewBO>( return DioRequest.instance.get<RoomOverviewBO>(
'/app/room/overview', '/app/room/overview',
queryParameters: {'floorId': floorId == 0 ? null : floorId}, queryParameters: param,
fromJsonT: (data) => RoomOverviewBO.fromJson(data as Map<String, dynamic>), fromJsonT: (data) => RoomOverviewBO.fromJson(data as Map<String, dynamic>),
); );
} }
......
...@@ -57,22 +57,6 @@ class RoomService { ...@@ -57,22 +57,6 @@ class RoomService {
throw Exception(result.msg); 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);
}
}
/// 客房状态总览-客房概览统计 /// 客房状态总览-客房概览统计
Future<RoomOverviewBO> getOverview(int? floorId) async { Future<RoomOverviewBO> getOverview(int? floorId) async {
final result = await _repository.getOverview(floorId); final result = await _repository.getOverview(floorId);
...@@ -96,4 +80,20 @@ class RoomService { ...@@ -96,4 +80,20 @@ class RoomService {
} }
throw Exception(result.msg); throw Exception(result.msg);
} }
/// 单设备送电
Future<void> powerSingleOn({required int deviceId}) async {
final result = await _repository.powerSingleOn(deviceId: deviceId);
if (!result.success) {
throw Exception(result.msg);
}
}
/// 单设备断电
Future<void> powerSingleOff({required int deviceId}) async {
final result = await _repository.powerSingleOff(deviceId: deviceId);
if (!result.success) {
throw Exception(result.msg);
}
}
} }
\ No newline at end of file
...@@ -4,7 +4,36 @@ class DealUtils { ...@@ -4,7 +4,36 @@ class DealUtils {
/// 去除多余0 /// 去除多余0
static String cleanNumber(String value) { static String cleanNumber(String value) {
try {
return value.replaceAll(RegExp(r'\.?0+$'), ''); return value.replaceAll(RegExp(r'\.?0+$'), '');
} catch (e) {
// rethrow;
return value;
}
}
/// 电流,电压
static String formatVoltage(String input) {
if (input.isEmpty) return input;
try {
// 匹配开头的数字部分(包括小数)
RegExp regExp = RegExp(r'^([\d.]+)');
String? numberPart = regExp.firstMatch(input)?.group(1);
String unitPart = input.replaceFirst(RegExp(r'^[\d.]+'), '');
if (numberPart == null) return input;
// 去掉尾随的零和多余的小数点
String formattedNumber = numberPart
.replaceFirst(RegExp(r'\.?0+$'), '') // 去掉末尾的0和可能的小数点
.replaceFirst(RegExp(r'\.$'), ''); // 如果只剩小数点,去掉
return formattedNumber + unitPart;
} catch (e) {
// rethrow;
return input;
}
} }
/// 设备图标 /// 设备图标
......
...@@ -102,7 +102,7 @@ class AbnormalDetailView extends StatelessWidget { ...@@ -102,7 +102,7 @@ class AbnormalDetailView extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
spacing: 20.h, spacing: 20.h,
children: [ children: [
if (alarmStatus != AlarmStatus.processed) if (alarmStatus != AlarmStatus.processed)//不等于已处理才显示
BlocBuilder<AbnormalCubit, AbnormalState>( BlocBuilder<AbnormalCubit, AbnormalState>(
builder: (context, state) { builder: (context, state) {
final isDisabled = state.isHandling || state.isHandled; final isDisabled = state.isHandling || state.isHandled;
......
...@@ -14,8 +14,12 @@ String? alarmStatusToApi(AlarmStatus status) { ...@@ -14,8 +14,12 @@ String? alarmStatusToApi(AlarmStatus status) {
return null; return null;
case AlarmStatus.pending: case AlarmStatus.pending:
return '0'; return '0';
case AlarmStatus.processing:
return '1';
case AlarmStatus.processed: case AlarmStatus.processed:
return '2'; return '2';
case AlarmStatus.close:
return '3';
case AlarmStatus.falseAlarm: case AlarmStatus.falseAlarm:
return '4'; return '4';
} }
...@@ -75,9 +79,46 @@ class AbnormalListCubit extends Cubit<AbnormalListState> { ...@@ -75,9 +79,46 @@ class AbnormalListCubit extends Cubit<AbnormalListState> {
_pagingController?.refresh(); _pagingController?.refresh();
} }
void onAlarmItemTap(AlarmItem item, BuildContext context) { Future<void> onAlarmItemTap(AlarmItem item, BuildContext context) async {
final alertId = int.tryParse(item.id) ?? 0; final alertId = int.tryParse(item.id) ?? 0;
context.pushRoute(AbnormalDetailRoute( final handled = await context.pushRoute(
alertId: alertId, alarmStatus: item.status)); AbnormalDetailRoute(alertId: alertId, alarmStatus: item.status),
);
// if (handled != null && handled is bool && handled == true) {
// _updateItemStatus(item.id);
// }
}
/// 在分页列表中定位并更新单条记录的状态(不重新请求接口)
void _updateItemStatus(String alertId) {
final state = _pagingController?.value;
if (state == null) return;
final pages = state.pages;
if (pages == null) return;
var found = false;
final newPages = pages.map((page) {
if (found) return page;
final index = page.indexWhere((i) => i.id == alertId);
if (index == -1) return page;
found = true;
final newPage = List<AlarmItem>.from(page);
newPage[index] = AlarmItem(
id: newPage[index].id,
title: newPage[index].title,
deviceInfo: newPage[index].deviceInfo,
alarmTime: newPage[index].alarmTime,
processTime: newPage[index].processTime,
status: AlarmStatus.processed,
level: newPage[index].level,
alertIcon: newPage[index].alertIcon,
);
return newPage;
}).toList();
if (found) {
_pagingController?.value = state.copyWith(pages: newPages);
}
} }
} }
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:smart_hotel_app/models/bo/alert_list_bo.dart'; import 'package:smart_hotel_app/models/bo/alert_list_bo.dart';
enum AlarmStatus { all, pending, processed, falseAlarm } /// 0=待处理 1=处理中 2=已处理 3=已关闭 4=误报关闭
enum AlarmStatus { all, pending, processing, processed, close, falseAlarm }
class AlarmItem extends Equatable { class AlarmItem extends Equatable {
final String id; final String id;
...@@ -37,13 +38,17 @@ class AlarmItem extends Equatable { ...@@ -37,13 +38,17 @@ class AlarmItem extends Equatable {
); );
} }
// 0=待处理 1=处理中 2=已确认 3=已关闭 4=误报关闭 // 0=待处理 1=处理中 2=已处理 3=已关闭 4=误报关闭
static AlarmStatus _mapAlertStatus(String alertStatus) { static AlarmStatus _mapAlertStatus(String alertStatus) {
switch (alertStatus) { switch (alertStatus) {
case '0': case '0':
return AlarmStatus.pending; return AlarmStatus.pending;
case '1':
return AlarmStatus.processing;
case '2': case '2':
return AlarmStatus.processed; return AlarmStatus.processed;
case '3':
return AlarmStatus.close;
case '4': case '4':
return AlarmStatus.falseAlarm; return AlarmStatus.falseAlarm;
default: default:
......
...@@ -185,7 +185,7 @@ class _AbnormalListBodyState extends State<_AbnormalListBody> { ...@@ -185,7 +185,7 @@ class _AbnormalListBodyState extends State<_AbnormalListBody> {
itemBuilder: (_, item, __) { itemBuilder: (_, item, __) {
return AlarmListItem( return AlarmListItem(
item: item, item: item,
onTap: (i) => cubit.onAlarmItemTap(i, context), onTap: (i) { cubit.onAlarmItemTap(i, context); },
); );
}, },
), ),
......
...@@ -170,7 +170,8 @@ class AlarmListItem extends StatelessWidget { ...@@ -170,7 +170,8 @@ class AlarmListItem extends StatelessWidget {
Color? bgColor; Color? bgColor;
Color? textColor; Color? textColor;
String text = ''; String text = '';
String icon = ''; String iconImg = '';
IconData? iconData;
double iconW = 0; double iconW = 0;
double iconH = 0; double iconH = 0;
...@@ -179,23 +180,39 @@ class AlarmListItem extends StatelessWidget { ...@@ -179,23 +180,39 @@ class AlarmListItem extends StatelessWidget {
bgColor = const Color.fromRGBO(254, 247, 217, 1); bgColor = const Color.fromRGBO(254, 247, 217, 1);
textColor = const Color.fromRGBO(250, 204, 21, 1); textColor = const Color.fromRGBO(250, 204, 21, 1);
text = '待处理'; text = '待处理';
icon = 'lib/assets/icon/info_dcl_bg.png'; iconImg = 'lib/assets/icon/info_dcl_bg.png';
iconW = 4.w; iconW = 4.w;
iconH = 15.h; iconH = 15.h;
break; break;
case AlarmStatus.processing:
bgColor = const Color.fromRGBO(245, 245, 245, 1);
textColor = const Color.fromRGBO(51, 51, 51, 1);
text = '处理中';
iconData = Icons.check;
iconW = 18.w;
iconH = 11.h;
break;
case AlarmStatus.processed: case AlarmStatus.processed:
bgColor = const Color.fromRGBO(209, 250, 229, 1); bgColor = const Color.fromRGBO(209, 250, 229, 1);
textColor = const Color.fromRGBO(20, 184, 166, 1); textColor = const Color.fromRGBO(20, 184, 166, 1);
text = '已处理'; text = '已处理';
icon = 'lib/assets/icon/info_ycl_bg.png'; iconData = Icons.check;
iconW = 18.w; iconW = 18.w;
iconH = 11.h; iconH = 11.h;
break; break;
case AlarmStatus.close:
bgColor = const Color.fromRGBO(245, 245, 245, 1);
textColor = const Color.fromRGBO(51, 51, 51, 1);
text = '关闭';
iconData = Icons.close;
iconW = 18.w;
iconH = 15.h;
break;
case AlarmStatus.falseAlarm: case AlarmStatus.falseAlarm:
bgColor = const Color.fromRGBO(255, 224, 224, 1); bgColor = const Color.fromRGBO(255, 224, 224, 1);
textColor = const Color.fromRGBO(255, 100, 101, 1); textColor = const Color.fromRGBO(255, 100, 101, 1);
text = '误报'; text = '误报';
icon = 'lib/assets/icon/info_wb_bg.png'; iconData = Icons.close;
iconW = 14.w; iconW = 14.w;
iconH = 11.h; iconH = 11.h;
break; break;
...@@ -218,7 +235,10 @@ class AlarmListItem extends StatelessWidget { ...@@ -218,7 +235,10 @@ class AlarmListItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
spacing: 6.w, spacing: 6.w,
children: [ children: [
Image.asset(icon, width: iconW, height: iconH), if (iconData != null)
Icon(iconData, color: textColor, size: 26.w)
else
Image.asset(iconImg, width: iconW, height: iconH),//没有纯感叹号的图标
Text( Text(
text, text,
style: TextStyle( style: TextStyle(
......
...@@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; ...@@ -3,6 +3,7 @@ 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/models/bo/alert_dashboard_bo.dart'; import 'package:smart_hotel_app/models/bo/alert_dashboard_bo.dart';
import 'package:smart_hotel_app/utils/deal_utils.dart';
import 'package:smart_hotel_app/views/home/index/cubit/home_index_cubit.dart'; import 'package:smart_hotel_app/views/home/index/cubit/home_index_cubit.dart';
import 'package:smart_hotel_app/views/home/index/cubit/home_index_state.dart'; import 'package:smart_hotel_app/views/home/index/cubit/home_index_state.dart';
import 'package:smart_hotel_app/views/home/index/widget/equipment_list_block.dart'; import 'package:smart_hotel_app/views/home/index/widget/equipment_list_block.dart';
...@@ -50,6 +51,41 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV ...@@ -50,6 +51,41 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<HomeIndexCubit, HomeIndexState>(
builder: (context, state) {
if (state.isLoading) {
return Container(
color: const Color.fromRGBO(242, 243, 245, 1),
child: const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0))),
);
}
if (state.error != null) {
return Container(
color: const Color.fromRGBO(242, 243, 245, 1),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'加载失败: ${state.error}',
style: TextStyle(
fontSize: 28.sp,
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
SizedBox(height: 16.h),
ElevatedButton(
onPressed: () =>
context.read<HomeIndexCubit>().reloadDashboard(),
child: const Text('重试'),
),
],
),
),
);
}
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
return SingleChildScrollView( return SingleChildScrollView(
...@@ -61,9 +97,7 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV ...@@ -61,9 +97,7 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV
width: double.infinity, width: double.infinity,
color: const Color.fromRGBO(242, 243, 245, 1), color: const Color.fromRGBO(242, 243, 245, 1),
padding: EdgeInsets.symmetric(horizontal: 28.w), padding: EdgeInsets.symmetric(horizontal: 28.w),
child: BlocBuilder<HomeIndexCubit, HomeIndexState>( child: Column(
builder: (context, state) {
return Column(
children: [ children: [
const TaskHeadBlock(), const TaskHeadBlock(),
SizedBox(height: 20.h), SizedBox(height: 20.h),
...@@ -79,14 +113,14 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV ...@@ -79,14 +113,14 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV
), ),
SizedBox(height: 20.h), SizedBox(height: 20.h),
], ],
);
},
), ),
), ),
), ),
); );
}, },
); );
},
);
} }
List<Widget> _buildAlertBlocks(List<AlertItemBO> alerts) { List<Widget> _buildAlertBlocks(List<AlertItemBO> alerts) {
...@@ -105,8 +139,8 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV ...@@ -105,8 +139,8 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV
temperatureAlarmTitle: alert.alertTitle, temperatureAlarmTitle: alert.alertTitle,
temperatureAlarmLocation: location, temperatureAlarmLocation: location,
currentTemperature: alert.temperature, currentTemperature: alert.temperature,
currentVoltage: alert.voltage, currentVoltage: DealUtils.formatVoltage(alert.voltage),
currentCurrent: alert.current, currentCurrent: DealUtils.formatVoltage(alert.current),
waitTime: alert.waitingDurationDesc, waitTime: alert.waitingDurationDesc,
alarmLevel: alert.alertLevelText, alarmLevel: alert.alertLevelText,
), ),
...@@ -121,7 +155,7 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV ...@@ -121,7 +155,7 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV
alertId: alert.alertId, alertId: alert.alertId,
voltageAlarmTitle: alert.alertTitle, voltageAlarmTitle: alert.alertTitle,
voltageAlarmLocation: location, voltageAlarmLocation: location,
voltageValue: alert.voltage, voltageValue: DealUtils.formatVoltage(alert.voltage),
alertContent: alert.alertContent.isNotEmpty ? alertContent: alert.alertContent.isNotEmpty ?
'(${alert.alertContent})' : '', '(${alert.alertContent})' : '',
voltageWaitTime: alert.waitingDurationDesc, voltageWaitTime: alert.waitingDurationDesc,
......
...@@ -83,6 +83,7 @@ class VoltageOperateBlock extends StatelessWidget { ...@@ -83,6 +83,7 @@ class VoltageOperateBlock extends StatelessWidget {
], ],
), ),
), ),
SizedBox(width: 15.w),
Text( Text(
voltageAlarmLevel, voltageAlarmLevel,
style: TextStyle( style: TextStyle(
......
...@@ -31,7 +31,7 @@ class InspectionCubit extends Cubit<InspectionState> { ...@@ -31,7 +31,7 @@ class InspectionCubit extends Cubit<InspectionState> {
final roomGroups = rooms.roomGroups; final roomGroups = rooms.roomGroups;
// 默认选中第一个区域、第一个房间 // 默认选中第一个区域、第一个房间
final defaultAreaIndex = roomGroups.isNotEmpty ? 0 : 0; const defaultAreaIndex = 0;
final defaultRoomId = roomGroups.isNotEmpty && final defaultRoomId = roomGroups.isNotEmpty &&
roomGroups[defaultAreaIndex].rooms.isNotEmpty roomGroups[defaultAreaIndex].rooms.isNotEmpty
? roomGroups[defaultAreaIndex].rooms.first.roomId ? roomGroups[defaultAreaIndex].rooms.first.roomId
...@@ -54,8 +54,7 @@ class InspectionCubit extends Cubit<InspectionState> { ...@@ -54,8 +54,7 @@ class InspectionCubit extends Cubit<InspectionState> {
} }
/// 从顶层 runStatus 汇总计算各 tab 数量 /// 从顶层 runStatus 汇总计算各 tab 数量
Map<DeviceStatusTab, int> _computeTabCounts( Map<DeviceStatusTab, int> _computeTabCounts(InspectionRoomRunStatusBO runStatus) {
InspectionRoomRunStatusBO runStatus) {
final total = final total =
runStatus.normal + runStatus.warning + runStatus.offline + runStatus.fault; runStatus.normal + runStatus.warning + runStatus.offline + runStatus.fault;
return { return {
......
...@@ -65,7 +65,7 @@ class InspectionDeviceCubit extends Cubit<InspectionDeviceState> { ...@@ -65,7 +65,7 @@ class InspectionDeviceCubit extends Cubit<InspectionDeviceState> {
lastInspectionTime: basicInfo.lastInspectTime, lastInspectionTime: basicInfo.lastInspectTime,
inspectionHistory: historyList, inspectionHistory: historyList,
inspectionItems: items, inspectionItems: items,
icon: Icons.devices, icon: Icons.devices_other,
)); ));
} catch (e) { } catch (e) {
emit(state.copyWith(isLoading: false, error: e.toString())); emit(state.copyWith(isLoading: false, error: e.toString()));
......
...@@ -82,16 +82,16 @@ class DeviceOverviewCard extends StatelessWidget { ...@@ -82,16 +82,16 @@ class DeviceOverviewCard extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: deviceStatus == '1' color: deviceStatus == '1'
? const Color.fromRGBO(225, 245, 238, 1.0) ? const Color.fromRGBO(209, 250, 229, 1.0)
: const Color.fromRGBO(255, 235, 238, 1.0), : const Color.fromRGBO(255, 235, 238, 1.0),
borderRadius: BorderRadius.circular(20.r), borderRadius: BorderRadius.circular(40.r),
), ),
child: Text( child: Text(
deviceStatus == '1' ? '在线' : '离线', deviceStatus == '1' ? '在线' : '离线',
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 24.sp,
color: deviceStatus == '1' color: deviceStatus == '1'
? const Color.fromRGBO(209, 250, 229, 1.0) ? const Color.fromRGBO(20, 184, 166, 1.0)
: const Color.fromRGBO(231, 76, 60, 1.0), : const Color.fromRGBO(231, 76, 60, 1.0),
), ),
), ),
......
...@@ -82,7 +82,7 @@ class ReportEnergyDetailView extends StatelessWidget { ...@@ -82,7 +82,7 @@ class ReportEnergyDetailView extends StatelessWidget {
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
ZoneChartBlock(zoneData: state.zoneData), ZoneChartBlock(zoneData: state.zoneData),
SizedBox(height: 20.h), SizedBox(height: 16.h),
], ],
), ),
); );
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/utils/deal_utils.dart';
import 'package:smart_hotel_app/views/report/energy/cubit/energy_state.dart'; import 'package:smart_hotel_app/views/report/energy/cubit/energy_state.dart';
class ZoneChartBlock extends StatelessWidget { class ZoneChartBlock extends StatelessWidget {
...@@ -36,11 +37,13 @@ class ZoneChartBlock extends StatelessWidget { ...@@ -36,11 +37,13 @@ class ZoneChartBlock extends StatelessWidget {
bottom: index < zoneData.length - 1 ? 20.h : 0), bottom: index < zoneData.length - 1 ? 20.h : 0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 12.h,
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Row( Row(
spacing: 8.w,
children: [ children: [
Container( Container(
width: 12.w, width: 12.w,
...@@ -52,7 +55,6 @@ class ZoneChartBlock extends StatelessWidget { ...@@ -52,7 +55,6 @@ class ZoneChartBlock extends StatelessWidget {
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
), ),
SizedBox(width: 8.w),
Text( Text(
data.name, data.name,
style: TextStyle( style: TextStyle(
...@@ -63,7 +65,8 @@ class ZoneChartBlock extends StatelessWidget { ...@@ -63,7 +65,8 @@ class ZoneChartBlock extends StatelessWidget {
], ],
), ),
Text( Text(
'${data.percentage.toInt()}% (${data.energy.toInt()} kWh)', '${DealUtils.cleanNumber(data.percentage.toString())}% '
'(${DealUtils.cleanNumber(data.energy.toString())} kWh)',
style: TextStyle( style: TextStyle(
color: index == 0 color: index == 0
? const Color.fromRGBO(59, 130, 246, 1) ? const Color.fromRGBO(59, 130, 246, 1)
...@@ -73,7 +76,6 @@ class ZoneChartBlock extends StatelessWidget { ...@@ -73,7 +76,6 @@ class ZoneChartBlock extends StatelessWidget {
), ),
], ],
), ),
SizedBox(height: 12.h),
Stack( Stack(
children: [ children: [
Container( Container(
......
...@@ -12,7 +12,7 @@ class ReportIndexCubit extends Cubit<ReportIndexState> { ...@@ -12,7 +12,7 @@ class ReportIndexCubit extends Cubit<ReportIndexState> {
ReportIndexCubit({DashboardService? service}) ReportIndexCubit({DashboardService? service})
: _service = service ?? DashboardService(repository: DashboardRepository()), : _service = service ?? DashboardService(repository: DashboardRepository()),
super(const ReportIndexState()) { super(const ReportIndexState()) {
loadData(); // loadData();
} }
Future<void> loadData() async { Future<void> loadData() async {
......
...@@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart'; ...@@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:smart_hotel_app/routes/app_router.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
class DeviceOnlineRate extends StatelessWidget { class DeviceOnlineRate extends StatelessWidget {
...@@ -13,10 +12,13 @@ class DeviceOnlineRate extends StatelessWidget { ...@@ -13,10 +12,13 @@ class DeviceOnlineRate extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final devices = final devices =
deviceOnlineRate['devices'] as List<Map<String, dynamic>>; (deviceOnlineRate['devices'] as List<dynamic>?)
?.map((e) => e as Map<String, dynamic>)
.toList() ??
<Map<String, dynamic>>[];
final totalDevices = final totalDevices =
devices.fold<int>(0, (sum, device) => sum + (device['count'] as int)); devices.fold<int>(0, (sum, device) => sum + ((device['count'] as int?) ?? 0));
final rate = deviceOnlineRate['rate'] as double; final rate = deviceOnlineRate['rate'] as double? ?? 0.0;
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
...@@ -36,7 +38,7 @@ class DeviceOnlineRate extends StatelessWidget { ...@@ -36,7 +38,7 @@ class DeviceOnlineRate extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
deviceOnlineRate['title'] as String, (deviceOnlineRate['title'] as String?) ?? '',
style: TextStyle( style: TextStyle(
fontSize: 28.sp, fontSize: 28.sp,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
...@@ -93,7 +95,7 @@ class DeviceOnlineRate extends StatelessWidget { ...@@ -93,7 +95,7 @@ class DeviceOnlineRate extends StatelessWidget {
), ),
), ),
Text( Text(
deviceOnlineRate['rateText'] as String, (deviceOnlineRate['rateText'] as String?) ?? '',
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 24.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
...@@ -113,14 +115,14 @@ class DeviceOnlineRate extends StatelessWidget { ...@@ -113,14 +115,14 @@ class DeviceOnlineRate extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
device['name'] as String, (device['name'] as String?) ?? '',
style: TextStyle( style: TextStyle(
fontSize: 22.sp, fontSize: 22.sp,
color: const Color.fromRGBO(107, 114, 128, 1), color: const Color.fromRGBO(107, 114, 128, 1),
), ),
), ),
Text( Text(
'${device['count']} 台', '${device['count'] ?? 0} 台',
style: TextStyle( style: TextStyle(
fontSize: 22.sp, fontSize: 22.sp,
color: const Color.fromRGBO(55, 65, 81, 1), color: const Color.fromRGBO(55, 65, 81, 1),
......
...@@ -11,7 +11,11 @@ class QuickActionsBlock extends StatelessWidget { ...@@ -11,7 +11,11 @@ class QuickActionsBlock extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final actions = quickActions['actions'] as List<Map<String, dynamic>>; final actions =
(quickActions['actions'] as List<dynamic>?)
?.map((e) => e as Map<String, dynamic>)
.toList() ??
<Map<String, dynamic>>[];
return Container( return Container(
width: double.infinity, width: double.infinity,
...@@ -24,7 +28,7 @@ class QuickActionsBlock extends StatelessWidget { ...@@ -24,7 +28,7 @@ class QuickActionsBlock extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
quickActions['title'] as String, (quickActions['title'] as String?) ?? '',
style: TextStyle( style: TextStyle(
fontSize: 28.sp, fontSize: 28.sp,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
...@@ -34,7 +38,7 @@ class QuickActionsBlock extends StatelessWidget { ...@@ -34,7 +38,7 @@ class QuickActionsBlock extends StatelessWidget {
SizedBox(height: 28.h), SizedBox(height: 28.h),
Row( Row(
children: actions.map((action) { children: actions.map((action) {
final name = action['name'] as String; final name = (action['name'] as String?) ?? '';
return Padding( return Padding(
padding: EdgeInsets.only(right: 60.w), padding: EdgeInsets.only(right: 60.w),
child: GestureDetector( child: GestureDetector(
...@@ -55,7 +59,7 @@ class QuickActionsBlock extends StatelessWidget { ...@@ -55,7 +59,7 @@ class QuickActionsBlock extends StatelessWidget {
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Icon( child: Icon(
action['icon'] as IconData, (action['icon'] as IconData?) ?? Icons.apps,
color: const Color.fromRGBO(59, 130, 246, 1), color: const Color.fromRGBO(59, 130, 246, 1),
size: 36.sp, size: 36.sp,
), ),
......
...@@ -9,20 +9,25 @@ class ReportMetricsBlock extends StatelessWidget { ...@@ -9,20 +9,25 @@ class ReportMetricsBlock extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final powerUsage = reportMetrics['powerUsage'] as Map<String, dynamic>; final powerUsage = reportMetrics.containsKey('powerUsage') &&
final pendingAlerts = reportMetrics['pendingAlerts'] as Map<String, dynamic>; reportMetrics['powerUsage'] != null
? Map<String, dynamic>.from(reportMetrics['powerUsage']) : {};
final pendingAlerts = reportMetrics.containsKey('pendingAlerts') &&
reportMetrics['pendingAlerts'] != null
? Map<String, dynamic>.from(reportMetrics['pendingAlerts']) : {};
return Row( return Row(
children: [ children: [
Expanded( Expanded(
child: _buildMetricCard( child: _buildMetricCard(
title: '今日用电', title: '今日用电',
value: DealUtils.cleanNumber(powerUsage['value'] as String), value: DealUtils.cleanNumber(powerUsage.containsKey('value') ?
unit: powerUsage['unit'] as String, powerUsage['value'] as String : ''),
changeText: powerUsage['changeText'] as String, unit: powerUsage['unit'] as String?,
changeText: powerUsage['changeText'] as String?,
changeColor: const Color.fromRGBO(20, 184, 166, 1), changeColor: const Color.fromRGBO(20, 184, 166, 1),
valueColor: const Color.fromRGBO(73, 149, 234, 1), valueColor: const Color.fromRGBO(73, 149, 234, 1),
progress: powerUsage['progress'] as double, progress: powerUsage['progress'] as double?,
progressColor: const Color.fromRGBO(73, 149, 234, 1), progressColor: const Color.fromRGBO(73, 149, 234, 1),
), ),
), ),
...@@ -30,12 +35,12 @@ class ReportMetricsBlock extends StatelessWidget { ...@@ -30,12 +35,12 @@ class ReportMetricsBlock extends StatelessWidget {
Expanded( Expanded(
child: _buildMetricCard( child: _buildMetricCard(
title: '待处理告警', title: '待处理告警',
value: pendingAlerts['value'], value: pendingAlerts['value'] as String?,
unit: pendingAlerts['unit'] as String, unit: pendingAlerts['unit'] as String?,
changeText: pendingAlerts['changeText'] as String, changeText: pendingAlerts['changeText'] as String?,
changeColor: const Color.fromRGBO(250, 204, 21, 1), changeColor: const Color.fromRGBO(250, 204, 21, 1),
valueColor: const Color.fromRGBO(250, 204, 21, 1), valueColor: const Color.fromRGBO(250, 204, 21, 1),
progress: pendingAlerts['progress'] as double, progress: pendingAlerts['progress'] as double?,
progressColor: const Color.fromRGBO(250, 204, 21, 1), progressColor: const Color.fromRGBO(250, 204, 21, 1),
), ),
), ),
...@@ -45,12 +50,12 @@ class ReportMetricsBlock extends StatelessWidget { ...@@ -45,12 +50,12 @@ class ReportMetricsBlock extends StatelessWidget {
Widget _buildMetricCard({ Widget _buildMetricCard({
required String title, required String title,
required String value, required String? value,
required String unit, required String? unit,
required String changeText, required String? changeText,
required Color changeColor, required Color changeColor,
required Color valueColor, required Color valueColor,
required double progress, required double? progress,
required Color progressColor, required Color progressColor,
}) { }) {
return Container( return Container(
...@@ -73,7 +78,7 @@ class ReportMetricsBlock extends StatelessWidget { ...@@ -73,7 +78,7 @@ class ReportMetricsBlock extends StatelessWidget {
), ),
), ),
Text( Text(
changeText, changeText ?? '',
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 24.sp,
color: changeColor, color: changeColor,
...@@ -86,8 +91,7 @@ class ReportMetricsBlock extends StatelessWidget { ...@@ -86,8 +91,7 @@ class ReportMetricsBlock extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text( Text(
value, value ?? '',
// cleanNumber(value),
style: TextStyle( style: TextStyle(
fontSize: 40.sp, fontSize: 40.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
...@@ -98,7 +102,7 @@ class ReportMetricsBlock extends StatelessWidget { ...@@ -98,7 +102,7 @@ class ReportMetricsBlock extends StatelessWidget {
Padding( Padding(
padding: EdgeInsets.only(bottom: 6.h), padding: EdgeInsets.only(bottom: 6.h),
child: Text( child: Text(
unit, unit ?? '',
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
color: const Color.fromRGBO(107, 114, 128, 1), color: const Color.fromRGBO(107, 114, 128, 1),
......
...@@ -12,8 +12,11 @@ class RoomStatusDistribution extends StatelessWidget { ...@@ -12,8 +12,11 @@ class RoomStatusDistribution extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final statuses = final statuses =
roomStatusDistribution['statuses'] as List<Map<String, dynamic>>; (roomStatusDistribution['statuses'] as List<dynamic>?)
final totalRooms = roomStatusDistribution['totalRooms'] as int; ?.map((e) => e as Map<String, dynamic>)
.toList() ??
<Map<String, dynamic>>[];
final totalRooms = roomStatusDistribution['totalRooms'] as int? ?? 0;
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
...@@ -33,7 +36,7 @@ class RoomStatusDistribution extends StatelessWidget { ...@@ -33,7 +36,7 @@ class RoomStatusDistribution extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
roomStatusDistribution['title'] as String, (roomStatusDistribution['title'] as String?) ?? '',
style: TextStyle( style: TextStyle(
fontSize: 28.sp, fontSize: 28.sp,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
...@@ -61,9 +64,9 @@ class RoomStatusDistribution extends StatelessWidget { ...@@ -61,9 +64,9 @@ class RoomStatusDistribution extends StatelessWidget {
), ),
SizedBox(height: 20.h), SizedBox(height: 20.h),
...statuses.map((status) { ...statuses.map((status) {
final count = status['count'] as int; final count = status['count'] as int? ?? 0;
final color = status['color'] as Color; final color = status['color'] as Color? ?? Colors.grey;
final name = status['name'] as String; final name = status['name'] as String? ?? '';
final percentage = totalRooms > 0 ? count / totalRooms : 0.0; final percentage = totalRooms > 0 ? count / totalRooms : 0.0;
final percentText = '${(percentage * 100).toInt()}%'; final percentText = '${(percentage * 100).toInt()}%';
......
...@@ -34,8 +34,8 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -34,8 +34,8 @@ class WeeklyPowerChart extends StatelessWidget {
double get _bottomInterval { double get _bottomInterval {
final len = _spots.length; final len = _spots.length;
if (len <= 1) return 1; if (len <= 1) return 1;
if (len <= 6) return 1; if (len <= 7) return 1;
if (len <= 12) return 2; if (len <= 14) return 2;
return (len - 1) / 4; return (len - 1) / 4;
} }
...@@ -71,6 +71,7 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -71,6 +71,7 @@ class WeeklyPowerChart extends StatelessWidget {
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 20.h,
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
...@@ -84,6 +85,7 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -84,6 +85,7 @@ class WeeklyPowerChart extends StatelessWidget {
), ),
), ),
Row( Row(
spacing: 8.w,
children: [ children: [
Text( Text(
weeklyPowerUsage['dateRange'] as String? ?? '', weeklyPowerUsage['dateRange'] as String? ?? '',
...@@ -92,7 +94,6 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -92,7 +94,6 @@ class WeeklyPowerChart extends StatelessWidget {
color: const Color.fromRGBO(156, 163, 175, 1), color: const Color.fromRGBO(156, 163, 175, 1),
), ),
), ),
SizedBox(width: 8.w),
Icon( Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
size: 24.sp, size: 24.sp,
...@@ -102,7 +103,6 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -102,7 +103,6 @@ class WeeklyPowerChart extends StatelessWidget {
), ),
], ],
), ),
SizedBox(height: 20.h),
Container( Container(
height: 200.h, height: 200.h,
padding: EdgeInsets.only(right: 28.w), padding: EdgeInsets.only(right: 28.w),
...@@ -131,7 +131,7 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -131,7 +131,7 @@ class WeeklyPowerChart extends StatelessWidget {
bottomTitles: AxisTitles( bottomTitles: AxisTitles(
sideTitles: SideTitles( sideTitles: SideTitles(
showTitles: true, showTitles: true,
interval: _bottomInterval, interval: _bottomInterval,//刻度间隔
getTitlesWidget: (value, meta) { getTitlesWidget: (value, meta) {
return Padding( return Padding(
padding: EdgeInsets.only(top: 8.h), padding: EdgeInsets.only(top: 8.h),
...@@ -144,7 +144,7 @@ class WeeklyPowerChart extends StatelessWidget { ...@@ -144,7 +144,7 @@ class WeeklyPowerChart extends StatelessWidget {
), ),
); );
}, },
reservedSize: 28, reservedSize: 20,//轴标签预留的外部空间
), ),
), ),
leftTitles: AxisTitles( leftTitles: AxisTitles(
......
...@@ -7,20 +7,27 @@ import 'package:smart_hotel_app/views/report/room/cubit/room_report_state.dart'; ...@@ -7,20 +7,27 @@ import 'package:smart_hotel_app/views/report/room/cubit/room_report_state.dart';
class RoomReportCubit extends Cubit<RoomReportState> { class RoomReportCubit extends Cubit<RoomReportState> {
final RoomService _service; final RoomService _service;
/// 全量数据缓存,切换楼层时直接从内存过滤,不重新请求接口
List<RoomGridBO> _allRoomGrid = [];
List<RoomDetailListBO> _allDetailRooms = [];
RoomReportCubit({RoomService? service}) RoomReportCubit({RoomService? service})
: _service = service ?? RoomService(repository: RoomRepository()), : _service = service ?? RoomService(repository: RoomRepository()),
super(const RoomReportState()) { super(const RoomReportState()) {
loadData(); loadData();
} }
Future<void> loadData({int floorId = 1}) async { Future<void> loadData() async {
emit(state.copyWith(isLoading: true, error: null)); emit(state.copyWith(isLoading: true, error: null, clearError: true));
try { try {
final overview = await _service.getOverview(floorId); // 不传 floorId,获取全量数据
final overview = await _service.getOverview(null);
final activeIndex = overview.floorList.indexWhere((f) => f.isActive); final activeIndex = overview.floorList.indexWhere((f) => f.isActive);
final selectedFloorIndex = activeIndex >= 0 ? activeIndex : 0;
// 过滤掉每个房间 deviceList 中名称含"分控"的设备 // 过滤掉每个房间 deviceList 中名称含"分控"的设备,并缓存全量
final filteredDetailRooms = overview.roomDetailList.map((room) { _allRoomGrid = overview.roomGrid;
_allDetailRooms = overview.roomDetailList.map((room) {
return RoomDetailListBO( return RoomDetailListBO(
roomBasicInfo: room.roomBasicInfo, roomBasicInfo: room.roomBasicInfo,
statusTags: room.statusTags, statusTags: room.statusTags,
...@@ -30,13 +37,16 @@ class RoomReportCubit extends Cubit<RoomReportState> { ...@@ -30,13 +37,16 @@ class RoomReportCubit extends Cubit<RoomReportState> {
); );
}).toList(); }).toList();
// 按选中楼层的 floorNumber 过滤
final floorNumber = overview.floorList[selectedFloorIndex].floorNumber;
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
summary: overview.summary, summary: overview.summary,
floors: overview.floorList, floors: overview.floorList,
selectedFloorIndex: activeIndex >= 0 ? activeIndex : 0, selectedFloorIndex: selectedFloorIndex,
roomGrid: overview.roomGrid, roomGrid: _filterRoomGrid(floorNumber),
detailRooms: filteredDetailRooms, detailRooms: _filterDetailRooms(floorNumber),
selectedRoomId: null, selectedRoomId: null,
)); ));
} catch (e) { } catch (e) {
...@@ -44,16 +54,33 @@ class RoomReportCubit extends Cubit<RoomReportState> { ...@@ -44,16 +54,33 @@ class RoomReportCubit extends Cubit<RoomReportState> {
} }
} }
/// 切换楼层
void selectFloor(int index) { void selectFloor(int index) {
if (state.selectedFloorIndex == index) return; if (state.selectedFloorIndex == index) return;
if (index < 0 || index >= state.floors.length) return;
final floorNumber = state.floors[index].floorNumber;
final floorId = state.floors[index].floorId; emit(state.copyWith(
emit(state.copyWith(selectedFloorIndex: index, selectedRoomId: null)); selectedFloorIndex: index,
loadData(floorId: floorId); roomGrid: _filterRoomGrid(floorNumber),
detailRooms: _filterDetailRooms(floorNumber),
selectedRoomId: null,
));
} }
void selectRoom(int roomId) { void selectRoom(int roomId) {
final newId = state.selectedRoomId == roomId ? null : roomId; final newId = state.selectedRoomId == roomId ? null : roomId;
emit(state.copyWith(selectedRoomId: newId)); emit(state.copyWith(selectedRoomId: newId));
} }
List<RoomGridBO> _filterRoomGrid(int floorNumber) {
return _allRoomGrid.where((r) => r.floorNumber == floorNumber).toList();
}
List<RoomDetailListBO> _filterDetailRooms(int floorNumber) {
return _allDetailRooms
.where((r) => r.roomBasicInfo.floorNumber == floorNumber)
.toList();
}
} }
...@@ -15,20 +15,22 @@ class FloorSelector extends StatelessWidget { ...@@ -15,20 +15,22 @@ class FloorSelector extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return SingleChildScrollView(
width: double.infinity, scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(vertical: 20.h), padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 20.h),
child: Row( child: Row(
spacing: 30.w,
children: floorNames.asMap().entries.map((entry) { children: floorNames.asMap().entries.map((entry) {
final index = entry.key; final index = entry.key;
final name = entry.value; final name = entry.value;
final isSelected = index == selectedIndex; final isSelected = index == selectedIndex;
return Expanded( return GestureDetector(
child: GestureDetector( behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
context.read<RoomReportCubit>().selectFloor(index); context.read<RoomReportCubit>().selectFloor(index);
}, },
child: Column( child: Column(
spacing: 10.h,
children: [ children: [
Text( Text(
name, name,
...@@ -37,12 +39,11 @@ class FloorSelector extends StatelessWidget { ...@@ -37,12 +39,11 @@ class FloorSelector extends StatelessWidget {
color: isSelected color: isSelected
? const Color.fromRGBO(80, 162, 255, 1) ? const Color.fromRGBO(80, 162, 255, 1)
: const Color.fromRGBO(10, 13, 20, 1), : const Color.fromRGBO(10, 13, 20, 1),
fontWeight: isSelected ? FontWeight.w500 : FontWeight.normal, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
), ),
), ),
SizedBox(height: 4.h),
Container( Container(
width: 50.w, width: 60.w,
height: 3.h, height: 3.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected color: isSelected
...@@ -53,7 +54,6 @@ class FloorSelector extends StatelessWidget { ...@@ -53,7 +54,6 @@ class FloorSelector extends StatelessWidget {
), ),
], ],
), ),
),
); );
}).toList(), }).toList(),
), ),
......
...@@ -73,10 +73,10 @@ class RoomDetailCard extends StatelessWidget { ...@@ -73,10 +73,10 @@ class RoomDetailCard extends StatelessWidget {
label: '通电中', label: '通电中',
isActive: room.statusTags.powerSupplyStatus, isActive: room.statusTags.powerSupplyStatus,
), ),
_StatusTag( // _StatusTag(
label: 'wifi正常', // label: 'wifi正常',
isActive: room.statusTags.wifiNormalStatus, // isActive: room.statusTags.wifiNormalStatus,
), // ),
], ],
), ),
], ],
...@@ -176,10 +176,7 @@ class _DeviceControl extends StatelessWidget { ...@@ -176,10 +176,7 @@ class _DeviceControl extends StatelessWidget {
), ),
SizedBox(width: 16.w), SizedBox(width: 16.w),
Expanded( Expanded(
child: Text( child: Text(device.deviceName,
device.deviceName.contains('-')
? device.deviceName.split('-').last
: device.deviceName,
style: TextStyle( style: TextStyle(
fontSize: 28.sp, fontSize: 28.sp,
color: const Color.fromRGBO(59, 130, 246, 1), color: const Color.fromRGBO(59, 130, 246, 1),
......
...@@ -17,52 +17,47 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -17,52 +17,47 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
repository: RoomStatisticsRepository(), repository: RoomStatisticsRepository(),
), ),
super(const ServiceIndexState()) { super(const ServiceIndexState()) {
_init(); // _init();
} }
Future<void> _init() async { // Future<void> _init() async {
await Future.wait([ // await Future.wait([
loadStatistics(), // loadStatistics(),
loadFloorAndAreas(), // loadFloorAndAreas(),
]); // ]);
} // }
Future<void> reloadAll() async { Future<void> reloadAll() async {
emit(state.copyWith(isLoading: true, error: null));
try {
await Future.wait([ await Future.wait([
loadStatistics(), loadStatistics(),
loadFloorAndAreas(), loadFloorAndAreas(),
]); ]);
emit(state.copyWith(isLoading: false));
} catch (e) {
emit(state.copyWith(isLoading: false, error: e.toString()));
}
} }
/// 加载客房服务看板-统计数据(待响应、入住中、空闲可清洁) /// 加载客房服务看板-统计数据(待响应、入住中、空闲可清洁)
Future<void> loadStatistics() async { Future<void> loadStatistics() async {
emit(state.copyWith(isLoading: true, error: null));
try {
final stats = await _statisticsService.getStatistics(); final stats = await _statisticsService.getStatistics();
emit(state.copyWith( emit(state.copyWith(
isLoading: false,
pendingCount: stats.pendingResponseCount, pendingCount: stats.pendingResponseCount,
occupiedRooms: stats.occupiedCount, occupiedRooms: stats.occupiedCount,
vacantRooms: stats.vacantCleanableCount, vacantRooms: stats.vacantCleanableCount,
)); ));
} catch (e) {
emit(state.copyWith(isLoading: false, error: e.toString()));
}
} }
/// 加载楼层和区域信息 + 合并房间数据 /// 加载楼层和区域信息 + 合并房间数据
Future<void> loadFloorAndAreas() async { Future<void> loadFloorAndAreas() async {
emit(state.copyWith(isLoading: true, error: null));
try {
final floorAreas = await _roomService.getFloorAreas(); final floorAreas = await _roomService.getFloorAreas();
_floorAreasCache = floorAreas; _floorAreasCache = floorAreas;
final floors = floorAreas.map((f) => {f.floorId: f.floorId.toString()}).toList(); final floors = floorAreas.map((f) => {f.floorId: f.floorName}).toList();
emit(state.copyWith( emit(state.copyWith(floors: floors));
isLoading: false,
floors: floors,
));
// 默认选中第一个楼层,加载其全部房间数据,再默认选中第一个区域和房间 // 默认选中第一个楼层,加载其全部房间数据,再默认选中第一个区域和房间
if (floors.isNotEmpty) { if (floors.isNotEmpty) {
...@@ -71,18 +66,16 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -71,18 +66,16 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
final firstFloorLabel = firstFloor.values.first; final firstFloorLabel = firstFloor.values.first;
_updateAreasForFloor(firstFloorLabel); _updateAreasForFloor(firstFloorLabel);
selectFloor(firstFloorLabel); selectFloor(firstFloorLabel);
await _loadAllRooms(floorId: firstFloorId); await _loadAllRooms(floorId: firstFloorId);
_selectFirstTypeAndRoom(); _selectFirstTypeAndRoom();
} }
} catch (e) {
emit(state.copyWith(isLoading: false, error: e.toString()));
}
} }
/// 根据选中的楼层更新 areas /// 根据选中的楼层更新 areas
void _updateAreasForFloor(String floorLabel) { void _updateAreasForFloor(String floorLabel) {
final matched = _floorAreasCache.where( final matched = _floorAreasCache.where(
(f) => f.floorId.toString() == floorLabel, (f) => f.floorName == floorLabel,
); );
final areas = matched.isNotEmpty ? matched.first.areas : <String>[]; final areas = matched.isNotEmpty ? matched.first.areas : <String>[];
emit(state.copyWith(areas: areas)); emit(state.copyWith(areas: areas));
...@@ -90,8 +83,6 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -90,8 +83,6 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
/// 加载某楼层的全部房间状态,与 FloorAreaBO.rooms 合并 /// 加载某楼层的全部房间状态,与 FloorAreaBO.rooms 合并
Future<void> _loadAllRooms({required int floorId}) async { Future<void> _loadAllRooms({required int floorId}) async {
emit(state.copyWith(isLoading: true, error: null));
try {
// 获取当前楼层的 FloorAreaBO // 获取当前楼层的 FloorAreaBO
final floorArea = _floorAreasCache.cast<FloorAreaBO?>().firstWhere( final floorArea = _floorAreasCache.cast<FloorAreaBO?>().firstWhere(
(f) => f?.floorId == floorId, (f) => f?.floorId == floorId,
...@@ -99,7 +90,7 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -99,7 +90,7 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
); );
if (floorArea == null) { if (floorArea == null) {
emit(state.copyWith(isLoading: false, rooms: [])); emit(state.copyWith(rooms: []));
return; return;
} }
...@@ -107,15 +98,15 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -107,15 +98,15 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
final roomStatuses = await _roomService.getRoomStatus(floorId: floorId); final roomStatuses = await _roomService.getRoomStatus(floorId: floorId);
// 以 roomId 为 key 建立状态映射 // 以 roomId 为 key 建立状态映射
final statusMap = <int, RoomStatusBO>{}; final roomIdMap = <int, RoomStatusBO>{};
for (final rs in roomStatuses) { for (final rs in roomStatuses) {
statusMap[rs.roomId] = rs; roomIdMap[rs.roomId] = rs;
} }
// 合并:遍历 floorArea.rooms,匹配状态数据,推断 area // 合并:遍历 floorArea.rooms,匹配状态数据,推断 area
final mergedRooms = <Map<String, dynamic>>[]; final mergedRooms = <Map<String, dynamic>>[];
for (final floorRoom in floorArea.rooms) { for (final floorRoom in floorArea.rooms) {
final status = statusMap[floorRoom.roomId]; final status = roomIdMap[floorRoom.roomId];
final area = _getAreaForRoom(floorRoom.roomName, floorArea.areas); final area = _getAreaForRoom(floorRoom.roomName, floorArea.areas);
mergedRooms.add(_buildRoomMap( mergedRooms.add(_buildRoomMap(
roomId: floorRoom.roomId, roomId: floorRoom.roomId,
...@@ -125,10 +116,7 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -125,10 +116,7 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
)); ));
} }
emit(state.copyWith(isLoading: false, rooms: mergedRooms)); emit(state.copyWith(rooms: mergedRooms));
} catch (e) {
emit(state.copyWith(isLoading: false, error: e.toString()));
}
} }
/// 根据 roomName 匹配所属区域类型(最长匹配优先) /// 根据 roomName 匹配所属区域类型(最长匹配优先)
...@@ -204,22 +192,18 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -204,22 +192,18 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
} }
} }
/// UI 层切换楼层(切换时重置类型/房间/搜索,重新加载数据) /// UI 层切换楼层(选中后不能取消,切换时重置类型/房间/搜索,重新加载数据)
Future<void> toggleFloor(String floorName, int floorId) async { Future<void> toggleFloor(String floorName, int floorId) async {
final isSameFloor = state.selectedFloor == floorName; if (state.selectedFloor == floorName) return;
final newFloor = isSameFloor ? null : floorName;
// 计算新楼层的 areas // 计算新楼层的 areas
List<String> areas = state.areas;
if (newFloor != null) {
final matched = _floorAreasCache.where( final matched = _floorAreasCache.where(
(f) => f.floorId.toString() == newFloor, (f) => f.floorName == floorName,
); );
areas = matched.isNotEmpty ? matched.first.areas : <String>[]; final areas = matched.isNotEmpty ? matched.first.areas : <String>[];
}
emit(state.copyWith( emit(state.copyWith(
selectedFloor: newFloor, selectedFloor: floorName,
selectedType: null, selectedType: null,
selectedRoom: null, selectedRoom: null,
selectedRoomId: null, selectedRoomId: null,
...@@ -227,9 +211,11 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> { ...@@ -227,9 +211,11 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
areas: areas, areas: areas,
)); ));
if (newFloor != null) { try {
await _loadAllRooms(floorId: floorId); await _loadAllRooms(floorId: floorId);
_selectFirstTypeAndRoom(); _selectFirstTypeAndRoom();
} catch (e) {
emit(state.copyWith(error: e.toString()));
} }
} }
......
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.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/repositories/room_repository.dart'; import 'package:smart_hotel_app/repositories/room_repository.dart';
...@@ -21,8 +20,9 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -21,8 +20,9 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
loadDetail(); loadDetail();
} }
Future<void> loadDetail() async { /// 客房详情接口
emit(state.copyWith(isLoading: true, error: null)); Future<void> loadDetail({bool isLoading = true}) async {
emit(state.copyWith(isLoading: isLoading, error: null));
try { try {
final detail = await _service.getRoomDetail(roomId: _roomId); final detail = await _service.getRoomDetail(roomId: _roomId);
emit(_mapDetailToState(detail)); emit(_mapDetailToState(detail));
...@@ -31,6 +31,7 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -31,6 +31,7 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
} }
} }
/// 数据处理
ServiceRoomState _mapDetailToState(RoomDetailBO detail) { ServiceRoomState _mapDetailToState(RoomDetailBO detail) {
final basic = detail.roomBasicInfo; final basic = detail.roomBasicInfo;
final statusTags = _buildStatusTags( final statusTags = _buildStatusTags(
...@@ -39,13 +40,12 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -39,13 +40,12 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
wifiOnlineStatus: basic.wifiOnlineStatus, wifiOnlineStatus: basic.wifiOnlineStatus,
); );
// 房间设备状态
final roomDevices = detail.deviceStatusList final roomDevices = detail.deviceStatusList
.where((d) => !d.deviceName.contains('分控')) .where((d) => !d.deviceName.contains('分控'))
.map((d) { .map((d) {
return RoomDevice( return RoomDevice(
name: d.deviceName.contains('-') name: d.deviceName,
? d.deviceName.split('-').last
: d.deviceName,
icon: DealUtils.deviceIcon(d.deviceTypeIcon), icon: DealUtils.deviceIcon(d.deviceTypeIcon),
isOn: d.powerStatus == '1' || d.powerStatus == 'on', isOn: d.powerStatus == '1' || d.powerStatus == 'on',
statusText: _buildDeviceStatusText(d), statusText: _buildDeviceStatusText(d),
...@@ -58,14 +58,13 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -58,14 +58,13 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
iconMap[d.deviceId] = d.deviceTypeIcon; iconMap[d.deviceId] = d.deviceTypeIcon;
} }
final controlDevices = detail.deviceControl.subDeviceControls // 分设备控制
final subDeviceControls = detail.deviceControl.subDeviceControls
.where((c) => !c.deviceName.contains('分控')) .where((c) => !c.deviceName.contains('分控'))
.map((c) { .map((c) {
return ControlDevice( return ControlDevice(
deviceId: c.deviceId, deviceId: c.deviceId,
name: c.deviceName.contains('-') name: c.deviceName,
? c.deviceName.split('-').last
: c.deviceName,
icon: DealUtils.deviceIcon(iconMap[c.deviceId] ?? ''), icon: DealUtils.deviceIcon(iconMap[c.deviceId] ?? ''),
isOn: c.powerOn, isOn: c.powerOn,
detailText: c.currentParamDisplay.isNotEmpty ? c.currentParamDisplay : null, detailText: c.currentParamDisplay.isNotEmpty ? c.currentParamDisplay : null,
...@@ -80,7 +79,7 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -80,7 +79,7 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
statusTags: statusTags, statusTags: statusTags,
roomDevices: roomDevices, roomDevices: roomDevices,
mainPowerOn: detail.deviceControl.roomPowerControl.powerOn, mainPowerOn: detail.deviceControl.roomPowerControl.powerOn,
controlDevices: controlDevices, controlDevices: subDeviceControls,
); );
} }
...@@ -130,34 +129,6 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -130,34 +129,6 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
} }
/// 房间总电源开关 /// 房间总电源开关
Future<void> toggleMainPowerForSwitch(bool value) async {
if (state.isPoweringOn || state.isPoweringOff) return;
// final loadingKey = value ? 'isPoweringOn' : 'isPoweringOff';
emit(state.copyWith(
isPoweringOn: value,
isPoweringOff: !value,
));
try {
if (value) {
await _service.roomPowerOn(roomId: _roomId);
} else {
await _service.roomPowerOff(roomId: _roomId);
}
emit(state.copyWith(
isPoweringOn: false,
isPoweringOff: false,
mainPowerOn: value,
));
} catch (e) {
emit(state.copyWith(
isPoweringOn: false,
isPoweringOff: false,
));
rethrow;
}
}
/// 房间总电源开关
Future<void> toggleMainPower(bool value) async { Future<void> toggleMainPower(bool value) async {
if (state.isPoweringOn || state.isPoweringOff) return; if (state.isPoweringOn || state.isPoweringOff) return;
emit(state.copyWith( emit(state.copyWith(
...@@ -175,6 +146,7 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -175,6 +146,7 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
isPoweringOff: false, isPoweringOff: false,
mainPowerOn: value, mainPowerOn: value,
)); ));
await loadDetail(isLoading: false);
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isPoweringOn: false, isPoweringOn: false,
...@@ -188,19 +160,33 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> { ...@@ -188,19 +160,33 @@ class ServiceRoomCubit extends Cubit<ServiceRoomState> {
Future<void> toggleControlDevice(int index, bool value) async { Future<void> toggleControlDevice(int index, bool value) async {
final devices = state.controlDevices; final devices = state.controlDevices;
if (index < 0 || index >= devices.length) return; if (index < 0 || index >= devices.length) return;
// Note: The API for individual device power control uses deviceId. final device = devices[index];
// However, we don't have deviceId in ControlDevice model yet.
// For now, just update UI state. The device control card in the view // 乐观更新 UI
// navigates to ServiceDeviceDetailRoute for AC control. final oldDevices = devices;
final updatedDevices = List<ControlDevice>.from(devices); final updatedDevices = List<ControlDevice>.from(devices);
updatedDevices[index] = ControlDevice( updatedDevices[index] = ControlDevice(
deviceId: updatedDevices[index].deviceId, deviceId: device.deviceId,
name: updatedDevices[index].name, name: device.name,
icon: updatedDevices[index].icon, icon: device.icon,
isOn: value, isOn: value,
detailText: updatedDevices[index].detailText, detailText: device.detailText,
deviceTypeName: updatedDevices[index].deviceTypeName, deviceTypeName: device.deviceTypeName,
); );
emit(state.copyWith(controlDevices: updatedDevices)); emit(state.copyWith(controlDevices: updatedDevices));
try {
if (value) {
await _service.powerSingleOn(deviceId: device.deviceId);
} else {
await _service.powerSingleOff(deviceId: device.deviceId);
}
await loadDetail(isLoading: false);
} catch (e) {
// 失败回滚
emit(state.copyWith(controlDevices: oldDevices));
rethrow;
} }
}
} }
...@@ -130,7 +130,7 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -130,7 +130,7 @@ class ServiceRoomDetailView extends StatelessWidget {
controlDevices: state.controlDevices, controlDevices: state.controlDevices,
onMainPowerToggle: (value) async { onMainPowerToggle: (value) async {
try { try {
await cubit.toggleMainPowerForSwitch(value); await cubit.toggleMainPower(value);
if (context.mounted) { if (context.mounted) {
showToast(value ? '送电成功' : '断电成功'); showToast(value ? '送电成功' : '断电成功');
} }
...@@ -143,6 +143,7 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -143,6 +143,7 @@ class ServiceRoomDetailView extends StatelessWidget {
onDeviceToggle: (index, value) => onDeviceToggle: (index, value) =>
cubit.toggleControlDevice(index, value), cubit.toggleControlDevice(index, value),
onDeviceTap: (index, device) { onDeviceTap: (index, device) {
/// item click
if (device.name.contains('空调')) { if (device.name.contains('空调')) {
context.pushRoute(ServiceDeviceDetailRoute(deviceId: device.deviceId)); context.pushRoute(ServiceDeviceDetailRoute(deviceId: device.deviceId));
} }
......
...@@ -32,7 +32,16 @@ class RoomBottomButtons extends StatelessWidget { ...@@ -32,7 +32,16 @@ class RoomBottomButtons extends StatelessWidget {
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Center( child: Center(
child: Text( child: isPoweringOn
? SizedBox(
width: 32.w,
height: 32.w,
child: CircularProgressIndicator(
strokeWidth: 3.w,
color: const Color.fromRGBO(66, 165, 245, 1.0),
),
)
: Text(
'送电', '送电',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
...@@ -56,7 +65,16 @@ class RoomBottomButtons extends StatelessWidget { ...@@ -56,7 +65,16 @@ class RoomBottomButtons extends StatelessWidget {
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Center( child: Center(
child: Text( child: isPoweringOff
? SizedBox(
width: 32.w,
height: 32.w,
child: CircularProgressIndicator(
strokeWidth: 3.w,
color: const Color.fromRGBO(229, 241, 255, 1),
),
)
: Text(
'断电', '断电',
style: TextStyle( style: TextStyle(
color: const Color.fromRGBO(100, 116, 139, 1), color: const Color.fromRGBO(100, 116, 139, 1),
......
...@@ -66,8 +66,8 @@ class RoomOverviewCard extends StatelessWidget { ...@@ -66,8 +66,8 @@ class RoomOverviewCard extends StatelessWidget {
return Container( return Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color.fromRGBO(225, 245, 238, 1.0), color: const Color.fromRGBO(229, 241, 255, 1.0),
borderRadius: BorderRadius.circular(12.r), borderRadius: BorderRadius.circular(24.r),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
......
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