Files
tuiche/lib/pages/mh_page/test/WebviewTestModel.dart
2025-09-11 09:38:14 +08:00

697 lines
25 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
import 'package:easydevice/easydevice.dart';
import 'package:easyweb/base/easyws.dart';
import 'package:easyweb/base/minisdk.dart';
import 'package:easyweb/easyweb.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/color/ServiceConstant.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/controller/user_info_controller.dart';
import 'package:vbvs_app/model/WebSocketMessage.dart';
import 'package:vbvs_app/pages/main_bottom/component/main_page_b_bottom_change.dart';
import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart';
import 'package:vbvs_app/pages/mh_page/device/mht_blueteeth_device_page.dart';
import 'package:vbvs_app/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart';
import 'package:vbvs_app/pages/mh_page/homepage/controller/mht_home_controller.dart';
class WebviewTestModel {
WebviewTestModel();
//EasyFlutter Start[Model]
//EasyFlutter End
}
class WebviewTestController extends GetControllerEx<WebviewTestModel> {
var selectDevice = {};
var lastSelectDevice = {};
var bluetooth = 0;
List personList = [];
List instantData = [];
RxBool initFlag = false.obs;
Timer? _resourceLoadTimer;
Widget webviewWidget = Container();
WebviewTestController() : super(WebviewTestModel()) {
web = WebviewHelper(
isheadless: false,
jsbridge: buildsdk(
// father: this,
// clientId: '494641114',
// clientId: '123',
// dbgserverUrl: 'ws://192.168.1.2:9001',
),
settings: buildsettings(),
params: PlatformHeadlessInAppWebViewCreationParams(
onLoadStop: (controller, url) {
setState(() {
ready.value = true;
});
},
onLoadResource: (controller, resource) {
// sourceTime = web.requestTimestamp;
// ef.log("[请求资源时间]${web.requestTimestamp}");`
// _startMonitoringIfNeeded();
},
),
);
try {
web.jsbridge!.bind((bridge) {
var minible = Minibleapp(
bridge: bridge,
onConnect: (args1, args2) {
final devices = args1.devices as Map<String, dynamic>;
final mac = args2 as String;
if (devices.containsKey(mac)) {
final device = devices[mac];
ef.log('Minibleapp connected(Android): $mac -> $device');
return device;
}
// iOS: 遍历所有设备,解析 manufacturerData 拿真实 deviceId(mac)
for (final entry in devices.entries) {
final manufacturerData = entry.value.manufacturerData;
String? deviceId;
if (manufacturerData != null) {
manufacturerData.forEach((key, data) {
if (data.isEmpty) return;
if (key == 65517) {
List<int> a = [0, 0, ...data];
final d = {};
advertisDataFormatter(a, d);
if (d['adData']?['deviceId'] != null) {
deviceId = d['adData']['deviceId'];
}
} else if (key == 11125 && data.length == 8) {
deviceId = ab2str(data.sublist(2, 8)).toUpperCase();
} else if (data.length == 8 &&
isQuanShiDevice(entry.value.name)) {
deviceId = ab2str(data.sublist(2, 8)).toUpperCase();
} else if ((data.length == 4 || data.length == 6) &&
isMHTSWES(entry.value.name)) {
List<int> a;
if (data.length == 4) {
ByteData bd = ByteData(2);
bd.setUint16(0, key, Endian.little);
a = [bd.getUint8(0), bd.getUint8(1), ...data];
} else {
a = [...data];
}
deviceId = ab2str(a).toUpperCase();
}
});
}
final normalizedMac = mac.replaceAll(":", "").toUpperCase();
if (deviceId != null &&
deviceId!.toUpperCase() == normalizedMac) {
return entry.value; // 返回匹配的设备
}
}
ef.log('Minibleapp connected: $mac not found in devices');
return null;
},
);
// ef.kvroot.devicelist.listen((x) {});
bridge.sdk.updateDeviceRoute((args) async {
ef.log('updateDeviceRoute: $args');
selectDevice['blueToothStatus'] = bluetooth;
Get.toNamed("${args[0]}", arguments: selectDevice);
return true;
});
bridge.sdk.selectDevice((args) async {
try {
ef.log('selectDevice: $args');
selectDevice = args[0];
await queryPersonInfoByMac();
if (selectDevice != null &&
selectDevice.isNotEmpty &&
selectDevice['mac'.tr] != null &&
(selectDevice['mac'.tr] != args[0]['mac'.tr])) {
lastSelectDevice = selectDevice;
}
edm.EasyDartModule.websocket.sendData(jsonEncode(
WebSocketMessage(path: "/smartbed/connect", type: 5, data: {
'mac'.tr: selectDevice['mac'.tr],
})));
dealInstantData(selectDevice);
} catch (e) {
ef.log("[切换设备失败]$e");
}
//查询人员信息
return true;
});
bridge.sdk.updateBlueToothStatus((args) async {
ef.log('updateBlueToothStatus: $args');
bluetooth = args[0];
selectDevice['blueToothStatus'] = bluetooth;
return true;
});
//sdk定义接口
bridge.sdk.querySelectDevice((args) async {
ef.log('querySelectDevice: $args');
// bluetooth = args[0];
MHTHomeController deviceController = Get.find();
await deviceController.getDeviceList(group: 'room');
final allDevices = deviceController.deviceList.values
.expand((list) => list)
.toList();
return allDevices;
});
//请求token信息
bridge.sdk.queryUserToken((args) async {
ef.log('queryUserToken: $args');
// bluetooth = args[0];
return edm.EasyDartModule.dio.token;
});
//请求设备人员信息
bridge.sdk.queryPersonInfo((args) async {
ef.log('queryPersonInfo: $args');
// bluetooth = args[0];
return personList;
});
//请求实时体征数据
bridge.sdk.queryInstantData((args) async {
ef.log('queryInstantData: $args');
// bluetooth = args[0];
return instantData;
});
bridge.sdk.startTimer((args) async {
ef.log('queryInstantData: $args');
MHTHomeController homeController = Get.find();
homeController.startTimer(args);
return true;
});
bridge.sdk.cancelTimer((args) async {
ef.log('queryInstantData: $args');
MHTHomeController homeController = Get.find();
homeController.cancelTimer(args);
return true;
});
bridge.sdk.restoreTimer((args) async {
ef.log('更新定时: $args[0]');
ef.log('queryInstantData: $args');
MHTHomeController homeController = Get.find();
var data = await homeController.restoreTimer(args);
return data;
});
bridge.sdk.toBindDevice((args) async {
ef.log('queryInstantData: $args');
Get.toNamed("/mHTDeviceTypePage");
return true;
});
bridge.sdk.saveSleepHabit((args) async {
ef.log('更新睡眠习惯: $args[0]');
try {
MHTBlueToothController blueToothController = Get.find();
await blueToothController.saveHabitData(args[0]);
} catch (e) {
ef.log("[更新睡眠习惯失败]:$e");
}
return true;
});
bridge.sdk.loadSleepHabit((args) async {
ef.log('查询睡眠习惯: $args[0]');
try {
MHTBlueToothController blueToothController = Get.find();
var sleepData = await blueToothController.loadHabitDataApi(args[0]);
return sleepData['data'];
} catch (e) {
ef.log("[查询睡眠习惯失败]:$e");
}
return true;
});
//--
bridge.sdk.saveMattressTimeData((args) async {
ef.log('更新睡眠习惯: $args[0]');
try {
MHTBlueToothController blueToothController = Get.find();
await blueToothController.saveMattressTimeData(args[0]);
} catch (e) {
ef.log("[更新睡眠习惯失败]:$e");
}
return true;
});
bridge.sdk.loadMattressTimeData((args) async {
ef.log('查询睡眠习惯: $args[0]');
try {
MHTBlueToothController blueToothController = Get.find();
var sleepData =
await blueToothController.loadMattressTimeData(args[0]);
return sleepData['data'];
} catch (e) {
ef.log("[查询睡眠习惯失败]:$e");
}
return true;
});
bridge.sdk.saveMemory((args) async {
ef.log('更新记忆: $args[0]');
try {
MHTBlueToothController blueToothController = Get.find();
// await blueToothController.saveHabitData(args[0]);
await blueToothController.saveJiYiData(args[0]);
} catch (e) {
ef.log("[更新记忆失败]:$e");
}
return true;
});
bridge.sdk.loadMemory((args) async {
try {
ef.log('查询记忆: $args[0]');
MHTBlueToothController blueToothController = Get.find();
var sleepData = await blueToothController.loadJiYiData(args[0]);
return sleepData['data'];
} catch (e) {
ef.log("[查询记忆失败]:$e");
}
return true;
});
bridge.sdk.webPageBuild((args) async {
ef.log('网页加载完成: $args[0]');
try {
initFlag.value = true;
return true;
} catch (e) {
ef.log("[网页加载失败]:$e");
}
return true;
});
bridge.sdk.updatePermisson((args) async {
// ef.log('获取权限: $args[0]');
try {
if (MainPageBBottomChange.getCurrentIndex() != 2) {
return false;
}
Map data = await checkBlueToothPermissin();
if (data == null || data.isEmpty) {
return false;
}
if (Platform.isIOS) {
if (!data['bluetoothScanGranted'] ||
!data['bluetoothConnectGranted']) {
return false;
}
} else if (Platform.isAndroid) {
if (!data['bluetoothScanGranted'] ||
!data['bluetoothConnectGranted'] ||
!data['locationGranted']) {
return false;
}
} else {
return false;
}
return true;
} catch (e) {
ef.log("[网页加载失败]:$e");
}
return true;
});
// bridge.sdk.bluetoothConnect((args) async {
// ef.log('[蓝牙连接失败]: $args[0]');
// try {
// selectDevice['blueToothStatus'] = 2;
// return true;
// } catch (e) {
// ef.log("[蓝牙连接失败]:$e");
// }
// return true;
// });
bridge.sdk.loadFinish((args) async {
ef.log('[资源加载完成]: $args[0]');
try {
loadRecource.value = true;
updateAll();
return true;
} catch (e) {
ef.log("[资源加载完成]:$e");
}
return true;
});
});
} catch (e, s) {
ef.log('$e,$s');
}
}
late WebviewHelper web;
var ready = false.obs;
var cnt = 0.obs;
var loadRecource = false.obs;
int sourceTime = 0;
Future<void> queryPersonInfoByMac() async {
UserInfoController userInfoController = Get.find();
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.person_info;
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?mac=${selectDevice['mac']}";
try {
final res = await requestWithLog(
logTitle: "查询设备绑定人员列表".tr,
method: MyHttpMethod.get,
queryUrl: queryUrl,
onSuccess: (res) {
personList = res.data;
});
} catch (e) {
print("查询设备绑定列表失败: $e");
}
}
void dealInstantData(selectDevice) {
//处理实时数据
// edm.EasyDartModule.websocket.sendData(
// jsonEncode(WebSocketMessage(path: "/vsbs/web/rt/marttress", type: 2)));
lastSelectDevice;
var ws;
ws = Easyws(
url: ServiceConstant.webSocketService,
onData: (data) {
// ef.log("ws recv =>$data");
try {
var tmp;
if (data is String) {
tmp = jsonDecode(data);
} else if (data is Map<String, dynamic>) {
tmp = data; // 直接用
} else {
print("未知数据格式".tr);
}
if (tmp['data'] != null && tmp['data'] is Map) {
var newData = tmp['data'];
var mac = newData['mac'.tr];
if (mac != null) {
// 删除已有的同 mac 项
instantData.removeWhere((element) => element['mac'.tr] == mac);
// 添加新的数据
instantData.add(newData);
}
}
} catch (e) {
ef.log("ws error =>$e");
}
},
onStateChange: (x) {
ef.log("ws =>$x");
if (x == EasywsState.connected) {
try {
if (lastSelectDevice != null && lastSelectDevice.isNotEmpty) {
List<String?> oldMacList = [
lastSelectDevice['bind_mac_a'],
lastSelectDevice['bind_mac_b'],
];
for (String? mac in oldMacList) {
if (mac != null && mac.isNotEmpty) {
bool success = ws.send({
"type": 2,
"path": "/vsbs/web/rt/marttress",
"data": {"mac".tr: mac},
});
if (success) {
// ef.log("✅ 已取消监听:$mac");
}
}
}
}
} catch (e) {
ef.log("❌ 取消旧设备监听失败: $e");
}
try {
// 2. 开始监听新设备A/B 都监听)
if (selectDevice != null && selectDevice.isNotEmpty) {
List<String?> newMacList = [
selectDevice['bind_mac_a'],
selectDevice['bind_mac_b'],
];
for (String? mac in newMacList) {
if (mac != null && mac.isNotEmpty) {
bool success = ws.send({
"type": 1,
"path": "/vsbs/web/rt/marttress",
"data": {"mac".tr: mac},
});
if (success) {
// ef.log("✅ 开始监听新设备:$mac");
}
}
}
// 更新记录
lastSelectDevice = selectDevice;
}
} catch (e) {
ef.log("❌ 监听新设备失败: $e");
}
}
},
);
ws.connect();
}
//EasyFlutter End
@override
void onInit() {
ef.log("webview test init =>${DateTime.now()}");
super.onInit();
try {
web.runApp('mhtControl').then((x) {
ready.value = true;
});
// web
// .network('https://wyf.it.real.he-info.cn:94/goods-front/index.html')
// .then((x) {
// ready.value = true;
// });
} catch (e, s) {
ef.log('$e,$s');
}
}
}
class WebviewTestView extends GetComponent<WebviewTestController> {
WebviewTestView({super.key, super.oncreate});
@override
WebviewTestController newinstance() {
if (ef.kvRoot.WebviewTestController == null) {
ef.kvRoot.WebviewTestController = WebviewTestController();
if (Get.isRegistered<WebviewTestController>() == false) {
Get.put<WebviewTestController>(ef.kvRoot.WebviewTestController);
WebviewTestController webviewTestController = Get.find();
webviewTestController.global = true;
return webviewTestController;
}
}
return ef.kvRoot.WebviewTestController;
}
@override
Widget build(BuildContext context) {
// controller.webviewWidget = controller.web.build();
return Obx(() {
UserInfoController userInfoController = Get.find();
MHTHomeController deviceController = Get.find();
final isLoggedIn = userInfoController.model.login == 1;
final hasDevice = deviceController.deviceList.values.isNotEmpty;
final showWeb = isLoggedIn && hasDevice;
final mainAxisAlignment =
showWeb ? MainAxisAlignment.start : MainAxisAlignment.center;
return Scaffold(
backgroundColor: Colors.transparent,
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: mainAxisAlignment,
children: [
// 未登录提示
if (!isLoggedIn)
Center(
child: InkWell(
onTap: () => Get.toNamed("/loginPage"),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "请先".tr,
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
),
),
WidgetSpan(
child: Stack(
children: [
Text(
"登录".tr,
style: TextStyle(
color: stringToColor("#84F5FF"),
fontSize: 30.rpx,
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 1,
color: stringToColor("#84F5FF"),
),
),
],
),
),
TextSpan(
text: "后,再进行设备控制".tr,
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
),
),
],
),
),
),
),
// 已登录但无设备提示
if (isLoggedIn && !hasDevice)
Center(
child: InkWell(
onTap: () => Get.toNamed("/mHTDeviceTypePage"),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "请先".tr,
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
),
),
WidgetSpan(
child: Stack(
children: [
Text(
"绑定设备".tr,
style: TextStyle(
color: stringToColor("#84F5FF"),
fontSize: 30.rpx,
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 1,
color: stringToColor("#84F5FF"),
),
),
],
),
),
TextSpan(
text: "后,再进行设备控制".tr,
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
),
),
],
),
),
),
),
// 显示 WebView
if (showWeb)
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Obx(() {
// return (controller.ready.value && (MainPageBBottomChange.getCurrentIndex() == 2))
// return (controller.ready.value && (MainPageBBottomChange.getCurrentIndex() == 2)&& controller.loadRecource.value == true)
// return Stack(children: [
// controller.ready.value
// ? controller.web.build()
// : Container(),
// Text("1222121212"),
// ]);
// return Stack(
// children: [
// controller.ready.value
// ? controller.web.build()
// : Container(),
// // 只有 loadRecource == false 时才显示覆盖文字
// if (!controller.loadRecource.value)
// Positioned.fill(
// child: Container(
// color: Colors.black54, // 半透明遮罩,可选
// alignment: Alignment.center,
// child: Text(
// "资源加载中...",
// style: TextStyle(
// color: Colors.red,
// fontSize: 30.rpx,
// fontWeight: FontWeight.bold,
// ),
// ),
// ),
// ),
// ],
// );
return Stack(
children: [
controller.ready.value
? controller.web.build()
: Container(),
if (!controller.loadRecource.value)
Positioned.fill(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/new_background.png'),
fit: BoxFit.fill,
),
),
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Colors.white),
),
],
),
),
),
],
);
}),
),
),
],
),
);
});
}
}