更新打鼾图显示

This commit is contained in:
wyf
2025-12-20 17:41:31 +08:00
parent 8e7411cf92
commit ee9965e3df
9 changed files with 529 additions and 235 deletions

View File

@@ -65,6 +65,7 @@ Widget getOnePickers(
void Function(int)? onChanged, void Function(int)? onChanged,
bool isMonthName = false, bool isMonthName = false,
Key? pickerKey, Key? pickerKey,
Color? selectedColor, // ✅ 新增:选中颜色(可选)
}) { }) {
ThemeController themeController = Get.find(); ThemeController themeController = Get.find();
final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false; final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false;
@@ -87,15 +88,14 @@ Widget getOnePickers(
}, },
childCount: arr.length, childCount: arr.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
bool isSelected = index == selectedIndex.value; final bool isSelected = index == selectedIndex.value;
// 处理显示文本 // 显示文本
String displayText; String displayText;
if (isMonthName && isEn && arr[index] is int) { if (isMonthName && isEn && arr[index] is int) {
displayText = DateFormat.MMMM('en').format(DateTime(0, arr[index])); displayText = DateFormat.MMMM('en').format(DateTime(0, arr[index]));
} else { } else {
// displayText = isEn ? "${arr[index]}" : "${arr[index]}$unit"; // 中文附带单位 displayText = "${arr[index]}$unit";
displayText = "${arr[index]}$unit"; // 中文附带单位
} }
return Center( return Center(
@@ -104,7 +104,8 @@ Widget getOnePickers(
style: TextStyle( style: TextStyle(
fontFamily: 'Readex Pro', fontFamily: 'Readex Pro',
color: isSelected color: isSelected
? themeController.currentColor.sc3 ? (selectedColor ??
themeController.currentColor.sc3) // ✅ 优先使用外部颜色
: const Color(0xFF9AA0B3), : const Color(0xFF9AA0B3),
fontSize: 30.rpx, fontSize: 30.rpx,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
@@ -329,6 +330,8 @@ Future showDateSelectionDialog(BuildContext context,
monthIndex, monthIndex,
isMonthName: true, isMonthName: true,
onChanged: (_) => updateDays(), onChanged: (_) => updateDays(),
selectedColor:
stringToColor("#003058"),
), ),
), ),
Expanded( Expanded(
@@ -336,6 +339,8 @@ Future showDateSelectionDialog(BuildContext context,
context, context,
daysSelect, daysSelect,
dayIndex, dayIndex,
selectedColor:
stringToColor("#003058"),
), ),
), ),
Expanded( Expanded(
@@ -344,6 +349,8 @@ Future showDateSelectionDialog(BuildContext context,
years, years,
yearIndex, yearIndex,
onChanged: (_) => updateDays(), onChanged: (_) => updateDays(),
selectedColor:
stringToColor("#003058"),
), ),
), ),
] ]
@@ -355,6 +362,8 @@ Future showDateSelectionDialog(BuildContext context,
yearIndex, yearIndex,
unit: "", unit: "",
onChanged: (_) => updateDays(), onChanged: (_) => updateDays(),
selectedColor:
stringToColor("#003058"),
), ),
), ),
Expanded( Expanded(
@@ -364,6 +373,8 @@ Future showDateSelectionDialog(BuildContext context,
monthIndex, monthIndex,
unit: "", unit: "",
onChanged: (_) => updateDays(), onChanged: (_) => updateDays(),
selectedColor:
stringToColor("#003058"),
), ),
), ),
Expanded( Expanded(
@@ -372,6 +383,8 @@ Future showDateSelectionDialog(BuildContext context,
daysSelect, daysSelect,
dayIndex, dayIndex,
unit: "", unit: "",
selectedColor:
stringToColor("#003058"),
), ),
), ),
], ],
@@ -688,6 +701,7 @@ Future<void> showWeightPickerDialog(
weights, weights,
tempIndex, // ✅ 传入 RxInt tempIndex, // ✅ 传入 RxInt
unit: "kg", unit: "kg",
selectedColor: stringToColor("#003058"),
), ),
), ),
], ],
@@ -815,6 +829,7 @@ Future<void> showHeightPickerDialog(
heights, heights,
tempIndex, // ✅ 传入 RxInt tempIndex, // ✅ 传入 RxInt
unit: "cm", unit: "cm",
selectedColor: stringToColor("#003058"),
), ),
), ),
], ],
@@ -1088,6 +1103,7 @@ Future showOneSelectionDialog(
arr, arr,
selectedIndex, selectedIndex,
unit: '', unit: '',
selectedColor: stringToColor("#003058"),
), ),
), ),
], ],

