From ee9965e3dfbe1771a14fb85df325947e3a5b9adb Mon Sep 17 00:00:00 2001 From: wyf <494641114@qq.com> Date: Sat, 20 Dec 2025 17:41:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=89=93=E9=BC=BE=E5=9B=BE?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/common/selectDialog.dart | 26 +- lib/pages/mh_page/device/mht_people_info.dart | 8 +- lib/pages/mh_page/new_settingPage.dart | 2 +- lib/pages/mh_page/people_info.dart | 320 +++++++---------- lib/pages/person/select_city.dart | 17 +- lib/pages/sleep_report/chart/SnoreChart.dart | 330 +++++++++++++++++- .../component/BreathePauseNewWidget.dart | 20 +- .../component/DailyDataWidget.dart | 2 +- .../component/SnoreViewWidget.dart | 39 ++- 9 files changed, 529 insertions(+), 235 deletions(-) diff --git a/lib/pages/common/selectDialog.dart b/lib/pages/common/selectDialog.dart index 9ecc882..1100c54 100644 --- a/lib/pages/common/selectDialog.dart +++ b/lib/pages/common/selectDialog.dart @@ -65,6 +65,7 @@ Widget getOnePickers( void Function(int)? onChanged, bool isMonthName = false, Key? pickerKey, + Color? selectedColor, // ✅ 新增:选中颜色(可选) }) { ThemeController themeController = Get.find(); final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false; @@ -87,15 +88,14 @@ Widget getOnePickers( }, childCount: arr.length, itemBuilder: (context, index) { - bool isSelected = index == selectedIndex.value; + final bool isSelected = index == selectedIndex.value; - // 处理显示文本 + // 显示文本 String displayText; if (isMonthName && isEn && arr[index] is int) { displayText = DateFormat.MMMM('en').format(DateTime(0, arr[index])); } else { - // displayText = isEn ? "${arr[index]}" : "${arr[index]}$unit"; // 中文附带单位 - displayText = "${arr[index]}$unit"; // 中文附带单位 + displayText = "${arr[index]}$unit"; } return Center( @@ -104,7 +104,8 @@ Widget getOnePickers( style: TextStyle( fontFamily: 'Readex Pro', color: isSelected - ? themeController.currentColor.sc3 + ? (selectedColor ?? + themeController.currentColor.sc3) // ✅ 优先使用外部颜色 : const Color(0xFF9AA0B3), fontSize: 30.rpx, fontWeight: FontWeight.normal, @@ -329,6 +330,8 @@ Future showDateSelectionDialog(BuildContext context, monthIndex, isMonthName: true, onChanged: (_) => updateDays(), + selectedColor: + stringToColor("#003058"), ), ), Expanded( @@ -336,6 +339,8 @@ Future showDateSelectionDialog(BuildContext context, context, daysSelect, dayIndex, + selectedColor: + stringToColor("#003058"), ), ), Expanded( @@ -344,6 +349,8 @@ Future showDateSelectionDialog(BuildContext context, years, yearIndex, onChanged: (_) => updateDays(), + selectedColor: + stringToColor("#003058"), ), ), ] @@ -355,6 +362,8 @@ Future showDateSelectionDialog(BuildContext context, yearIndex, unit: "年", onChanged: (_) => updateDays(), + selectedColor: + stringToColor("#003058"), ), ), Expanded( @@ -364,6 +373,8 @@ Future showDateSelectionDialog(BuildContext context, monthIndex, unit: "月", onChanged: (_) => updateDays(), + selectedColor: + stringToColor("#003058"), ), ), Expanded( @@ -372,6 +383,8 @@ Future showDateSelectionDialog(BuildContext context, daysSelect, dayIndex, unit: "日", + selectedColor: + stringToColor("#003058"), ), ), ], @@ -688,6 +701,7 @@ Future showWeightPickerDialog( weights, tempIndex, // ✅ 传入 RxInt unit: "kg", + selectedColor: stringToColor("#003058"), ), ), ], @@ -815,6 +829,7 @@ Future showHeightPickerDialog( heights, tempIndex, // ✅ 传入 RxInt unit: "cm", + selectedColor: stringToColor("#003058"), ), ), ], @@ -1088,6 +1103,7 @@ Future showOneSelectionDialog( arr, selectedIndex, unit: '', + selectedColor: stringToColor("#003058"), ), ), ], diff --git a/lib/pages/mh_page/device/mht_people_info.dart b/lib/pages/mh_page/device/mht_people_info.dart index f864ead..ab34586 100644 --- a/lib/pages/mh_page/device/mht_people_info.dart +++ b/lib/pages/mh_page/device/mht_people_info.dart @@ -489,7 +489,9 @@ class _MHTPeopleInfoPageState extends State { filled: true, hintText: "请输入姓名".tr, hintStyle: TextStyle( - color: Colors.white), + color: themeController + .currentColor.sc4, + ), border: InputBorder.none, contentPadding: EdgeInsets.all(0)), @@ -821,7 +823,9 @@ class _MHTPeopleInfoPageState extends State { filled: true, hintText: "请输入联系方式".tr, hintStyle: TextStyle( - color: Colors.white), + color: themeController + .currentColor.sc4, + ), border: InputBorder.none, contentPadding: EdgeInsets.all(0)), diff --git a/lib/pages/mh_page/new_settingPage.dart b/lib/pages/mh_page/new_settingPage.dart index 3a38d4f..d42e3b1 100644 --- a/lib/pages/mh_page/new_settingPage.dart +++ b/lib/pages/mh_page/new_settingPage.dart @@ -253,7 +253,7 @@ class _SettingPageState extends State { ), ].divide(SizedBox(width: 22.rpx)), ), - Text('SWES2025.12.17', + Text('SWES2025.12.20', style: TextStyle( color: Colors.white, fontSize: 26.rpx, diff --git a/lib/pages/mh_page/people_info.dart b/lib/pages/mh_page/people_info.dart index f32652c..d4fb82b 100644 --- a/lib/pages/mh_page/people_info.dart +++ b/lib/pages/mh_page/people_info.dart @@ -50,7 +50,8 @@ class PeopleInfoPage extends GetView { }); getPersonData(); - controller.cityDataFuture = cityController.loadAndSetCityData().then((success) { + controller.cityDataFuture = + cityController.loadAndSetCityData().then((success) { return cityController.cityList; }); return LayoutBuilder( @@ -297,20 +298,26 @@ class PeopleInfoPage extends GetView { fontSize: 30.rpx, color: Colors.white), - decoration: InputDecoration( - fillColor: Colors - .transparent, - filled: true, - hintText: - "请输入姓名".tr, - hintStyle: TextStyle( - color: Colors - .white), - border: InputBorder - .none, - contentPadding: - EdgeInsets.all( - 0)), + decoration: + InputDecoration( + fillColor: Colors + .transparent, + filled: true, + hintText: + "请输入姓名".tr, + hintStyle: + TextStyle( + color: themeController + .currentColor + .sc4, + ), + border: + InputBorder + .none, + contentPadding: + EdgeInsets + .all( + 0)), onChanged: (value) { controller.model .peopleList[ @@ -356,9 +363,11 @@ class PeopleInfoPage extends GetView { title: "选择性别".tr, arr: ["女".tr, "男".tr], checkIndex: controller - .model - .peopleList[ - index]['gender'], + .model + .peopleList[ + index] + ['gender'] ?? + 0, checkChange: (sindex) { controller.model.peopleList[ index]['gender'] = @@ -529,7 +538,7 @@ class PeopleInfoPage extends GetView { 'assets/img/icon/expand_more.svg', color: Colors.white, - )) + )), ], ), ], @@ -777,20 +786,25 @@ class PeopleInfoPage extends GetView { style: TextStyle( fontSize: 30.rpx, color: Colors.white), - decoration: InputDecoration( - fillColor: Colors - .transparent, - filled: true, - hintText: - "请输入联系方式".tr, - hintStyle: TextStyle( - color: - Colors.white), - border: - InputBorder.none, - contentPadding: - EdgeInsets.all( - 0)), + decoration: + InputDecoration( + fillColor: Colors + .transparent, + filled: true, + hintText: + "请输入联系方式".tr, + hintStyle: + TextStyle( + color: themeController + .currentColor + .sc4, + ), + border: + InputBorder + .none, + contentPadding: + EdgeInsets + .all(0)), onChanged: (value) { controller.model .peopleList[ @@ -903,6 +917,9 @@ class PeopleInfoPage extends GetView { selectedCityColor: stringToColor( "#84F5FF"), + selectedTextColor: + stringToColor( + "#011D33"), ), ); }); @@ -923,164 +940,47 @@ class PeopleInfoPage extends GetView { letterSpacing: 0, ), ), - Text( - getCityModel(index) != - null - ? MyUtils - .getDetailedCityDisplayText( - getCityModel( - index)) - : "请选择城市".tr, - style: TextStyle( - color: getCityModel( - index) != - null - ? themeController - .currentColor - .sc3 - : themeController - .currentColor - .sc4, - fontSize: AppConstants() - .title_text_fontSize, - ), + Row( + children: [ + Text( + getCityModel(index) != + null + ? MyUtils + .getDetailedCityDisplayText( + getCityModel( + index)) + : "请选择城市".tr, + style: TextStyle( + color: getCityModel( + index) != + null + ? themeController + .currentColor + .sc3 + : themeController + .currentColor + .sc4, + fontSize: AppConstants() + .title_text_fontSize, + ), + ), + SizedBox(width: 16.rpx), + Container( + height: 30.rpx, + width: 30.rpx, + child: SvgPicture + .asset( + 'assets/img/icon/expand_more.svg', + color: + Colors.white, + )), + ], ), ], ), ), ), getLine(), - // Container( - // height: 90.rpx, - // margin: EdgeInsets.only( - // left: 40.rpx, right: 35.rpx), - // child: InkWell( - // onTap: () { - // // if (widget.status == - // // BindType.share.code) { - // // TopSlideNotification.show( - // // context, - // // text: "被分享用户只能修改用户名称", - // // textColor: - // // themeController - // // .currentColor - // // .sc9); - // // return; - // // } - // FocusScope.of(context) - // .requestFocus( - // FocusNode()); - // Future.delayed( - // Duration( - // milliseconds: 250), - // () { - // // 使用当前选中的城市数据,如果没有则创建默认 - // CityModel? currentCity; - // if (controller - // .model - // .cityModels - // .isNotEmpty && - // index < - // controller - // .model - // .cityModels - // .length) { - // currentCity = controller - // .model - // .cityModels[index]; - // } else { - // currentCity = CityModel(); - // } - - // showCitySelectionDialog( - // context, - // selectedCity: currentCity, - // onCityChanged: - // (CityModel newCity) { - // final list = controller - // .model.cityModels; - // if (index < - // list.length) { - // // 替换 - // list[index] = newCity; - // } else { - // // 补齐并追加 - // list.add(newCity); - // } - // controller.model - // .peopleList[ - // index]['UTC'] = - // list[index].UTC; - // controller.model - // .peopleList[ - // index] - // ['city_id'] = list[ - // index] - // .id; - // controller.updateAll(); - // }, - - // title: "选择城市".tr, - // cityDataFuture: controller - // .cityDataFuture, // 传入预加载的数据 - // colors: - // CitySelectionColors( - // pickerBackgroundColor: - // stringToColor( - // "#003058"), - // confirmTextColor: - // stringToColor( - // "#84F5FF"), - // selectedCityColor: - // stringToColor( - // "#84F5FF"), - // ), - // ); - // }); - // }, - // child: Row( - // mainAxisAlignment: - // MainAxisAlignment - // .spaceBetween, - // children: [ - // Text( - // '慢病管理'.tr, - // style: TextStyle( - // fontFamily: - // 'Readex Pro', - // color: - // Color(0xFF9EA4B7), - // fontSize: 30.rpx, - // letterSpacing: 0, - // ), - // ), - // Text( - // getCityModel(index) != - // null - // ? MyUtils - // .getDetailedCityDisplayText( - // getCityModel( - // index)) - // : "请选择城市".tr, - // style: TextStyle( - // color: getCityModel( - // index) != - // null - // ? themeController - // .currentColor - // .sc3 - // : themeController - // .currentColor - // .sc4, - // fontSize: AppConstants() - // .title_text_fontSize, - // ), - // ), - // ], - // ), - // ), - // ), - Container( height: 90.rpx, margin: EdgeInsets.only( @@ -1162,23 +1062,39 @@ class PeopleInfoPage extends GetView { controller .diseaseList; - return Text( - getSelectedDiseaseNames( - diseases, - List.from( - selectedIds)), - style: TextStyle( - color: selectedIds - .isNotEmpty - ? themeController - .currentColor - .sc3 - : themeController - .currentColor - .sc4, - fontSize: AppConstants() - .title_text_fontSize, - ), + return Row( + children: [ + Text( + getSelectedDiseaseNames( + diseases, + List.from( + selectedIds)), + style: TextStyle( + color: selectedIds.isNotEmpty + ? themeController + .currentColor + .sc3 + : themeController + .currentColor + .sc4, + fontSize: + AppConstants() + .title_text_fontSize, + ), + ), + SizedBox( + width: 16.rpx, + ), + Container( + height: 30.rpx, + width: 30.rpx, + child: SvgPicture + .asset( + 'assets/img/icon/expand_more.svg', + color: Colors + .white, + )) + ], ); }), ], diff --git a/lib/pages/person/select_city.dart b/lib/pages/person/select_city.dart index a41f96b..107cd85 100644 --- a/lib/pages/person/select_city.dart +++ b/lib/pages/person/select_city.dart @@ -42,11 +42,13 @@ class CitySelectionColors { final Color? pickerBackgroundColor; // 选择器整体背景色 final Color? confirmTextColor; // 确定按钮文字颜色 final Color? selectedCityColor; // 选中的城市背景色 + final Color? selectedTextColor; // 选中的文字颜色 const CitySelectionColors({ this.pickerBackgroundColor, this.confirmTextColor, this.selectedCityColor, + this.selectedTextColor, }); } @@ -68,6 +70,8 @@ Future showCitySelectionDialog( colors?.confirmTextColor ?? themeController.currentColor.sc2; final Color selectedCityColor = colors?.selectedCityColor ?? themeController.currentColor.sc2; + final Color selectedTextColor = + colors?.selectedTextColor ?? themeController.currentColor.sc1; // 默认使用主题颜色 final RxList countries = [].obs; final RxList provinces = [].obs; @@ -300,6 +304,7 @@ Future showCitySelectionDialog( pickerBackgroundColor: pickerBackgroundColor, confirmTextColor: confirmTextColor, selectedCityColor: selectedCityColor, + selectedTextColor: selectedTextColor, countries: countries, provinces: provinces, cities: cities, @@ -388,6 +393,7 @@ Widget _buildCityPickerContent( required Color pickerBackgroundColor, required Color confirmTextColor, required Color selectedCityColor, + required Color selectedTextColor, required RxList countries, required RxList provinces, required RxList cities, @@ -664,7 +670,8 @@ Widget _buildCityPickerContent( unit: "", onChanged: (_) => updateProvinces(), pickerKey: ValueKey( - 'country_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key + 'country_${DateTime.now().millisecondsSinceEpoch}'), + selectedColor: selectedTextColor, // 传递选中文字颜色 ); }), ), @@ -681,7 +688,8 @@ Widget _buildCityPickerContent( unit: "", onChanged: (_) => updateCities(), pickerKey: ValueKey( - 'province_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key + 'province_${DateTime.now().millisecondsSinceEpoch}'), + selectedColor: selectedTextColor, // 传递选中文字颜色 ); }), ), @@ -697,7 +705,8 @@ Widget _buildCityPickerContent( cityIndex, unit: "", pickerKey: ValueKey( - 'city_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key + 'city_${DateTime.now().millisecondsSinceEpoch}'), + selectedColor: selectedTextColor, // 传递选中文字颜色 ); }), ), @@ -800,4 +809,4 @@ Widget _buildErrorBottomSheet( ], ), ); -} +} \ No newline at end of file diff --git a/lib/pages/sleep_report/chart/SnoreChart.dart b/lib/pages/sleep_report/chart/SnoreChart.dart index dd6b5ac..c9c4b40 100644 --- a/lib/pages/sleep_report/chart/SnoreChart.dart +++ b/lib/pages/sleep_report/chart/SnoreChart.dart @@ -1,5 +1,6 @@ import 'dart:ui' as ui; +//柱形图显示 import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:vbvs_app/common/color/appConstants.dart'; @@ -81,7 +82,7 @@ class _BarChartWidgetState extends State { onTapDown: (details) => _handleTapOrDrag(details.localPosition, constraints.biggest), child: CustomPaint( - size: Size(double.infinity, 500.rpx), + size: Size(double.infinity, 250.rpx), painter: BarChartPainter( widget.data, widget.startTime, @@ -282,3 +283,330 @@ class BarChartPainter extends CustomPainter { } } } + +//横线显示 +// import 'dart:math'; +// import 'dart:ui' as ui; + +// import 'package:flutter/material.dart'; +// import 'package:intl/intl.dart'; +// import 'package:vbvs_app/common/util/FitTool.dart'; +// import 'package:vbvs_app/common/util/MyUtils.dart'; + +// class BarData { +// final int st; // 起始时间(毫秒) +// final int et; // 结束时间(毫秒) +// final double value; // 横线的高度值 +// final int id; +// final String name; +// final Color color; + +// BarData({ +// required this.st, +// required this.et, +// required this.value, +// required this.id, +// required this.name, +// required this.color, +// }); +// } + +// class BarChartWidget extends StatefulWidget { +// final List data; +// final int startTime; // 毫秒时间戳 +// final int endTime; // 毫秒时间戳 +// final double maxYValue; // Y轴最大值 +// final int yStepCount; // Y轴分段数 + +// const BarChartWidget({ +// super.key, +// required this.data, +// required this.startTime, +// required this.endTime, +// required this.maxYValue, +// this.yStepCount = 5, +// }); + +// @override +// State createState() => _BarChartWidgetState(); +// } + +// class _BarChartWidgetState extends State { +// BarData? selectedBar; + +// void _handleTapOrDrag(Offset localPosition, Size size) { +// print('点击位置: $localPosition, 画布大小: $size'); +// final chartWidth = size.width - 30.rpx; +// final totalDuration = widget.endTime - widget.startTime; + +// // 使用与绘制相同的chartHeight计算方式 +// final double topPadding = 0; +// final double bottomPadding = 0; +// final double leftPadding = 30.rpx; +// final double chartHeight = size.height - topPadding - bottomPadding; + +// for (final d in widget.data) { +// final left = ((d.st - widget.startTime) / totalDuration) * chartWidth + +// leftPadding; +// final right = ((d.et - widget.startTime) / totalDuration) * chartWidth + +// leftPadding; + +// // 使用与绘制相同的Y坐标计算方式 +// final y = topPadding + chartHeight * (1 - d.value / widget.maxYValue); + +// // 判断点击是否在横线附近(增加容差范围) +// if (localPosition.dx >= left - 5.rpx && +// localPosition.dx <= right + 5.rpx && +// (localPosition.dy - y).abs() < 15.rpx) { +// setState(() { +// selectedBar = d; +// }); +// return; +// } +// } + +// setState(() { +// selectedBar = null; +// }); +// } + +// @override +// Widget build(BuildContext context) { +// return LayoutBuilder(builder: (context, constraints) { +// return GestureDetector( +// behavior: HitTestBehavior.opaque, +// onPanDown: (details) => +// _handleTapOrDrag(details.localPosition, constraints.biggest), +// onPanUpdate: (details) => +// _handleTapOrDrag(details.localPosition, constraints.biggest), +// onTapDown: (details) => +// _handleTapOrDrag(details.localPosition, constraints.biggest), +// child: CustomPaint( +// // size: Size(double.infinity, 500.rpx), +// size: Size(constraints.maxWidth, 500.rpx), // 使用约束的最大宽度 +// painter: BarChartPainter( +// widget.data, +// widget.startTime, +// widget.endTime, +// maxYValue: widget.maxYValue, +// yStepCount: widget.yStepCount, +// selectedBar: selectedBar, +// ), +// ), +// ); +// }); +// } +// } + +// class BarChartPainter extends CustomPainter { +// final List data; +// final int startTime; +// final int endTime; +// final double maxYValue; +// final int yStepCount; +// final BarData? selectedBar; + +// final double topPadding = 0; +// final double bottomPadding = 0; +// final double leftPadding = 30.rpx; + +// BarChartPainter( +// this.data, +// this.startTime, +// this.endTime, { +// required this.maxYValue, +// this.yStepCount = 5, +// this.selectedBar, +// }); + +// @override +// void paint(Canvas canvas, Size size) { +// final chartWidth = size.width - leftPadding; +// final chartHeight = size.height - topPadding - bottomPadding; +// final totalDuration = endTime - startTime; + +// final textPainter = TextPainter(textDirection: ui.TextDirection.ltr); +// final stepValue = maxYValue / yStepCount; + +// // Y轴刻度 - 从大到小显示(与参考代码一致) +// for (int i = 0; i <= yStepCount; i++) { +// final value = maxYValue - (stepValue * i); // 从最大值开始递减 +// final y = topPadding + chartHeight * i / yStepCount; + +// final dashPaint = Paint() +// ..color = Colors.grey.withOpacity(0.4) +// ..strokeWidth = 1.rpx; + +// // 最上面的线(i == ySegments)是实线 +// if (i == yStepCount) { +// canvas.drawLine( +// Offset(leftPadding, y), Offset(size.width, y), dashPaint); +// } else { +// // 其他线都是虚线 +// drawDashedLine( +// canvas, Offset(leftPadding, y), Offset(size.width, y), dashPaint); +// } + +// textPainter.text = TextSpan( +// text: value.toStringAsFixed(0), +// style: TextStyle( +// fontSize: 18.rpx, +// color: themeController.currentColor.sc4, +// ), +// ); +// textPainter.layout(); +// textPainter.paint( +// canvas, +// Offset(leftPadding - textPainter.width - 4, y - textPainter.height / 2), +// ); +// } + +// // X轴刻度 - 24小时制 +// final startDate = DateTime.fromMillisecondsSinceEpoch(startTime); +// final endDate = DateTime.fromMillisecondsSinceEpoch(endTime); +// final xAxisY = topPadding + chartHeight; // 这是最底部的Y坐标 + +// // 计算总小时数 +// final totalHours = endDate.difference(startDate).inHours + 1; +// final startHour = startDate.hour; + +// // 绘制X轴主线(实线) +// final xAxisPaint = Paint() +// ..color = Colors.grey.withOpacity(0.4) +// ..strokeWidth = 1.rpx; +// canvas.drawLine( +// Offset(leftPadding, xAxisY), +// Offset(size.width, xAxisY), +// xAxisPaint, +// ); + +// // 绘制左右两侧时间标签 +// final leftLabel = DateFormat('HH:mm').format(startDate); +// textPainter.text = TextSpan( +// text: leftLabel, +// style: TextStyle( +// fontSize: 18.rpx, +// color: themeController.currentColor.sc4, +// ), +// ); +// textPainter.layout(); +// textPainter.paint( +// canvas, Offset(leftPadding - textPainter.width / 2, xAxisY + 8.rpx)); + +// final rightLabel = DateFormat('HH:mm').format(endDate); +// textPainter.text = TextSpan( +// text: rightLabel, +// style: TextStyle( +// fontSize: 18.rpx, +// color: themeController.currentColor.sc4, +// ), +// ); +// textPainter.layout(); +// textPainter.paint( +// canvas, Offset(size.width - textPainter.width / 2, xAxisY + 8.rpx)); + +// // 绘制中间小时刻度 +// for (int i = 1; i < totalHours; i++) { +// final double x = leftPadding + chartWidth * i / totalHours; + +// int hourLabelNum = (startHour + i) % 24; +// final hourLabel = '$hourLabelNum'; + +// textPainter.text = TextSpan( +// text: hourLabel, +// style: TextStyle( +// fontSize: 18.rpx, +// color: themeController.currentColor.sc4, +// ), +// ); +// textPainter.layout(); +// textPainter.paint( +// canvas, Offset(x - textPainter.width / 2, xAxisY + 8.rpx)); +// } + +// // 绘制数据横线(根据数据值绘制水平线段) +// for (final d in data) { +// final left = +// ((d.st - startTime) / totalDuration) * chartWidth + leftPadding; +// final right = +// ((d.et - startTime) / totalDuration) * chartWidth + leftPadding; + +// // 根据value计算Y位置(0在底部,maxYValue在顶部) +// final y = topPadding + chartHeight * (1 - d.value / maxYValue); + +// final linePaint = Paint() +// ..style = PaintingStyle.stroke +// ..strokeWidth = 3.rpx +// ..color = d.color +// ..strokeCap = StrokeCap.round; + +// // 画水平线段 +// canvas.drawLine(Offset(left, y), Offset(right, y), linePaint); +// } + +// // 如果选中了某条横线,显示提示信息 +// // 如果选中了某条横线,显示提示信息 +// if (selectedBar != null) { +// final d = selectedBar!; +// final left = +// ((d.st - startTime) / totalDuration) * chartWidth + leftPadding; +// final right = +// ((d.et - startTime) / totalDuration) * chartWidth + leftPadding; +// final y = topPadding + chartHeight * (1 - d.value / maxYValue); + +// final tipText = +// '${d.name}\n${d.value.toStringAsFixed(1)}次\n${MyUtils.formatToHHmm(d.st)}'; + +// final tp = TextPainter( +// text: TextSpan( +// text: tipText, +// style: TextStyle(fontSize: 16.rpx, color: Colors.white), +// ), +// textAlign: TextAlign.center, +// textDirection: ui.TextDirection.ltr, +// ); +// tp.layout(); + +// final tipWidth = tp.width + 20.rpx; +// final tipHeight = tp.height + 10.rpx; +// final tipLeft = left + (right - left) / 2 - tipWidth / 2; +// final tipTop = y - tipHeight - 10.rpx; + +// // 确保tip不会超出画布顶部 - 明确转换为double +// final double adjustedTipTop = tipTop < 0 ? 0.0 : tipTop; + +// // 绘制tip背景 +// final rect = RRect.fromRectAndRadius( +// Rect.fromLTWH(tipLeft, adjustedTipTop, tipWidth, tipHeight), +// Radius.circular(8.rpx), +// ); +// final tipBgPaint = Paint()..color = Colors.black.withOpacity(0.8); +// canvas.drawRRect(rect, tipBgPaint); + +// // 绘制tip文字 +// tp.paint( +// canvas, +// Offset(tipLeft + 10.rpx, adjustedTipTop + 5.rpx), +// ); +// } +// } + +// @override +// bool shouldRepaint(covariant CustomPainter oldDelegate) => true; + +// void drawDashedLine(Canvas canvas, Offset start, Offset end, Paint paint, +// {double dashWidth = 4, double dashSpace = 3}) { +// final dx = end.dx - start.dx; +// final dy = end.dy - start.dy; +// final distance = sqrt(dx * dx + dy * dy); +// final direction = Offset(dx / distance, dy / distance); + +// double drawn = 0; +// while (drawn < distance) { +// final from = start + direction * drawn; +// final to = start + direction * (drawn + dashWidth).clamp(0, distance); +// canvas.drawLine(from, to, paint); +// drawn += dashWidth + dashSpace; +// } +// } +// } diff --git a/lib/pages/sleep_report/component/BreathePauseNewWidget.dart b/lib/pages/sleep_report/component/BreathePauseNewWidget.dart index 6a7ddd4..3fdc614 100644 --- a/lib/pages/sleep_report/component/BreathePauseNewWidget.dart +++ b/lib/pages/sleep_report/component/BreathePauseNewWidget.dart @@ -37,18 +37,18 @@ class _SnoreViewWidgetWidgetState extends State { @override Widget build(BuildContext context) { try { - if (widget.sleepReport == null || - widget.sleepReport is! Map || - widget.sleepReport.isEmpty) { - return Container(); + if (APPPackageType.TH.code == AppConstants().ent_type) { + if (widget.sleepReport == null || + widget.sleepReport is! Map || + widget.sleepReport.isEmpty) { + return Container(); + } } - List standard = widget.sleepReport['brs'] ?? []; final Map? result = standard.cast().firstWhere( (element) => element['id'] == 302, orElse: () => {}, ); - int threshold = 0; if (result != null && result.isNotEmpty) { final rangeValue = result['range']; @@ -58,16 +58,8 @@ class _SnoreViewWidgetWidgetState extends State { threshold = int.tryParse(rangeValue) ?? 0; } } - List> data = (widget.sleepReport['asp'] as List).cast>(); - // data = [ - // {"st": 1763494195669, "value": 11}, - // {"st": 1763494278485, "value": 18}, - // {"st": 1763494293453, "value": 18}, - // {"st": 1763494352321, "value": 14}, - // {"st": 1763494606757, "value": 12} - // ]; List> showLabel = convertToShowLabel(data); double maxTimes = 70; try { diff --git a/lib/pages/sleep_report/component/DailyDataWidget.dart b/lib/pages/sleep_report/component/DailyDataWidget.dart index 977746c..4ea7950 100644 --- a/lib/pages/sleep_report/component/DailyDataWidget.dart +++ b/lib/pages/sleep_report/component/DailyDataWidget.dart @@ -53,7 +53,7 @@ Widget DailyDataWidget( sleepReport: sleepReport, highlightItem: data['itemName'], ), - // SnoreViewWidgetWidget(sleepReport: sleepReport), + SnoreViewWidgetWidget(sleepReport: sleepReport), BreathePauseNewWidget(sleepReport: sleepReport), HeartHealthWidget(sleepReport: sleepReport), DiseasePercentsWidget(sleepReport: sleepReport), diff --git a/lib/pages/sleep_report/component/SnoreViewWidget.dart b/lib/pages/sleep_report/component/SnoreViewWidget.dart index dbf2801..e0f00b4 100644 --- a/lib/pages/sleep_report/component/SnoreViewWidget.dart +++ b/lib/pages/sleep_report/component/SnoreViewWidget.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:EasyDartModule/EasyDartModule.dart' as es; import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; @@ -10,7 +8,6 @@ import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/component/tool/ClickableContainer.dart'; import 'package:vbvs_app/enum/APPPackageType.dart'; import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart'; -import 'package:vbvs_app/pages/sleep_report/chart/LineChartByRange.dart'; import 'package:vbvs_app/pages/sleep_report/chart/SnoreChart.dart'; class SnoreViewWidgetWidget extends StatefulWidget { @@ -45,7 +42,10 @@ class _SnoreViewWidgetWidgetState extends State { widget.sleepReport.isEmpty) { return Container(); } - double maxY = 70; + // if (APPPackageType.TH.code == AppConstants().ent_type) { + // return Container(); + // } + double maxY = 250; var startTime = widget.sleepReport['startTime']; var endTime = widget.sleepReport['endTime']; List snoreValues = []; @@ -54,6 +54,35 @@ class _SnoreViewWidgetWidgetState extends State { List lightSnore = widget.sleepReport['ssp']['data'][0]; List heavySnore = widget.sleepReport['ssp']['data'][1]; + // lightSnore = [ + // ...lightSnore, + // { + // 'st': widget.sleepReport['startTime'] + 2 * 60 * 60 * 1000, // 开始后2小时 + // 'et': widget.sleepReport['startTime'] + 2 * 60 * 65 * 1000, // 持续5分钟 + // 'value': 25, + // }, + // { + // 'st': widget.sleepReport['startTime'] + 4 * 60 * 60 * 1000, // 开始后4小时 + // 'et': widget.sleepReport['startTime'] + 4 * 60 * 68 * 1000, // 持续8分钟 + // 'value': 18, + // } + // ]; + + // // 添加模拟数据到重度打鼾列表 + // heavySnore = [ + // ...heavySnore, + // { + // 'st': widget.sleepReport['startTime'] + 3 * 60 * 60 * 1000, // 开始后3小时 + // 'et': widget.sleepReport['startTime'] + 3 * 60 * 62 * 1000, // 持续2分钟 + // 'value': 68, + // }, + // { + // 'st': widget.sleepReport['startTime'] + 5 * 60 * 60 * 1000, // 开始后5小时 + // 'et': widget.sleepReport['startTime'] + 5 * 60 * 64 * 1000, // 持续4分钟 + // 'value': 72, + // } + // ]; + List processedLightSnore = lightSnore.map((item) { return { ...item, @@ -202,7 +231,7 @@ class _SnoreViewWidgetWidgetState extends State { startTime: startTime, endTime: endTime, maxYValue: maxY, // 最大值可自定义 - yStepCount: 7, // 分4段(0, 5, 10, 15, 20) + yStepCount: 3, // 分4段(0, 5, 10, 15, 20) ), ), Padding(