更新快检功能

This commit is contained in:
wyf
2026-03-10 12:01:00 +08:00
parent d0ae2a9f76
commit 6472baf993
48 changed files with 8046 additions and 120 deletions

View File

@@ -0,0 +1,364 @@
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:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/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/QcTimeSeriesChart.dart';
//心率基准
class QcHeartRateStandardWidget extends StatefulWidget {
var reportData;
QcHeartRateStandardWidget({super.key, required this.reportData});
@override
State<QcHeartRateStandardWidget> createState() =>
_QcHeartRateStandardWidgetState();
}
class _QcHeartRateStandardWidgetState extends State<QcHeartRateStandardWidget> {
@override
void setState(VoidCallback callback) {
super.setState(callback);
}
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
// 计算y轴的最大最小值
(double, double) _calculateYMinMax(List<QcTimeSeriesPoint> dataPoints) {
if (dataPoints.isEmpty) {
return (50.0, 150.0);
}
// 过滤掉无效数据点(值为-1的
final validPoints = dataPoints.where((point) => point.value >= 0).toList();
if (validPoints.isEmpty) {
return (50.0, 150.0);
}
// 找出数据中的实际最小值和最大值
double dataMin =
validPoints.map((point) => point.value).reduce((a, b) => a < b ? a : b);
double dataMax =
validPoints.map((point) => point.value).reduce((a, b) => a > b ? a : b);
// 计算最小值向下取整到10的倍数
double yMin = (dataMin / 10).floor() * 10.0;
// 如果最小值小于0设为0
if (yMin < 0) yMin = 0;
// 计算最大值向上取整到10的倍数
double yMax = (dataMax / 10).ceil() * 10.0;
// 确保至少有20的差值
if (yMax - yMin < 20) {
yMax = yMin + 20;
}
return (yMin, yMax);
}
@override
Widget build(BuildContext context) {
try {
if (widget.reportData == null || widget.reportData is! Map) {
return Container();
}
// 从reportData中获取hr数据
Map<String, dynamic> hrData = widget.reportData['hr'] ?? {};
if (hrData.isEmpty) {
return Container();
}
// 获取心率数据点
List<dynamic> dataList = hrData['data'] ?? [];
List<QcTimeSeriesPoint> dataPoints = [];
// 构建数据点(只保留值,不需要时间戳)
for (int i = 0; i < dataList.length; i++) {
dynamic value = dataList[i];
if (value == null || value == '') {
dataPoints.add(QcTimeSeriesPoint(-1));
} else {
double y = (value as num).toDouble();
dataPoints.add(QcTimeSeriesPoint(y));
}
}
// 计算动态的y轴范围
final (yMin, yMax) = _calculateYMinMax(dataPoints);
// 构建心率统计数据
Map<String, dynamic> avgHeartRate = {
'name': '平均心率'.tr,
'value': hrData['avg'].toInt() ?? 0,
'unit': '次/分'.tr,
};
Map<String, dynamic> baseHeartRate = {
'name': '基准心率'.tr,
'value': hrData['base'].toInt() ?? 0,
'unit': '次/分'.tr,
};
Map<String, dynamic> minHeartRate = {
'name': '最低心率'.tr,
'value': hrData['min'].toInt() ?? 0,
'unit': '次/分'.tr,
};
Map<String, dynamic> maxHeartRate = {
'name': '最高心率'.tr,
'value': hrData['max'].toInt() ?? 0,
'unit': '次/分'.tr,
};
// 构建正常范围字符串
String range = '';
if (baseHeartRate['value'] != 0) {
int baseValue = baseHeartRate['value'];
range = '${baseValue - 10}~${baseValue + 10}';
} else {
range = '60~100';
}
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, 45.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),
width: 28.rpx,
height: 28.rpx,
child: SvgPicture.asset(
'assets/img/icon/explain.svg',
fit: BoxFit.cover,
color: themeController.currentColor.sc4,
),
),
),
],
),
),
SizedBox(
height: 31.rpx,
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Column(
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 30.rpx, 0.rpx),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
width: 14.rpx,
height: 14.rpx,
decoration: BoxDecoration(
color: themeController.currentColor.sc2,
shape: BoxShape.circle,
),
),
SizedBox(width: 15.rpx),
Text(
'正常范围 '.tr + range,
style: TextStyle(
fontSize: AppConstants().smaller_text_fontSize,
color: themeController.currentColor.sc3,
),
),
],
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 30.rpx, 0.rpx),
child: Container(
width: double.infinity,
child: QcTimeSeriesChart(
yMin: yMin,
yMax: yMax,
dataPoints: dataPoints,
xSegmentCount: 11,
baseValue: hrData['base'].toDouble(), // 传入基准值
// baseValue: 65, // 传入基准值
baseLabel: '基准', // 可选的自定义标签
yAxisPadding: 20,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Row(
children: [
_buildHeartRateItem(avgHeartRate),
_buildHeartRateItem(baseHeartRate),
_buildHeartRateItem(minHeartRate),
_buildHeartRateItem(maxHeartRate),
],
),
),
].divide(SizedBox(
height: 18.rpx,
)),
),
),
],
),
),
);
} catch (e) {
es.EasyDartModule.logger.error("心率基准绘制异常${e}");
return Container();
}
}
Widget _buildHeartRateItem(Map<String, dynamic> data) {
return Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 4.rpx, vertical: 4.rpx),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
child: Text(
"${data['name']}",
style: TextStyle(
color: themeController.currentColor.sc3,
fontSize: AppConstants().normal_text_fontSize,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
SizedBox(height: 4.rpx),
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
fit: FlexFit.loose,
child: Text(
"${data['value']}",
style: TextStyle(
color: themeController.currentColor.sc2,
fontSize: AppConstants().normal_text_fontSize,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
SizedBox(width: 6.rpx),
Flexible(
fit: FlexFit.loose,
child: Text(
"${data['unit']}",
style: TextStyle(
color: themeController.currentColor.sc3,
fontSize: AppConstants().small_text_fontSize,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
],
),
),
],
),
),
);
}
}