diff --git a/assets/langs/zh_CN.json b/assets/langs/zh_CN.json index 4a86f2f..290220a 100644 --- a/assets/langs/zh_CN.json +++ b/assets/langs/zh_CN.json @@ -131,7 +131,7 @@ }, "wifi页":{ "标题":"WIFI配置", - "跳过":"跳过", + "跳过":"下一步", "WLAN":"网络", "未连接":"未连接", "已连接":"已连接", @@ -423,6 +423,12 @@ "昨日数据":"昨日数据", "次":"频次", "秒":"秒", - "当前暂无数据":"当前暂无数据" + "当前暂无数据":"当前暂无数据", + "下一步":"下一步", + "未配置网络提示":"当前设备未进行网络配置,是否确认跳过网络配置", + "退出":"退出", + "完成":"完成", + "时长":"时长:" + } \ No newline at end of file diff --git a/lib/common/color/ServiceConstant.dart b/lib/common/color/ServiceConstant.dart index db3f8c8..a73da94 100644 --- a/lib/common/color/ServiceConstant.dart +++ b/lib/common/color/ServiceConstant.dart @@ -1,5 +1,6 @@ class ServiceConstant { static const String baseHost = "vsbs-test.he-info.cn";//服务地址 + // static const String baseHost = "vsbst-api.he-info.cn/";//服务地址 static const String service_address = "http://$baseHost"; static String server_service = "/vsbs_app_server";//服务名称 diff --git a/lib/component/tool/cmd.dart b/lib/component/tool/cmd.dart index 856652f..8b66941 100644 --- a/lib/component/tool/cmd.dart +++ b/lib/component/tool/cmd.dart @@ -40,7 +40,7 @@ getWifiList(THapp tHapp) async { } return false; - }, 2); + }, 1); return wifilist; } catch (e) { @@ -247,7 +247,7 @@ Future getDeviceNetVersion(THapp tHapp, int times) async { } ss.over = false; return false; - }, times, 15); + }, times,15000); return netType; } catch (e) { diff --git a/lib/controller/device/blueteeth_bind_controller.dart b/lib/controller/device/blueteeth_bind_controller.dart index 4b27a5f..9ff0032 100644 --- a/lib/controller/device/blueteeth_bind_controller.dart +++ b/lib/controller/device/blueteeth_bind_controller.dart @@ -61,18 +61,21 @@ class BlueteethBindController extends GetControllerEx { Timer? _statusTimer; THapp? currentDevice; - RxInt wifiStatus = 0.obs; + RxInt wifiStatus = 0.obs;//wifi连接状态 0:未连接 1:已连接 RxList wifiList = [].obs; RxMap connect_wifi = {}.obs; RxString scanMac = "".obs; - RxString? currentDeviceMac = "".obs; + RxString currentDeviceMac = "".obs;//当前选中的设备mac地址 RxString? cid = "".obs; RxString search = "".obs; //搜索关键字 + RxBool bluetoothStatus = false.obs;//蓝牙开启状态 RxInt connectStatus = 0.obs;//当前wifi连接状态 0:未连接 1:已连接 - RxInt blueConnectFlag = 0.obs;//当前蓝牙连接状态 0.正在连接 1.为连接 2.已连接 + RxInt blueConnectFlag = 0.obs;//当前蓝牙连接状态 0.正在连接 1.未连接 2.已连接 + RxInt netType = 0.obs;//当前网络类型 0.正在检测 1.wifi 2.4g设备 3.未知 + RxInt wifiConnectStatus = 1.obs;//获取wifi状态 0.正在检测 1.已检测完 RxMap selectWifi = {}.obs; //正在连接wifi信息 diff --git a/lib/controller/device/device_calibration_controller.dart b/lib/controller/device/device_calibration_controller.dart index 2ee8114..d186221 100644 --- a/lib/controller/device/device_calibration_controller.dart +++ b/lib/controller/device/device_calibration_controller.dart @@ -29,6 +29,14 @@ class DeviceCalibrationController RxInt bed_calibration = 0.obs; //0.未完成 1.完成 RxInt position_calibration = 0.obs; //0.未完成 1.完成 RxInt bed_type = 0.obs; //0.单人 1.双人 - RxString tips = "开始校准".tr.obs; - bool complete = false; //校准完成 + RxString tips = "".obs; + RxInt flag = 0.obs; //0没有开始 1:校准中 2.校准完成 3.校准失败 + RxString statusContext = "".obs; + + + RxInt cd = 10000.obs; + bool forceStart = false; + + RxInt motionTips = 0.obs;//体动提示 + RxInt inBedTips = 0.obs;//在床提示 } diff --git a/lib/main.dart b/lib/main.dart index a2be13c..fa8d3d4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -109,7 +109,7 @@ void startMessagePolling() { messageController.getMessageStatus(); // print("轮询消息状态成功"); } catch (e) { - print("轮询消息状态失败: $e"); + print("轮询消息状态失败: $e"); } }); } @@ -129,6 +129,9 @@ void initEasyDartModule() { WebSocketConfig(ServiceConstant.webSocketService, (data) { // 接收到服务消息 var json = jsonDecode(data); + if (json['code'] != null && json['code'] != 200) { + EasyDartModule.logger.error("websocket连接失败--》" + json); + } if (json["path"] != null) { var call = CommonVariables.callMap[json["path"]]; if (call != null) { diff --git a/lib/pages/common/selectDialog.dart b/lib/pages/common/selectDialog.dart index 3e44ba6..8e3d85c 100644 --- a/lib/pages/common/selectDialog.dart +++ b/lib/pages/common/selectDialog.dart @@ -827,31 +827,16 @@ void showProgressDialog( if (Navigator.canPop(dialogContext)) { Navigator.of(dialogContext).pop(); } - // TopSlideNotification.show( - // context, - // text: "设备校准失败".tr, - // textColor: Colors.red, - // ); + }); } else if (progress >= 100) { // 延迟关闭弹窗和提示成功(可选) Future.delayed(Duration(milliseconds: 300), () { if (Navigator.canPop(dialogContext)) { Navigator.of(dialogContext).pop(); - } - // TopSlideNotification.show( - // context, - // text: "设备校准完成".tr, - // ); - // Obx(() { - // TopSlideNotification.show(context, - // text: - // deviceCalibrationController.tips.value); - // return Container(); - // }); + } }); } - return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -879,14 +864,11 @@ void showProgressDialog( ), ), ), - Container( - // width: progress * - // MediaQuery.of(context).size.width * - // 0.4, + Container( width: progress / 100 * MediaQuery.of(context).size.width * - 0.8, // 进度条宽度按比例计算,最大宽度是屏幕宽度的 0.8 + 0.8, height: 21.rpx, decoration: BoxDecoration( gradient: LinearGradient( @@ -919,7 +901,7 @@ void showProgressDialog( ), ), ], - ); + ); }, ); } diff --git a/lib/pages/device/component/DeviceDataComponentWidget.dart b/lib/pages/device/component/DeviceDataComponentWidget.dart index 1109440..16687c1 100644 --- a/lib/pages/device/component/DeviceDataComponentWidget.dart +++ b/lib/pages/device/component/DeviceDataComponentWidget.dart @@ -299,7 +299,7 @@ class _DeviceDataComponentWidgetState extends State { BlueteethBindController blueteethBindController = Get.find(); blueteethBindController.currentDeviceMac?.value = widget.device['mac']; - await Get.toNamed("/calibrationPage", arguments: 2); + await Get.toNamed("/calibrationPersonPage", arguments: 2); }, ), _buildMenuItem( @@ -1290,147 +1290,9 @@ class _DeviceDataComponentWidgetState extends State { Future dealWifi(device) async { bodyDeviceController.wifiMac = device['mac']; - Get.toNamed("/wifiPage", arguments: device); + Get.toNamed("/wifiPagePerson", arguments: device); return; - // final blueteethBindController = Get.find(); - // final themeController = Get.find(); - - // // 显示加载对话框 - // showLoadingDialog(Get.context!, title: "连接中...".tr); - - // // 设置超时定时器 - // Timer? timeoutTimer; - // bool isConnected = false; - - // try { - // // 开始扫描蓝牙设备 - // await FlutterBluePlus.startScan(timeout: Duration(seconds: 10)); - - // // 设置超时(20秒) - // timeoutTimer = Timer(Duration(seconds: 20), () { - // try { - // if (!isConnected) { - // Navigator.of(context).pop(); // 先关闭 dialog - // WidgetsBinding.instance.addPostFrameCallback((_) { - // TopSlideNotification.show( - // context, - // text: "设备连接超时,请重试".tr, - // textColor: themeController.currentColor.sc9, - // ); - // }); - // FlutterBluePlus.stopScan(); - // } - // } catch (e) { - // print(e); - // } - // }); - - // // 监听扫描结果 - // StreamSubscription>? scanSubscription; - // scanSubscription = FlutterBluePlus.scanResults.listen((results) async { - // // 过滤出符合条件的设备 - // ScanResult? targetDevice; - - // for (var r in results) { - // if (r.advertisementData.manufacturerData.containsKey(0xFFED)) { - // List rawData = r.advertisementData.manufacturerData[0xFFED]!; - // BleDeviceData deviceData = parseBleData(rawData); - // String deviceMac = - // deviceData.deviceId.replaceAll(':', '').toLowerCase(); - // if (deviceMac == mac.toLowerCase()) { - // targetDevice = r; - // break; - // } - // } - // } - - // if (targetDevice != null && !isConnected) { - // isConnected = true; - // FlutterBluePlus.stopScan(); - // scanSubscription?.cancel(); - // timeoutTimer?.cancel(); - - // try { - // // 连接设备 - // // await targetDevice.device.connect(); - // THapp bledevice = THapp(device: targetDevice.device); - // await bledevice.device.connect(); - // var res2 = bledevice.isConnected; - // if (res2) { - // Navigator.pop(context); - // TopSlideNotification.show( - // context, - // text: "蓝牙绑定.连接成功".tr, - // textColor: themeController.currentColor.sc2, - // ); - // blueteethBindController.currentDevice = bledevice; - // if (lisObj != null) { - // lisObj!.cancel(); - // } - // var aa; - // lisObj = blueteethBindController.currentDevice!.statusStream - // .listen((onData) async { - // if (onData.status == BleEventType.recvLineLog) { - // final line = onData.val; - // print("[bleee]:" + line); - // } - // if (onData.status == BleEventType.ready) { - // aa = await getDeviceNetVersion( - // blueteethBindController.currentDevice!, 1); - // if (aa == "4g") { - // // TopSlideNotification.show( - // // Get.context!, - // // text: "4g设备配置wifi提示".tr, - // // textColor: themeController.currentColor.sc9, - // // ); - // WidgetsBinding.instance.addPostFrameCallback((_) { - // TopSlideNotification.show( - // context, - // text: "4g设备配置wifi提示".tr, - // textColor: themeController.currentColor.sc9, - // ); - // }); - // return; - // } else { - // Get.toNamed("/wifiPage", arguments: 2); - // } - // } - // }); - - // // Get.toNamed("/wifiPage", arguments: {bledevice}); - // } else { - // Navigator.pop(context); - // TopSlideNotification.show( - // context, - // text: "蓝牙绑定.连接失败".tr, - // textColor: themeController.currentColor.sc9, - // ); - // } - // } catch (e) { - // Navigator.of(Get.context!).pop(); // 关闭加载对话框 - // TopSlideNotification.show( - // Get.context!, - // text: "设备连接失败".tr, - // textColor: themeController.currentColor.sc9, - // ); - // } - // } - // }); - - // // 等待扫描完成 - // await Future.delayed(Duration(seconds: 20)); - // } catch (e) { - // timeoutTimer?.cancel(); - // Navigator.of(Get.context!).pop(); // 关闭加载对话框 - // TopSlideNotification.show( - // Get.context!, - // text: "扫描过程中发生错误".tr, - // textColor: themeController.currentColor.sc9, - // ); - // } finally { - // timeoutTimer?.cancel(); - // await FlutterBluePlus.stopScan(); - // } + } double _calculateMaxMenuItemWidth(List texts, TextStyle style) { diff --git a/lib/pages/device/instant_body_page.dart b/lib/pages/device/instant_body_page.dart index 5f35174..386466b 100644 --- a/lib/pages/device/instant_body_page.dart +++ b/lib/pages/device/instant_body_page.dart @@ -206,8 +206,8 @@ class _InstantBodyPageState extends State { child: Row( mainAxisSize: MainAxisSize.max, children: [ - Expanded( - flex: 1, + Flexible( + flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -286,8 +286,8 @@ class _InstantBodyPageState extends State { .addToEnd(SizedBox(height: 36.rpx)), ), ), - Expanded( - flex: 1, + Flexible( + flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -325,43 +325,43 @@ class _InstantBodyPageState extends State { ), ].divide(SizedBox(height: 34.rpx)), ), - - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - '${device['code'] ?? '未知数据'.tr}', - // "D11250300003", - style: - FlutterFlowTheme.of(context) - .bodyMedium - .override( - fontFamily: 'Inter', - fontSize: 26.rpx, - letterSpacing: 0.0, - color: themeController - .currentColor.sc3, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - Text( - '${device['person']?['weight'] ?? '未知数据'.tr}kg', - style: - FlutterFlowTheme.of(context) - .bodyMedium - .override( - fontFamily: 'Inter', - fontSize: 26.rpx, - letterSpacing: 0.0, - color: themeController - .currentColor.sc3, - ), - ), - ].divide(SizedBox(height: 34.rpx)), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${device['code'] ?? '未知数据'.tr}', + // "D11250300003", + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + '${device['person']?['weight'] ?? '未知数据'.tr}kg', + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ].divide(SizedBox(height: 34.rpx)), + ), ), - ] .divide(SizedBox(width: 33.rpx)) .addToStart(SizedBox(width: 37.rpx)), diff --git a/lib/pages/device/message_review_page.dart b/lib/pages/device/message_review_page.dart index 302d939..30d5496 100644 --- a/lib/pages/device/message_review_page.dart +++ b/lib/pages/device/message_review_page.dart @@ -105,8 +105,8 @@ class _MessageReviewPageState extends State { child: Row( mainAxisSize: MainAxisSize.max, children: [ - Expanded( - flex: 1, + Flexible( + flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -181,8 +181,8 @@ class _MessageReviewPageState extends State { .addToEnd(SizedBox(height: 36.rpx)), ), ), - Expanded( - flex: 1, + Flexible( + flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -218,36 +218,42 @@ class _MessageReviewPageState extends State { ), ].divide(SizedBox(height: 34.rpx)), ), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - '${widget.data['code'] ?? '未知数据'.tr}', - // "D11250300003", - style: FlutterFlowTheme.of(context) - .bodyMedium - .override( - fontFamily: 'Inter', - fontSize: 26.rpx, - letterSpacing: 0.0, - color: themeController - .currentColor.sc3, - ), - ), - Text( - '${widget.data['person']?['weight'] ?? '未知数据'.tr}kg', - style: FlutterFlowTheme.of(context) - .bodyMedium - .override( - fontFamily: 'Inter', - fontSize: 26.rpx, - letterSpacing: 0.0, - color: themeController - .currentColor.sc3, - ), - ), - ].divide(SizedBox(height: 34.rpx)), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${widget.data['code'] ?? '未知数据'.tr}', + // "D11250300003", + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + '${widget.data['person']?['weight'] ?? '未知数据'.tr}kg', + style: + FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ].divide(SizedBox(height: 34.rpx)), + ), ), ] .divide(SizedBox(width: 33.rpx)) diff --git a/lib/pages/device_bind/bind_device_success.dart b/lib/pages/device_bind/bind_device_success.dart index d512e7b..3f0b55d 100644 --- a/lib/pages/device_bind/bind_device_success.dart +++ b/lib/pages/device_bind/bind_device_success.dart @@ -79,7 +79,15 @@ class _EPageState extends State { left: 40.rpx, child: ClickableContainer( onTap: () { - Get.offAllNamed("/mianPageBottomChange"); + if (blueteethBindController.returnPage == 0) { + Get.until((route) => + Get.currentRoute == "/mianPageBottomChange"); + } else { + // Get.offNamed("/bodyDevice"); + // Get.offNamedUntil(page, predicate); + Get.until( + (route) => Get.currentRoute == "/bodyDevice"); + } }, backgroundColor: Colors.transparent, highlightColor: Colors @@ -271,9 +279,13 @@ class _EPageState extends State { BlueteethBindController blueteethBindController = Get.find(); if (blueteethBindController.returnPage == 0) { - Get.offAllNamed("/mianPageBottomChange"); + Get.until((route) => + Get.currentRoute == "/mianPageBottomChange"); } else { - Get.offAllNamed("/bodyDevice"); + // Get.offNamed("/bodyDevice"); + // Get.offNamedUntil(page, predicate); + Get.until( + (route) => Get.currentRoute == "/bodyDevice"); } }, colors: [ diff --git a/lib/pages/device_bind/blueteeth_device_page.dart b/lib/pages/device_bind/blueteeth_device_page.dart index 3e95083..71458f4 100644 --- a/lib/pages/device_bind/blueteeth_device_page.dart +++ b/lib/pages/device_bind/blueteeth_device_page.dart @@ -123,6 +123,8 @@ class _BlueteethDevicePageState extends State { var bluetoothState = await FlutterBluePlus.isOn; if (!bluetoothState && !_isDialogShowing) { _isDialogShowing = true; + blueteethBindController.model.blelist = []; + blueteethBindController.updateAll(); await _showBluetoothNotEnabledDialog(); _isDialogShowing = false; return; @@ -134,68 +136,7 @@ class _BlueteethDevicePageState extends State { }); await FlutterBluePlus.startScan(timeout: Duration(seconds: 10)); - // await FlutterBluePlus.startScan(timeout: Duration(minutes: 30)); - - // _scanSubscription = FlutterBluePlus.scanResults.listen((results) { - // if (!mounted) return; // 确保页面未销毁 - // final signalThreshold = blueteethBindController.model.singal!; - // final filteredResults = results - // .where((r) => - // r.rssi > signalThreshold && - // r.advertisementData.localName == "AITH-V2" && - // r.advertisementData.manufacturerData.containsKey(0xFFED)) - // .toList(); - - // // 解析数据 - // final parsedDeviceList = []; - - // for (var r in filteredResults) { - // try { - // List rawData = r.advertisementData.manufacturerData[0xFFED]!; - // BleDeviceData deviceData = parseBleData(rawData); - // deviceData.name = r.advertisementData.advName; - // deviceData.rssi = r.rssi; - // deviceData.mac = deviceData.deviceId.replaceAll(':', ''); - // parsedDeviceList.add(deviceData); - // if (deviceData.mac!.toLowerCase() == 'b43a45c3dfa0') { - // print('匹配设备数据: ${deviceData.mac}-->sn:${deviceData.sn}'); - // } - // } catch (e) { - // print("设备数据解析失败: $e"); - // } - // } - - // // 使用一个临时变量 lastDeviceList 来比较是否有变化 - // setState(() { - // bool hasChanges = false; - - // // 如果 devicelist 长度不同或内容有差异,认为有变化 - // if (blueteethBindController.model.devicelist?.length != - // parsedDeviceList.length) { - // hasChanges = true; - // } else { - // // 深度比较每个设备的属性(比如 mac, rssi) - // for (int i = 0; - // i < blueteethBindController.model.devicelist!.length; - // i++) { - // if (blueteethBindController.model.devicelist![i].mac != - // parsedDeviceList[i].mac || - // blueteethBindController.model.devicelist![i].rssi != - // parsedDeviceList[i].rssi) { - // hasChanges = true; - // break; - // } - // } - // } - - // // 如果有变化,更新 devicelist 和 blelist - // if (hasChanges) { - // blueteethBindController.model.devicelist = parsedDeviceList; - // blueteethBindController.model.blelist = filteredResults; - // // blueteethBindController.updateDeviceStatus(); - // } - // }); - // }); + _scanSubscription = FlutterBluePlus.scanResults.listen((results) { if (!mounted) return; @@ -322,6 +263,7 @@ class _BlueteethDevicePageState extends State { _scanSubscription?.cancel(); // 取消扫描订阅 connectTimer?.cancel(); // 取消连接定时器 blueteethBindController.stopStatusPolling(); // 停止状态轮询 + blueteethBindController.model.blelist = []; super.dispose(); } @@ -753,19 +695,6 @@ class _BlueteethDevicePageState extends State { ), ], )); - // await showDialog( - // context: context, - // builder: (_) => AlertDialog( - // title: Text("蓝牙未开启"), - // content: Text("请先打开蓝牙再进行设备扫描"), - // actions: [ - // TextButton( - // onPressed: () => Navigator.of(context).pop(), - // child: Text("知道了"), - // ), - // ], - // ), - // ); } } diff --git a/lib/pages/device_bind/componnet/CalibrationProgressWidget.dart b/lib/pages/device_bind/componnet/CalibrationProgressWidget.dart new file mode 100644 index 0000000..0f81b67 --- /dev/null +++ b/lib/pages/device_bind/componnet/CalibrationProgressWidget.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.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'; + +class CalibrationProgressWidget extends StatelessWidget { + final ValueNotifier progressNotifier; + final ValueNotifier failureNotifier; + + const CalibrationProgressWidget({ + Key? key, + required this.progressNotifier, + required this.failureNotifier, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: progressNotifier, + builder: (context, progress, _) { + return ValueListenableBuilder( + valueListenable: failureNotifier, + builder: (context, isFailure, __) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + isFailure ? '失败'.tr : '${progress.toStringAsFixed(0)}%', + style: TextStyle( + fontSize: 26.rpx, + color: isFailure + ? Colors.red + : themeController.currentColor.sc3, + ), + ), + SizedBox(height: 40.rpx), + Stack( + children: [ + Container( + width: double.infinity, + height: 21.rpx, + decoration: BoxDecoration( + color: stringToColor("#D9D9D9"), + borderRadius: BorderRadius.circular( + AppConstants().button_container_radius, + ), + ), + ), + Container( + width: progress / 100 * + MediaQuery.of(context).size.width * + 0.8, + height: 21.rpx, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: isFailure + ? [themeController.currentColor.sc9] + : [ + themeController.currentColor.sc2, + themeController.currentColor.sc2, + ], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + borderRadius: BorderRadius.circular( + AppConstants().button_container_radius, + ), + ), + ), + ], + ), + ], + ); + }, + ); + }, + ); + } +} diff --git a/lib/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart b/lib/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart index 7c7a9b6..e359cf4 100644 --- a/lib/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart +++ b/lib/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart @@ -66,7 +66,7 @@ class _SingleBlueteethDeviceCompoentWidgetState showConfirmDialog( context, Container(), "其他设备正在绑定中,是否终止其他设备绑定?".tr, onConfirm: () { - blueteethBindController.currentDeviceMac = null; + blueteethBindController.currentDeviceMac.value = ""; blueteethBindController.updateAll(); }, onCancel: () {}); } @@ -76,7 +76,9 @@ class _SingleBlueteethDeviceCompoentWidgetState } if (device.bind == true) { - showHaveBindDialog(context); + await showHaveBindDialog(context); + blueteethBindController.currentDeviceMac.value = ""; + blueteethBindController.updateAll(); } else { showConfirmDialog( context, @@ -87,52 +89,14 @@ class _SingleBlueteethDeviceCompoentWidgetState await blueteethBindController.bindDeviceAndMAC(device); TopSlideNotification.show(context, text: response.msg!); if (response.code == HttpStatusCodes.ok) { - // showLoadingDialog(context); // 显示 loading - // Get.toNamed("/personPage"); + Get.toNamed("/wifiPage"); THapp bledevice = THapp(device: widget.bleDevice.device); blueteethBindController.currentDevice = bledevice; - // await bledevice.device.connect(); - // var res2 = bledevice.isConnected; - // if (res2) { - // // Navigator.pop(context); - // TopSlideNotification.show( - // context, - // text: "蓝牙绑定.连接成功".tr, - // textColor: themeController.currentColor.sc2, - // ); - // blueteethBindController.currentDevice = bledevice; - - // if (lisObj != null) { - // lisObj!.cancel(); - // } - // var aa; - // lisObj = blueteethBindController.currentDevice!.statusStream - // .listen((onData) async { - // if (onData.status == BleEventType.recvLineLog) { - // final line = onData.val; - // print("[bleee]:" + line); - // } - // if (onData.status == BleEventType.ready) { - // aa = await getDeviceNetVersion( - // blueteethBindController.currentDevice!, 1); - // if (aa == "4g") { - // Get.toNamed("/calibrationPage", arguments: 1); - // } else { - // Get.toNamed("/wifiPage"); - // } - // } - // }); - // } else { - // // Navigator.pop(context); - // TopSlideNotification.show( - // context, - // text: "蓝牙绑定.连接失败".tr, - // textColor: themeController.currentColor.sc9, - // ); - // } + // blueteethBindController.currentDeviceMac.value = ""; + } else { - blueteethBindController.currentDeviceMac = null; + blueteethBindController.currentDeviceMac.value = ""; blueteethBindController.updateAll(); TopSlideNotification.show( context, @@ -143,7 +107,7 @@ class _SingleBlueteethDeviceCompoentWidgetState }, onCancel: () { print('用户点击了取消'); - blueteethBindController.currentDeviceMac?.value = ""; + blueteethBindController.currentDeviceMac.value = ""; blueteethBindController.updateAll(); }, ); @@ -179,7 +143,8 @@ class _SingleBlueteethDeviceCompoentWidgetState ), ), Obx(() { - if (blueteethBindController.currentDeviceMac == device.mac) { + if (blueteethBindController.currentDeviceMac.value == + device.mac) { return SizedBox( width: 24.rpx, height: 24.rpx, diff --git a/lib/pages/device_bind/componnet/bind_dialog.dart b/lib/pages/device_bind/componnet/bind_dialog.dart index 07f4e8d..9920c0d 100644 --- a/lib/pages/device_bind/componnet/bind_dialog.dart +++ b/lib/pages/device_bind/componnet/bind_dialog.dart @@ -133,10 +133,10 @@ void showBindDoubleDialog(BuildContext context, List devices) { ); } -void showHaveBindDialog(BuildContext context) { +Future showHaveBindDialog(BuildContext context) async { ThemeController themeController = Get.find(); - showDialog( + return showDialog( context: context, barrierDismissible: true, barrierColor: Colors.black.withOpacity(0.5), @@ -207,7 +207,7 @@ void showHaveBindDialog(BuildContext context) { child: CustomCard( borderRadius: AppConstants().button_container_radius, onTap: () { - Get.back(); + Get.back(result: true); }, colors: [ themeController.currentColor.sc1, @@ -860,27 +860,24 @@ void showWifiDialog( ); } -String showTipDialog( +Future showTipDialog( BuildContext context, Widget widget, { - Color? backgroundColor, // 新增可选参数 -} - // String title, - ) { + Color? backgroundColor, +}) { ThemeController themeController = Get.find(); BlueteethBindController blueteethBindController = Get.find(); - showDialog( + return showDialog( context: context, barrierDismissible: true, - barrierColor: Colors.black.withOpacity(0.5), // 背景模糊色 + barrierColor: Colors.black.withOpacity(0.5), builder: (BuildContext context) { return FrostedDialog( blurSigma: 3.0, child: Container( decoration: BoxDecoration( - color: - backgroundColor ?? themeController.currentColor.sc17, // 使用默认颜色 + color: backgroundColor ?? themeController.currentColor.sc17, borderRadius: BorderRadius.circular(20.0), ), padding: EdgeInsetsDirectional.fromSTEB(64.rpx, 0, 64.rpx, 0), @@ -892,63 +889,20 @@ String showTipDialog( child: Column( mainAxisSize: MainAxisSize.min, children: [ - // 标题 - // Row( - // mainAxisAlignment: MainAxisAlignment.end, - // children: [ - // ClickableContainer( - // backgroundColor: Colors.transparent, // 容器背景色 - // highlightColor: - // themeController.currentColor.sc21, // 点击时的背景色 - // padding: EdgeInsets.zero, // 这里去掉外部的 padding,避免影响点击范围 - // onTap: () { - // Get.back(); - // }, - // child: Padding( - // padding: - // EdgeInsetsDirectional.fromSTEB(0, 33.rpx, 0, 0.rpx), - // child: SvgPicture.asset( - // 'assets/img/icon/close.svg', - // width: 25.rpx, - // height: 25.rpx, // 如果 SVG 中没有固定颜色,使用 color 设置 - // color: themeController.currentColor.sc3, - // ), - // ), - // ), - // ], - // ), - - // Align( - // alignment: AlignmentDirectional(0, 0), - // child: Padding( - // padding: EdgeInsetsDirectional.fromSTEB( - // 0.rpx, 93.rpx, 0, 74.rpx), - // child: Text( - // title, - // style: FlutterFlowTheme.of(context).bodyMedium.override( - // fontFamily: 'Inter', - // fontSize: 30.rpx, - // letterSpacing: 0.0, - // color: themeController.currentColor.sc3, - // ), - // ), - // ), - // ), Align( alignment: AlignmentDirectional(0, 0), child: Padding( - padding: EdgeInsetsDirectional.fromSTEB( - 0.rpx, 93.rpx, 0, 74.rpx), + padding: + EdgeInsetsDirectional.fromSTEB(0.rpx, 93.rpx, 0, 74.rpx), child: widget, ), ), - Padding( padding: EdgeInsetsDirectional.fromSTEB(0, 19.rpx, 0, 60.rpx), child: CustomCard( borderRadius: AppConstants().button_container_radius, onTap: () { - Get.back(); + Get.back(); // 关闭对话框 }, colors: [ themeController.currentColor.sc1, @@ -972,13 +926,12 @@ String showTipDialog( .override( color: themeController.currentColor.sc3, fontFamily: 'Inter', - fontSize: AppConstants().normal_text_fontSize, + fontSize: + AppConstants().normal_text_fontSize, letterSpacing: 0.0, ), ), - ].divide(SizedBox( - width: 17.rpx, - )), + ].divide(SizedBox(width: 17.rpx)), ), ), ), @@ -990,5 +943,4 @@ String showTipDialog( ); }, ); - return ""; } diff --git a/lib/pages/device_bind/device_calibration.dart b/lib/pages/device_bind/device_calibration.dart index 70dc75f..667fd6a 100644 --- a/lib/pages/device_bind/device_calibration.dart +++ b/lib/pages/device_bind/device_calibration.dart @@ -14,7 +14,7 @@ import 'package:vbvs_app/component/tool/CustomCard.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/device_calibration_controller.dart'; -import 'package:vbvs_app/pages/common/selectDialog.dart'; +import 'package:vbvs_app/pages/device_bind/componnet/CalibrationProgressWidget.dart'; import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart'; class CalibrationPage extends StatefulWidget { @@ -28,22 +28,29 @@ class CalibrationPage extends StatefulWidget { class _CalibrationPageState extends State { DeviceCalibrationController deviceCalibrationController = Get.find(); BlueteethBindController blueteethBindController = Get.find(); - int flag = 0; //默认没有开始校准过 0没有开始 + final ValueNotifier progressNotifier = ValueNotifier(0.0); + final ValueNotifier failureNotifier = ValueNotifier(false); + Timer? _pollingTimer; + bool exit = false; @override void initState() { super.initState(); deviceCalibrationController.process.value = 0; + deviceCalibrationController.cd.value = 10000; + deviceCalibrationController.flag.value = 0; deviceCalibrationController.bed_calibration.value = 0; deviceCalibrationController.position_calibration.value = 0; blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = false; + deviceCalibrationController.motionTips.value = 0; + deviceCalibrationController.inBedTips.value = 0; + deviceCalibrationController.statusContext.value = ""; } @override void dispose() { + _pollingTimer?.cancel(); blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = false; super.dispose(); } @@ -86,25 +93,19 @@ class _CalibrationPageState extends State { Positioned( left: 0, child: returnIconButtomAddCallback(() { - if (flag != 0) { + if (deviceCalibrationController.flag.value != 2) { try { showConfirmDialog( context, Container(), "校准未完成提示".tr, onConfirm: () async { exit = true; - if (widget.type == 2) { - Get.back(); - return; - } - await Get.toNamed("/personPage"); - print("object"); deviceCalibrationController.process.value = 0; deviceCalibrationController .bed_calibration.value = 0; deviceCalibrationController .position_calibration.value = 0; blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = false; + Get.back(); }, onCancel: () { exit = false; }); @@ -125,7 +126,8 @@ class _CalibrationPageState extends State { child: CustomCard( borderRadius: 20.rpx, onTap: () async { - if (flag != 0) { + if (deviceCalibrationController.flag.value != + 2) { showConfirmDialog( context, Container(), "校准未完成提示".tr, onConfirm: () async { @@ -138,8 +140,6 @@ class _CalibrationPageState extends State { deviceCalibrationController .position_calibration.value = 0; blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = - false; }, onCancel: () {}); } else { await Get.toNamed("/personPage"); @@ -149,23 +149,20 @@ class _CalibrationPageState extends State { deviceCalibrationController .position_calibration.value = 0; blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = false; } - - // Get.toNamed("/bindDeviceSuccess"); }, colors: [ themeController.currentColor.sc1, themeController.currentColor.sc2, ], child: Container( - width: 100.rpx, + width: 130.rpx, height: 60.rpx, alignment: Alignment.center, padding: EdgeInsetsDirectional.fromSTEB( 16.rpx, 0, 16.rpx, 0), child: Text( - '跳过'.tr, + '下一步'.tr, style: TextStyle( fontFamily: 'Inter Tight', color: themeController.currentColor.sc3, @@ -373,16 +370,6 @@ class _CalibrationPageState extends State { 0.3, child: Stack( children: [ - // Image.asset( - // deviceCalibrationController - // .bed_type.value == - // 0 - // ? "assets/img/single_pillow.png" - // : "assets/img/double_pillow.png", - // width: double.infinity, - // height: double.infinity, - // fit: BoxFit.contain, - // ), Image.asset( deviceCalibrationController .process.value == @@ -499,48 +486,77 @@ class _CalibrationPageState extends State { child: Obx(() { return Column( children: [ + getBodyMontion(), + SizedBox( + height: 10.rpx, + ), + getInBedMontion(), + SizedBox( + height: 10.rpx, + ), Text( (deviceCalibrationController - .process - .value == - 0 && - deviceCalibrationController - .bed_calibration - .value == - 1) || - (deviceCalibrationController - .process - .value == - 1 && - deviceCalibrationController - .position_calibration - .value == - 1) - ? '校准完成'.tr - : deviceCalibrationController - .process.value == - 0 - ? '离床校准提示'.tr - : '位置校准提示'.tr, + .cd.value == + 10000) + ? ((deviceCalibrationController + .process + .value == + 0 && + deviceCalibrationController + .bed_calibration + .value == + 1) || + (deviceCalibrationController + .process + .value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1) + ? (deviceCalibrationController + .flag.value == + 2 + ? '校准完成'.tr + : "校准失败".tr) + : deviceCalibrationController + .statusContext + .value + .isEmpty == + true + ? (deviceCalibrationController + .process + .value == + 0 + ? '离床校准提示'.tr + : '位置校准提示'.tr) + : deviceCalibrationController + .statusContext + .value) + : "${deviceCalibrationController.cd.value}" + + "s后超时".tr, style: TextStyle( fontSize: 38.rpx, letterSpacing: 0.0, color: ((deviceCalibrationController - .process - .value == - 0 && - deviceCalibrationController - .bed_calibration - .value == - 1) || + .process + .value == + 0 && + deviceCalibrationController + .bed_calibration + .value == + 1) || + (deviceCalibrationController + .process + .value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1)) && (deviceCalibrationController - .process - .value == - 1 && - deviceCalibrationController - .position_calibration - .value == - 1)) + .flag.value == + 2) ? themeController .currentColor.sc1 : themeController @@ -557,354 +573,261 @@ class _CalibrationPageState extends State { ), ); }), - Padding( - padding: EdgeInsetsDirectional.fromSTEB( - 100.rpx, 0.rpx, 100.rpx, 60.rpx), - child: CustomCard( - borderRadius: - AppConstants().button_container_radius, // 圆角半径 - onTap: () async { - if (deviceCalibrationController.complete) { - showConfirmDialog( - context, Container(), "校准已经完成,是否重新开始校准?", - onConfirm: () { - flag = 1; - BlueteethBindController - blueteethBindController = Get.find(); - deviceCalibrationController.process.value = 0; - deviceCalibrationController - .bed_calibration.value = 0; - deviceCalibrationController - .position_calibration.value = 0; - blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = false; + Obx(() { + if (deviceCalibrationController.flag.value == 1) { + return Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 0.rpx, 100.rpx, 60.rpx), + child: CalibrationProgressWidget( + progressNotifier: progressNotifier, + failureNotifier: failureNotifier, + ), + ); + } + return Container(); + }), + Obx(() { + if (deviceCalibrationController.flag.value != 1) { + return Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 0.rpx, 100.rpx, 60.rpx), + child: CustomCard( + borderRadius: AppConstants() + .button_container_radius, // 圆角半径 + onTap: () async { + if (deviceCalibrationController.flag.value == + 2) { + deviceCalibrationController + .statusContext.value = ""; + deviceCalibrationController.flag.value = 1; + progressNotifier.value = 0; + failureNotifier.value = false; + deviceCalibrationController.process.value = + 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + BlueteethBindController + blueteethBindController = Get.find(); + blueteethBindController.cid!.value = ""; - String serviceAddress = - "https://caibration.he-info.cn"; - String calibrationApi = - ServiceConstant.start_calibration; - String progressApi = - ServiceConstant.calibration_process; + deviceCalibrationController.process.value = + 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + String serviceAddress = + "https://caibration.he-info.cn"; + String calibrationApi = + ServiceConstant.start_calibration; + String progressApi = + ServiceConstant.calibration_process; - String queryUrl = - "$serviceAddress$calibrationApi"; + String queryUrl = + "$serviceAddress$calibrationApi"; - final ValueNotifier progressNotifier = - ValueNotifier(0.0); - final ValueNotifier failureNotifier = - ValueNotifier(false); - Timer? pollingTimer; + Timer? pollingTimer; - Map data = { - "macA": blueteethBindController - .currentDeviceMac!.value, - }; + Map data = { + "macA": blueteethBindController + .currentDeviceMac!.value, + }; - // 是否是二次点击(有cid表示进行第二阶段) - bool isSecondStep = blueteethBindController - .cid?.value.isNotEmpty ?? - false; + // 是否是二次点击(有cid表示进行第二阶段) + bool isSecondStep = blueteethBindController + .cid?.value.isNotEmpty ?? + false; - if (isSecondStep) { - data["id"] = - blueteethBindController.cid!.value; - } - - // 发起校准请求 - requestWithLog( - logTitle: "设备校准", - method: MyHttpMethod.post, - queryUrl: queryUrl, - data: data, - onSuccess: (res) { - if (!isSecondStep) { - // 保存第一次获取的 cid - String cid = - res.rawResponse.data['cid']; - blueteethBindController.cid!.value = - cid; - } - - void requestCalibrationProgress() { - String cid = - blueteethBindController.cid!.value; - String progressUrl = - "$serviceAddress$progressApi?id=$cid"; - requestWithLog( - logTitle: "设备校准进度", - method: MyHttpMethod.get, - queryUrl: progressUrl, - onSuccess: (res) { - final data = res.data; - double per = - (data['per'] ?? 0).toDouble(); - int currStep = - data['currStep'] ?? -1; - bool status = - data['status'] ?? false; - String tips = - data['statusText'] ?? ''; - - deviceCalibrationController - .tips.value = tips; - - progressNotifier.value = per; - if (!isSecondStep && per >= 20) { - progressNotifier.value = 100; - // 第一步完成:仅 per >= 100 - pollingTimer?.cancel(); - TopSlideNotification.show(context, - text: tips); - deviceCalibrationController - .process.value = 1; - deviceCalibrationController - .bed_calibration.value = 1; - - deviceCalibrationController - .updateAll(); - } - - if (isSecondStep && - per >= 100 && - currStep == 5 && - status == true) { - // 第二步完成:per >= 100 && currStep == 5 && status == true - flag = 0; - pollingTimer?.cancel(); - TopSlideNotification.show(context, - text: "设备校准完成".tr); - // 可在这里执行校准完成后的业务逻辑更新 - deviceCalibrationController - .bed_calibration.value = 1; - deviceCalibrationController - .position_calibration - .value = 1; - deviceCalibrationController - .process.value = 1; - deviceCalibrationController - .complete = true; - deviceCalibrationController - .updateAll(); - } - }, - onFailure: (res) { - pollingTimer?.cancel(); - failureNotifier.value = true; - TopSlideNotification.show( - context, - text: res.msg ?? "服务器.失败".tr, - textColor: themeController - .currentColor.sc9, - ); - }, - ); - } - - // 初始调用一次 - requestCalibrationProgress(); - - // 开始轮询 - pollingTimer = Timer.periodic( - Duration(seconds: 2), (_) { - requestCalibrationProgress(); - }); - - // 显示进度弹窗 - showProgressDialog(context, - progressNotifier, failureNotifier); - }, - onFailure: (res) { - TopSlideNotification.show( - context, - text: res.msg ?? "服务器.失败".tr, - textColor: - themeController.currentColor.sc9, - ); - }, - ); - }, onCancel: () { - return; - }); - } else { - flag = 1; - BlueteethBindController - blueteethBindController = Get.find(); - String serviceAddress = - "https://caibration.he-info.cn"; - String calibrationApi = - ServiceConstant.start_calibration; - String progressApi = - ServiceConstant.calibration_process; - - String queryUrl = - "$serviceAddress$calibrationApi"; - - final ValueNotifier progressNotifier = - ValueNotifier(0.0); - final ValueNotifier failureNotifier = - ValueNotifier(false); - Timer? pollingTimer; - - Map data = { - "macA": blueteethBindController - .currentDeviceMac!.value, - }; - - // 是否是二次点击(有cid表示进行第二阶段) - bool isSecondStep = blueteethBindController - .cid?.value.isNotEmpty ?? - false; - - if (isSecondStep) { - data["id"] = - blueteethBindController.cid!.value; - } - - // 发起校准请求 - requestWithLog( - logTitle: "设备校准", - method: MyHttpMethod.post, - queryUrl: queryUrl, - data: data, - onSuccess: (res) { - if (!isSecondStep) { - // 保存第一次获取的 cid - String cid = res.rawResponse.data['cid']; - blueteethBindController.cid!.value = cid; - } - - void requestCalibrationProgress() { - String cid = + if (isSecondStep) { + data["id"] = blueteethBindController.cid!.value; - String progressUrl = - "$serviceAddress$progressApi?id=$cid"; - requestWithLog( - logTitle: "设备校准进度", - method: MyHttpMethod.get, - queryUrl: progressUrl, - onSuccess: (res) { - final data = res.data; - double per = - (data['per'] ?? 0).toDouble(); - int currStep = data['currStep'] ?? -1; - bool status = data['status'] ?? false; - String tips = - data['statusText'] ?? ''; - - deviceCalibrationController - .tips.value = tips; - - progressNotifier.value = per; - if (!isSecondStep && per >= 20) { - progressNotifier.value = 100; - // 第一步完成:仅 per >= 100 - pollingTimer?.cancel(); - TopSlideNotification.show(context, - text: tips); - deviceCalibrationController - .process.value = 1; - deviceCalibrationController - .bed_calibration.value = 1; - - deviceCalibrationController - .updateAll(); - } - - if (isSecondStep && - per >= 100 && - currStep == 5 && - status == true) { - // 第二步完成:per >= 100 && currStep == 5 && status == true - pollingTimer?.cancel(); - TopSlideNotification.show(context, - text: "设备校准完成".tr); - // 可在这里执行校准完成后的业务逻辑更新 - deviceCalibrationController - .bed_calibration.value = 1; - deviceCalibrationController - .position_calibration.value = 1; - deviceCalibrationController - .process.value = 1; - deviceCalibrationController - .complete = true; - deviceCalibrationController - .updateAll(); - } - }, - onFailure: (res) { - pollingTimer?.cancel(); - failureNotifier.value = true; - TopSlideNotification.show( - context, - text: res.msg ?? "服务器.失败".tr, - textColor: themeController - .currentColor.sc9, - ); - }, - ); } - // 初始调用一次 - requestCalibrationProgress(); - - // 开始轮询 - pollingTimer = Timer.periodic( - Duration(seconds: 2), (_) { - requestCalibrationProgress(); - }); - - // 显示进度弹窗 - showProgressDialog(context, - progressNotifier, failureNotifier); - }, - onFailure: (res) { - TopSlideNotification.show( - context, - text: res.msg ?? "服务器.失败".tr, - textColor: - themeController.currentColor.sc9, + // 发起校准请求 + requestWithLog( + logTitle: "设备校准", + method: MyHttpMethod.post, + queryUrl: queryUrl, + data: data, + onSuccess: (res) { + if (!isSecondStep) { + // 保存第一次获取的 cid + String cid = + res.rawResponse.data['cid']; + blueteethBindController.cid!.value = + cid; + } + _startPollingProgress(serviceAddress, + progressApi, isSecondStep); + }, + onFailure: (res) { + deviceCalibrationController.flag.value = + 0; + blueteethBindController.cid!.value = ""; + blueteethBindController.updateAll(); + failureNotifier.value = true; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: + themeController.currentColor.sc9, + ); + }, ); - }, - ); - } - }, + } else { + deviceCalibrationController.flag.value = 1; + progressNotifier.value = 0; + failureNotifier.value = false; + _pollingTimer?.cancel(); - colors: [ - themeController.currentColor.sc1, - themeController.currentColor.sc2, - ], - 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: FlutterFlowTheme.of(context) - .bodyMedium - .override( - //todo 颜色 - color: - themeController.currentColor.sc3, - fontFamily: 'Inter', - fontSize: AppConstants() - .normal_text_fontSize, - letterSpacing: 0.0, - ), + BlueteethBindController + blueteethBindController = Get.find(); + String serviceAddress = + "https://caibration.he-info.cn"; + String calibrationApi = + ServiceConstant.start_calibration; + String progressApi = + ServiceConstant.calibration_process; + + String queryUrl = + "$serviceAddress$calibrationApi"; + + Map data = { + "macA": blueteethBindController + .currentDeviceMac!.value, + }; + + // 是否是二次点击(有cid表示进行第二阶段) + bool isSecondStep = blueteethBindController + .cid?.value.isNotEmpty ?? + false; + + if (isSecondStep) { + data["id"] = + blueteethBindController.cid!.value; + } else { + data["cancel"] = true; + } + + // 发起校准请求 + requestWithLog( + logTitle: "设备校准", + method: MyHttpMethod.post, + queryUrl: queryUrl, + data: data, + onSuccess: (res) { + if (!isSecondStep) { + // 保存第一次获取的 cid + String cid = + res.rawResponse.data['cid']; + blueteethBindController.cid!.value = + cid; + } + _startPollingProgress(serviceAddress, + progressApi, isSecondStep); + }, + onFailure: (res) { + deviceCalibrationController.flag.value = + 0; + blueteethBindController.cid!.value = ""; + blueteethBindController.updateAll(); + _pollingTimer?.cancel(); + failureNotifier.value = true; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: + themeController.currentColor.sc9, + ); + }, + ); + } + }, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + child: Container( + width: bodySize.maxWidth, + height: + MediaQuery.sizeOf(context).height * 0.055, + constraints: BoxConstraints( + minWidth: 500.rpx, + minHeight: 90.rpx, ), - ].divide(SizedBox( - width: 17.rpx, - )), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Obx(() { + if (deviceCalibrationController + .flag.value == + 0) { + return Text( + '开始校准'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + color: themeController + .currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ); + } + if (deviceCalibrationController + .flag.value == + 1) { + deviceCalibrationController + .statusContext.value = ""; + return Text( + '开始校准'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + color: themeController + .currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ); + } + if (deviceCalibrationController + .flag.value == + 2) { + return Text( + '重新校准'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + color: themeController + .currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ); + } + return Container(); + }), + ].divide(SizedBox( + width: 17.rpx, + )), + ), + ), ), - ), - ), - ), + ); + } + return Container(); + }), ], ), ), @@ -915,17 +838,16 @@ class _CalibrationPageState extends State { ), onWillPop: () async { bool exit = false; - if (flag != 0) { + if (deviceCalibrationController.flag.value != 2) { showConfirmDialog(context, Container(), "校准未完成提示".tr, onConfirm: () async { exit = true; - await Get.toNamed("/personPage"); - print("object"); + // await Get.toNamed("/personPage"); + // print("object"); deviceCalibrationController.process.value = 0; deviceCalibrationController.bed_calibration.value = 0; deviceCalibrationController.position_calibration.value = 0; blueteethBindController.cid!.value = ""; - deviceCalibrationController.complete = false; }, onCancel: () { exit = false; }); @@ -935,4 +857,169 @@ class _CalibrationPageState extends State { return exit; }); } + + void _startPollingProgress( + String serviceAddress, String progressApi, bool isSecondStep) { + // 立即请求一次 + _requestProgress(serviceAddress, progressApi, isSecondStep); + + // 设置定时器每2秒请求一次 + _pollingTimer = Timer.periodic(Duration(seconds: 1), (_) { + _requestProgress(serviceAddress, progressApi, isSecondStep); + }); + } + + void _requestProgress( + String serviceAddress, String progressApi, bool isSecondStep) { + String cid = blueteethBindController.cid!.value; + String progressUrl = "$serviceAddress$progressApi?id=$cid"; + + requestWithLog( + logTitle: "设备校准进度", + method: MyHttpMethod.get, + queryUrl: progressUrl, + onSuccess: (res) { + final data = res.data; + double per = (data['per'] ?? 0).toDouble(); + int currStep = data['currStep'] ?? -1; + String tips = data['statusText'] ?? ''; + try { + if (data['mattress'] != null) { + deviceCalibrationController.inBedTips.value = + data['mattress']['inBed']; + deviceCalibrationController.motionTips.value = + data['mattress']['bm']; + } + } catch (e) { + print(e); + } + + if (data['status'] == null) { + //当前进程执行中,执行倒计时 + if (data['cd'] != null) { + int cd = data['cd'] ?? 0; + deviceCalibrationController.cd.value = cd; + deviceCalibrationController.statusContext.value = ""; + } + } else { + if (data['status'] == true) { + //当前步骤执行成功 + deviceCalibrationController.tips.value = ""; + deviceCalibrationController.cd.value = 10000; + if (isSecondStep) { + deviceCalibrationController.statusContext.value = + data['statusText']; + deviceCalibrationController.updateAll(); + } + } else { + deviceCalibrationController.statusContext.value = ""; + //当前步骤执行失败 + deviceCalibrationController.bed_calibration.value == 0; + _pollingTimer?.cancel(); + blueteethBindController.cid?.value = ""; + deviceCalibrationController.process.value = 0; + deviceCalibrationController.flag.value = 0; + deviceCalibrationController.tips.value = ""; + deviceCalibrationController.cd.value = 10000; + deviceCalibrationController.updateAll(); + TopSlideNotification.show( + context, + text: tips, + textColor: themeController.currentColor.sc9, + ); + return; + } + } + bool status = data['status'] ?? false; + + // 更新进度 + progressNotifier.value = per; + if (per != 100 && per != 20) { + deviceCalibrationController.tips.value = tips; + } else { + deviceCalibrationController.tips.value = ""; + } + deviceCalibrationController.updateAll(); + + if (!isSecondStep && per >= 20) { + // 第一步完成 + _pollingTimer?.cancel(); + progressNotifier.value = 100; + TopSlideNotification.show(context, text: tips); + deviceCalibrationController.process.value = 1; + deviceCalibrationController.bed_calibration.value = 1; + deviceCalibrationController.flag.value = 0; // 重置标志允许再次点击 + } else if (isSecondStep && per >= 100 && currStep == 5 && status) { + // 第二步完成 + _pollingTimer?.cancel(); + TopSlideNotification.show(context, text: "设备校准完成".tr); + deviceCalibrationController.bed_calibration.value = 1; + deviceCalibrationController.position_calibration.value = 1; + deviceCalibrationController.process.value = 1; + deviceCalibrationController.flag.value = 2; + progressNotifier.value = 0; // 重置进度条 + failureNotifier.value = false; // 重置失败状态 + } + }, + onFailure: (res) { + deviceCalibrationController.flag.value = 0; + _pollingTimer?.cancel(); + blueteethBindController.cid!.value = ""; + failureNotifier.value = true; + deviceCalibrationController.flag.value = 0; + deviceCalibrationController.cd.value = 10000; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: themeController.currentColor.sc9, + ); + }, + ); + } + + getInBedMontion() { + if (deviceCalibrationController.cd.value == 10000) { + return Container(); + } + + if (deviceCalibrationController.process.value == 1) { + if (deviceCalibrationController.inBedTips.value == 0) { + return Text( + "请校准人员保持在床状态".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc9), + ); + } + } else { + if (deviceCalibrationController.inBedTips.value != 0) { + return Text( + "请校准人员暂时离开床铺".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc9), + ); + } + } + + return Container(); + } + + getBodyMontion() { + if (deviceCalibrationController.cd.value == 10000) { + return Container(); + } + if (deviceCalibrationController.process.value == 1) { + if (deviceCalibrationController.motionTips.value != 0) { + return Text( + "请保持身体静止".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc9), + ); + } + } + + return Container(); + } } diff --git a/lib/pages/device_bind/device_calibration_copy.dart b/lib/pages/device_bind/device_calibration_copy.dart new file mode 100644 index 0000000..a94585f --- /dev/null +++ b/lib/pages/device_bind/device_calibration_copy.dart @@ -0,0 +1,926 @@ +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/ServiceConstant.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/common/util/requestWithLog.dart'; +import 'package:vbvs_app/component/tool/ClickableContainer.dart'; +import 'package:vbvs_app/component/tool/CustomCard.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/device_calibration_controller.dart'; +import 'package:vbvs_app/pages/common/selectDialog.dart'; +import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart'; + +class CalibrationPage extends StatefulWidget { + int? type; //1.绑定时 2.绑定后 + CalibrationPage({super.key, required this.type}); + + @override + State createState() => _CalibrationPageState(); +} + +class _CalibrationPageState extends State { + DeviceCalibrationController deviceCalibrationController = Get.find(); + BlueteethBindController blueteethBindController = Get.find(); + + bool exit = false; + @override + void initState() { + super.initState(); + deviceCalibrationController.process.value = 0; + deviceCalibrationController.bed_calibration.value = 0; + deviceCalibrationController.position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + } + + @override + void dispose() { + blueteethBindController.cid!.value = ""; + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + child: LayoutBuilder( + builder: (context, bodySize) => GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/img/bgNoImg.png'), + fit: BoxFit.fill, + ), + ), + child: Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: themeController.currentColor.sc17, + automaticallyImplyLeading: false, + iconTheme: + IconThemeData(color: themeController.currentColor.sc3), + titleSpacing: 0, + title: Container( + width: double.infinity, + height: 180.rpx, + child: Stack( + alignment: Alignment.center, + children: [ + Text( + '设备校准'.tr, + style: TextStyle( + fontFamily: 'Readex Pro', + color: themeController.currentColor.sc3, + letterSpacing: 0, + fontSize: 30.rpx, + ), + ), + Positioned( + left: 0, + child: returnIconButtomAddCallback(() { + if (deviceCalibrationController.flag.value != 2) { + try { + showConfirmDialog( + context, Container(), "校准未完成提示".tr, + onConfirm: () async { + exit = true; + if (widget.type == 2) { + Get.back(); + return; + } + await Get.toNamed("/personPage"); + print("object"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + }, onCancel: () { + exit = false; + }); + } catch (e) { + print(e); + } + } else { + exit = true; + } + if (exit) { + Get.back(); + } + }, enableBack: exit), + ), + Positioned( + right: 20.rpx, + child: CustomCard( + borderRadius: 20.rpx, + onTap: () async { + if (deviceCalibrationController.flag.value != 2) { + showConfirmDialog( + context, Container(), "校准未完成提示".tr, + onConfirm: () async { + await Get.toNamed("/personPage"); + print("object"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + }, onCancel: () {}); + } else { + await Get.toNamed("/personPage"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + } + }, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + child: Container( + width: 130.rpx, + height: 60.rpx, + alignment: Alignment.center, + padding: EdgeInsetsDirectional.fromSTEB( + 16.rpx, 0, 16.rpx, 0), + child: Text( + '下一步'.tr, + style: TextStyle( + fontFamily: 'Inter Tight', + color: themeController.currentColor.sc3, + letterSpacing: 0.0, + ), + ), + ), + ), + ), + ], + ), + ), + actions: [], + centerTitle: false, + ), + body: SafeArea( + top: true, + // child: Container(), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0.rpx), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.rpx, 30.rpx, 0, 0), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: themeController.currentColor.sc5, + borderRadius: BorderRadius.circular(16.rpx), + ), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 10.rpx, 20.rpx, 34.rpx, 20.rpx), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: + themeController.currentColor.sc21, + borderRadius: 0, // 可按需设置圆角 + padding: EdgeInsets.symmetric( + vertical: 10.rpx), // 可自定义内边距 + onTap: () { + // deviceCalibrationController.process.value = 0; + // deviceCalibrationController.updateAll(); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Obx(() { + return Visibility( + maintainState: true, + maintainAnimation: true, + maintainSize: true, + visible: + deviceCalibrationController + .process.value == + 0, + child: SvgPicture.asset( + 'assets/img/icon/select_arrow.svg', + width: 17.rpx, + height: 17.rpx, + color: themeController + .currentColor.sc9, + ), + ); + }), + SizedBox(width: 8.rpx), + Text( + '离床校准'.tr, + style: TextStyle( + fontSize: 30.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ], + ), + Obx(() { + return Text( + deviceCalibrationController + .bed_calibration + .value == + 0 + ? '未完成'.tr + : "已完成".tr, + style: TextStyle( + fontSize: 26.rpx, + letterSpacing: 0.0, + color: deviceCalibrationController + .bed_calibration + .value == + 0 + ? themeController + .currentColor.sc3 + : themeController + .currentColor.sc1, + ), + ); + }), + ], + ), + ), + SizedBox(height: 41.rpx), + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: + themeController.currentColor.sc21, + borderRadius: 0, // 可根据需要设为圆角 + padding: EdgeInsets.symmetric( + vertical: 10.rpx), // 可根据需要调整上下内边距 + onTap: () { + // deviceCalibrationController.process.value = 1; + // deviceCalibrationController.updateAll(); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Obx(() { + return Visibility( + maintainState: true, + maintainAnimation: true, + maintainSize: true, + visible: + deviceCalibrationController + .process.value == + 1, + child: SvgPicture.asset( + 'assets/img/icon/select_arrow.svg', + width: 17.rpx, + height: 17.rpx, + color: themeController + .currentColor.sc9, + ), + ); + }), + SizedBox(width: 8.rpx), + Text( + '位置校准'.tr, + style: TextStyle( + fontSize: 30.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ], + ), + Obx(() { + return Text( + deviceCalibrationController + .position_calibration + .value == + 0 + ? '未完成'.tr + : "已完成".tr, + style: TextStyle( + fontSize: 26.rpx, + letterSpacing: 0.0, + color: deviceCalibrationController + .position_calibration + .value == + 0 + ? themeController + .currentColor.sc3 + : themeController + .currentColor.sc1, + ), + ); + }), + ], + ), + ), + ], + ), + ), + ), + ), + Obx(() { + return Expanded( + child: SizedBox( + width: double.infinity, + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 55.rpx, 100.rpx, 0), + child: Stack( + clipBehavior: Clip.none, + children: [ + Container( + width: MediaQuery.sizeOf(context).width * + 0.65, + height: + MediaQuery.sizeOf(context).height * + 0.3, + child: Stack( + children: [ + // Image.asset( + // deviceCalibrationController + // .bed_type.value == + // 0 + // ? "assets/img/single_pillow.png" + // : "assets/img/double_pillow.png", + // width: double.infinity, + // height: double.infinity, + // fit: BoxFit.contain, + // ), + Image.asset( + deviceCalibrationController + .process.value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1 + ? (deviceCalibrationController + .bed_type.value == + 0 + ? "assets/img/single_person.png" + : "assets/img/double_person.png") + : (deviceCalibrationController + .bed_type.value == + 0 + ? "assets/img/single_pillow.png" + : "assets/img/double_pillow.png"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.contain, + ), + + // 床头文字 + Positioned( + top: 23.rpx, + left: (MediaQuery.sizeOf(context) + .width * + 0.65) / + 2 - + 26.rpx, + child: Text( + '床头'.tr, + style: TextStyle( + fontSize: 26.rpx, + color: themeController + .currentColor.sc4, + ), + ), + ), + ], + ), + ), + Obx(() { + final double centerLeft = + (bodySize.maxWidth * 0.56) / 2; + if (deviceCalibrationController + .bed_type.value == + 0 && + deviceCalibrationController + .process.value == + 1) { + //单人床位置校准 + return Positioned( + top: -40.rpx, + left: centerLeft - 0.rpx, + child: Container( + width: bodySize.maxWidth * 0.087, + height: bodySize.maxHeight * 0.06, + constraints: BoxConstraints( + minWidth: 65.rpx, + minHeight: 76.rpx, + ), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'assets/img/tip_arrow.gif'), + fit: BoxFit.cover, + ), + ), + ), + ); + } + if (deviceCalibrationController + .bed_type.value == + 1 && + deviceCalibrationController + .process.value == + 1) { + //双人人床位置校准 + return Positioned( + top: -40.rpx, + left: (MediaQuery.sizeOf(context) + .width * + 0.65) * + 0.22 - + 0.rpx, + child: Container( + width: bodySize.maxWidth * 0.087, + height: bodySize.maxHeight * 0.06, + constraints: BoxConstraints( + minWidth: 65.rpx, + minHeight: 76.rpx, + ), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'assets/img/tip_arrow.gif'), + fit: BoxFit.cover, + ), + ), + ), + ); + } + + return Container(); + }), + Positioned( + top: MediaQuery.sizeOf(context).height * + 0.3 + + 82.rpx, + left: 0, + right: 0, + child: Obx(() { + return Column( + children: [ + Text( + (deviceCalibrationController + .process + .value == + 0 && + deviceCalibrationController + .bed_calibration + .value == + 1) || + (deviceCalibrationController + .process + .value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1) + ? '校准完成'.tr + : deviceCalibrationController + .process.value == + 0 + ? '离床校准提示'.tr + : '位置校准提示'.tr, + style: TextStyle( + fontSize: 38.rpx, + letterSpacing: 0.0, + color: ((deviceCalibrationController + .process + .value == + 0 && + deviceCalibrationController + .bed_calibration + .value == + 1) || + (deviceCalibrationController + .process + .value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1)) + ? themeController + .currentColor.sc1 + : themeController + .currentColor.sc9, + ), + ), + ], + ); + }), + ), + ], + ), + ), + ), + ); + }), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 0.rpx, 100.rpx, 60.rpx), + child: CustomCard( + borderRadius: + AppConstants().button_container_radius, // 圆角半径 + onTap: () async { + if (deviceCalibrationController.flag.value == 2) { + showConfirmDialog( + context, Container(), "校准已经完成,是否重新开始校准?", + onConfirm: () { + deviceCalibrationController.flag.value = 1; + BlueteethBindController + blueteethBindController = Get.find(); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + + String serviceAddress = + "https://caibration.he-info.cn"; + String calibrationApi = + ServiceConstant.start_calibration; + String progressApi = + ServiceConstant.calibration_process; + + String queryUrl = + "$serviceAddress$calibrationApi"; + + final ValueNotifier progressNotifier = + ValueNotifier(0.0); + final ValueNotifier failureNotifier = + ValueNotifier(false); + Timer? pollingTimer; + + Map data = { + "macA": blueteethBindController + .currentDeviceMac!.value, + }; + + // 是否是二次点击(有cid表示进行第二阶段) + bool isSecondStep = blueteethBindController + .cid?.value.isNotEmpty ?? + false; + + if (isSecondStep) { + data["id"] = + blueteethBindController.cid!.value; + } + + // 发起校准请求 + requestWithLog( + logTitle: "设备校准", + method: MyHttpMethod.post, + queryUrl: queryUrl, + data: data, + onSuccess: (res) { + if (!isSecondStep) { + // 保存第一次获取的 cid + String cid = + res.rawResponse.data['cid']; + blueteethBindController.cid!.value = + cid; + } + + void requestCalibrationProgress() { + String cid = + blueteethBindController.cid!.value; + String progressUrl = + "$serviceAddress$progressApi?id=$cid"; + requestWithLog( + logTitle: "设备校准进度", + method: MyHttpMethod.get, + queryUrl: progressUrl, + onSuccess: (res) { + final data = res.data; + double per = + (data['per'] ?? 0).toDouble(); + int currStep = + data['currStep'] ?? -1; + bool status = + data['status'] ?? false; + String tips = + data['statusText'] ?? ''; + + deviceCalibrationController + .tips.value = tips; + + progressNotifier.value = per; + if (!isSecondStep && per >= 20) { + progressNotifier.value = 100; + // 第一步完成:仅 per >= 100 + pollingTimer?.cancel(); + TopSlideNotification.show(context, + text: tips); + deviceCalibrationController + .process.value = 1; + deviceCalibrationController + .bed_calibration.value = 1; + + deviceCalibrationController + .updateAll(); + } + + if (isSecondStep && + per >= 100 && + currStep == 5 && + status == true) { + // 第二步完成:per >= 100 && currStep == 5 && status == true + deviceCalibrationController + .flag.value = 2; + pollingTimer?.cancel(); + TopSlideNotification.show(context, + text: "设备校准完成".tr); + // 可在这里执行校准完成后的业务逻辑更新 + deviceCalibrationController + .bed_calibration.value = 1; + deviceCalibrationController + .position_calibration + .value = 1; + deviceCalibrationController + .process.value = 1; + + deviceCalibrationController + .updateAll(); + } + }, + onFailure: (res) { + pollingTimer?.cancel(); + failureNotifier.value = true; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: themeController + .currentColor.sc9, + ); + }, + ); + } + + // 初始调用一次 + requestCalibrationProgress(); + + // 开始轮询 + pollingTimer = Timer.periodic( + Duration(seconds: 2), (_) { + requestCalibrationProgress(); + }); + + // 显示进度弹窗 + showProgressDialog(context, + progressNotifier, failureNotifier); + }, + onFailure: (res) { + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: + themeController.currentColor.sc9, + ); + }, + ); + }, onCancel: () { + return; + }); + } else { + deviceCalibrationController.flag.value = 1; + BlueteethBindController + blueteethBindController = Get.find(); + String serviceAddress = + "https://caibration.he-info.cn"; + String calibrationApi = + ServiceConstant.start_calibration; + String progressApi = + ServiceConstant.calibration_process; + + String queryUrl = + "$serviceAddress$calibrationApi"; + + final ValueNotifier progressNotifier = + ValueNotifier(0.0); + final ValueNotifier failureNotifier = + ValueNotifier(false); + Timer? pollingTimer; + + Map data = { + "macA": blueteethBindController + .currentDeviceMac!.value, + }; + + // 是否是二次点击(有cid表示进行第二阶段) + bool isSecondStep = blueteethBindController + .cid?.value.isNotEmpty ?? + false; + + if (isSecondStep) { + data["id"] = + blueteethBindController.cid!.value; + } + + // 发起校准请求 + requestWithLog( + logTitle: "设备校准", + method: MyHttpMethod.post, + queryUrl: queryUrl, + data: data, + onSuccess: (res) { + if (!isSecondStep) { + // 保存第一次获取的 cid + String cid = res.rawResponse.data['cid']; + blueteethBindController.cid!.value = cid; + } + + void requestCalibrationProgress() { + String cid = + blueteethBindController.cid!.value; + String progressUrl = + "$serviceAddress$progressApi?id=$cid"; + requestWithLog( + logTitle: "设备校准进度", + method: MyHttpMethod.get, + queryUrl: progressUrl, + onSuccess: (res) { + final data = res.data; + double per = + (data['per'] ?? 0).toDouble(); + int currStep = data['currStep'] ?? -1; + bool status = data['status'] ?? false; + String tips = + data['statusText'] ?? ''; + + deviceCalibrationController + .tips.value = tips; + + progressNotifier.value = per; + if (!isSecondStep && per >= 20) { + progressNotifier.value = 100; + // 第一步完成:仅 per >= 100 + pollingTimer?.cancel(); + TopSlideNotification.show(context, + text: tips); + deviceCalibrationController + .process.value = 1; + deviceCalibrationController + .bed_calibration.value = 1; + + deviceCalibrationController + .updateAll(); + } + + if (isSecondStep && + per >= 100 && + currStep == 5 && + status == true) { + // 第二步完成:per >= 100 && currStep == 5 && status == true + pollingTimer?.cancel(); + TopSlideNotification.show(context, + text: "设备校准完成".tr); + // 可在这里执行校准完成后的业务逻辑更新 + deviceCalibrationController + .bed_calibration.value = 1; + deviceCalibrationController + .position_calibration.value = 1; + deviceCalibrationController + .process.value = 1; + deviceCalibrationController + .flag.value = 2; + deviceCalibrationController + .updateAll(); + } + }, + onFailure: (res) { + pollingTimer?.cancel(); + failureNotifier.value = true; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: themeController + .currentColor.sc9, + ); + }, + ); + } + + // 初始调用一次 + requestCalibrationProgress(); + + // 开始轮询 + pollingTimer = Timer.periodic( + Duration(seconds: 2), (_) { + requestCalibrationProgress(); + }); + + // 显示进度弹窗 + showProgressDialog(context, + progressNotifier, failureNotifier); + }, + onFailure: (res) { + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: + themeController.currentColor.sc9, + ); + }, + ); + } + }, + + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + 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: FlutterFlowTheme.of(context) + .bodyMedium + .override( + //todo 颜色 + color: + themeController.currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ), + ].divide(SizedBox( + width: 17.rpx, + )), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ), + onWillPop: () async { + bool exit = false; + if (deviceCalibrationController.flag.value != 2) { + showConfirmDialog(context, Container(), "校准未完成提示".tr, + onConfirm: () async { + exit = true; + // await Get.toNamed("/personPage"); + // print("object"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController.bed_calibration.value = 0; + deviceCalibrationController.position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + }, onCancel: () { + exit = false; + }); + } else { + exit = true; + } + return exit; + }); + } +} diff --git a/lib/pages/device_bind/device_calibration_person.dart b/lib/pages/device_bind/device_calibration_person.dart new file mode 100644 index 0000000..84c2075 --- /dev/null +++ b/lib/pages/device_bind/device_calibration_person.dart @@ -0,0 +1,1027 @@ +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/ServiceConstant.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/common/util/requestWithLog.dart'; +import 'package:vbvs_app/component/tool/ClickableContainer.dart'; +import 'package:vbvs_app/component/tool/CustomCard.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/device_calibration_controller.dart'; +import 'package:vbvs_app/pages/device_bind/componnet/CalibrationProgressWidget.dart'; +import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart'; + +class CalibrationPersonPage extends StatefulWidget { + int? type; //1.绑定时 2.绑定后 + CalibrationPersonPage({super.key, required this.type}); + + @override + State createState() => _CalibrationPersonPageState(); +} + +class _CalibrationPersonPageState extends State { + DeviceCalibrationController deviceCalibrationController = Get.find(); + BlueteethBindController blueteethBindController = Get.find(); + final ValueNotifier progressNotifier = ValueNotifier(0.0); + final ValueNotifier failureNotifier = ValueNotifier(false); + Timer? _pollingTimer; + + bool exit = false; + @override + void initState() { + super.initState(); + deviceCalibrationController.process.value = 0; + deviceCalibrationController.cd.value = 10000; + deviceCalibrationController.flag.value = 0; + deviceCalibrationController.bed_calibration.value = 0; + deviceCalibrationController.position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + deviceCalibrationController.motionTips.value = 0; + deviceCalibrationController.inBedTips.value = 0; + deviceCalibrationController.statusContext.value = ""; + } + + @override + void dispose() { + _pollingTimer?.cancel(); + blueteethBindController.cid!.value = ""; + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + child: LayoutBuilder( + builder: (context, bodySize) => GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/img/bgNoImg.png'), + fit: BoxFit.fill, + ), + ), + child: Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: themeController.currentColor.sc17, + automaticallyImplyLeading: false, + iconTheme: + IconThemeData(color: themeController.currentColor.sc3), + titleSpacing: 0, + title: Container( + width: double.infinity, + height: 180.rpx, + child: Stack( + alignment: Alignment.center, + children: [ + Text( + '设备校准'.tr, + style: TextStyle( + fontFamily: 'Readex Pro', + color: themeController.currentColor.sc3, + letterSpacing: 0, + fontSize: 30.rpx, + ), + ), + Positioned( + left: 0, + child: returnIconButtomAddCallback(() { + if (deviceCalibrationController.flag.value != 2) { + try { + showConfirmDialog( + context, Container(), "校准未完成提示".tr, + onConfirm: () async { + exit = true; + if (widget.type == 2) { + Get.back(); + return; + } + await Get.toNamed("/personPage"); + print("object"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + }, onCancel: () { + exit = false; + }); + } catch (e) { + print(e); + } + } else { + exit = true; + } + if (exit) { + Get.back(); + } + }, enableBack: exit), + ), + Positioned( + right: 20.rpx, + child: CustomCard( + borderRadius: 20.rpx, + onTap: () async { + if (deviceCalibrationController.flag.value != 2) { + showConfirmDialog( + context, Container(), "校准未完成提示".tr, + onConfirm: () async { + Get.back(); + print("object"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + }, onCancel: () {}); + } else { + Get.back(); + deviceCalibrationController.process.value = 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + } + }, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + child: Container( + width: 130.rpx, + height: 60.rpx, + alignment: Alignment.center, + padding: EdgeInsetsDirectional.fromSTEB( + 16.rpx, 0, 16.rpx, 0), + child: Text( + '完成'.tr, + style: TextStyle( + fontFamily: 'Inter Tight', + color: themeController.currentColor.sc3, + letterSpacing: 0.0, + ), + ), + ), + ), + ), + ], + ), + ), + actions: [], + centerTitle: false, + ), + body: SafeArea( + top: true, + // child: Container(), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 0.rpx), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.rpx, 30.rpx, 0, 0), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: themeController.currentColor.sc5, + borderRadius: BorderRadius.circular(16.rpx), + ), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 10.rpx, 20.rpx, 34.rpx, 20.rpx), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: + themeController.currentColor.sc21, + borderRadius: 0, // 可按需设置圆角 + padding: EdgeInsets.symmetric( + vertical: 10.rpx), // 可自定义内边距 + onTap: () { + // deviceCalibrationController.process.value = 0; + // deviceCalibrationController.updateAll(); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Obx(() { + return Visibility( + maintainState: true, + maintainAnimation: true, + maintainSize: true, + visible: + deviceCalibrationController + .process.value == + 0, + child: SvgPicture.asset( + 'assets/img/icon/select_arrow.svg', + width: 17.rpx, + height: 17.rpx, + color: themeController + .currentColor.sc9, + ), + ); + }), + SizedBox(width: 8.rpx), + Text( + '离床校准'.tr, + style: TextStyle( + fontSize: 30.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ], + ), + Obx(() { + return Text( + deviceCalibrationController + .bed_calibration + .value == + 0 + ? '未完成'.tr + : "已完成".tr, + style: TextStyle( + fontSize: 26.rpx, + letterSpacing: 0.0, + color: deviceCalibrationController + .bed_calibration + .value == + 0 + ? themeController + .currentColor.sc3 + : themeController + .currentColor.sc1, + ), + ); + }), + ], + ), + ), + SizedBox(height: 41.rpx), + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: + themeController.currentColor.sc21, + borderRadius: 0, // 可根据需要设为圆角 + padding: EdgeInsets.symmetric( + vertical: 10.rpx), // 可根据需要调整上下内边距 + onTap: () { + // deviceCalibrationController.process.value = 1; + // deviceCalibrationController.updateAll(); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Obx(() { + return Visibility( + maintainState: true, + maintainAnimation: true, + maintainSize: true, + visible: + deviceCalibrationController + .process.value == + 1, + child: SvgPicture.asset( + 'assets/img/icon/select_arrow.svg', + width: 17.rpx, + height: 17.rpx, + color: themeController + .currentColor.sc9, + ), + ); + }), + SizedBox(width: 8.rpx), + Text( + '位置校准'.tr, + style: TextStyle( + fontSize: 30.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ], + ), + Obx(() { + return Text( + deviceCalibrationController + .position_calibration + .value == + 0 + ? '未完成'.tr + : "已完成".tr, + style: TextStyle( + fontSize: 26.rpx, + letterSpacing: 0.0, + color: deviceCalibrationController + .position_calibration + .value == + 0 + ? themeController + .currentColor.sc3 + : themeController + .currentColor.sc1, + ), + ); + }), + ], + ), + ), + ], + ), + ), + ), + ), + Obx(() { + return Expanded( + child: SizedBox( + width: double.infinity, + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 55.rpx, 100.rpx, 0), + child: Stack( + clipBehavior: Clip.none, + children: [ + Container( + width: MediaQuery.sizeOf(context).width * + 0.65, + height: + MediaQuery.sizeOf(context).height * + 0.3, + child: Stack( + children: [ + Image.asset( + deviceCalibrationController + .process.value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1 + ? (deviceCalibrationController + .bed_type.value == + 0 + ? "assets/img/single_person.png" + : "assets/img/double_person.png") + : (deviceCalibrationController + .bed_type.value == + 0 + ? "assets/img/single_pillow.png" + : "assets/img/double_pillow.png"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.contain, + ), + + // 床头文字 + Positioned( + top: 23.rpx, + left: (MediaQuery.sizeOf(context) + .width * + 0.65) / + 2 - + 26.rpx, + child: Text( + '床头'.tr, + style: TextStyle( + fontSize: 26.rpx, + color: themeController + .currentColor.sc4, + ), + ), + ), + ], + ), + ), + Obx(() { + final double centerLeft = + (bodySize.maxWidth * 0.56) / 2; + if (deviceCalibrationController + .bed_type.value == + 0 && + deviceCalibrationController + .process.value == + 1) { + //单人床位置校准 + return Positioned( + top: -40.rpx, + left: centerLeft - 0.rpx, + child: Container( + width: bodySize.maxWidth * 0.087, + height: bodySize.maxHeight * 0.06, + constraints: BoxConstraints( + minWidth: 65.rpx, + minHeight: 76.rpx, + ), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'assets/img/tip_arrow.gif'), + fit: BoxFit.cover, + ), + ), + ), + ); + } + if (deviceCalibrationController + .bed_type.value == + 1 && + deviceCalibrationController + .process.value == + 1) { + //双人人床位置校准 + return Positioned( + top: -40.rpx, + left: (MediaQuery.sizeOf(context) + .width * + 0.65) * + 0.22 - + 0.rpx, + child: Container( + width: bodySize.maxWidth * 0.087, + height: bodySize.maxHeight * 0.06, + constraints: BoxConstraints( + minWidth: 65.rpx, + minHeight: 76.rpx, + ), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'assets/img/tip_arrow.gif'), + fit: BoxFit.cover, + ), + ), + ), + ); + } + + return Container(); + }), + Positioned( + top: MediaQuery.sizeOf(context).height * + 0.3 + + 82.rpx, + left: 0, + right: 0, + child: Obx(() { + return Column( + children: [ + getBodyMontion(), + SizedBox( + height: 10.rpx, + ), + getInBedMontion(), + SizedBox( + height: 10.rpx, + ), + Text( + (deviceCalibrationController + .cd.value == + 10000) + ? ((deviceCalibrationController + .process + .value == + 0 && + deviceCalibrationController + .bed_calibration + .value == + 1) || + (deviceCalibrationController + .process + .value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1) + ? (deviceCalibrationController + .flag.value == + 2 + ? '校准完成'.tr + : "校准失败".tr) + : deviceCalibrationController + .statusContext + .value + .isEmpty == + true + ? (deviceCalibrationController + .process + .value == + 0 + ? '离床校准提示'.tr + : '位置校准提示'.tr) + : deviceCalibrationController + .statusContext + .value) + : "${deviceCalibrationController.cd.value}" + + "s后超时".tr, + style: TextStyle( + fontSize: 38.rpx, + letterSpacing: 0.0, + color: ((deviceCalibrationController + .process + .value == + 0 && + deviceCalibrationController + .bed_calibration + .value == + 1) || + (deviceCalibrationController + .process + .value == + 1 && + deviceCalibrationController + .position_calibration + .value == + 1)) && + (deviceCalibrationController + .flag.value == + 2) + ? themeController + .currentColor.sc1 + : themeController + .currentColor.sc9, + ), + ), + ], + ); + }), + ), + ], + ), + ), + ), + ); + }), + Obx(() { + if (deviceCalibrationController.flag.value == 1) { + return Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 0.rpx, 100.rpx, 60.rpx), + child: CalibrationProgressWidget( + progressNotifier: progressNotifier, + failureNotifier: failureNotifier, + ), + ); + } + return Container(); + }), + Obx(() { + if (deviceCalibrationController.flag.value != 1) { + return Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 100.rpx, 0.rpx, 100.rpx, 60.rpx), + child: CustomCard( + borderRadius: AppConstants() + .button_container_radius, // 圆角半径 + onTap: () async { + if (deviceCalibrationController.flag.value == + 2) { + deviceCalibrationController + .statusContext.value = ""; + deviceCalibrationController.flag.value = 1; + progressNotifier.value = 0; + failureNotifier.value = false; + deviceCalibrationController.process.value = + 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + BlueteethBindController + blueteethBindController = Get.find(); + blueteethBindController.cid!.value = ""; + + deviceCalibrationController.process.value = + 0; + deviceCalibrationController + .bed_calibration.value = 0; + deviceCalibrationController + .position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + String serviceAddress = + "https://caibration.he-info.cn"; + String calibrationApi = + ServiceConstant.start_calibration; + String progressApi = + ServiceConstant.calibration_process; + + String queryUrl = + "$serviceAddress$calibrationApi"; + + Timer? pollingTimer; + + Map data = { + "macA": blueteethBindController + .currentDeviceMac!.value, + }; + + // 是否是二次点击(有cid表示进行第二阶段) + bool isSecondStep = blueteethBindController + .cid?.value.isNotEmpty ?? + false; + + if (isSecondStep) { + data["id"] = + blueteethBindController.cid!.value; + } + + // 发起校准请求 + requestWithLog( + logTitle: "设备校准", + method: MyHttpMethod.post, + queryUrl: queryUrl, + data: data, + onSuccess: (res) { + if (!isSecondStep) { + // 保存第一次获取的 cid + String cid = + res.rawResponse.data['cid']; + blueteethBindController.cid!.value = + cid; + } + _startPollingProgress(serviceAddress, + progressApi, isSecondStep); + }, + onFailure: (res) { + deviceCalibrationController.flag.value = + 0; + blueteethBindController.cid!.value = ""; + blueteethBindController.updateAll(); + failureNotifier.value = true; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: + themeController.currentColor.sc9, + ); + }, + ); + } else { + deviceCalibrationController.flag.value = 1; + progressNotifier.value = 0; + failureNotifier.value = false; + _pollingTimer?.cancel(); + + BlueteethBindController + blueteethBindController = Get.find(); + String serviceAddress = + "https://caibration.he-info.cn"; + String calibrationApi = + ServiceConstant.start_calibration; + String progressApi = + ServiceConstant.calibration_process; + + String queryUrl = + "$serviceAddress$calibrationApi"; + + Map data = { + "macA": blueteethBindController + .currentDeviceMac!.value, + }; + + // 是否是二次点击(有cid表示进行第二阶段) + bool isSecondStep = blueteethBindController + .cid?.value.isNotEmpty ?? + false; + + if (isSecondStep) { + data["id"] = + blueteethBindController.cid!.value; + } else { + data["cancel"] = true; + } + + // 发起校准请求 + requestWithLog( + logTitle: "设备校准", + method: MyHttpMethod.post, + queryUrl: queryUrl, + data: data, + onSuccess: (res) { + if (!isSecondStep) { + // 保存第一次获取的 cid + String cid = + res.rawResponse.data['cid']; + blueteethBindController.cid!.value = + cid; + } + _startPollingProgress(serviceAddress, + progressApi, isSecondStep); + }, + onFailure: (res) { + deviceCalibrationController.flag.value = + 0; + blueteethBindController.cid!.value = ""; + blueteethBindController.updateAll(); + _pollingTimer?.cancel(); + failureNotifier.value = true; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: + themeController.currentColor.sc9, + ); + }, + ); + } + }, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + 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: [ + Obx(() { + if (deviceCalibrationController + .flag.value == + 0) { + return Text( + '开始校准'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + color: themeController + .currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ); + } + if (deviceCalibrationController + .flag.value == + 1) { + deviceCalibrationController + .statusContext.value = ""; + return Text( + '开始校准'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + color: themeController + .currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ); + } + if (deviceCalibrationController + .flag.value == + 2) { + return Text( + '重新校准'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + color: themeController + .currentColor.sc3, + fontFamily: 'Inter', + fontSize: AppConstants() + .normal_text_fontSize, + letterSpacing: 0.0, + ), + ); + } + return Container(); + }), + ].divide(SizedBox( + width: 17.rpx, + )), + ), + ), + ), + ); + } + return Container(); + }), + ], + ), + ), + ), + ), + ), + ), + ), + onWillPop: () async { + bool exit = false; + if (deviceCalibrationController.flag.value != 2) { + showConfirmDialog(context, Container(), "校准未完成提示".tr, + onConfirm: () async { + exit = true; + // await Get.toNamed("/personPage"); + // print("object"); + deviceCalibrationController.process.value = 0; + deviceCalibrationController.bed_calibration.value = 0; + deviceCalibrationController.position_calibration.value = 0; + blueteethBindController.cid!.value = ""; + }, onCancel: () { + exit = false; + }); + } else { + exit = true; + } + return exit; + }); + } + + void _startPollingProgress( + String serviceAddress, String progressApi, bool isSecondStep) { + // 立即请求一次 + _requestProgress(serviceAddress, progressApi, isSecondStep); + + // 设置定时器每2秒请求一次 + _pollingTimer = Timer.periodic(Duration(seconds: 1), (_) { + _requestProgress(serviceAddress, progressApi, isSecondStep); + }); + } + + void _requestProgress( + String serviceAddress, String progressApi, bool isSecondStep) { + String cid = blueteethBindController.cid!.value; + String progressUrl = "$serviceAddress$progressApi?id=$cid"; + + requestWithLog( + logTitle: "设备校准进度", + method: MyHttpMethod.get, + queryUrl: progressUrl, + onSuccess: (res) { + final data = res.data; + double per = (data['per'] ?? 0).toDouble(); + int currStep = data['currStep'] ?? -1; + String tips = data['statusText'] ?? ''; + try { + if (data['mattress'] != null) { + deviceCalibrationController.inBedTips.value = + data['mattress']['inBed']; + deviceCalibrationController.motionTips.value = + data['mattress']['bm']; + } + } catch (e) { + print(e); + } + + if (data['status'] == null) { + //当前进程执行中,执行倒计时 + if (data['cd'] != null) { + int cd = data['cd'] ?? 0; + deviceCalibrationController.cd.value = cd; + deviceCalibrationController.statusContext.value = ""; + } + } else { + if (data['status'] == true) { + //当前步骤执行成功 + deviceCalibrationController.tips.value = ""; + deviceCalibrationController.cd.value = 10000; + if (isSecondStep) { + deviceCalibrationController.statusContext.value = + data['statusText']; + deviceCalibrationController.updateAll(); + } + } else { + deviceCalibrationController.statusContext.value = ""; + //当前步骤执行失败 + deviceCalibrationController.bed_calibration.value == 0; + _pollingTimer?.cancel(); + blueteethBindController.cid?.value = ""; + deviceCalibrationController.process.value = 0; + deviceCalibrationController.flag.value = 0; + deviceCalibrationController.tips.value = ""; + deviceCalibrationController.cd.value = 10000; + deviceCalibrationController.updateAll(); + TopSlideNotification.show( + context, + text: tips, + textColor: themeController.currentColor.sc9, + ); + return; + } + } + bool status = data['status'] ?? false; + + // 更新进度 + progressNotifier.value = per; + if (per != 100 && per != 20) { + deviceCalibrationController.tips.value = tips; + } else { + deviceCalibrationController.tips.value = ""; + } + deviceCalibrationController.updateAll(); + + if (!isSecondStep && per >= 20) { + // 第一步完成 + _pollingTimer?.cancel(); + progressNotifier.value = 100; + TopSlideNotification.show(context, text: tips); + deviceCalibrationController.process.value = 1; + deviceCalibrationController.bed_calibration.value = 1; + deviceCalibrationController.flag.value = 0; // 重置标志允许再次点击 + } else if (isSecondStep && per >= 100 && currStep == 5 && status) { + // 第二步完成 + _pollingTimer?.cancel(); + TopSlideNotification.show(context, text: "设备校准完成".tr); + deviceCalibrationController.bed_calibration.value = 1; + deviceCalibrationController.position_calibration.value = 1; + deviceCalibrationController.process.value = 1; + deviceCalibrationController.flag.value = 2; + progressNotifier.value = 0; // 重置进度条 + failureNotifier.value = false; // 重置失败状态 + } + }, + onFailure: (res) { + deviceCalibrationController.flag.value = 0; + _pollingTimer?.cancel(); + blueteethBindController.cid!.value = ""; + failureNotifier.value = true; + deviceCalibrationController.flag.value = 0; + deviceCalibrationController.cd.value = 10000; + TopSlideNotification.show( + context, + text: res.msg ?? "服务器.失败".tr, + textColor: themeController.currentColor.sc9, + ); + }, + ); + } + + getInBedMontion() { + if (deviceCalibrationController.cd.value == 10000) { + return Container(); + } + + if (deviceCalibrationController.process.value == 1) { + if (deviceCalibrationController.inBedTips.value == 0) { + return Text( + "请校准人员保持在床状态".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc9), + ); + } + } else { + if (deviceCalibrationController.inBedTips.value != 0) { + return Text( + "请校准人员暂时离开床铺".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc9), + ); + } + } + + return Container(); + } + + getBodyMontion() { + if (deviceCalibrationController.cd.value == 10000) { + return Container(); + } + if (deviceCalibrationController.process.value == 1) { + if (deviceCalibrationController.motionTips.value != 0) { + return Text( + "请保持身体静止".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc9), + ); + } + } + + return Container(); + } +} diff --git a/lib/pages/device_bind/wifi_page.dart b/lib/pages/device_bind/wifi_page.dart index e4b6a82..c3e2e4b 100644 --- a/lib/pages/device_bind/wifi_page.dart +++ b/lib/pages/device_bind/wifi_page.dart @@ -23,7 +23,7 @@ import 'package:vbvs_app/pages/device_bind/blueteeth_device_page.dart'; import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart'; class WifiPage extends StatefulWidget { - var type; + var type; //为空,首次绑定 不为空,从设备列表进入 WifiPage({super.key, required this.type}); @override @@ -41,88 +41,75 @@ class _WifiPageState extends State { @override void initState() { super.initState(); + blueteethBindController.netType.value = 0; blueteethBindController.connectStatus.value = 0; blueteethBindController.wifiList = [].obs; blueteethBindController.wifiStatus = 0.obs; blueteethBindController.connect_wifi.value = {}; blueteethBindController.selectWifi.value = {}; - if (widget.type != null) { - blueteethBindController.wifiStatus.value = - widget.type['status']['status']; - } - if (widget.type == null) { - THapp bledevice = blueteethBindController.currentDevice!; - bledevice.device.connect().then((Value) { - var res2 = bledevice.isConnected; - if (res2) { - // WidgetsBinding.instance.addPostFrameCallback((_) { - // TopSlideNotification.show( - // context, - // text: "蓝牙绑定.连接成功".tr, - // textColor: themeController.currentColor.sc2, - // ); - // }); - blueteethBindController.blueConnectFlag.value = 2; - blueteethBindController.currentDevice = bledevice; - if (lisObj != null) { - lisObj!.cancel(); + THapp bledevice = blueteethBindController.currentDevice!; + bledevice.device.connect().then((Value) { + var res2 = bledevice.isConnected; + if (res2) { + blueteethBindController.blueConnectFlag.value = 2; + blueteethBindController.currentDevice = bledevice; + if (lisObj != null) { + lisObj!.cancel(); + } + var aa; + lisObj = blueteethBindController.currentDevice!.statusStream + .listen((onData) async { + if (onData.status == BleEventType.recvLineLog) { + final line = onData.val; + print("[bleee]:" + line); } - var aa; - lisObj = blueteethBindController.currentDevice!.statusStream - .listen((onData) async { - if (onData.status == BleEventType.recvLineLog) { - final line = onData.val; - print("[bleee]:" + line); - } - if (onData.status == BleEventType.ready) { - aa = await getDeviceNetVersion( - blueteethBindController.currentDevice!, 10); - if (aa == "4g") { + if (onData.status == BleEventType.ready) { + aa = await getDeviceNetVersion( + blueteethBindController.currentDevice!, 2); + if (aa == "4g") { + TopSlideNotification.show( + context, + text: "4g设备配置wifi提示".tr, + textColor: themeController.currentColor.sc2, + ); + blueteethBindController.netType.value = 2; + blueteethBindController.connectStatus.value = 1; + blueteethBindController.updateAll(); + Future.delayed(const Duration(seconds: 1), () { + Get.toNamed("/calibrationPage", arguments: 1); + }); + } else if (aa == 'unknown') { + // TopSlideNotification.show( + // context, + // text: "获取设备网络类型失败".tr, + // textColor: themeController.currentColor.sc9, + // ); + blueteethBindController.netType.value = 3; + blueteethBindController.updateAll(); + WidgetsBinding.instance.addPostFrameCallback((_) { TopSlideNotification.show( context, - text: "4g设备配置wifi提示".tr, - textColor: themeController.currentColor.sc2, + text: "获取设备网络类型失败".tr, + textColor: themeController.currentColor.sc9, ); - blueteethBindController.connectStatus.value = 1; - blueteethBindController.updateAll(); - Future.delayed(const Duration(seconds: 1), () { - Get.toNamed("/calibrationPage", arguments: 1); - }); - } else if (aa == 'unknown') { - // TopSlideNotification.show( - // context, - // text: "获取设备网络类型失败".tr, - // textColor: themeController.currentColor.sc9, - // ); - WidgetsBinding.instance.addPostFrameCallback((_) { - TopSlideNotification.show( - context, - text: "获取设备网络类型失败".tr, - textColor: themeController.currentColor.sc9, - ); - }); - } else { - await initWifiStatusAndWifiList(); - } + }); + } else { + blueteethBindController.netType.value = 1; + blueteethBindController.updateAll(); + await initWifiStatusAndWifiList(); } - }); - } else { - WidgetsBinding.instance.addPostFrameCallback((_) { - TopSlideNotification.show( - context, - text: "连接失败".tr, - textColor: themeController.currentColor.sc9, - ); - }); - } - }); - } else { - blueteethBindController.blueConnectFlag.value = 0; - blueteethBindController.updateAll(); - dealWifi(widget.type['mac']).then((aa) { - print("object"); - }); - } + } + }); + } else { + WidgetsBinding.instance.addPostFrameCallback((_) { + TopSlideNotification.show( + context, + text: "连接失败".tr, + textColor: themeController.currentColor.sc9, + ); + }); + } + }); } @override @@ -180,36 +167,21 @@ class _WifiPageState extends State { ), if (widget.type == null) Obx(() { + if (blueteethBindController.netType.value == 0) { + return SizedBox( + width: 24.rpx, + height: 24.rpx, + child: CircularProgressIndicator( + strokeWidth: 1, + valueColor: AlwaysStoppedAnimation( + Colors.white), + ), + ); + } + if (blueteethBindController.connectStatus.value == - 0) { - return SizedBox( - width: 24.rpx, - height: 24.rpx, - child: CircularProgressIndicator( - strokeWidth: 1, - valueColor: AlwaysStoppedAnimation( - Colors.white), - ), - ); - } - return Container(); - }), - if (widget.type != null) - Obx(() { - if (blueteethBindController.blueConnectFlag.value == - 0) { - return SizedBox( - width: 24.rpx, - height: 24.rpx, - child: CircularProgressIndicator( - strokeWidth: 1, - valueColor: AlwaysStoppedAnimation( - Colors.white), - ), - ); - } - if (blueteethBindController.connectStatus.value == - 0&&blueteethBindController.blueConnectFlag.value ==0) { + 0 && + blueteethBindController.netType.value != 0) { return SizedBox( width: 24.rpx, height: 24.rpx, @@ -222,6 +194,7 @@ class _WifiPageState extends State { } return Container(); }), + ], ), @@ -230,35 +203,35 @@ class _WifiPageState extends State { left: 0, child: returnIconButtom, ), + if (widget.type == null) Positioned( right: 20.rpx, child: CustomCard( borderRadius: 20.rpx, onTap: () async { - // if (blueteethBindController.wifiStatus.value != 1) { - // TopSlideNotification.show( - // context, - // text: "wifi页.需配网".tr, - // textColor: themeController.currentColor.sc9, - // ); - // } else { - // Get.toNamed("/calibrationPage", arguments: 1); - // } - Get.toNamed("/calibrationPage", arguments: 1); + if (blueteethBindController.wifiStatus.value != 1) { + showConfirmDialog( + context, Container(), "未配置网络提示".tr, + onConfirm: () { + Get.toNamed("/calibrationPage", arguments: 1); + }, onCancel: () {}); + } else { + Get.toNamed("/calibrationPage", arguments: 1); + } }, colors: [ themeController.currentColor.sc1, themeController.currentColor.sc2, ], child: Container( - width: 100.rpx, + width: 130.rpx, height: 60.rpx, alignment: Alignment.center, padding: EdgeInsetsDirectional.fromSTEB( 16.rpx, 0, 16.rpx, 0), child: Text( - 'wifi页.跳过'.tr, + '下一步'.tr, style: FlutterFlowTheme.of(context) .titleSmall .override( @@ -270,6 +243,7 @@ class _WifiPageState extends State { ), ), ), + ], ), ), @@ -749,31 +723,71 @@ class _WifiPageState extends State { horizontal: 20.rpx, vertical: 10.rpx), borderRadius: 20.rpx, onTap: () async { - if ((blueteethBindController - .blueConnectFlag == - 0 || - blueteethBindController - .blueConnectFlag == - 1) && - widget.type != null) { - blueteethBindController - .blueConnectFlag.value = 0; - dealWifi(widget.type['mac']).then((aa) { - print("object"); - }); - return; - } blueteethBindController .connectStatus.value = 0; blueteethBindController.updateAll(); print("点击刷新"); - await initWifiList(); - TopSlideNotification.show( - context, - text: "获取wifi列表成功".tr, - textColor: - themeController.currentColor.sc2, - ); + if (blueteethBindController + .netType.value == + 0) { + return; + } + if (blueteethBindController + .netType.value == + 3) { + var aa = await getDeviceNetVersion( + blueteethBindController + .currentDevice!, + 0); + if (aa == "4g") { + TopSlideNotification.show( + context, + text: "4g设备配置wifi提示".tr, + textColor: themeController + .currentColor.sc2, + ); + blueteethBindController + .netType.value = 2; + blueteethBindController + .connectStatus.value = 1; + blueteethBindController.updateAll(); + Future.delayed( + const Duration(seconds: 1), () { + Get.toNamed("/calibrationPage", + arguments: 1); + }); + } else if (aa == 'unknown') { + // TopSlideNotification.show( + // context, + // text: "获取设备网络类型失败".tr, + // textColor: themeController.currentColor.sc9, + // ); + blueteethBindController + .netType.value = 3; + blueteethBindController.updateAll(); + WidgetsBinding.instance + .addPostFrameCallback((_) { + TopSlideNotification.show( + context, + text: "获取设备网络类型失败".tr, + textColor: themeController + .currentColor.sc9, + ); + }); + } else { + blueteethBindController + .netType.value = 1; + blueteethBindController.updateAll(); + await initWifiStatusAndWifiList(); + } + } + // await initWifiList(); + // TopSlideNotification.show( + // context, + // text: "获取wifi列表成功".tr, + // textColor: + // themeController.currentColor.sc2, + // ); }, child: Row( mainAxisSize: MainAxisSize.min, @@ -832,6 +846,8 @@ class _WifiPageState extends State { if (aa != null && aa is Map) { wifiStatus = true; blueteethBindController.connect_wifi.value = aa; + } else { + wifiStatus = false; } blueteethBindController.wifiStatus.value = wifiStatus == true ? 1 : 0; List wifiList = []; @@ -982,9 +998,6 @@ class _WifiPageState extends State { } Future dealWifi(String mac) async { - // bodyDeviceController.wifiMac = mac; - // Get.toNamed("/wifiPage", arguments: 2); - // return; final blueteethBindController = Get.find(); final themeController = Get.find(); @@ -1072,7 +1085,7 @@ class _WifiPageState extends State { } if (onData.status == BleEventType.ready) { aa = await getDeviceNetVersion( - blueteethBindController.currentDevice!, 1); + blueteethBindController.currentDevice!, 0); if (aa == "4g") { // TopSlideNotification.show( // Get.context!, @@ -1088,14 +1101,21 @@ class _WifiPageState extends State { Get.back(); }); return; + } else if (aa == 'unknown') { + blueteethBindController.netType.value = 3; + blueteethBindController.updateAll(); + WidgetsBinding.instance.addPostFrameCallback((_) { + TopSlideNotification.show( + context, + text: "获取设备网络类型失败".tr, + textColor: themeController.currentColor.sc9, + ); + }); } else { - // Get.toNamed("/wifiPage", arguments: 2); await initWifiStatusAndWifiList(); } } }); - - // Get.toNamed("/wifiPage", arguments: {bledevice}); } else { // Navigator.pop(context); TopSlideNotification.show( diff --git a/lib/pages/device_bind/wifi_page_person.dart b/lib/pages/device_bind/wifi_page_person.dart new file mode 100644 index 0000000..7630f9b --- /dev/null +++ b/lib/pages/device_bind/wifi_page_person.dart @@ -0,0 +1,1097 @@ +import 'dart:async'; + +import 'package:easydevice/easydevice.dart'; +import 'package:ef/ef.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:flutterflow_ui/flutterflow_ui.dart'; +import 'package:vbvs_app/common/color/appConstants.dart'; +import 'package:vbvs_app/common/util/FitTool.dart'; +import 'package:vbvs_app/common/util/MyUtils.dart'; +import 'package:vbvs_app/component/tool/ClickableContainer.dart'; +import 'package:vbvs_app/component/tool/CustomCard.dart'; +import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; +import 'package:vbvs_app/component/tool/cmd.dart'; +import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart'; +import 'package:vbvs_app/controller/main_bottom/global_controller.dart'; +import 'package:vbvs_app/controller/person/person_controller.dart'; +import 'package:vbvs_app/controller/theme_controller/ThemeController.dart'; +import 'package:vbvs_app/controller/user_info_controller.dart'; +import 'package:vbvs_app/model/BleDeviceData.dart'; +import 'package:vbvs_app/pages/device_bind/blueteeth_device_page.dart'; +import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart'; + +class WifiPagePerson extends StatefulWidget { + var type; + WifiPagePerson({super.key, required this.type}); + + @override + State createState() => _WifiPagePersonState(); +} + +class _WifiPagePersonState extends State { + GlobalController globalController = Get.find(); + UserInfoController userInfoController = Get.find(); + BlueteethBindController blueteethBindController = Get.find(); + PersonController personController = Get.find(); + ThemeController themeController = Get.find(); + var lisObj; + + @override + void initState() { + super.initState(); + blueteethBindController.netType.value = 0; + blueteethBindController.connectStatus.value = 0; + blueteethBindController.wifiList = [].obs; + blueteethBindController.wifiStatus = 0.obs; + blueteethBindController.connect_wifi.value = {}; + blueteethBindController.selectWifi.value = {}; + blueteethBindController.wifiStatus.value = widget.type['status']['status']; + blueteethBindController.blueConnectFlag.value = 0; + blueteethBindController.wifiConnectStatus.value = 1; + blueteethBindController.updateAll(); + dealWifi(widget.type['mac']).then((aa) { + print("object"); + }); + } + + @override + void dispose() { + super.dispose(); + if (lisObj != null) { + lisObj.cancel(); + } + blueteethBindController.currentDevice!.disconnect(); + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, bodySize) => GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/img/bgNoImg.png'), // 本地图片 + fit: BoxFit.fill, // 填满整个 Container + ), + ), + child: Scaffold( + backgroundColor: Colors.transparent, // 加上这一行 + appBar: AppBar( + backgroundColor: themeController.currentColor.sc17, + automaticallyImplyLeading: false, + iconTheme: IconThemeData(color: themeController.currentColor.sc3), + titleSpacing: 0, + // leading: returnIconButtom, + title: Container( + width: double.infinity, + height: 180.rpx, + child: Stack( + alignment: Alignment.center, + children: [ + /// 居中标题 + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'wifi页.标题'.tr, + style: + FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: 'Readex Pro', + color: themeController.currentColor.sc3, + letterSpacing: 0, + fontSize: 30.rpx, + ), + ), + SizedBox( + width: 14.rpx, + ), + Obx(() { + if (!blueteethBindController.bluetoothStatus.value) { + return Container(); + } + if (blueteethBindController.blueConnectFlag.value == + 0) { + return SizedBox( + width: 24.rpx, + height: 24.rpx, + child: CircularProgressIndicator( + strokeWidth: 1, + valueColor: + AlwaysStoppedAnimation(Colors.white), + ), + ); + } + if (blueteethBindController.netType.value == 0) { + return SizedBox( + width: 24.rpx, + height: 24.rpx, + child: CircularProgressIndicator( + strokeWidth: 1, + valueColor: + AlwaysStoppedAnimation(Colors.white), + ), + ); + } + if (blueteethBindController.wifiConnectStatus.value == + 0) { + return SizedBox( + width: 24.rpx, + height: 24.rpx, + child: CircularProgressIndicator( + strokeWidth: 1, + valueColor: + AlwaysStoppedAnimation(Colors.white), + ), + ); + } + return Container(); + }), + ], + ), + + /// 左边返回按钮 + Positioned( + left: 0, + child: returnIconButtom, + ), + Positioned( + right: 20.rpx, + child: CustomCard( + borderRadius: 20.rpx, + onTap: () async { + Get.back(); + }, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + child: Container( + width: 130.rpx, + height: 60.rpx, + alignment: Alignment.center, + padding: EdgeInsetsDirectional.fromSTEB( + 16.rpx, 0, 16.rpx, 0), + child: Text( + '完成'.tr, + style: FlutterFlowTheme.of(context) + .titleSmall + .override( + fontFamily: 'Inter Tight', + color: themeController.currentColor.sc3, + letterSpacing: 0.0, + ), + ), + ), + ), + ), + ], + ), + ), + + actions: [], + centerTitle: false, + ), + + body: SafeArea( + top: true, + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: + EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: Color(0xFF242835), + borderRadius: BorderRadius.circular(20.rpx), + ), + child: Column( + children: [ + Align( + alignment: AlignmentDirectional(0, 0), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 30.rpx, 30.rpx, 30.rpx), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "wifi页.WLAN".tr, + style: TextStyle( + color: themeController + .currentColor.sc3, + fontSize: AppConstants() + .title_text_fontSize, + ), + ), + Obx(() { + return Text( + blueteethBindController + .wifiStatus.value == + 0 + ? "wifi页.未连接".tr + : "wifi页.已连接".tr, + style: TextStyle( + color: blueteethBindController + .wifiStatus.value == + 0 + ? themeController + .currentColor.sc4 + : themeController + .currentColor.sc2, + fontSize: AppConstants() + .normal_text_fontSize, + ), + ); + }), + ], + ), + ), + ), + Obx(() { + if (blueteethBindController + .connect_wifi.value == + null || + blueteethBindController + .connect_wifi.value.isEmpty) { + return Container(); + } else { + return Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 30.rpx, 0.rpx, 30.rpx, 30.rpx), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + blueteethBindController.connect_wifi + .value['ssid'] ?? + '未命名'.tr, + style: TextStyle( + color: themeController + .currentColor.sc3, + fontSize: AppConstants() + .title_text_fontSize, + ), + ), + getWifiIconByRsso( + blueteethBindController + .connect_wifi.value), + ], + ), + ); + } + }) + ], + )), + ), + Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.rpx, 25.rpx, 0.rpx, 0.rpx), + child: 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, + decoration: BoxDecoration(), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + '可用WLAN'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 30.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ], + ), + Obx(() { + final sortedList = [ + ...blueteethBindController.wifiList.value + ]..sort((a, b) => b['rssi'] + .compareTo(a['rssi'])); // 按 rssi 倒序 + + return Column( + mainAxisSize: MainAxisSize.max, + children: sortedList + .map((wifiItem) => ClickableContainer( + backgroundColor: + Colors.transparent, + highlightColor: themeController + .currentColor.sc3, + padding: EdgeInsets.symmetric( + vertical: 0.rpx, + horizontal: 0.rpx), + borderRadius: 16.rpx, + onTap: () { + showWifiDialog( + 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: Obx(() { + return TextFormField( + onChanged: + (value) { + blueteethBindController + .model + .wifiPass = + value; + }, + autofocus: + false, + obscureText: + blueteethBindController + .model + .wifiPassShow, + decoration: + InputDecoration( + isDense: + true, + labelStyle: FlutterFlowTheme.of( + context) + .labelMedium + .override( + fontFamily: + 'Inter', + fontSize: + 26.rpx, + letterSpacing: + 0.0, + ), + hintText: + '蓝牙绑定.输入wifi密码' + .tr, + hintStyle: FlutterFlowTheme.of(context).labelMedium.override( + 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), + ), + errorBorder: + OutlineInputBorder( + borderSide: + BorderSide( + color: FlutterFlowTheme.of(context) + .error, + width: 1 + .rpx, + ), + borderRadius: + BorderRadius.circular( + 8.rpx), + ), + focusedErrorBorder: + OutlineInputBorder( + borderSide: + BorderSide( + color: FlutterFlowTheme.of(context) + .error, + width: 1 + .rpx, + ), + borderRadius: + BorderRadius.circular( + 8.rpx), + ), + filled: + false, + fillColor: FlutterFlowTheme.of( + context) + .secondaryBackground, + suffixIcon: + InkWell( + onTap: + () { + blueteethBindController + .model + .wifiPassShow = !blueteethBindController.model.wifiPassShow; + blueteethBindController + .updateAll(); + }, + focusNode: + FocusNode( + skipTraversal: true), + child: + Icon( + blueteethBindController.model.wifiPassShow + ? Icons.visibility_outlined + : Icons.visibility_off_outlined, + size: 30 + .rpx, + ), + ), + ), + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: + 'Inter', + fontSize: 26 + .rpx, + letterSpacing: + 0.0, + color: Colors + .black), + cursorColor: + themeController + .currentColor + .sc3, + ); + })), + ), + ), + wifiItem['ssid'] ?? + '未命名'.tr, + onConfirm: () async { + // showLoadingDialog( + // context); // 显示 loading + blueteethBindController + .selectWifi + .value = wifiItem; + bool flag = await sendWifiSetting( + wifiItem, + blueteethBindController + .model.wifiPass!, + blueteethBindController + .currentDevice!); + // Navigator.pop(context); + if (flag) { + // bool wifiStatus = + // await getWifiStatus( + // blueteethBindController + // .currentDevice!); + bool wifiStatus = false; + var aa = await getDeviceWifiStatus( + blueteethBindController + .currentDevice!, + 1); + blueteethBindController + .selectWifi + .value = {}; + if (aa != null && + aa is Map) { + wifiStatus = true; + blueteethBindController + .connect_wifi + .value = aa; + } else { + blueteethBindController + .connect_wifi + .value = {}; + } + blueteethBindController + .wifiStatus + .value = + wifiStatus == true + ? 1 + : 0; + blueteethBindController + .wifiStatus + .value = + wifiStatus == true + ? 1 + : 0; + if (wifiStatus) { + // Navigator.pop(context); + TopSlideNotification + .show( + context, + text: "wifi页.配网成功".tr, + textColor: + themeController + .currentColor + .sc2, + ); + blueteethBindController + .wifiStatus + .value = 1; + blueteethBindController + .updateAll(); + } else { + // Navigator.pop(context); + TopSlideNotification + .show( + context, + text: "wifi页.配网失败".tr, + textColor: + themeController + .currentColor + .sc9, + ); + blueteethBindController + .wifiStatus + .value = 0; + blueteethBindController + .updateAll(); + } + } else { + // Navigator.pop(context); + TopSlideNotification.show( + context, + text: "wifi页.配网失败".tr, + textColor: + themeController + .currentColor + .sc9, + ); + blueteethBindController + .wifiStatus.value = 0; + blueteethBindController + .updateAll(); + } + }); + }, + child: Row( + mainAxisSize: + MainAxisSize.max, + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + wifiItem['ssid'] ?? '', + style: FlutterFlowTheme + .of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 30.rpx, + letterSpacing: 0.0, + color: + themeController + .currentColor + .sc3, + ), + ), + if (blueteethBindController + .selectWifi.value == + wifiItem) + SizedBox( + width: 32.rpx, + height: 32.rpx, + child: + CircularProgressIndicator( + strokeWidth: 1, + valueColor: + AlwaysStoppedAnimation< + Color>( + Colors.white), + ), + ) + else + getWifiIconByRsso( + wifiItem), + ], + ), + )) + .toList() + .divide(SizedBox(height: 67.rpx)), + ); + }), + ClickableContainer( + backgroundColor: Colors.transparent, + highlightColor: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 20.rpx, vertical: 10.rpx), + borderRadius: 20.rpx, + onTap: () async { + //检测蓝牙开关 + var bluetoothState = + await FlutterBluePlus.isOn; + blueteethBindController.bluetoothStatus + .value = bluetoothState; + if (!bluetoothState) { + await _showBluetoothNotEnabledDialog(); + return; + } + //检测蓝牙连接 + if (blueteethBindController + .blueConnectFlag.value == + 0 || + blueteethBindController + .blueConnectFlag.value == + 1) { + blueteethBindController + .blueConnectFlag.value = 0; + dealWifi(widget.type['mac']).then((aa) { + print("object"); + }); + return; + } + + if (blueteethBindController + .netType.value == + 0) { + return; + } + blueteethBindController.netType.value = 0; + blueteethBindController.updateAll(); + var aa = await getDeviceNetVersion( + blueteethBindController + .currentDevice!, + 1); + if (aa == "4g") { + TopSlideNotification.show( + context, + text: "4g设备配置wifi提示".tr, + textColor: + themeController.currentColor.sc2, + ); + blueteethBindController.netType.value = + 2; + blueteethBindController + .connectStatus.value = 1; + blueteethBindController.updateAll(); + Future.delayed( + const Duration(seconds: 1), () { + Get.toNamed("/calibrationPage", + arguments: 1); + }); + } else if (aa == 'unknown') { + blueteethBindController.netType.value = + 3; + blueteethBindController.updateAll(); + WidgetsBinding.instance + .addPostFrameCallback((_) { + TopSlideNotification.show( + context, + text: "获取设备网络类型失败".tr, + textColor: themeController + .currentColor.sc9, + ); + }); + } else { + blueteethBindController.netType.value = + 1; + blueteethBindController.updateAll(); + await initWifiStatusAndWifiList(); + } + }, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Container( + width: 25.rpx, + height: 25.rpx, + decoration: BoxDecoration(), + child: SvgPicture.asset( + 'assets/img/icon/refresh.svg', + fit: BoxFit.cover, + color: Colors.white, // 图标固定白色 + ), + ), + Text( + '刷新'.tr, + style: FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: 'Inter', + fontSize: 30.rpx, + letterSpacing: 0.0, + color: themeController + .currentColor.sc3, + ), + ), + ].divide(SizedBox(width: 26.rpx)), + ), + ), + ].divide(SizedBox(height: 65.rpx)), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ), + ); + } + + Future initWifiStatusAndWifiList() async { + if (lisObj != null) { + lisObj!.cancel(); + } + bool wifiStatus = false; + var aa = + await getDeviceWifiStatus(blueteethBindController.currentDevice!, 0); + if (aa != null && aa is Map) { + wifiStatus = true; + blueteethBindController.connect_wifi.value = aa; + } else { + wifiStatus = false; + } + blueteethBindController.wifiStatus.value = wifiStatus == true ? 1 : 0; + List wifiList = []; + try { + final result = await getWifiList(blueteethBindController.currentDevice!); + blueteethBindController.wifiConnectStatus.value = 1; + blueteethBindController.updateAll(); + if (result is List) { + wifiList = result; + } + } catch (e) { + print("异常: $e"); + blueteethBindController.wifiConnectStatus.value = 0; + blueteethBindController.updateAll(); + } + if (wifiList.length > 0) { + blueteethBindController.connectStatus.value = 1; + blueteethBindController.updateAll(); + // Navigator.pop(context); + TopSlideNotification.show( + context, + text: "获取wifi列表成功".tr, + textColor: themeController.currentColor.sc2, + ); + blueteethBindController.wifiList.value = wifiList; + blueteethBindController.updateAll(); + } else { + // Navigator.pop(context); + + TopSlideNotification.show( + context, + text: "获取wifi列表失败".tr, + textColor: themeController.currentColor.sc9, + ); + } + lisObj = blueteethBindController.currentDevice!.statusStream + .listen((onData) async { + if (onData.status == BleEventType.recvLineLog) { + final line = onData.val; + print("[bleee]:" + line); + } + }); + } + + getWifiIconByRsso(wifiItem) { + int? rssi = int.tryParse(wifiItem['rssi'].toString()); + + if (rssi != null) { + if (rssi >= -30) { + return Container( + width: 40.rpx, + height: 40.rpx, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(shape: BoxShape.circle), + child: Image.asset("assets/img/wifi4.png"), + ); + } else if (rssi >= -45) { + return Container( + width: 40.rpx, + height: 40.rpx, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(shape: BoxShape.circle), + child: Image.asset("assets/img/wifi3.png"), + ); + } else if (rssi >= -60) { + return Container( + width: 40.rpx, + height: 40.rpx, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(shape: BoxShape.circle), + child: Image.asset("assets/img/wifi3.png"), + ); + } else { + return Container( + width: 40.rpx, + height: 40.rpx, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(shape: BoxShape.circle), + child: Image.asset("assets/img/wifi1.png"), + ); + } + } else { + // RSSI 无法解析时的默认显示 + return Container( + width: 40.rpx, + height: 40.rpx, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(shape: BoxShape.circle), + child: Image.asset("assets/img/wifi1.png"), + ); + } + } + + Future dealWifi(String mac) async { + final blueteethBindController = Get.find(); + final themeController = Get.find(); + + // 显示加载对话框 + // showLoadingDialog(Get.context!, title: "连接中...".tr); + + // 设置超时定时器 + Timer? timeoutTimer; + bool isConnected = false; + + try { + // 开始扫描蓝牙设备 + var bluetoothState = await FlutterBluePlus.isOn; + blueteethBindController.bluetoothStatus.value = bluetoothState; + blueteethBindController.updateAll(); + if (!bluetoothState) { + await _showBluetoothNotEnabledDialog(); + return; + } + await FlutterBluePlus.startScan(timeout: Duration(seconds: 10)); + + // 设置超时(20秒) + timeoutTimer = Timer(Duration(seconds: 20), () { + try { + if (!isConnected) { + blueteethBindController.blueConnectFlag.value = 1; + blueteethBindController.updateAll(); + // Navigator.of(context).pop(); // 先关闭 dialog + WidgetsBinding.instance.addPostFrameCallback((_) { + TopSlideNotification.show( + context, + text: "设备连接超时,请重试".tr, + textColor: themeController.currentColor.sc9, + ); + }); + FlutterBluePlus.stopScan(); + } + } catch (e) { + print(e); + } + }); + + // 监听扫描结果 + StreamSubscription>? scanSubscription; + scanSubscription = FlutterBluePlus.scanResults.listen((results) async { + // 过滤出符合条件的设备 + ScanResult? targetDevice; + + for (var r in results) { + if (r.advertisementData.manufacturerData.containsKey(0xFFED)) { + List rawData = r.advertisementData.manufacturerData[0xFFED]!; + BleDeviceData deviceData = parseBleData(rawData); + String deviceMac = + deviceData.deviceId.replaceAll(':', '').toLowerCase(); + if (deviceMac == mac.toLowerCase()) { + targetDevice = r; + break; + } + } + } + + if (targetDevice != null && !isConnected) { + isConnected = true; + FlutterBluePlus.stopScan(); + scanSubscription?.cancel(); + timeoutTimer?.cancel(); + + try { + // 连接设备 + // await targetDevice.device.connect(); + THapp bledevice = THapp(device: targetDevice.device); + await bledevice.device.connect(); + var res2 = bledevice.isConnected; + if (res2) { + // Navigator.pop(context); + blueteethBindController.blueConnectFlag.value = 2; + TopSlideNotification.show( + context, + text: "蓝牙绑定.连接成功".tr, + textColor: themeController.currentColor.sc2, + ); + blueteethBindController.currentDevice = bledevice; + if (lisObj != null) { + lisObj!.cancel(); + } + var aa; + lisObj = blueteethBindController.currentDevice!.statusStream + .listen((onData) async { + if (onData.status == BleEventType.recvLineLog) { + final line = onData.val; + print("[bleee]:" + line); + } + if (onData.status == BleEventType.ready) { + aa = await getDeviceNetVersion( + blueteethBindController.currentDevice!, 0); + if (aa == "4g") { + // TopSlideNotification.show( + // Get.context!, + // text: "4g设备配置wifi提示".tr, + // textColor: themeController.currentColor.sc9, + // ); + blueteethBindController.netType.value = 2; + blueteethBindController.updateAll(); + // WidgetsBinding.instance.addPostFrameCallback((_) { + // TopSlideNotification.show( + // context, + // text: "4g设备配置wifi提示".tr, + // textColor: themeController.currentColor.sc9, + // ); + // // Get.back(); + // }); + await showTipDialog( + context, + Text( + "4g设备配置wifi提示".tr, + style: TextStyle( + color: themeController.currentColor.sc3, + fontSize: AppConstants().title_text_fontSize), + )); + // return; + } else if (aa == 'unknown') { + blueteethBindController.netType.value = 3; + blueteethBindController.updateAll(); + blueteethBindController.updateAll(); + WidgetsBinding.instance.addPostFrameCallback((_) { + TopSlideNotification.show( + context, + text: "获取设备网络类型失败".tr, + textColor: themeController.currentColor.sc9, + ); + }); + } else { + blueteethBindController.netType.value = 1; + blueteethBindController.updateAll(); + // TopSlideNotification.show( + // context, + // text: "当前设备为wifi网络设备".tr, + // textColor: themeController.currentColor.sc9, + // ); + blueteethBindController.wifiConnectStatus.value = 0; + blueteethBindController.updateAll(); + await initWifiStatusAndWifiList(); + } + } + }); + } else { + // Navigator.pop(context); + TopSlideNotification.show( + context, + text: "蓝牙绑定.连接失败".tr, + textColor: themeController.currentColor.sc9, + ); + } + } catch (e) { + // Navigator.of(Get.context!).pop(); // 关闭加载对话框 + TopSlideNotification.show( + Get.context!, + text: "设备连接失败".tr, + textColor: themeController.currentColor.sc9, + ); + } + } + }); + + // 等待扫描完成 + await Future.delayed(Duration(seconds: 20)); + } catch (e) { + timeoutTimer?.cancel(); + Navigator.of(Get.context!).pop(); // 关闭加载对话框 + TopSlideNotification.show( + Get.context!, + text: "扫描过程中发生错误".tr, + textColor: themeController.currentColor.sc9, + ); + } finally { + timeoutTimer?.cancel(); + await FlutterBluePlus.stopScan(); + } + } + + _showBluetoothNotEnabledDialog() async { + await showTipDialog( + context, + Column( + children: [ + Text( + "蓝牙未开启".tr, + style: TextStyle( + fontSize: AppConstants().title_text_fontSize, + color: themeController.currentColor.sc3), + ), + SizedBox( + height: 20.rpx, + ), + Text( + "请先打开蓝牙在进行设备扫描".tr, + style: TextStyle( + fontSize: AppConstants().normal_text_fontSize, + color: themeController.currentColor.sc3), + ), + ], + )); + } +} diff --git a/lib/pages/person/person_page.dart b/lib/pages/person/person_page.dart index c7c7d3a..9ecd134 100644 --- a/lib/pages/person/person_page.dart +++ b/lib/pages/person/person_page.dart @@ -50,6 +50,7 @@ class _EPageState extends State { personController.gender.value = 1; personController.birthday.value = ""; personController.weight.value = ""; + personController.height.value = ""; personController.dateTime = null; } @@ -66,6 +67,7 @@ class _EPageState extends State { ), ), child: Scaffold( + resizeToAvoidBottomInset: false, backgroundColor: Colors.transparent, // 加上这一行 appBar: AppBar( backgroundColor: themeController.currentColor.sc17, @@ -107,8 +109,7 @@ class _EPageState extends State { if (apiRespons.code == HttpStatusCodes.ok) { TopSlideNotification.show(context, text: apiRespons.msg!); - Get.offAllNamed("/bindDeviceSuccess"); - // Get.toNamed("/wifiPage"); + Get.offNamed("/bindDeviceSuccess"); } else { TopSlideNotification.show(context, text: apiRespons.msg!, diff --git a/lib/pages/person/update_person_page.dart b/lib/pages/person/update_person_page.dart index e7496df..375ea16 100644 --- a/lib/pages/person/update_person_page.dart +++ b/lib/pages/person/update_person_page.dart @@ -126,7 +126,7 @@ class _UpdatePageState extends State { padding: EdgeInsetsDirectional.fromSTEB( 16.rpx, 0, 16.rpx, 0), child: Text( - '人员资料.保存'.tr, + '完成'.tr, style: FlutterFlowTheme.of(context) .titleSmall .override( diff --git a/lib/pages/repair/apply_repair_success.dart b/lib/pages/repair/apply_repair_success.dart index a0395ce..cedd38f 100644 --- a/lib/pages/repair/apply_repair_success.dart +++ b/lib/pages/repair/apply_repair_success.dart @@ -77,7 +77,7 @@ class _ApplyRepairSuccessState extends State { left: 40.rpx, child: ClickableContainer( onTap: () { - Get.offAllNamed("/mianPageBottomChange"); + Get.offNamed("/mianPageBottomChange"); }, backgroundColor: Colors.transparent, highlightColor: Colors @@ -252,7 +252,7 @@ class _ApplyRepairSuccessState extends State { borderRadius: AppConstants().button_container_radius, // 圆角半径 onTap: () { - Get.offAllNamed("/mianPageBottomChange"); + Get.offNamed("/mianPageBottomChange"); }, colors: [ // 渐变色 diff --git a/lib/pages/sleep_report/chart/LineChartByRange.dart b/lib/pages/sleep_report/chart/LineChartByRange.dart index 37ffa44..a2ed657 100644 --- a/lib/pages/sleep_report/chart/LineChartByRange.dart +++ b/lib/pages/sleep_report/chart/LineChartByRange.dart @@ -1,3 +1,4 @@ +import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; @@ -480,7 +481,7 @@ class _LineChartByRangeState extends State { child: Text( '${DateFormat('HH:mm').format(DateTime.fromMillisecondsSinceEpoch(selectedData!['startTime']))} - ' '${DateFormat('HH:mm').format(DateTime.fromMillisecondsSinceEpoch(selectedData!['endTime']))}\n' - '次数: ${selectedData!['times']}', + "时长".tr+ ' ${selectedData!['times']}', style: TextStyle( fontSize: 18.rpx, color: Colors.white, diff --git a/lib/pages/sleep_report/chart/SnoreChart.dart b/lib/pages/sleep_report/chart/SnoreChart.dart index f6295ce..055cbad 100644 --- a/lib/pages/sleep_report/chart/SnoreChart.dart +++ b/lib/pages/sleep_report/chart/SnoreChart.dart @@ -24,7 +24,7 @@ class BarData { }); } -class BarChartWidget extends StatelessWidget { +class BarChartWidget extends StatefulWidget { final List data; final int startTime; // 毫秒时间戳 final int endTime; // 毫秒时间戳 @@ -40,18 +40,59 @@ class BarChartWidget extends StatelessWidget { this.yStepCount = 5, }); + @override + State createState() => _BarChartWidgetState(); +} + +class _BarChartWidgetState extends State { + BarData? selectedBar; + + void _handleTapOrDrag(Offset localPosition, Size size) { + final chartWidth = size.width - 30.rpx; + final totalDuration = widget.endTime - widget.startTime; + + for (final d in widget.data) { + final left = + ((d.st - widget.startTime) / totalDuration) * chartWidth + 30.rpx; + final right = + ((d.et - widget.startTime) / totalDuration) * chartWidth + 30.rpx; + if (localPosition.dx >= left && localPosition.dx <= right) { + setState(() { + selectedBar = d; + }); + return; + } + } + + setState(() { + selectedBar = null; + }); + } + @override Widget build(BuildContext context) { - return CustomPaint( - size: Size(double.infinity, 500.rpx), - painter: BarChartPainter( - data, - startTime, - endTime, - maxYValue: maxYValue, - yStepCount: yStepCount, - ), - ); + return LayoutBuilder(builder: (context, constraints) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (details) => + _handleTapOrDrag(details.localPosition, constraints.biggest), + onPanUpdate: (details) => + _handleTapOrDrag(details.localPosition, constraints.biggest), + onTapDown: (details) => + _handleTapOrDrag(details.localPosition, constraints.biggest), + child: CustomPaint( + size: Size(double.infinity, 500.rpx), + painter: BarChartPainter( + widget.data, + widget.startTime, + widget.endTime, + maxYValue: widget.maxYValue, + yStepCount: widget.yStepCount, + selectedBar: selectedBar, + ), + ), + ); + }); } } @@ -61,11 +102,11 @@ class BarChartPainter extends CustomPainter { final int endTime; final double maxYValue; final int yStepCount; + final BarData? selectedBar; - final double topPadding = 0; // 控制顶部间距 - final double bottomPadding = 0; // 控制底部间距 + final double topPadding = 0; + final double bottomPadding = 0; final double leftPadding = 30.rpx; - // final double labelHeight = 50.rpx; BarChartPainter( this.data, @@ -73,6 +114,7 @@ class BarChartPainter extends CustomPainter { this.endTime, { required this.maxYValue, this.yStepCount = 5, + this.selectedBar, }); @override @@ -84,19 +126,11 @@ class BarChartPainter extends CustomPainter { final textPainter = TextPainter(textDirection: ui.TextDirection.ltr); final stepValue = maxYValue / yStepCount; - // 绘制 Y 轴刻度线和文字 + // Y轴刻度 for (int i = 0; i <= yStepCount; i++) { final value = stepValue * i; final y = topPadding + chartHeight - (value / maxYValue) * chartHeight; - // 横线 - // canvas.drawLine( - // Offset(leftPadding, y), - // Offset(size.width, y), - // Paint() - // ..color = Colors.grey.withOpacity(0.3) - // ..strokeWidth = 0.5, - // ); final dashPaint = Paint() ..color = Colors.grey.withOpacity(0.5) ..strokeWidth = 0.5; @@ -104,7 +138,6 @@ class BarChartPainter extends CustomPainter { drawDashedLine( canvas, Offset(leftPadding, y), Offset(size.width, y), dashPaint); - // Y轴刻度文字 textPainter.text = TextSpan( text: value.toStringAsFixed(0), style: TextStyle( @@ -114,25 +147,21 @@ class BarChartPainter extends CustomPainter { ); textPainter.layout(); textPainter.paint( - canvas, - Offset( - leftPadding - textPainter.width - 4, y - textPainter.height / 2)); + canvas, + Offset(leftPadding - textPainter.width - 4, y - textPainter.height / 2), + ); } - // X轴时间刻度 + // X轴刻度 final startDate = DateTime.fromMillisecondsSinceEpoch(startTime); final endDate = DateTime.fromMillisecondsSinceEpoch(endTime); final hourStep = const Duration(hours: 1); - final xPaint = Paint()..color = Colors.grey; - final xAxisY = topPadding + chartHeight; - // 绘制整点小时刻度 for (DateTime t = startDate; t.isBefore(endDate); t = t.add(hourStep)) { final x = ((t.millisecondsSinceEpoch - startTime) / totalDuration) * chartWidth + leftPadding; - final timeLabel = (t == startDate || t == endDate) ? DateFormat('HH:mm').format(t) : DateFormat('h').format(t); @@ -148,7 +177,7 @@ class BarChartPainter extends CustomPainter { textPainter.paint(canvas, Offset(x - textPainter.width / 2, xAxisY + 4)); } - // ✅ 强制绘制结束时间刻度(确保显示) + // 额外终点标签 final endX = ((endTime - startTime) / totalDuration) * chartWidth + leftPadding; final endLabel = DateFormat('HH:mm').format(endDate); @@ -162,7 +191,12 @@ class BarChartPainter extends CustomPainter { textPainter.layout(); textPainter.paint(canvas, Offset(endX - textPainter.width / 2, xAxisY + 4)); - // 绘制柱子 + // 柱子绘制 & 提示信息缓存 + Offset? tipOffset; + Size? tipSize; + String? tipText; + Color tipColor = Colors.black; + for (final d in data) { final left = ((d.st - startTime) / totalDuration) * chartWidth + leftPadding; @@ -172,9 +206,60 @@ class BarChartPainter extends CustomPainter { final top = topPadding + chartHeight - barHeight; final barPaint = Paint()..color = d.color; - canvas.drawRect( - Rect.fromLTRB(left, top, right, topPadding + chartHeight), barPaint); + Rect.fromLTRB(left, top, right, topPadding + chartHeight), + barPaint, + ); + + // 缓存 tip 信息 + if (selectedBar == d) { + tipText = + '${d.name}\n${d.value.toStringAsFixed(1)}\n${MyUtils.formatToHHmm(d.st)}'; + + final tp = TextPainter( + text: TextSpan( + text: tipText, + style: TextStyle(fontSize: 16.rpx, color: Colors.white), + ), + textAlign: TextAlign.center, + textDirection: ui.TextDirection.ltr, + ); + tp.layout(); + + final tipWidth = tp.width + 20.rpx; + final tipHeight = tp.height + 10.rpx; + final tipLeft = left + (right - left) / 2 - tipWidth / 2; + final tipTop = top - tipHeight - 10.rpx; + + tipOffset = Offset(tipLeft, tipTop); + tipSize = Size(tipWidth, tipHeight); + tipColor = Colors.black.withOpacity(0.8); + } + } + + // 绘制 tip(在柱子之上) + if (tipText != null && tipOffset != null && tipSize != null) { + final rect = RRect.fromRectAndRadius( + Rect.fromLTWH( + tipOffset.dx, tipOffset.dy, tipSize.width, tipSize.height), + Radius.circular(8.rpx), + ); + final tipBgPaint = Paint()..color = tipColor; + canvas.drawRRect(rect, tipBgPaint); + + final tipTextPainter = TextPainter( + text: TextSpan( + text: tipText, + style: TextStyle(fontSize: 16.rpx, color: Colors.white), + ), + textAlign: TextAlign.center, + textDirection: ui.TextDirection.ltr, + ); + tipTextPainter.layout(); + tipTextPainter.paint( + canvas, + Offset(tipOffset.dx + 10.rpx, tipOffset.dy + 5.rpx), + ); } } diff --git a/lib/pages/sleep_report/chart/TimeSeriesChart.dart b/lib/pages/sleep_report/chart/TimeSeriesChart.dart index f124217..f3ce82f 100644 --- a/lib/pages/sleep_report/chart/TimeSeriesChart.dart +++ b/lib/pages/sleep_report/chart/TimeSeriesChart.dart @@ -1,243 +1,57 @@ import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; +import 'package:vbvs_app/common/color/appConstants.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; -import 'dart:math'; - import 'package:vbvs_app/common/util/MyUtils.dart'; +class TimeSeriesPoint { + final int timestamp; + final double value; + TimeSeriesPoint(this.timestamp, this.value); +} + class TimeSeriesChart extends StatelessWidget { - final int startTime; + final int startTime; // 毫秒时间戳 final int endTime; final double yMin; final double yMax; final List dataPoints; - final double actYMin; - final double actYMax; - TimeSeriesChart({ + const TimeSeriesChart({ + Key? key, required this.startTime, required this.endTime, required this.yMin, required this.yMax, required this.dataPoints, - required this.actYMin, - required this.actYMax, - }); - - @override - Widget build(BuildContext context) { - final midValue = (yMax + yMin) / 2; - final xLabels = _generateXLabels(); - - // Prepare spots and segments - List spots = []; - List lineColors = []; - - for (int i = 0; i < dataPoints.length; i++) { - final point = dataPoints[i]; - final xValue = _convertTimeToXValue(point.timestamp); - final yValue = point.value; - - spots.add(FlSpot(xValue, yValue)); - if (yValue >= yMin && yValue <= yMax) { - lineColors.add(Colors.green); // Color for points within range - } else { - lineColors.add(Colors.red); // Color for points outside range - } - } - - return AspectRatio( - aspectRatio: 2, - child: LineChart( - LineChartData( - lineTouchData: LineTouchData( - touchTooltipData: LineTouchTooltipData( - getTooltipItems: (List touchedSpots) { - return touchedSpots.map((spot) { - final time = DateTime.fromMillisecondsSinceEpoch( - _convertXValueToTime(spot.x), - ); - return LineTooltipItem( - '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}\n${spot.y.toStringAsFixed(0)}', - const TextStyle(color: Colors.black), - ); - }).toList(); - }, - ), - ), - gridData: FlGridData( - show: true, - drawVerticalLine: false, - getDrawingHorizontalLine: (value) { - if (value == 0) { - return FlLine( - color: themeController.currentColor.sc4, - strokeWidth: 1, - ); - } else if (value == yMin) { - return FlLine( - color: themeController.currentColor.sc9, - strokeWidth: 1, - dashArray: [5, 5], - ); - } else if (value == yMax) { - return FlLine( - color: themeController.currentColor.sc9, - strokeWidth: 1, - dashArray: [5, 5], - ); - } else if (value == midValue) { - return FlLine( - color: themeController.currentColor.sc4, - strokeWidth: 1, - dashArray: [5, 5], - ); - } - return FlLine( - color: Colors.grey.withOpacity(0.1), - strokeWidth: 1, - ); - }, - ), - titlesData: FlTitlesData( - show: true, - rightTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - topTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 30, - getTitlesWidget: (value, meta) { - final index = value.toInt(); - if (index >= 0 && index < xLabels.length) { - return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - xLabels[index].label, - style: TextStyle( - fontSize: 10, - color: Colors.grey, - ), - ), - ); - } - return const Text(''); - }, - ), - ), - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) { - if (value == 0) { - return Padding( - padding: EdgeInsets.only(right: 14.rpx), - child: Text( - value.toStringAsFixed(0), - style: TextStyle( - fontSize: 18.rpx, - color: themeController.currentColor.sc4, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.right, - ), - ); - } else if (value == yMin) { - return Padding( - padding: EdgeInsets.only(right: 14.rpx), - child: Text( - "${actYMin.toStringAsFixed(0)}", - style: TextStyle( - fontSize: 18.rpx, - color: themeController.currentColor.sc4, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.right, - ), - ); - } else if (value == midValue) { - return Padding( - padding: EdgeInsets.only(right: 14.rpx), - child: Text( - "${((actYMax + actYMin) / 2).toStringAsFixed(0)}", - // "${midValue}", - style: TextStyle( - fontSize: 18.rpx, - color: themeController.currentColor.sc4, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.right, - ), - ); - } else if (value == yMax) { - return Padding( - padding: EdgeInsets.only(right: 14.rpx), - child: Text( - "${actYMax.toStringAsFixed(0)}", - style: TextStyle( - fontSize: 18.rpx, - color: themeController.currentColor.sc4, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.right, - ), - ); - } - return const Text(''); - }, - reservedSize: 40, - ), - ), - ), - borderData: FlBorderData( - show: false, - border: Border.all(color: Colors.grey.withOpacity(0.3)), - ), - minX: 0, - maxX: xLabels.length - 1, - minY: min(0, yMin) - (yMax - yMin) * 0.2, - maxY: yMax + (yMax - yMin) * 0.2, - lineBarsData: [ - LineChartBarData( - spots: spots, - isCurved: false, - color: themeController.currentColor.sc2, - barWidth: 2, - isStrokeCapRound: true, - dotData: FlDotData(show: false), // Disable dots - belowBarData: BarAreaData(show: false), - ), - ], - ), - ), - ); - } + }) : super(key: key); + // X轴刻度数据 List _generateXLabels() { final labels = []; final startDate = DateTime.fromMillisecondsSinceEpoch(startTime); final endDate = DateTime.fromMillisecondsSinceEpoch(endTime); + // 第一个刻度,原始 startTime,HH:mm格式 labels.add(XLabel( time: startTime, label: '${startDate.hour.toString().padLeft(2, '0')}:${startDate.minute.toString().padLeft(2, '0')}', )); + // 生成中间整点小时刻度,注意起点向上取整一个小时 DateTime current = DateTime( startDate.year, startDate.month, startDate.day, - startDate.hour + 1, + startDate.hour, ); + if (startDate.minute > 0 || + startDate.second > 0 || + startDate.millisecond > 0) { + // 如果 startTime 不是整点,跳到下一个整点小时 + current = current.add(Duration(hours: 1)); + } while (current.isBefore(endDate)) { labels.add(XLabel( @@ -247,6 +61,7 @@ class TimeSeriesChart extends StatelessWidget { current = current.add(Duration(hours: 1)); } + // 最后一个刻度,原始 endTime,HH:mm格式 labels.add(XLabel( time: endTime, label: @@ -256,31 +71,157 @@ class TimeSeriesChart extends StatelessWidget { return labels; } - double _convertTimeToXValue(int timestamp) { - final totalDuration = endTime - startTime; - final pointDuration = timestamp - startTime; - final xLabels = _generateXLabels(); - return (pointDuration / totalDuration) * (xLabels.length - 1); + // 时间戳映射到0~(labels.length-1)之间 + double _timeToX(double timestamp, List labels) { + int start = labels.first.time; + int end = labels.last.time; + double total = (end - start).toDouble(); + double pos = (timestamp - start).clamp(0, total).toDouble(); + return pos / total * (labels.length - 1); } - int _convertXValueToTime(double xValue) { + @override + Widget build(BuildContext context) { final xLabels = _generateXLabels(); - final totalDuration = endTime - startTime; - final ratio = xValue / (xLabels.length - 1); - return startTime + (totalDuration * ratio).round(); + final midY = (yMin + yMax) / 2; + + List spots = dataPoints.map((p) { + return FlSpot(_timeToX(p.timestamp.toDouble(), xLabels), p.value); + }).toList(); + + return AspectRatio( + aspectRatio: 2, + child: LineChart( + LineChartData( + minX: 0, + maxX: (xLabels.length - 1).toDouble(), + minY: yMin < 0 ? yMin : 0, + maxY: yMax, + gridData: FlGridData(show: false), + extraLinesData: ExtraLinesData( + horizontalLines: [ + HorizontalLine( + y: 0, + color: themeController.currentColor.sc4, + strokeWidth: 1.rpx), + HorizontalLine( + y: yMin, + color: themeController.currentColor.sc9, + strokeWidth: 1.rpx, + dashArray: [5, 5]), + HorizontalLine( + y: yMax, + color: themeController.currentColor.sc9, + strokeWidth: 1.rpx, + dashArray: [5, 5]), + HorizontalLine( + y: midY, + color: themeController.currentColor.sc4, + strokeWidth: 1.rpx, + dashArray: [5, 5]), + ], + ), + titlesData: FlTitlesData( + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 30, + interval: 1, + getTitlesWidget: (value, meta) { + int index = value.toInt(); + if (index < 0 || index >= xLabels.length) + return const SizedBox.shrink(); + + final dateTime = + DateTime.fromMillisecondsSinceEpoch(xLabels[index].time); + + if (index == 0 || index == xLabels.length - 1) { + // 开始和结束显示 HH:mm + final formatted = + '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}'; + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text(formatted, + style: TextStyle( + color: themeController.currentColor.sc4, + fontSize: 16.rpx)), + ); + } else { + // 中间显示小时H,24小时制,不补零 + final formatted = '${dateTime.hour}'; + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text(formatted, + style: TextStyle( + color: themeController.currentColor.sc4, + fontSize: 16.rpx)), + ); + } + }, + ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 40.rpx, + interval: 1, + getTitlesWidget: (value, meta) { + // 只显示 yMin, midY, yMax, 和 0 + if ((value - 0).abs() < 0.01) { + return Text('0', + style: TextStyle( + color: themeController.currentColor.sc4, + fontSize: 16.rpx)); + } else if ((value - yMin).abs() < 0.01) { + return Text(yMin.toStringAsFixed(0), + style: TextStyle( + color: themeController.currentColor.sc4, + fontSize: 16.rpx)); + } else if ((value - midY).abs() < 0.01) { + return Text(midY.toStringAsFixed(0), + style: TextStyle( + color: themeController.currentColor.sc4, + fontSize: 16.rpx)); + } else if ((value - yMax).abs() < 0.01) { + return Text(yMax.toStringAsFixed(0), + style: TextStyle( + color: themeController.currentColor.sc4, + fontSize: 16.rpx)); + } else { + return const SizedBox.shrink(); + } + }, + ), + ), + rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), + topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), + ), + borderData: FlBorderData( + show: true, + border: Border( + bottom: BorderSide(color: Colors.grey.withOpacity(0.3)), + left: BorderSide.none, + right: BorderSide.none, + top: BorderSide.none, + ), + ), + lineBarsData: [ + LineChartBarData( + spots: spots, + isCurved: false, + color: themeController.currentColor.sc2, + barWidth: 2, + dotData: FlDotData(show: false), + ) + ], + ), + ), + ); } } -class TimeSeriesPoint { - final int timestamp; - final double value; - - TimeSeriesPoint(this.timestamp, this.value); -} - class XLabel { final int time; final String label; - XLabel({required this.time, required this.label}); } diff --git a/lib/pages/sleep_report/component/BreatheStandardWidget.dart b/lib/pages/sleep_report/component/BreatheStandardWidget.dart index 32ffadb..159a140 100644 --- a/lib/pages/sleep_report/component/BreatheStandardWidget.dart +++ b/lib/pages/sleep_report/component/BreatheStandardWidget.dart @@ -192,11 +192,11 @@ class _BreatheStandardWidgetState extends State { child: TimeSeriesChart( startTime: startTime, endTime: endTime, - yMin: 50, - yMax: 150, + yMin: 8, + yMax: 20, dataPoints: dataPoints, - actYMax: max.toDouble(), - actYMin: min.toDouble(), + // actYMax: max.toDouble(), + // actYMin: min.toDouble(), ), ), Padding( @@ -364,7 +364,7 @@ class _BreatheStandardWidgetState extends State { ), ); } catch (e) { - es.EasyDartModule.logger.error("打鼾监测绘制异常${e}"); + es.EasyDartModule.logger.error("打鼾监测绘制异常${e}"); return Container(); } } diff --git a/lib/pages/sleep_report/component/HeartRateStandardWidget.dart b/lib/pages/sleep_report/component/HeartRateStandardWidget.dart index 159fc8a..c344019 100644 --- a/lib/pages/sleep_report/component/HeartRateStandardWidget.dart +++ b/lib/pages/sleep_report/component/HeartRateStandardWidget.dart @@ -206,8 +206,8 @@ class _HeartRateStandardWidgetState extends State { yMin: 50, yMax: 150, dataPoints: dataPoints, - actYMin: min.toDouble(), - actYMax: max.toDouble(), + // actYMin: min.toDouble(), + // actYMax: max.toDouble(), ), ), Padding( @@ -375,7 +375,7 @@ class _HeartRateStandardWidgetState extends State { ), ); } catch (e) { - es.EasyDartModule.logger.error("打鼾监测绘制异常${e}"); + es.EasyDartModule.logger.error("打鼾监测绘制异常${e}"); return Container(); } } diff --git a/lib/pages/sleep_report/new_sleep_report_page.dart b/lib/pages/sleep_report/new_sleep_report_page.dart index 353d50c..ccb4ba3 100644 --- a/lib/pages/sleep_report/new_sleep_report_page.dart +++ b/lib/pages/sleep_report/new_sleep_report_page.dart @@ -387,8 +387,8 @@ class _NewSleepReportPageState extends State { child: Row( mainAxisSize: MainAxisSize.max, children: [ - Expanded( - flex: 1, + Flexible( + flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -467,8 +467,8 @@ class _NewSleepReportPageState extends State { .addToEnd(SizedBox(height: 36.rpx)), ), ), - Expanded( - flex: 1, + Flexible( + flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/routers/routers.dart b/lib/routers/routers.dart index cfc3f7f..86a613a 100644 --- a/lib/routers/routers.dart +++ b/lib/routers/routers.dart @@ -12,11 +12,13 @@ import 'package:vbvs_app/pages/device_bind/MobileScannerTestPage.dart'; import 'package:vbvs_app/pages/device_bind/bind_device_success.dart'; import 'package:vbvs_app/pages/device_bind/blueteeth_device_page.dart'; import 'package:vbvs_app/pages/device_bind/device_calibration.dart'; +import 'package:vbvs_app/pages/device_bind/device_calibration_person.dart'; import 'package:vbvs_app/pages/device_bind/device_share_list_page.dart'; import 'package:vbvs_app/pages/device_bind/device_share_page.dart'; import 'package:vbvs_app/pages/device_bind/device_type.dart'; import 'package:vbvs_app/pages/device_bind/device_type_list.dart'; import 'package:vbvs_app/pages/device_bind/wifi_page.dart'; +import 'package:vbvs_app/pages/device_bind/wifi_page_person.dart'; import 'package:vbvs_app/pages/login/login.dart'; import 'package:vbvs_app/pages/login/other_login.dart'; import 'package:vbvs_app/pages/main_bottom/e_page.dart'; @@ -59,6 +61,7 @@ var routes = { "/personPage": (contxt) => PersonPage(), "/bindDeviceSuccess": (contxt) => BindDeviceSuccess(), "/wifiPage": (contxt, {arguments}) => WifiPage(type: arguments), + "/wifiPagePerson": (contxt, {arguments}) => WifiPagePerson(type: arguments), "/updateUserPage": (contxt) => UpdateUserPage(), "/settingPage": (contxt) => SettingPage(), "/aboutUsPage": (contxt) => AboutUsPage(), @@ -75,6 +78,7 @@ var routes = { "/deviceShareListPage": (contxt, {arguments}) => DeviceShareListPage(device: arguments), "/calibrationPage": (contxt, {arguments}) => CalibrationPage(type: arguments), + "/calibrationPersonPage": (contxt, {arguments}) => CalibrationPersonPage(type: arguments), "/applyRepairPage": (contxt) => ApplyRepairPage(), "/languageSetting": (contxt) => LanguageSetting(), "/helpPage": (contxt) => HelpPage(),