Merge remote-tracking branch 'origin/master'

# Conflicts:
#	lib/pages/mh_page/room_picker.dart
This commit is contained in:
czz
2025-07-15 14:54:26 +08:00
10 changed files with 684 additions and 56 deletions

View File

@@ -177,6 +177,10 @@ void initEasyDartModule() {
WebSocketConfig(ServiceConstant.webSocketService, (data) {
// 接收到服务消息
var json = jsonDecode(data);
ef.log("[websokcet]:${json}");
if (json['wsId'] != null) {
ef.kvRoot.websocketId = json['wsId'];
}
if (json['code'] != null && json['code'] != 200) {
EasyDartModule.logger.error("websocket连接失败--》" + json);
}
@@ -184,7 +188,11 @@ void initEasyDartModule() {
var call = CommonVariables.callMap[json["path"]];
if (call != null) {
try {
call(json["data"]);
if (json['path'] != "/smartbed/connect") {
call(json["data"]);
} else {
call(json);
}
} catch (e) {
print(e);
}

View File

@@ -7,8 +7,9 @@ class WebSocketMessage {
String path;
int? type;
dynamic data;
String? to;
WebSocketMessage({required this.path, this.type, this.data});
WebSocketMessage({required this.path, this.type, this.data, this.to});
static WebSocketMessage fromJson(Map<String, dynamic> json) =>
_$WebSocketMessageFromJson(json);

View File

@@ -11,6 +11,7 @@ WebSocketMessage _$WebSocketMessageFromJson(Map<String, dynamic> json) =>
path: json['path'] as String,
type: (json['type'] as num?)?.toInt(),
data: json['data'],
to: json['to'] as String?,
);
Map<String, dynamic> _$WebSocketMessageToJson(WebSocketMessage instance) =>
@@ -18,4 +19,5 @@ Map<String, dynamic> _$WebSocketMessageToJson(WebSocketMessage instance) =>
'path': instance.path,
'type': instance.type,
'data': instance.data,
'to': instance.to,
};

View File

@@ -4,6 +4,7 @@ import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/component/NullDataComponentWidget.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/WebSocketMessage.dart';
import 'package:vbvs_app/pages/common/bezier_bottom_navigation_bar.dart';
import 'package:vbvs_app/pages/mh_page/MattressControl.dart';
@@ -139,26 +140,90 @@ class _HomePageState extends State<MainPageBBottomChange>
setState(() {
selectedIndex = index;
dealWebSource(index);
});
}
Future<void> dealWebSource(int index) async {
try {
UserInfoController userInfoController = Get.find();
WebviewTestController webviewTestController = Get.find();
if (index == 2) {
await webviewTestController.web.jsbridge?.dart.pageActive(true);
//激活websocket
CommonVariables.callMap["/smartbed/connect"] = (data) {
//订阅连接消息
ef.log("[设备申请连接]:$data");
};
edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
path: "/smartbed/connect",
type: 5,
data: {"mac": webviewTestController.selectDevice['mac']})));
path: "/smartbed/connect",
type: 1,
)));
await Future.delayed(Duration(seconds: 1));
edm.EasyDartModule.websocket.sendData(jsonEncode(
WebSocketMessage(path: "/smartbed/connect", type: 5, data: {
'mac': webviewTestController.selectDevice['mac'],
})));
} else {
await webviewTestController.web.jsbridge?.dart.pageInActive();
}
CommonVariables.callMap["/smartbed/connect"] = (data) {
//订阅连接消息
ef.log("[websocket]:$data");
ef.log("[设备申请连接]:$data");
if (data['type'] == 4) {
if (ef.kvRoot.websocketId == data['from']) {
return;
}
//接收到有人正在控制,停止连接
if (index == 2) {
//通知显示弹窗已被用户绑定
try {
webviewTestController.web.jsbridge?.dart.haveConnected(data);
} catch (e) {
ef.log("[websocket]调用网页异常:$e");
}
}
}
if (data['type'] == 5) {
//接收到别人正在申请控制,判断自己是否处于控制页并且连接了该设备
if (ef.kvRoot.websocketId == null) {
return;
}
if (ef.kvRoot.websocketId == data['from']) {
return;
}
if (webviewTestController.selectDevice['mac'] == null) {
return;
}
if (index != 2) {
//当前不处于控制页且没有连接该设备
if (webviewTestController.selectDevice == null ||
webviewTestController.selectDevice['mac'] !=
data['data']?['mac']) {
//如果当前没有连接该设备,则返回
return;
}
//当前不处于控制页且连接了该设备-->进行断开
//web todo 断开设备连接
webviewTestController.web.jsbridge?.dart.disconnectByOtherUser();
} else {
ef.log("[websocket]:当前处于控制页给指定用户发送xxx用户已连接");
//当前处于控制页给指定用户发送xxx用户已连接
if (webviewTestController.selectDevice == null ||
webviewTestController.selectDevice['mac'] !=
data['data']['mac']) {
//如果当前没有连接该设备,则返回
return;
}
edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
to: data['from'],
// to: ef.kvRoot.websocketId,
path: "/smartbed/connect",
type: 4,
data: {
"mac": webviewTestController.selectDevice['mac'],
"user": userInfoController.model
})));
}
}
};
} catch (e) {
ef.log("[激活控制页面报错]:$e");
}

