|
@@ -59,6 +59,8 @@ namespace HealthMonitor.WebApi |
|
|
|
|
|
|
|
|
private CancellationTokenSource _tokenSource = default!; |
|
|
private CancellationTokenSource _tokenSource = default!; |
|
|
|
|
|
|
|
|
|
|
|
private static int INTERVAL_FHR = 15; |
|
|
|
|
|
|
|
|
public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr, |
|
|
public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr, |
|
|
BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService, |
|
|
BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService, |
|
|
IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, |
|
|
IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, |
|
@@ -274,16 +276,17 @@ namespace HealthMonitor.WebApi |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// health_monitor/schedule_push/cal_fetal_heart_rate/imei/ |
|
|
// health_monitor/schedule_push/cal_fetal_heart_rate/imei/ |
|
|
|
|
|
// 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长 |
|
|
if (key.Contains("health_monitor/schedule_push/cal_freqhr_fetal_heart_rate/imei/")) |
|
|
if (key.Contains("health_monitor/schedule_push/cal_freqhr_fetal_heart_rate/imei/")) |
|
|
{ |
|
|
{ |
|
|
/// 延时计算高频状态的胎心数据,防止高频结束后与触发数据时间相隔过长。 |
|
|
/// 延时计算高频状态的胎心数据,防止高频结束后与触发数据时间相隔过长。 |
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel); |
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel); |
|
|
// 高频不停,15分钟内只下发一条 |
|
|
// 高频不停,15分钟内只下发一条 |
|
|
var push =await _deviceCacheMgr.GetBizIntervalAsync(imeiDel, "SaveAndPushFetalHeartRate"); |
|
|
|
|
|
|
|
|
var push = await _deviceCacheMgr.GetBizIntervalAsync(imeiDel, "SaveAndPushFetalHeartRate"); |
|
|
var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; |
|
|
var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; |
|
|
var trigger = triggerValue["trigger"]?.ToString(); |
|
|
var trigger = triggerValue["trigger"]?.ToString(); |
|
|
// 验证高频首条是否还存在 |
|
|
// 验证高频首条是否还存在 |
|
|
if (phrFreqstatus!=null && string.IsNullOrEmpty(push)) |
|
|
|
|
|
|
|
|
if (phrFreqstatus != null && string.IsNullOrEmpty(push)) |
|
|
{ |
|
|
{ |
|
|
if (!string.IsNullOrEmpty(trigger)) |
|
|
if (!string.IsNullOrEmpty(trigger)) |
|
|
{ |
|
|
{ |
|
@@ -316,7 +319,7 @@ namespace HealthMonitor.WebApi |
|
|
var phrFromFreqstatus = phr.Where(i => i.LastUpdate >= phrFreqstatus.LastUpdate).ToList(); |
|
|
var phrFromFreqstatus = phr.Where(i => i.LastUpdate >= phrFreqstatus.LastUpdate).ToList(); |
|
|
// 高频数据 |
|
|
// 高频数据 |
|
|
var phrInFreqstatus = GetFreqPregnancyHeartRate(phrFromFreqstatus, highFreqSampleInterval) |
|
|
var phrInFreqstatus = GetFreqPregnancyHeartRate(phrFromFreqstatus, highFreqSampleInterval) |
|
|
.OrderByDescending(i=>i.LastUpdate).ToList(); |
|
|
|
|
|
|
|
|
.OrderByDescending(i => i.LastUpdate).ToList(); |
|
|
|
|
|
|
|
|
if (phrInFreqstatus.Count > stopHighFreqSampleCount) |
|
|
if (phrInFreqstatus.Count > stopHighFreqSampleCount) |
|
|
{ |
|
|
{ |
|
@@ -355,154 +358,187 @@ namespace HealthMonitor.WebApi |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (key.Contains("health_monitor/schedule_push/cal_fetal_heart_rate/imei/")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 延时计算常规胎心数据 |
|
|
|
|
|
else if (key.Contains("health_monitor/schedule_push/cal_normalphr_fetal_heart_rate/imei/")) |
|
|
{ |
|
|
{ |
|
|
/** |
|
|
|
|
|
var triggerValue= (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; |
|
|
|
|
|
|
|
|
var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; |
|
|
var trigger = triggerValue["trigger"]?.ToString(); |
|
|
var trigger = triggerValue["trigger"]?.ToString(); |
|
|
if (!string.IsNullOrEmpty(trigger)) |
|
|
if (!string.IsNullOrEmpty(trigger)) |
|
|
{ |
|
|
{ |
|
|
var triggerHeartRate= JsonConvert.DeserializeObject<HisGpsHeartRate>(trigger); |
|
|
|
|
|
|
|
|
var triggerHeartRate = JsonConvert.DeserializeObject<HisGpsHeartRate>(trigger); |
|
|
using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = triggerHeartRate?.MessageId! })) |
|
|
using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = triggerHeartRate?.MessageId! })) |
|
|
{ |
|
|
{ |
|
|
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067"); |
|
|
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067"); |
|
|
_logger.LogInformation($"触发常规心率计算胎心"); |
|
|
|
|
|
|
|
|
_logger.LogInformation($"{imeiDel}延迟常规胎心数据产生的胎心数据"); |
|
|
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; |
|
|
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; |
|
|
|
|
|
|
|
|
if (isFetalHeartEnable) |
|
|
if (isFetalHeartEnable) |
|
|
{ |
|
|
{ |
|
|
// 告警上限阀值 |
|
|
|
|
|
var upperAlarmThreshold = (int)watchConfig!["upperAlarmThreshold"]!; |
|
|
|
|
|
// 告警下限阀值 |
|
|
|
|
|
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!; |
|
|
|
|
|
|
|
|
|
|
|
// 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容(最小highFreqSampleInterval=60) |
|
|
|
|
|
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! + 5 : 60; |
|
|
|
|
|
|
|
|
|
|
|
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel); |
|
|
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel); |
|
|
|
|
|
|
|
|
// 最后一条孕妇心率 |
|
|
|
|
|
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(imeiDel); |
|
|
|
|
|
var isNormalHeartRate = triggerHeartRate?.MessageId == lastPhr.MessageId; |
|
|
|
|
|
// 判断最后一条孕妇心率与解析器的触发心率是否一致 |
|
|
|
|
|
if (isNormalHeartRate) |
|
|
|
|
|
|
|
|
if (commonPHR!=null) |
|
|
{ |
|
|
{ |
|
|
//最后一条孕妇心率与解析器的触发心率一致 |
|
|
|
|
|
HisGpsHeartRate heartRate = new() |
|
|
|
|
|
{ |
|
|
|
|
|
CreateTime = lastPhr.CreateTime, |
|
|
|
|
|
DeviceKey = lastPhr.DeviceKey, |
|
|
|
|
|
HeartRate = lastPhr.PregnancyHeartRate, |
|
|
|
|
|
HeartRateId = lastPhr.PregnancyHeartRateId, |
|
|
|
|
|
IsDisplay = lastPhr.IsDisplay ? 1 : 0, |
|
|
|
|
|
MessageId = lastPhr.MessageId, |
|
|
|
|
|
LastUpdate = lastPhr.LastUpdate, |
|
|
|
|
|
Method = lastPhr.Method, |
|
|
|
|
|
PersonId = lastPhr.PersonId, |
|
|
|
|
|
Serialno = lastPhr.SerialNumber |
|
|
|
|
|
}; |
|
|
|
|
|
var intervalFHR = 15; |
|
|
|
|
|
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR); |
|
|
|
|
|
|
|
|
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! : 60; |
|
|
|
|
|
await CalculateNormalFetalHeartRateIntervalAsync(triggerHeartRate!, commonPHR, highFreqSampleInterval); |
|
|
} |
|
|
} |
|
|
// 最后一条孕妇心率与解析器的触发心率不一致,触发心率是高频心率的首条 |
|
|
|
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7); |
|
|
|
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel); |
|
|
|
|
|
|
|
|
|
|
|
if (phrFreqstatus != null) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
#region 高频缓存 |
|
|
|
|
|
// 高频首条是触发心率,30秒后,高频第二条已经写入首条高频缓存 |
|
|
|
|
|
var diffCount = phr.Where(i => i.CreateTime >= phrFreqstatus.CreateTime && i.CreateTime <= lastPhr.CreateTime) |
|
|
|
|
|
.OrderByDescending(i => i.CreateTime); |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 存在高频缓存,高频心率首条记录${phrFreqstatus.MessageId},高频首条到当前的MSG ID{string.Join(",",diffCount.Select(i=>i.MessageId))}"); |
|
|
|
|
|
#endregion |
|
|
|
|
|
} |
|
|
|
|
|
// 不在高频状态状态,但触发孕妇心率与最后一条孕妇心率不一致, |
|
|
|
|
|
// 常规心率数据是批量上报,需要计算每条心率对应的胎心数据 |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 常规心率数据是批量上报,需要计算每条心率对应的胎心数据"); |
|
|
|
|
|
|
|
|
|
|
|
#region 计算每条心率对应的胎心数据 |
|
|
|
|
|
phr = phr.OrderByDescending(i => i.LastUpdate).ToList(); |
|
|
|
|
|
// 获取高频数据 |
|
|
|
|
|
var freqCollection = new List<PregnancyHeartRateModel>(); |
|
|
|
|
|
PregnancyHeartRateModel? previousItem = null; |
|
|
|
|
|
foreach (var item in phr) |
|
|
|
|
|
{ |
|
|
|
|
|
if (previousItem != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds; |
|
|
|
|
|
if (timeNextDiff <= highFreqSampleInterval) |
|
|
|
|
|
{ |
|
|
|
|
|
freqCollection.Add(item); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
previousItem = item; |
|
|
|
|
|
} |
|
|
|
|
|
//去除高频 |
|
|
|
|
|
foreach (var item in freqCollection) |
|
|
|
|
|
{ |
|
|
|
|
|
phr.Remove(item); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 排序并过滤高频数据 |
|
|
|
|
|
//var previousItem = phr.OrderByDescending(i => i.LastUpdate).ToList().First(); |
|
|
|
|
|
//phr = phr.Skip(1) |
|
|
|
|
|
// .Where(item => |
|
|
|
|
|
// { |
|
|
|
|
|
// var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds; |
|
|
|
|
|
// previousItem = item; |
|
|
|
|
|
// return timeNextDiff > highFreqSampleInterval; |
|
|
|
|
|
// }) |
|
|
|
|
|
// .Prepend(previousItem) |
|
|
|
|
|
// .OrderByDescending(i => i.LastUpdate) |
|
|
|
|
|
// .ToList(); |
|
|
|
|
|
|
|
|
|
|
|
var calFhrTasks = phr.Where(p => p.LastUpdate >= triggerHeartRate!.LastUpdate) |
|
|
|
|
|
.Select( async p => |
|
|
|
|
|
{ |
|
|
|
|
|
HisGpsHeartRate heartRate = new() |
|
|
|
|
|
{ |
|
|
|
|
|
CreateTime = p.CreateTime, |
|
|
|
|
|
DeviceKey = p.DeviceKey, |
|
|
|
|
|
HeartRate = p.PregnancyHeartRate, |
|
|
|
|
|
HeartRateId = p.PregnancyHeartRateId, |
|
|
|
|
|
IsDisplay = p.IsDisplay ? 1 : 0, |
|
|
|
|
|
MessageId = p.MessageId, |
|
|
|
|
|
LastUpdate = p.LastUpdate, |
|
|
|
|
|
Method = p.Method, |
|
|
|
|
|
PersonId = p.PersonId, |
|
|
|
|
|
Serialno = p.SerialNumber |
|
|
|
|
|
}; |
|
|
|
|
|
var intervalFHR = 15; |
|
|
|
|
|
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR); |
|
|
|
|
|
}); |
|
|
|
|
|
await Task.WhenAll(calFhrTasks); |
|
|
|
|
|
#endregion |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
_logger.LogWarning($"{imeiDel} 胎心数据建模中..."); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
_logger.LogWarning($"{imeiDel} 胎心监测功能没有开启"); |
|
|
|
|
|
|
|
|
_logger.LogWarning($"{imeiDel} 胎心监测功能没有启动"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogWarning($"{imeiDel} trigger is not set"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
else if (key.Contains("health_monitor/schedule_push/cal_fetal_heart_rate/imei/")) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
var triggerValue= (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; |
|
|
|
|
|
var trigger = triggerValue["trigger"]?.ToString(); |
|
|
|
|
|
if (!string.IsNullOrEmpty(trigger)) |
|
|
|
|
|
{ |
|
|
|
|
|
var triggerHeartRate= JsonConvert.DeserializeObject<HisGpsHeartRate>(trigger); |
|
|
|
|
|
using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = triggerHeartRate?.MessageId! })) |
|
|
|
|
|
{ |
|
|
|
|
|
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067"); |
|
|
|
|
|
_logger.LogInformation($"触发常规心率计算胎心"); |
|
|
|
|
|
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; |
|
|
|
|
|
|
|
|
|
|
|
if (isFetalHeartEnable) |
|
|
|
|
|
{ |
|
|
|
|
|
// 告警上限阀值 |
|
|
|
|
|
var upperAlarmThreshold = (int)watchConfig!["upperAlarmThreshold"]!; |
|
|
|
|
|
// 告警下限阀值 |
|
|
|
|
|
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!; |
|
|
|
|
|
|
|
|
|
|
|
// 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容(最小highFreqSampleInterval=60) |
|
|
|
|
|
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! + 5 : 60; |
|
|
|
|
|
|
|
|
|
|
|
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel); |
|
|
|
|
|
|
|
|
|
|
|
// 最后一条孕妇心率 |
|
|
|
|
|
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(imeiDel); |
|
|
|
|
|
var isNormalHeartRate = triggerHeartRate?.MessageId == lastPhr.MessageId; |
|
|
|
|
|
// 判断最后一条孕妇心率与解析器的触发心率是否一致 |
|
|
|
|
|
if (isNormalHeartRate) |
|
|
|
|
|
{ |
|
|
|
|
|
//最后一条孕妇心率与解析器的触发心率一致 |
|
|
|
|
|
HisGpsHeartRate heartRate = new() |
|
|
|
|
|
{ |
|
|
|
|
|
CreateTime = lastPhr.CreateTime, |
|
|
|
|
|
DeviceKey = lastPhr.DeviceKey, |
|
|
|
|
|
HeartRate = lastPhr.PregnancyHeartRate, |
|
|
|
|
|
HeartRateId = lastPhr.PregnancyHeartRateId, |
|
|
|
|
|
IsDisplay = lastPhr.IsDisplay ? 1 : 0, |
|
|
|
|
|
MessageId = lastPhr.MessageId, |
|
|
|
|
|
LastUpdate = lastPhr.LastUpdate, |
|
|
|
|
|
Method = lastPhr.Method, |
|
|
|
|
|
PersonId = lastPhr.PersonId, |
|
|
|
|
|
Serialno = lastPhr.SerialNumber |
|
|
|
|
|
}; |
|
|
|
|
|
var intervalFHR = 15; |
|
|
|
|
|
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR); |
|
|
|
|
|
} |
|
|
|
|
|
// 最后一条孕妇心率与解析器的触发心率不一致,触发心率是高频心率的首条 |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7); |
|
|
|
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel); |
|
|
|
|
|
|
|
|
|
|
|
if (phrFreqstatus != null) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
#region 高频缓存 |
|
|
|
|
|
// 高频首条是触发心率,30秒后,高频第二条已经写入首条高频缓存 |
|
|
|
|
|
var diffCount = phr.Where(i => i.CreateTime >= phrFreqstatus.CreateTime && i.CreateTime <= lastPhr.CreateTime) |
|
|
|
|
|
.OrderByDescending(i => i.CreateTime); |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 存在高频缓存,高频心率首条记录${phrFreqstatus.MessageId},高频首条到当前的MSG ID{string.Join(",",diffCount.Select(i=>i.MessageId))}"); |
|
|
|
|
|
#endregion |
|
|
|
|
|
} |
|
|
|
|
|
// 不在高频状态状态,但触发孕妇心率与最后一条孕妇心率不一致, |
|
|
|
|
|
// 常规心率数据是批量上报,需要计算每条心率对应的胎心数据 |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 常规心率数据是批量上报,需要计算每条心率对应的胎心数据"); |
|
|
|
|
|
|
|
|
|
|
|
#region 计算每条心率对应的胎心数据 |
|
|
|
|
|
phr = phr.OrderByDescending(i => i.LastUpdate).ToList(); |
|
|
|
|
|
// 获取高频数据 |
|
|
|
|
|
var freqCollection = new List<PregnancyHeartRateModel>(); |
|
|
|
|
|
PregnancyHeartRateModel? previousItem = null; |
|
|
|
|
|
foreach (var item in phr) |
|
|
|
|
|
{ |
|
|
|
|
|
if (previousItem != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds; |
|
|
|
|
|
if (timeNextDiff <= highFreqSampleInterval) |
|
|
|
|
|
{ |
|
|
|
|
|
freqCollection.Add(item); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
previousItem = item; |
|
|
|
|
|
} |
|
|
|
|
|
//去除高频 |
|
|
|
|
|
foreach (var item in freqCollection) |
|
|
|
|
|
{ |
|
|
|
|
|
phr.Remove(item); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 排序并过滤高频数据 |
|
|
|
|
|
//var previousItem = phr.OrderByDescending(i => i.LastUpdate).ToList().First(); |
|
|
|
|
|
//phr = phr.Skip(1) |
|
|
|
|
|
// .Where(item => |
|
|
|
|
|
// { |
|
|
|
|
|
// var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds; |
|
|
|
|
|
// previousItem = item; |
|
|
|
|
|
// return timeNextDiff > highFreqSampleInterval; |
|
|
|
|
|
// }) |
|
|
|
|
|
// .Prepend(previousItem) |
|
|
|
|
|
// .OrderByDescending(i => i.LastUpdate) |
|
|
|
|
|
// .ToList(); |
|
|
|
|
|
|
|
|
|
|
|
var calFhrTasks = phr.Where(p => p.LastUpdate >= triggerHeartRate!.LastUpdate) |
|
|
|
|
|
.Select( async p => |
|
|
|
|
|
{ |
|
|
|
|
|
HisGpsHeartRate heartRate = new() |
|
|
|
|
|
{ |
|
|
|
|
|
CreateTime = p.CreateTime, |
|
|
|
|
|
DeviceKey = p.DeviceKey, |
|
|
|
|
|
HeartRate = p.PregnancyHeartRate, |
|
|
|
|
|
HeartRateId = p.PregnancyHeartRateId, |
|
|
|
|
|
IsDisplay = p.IsDisplay ? 1 : 0, |
|
|
|
|
|
MessageId = p.MessageId, |
|
|
|
|
|
LastUpdate = p.LastUpdate, |
|
|
|
|
|
Method = p.Method, |
|
|
|
|
|
PersonId = p.PersonId, |
|
|
|
|
|
Serialno = p.SerialNumber |
|
|
|
|
|
}; |
|
|
|
|
|
var intervalFHR = 15; |
|
|
|
|
|
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR); |
|
|
|
|
|
}); |
|
|
|
|
|
await Task.WhenAll(calFhrTasks); |
|
|
|
|
|
#endregion |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogWarning($"{imeiDel} 胎心监测功能没有开启"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogWarning($"{imeiDel} trigger is not set"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
// 胎动计算 |
|
|
// 胎动计算 |
|
|
//health_monitor/schedule_push/cal_fetal_movement/imei/ |
|
|
//health_monitor/schedule_push/cal_fetal_movement/imei/ |
|
@@ -1026,7 +1062,7 @@ namespace HealthMonitor.WebApi |
|
|
statStartTime = firstHmBp!.Timestamp; |
|
|
statStartTime = firstHmBp!.Timestamp; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// NewMethod(systolicRefValue, hmBpParser); |
|
|
|
|
|
|
|
|
// GetSampleTime(systolicRefValue, hmBpParser); |
|
|
|
|
|
|
|
|
// 最大值 |
|
|
// 最大值 |
|
|
//systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!; |
|
|
//systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!; |
|
@@ -1532,5 +1568,279 @@ namespace HealthMonitor.WebApi |
|
|
|
|
|
|
|
|
return freqCollection; |
|
|
return freqCollection; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public async Task CalculateNormalFetalHeartRateIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,int highFreqSampleInterval) |
|
|
|
|
|
{ |
|
|
|
|
|
var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7); |
|
|
|
|
|
var filteredPhr = daysPhr.Where(i => i.LastUpdate >= heartRate.LastUpdate && i.LastUpdate <= DateTime.Now).ToList(); |
|
|
|
|
|
// 去除高频 |
|
|
|
|
|
var normalPhr = GetNonFreqPregnancyHeartRate(filteredPhr, highFreqSampleInterval).OrderBy(i => i.LastUpdate); |
|
|
|
|
|
|
|
|
|
|
|
var startPhr = normalPhr.First(); |
|
|
|
|
|
var endPhr = normalPhr.Last(); |
|
|
|
|
|
|
|
|
|
|
|
//var sampleTime = GetSampleTimeFromLastUpdate((DateTime)heartRate.LastUpdate!, INTERVAL_FHR); |
|
|
|
|
|
// 数据统计边界 |
|
|
|
|
|
var boundaryStatStartTime = GetSampleTimeFromLastUpdate((DateTime)startPhr.LastUpdate!, INTERVAL_FHR); |
|
|
|
|
|
var boundaryStatEndTime = GetSampleTimeFromLastUpdate((DateTime)endPhr.LastUpdate!, INTERVAL_FHR).AddMinutes(INTERVAL_FHR); |
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 统计边界{boundaryStatStartTime}-{boundaryStatEndTime}"); |
|
|
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
|
{ |
|
|
|
|
|
while (true) |
|
|
|
|
|
{ |
|
|
|
|
|
var c = 0; |
|
|
|
|
|
var segmentStatStartTime = boundaryStatStartTime.AddMinutes(c * INTERVAL_FHR); |
|
|
|
|
|
var segmentStatEndTime = segmentStatStartTime.AddMinutes(INTERVAL_FHR); |
|
|
|
|
|
c++; |
|
|
|
|
|
|
|
|
|
|
|
var statStartTime = segmentStatStartTime; |
|
|
|
|
|
var statEndTime = segmentStatEndTime; |
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 当前统计周期{statStartTime}-{statEndTime}"); |
|
|
|
|
|
|
|
|
|
|
|
var segmentPhr = daysPhr |
|
|
|
|
|
.Where(i => i.LastUpdate <= statEndTime && i.LastUpdate >= statStartTime) |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
|
|
|
|
|
|
if (segmentPhr.Count == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
// 跳出当次迭代,进入下次迭代 |
|
|
|
|
|
_logger.LogWarning($"{heartRate.Serialno} 统计周期:{statStartTime}-{statEndTime} 孕妇心率数据不足,{segmentPhr.Count}条记录,不处理"); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var sampleTime = DateTimeUtil.ConvertToTimeStamp(segmentStatStartTime).ToString(); |
|
|
|
|
|
sampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : sampleTime; |
|
|
|
|
|
|
|
|
|
|
|
//检测 是否存在,不存在则处理 |
|
|
|
|
|
GeneralParam param = new() |
|
|
|
|
|
{ |
|
|
|
|
|
Filters = new List<QueryFilterCondition> |
|
|
|
|
|
{ |
|
|
|
|
|
new () |
|
|
|
|
|
{ |
|
|
|
|
|
Key=nameof(HisGpsFetalHeartRate.Serialno), |
|
|
|
|
|
Value=heartRate.Serialno, |
|
|
|
|
|
ValueType=QueryValueTypeEnum.String, |
|
|
|
|
|
Operator=QueryOperatorEnum.Equal |
|
|
|
|
|
}, |
|
|
|
|
|
new () |
|
|
|
|
|
{ |
|
|
|
|
|
Key=nameof(HisGpsFetalHeartRate.SampleTime), |
|
|
|
|
|
Value=sampleTime, |
|
|
|
|
|
ValueType=QueryValueTypeEnum.String, |
|
|
|
|
|
Operator=QueryOperatorEnum.Equal |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
OrderBys = new List<OrderByCondition> |
|
|
|
|
|
{ |
|
|
|
|
|
new (){ |
|
|
|
|
|
IsDesc=true, |
|
|
|
|
|
Key=nameof(HisGpsFetalHeartRate.SampleTime) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var fhr = await _hisFetalHeartApiClient.GetFirstAsync(param, heartRate.Serialno[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") }); |
|
|
|
|
|
|
|
|
|
|
|
if (fhr == null) |
|
|
|
|
|
{ |
|
|
|
|
|
var avgPhr = segmentPhr.Count == 1 |
|
|
|
|
|
? segmentPhr.First().PregnancyHeartRate |
|
|
|
|
|
: segmentPhr.Average(i => i.PregnancyHeartRate); |
|
|
|
|
|
|
|
|
|
|
|
heartRate.HeartRate = (int)avgPhr; |
|
|
|
|
|
|
|
|
|
|
|
#region 胎心系数使用基于心率与中位数对比 |
|
|
|
|
|
var coefficient = 0f; |
|
|
|
|
|
// 孕妇心率少于中位数,取StatMinValueFprCoefficient |
|
|
|
|
|
if (heartRate.HeartRate < commonPHR!.Mode) |
|
|
|
|
|
{ |
|
|
|
|
|
coefficient = commonPHR.StatMinValueFprCoefficient!; |
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率少于中位数,使用最小值系数 {coefficient}"); |
|
|
|
|
|
} |
|
|
|
|
|
// 孕妇心率大于中位数,取StatMaxValueFprCoefficient与StatModeAvgFprCoefficient中少的那个 |
|
|
|
|
|
else if (heartRate.HeartRate > commonPHR.Mode) |
|
|
|
|
|
{ |
|
|
|
|
|
if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMaxValueFprCoefficient) |
|
|
|
|
|
{ |
|
|
|
|
|
coefficient = commonPHR.StatMaxValueFprCoefficient!; |
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于中位数,使用最大值系数 {coefficient}"); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
coefficient = commonPHR.StatModeAvgFprCoefficient!; |
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于中位数,使用均值系数 {coefficient}"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
coefficient = commonPHR.StatModeAvgFprCoefficient; |
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率等于中位数,使用均值系数 {coefficient}"); |
|
|
|
|
|
} |
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
#region 胎心阈值判断 |
|
|
|
|
|
//var fetalHeartRate = SafeType.SafeInt(heartRate.HeartRate * coefficient); |
|
|
|
|
|
//// 胎心的最大值调整为220,超过都按该值220输出 |
|
|
|
|
|
//// fetalHeartRate = fetalHeartRate>= 220 ? 220 : fetalHeartRate; |
|
|
|
|
|
|
|
|
|
|
|
//if (fetalHeartRate > 220) |
|
|
|
|
|
//{ |
|
|
|
|
|
// fetalHeartRate = 220; |
|
|
|
|
|
// _logger.LogWarning($"{heartRate.Serialno} 大于220,按220输出,计算因子:孕妇心率 {heartRate.HeartRate},系数 {coefficient},周期 周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}"); |
|
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
|
|
//// 胎心的最小值调整为90,超过都按该值90 |
|
|
|
|
|
//if (fetalHeartRate < 90) |
|
|
|
|
|
//{ |
|
|
|
|
|
// fetalHeartRate = 90; |
|
|
|
|
|
// _logger.LogWarning($"{heartRate.Serialno} 小于90,按90输出,计算因子:孕妇心率 {heartRate.HeartRate},系数 {coefficient},周期 周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}"); |
|
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算胎心率并进行边界检查 |
|
|
|
|
|
var fetalHeartRate = Math.Clamp((int)(heartRate.HeartRate * coefficient), 90, 220); |
|
|
|
|
|
if (fetalHeartRate != (int)(heartRate.HeartRate * coefficient)) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogWarning($"{heartRate.Serialno} 胎心率超出范围, 按修正值 {fetalHeartRate} 输出, 计算因子:孕妇心率 {heartRate.HeartRate}, 系数 {coefficient}, 周期 {statStartTime} - {statEndTime}"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 在 常规 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}"); |
|
|
|
|
|
var isAbnormal = 0; |
|
|
|
|
|
|
|
|
|
|
|
#region 保存到Mysql数据库 |
|
|
|
|
|
// 保存到 数据服务 MySQL 数据库 |
|
|
|
|
|
HisGpsFetalHeartRate gpsFetalHeartRate = new() |
|
|
|
|
|
{ |
|
|
|
|
|
FetalHeartRateId = Guid.NewGuid().ToString("D"), |
|
|
|
|
|
PersonId = commonPHR!.PersonId, |
|
|
|
|
|
Serialno = heartRate.Serialno, |
|
|
|
|
|
HeartRate = fetalHeartRate, |
|
|
|
|
|
SampleTime = sampleTime, |
|
|
|
|
|
IsAbnormal = isAbnormal, |
|
|
|
|
|
StatStartTime = statStartTime, |
|
|
|
|
|
StatEndTime = statEndTime,//commonPHR.StatEndTime, |
|
|
|
|
|
CreateTime = DateTime.Now, |
|
|
|
|
|
Method = 1, |
|
|
|
|
|
IsDisplay = 1, |
|
|
|
|
|
DeviceKey = commonPHR!.DeviceKey |
|
|
|
|
|
}; |
|
|
|
|
|
await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false); |
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
#region 推送最后一条常规心率计算的胎心数据到iot设备 |
|
|
|
|
|
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(heartRate.Serialno); |
|
|
|
|
|
if (segmentStatEndTime == boundaryStatEndTime) |
|
|
|
|
|
{ |
|
|
|
|
|
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); |
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备"); |
|
|
|
|
|
} |
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
#region 推送到第三方 |
|
|
|
|
|
var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false); |
|
|
|
|
|
var fhrMsgId = $"{heartRate.Serialno}-{sampleTime}-{Guid.NewGuid().ToString("D")[^3..]}"; |
|
|
|
|
|
var fhrMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(sampleTime.Length < 13 ? sampleTime.PadRight(13, '0') : sampleTime)).ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
|
|
|
var topic = "topic.push.third"; |
|
|
|
|
|
var fhrThridMsg = new |
|
|
|
|
|
{ |
|
|
|
|
|
messageId = fhrMsgId, |
|
|
|
|
|
topic = topic, |
|
|
|
|
|
time = fhrMsgTime, |
|
|
|
|
|
data = new |
|
|
|
|
|
{ |
|
|
|
|
|
imei = heartRate.Serialno, |
|
|
|
|
|
value = fetalHeartRate, |
|
|
|
|
|
isAbnormal, |
|
|
|
|
|
type = "fetalHeart" |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31, fhrThridMsg).ConfigureAwait(false); |
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
#region 推送到微信 |
|
|
|
|
|
if (isAbnormal != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
topic = "topic.push.wx"; |
|
|
|
|
|
var fhrMsg = new |
|
|
|
|
|
{ |
|
|
|
|
|
messageId = fhrMsgId, |
|
|
|
|
|
topic = topic, |
|
|
|
|
|
time = fhrMsgTime, |
|
|
|
|
|
data = new |
|
|
|
|
|
{ |
|
|
|
|
|
deviceId = device?.DeviceId, |
|
|
|
|
|
imei = heartRate.Serialno, |
|
|
|
|
|
alarmTypeId = 12, |
|
|
|
|
|
alarmDeviceName = heartRate.Serialno, |
|
|
|
|
|
alarmRemarks = JsonConvert.SerializeObject(new { fetalHeartValue = fetalHeartRate, isAbnormal = isAbnormal }), |
|
|
|
|
|
address = string.Empty, |
|
|
|
|
|
deviceKey = device?.DeviceId |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, fhrMsg).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")} ,胎心已处理"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 跳出循环 |
|
|
|
|
|
if (statEndTime == boundaryStatEndTime) |
|
|
|
|
|
{ |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
catch (Exception ex) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogError($"处理心率数据时发生错误: {ex.Message}"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//for (var segmentStatStartTime = boundaryStatStartTime; |
|
|
|
|
|
// segmentStatStartTime < boundaryStatEndTime; |
|
|
|
|
|
// segmentStatStartTime = segmentStatStartTime.AddMinutes(INTERVAL_FHR)) |
|
|
|
|
|
//{ |
|
|
|
|
|
// var segmentStatEndTime = segmentStatStartTime.AddMinutes(INTERVAL_FHR); |
|
|
|
|
|
|
|
|
|
|
|
// var segmentPhr = daysPhr |
|
|
|
|
|
// .Where(i => i.LastUpdate <= segmentStatEndTime && i.LastUpdate >= segmentStatStartTime) |
|
|
|
|
|
// .ToList(); |
|
|
|
|
|
|
|
|
|
|
|
// if (segmentStatEndTime == boundaryStatEndTime) |
|
|
|
|
|
// { |
|
|
|
|
|
// break; |
|
|
|
|
|
// } |
|
|
|
|
|
//} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private DateTime GetSampleTimeFromLastUpdate(DateTime lastUpdate,int interval) |
|
|
|
|
|
{ |
|
|
|
|
|
DateTime nowInterval = lastUpdate; |
|
|
|
|
|
if (nowInterval.Second > 0) |
|
|
|
|
|
{ |
|
|
|
|
|
nowInterval = nowInterval.AddMinutes(1); |
|
|
|
|
|
} |
|
|
|
|
|
// 计算last_update到上一间隔的分钟数 |
|
|
|
|
|
int minutesToSubtract = nowInterval.Minute % interval; |
|
|
|
|
|
|
|
|
|
|
|
// 计算上一间隔的时间 |
|
|
|
|
|
DateTime previousInterval = nowInterval.AddMinutes(-minutesToSubtract).AddSeconds(-nowInterval.Second).AddMilliseconds(-nowInterval.Millisecond); |
|
|
|
|
|
|
|
|
|
|
|
return previousInterval; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |