import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:vbvs_app/common/color/appConstants.dart'; import 'package:vbvs_app/common/color/app_uri_status.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/component/NullDataComponentWidget.dart'; import 'package:vbvs_app/component/tool/ClickableContainer.dart'; import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; import 'package:vbvs_app/controller/main_bottom/global_controller.dart'; import 'package:vbvs_app/controller/user_info_controller.dart'; import 'package:vbvs_app/controller/weather/weather_controller.dart'; import 'package:vbvs_app/pages/mh_page/FloatingSvgIcon.dart'; import 'package:vbvs_app/pages/mh_page/homepage/component/HomeDeviceWidget.dart'; import 'package:vbvs_app/pages/mh_page/homepage/controller/mht_home_controller.dart'; class NewHomePage extends StatefulWidget { const NewHomePage({super.key}); @override State createState() => _NewHomePageState(); } class _NewHomePageState extends State { UserInfoController userInfoController = Get.find(); MHTHomeController deviceController = Get.find(); MHTHomeController homeController = Get.find(); double borderRadius = 16.rpx; var formFieldController = FormFieldController(null); var personInfo = {}.obs; GlobalController gloablController = Get.find(); WeatherModelController weatherModelController = Get.find(); // var selectedDayIndex = (6).obs; @override void initState() { super.initState(); if (userInfoController.model.login == 1) { //查询人员信息列表 deviceController.getPersonList(); //请求绑定设备列表 // homeController.getSleepReport(); deviceController.getDeviceNum().then((apiResponse) { if (apiResponse.code != HttpStatusCodes.ok) { TopSlideNotification.show( Get.context!, text: apiResponse.msg!, textColor: themeController.currentColor.sc9, ); } }); deviceController.getDeviceList(group: 'room').then((apiResponse) { if (apiResponse.code != HttpStatusCodes.ok) { TopSlideNotification.show( Get.context!, text: apiResponse.msg!, textColor: themeController.currentColor.sc9, ); } else { //请求睡眠报告 // deviceController.getSleepReport(); } }); } WidgetsBinding.instance.addPostFrameCallback((_) { if (homeController.homeSleepDays.value.isNotEmpty) { homeController.selectedDayIndex.value = homeController.homeSleepDays.value.length - 1; } }); } getWeekName(int i) { String v = ""; switch (i) { case 1: v = "周一"; break; case 2: v = "周二"; break; case 3: v = "周三"; break; case 4: v = "周四"; break; case 5: v = "周五"; break; case 6: v = "周六"; break; case 7: v = "周日"; break; } return v; } @override Widget build(BuildContext context) { deviceController.getDeviceList(group: 'room').then((apiResponse) { if (apiResponse.code != HttpStatusCodes.ok) { TopSlideNotification.show( context, text: apiResponse.msg!, textColor: themeController.currentColor.sc9, ); } else { //请求睡眠报告 // deviceController.getSleepReport(); } }); if (userInfoController.model.login == 1) { //查询人员信息列表 deviceController.getPersonList(); //请求绑定设备列表 // homeController.getSleepReport(); deviceController.getDeviceNum().then((apiResponse) { if (apiResponse.code != HttpStatusCodes.ok) { TopSlideNotification.show( Get.context!, text: apiResponse.msg!, textColor: themeController.currentColor.sc9, ); } }); deviceController.getDeviceList(group: 'room').then((apiResponse) { if (apiResponse.code != HttpStatusCodes.ok) { TopSlideNotification.show( Get.context!, text: apiResponse.msg!, textColor: themeController.currentColor.sc9, ); } else { //请求睡眠报告 // deviceController.getSleepReport(); } }); } WidgetsBinding.instance.addPostFrameCallback((_) { if (homeController.homeSleepDays.value.isNotEmpty) { homeController.selectedDayIndex.value = homeController.homeSleepDays.value.length - 1; } }); int login = userInfoController.model.login!; return GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/new_background.png'), // 本地图片 fit: BoxFit.fill, // 填满整个 Container ), ), child: Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( iconTheme: IconThemeData(color: themeController.currentColor.sc3), backgroundColor: Colors.transparent, automaticallyImplyLeading: false, titleSpacing: 0, title: Container( height: 180.rpx, child: Row( children: [ // 左侧头像 Obx(() { return InkWell( onTap: () { if (userInfoController.model.login == 0) { Get.toNamed("/loginPage"); } }, child: userInfo(userInfoController.model.login), ); }), const Spacer(), // 左右分隔 FloatingSvgIcon( assetPath: 'assets/img/icon/xiaoyi.svg', width: 60.rpx, height: 60.rpx, onTap: () { print("点击了小鹅图标"); }, ), SizedBox(width: 40.rpx), ], ), ), ), body: SafeArea( child: Container( width: MediaQuery.sizeOf(context).width, height: MediaQuery.sizeOf(context).height * 1.123, child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.max, children: [ //天气 Container( padding: EdgeInsets.fromLTRB(26.rpx, 10.rpx, 26.rpx, 40.rpx), width: double.infinity, child: Padding( padding: EdgeInsets.symmetric(horizontal: 0.rpx), child: Column( children: [ Padding( padding: EdgeInsets.fromLTRB(17.rpx, 30.rpx, 0, 0), child: Row( children: [ Obx(() { return Row( children: [ Text( "${weatherModelController.model.cityName ?? '未知数据'.tr}", style: TextStyle( color: Colors.white, fontSize: AppConstants() .normal_text_fontSize, ), ), Text( "${(weatherModelController.model.current_temperature != null && weatherModelController.model.current_temperature! > 0) ? weatherModelController.model.current_temperature : '未知数据'.tr}" + "°C", style: TextStyle( color: Colors.white, fontSize: AppConstants() .normal_text_fontSize, ), ), Text( "${(weatherModelController.model.weather_info?.isNotEmpty ?? false) ? weatherModelController.model.weather_info : '未知数据'.tr}", style: TextStyle( color: Colors.white, fontSize: AppConstants() .normal_text_fontSize, ), ), if (weatherModelController .model.weatherIconurl != null && weatherModelController.model .weatherIconurl!.isNotEmpty) Container( width: 35.rpx, height: 26.rpx, clipBehavior: Clip.antiAlias, decoration: BoxDecoration( shape: BoxShape.circle), child: Image.network( weatherModelController .model.weatherIconurl!, fit: BoxFit.cover, ), ), ].divide(SizedBox( width: 20.rpx, )), ); }), ], ), ), ], ), ), ), //未登录 Obx(() { if (userInfoController.model.login! == null || userInfoController.model.login! == 0) { return Padding( padding: EdgeInsetsDirectional.fromSTEB( 30.rpx, 0, 30.rpx, 80.rpx), child: ClickableContainer( backgroundColor: Colors.transparent, highlightColor: Colors.transparent, padding: EdgeInsets.all(0), onTap: () { if (userInfoController.model.login == null || userInfoController.model.login == 0) { TopSlideNotification.show(context, text: "请先登录".tr, textColor: themeController.currentColor.sc9); Get.toNamed("/loginPage"); } else { Get.toNamed("/mHTDeviceTypePage"); } }, child: Container( width: MediaQuery.sizeOf(context).width, height: 302.rpx, padding: EdgeInsets.only( top: 90.rpx, bottom: 80.rpx), decoration: BoxDecoration( borderRadius: BorderRadius.circular(borderRadius), border: Border.all( color: stringToColor("#85F5FF"), // 边框颜色 width: 1.rpx, // 边框宽度 ), ), child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ SvgPicture.asset( 'assets/images/icon/add.svg', width: 42.rpx, height: 42.rpx, ), SizedBox( height: 32.rpx, ), Text( '添加一台新设备'.tr, style: TextStyle( color: stringToColor("#85F5FF"), fontSize: AppConstants().normal_text_fontSize, letterSpacing: 0, ), ), ], ), ), ), ); } return Container(); }), //已登录 Obx(() { if (userInfoController.model.login! != null && userInfoController.model.login! == 1) { final list = deviceController.personnelList.value; // 当数据第一次到达时自动赋值 if (list.isNotEmpty && formFieldController.value == null) { WidgetsBinding.instance.addPostFrameCallback((_) { formFieldController.value = list[0]["mac"]; personInfo.value = list[0]; homeController.selectPerson.value = list[0]; homeController.selectDevcie.value = list[0]["mac"]; deviceController .getHomeSleeps(formFieldController.value); homeController.updateAll(); }); } return SingleChildScrollView( child: Column( children: [ if (homeController.personnelList.value.length != 0) Padding( padding: EdgeInsetsDirectional.fromSTEB( 30.rpx, 40.rpx, 30.rpx, 10.rpx), child: Container( width: MediaQuery.sizeOf(context).width, height: MediaQuery.sizeOf(context).height * 0.184, constraints: BoxConstraints( minHeight: 354.rpx, ), decoration: BoxDecoration( color: stringToColor("#003058"), borderRadius: BorderRadius.circular(20.rpx), ), child: Column( mainAxisSize: MainAxisSize.max, children: [ Padding( padding: EdgeInsetsDirectional.fromSTEB( 20.rpx, 20.rpx, 16.rpx, 25.rpx), child: Container( width: MediaQuery.sizeOf(context) .width, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment .spaceBetween, children: [ ScrollbarTheme( data: ScrollbarThemeData( thumbColor: MaterialStateProperty .all(Colors .transparent), trackColor: MaterialStateProperty .all(Colors .transparent), trackBorderColor: MaterialStateProperty .all(Colors .transparent), ), child: ValueListenableBuilder( valueListenable: formFieldController, builder: (c, a, s) => FlutterFlowDropDown< String>( controller: formFieldController, options: deviceController .personnelList.value .map((d) => "${d["mac"]}") .toList(), optionLabels: deviceController .personnelList .value .map( (d) { var s = d["name"] ?? d["mac"]; if (s == null) { return ""; } else { return "$s"; } }).toList(), onChanged: (val) { final list = deviceController .personnelList .value; final selectedPerson = list.firstWhere( (element) => element[ 'mac'] == val, orElse: () => null, // 防止找不到时报错 ); homeController .selectPerson .value = selectedPerson; personInfo.value = selectedPerson; homeController .selectedDayIndex = (6).obs; print("$val"); if (val == null) { homeController .homeSleepDays .value = []; } else { homeController .selectDevcie .value = formFieldController .value!; deviceController .getHomeSleeps( formFieldController .value); homeController .updateAll(); } }, width: 300.rpx, height: 81.rpx, maxHeight: 300.rpx, textStyle: TextStyle( fontSize: 28.rpx, overflow: TextOverflow .ellipsis, color: Colors.white, ), hintText: '', icon: Icon( Icons .keyboard_arrow_down_rounded, color: stringToColor( "#FFFFFF"), size: 30.rpx, ), fillColor: stringToColor( "##011D33"), elevation: 2, borderColor: Colors.transparent, borderWidth: 2, borderRadius: 18, margin: EdgeInsetsDirectional .fromSTEB( 32.rpx, 8.rpx, 32.rpx, 8.rpx), hidesUnderline: true, isOverButton: false, isSearchable: false, isMultiSelect: false, ), ), ), InkWell( onTap: () { if (formFieldController .value != null) { Get.toNamed( "/newSleepReportPage", arguments: { 'mac': formFieldController .value!, 'type': 1, "person": personInfo .value, 'backgroundImg': 'assets/images/new_background.png', 'date': DateTime .now() .millisecondsSinceEpoch, }, ); } }, child: Row( mainAxisSize: MainAxisSize.max, children: [ SizedBox( width: 12.rpx, ), SvgPicture.asset( "assets/images/table.svg", width: 28.rpx, height: 28.rpx, color: stringToColor( "#FFFFFF"), ), SizedBox( width: 20.rpx, ), ], ), ), ], ), ), ), if (homeController .homeSleepDays.value.length == 0) Expanded(child: NullDataWidget()), if (homeController .homeSleepDays.value.length != 0) Container( padding: EdgeInsets.only( top: 0.rpx, bottom: 20.rpx, left: 16.rpx, right: 16.rpx, ), width: double.infinity, decoration: BoxDecoration(), child: Obx(() => Row( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment .start, children: [ ...List.generate( homeController .homeSleepDays .value .length, (index) { var day = homeController .homeSleepDays[ index]; bool isSelected = homeController .selectedDayIndex .value == index; return Expanded( child: GestureDetector( onTap: () { homeController .selectedDayIndex .value = index; int? timeMillis = parseToInt(day[ 'time']); Get.toNamed( "/newSleepReportPage", arguments: { 'date': timeMillis, 'mac': formFieldController .value!, 'type': 1, "person": personInfo .value, 'backgroundImg': 'assets/images/new_background.png', 'date': timeMillis, // 'backgroundColor':stringToColor("#003058"), }, ); }, child: Container( padding: EdgeInsets .only( top: 10.rpx, bottom: 20.rpx, ), width: 90.rpx, decoration: BoxDecoration( color: isSelected ? stringToColor( "#011D33") : Colors .transparent, borderRadius: BorderRadius .circular( 8.rpx), ), child: Column( mainAxisSize: MainAxisSize .max, mainAxisAlignment: MainAxisAlignment .start, crossAxisAlignment: CrossAxisAlignment .center, children: [ Text( day['week'], style: TextStyle( fontFamily: 'Readex Pro', fontSize: 30.rpx, letterSpacing: 0, color: stringToColor( "#FFFFFF"), ), ), SizedBox( height: 12 .rpx), Text( day['date'], // "哈哈", style: TextStyle( fontFamily: 'Readex Pro', letterSpacing: 0, fontSize: 22.rpx, color: stringToColor( "#929699"), ), ), SizedBox( height: 39 .rpx), buildScoreOrIcon( day['score']), ], ), ), ), ); }) ], )), ), ], ), ), ), if (homeController.bindDeviceNum.value != 0) Padding( padding: EdgeInsetsDirectional.fromSTEB( 30.rpx, 40.rpx, 30.rpx, 100.rpx), child: Column( children: homeController .deviceList.entries .map((entry) => HomeDeviceWidget( roomName: entry.key, deviceStatusList: entry.value, )) .toList() .divide(SizedBox(height: 30.rpx)), ), ), if (homeController.bindDeviceNum.value == 0) Padding( padding: EdgeInsetsDirectional.fromSTEB( 30.rpx, 0, 30.rpx, 80.rpx), child: ClickableContainer( backgroundColor: Colors.transparent, highlightColor: Colors.transparent, padding: EdgeInsets.all(0), onTap: () { if (userInfoController.model.login == null || userInfoController.model.login == 0) { TopSlideNotification.show(context, text: "请先登录".tr, textColor: themeController .currentColor.sc9); Get.toNamed("/loginPage"); } else { Get.toNamed("/mHTDeviceTypePage"); } }, child: Container( width: MediaQuery.sizeOf(context).width, height: 302.rpx, padding: EdgeInsets.only( top: 90.rpx, bottom: 80.rpx), decoration: BoxDecoration( borderRadius: BorderRadius.circular( borderRadius), border: Border.all( color: stringToColor( "#85F5FF"), // 边框颜色 width: 1.rpx, // 边框宽度 ), ), child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ SvgPicture.asset( 'assets/images/icon/add.svg', width: 42.rpx, height: 42.rpx, ), SizedBox( height: 32.rpx, ), Text( '添加一台新设备'.tr, style: TextStyle( color: stringToColor("#85F5FF"), fontSize: AppConstants() .normal_text_fontSize, letterSpacing: 0, ), ), ], ), ), ), ), if (homeController.bindDeviceNum.value != 0) Padding( padding: EdgeInsetsDirectional.fromSTEB( 30.rpx, 0.rpx, 30.rpx, 100.rpx), child: ClickableContainer( onTap: () { // 点击逻辑 Get.toNamed("/mHTDeviceTypePage"); }, backgroundColor: Colors.transparent, highlightColor: themeController .currentColor .sc21, // 这里可以自定义高亮色,透明就用 Colors.transparent borderRadius: borderRadius, padding: EdgeInsetsDirectional.fromSTEB( 0.rpx, 0, 0.rpx, 0), child: Container( height: 92.rpx, alignment: Alignment.center, decoration: BoxDecoration( border: Border.all( color: stringToColor( "#85F5FF"), // 边框颜色 width: 1.rpx, // 边框宽度 ), borderRadius: BorderRadius.circular( borderRadius), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ // Icon( // Icons.add, // size: 60.rpx, // color: stringToColor("#85F5FF"), // ), SvgPicture.asset( 'assets/images/icon/add.svg', width: 42.rpx, height: 42.rpx, ), SizedBox(width: 20.rpx), Text( '添加新设备'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: stringToColor("#85F5FF"), letterSpacing: 0, fontSize: 30.rpx, ), ), ], ), ), ), ), ], ), ); } return Container(); }), ], ), ), ), ), ), )); } //1 :登录 0:未登录 Widget userInfo(int? login) { return Row( children: (login == 1) ? [ SizedBox(width: 40.rpx), CircleAvatar( radius: 27.rpx, // 可根据需求调整 backgroundImage: login == 1 ? (userInfoController.model.user!.avatar == null || userInfoController.model.user!.avatar!.isEmpty ? const AssetImage( "assets/images/default_avatar.png", ) : NetworkImage( userInfoController.model.user!.avatar!, )) : const AssetImage( "assets/images/default_avatar.png", ), ), SizedBox(width: 23.rpx), // 左侧头像和文本之间的间距 Text( '${userInfoController.model.user?.nick_name?.isNotEmpty == true ? userInfoController.model.user!.nick_name : '未命名'.tr}', style: TextStyle(fontSize: 30.rpx, color: Colors.white), ) ] : [ SizedBox(width: 40.rpx), CircleAvatar( radius: 27.rpx, // 可根据需求调整 backgroundImage: login == 1 ? (userInfoController.model.user!.avatar == null || userInfoController.model.user!.avatar!.isEmpty ? const AssetImage( "assets/images/default_avatar.png", ) : NetworkImage( userInfoController.model.user!.avatar!, )) : const AssetImage( "assets/images/default_avatar.png", ), ), SizedBox(width: 23.rpx), // 左侧头像和文本之间的间距 Text( '未命名'.tr, style: TextStyle(fontSize: 30.rpx, color: Colors.white), ) ], ); } Widget buildScoreOrIcon(dynamic score) { return SizedBox( width: 50.rpx, height: 50.rpx, child: Center( child: (score != null) ? FittedBox( child: Text( '${score['socre']}', style: TextStyle( fontFamily: 'Readex Pro', fontSize: 40.rpx, letterSpacing: 0, color: Colors.white, ), ), ) : SvgPicture.asset( 'assets/img/icon/close.svg', width: 25.rpx, height: 25.rpx, color: themeController.currentColor.sc3, ), ), ); } int? parseToInt(dynamic value) { if (value == null) return null; if (value is int) return value; if (value is String) return int.tryParse(value); return null; } } class ScoreItem { final String weekday; // 如“周四” final String dateStr; // 如“07/03” final int score; final bool isToday; ScoreItem({ required this.weekday, required this.dateStr, required this.score, this.isToday = false, }); } class ScoreCard extends StatelessWidget { final String selectedUser; final List scoreList; final ValueChanged? onUserChanged; final VoidCallback? onChartPressed; const ScoreCard({ super.key, required this.selectedUser, required this.scoreList, this.onUserChanged, this.onChartPressed, }); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: const Color(0xff0F2B44), borderRadius: BorderRadius.circular(16), ), padding: const EdgeInsets.all(12), child: Column( children: [ // 顶部用户选择 + 图标按钮 Row( children: [ DropdownButtonHideUnderline( child: DropdownButton( value: selectedUser, borderRadius: BorderRadius.circular(12), dropdownColor: const Color(0xff0F2B44), iconEnabledColor: Colors.white, style: const TextStyle(color: Colors.white), items: ['Eason Chan', 'Jay Chou', 'G.E.M.'] .map((user) => DropdownMenuItem( value: user, child: Text(user), )) .toList(), onChanged: onUserChanged, ), ), const Spacer(), IconButton( onPressed: onChartPressed, icon: const Icon(Icons.bar_chart, color: Colors.white), ), ], ), const SizedBox(height: 12), // 日期+分数 横向滚动展示 SizedBox( height: 70, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: scoreList.length, separatorBuilder: (_, __) => const SizedBox(width: 12), itemBuilder: (context, index) { final item = scoreList[index]; final isToday = item.isToday; return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: isToday ? Colors.white.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(item.weekday, style: const TextStyle( color: Colors.white70, fontSize: 12)), Text(item.dateStr, style: const TextStyle( color: Colors.white54, fontSize: 10)), const SizedBox(height: 4), Text( item.score.toString(), style: TextStyle( color: Colors.white, fontWeight: isToday ? FontWeight.bold : FontWeight.normal, fontSize: 16, ), ), ], ), ); }, ), ) ], ), ); } }