View File

@@ -489,7 +489,9 @@ class _MHTPeopleInfoPageState extends State<MHTPeopleInfoPage> {
filled: true, filled: true,
hintText: "请输入姓名".tr, hintText: "请输入姓名".tr,
hintStyle: TextStyle( hintStyle: TextStyle(
color: Colors.white), color: themeController
.currentColor.sc4,
),
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding:
EdgeInsets.all(0)), EdgeInsets.all(0)),
@@ -821,7 +823,9 @@ class _MHTPeopleInfoPageState extends State<MHTPeopleInfoPage> {
filled: true, filled: true,
hintText: "请输入联系方式".tr, hintText: "请输入联系方式".tr,
hintStyle: TextStyle( hintStyle: TextStyle(
color: Colors.white), color: themeController
.currentColor.sc4,
),
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding:
EdgeInsets.all(0)), EdgeInsets.all(0)),

View File

@@ -253,7 +253,7 @@ class _SettingPageState extends State<SettingPage> {
), ),
].divide(SizedBox(width: 22.rpx)), ].divide(SizedBox(width: 22.rpx)),
), ),
Text('SWES2025.12.17', Text('SWES2025.12.20',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 26.rpx, fontSize: 26.rpx,

View File

@@ -50,7 +50,8 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
}); });
getPersonData(); getPersonData();
controller.cityDataFuture = cityController.loadAndSetCityData().then((success) { controller.cityDataFuture =
cityController.loadAndSetCityData().then((success) {
return cityController.cityList; return cityController.cityList;
}); });
return LayoutBuilder( return LayoutBuilder(
@@ -297,20 +298,26 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
fontSize: 30.rpx, fontSize: 30.rpx,
color: color:
Colors.white), Colors.white),
decoration: InputDecoration( decoration:
fillColor: Colors InputDecoration(
.transparent, fillColor: Colors
filled: true, .transparent,
hintText: filled: true,
"请输入姓名".tr, hintText:
hintStyle: TextStyle( "请输入姓名".tr,
color: Colors hintStyle:
.white), TextStyle(
border: InputBorder color: themeController
.none, .currentColor
contentPadding: .sc4,
EdgeInsets.all( ),
0)), border:
InputBorder
.none,
contentPadding:
EdgeInsets
.all(
0)),
onChanged: (value) { onChanged: (value) {
controller.model controller.model
.peopleList[ .peopleList[
@@ -356,9 +363,11 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
title: "选择性别".tr, title: "选择性别".tr,
arr: ["".tr, "".tr], arr: ["".tr, "".tr],
checkIndex: controller checkIndex: controller
.model .model
.peopleList[ .peopleList[
index]['gender'], index]
['gender'] ??
0,
checkChange: (sindex) { checkChange: (sindex) {
controller.model.peopleList[ controller.model.peopleList[
index]['gender'] = index]['gender'] =
@@ -529,7 +538,7 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
'assets/img/icon/expand_more.svg', 'assets/img/icon/expand_more.svg',
color: color:
Colors.white, Colors.white,
)) )),
], ],
), ),
], ],
@@ -777,20 +786,25 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
style: TextStyle( style: TextStyle(
fontSize: 30.rpx, fontSize: 30.rpx,
color: Colors.white), color: Colors.white),
decoration: InputDecoration( decoration:
fillColor: Colors InputDecoration(
.transparent, fillColor: Colors
filled: true, .transparent,
hintText: filled: true,
"请输入联系方式".tr, hintText:
hintStyle: TextStyle( "请输入联系方式".tr,
color: hintStyle:
Colors.white), TextStyle(
border: color: themeController
InputBorder.none, .currentColor
contentPadding: .sc4,
EdgeInsets.all( ),
0)), border:
InputBorder
.none,
contentPadding:
EdgeInsets
.all(0)),
onChanged: (value) { onChanged: (value) {
controller.model controller.model
.peopleList[ .peopleList[
@@ -903,6 +917,9 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
selectedCityColor: selectedCityColor:
stringToColor( stringToColor(
"#84F5FF"), "#84F5FF"),
selectedTextColor:
stringToColor(
"#011D33"),
), ),
); );
}); });
@@ -923,164 +940,47 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
letterSpacing: 0, letterSpacing: 0,
), ),
), ),
Text( Row(
getCityModel(index) != children: [
null Text(
? MyUtils getCityModel(index) !=
.getDetailedCityDisplayText( null
getCityModel( ? MyUtils
index)) .getDetailedCityDisplayText(
: "请选择城市".tr, getCityModel(
style: TextStyle( index))
color: getCityModel( : "请选择城市".tr,
index) != style: TextStyle(
null color: getCityModel(
? themeController index) !=
.currentColor null
.sc3 ? themeController
: themeController .currentColor
.currentColor .sc3
.sc4, : themeController
fontSize: AppConstants() .currentColor
.title_text_fontSize, .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(), 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( Container(
height: 90.rpx, height: 90.rpx,
margin: EdgeInsets.only( margin: EdgeInsets.only(
@@ -1162,23 +1062,39 @@ class PeopleInfoPage extends GetView<PeopleInfoController> {
controller controller
.diseaseList; .diseaseList;
return Text( return Row(
getSelectedDiseaseNames( children: [
diseases, Text(
List<String>.from( getSelectedDiseaseNames(
selectedIds)), diseases,
style: TextStyle( List<String>.from(
color: selectedIds selectedIds)),
.isNotEmpty style: TextStyle(
? themeController color: selectedIds.isNotEmpty
.currentColor ? themeController
.sc3 .currentColor
: themeController .sc3
.currentColor : themeController
.sc4, .currentColor
fontSize: AppConstants() .sc4,
.title_text_fontSize, 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,
))
],
); );
}), }),
], ],

View File

@@ -42,11 +42,13 @@ class CitySelectionColors {
final Color? pickerBackgroundColor; // 选择器整体背景色 final Color? pickerBackgroundColor; // 选择器整体背景色
final Color? confirmTextColor; // 确定按钮文字颜色 final Color? confirmTextColor; // 确定按钮文字颜色
final Color? selectedCityColor; // 选中的城市背景色 final Color? selectedCityColor; // 选中的城市背景色
final Color? selectedTextColor; // 选中的文字颜色
const CitySelectionColors({ const CitySelectionColors({
this.pickerBackgroundColor, this.pickerBackgroundColor,
this.confirmTextColor, this.confirmTextColor,
this.selectedCityColor, this.selectedCityColor,
this.selectedTextColor,
}); });
} }
@@ -68,6 +70,8 @@ Future showCitySelectionDialog(
colors?.confirmTextColor ?? themeController.currentColor.sc2; colors?.confirmTextColor ?? themeController.currentColor.sc2;
final Color selectedCityColor = final Color selectedCityColor =
colors?.selectedCityColor ?? themeController.currentColor.sc2; colors?.selectedCityColor ?? themeController.currentColor.sc2;
final Color selectedTextColor =
colors?.selectedTextColor ?? themeController.currentColor.sc1; // 默认使用主题颜色
final RxList<String> countries = <String>[].obs; final RxList<String> countries = <String>[].obs;
final RxList<String> provinces = <String>[].obs; final RxList<String> provinces = <String>[].obs;
@@ -300,6 +304,7 @@ Future showCitySelectionDialog(
pickerBackgroundColor: pickerBackgroundColor, pickerBackgroundColor: pickerBackgroundColor,
confirmTextColor: confirmTextColor, confirmTextColor: confirmTextColor,
selectedCityColor: selectedCityColor, selectedCityColor: selectedCityColor,
selectedTextColor: selectedTextColor,
countries: countries, countries: countries,
provinces: provinces, provinces: provinces,
cities: cities, cities: cities,
@@ -388,6 +393,7 @@ Widget _buildCityPickerContent(
required Color pickerBackgroundColor, required Color pickerBackgroundColor,
required Color confirmTextColor, required Color confirmTextColor,
required Color selectedCityColor, required Color selectedCityColor,
required Color selectedTextColor,
required RxList<String> countries, required RxList<String> countries,
required RxList<String> provinces, required RxList<String> provinces,
required RxList<String> cities, required RxList<String> cities,
@@ -664,7 +670,8 @@ Widget _buildCityPickerContent(
unit: "", unit: "",
onChanged: (_) => updateProvinces(), onChanged: (_) => updateProvinces(),
pickerKey: ValueKey( pickerKey: ValueKey(
'country_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key 'country_${DateTime.now().millisecondsSinceEpoch}'),
selectedColor: selectedTextColor, // 传递选中文字颜色
); );
}), }),
), ),
@@ -681,7 +688,8 @@ Widget _buildCityPickerContent(
unit: "", unit: "",
onChanged: (_) => updateCities(), onChanged: (_) => updateCities(),
pickerKey: ValueKey( pickerKey: ValueKey(
'province_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key 'province_${DateTime.now().millisecondsSinceEpoch}'),
selectedColor: selectedTextColor, // 传递选中文字颜色
); );
}), }),
), ),
@@ -697,7 +705,8 @@ Widget _buildCityPickerContent(
cityIndex, cityIndex,
unit: "", unit: "",
pickerKey: ValueKey( pickerKey: ValueKey(
'city_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key 'city_${DateTime.now().millisecondsSinceEpoch}'),
selectedColor: selectedTextColor, // 传递选中文字颜色
); );
}), }),
), ),
@@ -800,4 +809,4 @@ Widget _buildErrorBottomSheet(
], ],
), ),
); );
} }