View File

@@ -211,7 +211,7 @@ class DeviceInfoWidget extends GetView {
webviewTestController.web.jsbridge?.dart
.pageActive(false);
await Future.delayed(Duration(seconds: 1));
// await Future.delayed(Duration(seconds: 1));
webviewTestController.web.jsbridge?.dart
.appToHtmlDevice(device);
MainPageBBottomChange.jumpTo(2);

View File

@@ -33,32 +33,39 @@ class _HomeDeviceStausWidgetState extends State<HomeDeviceStausWidget> {
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,
Flexible(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
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,
Text(
'${(widget.deviceStatus['name'] ?? '').isEmpty ? '未命名'.tr : widget.deviceStatus['name']}',
style: TextStyle(
color: Colors.white,
fontSize: 26.rpx,
letterSpacing: 0.0.rpx,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
].divide(SizedBox(height: 26.rpx)),
].divide(SizedBox(height: 26.rpx)),
),
),
SizedBox(width: 26.rpx),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [

View File

@@ -282,7 +282,7 @@ class _MhtSleepReportPageState extends State<MhtSleepReportPage> {
borderColor:
Colors.transparent,
borderWidth: 2,
borderRadius: 0.rpx,
borderRadius: 100.rpx,
margin:
EdgeInsetsDirectional
.fromSTEB(

View File

@@ -540,7 +540,7 @@ class _NewHomePageState extends State<NewHomePage> {
borderColor:
Colors.transparent,
borderWidth: 2,
borderRadius: 18,
borderRadius: 100.rpx,
margin:
EdgeInsetsDirectional
.fromSTEB(

View File

@@ -13,6 +13,7 @@ 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/mh_page/homepage/controller/mht_home_controller.dart';
class WebviewTestModel {
@@ -69,13 +70,15 @@ class WebviewTestController extends GetControllerEx<WebviewTestModel> {
(selectDevice['mac'] != args[0]['mac'])) {
lastSelectDevice = selectDevice;
}
edm.EasyDartModule.websocket.sendData(jsonEncode(
WebSocketMessage(path: "/smartbed/connect", type: 5, data: {
'mac': selectDevice['mac'],
})));
dealInstantData(selectDevice);
} catch (e) {
ef.log("[aaaa]$e");
ef.log("[切换设备失败]$e");
}
//查询人员信息
return true;
});
bridge.sdk.updateBlueToothStatus((args) async {

View File

@@ -155,15 +155,6 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Container(
// decoration: BoxDecoration(
// image: DecorationImage(
// image: (widget.data['backgroundImg'] != null &&
// widget.data['backgroundImg'].toString().isNotEmpty)
// ? AssetImage(widget.data['backgroundImg'])
// : AssetImage('assets/img/bgNoImg.png') as ImageProvider,
// fit: BoxFit.fill,
// ),
// ),
decoration: BoxDecoration(
image: (widget.data['noBackImg'] != null &&
widget.data['noBackImg'] == true)
@@ -176,7 +167,6 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
fit: BoxFit.fill,
),
),
child: Scaffold(
backgroundColor: Colors.transparent, // 背景透明
// appBar: AppBar(
@@ -252,13 +242,12 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
),
),
),
body: SafeArea(
top: true,
child: SingleChildScrollView(
child: Obx(() {
var sleepReport = sleepReportController.sleepReport;
print(sleepReport);
child: Obx(() {
var sleepReport = sleepReportController.sleepReport;
print(sleepReport);
if (sleepReport.isEmpty || sleepReport.isEmpty) {
return Column(
children: [
Padding(
@@ -767,7 +756,7 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
),
(sleepReport.value == null || sleepReport.value.isEmpty)
? Container(
child: NullDataWidget(),
child: Expanded(child: NullDataWidget()),
)
: (sleepReportController.model.type == 1
? DailyDataWidget(sleepReport, sleepCardKey,
@@ -782,8 +771,561 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
height: 25.rpx,
)),
);
}),
),
} else {
return SingleChildScrollView(
child: Column(
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
child: Container(
width: double.infinity,
constraints: BoxConstraints(
minHeight: 90.rpx,
),
decoration: BoxDecoration(
color: widget.data['backgroundColor'] != null
? widget.data['backgroundColor']
: themeController.currentColor.sc5,
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 15.rpx, 30.rpx, 15.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Stack(
alignment: Alignment.bottomLeft,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: themeController
.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
sleepReportController.model.type =
1;
String data = MyUtils.formatDate(
calendarController
.selectedDate.value!);
await requestWithLog(
logTitle: "查询睡眠报告",
method: MyHttpMethod.get,
queryUrl:
"https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${data}&type=${sleepReportController.model.type}",
onSuccess: (res) {
print(res);
sleepReportController
.sleepReport
.value = res.data;
sleepReportController
.updateAll();
},
onFailure: (res) {
if (MainPageBBottomChange
.getCurrentIndex() !=
null) {
if (MainPageBBottomChange
.getCurrentIndex() ==
1) {
TopSlideNotification.show(
context,
text: res.msg!,
textColor:
themeController
.currentColor
.sc9);
}
} else {
TopSlideNotification.show(
context,
text: res.msg!,
textColor:
themeController
.currentColor
.sc9);
}
sleepReportController
.sleepReport.value = {};
sleepReportController
.updateAll();
print(res);
});
sleepReportController.updateAll();
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width:
115.rpx, // 固定宽度为 160.rpx
alignment:
Alignment.center, // 文字居中
child: Text(
'日报'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color: sleepReportController
.model.type ==
1
? themeController
.currentColor.sc2
: themeController
.currentColor.sc3,
),
),
),
SizedBox(height: 10.rpx),
],
),
),
Obx(() {
return ClickableContainer(
backgroundColor:
Colors.transparent,
highlightColor: themeController
.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
sleepReportController
.model.type = 2;
String data =
MyUtils.formatDate(
calendarController
.selectedDate
.value!);
await requestWithLog(
logTitle: "查询睡眠报告",
method: MyHttpMethod.get,
queryUrl:
"https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${data}&type=${sleepReportController.model.type}",
onSuccess: (res) {
print(res);
sleepReportController
.sleepReport
.value = res.data;
sleepReportController
.updateAll();
},
onFailure: (res) {
if (MainPageBBottomChange
.getCurrentIndex() !=
null) {
if (MainPageBBottomChange
.getCurrentIndex() ==
1) {
TopSlideNotification.show(
context,
text: res.msg!,
textColor:
themeController
.currentColor
.sc9);
}
} else {
TopSlideNotification.show(
context,
text: res.msg!,
textColor:
themeController
.currentColor
.sc9);
}
sleepReportController
.sleepReport
.value = {};
sleepReportController
.updateAll();
print(res);
});
sleepReportController
.updateAll();
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 115
.rpx, // 固定宽度为 160.rpx
alignment: Alignment
.center, // 文字居中
child: Text('周报'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color: sleepReportController
.model
.type ==
2
? themeController
.currentColor
.sc2
: themeController
.currentColor
.sc3,
)),
),
SizedBox(height: 10.rpx),
],
),
);
}),
Obx(() {
return ClickableContainer(
backgroundColor:
Colors.transparent,
highlightColor: themeController
.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
sleepReportController
.model.type = 3;
String data =
MyUtils.formatDate(
calendarController
.selectedDate
.value!);
await requestWithLog(
logTitle: "查询睡眠报告",
method: MyHttpMethod.get,
queryUrl:
"https://sleepdata.he-info.com/api/analysis/sleep/analysis?mac=${widget.data['mac']}&time=${data}&type=${sleepReportController.model.type}",
onSuccess: (res) {
print(res);
sleepReportController
.sleepReport
.value = res.data;
sleepReportController
.updateAll();
},
onFailure: (res) {
if (MainPageBBottomChange
.getCurrentIndex() !=
null) {
if (MainPageBBottomChange
.getCurrentIndex() ==
1) {
TopSlideNotification.show(
context,
text: res.msg!,
textColor:
themeController
.currentColor
.sc9);
}
} else {
TopSlideNotification.show(
context,
text: res.msg!,
textColor:
themeController
.currentColor
.sc9);
}
sleepReportController
.sleepReport
.value = {};
sleepReportController
.updateAll();
print(res);
});
sleepReportController
.updateAll();
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 115
.rpx, // 固定宽度为 160.rpx
alignment: Alignment
.center, // 文字居中
child: Text(
'月报'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color:
sleepReportController
.model
.type ==
3
? themeController
.currentColor
.sc2
: themeController
.currentColor
.sc3,
),
),
),
SizedBox(height: 10.rpx),
],
),
);
}),
],
),
AnimatedPositioned(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
bottom: 0,
left:
sleepReportController.model.type ==
1
? 0
: sleepReportController
.model.type ==
2
? 115.rpx
: 230.rpx,
child: Container(
width: lineWidth,
height: 4.rpx,
decoration: BoxDecoration(
color: themeController
.currentColor.sc2,
borderRadius:
BorderRadius.circular(2.rpx),
),
),
),
],
),
],
),
),
),
),
Container(
width: double.infinity,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 32.rpx, 30.rpx, 32.rpx),
child: getTimeWidget(),
),
),
if (widget.data['person_show'] == null ||
widget.data['person_show'] != false)
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 0.rpx, 30.rpx, 51.rpx),
child: ClickableContainer(
backgroundColor:
widget.data['backgroundColor'] != null
? widget.data['backgroundColor']
: themeController.currentColor.sc5,
highlightColor: themeController
.currentColor.sc5, // 或你希望的点击水波纹颜色
borderRadius: AppConstants()
.normal_container_radius, // 如果你想加圆角可以设置 eg. 12.rpx
padding: EdgeInsets.zero,
onTap: () {},
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
flex: 2,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Text(
'姓名'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
Text(
'年龄'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
].divide(
SizedBox(height: 34.rpx)),
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
(widget.data['person']
?['name']
?.toString()
.trim()
.isNotEmpty ??
false)
? widget.data['person']![
'name']
.toString()
: '未知数据'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Text(
'${MyUtils.getAgeByDate(MyUtils.formatBirthdayTime(widget.data['person']?['birthday'])) ?? '未知数据'.tr}',
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
].divide(
SizedBox(height: 34.rpx)),
),
]
.divide(SizedBox(width: 33.rpx))
.addToStart(
SizedBox(width: 37.rpx)),
),
]
.addToStart(SizedBox(height: 36.rpx))
.addToEnd(SizedBox(height: 36.rpx)),
),
),
Flexible(
flex: 3,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Text(
'设备ID'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
Text(
'体重'.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
].divide(
SizedBox(height: 34.rpx)),
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'${widget.data['code'] ?? '未知数据'.tr}',
// "D11250300003",
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
maxLines: 1,
overflow:
TextOverflow.ellipsis,
),
Text(
'${widget.data['person']?['weight'] ?? '未知数据'.tr}kg',
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
].divide(
SizedBox(height: 34.rpx)),
),
]
.divide(SizedBox(width: 33.rpx))
.addToStart(
SizedBox(width: 37.rpx)),
),
]
.addToStart(SizedBox(height: 36.rpx))
.addToEnd(SizedBox(height: 36.rpx)),
),
),
],
),
),
),
(sleepReport.value == null || sleepReport.value.isEmpty)
? Container(
child: NullDataWidget(),
)
: (sleepReportController.model.type == 1
? DailyDataWidget(
sleepReport,
sleepCardKey,
heartRateCardKey,
breatheCardKey,
widget.data)
: sleepReportController.model.type == 2
? WeekDataWidget(sleepReport, widget.data)
: sleepReportController.model.type == 3
? MonthDataWidget(
sleepReport, widget.data)
: NullDataWidget()),
].divide(SizedBox(
height: 25.rpx,
)),
),
);
}
}),
),
),
),