更新棉花糖
This commit is contained in:
@@ -62,7 +62,26 @@
|
|||||||
"输入新密码":"输入新密码",
|
"输入新密码":"输入新密码",
|
||||||
"确认验证码":"确认验证码",
|
"确认验证码":"确认验证码",
|
||||||
"输入手机号码":"输入手机号码",
|
"输入手机号码":"输入手机号码",
|
||||||
"操作成功":"操作成功"
|
"操作成功":"操作成功",
|
||||||
|
"添加设备":"添加设备",
|
||||||
|
"扫描中":"扫描中...",
|
||||||
|
"检索设备":"检索设备",
|
||||||
|
"搜索":"搜索",
|
||||||
|
"匹配出的外围设备":"匹配出的外围设备",
|
||||||
|
"知道了":"知道了",
|
||||||
|
"蓝牙未开启":"蓝牙未开启",
|
||||||
|
"请先打开蓝牙在进行设备扫描":"请先打开蓝牙在进行设备扫描",
|
||||||
|
"等待扫描":"等待扫描",
|
||||||
|
"默认设备名称":"默认设备名称",
|
||||||
|
"连接异常":"连接异常",
|
||||||
|
"蓝牙绑定提示":"用手机进行设备添加时,请打开手机蓝牙搜索,靠近目标位置3米以内进行。",
|
||||||
|
"蓝牙连接成功":"蓝牙连接成功",
|
||||||
|
"蓝牙连接失败":"蓝牙连接失败,请重试",
|
||||||
|
"绑定失败请重试":"绑定失败请重试",
|
||||||
|
"无法绑定":"无法绑定!",
|
||||||
|
"无法绑定1":"检测到该设备",
|
||||||
|
"无法绑定2":"已被绑定",
|
||||||
|
"无法绑定3":",绑定前请先进行解绑,有疑问请联系客服"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
|
||||||
class AppConstants {
|
class AppConstants {
|
||||||
// App-related constants
|
// App-related constants
|
||||||
@@ -28,5 +31,11 @@ class AppConstants {
|
|||||||
double dropdown_height = 90.rpx; //标题文字字号
|
double dropdown_height = 90.rpx; //标题文字字号
|
||||||
double border_width = 1.rpx; //标题文字字号//border宽度
|
double border_width = 1.rpx; //标题文字字号//border宽度
|
||||||
|
|
||||||
|
List<Color> mhtButtongradientColors = [
|
||||||
|
stringToColor("FCFCFC"), // 浅蓝
|
||||||
|
stringToColor("F8FAF9"), // 浅蓝
|
||||||
|
stringToColor("ECF6F3"), // 浅蓝
|
||||||
|
stringToColor("D9F0E9"), // 浅蓝
|
||||||
|
stringToColor("CEECE3"), // 浅蓝
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ class DailyLogUtils {
|
|||||||
await _writeLogWithLevel('DEBUG', content);
|
await _writeLogWithLevel('DEBUG', content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<void> printLog(String content) async {
|
||||||
|
print("logger--->"+content);
|
||||||
|
// await writeLog(content);
|
||||||
|
}
|
||||||
|
|
||||||
// 读取当天日志
|
// 读取当天日志
|
||||||
static Future<String> readTodayLog() async {
|
static Future<String> readTodayLog() async {
|
||||||
final file = await _getLogFile();
|
final file = await _getLogFile();
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
//蓝牙指令
|
//蓝牙指令
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
|
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
|
||||||
import 'package:easydevice/src/app/thapp.dart';
|
import 'package:easydevice/src/app/thapp.dart';
|
||||||
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/model/BlueToothDataModel.dart';
|
||||||
|
|
||||||
// wifi列表指令
|
// wifi列表指令
|
||||||
getWifiList(THapp tHapp) async {
|
getWifiList(THapp tHapp) async {
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ import 'package:vbvs_app/language/AppLanguage.dart';
|
|||||||
import 'package:vbvs_app/model/CustomThemeColor.dart';
|
import 'package:vbvs_app/model/CustomThemeColor.dart';
|
||||||
import 'package:vbvs_app/model/user_data.dart';
|
import 'package:vbvs_app/model/user_data.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/MattressControl.dart';
|
import 'package:vbvs_app/pages/mh_page/MattressControl.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/component/mht_device_calibration_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/homepage/controller/mht_home_controller.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/user/controller/mht_login_controller.dart';
|
import 'package:vbvs_app/pages/mh_page/user/controller/mht_login_controller.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/user/controller/mht_register_controller.dart';
|
import 'package:vbvs_app/pages/mh_page/user/controller/mht_register_controller.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/user/controller/update_password_controller.dart';
|
import 'package:vbvs_app/pages/mh_page/user/controller/update_password_controller.dart';
|
||||||
@@ -335,6 +338,9 @@ class MyApp extends StatelessWidget {
|
|||||||
Get.lazyPut(() => RegisterController()),
|
Get.lazyPut(() => RegisterController()),
|
||||||
Get.lazyPut(() => UpdatePasswordController()),
|
Get.lazyPut(() => UpdatePasswordController()),
|
||||||
Get.lazyPut(() => DeviceListController()),
|
Get.lazyPut(() => DeviceListController()),
|
||||||
|
Get.lazyPut(() => MHTBlueToothController()),
|
||||||
|
Get.lazyPut(() => MHTHomeController()),
|
||||||
|
Get.lazyPut(() => MHTDeviceCalibrationController()),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
|||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/controller/weather/weather_controller.dart';
|
import 'package:vbvs_app/controller/weather/weather_controller.dart';
|
||||||
import 'package:vbvs_app/enum/LoginStatus.dart';
|
import 'package:vbvs_app/enum/LoginStatus.dart';
|
||||||
import 'package:vbvs_app/main.dart';
|
|
||||||
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
@@ -35,7 +34,6 @@ class HomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _HomePageState extends State<HomePage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
GlobalController globalController = Get.find();
|
|
||||||
UserInfoController userInfoController = Get.find();
|
UserInfoController userInfoController = Get.find();
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
BodyDeviceController deviceController = Get.find();
|
BodyDeviceController deviceController = Get.find();
|
||||||
|
|||||||
1150
lib/pages/mh_page/component/mht_bind_dialog.dart
Normal file
1150
lib/pages/mh_page/component/mht_bind_dialog.dart
Normal file
File diff suppressed because it is too large
Load Diff
616
lib/pages/mh_page/device/component/DeviceComponentWidget.dart
Normal file
616
lib/pages/mh_page/device/component/DeviceComponentWidget.dart
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
|
||||||
|
import 'package:EasyDartModule/base/logger/Logger.dart';
|
||||||
|
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:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/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/component/tool/cmd.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/model/BleDeviceData.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/component/mht_bind_dialog.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/model/BlueToothDataModel.dart';
|
||||||
|
|
||||||
|
class DeviceComponentWidget extends StatefulWidget {
|
||||||
|
BlueToothDataModel bleDevice;
|
||||||
|
|
||||||
|
DeviceComponentWidget({
|
||||||
|
super.key,
|
||||||
|
required this.bleDevice,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DeviceComponentWidget> createState() => _DeviceComponentWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DeviceComponentWidgetState extends State<DeviceComponentWidget> {
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
MHTBlueToothController blueteethBindController = Get.find();
|
||||||
|
var lisObj;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Map device = {
|
||||||
|
"name": widget.bleDevice.name,
|
||||||
|
"mac": widget.bleDevice.mac,
|
||||||
|
"rssi": widget.bleDevice.scanResult.rssi,
|
||||||
|
"bind": widget.bleDevice.bind,
|
||||||
|
};
|
||||||
|
return ClickableContainer(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
highlightColor: Colors.white,
|
||||||
|
borderRadius: 20.rpx,
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 36.rpx, 55.rpx, 52.rpx),
|
||||||
|
onTap: () async {},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${device['name']}",
|
||||||
|
style: TextStyle(
|
||||||
|
color: stringToColor("#333333"), fontSize: 30.rpx),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 10.rpx,
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
if (blueteethBindController.currentDeviceMac.value ==
|
||||||
|
device['mac']) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 24.rpx,
|
||||||
|
height: 24.rpx,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 1,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
|
stringToColor("#929699")),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.14,
|
||||||
|
constraints: BoxConstraints(minWidth: 106.rpx),
|
||||||
|
child: Text(
|
||||||
|
"MAC".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: stringToColor("#929699"),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${device['mac']}",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
color: stringToColor("#333333")),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 33.rpx)),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.14,
|
||||||
|
constraints: BoxConstraints(minWidth: 106.rpx),
|
||||||
|
child: Text(
|
||||||
|
"信号强度".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: stringToColor("#929699"),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${device['rssi']}" + "dBm".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
color: stringToColor("#333333")),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 33.rpx)),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.14,
|
||||||
|
constraints: BoxConstraints(minWidth: 106.rpx),
|
||||||
|
child: Text(
|
||||||
|
"设备状态".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: stringToColor("#929699"),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${device['bind'] == true ? "已被绑定" : "可绑定"}",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
color: device['bind'] == true
|
||||||
|
? stringToColor("#FF7159")
|
||||||
|
: stringToColor("#6BFDAC"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 33.rpx)),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 37.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CustomCard(
|
||||||
|
borderRadius: 16.rpx,
|
||||||
|
onTap: () async {
|
||||||
|
try {
|
||||||
|
// 连接前暂停扫描
|
||||||
|
blueteethBindController.pauseScanning();
|
||||||
|
if (blueteethBindController.currentDeviceMac?.value !=
|
||||||
|
null &&
|
||||||
|
blueteethBindController
|
||||||
|
.currentDeviceMac!.value.isNotEmpty) {
|
||||||
|
if (blueteethBindController.currentDeviceMac?.value !=
|
||||||
|
device['mac']) {
|
||||||
|
showConfirmDialog(
|
||||||
|
context, Container(), "其他设备正在绑定中,是否终止其他设备绑定?".tr,
|
||||||
|
onConfirm: () {
|
||||||
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
}, onCancel: () {
|
||||||
|
blueteethBindController.resumeScanning();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blueteethBindController.currentDeviceMac?.value =
|
||||||
|
device['mac']!;
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
|
||||||
|
if (device['bind'] == true) {
|
||||||
|
await showHaveBindDialog(context);
|
||||||
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
|
blueteethBindController.resumeScanning();
|
||||||
|
} else {
|
||||||
|
showConfirmDialog(
|
||||||
|
context,
|
||||||
|
Container(),
|
||||||
|
'是否确认绑定?'.tr,
|
||||||
|
onConfirm: () async {
|
||||||
|
//连接蓝牙 ,获取设备信息
|
||||||
|
blueteethBindController.currentDeviceMac.value =
|
||||||
|
widget.bleDevice.mac;
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
String mac =
|
||||||
|
await getBindTHMAC(context, widget.bleDevice);
|
||||||
|
if (mac != null && mac.isNotEmpty) {
|
||||||
|
bool flag =
|
||||||
|
await fillTHMac(mac, widget.bleDevice, context);
|
||||||
|
if (!flag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blueteethBindController.currentFullDevice =
|
||||||
|
widget.bleDevice;
|
||||||
|
ApiResponse response = await blueteethBindController
|
||||||
|
.bindDeviceAndMAC(widget.bleDevice, context);
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: response.msg!);
|
||||||
|
if (response.code == HttpStatusCodes.ok) {
|
||||||
|
//更新设备绑定流程
|
||||||
|
Get.toNamed("/mHTwifiPage",arguments: widget.bleDevice);
|
||||||
|
THapp bledevice = THapp(
|
||||||
|
device: widget.bleDevice.scanResult.device);
|
||||||
|
blueteethBindController.currentDevice = bledevice;
|
||||||
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
|
} else {
|
||||||
|
blueteethBindController.resumeScanning();
|
||||||
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: response.msg ?? "蓝牙绑定.连接异常".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel: () {
|
||||||
|
print('用户点击了取消');
|
||||||
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
|
blueteethBindController.resumeScanning();
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "连接异常".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
edm.EasyDartModule.logger.info("连接异常: $e");
|
||||||
|
DailyLogUtils.writeLog("连接异常: $e");
|
||||||
|
} finally {
|
||||||
|
// 确保在任何情况下都恢复扫描
|
||||||
|
if (blueteethBindController
|
||||||
|
.currentDeviceMac.value.isEmpty) {
|
||||||
|
blueteethBindController.resumeScanning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: [stringToColor("1592AA"), stringToColor("006FA3")],
|
||||||
|
child: Container(
|
||||||
|
width: 150.rpx,
|
||||||
|
height: 90.rpx,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
"添加".tr,
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 26.rpx),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 37.rpx)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新设备绑定状态
|
||||||
|
void updateDeviceBindStatus(BleDeviceData device) {
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.user_setting;
|
||||||
|
String mac = device.mac!;
|
||||||
|
String type = "device_bind_status_${mac}";
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
"type": type,
|
||||||
|
"mac": mac,
|
||||||
|
"wifi": false,
|
||||||
|
"celibration": false,
|
||||||
|
"person_info": false,
|
||||||
|
"time": DateTime.now().millisecondsSinceEpoch,
|
||||||
|
};
|
||||||
|
requestWithLog(
|
||||||
|
logTitle: "更新用户绑定流程",
|
||||||
|
method: MyHttpMethod.put,
|
||||||
|
queryUrl: queryUrl,
|
||||||
|
data: data,
|
||||||
|
onSuccess: (res) {},
|
||||||
|
onFailure: (res) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDeviceInfoSection(device, BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 0.rpx, 30.rpx, 0.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
device.name ?? '蓝牙绑定.默认设备名称'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFF6FAFD),
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
if (blueteethBindController.currentDeviceMac.value ==
|
||||||
|
device.mac) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 24.rpx,
|
||||||
|
height: 24.rpx,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 1,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.信号强度".tr + ':${device.rssi ?? '-'}dBm',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFEBF2F8),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 40.rpx),
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.SN".tr + ':${device.sn ?? '-'}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFF5F9FD),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.蓝牙地址".tr + ':${device.deviceId ?? '-'}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFF6FAFD),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.mac".tr + ':${device.mac ?? '-'}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFF6FAFD),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.网络".tr +
|
||||||
|
':${device.isOnline == true ? '蓝牙绑定.在线'.tr : '蓝牙绑定.离线'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFEBF2F8),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 145.rpx),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.传感器".tr + ":",
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFEBF2F8),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
device.bind == false ? '蓝牙绑定.可绑定'.tr : '蓝牙绑定.已被绑定'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: device.bind == false
|
||||||
|
? const Color(0xFF1AD2B5)
|
||||||
|
: themeController.currentColor.sc9,
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"版本".tr + '${device.version ?? '-'}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFF6FAFD),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(
|
||||||
|
height: 37.rpx,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取传感器mac
|
||||||
|
Future<String> getBindTHMAC(
|
||||||
|
BuildContext context, BlueToothDataModel device) async {
|
||||||
|
const int maxRetries = 2;
|
||||||
|
const Duration timeout = Duration(seconds: 5);
|
||||||
|
String? macAddress;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 连接设备
|
||||||
|
THapp bledevice = THapp(device: device.scanResult.device);
|
||||||
|
await bledevice.connect();
|
||||||
|
var res2 = bledevice.isConnected;
|
||||||
|
|
||||||
|
if (!res2) {
|
||||||
|
edm.EasyDartModule.logger.error("蓝牙连接失败");
|
||||||
|
DailyLogUtils.printLog("蓝牙连接失败");
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "蓝牙连接失败".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
throw Exception("蓝牙连接失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
blueteethBindController.blueConnectFlag.value = 2;
|
||||||
|
blueteethBindController.currentDevice = bledevice;
|
||||||
|
|
||||||
|
var read = bledevice.getresource('fff0/fff1');
|
||||||
|
await read!.characteristic.setNotifyValue(true);
|
||||||
|
|
||||||
|
var write = bledevice.getresource('fff0/fff2');
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt < maxRetries; attempt++) {
|
||||||
|
var completer = Completer<String>();
|
||||||
|
|
||||||
|
StreamSubscription? subscription;
|
||||||
|
subscription = read.characteristic.onValueReceived.listen((onData) {
|
||||||
|
if (onData.length >= 14) {
|
||||||
|
// 按照你提供的协议,返回数据长度至少 17字节,这里保险起见 14起步
|
||||||
|
String parsedMac = parseMacFromBleResponse(onData);
|
||||||
|
completer.complete(parsedMac);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 发送查询命令
|
||||||
|
var order = [
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x40,
|
||||||
|
0x01,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x45,
|
||||||
|
0xFD
|
||||||
|
];
|
||||||
|
await write!.characteristic.write(order);
|
||||||
|
|
||||||
|
try {
|
||||||
|
macAddress = await completer.future.timeout(timeout);
|
||||||
|
await subscription.cancel();
|
||||||
|
break; // 成功拿到,跳出重试
|
||||||
|
} catch (e) {
|
||||||
|
await subscription.cancel();
|
||||||
|
if (attempt == maxRetries - 1) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "获取MAC地址超时,请重试".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
throw Exception("获取MAC地址失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macAddress == null) {
|
||||||
|
throw Exception("未能获取到MAC地址");
|
||||||
|
}
|
||||||
|
|
||||||
|
// device.macA = macAddress;
|
||||||
|
print('MAC地址: $macAddress');
|
||||||
|
return macAddress;
|
||||||
|
} catch (e) {
|
||||||
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
|
edm.EasyDartModule.logger.error("蓝牙获取MAC失败:$e");
|
||||||
|
DailyLogUtils.printLog("蓝牙获取MAC失败:$e");
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "设备连接失败,请重试".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fillTHMac(
|
||||||
|
String mac, BlueToothDataModel bleDevice, BuildContext context) async {
|
||||||
|
bool flag = false;
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.get_bluetooth_device_status;
|
||||||
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
|
String macParam =
|
||||||
|
"mac=${Uri.encodeQueryComponent(mac.replaceAll(':', ''))}";
|
||||||
|
if (queryUrl.contains('?')) {
|
||||||
|
queryUrl += '&$macParam';
|
||||||
|
} else {
|
||||||
|
queryUrl += '?$macParam';
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestWithLog(
|
||||||
|
logTitle: "获取设备状态",
|
||||||
|
method: MyHttpMethod.get,
|
||||||
|
queryUrl: queryUrl,
|
||||||
|
onSuccess: (res) {
|
||||||
|
flag = true;
|
||||||
|
if (res.code != HttpStatusCodes.ok) return;
|
||||||
|
|
||||||
|
if (res.data != null && res.data is List) {
|
||||||
|
List<dynamic> responseList = res.data;
|
||||||
|
|
||||||
|
// 查找当前MAC对应的数据
|
||||||
|
String macKey = mac.replaceAll(':', '').toUpperCase();
|
||||||
|
for (var item in responseList) {
|
||||||
|
if (item['mac'].toString().toUpperCase() == macKey) {
|
||||||
|
// 更新 bleDevice 的状态
|
||||||
|
//如果传感器已经绑定 暂时不处理
|
||||||
|
// bleDevice.bind = item['bind'] ?? bleDevice.bind;
|
||||||
|
bleDevice.macA = item['mac'];
|
||||||
|
if (item['bindMac'] != null &&
|
||||||
|
item['bindMac'].toString().isNotEmpty) {
|
||||||
|
bleDevice.macB = item['bindMac'];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFailure: (res) {
|
||||||
|
flag = false;
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: "获取设备状态失败".tr, textColor: themeController.currentColor.sc9);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String parseMacFromBleResponse(List<int> data) {
|
||||||
|
// 先做简单的合法性判断
|
||||||
|
if (data.length >= 17 &&
|
||||||
|
data[0] == 0xFF &&
|
||||||
|
data[1] == 0xFF &&
|
||||||
|
data[2] == 0xFF &&
|
||||||
|
data[3] == 0xFF &&
|
||||||
|
data[6] == 0x40 &&
|
||||||
|
data[7] == 0x01) {
|
||||||
|
// 取出 Byte8 ~ Byte13
|
||||||
|
List<int> macBytes = data.sublist(8, 14);
|
||||||
|
String macAddress = macBytes
|
||||||
|
.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase())
|
||||||
|
.join('');
|
||||||
|
return macAddress;
|
||||||
|
} else {
|
||||||
|
throw Exception("BLE返回数据格式不正确");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'mht_device_calibration_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class MHTDeviceCalibrationModel {
|
||||||
|
MHTDeviceCalibrationModel();
|
||||||
|
|
||||||
|
factory MHTDeviceCalibrationModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$MHTDeviceCalibrationModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
return MHTDeviceCalibrationModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$MHTDeviceCalibrationModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MHTDeviceCalibrationController
|
||||||
|
extends GetControllerEx<MHTDeviceCalibrationModel> {
|
||||||
|
MHTDeviceCalibrationController() {
|
||||||
|
attr = GetModel(MHTDeviceCalibrationModel()).obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
RxInt process = 0.obs; //校准流程 0.离床校准 1.位置校准
|
||||||
|
RxInt bed_calibration = 0.obs; //0.未完成 1.完成
|
||||||
|
RxInt position_calibration = 0.obs; //0.未完成 1.完成
|
||||||
|
RxInt bed_type = 0.obs; //0.单人 1.双人
|
||||||
|
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;//在床提示
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'mht_device_calibration_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
MHTDeviceCalibrationModel _$MHTDeviceCalibrationModelFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
MHTDeviceCalibrationModel();
|
||||||
|
|
||||||
|
Map<String, dynamic> _$MHTDeviceCalibrationModelToJson(
|
||||||
|
MHTDeviceCalibrationModel instance) =>
|
||||||
|
<String, dynamic>{};
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:easydevice/src/app/thapp.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/model/BlueToothDataModel.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/user/controller/mht_register_controller.dart';
|
||||||
|
|
||||||
|
part 'mht_bluetooth_controller.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class MHTBlueToothModel {
|
||||||
|
bool? bluetooth = false; //蓝牙开关
|
||||||
|
double? singal = -100;
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
List<BlueToothDataModel>? blueRawData; //蓝牙原始数据
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
List<BlueToothDataModel>? deviceDataStatus; //已经请求过状态的数据
|
||||||
|
|
||||||
|
int? read = 0;
|
||||||
|
int? deviceType; //绑定设备类型
|
||||||
|
|
||||||
|
bool wifiPassShow = false;
|
||||||
|
String? wifiPass;
|
||||||
|
|
||||||
|
MHTBlueToothModel();
|
||||||
|
|
||||||
|
static MHTBlueToothModel fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$MHTBlueToothModelFromJson(json);
|
||||||
|
Map<String, dynamic> toJson() => _$MHTBlueToothModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MHTBlueToothController extends GetControllerEx<MHTBlueToothModel> {
|
||||||
|
MHTBlueToothController() {
|
||||||
|
attr = GetModel(MHTBlueToothModel()).obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer? _statusTimer;
|
||||||
|
MHTRegisterController registerController = Get.find();
|
||||||
|
|
||||||
|
RxString search = "".obs;
|
||||||
|
|
||||||
|
RxString currentDeviceMac = "".obs; //当前正在绑定的设备,用来显示loading
|
||||||
|
|
||||||
|
THapp? currentDevice; //当前连接的设备
|
||||||
|
BlueToothDataModel? currentFullDevice; //当前连接的设备
|
||||||
|
|
||||||
|
RxInt blueConnectFlag = 0.obs; //当前蓝牙连接状态 0.正在连接 1.未连接 2.已连接
|
||||||
|
|
||||||
|
RxBool bluetoothStatus = false.obs; //蓝牙开启状态
|
||||||
|
RxInt connectStatus = 0.obs; //当前wifi连接状态 0:未连接 1:已连接
|
||||||
|
RxInt netType = 0.obs; //当前网络类型 0.正在检测 1.wifi 2.4g设备 3.未知
|
||||||
|
RxInt wifiConnectStatus = 1.obs; //获取wifi状态 0.正在检测 1.已检测完
|
||||||
|
|
||||||
|
RxMap selectWifi = {}.obs; //正在连接wifi信息
|
||||||
|
|
||||||
|
int returnPage = 0; //0返回首页 1.返回设备列表
|
||||||
|
|
||||||
|
RxInt wifiStatus = 0.obs; //wifi连接状态 0:未连接 1:已连接
|
||||||
|
RxList wifiList = [].obs;
|
||||||
|
RxMap connect_wifi = {}.obs;
|
||||||
|
RxString? cid = "".obs;
|
||||||
|
|
||||||
|
void startStatusPolling() {
|
||||||
|
updateDeviceStatus().then((res) {
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
updateAll();
|
||||||
|
} else {
|
||||||
|
safeShowNotification(res.msg ?? "获取设备状态异常");
|
||||||
|
EasyDartModule.logger.info("获取设备状态异常: $res");
|
||||||
|
DailyLogUtils.writeLog("获取设备状态异常: $res");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_statusTimer == null) {
|
||||||
|
_statusTimer = Timer.periodic(Duration(seconds: 2), (timer) {
|
||||||
|
updateDeviceStatus().then((res) {
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
updateAll();
|
||||||
|
} else {
|
||||||
|
safeShowNotification(res.msg ?? "获取设备状态异常");
|
||||||
|
EasyDartModule.logger.info("获取设备状态异常: $res");
|
||||||
|
DailyLogUtils.writeLog("获取设备状态异常: $res");
|
||||||
|
}
|
||||||
|
}).catchError((e, stack) {
|
||||||
|
print("updateDeviceStatus 执行异常: $e\n$stack");
|
||||||
|
safeShowNotification("设备状态请求失败");
|
||||||
|
EasyDartModule.logger.info("设备状态异常: $e");
|
||||||
|
DailyLogUtils.writeLog("设备状态异常: $e");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopStatusPolling() {
|
||||||
|
_statusTimer?.cancel();
|
||||||
|
_statusTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shouldScan = true.obs;
|
||||||
|
|
||||||
|
void pauseScanning() {
|
||||||
|
shouldScan.value = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复扫描
|
||||||
|
void resumeScanning() {
|
||||||
|
shouldScan.value = true;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> updateDeviceStatus() async {
|
||||||
|
try {
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.get_bluetooth_device_status;
|
||||||
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
|
|
||||||
|
if (model.blueRawData != null && model.blueRawData!.isNotEmpty) {
|
||||||
|
final macParams = model.blueRawData!
|
||||||
|
.map((device) =>
|
||||||
|
"mac=${Uri.encodeQueryComponent(device.mac!.replaceAll(':', ''))}")
|
||||||
|
.join("&");
|
||||||
|
|
||||||
|
if (queryUrl.contains('?')) {
|
||||||
|
queryUrl += '&$macParams';
|
||||||
|
} else {
|
||||||
|
queryUrl += '?$macParams';
|
||||||
|
}
|
||||||
|
|
||||||
|
String? language = "";
|
||||||
|
if (languageController.selectLanguage != null) {
|
||||||
|
language = languageController.selectLanguage.value!.language_code;
|
||||||
|
}
|
||||||
|
if (language != null && language.isNotEmpty) {
|
||||||
|
if (queryUrl.contains("?")) {
|
||||||
|
queryUrl += "&lang=$language";
|
||||||
|
} else {
|
||||||
|
queryUrl += "?lang=$language";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
if (res.code != HttpStatusCodes.ok) return res;
|
||||||
|
|
||||||
|
if (response.data['data'] != null && response.data['data'] is List) {
|
||||||
|
List<dynamic> responseList = response.data['data'];
|
||||||
|
|
||||||
|
// 新建一个 Map,便于快速通过 mac 查找返回的设备状态
|
||||||
|
final Map<String, dynamic> responseMap = {
|
||||||
|
for (var item in responseList)
|
||||||
|
item['mac'].toString().toUpperCase(): item
|
||||||
|
};
|
||||||
|
|
||||||
|
// 遍历 blueRawData,更新 bind 状态
|
||||||
|
for (var device in model.blueRawData!) {
|
||||||
|
final macKey = device.mac!.replaceAll(':', '').toUpperCase();
|
||||||
|
if (responseMap.containsKey(macKey)) {
|
||||||
|
var item = responseMap[macKey];
|
||||||
|
// 更新 device 绑定状态等信息
|
||||||
|
device.bind = item['bind'] ?? device.bind;
|
||||||
|
device.mac = item['bindMac'] ?? device.mac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model.deviceDataStatus =
|
||||||
|
List<BlueToothDataModel>.from(model.blueRawData!);
|
||||||
|
} else {
|
||||||
|
model.deviceDataStatus = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
model.deviceDataStatus = [];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("获取设备状态异常: $e");
|
||||||
|
EasyDartModule.logger.info("获取设备状态异常: $e");
|
||||||
|
DailyLogUtils.writeLog("获取设备状态异常: $e");
|
||||||
|
return ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindDeviceAndMAC(BlueToothDataModel bleDevice, BuildContext context) async {
|
||||||
|
try {
|
||||||
|
if ((bleDevice.macA == null || bleDevice.macA.isEmpty) &&
|
||||||
|
(bleDevice.macB == null || bleDevice.macB.isEmpty)) {
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: "传感器mac读取失败".tr, textColor: themeController.currentColor.sc9);
|
||||||
|
currentDeviceMac.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_bind;
|
||||||
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
|
var data = {
|
||||||
|
"deviceType": model.deviceType,
|
||||||
|
"mac": bleDevice.mac,
|
||||||
|
"macA": bleDevice.macA,
|
||||||
|
if (bleDevice.macB != null && bleDevice.macB!.isNotEmpty)
|
||||||
|
"macB": bleDevice.macB,
|
||||||
|
};
|
||||||
|
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "绑定成功".tr, "绑定成功".tr);
|
||||||
|
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
// PersonController personController = Get.find();
|
||||||
|
// personController.currentPersonId.value = res.data['id'];
|
||||||
|
currentDeviceMac.value = "";
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器失败".tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("绑定异常: $e");
|
||||||
|
DailyLogUtils.writeLog("蓝牙绑定: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void safeShowNotification(String msg) {
|
||||||
|
try {
|
||||||
|
final ctx = Get.context;
|
||||||
|
if (ctx != null && ctx.mounted) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
ctx,
|
||||||
|
text: msg,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print("TopSlideNotification 未显示:context 不可用或未挂载");
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
// print("TopSlideNotification 显示异常: $e\n$stack");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'mht_bluetooth_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
MHTBlueToothModel _$MHTBlueToothModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
MHTBlueToothModel()
|
||||||
|
..bluetooth = json['bluetooth'] as bool?
|
||||||
|
..singal = (json['singal'] as num?)?.toDouble()
|
||||||
|
..read = (json['read'] as num?)?.toInt()
|
||||||
|
..deviceType = (json['deviceType'] as num?)?.toInt()
|
||||||
|
..wifiPassShow = json['wifiPassShow'] as bool
|
||||||
|
..wifiPass = json['wifiPass'] as String?;
|
||||||
|
|
||||||
|
Map<String, dynamic> _$MHTBlueToothModelToJson(MHTBlueToothModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'bluetooth': instance.bluetooth,
|
||||||
|
'singal': instance.singal,
|
||||||
|
'read': instance.read,
|
||||||
|
'deviceType': instance.deviceType,
|
||||||
|
'wifiPassShow': instance.wifiPassShow,
|
||||||
|
'wifiPass': instance.wifiPass,
|
||||||
|
};
|
||||||
229
lib/pages/mh_page/device/mht_bind_device_type.dart
Normal file
229
lib/pages/mh_page/device/mht_bind_device_type.dart
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart';
|
||||||
|
|
||||||
|
class MHTBindDeviceTypePage extends StatefulWidget {
|
||||||
|
int type = 0; //0绑定设备 1.查询我的设备
|
||||||
|
MHTBindDeviceTypePage({super.key, this.type = 0});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MHTBindDeviceTypePage> createState() => _MHTBindDeviceTypePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MHTBindDeviceTypePageState extends State<MHTBindDeviceTypePage> {
|
||||||
|
GlobalController globalController = Get.find();
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
// BlueteethBindController blueteethBindController = Get.find();
|
||||||
|
MHTBlueToothController blueteethBindController = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
DeviceTypeController deviceTypeController = Get.find();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
deviceTypeController.getDeviceType().then((response) {
|
||||||
|
if (response.code != HttpStatusCodes.ok) {
|
||||||
|
// 延迟到 widget 构建后再执行 show
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context, // 用当前页面 context 替代 Get.context!
|
||||||
|
text: response.msg ?? "服务器.失败".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
int read = blueteethBindController.model.read!;
|
||||||
|
if (blueteethBindController.model.read == 1) {
|
||||||
|
//需要弹窗显示教程
|
||||||
|
}
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, bodySize) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/images/new_background.png'), // 本地图片
|
||||||
|
fit: BoxFit.fill, // 填满整个 Container
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent, // 加上这一行
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
// backgroundColor: Colors.transparent,
|
||||||
|
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: [
|
||||||
|
/// 居中标题
|
||||||
|
Text(
|
||||||
|
'添加设备'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// 左边返回按钮
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
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,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 使用 Obx 来监听 deviceTypeList 的变化
|
||||||
|
SizedBox(height: 26.rpx), // 开始的间隔
|
||||||
|
Text(
|
||||||
|
"选择类型",
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 30.rpx),
|
||||||
|
),
|
||||||
|
SizedBox(height: 32.rpx), // 开始的间隔
|
||||||
|
Obx(() {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
...deviceTypeController.deviceTypeList.value
|
||||||
|
.map((device) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: 26.rpx), // 添加每个设备之间的间隔
|
||||||
|
child: _buildDeviceCard(
|
||||||
|
context,
|
||||||
|
title: device['name'], // 这里假设 device 是一个 Map
|
||||||
|
imageUrl: device['image'],
|
||||||
|
type: device['type'],
|
||||||
|
desc: device['desc'] ?? [],
|
||||||
|
reg: device['device_reg'] ?? [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
SizedBox(height: 26.rpx), // 结束的间隔
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDeviceCard(BuildContext context,
|
||||||
|
{required String title,
|
||||||
|
required String imageUrl,
|
||||||
|
required double type,
|
||||||
|
required List<dynamic>? desc,
|
||||||
|
required List<dynamic>? reg}) {
|
||||||
|
if (type == 1) {
|
||||||
|
return SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map data = {
|
||||||
|
"reg":reg,
|
||||||
|
"type":type,
|
||||||
|
};
|
||||||
|
return CustomCard(
|
||||||
|
borderRadius: 20.rpx,
|
||||||
|
onTap: () {
|
||||||
|
MHTBlueToothController mhtBlueToothController = Get.find();
|
||||||
|
mhtBlueToothController.model.deviceType = type.toInt();
|
||||||
|
Get.toNamed("/mHTBlueteethDevicePage", arguments: data);
|
||||||
|
},
|
||||||
|
colors: [Colors.white],
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.135,
|
||||||
|
constraints: BoxConstraints(minHeight: 220.rpx),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 30.rpx),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 58.rpx),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
child: Image.network(
|
||||||
|
imageUrl,
|
||||||
|
width: 177.rpx,
|
||||||
|
height: 85.rpx,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 30.rpx),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: stringToColor("#333333"),
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
if (desc != null && desc.isNotEmpty) ...[
|
||||||
|
SizedBox(height: 10.rpx),
|
||||||
|
Text(
|
||||||
|
desc.join(' '),
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: stringToColor("#666666"),
|
||||||
|
fontSize: 24.rpx,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
textAlign: TextAlign.left, // 或 center 看你整体布局需求
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
717
lib/pages/mh_page/device/mht_blueteeth_device_page.dart
Normal file
717
lib/pages/mh_page/device/mht_blueteeth_device_page.dart
Normal file
@@ -0,0 +1,717 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
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:permission_handler/permission_handler.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/controller/main_bottom/global_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/component/mht_bind_dialog.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/component/DeviceComponentWidget.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/model/BlueToothDataModel.dart';
|
||||||
|
|
||||||
|
class MHTBlueteethDevicePage extends StatefulWidget {
|
||||||
|
var data;
|
||||||
|
MHTBlueteethDevicePage({super.key, required this.data});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MHTBlueteethDevicePage> createState() => _MHTBlueteethDevicePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MHTBlueteethDevicePageState extends State<MHTBlueteethDevicePage> {
|
||||||
|
MHTBlueToothController mhtBlueToothController = Get.find();
|
||||||
|
GlobalController globalController = Get.find();
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
late FlutterBluePlus flutterBlue;
|
||||||
|
List<ScanResult> scanResults = [];
|
||||||
|
bool isScanning = false;
|
||||||
|
Timer? _timer;
|
||||||
|
bool _isDialogShowing = false;
|
||||||
|
|
||||||
|
var currentConnectedDeviceProp;
|
||||||
|
var connectDeviceCurrent = null;
|
||||||
|
List bleDevice = [];
|
||||||
|
String currentMsg = "寻找设备中...";
|
||||||
|
Timer? connectTimer;
|
||||||
|
bool isFind = false;
|
||||||
|
List bindArrBackup = [];
|
||||||
|
List bindArr = ["", "", ""];
|
||||||
|
StreamSubscription<List<ScanResult>>? _scanSubscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
mhtBlueToothController.model.blueRawData = [];
|
||||||
|
mhtBlueToothController.model.deviceDataStatus = [];
|
||||||
|
flutterBlue = FlutterBluePlus();
|
||||||
|
_checkBluetoothPermission();
|
||||||
|
mhtBlueToothController.startStatusPolling();
|
||||||
|
mhtBlueToothController.search.value = "";
|
||||||
|
mhtBlueToothController.currentDeviceMac?.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _checkBluetoothPermission() async {
|
||||||
|
PermissionStatus bluetoothStatus = await Permission.bluetooth.status;
|
||||||
|
PermissionStatus locationStatus = await Permission.location.status;
|
||||||
|
|
||||||
|
if (bluetoothStatus.isGranted && locationStatus.isGranted) {
|
||||||
|
_startScanning();
|
||||||
|
_startPeriodicScan();
|
||||||
|
} else {
|
||||||
|
_requestBluetoothPermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _requestBluetoothPermission() async {
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.bluetoothScan,
|
||||||
|
Permission.bluetoothConnect,
|
||||||
|
Permission.location,
|
||||||
|
].request();
|
||||||
|
|
||||||
|
bool allGranted = statuses[Permission.bluetoothScan]?.isGranted == true &&
|
||||||
|
statuses[Permission.bluetoothConnect]?.isGranted == true &&
|
||||||
|
statuses[Permission.location]?.isGranted == true;
|
||||||
|
|
||||||
|
if (allGranted) {
|
||||||
|
_startScanning();
|
||||||
|
_startPeriodicScan();
|
||||||
|
} else {
|
||||||
|
_showPermissionDeniedDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showPermissionDeniedDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text("权限提示".tr),
|
||||||
|
content: Text("应用需要蓝牙和位置权限才能扫描设备。请授予权限。".tr),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text("确定".tr),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startScanning() async {
|
||||||
|
if (!mounted || isScanning || !mhtBlueToothController.shouldScan.value) return;
|
||||||
|
|
||||||
|
_scanSubscription?.cancel();
|
||||||
|
var bluetoothState = await FlutterBluePlus.isOn;
|
||||||
|
mhtBlueToothController.model.bluetooth = bluetoothState;
|
||||||
|
mhtBlueToothController.updateAll();
|
||||||
|
|
||||||
|
if (!bluetoothState && !_isDialogShowing) {
|
||||||
|
_isDialogShowing = true;
|
||||||
|
mhtBlueToothController.model.blueRawData = [];
|
||||||
|
mhtBlueToothController.model.deviceDataStatus = [];
|
||||||
|
mhtBlueToothController.updateAll();
|
||||||
|
await _showBluetoothNotEnabledDialog();
|
||||||
|
_isDialogShowing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isScanning) {
|
||||||
|
setState(() {
|
||||||
|
isScanning = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await FlutterBluePlus.startScan(timeout: Duration(seconds: 10));
|
||||||
|
|
||||||
|
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
final signalThreshold = mhtBlueToothController.model.singal!;
|
||||||
|
final searchKey = mhtBlueToothController.search.value.trim().toLowerCase();
|
||||||
|
|
||||||
|
final filteredResults = results.where((r) {
|
||||||
|
final localName = r.advertisementData.localName;
|
||||||
|
final isTarget = r.rssi > signalThreshold &&
|
||||||
|
isTargetDevice(localName, widget.data['reg'].cast<String>());
|
||||||
|
|
||||||
|
if (!isTarget) return false;
|
||||||
|
|
||||||
|
final name = r.advertisementData.advName.toLowerCase();
|
||||||
|
String macAddress = r.device.remoteId.str;
|
||||||
|
final mac = macAddress.replaceAll(':', '');
|
||||||
|
final search = searchKey.trim().replaceAll(':', '').toLowerCase();
|
||||||
|
|
||||||
|
if (search.isNotEmpty &&
|
||||||
|
!name.contains(search) &&
|
||||||
|
!mac.replaceAll(':', '').toLowerCase().contains(search)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}).map((r) {
|
||||||
|
return BlueToothDataModel.fromScanResult(
|
||||||
|
r, widget.data['type']?.toInt(),
|
||||||
|
bind: false,
|
||||||
|
name: r.advertisementData.localName,
|
||||||
|
mac: r.device.remoteId.str.replaceAll(':', ''));
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
mhtBlueToothController.model.blueRawData = filteredResults;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await Future.delayed(Duration(seconds: 10));
|
||||||
|
await FlutterBluePlus.stopScan();
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isScanning = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startPeriodicScan() {
|
||||||
|
_timer = Timer.periodic(Duration(seconds: 10), (timer) {
|
||||||
|
if (mhtBlueToothController.shouldScan.value && !isScanning) {
|
||||||
|
_startScanning();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _stopScanning() {
|
||||||
|
if (isScanning) {
|
||||||
|
FlutterBluePlus.stopScan();
|
||||||
|
_scanSubscription?.cancel();
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isScanning = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _stopPeriodicScan() {
|
||||||
|
_timer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_stopPeriodicScan();
|
||||||
|
_stopScanning();
|
||||||
|
_scanSubscription?.cancel();
|
||||||
|
connectTimer?.cancel();
|
||||||
|
mhtBlueToothController.stopStatusPolling();
|
||||||
|
mhtBlueToothController.model.blueRawData = [];
|
||||||
|
mhtBlueToothController.model.deviceDataStatus = [];
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTargetDevice(String? name, List<String> keywords) {
|
||||||
|
if (name == null) return false;
|
||||||
|
return keywords.any((k) => name.contains(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
_showBluetoothNotEnabledDialog() async {
|
||||||
|
await showTipDialog(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
context,
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"蓝牙未开启".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: AppConstants().title_text_fontSize,
|
||||||
|
color: stringToColor("#333333"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 20.rpx,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"请先打开蓝牙在进行设备扫描".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: AppConstants().normal_text_fontSize,
|
||||||
|
color: stringToColor("#333333"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, boxConstraints) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/images/new_background.png'),
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
appBar: AppBar(
|
||||||
|
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
titleSpacing: 0,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'添加设备'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [],
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
stringToColor("FCFCFC"),
|
||||||
|
stringToColor("CEECE3")
|
||||||
|
],
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20.rpx),
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 30.rpx, 0, 30.rpx),
|
||||||
|
child: Obx(() {
|
||||||
|
return Text(
|
||||||
|
(mhtBlueToothController.model.bluetooth ==
|
||||||
|
null ||
|
||||||
|
mhtBlueToothController
|
||||||
|
.model.bluetooth ==
|
||||||
|
false)
|
||||||
|
? "等待扫描".tr
|
||||||
|
: '扫描中'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: stringToColor("#003058"),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
stringToColor("FCFCFC"),
|
||||||
|
stringToColor("CEECE3")
|
||||||
|
],
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20.rpx),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
21.rpx, 5.rpx, 21.rpx, 5.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'最小信号强度'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: stringToColor("#003058"),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Obx(() {
|
||||||
|
return Slider(
|
||||||
|
activeColor: Color(0xFF1FCC9B),
|
||||||
|
inactiveColor:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.alternate,
|
||||||
|
min: -100,
|
||||||
|
max: 50,
|
||||||
|
value:
|
||||||
|
mhtBlueToothController.model.singal!,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
newValue = double.parse(
|
||||||
|
newValue.toStringAsFixed(0));
|
||||||
|
mhtBlueToothController.model.singal =
|
||||||
|
newValue;
|
||||||
|
_startScanning();
|
||||||
|
mhtBlueToothController.updateAll();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
return Text(
|
||||||
|
'${mhtBlueToothController.model.singal!.toInt()}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: stringToColor("#003058"),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
].divide(SizedBox(width: 30.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
borderRadius: BorderRadius.circular(20.rpx),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
35.rpx, 0, 35.rpx, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 0.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 25.rpx,
|
||||||
|
height: 25.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/query.svg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
color: stringToColor("#333333"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
width: 100.rpx,
|
||||||
|
height: 90.rpx,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: FlutterFlowTheme.of(context)
|
||||||
|
.secondaryBackground,
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment:
|
||||||
|
AlignmentDirectional(-1, 0),
|
||||||
|
child: TextFormField(
|
||||||
|
initialValue:
|
||||||
|
mhtBlueToothController
|
||||||
|
.search.value,
|
||||||
|
onChanged: (Value) {
|
||||||
|
mhtBlueToothController
|
||||||
|
.search.value = Value;
|
||||||
|
},
|
||||||
|
autofocus: false,
|
||||||
|
obscureText: false,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
labelStyle:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
hintText: '检索设备'.tr,
|
||||||
|
hintStyle:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
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: themeController
|
||||||
|
.currentColor.sc22,
|
||||||
|
),
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
cursorColor:
|
||||||
|
stringToColor("#003058"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 6.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
26.rpx, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 50.rpx,
|
||||||
|
child: VerticalDivider(
|
||||||
|
thickness: 2.rpx,
|
||||||
|
color: stringToColor("#333333"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc4,
|
||||||
|
borderRadius: 6.rpx,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onTap: () async {
|
||||||
|
_startScanning();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'搜索'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: stringToColor("#333333"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 26.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 60.rpx, 0, 32.rpx),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
19.rpx, 0, 0, 0),
|
||||||
|
child: Obx(() {
|
||||||
|
return Text(
|
||||||
|
'匹配出的外围设备'.tr +
|
||||||
|
"(${mhtBlueToothController.model.deviceDataStatus!.length})",
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
if (mhtBlueToothController
|
||||||
|
.model.deviceDataStatus!.isNotEmpty) {
|
||||||
|
return Expanded(
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
...mhtBlueToothController
|
||||||
|
.model.deviceDataStatus!
|
||||||
|
.map((device) {
|
||||||
|
return DeviceComponentWidget(
|
||||||
|
bleDevice: device,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(height: 30.rpx))
|
||||||
|
.addToEnd(SizedBox(height: 30.rpx)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
|
}),
|
||||||
|
].divide(SizedBox(
|
||||||
|
height: 30.rpx,
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 52.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20.rpx),
|
||||||
|
border: Border.all(
|
||||||
|
color: themeController.currentColor.sc4
|
||||||
|
.withOpacity(0.5),
|
||||||
|
width: AppConstants().border_width,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 30.rpx, 30.rpx, 30.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 8.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 23.rpx,
|
||||||
|
height: 23.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/tips.svg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'蓝牙绑定提示'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 23.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 30.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
1060
lib/pages/mh_page/device/mht_device_calibration.dart
Normal file
1060
lib/pages/mh_page/device/mht_device_calibration.dart
Normal file
File diff suppressed because it is too large
Load Diff
1119
lib/pages/mh_page/device/mht_wifi_page.dart
Normal file
1119
lib/pages/mh_page/device/mht_wifi_page.dart
Normal file
File diff suppressed because it is too large
Load Diff
36
lib/pages/mh_page/device/model/BlueToothDataModel.dart
Normal file
36
lib/pages/mh_page/device/model/BlueToothDataModel.dart
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
|
|
||||||
|
class BlueToothDataModel {
|
||||||
|
String name;
|
||||||
|
bool bind;
|
||||||
|
String mac;
|
||||||
|
ScanResult scanResult;
|
||||||
|
String macA;
|
||||||
|
String macB;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
BlueToothDataModel({
|
||||||
|
this.name = '',
|
||||||
|
required this.bind,
|
||||||
|
required this.mac,
|
||||||
|
required this.scanResult,
|
||||||
|
required this.type,
|
||||||
|
this.macA = '',
|
||||||
|
this.macB = '',
|
||||||
|
});
|
||||||
|
|
||||||
|
factory BlueToothDataModel.fromScanResult(ScanResult result,int type,
|
||||||
|
{bool bind = false, String name = '', String mac = ''}) {
|
||||||
|
// 如果外部没有传入 name,则取 localName
|
||||||
|
String finalName =
|
||||||
|
name.isNotEmpty ? name : (result.advertisementData.localName ?? '');
|
||||||
|
|
||||||
|
return BlueToothDataModel(
|
||||||
|
name: finalName,
|
||||||
|
bind: bind,
|
||||||
|
mac: mac,
|
||||||
|
scanResult: result,
|
||||||
|
type:type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
103
lib/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart
Normal file
103
lib/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.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/component/tool/CustomCard.dart';
|
||||||
|
|
||||||
|
class HomeDeviceStausWidget extends StatefulWidget {
|
||||||
|
final deviceStatus;
|
||||||
|
|
||||||
|
const HomeDeviceStausWidget({super.key, required this.deviceStatus});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeDeviceStausWidget> createState() => _HomeDeviceStausWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeDeviceStausWidgetState extends State<HomeDeviceStausWidget> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: BoxConstraints(minHeight: 180.rpx),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xFF003058),
|
||||||
|
borderRadius: BorderRadius.circular(16.rpx),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(67.rpx, 0.rpx, 30.rpx, 0.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 170.rpx,
|
||||||
|
height: 81.rpx,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
child: Image.network(
|
||||||
|
widget.deviceStatus['device_image'], // 从DeviceStatus获取图片
|
||||||
|
width: 200.rpx,
|
||||||
|
height: 200.rpx,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${(widget.deviceStatus['name'] ?? '').isEmpty ? '未命名'.tr : widget.deviceStatus['name']}',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 26.rpx)),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Text(
|
||||||
|
// widget.deviceStatus['status'] == 1 ? '在线'.tr : '离线'.tr,
|
||||||
|
// style: TextStyle(
|
||||||
|
// color: widget.deviceStatus['status'] == 1
|
||||||
|
// ? stringToColor("#07BD60")
|
||||||
|
// : stringToColor("#F84B20"),
|
||||||
|
// fontSize: 26.rpx,
|
||||||
|
// letterSpacing: 0.0.rpx,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
CustomCard(
|
||||||
|
gradientDirection: GradientDirection.vertical,
|
||||||
|
borderRadius: 10.rpx,
|
||||||
|
onTap: () {
|
||||||
|
// 点击回调逻辑放这里
|
||||||
|
},
|
||||||
|
colors:
|
||||||
|
AppConstants().mhtButtongradientColors, // 你原本没有渐变,单色即可
|
||||||
|
enableGradient: true, // 关闭渐变
|
||||||
|
enableAnimation: true, // 启用缩放动画
|
||||||
|
child: SizedBox(
|
||||||
|
width: 150.rpx,
|
||||||
|
height: 61.rpx,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'控制'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Color(0xFF003058),
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 36.rpx)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
lib/pages/mh_page/homepage/component/HomeDeviceWidget.dart
Normal file
53
lib/pages/mh_page/homepage/component/HomeDeviceWidget.dart
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart';
|
||||||
|
|
||||||
|
class HomeDeviceWidget extends StatefulWidget {
|
||||||
|
final String roomName;
|
||||||
|
final List deviceStatusList;
|
||||||
|
|
||||||
|
const HomeDeviceWidget({
|
||||||
|
super.key,
|
||||||
|
required this.roomName,
|
||||||
|
required this.deviceStatusList,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeDeviceWidget> createState() => _HomeDeviceWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeDeviceWidgetState extends State<HomeDeviceWidget> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(16.rpx, 0.rpx, 0.rpx, 35.rpx),
|
||||||
|
child: Text(
|
||||||
|
widget.roomName,
|
||||||
|
maxLines: 2,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Color(0xFFFBFDFF),
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: widget.deviceStatusList
|
||||||
|
.map((deviceStatus) => HomeDeviceStausWidget(deviceStatus: deviceStatus))
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(height: 30.rpx)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
330
lib/pages/mh_page/homepage/controller/mht_home_controller.dart
Normal file
330
lib/pages/mh_page/homepage/controller/mht_home_controller.dart
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
|
part 'mht_home_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class MHTHomeModel {
|
||||||
|
MHTHomeModel();
|
||||||
|
|
||||||
|
// 从JSON反序列化时的异常处理
|
||||||
|
|
||||||
|
factory MHTHomeModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$MHTHomeModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
||||||
|
return MHTHomeModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$MHTHomeModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MHTHomeController extends GetControllerEx<MHTHomeModel> {
|
||||||
|
MHTHomeController() {
|
||||||
|
attr = GetModel(MHTHomeModel()).obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
RxInt bindDeviceNum = 0.obs; //设备数量
|
||||||
|
RxMap deviceList = {}.obs; //设备列表
|
||||||
|
RxMap<String, List<dynamic>> sleepReportData = <String, List<dynamic>>{}.obs;
|
||||||
|
|
||||||
|
RxString keyWord = "".obs;
|
||||||
|
|
||||||
|
String wifiMac = "";
|
||||||
|
|
||||||
|
Future<ApiResponse> getDeviceNum() async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_list;
|
||||||
|
String queryUrl =
|
||||||
|
"${serviceAddress}${serviceName}${serviceApi}?bindNum=1";
|
||||||
|
String? language = "";
|
||||||
|
if (languageController.selectLanguage != null) {
|
||||||
|
language = languageController.selectLanguage.value!.language_code;
|
||||||
|
}
|
||||||
|
if (language != null && language.isNotEmpty) {
|
||||||
|
if (queryUrl.contains("?")) {
|
||||||
|
queryUrl += "&lang=$language";
|
||||||
|
} else {
|
||||||
|
queryUrl += "?lang=$language";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "设备.设备列表请求成功".tr, "设备.设备列表请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
bindDeviceNum.value = res.total!;
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> getDeviceList(
|
||||||
|
{String? key, String? group, int? bindType}) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_list;
|
||||||
|
|
||||||
|
// 初始URL
|
||||||
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
|
|
||||||
|
// 用Map统一管理query参数
|
||||||
|
Map<String, String> queryParams = {};
|
||||||
|
|
||||||
|
if (key != null && key.isNotEmpty) {
|
||||||
|
queryParams['key'] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group != null && group.isNotEmpty) {
|
||||||
|
queryParams['group'] = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindType != null) {
|
||||||
|
queryParams['bindType'] = bindType.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String? language = "";
|
||||||
|
if (languageController.selectLanguage != null) {
|
||||||
|
language = languageController.selectLanguage.value!.language_code;
|
||||||
|
}
|
||||||
|
if (language != null && language.isNotEmpty) {
|
||||||
|
queryParams['lang'] = language;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接完整URL
|
||||||
|
if (queryParams.isNotEmpty) {
|
||||||
|
queryUrl += '?' + Uri(queryParameters: queryParams).query;
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "设备.设备列表请求成功".tr, "设备.设备列表请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
deviceList.value = res.data!;
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> deleteDevice(Map<String, dynamic> device) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_bind;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
String? language = "";
|
||||||
|
if (languageController.selectLanguage != null) {
|
||||||
|
language = languageController.selectLanguage.value!.language_code;
|
||||||
|
}
|
||||||
|
if (language != null && language.isNotEmpty) {
|
||||||
|
if (queryUrl.contains("?")) {
|
||||||
|
queryUrl += "&lang=$language";
|
||||||
|
} else {
|
||||||
|
queryUrl += "?lang=$language";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final data = {
|
||||||
|
"mac": device['mac'],
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.delete(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("解绑设备: $e");
|
||||||
|
DailyLogUtils.writeLog("解绑设备: $e");
|
||||||
|
} finally {
|
||||||
|
EasyDartModule.logger.info("用户操作:解绑设备");
|
||||||
|
DailyLogUtils.writeLog("用户操作:解绑设备");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> getSleepReport() async {
|
||||||
|
try {
|
||||||
|
sleepReportData.value = {};
|
||||||
|
ApiResponse<Map<String, List<dynamic>>> apiResponse = ApiResponse(
|
||||||
|
code: -1,
|
||||||
|
msg: "请求失败".tr,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (deviceList.value.isEmpty) {
|
||||||
|
return ApiResponse(
|
||||||
|
code: HttpStatusCodes.ok,
|
||||||
|
msg: "请求成功".tr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.sleep_report;
|
||||||
|
|
||||||
|
// for (var device in deviceList.value) {
|
||||||
|
// String mac = device['mac'] ?? "";
|
||||||
|
// if (mac.isEmpty) continue;
|
||||||
|
|
||||||
|
// sleepReportData[mac] = []; // 初始化当前设备的数据列表
|
||||||
|
|
||||||
|
// String queryUrl =
|
||||||
|
// "$serviceAddress$serviceName$serviceApi?mac=$mac&time=${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// String? language = "";
|
||||||
|
// if (languageController.selectLanguage != null) {
|
||||||
|
// language = languageController.selectLanguage.value!.language_code;
|
||||||
|
// }
|
||||||
|
// if (language != null && language.isNotEmpty) {
|
||||||
|
// if (queryUrl.contains("?")) {
|
||||||
|
// queryUrl += "&lang=$language";
|
||||||
|
// } else {
|
||||||
|
// queryUrl += "?lang=$language";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
// if (response != null) {
|
||||||
|
// var responseData = response.data is String
|
||||||
|
// ? jsonDecode(response.data)
|
||||||
|
// : response.data;
|
||||||
|
|
||||||
|
// ApiResponse res =
|
||||||
|
// ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
|
||||||
|
// if (res.code == HttpStatusCodes.ok && res.data != null) {
|
||||||
|
// // 确保数据是一个列表
|
||||||
|
// if (res.data is List) {
|
||||||
|
// sleepReportData[mac] = List.from(res.data);
|
||||||
|
// } else {
|
||||||
|
// sleepReportData[mac] = [res.data];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// EasyDartModule.logger.warning("请求设备 $mac 的睡眠数据失败: $e");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (sleepReportData.value.isNotEmpty) {
|
||||||
|
// 遍历 Map 中的每一个键值对
|
||||||
|
sleepReportData.value.forEach((key, report) {
|
||||||
|
// 确保 report 列表不为空
|
||||||
|
if (report.isNotEmpty) {
|
||||||
|
// 获取该列表的最后一个元素
|
||||||
|
var lastElement = report.last;
|
||||||
|
|
||||||
|
// 给最后一个元素添加 selected 属性
|
||||||
|
lastElement['selected'] = true; // 假设每个元素是一个 Map 类型
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAll();
|
||||||
|
|
||||||
|
return ApiResponse(
|
||||||
|
code: HttpStatusCodes.ok,
|
||||||
|
msg: "请求成功".tr,
|
||||||
|
data: sleepReportData,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表异常: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表异常: $e");
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr, data: {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDeviceShow(device) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "操作失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_show;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
String? language = "";
|
||||||
|
if (languageController.selectLanguage != null) {
|
||||||
|
language = languageController.selectLanguage.value!.language_code;
|
||||||
|
}
|
||||||
|
if (language != null && language.isNotEmpty) {
|
||||||
|
if (queryUrl.contains("?")) {
|
||||||
|
queryUrl += "&lang=$language";
|
||||||
|
} else {
|
||||||
|
queryUrl += "?lang=$language";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
"id": device['_id'],
|
||||||
|
"show": !device['show'],
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("更新显示异常: $e");
|
||||||
|
DailyLogUtils.writeLog("更新显示异常: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'mht_home_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
MHTHomeModel _$MHTHomeModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
MHTHomeModel();
|
||||||
|
|
||||||
|
Map<String, dynamic> _$MHTHomeModelToJson(MHTHomeModel instance) =>
|
||||||
|
<String, dynamic>{};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ part 'mht_login_controller.g.dart';
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class LoginModel {
|
class LoginModel {
|
||||||
//版本id
|
//版本id
|
||||||
int? loginStyle = 1; //1.密码登录 2.短信登录
|
int? loginStyle = 1; //1.密码登录 2.短信登录(登录类型: 1:手机号/邮箱+验证码 2:微信一键登录 3:手机号+密码)
|
||||||
|
|
||||||
String? account = '17649984946'; //账户
|
String? account = '17649984946'; //账户
|
||||||
// String? account = '13953240733'; //账户
|
// String? account = '13953240733'; //账户
|
||||||
@@ -124,13 +124,20 @@ class MHTLoginController extends GetControllerEx<LoginModel> {
|
|||||||
if (registerController.model.register_agree == null ||
|
if (registerController.model.register_agree == null ||
|
||||||
registerController.model.register_agree != true) {
|
registerController.model.register_agree != true) {
|
||||||
message = "需要同意协议".tr;
|
message = "需要同意协议".tr;
|
||||||
showToast(message);
|
TopSlideNotification.show(context,
|
||||||
|
text: message, textColor: themeController.currentColor.sc9);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
int type = 1;
|
||||||
|
if (model.loginStyle == 1) {
|
||||||
|
type = 3;
|
||||||
|
} else if (model.loginStyle == 2) {
|
||||||
|
type = 1;
|
||||||
|
}
|
||||||
var data = {
|
var data = {
|
||||||
"type": model.loginStyle == 1 ? 3 : 2,
|
"type": type,
|
||||||
"userName": model.account,
|
"userName": model.account,
|
||||||
"password": model.password,
|
"password": password,
|
||||||
};
|
};
|
||||||
String serviceAddress = ServiceConstant.service_address;
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
String serviceName = ServiceConstant.server_service;
|
String serviceName = ServiceConstant.server_service;
|
||||||
@@ -169,20 +176,42 @@ class MHTLoginController extends GetControllerEx<LoginModel> {
|
|||||||
if (registerController.model.register_agree == null ||
|
if (registerController.model.register_agree == null ||
|
||||||
registerController.model.register_agree != true) {
|
registerController.model.register_agree != true) {
|
||||||
message = "需要同意协议".tr;
|
message = "需要同意协议".tr;
|
||||||
showToast(message);
|
TopSlideNotification.show(context,
|
||||||
|
text: message, textColor: themeController.currentColor.sc9);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
if (model.phone == null || model.phone!.isEmpty) {
|
if (model.phone == null || model.phone!.isEmpty) {
|
||||||
message = "请输入手机号".tr;
|
message = "请输入手机号".tr;
|
||||||
showToast(message);
|
TopSlideNotification.show(context,
|
||||||
|
text: message, textColor: themeController.currentColor.sc9);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
if (!MyUtils.isValidPhoneNumber(model.phone!)) {
|
if (!MyUtils.isValidPhoneNumber(model.phone!)) {
|
||||||
message = '请输入正确的手机号'.tr;
|
message = '请输入正确的手机号'.tr;
|
||||||
showToast(message);
|
TopSlideNotification.show(context,
|
||||||
|
text: message, textColor: themeController.currentColor.sc9);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
return '';
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.send_code;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var data = {"userName": model.phone, "type": 1};
|
||||||
|
await requestWithLog(
|
||||||
|
data: data,
|
||||||
|
logTitle: "发送验证码",
|
||||||
|
method: MyHttpMethod.post,
|
||||||
|
queryUrl: queryUrl,
|
||||||
|
onSuccess: (res) {
|
||||||
|
TopSlideNotification.show(context, text: "发送验证码成功".tr);
|
||||||
|
},
|
||||||
|
onFailure: (res) {
|
||||||
|
message = res.msg!;
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: message, textColor: themeController.currentColor.sc9);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
//微信登录
|
//微信登录
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ RegisterModel _$RegisterModelFromJson(Map<String, dynamic> json) =>
|
|||||||
..register_confirm_pd = json['register_confirm_pd'] as String?
|
..register_confirm_pd = json['register_confirm_pd'] as String?
|
||||||
..register_code = json['register_code'] as String?
|
..register_code = json['register_code'] as String?
|
||||||
..register_agree = json['register_agree'] as bool?
|
..register_agree = json['register_agree'] as bool?
|
||||||
|
..save_password = json['save_password'] as bool?
|
||||||
..pdshow = json['pdshow'] as bool?
|
..pdshow = json['pdshow'] as bool?
|
||||||
..cpdshow = json['cpdshow'] as bool?;
|
..cpdshow = json['cpdshow'] as bool?;
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ Map<String, dynamic> _$RegisterModelToJson(RegisterModel instance) =>
|
|||||||
'register_confirm_pd': instance.register_confirm_pd,
|
'register_confirm_pd': instance.register_confirm_pd,
|
||||||
'register_code': instance.register_code,
|
'register_code': instance.register_code,
|
||||||
'register_agree': instance.register_agree,
|
'register_agree': instance.register_agree,
|
||||||
|
'save_password': instance.save_password,
|
||||||
'pdshow': instance.pdshow,
|
'pdshow': instance.pdshow,
|
||||||
'cpdshow': instance.cpdshow,
|
'cpdshow': instance.cpdshow,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:vbvs_app/common/util/CheckNetwork.dart';
|
|||||||
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.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/CustomCard.dart';
|
||||||
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
import 'package:vbvs_app/controller/time/countdown_controller.dart';
|
import 'package:vbvs_app/controller/time/countdown_controller.dart';
|
||||||
@@ -947,7 +948,7 @@ class MHTLoginPage extends GetView<MHTLoginController> {
|
|||||||
.countdown
|
.countdown
|
||||||
.value ==
|
.value ==
|
||||||
0
|
0
|
||||||
? '获取验证码'
|
? '获取验证码'.tr
|
||||||
: '${countdownController.countdown.value}' +
|
: '${countdownController.countdown.value}' +
|
||||||
'秒'.tr,
|
'秒'.tr,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -2049,7 +2050,32 @@ class MHTLoginPage extends GetView<MHTLoginController> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 30.rpx,
|
height: 30.rpx,
|
||||||
),
|
),
|
||||||
Container(
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.white, // 背景色
|
||||||
|
highlightColor: Colors.grey, // 点击水波纹颜色
|
||||||
|
borderRadius: 999.rpx,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onTap: () async {
|
||||||
|
//loginController.model.isIos == true &&
|
||||||
|
// if (loginController
|
||||||
|
// .model.register_agree ==
|
||||||
|
// null ||
|
||||||
|
// loginController
|
||||||
|
// .model.register_agree !=
|
||||||
|
// true) {
|
||||||
|
// TopSlideNotification.show(
|
||||||
|
// context,
|
||||||
|
// text: "登录页.未同意协议".tr,
|
||||||
|
// textColor:
|
||||||
|
// themeController.currentColor.sc9,
|
||||||
|
// );
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// await loginController
|
||||||
|
// .wxLoginSendAuth(context);
|
||||||
|
TopSlideNotification.show(context,text: "测试阶段,暂不支持".tr);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
width: 90.rpx,
|
width: 90.rpx,
|
||||||
height: 90.rpx,
|
height: 90.rpx,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -2060,6 +2086,7 @@ class MHTLoginPage extends GetView<MHTLoginController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ class _EPageState extends State<PersonPage> {
|
|||||||
if (apiRespons.code == HttpStatusCodes.ok) {
|
if (apiRespons.code == HttpStatusCodes.ok) {
|
||||||
TopSlideNotification.show(context,
|
TopSlideNotification.show(context,
|
||||||
text: apiRespons.msg!);
|
text: apiRespons.msg!);
|
||||||
updateDeviceBindStatus(blueteethBindController.currentDeviceMac!.value);
|
updateDeviceBindStatus(blueteethBindController
|
||||||
|
.currentDeviceMac!.value);
|
||||||
Get.offNamed("/bindDeviceSuccess");
|
Get.offNamed("/bindDeviceSuccess");
|
||||||
} else {
|
} else {
|
||||||
TopSlideNotification.show(context,
|
TopSlideNotification.show(context,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
|
||||||
|
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/main.dart';
|
import 'package:vbvs_app/pages/device_bind/bind_device_success.dart';
|
||||||
import 'package:vbvs_app/pages/main_bottom/component/main_page_b_bottom_change.dart';
|
import 'package:vbvs_app/pages/main_bottom/component/main_page_b_bottom_change.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/HomeDeviceType.dart';
|
import 'package:vbvs_app/pages/mh_page/HomeDeviceType.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/LanguagePage.dart';
|
import 'package:vbvs_app/pages/mh_page/LanguagePage.dart';
|
||||||
@@ -12,6 +11,10 @@ import 'package:vbvs_app/pages/mh_page/address_list_page.dart';
|
|||||||
import 'package:vbvs_app/pages/mh_page/apply_repair_page.dart';
|
import 'package:vbvs_app/pages/mh_page/apply_repair_page.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/book_info_page.dart';
|
import 'package:vbvs_app/pages/mh_page/book_info_page.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/book_success_page.dart';
|
import 'package:vbvs_app/pages/mh_page/book_success_page.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/mht_bind_device_type.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/mht_blueteeth_device_page.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/mht_device_calibration.dart';
|
||||||
|
import 'package:vbvs_app/pages/mh_page/device/mht_wifi_page.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/device_list.dart';
|
import 'package:vbvs_app/pages/mh_page/device_list.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/device_people_info.dart';
|
import 'package:vbvs_app/pages/mh_page/device_people_info.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/device_share_page.dart';
|
import 'package:vbvs_app/pages/mh_page/device_share_page.dart';
|
||||||
@@ -51,9 +54,8 @@ var mhroutes = {
|
|||||||
"/addressListPage": (contxt) => AddressListPage(),
|
"/addressListPage": (contxt) => AddressListPage(),
|
||||||
"/editAddressPage": (contxt) => EditAddressPage(),
|
"/editAddressPage": (contxt) => EditAddressPage(),
|
||||||
"/languagePage": (context) => LanguagePage(),
|
"/languagePage": (context) => LanguagePage(),
|
||||||
'/bluetoothPage': (context, {arguments}) => BluetoothPage(data: arguments),
|
// '/bluetoothPage': (context) => BluetoothPage(),
|
||||||
"/devicePeopleInfo": (context, {arguments}) =>
|
// "/devicePeopleInfo": (context) => DevicePeopleInfo(),
|
||||||
DevicePeopleInfo(data: arguments),
|
|
||||||
"/sleepHabitPage": (context) => SleepHabitPage(),
|
"/sleepHabitPage": (context) => SleepHabitPage(),
|
||||||
'/syms': (context) => Smys(),
|
'/syms': (context) => Smys(),
|
||||||
"/applyRepairPage": (context) => ApplyRepairPage(),
|
"/applyRepairPage": (context) => ApplyRepairPage(),
|
||||||
@@ -71,6 +73,12 @@ var mhroutes = {
|
|||||||
"/updatePasswordPage": (context) => UpdatePasswordPage(),
|
"/updatePasswordPage": (context) => UpdatePasswordPage(),
|
||||||
"/deviceSharePage": (context) => ShareDeviceWidget(),
|
"/deviceSharePage": (context) => ShareDeviceWidget(),
|
||||||
"/deviceListPage": (context) => DeviceListPage(),
|
"/deviceListPage": (context) => DeviceListPage(),
|
||||||
|
"/mHTDeviceTypePage": (context, {arguments}) => MHTBindDeviceTypePage(),
|
||||||
|
"/mHTBlueteethDevicePage": (context, {arguments}) =>
|
||||||
|
MHTBlueteethDevicePage(data: arguments),
|
||||||
|
"/mHTwifiPage": (contxt, {arguments}) => MHTWifiPage(deviceInfo: arguments),
|
||||||
|
"/calibrationPage": (contxt) => MHTCalibrationPage(),
|
||||||
|
"/bindDeviceSuccess": (contxt) => BindDeviceSuccess(),
|
||||||
};
|
};
|
||||||
var mhonGenerateRoute = (RouteSettings settings) {
|
var mhonGenerateRoute = (RouteSettings settings) {
|
||||||
final String? name = settings.name; // 获取路由名称,如 /news 或 /search
|
final String? name = settings.name; // 获取路由名称,如 /news 或 /search
|
||||||
|
|||||||
Reference in New Issue
Block a user