Files
tuiche/lib/pages/device/component/DeviceDataComponentWidget.dart
2026-01-07 15:19:16 +08:00

1722 lines
68 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:math' as math;
import 'dart:ui' as ui;
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/color/app_uri_status.dart';
import 'package:vbvs_app/common/pojo/city.dart';
import 'package:vbvs_app/common/util/EventBus.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/common/util/eventType.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/component/tool/ToggleColorContainer.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/person/person_controller.dart';
import 'package:vbvs_app/enum/BindType.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class DeviceDataComponentWidget extends StatefulWidget {
final Map<String, dynamic> device;
const DeviceDataComponentWidget({super.key, required this.device});
@override
State<DeviceDataComponentWidget> createState() =>
_DeviceDataComponentWidgetState();
}
class _DeviceDataComponentWidgetState extends State<DeviceDataComponentWidget> {
final GlobalKey _arrowKey = GlobalKey();
OverlayEntry? _popupEntry;
BodyDeviceController bodyDeviceController = Get.find();
PersonController personController = Get.find();
bool _isPopupOpen = false;
var lisObj;
late StreamSubscription<ScrollNotificationEvent> _scrollSubscription;
@override
void dispose() {
_popupEntry?.remove();
super.dispose();
}
@override
void initState() {
super.initState();
late StreamSubscription<SwitchLanguageEvent> subscription;
// 监听切换语言
subscription = EventBus().on<SwitchLanguageEvent>().listen((event) async {
final CityModelController cityController =
Get.find<CityModelController>();
ef.log("切换语言事件通知:${event.language}");
cityController.cityList = [];
await initializeCityData();
});
_scrollSubscription =
EventBus().on<ScrollNotificationEvent>().listen((event) {
if (_isPopupOpen) {
_closePopup();
}
});
}
void _showPopup() {
setState(() {
_isPopupOpen = true;
});
final RenderBox? renderBox =
_arrowKey.currentContext?.findRenderObject() as RenderBox?;
if (renderBox == null) return;
final position = renderBox.localToGlobal(Offset.zero);
final size = renderBox.size;
final screenSize = MediaQuery.of(context).size;
final screenHeight = screenSize.height;
final screenWidth = screenSize.width;
// final popupWidth = 190.rpx;
var popupWidth = 190.rpx;
final paddingOffset = 10.rpx;
// 构建弹窗内容
final popupContent = _buildPopupContent();
final textStyle = TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
);
final allTexts = [
"体征检测设备.首页展示".tr,
"体征检测设备.设备详情".tr,
"WIFI配置".tr,
"设备校准".tr,
"分享设备".tr,
"消息设置".tr,
"体征检测设备.重命名".tr,
"体征检测设备.删除".tr,
];
final menuWidth = _calculateMaxMenuItemWidth(allTexts, textStyle);
popupWidth = menuWidth;
// 计算弹窗需要的实际高度(估算)
final estimatedItemHeight = 66.rpx; // 每个菜单项的估算高度
//todo 更新菜单项,需要在此添加数量
// final itemCount =
// widget.device['bind_type'] == BindType.active.code ? 9 : 5;
final itemCount = widget.device['bind_type'] == BindType.active.code
? 9
: (getWifiPermissionByOpType(widget.device) ? 6 : 5);
final estimatedPopupHeight =
(itemCount * estimatedItemHeight) + 40.rpx; // 加上padding
// 计算可用空间
final availableSpaceBelow =
screenHeight - position.dy - size.height - paddingOffset;
final availableSpaceAbove = position.dy - paddingOffset;
// 决定显示位置和实际高度
bool showAbove;
double popupTop;
double actualPopupHeight;
if (availableSpaceBelow >= estimatedPopupHeight ||
(availableSpaceBelow < estimatedPopupHeight &&
availableSpaceAbove > availableSpaceBelow)) {
// 显示在下方的条件:下方空间足够,或者下方空间比上方大
showAbove = false;
popupTop = position.dy + size.height + paddingOffset;
actualPopupHeight = math.min(estimatedPopupHeight, availableSpaceBelow);
} else {
// 显示在上方
showAbove = true;
actualPopupHeight = math.min(estimatedPopupHeight, availableSpaceAbove);
popupTop = position.dy - actualPopupHeight - paddingOffset;
}
// 确保弹窗不会超出屏幕边界
popupTop = math.max(paddingOffset, popupTop);
actualPopupHeight =
math.min(actualPopupHeight, screenHeight * 0.7); // 限制最大高度为屏幕的70%
// 计算左侧位置,确保不会超出屏幕右侧
double popupLeft = position.dx + size.width - popupWidth;
if (popupLeft + popupWidth > screenWidth) {
popupLeft = screenWidth - popupWidth - paddingOffset;
}
// setState(() {
// _isPopupOpen = false;
// });
_popupEntry?.remove();
_popupEntry = OverlayEntry(
builder: (context) => GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
},
child: Stack(
children: [
Positioned(
top: popupTop,
left: popupLeft,
child: Material(
color: Colors.transparent,
child: Container(
constraints: BoxConstraints(
// maxWidth: popupWidth,
maxWidth: screenWidth,
maxHeight: actualPopupHeight,
),
decoration: BoxDecoration(
color: themeController.currentColor.sc17,
borderRadius: BorderRadius.circular(12.rpx),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 12.rpx,
spreadRadius: 1.rpx,
offset: Offset(0, 6.rpx),
),
],
),
child: SingleChildScrollView(
child: popupContent,
),
),
),
),
],
),
),
);
Overlay.of(context)?.insert(_popupEntry!);
}
// 构建弹窗内容
Widget _buildPopupContent() {
final content = Container(
padding: EdgeInsets.all(20.rpx),
// decoration: BoxDecoration(
// color: themeController.currentColor.sc17,
// borderRadius: BorderRadius.circular(12.rpx),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.2),
// blurRadius: 12.rpx,
// spreadRadius: 1.rpx,
// offset: Offset(0, 6.rpx),
// ),
// ],
// ),
child: Column(
mainAxisSize: MainAxisSize.min,
children: _buildMenuItems().divide(SizedBox(
height: 6.rpx,
)),
),
);
return widget.device['bind_type'] == BindType.active.code
? _buildActiveDeviceContent(content)
: _buildSharedDeviceContent(content);
}
// 构建主动绑定设备的菜单项
Widget _buildActiveDeviceContent(Widget content) {
return IntrinsicWidth(
child: content,
);
}
// 构建共享设备的菜单项
Widget _buildSharedDeviceContent(Widget content) {
return IntrinsicWidth(
child: content,
);
}
// 构建菜单项列表
List<Widget> _buildMenuItems() {
final items = <Widget>[
_buildMenuItem(
icon: widget.device['show'] != null && widget.device['show'] == true
? Icon(Icons.check,
size: 24.rpx, color: themeController.currentColor.sc2)
: null,
text: "体征检测设备.首页展示".tr,
onTap: () async {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
ApiResponse apiResponse =
await bodyDeviceController.updateDeviceShow(widget.device);
if (apiResponse.code == HttpStatusCodes.ok) {
bodyDeviceController.getDeviceList();
bodyDeviceController.updateAll();
} else {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: themeController.currentColor.sc9,
);
}
},
textColor:
(widget.device['show'] != null && widget.device['show'] == true)
? themeController.currentColor.sc2
: themeController.currentColor.sc3,
),
_buildMenuItem(
text: "体征检测设备.设备详情".tr,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
Get.toNamed("/deviceDetail", arguments: widget.device);
},
),
];
// if ((widget.device['bind_type'] == BindType.active.code &&
// !AppConstants.is_test_account) ||
// (getWifiPermissionByOpType(widget.device))) {
// items.addAll([
// _buildMenuItem(
// text: "WIFI配置".tr,
// onTap: () {
// setState(() {
// _isPopupOpen = false;
// });
// _popupEntry?.remove();
// _popupEntry = null;
// dealWifi(widget.device);
// },
// ),
// _buildMenuItem(
// text: "设备校准".tr,
// onTap: () async {
// setState(() {
// _isPopupOpen = false;
// });
// _popupEntry?.remove();
// _popupEntry = null;
// BlueteethBindController blueteethBindController = Get.find();
// blueteethBindController.currentDeviceMac?.value =
// widget.device['mac'];
// await Get.toNamed("/calibrationPersonPage", arguments: 2);
// },
// ),
// _buildMenuItem(
// text: "分享设备".tr,
// onTap: () {
// setState(() {
// _isPopupOpen = false;
// });
// _popupEntry?.remove();
// _popupEntry = null;
// Get.toNamed("/deviceSharePage", arguments: widget.device);
// },
// ),
// _buildMenuItem(
// text: "消息设置".tr,
// onTap: () {
// setState(() {
// _isPopupOpen = false;
// });
// _popupEntry?.remove();
// _popupEntry = null;
// // Get.toNamed("/deviceDetail", arguments: widget.device);
// Get.toNamed("/messageSettingPage", arguments: widget.device);
// // TopSlideNotification.show(context, text: "待开发功能".tr);
// },
// ),
// ]);
// }
// 是否有基础操作权限(除 WIFI 外)
bool hasBasePermission =
widget.device['bind_type'] == BindType.active.code &&
!AppConstants.is_test_account;
// 是否有 WIFI 权限
bool hasWifiPermission = getWifiPermissionByOpType(widget.device);
// WIFI 配置 —— 单独判断
if (hasBasePermission || hasWifiPermission) {
items.add(
_buildMenuItem(
text: "WIFI配置".tr,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
dealWifi(widget.device);
},
),
);
// 下面这些 **只受 hasBasePermission 影响**
if (hasBasePermission) {
items.addAll([
_buildMenuItem(
text: "设备校准".tr,
onTap: () async {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
BlueteethBindController blueteethBindController = Get.find();
blueteethBindController.currentDeviceMac?.value =
widget.device['mac'];
await Get.toNamed("/calibrationPersonPage", arguments: 2);
},
),
_buildMenuItem(
text: "分享设备".tr,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
Get.toNamed("/deviceSharePage", arguments: widget.device);
},
),
_buildMenuItem(
text: "消息设置".tr,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
Get.toNamed("/messageSettingPage", arguments: widget.device);
},
),
]);
}
}
items.addAll([
_buildMenuItem(
text: "体征检测设备.重命名".tr,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
_showRenameDialog();
},
),
_buildMenuItem(
text: widget.device['bind_type'] == BindType.active.code
? "解绑".tr
: "删除".tr,
onTap: () {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
_showUnbindConfirmDialog();
},
),
]);
return items;
}
// 构建单个菜单项
Widget _buildMenuItem({
Widget? icon,
required String text,
required VoidCallback onTap,
Color? textColor,
}) {
return ClickableContainer(
padding: EdgeInsets.symmetric(vertical: 16.rpx),
backgroundColor: Colors.transparent,
highlightColor: themeController.currentColor.sc16.withOpacity(0.1),
borderRadius: 8.rpx,
onTap: onTap,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
icon ?? SizedBox(width: 24.rpx, height: 24.rpx),
SizedBox(width: 10.rpx),
Expanded(
child: Text(
text,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: textColor ?? themeController.currentColor.sc3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
}
// 显示重命名对话框
void _showRenameDialog() {
personController.currentPersonId.value = widget.device['_id'];
personController.name.value = "";
String text = "确定".tr;
showSingleConfirmDialog(
context,
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 41.rpx, 0.rpx, 0),
child: Container(
height: 80.rpx,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.rpx),
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: TextFormField(
onChanged: (value) {
if (value == null || value.isEmpty) {
personController.name.value = "体征监测设备".tr;
} else {
personController.name.value = value;
}
},
autofocus: false,
decoration: InputDecoration(
isDense: true,
// hintText: '请输入人员名称'.tr,
hintText: "体征监测设备".tr,
hintStyle: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
),
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: Colors.black,
),
cursorColor: Colors.white,
initialValue: widget.device['person'] == null ||
widget.device['person']['name'] == null ||
widget.device['person']['name'] == ""
? "体征监测设备".tr
: widget.device['person']['name'],
),
),
),
),
'修改人员名称'.tr,
onConfirm: () async {
ApiResponse response = await personController.updatePersonName(
widget.device['person'],
widget.device['_id'],
);
if (response.code == HttpStatusCodes.ok) {
NewTopSlideNotification.show(
text: response.msg!,
);
await bodyDeviceController.getDeviceList();
bodyDeviceController.updateAll();
} else {
TopSlideNotification.show(
context,
text: response.msg!,
textColor: themeController.currentColor.sc9,
);
}
},
onCancel: () {
print('用户点击了取消');
},
confirmText: text,
);
}
// 显示解绑确认对话框
void _showUnbindConfirmDialog() {
showConfirmDialog(
context,
Container(),
"是否确认解绑".tr,
onConfirm: () async {
ApiResponse apiResponse =
await bodyDeviceController.deleteDevice(widget.device);
if (apiResponse.code == HttpStatusCodes.ok) {
bodyDeviceController.getDeviceList();
TopSlideNotification.show(
context,
text: apiResponse.msg!,
);
} else {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: themeController.currentColor.sc9,
);
}
},
onCancel: () {},
);
}
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
borderRadius: BorderRadius.circular(20.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 30.rpx, 30.rpx, 30.rpx),
child: Container(
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
constraints: BoxConstraints(
// maxWidth: MediaQuery.sizeOf(context).width - 200.rpx,
maxWidth: MediaQuery.sizeOf(context).width * 0.6,
),
child: Text(
'${(widget.device['person']?['name'] as String?)?.isNotEmpty == true ? widget.device['person']!['name'] : '体征检测设备'.tr}',
style: TextStyle(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
// ClickableContainer(
// key: _arrowKey,
// padding: EdgeInsetsDirectional.fromSTEB(
// 16.rpx, 16.rpx, 14.rpx, 16.rpx),
// backgroundColor: Colors.transparent,
// highlightColor: Colors.black.withOpacity(0.1),
// borderRadius: 8.rpx,
// onTap: _showPopup,
// child: Container(
// width: 15.rpx,
// height: 8.rpx,
// child: SvgPicture.asset(
// 'assets/img/icon/arrow_down.svg',
// fit: BoxFit.cover,
// color: Colors.white,
// ),
// ),
// ),
ToggleColorContainer(
key: _arrowKey,
padding: EdgeInsetsDirectional.fromSTEB(
// 16.rpx,
// 16.rpx,
// 14.rpx,
// 16.rpx,
25.rpx,
16.rpx,
25.rpx,
16.rpx,
),
initialColor: Colors.transparent,
toggledColor: Colors.black.withOpacity(0.5),
borderRadius: 8.rpx,
onToggle: _showPopup,
toggled: _isPopupOpen,
child: Container(
width: 15.rpx,
height: 8.rpx,
child: SvgPicture.asset(
'assets/img/icon/arrow_down.svg',
fit: BoxFit.cover,
color: Colors.white,
),
),
),
],
),
SizedBox(height: 40.rpx),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 100.rpx,
constraints: BoxConstraints(
minWidth: 105.rpx,
),
decoration: BoxDecoration(),
child: Text(
'设备ID'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
),
Text(
'${widget.device['code'] ?? '未知数据'.tr}',
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 34.rpx)),
),
SizedBox(height: 40.rpx),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 100.rpx,
constraints: BoxConstraints(
minWidth: 105.rpx,
),
decoration: BoxDecoration(),
child: Text(
'更新时间'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
),
Text(
'${widget.device['status']['updateTime'] != null ? MyUtils.timestampToDateString(widget.device['status']['updateTime']) : '未知时间'.tr}',
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 34.rpx)),
),
SizedBox(height: 40.rpx),
if (widget.device['bind_type'] == BindType.active.code)
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 100.rpx,
constraints: BoxConstraints(
minWidth: 105.rpx,
),
decoration: BoxDecoration(),
child: Text(
'已分享'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
),
Text(
'${widget.device['shareNum']}' + "".tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 34.rpx)),
),
// Icon(
// Icons.arrow_back,
// color: FlutterFlowTheme.of(context).primaryText,
// size: 24.rpx,
// ),
// Padding(
// padding:
// EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 14.rpx, 0),
// child: Container(
// width: 28.rpx,
// height: 28.rpx,
// // width: double.infinity,
// decoration: BoxDecoration(),
// child: SvgPicture.asset(
// 'assets/img/icon/group.svg',
// fit: BoxFit.cover,
// // color: stringToColor("#333333"), //固定
// color: Colors.white,
// ),
// ),
// ),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.white, // 或设置为你需要的水波纹颜色
padding: EdgeInsetsDirectional.fromSTEB(
14.rpx, 0.rpx, 14.rpx, 0), //
borderRadius: 0.rpx, // 圆形点击区域
onTap: () {
// 你的点击逻辑
Get.toNamed("/deviceShareListPage",
arguments: widget.device['mac']);
},
child: Container(
padding: EdgeInsetsDirectional.fromSTEB(
0, 0.rpx, 0.rpx, 0), // 外部 padding 移到内部
width: 28.rpx,
height: 24.rpx,
child: SvgPicture.asset(
'assets/img/icon/group.svg',
fit: BoxFit.fill,
color: Colors.white,
),
),
)
].divide(SizedBox(width: 34.rpx)),
),
if (widget.device['bind_type'] == BindType.share.code)
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 100.rpx,
constraints: BoxConstraints(
minWidth: 105.rpx,
),
decoration: BoxDecoration(),
child: Text(
'设备来源'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
),
Text(
(widget.device['source']?.toString().isEmpty ?? true)
? '未知数据'.tr
: widget.device['source'].toString(),
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 34.rpx)),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 14.rpx, 0),
child: Container(
decoration: BoxDecoration(),
child: Text(
"云关爱".tr,
style: TextStyle(
color: themeController.currentColor.sc4,
fontSize: AppConstants().normal_text_fontSize,
),
),
),
),
].divide(SizedBox(width: 34.rpx)),
),
SizedBox(height: 40.rpx),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 100.rpx,
constraints: BoxConstraints(
minWidth: 105.rpx,
),
decoration: BoxDecoration(),
child: Text(
'体征检测设备.设备状态'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
if (widget.device['status']['signal'] != null &&
widget.device['status']['signal'] != -1 &&
widget.device['status']['status'] != null &&
widget.device['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: themeController.currentColor.sc3,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
TextSpan(
text: getBedSignal(
widget.device['status']
['signal']), // 状态部分
style: TextStyle(
color: themeController.currentColor
.sc2, // 同样颜色,也可改成其他颜色
fontSize: AppConstants()
.title_text_fontSize,
),
),
],
),
),
),
);
},
child: Container(
width: 30.rpx,
height: 24.rpx,
child: Image.asset(
'assets/img/signal${_getSignalLevel(widget.device['status']['signal'])}.png'),
),
),
if (widget.device['status']['inBed'] != null &&
widget.device['status']['status'] != null &&
widget.device['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: themeController.currentColor.sc3,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
TextSpan(
text: getBedStatus(widget
.device['status']['inBed']), // 状态部分
style: TextStyle(
color: widget.device['status']
['inBed'] ==
1
? themeController.currentColor.sc2
: themeController.currentColor
.sc9, // 同样颜色,也可改成其他颜色
fontSize: AppConstants()
.title_text_fontSize,
),
),
],
),
),
),
);
},
child: SizedBox(
width: 16.rpx,
height: 36.rpx,
child: SvgPicture.asset(
widget.device['status']['inBed'] == 0
? 'assets/img/icon/not_bed.svg'
: 'assets/img/icon/in_bed.svg',
fit: BoxFit.fill,
),
),
),
if (widget.device['status']['failure'] != 0 &&
widget.device['status']['status'] != null &&
widget.device['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: themeController.currentColor.sc9,
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,
// ),
// ),
],
),
),
),
);
},
child: SizedBox(
width: 27.rpx,
height: 27.rpx,
child: SvgPicture.asset(
'assets/img/icon/device_issue.svg',
fit: BoxFit.cover,
),
),
),
if (widget.device['status']['upgrade'] != 0 &&
widget.device['status']['status'] != null &&
widget.device['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 (widget.device['status']['status'] != null &&
widget.device['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: themeController.currentColor.sc3,
fontSize:
AppConstants().title_text_fontSize,
),
children: [
TextSpan(
text: widget.device['status']
['status'] ==
1
? "在线".tr
: "离线".tr, // 状态部分
style: TextStyle(
color: widget.device['status']
['status'] ==
1
? themeController.currentColor.sc2
: themeController.currentColor
.sc9, // 同样颜色,也可改成其他颜色
fontSize: AppConstants()
.title_text_fontSize,
),
),
],
),
),
),
);
},
child: SizedBox(
width: 27.rpx,
height: 27.rpx,
child: SvgPicture.asset(
// widget.device['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)),
),
SizedBox(height: 20.rpx),
Divider(
thickness: 0.5,
color: themeController.currentColor.sc4,
),
SizedBox(height: 5.rpx),
if (!AppConstants.is_test_account)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () async {
if (widget.device['person'] != null) {
personController.currentPersonId.value =
widget.device['_id'];
personController.name.value =
widget.device['person']['name'];
personController.update_person_mac.value =
widget.device['mac'];
personController.gender.value =
widget.device['person']['gender'] ?? 1;
personController.weight?.value =
widget.device['person']['weight'] == null
? ''
: widget.device['person']['weight']
.toString();
personController.height.value =
widget.device['person']['height'] == null
? ''
: widget.device['person']['height']
.toString();
personController.selectedDiseaseIds.value =
widget.device['person']['disease'] ?? [];
personController.birthday.value =
widget.device['person']['birthday'] ?? '';
personController.dateTime =
MyUtils.formatBirthdayTime(
widget.device['person']['birthday']);
personController.timeZone.value =
widget.device['person']['UTC'] ?? '';
if (widget.device['person']['city_id'] != null) {
// 根据city_id查找完整的城市数据
final int cityId =
widget.device['person']['city_id'];
await initializeCityData();
final CityModel? completeCityData =
_findCityDataById(cityId);
if (completeCityData != null) {
personController.cityModel = completeCityData;
} else {
personController.cityModel = null;
}
} else {
personController.cityModel = null;
}
} else {
personController.update_person_mac.value =
widget.device['mac'];
personController.currentPersonId.value =
widget.device['_id'];
personController.name.value = "";
personController.gender.value = 1;
personController.dateTime = null;
personController.height.value = "";
personController.weight.value = "";
personController.diseaseList.value = [];
personController.cityModel = null;
personController.timeZone.value = "";
}
await Get.toNamed("/updatePersonPage",
arguments: widget.device['bind_type']);
bodyDeviceController.getDeviceList();
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Container(
alignment: Alignment.center,
height: MediaQuery.sizeOf(context).height * 0.0037,
constraints: BoxConstraints(
minWidth: 143.rpx,
minHeight: 61.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(
width: 20.rpx,
),
Expanded(
// 使用 Expanded 来占据屏幕宽度
child: CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
Get.toNamed("/instantBodyPage",
arguments: widget.device);
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
alignment: Alignment.center,
height: MediaQuery.sizeOf(context).height * 0.0037,
constraints: BoxConstraints(
minWidth: 143.rpx,
minHeight: 61.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 (!AppConstants.is_test_account)
SizedBox(
height: 20.rpx,
),
if (!AppConstants.is_test_account)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
// 使用 Expanded 来占据屏幕宽度的一半
child: CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
// TopSlideNotification.show(context, text: "待开发功能".tr);
Get.toNamed("/messageReviewPage",
arguments: widget.device);
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Container(
alignment: Alignment.center,
height: MediaQuery.sizeOf(context).height * 0.0037,
constraints: BoxConstraints(
minWidth: 143.rpx,
minHeight: 61.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(
width: 20.rpx,
),
Expanded(
// 使用 Expanded 来占据屏幕宽度的一半
child: CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
// String mac = widget.device['mac'];
// String sleepReportUrl =
// "${ServiceConstant.sleep_report_url}?mac=${mac}&token=${ServiceConstant.sleep_token}";
// Get.toNamed("/sleepReportPage",
// arguments: sleepReportUrl);
Get.toNamed("/newSleepReportPage", arguments: {
'date': DateTime.now().millisecondsSinceEpoch,
"mac": widget.device['mac'],
'type': 1,
'name': 'sleep', //'sleep', 'heartRate' 或 'breathe'
// 'itemName': widget.data['id'],
'person': widget.device['person'],
});
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Container(
alignment: Alignment.center,
height: MediaQuery.sizeOf(context).height * 0.0037,
constraints: BoxConstraints(
minWidth: 143.rpx,
minHeight: 61.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 (AppConstants.is_test_account)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// Expanded(
// child: CustomCard(
// borderRadius: AppConstants().button_container_radius,
// onTap: () async {
// if (widget.device['person'] != null) {
// personController.currentPersonId.value =
// widget.device['_id'];
// personController.name.value =
// widget.device['person']['name'];
// personController.update_person_mac.value =
// widget.device['mac'];
// personController.gender.value =
// widget.device['person']['gender'] ?? 1;
// personController.weight?.value =
// widget.device['person']['weight'] == null
// ? ''
// : widget.device['person']['weight']
// .toString();
// personController.height.value =
// widget.device['person']['height'] == null
// ? ''
// : widget.device['person']['height']
// .toString();
// personController.selectedDiseaseIds.value =
// widget.device['person']['disease'] ?? [];
// personController.birthday.value =
// widget.device['person']['birthday'] ?? '';
// personController.dateTime =
// MyUtils.formatBirthdayTime(
// widget.device['person']['birthday']);
// } else {
// personController.update_person_mac.value =
// widget.device['mac'];
// personController.currentPersonId.value =
// widget.device['_id'];
// personController.name.value = "";
// personController.gender.value = 1;
// personController.dateTime = null;
// personController.height.value = "";
// personController.weight.value = "";
// personController.diseaseList.value = [];
// }
// await Get.toNamed("/updatePersonPage",
// arguments: widget.device['bind_type']);
// bodyDeviceController.getDeviceList();
// },
// colors: [
// themeController.currentColor.sc1,
// themeController.currentColor.sc2,
// ],
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 0.rpx, 0.rpx, 0.rpx),
// child: Container(
// alignment: Alignment.center,
// height: MediaQuery.sizeOf(context).height * 0.0037,
// constraints: BoxConstraints(
// minWidth: 143.rpx,
// minHeight: 61.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(
// width: 20.rpx,
// ),
Expanded(
// 使用 Expanded 来占据屏幕宽度的一半
child: CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
// TopSlideNotification.show(context, text: "待开发功能".tr);
Get.toNamed("/messageReviewPage",
arguments: widget.device);
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Container(
alignment: Alignment.center,
height: MediaQuery.sizeOf(context).height * 0.0037,
constraints: BoxConstraints(
minWidth: 143.rpx,
minHeight: 61.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)),
),
),
),
),
),
],
),
].divide(SizedBox(height: 0.rpx)),
),
),
),
);
}
String getBedStatus(int status) {
if (status == 0) {
return "离床".tr;
} else if (status == 1) {
return "在床".tr;
}
return "";
}
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;
}
Future<void> dealWifi(device) async {
bodyDeviceController.wifiMac = device['mac'];
Get.toNamed("/wifiPagePerson", arguments: device);
return;
}
double _calculateMaxMenuItemWidth(List<String> texts, TextStyle style) {
double maxTextWidth = 0;
for (final text in texts) {
final painter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: 1,
textDirection: ui.TextDirection.ltr,
)..layout();
if (painter.width > maxTextWidth) {
maxTextWidth = painter.width;
}
}
final iconWidth = 24.rpx;
final spacing = 10.rpx;
final horizontalPadding = 40.rpx;
return iconWidth + spacing + maxTextWidth + horizontalPadding;
}
int _getSignalLevel(int signal) {
if (signal <= 25) {
return 1;
} else if (signal <= 50) {
return 2;
} else if (signal <= 75) {
return 3;
} else {
return 4;
}
}
// 根据ID查找完整的城市数据
CityModel? _findCityDataById(int cityId) {
try {
if (cityId == null) {
return null;
}
// 从加载的城市数据中查找
final cityData = Get.find<CityModelController>().cityList;
// 遍历三级数据结构查找匹配的ID
for (var country in cityData) {
// 检查国家节点
if (country.id == cityId) {
return CityModel(
id: country.id,
value: country.value,
label: country.label,
country: country.value ?? country.country,
province: null,
city: null,
UTC: country.UTC,
children: country.children,
);
}
// 检查省份节点
for (var province in country.children ?? []) {
if (province.id == cityId) {
return CityModel(
id: province.id,
value: province.value,
label: province.label,
country: country.value ?? country.country,
province: province.value ?? province.province,
city: null,
UTC: province.UTC,
children: province.children,
);
}
// 检查城市节点
for (var city in province.children ?? []) {
if (city.id == cityId) {
return CityModel(
id: city.id,
value: city.value,
label: city.label,
country: country.value ?? country.country,
province: province.value ?? province.province,
city: city.value ?? city.city,
UTC: city.UTC,
children: city.children,
);
}
}
}
}
return null;
} catch (e) {
ef.log("根据ID查找城市数据失败$e");
return null;
}
}
Future initializeCityData() async {
final CityModelController cityController = Get.find<CityModelController>();
// 确保城市数据已加载
if (!cityController.isDataLoaded) {
await cityController.loadAndSetCityData();
}
// 如果device中有city_id查找并设置城市数据
if (widget.device['person']['city_id'] != null) {
final String cityId = widget.device['person']['city_id'].toString();
ef.log("开始查找city_id: $cityId");
final CityModel? completeCityData = cityController.findCityById(cityId);
if (completeCityData != null) {
personController.cityModel = completeCityData;
ef.log("成功设置城市数据: ${completeCityData.displayName}");
} else {
personController.cityModel = CityModel(id: int.tryParse(cityId));
ef.log("未找到对应城市数据创建默认CityModel");
}
personController.updateAll();
}
}
getWifiPermissionByOpType(Map<String, dynamic> device) {
int opType = device['op_type'] ?? 2;
if (opType != null && opType == 1) {
return true;
}
return false;
}
void _closePopup() {
setState(() {
_isPopupOpen = false;
});
_popupEntry?.remove();
_popupEntry = null;
}
}