View File

@@ -1,5 +1,6 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
//柱形图显示
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:vbvs_app/common/color/appConstants.dart'; import 'package:vbvs_app/common/color/appConstants.dart';
@@ -81,7 +82,7 @@ class _BarChartWidgetState extends State<BarChartWidget> {
onTapDown: (details) => onTapDown: (details) =>
_handleTapOrDrag(details.localPosition, constraints.biggest), _handleTapOrDrag(details.localPosition, constraints.biggest),
child: CustomPaint( child: CustomPaint(
size: Size(double.infinity, 500.rpx), size: Size(double.infinity, 250.rpx),
painter: BarChartPainter( painter: BarChartPainter(
widget.data, widget.data,
widget.startTime, 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<BarData> 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<BarChartWidget> createState() => _BarChartWidgetState();
// }
// class _BarChartWidgetState extends State<BarChartWidget> {
// 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<BarData> 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;
// }
// }
// }

View File

@@ -37,18 +37,18 @@ class _SnoreViewWidgetWidgetState extends State<BreathePauseNewWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
try { try {
if (widget.sleepReport == null || if (APPPackageType.TH.code == AppConstants().ent_type) {
widget.sleepReport is! Map || if (widget.sleepReport == null ||
widget.sleepReport.isEmpty) { widget.sleepReport is! Map ||
return Container(); widget.sleepReport.isEmpty) {
return Container();
}
} }
List standard = widget.sleepReport['brs'] ?? []; List standard = widget.sleepReport['brs'] ?? [];
final Map? result = standard.cast<Map>().firstWhere( final Map? result = standard.cast<Map>().firstWhere(
(element) => element['id'] == 302, (element) => element['id'] == 302,
orElse: () => <dynamic, dynamic>{}, orElse: () => <dynamic, dynamic>{},
); );
int threshold = 0; int threshold = 0;
if (result != null && result.isNotEmpty) { if (result != null && result.isNotEmpty) {
final rangeValue = result['range']; final rangeValue = result['range'];
@@ -58,16 +58,8 @@ class _SnoreViewWidgetWidgetState extends State<BreathePauseNewWidget> {
threshold = int.tryParse(rangeValue) ?? 0; threshold = int.tryParse(rangeValue) ?? 0;
} }
} }
List<Map<String, dynamic>> data = List<Map<String, dynamic>> data =
(widget.sleepReport['asp'] as List).cast<Map<String, dynamic>>(); (widget.sleepReport['asp'] as List).cast<Map<String, dynamic>>();
// data = [
// {"st": 1763494195669, "value": 11},
// {"st": 1763494278485, "value": 18},
// {"st": 1763494293453, "value": 18},
// {"st": 1763494352321, "value": 14},
// {"st": 1763494606757, "value": 12}
// ];
List<Map<String, dynamic>> showLabel = convertToShowLabel(data); List<Map<String, dynamic>> showLabel = convertToShowLabel(data);
double maxTimes = 70; double maxTimes = 70;
try { try {

View File

@@ -53,7 +53,7 @@ Widget DailyDataWidget(
sleepReport: sleepReport, sleepReport: sleepReport,
highlightItem: data['itemName'], highlightItem: data['itemName'],
), ),
// SnoreViewWidgetWidget(sleepReport: sleepReport), SnoreViewWidgetWidget(sleepReport: sleepReport),
BreathePauseNewWidget(sleepReport: sleepReport), BreathePauseNewWidget(sleepReport: sleepReport),
HeartHealthWidget(sleepReport: sleepReport), HeartHealthWidget(sleepReport: sleepReport),
DiseasePercentsWidget(sleepReport: sleepReport), DiseasePercentsWidget(sleepReport: sleepReport),

View File

@@ -1,5 +1,3 @@
import 'dart:math';
import 'package:EasyDartModule/EasyDartModule.dart' as es; import 'package:EasyDartModule/EasyDartModule.dart' as es;
import 'package:ef/ef.dart'; import 'package:ef/ef.dart';
import 'package:flutter/material.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/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/enum/APPPackageType.dart'; import 'package:vbvs_app/enum/APPPackageType.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.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'; import 'package:vbvs_app/pages/sleep_report/chart/SnoreChart.dart';
class SnoreViewWidgetWidget extends StatefulWidget { class SnoreViewWidgetWidget extends StatefulWidget {
@@ -45,7 +42,10 @@ class _SnoreViewWidgetWidgetState extends State<SnoreViewWidgetWidget> {
widget.sleepReport.isEmpty) { widget.sleepReport.isEmpty) {
return Container(); return Container();
} }
double maxY = 70; // if (APPPackageType.TH.code == AppConstants().ent_type) {
// return Container();
// }
double maxY = 250;
var startTime = widget.sleepReport['startTime']; var startTime = widget.sleepReport['startTime'];
var endTime = widget.sleepReport['endTime']; var endTime = widget.sleepReport['endTime'];
List snoreValues = []; List snoreValues = [];
@@ -54,6 +54,35 @@ class _SnoreViewWidgetWidgetState extends State<SnoreViewWidgetWidget> {
List lightSnore = widget.sleepReport['ssp']['data'][0]; List lightSnore = widget.sleepReport['ssp']['data'][0];
List heavySnore = widget.sleepReport['ssp']['data'][1]; 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<Map> processedLightSnore = lightSnore.map((item) { List<Map> processedLightSnore = lightSnore.map((item) {
return { return {
...item, ...item,
@@ -202,7 +231,7 @@ class _SnoreViewWidgetWidgetState extends State<SnoreViewWidgetWidget> {
startTime: startTime, startTime: startTime,
endTime: endTime, endTime: endTime,
maxYValue: maxY, // 最大值可自定义 maxYValue: maxY, // 最大值可自定义
yStepCount: 7, // 分4段0, 5, 10, 15, 20 yStepCount: 3, // 分4段0, 5, 10, 15, 20
), ),
), ),
Padding( Padding(