diff --git a/lib/pages/main_bottom/component/main_page_b_bottom_change.dart b/lib/pages/main_bottom/component/main_page_b_bottom_change.dart index 14527a2..9ddef08 100644 --- a/lib/pages/main_bottom/component/main_page_b_bottom_change.dart +++ b/lib/pages/main_bottom/component/main_page_b_bottom_change.dart @@ -1,11 +1,9 @@ - import 'package:flutter/material.dart'; import 'package:vbvs_app/pages/common/bezier_bottom_navigation_bar.dart'; import 'package:vbvs_app/pages/mh_page/MattressControl.dart'; +import 'package:vbvs_app/pages/mh_page/homepage/mht_sleep_report_page.dart'; import 'package:vbvs_app/pages/mh_page/homepage/new_Home_page.dart'; -import 'package:vbvs_app/pages/mh_page/device_list.dart'; import 'package:vbvs_app/pages/mh_page/new_mine_page.dart'; -import 'package:vbvs_app/pages/mh_page/user/page/register_page.dart'; class MainPageBBottomChange extends StatefulWidget { @override @@ -33,7 +31,7 @@ class _HomePageState extends State // Text('报告'), // RegisterPage(), // ShareDeviceWidget(), - DeviceListPage(), + MhtSleepReportPage(), // FindPasswordPage(), // Smys(), MattressControlPage(), diff --git a/lib/pages/mh_page/homepage/controller/mht_home_controller.dart b/lib/pages/mh_page/homepage/controller/mht_home_controller.dart index 8434e79..9bcb6ef 100644 --- a/lib/pages/mh_page/homepage/controller/mht_home_controller.dart +++ b/lib/pages/mh_page/homepage/controller/mht_home_controller.dart @@ -50,6 +50,9 @@ class MHTHomeController extends GetControllerEx { var selectedDayIndex = (6).obs; + var selectDevcie = ''.obs; + var selectPerson = {}.obs; + Future getDeviceNum() async { try { ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr); diff --git a/lib/pages/mh_page/homepage/mht_sleep_report_page.dart b/lib/pages/mh_page/homepage/mht_sleep_report_page.dart new file mode 100644 index 0000000..a620fd8 --- /dev/null +++ b/lib/pages/mh_page/homepage/mht_sleep_report_page.dart @@ -0,0 +1,371 @@ +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'; +import 'package:vbvs_app/pages/sleep_report/mht_new_sleep_report_page.dart'; + +class MhtSleepReportPage extends StatefulWidget { + const MhtSleepReportPage({super.key}); + @override + State createState() => _MhtSleepReportPageState(); +} + +class _MhtSleepReportPageState 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.sleepDays.value.isNotEmpty) { + homeController.selectedDayIndex.value = + homeController.sleepDays.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( + Get.context!, + text: apiResponse.msg!, + textColor: themeController.currentColor.sc9, + ); + } else { + //请求睡眠报告 + // deviceController.getSleepReport(); + } + }); + 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, + body: SafeArea( + child: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: (userInfoController.model.login! != null && + userInfoController.model.login! == 1) + ? MainAxisAlignment.start + : MainAxisAlignment.center, + children: [ + //未登录 + Obx(() { + if (userInfoController.model.login! == null || + userInfoController.model.login! == 0) { + return Text( + "登录查看睡眠报告".tr, + style: + TextStyle(color: Colors.white, fontSize: 30.rpx), + ); + } + 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 + .getSleeps(formFieldController.value); + homeController.updateAll(); + }); + } + if (homeController.personnelList.value.length != 0) + return Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.rpx, 40.rpx, 30.rpx, 10.rpx), + child: Container( + width: MediaQuery.sizeOf(context).width, + // height: + // MediaQuery.sizeOf(context).height * + // 0.033, + constraints: BoxConstraints( + minHeight: 60.rpx, + ), + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(20.rpx), + ), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 16.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) => ClipRRect( + borderRadius: + BorderRadius.circular( + 36.rpx), + child: Theme( + data: Theme.of(context) + .copyWith( + splashColor: + Colors.transparent, + highlightColor: + Colors.transparent, + hoverColor: + Colors.transparent, + ), + child: 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.sleepDays + .value = []; + } else { + homeController + .selectDevcie + .value = + formFieldController + .value!; + deviceController.getSleeps( + 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( + "#184468"), + elevation: 2, + borderColor: + Colors.transparent, + borderWidth: 2, + borderRadius: 0.rpx, + margin: + EdgeInsetsDirectional + .fromSTEB( + 32.rpx, + 8.rpx, + 32.rpx, + 8.rpx), + hidesUnderline: true, + isOverButton: false, + isSearchable: false, + isMultiSelect: false, + ), + ))), + ), + ], + ), + ), + ), + ), + ); + } + 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 + .getSleeps(formFieldController.value); + homeController.updateAll(); + }); + } + if (homeController.selectDevcie.value != null && + homeController.selectDevcie.value!.isNotEmpty) + return Expanded( + child: MHTNewSleepReportPage( + data: { + 'date': DateTime.now().millisecondsSinceEpoch, + 'mac': homeController.selectDevcie.value, + 'person': homeController.selectPerson.value, + 'backgroundImg': + 'assets/images/new_background.png', + }, + ), + ); + } + return Container(); + }), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/pages/mh_page/homepage/new_Home_page.dart b/lib/pages/mh_page/homepage/new_Home_page.dart index 9267e45..8ea666a 100644 --- a/lib/pages/mh_page/homepage/new_Home_page.dart +++ b/lib/pages/mh_page/homepage/new_Home_page.dart @@ -307,10 +307,16 @@ class _NewHomePageState extends State { // 当数据第一次到达时自动赋值 if (list.isNotEmpty && formFieldController.value == null) { - formFieldController.value = list[0]["mac"]; - personInfo.value = list[0]; - deviceController - .getSleeps(formFieldController.value); + WidgetsBinding.instance.addPostFrameCallback((_) { + formFieldController.value = list[0]["mac"]; + personInfo.value = list[0]; + homeController.selectPerson.value = list[0]; + homeController.selectDevcie.value = + list[0]["mac"]; + deviceController + .getSleeps(formFieldController.value); + homeController.updateAll(); + }); } return SingleChildScrollView( child: Column( @@ -409,7 +415,10 @@ class _NewHomePageState extends State { orElse: () => null, // 防止找不到时报错 ); - + homeController + .selectPerson + .value = + selectedPerson; personInfo.value = selectedPerson; @@ -422,10 +431,17 @@ class _NewHomePageState extends State { .sleepDays .value = []; } else { + homeController + .selectDevcie + .value = + formFieldController + .value!; deviceController .getSleeps( formFieldController .value); + homeController + .updateAll(); } }, width: 300.rpx, diff --git a/lib/pages/sleep_report/mht_new_sleep_report_page.dart b/lib/pages/sleep_report/mht_new_sleep_report_page.dart new file mode 100644 index 0000000..0cde4a8 --- /dev/null +++ b/lib/pages/sleep_report/mht_new_sleep_report_page.dart @@ -0,0 +1,1020 @@ +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/util/FitTool.dart'; +import 'package:vbvs_app/common/util/MyUtils.dart'; +import 'package:vbvs_app/common/util/requestWithLog.dart'; +import 'package:vbvs_app/component/tool/ClickableContainer.dart'; +import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; +import 'package:vbvs_app/controller/date/CalendarController.dart'; +import 'package:vbvs_app/controller/sleep/sleep_report_controller.dart'; +import 'package:vbvs_app/language/AppLanguage.dart'; +import 'package:vbvs_app/pages/common/selectDialog.dart'; +import 'package:vbvs_app/pages/sleep_report/component/AIAdviceWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/BreatheCard.dart'; +import 'package:vbvs_app/pages/sleep_report/component/BreathePauseNewWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/BreatheStandardWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/CompareSleepWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/DiseasePercentsWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/HeartChangeWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/HeartHealthWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/HeartPointWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/HeartRateCard.dart'; +import 'package:vbvs_app/pages/sleep_report/component/HeartRateStandardWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/SkinPercentWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/SleepCard.dart'; +import 'package:vbvs_app/pages/sleep_report/component/SleepScoreWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/SleepView.dart'; +import 'package:vbvs_app/pages/sleep_report/component/SnoreViewWidget.dart'; +import 'package:vbvs_app/pages/sleep_report/component/ZiZhuShenJingPercentWidget.dart'; + +class MHTNewSleepReportPage extends StatefulWidget { + var data; + MHTNewSleepReportPage({super.key, required this.data}); + + @override + State createState() => _MHTNewSleepReportPageState(); +} + +class _MHTNewSleepReportPageState extends State { + SleepReportController sleepReportController = Get.find(); + CalendarController calendarController = Get.find(); + + final GlobalKey sleepCardKey = GlobalKey(); + final GlobalKey heartRateCardKey = GlobalKey(); + final GlobalKey breatheCardKey = GlobalKey(); + final ScrollController _scrollController = ScrollController(); + + @override + void didUpdateWidget(MHTNewSleepReportPage oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.data['name'] != oldWidget.data['name'] || + widget.data['itemId'] != oldWidget.data['itemId']) { + _scrollToTargetComponent(sleepReportController.sleepReport); + } + } + + @override + void initState() { + sleepReportController.sleepReport.value = {}; + if (widget.data['date'] == null) { + widget.data['date'] = DateTime.now(); + } + calendarController.selectedDate.value = + DateTime.fromMillisecondsSinceEpoch(widget.data['date']); + sleepReportController.selectedDate.value = + DateTime.fromMillisecondsSinceEpoch(widget.data['date']); + if (widget.data['type'] != null) { + sleepReportController.model.type = widget.data['type']; + } else { + sleepReportController.model.type = 1; + } + String date = MyUtils.formatToDate(widget.data['date']); + // String date = '2025-5-27'; + requestWithLog( + logTitle: "查询睡眠报告", + method: MyHttpMethod.get, + queryUrl: + "https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${date}&type=${sleepReportController.model.type}", + onSuccess: (res) { + print(res); + sleepReportController.sleepReport.value = res.data; + sleepReportController.updateAll(); + _scrollToTargetComponent(sleepReportController.sleepReport); + }, + onFailure: (res) { + TopSlideNotification.show(context, + text: res.msg!, textColor: themeController.currentColor.sc9); + sleepReportController.sleepReport.value = {}; + sleepReportController.updateAll(); + print(res); + }); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + double lineWidth = 115.rpx; + return LayoutBuilder( + builder: (context, bodySize) => GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: (widget.data['backgroundImg'] != null && + widget.data['backgroundImg'].toString().isNotEmpty) + ? AssetImage(widget.data['backgroundImg']) + : AssetImage('assets/img/bgNoImg.png') as ImageProvider, + fit: BoxFit.fill, + ), + ), + child: Scaffold( + backgroundColor: Colors.transparent, // 背景透明 + appBar: AppBar( + backgroundColor: widget.data['backgroundColor'] != null + ? widget.data['backgroundColor'].withOpacity(0.8) + : themeController.currentColor.sc5, + automaticallyImplyLeading: false, + iconTheme: IconThemeData(color: themeController.currentColor.sc3), + titleSpacing: 0, + title: Container( + width: double.infinity, + height: 180.rpx, + child: Stack( + alignment: Alignment.center, + children: [ + /// 居中标题 + Text( + '健康报告'.tr, + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: 'Readex Pro', + color: themeController.currentColor.sc3, + letterSpacing: 0, + fontSize: 30.rpx, + ), + ), + + /// 左边返回按钮 + if (widget.data['arrow'] == null || + widget.data['arrow'] == true) + Positioned( + left: 0, + child: returnIconButtom, + ), + ], + ), + ), + ), + body: SafeArea( + top: true, + child: SingleChildScrollView( + child: Obx(() { + var sleepReport = sleepReportController.sleepReport; + print(sleepReport); + return Column( + children: [ + Padding( + padding: + EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0), + child: Container( + width: double.infinity, + constraints: BoxConstraints( + minHeight: 90.rpx, + ), + decoration: BoxDecoration( + color: widget.data['backgroundColor'] != null + ? widget.data['backgroundColor'] + : themeController.currentColor.sc5, + ), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 15.rpx, 30.rpx, 15.rpx), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Stack( + alignment: Alignment.bottomLeft, + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: + themeController.currentColor.sc3, + borderRadius: 8.rpx, + padding: EdgeInsets.all(0), + onTap: () async { + sleepReportController.model.type = + 1; + sleepReportController.updateAll(); + }, + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + width: 115.rpx, // 固定宽度为 160.rpx + alignment: + Alignment.center, // 文字居中 + child: Text( + '日报'.tr, + style: FlutterFlowTheme.of( + context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: AppConstants() + .title_text_fontSize, + letterSpacing: 0.0, + color: + sleepReportController + .model + .type == + 1 + ? themeController + .currentColor + .sc2 + : themeController + .currentColor + .sc3, + ), + ), + ), + SizedBox(height: 10.rpx), + ], + ), + ), + + // Obx(() { + // return ClickableContainer( + // backgroundColor: Colors.transparent, + // highlightColor: + // themeController.currentColor.sc3, + // borderRadius: 8.rpx, + // padding: EdgeInsets.all(0), + // onTap: () async { + // sleepReportController.model.type = + // 2; + // sleepReportController.updateAll(); + // }, + // child: Column( + // mainAxisSize: MainAxisSize.max, + // children: [ + // Container( + // width: 115.rpx, // 固定宽度为 160.rpx + // alignment: + // Alignment.center, // 文字居中 + // child: Text( + // '周报'.tr, + // style: FlutterFlowTheme.of( + // context) + // .bodyMedium + // .override( + // fontFamily: 'Inter', + // fontSize: AppConstants() + // .title_text_fontSize, + // letterSpacing: 0.0, + // color: + // sleepReportController + // .model + // .type == + // 2 + // ? themeController + // .currentColor + // .sc2 + // : themeController + // .currentColor + // .sc3, + // ), + // ), + // ), + // SizedBox(height: 10.rpx), + // ], + // ), + // ); + // }), + // Obx(() { + // return ClickableContainer( + // backgroundColor: Colors.transparent, + // highlightColor: + // themeController.currentColor.sc3, + // borderRadius: 8.rpx, + // padding: EdgeInsets.all(0), + // onTap: () async { + // sleepReportController.model.type = + // 3; + // sleepReportController.updateAll(); + // }, + // child: Column( + // mainAxisSize: MainAxisSize.max, + // children: [ + // Container( + // width: 115.rpx, // 固定宽度为 160.rpx + // alignment: + // Alignment.center, // 文字居中 + // child: Text( + // '月报'.tr, + // style: FlutterFlowTheme.of( + // context) + // .bodyMedium + // .override( + // fontFamily: 'Inter', + // fontSize: AppConstants() + // .title_text_fontSize, + // letterSpacing: 0.0, + // color: + // sleepReportController + // .model + // .type == + // 3 + // ? themeController + // .currentColor + // .sc2 + // : themeController + // .currentColor + // .sc3, + // ), + // ), + // ), + // SizedBox(height: 10.rpx), + // ], + // ), + // ); + // }), + ], + ), + AnimatedPositioned( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + bottom: 0, + left: sleepReportController.model.type == + 1 + ? 0 + : sleepReportController.model.type == + 2 + ? 115.rpx + : 230.rpx, + child: Container( + width: lineWidth, + height: 4.rpx, + decoration: BoxDecoration( + color: + themeController.currentColor.sc2, + borderRadius: + BorderRadius.circular(2.rpx), + ), + ), + ), + ], + ), + // Padding( + // padding: EdgeInsetsDirectional.fromSTEB( + // 0, 0.rpx, 0.rpx, 0), + // child: Container( + // width: 28.rpx, + // height: 28.rpx, + // // width: double.infinity, + // decoration: BoxDecoration(), + // child: SvgPicture.asset( + // 'assets/img/icon/share.svg', + // fit: BoxFit.cover, + // color: themeController.currentColor.sc3, + // ), + // ), + // ), + ], + ), + ), + ), + ), + Container( + width: double.infinity, + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 32.rpx, 30.rpx, 32.rpx), + child: getTimeWidget(), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 58.rpx), + child: ClickableContainer( + backgroundColor: + widget.data['backgroundColor'] != null + ? widget.data['backgroundColor'] + : themeController.currentColor.sc5, + highlightColor: + themeController.currentColor.sc5, // 或你希望的点击水波纹颜色 + borderRadius: AppConstants() + .normal_container_radius, // 如果你想加圆角可以设置 eg. 12.rpx + padding: EdgeInsets.zero, + onTap: () {}, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ + Text( + '姓名'.tr, + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc4, + ), + ), + Text( + '年龄'.tr, + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc4, + ), + ), + ].divide(SizedBox(height: 34.rpx)), + ), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + (widget.data['person']?['name'] + ?.toString() + .trim() + .isNotEmpty ?? + false) + ? widget + .data['person']!['name'] + .toString() + : '未知数据'.tr, + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + Text( + '${MyUtils.getAgeByDate(MyUtils.formatBirthdayTime(widget.data['person']?['birthday'])) ?? '未知数据'.tr}', + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ].divide(SizedBox(height: 34.rpx)), + ), + ] + .divide(SizedBox(width: 33.rpx)) + .addToStart(SizedBox(width: 37.rpx)), + ), + ] + .addToStart(SizedBox(height: 36.rpx)) + .addToEnd(SizedBox(height: 36.rpx)), + ), + ), + Flexible( + flex: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ + Text( + '设备ID'.tr, + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc4, + ), + ), + Text( + '体重'.tr, + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc4, + ), + ), + ].divide(SizedBox(height: 34.rpx)), + ), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${widget.data['code'] ?? '未知数据'.tr}', + // "D11250300003", + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + '${widget.data['person']?['weight'] ?? '未知数据'.tr}kg', + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ].divide(SizedBox(height: 34.rpx)), + ), + ] + .divide(SizedBox(width: 33.rpx)) + .addToStart(SizedBox(width: 37.rpx)), + ), + ] + .addToStart(SizedBox(height: 36.rpx)) + .addToEnd(SizedBox(height: 36.rpx)), + ), + ), + ], + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: + SleepScoreWidget(sleepReport: sleepReport.value), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: SleepViewWidget( + sleepReport: sleepReport, + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + key: sleepCardKey, + width: double.infinity, + child: SleepCard( + sleepReport: sleepReport, + highlightItem: widget.data['itemName'] ?? null, + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: CompareSleepWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: HeartPointWidget( + sleepReport: sleepReport, + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: AIAdviceWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: + HeartRateStandardWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + key: heartRateCardKey, + width: double.infinity, + child: HeartRateCard( + sleepReport: sleepReport, + highlightItem: widget.data['itemName'] ?? null, + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: HeartChangeWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: + BreatheStandardWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + key: breatheCardKey, + width: double.infinity, + child: BreatheCard( + sleepReport: sleepReport, + highlightItem: widget.data['itemName'] ?? null, + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: + SnoreViewWidgetWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: + BreathePauseNewWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: HeartHealthWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: + DiseasePercentsWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: SkinPercentWidget(sleepReport: sleepReport), + ), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0), + child: Container( + width: double.infinity, + child: ZiZhuShenJingPercentWidget( + sleepReport: sleepReport), + ), + ), + ].divide(SizedBox( + height: 25.rpx, + )), + ); + }), + ), + ), + ), + ), + ), + ); + } + + Widget getTimeWidget() { + final selectedDate = sleepReportController.selectedDate.value!; + final type = sleepReportController.model.type; + bool isChinese = AppLanguage().isChinese(); + String displayText = ''; + if (isChinese) { + if (type == 1) { + // 日报 + displayText = + MyUtils.getFormatChineseTime(selectedDate.millisecondsSinceEpoch); + } else if (type == 2) { + // 周报 + final startOfWeek = + selectedDate.subtract(Duration(days: selectedDate.weekday - 1)); + final endOfWeek = startOfWeek.add(const Duration(days: 6)); + displayText = + '${MyUtils.getFormatChineseTime(startOfWeek.millisecondsSinceEpoch, showWeekday: false)}-${MyUtils.getFormatChineseTime(endOfWeek.millisecondsSinceEpoch, showWeekday: false)}'; + } else if (type == 3) { + // 月报 + displayText = + '${selectedDate.year}年${selectedDate.month.toString().padLeft(2, '0')}月'; + } + } else { + if (type == 1) { + // Daily Report + displayText = + MyUtils.getFormatEnglishDate(selectedDate.millisecondsSinceEpoch); + } else if (type == 2) { + // Weekly Report + final startOfWeek = + selectedDate.subtract(Duration(days: selectedDate.weekday - 1)); + final endOfWeek = startOfWeek.add(const Duration(days: 6)); + displayText = + '${MyUtils.getFormatEnglishDate(startOfWeek.millisecondsSinceEpoch)} - ${MyUtils.getFormatEnglishDate(endOfWeek.millisecondsSinceEpoch)}'; + } else if (type == 3) { + // Monthly Report + displayText = + '${_getEnglishMonthName(selectedDate.month)} ${selectedDate.year}'; + } + } + + void onLeftArrowTap() { + if (type == 1) { + sleepReportController.selectedDate.value = + selectedDate.subtract(const Duration(days: 1)); + } else if (type == 2) { + sleepReportController.selectedDate.value = + selectedDate.subtract(const Duration(days: 7)); + } else if (type == 3) { + sleepReportController.selectedDate.value = DateTime( + selectedDate.year, + selectedDate.month - 1, + selectedDate.day, + ); + } + calendarController.selectedDate.value = + sleepReportController.selectedDate.value; + // String date = MyUtils.formatToDate(widget.data['date']); + String data = MyUtils.formatDate(calendarController.selectedDate.value!); + requestWithLog( + logTitle: "查询睡眠报告", + method: MyHttpMethod.get, + queryUrl: + "https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${data}&type=${sleepReportController.model.type}", + onSuccess: (res) { + print(res); + sleepReportController.sleepReport.value = res.data; + sleepReportController.updateAll(); + }, + onFailure: (res) { + TopSlideNotification.show(context, + text: res.msg!, textColor: themeController.currentColor.sc9); + sleepReportController.sleepReport.value = {}; + sleepReportController.updateAll(); + print(res); + }); + + sleepReportController.updateAll(); + calendarController.updateAll(); + } + + void onRightArrowTap() { + if (type == 1) { + sleepReportController.selectedDate.value = + selectedDate.add(const Duration(days: 1)); + } else if (type == 2) { + sleepReportController.selectedDate.value = + selectedDate.add(const Duration(days: 7)); + } else if (type == 3) { + sleepReportController.selectedDate.value = DateTime( + selectedDate.year, + selectedDate.month + 1, + selectedDate.day, + ); + } + calendarController.selectedDate.value = + sleepReportController.selectedDate.value; + String data = MyUtils.formatDate(calendarController.selectedDate.value!); + requestWithLog( + logTitle: "查询睡眠报告", + method: MyHttpMethod.get, + queryUrl: + "https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${data}&type=${sleepReportController.model.type}", + onSuccess: (res) { + print(res); + sleepReportController.sleepReport.value = res.data; + sleepReportController.updateAll(); + }, + onFailure: (res) { + TopSlideNotification.show(context, + text: res.msg!, textColor: themeController.currentColor.sc9); + sleepReportController.sleepReport.value = {}; + sleepReportController.updateAll(); + print(res); + }); + sleepReportController.updateAll(); + calendarController.updateAll(); + } + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(width: 28.rpx, height: 28.rpx), // 占位 + Row( + children: [ + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: themeController.currentColor.sc3, + padding: EdgeInsets.all(10.rpx), + borderRadius: 8.rpx, + onTap: onLeftArrowTap, + child: SizedBox( + width: 9.rpx, + height: 14.rpx, + child: SvgPicture.asset( + 'assets/img/icon/arrow_left.svg', + color: themeController.currentColor.sc3, + ), + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 26.rpx), + child: Text( + displayText, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc3, + ), + ), + ), + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: themeController.currentColor.sc3, + padding: EdgeInsets.all(10.rpx), + borderRadius: 8.rpx, + onTap: onRightArrowTap, + child: SizedBox( + width: 9.rpx, + height: 14.rpx, + child: SvgPicture.asset( + 'assets/img/icon/arrow_right.svg', + color: themeController.currentColor.sc3, + ), + ), + ), + ], + ), + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: themeController.currentColor.sc3, + padding: EdgeInsets.zero, + borderRadius: 8, + onTap: () { + showSleepCalendarBottomSheet( + type: sleepReportController.model.type, + timestamp: selectedDate.millisecondsSinceEpoch, + context: context, + onDateSelected: (newDate) { + sleepReportController.selectedDate.value = newDate; + calendarController.selectedDate.value = newDate; + String data = + MyUtils.formatDate(calendarController.selectedDate.value!); + requestWithLog( + logTitle: "查询睡眠报告", + method: MyHttpMethod.get, + queryUrl: + "https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${data}&type=${sleepReportController.model.type}", + onSuccess: (res) { + print(res); + sleepReportController.sleepReport.value = res.data; + sleepReportController.updateAll(); + }, + onFailure: (res) { + TopSlideNotification.show(context, + text: res.msg!, + textColor: themeController.currentColor.sc9); + sleepReportController.sleepReport.value = {}; + sleepReportController.updateAll(); + print(res); + }); + sleepReportController.updateAll(); + calendarController.updateAll(); + }, + ); + }, + child: SizedBox( + width: 28.rpx, + height: 28.rpx, + child: SvgPicture.asset( + 'assets/img/icon/calendar.svg', + fit: BoxFit.cover, + color: themeController.currentColor.sc3, + ), + ), + ), + ], + ); + } + + static String _getEnglishMonthName(int month) { + const monthNames = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ]; + return monthNames[month - 1]; + } + + void _scrollToTargetComponent(RxMap sleepReport) { + if (sleepReport.isEmpty) { + return; + } + WidgetsBinding.instance.addPostFrameCallback((_) { + final targetName = widget.data['name']; + final targetID = widget.data['itemName']; + GlobalKey? targetKey; + + List sleepdata = sleepReport['bs'] ?? []; // 睡眠数据 + List heartdata = sleepReport['hrs'] ?? []; // 心率数据 + List breathedata = sleepReport['brs'] ?? []; // 呼吸数据 + + if (sleepdata.any((e) => e['id'] == targetID)) { + targetKey = sleepCardKey; + } else if (heartdata.any((e) => e['id'] == targetID)) { + targetKey = heartRateCardKey; + } else if (breathedata.any((e) => e['id'] == targetID)) { + targetKey = breatheCardKey; + } else { + return; + } + + if (targetKey?.currentContext != null) { + Scrollable.ensureVisible( + targetKey!.currentContext!, + duration: Duration(milliseconds: 500), + curve: Curves.easeInOut, + alignment: 0.1, + ); + } + }); + } +} diff --git a/lib/pages/sleep_report/new_sleep_report_page.dart b/lib/pages/sleep_report/new_sleep_report_page.dart index 1135d03..f83456c 100644 --- a/lib/pages/sleep_report/new_sleep_report_page.dart +++ b/lib/pages/sleep_report/new_sleep_report_page.dart @@ -142,10 +142,12 @@ class _NewSleepReportPageState extends State { ), /// 左边返回按钮 - Positioned( - left: 0, - child: returnIconButtom, - ), + if (widget.data['arrow'] == null || + widget.data['arrow'] == true) + Positioned( + left: 0, + child: returnIconButtom, + ), ], ), ),