Commit e9fe298f authored by 张宏's avatar 张宏

11

parent 9db068bb
...@@ -10,6 +10,7 @@ import 'package:smart_hotel_app/services/auth_service.dart'; ...@@ -10,6 +10,7 @@ import 'package:smart_hotel_app/services/auth_service.dart';
import 'package:smart_hotel_app/utils/http/dio_request.dart'; import 'package:smart_hotel_app/utils/http/dio_request.dart';
import 'package:smart_hotel_app/utils/event_bus.dart'; import 'package:smart_hotel_app/utils/event_bus.dart';
import 'package:smart_hotel_app/utils/storage/storage_service.dart'; import 'package:smart_hotel_app/utils/storage/storage_service.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
...@@ -98,12 +99,7 @@ class _MyAppState extends State<MyApp> { ...@@ -98,12 +99,7 @@ class _MyAppState extends State<MyApp> {
_appRouter.replaceAll([const DefaultLayoutRoute()]); _appRouter.replaceAll([const DefaultLayoutRoute()]);
} }
if (state is AuthTokenExpired) { if (state is AuthTokenExpired) {
_scaffoldMessengerKey.currentState?.showSnackBar( showToast('登录已过期,请重新登录');
const SnackBar(
content: Text('登录已过期,请重新登录'),
backgroundColor: Colors.red,
),
);
_appRouter.replaceAll([LoginRoute()]); _appRouter.replaceAll([LoginRoute()]);
} }
if (state is AuthLoggedOut) { if (state is AuthLoggedOut) {
......
...@@ -6,11 +6,17 @@ class InspectionDeviceRepository { ...@@ -6,11 +6,17 @@ class InspectionDeviceRepository {
Future<ResponseModel<InspectionDeviceListBO>> getList({ Future<ResponseModel<InspectionDeviceListBO>> getList({
required int pageSize, required int pageSize,
required int pageNum, required int pageNum,
int? roomId int? roomId,
String? runStatus,
}) { }) {
return DioRequest.instance.get<InspectionDeviceListBO>( return DioRequest.instance.get<InspectionDeviceListBO>(
'/app/device/inspection', '/app/device/inspection',
queryParameters: {'pageSize': pageSize, 'pageNum': pageNum, "roomId": roomId}, queryParameters: {
'pageSize': pageSize,
'pageNum': pageNum,
'roomId': roomId,
'runStatus': runStatus,
},
fromJsonT: (data) => fromJsonT: (data) =>
InspectionDeviceListBO.fromJson(data as Map<String, dynamic>), InspectionDeviceListBO.fromJson(data as Map<String, dynamic>),
); );
......
...@@ -11,9 +11,14 @@ class InspectionDeviceService { ...@@ -11,9 +11,14 @@ class InspectionDeviceService {
required int pageSize, required int pageSize,
required int pageNum, required int pageNum,
int? roomId, int? roomId,
String? runStatus,
}) async { }) async {
final result = await _repository.getList( final result = await _repository.getList(
pageSize: pageSize, pageNum: pageNum, roomId: roomId); pageSize: pageSize,
pageNum: pageNum,
roomId: roomId,
runStatus: runStatus,
);
if (result.success && result.data != null) { if (result.success && result.data != null) {
return result.data!; return result.data!;
} }
......
import 'dart:ui';
import 'package:fluttertoast/fluttertoast.dart';
void showToast(String msg) {
Fluttertoast.showToast(
msg: msg,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: const Color(0xDD000000),
textColor: const Color(0xFFFFFFFF),
fontSize: 16.0,
);
}
\ No newline at end of file
...@@ -8,6 +8,7 @@ import 'package:smart_hotel_app/views/home/abnormal/cubit/abnormal_state.dart'; ...@@ -8,6 +8,7 @@ import 'package:smart_hotel_app/views/home/abnormal/cubit/abnormal_state.dart';
import 'package:smart_hotel_app/views/home/abnormal/widget/alarm_info_block.dart'; import 'package:smart_hotel_app/views/home/abnormal/widget/alarm_info_block.dart';
import 'package:smart_hotel_app/views/home/abnormal/widget/temperature_block.dart'; import 'package:smart_hotel_app/views/home/abnormal/widget/temperature_block.dart';
import 'package:smart_hotel_app/views/home/abnormal/widget/temperature_char_block.dart'; import 'package:smart_hotel_app/views/home/abnormal/widget/temperature_char_block.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
@RoutePage() @RoutePage()
class AbnormalDetailView extends StatelessWidget { class AbnormalDetailView extends StatelessWidget {
...@@ -169,15 +170,11 @@ class AbnormalDetailView extends StatelessWidget { ...@@ -169,15 +170,11 @@ class AbnormalDetailView extends StatelessWidget {
try { try {
await cubit.handleConfirm(); await cubit.handleConfirm();
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作成功');
const SnackBar(content: Text('操作成功')),
);
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作失败: $e');
SnackBar(content: Text('操作失败: $e')),
);
} }
} }
} }
......
class DeviceInfo { import 'package:equatable/equatable.dart';
class DeviceInfo extends Equatable {
final String deviceName; final String deviceName;
final String deviceId; final String deviceId;
final String location; final String location;
...@@ -22,9 +24,26 @@ class DeviceInfo { ...@@ -22,9 +24,26 @@ class DeviceInfo {
required this.powerData, required this.powerData,
required this.tempData, required this.tempData,
}); });
@override
List<Object?> get props => [
deviceName,
deviceId,
location,
status,
voltage,
current,
power,
temperature,
powerData,
tempData,
];
} }
class DeviceState { /// copyWith 中用作 "未传参" 哨兵,区分 "保持原值" 和 "显式设为 null"。
const Object _unset = Object();
class DeviceState extends Equatable {
final bool isLoading; final bool isLoading;
final String? error; final String? error;
final DeviceInfo? deviceInfo; final DeviceInfo? deviceInfo;
...@@ -43,19 +62,33 @@ class DeviceState { ...@@ -43,19 +62,33 @@ class DeviceState {
DeviceState copyWith({ DeviceState copyWith({
bool? isLoading, bool? isLoading,
String? error, Object? error = _unset,
DeviceInfo? deviceInfo, Object? deviceInfo = _unset,
bool? isPoweringOn, bool? isPoweringOn,
bool? isPoweringOff, bool? isPoweringOff,
String? operationMessage, Object? operationMessage = _unset,
}) { }) {
return DeviceState( return DeviceState(
isLoading: isLoading ?? this.isLoading, isLoading: isLoading ?? this.isLoading,
error: error ?? this.error, error: identical(error, _unset) ? this.error : error as String?,
deviceInfo: deviceInfo ?? this.deviceInfo, deviceInfo: identical(deviceInfo, _unset)
? this.deviceInfo
: deviceInfo as DeviceInfo?,
isPoweringOn: isPoweringOn ?? this.isPoweringOn, isPoweringOn: isPoweringOn ?? this.isPoweringOn,
isPoweringOff: isPoweringOff ?? this.isPoweringOff, isPoweringOff: isPoweringOff ?? this.isPoweringOff,
operationMessage: operationMessage ?? this.operationMessage, operationMessage: identical(operationMessage, _unset)
? this.operationMessage
: operationMessage as String?,
); );
} }
@override
List<Object?> get props => [
isLoading,
error,
deviceInfo,
isPoweringOn,
isPoweringOff,
operationMessage,
];
} }
\ No newline at end of file
...@@ -7,6 +7,7 @@ import 'package:smart_hotel_app/views/home/device/cubit/device_state.dart'; ...@@ -7,6 +7,7 @@ import 'package:smart_hotel_app/views/home/device/cubit/device_state.dart';
import 'package:smart_hotel_app/views/home/device/widget/device_parms_block.dart'; import 'package:smart_hotel_app/views/home/device/widget/device_parms_block.dart';
import 'package:smart_hotel_app/views/home/device/widget/power_char_block.dart'; import 'package:smart_hotel_app/views/home/device/widget/power_char_block.dart';
import 'package:smart_hotel_app/views/home/device/widget/state_info_block.dart'; import 'package:smart_hotel_app/views/home/device/widget/state_info_block.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
@RoutePage() @RoutePage()
class DeviceDetailView extends StatelessWidget { class DeviceDetailView extends StatelessWidget {
...@@ -19,14 +20,12 @@ class DeviceDetailView extends StatelessWidget { ...@@ -19,14 +20,12 @@ class DeviceDetailView extends StatelessWidget {
return BlocProvider( return BlocProvider(
create: (_) => DeviceCubit(deviceId: deviceId), create: (_) => DeviceCubit(deviceId: deviceId),
child: BlocListener<DeviceCubit, DeviceState>( child: BlocListener<DeviceCubit, DeviceState>(
listenWhen: (prev, curr) =>
curr.operationMessage != null &&
prev.operationMessage != curr.operationMessage,
listener: (context, state) { listener: (context, state) {
final message = state.operationMessage; showToast(state.operationMessage!);
if (message != null) { context.read<DeviceCubit>().clearOperationMessage();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
context.read<DeviceCubit>().clearOperationMessage();
}
}, },
child: Scaffold( child: Scaffold(
backgroundColor: const Color.fromRGBO(242, 243, 245, 1), backgroundColor: const Color.fromRGBO(242, 243, 245, 1),
......
...@@ -106,6 +106,7 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV ...@@ -106,6 +106,7 @@ class _HomeViewState extends State<HomeView> with AutoRouteAwareStateMixin<HomeV
]); ]);
case 'voltage': case 'voltage':
case 'current': case 'current':
case 'device':
case 'power': case 'power':
blocks.addAll([ blocks.addAll([
SizedBox(height: 20.h), SizedBox(height: 20.h),
......
...@@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; ...@@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smart_hotel_app/repositories/alert_detail_repository.dart'; import 'package:smart_hotel_app/repositories/alert_detail_repository.dart';
import 'package:smart_hotel_app/services/alert_detail_service.dart'; import 'package:smart_hotel_app/services/alert_detail_service.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/utils/toast_utils.dart';
class TemperatureBlock extends StatelessWidget { class TemperatureBlock extends StatelessWidget {
final int alertId; final int alertId;
...@@ -339,16 +340,12 @@ class TemperatureBlock extends StatelessWidget { ...@@ -339,16 +340,12 @@ class TemperatureBlock extends StatelessWidget {
AlertDetailService(repository: AlertDetailRepository()); AlertDetailService(repository: AlertDetailRepository());
await service.handleAlert(alertId: alertId); await service.handleAlert(alertId: alertId);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作成功');
const SnackBar(content: Text('操作成功')),
);
context.read<HomeIndexCubit>().reloadDashboard(); context.read<HomeIndexCubit>().reloadDashboard();
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作失败: $e');
SnackBar(content: Text('操作失败: $e')),
);
} }
} }
} }
......
...@@ -6,6 +6,7 @@ import 'package:smart_hotel_app/repositories/alert_detail_repository.dart'; ...@@ -6,6 +6,7 @@ import 'package:smart_hotel_app/repositories/alert_detail_repository.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
import 'package:smart_hotel_app/services/alert_detail_service.dart'; import 'package:smart_hotel_app/services/alert_detail_service.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/utils/toast_utils.dart';
class VoltageOperateBlock extends StatelessWidget { class VoltageOperateBlock extends StatelessWidget {
final int alertId; final int alertId;
...@@ -278,16 +279,12 @@ class VoltageOperateBlock extends StatelessWidget { ...@@ -278,16 +279,12 @@ class VoltageOperateBlock extends StatelessWidget {
AlertDetailService(repository: AlertDetailRepository()); AlertDetailService(repository: AlertDetailRepository());
await service.handleAlert(alertId: alertId); await service.handleAlert(alertId: alertId);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作成功');
const SnackBar(content: Text('操作成功')),
);
context.read<HomeIndexCubit>().reloadDashboard(); context.read<HomeIndexCubit>().reloadDashboard();
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作失败: $e');
SnackBar(content: Text('操作失败: $e')),
);
} }
} }
} }
......
...@@ -10,7 +10,10 @@ class InspectionCubit extends Cubit<InspectionState> { ...@@ -10,7 +10,10 @@ class InspectionCubit extends Cubit<InspectionState> {
final InspectionRoomService _roomService; final InspectionRoomService _roomService;
final InspectionDeviceService _deviceService; final InspectionDeviceService _deviceService;
static const int _pageSize = 20; static const int pageSize = 20;
/// 完整房间列表缓存,用于在切换 Tab 时按 runStatus 重新过滤
List<InspectionRoomBO> _allRoomsRaw = const [];
InspectionCubit({ InspectionCubit({
InspectionRoomService? roomService, InspectionRoomService? roomService,
...@@ -27,19 +30,21 @@ class InspectionCubit extends Cubit<InspectionState> { ...@@ -27,19 +30,21 @@ class InspectionCubit extends Cubit<InspectionState> {
Future<void> initData() async { Future<void> initData() async {
try { try {
final rooms = await _roomService.getRooms(); final rooms = await _roomService.getRooms();
final roomsMap = <int, String>{}; _allRoomsRaw = rooms;
for (final r in rooms) {
roomsMap[r.roomId] = r.roomNumber;
}
final tabCounts = _computeTabCounts(rooms); final tabCounts = _computeTabCounts(rooms);
final filteredRooms = _filterRooms(rooms, state.selectedTab);
final firstRoomIds = rooms.isNotEmpty ? [rooms.first.roomId] : <int>[]; // 仅当首次进入(之前没有选过房间)时,默认选中过滤后的第一个房间
final initialRoomIds = filteredRooms.isNotEmpty
? [filteredRooms.entries.first.key]
: <int>[];
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
error: null, error: null,
allRooms: roomsMap, allRooms: filteredRooms,
selectedRoomIds: firstRoomIds, selectedRoomIds: initialRoomIds,
tabCounts: tabCounts, tabCounts: tabCounts,
)); ));
} catch (e) { } catch (e) {
...@@ -57,10 +62,17 @@ class InspectionCubit extends Cubit<InspectionState> { ...@@ -57,10 +62,17 @@ class InspectionCubit extends Cubit<InspectionState> {
: null; : null;
final result = await _deviceService.getList( final result = await _deviceService.getList(
pageSize: _pageSize, pageSize: pageSize,
pageNum: pageKey, pageNum: pageKey,
roomId: roomId, roomId: roomId,
runStatus: state.selectedTab.runStatus,
); );
// 首页时记录总数,供翻页判断是否到底
if (pageKey == 1) {
emit(state.copyWith(totalCount: result.total));
}
return result.data return result.data
.map((e) => InspectionDevice.fromInspectionDeviceBO(e)) .map((e) => InspectionDevice.fromInspectionDeviceBO(e))
.toList(); .toList();
...@@ -89,8 +101,54 @@ class InspectionCubit extends Cubit<InspectionState> { ...@@ -89,8 +101,54 @@ class InspectionCubit extends Cubit<InspectionState> {
}; };
} }
/// 根据 Tab 的 runStatus 过滤房间:
/// - total / runStatus 为 null → 返回全部
/// - 其他 → 仅保留对应状态计数 > 0 的房间
Map<int, String> _filterRooms(
List<InspectionRoomBO> rooms, DeviceStatusTab tab) {
final result = <int, String>{};
for (final room in rooms) {
if (_roomMatchesTab(room, tab)) {
result[room.roomId] = room.roomNumber;
}
}
return result;
}
bool _roomMatchesTab(InspectionRoomBO room, DeviceStatusTab tab) {
switch (tab) {
case DeviceStatusTab.total:
return true;
case DeviceStatusTab.on:
return room.runStatus.normal > 0;
case DeviceStatusTab.off:
case DeviceStatusTab.offline:
return room.runStatus.offline > 0;
case DeviceStatusTab.alarm:
return room.runStatus.warning > 0;
case DeviceStatusTab.fault:
return room.runStatus.fault > 0;
}
}
void selectTab(DeviceStatusTab tab) { void selectTab(DeviceStatusTab tab) {
emit(state.copyWith(selectedTab: tab)); final filteredRooms = _filterRooms(_allRoomsRaw, tab);
// 过滤后剔除已不存在的已选房间;若全被剔除则默认选第一个
final keptSelection = state.selectedRoomIds
.where(filteredRooms.containsKey)
.toList();
final newSelectedRoomIds = keptSelection.isNotEmpty
? keptSelection
: (filteredRooms.isNotEmpty
? [filteredRooms.entries.first.key]
: <int>[]);
emit(state.copyWith(
selectedTab: tab,
allRooms: filteredRooms,
selectedRoomIds: newSelectedRoomIds,
));
} }
void toggleRoom(int roomId) { void toggleRoom(int roomId) {
......
...@@ -4,6 +4,27 @@ import 'package:smart_hotel_app/models/bo/inspection_device_bo.dart'; ...@@ -4,6 +4,27 @@ import 'package:smart_hotel_app/models/bo/inspection_device_bo.dart';
enum DeviceStatusTab { total, on, off, offline, alarm, fault } enum DeviceStatusTab { total, on, off, offline, alarm, fault }
extension DeviceStatusTabRunStatus on DeviceStatusTab {
/// 映射为接口 runStatus 入参:
/// online=开启(绿) offline=关闭/离线(灰) warning=告警(黄) fault=故障(红)
String? get runStatus {
switch (this) {
case DeviceStatusTab.total:
return null;
case DeviceStatusTab.on:
return 'online';
case DeviceStatusTab.off:
return 'offline';
case DeviceStatusTab.offline:
return 'offline';
case DeviceStatusTab.alarm:
return 'warning';
case DeviceStatusTab.fault:
return 'fault';
}
}
}
class InspectionDevice { class InspectionDevice {
final String id; final String id;
final IconData icon; final IconData icon;
...@@ -89,6 +110,7 @@ class InspectionState extends Equatable { ...@@ -89,6 +110,7 @@ class InspectionState extends Equatable {
final List<int> selectedRoomIds; final List<int> selectedRoomIds;
final Map<int, String> allRooms; final Map<int, String> allRooms;
final Map<DeviceStatusTab, int> tabCounts; final Map<DeviceStatusTab, int> tabCounts;
final int totalCount;
const InspectionState({ const InspectionState({
this.isLoading = false, this.isLoading = false,
...@@ -104,6 +126,7 @@ class InspectionState extends Equatable { ...@@ -104,6 +126,7 @@ class InspectionState extends Equatable {
DeviceStatusTab.alarm: 0, DeviceStatusTab.alarm: 0,
DeviceStatusTab.fault: 0, DeviceStatusTab.fault: 0,
}, },
this.totalCount = 0,
}); });
InspectionState copyWith({ InspectionState copyWith({
...@@ -113,6 +136,7 @@ class InspectionState extends Equatable { ...@@ -113,6 +136,7 @@ class InspectionState extends Equatable {
List<int>? selectedRoomIds, List<int>? selectedRoomIds,
Map<int, String>? allRooms, Map<int, String>? allRooms,
Map<DeviceStatusTab, int>? tabCounts, Map<DeviceStatusTab, int>? tabCounts,
int? totalCount,
}) { }) {
return InspectionState( return InspectionState(
isLoading: isLoading ?? this.isLoading, isLoading: isLoading ?? this.isLoading,
...@@ -121,6 +145,7 @@ class InspectionState extends Equatable { ...@@ -121,6 +145,7 @@ class InspectionState extends Equatable {
selectedRoomIds: selectedRoomIds ?? this.selectedRoomIds, selectedRoomIds: selectedRoomIds ?? this.selectedRoomIds,
allRooms: allRooms ?? this.allRooms, allRooms: allRooms ?? this.allRooms,
tabCounts: tabCounts ?? this.tabCounts, tabCounts: tabCounts ?? this.tabCounts,
totalCount: totalCount ?? this.totalCount,
); );
} }
...@@ -132,5 +157,6 @@ class InspectionState extends Equatable { ...@@ -132,5 +157,6 @@ class InspectionState extends Equatable {
selectedRoomIds, selectedRoomIds,
allRooms, allRooms,
tabCounts, tabCounts,
totalCount,
]; ];
} }
\ No newline at end of file
...@@ -31,19 +31,25 @@ class _InspectionDetailBody extends StatefulWidget { ...@@ -31,19 +31,25 @@ class _InspectionDetailBody extends StatefulWidget {
class _InspectionDetailBodyState extends State<_InspectionDetailBody> { class _InspectionDetailBodyState extends State<_InspectionDetailBody> {
late final PagingController<int, InspectionDevice> _pagingController; late final PagingController<int, InspectionDevice> _pagingController;
late final InspectionCubit _cubit;
DeviceStatusTab? _lastTab; DeviceStatusTab? _lastTab;
List<int>? _lastRoomIds; List<int>? _lastRoomIds;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_cubit = context.read<InspectionCubit>();
_pagingController = PagingController<int, InspectionDevice>( _pagingController = PagingController<int, InspectionDevice>(
getNextPageKey: (state) { getNextPageKey: (state) {
if (state.keys == null || state.keys!.isEmpty) return 1; if (state.keys == null || state.keys!.isEmpty) return 1;
return state.lastPageIsEmpty ? null : state.nextIntPageKey; final total = _cubit.state.totalCount;
final nextKey = state.nextIntPageKey;
if ((nextKey - 1) * InspectionCubit.pageSize >= total) {
return null;
}
return nextKey;
}, },
fetchPage: (pageKey) => fetchPage: (pageKey) => _cubit.fetchPage(pageKey),
context.read<InspectionCubit>().fetchPage(pageKey),
); );
} }
......
...@@ -40,88 +40,82 @@ class FilterPanel extends StatelessWidget { ...@@ -40,88 +40,82 @@ class FilterPanel extends StatelessWidget {
} }
Widget _buildStatusTabs() { Widget _buildStatusTabs() {
return Column( return Row(
children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
Row( children: DeviceStatusTab.values.map((tab) {
mainAxisAlignment: MainAxisAlignment.spaceBetween, final isSelected = selectedTab == tab;
children: DeviceStatusTab.values.map((tab) { final count = tabCounts[tab] ?? 0;
final isSelected = selectedTab == tab; return Expanded(
final count = tabCounts[tab] ?? 0; child: GestureDetector(
return Expanded( behavior: HitTestBehavior.opaque,
child: GestureDetector( onTap: () => onTabSelected(tab),
onTap: () => onTabSelected(tab), child: Padding(
child: Stack( padding: EdgeInsets.symmetric(vertical: 8.h),
clipBehavior: Clip.none, child: Column(
alignment: Alignment.center, mainAxisSize: MainAxisSize.min,
children: [ children: [
Padding( Stack(
padding: EdgeInsets.only(top: 8.h), clipBehavior: Clip.none,
child: Text( children: [
_getTabLabel(tab), Padding(
style: TextStyle( padding: EdgeInsets.only(right: 16.w),
fontSize: 28.sp, child: Text(
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, _getTabLabel(tab),
color: isSelected style: TextStyle(
? const Color.fromRGBO(66, 165, 245, 1.0) fontSize: isSelected ? 32.sp : 28.sp,
: const Color.fromRGBO(100, 116, 139, 1.0), fontWeight: isSelected
? FontWeight.bold
: FontWeight.normal,
color: isSelected
? const Color.fromRGBO(66, 165, 245, 1.0)
: const Color.fromRGBO(100, 116, 139, 1.0),
height: 1.0,
),
), ),
), ),
),
if (count > 0)
Positioned( Positioned(
top: 0, top: -20.h,
right: -8.w, right: -18.h,
child: Container( child: Container(
width: 28.w, constraints: BoxConstraints(
height: 28.h, minWidth: 32.w,
minHeight: 32.w,
),
padding:
EdgeInsets.symmetric(horizontal: 6.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getTabColor(tab), color: _getTabColor(tab),
borderRadius: BorderRadius.circular(12.r), shape: BoxShape.circle,
), ),
child: Center( alignment: Alignment.center,
child: Text( child: Text(
count.toString(), count.toString(),
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 14.sp,
fontWeight: FontWeight.bold, color: Colors.white,
color: Colors.white, height: 1.0,
),
), ),
), ),
), ),
), ),
], ],
), ),
), SizedBox(height: 12.h),
); AnimatedContainer(
}).toList(),
),
SizedBox(height: 12.h),
Container(
height: 4.h,
width: double.infinity,
color: const Color.fromRGBO(242, 243, 245, 1),
child: Stack(
children: [
LayoutBuilder(
builder: (context, constraints) {
final segmentWidth = constraints.maxWidth / DeviceStatusTab.values.length;
final selectedIndex = DeviceStatusTab.values.indexOf(selectedTab);
return AnimatedPositioned(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
left: selectedIndex * segmentWidth, height: 4.h,
width: segmentWidth, width: isSelected ? 48.w : 0,
child: Container( decoration: BoxDecoration(
height: 4.h,
color: const Color.fromRGBO(66, 165, 245, 1.0), color: const Color.fromRGBO(66, 165, 245, 1.0),
borderRadius: BorderRadius.circular(2.r),
), ),
); ),
}, ],
), ),
], ),
), ),
), );
], }).toList(),
); );
} }
......
...@@ -8,6 +8,7 @@ import 'package:smart_hotel_app/blocs/auth/auth_state.dart'; ...@@ -8,6 +8,7 @@ import 'package:smart_hotel_app/blocs/auth/auth_state.dart';
import 'package:smart_hotel_app/repositories/inspection_device_repository.dart'; import 'package:smart_hotel_app/repositories/inspection_device_repository.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
import 'package:smart_hotel_app/services/inspection_device_service.dart'; import 'package:smart_hotel_app/services/inspection_device_service.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
class StartInspectionButton extends StatelessWidget { class StartInspectionButton extends StatelessWidget {
final String deviceId; final String deviceId;
...@@ -75,9 +76,7 @@ class StartInspectionButton extends StatelessWidget { ...@@ -75,9 +76,7 @@ class StartInspectionButton extends StatelessWidget {
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
context.popRoute(); context.popRoute();
ScaffoldMessenger.of(context).showSnackBar( showToast('巡检失败: $e');
SnackBar(content: Text('巡检失败: $e')),
);
} }
} }
}, },
......
...@@ -12,7 +12,7 @@ class RoomReportCubit extends Cubit<RoomReportState> { ...@@ -12,7 +12,7 @@ class RoomReportCubit extends Cubit<RoomReportState> {
loadData(); loadData();
} }
Future<void> loadData({int? floorId}) async { Future<void> loadData({int floorId = 1}) async {
emit(state.copyWith(isLoading: true, error: null)); emit(state.copyWith(isLoading: true, error: null));
try { try {
final overview = await _service.getOverview(floorId); final overview = await _service.getOverview(floorId);
......
...@@ -6,6 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:smart_hotel_app/routes/app_router.gr.dart'; import 'package:smart_hotel_app/routes/app_router.gr.dart';
import 'package:smart_hotel_app/views/service/index/cubit/service_index_state.dart'; import 'package:smart_hotel_app/views/service/index/cubit/service_index_state.dart';
import 'package:smart_hotel_app/views/service/index/widget/area_device_list.dart'; import 'package:smart_hotel_app/views/service/index/widget/area_device_list.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
class RoomManagementBlock extends StatefulWidget { class RoomManagementBlock extends StatefulWidget {
const RoomManagementBlock({super.key}); const RoomManagementBlock({super.key});
...@@ -517,15 +518,11 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> { ...@@ -517,15 +518,11 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
try { try {
await cubit.powerOnRoom(_selectedRoom!); await cubit.powerOnRoom(_selectedRoom!);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('送电成功');
const SnackBar(content: Text('送电成功')),
);
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('送电失败: $e');
SnackBar(content: Text('送电失败: $e')),
);
} }
} }
} }
...@@ -561,15 +558,11 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> { ...@@ -561,15 +558,11 @@ class _RoomManagementBlockState extends State<RoomManagementBlock> {
try { try {
await cubit.powerOffRoom(_selectedRoom!); await cubit.powerOffRoom(_selectedRoom!);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('断电成功');
const SnackBar(content: Text('断电成功')),
);
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('断电失败: $e');
SnackBar(content: Text('断电失败: $e')),
);
} }
} }
} }
......
...@@ -9,6 +9,7 @@ import 'package:smart_hotel_app/views/service/room/widget/room_overview_card.dar ...@@ -9,6 +9,7 @@ import 'package:smart_hotel_app/views/service/room/widget/room_overview_card.dar
import 'package:smart_hotel_app/views/service/room/widget/room_device_status_card.dart'; import 'package:smart_hotel_app/views/service/room/widget/room_device_status_card.dart';
import 'package:smart_hotel_app/views/service/room/widget/device_control_card.dart'; import 'package:smart_hotel_app/views/service/room/widget/device_control_card.dart';
import 'package:smart_hotel_app/views/service/room/widget/room_bottom_buttons.dart'; import 'package:smart_hotel_app/views/service/room/widget/room_bottom_buttons.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
@RoutePage() @RoutePage()
class ServiceRoomDetailView extends StatelessWidget { class ServiceRoomDetailView extends StatelessWidget {
...@@ -105,24 +106,18 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -105,24 +106,18 @@ class ServiceRoomDetailView extends StatelessWidget {
try { try {
await cubit.toggleMainPowerForSwitch(value); await cubit.toggleMainPowerForSwitch(value);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast(value ? '送电成功' : '断电成功');
SnackBar(
content: Text(value ? '送电成功' : '断电成功'),
),
);
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('操作失败: $e');
SnackBar(content: Text('操作失败: $e')),
);
} }
} }
}, },
onDeviceToggle: (index, value) => onDeviceToggle: (index, value) =>
cubit.toggleControlDevice(index, value), cubit.toggleControlDevice(index, value),
onDeviceTap: (index, device) { onDeviceTap: (index, device) {
if (device.deviceTypeName == '空调' || device.deviceTypeName?.contains('空调') == true) { if (device.name == '空调' || device.name?.contains('空调') == true) {
context.pushRoute(ServiceDeviceDetailRoute(deviceId: device.deviceId)); context.pushRoute(ServiceDeviceDetailRoute(deviceId: device.deviceId));
} }
}, },
...@@ -134,15 +129,11 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -134,15 +129,11 @@ class ServiceRoomDetailView extends StatelessWidget {
try { try {
await cubit.toggleMainPower(true); await cubit.toggleMainPower(true);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('送电成功');
const SnackBar(content: Text('送电成功')),
);
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('送电失败: $e');
SnackBar(content: Text('送电失败: $e')),
);
} }
} }
}, },
...@@ -150,15 +141,11 @@ class ServiceRoomDetailView extends StatelessWidget { ...@@ -150,15 +141,11 @@ class ServiceRoomDetailView extends StatelessWidget {
try { try {
await cubit.toggleMainPower(false); await cubit.toggleMainPower(false);
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('断电成功');
const SnackBar(content: Text('断电成功')),
);
} }
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( showToast('断电失败: $e');
SnackBar(content: Text('断电失败: $e')),
);
} }
} }
}, },
......
...@@ -404,10 +404,10 @@ packages: ...@@ -404,10 +404,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fluttertoast name: fluttertoast
sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8" sha256: "7903c9d5339173497bfecbc23bc4212f5a87e0edfac2e1693fb74465ea67da7e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.2.14" version: "9.1.0"
frontend_server_client: frontend_server_client:
dependency: transitive dependency: transitive
description: description:
...@@ -942,5 +942,5 @@ packages: ...@@ -942,5 +942,5 @@ packages:
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.10.3 <4.0.0" dart: ">=3.11.0 <4.0.0"
flutter: ">=3.38.4" flutter: ">=3.41.0"
...@@ -42,7 +42,7 @@ dependencies: ...@@ -42,7 +42,7 @@ dependencies:
flutter_bloc: ^8.1.5 flutter_bloc: ^8.1.5
equatable: ^2.0.5 equatable: ^2.0.5
flutter_screenutil: ^5.9.3 flutter_screenutil: ^5.9.3
fluttertoast: ^8.2.5 fluttertoast: ^9.1.0
loading_animation_widget: ^1.3.0 loading_animation_widget: ^1.3.0
# fl_chart: ^1.2.0 # fl_chart: ^1.2.0
flutter_switch: ^0.3.2 flutter_switch: ^0.3.2
......
# 智慧酒店 App 接口对接方案 # 智慧酒店 App 接口对接方案
...@@ -1240,6 +1240,7 @@ class xxxBO extends Equatable { ...@@ -1240,6 +1240,7 @@ class xxxBO extends Equatable {
求体: 求体:
{ {
"roomId":0, "roomId":0,
"runStatus":String,// 运行状态码,与入参保持一致:online=开启(绿) offline=关闭/离线(灰) warning=告警(黄) fault=故障(红)
"pageSize": 20, "pageSize": 20,
"pageNum": 1 "pageNum": 1
} }
......
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