// import 'dart:async'; // import 'dart:convert'; // // import 'dart:math'; // import 'package:EasyDartModule/EasyDartModule.dart' as edm; // import '../const/CommonVariables.dart'; // import '../model/WebSocketMessage.dart'; // import '../repository/AreaRepository.dart'; // // import 'package:http/http.dart' as http; // import '../const/ServiceConstant.dart'; // import '../util/requestWithLog.dart'; // import '../enum/ReportStatus.dart'; // class AreaService { // final AreaRepository areaRepository = AreaRepository(); // Map>> bodyDataCache = // {}; // 存储原始实时数据 mac -> list实时数据列表 // Map>> processedDataCache = // {}; // 存储处理过的数据 mac -> list处理数据列表 // Map> userInfoMap = {}; // 存储用户信息 mac -> 用户信息 // Map deviceUserMap = {}; // 设备与用户的映射 mac -> openId // Map macProcess = {}; // 存储检测进度 mac -> 进度百分比 // Map deviceStartTimeMap = {}; // mac -> 开始体验的时间戳(毫秒) // Map deviceTimers = {}; // 设备超时定时器 mac -> Timer // Map lastValidDataTime = {}; // 最后有效数据时间 mac -> timestamp // Map lastBedStatusTime = {}; // 最后离床状态开始时间 mac -> timestamp // // 新增:进度相关 // Map _progressTimers = {}; // 进度更新定时器 // Map _lastProgressTime = {}; // 最后更新进度的时间 // // 新增:记录初始数据处理状态 // Map _initialDataProcessed = {}; // 是否已处理过初始数据 // // 新增:心率直线检测相关 // Map>> _heartRateSequenceCache = // {}; // 存储心率连续相同序列 // Map _inStraightLineMode = {}; // 是否处于直线检测模式 // Map> _lastStraightLineStart = {}; // 直线开始的第一个数据 // // 新增:报告生成状态管理 // Map _reportGeneratingMap = {}; // mac -> 是否正在生成报告 // Map _reportGeneratedMap = {}; // mac -> 是否已生成报告 // int dataLength = 300; // 目标有效数据长度 // int initialDataLength = 180; // 初始需要的数据长度(3分钟) // int noDataTimeout = 20 * 1000; // 20秒无数据超时 // int bedOffTimeout = 20 * 1000; // 20秒离床超时 // int totalTimeout = 20 * 60 * 1000; // 20分钟总超时 // int totalHeartPercent = 80; // 心率有效占比 // int standardThreshold = 5; // 允许跳动范围 // int heartStillTime = 10; // 心率直线判断阈值 // Timer? _offlineCheckTimer; // bool _isTimerRunning = false; // AreaService() { // // 从Redis恢复体验中的设备 // _recoverExperiences(); // // 启动离线检测定时器 // _startOfflineCheckTimer(); // } // // 从Redis恢复体验中的设备 // Future _recoverExperiences() async { // try { // // 使用keys方法获取所有体验中的设备 // final keys = await edm.EasyDartModule.redis.keys("experience_*"); // for (var key in keys) { // try { // final experienceData = await edm.EasyDartModule.redis.get(key); // if (experienceData != null) { // final data = jsonDecode(experienceData); // final mac = data['mac']; // final openId = data['openId']; // final startTime = data['startTime']; // final now = DateTime.now().millisecondsSinceEpoch; // // 如果体验时间超过20分钟,结束体验 // if (now - startTime > totalTimeout) { // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "超时自动结束"); // await _callRemoteEndExperience(mac, openId, "超时自动结束", // ReportStatus.reportExceptionClose.value); // await edm.EasyDartModule.redis.delete(key); // } else { // // 恢复设备体验状态 // deviceStartTimeMap[mac] = startTime; // deviceUserMap[mac] = openId; // // 恢复用户信息 // final userInfoKey = "user_info_$mac"; // final userInfoData = // await edm.EasyDartModule.redis.get(userInfoKey); // if (userInfoData != null) { // userInfoMap[mac] = jsonDecode(userInfoData); // } // // 恢复初始数据处理状态 // _initialDataProcessed[mac] = false; // // 初始化心率序列缓存 // _heartRateSequenceCache[mac] = []; // _inStraightLineMode[mac] = false; // // 初始化报告状态 // _reportGeneratingMap[mac] = false; // _reportGeneratedMap[mac] = false; // // 启动设备超时定时器 // _startDeviceTimeoutTimer(mac); // // 恢复进度定时器 // _startProgressTimer(mac); // print("从Redis恢复设备体验: $mac, openId: $openId"); // } // } // } catch (e) { // print("恢复设备体验数据失败: $e"); // } // } // } catch (e) { // print("从Redis恢复体验失败: $e"); // } // } // // 保存体验信息到Redis // Future _saveExperienceToRedis(String mac, Map userInfo, // String openId, int startTime) async { // try { // final key = "experience_$mac"; // final data = { // 'mac': mac, // 'openId': openId, // 'startTime': startTime, // 'saveTime': DateTime.now().millisecondsSinceEpoch, // }; // // 保存体验信息 // await edm.EasyDartModule.redis.set(key, jsonEncode(data)); // // 保存用户信息 // final userInfoKey = "user_info_$mac"; // await edm.EasyDartModule.redis.set(userInfoKey, jsonEncode(userInfo)); // print("保存体验信息到Redis: $mac, openId: $openId"); // } catch (e) { // print("保存体验信息到Redis失败: $e"); // } // } // // 从Redis删除体验信息 // Future _removeExperienceFromRedis(String mac) async { // try { // await edm.EasyDartModule.redis.delete("experience_$mac"); // await edm.EasyDartModule.redis.delete("user_info_$mac"); // print("从Redis删除体验信息: $mac"); // } catch (e) { // print("从Redis删除体验信息失败: $e"); // } // } // // 启动设备超时定时器 // void _startDeviceTimeoutTimer(String mac) { // // 先取消现有的定时器 // _stopDeviceTimeoutTimer(mac); // // 启动新的定时器 // deviceTimers[mac] = Timer(Duration(milliseconds: totalTimeout), () { // _handleDeviceTimeout(mac); // }); // } // // 停止设备超时定时器 // void _stopDeviceTimeoutTimer(String mac) { // if (deviceTimers.containsKey(mac) && deviceTimers[mac] != null) { // deviceTimers[mac]!.cancel(); // deviceTimers[mac] = null; // } // } // // 处理设备超时 // void _handleDeviceTimeout(String mac) async { // final openId = deviceUserMap[mac]; // if (openId != null) { // print("设备超时: $mac, openId: $openId"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "体验超时"); // await _endExperience( // mac, openId, "体验超时", ReportStatus.reportExceptionClose.value); // } // } // // 启动进度更新定时器 // void _startProgressTimer(String mac) { // // 先取消现有的定时器 // _stopProgressTimer(mac); // // 每秒更新一次进度 // _progressTimers[mac] = Timer.periodic(Duration(seconds: 1), (timer) { // _updateProgress(mac); // }); // _lastProgressTime[mac] = DateTime.now().millisecondsSinceEpoch; // } // // 停止进度更新定时器 // void _stopProgressTimer(String mac) { // if (_progressTimers.containsKey(mac) && _progressTimers[mac] != null) { // _progressTimers[mac]!.cancel(); // _progressTimers[mac] = null; // } // _lastProgressTime.remove(mac); // } // // 更新进度 // void _updateProgress(String mac) { // try { // // 如果设备不在体验中,停止定时器 // if (!checkUsing(mac)) { // _stopProgressTimer(mac); // return; // } // final startTime = deviceStartTimeMap[mac]; // if (startTime == null) return; // final now = DateTime.now().millisecondsSinceEpoch; // final duration = now - startTime; // // 计算基于时间的进度(20分钟 = 1200秒) // int timeBasedProgress = (duration / (20 * 60 * 1000) * 100).toInt(); // // 计算基于数据的进度 // final processedCount = processedDataCache[mac]?.length ?? 0; // int dataBasedProgress = (processedCount / dataLength * 100).toInt(); // // 综合进度策略: // // 1. 前期(前2分钟)以时间进度为主 // // 2. 中期(2-5分钟)时间和数据进度结合 // // 3. 后期(5分钟后)以数据进度为主 // int finalProgress; // if (duration < 2 * 60 * 1000) { // // 前2分钟 // // 80%时间进度 + 20%数据进度 // finalProgress = // (timeBasedProgress * 0.8 + dataBasedProgress * 0.2).toInt(); // } else if (duration < 5 * 60 * 1000) { // // 2-5分钟 // // 50%时间进度 + 50%数据进度 // finalProgress = // (timeBasedProgress * 0.5 + dataBasedProgress * 0.5).toInt(); // } else { // // 5分钟后 // // 20%时间进度 + 80%数据进度 // finalProgress = // (timeBasedProgress * 0.2 + dataBasedProgress * 0.8).toInt(); // } // // 确保进度不会减少(用户体验角度) // final int currentProgress = macProcess[mac] ?? 0; // if (finalProgress > currentProgress) { // macProcess[mac] = finalProgress.clamp(0, 100); // } else if (duration > 30 * 1000) { // // 30秒后允许轻微下降,避免卡住 // // 如果有数据但进度不增长,缓慢增加时间进度 // if (processedCount > 0 && currentProgress < 10) { // macProcess[mac] = (currentProgress + 1).clamp(0, 100); // } // } // // 如果报告已生成或正在生成,进度设为100% // if ((_reportGeneratingMap[mac] ?? false) || // (_reportGeneratedMap[mac] ?? false)) { // macProcess[mac] = 100; // } // // 记录最后更新时间 // _lastProgressTime[mac] = now; // } catch (e) { // print("更新进度异常: $e, MAC=$mac"); // } // } // // 析构函数,清理定时器 // void dispose() { // _stopOfflineCheckTimer(); // // 清理所有设备定时器 // deviceTimers.forEach((mac, timer) { // if (timer != null) { // timer.cancel(); // } // }); // deviceTimers.clear(); // // 清理所有进度定时器 // _progressTimers.forEach((mac, timer) { // if (timer != null) { // timer.cancel(); // } // }); // _progressTimers.clear(); // // 清理心率序列缓存 // _heartRateSequenceCache.clear(); // _inStraightLineMode.clear(); // _lastStraightLineStart.clear(); // // 清理报告状态 // _reportGeneratingMap.clear(); // _reportGeneratedMap.clear(); // } // // 开始离线检测定时器 // void _startOfflineCheckTimer() { // if (_isTimerRunning) return; // _isTimerRunning = true; // _offlineCheckTimer = Timer.periodic(Duration(seconds: 1), (timer) { // _checkDeviceOfflineStatus(); // }); // edm.EasyDartModule.logger.info("离线检测定时器已启动"); // } // // 停止离线检测定时器 // void _stopOfflineCheckTimer() { // if (_offlineCheckTimer != null) { // _offlineCheckTimer!.cancel(); // _offlineCheckTimer = null; // } // _isTimerRunning = false; // edm.EasyDartModule.logger.info("离线检测定时器已停止"); // } // // 检查设备离线状态 // void _checkDeviceOfflineStatus() { // try { // final now = DateTime.now().millisecondsSinceEpoch; // // 检查无数据超时 // lastValidDataTime.forEach((mac, lastTime) { // if (now - lastTime > noDataTimeout) { // print("设备无数据超时: $mac"); // _handleNoDataTimeout(mac); // } // }); // // 检查离床状态超时 // lastBedStatusTime.forEach((mac, offBedTime) { // if (now - offBedTime > bedOffTimeout) { // print("设备离床超时: $mac"); // _handleBedOffTimeout(mac); // } // }); // } catch (e) { // print("检测离线异常: $e"); // } // } // // 处理无数据超时 // void _handleNoDataTimeout(String mac) async { // final openId = deviceUserMap[mac]; // if (openId != null) { // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "无数据超时"); // await _endExperience( // mac, openId, "无数据超时", ReportStatus.reportExceptionClose.value); // } // } // // 处理离床超时 // void _handleBedOffTimeout(String mac) async { // final openId = deviceUserMap[mac]; // if (openId != null) { // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "离床超时"); // await _endExperience( // mac, openId, "离床超时", ReportStatus.reportExceptionClose.value); // } // } // // 开始快检体验 // Future> startKuaijian(Map data) async { // String msg = ""; // int flag = 1; // try { // String mac = _normalizeMac(data['mac']); // String openId = data['openId']?.toString() ?? ''; // if (openId.isEmpty) { // return {"msg": "openId不能为空", "flag": 0}; // } // bool haveRun = await checkHaveRun(data); // if (haveRun) { // print( // "[调试][${DateTime.now().toIso8601String()}]: 已经在运行,跳过 ${data['mac']}"); // msg = "该设备正在体验中"; // flag = 0; // return {"msg": msg, "flag": flag}; // } // // 检查该mac是否正在体验中 // bool using = checkUsing(mac); // if (using) { // msg = "该设备正在体验中"; // flag = 0; // return {"msg": msg, "flag": flag}; // } // bool state = await checkDeviceState(mac); // if (!state) { // msg = "设备离线"; // flag = 0; // return {"msg": msg, "flag": flag}; // } // // 提取并处理用户信息(设置默认值) // final userInfo = _processUserInfo(data); // // 2. 记录开始体验时间 // final startTime = DateTime.now().millisecondsSinceEpoch; // deviceStartTimeMap[mac] = startTime; // deviceUserMap[mac] = openId; // userInfoMap[mac] = userInfo; // lastValidDataTime[mac] = startTime; // 初始化最后有效数据时间 // _initialDataProcessed[mac] = false; // 初始化初始数据处理标志 // // 3. 初始化心率序列相关缓存 // _heartRateSequenceCache[mac] = []; // _inStraightLineMode[mac] = false; // // 4. 初始化报告状态 // _reportGeneratingMap[mac] = false; // _reportGeneratedMap[mac] = false; // // 5. 保存到Redis // await _saveExperienceToRedis(mac, userInfo, openId, startTime); // // 6. 启动设备超时定时器 // _startDeviceTimeoutTimer(mac); // // 7. 启动进度定时器 // _startProgressTimer(mac); // edm.EasyDartModule.logger // .info("记录设备开始体验时间: $mac, openId: $openId, 时间: $startTime"); // // 8. 调用服务号后端通知开始体验 // await rpcStartKuaijian(data); // // 9. 开始记录实时数据 // startGetBodyData(data); // //10.更新远程api // await rpcStart(data); // } catch (e) { // print("申请体验报告失败: $e"); // return {"msg": "系统异常", "flag": 0}; // } // return {"msg": "开始体验成功", "flag": flag}; // } // // 处理用户信息,设置默认值 // Map _processUserInfo(Map data) { // // 设置默认值 // final defaultValues = { // 'username': '体验用户', // 'age': 30, // 'height': 170, // 'weight': 60, // 'gender': 1, // 1:男, 2:女 // 'phoneNo': '未知', // 'deviceNo': data['mac'] ?? '', // }; // // 处理用户信息,空值或无效值使用默认值 // final userInfo = { // 'username': // _getValueOrDefault(data['username'], defaultValues['username']), // 'age': _getIntValueOrDefault(data['age'], defaultValues['age']), // 'height': _getIntValueOrDefault(data['height'], defaultValues['height']), // 'weight': _getIntValueOrDefault(data['weight'], defaultValues['weight']), // 'gender': _getIntValueOrDefault(data['gender'], defaultValues['gender']), // 'phoneNo': _getValueOrDefault(data['phoneNo'], defaultValues['phoneNo']), // 'deviceNo': _getValueOrDefault( // data['deviceNo'] ?? data['mac'], defaultValues['deviceNo']), // }; // // 验证年龄、身高、体重范围 - 修复类型转换问题 // userInfo['age'] = _validateRange( // userInfo['age'] as int, 1, 120, defaultValues['age'] as int); // userInfo['height'] = _validateRange( // userInfo['height'] as int, 50, 250, defaultValues['height'] as int); // userInfo['weight'] = _validateRange( // userInfo['weight'] as int, 10, 300, defaultValues['weight'] as int); // userInfo['gender'] = _validateRange( // userInfo['gender'] as int, 1, 2, defaultValues['gender'] as int); // print("处理后的用户信息: $userInfo"); // return userInfo; // } // // 获取字符串值或默认值 // String _getValueOrDefault(dynamic value, String defaultValue) { // if (value == null) return defaultValue; // final strValue = value.toString().trim(); // if (strValue.isEmpty) return defaultValue; // return strValue; // } // // 获取整数值或默认值 // int _getIntValueOrDefault(dynamic value, int defaultValue) { // if (value == null) return defaultValue; // try { // if (value is String) { // final trimmed = value.trim(); // if (trimmed.isEmpty) return defaultValue; // return int.tryParse(trimmed) ?? defaultValue; // } else if (value is int) { // return value; // } else if (value is double) { // return value.toInt(); // } else if (value is num) { // return value.toInt(); // } // } catch (e) { // print("转换整数值失败: $value, $e"); // } // return defaultValue; // } // // 验证数值范围 // int _validateRange(int value, int min, int max, int defaultValue) { // if (value >= min && value <= max) { // return value; // } // return defaultValue; // } // // 结束快检体验 // Future> endKuaijian(Map data) async { // String msg = ""; // int flag = 1; // try { // String mac = _normalizeMac(data['mac']); // String openId = data['openId']?.toString() ?? ''; // if (openId.isEmpty) { // return {"msg": "openId不能为空", "flag": 0}; // } // // 检查该设备是否在体验中 // if (!checkUsing(mac)) { // return {"msg": "该设备未在体验中", "flag": 0}; // } // // 检查是否是同一个用户 // if (deviceUserMap[mac] != openId) { // return {"msg": "无权结束该设备的体验", "flag": 0}; // } // // 检查是否已经在生成报告 // if (_reportGeneratingMap[mac] ?? false) { // return {"msg": "报告正在生成中,请稍候", "flag": 0}; // } // // 检查是否已经生成报告 // if (_reportGeneratedMap[mac] ?? false) { // return {"msg": "报告已生成,请查看结果", "flag": 0}; // } // // 获取当前有效数据量 // final processedCount = processedDataCache[mac]?.length ?? 0; // if (processedCount >= dataLength) { // // 正常完成体验,生成报告 // final reportId = await _requestSleepAnalytics(mac, openId); // if (reportId != null) { // msg = "体验完成,报告ID: $reportId"; // await _callRemoteCompleteExperience( // mac, openId, "正常完成", reportId, ReportStatus.completed.value); // } else { // msg = "体验完成,但生成报告失败"; // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "报告生成失败"); // await _endExperience( // mac, openId, "报告生成失败", ReportStatus.reportExceptionClose.value); // } // } else { // // 提前结束体验 // await updateDeviceConnectStatus(ReportStatus.appNormalClose.value, mac, // remark: "用户主动结束"); // await _endExperience( // mac, openId, "用户主动结束", ReportStatus.appNormalClose.value); // msg = "体验已提前结束"; // } // } catch (e) { // print("结束体验失败: $e"); // return {"msg": "系统异常", "flag": 0}; // } // return {"msg": msg, "flag": flag}; // } // // 结束体验的通用方法 // Future _endExperience( // String mac, String openId, String reason, int reportStatus, // {bool rpc = true}) async { // try { // print("结束体验: MAC=$mac, openId=$openId, 原因=$reason"); // // 1. 调用远程结束接口 // if (rpc) { // await _callRemoteEndExperience(mac, openId, reason, reportStatus); // } // // 2. 清理本地数据 // deviceStartTimeMap.remove(mac); // deviceUserMap.remove(mac); // userInfoMap.remove(mac); // bodyDataCache.remove(mac); // processedDataCache.remove(mac); // macProcess.remove(mac); // lastValidDataTime.remove(mac); // lastBedStatusTime.remove(mac); // _initialDataProcessed.remove(mac); // // 3. 清理心率序列相关缓存 // _heartRateSequenceCache.remove(mac); // _inStraightLineMode.remove(mac); // _lastStraightLineStart.remove(mac); // // 4. 清理报告状态 // _reportGeneratingMap.remove(mac); // _reportGeneratedMap.remove(mac); // // 5. 停止定时器 // _stopDeviceTimeoutTimer(mac); // _stopProgressTimer(mac); // // 6. 从Redis删除 // await _removeExperienceFromRedis(mac); // // 7. 停止监听设备数据 // _stopListeningDeviceData(mac); // // 8. 通知前端 // _notifyExperienceEnd(mac, openId, reason); // edm.EasyDartModule.logger.info("体验已结束: $mac, 原因: $reason"); // } catch (e) { // edm.EasyDartModule.logger.error("结束体验异常: $e, MAC=$mac"); // } // } // // 请求睡眠分析报告 // Future _requestSleepAnalytics(String mac, String openId) async { // try { // // 检查是否已经在生成报告 // if (_reportGeneratingMap[mac] ?? false) { // print("报告已经在生成中,跳过重复请求: $mac"); // return null; // } // // 检查是否已经生成报告 // if (_reportGeneratedMap[mac] ?? false) { // print("报告已经生成,跳过重复请求: $mac"); // return null; // } // final userInfo = userInfoMap[mac]; // final processedData = processedDataCache[mac]; // if (userInfo == null || // processedData == null || // processedData.length < dataLength) { // print("请求报告失败: 数据不足或用户信息缺失"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "数据不足或用户信息缺失"); // return null; // } // // 设置报告正在生成中 // _reportGeneratingMap[mac] = true; // print("开始生成报告: $mac, openId: $openId, 数据量: ${processedData.length}"); // // 准备请求数据 // final Map requestData = { // "username": userInfo['username'], // "age": userInfo['age'], // "height": userInfo['height'], // "weight": userInfo['weight'], // "gender": userInfo['gender'], // "deviceNo": userInfo['deviceNo'], // "phoneNo": userInfo['phoneNo'], // "dataList": processedData, // }; // print( // "用户信息: ${userInfo['username']}, 年龄: ${userInfo['age']}, 电话: ${userInfo['phoneNo']}"); // // 发送HTTP请求 // final reportId = await _sendReportRequest(requestData, mac); // // 报告生成完成 // _reportGeneratingMap[mac] = false; // if (reportId != null) { // _reportGeneratedMap[mac] = true; // print("报告生成成功: $reportId"); // return reportId; // } else { // print("报告生成失败"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "报告生成失败"); // return null; // } // } catch (e) { // print("请求睡眠分析异常: $e"); // _reportGeneratingMap[mac] = false; // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "请求睡眠分析异常: $e"); // return null; // } // } // // 发送报告请求 // Future _sendReportRequest( // Map data, String mac) async { // try { // // 处理 dataList 的数据转换 // if (data['dataList'] != null && data['dataList'] is List) { // List> originalList = // List>.from(data['dataList']); // // 将原始数据转换为新的格式 // List> transformedList = originalList.map((item) { // // 从原始数据中提取 heartRate 和 breathRate // // 如果字段不存在或为null,则使用默认值0 // int heartRate = item['heartRate'] is int // ? item['heartRate'] // : (item['heartRate'] is double // ? (item['heartRate'] as double).toInt() // : 0); // int breathRate = item['breathRate'] is int // ? item['breathRate'] // : (item['breathRate'] is double // ? (item['breathRate'] as double).toInt() // : 0); // // 创建新的数据结构 // return { // 'breath': breathRate, // 'heart': heartRate, // }; // }).toList(); // // 替换原始 dataList 为转换后的数据 // data['dataList'] = transformedList; // } // // 打印转换后的数据用于调试 // print('转换后的数据: ${jsonEncode(data)}'); // await requestSleepAnalytics(data, mac); // return null; // 由于是异步调用,这里返回null,实际结果在回调中处理 // } catch (e) { // print("发送报告请求异常: $e"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "发送报告请求异常: $e"); // return null; // } // } // // 调用远程完成接口 // Future _callRemoteCompleteExperience(String mac, String openId, // String reason, String reportId, int reportStatus) async { // try { // // 调用您的远程完成接口 // print("调用远程完成接口: $mac, openId: $openId, 原因: $reason, 报告ID: $reportId"); // // 结束体验 // await _endExperience( // mac, openId, "$reason, 报告ID: $reportId", reportStatus); // } catch (e) { // print("调用远程完成接口失败: $e"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "调用远程完成接口失败: $e"); // } // } // // 调用远程结束接口 // Future _callRemoteEndExperience( // String mac, String openId, String reason, int reportStatus) async { // try { // // 调用您的远程完成接口 // print("调用远程结束接口: $mac, openId: $openId, 原因: $reason"); // // TODO: 实现具体的远程调用 // await updateDeviceConnectStatus(reportStatus, mac, remark: reason); // } catch (e) { // print("调用远程结束接口失败: $e"); // } // } // // 通知体验结束 // void _notifyExperienceEnd(String mac, String openId, String reason) { // try { // edm.EasyDartModule.websocket.sendData(jsonEncode({ // "type": "experience_end", // "mac": mac, // "openId": openId, // "reason": reason, // "timestamp": DateTime.now().millisecondsSinceEpoch, // "message": "体验已结束: $reason" // })); // } catch (e) { // print("发送体验结束通知失败: $e"); // } // } // // 检查是否体验中 // bool checkUsing(String mac) { // String normalizedMac = _normalizeMac(mac); // return deviceStartTimeMap.containsKey(normalizedMac); // } // // 远程通知分析开始 // Future rpcStartKuaijian(data) async { // // TODO: 实现远程开始接口 // } // // 开始获取实时数据 // void startGetBodyData(data) { // try { // String mac = _normalizeMac(data['mac']); // data['mac'] = mac; // 统一格式 // // 监听 WebSocket 实时数据 // CommonVariables.callMap["/vsbs/web/rt/marttress"] = (receivedData) { // _handleWebSocketData(receivedData); // }; // print("开始监听体征数据"); // edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage( // path: "/vsbs/web/rt/marttress", type: 1, data: {"mac": mac}))); // } catch (e) { // edm.EasyDartModule.logger.error("[websocket]获取体征数据异常: $e"); // } // } // // 处理WebSocket数据 // Future _handleWebSocketData(dynamic receivedData) async { // try { // print("当前心率为: ${receivedData['heartRate']}"); // print("当前有效数据为: ${processedDataCache['${receivedData['mac']}']?.length}"); // if (receivedData is! Map) return; // // 将Map转换为Map // final Map data = {}; // receivedData.forEach((key, value) { // data[key.toString()] = value; // }); // // 为数据添加时间戳 // data['timestamp'] = DateTime.now().millisecondsSinceEpoch; // // 统一mac格式 // if (data.containsKey('mac')) { // String mac = _normalizeMac(data['mac']); // data['mac'] = mac; // // 检查设备是否在体验中 // if (!checkUsing(mac)) { // return; // 不在体验中的设备数据直接忽略 // } // // 检查是否已经生成报告,如果已经生成则不再处理数据 // if (_reportGeneratedMap[mac] ?? false) { // print("报告已生成,不再处理数据: $mac"); // return; // } // // 更新最后有效数据时间 // lastValidDataTime[mac] = data['timestamp']; // // 处理离床状态 // _handleBedStatus(mac, data); // // 处理离线状态 // if (data['status'] == "离线") { // final openId = deviceUserMap[mac]; // if (openId != null) { // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "设备离线"); // _endExperience( // mac, openId, "设备离线", ReportStatus.reportExceptionClose.value); // } // return; // } // // 存储原始数据 // storeInstantData(data); // // 处理数据(包含心率直线检测) // _processDataWithHeartRateDetection(mac, data); // edm.EasyDartModule.logger.info("[websocket]实时体征数据-->$data"); // } // } catch (e) { // print("处理WebSocket数据异常: $e"); // } // } // // 处理离床状态 // void _handleBedStatus(String mac, Map data) { // if (data["inBed"] == "离床") { // // 记录离床开始时间 // if (!lastBedStatusTime.containsKey(mac)) { // lastBedStatusTime[mac] = data['timestamp']; // } // } else { // // 清除离床计时 // lastBedStatusTime.remove(mac); // } // } // // 存储原始实时数据 // void storeInstantData(Map data) { // try { // String mac = data['mac']; // // 如果不存在该 mac,则先创建一个空 list // bodyDataCache.putIfAbsent(mac, () => []); // // 往对应的 list 中添加数据 // bodyDataCache[mac]!.add(Map.from(data)); // // 限制数据长度(保留足够的数据用于处理) // if (bodyDataCache[mac]!.length > dataLength * 2) { // bodyDataCache[mac]!.removeAt(0); // } // } catch (e) { // print("storeInstantData异常: $e"); // } // } // Future _processDataWithHeartRateDetection( // String mac, Map data) async { // try { // // 检查是否已经生成报告,如果已经生成则不再处理数据 // if (_reportGeneratedMap[mac] ?? false) { // return; // } // // 初始化处理数据缓存 // processedDataCache.putIfAbsent(mac, () => []); // _heartRateSequenceCache.putIfAbsent(mac, () => []); // final processedList = processedDataCache[mac]!; // final sequenceCache = _heartRateSequenceCache[mac]!; // // 检查数据有效性 // if (data['heartRate'] == -1 || // data['heartRate'] == 0 || // data['breathRate'] == -1 || // data['breathRate'] == 0 || // data['bodyMotion'] != 0 || // data['inBed'] != '在床') { // // 无效数据,重置序列 // if (sequenceCache.isNotEmpty) { // sequenceCache.clear(); // } // return; // } // // 获取当前心率 // int currentHeartRate = data['heartRate'] is int // ? data['heartRate'] // : (data['heartRate'] is double // ? (data['heartRate'] as double).toInt() // : 0); // // === 修正的核心逻辑 === // // 如果序列为空或当前心率与序列最后心率相同 // if (sequenceCache.isEmpty || // (sequenceCache.isNotEmpty && // sequenceCache.last['heartRate'] == currentHeartRate)) { // // 添加到连续相同心率序列 // sequenceCache.add({ // 'heartRate': currentHeartRate, // 'data': data, // 'timestamp': data['timestamp'], // }); // } else { // // 心率发生变化 - 处理之前的序列 // _processHeartRateSequence(mac, sequenceCache, processedList); // // 清空序列,开始新的序列 // sequenceCache.clear(); // sequenceCache.add({ // 'heartRate': currentHeartRate, // 'data': data, // 'timestamp': data['timestamp'], // }); // } // // === 修正的核心逻辑结束 === // // 处理初始数据(只执行一次) // if (processedList.length == initialDataLength && // !_initialDataProcessed[mac]!) { // print("开始处理初始数据,数据量: ${processedList.length}"); // _processInitialData(mac); // _initialDataProcessed[mac] = true; // } // // 检查是否达到目标数据量 - 修改为只触发一次 // if (processedList.length >= dataLength && // !(_reportGeneratingMap[mac] ?? false) && // !(_reportGeneratedMap[mac] ?? false)) { // final openId = deviceUserMap[mac]; // if (openId != null) { // print("达到目标数据量,开始生成报告: $mac, 数据量: ${processedList.length}"); // // 异步生成报告,避免阻塞数据处理 // Future.delayed(Duration.zero, () { // _requestSleepAnalytics(mac, openId).then((reportId) { // if (reportId != null) { // _callRemoteCompleteExperience(mac, openId, "数据采集完成", reportId, // ReportStatus.completed.value); // } else { // // 报告生成失败,继续收集数据 // print("报告生成失败,继续收集数据: $mac"); // } // }); // }); // } // } // print("当前有效数据为: ${processedDataCache['$mac']?.length}"); // } catch (e) { // print("处理数据异常: $e, MAC=$mac"); // // 处理数据异常时更新状态 // if (checkUsing(mac)) { // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "处理数据异常: $e"); // } // } // } // // 新增:处理心率序列的辅助方法 // void _processHeartRateSequence( // String mac, // List> sequenceCache, // List> processedList) { // if (sequenceCache.isEmpty) return; // if (sequenceCache.length >= heartStillTime) { // // 连续相同心率达到或超过10次 - 只保留第一个和最后一个 // print("连续相同心率达到${sequenceCache.length}次(>=${heartStillTime}),进行去重处理"); // // 第一个数据点 // final firstData = sequenceCache.first['data']; // final firstProcessedData = { // 'mac': mac, // 'heartRate': firstData['heartRate'], // 'breathRate': firstData['breathRate'], // 'timestamp': firstData['timestamp'], // 'bodyMotion': firstData['bodyMotion'], // }; // // 检查是否重复(与上一个处理的数据比较) // if (processedList.isEmpty || // processedList.last['heartRate'] != firstProcessedData['heartRate'] || // processedList.last['breathRate'] != // firstProcessedData['breathRate']) { // processedList.add(firstProcessedData); // print("添加直线开始数据点: 心率 ${firstProcessedData['heartRate']}"); // } // // 最后一个数据点 // final lastData = sequenceCache.last['data']; // final lastProcessedData = { // 'mac': mac, // 'heartRate': lastData['heartRate'], // 'breathRate': lastData['breathRate'], // 'timestamp': lastData['timestamp'], // 'bodyMotion': lastData['bodyMotion'], // }; // // 检查是否重复(与上一个处理的数据比较) // if (processedList.isEmpty || // processedList.last['heartRate'] != lastProcessedData['heartRate'] || // processedList.last['breathRate'] != lastProcessedData['breathRate']) { // processedList.add(lastProcessedData); // print("添加直线结束数据点: 心率 ${lastProcessedData['heartRate']}"); // } // } else { // // 连续相同心率少于10次 - 全部保留 // print("连续相同心率${sequenceCache.length}次(<${heartStillTime}),全部保留"); // for (var seqData in sequenceCache) { // final processedData = { // 'mac': mac, // 'heartRate': seqData['data']['heartRate'], // 'breathRate': seqData['data']['breathRate'], // 'timestamp': seqData['data']['timestamp'], // 'bodyMotion': seqData['data']['bodyMotion'], // }; // // 检查是否重复(与上一个处理的数据比较) // // 这里注意:对于连续相同的数据,我们不应该去重,所以去掉这个检查 // processedList.add(processedData); // } // } // } // // 处理初始数据(前3分钟) // void _processInitialData(String mac) async { // try { // final processedList = processedDataCache[mac]!; // // 1. 检查数据量是否足够 // if (processedList.length < initialDataLength ~/ 2) { // // 数据量少于一半,结束体验 // final openId = deviceUserMap[mac]; // if (openId != null) { // print("初始数据不足,结束体验: $mac, 数据量: ${processedList.length}"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "初始数据不足"); // _endExperience( // mac, openId, "初始数据不足", ReportStatus.reportExceptionClose.value); // } // return; // } // // 2. 计算平均心率 // int totalHeartRate = 0; // for (var data in processedList) { // final heartRate = data['heartRate']; // if (heartRate is int) { // totalHeartRate += heartRate; // } else if (heartRate is num) { // totalHeartRate += heartRate.toInt(); // } else if (heartRate is String) { // totalHeartRate += int.tryParse(heartRate) ?? 0; // } // } // double avgHeartRate = totalHeartRate / processedList.length; // // 3. 计算在平均值±5范围内的数据百分比 // int inRangeCount = 0; // for (var data in processedList) { // final heartRate = data['heartRate']; // double? hrValue; // if (heartRate is int) { // hrValue = heartRate.toDouble(); // } else if (heartRate is num) { // hrValue = heartRate.toDouble(); // } else if (heartRate is String) { // hrValue = double.tryParse(heartRate); // } // if (hrValue != null && // hrValue >= avgHeartRate - standardThreshold && // hrValue <= avgHeartRate + standardThreshold) { // inRangeCount++; // } // } // double inRangePercent = (inRangeCount / processedList.length) * 100; // // 4. 如果小于阈值,结束体验 // if (inRangePercent < totalHeartPercent) { // final openId = deviceUserMap[mac]; // if (openId != null) { // print( // "心率数据不稳定,结束体验: $mac, 平均心率: $avgHeartRate, 在范围比例: $inRangePercent%"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "心率数据不稳定"); // _endExperience( // mac, openId, "心率数据不稳定", ReportStatus.reportExceptionClose.value); // } // return; // } // print("初始数据处理通过: $mac, 平均心率: $avgHeartRate, 在范围比例: $inRangePercent%"); // } catch (e) { // print("处理初始数据异常: $e, MAC=$mac"); // // 处理初始数据异常时更新状态 // if (checkUsing(mac)) { // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "处理初始数据异常: $e"); // } // } // } // // 获取实时数据 // Map getInstantData(String mac, String openId) { // String normalizedMac = _normalizeMac(mac); // String msg = ""; // int flag = 1; // var data; // // 检查设备是否在体验中 // if (!deviceStartTimeMap.containsKey(normalizedMac)) { // flag = -1; // msg = "该设备未开始体验"; // data = null; // } // // 检查用户是否匹配 // else if (deviceUserMap[normalizedMac] != openId) { // flag = -2; // msg = "无权查看该设备数据"; // data = null; // } // // 检查是否有缓存数据 // else if (!bodyDataCache.containsKey(normalizedMac) || // bodyDataCache[normalizedMac]!.isEmpty) { // flag = 0; // msg = "该设备暂无数据"; // data = null; // } else { // // 取最新一次数据 // data = Map.from(bodyDataCache[normalizedMac]!.last); // // 添加进度信息 // data['process'] = macProcess[normalizedMac] ?? 0; // data['openId'] = openId; // // 添加体验时长 // final startTime = deviceStartTimeMap[normalizedMac]!; // final duration = DateTime.now().millisecondsSinceEpoch - startTime; // data['experienceDuration'] = duration ~/ 1000; // 转换为秒 // // 添加有效数据量 // final processedCount = processedDataCache[normalizedMac]?.length ?? 0; // data['processedDataCount'] = processedCount; // data['targetDataCount'] = dataLength; // // 添加报告状态 // data['reportGenerating'] = _reportGeneratingMap[normalizedMac] ?? false; // data['reportGenerated'] = _reportGeneratedMap[normalizedMac] ?? false; // // 添加用户信息(可选) // data['userInfo'] = userInfoMap[normalizedMac]; // } // return {"msg": msg, "flag": flag, "data": data}; // } // // 停止监听设备数据 // void _stopListeningDeviceData(String mac) { // try { // edm.EasyDartModule.websocket.sendData(jsonEncode( // WebSocketMessage(path: "/vsbs/web/rt/marttress", type: 2))); // } catch (e) { // print("停止监听设备数据失败: $e"); // } // } // // 获取所有正在体验的设备列表 // List> getActiveDevices() { // return deviceStartTimeMap.entries.map((entry) { // final mac = entry.key; // return { // 'mac': mac, // 'openId': deviceUserMap[mac], // 'startTime': entry.value, // 'progress': macProcess[mac] ?? 0, // 'processedData': processedDataCache[mac]?.length ?? 0, // 'reportGenerating': _reportGeneratingMap[mac] ?? false, // 'reportGenerated': _reportGeneratedMap[mac] ?? false, // 'userInfo': userInfoMap[mac], // }; // }).toList(); // } // // 获取设备体验时长 // int? getDeviceExperienceDuration(String mac) { // String normalizedMac = _normalizeMac(mac); // if (deviceStartTimeMap.containsKey(normalizedMac)) { // final now = DateTime.now().millisecondsSinceEpoch; // return now - deviceStartTimeMap[normalizedMac]!; // } // return null; // } // // 统一mac地址格式 // String _normalizeMac(String mac) { // if (mac == null || mac.isEmpty) return ''; // String normalized = // mac.toString().replaceAll(RegExp(r'[:-\s]'), '').toUpperCase().trim(); // return normalized; // } // // 调试方法:打印当前状态 // void printStatus() { // print("=== AreaService 状态 ==="); // print("正在体验的设备:"); // deviceStartTimeMap.forEach((mac, startTime) { // final openId = deviceUserMap[mac]; // final progress = macProcess[mac] ?? 0; // final processedCount = processedDataCache[mac]?.length ?? 0; // final reportGenerating = _reportGeneratingMap[mac] ?? false; // final reportGenerated = _reportGeneratedMap[mac] ?? false; // final userInfo = userInfoMap[mac]; // print(" $mac (用户: $openId) - 进度: $progress%, 有效数据: $processedCount"); // print(" 报告状态: 生成中=$reportGenerating, 已生成=$reportGenerated"); // print( // " 用户信息: ${userInfo?['username']}, 年龄: ${userInfo?['age']}, 电话: ${userInfo?['phoneNo']}"); // }); // print("======================"); // } // checkHaveRun(data) async { // data['deviceNo'] = data['mac']; // String serviceAddress = ServiceConstant.service_address; // String serviceName = ServiceConstant.app_server_service; // String serviceApi = "/checkreport/${data['mac']}"; // String queryUrl = "${serviceAddress}${serviceName}${serviceApi}"; // bool flag = false; // await requestWithLog( // logTitle: "APP端提检查快检报告开始体验", // method: MyHttpMethod.get, // queryUrl: queryUrl, // data: data['data'], // onSuccess: (res) { // flag = res.data; // print("[调试][成功][${DateTime.now().toIso8601String()}]: 接收到数据结果为${flag}"); // }, // onFailure: (res) { // flag = true; // print("[调试][失败][${DateTime.now().toIso8601String()}]: 接收到数据结果为${flag}"); // }, // ); // return flag; // } // Future rpcStart(Map data) async { // try { // String serviceAddress = ServiceConstant.service_address; // String serviceName = ServiceConstant.app_server_service; // String serviceApi = "/reportsubmit"; // String queryUrl = "${serviceAddress}${serviceName}${serviceApi}"; // data['openid'] = data['openId']; // data['status'] = ReportStatus.experienceing.value; // await requestWithLog( // logTitle: "APP端提交快检报告开始体验", // method: MyHttpMethod.post, // queryUrl: queryUrl, // data: data, // onSuccess: (res) { // print("通知体验开始成功"); // }, // onFailure: (res) { // print("提交快检报告开始体验失败"); // }, // ); // } catch (e) { // print("远程调用失败:$e"); // } // } // Future requestSleepAnalytics( // Map data, String mac) async { // try { // String queryUrl = // "https://health.ciotcp.com/api/api/h5/getReportByOtherData"; // int retryCount = 0; // bool isSuccess = false; // while (retryCount < 3 && !isSuccess) { // await requestWithLog( // logTitle: "请求实时分析", // method: MyHttpMethod.post, // data: data, // queryUrl: queryUrl, // onSuccess: (res) async { // if (res.data == null || res.data == "") { // retryCount++; // if (retryCount < 3) { // print("请求失败,正在尝试第${retryCount}次重试..."); // } else { // print("请求失败,已尝试3次,停止重试"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "报告请求失败"); // } // } else { // isSuccess = true; // print("请求成功,报告ID: ${res.data}"); // print( // "报告地址: https://health.ciotcp.com/mobile/quickDetail?type=quickCheck&useFrom=Quansi&reportId=${res.data}"); // String openId = deviceUserMap[mac] ?? ""; // await finishDevice(res.data, mac); // await _endExperience( // mac, openId, "体验结束", ReportStatus.reportExceptionClose.value, // rpc: false); // } // }, // onFailure: (res) async { // if (res.code == 20000 && res.data != null) { // // 请求成功,通常不应该进入这里,但为了确保 // isSuccess = true; // print("请求成功,报告ID: ${res.data}"); // await finishDevice(res.data, mac); // } else { // // 请求失败,重新尝试 // retryCount++; // if (retryCount < 3) { // print("请求失败,正在尝试第${retryCount}次重试..."); // } else { // print("请求失败,已尝试3次,停止重试"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "报告请求失败"); // } // } // }, // ); // } // if (!isSuccess) { // print("最终请求失败,无法获取报告数据"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "最终请求失败,无法获取报告数据"); // } // } catch (e) { // print("[请求报告失败]:报告异常:$e"); // print("[微信]:报告异常:$e"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "请求报告失败异常: $e"); // } // } // Future finishDevice(String reportId, String mac) async { // try { // // 从 deviceUserMap 中获取对应的 openid // String? openid = deviceUserMap[mac]; // if (openid == null) { // print("无法找到设备 $mac 对应的用户信息"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "无法找到用户信息"); // return; // } // String serviceAddress = ServiceConstant.service_address; // String serviceName = ServiceConstant.app_server_service; // String serviceApi = "/reportfinish"; // String queryUrl = "${serviceAddress}${serviceName}${serviceApi}"; // // 从 userInfoMap 中获取 deviceNo 或使用 mac // final userInfo = userInfoMap[mac]; // String deviceNo = userInfo?['deviceNo'] ?? mac; // Map finishData = { // "deviceNo": deviceNo, // "openid": openid, // "reportId": reportId, // }; // print("发送报告完成请求: deviceNo=$deviceNo, openid=$openid, reportId=$reportId"); // await requestWithLog( // logTitle: "更新完成状态", // method: MyHttpMethod.post, // data: finishData, // queryUrl: queryUrl, // onSuccess: (res) { // print("[微信]:报告完成成功 $finishData"); // }, // onFailure: (res) { // print("[微信]:报告完成失败 $finishData"); // // 报告完成失败时也要更新状态 // updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "报告完成失败"); // }, // ); // } catch (e) { // print("发送报告完成请求异常: $e"); // await updateDeviceConnectStatus( // ReportStatus.reportExceptionClose.value, mac, // remark: "发送报告完成请求异常: $e"); // } // } // //更新设备状态 // Future updateDeviceConnectStatus(int status, String mac, // {String? remark}) async { // try { // String serviceAddress = ServiceConstant.service_address; // String serviceName = ServiceConstant.app_server_service; // String serviceApi = "/reportupdatestatus"; // String queryUrl = "${serviceAddress}${serviceName}${serviceApi}"; // String? openid = deviceUserMap[mac]; // if (openid == null) { // print("无法找到设备 $mac 对应的用户信息"); // return; // } // // 初始化 data // Map data = { // "deviceNo": mac, // "openid": openid, // "status": status, // }; // // 如果 remark 不为空,则添加到 data 中 // if (remark != null && remark.isNotEmpty) { // data['remark'] = remark; // } // await requestWithLog( // logTitle: "更新设备处理状态", // method: MyHttpMethod.post, // data: data, // queryUrl: queryUrl, // onSuccess: (res) { // print("[微信]:更新状态成功为$data"); // }, // onFailure: (res) { // //更新失败 // print("[微信]:更新状态失败,数据为$data"); // }, // ); // } catch (e) { // print("[微信]:更新失状态败-》$e"); // } // } // checkDeviceState(String mac) async { // try { // bool flag = false; // String queryUrl = // "https://iot.he-info.cn/api/iot/device/info/status?did=${mac}&token=M5Y3B4Frr6T1ACtwMfTNaSaxE2DT16Tn"; // await requestWithLog( // logTitle: "查询设备状态", // method: MyHttpMethod.get, // queryUrl: queryUrl, // onSuccess: (res) { // flag = (res.data[0]['state']) == 3 || // (res.data[0]['state']) == 4 // ? true // : false; // }, // onFailure: (res) { // //更新失败 // flag = (res.data[0]['state']) == 3 || // (res.data[0]['state']) == 4 // ? true // : false; // }, // ); // return flag; // } catch (e) { // print("获取设备状态失败,数据为$e"); // return false; // } // } // }