Commit 59e6cf59 authored by huqu's avatar huqu

fix bugs

parent 1244f87e
......@@ -341,10 +341,10 @@ class AreaDeviceBO extends Equatable {
class RoomStatusBO extends Equatable {
final int roomId;
final String roomNumber;
final String occupancyStatus;
final String roomStatus;
final String cleanStatus;
final String devicePowerStatus;
final String occupancyStatus;//房间有无人状态,0=无人 1=有人
final String roomStatus;//房间状态,0=无人 1=有人
final String cleanStatus;//清洁灯状态,0=待清洁 2=已完成
final String devicePowerStatus;//设备开关状态 0=关 1=开
const RoomStatusBO({
required this.roomId,
......
import 'dart:convert';
import '../repositories/inspection_device_repository.dart';
import '../models/bo/inspection_device_bo.dart';
......@@ -37,9 +39,28 @@ class InspectionDeviceService {
required int deviceId,
required int inspectorId,
}) async {
List<Map<String, dynamic>> list = [
{
'name': '检查输入电压是否正常',
'value': '正常',
'status': 2,
},
{
'name': '确认设备是否正常运行',
'value': '正常',
'status': 2,
},
{
'name': '若异常,请联系电工',
'value': '正常',
'status': 2,
},
];
final result = await _repository.startInspection({
'deviceId': deviceId,
'inspectorId': inspectorId,
'remark': '巡检完成',//后端要先写死
'items_detail': jsonEncode(list),//后端要先写死
});
if (result.success && result.data != null) {
return result.data!;
......
......@@ -52,7 +52,7 @@ class AbnormalDetailView extends StatelessWidget {
body: BlocBuilder<AbnormalCubit, AbnormalState>(
builder: (context, state) {
if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0)));
}
if (state.error != null) {
return Center(
......@@ -121,7 +121,7 @@ class AbnormalDetailView extends StatelessWidget {
height: 32.sp,
child: const CircularProgressIndicator(
strokeWidth: 3,
color: Color.fromRGBO(237, 245, 255, 1),
color: Color.fromRGBO(66, 165, 245, 1.0),
),
)
: Text(
......
......@@ -111,6 +111,19 @@ class _AbnormalListBodyState extends State<_AbnormalListBody> {
state: pagingState,
fetchNextPage: fetchNextPage,
builderDelegate: PagedChildBuilderDelegate<AlarmItem>(
firstPageProgressIndicatorBuilder: (_) => const Center(
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
newPageProgressIndicatorBuilder: (_) => const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
),
firstPageErrorIndicatorBuilder: (_) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
......
......@@ -52,7 +52,7 @@ class DeviceDetailView extends StatelessWidget {
body: BlocBuilder<DeviceCubit, DeviceState>(
builder: (context, state) {
if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0)));
}
if (state.error != null) {
return Center(
......@@ -120,7 +120,7 @@ class DeviceDetailView extends StatelessWidget {
height: 32.sp,
child: const CircularProgressIndicator(
strokeWidth: 3,
color: Color.fromRGBO(237, 245, 255, 1),
color: Color.fromRGBO(66, 165, 245, 1.0),
),
)
: Text(
......@@ -157,7 +157,7 @@ class DeviceDetailView extends StatelessWidget {
height: 32.sp,
child: const CircularProgressIndicator(
strokeWidth: 3,
color: Color.fromRGBO(100, 116, 139, 1),
color: Color.fromRGBO(66, 165, 245, 1.0),
),
)
: Text(
......
......@@ -2,17 +2,26 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:smart_hotel_app/models/bo/alert_dashboard_bo.dart';
import 'package:smart_hotel_app/repositories/alert_dashboard_repository.dart';
import 'package:smart_hotel_app/repositories/alert_detail_repository.dart';
import 'package:smart_hotel_app/services/alert_dashboard_service.dart';
import 'package:smart_hotel_app/services/alert_detail_service.dart';
import 'package:smart_hotel_app/views/home/index/cubit/home_index_state.dart';
class HomeIndexCubit extends Cubit<HomeIndexState> {
final AlertDashboardService _service;
final AlertDetailService _alertDetailService;
HomeIndexCubit({AlertDashboardService? service})
: _service = service ??
HomeIndexCubit({
AlertDashboardService? service,
AlertDetailService? alertDetailService,
}) : _service = service ??
AlertDashboardService(
repository: AlertDashboardRepository(),
),
_alertDetailService = alertDetailService ??
AlertDetailService(
repository: AlertDetailRepository(),
),
super(const HomeIndexState()) {
loadDashboard();
}
......@@ -31,6 +40,20 @@ class HomeIndexCubit extends Cubit<HomeIndexState> {
loadDashboard();
}
/// 处理告警
Future<void> handleAlert(int alertId) async {
if (state.isHandlingAlert) return;
emit(state.copyWith(isHandlingAlert: true));
try {
await _alertDetailService.handleAlert(alertId: alertId);
emit(state.copyWith(isHandlingAlert: false));
await reloadDashboard();
} catch (e) {
emit(state.copyWith(isHandlingAlert: false, error: e.toString()));
rethrow;
}
}
void _emitFromDashboard(AlertDashboardBO dashboard) {
emit(state.copyWith(
isLoading: false,
......
......@@ -19,7 +19,10 @@ class EquipmentItem {
}
class HomeIndexState extends Equatable {
static const _nothing = Object();
final bool isLoading;
final bool isHandlingAlert;
final String? error;
final int highAlarmCount;
final int mediumAlarmCount;
......@@ -29,6 +32,7 @@ class HomeIndexState extends Equatable {
const HomeIndexState({
this.isLoading = false,
this.isHandlingAlert = false,
this.error,
this.highAlarmCount = 0,
this.mediumAlarmCount = 0,
......@@ -39,7 +43,8 @@ class HomeIndexState extends Equatable {
HomeIndexState copyWith({
bool? isLoading,
String? error,
bool? isHandlingAlert,
Object? error = _nothing,
int? highAlarmCount,
int? mediumAlarmCount,
int? onlineDeviceCount,
......@@ -48,7 +53,8 @@ class HomeIndexState extends Equatable {
}) {
return HomeIndexState(
isLoading: isLoading ?? this.isLoading,
error: error,
isHandlingAlert: isHandlingAlert ?? this.isHandlingAlert,
error: identical(error, _nothing) ? this.error : error as String?,
highAlarmCount: highAlarmCount ?? this.highAlarmCount,
mediumAlarmCount: mediumAlarmCount ?? this.mediumAlarmCount,
onlineDeviceCount: onlineDeviceCount ?? this.onlineDeviceCount,
......@@ -60,6 +66,7 @@ class HomeIndexState extends Equatable {
@override
List<Object?> get props => [
isLoading,
isHandlingAlert,
error,
highAlarmCount,
mediumAlarmCount,
......
......@@ -12,30 +12,30 @@ class EquipmentListBlock extends StatelessWidget {
required this.equipmentList,
});
Widget _buildEquipmentItem(EquipmentItem item) {
Widget _buildEquipmentItem(EquipmentItem item, bool isLast) {
return Container(
padding: EdgeInsets.symmetric(vertical: 16.h),
decoration: BoxDecoration(
border: Border(
border: !isLast ? Border(
bottom: BorderSide(
color: const Color.fromRGBO(235, 235, 235, 1.0),
width: 1.w,
),
width: 1.h,
),
) : null,
),
child: Row(
children: [
Container(
width: 64.w,
height: 66.h,
height: 53.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: const Color.fromRGBO(66, 165, 245, 1.0),
width: 2.w,
style: BorderStyle.solid,
),
color: const Color.fromRGBO(229, 241, 255, 1.0),
borderRadius: BorderRadius.circular(8.r),
// border: Border.all(
// color: const Color.fromRGBO(66, 165, 245, 1.0),
// width: 2.w,
// style: BorderStyle.solid,
// ),
),
child: Icon(
item.icon,
......@@ -47,6 +47,7 @@ class EquipmentListBlock extends StatelessWidget {
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 5.h,
children: [
Transform.translate(
offset: Offset(0, 2.h),
......@@ -59,7 +60,6 @@ class EquipmentListBlock extends StatelessWidget {
),
),
),
SizedBox(height: 4.h),
Text(
item.subtitle,
style: TextStyle(
......@@ -85,11 +85,12 @@ class EquipmentListBlock extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
spacing: 12.h,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
......@@ -111,21 +112,20 @@ class EquipmentListBlock extends StatelessWidget {
Text(
'查看全部',
style: TextStyle(
fontSize: 24.sp,
fontSize: 28.sp,
color: const Color.fromRGBO(66, 165, 245, 1.0),
),
),
Icon(
Icons.chevron_right,
color: const Color.fromRGBO(66, 165, 245, 1.0),
size: 24.sp,
size: 30.sp,
),
],
),
),
],
),
SizedBox(height: 12.h),
Container(
decoration: BoxDecoration(
color: Colors.white,
......@@ -133,7 +133,13 @@ class EquipmentListBlock extends StatelessWidget {
),
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
children: equipmentList.take(5).map((item) => _buildEquipmentItem(item)).toList(),
// children: equipmentList.take(5).map((item) => _buildEquipmentItem(item)).toList(),
children: equipmentList.take(5).toList().asMap().entries.map((entry) {
int index = entry.key;
var item = entry.value;
bool isLast = index == equipmentList.take(5).length - 1;
return _buildEquipmentItem(item, isLast);
}).toList(),
),
),
],
......
......@@ -6,17 +6,37 @@ class TaskHeadBlock extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
return Stack(
clipBehavior: Clip.none,
children: [
Positioned(
left: -28.w,
right: -28.w,
top: 0,
child: Container(
height: 150.h,
color: Colors.white,
),
),
Container(
height: 150.h,
padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight),
child: Text(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'设备告警看板',
style: TextStyle(
fontSize: 28.sp,
fontSize: 32.sp,
fontWeight: FontWeight.bold,
color: const Color.fromRGBO(51, 51, 51, 1.0),
color: const Color.fromRGBO(0, 0, 0, 1),
),
),
],
),
),
],
);
}
}
\ No newline at end of file
......@@ -2,9 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
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/services/alert_detail_service.dart';
import 'package:smart_hotel_app/views/home/abnormal_list/cubit/abnormal_list_state.dart';
import 'package:smart_hotel_app/views/home/index/cubit/home_index_cubit.dart';
import 'package:smart_hotel_app/utils/toast_utils.dart';
......@@ -17,7 +15,6 @@ class VoltageOperateBlock extends StatelessWidget {
final String normalVoltage;
final String voltageWaitTime;
final String voltageAlarmLevel;
final AlertDetailService? alertDetailService;
const VoltageOperateBlock({
super.key,
......@@ -28,7 +25,6 @@ class VoltageOperateBlock extends StatelessWidget {
required this.normalVoltage,
required this.voltageWaitTime,
required this.voltageAlarmLevel,
this.alertDetailService,
});
@override
......@@ -51,20 +47,20 @@ class VoltageOperateBlock extends StatelessWidget {
children: [
Container(
width: 64.w,
height: 66.h,
height: 54.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: const Color.fromRGBO(66, 165, 245, 1.0),
width: 2.w,
style: BorderStyle.solid,
),
// border: Border.all(
// color: const Color.fromRGBO(66, 165, 245, 1.0),
// width: 2.w,
// style: BorderStyle.solid,
// ),
),
child: Icon(
Icons.thermostat_outlined,
color: const Color.fromRGBO(66, 165, 245, 1.0),
size: 32.sp,
size: 40.sp,
),
),
SizedBox(width: 16.w),
......@@ -95,7 +91,9 @@ class VoltageOperateBlock extends StatelessWidget {
voltageAlarmLevel,
style: TextStyle(
fontSize: 24.sp,
color: voltageAlarmLevel=="置顶" ? const Color.fromRGBO(255, 100, 101, 1.0) : const Color.fromRGBO(255, 204, 21, 1.0),
color: voltageAlarmLevel=="置顶" ?
const Color.fromRGBO(255, 100, 101, 1.0) :
const Color.fromRGBO(255, 204, 21, 1.0),
),
),
],
......@@ -105,22 +103,23 @@ class VoltageOperateBlock extends StatelessWidget {
width: double.infinity,
margin: EdgeInsets.only(left: 80.w, bottom: 20.h),
child: Text(
'电压${voltageValue}V (正常≤${normalVoltage}V)·已等待$voltageWaitTime',
'电压${voltageValue}V (正常≤${normalVoltage}V)·$voltageWaitTime',
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
),
Container(
SizedBox(
width: double.infinity,
child: Row(
spacing: 20.w,
children: [
Expanded(
child: GestureDetector(
onTap: () => _showHandleDialog(context),
child: Container(
height: 88.h,
padding: EdgeInsets.symmetric(vertical: 20.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(66, 165, 245, 1.0),
borderRadius: BorderRadius.circular(16.r),
......@@ -137,14 +136,13 @@ class VoltageOperateBlock extends StatelessWidget {
),
),
),
SizedBox(width: 20.w),
Expanded(
child: GestureDetector(
onTap: () {
context.pushRoute(AbnormalDetailRoute(alertId: alertId, alarmStatus: AlarmStatus.pending));
},
child: Container(
height: 88.h,
padding: EdgeInsets.symmetric(vertical: 20.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(16.r),
......@@ -244,9 +242,18 @@ class VoltageOperateBlock extends StatelessWidget {
),
SizedBox(height: 20.h),
GestureDetector(
onTap: () {
onTap: () async {
Navigator.of(dialogContext).pop();
_handleAlert(context);
try {
await context.read<HomeIndexCubit>().handleAlert(alertId);
if (context.mounted) {
showToast('操作成功');
}
} catch (e) {
if (context.mounted) {
showToast('操作失败: $e');
}
}
},
child: Container(
width: double.infinity,
......@@ -273,20 +280,4 @@ class VoltageOperateBlock extends StatelessWidget {
},
);
}
Future<void> _handleAlert(BuildContext context) async {
try {
final service = alertDetailService ??
AlertDetailService(repository: AlertDetailRepository());
await service.handleAlert(alertId: alertId);
if (context.mounted) {
showToast('操作成功');
context.read<HomeIndexCubit>().reloadDashboard();
}
} catch (e) {
if (context.mounted) {
showToast('操作失败: $e');
}
}
}
}
\ No newline at end of file
......@@ -86,7 +86,7 @@ class _InspectionDetailBodyState extends State<_InspectionDetailBody> {
return Scaffold(
backgroundColor: const Color.fromRGBO(242, 243, 245, 1),
appBar: _buildAppBar(context),
body: const Center(child: CircularProgressIndicator()),
body: const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0))),
);
}
......
......@@ -24,6 +24,19 @@ class DeviceList extends StatelessWidget {
state: pagingState,
fetchNextPage: fetchNextPage,
builderDelegate: PagedChildBuilderDelegate<InspectionDevice>(
firstPageProgressIndicatorBuilder: (_) => const Center(
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
newPageProgressIndicatorBuilder: (_) => const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
),
firstPageErrorIndicatorBuilder: (_) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
......
......@@ -87,7 +87,6 @@ class InspectionDeviceView extends StatelessWidget {
),
],
if (state.inspectionItems.isNotEmpty) ...[
SizedBox(height: 20.h),
InspectionItemsCard(
items: state.inspectionItems,
),
......@@ -104,26 +103,21 @@ class InspectionDeviceView extends StatelessWidget {
child: Container(
width: double.infinity,
height: 88.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24.r),
border: Border.all(
color: const Color.fromRGBO(66, 165, 245, 1.0),
width: 2.w,
),
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: Text(
'巡检记录',
style: TextStyle(
color: const Color.fromRGBO(66, 165, 245, 1.0),
color: Colors.white,
fontSize: 32.sp,
fontWeight: FontWeight.bold,
),
),
),
),
),
SizedBox(height: 30.h),
],
);
......
......@@ -45,25 +45,36 @@ class InspectionHistoryCard extends StatelessWidget {
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 12.w,
children: [
Container(
width: 60.w,
height: 60.h,
width: 80.w,
height: 64.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(242, 243, 245, 1.0),
color: const Color.fromRGBO(229, 241, 255, 1.0),
borderRadius: BorderRadius.circular(8.r),
),
child: Container(
width: 44.w,
height: 44.h,
decoration: const BoxDecoration(
color: Color.fromRGBO(73, 149, 234, 1),
shape: BoxShape.circle,
),
child: Icon(
Icons.person,
color: const Color.fromRGBO(100, 116, 139, 1.0),
size: 32.sp,
color: Colors.white,
size: 40.sp,
),
),
),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4.h,
children: [
Text(
item.inspectorName,
......@@ -73,19 +84,18 @@ class InspectionHistoryCard extends StatelessWidget {
color: const Color.fromRGBO(10, 13, 20, 1.0),
),
),
SizedBox(height: 4.h),
Row(
children: [
Icon(
Icons.access_time,
color: const Color.fromRGBO(100, 116, 139, 1.0),
size: 20.sp,
size: 24.sp,
),
SizedBox(width: 4.w),
Text(
item.inspectionTime,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
......@@ -96,23 +106,23 @@ class InspectionHistoryCard extends StatelessWidget {
],
),
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(225, 245, 238, 1.0),
borderRadius: BorderRadius.circular(10.r),
borderRadius: BorderRadius.circular(40.r),
),
child: Row(
children: [
Icon(
Icons.check,
color: const Color.fromRGBO(26, 188, 156, 1.0),
size: 20.sp,
size: 24.sp,
),
SizedBox(width: 4.w),
Text(
item.result,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: const Color.fromRGBO(26, 188, 156, 1.0),
fontWeight: FontWeight.bold,
),
......@@ -122,10 +132,10 @@ class InspectionHistoryCard extends StatelessWidget {
),
],
),
SizedBox(height: 16.h),
SizedBox(height: 20.h),
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(242, 243, 245, 1.0),
borderRadius: BorderRadius.circular(12.r),
......@@ -133,12 +143,11 @@ class InspectionHistoryCard extends StatelessWidget {
child: Text(
item.remark,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
),
SizedBox(height: 20.h),
],
);
}
......
......@@ -28,8 +28,7 @@ class InspectionItemsCard extends StatelessWidget {
'巡检项目',
style: TextStyle(
fontSize: 26.sp,
fontWeight: FontWeight.bold,
color: const Color.fromRGBO(10, 13, 20, 1.0),
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
SizedBox(height: 20.h),
......@@ -66,23 +65,23 @@ class InspectionItemsCard extends StatelessWidget {
),
SizedBox(width: 12.w),
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(225, 245, 238, 1.0),
borderRadius: BorderRadius.circular(10.r),
borderRadius: BorderRadius.circular(40.r),
),
child: Row(
children: [
Icon(
Icons.check,
color: const Color.fromRGBO(26, 188, 156, 1.0),
size: 20.sp,
size: 24.sp,
),
SizedBox(width: 4.w),
Text(
item.result,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: const Color.fromRGBO(26, 188, 156, 1.0),
fontWeight: FontWeight.bold,
),
......
......@@ -83,11 +83,11 @@ class StartInspectionButton extends StatelessWidget {
child: Container(
width: double.infinity,
height: 88.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(66, 165, 245, 1.0),
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: Text(
'开始巡检',
style: TextStyle(
......@@ -97,7 +97,6 @@ class StartInspectionButton extends StatelessWidget {
),
),
),
),
);
},
);
......
......@@ -49,7 +49,6 @@ class _InspectionHistoryBodyState extends State<_InspectionHistoryBody> {
final total =
context.read<InspectionHistoryCubit>().state.totalCount;
final nextKey = state.nextIntPageKey;
if (nextKey == null) return null;
if ((nextKey - 1) * InspectionHistoryCubit.pageSize >= total) {
return null;
}
......@@ -129,8 +128,7 @@ class _InspectionHistoryBodyState extends State<_InspectionHistoryBody> {
style: TextStyle(
fontSize: 28.sp,
fontWeight: FontWeight.bold,
color:
const Color.fromRGBO(10, 13, 20, 1.0),
color: const Color.fromRGBO(10, 13, 20, 1.0),
),
),
],
......@@ -144,6 +142,19 @@ class _InspectionHistoryBodyState extends State<_InspectionHistoryBody> {
fetchNextPage: fetchNextPage,
builderDelegate:
PagedChildBuilderDelegate<InspectionRecord>(
firstPageProgressIndicatorBuilder: (_) => const Center(
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
newPageProgressIndicatorBuilder: (_) => const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
),
firstPageErrorIndicatorBuilder: (_) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
......
......@@ -12,37 +12,40 @@ class InspectionRecordItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final resultColor = _getResultColor(record.result);
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.r),
),
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h),
padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 28.h),
margin: EdgeInsets.only(bottom: 20.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 60.w,
height: 60.h,
width: 80.w,
height: 64.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(242, 243, 245, 1.0),
color: const Color.fromRGBO(229, 241, 255, 1.0),
borderRadius: BorderRadius.circular(8.r),
),
child: Icon(
record.icon,
color: const Color.fromRGBO(100, 116, 139, 1.0),
color: const Color.fromRGBO(73, 149, 234, 1.0),
size: 32.sp,
),
),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
SizedBox(width: 20.w),
Expanded(
child: Column(
spacing: 10.h,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
record.deviceName,
......@@ -52,81 +55,89 @@ class InspectionRecordItem extends StatelessWidget {
color: const Color.fromRGBO(10, 13, 20, 1.0),
),
),
SizedBox(height: 8.h),
Row(
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4.h),
decoration: BoxDecoration(
color: resultColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(40.r),
),
child: Row(
children: [
Icon(
Icons.person,
color: const Color.fromRGBO(66, 165, 245, 1.0),
size: 18.sp,
_getResultIcon(record.result),
color: resultColor,
size: 24.sp,
),
SizedBox(width: 4.w),
Text(
record.inspectorName,
record.result,
style: TextStyle(
fontSize: 22.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
fontSize: 24.sp,
color: resultColor,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 4.w,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h),
decoration: BoxDecoration(
color: _getResultColor(record.result).withOpacity(0.1),
borderRadius: BorderRadius.circular(10.r),
border: Border.all(
color: _getResultColor(record.result),
width: 1.w,
width: 24.w,
height: 24.h,
decoration: const BoxDecoration(
color: Color.fromRGBO(73, 149, 234, 1),
shape: BoxShape.circle,
),
child: Icon(
Icons.person,
color: Colors.white,
size: 22.sp,
),
child: Row(
children: [
Icon(
_getResultIcon(record.result),
color: _getResultColor(record.result),
size: 18.sp,
),
SizedBox(width: 4.w),
Text(
record.result,
record.inspectorName,
style: TextStyle(
fontSize: 22.sp,
color: _getResultColor(record.result),
fontWeight: FontWeight.bold,
),
),
],
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
],
),
SizedBox(height: 12.h),
Row(
children: [
Icon(
Icons.access_time,
color: const Color.fromRGBO(100, 116, 139, 1.0),
size: 20.sp,
size: 24.sp,
),
SizedBox(width: 4.w),
Text(
record.inspectionTime,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
],
),
SizedBox(height: 16.h),
],
)
],
)
),
],
),
SizedBox(height: 20.h),
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(242, 243, 245, 1.0),
borderRadius: BorderRadius.circular(12.r),
......@@ -134,23 +145,24 @@ class InspectionRecordItem extends StatelessWidget {
child: Text(
record.remark,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
),
SizedBox(height: 16.h),
SizedBox(height: 20.h),
Divider(
color: const Color.fromRGBO(242, 243, 245, 1.0),
height: 1.h,
thickness: 0.5,
color: const Color.fromRGBO(100, 116, 139, 0.2),
),
SizedBox(height: 16.h),
SizedBox(height: 20.h),
Text(
'巡检项目',
style: TextStyle(
fontSize: 24.sp,
fontWeight: FontWeight.bold,
color: const Color.fromRGBO(71, 85, 105, 1.0),
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
SizedBox(height: 12.h),
......@@ -182,27 +194,27 @@ class InspectionRecordItem extends StatelessWidget {
}
Widget _buildItemTag(InspectionItemRecord item) {
final resultColor = _getResultColor(item.result);
final resultColor = _getResultColor(record.result);
return Container(
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h),
decoration: BoxDecoration(
color: Color.fromRGBO(209, 250, 229, 1.0), // resultColor.withValues(alpha: 0.18),
borderRadius: BorderRadius.circular(18.r),
color: resultColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(40.r),
),
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 6.w,
children: [
Icon(
_getResultIcon(item.result),
_getResultIcon(record.result),
color: resultColor,
size: 18.sp,
size: 24.sp,
),
SizedBox(width: 6.w),
Text(
item.name,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: resultColor,
),
),
......
......@@ -26,10 +26,10 @@ class StatisticsCard extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildStatItem('总计', totalCount, const Color.fromRGBO(66, 165, 245, 1.0)),
_buildStatItem('通过', passCount, const Color.fromRGBO(26, 188, 156, 1.0)),
_buildStatItem('警告', warningCount, const Color.fromRGBO(247, 184, 75, 1.0)),
_buildStatItem('不通过', failCount, const Color.fromRGBO(239, 68, 68, 1.0)),
_buildStatItem('总计', totalCount, const Color.fromRGBO(73, 149, 234, 1.0)),
_buildStatItem('通过', passCount, const Color.fromRGBO(20, 184, 166, 1.0)),
_buildStatItem('警告', warningCount, const Color.fromRGBO(250, 204, 21, 1.0)),
_buildStatItem('不通过', failCount, const Color.fromRGBO(255, 100, 101, 1.0)),
],
),
);
......@@ -37,6 +37,7 @@ class StatisticsCard extends StatelessWidget {
Widget _buildStatItem(String label, int count, Color color) {
return Column(
spacing: 5.h,
children: [
Text(
count.toString(),
......@@ -46,7 +47,6 @@ class StatisticsCard extends StatelessWidget {
color: color,
),
),
SizedBox(height: 4.h),
Text(
label,
style: TextStyle(
......
......@@ -55,7 +55,7 @@ class InspectionTopologyPage extends StatelessWidget {
builder: (context, state) {
if (state.isLoading) {
return const Center(
child: CircularProgressIndicator(),
child: CircularProgressIndicator(color: const Color.fromRGBO(66, 165, 245, 1.0)),
);
}
......
......@@ -33,7 +33,7 @@ class BtnLogin extends StatelessWidget {
height: 40.w,
child: CircularProgressIndicator(
strokeWidth: 3.w,
color: Colors.white,
color: const Color.fromRGBO(66, 165, 245, 1.0),
),
)
: Text(
......
......@@ -16,14 +16,14 @@ class ProfileHeaderBlock extends StatelessWidget {
return Container(
width: double.infinity,
color: Colors.white,
padding: EdgeInsets.only(left: 28.w, right: 28.w, top: ScreenUtil().statusBarHeight + 32.h, bottom: 32.h),
padding: EdgeInsets.only(left: 28.w, right: 28.w, top: ScreenUtil().statusBarHeight + 20.h, bottom: 32.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'我的',
style: TextStyle(
fontSize: 36.sp,
fontSize: 32.sp,
fontWeight: FontWeight.w500,
color: Colors.black,
),
......
......@@ -115,6 +115,19 @@ class _ReportDeviceListBodyState extends State<_ReportDeviceListBody> {
state: pagingState,
fetchNextPage: fetchNextPage,
builderDelegate: PagedChildBuilderDelegate<DeviceInfo>(
firstPageProgressIndicatorBuilder: (_) => const Center(
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
newPageProgressIndicatorBuilder: (_) => const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: CircularProgressIndicator(
color: Color.fromRGBO(66, 165, 245, 1.0),
),
),
),
firstPageErrorIndicatorBuilder: (_) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
......
......@@ -40,7 +40,7 @@ class ReportEnergyDetailView extends StatelessWidget {
body: BlocBuilder<EnergyCubit, EnergyState>(
builder: (context, state) {
if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0)));
}
if (state.error != null) {
return Center(
......
......@@ -51,9 +51,10 @@ class _ReportIndexViewState extends State<ReportIndexView> with AutoRouteAwareSt
if (state.isLoading) {
return Container(
color: const Color.fromRGBO(242, 243, 245, 1),
child: const Center(child: CircularProgressIndicator()),
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),
......@@ -79,6 +80,7 @@ class _ReportIndexViewState extends State<ReportIndexView> with AutoRouteAwareSt
),
);
}
return LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
......@@ -89,31 +91,16 @@ class _ReportIndexViewState extends State<ReportIndexView> with AutoRouteAwareSt
child: Container(
width: double.infinity,
color: const Color.fromRGBO(242, 243, 245, 1),
padding: EdgeInsets.only(
left: 28.w,
right: 28.w,
top: ScreenUtil().statusBarHeight),
padding: EdgeInsets.only(left: 28.w, right: 28.w, bottom: 15.h),
child: Column(
spacing: 15.h,
children: [
ReportHeaderBlock(
reportHeader: state.reportHeader),
SizedBox(height: 10.h),
ReportMetricsBlock(
reportMetrics: state.reportMetrics),
SizedBox(height: 10.h),
WeeklyPowerChart(
weeklyPowerUsage: state.weeklyPowerUsage),
SizedBox(height: 10.h),
RoomStatusDistribution(
roomStatusDistribution:
state.roomStatusDistribution),
SizedBox(height: 10.h),
DeviceOnlineRate(
deviceOnlineRate: state.deviceOnlineRate),
SizedBox(height: 10.h),
QuickActionsBlock(
quickActions: state.quickActions),
SizedBox(height: 10.h),
const ReportHeaderBlock(),
ReportMetricsBlock(reportMetrics: state.reportMetrics),
WeeklyPowerChart(weeklyPowerUsage: state.weeklyPowerUsage),
RoomStatusDistribution(roomStatusDistribution: state.roomStatusDistribution),
DeviceOnlineRate(deviceOnlineRate: state.deviceOnlineRate),
QuickActionsBlock(quickActions: state.quickActions),
],
),
),
......
......@@ -2,23 +2,39 @@ import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ReportHeaderBlock extends StatelessWidget {
final Map<String, dynamic> reportHeader;
const ReportHeaderBlock({super.key, required this.reportHeader});
const ReportHeaderBlock({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 0.w, vertical: 16.h),
child: Text(
reportHeader['title'] as String,
return Stack(
clipBehavior: Clip.none,
children: [
Positioned(
left: -28.w,
right: -28.w,
top: 0,
child: Container(
height: 150.h,
color: Colors.white,
),
),
Container(
height: 150.h,
padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight),
child: Row(
children: [
Text(
'经营概览看板',
style: TextStyle(
fontSize: 36.sp,
fontWeight: FontWeight.w500,
color: const Color.fromRGBO(71, 71, 71, 1),
fontSize: 32.sp,
fontWeight: FontWeight.bold,
color: const Color.fromRGBO(0, 0, 0, 1),
),
),
],
),
),
],
);
}
}
\ No newline at end of file
......@@ -43,7 +43,7 @@ class ReportRoomDetailView extends StatelessWidget {
),
centerTitle: true,
),
body: const Center(child: CircularProgressIndicator()),
body: const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0))),
);
}
......@@ -126,7 +126,7 @@ class ReportRoomDetailView extends StatelessWidget {
if (state.isLoading)
const Padding(
padding: EdgeInsets.all(16.0),
child: Center(child: CircularProgressIndicator()),
child: Center(child: CircularProgressIndicator(color: const Color.fromRGBO(66, 165, 245, 1.0))),
),
...state.detailRooms.map((room) {
return Padding(
......
......@@ -44,7 +44,7 @@ class ServiceDeviceDetailView extends StatelessWidget {
builder: (context, state) {
final cubit = context.read<ServiceDeviceCubit>();
if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator(color: Color.fromRGBO(66, 165, 245, 1.0)));
}
if (state.error != null) {
return Center(
......@@ -68,10 +68,15 @@ class ServiceDeviceDetailView extends StatelessWidget {
);
}
return SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 28.w),
padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 20.h),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 40.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24.r),
),
child: Column(
children: [
SizedBox(height: 20.h),
TemperatureControlBlock(
isOn: state.isOn,
targetTemperature: state.targetTemperature,
......@@ -93,9 +98,9 @@ class ServiceDeviceDetailView extends StatelessWidget {
speedOptions: state.speedOptions,
onSetWindSpeed: cubit.setWindSpeed,
),
SizedBox(height: 20.h),
],
),
),
);
},
),
......
......@@ -67,7 +67,7 @@ class _ModeSelectionBlockState extends State<ModeSelectionBlock> {
Text(
mode['name'] as String,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: isSelected
? Colors.white
: const Color.fromRGBO(107, 114, 128, 1),
......
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_switch/flutter_switch.dart';
import 'dart:math' as math;
class TemperatureControlBlock extends StatefulWidget {
......@@ -29,83 +30,37 @@ class TemperatureControlBlock extends StatefulWidget {
_TemperatureControlBlockState();
}
class _TemperatureControlBlockState extends State<TemperatureControlBlock>
with SingleTickerProviderStateMixin {
class _TemperatureControlBlockState extends State<TemperatureControlBlock> {
@override
Widget build(BuildContext context) {
final progress = (widget.targetTemperature - widget.minTemperature) /
(widget.maxTemperature - widget.minTemperature);
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 20.w),
child: Column(
return Column(
children: [
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(right: 20.w),
child: _buildPowerSwitch(),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FlutterSwitch(
width: 80.w,
height: 35.h,
valueFontSize: 20.sp,
toggleSize: 25.h,
borderRadius: 20.r,
padding: 4.w,
value: widget.isOn,
activeColor: const Color.fromRGBO(80, 162, 255, 1),
inactiveColor: const Color.fromRGBO(210, 213, 218, 1),
onToggle: widget.onTogglePower,
),
SizedBox(width: 20.w),
],
),
SizedBox(height: 20.h),
_buildCircularTemperatureControl(progress),
SizedBox(height: 40.h),
_buildControlButtons(),
],
),
);
}
Widget _buildPowerSwitch() {
return GestureDetector(
onTap: () => widget.onTogglePower(!widget.isOn),
child: Container(
width: 88.w,
height: 48.h,
decoration: BoxDecoration(
gradient: widget.isOn
? const LinearGradient(
colors: [
Color.fromRGBO(96, 165, 250, 1),
Color.fromRGBO(59, 130, 246, 1),
],
)
: const LinearGradient(
colors: [
Color.fromRGBO(209, 213, 219, 1),
Color.fromRGBO(156, 163, 175, 1),
],
),
borderRadius: BorderRadius.circular(24.r),
),
child: Stack(
children: [
AnimatedAlign(
duration: const Duration(milliseconds: 200),
alignment: widget.isOn ? Alignment.centerRight : Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
),
),
),
],
),
),
);
}
......@@ -138,40 +93,38 @@ class _TemperatureControlBlockState extends State<TemperatureControlBlock>
Text(
'${widget.targetTemperature}',
style: TextStyle(
fontSize: 100.sp,
fontSize: 68.sp,
fontWeight: FontWeight.w500,
color: widget.isOn
? const Color.fromRGBO(37, 99, 235, 1)
? const Color.fromRGBO(35, 89, 245, 1)
: const Color.fromRGBO(209, 213, 219, 1),
),
),
SizedBox(height: 8.h),
Text(
'°C',
style: TextStyle(
fontSize: 48.sp,
fontSize: 36.sp,
fontWeight: FontWeight.w400,
color: widget.isOn
? const Color.fromRGBO(59, 130, 246, 1)
? const Color.fromRGBO(35, 89, 245, 1)
: const Color.fromRGBO(209, 213, 219, 1),
),
),
SizedBox(height: 20.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'当前室温 ',
style: TextStyle(
fontSize: 28.sp,
color: const Color.fromRGBO(156, 163, 175, 1),
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
Text(
'${widget.currentTemperature}°C',
style: TextStyle(
fontSize: 28.sp,
color: const Color.fromRGBO(107, 114, 128, 1),
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
],
......@@ -186,14 +139,14 @@ class _TemperatureControlBlockState extends State<TemperatureControlBlock>
child: Container(
width: 64.w,
height: 64.w,
decoration: BoxDecoration(
color: const Color.fromRGBO(37, 99, 235, 1),
decoration: const BoxDecoration(
color: Color.fromRGBO(37, 99, 235, 1),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(37, 99, 235, 0.3),
color: Color.fromRGBO(37, 99, 235, 0.3),
blurRadius: 10,
offset: const Offset(0, 4),
offset: Offset(0, 4),
),
],
),
......@@ -217,44 +170,43 @@ class _TemperatureControlBlockState extends State<TemperatureControlBlock>
Widget _buildControlButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 40.w,
children: [
GestureDetector(
onTap: widget.onDecreaseTemperature,
child: Container(
width: 140.w,
height: 120.h,
width: 102.w,
height: 82.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(229, 231, 235, 1),
borderRadius: BorderRadius.circular(40.r),
color: const Color.fromRGBO(224, 227, 232, 1),
borderRadius: BorderRadius.circular(26.r),
),
child: Icon(
Icons.remove,
size: 48.sp,
size: 70.sp,
color: const Color.fromRGBO(107, 114, 128, 1),
),
),
),
SizedBox(width: 40.w),
Text(
'温度调节',
style: TextStyle(
fontSize: 32.sp,
color: const Color.fromRGBO(107, 114, 128, 1),
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
SizedBox(width: 40.w),
GestureDetector(
onTap: widget.onIncreaseTemperature,
child: Container(
width: 140.w,
height: 120.h,
width: 102.w,
height: 82.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(229, 231, 235, 1),
borderRadius: BorderRadius.circular(40.r),
color: const Color.fromRGBO(224, 227, 232, 1),
borderRadius: BorderRadius.circular(26.r),
),
child: Icon(
Icons.add,
size: 48.sp,
size: 70.sp,
color: const Color.fromRGBO(107, 114, 128, 1),
),
),
......
......@@ -58,7 +58,7 @@ class _WindSpeedBlockState extends State<WindSpeedBlock> {
child: Text(
speed,
style: TextStyle(
fontSize: 22.sp,
fontSize: 24.sp,
color: isSelected
? Colors.white
: const Color.fromRGBO(107, 114, 128, 1),
......
......@@ -89,10 +89,7 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
}
/// 加载房间状态列表
Future<void> loadRooms({
int? floorId,
String? areaType,
}) async {
Future<void> loadRooms({int? floorId, String? areaType}) async {
emit(state.copyWith(isLoading: true, error: null));
try {
final roomStatuses = await _roomService.getRoomStatus(
......@@ -151,7 +148,11 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
'roomId': rs.roomId,
'number': rs.roomNumber,
'status': displayStatus,
'type': '客房', // 默认类型,后续可通过楼层areas信息扩展
'type': '客房',
'occupancyStatus': rs.occupancyStatus, // 0=无人 1=有人
'roomStatus': rs.roomStatus, // 0=无人 1=有人
'cleanStatus': rs.cleanStatus, // 0=待清洁 2=已完成
'devicePowerStatus': rs.devicePowerStatus, // 0=关 1=开
};
}
......@@ -183,15 +184,8 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
}
}
void selectType(String? type) {
emit(state.copyWith(selectedType: type));
}
/// 加载非客房-相关楼层区域设备
Future<void> loadAreaDevices({
required int floorId,
required String areaType,
}) async {
Future<void> loadAreaDevices({required int floorId, required String areaType}) async {
emit(state.copyWith(isLoadingAreaDevices: true, error: null));
try {
final devices = await _roomService.getAreaDevices(
......@@ -210,8 +204,103 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
}
}
void selectRoom(String? room) {
emit(state.copyWith(selectedRoom: room));
/// 选择房间
void selectRoom({String? room, int? roomId}) {
emit(state.copyWith(selectedRoom: room, selectedRoomId: roomId));
}
/// UI 层切换楼层(含取消选中、重置类型/房间/搜索、加载房间数据)
void toggleFloor(String floorName, int floorId) {
final isSameFloor = state.selectedFloor == floorName;
final newFloor = isSameFloor ? null : floorName;
// 计算新楼层的 areas
List<String> areas = state.areas;
if (newFloor != null) {
final matched = _floorAreasCache.where(
(f) => f.floorId.toString() == newFloor,
);
areas = matched.isNotEmpty ? matched.first.areas : <String>[];
}
emit(state.copyWith(
selectedFloor: newFloor,
selectedType: null,
selectedRoom: null,
selectedRoomId: null,
searchText: '',
areas: areas,
));
if (newFloor != null) {
loadRooms(floorId: floorId);
}
}
/// UI 层切换区域类型(含取消选中、重置房间、加载非客房设备)
void toggleType(String type) {
final newType = state.selectedType != type ? type : null;
emit(state.copyWith(
selectedType: newType,
selectedRoom: null,
selectedRoomId: null,
));
if (newType != null && newType != '客房') {
_loadAreaDevicesForCurrentFloor(newType);
}
}
/// 获取当前筛选条件下的房间列表
List<Map<String, dynamic>> getFilteredRooms() {
List<Map<String, dynamic>> allRooms;
if (state.selectedFloor == null) {
allRooms = [];
for (final floorMap in (state.floors ?? [])) {
final floorName = floorMap.values.first;
allRooms.addAll(getRoomsByFloor(floorName));
}
} else {
allRooms = getRoomsByFloor(state.selectedFloor!);
}
if (state.selectedType != null) {
allRooms =
allRooms.where((room) => room['type'] == state.selectedType).toList();
}
if (state.searchText.isEmpty) {
return allRooms;
}
return allRooms
.where((room) => (room['number'] as String)
.toLowerCase()
.contains(state.searchText.toLowerCase()))
.toList();
}
/// 获取当前选中房间的完整数据
Map<String, dynamic>? getSelectedRoomDetail() {
if (state.selectedRoom == null) return null;
return _findRoomByNumber(state.selectedRoom!);
}
/// 根据楼层标签获取楼层 ID
int? getFloorIdByLabel(String floorLabel) {
for (final floorMap in (state.floors ?? [])) {
if (floorMap.values.first == floorLabel) {
return floorMap.keys.first;
}
}
return null;
}
/// 根据当前选中楼层加载非客房区域设备
void _loadAreaDevicesForCurrentFloor(String areaType) {
if (state.selectedFloor == null) return;
final floorId = getFloorIdByLabel(state.selectedFloor!);
if (floorId == null) return;
loadAreaDevices(floorId: floorId, areaType: areaType);
}
void setSearchText(String text) {
......@@ -261,4 +350,10 @@ class ServiceIndexCubit extends Cubit<ServiceIndexState> {
}
return null;
}
@override
Future<void> close() {
return super.close();
}
}
......@@ -2,15 +2,18 @@ import 'package:equatable/equatable.dart';
import 'package:smart_hotel_app/models/bo/room_bo.dart';
class ServiceIndexState extends Equatable {
/// copyWith sentinel: 区分「未传参」和「显式传 null」
static const _nothing = Object();
final int pendingCount;
final int occupiedRooms;
final int vacantRooms;
// final List<String> floors;
final List<Map<int,String>>? floors;
final List<String> areas;
final String? selectedFloor;
final String? selectedType;
final String? selectedRoom;
final int? selectedRoomId;
final String searchText;
final List<Map<String, dynamic>> rooms;
final List<AreaDeviceBO> areaDevices;
......@@ -29,6 +32,7 @@ class ServiceIndexState extends Equatable {
this.selectedFloor,
this.selectedType,
this.selectedRoom,
this.selectedRoomId,
this.searchText = '',
this.rooms = const [],
this.areaDevices = const [],
......@@ -43,18 +47,18 @@ class ServiceIndexState extends Equatable {
int? pendingCount,
int? occupiedRooms,
int? vacantRooms,
// List<String>? floors,
List<Map<int,String>>? floors,
List<String>? areas,
String? selectedFloor,
String? selectedType,
String? selectedRoom,
Object? selectedFloor = _nothing,
Object? selectedType = _nothing,
Object? selectedRoom = _nothing,
Object? selectedRoomId = _nothing,
String? searchText,
List<Map<String, dynamic>>? rooms,
List<AreaDeviceBO>? areaDevices,
bool? isLoading,
bool? isLoadingAreaDevices,
String? error,
Object? error = _nothing,
bool? isPoweringOn,
bool? isPoweringOff,
}) {
......@@ -64,15 +68,16 @@ class ServiceIndexState extends Equatable {
vacantRooms: vacantRooms ?? this.vacantRooms,
floors: floors ?? this.floors,
areas: areas ?? this.areas,
selectedFloor: selectedFloor ?? this.selectedFloor,
selectedType: selectedType ?? this.selectedType,
selectedRoom: selectedRoom ?? this.selectedRoom,
selectedFloor: identical(selectedFloor, _nothing) ? this.selectedFloor : selectedFloor as String?,
selectedType: identical(selectedType, _nothing) ? this.selectedType : selectedType as String?,
selectedRoom: identical(selectedRoom, _nothing) ? this.selectedRoom : selectedRoom as String?,
selectedRoomId: identical(selectedRoomId, _nothing) ? this.selectedRoomId : selectedRoomId as int?,
searchText: searchText ?? this.searchText,
rooms: rooms ?? this.rooms,
areaDevices: areaDevices ?? this.areaDevices,
isLoading: isLoading ?? this.isLoading,
isLoadingAreaDevices: isLoadingAreaDevices ?? this.isLoadingAreaDevices,
error: error ?? this.error,
error: identical(error, _nothing) ? this.error : error as String?,
isPoweringOn: isPoweringOn ?? this.isPoweringOn,
isPoweringOff: isPoweringOff ?? this.isPoweringOff,
);
......@@ -88,6 +93,7 @@ class ServiceIndexState extends Equatable {
selectedFloor,
selectedType,
selectedRoom,
selectedRoomId,
searchText,
rooms,
areaDevices,
......
......@@ -64,7 +64,7 @@ class _ServiceIndexViewState extends State<ServiceIndexView> with AutoRouteAware
occupiedCount: state.occupiedRooms,
vacantCount: state.vacantRooms,
),
RoomManagementBlock(),
const RoomManagementBlock(),
SizedBox(height: 18.h),
],
);
......
......@@ -50,7 +50,7 @@ class AreaDeviceList extends StatelessWidget {
return const Center(
child: Padding(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(),
child: CircularProgressIndicator(color: const Color.fromRGBO(66, 165, 245, 1.0)),
),
);
}
......
......@@ -6,7 +6,6 @@ class ServiceHeadBlock extends StatelessWidget {
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return Stack(
clipBehavior: Clip.none,
children: [
......@@ -21,7 +20,7 @@ class ServiceHeadBlock extends StatelessWidget {
),
Container(
height: 150.h,
padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight, left: 20.w, right: 20.w),
padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
......@@ -31,26 +30,31 @@ class ServiceHeadBlock extends StatelessWidget {
fontSize: 32.sp,
fontWeight: FontWeight.bold,
color: const Color.fromRGBO(0, 0, 0, 1),
fontFamily: 'FZLTXH',
),
),
Container(
width: 64.w,
height: 64.w,
height: 64.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(229, 241, 255, 1),
shape: BoxShape.circle,
border: Border.all(
color: const Color.fromRGBO(73, 149, 234, 1),
width: 1.w,
width: 2.w,
),
),
child: CircleAvatar(
radius: 40.w,
backgroundColor: Colors.white,
child: Container(
width: 40.w,
height: 40.h,
decoration: const BoxDecoration(
color: Color.fromRGBO(73, 149, 234, 1),
shape: BoxShape.circle,
),
child: Icon(
Icons.person,
color: const Color.fromRGBO(73, 149, 234, 1),
size: 48.sp,
color: Colors.white,
size: 28.sp,
),
),
),
......@@ -60,4 +64,5 @@ class ServiceHeadBlock extends StatelessWidget {
],
);
}
}
......@@ -18,64 +18,40 @@ class ServiceStatsBlock extends StatelessWidget {
return Container(
width: double.infinity,
padding: EdgeInsets.only(top: 20.w, bottom: 20.w),
decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(24.r),
color: Color.fromRGBO(242, 243, 245, 1.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text(
// '服务概览',
// style: TextStyle(
// fontSize: 28.sp,
// fontWeight: FontWeight.bold,
// color: const Color.fromRGBO(31, 41, 55, 1),
// ),
// ),
// SizedBox(height: 20.h),
Row(
child: Row(
spacing: 12.w,
children: [
_buildStatCard(
'待响应需求',
'待响应',
'$pendingCount',
const Color.fromRGBO(239, 68, 68, 1),
Icons.warning_amber_rounded,
const Color.fromRGBO(73, 149, 234, 1),
),
SizedBox(width: 12.w),
_buildStatCard(
'入住中',
'$occupiedCount',
const Color.fromRGBO(34, 197, 94, 1),
Icons.meeting_room_outlined,
const Color.fromRGBO(20, 184, 166, 1),
),
SizedBox(width: 12.w),
_buildStatCard(
'空闲可清洁',
'$vacantCount',
const Color.fromRGBO(59, 130, 246, 1),
Icons.cleaning_services_outlined,
),
],
const Color.fromRGBO(10, 13, 20, 1),
),
],
),
);
}
Widget _buildStatCard(
String label, String value, Color color, IconData icon) {
Widget _buildStatCard(String label, String value, Color color) {
return Expanded(
child: Container(
padding: EdgeInsets.all(16.w),
padding: EdgeInsets.symmetric(vertical: 16.h),
decoration: BoxDecoration(
color: color.withOpacity(0.08),
borderRadius: BorderRadius.circular(16.r),
color: Colors.white,
borderRadius: BorderRadius.circular(24.r),
),
child: Column(
spacing: 5.h,
children: [
// Icon(icon, color: color, size: 28.sp),
SizedBox(height: 8.h),
Text(
value,
style: TextStyle(
......@@ -84,12 +60,11 @@ class ServiceStatsBlock extends StatelessWidget {
color: color,
),
),
SizedBox(height: 4.h),
Text(
label,
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(107, 114, 128, 1),
color: const Color.fromRGBO(100, 116, 139, 1),
),
),
],
......
......@@ -55,7 +55,7 @@ class ServiceRoomDetailView extends StatelessWidget {
builder: (context, state) {
if (state.isLoading) {
return const Center(
child: CircularProgressIndicator(),
child: CircularProgressIndicator(color: const Color.fromRGBO(66, 165, 245, 1.0)),
);
}
......@@ -117,7 +117,7 @@ class ServiceRoomDetailView extends StatelessWidget {
onDeviceToggle: (index, value) =>
cubit.toggleControlDevice(index, value),
onDeviceTap: (index, device) {
if (device.name == '空调' || device.name?.contains('空调') == true) {
if (device.name.contains('空调')) {
context.pushRoute(ServiceDeviceDetailRoute(deviceId: device.deviceId));
}
},
......
......@@ -49,7 +49,7 @@ class DeviceControlCard extends StatelessWidget {
color: const Color.fromRGBO(10, 13, 20, 1.0),
),
),
SizedBox(height: 20.h),
SizedBox(height: 30.h),
...controlDevices.asMap().entries.map((entry) {
final index = entry.key;
final device = entry.value;
......@@ -71,10 +71,11 @@ class DeviceControlCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 16.w,
children: [
Container(
width: 64.w,
height: 64.h,
height: 53.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(12.r),
......@@ -85,7 +86,6 @@ class DeviceControlCard extends StatelessWidget {
size: 36.sp,
),
),
SizedBox(width: 16.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
......@@ -109,27 +109,24 @@ class DeviceControlCard extends StatelessWidget {
],
),
FlutterSwitch(
width: 48.0,
height: 25.0,
width: 80.w,
height: 35.h,
valueFontSize: 20.sp,
toggleSize: 25.h,
borderRadius: 20.r,
padding: 4.w,
value: mainPowerOn,
showOnOff: false,
onToggle: onMainPowerToggle
),
// FlutterSwitch(
// value: mainPowerOn,
// onToggle: onMainPowerToggle,
// activeColor: const Color.fromRGBO(59, 130, 246, 1),
// inactiveColor: const Color.fromRGBO(209, 213, 219, 1),
// width: 50.w,
// height: 28.h,
// // toggleSize: 26,
// ),
activeColor: const Color.fromRGBO(80, 162, 255, 1),
inactiveColor: const Color.fromRGBO(210, 213, 218, 1),
onToggle: onMainPowerToggle,
),
],
),
SizedBox(height: 20.h),
SizedBox(height: 30.h),
Divider(
color: const Color.fromRGBO(242, 243, 245, 1.0),
thickness: 1.h,
height: 0.5.h,
color: const Color.fromRGBO(100, 116, 139, 0.2),
thickness: 0.5,
),
],
);
......@@ -147,10 +144,7 @@ class DeviceControlCard extends StatelessWidget {
color: Colors.transparent,
child: InkWell(
onTap: onDeviceTap != null ? () => onDeviceTap!(index, device) : null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
child: Row(
children: [
Icon(
device.icon,
......@@ -168,44 +162,29 @@ class DeviceControlCard extends StatelessWidget {
),
],
),
if (device.detailText != null) ...[
SizedBox(height: 8.h),
Text(
device.detailText!,
style: TextStyle(
fontSize: 24.sp,
color: const Color.fromRGBO(100, 116, 139, 1.0),
),
),
],
],
),
),
),
),
FlutterSwitch(
width: 48.0,
height: 25.0,
width: 80.w,
height: 35.h,
valueFontSize: 20.sp,
toggleSize: 25.h,
borderRadius: 20.r,
padding: 4.w,
value: device.isOn,
showOnOff: false,
activeColor: const Color.fromRGBO(80, 162, 255, 1),
inactiveColor: const Color.fromRGBO(210, 213, 218, 1),
onToggle: (value) => onDeviceToggle(index, value),
),
// FlutterSwitch(
// value: device.isOn,
// onToggle: (value) => onDeviceToggle(index, value),
// activeColor: const Color.fromRGBO(66, 165, 245, 1.0),
// inactiveColor: const Color.fromRGBO(200, 208, 220, 1.0),
// width: 60.w,
// height: 30.h,
// toggleSize: 26,
// ),
],
),
if (index < controlDevices.length - 1) ...[
SizedBox(height: 20.h),
SizedBox(height: 30.h),
Divider(
color: const Color.fromRGBO(242, 243, 245, 1.0),
thickness: 1.h,
height: 0.5.h,
color: const Color.fromRGBO(100, 116, 139, 0.2),
thickness: 0.5,
),
],
],
......
......@@ -4,59 +4,59 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
class RoomBottomButtons extends StatelessWidget {
final VoidCallback? onPowerOn;
final VoidCallback? onPowerOff;
final VoidCallback? onDeviceControl;
// final VoidCallback? onDeviceControl;
final bool isProcessing;
const RoomBottomButtons({
super.key,
this.onPowerOn,
this.onPowerOff,
this.onDeviceControl,
// this.onDeviceControl,
this.isProcessing = false,
});
@override
Widget build(BuildContext context) {
return Row(
spacing: 12.w,
children: [
Expanded(
child: GestureDetector(
onTap: (onPowerOn != null && !isProcessing) ? onPowerOn : null,
child: Container(
height: 88.h,
height: 70.h,
decoration: BoxDecoration(
color: (onPowerOn != null && !isProcessing)
? const Color.fromRGBO(66, 165, 245, 1.0)
? const Color.fromRGBO(73, 149, 234, 1)
: const Color.fromRGBO(204, 204, 204, 1),
borderRadius: BorderRadius.circular(20.r),
borderRadius: BorderRadius.circular(16.r),
),
child: Center(
child: Text(
'送电',
style: TextStyle(
color: Colors.white,
fontSize: 32.sp,
fontWeight: FontWeight.bold,
fontSize: 28.sp,
fontWeight: FontWeight.w500,
),
),
),
),
),
),
SizedBox(width: 12.w),
Expanded(
child: GestureDetector(
onTap: (onPowerOff != null && !isProcessing) ? onPowerOff : null,
child: Container(
height: 88.h,
height: 70.h,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.r),
color: const Color.fromRGBO(229, 241, 255, 1),
borderRadius: BorderRadius.circular(16.r),
border: Border.all(
color: (onPowerOff != null && !isProcessing)
? const Color.fromRGBO(66, 165, 245, 1.0)
? const Color.fromRGBO(73, 149, 234, 1)
: const Color.fromRGBO(204, 204, 204, 1),
width: 2.w,
width: 1.w,
),
),
child: Center(
......@@ -66,37 +66,36 @@ class RoomBottomButtons extends StatelessWidget {
color: (onPowerOff != null && !isProcessing)
? const Color.fromRGBO(66, 165, 245, 1.0)
: const Color.fromRGBO(100, 116, 139, 1),
fontSize: 32.sp,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
SizedBox(width: 12.w),
Expanded(
child: GestureDetector(
onTap: onDeviceControl,
child: Container(
height: 88.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(200, 208, 220, 1.0),
borderRadius: BorderRadius.circular(20.r),
),
child: Center(
child: Text(
'设备控制',
style: TextStyle(
color: const Color.fromRGBO(100, 116, 139, 1.0),
fontSize: 32.sp,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
fontSize: 28.sp,
fontWeight: FontWeight.w500,
),
),
),
),
),
),
// Expanded(
// child: GestureDetector(
// onTap: onDeviceControl,
// child: Container(
// height: 70.h,
// decoration: BoxDecoration(
// color: const Color.fromRGBO(100, 116, 139, 0.2),
// borderRadius: BorderRadius.circular(16.r),
// ),
// child: Center(
// child: Text(
// '设备控制',
// style: TextStyle(
// color: const Color.fromRGBO(100, 116, 139, 1.0),
// fontSize: 28.sp,
// fontWeight: FontWeight.w500,
// ),
// ),
// ),
// ),
// ),
// ),
],
);
}
......
......@@ -20,6 +20,7 @@ class RoomDeviceStatusCard extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 20.h,
children: [
Text(
'房间设备状态',
......@@ -29,7 +30,6 @@ class RoomDeviceStatusCard extends StatelessWidget {
color: const Color.fromRGBO(10, 13, 20, 1.0),
),
),
SizedBox(height: 20.h),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
......@@ -37,7 +37,7 @@ class RoomDeviceStatusCard extends StatelessWidget {
crossAxisCount: 2,
crossAxisSpacing: 16.w,
mainAxisSpacing: 16.h,
childAspectRatio: 2,
childAspectRatio: 2.5,
),
itemCount: devices.length,
itemBuilder: (context, index) {
......@@ -47,18 +47,20 @@ class RoomDeviceStatusCard extends StatelessWidget {
color: const Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(28.r),
),
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h),
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
Row(
spacing: 8.w,
children: [
Icon(
device.icon,
color: const Color.fromRGBO(66, 165, 245, 1.0),
size: 36.sp,
),
SizedBox(width: 8.w),
Text(
device.name,
style: TextStyle(
......@@ -69,7 +71,6 @@ class RoomDeviceStatusCard extends StatelessWidget {
),
],
),
SizedBox(height: 12.h),
if (device.statusText != null)
Text(
device.statusText!,
......
......@@ -24,12 +24,13 @@ class RoomOverviewCard extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Container(
width: 88.w,
height: 88.h,
width: 64.w,
height: 53.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(235, 244, 255, 1.0),
borderRadius: BorderRadius.circular(16.r),
......@@ -41,11 +42,6 @@ class RoomOverviewCard extends StatelessWidget {
),
),
SizedBox(width: 20.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
roomNumber,
style: TextStyle(
......@@ -64,11 +60,6 @@ class RoomOverviewCard extends StatelessWidget {
),
],
),
],
),
],
),
SizedBox(height: 24.h),
Wrap(
spacing: 8.w,
children: statusTags.map((tag) {
......@@ -80,13 +71,13 @@ class RoomOverviewCard extends StatelessWidget {
),
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 4.w,
children: [
Icon(
Icons.check,
color: const Color.fromRGBO(26, 188, 156, 1.0),
size: 20.sp,
),
SizedBox(width: 4.w),
Text(
_getTagLabel(tag),
style: TextStyle(
......
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