From 516ad431addc2bb3c534066541c768fa8e16fc21 Mon Sep 17 00:00:00 2001 From: wyf <494641114@qq.com> Date: Sat, 20 Dec 2025 18:09:14 +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/sleep_report/chart/SnoreChart.dart | 91 ++-- .../component/SnoreViewWidget.dart | 483 +++++++++++++++--- 2 files changed, 475 insertions(+), 99 deletions(-) diff --git a/lib/pages/sleep_report/chart/SnoreChart.dart b/lib/pages/sleep_report/chart/SnoreChart.dart index c9c4b40..d51cea3 100644 --- a/lib/pages/sleep_report/chart/SnoreChart.dart +++ b/lib/pages/sleep_report/chart/SnoreChart.dart @@ -82,7 +82,7 @@ class _BarChartWidgetState extends State { onTapDown: (details) => _handleTapOrDrag(details.localPosition, constraints.biggest), child: CustomPaint( - size: Size(double.infinity, 250.rpx), + size: Size(constraints.maxWidth, 250.rpx), // 使用约束的最大宽度 painter: BarChartPainter( widget.data, widget.startTime, @@ -133,8 +133,8 @@ class BarChartPainter extends CustomPainter { final y = topPadding + chartHeight - (value / maxYValue) * chartHeight; final dashPaint = Paint() - ..color = Colors.grey.withOpacity(0.5) - ..strokeWidth = 0.5; + ..color = Colors.grey.withOpacity(0.4) + ..strokeWidth = 1.rpx; drawDashedLine( canvas, Offset(leftPadding, y), Offset(size.width, y), dashPaint); @@ -142,7 +142,7 @@ class BarChartPainter extends CustomPainter { textPainter.text = TextSpan( text: value.toStringAsFixed(0), style: TextStyle( - fontSize: 20.rpx, + fontSize: 18.rpx, color: themeController.currentColor.sc4, ), ); @@ -153,44 +153,68 @@ class BarChartPainter extends CustomPainter { ); } - // X轴刻度 + // X轴刻度 - 参考横线图的24小时制 final startDate = DateTime.fromMillisecondsSinceEpoch(startTime); final endDate = DateTime.fromMillisecondsSinceEpoch(endTime); - final hourStep = const Duration(hours: 1); - final xAxisY = topPadding + chartHeight; + final xAxisY = topPadding + chartHeight; // 这是最底部的Y坐标 - for (DateTime t = startDate; t.isBefore(endDate); t = t.add(hourStep)) { - final x = ((t.millisecondsSinceEpoch - startTime) / totalDuration) * - chartWidth + - leftPadding; - final timeLabel = (t == startDate || t == endDate) - ? DateFormat('HH:mm').format(t) - : DateFormat('h').format(t); + // 计算总小时数 + final totalHours = endDate.difference(startDate).inHours + 1; + final startHour = startDate.hour; - textPainter.text = TextSpan( - text: timeLabel, - style: TextStyle( - fontSize: AppConstants().smaller_text_fontSize, - color: themeController.currentColor.sc4, - ), - ); - textPainter.layout(); - textPainter.paint(canvas, Offset(x - textPainter.width / 2, xAxisY + 4)); - } + // 绘制X轴主线(实线) + final xAxisPaint = Paint() + ..color = Colors.grey.withOpacity(0.4) + ..strokeWidth = 1.rpx; + canvas.drawLine( + Offset(leftPadding, xAxisY), + Offset(size.width, xAxisY), + xAxisPaint, + ); - // 额外终点标签 - final endX = - ((endTime - startTime) / totalDuration) * chartWidth + leftPadding; - final endLabel = DateFormat('HH:mm').format(endDate); + // 绘制左右两侧时间标签(HH:mm格式) + final leftLabel = DateFormat('HH:mm').format(startDate); textPainter.text = TextSpan( - text: endLabel, + text: leftLabel, style: TextStyle( - fontSize: AppConstants().smaller_text_fontSize, + fontSize: 18.rpx, color: themeController.currentColor.sc4, ), ); textPainter.layout(); - textPainter.paint(canvas, Offset(endX - textPainter.width / 2, xAxisY + 4)); + 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)); + } // 柱子绘制 & 提示信息缓存 Offset? tipOffset; @@ -232,7 +256,10 @@ class BarChartPainter extends CustomPainter { final tipLeft = left + (right - left) / 2 - tipWidth / 2; final tipTop = top - tipHeight - 10.rpx; - tipOffset = Offset(tipLeft, tipTop); + // 确保tip不会超出画布顶部 + final double adjustedTipTop = tipTop < 0 ? 0.0 : tipTop; + + tipOffset = Offset(tipLeft, adjustedTipTop); tipSize = Size(tipWidth, tipHeight); tipColor = Colors.black.withOpacity(0.8); } diff --git a/lib/pages/sleep_report/component/SnoreViewWidget.dart b/lib/pages/sleep_report/component/SnoreViewWidget.dart index e0f00b4..60c5b4a 100644 --- a/lib/pages/sleep_report/component/SnoreViewWidget.dart +++ b/lib/pages/sleep_report/component/SnoreViewWidget.dart @@ -1,3 +1,380 @@ +// import 'package:EasyDartModule/EasyDartModule.dart' as es; +// import 'package:ef/ef.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_svg/svg.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/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/SnoreChart.dart'; + +// class SnoreViewWidgetWidget extends StatefulWidget { +// var sleepReport; +// SnoreViewWidgetWidget({super.key, required this.sleepReport}); + +// @override +// State createState() => _SnoreViewWidgetWidgetState(); +// } + +// class _SnoreViewWidgetWidgetState extends State { +// @override +// void setState(VoidCallback callback) { +// super.setState(callback); +// } + +// @override +// void initState() { +// super.initState(); +// } + +// @override +// void dispose() { +// super.dispose(); +// } + +// @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) { +// // return Container(); +// // } +// double maxY = 250; +// var startTime = widget.sleepReport['startTime']; +// var endTime = widget.sleepReport['endTime']; +// List snoreValues = []; + +// List type = widget.sleepReport['ssp']['type']; +// 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, +// 'id': type[0]['id'], +// 'name': type[0]['name'], +// 'color': type[0]['color'], +// }; +// }).toList(); + +// List processedHeavySnore = heavySnore.map((item) { +// return { +// ...item, +// 'id': type[1]['id'], +// 'name': type[1]['name'], +// 'color': type[1]['color'], +// }; +// }).toList(); + +// snoreValues = [...processedLightSnore, ...processedHeavySnore]; +// snoreValues.sort((a, b) => a['st'].compareTo(b['st'])); +// print(snoreValues); +// List barDataList = snoreValues.map((item) { +// return BarData( +// st: item['st'], +// et: item['et'], +// value: (item['value'] as num).toDouble() > maxY +// ? maxY + 3 +// : (item['value'] as num).toDouble(), +// id: item['id'], +// name: item['name'], +// color: (item['color'] == null || item['color'].isEmpty) +// ? (item['id'] == 1 ? Colors.green : Colors.red) +// : stringToColor(item['color']), +// ); +// }).toList(); + +// // List> data = +// // (widget.sleepReport['ssp'] as List).cast>(); +// // List> showLabel = convertToShowLabel(data); + +// return Container( +// width: double.infinity, +// decoration: BoxDecoration( +// color: themeController.currentColor.sc5, +// borderRadius: BorderRadius.circular( +// AppConstants().normal_container_radius), // 你可以按需调整圆角半径 +// ), +// child: Padding( +// padding: +// EdgeInsetsDirectional.fromSTEB(26.rpx, 29.rpx, 26.rpx, 0.rpx), +// child: Column( +// mainAxisSize: MainAxisSize.max, +// children: [ +// Container( +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Text( +// "打鼾监测".tr, +// style: TextStyle( +// color: themeController.currentColor.sc3, +// fontSize: AppConstants().title_text_fontSize), +// ), +// ClickableContainer( +// backgroundColor: Colors.transparent, +// highlightColor: Colors.white, // 或设置为你需要的水波纹颜色 +// padding: EdgeInsetsDirectional.fromSTEB( +// 14.rpx, 10.rpx, 14.rpx, 10.rpx), // +// borderRadius: 0.rpx, // 圆形点击区域 +// onTap: () { +// if (AppConstants().ent_type == +// APPPackageType.MHT.code) { +// showTipDialog( +// context, +// Container( +// child: Text( +// // "打鼾监测介绍。", +// "打鼾监测是指用户在睡眠过程中打鼾频次的图表说明。".tr, +// style: TextStyle( +// fontSize: 26.rpx, +// color: Colors.black, +// ), +// ), +// ), +// backgroundColor: Color(0xFFFFFFFF), +// colors: [ +// Color(0XFF1592AA), +// Color(0xFF0C83A7), +// Color(0xFF006FA3) +// ], +// ); +// } else { +// showTipDialog( +// context, +// Container( +// child: Text( +// "打鼾监测是指用户在睡眠过程中打鼾频次的图表说明。".tr, +// style: TextStyle( +// fontSize: 26.rpx, +// color: themeController.currentColor.sc3, +// ), +// ), +// ), +// backgroundColor: themeController.currentColor.sc17, +// colors: AppConstants().thNormalButton, +// ); +// } +// }, +// child: Container( +// padding: EdgeInsetsDirectional.fromSTEB( +// 0, 0.rpx, 0.rpx, 0), // 外部 padding 移到内部 +// width: 28.rpx, +// height: 28.rpx, +// child: SvgPicture.asset( +// 'assets/img/icon/explain.svg', +// fit: BoxFit.cover, +// color: themeController.currentColor.sc4, +// ), +// ), +// ), +// ], +// ), +// ), +// SizedBox( +// height: 32.rpx, +// ), +// Row( +// children: [ +// Text( +// "次".tr, +// style: TextStyle( +// color: stringToColor("#FFFFFF"), fontSize: 18.rpx), +// ), +// ], +// ), +// Padding( +// padding: EdgeInsetsDirectional.fromSTEB( +// 0.rpx, 40.rpx, 20.rpx, 0.rpx), +// // child: LineChartByRange( +// // showLabel: showLabel, +// // startTime: startTime, +// // endTime: endTime, +// // ), +// child: BarChartWidget( +// data: barDataList, +// startTime: startTime, +// endTime: endTime, +// maxYValue: maxY, // 最大值可自定义 +// yStepCount: 3, // 分4段(0, 5, 10, 15, 20) +// ), +// ), +// Padding( +// padding: +// EdgeInsetsDirectional.fromSTEB(0.rpx, 52.rpx, 0.rpx, 0.rpx), +// child: Container( +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceAround, +// children: [ +// Column( +// crossAxisAlignment: CrossAxisAlignment.center, // 左对齐 +// children: [ +// Row( +// children: [ +// // 小圆球 +// Container( +// width: 14.rpx, +// height: 14.rpx, +// decoration: BoxDecoration( +// color: (type[0]?['color'] == null || +// type[0]?['color'].isEmpty) +// ? Colors.green +// : stringToColor( +// "${type[0]['color']}"), // 你想要的颜色 +// shape: BoxShape.circle, +// ), +// ), +// SizedBox(width: 12.rpx), // 小圆球和文字间距 +// Text( +// '${type[0]?['name']}', +// style: TextStyle( +// fontSize: +// AppConstants().normal_text_fontSize, +// color: themeController.currentColor.sc3), +// ), +// ], +// ), +// SizedBox(height: 16.rpx), // 两行文字间距 +// Text( +// '${(type[0]?['value'] == null || type[0]['value'].toString().isEmpty) ? '未知数据'.tr : '${type[0]?['value']}${(type[0]?['unit'] == null || type[0]['unit'].toString().isEmpty) ? '' : type[0]?['unit']}'}', +// style: TextStyle( +// fontSize: AppConstants().small_text_fontSize, +// color: themeController.currentColor.sc4), +// ), +// ], +// ), +// Column( +// crossAxisAlignment: CrossAxisAlignment.center, // 左对齐 +// children: [ +// Row( +// children: [ +// // 小圆球 +// Container( +// width: 14.rpx, +// height: 14.rpx, +// decoration: BoxDecoration( +// color: (type[1]?['color'] == null || +// type[1]?['color'].isEmpty) +// ? Colors.red +// : stringToColor( +// "${type[1]['color']}"), // 你想要的颜色 +// shape: BoxShape.circle, +// ), +// ), +// SizedBox(width: 12.rpx), // 小圆球和文字间距 +// Text( +// '${type[1]?['name']}', +// style: TextStyle( +// fontSize: +// AppConstants().normal_text_fontSize, +// color: themeController.currentColor.sc3), +// ), +// ], +// ), +// SizedBox(height: 16.rpx), // 两行文字间距 +// Text( +// '${(type[1]?['value'] == null || type[1]['value'].toString().isEmpty) ? '未知数据'.tr : '${type[1]?['value']}${(type[1]?['unit'] == null || type[1]['unit'].toString().isEmpty) ? '' : type[1]?['unit']}'}', +// style: TextStyle( +// fontSize: AppConstants().small_text_fontSize, +// color: themeController.currentColor.sc4), +// ), +// ], +// ), +// ], +// ), +// ), +// ), +// SizedBox( +// height: 52.rpx, +// ), +// ], +// ), +// ), +// ); +// } catch (e) { +// es.EasyDartModule.logger.error("打鼾监测绘制异常${e}"); +// return Container(); +// } +// } + +// List> convertToShowLabel( +// List> data) { +// if (data.isEmpty) return []; + +// data.sort((a, b) => a['st'].compareTo(b['st'])); // 确保时间有序 + +// List> result = []; + +// int startTime = data[0]['st']; +// int endTime = data[0]['et']; +// int currentValue = data[0]['value']; + +// for (int i = 1; i < data.length; i++) { +// final item = data[i]; +// final st = item['st']; +// final value = item['value']; +// final et = item['et']; + +// if (value == currentValue) { +// endTime = st; +// } else { +// result.add({ +// "startTime": startTime, +// "endTime": endTime, +// "times": currentValue, +// }); +// startTime = st; +// endTime = et; +// currentValue = value; +// } +// } + +// // 添加最后一段 +// result.add({ +// "startTime": startTime, +// "endTime": endTime, +// "times": currentValue, +// }); + +// return result; +// } +// } + import 'package:EasyDartModule/EasyDartModule.dart' as es; import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; @@ -45,7 +422,7 @@ class _SnoreViewWidgetWidgetState extends State { // 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,35 +431,6 @@ 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, @@ -103,14 +451,30 @@ class _SnoreViewWidgetWidgetState extends State { snoreValues = [...processedLightSnore, ...processedHeavySnore]; snoreValues.sort((a, b) => a['st'].compareTo(b['st'])); - print(snoreValues); + + // 动态计算最大值 + double maxY = 0; + for (final item in snoreValues) { + if (item['value'] != null) { + final value = (item['value'] as num).toDouble(); + if (value > maxY) { + maxY = value; + } + } + } + + // 添加20的偏移量,确保所有数据都能正常显示 + maxY = maxY + 5; + // 如果数据都为空,给一个默认值 + if (maxY <= 5) { + maxY = 20; // 或根据业务需要设置一个合理的默认值 + } + List barDataList = snoreValues.map((item) { return BarData( st: item['st'], et: item['et'], - value: (item['value'] as num).toDouble() > maxY - ? maxY + 3 - : (item['value'] as num).toDouble(), + value: (item['value'] as num).toDouble(), id: item['id'], name: item['name'], color: (item['color'] == null || item['color'].isEmpty) @@ -119,16 +483,12 @@ class _SnoreViewWidgetWidgetState extends State { ); }).toList(); - // List> data = - // (widget.sleepReport['ssp'] as List).cast>(); - // List> showLabel = convertToShowLabel(data); - return Container( width: double.infinity, decoration: BoxDecoration( color: themeController.currentColor.sc5, - borderRadius: BorderRadius.circular( - AppConstants().normal_container_radius), // 你可以按需调整圆角半径 + borderRadius: + BorderRadius.circular(AppConstants().normal_container_radius), ), child: Padding( padding: @@ -148,10 +508,10 @@ class _SnoreViewWidgetWidgetState extends State { ), ClickableContainer( backgroundColor: Colors.transparent, - highlightColor: Colors.white, // 或设置为你需要的水波纹颜色 + highlightColor: Colors.white, padding: EdgeInsetsDirectional.fromSTEB( - 14.rpx, 10.rpx, 14.rpx, 10.rpx), // - borderRadius: 0.rpx, // 圆形点击区域 + 14.rpx, 10.rpx, 14.rpx, 10.rpx), + borderRadius: 0.rpx, onTap: () { if (AppConstants().ent_type == APPPackageType.MHT.code) { @@ -159,7 +519,6 @@ class _SnoreViewWidgetWidgetState extends State { context, Container( child: Text( - // "打鼾监测介绍。", "打鼾监测是指用户在睡眠过程中打鼾频次的图表说明。".tr, style: TextStyle( fontSize: 26.rpx, @@ -192,8 +551,8 @@ class _SnoreViewWidgetWidgetState extends State { } }, child: Container( - padding: EdgeInsetsDirectional.fromSTEB( - 0, 0.rpx, 0.rpx, 0), // 外部 padding 移到内部 + padding: + EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0.rpx, 0), width: 28.rpx, height: 28.rpx, child: SvgPicture.asset( @@ -221,17 +580,12 @@ class _SnoreViewWidgetWidgetState extends State { Padding( padding: EdgeInsetsDirectional.fromSTEB( 0.rpx, 40.rpx, 20.rpx, 0.rpx), - // child: LineChartByRange( - // showLabel: showLabel, - // startTime: startTime, - // endTime: endTime, - // ), child: BarChartWidget( data: barDataList, startTime: startTime, endTime: endTime, - maxYValue: maxY, // 最大值可自定义 - yStepCount: 3, // 分4段(0, 5, 10, 15, 20) + maxYValue: maxY, + yStepCount: 5, // 可以保持5段或根据需求调整 ), ), Padding( @@ -242,11 +596,10 @@ class _SnoreViewWidgetWidgetState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column( - crossAxisAlignment: CrossAxisAlignment.center, // 左对齐 + crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( children: [ - // 小圆球 Container( width: 14.rpx, height: 14.rpx, @@ -254,12 +607,11 @@ class _SnoreViewWidgetWidgetState extends State { color: (type[0]?['color'] == null || type[0]?['color'].isEmpty) ? Colors.green - : stringToColor( - "${type[0]['color']}"), // 你想要的颜色 + : stringToColor("${type[0]['color']}"), shape: BoxShape.circle, ), ), - SizedBox(width: 12.rpx), // 小圆球和文字间距 + SizedBox(width: 12.rpx), Text( '${type[0]?['name']}', style: TextStyle( @@ -269,7 +621,7 @@ class _SnoreViewWidgetWidgetState extends State { ), ], ), - SizedBox(height: 16.rpx), // 两行文字间距 + SizedBox(height: 16.rpx), Text( '${(type[0]?['value'] == null || type[0]['value'].toString().isEmpty) ? '未知数据'.tr : '${type[0]?['value']}${(type[0]?['unit'] == null || type[0]['unit'].toString().isEmpty) ? '' : type[0]?['unit']}'}', style: TextStyle( @@ -279,11 +631,10 @@ class _SnoreViewWidgetWidgetState extends State { ], ), Column( - crossAxisAlignment: CrossAxisAlignment.center, // 左对齐 + crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( children: [ - // 小圆球 Container( width: 14.rpx, height: 14.rpx, @@ -291,12 +642,11 @@ class _SnoreViewWidgetWidgetState extends State { color: (type[1]?['color'] == null || type[1]?['color'].isEmpty) ? Colors.red - : stringToColor( - "${type[1]['color']}"), // 你想要的颜色 + : stringToColor("${type[1]['color']}"), shape: BoxShape.circle, ), ), - SizedBox(width: 12.rpx), // 小圆球和文字间距 + SizedBox(width: 12.rpx), Text( '${type[1]?['name']}', style: TextStyle( @@ -306,7 +656,7 @@ class _SnoreViewWidgetWidgetState extends State { ), ], ), - SizedBox(height: 16.rpx), // 两行文字间距 + SizedBox(height: 16.rpx), Text( '${(type[1]?['value'] == null || type[1]['value'].toString().isEmpty) ? '未知数据'.tr : '${type[1]?['value']}${(type[1]?['unit'] == null || type[1]['unit'].toString().isEmpty) ? '' : type[1]?['unit']}'}', style: TextStyle( @@ -336,7 +686,7 @@ class _SnoreViewWidgetWidgetState extends State { List> data) { if (data.isEmpty) return []; - data.sort((a, b) => a['st'].compareTo(b['st'])); // 确保时间有序 + data.sort((a, b) => a['st'].compareTo(b['st'])); List> result = []; @@ -364,7 +714,6 @@ class _SnoreViewWidgetWidgetState extends State { } } - // 添加最后一段 result.add({ "startTime": startTime, "endTime": endTime,