|
@@ -12,6 +12,7 @@ using HealthMonitor.Service.Biz; |
|
|
using HealthMonitor.Service.Biz.db; |
|
|
using HealthMonitor.Service.Biz.db; |
|
|
using HealthMonitor.Service.Cache; |
|
|
using HealthMonitor.Service.Cache; |
|
|
using HealthMonitor.Service.Etcd; |
|
|
using HealthMonitor.Service.Etcd; |
|
|
|
|
|
using HealthMonitor.Service.MessageQueue; |
|
|
using HealthMonitor.Service.Sub; |
|
|
using HealthMonitor.Service.Sub; |
|
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
|
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
|
|
using Microsoft.EntityFrameworkCore.Metadata.Internal; |
|
|
using Microsoft.EntityFrameworkCore.Metadata.Internal; |
|
@@ -48,6 +49,9 @@ namespace HealthMonitor.WebApi |
|
|
private readonly FetalMovementNormalValueRangeCacheManager _mgrFetalMovementNormalValueRangeCache; |
|
|
private readonly FetalMovementNormalValueRangeCacheManager _mgrFetalMovementNormalValueRangeCache; |
|
|
|
|
|
|
|
|
private readonly GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> _hisFetalHeartApiClient; |
|
|
private readonly GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> _hisFetalHeartApiClient; |
|
|
|
|
|
private readonly GpsLocationHistoryAccessorClient<HisGpsFetalMovement> _hisFetalMovementApiClient; |
|
|
|
|
|
|
|
|
|
|
|
private readonly MqProcessLogic _serviceMqProcess; |
|
|
|
|
|
|
|
|
private CancellationTokenSource _tokenSource = default!; |
|
|
private CancellationTokenSource _tokenSource = default!; |
|
|
|
|
|
|
|
@@ -56,7 +60,8 @@ namespace HealthMonitor.WebApi |
|
|
IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, |
|
|
IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, |
|
|
TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, |
|
|
TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, |
|
|
GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> hisFetalHeartApiClient, |
|
|
GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> hisFetalHeartApiClient, |
|
|
FetalMovementNormalValueRangeCacheManager fetalMovementNormalValueRangeCacheMgr, |
|
|
|
|
|
|
|
|
GpsLocationHistoryAccessorClient<HisGpsFetalMovement> hisFetalMovementApiClient, |
|
|
|
|
|
FetalMovementNormalValueRangeCacheManager fetalMovementNormalValueRangeCacheMgr, MqProcessLogic serviceMqProcess, |
|
|
HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr) |
|
|
HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr) |
|
|
{ |
|
|
{ |
|
|
_logger = logger; |
|
|
_logger = logger; |
|
@@ -72,6 +77,8 @@ namespace HealthMonitor.WebApi |
|
|
_personCacheMgr = personCacheMgr; |
|
|
_personCacheMgr = personCacheMgr; |
|
|
_deviceCacheMgr = deviceCacheMgr; |
|
|
_deviceCacheMgr = deviceCacheMgr; |
|
|
_hisFetalHeartApiClient = hisFetalHeartApiClient; |
|
|
_hisFetalHeartApiClient = hisFetalHeartApiClient; |
|
|
|
|
|
_hisFetalMovementApiClient = hisFetalMovementApiClient; |
|
|
|
|
|
_serviceMqProcess = serviceMqProcess; |
|
|
_mgrFetalMovementNormalValueRangeCache = fetalMovementNormalValueRangeCacheMgr; |
|
|
_mgrFetalMovementNormalValueRangeCache = fetalMovementNormalValueRangeCacheMgr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -371,7 +378,7 @@ namespace HealthMonitor.WebApi |
|
|
// .Select(i => i.InitialMovement) |
|
|
// .Select(i => i.InitialMovement) |
|
|
// .FirstOrDefault() |
|
|
// .FirstOrDefault() |
|
|
// ; |
|
|
// ; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var fetalMovementValue = fetalMovementMapValue * duringMins * 2 / 120; |
|
|
// var fetalMovementValue = fetalMovementMapValue * duringMins * 2 / 120; |
|
|
// // 四舍五入 |
|
|
// // 四舍五入 |
|
|
// var fetalMovement= (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero); |
|
|
// var fetalMovement= (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero); |
|
@@ -388,7 +395,7 @@ namespace HealthMonitor.WebApi |
|
|
// { |
|
|
// { |
|
|
// new () |
|
|
// new () |
|
|
// { |
|
|
// { |
|
|
// Key=nameof(HisGpsFetalHeartRate.Serialno), |
|
|
|
|
|
|
|
|
// Key=nameof(HisGpsFetalimeiDel), |
|
|
// Value=imeiDel, |
|
|
// Value=imeiDel, |
|
|
// ValueType=QueryValueTypeEnum.String, |
|
|
// ValueType=QueryValueTypeEnum.String, |
|
|
// Operator=QueryOperatorEnum.Equal |
|
|
// Operator=QueryOperatorEnum.Equal |
|
@@ -422,7 +429,177 @@ namespace HealthMonitor.WebApi |
|
|
// #endregion |
|
|
// #endregion |
|
|
//} |
|
|
//} |
|
|
|
|
|
|
|
|
|
|
|
#region 胎动延时计算 |
|
|
|
|
|
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067"); |
|
|
|
|
|
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; |
|
|
|
|
|
if (isFetalHeartEnable) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var edoc = DateTimeUtil.ToDateTime(watchConfig!["EDOC"]!.ToString()); |
|
|
|
|
|
// 已经建模 |
|
|
|
|
|
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel); |
|
|
|
|
|
if (commonPHR != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7); |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 计算胎动数据 "); |
|
|
|
|
|
|
|
|
|
|
|
var fmNow = DateTime.Now; |
|
|
|
|
|
// 两小时前 |
|
|
|
|
|
var fmNowSubtract = fmNow.AddMinutes(-fmNow.Minute).AddSeconds(-fmNow.Second).AddMilliseconds(-fmNow.Millisecond); |
|
|
|
|
|
|
|
|
|
|
|
var fetalMovementSampleTime = DateTimeUtil.ConvertToTimeStamp(fmNowSubtract).ToString()[..10]; |
|
|
|
|
|
|
|
|
|
|
|
// 统计开始时间 |
|
|
|
|
|
var statStartTime = fmNowSubtract.AddHours(-2); |
|
|
|
|
|
// 统计结束时间 |
|
|
|
|
|
var statEndTime = fmNowSubtract; |
|
|
|
|
|
|
|
|
|
|
|
var isFetalMovementExisted = await _deviceCacheMgr.FetalMovementIsExistedAsync(imeiDel, fetalMovementSampleTime); |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{fmNowSubtract.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 开始"); |
|
|
|
|
|
|
|
|
|
|
|
if (!isFetalMovementExisted) |
|
|
|
|
|
{ |
|
|
|
|
|
/// 开始计算 |
|
|
|
|
|
var phrRange = phr.Where(i => i.LastUpdate >= statStartTime && i.LastUpdate <= statEndTime) |
|
|
|
|
|
.OrderByDescending(i => i.LastUpdate) |
|
|
|
|
|
.Select(i => i.LastUpdate) |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
// 判断是否有持续佩戴 |
|
|
|
|
|
if (phrRange.Count >= 2) |
|
|
|
|
|
{ |
|
|
|
|
|
var duringMins = Math.Abs((phrRange.First() - statStartTime).TotalMinutes); |
|
|
|
|
|
//在餐后时间段(8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00)取中间值。其他时间段取正常起始值 |
|
|
|
|
|
bool isInTimeRanges = IsLastUpdateInTimeRanges(statEndTime); |
|
|
|
|
|
|
|
|
|
|
|
int pregnancyWeeks = (DateTime.Now - edoc.AddDays(-280)).Days / 7; |
|
|
|
|
|
if (pregnancyWeeks >= 12 && pregnancyWeeks <= 50) |
|
|
|
|
|
{ |
|
|
|
|
|
var fetalMovementMap = _mgrFetalMovementNormalValueRangeCache.GetFetalMovements(); |
|
|
|
|
|
|
|
|
|
|
|
var fetalMovementMapValue = isInTimeRanges ? fetalMovementMap |
|
|
|
|
|
.Where(i => |
|
|
|
|
|
i.PregnancyPeriod![0] <= pregnancyWeeks && |
|
|
|
|
|
i.PregnancyPeriod[1] >= pregnancyWeeks) |
|
|
|
|
|
.Select(i => i.MedianMovement) |
|
|
|
|
|
.FirstOrDefault() |
|
|
|
|
|
: |
|
|
|
|
|
fetalMovementMap |
|
|
|
|
|
.Where(i => |
|
|
|
|
|
i.PregnancyPeriod![0] <= pregnancyWeeks && |
|
|
|
|
|
i.PregnancyPeriod[1] >= pregnancyWeeks) |
|
|
|
|
|
.Select(i => i.InitialMovement) |
|
|
|
|
|
.FirstOrDefault() |
|
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
|
|
var fetalMovementValue = (fetalMovementMapValue * duringMins * 2) / 120; |
|
|
|
|
|
// 四舍五入 |
|
|
|
|
|
var fetalMovement = (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero); |
|
|
|
|
|
// _logger.LogInformation($"{imeiDel} segmentCountFMIndex: {i} -- fetalMovementSampleTime:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")} -- statStartTime: {statStartTime} -- statEndTime: {statEndTime}-- isFetalMovementExisted: {isFetalMovementExisted} "); |
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 胎动数据采样时间:{fetalMovementSampleTime}|{fmNowSubtract.ToString("yyyy-MM-dd HH:mm:ss")}, 采样周期:{statStartTime}-{statEndTime}, 原始胎动值:{fetalMovementMapValue}, 佩戴时间 :{duringMins}|{statStartTime}-{phrRange.First()}, 胎动计算值:{fetalMovementValue}, 胎动最终值:{fetalMovement} 已完成."); |
|
|
|
|
|
|
|
|
|
|
|
// 读取胎心数据 |
|
|
|
|
|
GeneralParam param = new() |
|
|
|
|
|
{ |
|
|
|
|
|
Filters = new List<QueryFilterCondition> |
|
|
|
|
|
{ |
|
|
|
|
|
new () |
|
|
|
|
|
{ |
|
|
|
|
|
Key=nameof(HisGpsFetalHeartRate.Serialno), |
|
|
|
|
|
Value=imeiDel, |
|
|
|
|
|
ValueType=QueryValueTypeEnum.String, |
|
|
|
|
|
Operator=QueryOperatorEnum.Equal |
|
|
|
|
|
}, |
|
|
|
|
|
//new () |
|
|
|
|
|
//{ |
|
|
|
|
|
// Key=nameof(HisGpsFetalHeartRate.SampleTime), |
|
|
|
|
|
// Value=sampleTime, |
|
|
|
|
|
// ValueType=QueryValueTypeEnum.String, |
|
|
|
|
|
// Operator=QueryOperatorEnum.GreaterEqual |
|
|
|
|
|
//}, |
|
|
|
|
|
}, |
|
|
|
|
|
OrderBys=new List<OrderByCondition> |
|
|
|
|
|
{ |
|
|
|
|
|
new (){ |
|
|
|
|
|
IsDesc=true, |
|
|
|
|
|
Key=nameof(HisGpsFetalHeartRate.SampleTime) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
var fetalHeartRateIsAbnormal = 0; |
|
|
|
|
|
var fhr = await _hisFetalHeartApiClient.GetFirstAsync(param, imeiDel[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") }); |
|
|
|
|
|
// 获取胎心数据状态与胎动数据状态一致 |
|
|
|
|
|
var feltalMovementIsAbnormal = fetalHeartRateIsAbnormal; |
|
|
|
|
|
//var feltalMovementIsAbnormal = 0; |
|
|
|
|
|
// 推送到api/v1/open/OpenIot/SetFetalMovementConfig |
|
|
|
|
|
|
|
|
|
|
|
await _serviceIotApi.SetFetalMovementConfig(imeiDel, fetalMovement, fetalMovementSampleTime, feltalMovementIsAbnormal); |
|
|
|
|
|
|
|
|
|
|
|
// 保存到MySQL数据库 |
|
|
|
|
|
HisGpsFetalMovement fm = new() |
|
|
|
|
|
{ |
|
|
|
|
|
FetalMovementId = Guid.NewGuid().ToString("D"), |
|
|
|
|
|
PersonId = commonPHR!.PersonId, |
|
|
|
|
|
Serialno = imeiDel, |
|
|
|
|
|
CreateTime = DateTime.Now, |
|
|
|
|
|
IsAbnormal = feltalMovementIsAbnormal, |
|
|
|
|
|
FetalMovementValue = fetalMovement, |
|
|
|
|
|
SampleTime = fetalMovementSampleTime, |
|
|
|
|
|
Method = 1, |
|
|
|
|
|
IsDisplay = 1, |
|
|
|
|
|
DeviceKey = commonPHR!.DeviceKey |
|
|
|
|
|
}; |
|
|
|
|
|
await _hisFetalMovementApiClient.AddAsync(fm).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
|
|
|
// 发送到微信 |
|
|
|
|
|
if (feltalMovementIsAbnormal != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(imeiDel).ConfigureAwait(false); |
|
|
|
|
|
var fmMsgId = $"{imeiDel}-{fetalMovementSampleTime}-{Guid.NewGuid().ToString("D")[^3..]}"; |
|
|
|
|
|
var topic = "topic.push.wx"; |
|
|
|
|
|
var fmMsg = new |
|
|
|
|
|
{ |
|
|
|
|
|
messageId = Guid.NewGuid().ToString("D"), |
|
|
|
|
|
topic = topic, |
|
|
|
|
|
time = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(fetalMovementSampleTime.Length < 13 ? fetalMovementSampleTime.PadRight(13, '0') : fetalMovementSampleTime)).ToString("yyyy-MM-dd HH:mm:ss"), |
|
|
|
|
|
data = new |
|
|
|
|
|
{ |
|
|
|
|
|
deviceId = device?.DeviceId, |
|
|
|
|
|
imei = imeiDel, |
|
|
|
|
|
alarmTypeId = 12, |
|
|
|
|
|
alarmDeviceName = imeiDel, |
|
|
|
|
|
alarmRemarks = JsonConvert.SerializeObject(new { fetalMovementValue = fetalMovement, isAbnormal = feltalMovementIsAbnormal }), |
|
|
|
|
|
address = string.Empty, |
|
|
|
|
|
deviceKey = device?.DeviceId |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fmMsgId, topic, fmMsg).ConfigureAwait(false); |
|
|
|
|
|
} |
|
|
|
|
|
// 设置入库缓存记录 |
|
|
|
|
|
await _deviceCacheMgr.SetFetalMovementAsync(imeiDel, fetalMovementSampleTime, fm); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogWarning($"{imeiDel} 孕周 {pregnancyWeeks},超出胎动计算范围"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{fmNowSubtract.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足两条,不能判断是否持续佩戴"); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{fmNowSubtract.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
#endregion |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
@@ -794,5 +971,22 @@ namespace HealthMonitor.WebApi |
|
|
|
|
|
|
|
|
return timeRanges.Any(range => now >= range.Start && now <= range.End); |
|
|
return timeRanges.Any(range => now >= range.Start && now <= range.End); |
|
|
} |
|
|
} |
|
|
|
|
|
public static bool IsLastUpdateInTimeRanges(DateTime lastUpdate) |
|
|
|
|
|
{ |
|
|
|
|
|
var now = lastUpdate.TimeOfDay; |
|
|
|
|
|
|
|
|
|
|
|
var timeRanges = new List<(TimeSpan Start, TimeSpan End)> |
|
|
|
|
|
{ |
|
|
|
|
|
// 8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00 |
|
|
|
|
|
(new TimeSpan(8, 0, 0), new TimeSpan(10, 0, 0)), |
|
|
|
|
|
(new TimeSpan(12, 0, 0), new TimeSpan(14, 0, 0)), |
|
|
|
|
|
(new TimeSpan(18, 0, 0), new TimeSpan(20, 0, 0)), |
|
|
|
|
|
(new TimeSpan(22, 0, 0), new TimeSpan(24, 0, 0)) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return timeRanges.Any(range => now >= range.Start && now <= range.End); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |