From 1cc26aa46d5dbf25362d014381b41842ae80b814 Mon Sep 17 00:00:00 2001 From: wyf <494641114@qq.com> Date: Mon, 1 Dec 2025 15:41:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/langs/en_US.json | 4 +- lib/common/pojo/city.dart | 139 ++++- lib/common/util/ListSearchWidget.dart | 24 +- lib/controller/home/Dio.dart | 46 ++ lib/main.dart | 9 +- lib/pages/common/selectDialog.dart | 3 + lib/pages/device/BodyDeviceWidget.dart | 221 ++++---- lib/pages/device_bind/device_calibration.dart | 14 +- .../device_calibration_person.dart | 12 +- lib/pages/login/other_login.dart | 37 ++ lib/pages/main_bottom/mine_page.dart | 2 +- lib/pages/person/select_city.dart | 476 +----------------- .../sleep_report/chart/LineChartByRange.dart | 1 + .../sleep_report/chart/SleepRadarChart.dart | 119 ++++- .../sleep_report/component/BreatheCard.dart | 5 + .../component/DailyDataWidget.dart | 3 +- .../sleep_report/component/HeartRateCard.dart | 29 +- .../sleep_report/new_sleep_report_page.dart | 35 +- 18 files changed, 502 insertions(+), 677 deletions(-) create mode 100644 lib/controller/home/Dio.dart diff --git a/assets/langs/en_US.json b/assets/langs/en_US.json index 03128b8..8fe65c1 100644 --- a/assets/langs/en_US.json +++ b/assets/langs/en_US.json @@ -414,8 +414,8 @@ "呼吸数据介绍": "Respiration data refers to basic respiration metrics during sleep, serving as core indicators for evaluating sleep respiration quality and screening sleep breathing disorders.", "心率散点图": "Heart rate scatter plot", "心率散点图介绍": "The ECG scatter plot is a nonlinear graphical method for recording continuous heart rate RR interval diagrams, also called scatter plots as they consist of scattered points.", - "今日数据": "yesterday", - "昨日数据": "today", + "今日数据": "today", + "昨日数据": "yesterday", "次": "times", "秒": "sec", "暂无": "None", diff --git a/lib/common/pojo/city.dart b/lib/common/pojo/city.dart index 9372024..aab1327 100644 --- a/lib/common/pojo/city.dart +++ b/lib/common/pojo/city.dart @@ -221,6 +221,39 @@ class CityModelController extends GetControllerEx { // 检查是否已加载数据 bool get isDataLoaded => cityList.isNotEmpty; + // void searchCities(String keyword) { + // model.keyword = keyword; + // searchResults?.clear(); + + // if (keyword.isEmpty) { + // return; + // } + + // final keywordLower = keyword.toLowerCase(); + + // // 遍历所有城市数据 + // for (var country in cityList) { + // final countryName = country.value ?? country.country ?? ''; + + // for (var province in country.children ?? []) { + // final provinceName = province.value ?? province.province ?? ''; + + // for (var city in province.children ?? []) { + // final cityName = city.value ?? city.city ?? ''; + // final displayName = '$countryName-$provinceName-$cityName'; + + // // 模糊匹配 + // if (countryName.toLowerCase().contains(keywordLower) || + // provinceName.toLowerCase().contains(keywordLower) || + // cityName.toLowerCase().contains(keywordLower) || + // displayName.toLowerCase().contains(keywordLower)) { + // searchResults?.add(displayName); + // } + // } + // } + // } + // } + void searchCities(String keyword) { model.keyword = keyword; searchResults?.clear(); @@ -231,23 +264,43 @@ class CityModelController extends GetControllerEx { final keywordLower = keyword.toLowerCase(); - // 遍历所有城市数据 for (var country in cityList) { final countryName = country.value ?? country.country ?? ''; - for (var province in country.children ?? []) { + // 如果该国家没有 children(一级结构) + if (country.children == null || country.children!.isEmpty) { + final name = countryName; + if (name.toLowerCase().contains(keywordLower)) { + searchResults?.add(name); + } + continue; + } + + // 二层循环:省份或城市 + for (var province in country.children!) { final provinceName = province.value ?? province.province ?? ''; + final level2Name = '$countryName-$provinceName'; - for (var city in province.children ?? []) { + // 省本身是否匹配(适用于 国家→省 二级结构) + if (province.children == null || province.children!.isEmpty) { + if (countryName.toLowerCase().contains(keywordLower) || + provinceName.toLowerCase().contains(keywordLower) || + level2Name.toLowerCase().contains(keywordLower)) { + searchResults?.add(level2Name); + } + continue; + } + + // 有第三级城市 → 遍历城市 + for (var city in province.children!) { final cityName = city.value ?? city.city ?? ''; - final displayName = '$countryName-$provinceName-$cityName'; + final level3Name = '$countryName-$provinceName-$cityName'; - // 模糊匹配 if (countryName.toLowerCase().contains(keywordLower) || provinceName.toLowerCase().contains(keywordLower) || cityName.toLowerCase().contains(keywordLower) || - displayName.toLowerCase().contains(keywordLower)) { - searchResults?.add(displayName); + level3Name.toLowerCase().contains(keywordLower)) { + searchResults?.add(level3Name); } } } @@ -255,27 +308,77 @@ class CityModelController extends GetControllerEx { } // 根据显示名称获取对应的 CityModel + // CityModel? getCityByDisplayName(String displayName) { + // final parts = displayName.split('-'); + // if (parts.length != 3) return null; + + // final countryName = parts[0]; + // final provinceName = parts[1]; + // final cityName = parts[2]; + + // for (var country in cityList) { + // if ((country.value ?? country.country ?? '') == countryName) { + // for (var province in country.children ?? []) { + // if ((province.value ?? province.province ?? '') == provinceName) { + // for (var city in province.children ?? []) { + // if ((city.value ?? city.city ?? '') == cityName) { + // return city; + // } + // } + // } + // } + // } + // } + // return null; + // } CityModel? getCityByDisplayName(String displayName) { final parts = displayName.split('-'); - if (parts.length != 3) return null; + + if (parts.isEmpty) return null; final countryName = parts[0]; - final provinceName = parts[1]; - final cityName = parts[2]; + final provinceName = parts.length >= 2 ? parts[1] : null; + final cityName = parts.length >= 3 ? parts[2] : null; for (var country in cityList) { - if ((country.value ?? country.country ?? '') == countryName) { - for (var province in country.children ?? []) { - if ((province.value ?? province.province ?? '') == provinceName) { - for (var city in province.children ?? []) { - if ((city.value ?? city.city ?? '') == cityName) { - return city; - } - } + final cName = country.value ?? country.country ?? ''; + if (cName != countryName) continue; + + // 一级结构:直接 return 国家 + if (provinceName == null) { + return country; + } + + // 如果没有 children,就不可能有省或市 + if (country.children == null || country.children!.isEmpty) { + return null; + } + + // 二级匹配:省或城市 + for (var province in country.children!) { + final pName = province.value ?? province.province ?? ''; + if (pName != provinceName) continue; + + // 二级结构:国家-省 + if (cityName == null) { + return province; + } + + // 有城市才继续 + if (province.children == null || province.children!.isEmpty) { + return null; + } + + // 三级结构:国家-省-市 + for (var city in province.children!) { + final ciName = city.value ?? city.city ?? ''; + if (ciName == cityName) { + return city; } } } } + return null; } } diff --git a/lib/common/util/ListSearchWidget.dart b/lib/common/util/ListSearchWidget.dart index d01727f..e6aabc0 100644 --- a/lib/common/util/ListSearchWidget.dart +++ b/lib/common/util/ListSearchWidget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; +import 'package:vbvs_app/component/tool/ClickableContainer.dart'; import '../../common/util/MyUtils.dart'; class ListSearchWidget extends GetView { @@ -38,7 +39,8 @@ class ListSearchWidget extends GetView { children: [ // 搜索框部分 Padding( - padding: padding ?? EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0), + padding: + padding ?? EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0), child: Container( width: double.infinity, decoration: BoxDecoration( @@ -46,7 +48,7 @@ class ListSearchWidget extends GetView { borderRadius: BorderRadius.circular(16.rpx), ), child: Padding( - padding: EdgeInsetsDirectional.fromSTEB(35.rpx, 0, 35.rpx, 0), + padding: EdgeInsetsDirectional.fromSTEB(35.rpx, 0, 0.rpx, 0), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -139,7 +141,9 @@ class ListSearchWidget extends GetView { }, onTap: () { // 点击输入框时显示结果列表(如果开启了显示功能且有搜索结果) - if (showResultList && searchResults != null && searchResults!.isNotEmpty) { + if (showResultList && + searchResults != null && + searchResults!.isNotEmpty) { _showResults.value = true; } }, @@ -151,8 +155,12 @@ class ListSearchWidget extends GetView { ), ), Padding( - padding: EdgeInsetsDirectional.fromSTEB(26.rpx, 0, 0, 0), - child: InkWell( + padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 0, 0, 0), + child: ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: + themeController.currentColor.sc4.withOpacity(0.8), + padding: EdgeInsets.fromLTRB(0, 0, 35.rpx, 0), onTap: () { findCallback?.call(); // 点击搜索按钮后显示结果列表(如果开启了显示功能) @@ -192,7 +200,9 @@ class ListSearchWidget extends GetView { // 搜索结果列表(可选显示) if (showResultList) ...[ Obx(() { - if (!_showResults.value || searchResults == null || searchResults!.isEmpty) { + if (!_showResults.value || + searchResults == null || + searchResults!.isEmpty) { return SizedBox.shrink(); } @@ -244,4 +254,4 @@ class ListSearchWidget extends GetView { ], ); } -} \ No newline at end of file +} diff --git a/lib/controller/home/Dio.dart b/lib/controller/home/Dio.dart new file mode 100644 index 0000000..8f82702 --- /dev/null +++ b/lib/controller/home/Dio.dart @@ -0,0 +1,46 @@ +import 'package:dio/dio.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:vbvs_app/common/util/MyUtils.dart'; +import 'package:vbvs_app/controller/login/login_controller.dart'; +import 'package:vbvs_app/pages/common/selectDialog.dart'; + +class ApiService { + static Dio dio = Dio(); + + static Dio request = Dio(); + static Dio requestNoInfo = Dio(); + static Dio requestNoError = Dio(); //不处理错误的请求,用于设备操作上报 + + static Dio reservation = Dio(); + + static void init() { + + reservationInit(); + } + + static void reservationInit() { + reservation.options.baseUrl = "https://crm-api.swes.com.cn"; + reservation.options.connectTimeout = const Duration(seconds: 15); + reservation.options.receiveTimeout = const Duration(seconds: 10); + reservation.options.sendTimeout = const Duration(seconds: 10); + reservation.interceptors.add(InterceptorsWrapper( + onRequest: (options, handler) { + print("---> ${options.method}, ${options.path}, ${options.data}"); + options.headers['token'] = + "bMAQVR1x48t66u8EDYSftAJGo17r0rIB3z15JgyyoGz1rAEZHs1htHOCorYFJ2RT"; + return handler.next(options); + }, + onResponse: (response, ResponseInterceptorHandler handler) { + print("<--- ${response.statusCode} ${response.data}"); + return handler.next(response); + }, + onError: (e, handler) { + // 错误处理,例如打印错误信息 + showToast("网络异常或服务连接异常,请稍候再试", color: color_error); + print("DioError: $e"); + return handler.reject(e); + }, + )); + } +} diff --git a/lib/main.dart b/lib/main.dart index 711a09d..2dfa8f8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,7 +20,7 @@ import 'package:vbvs_app/common/pojo/city.dart'; import 'package:vbvs_app/common/util/CheckNetwork.dart'; import 'package:vbvs_app/common/util/CommonVariables.dart'; import 'package:vbvs_app/common/util/DailyLogUtils.dart'; -import 'package:vbvs_app/common/util/Dio.dart'; +// import 'package:vbvs_app/common/util/Dio.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/JPushUtil.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; @@ -32,6 +32,7 @@ import 'package:vbvs_app/controller/device/device_calibration_controller.dart'; import 'package:vbvs_app/controller/device/device_share_controller.dart'; import 'package:vbvs_app/controller/device/device_share_list_controller.dart'; import 'package:vbvs_app/controller/device/device_type_controller.dart'; +import 'package:vbvs_app/controller/home/Dio.dart'; import 'package:vbvs_app/controller/home/home_controller.dart'; import 'package:vbvs_app/controller/login/login_controller.dart'; import 'package:vbvs_app/controller/main_bottom/global_controller.dart'; @@ -94,6 +95,12 @@ Future main() async { final ThemeController themeController = Get.put(ThemeController()); WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, // 状态栏透明 + statusBarIconBrightness: Brightness.light, // Android:白色图标 + statusBarBrightness: Brightness.dark, // iOS:白色图标 + )); + final Locale? deviceLocale = Get.deviceLocale; print('系统语言: ${deviceLocale?.languageCode}'); diff --git a/lib/pages/common/selectDialog.dart b/lib/pages/common/selectDialog.dart index 2c2dfd1..d204d6d 100644 --- a/lib/pages/common/selectDialog.dart +++ b/lib/pages/common/selectDialog.dart @@ -64,12 +64,15 @@ Widget getOnePickers( bool looping = false, void Function(int)? onChanged, bool isMonthName = false, + Key? pickerKey, }) { ThemeController themeController = Get.find(); final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false; return Obx(() { + final dynamicKey = ValueKey('picker_${arr.length}_${selectedIndex.value}'); return CupertinoPicker.builder( + key: pickerKey ?? dynamicKey, itemExtent: 90.rpx, useMagnifier: false, magnification: 1, diff --git a/lib/pages/device/BodyDeviceWidget.dart b/lib/pages/device/BodyDeviceWidget.dart index 400c615..b2552b8 100644 --- a/lib/pages/device/BodyDeviceWidget.dart +++ b/lib/pages/device/BodyDeviceWidget.dart @@ -30,9 +30,11 @@ class _BodyDevicePageState extends State { final BodyDeviceController bodyDeviceController = Get.find(); HomeController homeController = Get.find(); final GlobalKey addIconKey = GlobalKey(); - final ScrollController _scrollController = ScrollController(); + final ScrollController _myDeviceScrollController = ScrollController(); + final ScrollController _cloudDeviceScrollController = ScrollController(); OverlayEntry? _popupEntry; Timer? _timer; + late PageController _pageController; void _showPopup() { final renderBox = @@ -42,20 +44,16 @@ class _BodyDevicePageState extends State { final size = renderBox.size; double popupWidth = 190.rpx; - // 移除之前的弹窗 _popupEntry?.remove(); - // 创建新的OverlayEntry _popupEntry = OverlayEntry( builder: (context) => Stack( children: [ - // 半透明背景,点击后关闭弹窗 ModalBarrier( dismissible: true, color: Colors.transparent, onDismiss: _hidePopup, ), - // 弹窗内容 Positioned( top: position.dy + size.height + 26.rpx, left: position.dx + size.width - popupWidth - 40.rpx, @@ -81,36 +79,6 @@ class _BodyDevicePageState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 11.rpx), - // ClickableContainer( - // padding: EdgeInsets.symmetric(vertical: 10.rpx), - // backgroundColor: Colors.transparent, - // highlightColor: - // themeController.currentColor.sc16.withOpacity(0.1), - // borderRadius: 0.rpx, - // onTap: () { - // print('点击扫一扫'); - // _hidePopup(); - // TopSlideNotification.show( - // context, - // text: "待开发.提示".tr, - // textColor: themeController.currentColor.sc2, - // ); - // }, - // child: Container( - // width: double.infinity, - // child: Center( - // child: Text( - // '扫一扫.标题'.tr, - // style: TextStyle( - // fontSize: AppConstants().normal_text_fontSize, - // color: themeController.currentColor.sc3, - // ), - // ), - // ), - // ), - // ), - // SizedBox(height: 35.rpx), - ClickableContainer( padding: EdgeInsets.symmetric(vertical: 10.rpx), backgroundColor: Colors.transparent, @@ -147,7 +115,6 @@ class _BodyDevicePageState extends State { ), ); - // 插入新的OverlayEntry Overlay.of(context)!.insert(_popupEntry!); } @@ -161,6 +128,10 @@ class _BodyDevicePageState extends State { bodyDeviceController.keyWord.value = ""; super.initState(); + // 初始化PageController,根据当前类型设置初始页面 + _pageController = PageController( + initialPage: bodyDeviceController.model.type == 1 ? 0 : 1); + // 处理传入的type参数 if (widget.type != null && widget.type is Map) { final bindType = widget.type['bind_type']; @@ -169,23 +140,22 @@ class _BodyDevicePageState extends State { if (bindType != null) { bodyDeviceController.model.type = bindType; homeController.model.type = bindType; + // 更新PageController到正确的位置 + _pageController = PageController( + initialPage: bodyDeviceController.model.type == 1 ? 0 : 1); } - // 初次请求设备列表 _fetchDeviceList().then((_) { if (mac != null) { - // 延迟执行以确保列表已渲染 WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToDeviceWithMac(mac); }); } }); } else { - // 没有传入type时的默认逻辑 _fetchDeviceList(); } - // 每5秒定时请求一次 _timer = Timer.periodic(Duration(seconds: 5), (timer) { _fetchDeviceList(); }); @@ -209,28 +179,54 @@ class _BodyDevicePageState extends State { final deviceList = bodyDeviceController.deviceList.value; final index = deviceList.indexWhere((device) => device['mac'] == mac); - if (index != -1 && _scrollController.hasClients) { - // 动态计算高度:最小为 501.rpx,最大为 26.6% 屏幕高度 + if (index != -1) { final screenHeight = MediaQuery.of(Get.context!).size.height; final dynamicItemHeight = (screenHeight * 0.266).rpx; final itemHeight = dynamicItemHeight < 501.rpx ? 501.rpx : dynamicItemHeight; - final spacing = 25.rpx; final targetPosition = index * (itemHeight + spacing); - _scrollController.animateTo( - targetPosition, - duration: const Duration(milliseconds: 500), - curve: Curves.easeInOut, - ); + // 根据当前类型选择对应的ScrollController + final currentScrollController = + bodyDeviceController.model.type == 1 + ? _myDeviceScrollController + : _cloudDeviceScrollController; + + if (currentScrollController.hasClients) { + currentScrollController.animateTo( + targetPosition, + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + ); + } + } + } + + // 标签切换回调 + void _onTabChanged(int index) { + _pageController.animateToPage(index, + duration: const Duration(milliseconds: 300), curve: Curves.easeInOut); + } + + // 页面切换回调 + void _onPageChanged(int index) { + int newType = index == 0 ? 1 : 2; + if (bodyDeviceController.model.type != newType) { + bodyDeviceController.model.type = newType; + homeController.model.type = newType; + bodyDeviceController.updateAll(); + homeController.updateAll(); + _fetchDeviceList(); } } @override void dispose() { - _timer?.cancel(); // 页面销毁时取消定时器 - _scrollController.dispose(); + _timer?.cancel(); + _myDeviceScrollController.dispose(); + _cloudDeviceScrollController.dispose(); + _pageController.dispose(); super.dispose(); } @@ -238,7 +234,10 @@ class _BodyDevicePageState extends State { Widget build(BuildContext context) { return LayoutBuilder( builder: (context, bodysize) => GestureDetector( - // onTap: () => FocusScope.of(context).unfocus(),, + onTap: () { + _hidePopup(); + FocusScope.of(context).unfocus(); + }, child: Container( decoration: BoxDecoration( image: DecorationImage( @@ -262,7 +261,6 @@ class _BodyDevicePageState extends State { child: Stack( alignment: Alignment.center, children: [ - /// 居中标题 Text( '体征检测设备.标题'.tr, style: TextStyle( @@ -288,7 +286,6 @@ class _BodyDevicePageState extends State { highlightColor: themeController.currentColor.sc16, padding: EdgeInsets.all(8.rpx), onTap: () { - // 点击图标时,展示弹窗 if (_popupEntry == null) { _showPopup(); } else { @@ -310,7 +307,7 @@ class _BodyDevicePageState extends State { centerTitle: false, ), body: GestureDetector( - onTap: _hidePopup, // 点击空白处自动关闭弹窗 + onTap: _hidePopup, child: SafeArea( top: true, child: Padding( @@ -335,6 +332,7 @@ class _BodyDevicePageState extends State { mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + // 标签切换部分 - 保持原有样式 Stack( alignment: Alignment.bottomLeft, children: [ @@ -348,19 +346,7 @@ class _BodyDevicePageState extends State { .currentColor.sc3, borderRadius: 8.rpx, padding: EdgeInsets.all(0), - onTap: () async { - bodyDeviceController.model.type = - 1; - homeController.model.type = 1; - await bodyDeviceController - .getDeviceList(); - await bodyDeviceController - .getDeviceList(); - await bodyDeviceController - .getSleepReport(); - bodyDeviceController.updateAll(); - homeController.updateAll(); - }, + onTap: () => _onTabChanged(0), child: Column( mainAxisSize: MainAxisSize.max, children: [ @@ -400,19 +386,7 @@ class _BodyDevicePageState extends State { .currentColor.sc3, borderRadius: 8.rpx, padding: EdgeInsets.all(0), - onTap: () async { - homeController.model.type = 2; - bodyDeviceController.model.type = - 2; - await bodyDeviceController - .getDeviceList(); - await bodyDeviceController - .getDeviceList(); - await bodyDeviceController - .getSleepReport(); - bodyDeviceController.updateAll(); - homeController.updateAll(); - }, + onTap: () => _onTabChanged(1), child: Column( mainAxisSize: MainAxisSize.max, children: [ @@ -451,7 +425,7 @@ class _BodyDevicePageState extends State { ], ), Obx(() { - // 横线宽度固定为180.rpx + // 保持原有的横线宽度180.rpx double lineWidth = 180.rpx; return AnimatedPositioned( duration: Duration(milliseconds: 300), @@ -475,6 +449,7 @@ class _BodyDevicePageState extends State { }), ], ), + // 搜索框部分保持不变 Container( width: MediaQuery.sizeOf(context).width * 0.38, @@ -636,31 +611,63 @@ class _BodyDevicePageState extends State { ), ), ), - Obx(() { - final isEmpty = - bodyDeviceController.deviceList.value.isEmpty; - return Expanded( - child: isEmpty - ? NullDataWidget() - : Padding( - padding: EdgeInsetsDirectional.fromSTEB( - 30.rpx, 26.rpx, 30.rpx, 0), - child: SingleChildScrollView( - controller: _scrollController, - child: Column( - mainAxisSize: MainAxisSize.max, - children: bodyDeviceController - .deviceList.value - .map((device) => - DeviceDataComponentWidget( - device: device)) - .toList() - .divide(SizedBox(height: 25.rpx)), - ), - ), - ), - ); - }), + // 使用PageView替换原来的单一列表 + Expanded( + child: PageView( + controller: _pageController, + onPageChanged: _onPageChanged, + children: [ + // 我的e护页面 + Obx(() { + final myDeviceList = bodyDeviceController.deviceList.value + .where((device) => device['type'] == 1 || device['bind_type'] == 1) + .toList(); + return myDeviceList.isEmpty + ? NullDataWidget() + : Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 26.rpx, 30.rpx, 0), + child: SingleChildScrollView( + controller: _myDeviceScrollController, + child: Column( + mainAxisSize: MainAxisSize.max, + children: myDeviceList + .map((device) => + DeviceDataComponentWidget( + device: device)) + .toList() + .divide(SizedBox(height: 25.rpx)), + ), + ), + ); + }), + // 云关爱页面 + Obx(() { + final cloudDeviceList = bodyDeviceController.deviceList.value + .where((device) => device['type'] == 2 || device['bind_type'] == 2) + .toList(); + return cloudDeviceList.isEmpty + ? NullDataWidget() + : Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 26.rpx, 30.rpx, 0), + child: SingleChildScrollView( + controller: _cloudDeviceScrollController, + child: Column( + mainAxisSize: MainAxisSize.max, + children: cloudDeviceList + .map((device) => + DeviceDataComponentWidget( + device: device)) + .toList() + .divide(SizedBox(height: 25.rpx)), + ), + ), + ); + }), + ], + ), + ), ], ), ), @@ -717,4 +724,4 @@ class _BodyDevicePageState extends State { ), ); } -} +} \ No newline at end of file diff --git a/lib/pages/device_bind/device_calibration.dart b/lib/pages/device_bind/device_calibration.dart index 0fb1099..3b8262b 100644 --- a/lib/pages/device_bind/device_calibration.dart +++ b/lib/pages/device_bind/device_calibration.dart @@ -33,7 +33,7 @@ class _CalibrationPageState extends State { Timer? _pollingTimer; bool exit = false; - bool start = false;//是否开始进行校准 + bool start = false; //是否开始进行校准 @override void initState() { @@ -691,6 +691,10 @@ class _CalibrationPageState extends State { progressApi, isSecondStep); }, onFailure: (res) { + deviceCalibrationController + .process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; deviceCalibrationController.flag.value = 0; blueteethBindController.cid!.value = ""; @@ -757,6 +761,10 @@ class _CalibrationPageState extends State { progressApi, isSecondStep); }, onFailure: (res) { + deviceCalibrationController + .process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; deviceCalibrationController.flag.value = 0; blueteethBindController.cid!.value = ""; @@ -935,7 +943,7 @@ class _CalibrationPageState extends State { } else { deviceCalibrationController.statusContext.value = ""; //当前步骤执行失败 - deviceCalibrationController.bed_calibration.value == 0; + deviceCalibrationController.bed_calibration.value = 0; _pollingTimer?.cancel(); blueteethBindController.cid?.value = ""; deviceCalibrationController.process.value = 0; @@ -985,6 +993,8 @@ class _CalibrationPageState extends State { } }, onFailure: (res) { + deviceCalibrationController.process.value = 0; + deviceCalibrationController.bed_calibration.value = 0; deviceCalibrationController.flag.value = 0; _pollingTimer?.cancel(); blueteethBindController.cid!.value = ""; diff --git a/lib/pages/device_bind/device_calibration_person.dart b/lib/pages/device_bind/device_calibration_person.dart index b031863..9874a72 100644 --- a/lib/pages/device_bind/device_calibration_person.dart +++ b/lib/pages/device_bind/device_calibration_person.dart @@ -685,6 +685,10 @@ class _CalibrationPersonPageState extends State { progressApi, isSecondStep); }, onFailure: (res) { + deviceCalibrationController + .process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; deviceCalibrationController.flag.value = 0; blueteethBindController.cid!.value = ""; @@ -751,6 +755,10 @@ class _CalibrationPersonPageState extends State { progressApi, isSecondStep); }, onFailure: (res) { + deviceCalibrationController + .process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; deviceCalibrationController.flag.value = 0; blueteethBindController.cid!.value = ""; @@ -934,7 +942,7 @@ class _CalibrationPersonPageState extends State { } else { deviceCalibrationController.statusContext.value = ""; //当前步骤执行失败 - deviceCalibrationController.bed_calibration.value == 0; + deviceCalibrationController.bed_calibration.value = 0; _pollingTimer?.cancel(); blueteethBindController.cid?.value = ""; deviceCalibrationController.process.value = 0; @@ -984,6 +992,8 @@ class _CalibrationPersonPageState extends State { } }, onFailure: (res) { + deviceCalibrationController.process.value = 0; + deviceCalibrationController.bed_calibration.value = 0; deviceCalibrationController.flag.value = 0; _pollingTimer?.cancel(); blueteethBindController.cid!.value = ""; diff --git a/lib/pages/login/other_login.dart b/lib/pages/login/other_login.dart index 659d8bc..4d79588 100644 --- a/lib/pages/login/other_login.dart +++ b/lib/pages/login/other_login.dart @@ -275,6 +275,43 @@ class _OtherLoginPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 26.rpx, 0, 0, 0), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + InkWell( + onTap: () async {}, + child: Container( + alignment: Alignment.center, + // constraints: BoxConstraints( + // minWidth: 150.rpx, + // ), + child: Text( + "+86", + style: TextStyle( + fontFamily: 'Readex Pro', + color: themeController + .currentColor.sc4, + fontSize: AppConstants() + .middler_text_fontSize, + letterSpacing: 0, + ), + ), + ), + ), + SizedBox( + height: 30.rpx, + child: VerticalDivider( + thickness: 2.rpx, + color: themeController + .currentColor.sc4, + ), + ), + ].divide(SizedBox(width: 10.rpx)), + ), + ), Expanded( child: Container( child: Align( diff --git a/lib/pages/main_bottom/mine_page.dart b/lib/pages/main_bottom/mine_page.dart index 573965b..633e3fe 100644 --- a/lib/pages/main_bottom/mine_page.dart +++ b/lib/pages/main_bottom/mine_page.dart @@ -690,7 +690,7 @@ class _MinePageState extends State { mainAxisSize: MainAxisSize.max, children: [ Text( - 'V1.0.2511.18', + 'V1.0.2511.21', style: TextStyle( fontFamily: 'Inter', // color: Color(0xFFD9E3EB), diff --git a/lib/pages/person/select_city.dart b/lib/pages/person/select_city.dart index ec92315..41f8f9a 100644 --- a/lib/pages/person/select_city.dart +++ b/lib/pages/person/select_city.dart @@ -281,476 +281,6 @@ Future showCitySelectionDialog( ); } -// 加载中弹窗 -Widget _buildLoadingDialog(ThemeController themeController) { - return Stack( - children: [ - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Material( - color: Colors.transparent, - child: Dialog( - backgroundColor: themeController.currentColor.sc17, - insetPadding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0), - ), - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB(30.rpx, 40.rpx, 30.rpx, 90.rpx), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - CircularProgressIndicator( - color: themeController.currentColor.sc2, - ), - SizedBox(height: 20.rpx), - Text( - "加载中...".tr, - style: TextStyle( - color: themeController.currentColor.sc3, - fontSize: 28.rpx, - ), - ), - ], - ), - ), - ), - ), - ), - ], - ); -} - -// 错误弹窗 -Widget _buildErrorDialog( - ThemeController themeController, BuildContext context) { - return Stack( - children: [ - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Material( - color: Colors.transparent, - child: Dialog( - backgroundColor: themeController.currentColor.sc17, - insetPadding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0), - ), - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB(30.rpx, 40.rpx, 30.rpx, 90.rpx), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "数据加载失败".tr, - style: TextStyle( - color: themeController.currentColor.sc3, - fontSize: 28.rpx, - ), - ), - SizedBox(height: 20.rpx), - ClickableContainer( - onTap: () => Navigator.of(context).pop(), - backgroundColor: Colors.transparent, - highlightColor: Colors.transparent, - padding: EdgeInsets.all(0), - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 30.rpx, vertical: 15.rpx), - decoration: BoxDecoration( - color: themeController.currentColor.sc2, - borderRadius: BorderRadius.circular(8.rpx), - ), - child: Text( - "关闭".tr, - style: TextStyle( - color: Colors.white, - fontSize: 28.rpx, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ), - ], - ); -} - -// 城市选择器弹窗 -Widget _buildCityPickerDialog( - BuildContext context, - ThemeController themeController, - bool isChinese, - String title, - List cityData, - Function? onCityChanged, { - required RxList countries, - required RxList provinces, - required RxList cities, - required RxInt countryIndex, - required RxInt provinceIndex, - required RxInt cityIndex, -}) { - // 内部更新方法 - void updateCities() { - try { - if (provinces.isEmpty || countries.isEmpty) return; - - final selectedCountry = countries[countryIndex.value]; - final selectedProvince = provinces[provinceIndex.value]; - - for (var country in cityData) { - if (country.value == selectedCountry) { - for (var province in country.children ?? []) { - if (province.value == selectedProvince) { - // 安全地处理城市列表 - final cityList = (province.children ?? []) - .map((city) => city?.value ?? city?.city ?? '') - .where((cityName) => - (cityName as String).isNotEmpty) // 明确转换为 String - .toList() - .cast(); - - cities.value = cityList; - cityIndex.value = cities.isNotEmpty ? 0 : 0; - return; - } - } - } - } - cities.value = []; - cityIndex.value = 0; - } catch (e) { - ef.log("更新城市列表失败:$e"); - cities.value = []; - cityIndex.value = 0; - } - } - - void updateProvinces() { - try { - if (countries.isEmpty) return; - - final selectedCountry = countries[countryIndex.value]; - - for (var country in cityData) { - if (country.value == selectedCountry) { - // 安全地处理省份列表 - final provinceList = (country.children ?? []) - .map((province) => province?.value ?? province?.province ?? '') - .where((provinceName) => provinceName.isNotEmpty) - .toList() - .cast(); - - provinces.value = provinceList; - provinceIndex.value = provinces.isNotEmpty ? 0 : 0; - - // 更新城市 - updateCities(); - return; - } - } - provinces.value = []; - provinceIndex.value = 0; - cities.value = []; - cityIndex.value = 0; - } catch (e) { - ef.log("更新省份列表失败:$e"); - provinces.value = []; - provinceIndex.value = 0; - cities.value = []; - cityIndex.value = 0; - } - } - - CityModel? getSelectedCityData() { - try { - if (countries.isEmpty) return null; - - final selectedCountry = countries[countryIndex.value]; - - // 查找匹配的国家 - for (var country in cityData) { - final countryName = country.value ?? country.country; - if (countryName == selectedCountry) { - // 情况1: 只有国家一级(没有省份和城市) - if ((country.children == null || country.children!.isEmpty) && - (country.city != null || country.value != null)) { - return country; // 直接返回国家数据 - } - - // 情况2: 有省份但没有城市数据 - if (provinces.isNotEmpty && provinceIndex.value < provinces.length) { - final selectedProvince = provinces[provinceIndex.value]; - - for (var province in country.children ?? []) { - final provinceName = province.value ?? province.province; - if (provinceName == selectedProvince) { - // 情况2.1: 省份有城市数据 - if (cities.isNotEmpty && cityIndex.value < cities.length) { - final selectedCityName = cities[cityIndex.value]; - - for (var city in province.children ?? []) { - final cityName = city.value ?? city.city; - if (cityName == selectedCityName) { - return city; // 返回城市数据 - } - } - } - - // 情况2.2: 省份没有城市数据,但省份本身有信息 - if ((province.children == null || province.children!.isEmpty) && - (province.city != null || province.value != null)) { - return province; // 返回省份数据 - } - } - } - } - - // 情况3: 有省份但没有选择具体省份,返回国家数据 - return country; - } - } - - return null; - } catch (e) { - ef.log("获取选中城市数据失败:$e"); - return null; - } - } - - return Scaffold( - resizeToAvoidBottomInset: false, // 在这里也设置 - backgroundColor: Colors.transparent, - body: Stack( - children: [ - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Material( - color: Colors.transparent, - child: Dialog( - backgroundColor: themeController.currentColor.sc17, - insetPadding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0), - ), - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB(30.rpx, 10.rpx, 30.rpx, 0.rpx), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ClickableContainer( - backgroundColor: Colors.transparent, - highlightColor: Colors.transparent, - padding: EdgeInsets.zero, - onTap: () => Navigator.of(context).pop(), - child: Container( - width: 110.rpx, - height: 60.rpx, - alignment: Alignment.center, - child: Text("取消".tr, - style: TextStyle( - fontSize: 30.rpx, color: Colors.white)), - ), - ), - Text( - title, - style: TextStyle( - fontFamily: 'Readex Pro', - color: themeController.currentColor.sc3, - fontSize: 30.rpx, - ), - ), - Obx(() { - CityModelController cityModelController = Get.find(); - cityModelController.tmp; - ef.log("${cityModelController.tmp.value}"); - return ClickableContainer( - backgroundColor: Colors.transparent, - highlightColor: Colors.transparent, - padding: EdgeInsets.zero, - // onTap: () { - // final selectedCityData = getSelectedCityData(); - // if (selectedCityData != null) { - // onCityChanged?.call(selectedCityData); - // } - // Navigator.of(context).pop(); - // }, - onTap: () { - final selectedCityData = getSelectedCityData(); - if (selectedCityData != null) { - // 根据ID查找完整的层级数据并补全 - final fullCityData = findCompleteCityDataById( - selectedCityData.id, cityData); - if (fullCityData != null) { - // 使用完整的数据 - onCityChanged?.call(fullCityData); - } else { - // 如果没有找到完整数据,使用当前选中的数据 - onCityChanged?.call(selectedCityData); - } - } - Navigator.of(context).pop(); - }, - child: Container( - width: 110.rpx, - height: 60.rpx, - alignment: Alignment.center, - child: Text("确定".tr, - style: TextStyle( - fontSize: 30.rpx, - color: themeController.currentColor.sc2, - )), - ), - ); - }), - ], - ), - Padding( - padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0), - child: ListSearchWidget( - keyword: cityModelController.model.keyword, - color: cityModelController.model.color, - hint: "输入国家、省份或城市".tr, - onChange: (d) { - cityModelController.model.keyword = d; - // 实时搜索 - cityModelController.searchCities(d); - }, - findCallback: () { - // 点击搜索按钮时搜索 - cityModelController.searchCities( - cityModelController.model.keyword ?? ""); - }, - padding: EdgeInsets.fromLTRB( - 0.rpx, - 30.rpx, - 0.rpx, - 10.rpx, - ), - showResultList: true, // 开启结果列表 - searchResults: - cityModelController.searchResults, // 搜索结果 - onResultTap: (result) { - // 处理选择结果 - final selectedCity = - cityModelController.getCityByDisplayName(result); - - if (selectedCity != null) { - final fullCityData = findCompleteCityDataById( - selectedCity.id, cityData); - // 更新选中的城市 - PersonController personController = Get.find(); - personController.cityModel = fullCityData; - personController.updateAll(); - ef.log("选择了城市: ${selectedCity.displayName}"); - - // 关闭弹窗(如果是在弹窗中使用) - Navigator.of(context).pop(); - } - }, - ), - ), - SizedBox(height: 20.rpx), - Stack( - children: [ - Positioned.fill( - child: IgnorePointer( - child: Center( - child: Container( - height: 90.rpx, - margin: EdgeInsets.symmetric(horizontal: 0.rpx), - decoration: BoxDecoration( - color: themeController.currentColor.sc2, - borderRadius: BorderRadius.circular(16.rpx), - ), - ), - ), - ), - ), - Container( - child: Padding( - padding: EdgeInsets.fromLTRB(20.rpx, 0, 20.rpx, 0), - child: Row( - children: [ - Expanded( - child: Obx(() { - CityModelController cityModelController = - Get.find(); - cityModelController.tmp; - ef.log("${cityModelController.tmp.value}"); - return getOnePickers( - context, - countries, - countryIndex, - unit: "", - onChanged: (_) => updateProvinces(), - ); - }), - ), - Expanded( - child: Obx(() { - CityModelController cityModelController = - Get.find(); - cityModelController.tmp; - ef.log("${cityModelController.tmp.value}"); - return getOnePickers( - context, - provinces, - provinceIndex, - unit: "", - onChanged: (_) => updateCities(), - ); - }), - ), - Expanded( - child: Obx(() { - CityModelController cityModelController = - Get.find(); - cityModelController.tmp; - ef.log("${cityModelController.tmp.value}"); - return getOnePickers( - context, - cities, - cityIndex, - unit: "", - ); - }), - ), - ], - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), - ), - ], - ), - ); -} - // 根据ID查找完整的城市数据(包含国家、省份、城市信息) CityModel? findCompleteCityDataById(int? id, List cityData) { if (id == null) return null; @@ -1095,6 +625,8 @@ Widget _buildCityPickerContent( countryIndex, unit: "", onChanged: (_) => updateProvinces(), + pickerKey: ValueKey( + 'country_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key ); }), ), @@ -1110,6 +642,8 @@ Widget _buildCityPickerContent( provinceIndex, unit: "", onChanged: (_) => updateCities(), + pickerKey: ValueKey( + 'province_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key ); }), ), @@ -1124,6 +658,8 @@ Widget _buildCityPickerContent( cities, cityIndex, unit: "", + pickerKey: ValueKey( + 'city_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key ); }), ), diff --git a/lib/pages/sleep_report/chart/LineChartByRange.dart b/lib/pages/sleep_report/chart/LineChartByRange.dart index ce49c93..7f55960 100644 --- a/lib/pages/sleep_report/chart/LineChartByRange.dart +++ b/lib/pages/sleep_report/chart/LineChartByRange.dart @@ -199,6 +199,7 @@ class _LineChartByRangePainter extends CustomPainter { for (var item in data) { int start = item['startTime']; int end = item['endTime']; + // int times = item['times']; int times = item['times']; double startX = xStart * 2 + diff --git a/lib/pages/sleep_report/chart/SleepRadarChart.dart b/lib/pages/sleep_report/chart/SleepRadarChart.dart index 849989b..9c2b8e4 100644 --- a/lib/pages/sleep_report/chart/SleepRadarChart.dart +++ b/lib/pages/sleep_report/chart/SleepRadarChart.dart @@ -29,41 +29,112 @@ class SleepRadarChart extends StatelessWidget { ); } + // Widget _buildRadarChart() { + // return AspectRatio( + // aspectRatio: 1.3, + // child: RadarChart( + // RadarChartData( + // dataSets: [ + // // 今日数据 + // RadarDataSet( + // dataEntries: data + // .map((e) => RadarEntry(value: (e['t'] as num).toDouble())) + // .toList(), + // borderColor: stringToColor("#00C1AA"), + // borderWidth: 2, + // fillColor: Colors.transparent, + // entryRadius: 0, + // ), + // // 昨日数据 + // RadarDataSet( + // dataEntries: data + // .map((e) => RadarEntry(value: (e['y'] as num).toDouble())) + // .toList(), + // borderColor: stringToColor("#FFD251"), + // borderWidth: 2, + // fillColor: Colors.transparent, + // entryRadius: 0, + // ), + // ], + // radarBackgroundColor: stringToColor("#343844").withOpacity(0.6), + // radarBorderData: BorderSide( + // color: themeController.currentColor.sc4, width: 0.5.rpx), + // radarShape: RadarShape.polygon, + // titlePositionPercentageOffset: 0.2, + // titleTextStyle: TextStyle( + // fontSize: AppConstants().normal_text_fontSize, + // color: themeController.currentColor.sc3), + // getTitle: (index, angle) { + // return RadarChartTitle(text: data[index]['name'] ?? '未知'.tr); + // }, + // tickCount: 5, + // ticksTextStyle: + // const TextStyle(color: Colors.transparent, fontSize: 10), + // gridBorderData: BorderSide(color: Colors.transparent, width: 1), + // tickBorderData: BorderSide( + // color: themeController.currentColor.sc4, width: 0.5.rpx), + // ), + // swapAnimationDuration: const Duration(milliseconds: 400), + // ), + // ); + // } + Widget _buildRadarChart() { + // 判断 t 是否全为 0(今日) + final bool isTodayAllZero = + data.every((e) => (e['t'] as num).toDouble() == 0); + + // 判断 y 是否全为 0(昨日) + final bool isYesterdayAllZero = + data.every((e) => (e['y'] as num).toDouble() == 0); + + // 构建 dataSets + final List dataSets = []; + + // 今日数据(非全 0 才加入) + if (!isTodayAllZero) { + dataSets.add( + RadarDataSet( + dataEntries: data + .map((e) => RadarEntry(value: (e['t'] as num).toDouble())) + .toList(), + borderColor: stringToColor("#00C1AA"), + borderWidth: 2, + fillColor: Colors.transparent, + entryRadius: 0, + ), + ); + } + + // 昨日数据(非全 0 才加入) + if (!isYesterdayAllZero) { + dataSets.add( + RadarDataSet( + dataEntries: data + .map((e) => RadarEntry(value: (e['y'] as num).toDouble())) + .toList(), + borderColor: stringToColor("#FFD251"), + borderWidth: 2, + fillColor: Colors.transparent, + entryRadius: 0, + ), + ); + } + return AspectRatio( aspectRatio: 1.3, child: RadarChart( RadarChartData( - dataSets: [ - // 今日数据 - RadarDataSet( - dataEntries: data - .map((e) => RadarEntry(value: (e['t'] as num).toDouble())) - .toList(), - borderColor: stringToColor("#00C1AA"), - borderWidth: 2, - fillColor: Colors.transparent, - entryRadius: 0, - ), - // 昨日数据 - RadarDataSet( - dataEntries: data - .map((e) => RadarEntry(value: (e['y'] as num).toDouble())) - .toList(), - borderColor: stringToColor("#FFD251"), - borderWidth: 2, - fillColor: Colors.transparent, - entryRadius: 0, - ), - ], + dataSets: dataSets, radarBackgroundColor: stringToColor("#343844").withOpacity(0.6), radarBorderData: BorderSide( color: themeController.currentColor.sc4, width: 0.5.rpx), radarShape: RadarShape.polygon, titlePositionPercentageOffset: 0.2, titleTextStyle: TextStyle( - fontSize: AppConstants().normal_text_fontSize, - color: themeController.currentColor.sc3), + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc3, + ), getTitle: (index, angle) { return RadarChartTitle(text: data[index]['name'] ?? '未知'.tr); }, diff --git a/lib/pages/sleep_report/component/BreatheCard.dart b/lib/pages/sleep_report/component/BreatheCard.dart index 5b640f2..11cd23a 100644 --- a/lib/pages/sleep_report/component/BreatheCard.dart +++ b/lib/pages/sleep_report/component/BreatheCard.dart @@ -83,8 +83,13 @@ class _BreatheCardState extends State return Container(); } + // List data = widget.sleepReport['brs'] ?? []; List data = widget.sleepReport['brs'] ?? []; + data = data.where((item) { + return item['show'] != false; // 只保留 show 不为 false 的元素 + }).toList(); // 添加 .toList() + return Container( width: double.infinity, decoration: BoxDecoration( diff --git a/lib/pages/sleep_report/component/DailyDataWidget.dart b/lib/pages/sleep_report/component/DailyDataWidget.dart index 475a831..0d7cc81 100644 --- a/lib/pages/sleep_report/component/DailyDataWidget.dart +++ b/lib/pages/sleep_report/component/DailyDataWidget.dart @@ -25,10 +25,11 @@ Widget DailyDataWidget( GlobalKey breatheCardKey, dynamic data, ) { + List _buildSectionList() { EdgeInsetsDirectional padding = EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 25.rpx); - + return [ SleepScoreWidget(sleepReport: sleepReport), SleepViewWidget(sleepReport: sleepReport), diff --git a/lib/pages/sleep_report/component/HeartRateCard.dart b/lib/pages/sleep_report/component/HeartRateCard.dart index 68fb00d..34620b6 100644 --- a/lib/pages/sleep_report/component/HeartRateCard.dart +++ b/lib/pages/sleep_report/component/HeartRateCard.dart @@ -15,7 +15,8 @@ class HeartRateCard extends StatefulWidget { State createState() => _HeartRateCardState(); } -class _HeartRateCardState extends State with TickerProviderStateMixin { +class _HeartRateCardState extends State + with TickerProviderStateMixin { final GlobalKey _highlightKey = GlobalKey(); AnimationController? _animationController; bool _shouldAnimate = false; @@ -30,9 +31,10 @@ class _HeartRateCardState extends State with TickerProviderStateM _shouldAnimate = true; _initAnimation(); } - + WidgetsBinding.instance.addPostFrameCallback((_) { - if (widget.highlightItem != null && _highlightKey.currentContext != null) { + if (widget.highlightItem != null && + _highlightKey.currentContext != null) { Scrollable.ensureVisible( _highlightKey.currentContext!, duration: Duration(milliseconds: 500), @@ -67,7 +69,7 @@ class _HeartRateCardState extends State with TickerProviderStateM } } }); - + _animationController!.forward(); } @@ -86,8 +88,16 @@ class _HeartRateCardState extends State with TickerProviderStateM return Container(); } + // List data = widget.sleepReport['hrs'] ?? []; + + // data = data.where((item) { + // return item['show'] != false; // 只保留 show 不为 false 的元素 + // }); List data = widget.sleepReport['hrs'] ?? []; + data = data.where((item) { + return item['show'] != false; // 只保留 show 不为 false 的元素 + }).toList(); // 添加 .toList() return Container( width: double.infinity, decoration: BoxDecoration( @@ -104,9 +114,9 @@ class _HeartRateCardState extends State with TickerProviderStateM children: List.generate(data.length, (index) { final item = data[index]; item['showTip'] = true; - final bool isHighlighted = _shouldAnimate && - item['id'] == _highlightedId; - + final bool isHighlighted = + _shouldAnimate && item['id'] == _highlightedId; + return SizedBox( width: (MediaQuery.of(context).size.width - 160.rpx) / 3, child: AnimatedBuilder( @@ -118,7 +128,8 @@ class _HeartRateCardState extends State with TickerProviderStateM ? BoxDecoration( border: Border.all( color: themeController.currentColor.sc2 - .withOpacity(_animationController?.value ?? 0), + .withOpacity( + _animationController?.value ?? 0), width: 1.rpx, ), borderRadius: BorderRadius.circular(8), @@ -138,4 +149,4 @@ class _HeartRateCardState extends State with TickerProviderStateM return Container(); } } -} \ No newline at end of file +} diff --git a/lib/pages/sleep_report/new_sleep_report_page.dart b/lib/pages/sleep_report/new_sleep_report_page.dart index a1e0e18..7c885e5 100644 --- a/lib/pages/sleep_report/new_sleep_report_page.dart +++ b/lib/pages/sleep_report/new_sleep_report_page.dart @@ -842,40 +842,7 @@ class _NewSleepReportPageState extends State { ], ), ), - ), - // Obx(() { - // if (sleepReportController.isLoading.value) { - // return Center( - // child: CircularProgressIndicator( - // strokeWidth: 2, - // valueColor: AlwaysStoppedAnimation( - // themeController.currentColor.sc1, - // ), - // ), - // ); - // } - // switch (sleepReportController.model.type) { - // case 1: - // return DailyDataWidget( - // sleepReport, - // sleepCardKey, - // heartRateCardKey, - // breatheCardKey, - // widget.data); - // case 2: - // return WeekDataWidget( - // sleepReport, - // widget.data, - // ); - // case 3: - // return MonthDataWidget( - // sleepReport, - // widget.data, - // ); - // default: - // return NullDataWidget(); - // } - // }), + ), Obx(() { if (sleepReportController.isLoading.value) { return Center(