Files
tuiche/lib/pages/mh_page/Vital_signs_sensor.dart
2025-07-30 16:48:48 +08:00

513 lines
20 KiB
Dart

import 'dart:async';
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/NullDataComponentWidget.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/mh_controller/device_list_controller.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class VitalSignsSensorPage extends StatefulWidget {
Map data;
VitalSignsSensorPage({required this.data});
@override
_VitalSignsSensorState createState() => _VitalSignsSensorState();
}
class _VitalSignsSensorState extends State<VitalSignsSensorPage> {
BoxConstraints? bodysize;
DeviceListController controller = Get.find();
Timer? _timer;
@override
void initState() {
super.initState();
_fetchDeviceList();
_timer = Timer.periodic(Duration(seconds: 5), (timer) {
_fetchDeviceList();
});
}
_fetchDeviceList() async {
await controller.getVitalList(widget.data['mac'.tr]);
}
@override
void dispose() {
_timer?.cancel(); // 页面销毁时取消定时器
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, cc) {
bodysize = cc;
return GestureDetector(
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/new_background.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.transparent,
iconTheme: const IconThemeData(color: Colors.white),
automaticallyImplyLeading: false,
titleSpacing: 0,
title: SizedBox(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
// 中间居中的标题
Text(
"体征传感器".tr,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
),
),
// 左侧图标
Positioned(
left: 0.rpx,
child: returnIconButtomNew(),
),
],
),
),
centerTitle: false,
),
body: SafeArea(
child: Obx(() {
var list = controller.model.vitalList;
return list.isEmpty
? const NullDataWidget()
: _buildVitalListView(list);
}),
),
)));
});
}
Widget _buildVitalListView(List dataList) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 30.rpx),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 30.rpx),
...List.generate(dataList.length, (index) {
final item = dataList[index];
final title =
index == 0 ? '体征传感器A'.tr : '体征传感器B'.tr; // ✅ 只处理 A/B 场景
return VitalWidget(title: title, data: item);
}).divide(SizedBox(height: 30.rpx)),
SizedBox(height: 30.rpx),
],
),
),
);
}
}
class VitalWidget extends StatelessWidget {
final String title;
final Map<String, dynamic> data;
const VitalWidget({super.key, required this.title, required this.data});
@override
Widget build(BuildContext context) {
final String id = data['mac'.tr] ?? '--';
final int? timestamp = data['status']['updateTime'];
final String time = (timestamp != null)
? DateFormat('yyyy-MM-dd HH:mm')
.format(DateTime.fromMillisecondsSinceEpoch(timestamp))
: '--';
final List<IconData> icons = data['icons'] ?? [];
return ClickableContainer(
backgroundColor: Color(0xFF003058),
highlightColor: Color(0xFF055466),
borderRadius: 20.rpx,
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 30.rpx, 30.rpx, 40.rpx),
onTap: () {},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
// constraints: BoxConstraints(
// minHeight: 60.rpx,
// ),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
// '实时监测结果通知'.tr,
title,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(minWidth: 106.rpx),
child: Text(
"设备ID".tr,
style: TextStyle(
color: stringToColor("#929699"),
fontSize: 26.rpx,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Text(
id,
style: TextStyle(fontSize: 26.rpx, color: Color(0xFFFFFFFF)),
),
].divide(SizedBox(width: 33.rpx)),
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(minWidth: 106.rpx),
child: Text(
"更新时间".tr,
style: TextStyle(
color: stringToColor("#929699"),
fontSize: 26.rpx,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Text(
time,
style: TextStyle(fontSize: 26.rpx, color: Color(0xFFFFFFFF)),
),
].divide(SizedBox(width: 33.rpx)),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(minWidth: 106.rpx),
child: Text(
"设备状态".tr,
style: TextStyle(
color: stringToColor("#929699"),
fontSize: 26.rpx,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
if (data['status']['signal'] != null &&
data['status']['signal'] != -1 &&
data['status']['status'] != null &&
data['status']['status'] == 1)
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey, // 或根据你主题定制颜色
padding: EdgeInsets.zero,
borderRadius: 0,
onTap: () {
// 点击事件
showTipDialog(
context,
Container(
child: RichText(
text: TextSpan(
text: "信号强度".tr, // 文本前缀部分
style: TextStyle(
color: Colors.black,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
TextSpan(
text: getBedSignal(
data['status']['signal']), // 状态部分
style: TextStyle(
color: themeController
.currentColor.sc2, // 同样颜色,也可改成其他颜色
fontSize:
AppConstants().title_text_fontSize,
),
),
],
),
),
),
backgroundColor: Color(0xFFFFFFFF),
colors: [
Color(0XFF1592AA),
Color(0xFF0C83A7),
Color(0xFF006FA3)
],
);
},
child: Container(
width: 30.rpx,
height: 24.rpx,
child: Image.asset(
'assets/img/signal${_getSignalLevel(data['status']['signal'])}.png'),
),
),
if (data['status']['inBed'] != null &&
data['status']['status'] != null &&
data['status']['status'] == 1)
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey,
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
borderRadius: 0,
onTap: () {
showTipDialog(
context,
Container(
child: RichText(
text: TextSpan(
text: "是否在床".tr, // 文本前缀部分
style: TextStyle(
color: Colors.black,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
TextSpan(
text: getBedStatus(
data['status']['inBed']), // 状态部分
style: TextStyle(
color: themeController
.currentColor.sc2, // 同样颜色,也可改成其他颜色
fontSize:
AppConstants().title_text_fontSize,
),
),
],
),
),
),
backgroundColor: Color(0xFFFFFFFF),
colors: [
Color(0XFF1592AA),
Color(0xFF0C83A7),
Color(0xFF006FA3)
],
);
},
child: SizedBox(
width: 16.rpx,
height: 36.rpx,
child: SvgPicture.asset(
data['status']['inBed'] == 0
? 'assets/img/icon/not_bed.svg'
: 'assets/img/icon/in_bed.svg',
fit: BoxFit.fill,
),
),
),
if (data['status']['failure'] != 0 &&
data['status']['status'] != null &&
data['status']['status'] == 1)
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey, // 可自定义点击水波纹颜色
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
borderRadius: 0,
onTap: () {
showTipDialog(
context,
Container(
child: RichText(
text: TextSpan(
text: "设备故障".tr, // 文本前缀部分
style: TextStyle(
color: Colors.black,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
// TextSpan(
// text:widget
// .device['status']['status'] == 1?"在线".tr:"离线".tr, // 状态部分
// style: TextStyle(
// color: themeController.currentColor
// .sc2, // 同样颜色,也可改成其他颜色
// fontSize: AppConstants()
// .title_text_fontSize,
// ),
// ),
],
),
),
),
backgroundColor: Color(0xFFFFFFFF),
colors: [
Color(0XFF1592AA),
Color(0xFF0C83A7),
Color(0xFF006FA3)
],
);
},
child: SizedBox(
width: 27.rpx,
height: 27.rpx,
child: SvgPicture.asset(
'assets/img/icon/device_issue.svg',
fit: BoxFit.cover,
),
),
),
if (data['status']['upgrade'] != 0 &&
data['status']['status'] != null &&
data['status']['status'] == 1)
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey, // 可自定义点击效果颜色
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
borderRadius: 0,
onTap: () {
//todo 升级
},
child: SizedBox(
width: 34.rpx,
height: 24.rpx,
child: SvgPicture.asset(
'assets/img/icon/upgrade.svg',
fit: BoxFit.cover,
// color: themeController.currentColor.sc3, // 若你想加颜色控制可取消注释
),
),
),
if (data['status']['status'] != null &&
data['status']['status'] == 0)
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey, // 可替换为点击高亮色
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
borderRadius: 0,
onTap: () {
showTipDialog(
context,
Container(
child: RichText(
text: TextSpan(
text: "网络状态".tr, // 文本前缀部分
style: TextStyle(
color: Colors.black,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
TextSpan(
text: data['status']['status'] == 1
? "在线".tr
: "离线".tr, // 状态部分
style: TextStyle(
color: themeController
.currentColor.sc2, // 同样颜色,也可改成其他颜色
fontSize:
AppConstants().title_text_fontSize,
),
),
],
),
),
),
backgroundColor: Color(0xFFFFFFFF),
colors: [
Color(0XFF1592AA),
Color(0xFF0C83A7),
Color(0xFF006FA3)
],
);
},
child: SizedBox(
width: 27.rpx,
height: 27.rpx,
child: SvgPicture.asset(
// data['status']['status'] == 1
// ? 'assets/img/icon/device_online.svg'
// : 'assets/img/icon/device_offline.svg',
'assets/img/icon/device_issue.svg',
fit: BoxFit.cover,
),
),
),
].divide(SizedBox(width: 50.rpx)),
),
].divide(SizedBox(width: 34.rpx)),
),
].divide(
SizedBox(height: 20.rpx),
)),
);
}
getBedSignal(signal) {
if (signal <= 1) {
return "较弱".tr;
}
if (signal > 1 && signal <= 2) {
return "".tr;
}
if (signal > 2 && signal <= 3) {
return "一般".tr;
}
if (signal > 3) {
return "".tr;
}
return "未知数据".tr;
}
String getBedStatus(int status) {
if (status == 0) {
return "离床".tr;
} else if (status == 1) {
return "在床".tr;
}
return "";
}
int _getSignalLevel(int signal) {
if (signal <= 25) {
return 1;
} else if (signal <= 50) {
return 2;
} else if (signal <= 75) {
return 3;
} else {
return 4;
}
}
}