Files
tuiche/lib/pages/device/health_experience.dart
2026-04-07 14:49:31 +08:00

2570 lines
146 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// import 'dart:async';
// import 'dart:ui' as ui;
// import 'package:EasyDartModule/EasyDartModule.dart' as edm;
// import 'package:ef/ef.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter/services.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/CommonVariables.dart';
// import 'package:vbvs_app/common/util/DailyLogUtils.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/component/tool/CustomCard.dart';
// import 'package:vbvs_app/component/tool/NewTopSlideNotification.dart';
// import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
// import 'package:vbvs_app/controller/device/device_type_controller.dart';
// import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
// import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
// import 'package:vbvs_app/controller/user_info_controller.dart';
// import 'package:vbvs_app/enum/APPQuickCheckStatus.dart';
// import 'package:vbvs_app/model/WebSocketMessage.dart';
// import 'package:vbvs_app/pages/device/component/DeviceStatusInfoWidget.dart';
// import 'package:vbvs_app/pages/device/component/health_experience_tool.dart';
// import 'package:vbvs_app/pages/device_bind/componnet/CalibrationProgressWidget.dart';
// import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
// import 'package:vibration/vibration.dart';
// import 'component/SpeedControlledGif.dart';
// class HealthCheckPage extends StatefulWidget {
// var personInfo;
// HealthCheckPage({super.key, required this.personInfo});
// @override
// State<HealthCheckPage> createState() => _HealthCheckPageState();
// }
// class _HealthCheckPageState extends State<HealthCheckPage>
// with WidgetsBindingObserver {
// GlobalController globalController = Get.find();
// UserInfoController userInfoController = Get.find();
// BlueteethBindController blueteethBindController = Get.find();
// ThemeController themeController = Get.find();
// DeviceTypeController deviceTypeController = Get.find();
// int maxBodyMotion = 1;
// String breathState = "-";
// String inBed = "-";
// String onlineState = "离线".tr;
// Timer? _onlineTimer; // 添加 Timer 引用
// int bodyMotion = -1;
// int breathrate = -1;
// String snores = "-";
// int heartrate = -1;
// final ValueNotifier<double> progressNotifier = ValueNotifier<double>(0.0);
// final ValueNotifier<bool> failureNotifier = ValueNotifier<bool>(false);
// Timer? _checkStatusTimer; // 添加状态查询定时器
// bool _isInitialized = false; // 添加初始化标志
// @override
// void initState() {
// WidgetsBinding.instance.addObserver(this); // 添加生命周期观察者
// try {
// deviceTypeController
// .checkReportStatus(widget.personInfo['mac'])
// .then((_) {
// setState(() {
// _isInitialized = true;
// });
// // 如果当前状态是体验中,启动定时器
// if (deviceTypeController.experience_status.value == 200 &&
// deviceTypeController.own.value) {
// _startCheckStatusTimer();
// }
// });
// } catch (e) {
// ef.log("快检初始化数据失败");
// }
// _initWebSocket();
// super.initState();
// }
// Future<void> _initWebSocket() async {
// // 发送WebSocket请求
// try {
// Future.delayed(Duration(seconds: 0), () {
// CommonVariables.callMap["/vsbs/web/rt/marttress"] = (data) {
// edm.EasyDartModule.logger.info("[websocket]实时体征页面数据-->${data}]");
// ef.log("[websocket]实时体征页面数据-->${data}]");
// if (data['status'] == "离线") {
// inBed = "-";
// bodyMotion = -1;
// heartrate = -1;
// snores = "-";
// breathrate = -1;
// breathState = "-";
// onlineState = "离线".tr;
// return;
// }
// inBed = data["inBed"];
// // 心率 呼吸 体动 呼吸暂停
// if ("离床".tr == inBed) {
// breathState = "否".tr;
// bodyMotion = 0;
// breathrate = 0;
// heartrate = 0;
// snores = "否".tr;
// } else {
// onlineState = "在线".tr; // 接收到数据,设置为在线
// breathState =
// data["breathState"] == null || data["breathState"] == ""
// ? "-"
// : data["breathState"].toString().tr;
// bodyMotion = data['bodyMotion'] == null ? -1 : data['bodyMotion'];
// breathrate = data["breathRate"] == null ? -1 : data["breathRate"];
// heartrate = data['heartRate'] == null ? -1 : data['heartRate'];
// snores = data['snores'] == null ||
// data['snores'] == "" ||
// data['snores'] == "否".tr
// ? "否".tr
// : "${data['snores']}".tr;
// }
// if (mounted) {
// setState(() {
// onlineState = "在线".tr; // 接收到数据,设置为在线
// });
// }
// _startOnlineTimer(); // 重置定时器
// };
// });
// } catch (e) {
// print(e);
// edm.EasyDartModule.logger
// .error("[webscoekt]格式化数据错误-->${{"mac": widget.personInfo['mac']}}");
// }
// if (widget.personInfo['status'] != null) {
// try {
// onlineState =
// widget.personInfo['status']['status'] == 1 ? "在线".tr : "离线".tr;
// if (widget.personInfo['status']['status'] != 0) {
// inBed = widget.personInfo['status']['inBed'] == 1 ? "在床".tr : "离床".tr;
// }
// } catch (e) {
// edm.EasyDartModule.logger
// .error("[webscoekt]格式化数据错误-->${{"mac": widget.personInfo['mac']}}");
// }
// }
// edm.EasyDartModule.logger
// .info("[webscoekt]发送请求:数据-->${{"mac": widget.personInfo['mac']}}");
// DailyLogUtils.writeLog(
// "[webscoekt]发送请求:数据-->${{"mac": widget.personInfo['mac']}}");
// edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
// path: "/vsbs/web/rt/marttress",
// type: 1,
// data: {"mac": widget.personInfo['mac']})));
// await Future.delayed(Duration(seconds: 3));
// edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
// path: "/vsbs/web/rt/marttress",
// type: 1,
// data: {"mac": widget.personInfo['mac']})));
// _startOnlineTimer();
// }
// //y
// @override
// void dispose() {
// WidgetsBinding.instance.removeObserver(this); // 移除生命周期观察者
// _onlineTimer?.cancel();
// _checkStatusTimer?.cancel(); // 取消状态查询定时器
// _closeWebSocket();
// CommonVariables.callMap.remove("/vsbs/web/rt/marttress");
// super.dispose();
// }
// // 监听应用生命周期变化
// @override
// void didChangeAppLifecycleState(AppLifecycleState state) {
// if (state == AppLifecycleState.resumed) {
// // 应用回到前台时重新连接WebSocket
// edm.EasyDartModule.logger.info("app切回页面重连websocket");
// _initWebSocket();
// _initWebSocket();
// // 重新查询状态,然后根据状态决定是否启动定时器
// deviceTypeController
// .checkReportStatus(widget.personInfo['mac'])
// .then((_) {
// // 如果当前状态是体验中,重新启动定时器
// if (deviceTypeController.experience_status.value != 404 &&
// deviceTypeController.own.value) {
// _startCheckStatusTimer();
// }
// });
// } else if (state == AppLifecycleState.paused) {
// // 应用进入后台时关闭WebSocket和定时器
// _closeWebSocket();
// _checkStatusTimer?.cancel();
// }
// }
// void _startOnlineTimer() {
// _onlineTimer?.cancel(); // 取消之前的定时器
// _onlineTimer = Timer.periodic(Duration(seconds: 60), (timer) {
// if (mounted) {
// setState(() {
// edm.EasyDartModule.logger.info("60 秒内没有接收到数据,设置为离线");
// onlineState = "离线".tr; // 30 秒内没有接收到数据,设置为离线
// inBed = "-";
// bodyMotion = -1;
// heartrate = -1;
// snores = "-";
// breathrate = -1;
// breathState = "-";
// });
// }
// });
// }
// @override
// Widget build(BuildContext context) {
// Map device = widget.personInfo;
// return LayoutBuilder(
// builder: (context, bodySize) => GestureDetector(
// // onTap: () => FocusScope.of(context).unfocus(),,
// child: Container(
// decoration: BoxDecoration(
// image: DecorationImage(
// image: AssetImage(getBackgroundImageNoImage()),
// fit: BoxFit.fill,
// ),
// ),
// child: Scaffold(
// backgroundColor: Colors.transparent,
// appBar: AppBar(
// systemOverlayStyle: SystemUiOverlayStyle(
// statusBarColor: Colors.transparent, // 状态栏背景色
// statusBarIconBrightness: Brightness.light, // 图标颜色Android
// statusBarBrightness: Brightness.light, // 图标颜色iOS
// ),
// backgroundColor: themeController.currentColor.sc17,
// automaticallyImplyLeading: false,
// iconTheme: IconThemeData(color: themeController.currentColor.sc3),
// titleSpacing: 0.rpx,
// title: Container(
// width: double.infinity,
// height: 180.rpx,
// child: Stack(
// alignment: Alignment.center,
// children: [
// RichText(
// text: TextSpan(
// style: TextStyle(
// fontFamily: 'Readex Pro',
// color: themeController.currentColor.sc3,
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// ),
// children: [
// TextSpan(
// text: '健康快检'.tr,
// ),
// ],
// ),
// ),
// Positioned(
// left: 0.rpx,
// child: returnIconButtom,
// ),
// Obx(() {
// return deviceTypeController.experience_status.value !=
// 200 ||
// !deviceTypeController.own.value
// ? Positioned(
// right: 0.rpx,
// child: ClickableContainer(
// backgroundColor: Colors.transparent,
// highlightColor: Colors.transparent,
// padding: EdgeInsets.fromLTRB(
// 20.rpx, 20.rpx, 20.rpx, 20.rpx),
// onTap: () async {
// Get.toNamed('/healthExperienceHistory',
// arguments: widget.personInfo);
// },
// child: SvgPicture.asset(
// 'assets/img/icon/history.svg',
// width: 35.rpx,
// height: 35.rpx,
// color: themeController.currentColor.sc3,
// ),
// ),
// )
// : Container();
// })
// ],
// ),
// ),
// actions: [],
// centerTitle: false,
// ),
// body: SafeArea(
// top: true,
// child: Obx(() {
// return Stack(
// children: [
// Align(
// alignment: Alignment.center,
// child: FractionallySizedBox(
// heightFactor: 0.5,
// widthFactor: 0.5,
// child: Opacity(
// opacity: 0.7,
// child: (onlineState == "离线".tr || inBed == '离床'.tr)
// ? Image.asset(
// 'assets/img/black_body_still.png',
// fit: BoxFit.contain,
// )
// : SpeedControlledGif(
// 'assets/img/body_black.gif',
// speedFactor:
// 2, // 2.0 for 2x speed, 0.5 for half speed
// fit: BoxFit.contain,
// ),
// ),
// ),
// ),
// // 其余内容放在上层
// Positioned.fill(
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 29.rpx, 0.rpx, 0.rpx),
// child: Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// if (deviceTypeController
// .experience_status.value !=
// 200 ||
// !deviceTypeController.own.value)
// Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 30.rpx, 0.rpx, 30.rpx, 100.rpx),
// child: ClickableContainer(
// backgroundColor:
// themeController.currentColor.sc5,
// highlightColor:
// Colors.transparent, // 点击涟漪颜色
// borderRadius: AppConstants()
// .normal_container_radius, // 如果你想加圆角可以设置 eg. 12.rpx
// padding: EdgeInsets.zero,
// onTap: () {
// print('点击了体征卡片');
// },
// child: Column(
// children: [
// Container(
// padding: EdgeInsets.fromLTRB(
// 37.rpx, 37.rpx, 20.rpx, 37.rpx),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// // 左侧列 - 标签和值
// Expanded(
// flex: 3,
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// // 姓名行
// Row(
// crossAxisAlignment:
// CrossAxisAlignment
// .center,
// children: [
// // 标签 - 也不能换行,超出显示...
// Expanded(
// flex: 3,
// child: Text(
// '实时体征.姓名'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc4,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// SizedBox(
// width: 20
// .rpx), // 标签和值之间的间距
// // 值
// Expanded(
// flex: 4,
// child: Text(
// device['person'] !=
// null &&
// device['person'][
// 'name'] !=
// null &&
// device['person']
// [
// 'name']
// .toString()
// .trim()
// .isNotEmpty
// ? device['person']
// ['name']
// .toString()
// : '体征检测设备'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc3,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// ],
// ),
// SizedBox(height: 36.rpx),
// // 性别行
// Row(
// crossAxisAlignment:
// CrossAxisAlignment
// .center,
// children: [
// Expanded(
// flex: 3,
// child: Text(
// '性别'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc4,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// SizedBox(width: 20.rpx),
// Expanded(
// flex: 4,
// child: Text(
// device['person'] !=
// null &&
// device['person']
// [
// 'gender'] !=
// null &&
// device['person']
// [
// 'gender']
// .toString()
// .trim()
// .isNotEmpty
// ? getGenderText(
// device['person']
// [
// 'gender'])
// : '-'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc3,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// ],
// ),
// SizedBox(height: 36.rpx),
// // 身高行
// Row(
// crossAxisAlignment:
// CrossAxisAlignment
// .center,
// children: [
// Expanded(
// flex: 3,
// child: Text(
// '身高'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc4,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// SizedBox(width: 20.rpx),
// Expanded(
// flex: 4,
// child: Text(
// device['person'] !=
// null &&
// device['person']
// [
// 'height'] !=
// null &&
// device['person']
// [
// 'height']
// .toString()
// .trim()
// .isNotEmpty
// ? '${device['person']['height']}cm'
// : '-'.tr + "cm",
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc3,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// ],
// ),
// ],
// ),
// ),
// SizedBox(
// width: 30.rpx), // 左右两列之间的间距
// // 右侧列 - 标签和值
// Expanded(
// flex: 4,
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// // 设备ID行
// Row(
// crossAxisAlignment:
// CrossAxisAlignment
// .center,
// children: [
// Expanded(
// flex: 1,
// child: Text(
// '实时体征.设备ID'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc4,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// SizedBox(width: 20.rpx),
// Expanded(
// flex: 2,
// child: Text(
// '${device['code'] ?? '未知数据'.tr}',
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc3,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// ],
// ),
// SizedBox(height: 36.rpx),
// // 年龄行
// Row(
// crossAxisAlignment:
// CrossAxisAlignment
// .center,
// children: [
// Expanded(
// flex: 1,
// child: Text(
// '年龄'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc4,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// SizedBox(width: 20.rpx),
// Expanded(
// flex: 2,
// child: Text(
// device['person'] !=
// null &&
// device['person']
// [
// 'birthday'] !=
// null &&
// device['person']
// [
// 'birthday']
// .toString()
// .trim()
// .isNotEmpty
// ? calculateAge(device[
// 'person']
// [
// 'birthday']
// .toString())
// : '-'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc3,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// ],
// ),
// SizedBox(height: 36.rpx),
// // 体重行
// Row(
// crossAxisAlignment:
// CrossAxisAlignment
// .center,
// children: [
// Expanded(
// flex: 1,
// child: Text(
// '体重'.tr,
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc4,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// SizedBox(width: 20.rpx),
// Expanded(
// flex: 2,
// child: Text(
// device['person'] !=
// null &&
// device['person']
// [
// 'weight'] !=
// null &&
// device['person']
// [
// 'weight']
// .toString()
// .trim()
// .isNotEmpty
// ? '${device['person']['weight']}kg'
// : '-'.tr + "kg",
// style: TextStyle(
// fontFamily:
// 'Inter',
// fontSize: 26.rpx,
// color: themeController
// .currentColor
// .sc3,
// ),
// maxLines: 1,
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// ],
// ),
// ],
// ),
// ),
// ],
// ),
// ),
// ],
// ),
// ),
// ),
// if (deviceTypeController
// .experience_status.value ==
// 200 &&
// deviceTypeController.own.value)
// Padding(
// padding:
// EdgeInsets.fromLTRB(46.rpx, 0, 46.rpx, 0),
// child: Column(
// children: [
// SizedBox(
// height: 103.rpx,
// ),
// Text(
// "快检中...".tr,
// style: TextStyle(
// color:
// themeController.currentColor.sc1,
// fontSize: AppConstants()
// .title_text_fontSize,
// ),
// ),
// SizedBox(
// height: 30.rpx,
// ),
// Text(
// "MAC号".tr +
// ": ${widget.personInfo['mac'] ?? '未知数据'.tr}",
// style: TextStyle(
// color:
// themeController.currentColor.sc4,
// fontSize: AppConstants()
// .smaller_text_fontSize,
// ),
// ),
// SizedBox(
// height: 4.rpx,
// ),
// Text(
// "睡眠报告提示".tr,
// style: TextStyle(
// color:
// themeController.currentColor.sc4,
// fontSize: AppConstants()
// .smaller_text_fontSize,
// ),
// ),
// SizedBox(
// height: 48.rpx,
// ),
// ],
// ),
// ),
// Expanded(
// child: SingleChildScrollView(
// child: deviceTypeController
// .experience_status.value !=
// 200 ||
// !deviceTypeController.own.value
// ? Container()
// : Column(
// children: [
// Padding(
// padding:
// EdgeInsetsDirectional.fromSTEB(
// 30.rpx, 0, 30.rpx, 0),
// child: Container(
// child: Column(
// children: [
// Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// DeviceStatusInfoWidget(
// title: "在离床".tr,
// iconAsset:
// "assets/img/icon/bed_status.svg",
// value: inBed,
// ),
// DeviceStatusInfoWidget(
// title: "体动".tr,
// iconAsset:
// "assets/img/icon/bodymotion.svg",
// value: inBed == "离床".tr
// ? ("-")
// : (bodyMotion ==
// null ||
// bodyMotion ==
// -1)
// ? "-"
// : "$bodyMotion",
// ),
// ],
// ),
// Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// DeviceStatusInfoWidget(
// title: "心率".tr,
// iconAsset:
// "assets/img/icon/heart.svg",
// value: inBed == "离床".tr
// ? "-"
// : ((heartrate ==
// null ||
// heartrate ==
// -1)
// ? "-"
// : "$heartrate"),
// ),
// DeviceStatusInfoWidget(
// title: "打鼾".tr,
// iconAsset:
// "assets/img/icon/snore.svg",
// value: inBed == "离床".tr
// ? "-"
// : ('${snores}'.tr),
// ),
// ],
// ),
// Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// DeviceStatusInfoWidget(
// title: "呼吸".tr,
// iconAsset:
// "assets/img/icon/breathe.svg",
// value: inBed == "离床".tr
// ? ("-")
// : ((breathrate ==
// null ||
// breathrate ==
// -1)
// ? "-"
// : "$breathrate"),
// ),
// DeviceStatusInfoWidget(
// title: "呼吸暂停".tr,
// iconAsset:
// "assets/img/icon/breathe_pause.svg",
// value: inBed == "离床".tr
// ? "-"
// : ('${breathState}'),
// ),
// ],
// ),
// ].divide(
// SizedBox(height: 49.rpx)),
// ),
// ),
// ),
// Padding(
// padding:
// EdgeInsetsDirectional.fromSTEB(
// 0.rpx,
// 67.rpx,
// 0.rpx,
// 0.rpx),
// child: Container(
// height: 40.rpx,
// child: Text(
// bodyMotion >= maxBodyMotion
// ? '请保持静止'.tr
// : "",
// style: TextStyle(
// fontFamily: 'Inter',
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc9,
// ),
// ),
// ),
// ),
// // SizedBox(
// // height: 207.rpx,
// // ),
// ],
// ),
// )),
// if (deviceTypeController
// .experience_status.value !=
// 200 ||
// !deviceTypeController.own.value)
// ClickableContainer(
// backgroundColor:
// Colors.transparent, // 可自定义背景色
// highlightColor: Colors.transparent, // 点击涟漪颜色
// borderRadius: 16.rpx, // 圆角大小,可按需调整
// padding: EdgeInsetsDirectional.fromSTEB(
// 30.rpx, 0.rpx, 30.rpx, 0.rpx),
// onTap: () {},
// child: Container(
// padding: EdgeInsetsDirectional.fromSTEB(
// 26.rpx, 26.rpx, 26.rpx, 26.rpx),
// decoration: BoxDecoration(
// // color: FlutterFlowTheme.of(context)
// // .primaryBackground
// // .withOpacity(0.6), // 半透明背景
// borderRadius:
// BorderRadius.circular(16.rpx),
// border: Border.all(
// color: themeController.currentColor.sc4
// .withOpacity(0.5),
// width: 0.5.rpx,
// ),
// ),
// child: Row(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// Padding(
// padding:
// EdgeInsetsDirectional.fromSTEB(
// 0, 8.rpx, 0, 0),
// child: Container(
// width: 23.rpx,
// height: 23.rpx,
// // width: double.infinity,
// decoration: BoxDecoration(),
// child: SvgPicture.asset(
// 'assets/img/icon/tips.svg',
// fit: BoxFit.cover,
// color: themeController
// .currentColor.sc4,
// ),
// ),
// ),
// Expanded(
// child: Text(
// '使用方式:人员使用健康快检功能时,只需平躺或坐在正常运行中的体征传感器传感器上方,保持静止,然后点击“启动快检”,待进度条完成,即可得出快检报告。'
// .tr,
// style: TextStyle(
// fontFamily: 'Inter',
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc4,
// ),
// ),
// ),
// ].divide(SizedBox(width: 23.rpx)),
// ),
// ),
// ),
// SizedBox(
// height: 40.rpx,
// ),
// if (deviceTypeController
// .experience_status.value !=
// 200 ||
// !deviceTypeController.own.value)
// Padding(
// padding: EdgeInsets.fromLTRB(
// 100.rpx, 0, 100.rpx, 0),
// child: Column(
// children: [
// CustomCard(
// borderRadius: AppConstants()
// .button_container_radius, // 圆角半径
// onTap: () async {
// // HapticFeedback.lightImpact();
// bool canStart =
// await deviceTypeController
// .checkReportStatus(
// widget.personInfo['mac']);
// // if (!canStart) {
// // NewTopSlideNotification.show(
// // text: "设备正在快检中,请稍后再试!".tr,
// // textColor: themeController
// // .currentColor.sc9);
// // return;
// // }
// if (!deviceTypeController.own.value &&
// deviceTypeController
// .experience_status
// .value ==
// APPQuickCheckStatus
// .inProgress.value) {
// NewTopSlideNotification.show(
// text: "设备正在快检中,请稍后再试!".tr,
// textColor: themeController
// .currentColor.sc9);
// return;
// }
// bool opRes =
// await deviceTypeController
// .qcCheckControl(
// widget.personInfo, 1);
// if (!opRes) {
// return;
// }
// deviceTypeController
// .experience_percent.value = 0;
// progressNotifier.value = 0;
// deviceTypeController
// .experience_status.value = 200;
// _startCheckStatusTimer();
// deviceTypeController.updateAll();
// },
// colors: AppConstants()
// .thNormalButton, // 渐变色是同一个色,也可以根据需要调整
// child: Container(
// width:
// // MediaQuery.sizeOf(context).width * 0.66,
// bodySize.maxWidth,
// height: MediaQuery.sizeOf(context)
// .height *
// 0.055,
// constraints: BoxConstraints(
// minWidth: 500.rpx,
// minHeight: 90.rpx,
// ),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.center,
// children: [
// Text(
// '开始快检'.tr,
// style: TextStyle(
// color: themeController
// .currentColor.sc3,
// fontFamily: 'Inter',
// fontSize: AppConstants()
// .normal_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(
// width: 17.rpx,
// )),
// ),
// ),
// ),
// ],
// ),
// ),
// if (deviceTypeController
// .experience_status.value ==
// 200 &&
// deviceTypeController.own.value)
// Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 100.rpx, 0.rpx, 100.rpx, 60.rpx),
// child: CalibrationProgressWidget(
// progressNotifier: progressNotifier,
// failureNotifier: failureNotifier,
// ),
// ),
// if (deviceTypeController
// .experience_status.value ==
// 200 &&
// deviceTypeController.own.value)
// Padding(
// padding: EdgeInsets.fromLTRB(
// 100.rpx, 0, 100.rpx, 0),
// child: Column(
// children: [
// CustomCard(
// borderRadius: AppConstants()
// .button_container_radius, // 圆角半径
// onTap: () {
// showCancelConfirmDialog(
// context, widget.personInfo);
// },
// colors: [
// themeController.currentColor.sc9
// ], // 渐变色是同一个色,也可以根据需要调整
// child: Container(
// width:
// // MediaQuery.sizeOf(context).width * 0.66,
// bodySize.maxWidth,
// height: MediaQuery.sizeOf(context)
// .height *
// 0.055,
// constraints: BoxConstraints(
// minWidth: 500.rpx,
// minHeight: 90.rpx,
// ),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.center,
// children: [
// Text(
// '终止'.tr,
// style: TextStyle(
// color: themeController
// .currentColor.sc3,
// fontFamily: 'Inter',
// fontSize: AppConstants()
// .normal_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(
// width: 17.rpx,
// )),
// ),
// ),
// ),
// ],
// ),
// ),
// SizedBox(
// height: 40.rpx,
// ),
// SizedBox(
// height: 26.rpx,
// ),
// ],
// ),
// ),
// ),
// ],
// );
// })),
// ),
// ),
// ),
// );
// }
// void _closeWebSocket() {
// // 取消WebSocket订阅
// edm.EasyDartModule.websocket.sendData(
// jsonEncode(WebSocketMessage(path: "/vsbs/web/rt/marttress", type: 2)));
// _onlineTimer?.cancel();
// }
// // 开始状态查询定时器
// void _startCheckStatusTimer() {
// _checkStatusTimer?.cancel(); // 取消之前的定时器
// _checkStatusTimer = Timer.periodic(Duration(seconds: 3), (timer) {
// if (mounted) {
// edm.EasyDartModule.logger.info("定时查询快检状态");
// deviceTypeController
// .checkReportStatus(widget.personInfo['mac'])
// .then((_) async {
// // 如果状态变回404非体验中停止定时器
// progressNotifier.value =
// deviceTypeController.experience_percent.value.toDouble();
// deviceTypeController.updateAll();
// if (deviceTypeController.experience_status.value ==
// APPQuickCheckStatus.completed.value) {
// //体验正常结束
// try {
// deviceTypeController.experience_status.value = 404;
// deviceTypeController.experience_status.value = 0;
// progressNotifier.value = 0;
// edm.EasyDartModule.logger.info("快检结束,停止定时查询");
// _checkStatusTimer?.cancel();
// Map data = {
// "id": deviceTypeController.experience_id.value,
// "mac": widget.personInfo['mac']
// };
// // await deviceTypeController.getCheckHistory(
// // id: deviceTypeController.experience_id.value,
// // mac: widget.personInfo['mac']);
// bool hasVibrator = await Vibration.hasVibrator();
// if (hasVibrator) {
// // 震动1000毫秒1秒
// Vibration.vibrate(duration: 500);
// }
// Get.toNamed('/healthQuickCheckReportPage', arguments: data);
// } catch (e) {
// edm.EasyDartModule.logger.error("快检报告页面加载失败---?${e.toString()}");
// }
// }
// if (deviceTypeController.experience_status.value ==
// APPQuickCheckStatus.timeout.value ||
// deviceTypeController.experience_status.value ==
// APPQuickCheckStatus.calculateError.value ||
// deviceTypeController.experience_status.value ==
// APPQuickCheckStatus.insufficientData.value) {
// // 根据状态码获取对应的枚举
// APPQuickCheckStatus? status = APPQuickCheckStatusExtension.fromInt(
// deviceTypeController.experience_status.value);
// // 获取对应的状态描述文字
// String statusMessage = status?.description ?? "体验异常结束".tr;
// //体验异常结束
// deviceTypeController.experience_status.value = 404;
// deviceTypeController.experience_percent.value = 0;
// progressNotifier.value = 0;
// edm.EasyDartModule.logger
// .info("快检结束,停止定时查询 - 状态: ${status?.description}");
// _checkStatusTimer?.cancel();
// await showTipDialog(
// context,
// Text(
// statusMessage,
// style: TextStyle(
// color: Colors.white,
// ),
// ),
// );
// }
// if (!deviceTypeController.own.value) {
// _checkStatusTimer?.cancel();
// }
// });
// }
// });
// }
// }
import 'dart:async';
import 'dart:ui' as ui;
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.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/CommonVariables.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.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/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/NewTopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/device/device_type_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/enum/APPQuickCheckStatus.dart';
import 'package:vbvs_app/model/WebSocketMessage.dart';
import 'package:vbvs_app/pages/device/component/DeviceStatusInfoWidget.dart';
import 'package:vbvs_app/pages/device/component/health_experience_tool.dart';
import 'package:vbvs_app/pages/device_bind/componnet/CalibrationProgressWidget.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
import 'package:vibration/vibration.dart';
import 'component/SpeedControlledGif.dart';
class HealthCheckPage extends StatefulWidget {
var personInfo;
HealthCheckPage({super.key, required this.personInfo});
@override
State<HealthCheckPage> createState() => _HealthCheckPageState();
}
class _HealthCheckPageState extends State<HealthCheckPage>
with WidgetsBindingObserver, SingleTickerProviderStateMixin {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
int maxBodyMotion = 1;
String breathState = "-";
String inBed = "-";
String onlineState = "离线".tr;
Timer? _onlineTimer;
int bodyMotion = -1;
int breathrate = -1;
String snores = "-";
int heartrate = -1;
final ValueNotifier<double> progressNotifier = ValueNotifier<double>(0.0);
final ValueNotifier<bool> failureNotifier = ValueNotifier<bool>(false);
Timer? _checkStatusTimer;
bool _isInitialized = false;
// 动画控制器
late AnimationController _animationController;
// 顶部动画:从上往下滑动
late Animation<Offset> _topSlideAnimation;
// 左侧容器动画:从左向右滑动
late Animation<Offset> _leftSlideAnimation;
// 右侧容器动画:从右向左滑动
late Animation<Offset> _rightSlideAnimation;
@override
void initState() {
// 初始化动画控制器
_animationController = AnimationController(
duration: const Duration(milliseconds: 400),
vsync: this,
);
// 顶部下滑动画:从顶部滑入
_topSlideAnimation = Tween<Offset>(
begin: const Offset(0, -1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeOutCubic,
));
// 左侧滑动动画:从左向右
_leftSlideAnimation = Tween<Offset>(
begin: const Offset(-1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeOutCubic,
));
// 右侧滑动动画:从右向左
_rightSlideAnimation = Tween<Offset>(
begin: const Offset(1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeOutCubic,
));
WidgetsBinding.instance.addObserver(this);
try {
deviceTypeController
.checkReportStatus(widget.personInfo['mac'])
.then((_) {
setState(() {
_isInitialized = true;
});
if (deviceTypeController.experience_status.value == 200 &&
deviceTypeController.own.value) {
_startCheckStatusTimer();
// 如果已经在体验中,直接播放动画
_animationController.forward();
}
});
} catch (e) {
ef.log("快检初始化数据失败");
}
_initWebSocket();
// 监听状态变化,控制动画
ever(deviceTypeController.experience_status, (status) {
final isExperiencing = status == 200 && deviceTypeController.own.value;
if (isExperiencing) {
_animationController.forward();
} else {
_animationController.reverse();
}
});
ever(deviceTypeController.own, (own) {
final isExperiencing =
deviceTypeController.experience_status.value == 200 && own;
if (isExperiencing) {
_animationController.forward();
} else {
_animationController.reverse();
}
});
super.initState();
}
Future<void> _initWebSocket() async {
try {
Future.delayed(Duration(seconds: 0), () {
CommonVariables.callMap["/vsbs/web/rt/marttress"] = (data) {
edm.EasyDartModule.logger.info("[websocket]实时体征页面数据-->${data}]");
ef.log("[websocket]实时体征页面数据-->${data}]");
if (data['status'] == "离线") {
inBed = "-";
bodyMotion = -1;
heartrate = -1;
snores = "-";
breathrate = -1;
breathState = "-";
onlineState = "离线".tr;
return;
}
inBed = data["inBed"];
if ("离床".tr == inBed) {
breathState = "".tr;
bodyMotion = 0;
breathrate = 0;
heartrate = 0;
snores = "".tr;
} else {
onlineState = "在线".tr;
breathState =
data["breathState"] == null || data["breathState"] == ""
? "-"
: data["breathState"].toString().tr;
bodyMotion = data['bodyMotion'] == null ? -1 : data['bodyMotion'];
breathrate = data["breathRate"] == null ? -1 : data["breathRate"];
heartrate = data['heartRate'] == null ? -1 : data['heartRate'];
snores = data['snores'] == null ||
data['snores'] == "" ||
data['snores'] == "".tr
? "".tr
: "${data['snores']}".tr;
}
if (mounted) {
setState(() {
onlineState = "在线".tr;
});
}
_startOnlineTimer();
};
});
} catch (e) {
print(e);
edm.EasyDartModule.logger
.error("[webscoekt]格式化数据错误-->${{"mac": widget.personInfo['mac']}}");
}
if (widget.personInfo['status'] != null) {
try {
onlineState =
widget.personInfo['status']['status'] == 1 ? "在线".tr : "离线".tr;
if (widget.personInfo['status']['status'] != 0) {
inBed = widget.personInfo['status']['inBed'] == 1 ? "在床".tr : "离床".tr;
}
} catch (e) {
edm.EasyDartModule.logger
.error("[webscoekt]格式化数据错误-->${{"mac": widget.personInfo['mac']}}");
}
}
edm.EasyDartModule.logger
.info("[webscoekt]发送请求:数据-->${{"mac": widget.personInfo['mac']}}");
DailyLogUtils.writeLog(
"[webscoekt]发送请求:数据-->${{"mac": widget.personInfo['mac']}}");
edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
path: "/vsbs/web/rt/marttress",
type: 1,
data: {"mac": widget.personInfo['mac']})));
await Future.delayed(Duration(seconds: 3));
edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
path: "/vsbs/web/rt/marttress",
type: 1,
data: {"mac": widget.personInfo['mac']})));
_startOnlineTimer();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_onlineTimer?.cancel();
_checkStatusTimer?.cancel();
_closeWebSocket();
// _animationController.dispose();
CommonVariables.callMap.remove("/vsbs/web/rt/marttress");
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
edm.EasyDartModule.logger.info("app切回页面重连websocket");
_initWebSocket();
_initWebSocket();
deviceTypeController
.checkReportStatus(widget.personInfo['mac'])
.then((_) {
if (deviceTypeController.experience_status.value != 404 &&
deviceTypeController.own.value) {
_startCheckStatusTimer();
}
});
} else if (state == AppLifecycleState.paused) {
_closeWebSocket();
_checkStatusTimer?.cancel();
}
}
void _startOnlineTimer() {
_onlineTimer?.cancel();
_onlineTimer = Timer.periodic(Duration(seconds: 60), (timer) {
if (mounted) {
setState(() {
edm.EasyDartModule.logger.info("60 秒内没有接收到数据,设置为离线");
onlineState = "离线".tr;
inBed = "-";
bodyMotion = -1;
heartrate = -1;
snores = "-";
breathrate = -1;
breathState = "-";
});
}
});
}
void _closeWebSocket() {
edm.EasyDartModule.websocket.sendData(
jsonEncode(WebSocketMessage(path: "/vsbs/web/rt/marttress", type: 2)));
_onlineTimer?.cancel();
}
void _startCheckStatusTimer() {
_checkStatusTimer?.cancel();
_checkStatusTimer = Timer.periodic(Duration(seconds: 3), (timer) {
if (mounted) {
edm.EasyDartModule.logger.info("定时查询快检状态");
deviceTypeController
.checkReportStatus(widget.personInfo['mac'])
.then((_) async {
progressNotifier.value =
deviceTypeController.experience_percent.value.toDouble();
deviceTypeController.updateAll();
if (deviceTypeController.experience_status.value ==
APPQuickCheckStatus.completed.value) {
try {
deviceTypeController.experience_status.value = 404;
deviceTypeController.experience_status.value = 0;
progressNotifier.value = 0;
edm.EasyDartModule.logger.info("快检结束,停止定时查询");
_checkStatusTimer?.cancel();
Map data = {
"id": deviceTypeController.experience_id.value,
"mac": widget.personInfo['mac']
};
bool hasVibrator = await Vibration.hasVibrator();
if (hasVibrator) {
Vibration.vibrate(duration: 500);
}
Get.toNamed('/healthQuickCheckReportPage', arguments: data);
} catch (e) {
edm.EasyDartModule.logger.error("快检报告页面加载失败---?${e.toString()}");
}
}
if (deviceTypeController.experience_status.value ==
APPQuickCheckStatus.timeout.value ||
deviceTypeController.experience_status.value ==
APPQuickCheckStatus.calculateError.value ||
deviceTypeController.experience_status.value ==
APPQuickCheckStatus.insufficientData.value) {
APPQuickCheckStatus? status = APPQuickCheckStatusExtension.fromInt(
deviceTypeController.experience_status.value);
String statusMessage = status?.description ?? "体验异常结束".tr;
deviceTypeController.experience_status.value = 404;
deviceTypeController.experience_percent.value = 0;
progressNotifier.value = 0;
edm.EasyDartModule.logger
.info("快检结束,停止定时查询 - 状态: ${status?.description}");
_checkStatusTimer?.cancel();
bool hasVibrator = await Vibration.hasVibrator();
if (hasVibrator) {
Vibration.vibrate(duration: 500);
}
await showTipDialog(
context,
Text(
statusMessage,
style: TextStyle(
color: themeController.currentColor.sc9,
),
),
);
}
if (!deviceTypeController.own.value) {
_checkStatusTimer?.cancel();
}
});
}
});
}
@override
Widget build(BuildContext context) {
Map device = widget.personInfo;
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(getBackgroundImageNoImage()),
fit: BoxFit.fill,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // 状态栏背景色
statusBarIconBrightness: Brightness.light, // 图标颜色Android
statusBarBrightness: Brightness.light, // 图标颜色iOS
),
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
titleSpacing: 0.rpx,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
RichText(
text: TextSpan(
style: TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
letterSpacing: 0.0,
),
children: [
TextSpan(
text: '健康快检'.tr,
),
],
),
),
Positioned(
left: 0.rpx,
child: returnIconButtom,
),
Obx(() {
return deviceTypeController.experience_status.value !=
200 ||
!deviceTypeController.own.value
? Positioned(
right: 0.rpx,
child: ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.fromLTRB(
20.rpx, 20.rpx, 20.rpx, 20.rpx),
onTap: () async {
Get.toNamed('/healthExperienceHistory',
arguments: widget.personInfo);
},
child: SvgPicture.asset(
'assets/img/icon/history.svg',
width: 35.rpx,
height: 35.rpx,
color: themeController.currentColor.sc3,
),
),
)
: Container();
})
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Obx(() {
final isExperiencing =
deviceTypeController.experience_status.value == 200 &&
deviceTypeController.own.value;
return Stack(
children: [
Align(
alignment: Alignment.center,
child: FractionallySizedBox(
heightFactor: 0.5,
widthFactor: 0.5,
child: Opacity(
opacity: 0.7,
child: (onlineState == "离线".tr || inBed == '离床'.tr)
? Image.asset(
'assets/img/black_body_still.png',
fit: BoxFit.contain,
)
: SpeedControlledGif(
'assets/img/body_black.gif',
speedFactor: 2,
fit: BoxFit.contain,
),
),
),
),
// 其余内容放在上层
Positioned.fill(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 29.rpx, 0.rpx, 0.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// 顶部区域 - 未体验显示个人信息,体验中显示快检中信息(带动画)
if (!isExperiencing)
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 0.rpx, 30.rpx, 100.rpx),
child: ClickableContainer(
backgroundColor:
themeController.currentColor.sc5,
highlightColor: Colors.transparent,
borderRadius:
AppConstants().normal_container_radius,
padding: EdgeInsets.zero,
onTap: () {
print('点击了体征卡片');
},
child: Column(
children: [
Container(
padding: EdgeInsets.fromLTRB(
37.rpx, 37.rpx, 20.rpx, 37.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// 左侧列 - 标签和值
Expanded(
flex: 3,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// 姓名行
Row(
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
Expanded(
flex: 3,
child: Text(
'实时体征.姓名'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc4,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
SizedBox(width: 20.rpx),
Expanded(
flex: 4,
child: Text(
device['person'] !=
null &&
device['person'][
'name'] !=
null &&
device['person']
[
'name']
.toString()
.trim()
.isNotEmpty
? device['person']
['name']
.toString()
: '体征检测设备'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc3,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
],
),
SizedBox(height: 36.rpx),
// 性别行
Row(
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
Expanded(
flex: 3,
child: Text(
'性别'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc4,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
SizedBox(width: 20.rpx),
Expanded(
flex: 4,
child: Text(
device['person'] !=
null &&
device['person']
[
'gender'] !=
null &&
device['person']
[
'gender']
.toString()
.trim()
.isNotEmpty
? getGenderText(
device['person']
[
'gender'])
: '-'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc3,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
],
),
SizedBox(height: 36.rpx),
// 身高行
Row(
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
Expanded(
flex: 3,
child: Text(
'身高'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc4,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
SizedBox(width: 20.rpx),
Expanded(
flex: 4,
child: Text(
device['person'] !=
null &&
device['person']
[
'height'] !=
null &&
device['person']
[
'height']
.toString()
.trim()
.isNotEmpty
? '${device['person']['height']}cm'
: '-'.tr + "cm",
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc3,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
],
),
],
),
),
SizedBox(width: 30.rpx),
// 右侧列 - 标签和值
Expanded(
flex: 4,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// 设备ID行
Row(
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
Expanded(
flex: 1,
child: Text(
'实时体征.设备ID'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc4,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
SizedBox(width: 20.rpx),
Expanded(
flex: 2,
child: Text(
'${device['code'] ?? '未知数据'.tr}',
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc3,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
],
),
SizedBox(height: 36.rpx),
// 年龄行
Row(
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
Expanded(
flex: 1,
child: Text(
'年龄'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc4,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
SizedBox(width: 20.rpx),
Expanded(
flex: 2,
child: Text(
device['person'] !=
null &&
device['person']
[
'birthday'] !=
null &&
device['person']
[
'birthday']
.toString()
.trim()
.isNotEmpty
? calculateAge(device[
'person']
[
'birthday']
.toString())
: '-'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc3,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
],
),
SizedBox(height: 36.rpx),
// 体重行
Row(
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
Expanded(
flex: 1,
child: Text(
'体重'.tr,
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc4,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
SizedBox(width: 20.rpx),
Expanded(
flex: 2,
child: Text(
device['person'] !=
null &&
device['person']
[
'weight'] !=
null &&
device['person']
[
'weight']
.toString()
.trim()
.isNotEmpty
? '${device['person']['weight']}kg'
: '-'.tr + "kg",
style: TextStyle(
fontFamily:
'Inter',
fontSize: 26.rpx,
color: themeController
.currentColor
.sc3,
),
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
),
),
],
),
],
),
),
],
),
),
],
),
),
)
else
// 体验中状态 - 快检中信息(带动画)
AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return SlideTransition(
position: _topSlideAnimation,
child: Padding(
padding: EdgeInsets.fromLTRB(
46.rpx, 0, 46.rpx, 0),
child: Column(
children: [
SizedBox(
height: 103.rpx,
),
Text(
"快检中...".tr,
style: TextStyle(
color: themeController
.currentColor.sc1,
fontSize: AppConstants()
.bigger_text_fontSize,
),
),
SizedBox(
height: 30.rpx,
),
Text(
"MAC号".tr +
": ${widget.personInfo['mac'] ?? '未知数据'.tr}",
style: TextStyle(
color: themeController
.currentColor.sc4,
fontSize: AppConstants()
.smaller_text_fontSize,
),
),
SizedBox(
height: 4.rpx,
),
Text(
"睡眠报告提示".tr,
style: TextStyle(
color: themeController
.currentColor.sc4,
fontSize: AppConstants()
.smaller_text_fontSize,
),
),
SizedBox(
height: 48.rpx,
),
],
),
),
);
},
),
// 中间区域 - 体征信息(体验中时显示,带动画)
if (isExperiencing)
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(
30.rpx, 0, 30.rpx, 0),
child: Row(
children: [
// 左侧三个容器(从左向右滑动)
Expanded(
child: AnimatedBuilder(
animation:
_animationController,
builder: (context, child) {
return SlideTransition(
position:
_leftSlideAnimation,
child: Column(
children: [
DeviceStatusInfoWidget(
title: "在离床".tr,
iconAsset:
"assets/img/icon/bed_status.svg",
value: inBed,
),
SizedBox(
height: 49.rpx),
DeviceStatusInfoWidget(
title: "心率".tr,
iconAsset:
"assets/img/icon/heart.svg",
value: inBed ==
"离床".tr
? "-"
: ((heartrate ==
null ||
heartrate ==
-1)
? "-"
: "$heartrate"),
),
SizedBox(
height: 49.rpx),
DeviceStatusInfoWidget(
title: "呼吸".tr,
iconAsset:
"assets/img/icon/breathe.svg",
value: inBed ==
"离床".tr
? ("-")
: ((breathrate ==
null ||
breathrate ==
-1)
? "-"
: "$breathrate"),
),
],
),
);
},
),
),
SizedBox(width: 20.rpx),
// 右侧三个容器(从右向左滑动)
Expanded(
child: AnimatedBuilder(
animation:
_animationController,
builder: (context, child) {
return SlideTransition(
position:
_rightSlideAnimation,
child: Column(
children: [
DeviceStatusInfoWidget(
title: "体动".tr,
iconAsset:
"assets/img/icon/bodymotion.svg",
value: inBed ==
"离床".tr
? ("-")
: (bodyMotion ==
null ||
bodyMotion ==
-1)
? "-"
: "$bodyMotion",
),
SizedBox(
height: 49.rpx),
DeviceStatusInfoWidget(
title: "打鼾".tr,
iconAsset:
"assets/img/icon/snore.svg",
value: inBed ==
"离床".tr
? "-"
: ('${snores}'
.tr),
),
SizedBox(
height: 49.rpx),
DeviceStatusInfoWidget(
title: "呼吸暂停".tr,
iconAsset:
"assets/img/icon/breathe_pause.svg",
value: inBed ==
"离床".tr
? "-"
: ('${breathState}'),
),
],
),
);
},
),
),
],
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(
0.rpx, 67.rpx, 0.rpx, 0.rpx),
child: Container(
height: 40.rpx,
child: Text(
bodyMotion >= maxBodyMotion
? '请保持静止'.tr
: "",
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc9,
),
),
),
),
],
),
),
)
else
// 未体验状态 - 占位空白
Expanded(child: Container()),
// 底部区域 - 未体验显示说明和开始按钮,体验中显示进度条和终止按钮(无动画)
if (!isExperiencing)
Column(
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
borderRadius: 16.rpx,
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 0.rpx, 30.rpx, 0.rpx),
onTap: () {},
child: Container(
padding: EdgeInsetsDirectional.fromSTEB(
26.rpx, 26.rpx, 26.rpx, 26.rpx),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(16.rpx),
border: Border.all(
color: themeController
.currentColor.sc4
.withOpacity(0.5),
width: 0.5.rpx,
),
),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsetsDirectional
.fromSTEB(0, 8.rpx, 0, 0),
child: Container(
width: 23.rpx,
height: 23.rpx,
decoration: BoxDecoration(),
child: SvgPicture.asset(
'assets/img/icon/tips.svg',
fit: BoxFit.cover,
color: themeController
.currentColor.sc4,
),
),
),
Expanded(
child: Text(
'使用方式:人员使用健康快检功能时,只需平躺或坐在正常运行中的体征传感器传感器上方,保持静止,然后点击“启动快检”,待进度条完成,即可得出快检报告。'
.tr,
style: TextStyle(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
),
].divide(SizedBox(width: 23.rpx)),
),
),
),
SizedBox(height: 40.rpx),
Padding(
padding: EdgeInsets.fromLTRB(
100.rpx, 0, 100.rpx, 0),
child: Column(
children: [
CustomCard(
borderRadius: AppConstants()
.button_container_radius,
onTap: () async {
bool opRes =
await deviceTypeController
.qcCheckControl(
widget.personInfo, 1);
if (!opRes) {
return;
}
deviceTypeController
.experience_percent.value = 0;
progressNotifier.value = 0;
deviceTypeController
.experience_status
.value = 200;
_startCheckStatusTimer();
deviceTypeController.updateAll();
},
colors:
AppConstants().thNormalButton,
child: Container(
width: bodySize.maxWidth,
height: MediaQuery.sizeOf(context)
.height *
0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
'开始快检'.tr,
style: TextStyle(
color: themeController
.currentColor.sc3,
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(
SizedBox(width: 17.rpx)),
),
),
),
],
),
),
SizedBox(height: 40.rpx),
SizedBox(height: 26.rpx),
],
)
else
Column(
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 0.rpx, 100.rpx, 60.rpx),
child: CalibrationProgressWidget(
progressNotifier: progressNotifier,
failureNotifier: failureNotifier,
),
),
Padding(
padding: EdgeInsets.fromLTRB(
100.rpx, 0, 100.rpx, 0),
child: Column(
children: [
CustomCard(
borderRadius: AppConstants()
.button_container_radius,
onTap: () {
showCancelConfirmDialog(
context, widget.personInfo);
},
colors: [
themeController.currentColor.sc9
],
child: Container(
width: bodySize.maxWidth,
height: MediaQuery.sizeOf(context)
.height *
0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
'终止'.tr,
style: TextStyle(
color: themeController
.currentColor.sc3,
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(
SizedBox(width: 17.rpx)),
),
),
),
],
),
),
SizedBox(height: 40.rpx),
SizedBox(height: 26.rpx),
],
),
],
),
),
),
],
);
})),
),
),
),
);
}
}