|
- using dotnet_etcd;
- using Etcdserverpb;
- using Google.Protobuf.WellKnownTypes;
- using HealthMonitor.Common;
- using HealthMonitor.Common.helper;
- using HealthMonitor.Core.Common.Extensions;
- using HealthMonitor.Core.Pipeline;
- using HealthMonitor.Model.Config;
- using HealthMonitor.Model.Service;
- using HealthMonitor.Model.Service.Mapper;
- using HealthMonitor.Service.Biz;
- using HealthMonitor.Service.Biz.db;
- using HealthMonitor.Service.Cache;
- using HealthMonitor.Service.Etcd;
- using HealthMonitor.Service.MessageQueue;
- using HealthMonitor.Service.Sub;
- using Microsoft.AspNetCore.Mvc.RazorPages;
- using Microsoft.EntityFrameworkCore.Metadata;
- using Microsoft.EntityFrameworkCore.Metadata.Internal;
- using Microsoft.Extensions.Options;
- using NetTaste;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- using System;
- using System.Reflection;
- using System.Text.RegularExpressions;
- using System.Threading.Channels;
- using TDengineDriver;
- using TDengineTMQ;
- using TelpoDataService.Util.Clients;
- using TelpoDataService.Util.Entities.GpsCard;
- using TelpoDataService.Util.Entities.GpsLocationHistory;
- using TelpoDataService.Util.Models;
- using TelpoDataService.Util.QueryObjects;
-
- namespace HealthMonitor.WebApi
- {
- public class Worker : BackgroundService
- {
- private readonly ILogger<Worker> _logger;
- private readonly IServiceProvider _services;
- private readonly TDengineDataSubcribe _tdEngineDataSubcribe;
- private readonly PackageProcess _processor;
- private readonly TDengineService _serviceTDengine;
- private readonly EtcdService _serviceEtcd;
- private readonly HttpHelper _httpHelper = default!;
- private readonly IotApiService _serviceIotApi;
- private readonly BoodPressResolverConfig _configBoodPressResolver;
- private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager;
- private readonly PersonCacheManager _personCacheMgr;
- private readonly DeviceCacheManager _deviceCacheMgr;
- private readonly FetalMovementNormalValueRangeCacheManager _mgrFetalMovementNormalValueRangeCache;
-
- private readonly GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> _hisFetalHeartApiClient;
- private readonly GpsLocationHistoryAccessorClient<HisGpsFetalMovement> _hisFetalMovementApiClient;
-
- private readonly GpsLocationHistoryAccessorClient<HisGpsPsychResult> _hisPsychResultApiClient;
-
- private readonly MqProcessLogic _serviceMqProcess;
-
- private CancellationTokenSource _tokenSource = default!;
-
- private static int INTERVAL_FHR = 15;
-
- public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr,
- BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService,
- IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor,
- TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine,
- GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> hisFetalHeartApiClient,
- GpsLocationHistoryAccessorClient<HisGpsFetalMovement> hisFetalMovementApiClient,
- GpsLocationHistoryAccessorClient<HisGpsPsychResult> hisGpsPsychResultApiClient,
- FetalMovementNormalValueRangeCacheManager fetalMovementNormalValueRangeCacheMgr, MqProcessLogic serviceMqProcess,
- HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr)
- {
- _logger = logger;
- _tdEngineDataSubcribe = tdEngineDataSubcribe;
- _services = services;
- _serviceIotApi = IotApiService;
- _processor = processor;
- _serviceEtcd = serviceEtcd;
- _serviceTDengine = serviceDengine;
- _httpHelper = httpHelper;
- _configBoodPressResolver = optionBoodPressResolver.Value;
- _bpRefValCacheManager = bpRefValCacheManager;
- _personCacheMgr = personCacheMgr;
- _deviceCacheMgr = deviceCacheMgr;
- _hisFetalHeartApiClient = hisFetalHeartApiClient;
- _hisFetalMovementApiClient = hisFetalMovementApiClient;
- _hisPsychResultApiClient = hisGpsPsychResultApiClient;
- _serviceMqProcess = serviceMqProcess;
- _mgrFetalMovementNormalValueRangeCache = fetalMovementNormalValueRangeCacheMgr;
-
- }
-
- public override Task StartAsync(CancellationToken cancellationToken)
- {
- //_logger.LogInformation("------StartAsync");
- _tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
- return base.StartAsync(cancellationToken);
- }
-
- public override Task StopAsync(CancellationToken cancellationToken)
- {
- //_logger.LogInformation("------StopAsync");
- _tokenSource.Cancel(); //停止工作线程
- return base.StopAsync(cancellationToken);
- }
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- var tasks = new[]
- {
- Task.Run(async () =>
- {
- _logger.LogInformation("解析器启动");
- while (!stoppingToken.IsCancellationRequested)
- {
- await _processor.ResolveAsync().ConfigureAwait(false);
- }
- }, stoppingToken),
-
- Task.Run(() =>
- {
- _logger.LogInformation("TDengine 订阅启动");
- while (!stoppingToken.IsCancellationRequested)
- {
- _tdEngineDataSubcribe.BeginListen(stoppingToken);
- }
- }, stoppingToken),
-
- Task.Run(() =>
- _serviceEtcd.WacthKeysWithPrefixResponseAsync("health_monitor/schedule_push", WatchEvents),
- stoppingToken)
- };
-
- await Task.WhenAll(tasks);
- }
-
- private void WatchEvents(WatchResponse response)
- {
-
- response.Events.ToList<Mvccpb.Event>().ForEach(async e =>
- {
- try
- {
- switch (e.Type.ToString())
- {
- case "Put":
- // 获取时间点计算TTL
- Console.BackgroundColor = ConsoleColor.Blue;
- Console.WriteLine($"--- {e.Type}--{e.Kv.Key.ToStringUtf8()}--{e.Kv.Value.ToStringUtf8()}---{DateTime.Now}");
- Console.BackgroundColor = ConsoleColor.Black;
- break;
-
- case "Delete":
- // TTL到了重新计算TTL,下发
- //Console.BackgroundColor = ConsoleColor.Green;
- //Console.WriteLine($"--- {e.Type}--{e.Kv.Key.ToStringUtf8()}--{e.Kv.Value.ToStringUtf8()}---{DateTime.Now}");
-
- // var key = $"health_monitor/schedule_push/imei/{bp.Serialno}";
- var key = e.Kv.Key.ToStringUtf8();
- //var imeiDel = key.Split('/')[^1];
- var imeiDel = ExtractImei(key);
- if (string.IsNullOrEmpty(imeiDel))
- {
- _logger.LogWarning("定时器不能抽取imei");
- return;
- }
- var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);
- if (string.IsNullOrWhiteSpace(schedule_push))
- {
- // 胎心数据建模
- if (key.Contains("pregnancy_heart_rate"))
- {
- using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = $"MODE-{imeiDel}-{DateTime.Now.ToString("yyyyMMddHHmmss")}" }))
- {
- #region 胎心数据建模
- var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
- var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
-
- if (isFetalHeartEnable)
- {
- // 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容
- //var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! + 5;
- // 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容(最小highFreqSampleInterval=60)
- var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! + 5 : 60;
- // 处理孕妇业务,计算一般心率并下发
- var commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(imeiDel, highFreqSampleInterval: highFreqSampleInterval);
- if (commonPHR == null)
- {
- // 建模中
- var flag = await _serviceIotApi.SetFetalConfig(imeiDel);
- _logger.LogInformation($"{imeiDel} 建模建模中");
- }
- else
- {
- // 建模完成
- var flag = await _serviceIotApi.SetFetalConfig(imeiDel, 1, commonPHR.MaxValue, commonPHR.MinValue);
- _logger.LogInformation($"{imeiDel} 建模完成");
- // 保存到TDengine数据库
- await _serviceTDengine.InsertAsync<PregnancyCommonHeartRateModel>("hm_pchr", commonPHR);
- _logger.LogInformation($"保存TDengine完成");
-
- //
- }
- }
-
- #endregion
-
- #region 注册定时下发
- var startTime = DateTime.Now;
- // 注册下次下推
- var endTime = DateTime.Now;
-
- #if DEBUG
-
-
- //long ttl = (long)((60 * 1000-(endTime-startTime).TotalMilliseconds)/1000);
- //await _serviceEtcd.PutValAsync(key, imeiDel,ttl, false).ConfigureAwait(false);
-
- var interval = 0;
- // 获取当前时间
- DateTime now = DateTime.Now;
-
- // 计算距离下一个$interval天后的8点的时间间隔
- DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 2, 0).AddDays(interval);
- TimeSpan timeUntilNextRun = nextRunTime - now;
-
- // 如果当前时间已经超过了8点,将等待到明天后的8点
- if (timeUntilNextRun < TimeSpan.Zero)
- {
- timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1));
- nextRunTime += timeUntilNextRun;
- }
-
- //long ttl = timeUntilNextRun.Milliseconds/1000;
- long ttl = (long)((timeUntilNextRun.TotalMilliseconds - (endTime - startTime).TotalMilliseconds) / 1000);
- var data = new
- {
- imei = imeiDel,
- create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
- ttl,
- next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
- };
- var result = JsonConvert.SerializeObject(data);
-
- await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
-
-
- #else
- // 每$interval天,晚上8点
- var interval = 1;
- // 获取当前时间
- DateTime now = DateTime.Now;
- var rand = new Random();
-
- var pushSec = rand.Next(59);
- int pushMin = int.TryParse(imeiDel.AsSpan(imeiDel.Length - 1), out pushMin) ? pushMin : 10;
- // 计算距离下一个$interval天后的0点的时间间隔
- DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 6, pushMin, pushSec).AddDays(interval);
- TimeSpan timeUntilNextRun = nextRunTime - now;
-
- // 如果当前时间已经超过了8点,将等待到明天后的8点
- if (timeUntilNextRun < TimeSpan.Zero)
- {
- timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
- nextRunTime += timeUntilNextRun;
- }
-
- // var ttl = timeUntilNextRun.TotalMilliseconds;
- long ttl = (long)((timeUntilNextRun.TotalMilliseconds-(endTime-startTime).TotalMilliseconds)/1000);
- var data = new
- {
- imei = imeiDel,
- create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
- ttl,
- next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
- };
- var result = JsonConvert.SerializeObject(data);
- await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
- #endif
- #endregion
-
- }
- }
- // health_monitor/schedule_push/cal_fetal_heart_rate/imei/
- // 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长
- if (key.Contains("health_monitor/schedule_push/cal_freqhr_fetal_heart_rate/imei/"))
- {
- /// 延时计算高频状态的胎心数据,防止高频结束后与触发数据时间相隔过长。
- var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel);
- // 高频不停,15分钟内只下发一条
- var push = await _deviceCacheMgr.GetBizIntervalAsync(imeiDel, "SaveAndPushFetalHeartRate");
- var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!;
- var trigger = triggerValue["trigger"]?.ToString();
- // 验证高频首条是否还存在
- if (phrFreqstatus != null && string.IsNullOrEmpty(push))
- {
- 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($"{imeiDel}高频结束后,延迟计算高频数据产生的胎心数据");
- var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
- if (isFetalHeartEnable)
- {
- // 防止超过12条连续正常,高频不停止
- if (phrFreqstatus.MessageId == triggerHeartRate?.MessageId)
- {
- // 告警上限阀值
- 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 stopHighFreqSampleCount = (int)watchConfig["stopHighFreqSampleCount"]!;
-
- // 高频心率采集时长 0 为持续采集,非零为高频心率的采集时长
- //var highFreqSampleTimes = (int)watchConfig["highFreqSampleTimes"]!;
- var highFreqSampleTimes = 540;
-
- var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel);
-
-
- var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7);
- var phrFromFreqstatus = phr.Where(i => i.LastUpdate >= phrFreqstatus.LastUpdate).ToList();
- // 高频数据
- var phrInFreqstatus = GetFreqPregnancyHeartRate(phrFromFreqstatus, highFreqSampleInterval)
- .OrderByDescending(i => i.LastUpdate).ToList();
-
- if (phrInFreqstatus.Count > stopHighFreqSampleCount)
- {
- // 取最后 stopHighFreqSampleCount 条高频数据
- phrInFreqstatus = phrInFreqstatus
- .OrderByDescending(i => i.LastUpdate)
- .Take(stopHighFreqSampleCount).ToList(); // 计算最后12条
-
- var avgPhr = phrInFreqstatus
- .Select(i => i.PregnancyHeartRate).Average();
-
- var FreqStatsEnd = phrInFreqstatus.First().LastUpdate;
-
- _logger.LogInformation($"延时计算,{imeiDel} 高频状态持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,统计周期:{phrFreqstatus!.LastUpdate.ToString("yyyy-MM-dd HH:mm:ss")}----{FreqStatsEnd.ToString("yyyy-MM-dd HH:mm:ss")},高频心率平均值:{(int)avgPhr},将下发指令");
-
- //await SaveAndPushFetalHeartRateAsync(triggerHeartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);
- triggerHeartRate.HeartRate = (int)avgPhr;
- //await SaveAndPushFetalHeartRateEndFreqHeartRateAsync(triggerHeartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);
-
- // 判断是否够highFreqSampleTimes,540s
- var lastPhr = phrInFreqstatus;
- // 最后一条高频心率
- var lastFreqHr = phrInFreqstatus.First();
- var ts = DateTimeUtil.GetTimeDifferenceInSeconds((DateTime)lastFreqHr.LastUpdate!, phrFreqstatus!.LastUpdate);
- if (ts < highFreqSampleTimes)
- {
- /// 不够10分钟最近12个数据的最小值生成胎心值
- _logger.LogInformation($"{triggerHeartRate.Serialno} 不够10分钟最近12个数据的最小值生成胎心值");
- triggerHeartRate.HeartRate = lastPhr.Select(i => i.PregnancyHeartRate).Min();
- triggerHeartRate.LastUpdate = lastFreqHr.LastUpdate;
- }
- _logger.LogInformation($"{triggerHeartRate.Serialno} 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理");
-
- await SaveAndPushFetalHeartRateEndFreqHeartRateAsync(triggerHeartRate, commonPHR, highFreqSampleTimes, upperAlarmThreshold, lowerAlarmThreshold, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 高频心率的数据不大于{stopHighFreqSampleCount}条,不进行高频数据的胎心计算");
-
- }
- // 删除高频状态的首条记录
- await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(imeiDel);
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 超过12条连续正常,高频不停止,暂不处理");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 胎心监测功能没有启动");
- }
- }
- }
- }
- }
-
- // 延时计算常规胎心数据
- else if (key.Contains("health_monitor/schedule_push/cal_normalphr_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($"{imeiDel}延迟常规胎心数据产生的胎心数据");
- var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
- if (isFetalHeartEnable)
- {
- var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel);
- if (commonPHR!=null)
- {
- var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! : 60;
- await CalculateNormalFetalHeartRateIntervalAsync(triggerHeartRate!, commonPHR, highFreqSampleInterval);
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 胎心数据建模中...");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 胎心监测功能没有启动");
- }
- }
- }
- }
- 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/
- else if (key.Contains("health_monitor/schedule_push/cal_fetal_movement/imei/"))
- {
- #region 相隔2小时胎动延时计算(实时now是3小时,计算 lastupdate 0~2范围的数据,)
- /**
- ///实时now的hour是3小时,计算 lastupdate 0~2范围的数据,
- ///只在 HOUR = new int[] { 1, 3, 5, 7, 9, 11,13, 15, 17, 19, 21, 23 };是奇数
-
- using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = $"FM-{imeiDel}-{DateTime.Now.ToString("yyyyMMddHHmmss")}" }))
- {
- try
- {
- var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
- _logger.LogInformation($"触发胎动计算,设备配置{JsonConvert.SerializeObject(watchConfig)}");
- var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
- var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! : 60;
-
- 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} 计算胎动数据 ");
-
- DateTime fmNow = DateTime.Now;
- int fmNowHour = fmNow.Hour;
- DateTime statStartTime;
- DateTime statEndTime;
-
- if (fmNowHour == 1)
- {
- // last_update 22~0
- statStartTime = fmNow.Date.AddDays(-1).AddHours(22);
- statEndTime = fmNow.Date;
- }
- else
- {
- statStartTime = fmNow.Date.AddHours(fmNowHour - 3);
- statEndTime = fmNow.Date.AddHours(fmNowHour - 1);
- }
-
- _logger.LogInformation($"{imeiDel} 胎动统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
-
-
- var fetalMovementSampleTime = DateTimeUtil.ConvertToTimeStamp(statEndTime).ToString()[..10];
- var isFetalMovementExisted = await _deviceCacheMgr.FetalMovementIsExistedAsync(imeiDel, fetalMovementSampleTime);
-
- 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)
- {
- // 读取胎心数据
- 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 time = long.Parse(fhr.SampleTime.Length < 13 ? fhr.SampleTime.PadRight(13, '0') : fhr.SampleTime);
- var fhrSampleTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(time);
-
- // 胎心数据时间与胎动时间一致,最后一条胎心数据与胎动数据的小时差不大于3
- if ((DateTime.Now.Hour - fhrSampleTime.Hour) <= 3)
- {
- var duringMins = Math.Abs((phrRange.First() - phrRange.Last()).TotalMinutes);
- //在餐后时间段(8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00)取中间值。其他时间段取正常起始值
- bool isInTimeRanges = IsLastUpdateInTimeRanges(phrRange.First());
-
- 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 fetalMovementTimeVar = (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} ");
-
- #region 生理健康与胎动的关系
- /// (步数)运动步数超过1500步则加1;
- /// (体温)低烧则胎动减1,高烧胎动减2;低烧是37.3~38.5,38.6以上是高烧。
- /// (血压)血压收缩压大于160则加1。
- /// (心理)心理压力高加2,压力中加1;
-
- var fetalMovementStepVar = 0;
- var fetalMovementTempVar = 0;
- var fetalMovementBpVar = 0;
- var fetalMovementPpVar = 0;
- var fetalMovementFhrVar = 0;
- // 步数
- if (false)
- {
- var step = await _personCacheMgr.GetStepPeriodicityAsync(imeiDel);
- if (step != null)
- {
- if (DateTime.Now.Hour - ((DateTime)step?.LastUpdate!).Hour <= 2)
- {
- if (step.Steps > 1500) fetalMovementStepVar = 1;
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期步数 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期步数无数据");
- }
-
- }
-
- // 体温
- if (true)
- {
- var temp = await _personCacheMgr.GetTemperaturePeriodicityAsync(imeiDel);
- if (temp != null)
- {
- if (DateTime.Now.Hour - ((DateTime)temp?.LastUpdate!).Hour <= 2)
- {
- // 中烧
- if (temp.Temperature >= 37.3M && temp.Temperature <= 38.5M)
- {
- fetalMovementTempVar = -1;
- }
- // 高烧
- if (temp.Temperature >= 38.6M)
- {
- fetalMovementTempVar = -2;
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期体温 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期体温无数据");
- }
-
- }
-
- // 血压
- if (true)
- {
- var bp = await _personCacheMgr.GetBloodPressPeriodicityAsync(imeiDel);
- if (bp != null)
- {
- if (DateTime.Now.Hour - ((DateTime)bp?.LastUpdate!).Hour <= 2)
- {
- if (bp.SystolicValue > 160)
- {
- fetalMovementBpVar = 1;
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期血压 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期血压无数据");
- }
-
- }
- // 心理
- if (false)
- {
- //-1 不处理,
- //0 正常,
- //1 轻度,
- //2 中度;
- //3 重度;
- GeneralParam psychResultParam = new()
- {
- Filters = new List<QueryFilterCondition>
- {
- new ()
- {
- Key=nameof(HisGpsPsychResult.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(HisGpsPsychResult.Serialno)
- }
- }
- };
- var psych = await _hisPsychResultApiClient.GetFirstAsync(psychResultParam, imeiDel[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") });
- if (psych != null)
- {
- if (psych?.StressScore == 2)
- {
- fetalMovementPpVar = 1;
- }
-
- if (psych?.StressScore == 3)
- {
- fetalMovementPpVar = 2;
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期心理压力无数据");
- }
-
- }
-
- #endregion
-
- #region 胎心与胎动的关系
- /// 胎心值过缓时,则胎动数量减1;胎心值过速时,则胎动也加1。
- /// 此值允许在上限值上继续增加,在下限值上继续减少,最小值为0。
- /// 告警上限阀值
-
- //1表示偏高;2表示偏低
- if (true)
- {
- if (fhr.IsAbnormal == 2)
- {
- fetalMovementPpVar = -1;
- }
-
- if (fhr.IsAbnormal == 1)
- {
- fetalMovementPpVar = 1;
- }
- }
-
- #endregion
- //var fetalMovementTimeVar = fetalMovementValue;
-
- _logger.LogInformation($"{imeiDel} 时间比例胎动值:{fetalMovementTimeVar}, 步数参数变动值:{fetalMovementStepVar},体温参数变动值:{fetalMovementTempVar},血压参数变动值:{fetalMovementBpVar},心理压力参数变动值:{fetalMovementPpVar},胎心参数变动值:{fetalMovementFhrVar}");
-
-
- var fetalMovementValue = fetalMovementTimeVar + fetalMovementStepVar + fetalMovementTempVar + fetalMovementBpVar + fetalMovementPpVar + fetalMovementFhrVar;
-
- // 四舍五入
- var fetalMovement = (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero);
-
- _logger.LogInformation($"{imeiDel} 孕周:{pregnancyWeeks},胎动数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 采样周期:{statStartTime}-{statEndTime}, 时间比例胎动值:{fetalMovementMapValue}, 佩戴时间 :{duringMins}|{phrRange.Last()}-{phrRange.First()}, 胎动计算值:{fetalMovementTimeVar}, 胎动四舍五入最终值:{fetalMovement} 已完成.");
-
- // 获取胎心数据状态与胎动数据状态一致
- //etalHeartRateIsAbnormal= fhr.IsAbnormal;
- var feltalMovementIsAbnormal = fetalHeartRateIsAbnormal;
-
- 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);
-
- var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(imeiDel).ConfigureAwait(false);
- var fmMsgId = $"{imeiDel}-{fetalMovementSampleTime}-{Guid.NewGuid().ToString("D")[^3..]}";
- var fmMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(fetalMovementSampleTime.Length < 13 ? fetalMovementSampleTime.PadRight(13, '0') : fetalMovementSampleTime)).ToString("yyyy-MM-dd HH:mm:ss");
- // 胎动数据推送到第三方
- var topic = "topic.push.third";
- var fmThridMsg = new
- {
- messageId = fmMsgId,
- topic = topic,
- time = fmMsgTime,
- data = new
- {
- imei = imeiDel,
- value = fetalMovement,
- isAbnormal = feltalMovementIsAbnormal,
- type = "fetalMovement"
- }
- };
- await _serviceMqProcess.ProcessIMEIEventMessageAsync(fmMsgId, topic, 31, fmThridMsg).ConfigureAwait(false);
-
- // 胎动数据推送到微信
- if (feltalMovementIsAbnormal != 0)
- {
- 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.LogWarning($"{imeiDel} 最后一条胎心数据与胎动数据的小时差大于2,不计算胎动数据");
- }
- }
- else
- {
- _logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足两条,不能判断是否持续佩戴");
-
- }
- }
- else
- {
- _logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 没有胎心建模数据");
- }
-
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 胎心监测功能没有开启");
- }
- }
- catch (Exception ex )
- {
-
- _logger.LogError($"{imeiDel} 计算胎动数据异常 {ex.Message}\n {ex.StackTrace}");
- }
-
-
- }
- */
- #endregion
-
- #region 相隔1小时胎动延时计算(实时now是2小时,计算 lastupdate 0~1范围的数据,)
- /**
- 0~1->2
- 1~2->3
- 2~3->4
- 3~4->5
- 4~5->6
- 5~6->7
- 7~8->9
- 8~9->10
- 9~10->11
- 10~11->12
- 11~12->13
- 12~13->14
- 14~15->16
- 14~15->16
- 15~16->17
- 16~17->18
- 17~18->19
- 18~19->20
- 19~20->21
- 20~21->22
- 21~22->23
- 22~23->0
- 23~0->1
- */
- /*
- using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = $"FM-{imeiDel}-{DateTime.Now.ToString("yyyyMMddHHmmss")}" }))
- {
- try
- {
- var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
- _logger.LogInformation($"触发胎动计算,设备配置{JsonConvert.SerializeObject(watchConfig)}");
- var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
- var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! : 60;
-
- 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} 计算胎动数据 ");
-
- DateTime fmNow = DateTime.Now;
- int fmNowHour = fmNow.Hour;
- DateTime statStartTime;
- DateTime statEndTime;
-
- if (fmNowHour == 1)
- {
- // last_update 23~0
- statStartTime = fmNow.Date.AddDays(-1).AddHours(23);
- statEndTime = fmNow.Date;
- }
- else
- {
- // last_update 0~1->2,1~2->3,2~3->4...21~22->23
- statStartTime = fmNow.Date.AddHours(fmNowHour - 2);
- statEndTime = fmNow.Date.AddHours(fmNowHour - 1);
- }
-
- _logger.LogInformation($"{imeiDel} 胎动统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
-
-
- var fetalMovementSampleTime = DateTimeUtil.ConvertToTimeStamp(statStartTime).ToString()[..10];
- var isFetalMovementExisted = await _deviceCacheMgr.FetalMovementIsExistedAsync(imeiDel, fetalMovementSampleTime);
-
- 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)
- {
- // 读取胎心数据
- 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 time = long.Parse(fhr.SampleTime.Length < 13 ? fhr.SampleTime.PadRight(13, '0') : fhr.SampleTime);
- var fhrSampleTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(time);
-
- //// 胎心数据时间与胎动时间一致,最后一条胎心数据与胎动数据的小时差不大于3
- //if ((DateTime.Now.Hour - fhrSampleTime.Hour) <= 3)
-
- // 胎心数据时间与胎动时间一致,最后一条胎心数据与胎动数据的小时差不大于2
- if ((DateTime.Now.Hour - fhrSampleTime.Hour) <= 2)
- {
- var duringMins = Math.Abs((phrRange.First() - phrRange.Last()).TotalMinutes);
- //在餐后时间段(8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00)取中间值。其他时间段取正常起始值
- bool isInTimeRanges = IsLastUpdateInTimeRanges(phrRange.First());
-
- 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 fetalMovementTimeVar = (fetalMovementMapValue * duringMins * 2) / 120;
- var fetalMovementTimeVar = (fetalMovementMapValue * duringMins ) / 60;
-
- if (duringMins < 59)
- {
- // 取12小时胎动总数最小值
- fetalMovementMapValue = fetalMovementMap
- .Where(i =>i.PregnancyPeriod![0] <= pregnancyWeeks &&i.PregnancyPeriod[1] >= pregnancyWeeks)
- .First()
- .TwelveHourMovementRange[0];
- //取12小时胎动总数最小值的平均值
- fetalMovementTimeVar = fetalMovementMapValue / 12;
-
- _logger.LogWarning($"{imeiDel} 佩戴不足1小时,12小时胎动总数最小值{fetalMovementMapValue},平均值{fetalMovementTimeVar}");
- }
-
-
- #region 生理健康与胎动的关系
- /// (步数)运动步数超过1500步则加1;
- /// (体温)低烧则胎动减1,高烧胎动减2;低烧是37.3~38.5,38.6以上是高烧。
- /// (血压)血压收缩压大于160则加1。
- /// (心理)心理压力高加2,压力中加1;
-
- var fetalMovementStepVar = 0;
- var fetalMovementTempVar = 0;
- var fetalMovementBpVar = 0;
- var fetalMovementPpVar = 0;
- var fetalMovementFhrVar = 0;
- // 步数
- if (false)
- {
- var step = await _personCacheMgr.GetStepPeriodicityAsync(imeiDel);
- if (step != null)
- {
- if (DateTime.Now.Hour - ((DateTime)step?.LastUpdate!).Hour <= 2)
- {
- if (step.Steps > 1500) fetalMovementStepVar = 1;
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期步数 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期步数无数据");
- }
-
- }
-
- // 体温
- if (true)
- {
- var temp = await _personCacheMgr.GetTemperaturePeriodicityAsync(imeiDel);
- if (temp != null)
- {
- if (DateTime.Now.Hour - ((DateTime)temp?.LastUpdate!).Hour <= 2)
- {
- // 中烧
- if (temp.Temperature >= 37.3M && temp.Temperature <= 38.5M)
- {
- fetalMovementTempVar = -1;
- }
- // 高烧
- if (temp.Temperature >= 38.6M)
- {
- fetalMovementTempVar = -2;
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期体温 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期体温无数据");
- }
-
- }
-
- // 血压
- if (true)
- {
- var bp = await _personCacheMgr.GetBloodPressPeriodicityAsync(imeiDel);
- if (bp != null)
- {
- if (DateTime.Now.Hour - ((DateTime)bp?.LastUpdate!).Hour <= 2)
- {
- if (bp.SystolicValue > 160)
- {
- fetalMovementBpVar = 1;
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期血压 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期血压无数据");
- }
-
- }
- // 心理
- if (false)
- {
- //-1 不处理,
- //0 正常,
- //1 轻度,
- //2 中度;
- //3 重度;
- GeneralParam psychResultParam = new()
- {
- Filters = new List<QueryFilterCondition>
- {
- new ()
- {
- Key=nameof(HisGpsPsychResult.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(HisGpsPsychResult.Serialno)
- }
- }
- };
- var psych = await _hisPsychResultApiClient.GetFirstAsync(psychResultParam, imeiDel[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") });
- if (psych != null)
- {
- if (psych?.StressScore == 2)
- {
- fetalMovementPpVar = 1;
- }
-
- if (psych?.StressScore == 3)
- {
- fetalMovementPpVar = 2;
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 周期心理压力无数据");
- }
-
- }
-
- #endregion
-
- #region 胎心与胎动的关系
- /// 胎心值过缓时,则胎动数量减1;胎心值过速时,则胎动也加1。
- /// 此值允许在上限值上继续增加,在下限值上继续减少,最小值为0。
- /// 告警上限阀值
-
- //1表示偏高;2表示偏低
- if (true)
- {
- if (fhr.IsAbnormal == 2)
- {
- fetalMovementPpVar = -1;
- }
-
- if (fhr.IsAbnormal == 1)
- {
- fetalMovementPpVar = 1;
- }
- }
-
- #endregion
-
- _logger.LogInformation($"{imeiDel} 时间比例胎动值:{fetalMovementTimeVar}, 步数参数变动值:{fetalMovementStepVar},体温参数变动值:{fetalMovementTempVar},血压参数变动值:{fetalMovementBpVar},心理压力参数变动值:{fetalMovementPpVar},胎心参数变动值:{fetalMovementFhrVar}");
-
-
- var fetalMovementValue = fetalMovementTimeVar + fetalMovementStepVar + fetalMovementTempVar + fetalMovementBpVar + fetalMovementPpVar + fetalMovementFhrVar;
-
- // 四舍五入
- var fetalMovement = (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero);
-
- _logger.LogInformation($"{imeiDel} 孕周:{pregnancyWeeks},胎动数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 采样周期:{statStartTime}-{statEndTime}, 时间比例胎动值:{fetalMovementMapValue}, 佩戴时间 :{duringMins}|{phrRange.Last()}-{phrRange.First()}, 胎动计算值:{fetalMovementTimeVar}, 胎动四舍五入最终值:{fetalMovement} 已完成.");
-
- // 获取胎心数据状态与胎动数据状态一致
- //etalHeartRateIsAbnormal= fhr.IsAbnormal;
- var feltalMovementIsAbnormal = fetalHeartRateIsAbnormal;
-
- 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);
-
- var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(imeiDel).ConfigureAwait(false);
- var fmMsgId = $"{imeiDel}-{fetalMovementSampleTime}-{Guid.NewGuid().ToString("D")[^3..]}";
- var fmMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(fetalMovementSampleTime.Length < 13 ? fetalMovementSampleTime.PadRight(13, '0') : fetalMovementSampleTime)).ToString("yyyy-MM-dd HH:mm:ss");
- // 胎动数据推送到第三方
- var topic = "topic.push.third";
- var fmThridMsg = new
- {
- messageId = fmMsgId,
- topic = topic,
- time = fmMsgTime,
- data = new
- {
- imei = imeiDel,
- value = fetalMovement,
- isAbnormal = feltalMovementIsAbnormal,
- type = "fetalMovement"
- }
- };
- await _serviceMqProcess.ProcessIMEIEventMessageAsync(fmMsgId, topic, 31, fmThridMsg).ConfigureAwait(false);
-
- // 胎动数据推送到微信
- if (feltalMovementIsAbnormal != 0)
- {
- 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.LogWarning($"{imeiDel} 最后一条胎心数据与胎动数据的小时差大于2,不计算胎动数据");
- }
- }
- else
- {
- _logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足两条,不能判断是否持续佩戴");
-
- }
- }
- else
- {
- _logger.LogInformation($"{imeiDel} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理");
- }
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 没有胎心建模数据");
- }
-
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 胎心监测功能没有开启");
- }
- }
- catch (Exception ex)
- {
-
- _logger.LogError($"{imeiDel} 计算胎动数据异常 {ex.Message}\n {ex.StackTrace}");
- }
-
-
- }
- */
- #endregion
-
-
- #region 相隔1小时胎动延时计算(实时now是2小时,计算 lastupdate 0~1范围的数据,)
- /**
- 0~1->2,0~1 的lastupdate数据,sample_time 是1点,计算时间2点
- 1~2->3
- 2~3->4
- 3~4->5
- 4~5->6
- 5~6->7
- 7~8->9
- 8~9->10
- 9~10->11
- 10~11->12
- 11~12->13
- 12~13->14
- 14~15->16
- 15~16->17
- 16~17->18
- 17~18->19
- 18~19->20
- 19~20->21
- 20~21->22
- 21~22->23
- 22~23->0
- 23~0->1
- */
-
- 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"] = $"FM-{imeiDel}-{triggerHeartRate?.MessageId}" }))
- {
- try
- {
- var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
- _logger.LogInformation($"触发胎动计算,设备配置{JsonConvert.SerializeObject(watchConfig)}");
- var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
- var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! : 60;
-
- if (isFetalHeartEnable)
- {
- var edoc = DateTimeUtil.ToDateTime(watchConfig!["EDOC"]!.ToString());
- // 已经建模
- var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel);
- if (commonPHR != null)
- {
- await CalculateFetalMovementIntervalAsync(triggerHeartRate!, commonPHR, edoc);
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 没有胎心建模数据");
- }
-
- }
- else
- {
- _logger.LogWarning($"{imeiDel} 胎心监测功能没有开启");
- }
- }
- catch (Exception ex)
- {
-
- _logger.LogError($"{imeiDel} 计算胎动数据异常 {ex.Message}\n {ex.StackTrace}");
- }
-
-
- }
-
- }
-
-
- #endregion
- }
- else
- {
- // 处理血压业务
- int systolicInc;
- int diastolicInc;
-
- int systolicRefValue;
- int diastolicRefValue;
-
- decimal systolicAvg;
- decimal diastolicAvg;
-
- int systolicMax = 0;
- int diastolicMax = 0;
-
- // 统计时间
- //DateTime endTime = DateTime.Now; //测试
- DateTime statStartTime = DateTime.Now;
-
-
- // 最小值
- int systolicMin = 0;
- int diastolicMin = 0;
-
- // 偏移参数
- var avgOffset = 0.25M;
- var systolicAvgOffset = avgOffset;
- var diastolicAvgOffset = avgOffset;
-
- // 最后一次下发值
- int lastPushSystolicInc = 0;
- int lastPushDiastolicInc = 0;
-
-
- var startTime = DateTime.Now;
- // 下发增量值
- #region 统计定时下发增量值
- //var last = await _serviceTDengine.GetLastAsync("stb_hm_bloodpress_stats_inc", $"serialno='{imeiDel}' order by last_update desc");
- //var ts = last?[0];
-
- // 最后一条血压数据
- var condition = $"serialno='{imeiDel}' order by last_update desc";
- var field = "last_row(*)";
- var lastHmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition, field);
- var lastHmBpParser = JsonConvert.DeserializeObject<ParseTDengineRestResponse<BloodPressureModel>>(lastHmBpResponse!);
- var lastHmBp = lastHmBpParser?.Select().FirstOrDefault();
- //if (lastHmBpParser?.Select()?.ToList().Count < 2)
- //{
- // _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} -- 血压数据条目不足");
- // break;
- //}
-
- // 7 天有效数据
- if (lastHmBp?.Timestamp.AddDays(7) > DateTime.Now)
- {
- // 计算增量值
- condition = $"serialno='{imeiDel}' order by ts desc";
- var lastPushResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bp_push_ref_inc_value", condition, field);
- if (lastPushResponse == null)
- {
- _logger.LogInformation($"{imeiDel}--没有下发记录");
- break;
- }
- var lastPushParser = JsonConvert.DeserializeObject<ParseTDengineRestResponse<BloodPressurePushRefIncModel>>(lastPushResponse);
- var lastPush = lastPushParser!.Select().FirstOrDefault();
- // 有下推记录
- if (lastPush != null)
- {
- systolicRefValue = lastPush!.SystolicRefValue;
- diastolicRefValue = lastPush!.DiastolicRefValue;
- lastPushSystolicInc = lastPush!.SystolicIncValue;
- lastPushDiastolicInc = lastPush!.DiastolicIncValue;
- condition = $"ts between '{lastPush?.Timestamp:yyyy-MM-dd HH:mm:ss.fff}' and '{startTime:yyyy-MM-dd HH:mm:ss.fff}' " +
- $"and serialno='{imeiDel}' " +
- $"and is_display = true";
- // 使用最近一次的下推时间作为统计的开始时间
- statStartTime = lastPush!.Timestamp;
- }
- // 没有下推记录(历史遗留数据),没有初始的测量值产生的平均值(测量值=平均值)
- else
- {
- #region 获取个人信息
-
- var person = await _personCacheMgr.GetDeviceGpsPersonCacheBySerialNoAsync(Guid.NewGuid().ToString(), imeiDel).ConfigureAwait(false);
- //验证这个信息是否存在
- if (person == null || person?.Person.BornDate == null)
- {
- _logger.LogWarning($"{nameof(Worker)}--{imeiDel} 验证个人信息,找不到个人信息,跳过此消息");
- break;
- }
- // 验证年龄是否在范围 (2 - 120)
- var age = SafeType.SafeInt(DateTime.Today.Year - person?.Person.BornDate!.Value.Year!);
- if (age < 2 || age > 120)
- {
- _logger.LogWarning($"{nameof(Worker)}--{imeiDel} 验证年龄,不在范围 (2 - 120)岁,跳过此消息");
- break;
- }
-
- var gender = person?.Person.Gender == true ? 1 : 2;
- var isHypertension = SafeType.SafeBool(person?.Person.Ishypertension!);
- var height = SafeType.SafeDouble(person?.Person.Height!);
- var weight = SafeType.SafeDouble(person?.Person.Weight!);
-
- #endregion
-
- #region 初始化常规血压标定值标定值
- var bpRef = await _bpRefValCacheManager.GetBloodPressReferenceValueAsync(age, gender, isHypertension);
- //systolicRefValue = bpRef!.Systolic;//?
- //diastolicRefValue = bpRef!.Diastolic;//?
- #endregion
-
- systolicRefValue = bpRef!.Systolic;
- diastolicRefValue = bpRef!.Diastolic;
- lastPushSystolicInc = 0;
- lastPushDiastolicInc = 0;
- condition = $"ts <= '{startTime:yyyy-MM-dd HH:mm:ss.fff}' " +
- $"and serialno='{imeiDel}' " +
- $"and is_display = true";
- }
-
-
-
- var hmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition);
- var hmBpParser = JsonConvert.DeserializeObject<ParseTDengineRestResponse<BloodPressureModel>>(hmBpResponse!);
- var hmBp = hmBpParser?.Select();
- //if (hmBp?.ToList().Count < 2)
- // 1. 判断数据样本数量
- if (hmBpParser!.Rows < 5)
- {
- _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} -- 统计定时下发,计算增量值的数据条目不足:{hmBpParser!.Rows} < 5");
- _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} 没有足够的数据样本,不会定时下发");
- break;
- }
- // 没有下推记录重新计算统计时间
- if (lastPush == null)
- {
- var firstHmBp = hmBpParser?.Select(i => i).OrderBy(i => i.Timestamp).FirstOrDefault();
- statStartTime = firstHmBp!.Timestamp;
- }
-
- // GetSampleTime(systolicRefValue, hmBpParser);
-
- // 最大值
- //systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!;
- //diastolicMax = (int)hmBpParser?.Select(i => i.DiastolicValue).Max()!;
- //// 最小值
- //systolicMin = (int)hmBpParser?.Select(i => i.SystolicValue).Min()!;
- //diastolicMin = (int)hmBpParser?.Select(i => i.DiastolicValue).Min()!;
-
- //systolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.SystolicValue, SafeType.SafeInt(systolicRefValue!)))!;
- //diastolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.DiastolicValue, SafeType.SafeInt(diastolicRefValue!)))!;
-
- var avgs = _serviceTDengine.AverageAfterRemovingOneMinMaxRef(hmBpParser!);
- systolicAvg = avgs[0];
- diastolicAvg = avgs[1];
-
-
- // 2. 判断能否计算增量值
- if (systolicAvg.Equals(0))
- {
- _logger.LogInformation($"{imeiDel}--{nameof(Worker)}--计算平均值" +
- $"\n currentSystolicAvg:{systolicAvg} -- lastPushSystolicInc:{lastPushSystolicInc}" +
- $"\n currentDiastolicInc:{diastolicAvg} -- lastPushDiastolicInc:{lastPushDiastolicInc}");
- _logger.LogInformation($"{imeiDel}--{nameof(Worker)} 没有足够的数据样本计算平均值,不会定时下发");
- break;
- }
- // 除最大值和最小值后的平均值与标定值差值少于4后(当天计算出该结果则也不产生增量调整),就不再进行增量值调整了。
- if (systolicRefValue - systolicAvg < 4)
- {
- _logger.LogInformation($"diastolic 舒张压 {imeiDel}除最大值和最小值后的平均值:{diastolicAvg}与标定值:{diastolicRefValue}\n systolic 收缩压 {imeiDel}除最大值和最小值后的平均值:{systolicAvg}与标定值:{systolicRefValue}的差值(标定值-平均值)少于4后,systolic 收缩压 不再进行增量值调整");
- break;
- }
-
- if (diastolicRefValue - diastolicAvg < 4)
- {
- _logger.LogInformation($"systolic 收缩压 {imeiDel}除最大值和最小值后的平均值:{systolicAvg}与标定值:{systolicRefValue}\n diastolic 舒张压 {imeiDel}除最大值和最小值后的平均值:{diastolicAvg}与标定值:{diastolicRefValue}的差值(标定值-平均值)少于4后,diastolic 舒张压 不再进行增量值调整");
- break;
- }
-
- // 增量值=(标定值-平均值)* 0.25
- var currentSystolicInc = (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!;
- var currentDiastolicInc = (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!;
-
-
- // 累计增量
- systolicInc = currentSystolicInc + lastPushSystolicInc;
- diastolicInc = currentDiastolicInc + lastPushDiastolicInc;
-
- _logger.LogInformation($"{imeiDel}--{nameof(Worker)}--计算增量值" +
- $"\n {imeiDel} -- systolicAvg:{systolicAvg}-- systolicInc:{systolicInc}-- currentSystolicInc:{currentSystolicInc} -- lastPushSystolicInc:{lastPushSystolicInc}" +
- $"\n {imeiDel} -- diastolicAvg:{diastolicAvg}-- diastolicInc:{diastolicInc} --currentDiastolicInc:{currentDiastolicInc} -- lastPushDiastolicInc:{lastPushDiastolicInc}");
- _logger.LogInformation($"{imeiDel}--{nameof(Worker)}-- 定时校准,发给设备的绝对增量值=(上次绝对增量值+新数据的增量值)");
-
-
- _logger.LogInformation($"{nameof(Worker)} 开启血压标定值下发: {_configBoodPressResolver.EnableBPRefPush}");
- if (_configBoodPressResolver.EnableBPRefPush)
- // if (false) // 临时关闭
- {
- BloodPressCalibrationConfigModel bpIncData = new()
- {
-
- Imei = imeiDel,
- SystolicRefValue = SafeType.SafeInt(((int)systolicRefValue!)), //收缩压标定值,值为0 表示不生效
- DiastolicRefValue = SafeType.SafeInt(((int)diastolicRefValue!)), //舒张压标定值,值为0表示不生效
- SystolicIncValue = SafeType.SafeInt(((int)systolicInc!)), //收缩压显示增量,值为0 表示不生效
- DiastolicIncValue = SafeType.SafeInt(((int)diastolicInc!)) //舒张压显示增量,值为0 表示不生效
- };
- //var pushedBP = await _serviceIotApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false);
- var response = await _serviceIotApi.SetBloodPressCalibrationConfig2Async(bpIncData).ConfigureAwait(false);
- var pushedBP = response.Flag;
- if (pushedBP)
- {
- #region 保存下推记录 stb_hm_bp_push_ref_inc_value
- var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imeiDel.Substring(imeiDel.Length - 2)} " +
- $"USING health_monitor.stb_hm_bp_push_ref_inc_value " +
- $"TAGS ('{imeiDel.Substring(imeiDel.Length - 2)}') " +
- $"VALUES(" +
- $"'{startTime:yyyy-MM-dd HH:mm:ss.fff}'," +
- $"'{imeiDel}'," +
- $"{bpIncData.SystolicRefValue}," +
- $"{bpIncData.DiastolicRefValue}," +
- $"{bpIncData.SystolicIncValue}," +
- $"{bpIncData.DiastolicIncValue}," +
- $"{false}," +
- $"{systolicAvg}," +
- $"{diastolicAvg}," +
- $"{systolicAvgOffset}," +
- $"{diastolicAvgOffset}," +
- $"'{statStartTime:yyyy-MM-dd HH:mm:ss.fff}'," +
- $"'{startTime:yyyy-MM-dd HH:mm:ss.fff}'" +
- $")";
- _serviceTDengine.ExecuteInsertSQL(sql);
- #endregion
-
- #region 注册定时下发
- // 注册下次下推
- var endTime = DateTime.Now;
-
- #if DEBUG
-
-
- //long ttl = (long)((60 * 1000-(endTime-startTime).TotalMilliseconds)/1000);
- //await _serviceEtcd.PutValAsync(key, imeiDel,ttl, false).ConfigureAwait(false);
-
- var interval = 0;
- // 获取当前时间
- DateTime now = DateTime.Now;
-
- // 计算距离下一个$interval天后的8点的时间间隔
- DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 2, 0).AddDays(interval);
- TimeSpan timeUntilNextRun = nextRunTime - now;
-
- // 如果当前时间已经超过了8点,将等待到明天后的8点
- if (timeUntilNextRun < TimeSpan.Zero)
- {
- timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1));
- nextRunTime += timeUntilNextRun;
- }
-
- // var ttl = timeUntilNextRun.TotalMilliseconds;
- long ttl = (long)((timeUntilNextRun.TotalMilliseconds - (endTime - startTime).TotalMilliseconds) / 1000);
- var data = new
- {
- imei = imeiDel,
- create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
- ttl,
- next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
- };
- var result = JsonConvert.SerializeObject(data);
-
- await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
-
-
- #else
- // 每$interval天,晚上8点
- var interval = 1;
- // 获取当前时间
- DateTime now = DateTime.Now;
-
- // 计算距离下一个$interval天后的8点的时间间隔
- DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 20, 0, 0).AddDays(interval);
- TimeSpan timeUntilNextRun = nextRunTime - now;
-
- // 如果当前时间已经超过了8点,将等待到明天后的8点
- if (timeUntilNextRun < TimeSpan.Zero)
- {
- timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
- nextRunTime += timeUntilNextRun;
- }
-
- // var ttl = timeUntilNextRun.TotalMilliseconds;
- long ttl = (long)((timeUntilNextRun.TotalMilliseconds-(endTime-startTime).TotalMilliseconds)/1000);
- var data = new
- {
- imei = imeiDel,
- create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
- ttl,
- next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
- };
- var result = JsonConvert.SerializeObject(data);
- await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
- #endif
- #endregion
-
- }
- else
- {
- _logger.LogInformation($"错误响应,没有下推数据:{response.Message}");
- }
- }
- }
- else
- {
- _logger.LogInformation($"向{imeiDel}统计数据已经失效");
- }
- #endregion
-
- }
-
- }
- break;
- }
- }
- catch (Exception ex)
- {
- _logger.LogError($"{nameof(WatchEvents)},出错: |{ex.Message}|{ex.StackTrace}");
- }
-
-
- });
-
- }
-
-
- private async Task SetIntervalTriggerAsync(string key, string imei, long interval)
-
- {
- // var key = $"health_monitor/schedule_push/{type}/imei/{imei}";
- var schedulePush = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);
- if (string.IsNullOrWhiteSpace(schedulePush))
- {
- var now = DateTime.Now;
- var timeNextRun = now.Add(TimeSpan.FromSeconds(interval));
- var data = new
- {
- imei,
- create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
- ttl = interval,
- next_run_time = timeNextRun.ToString("yyyy-MM-dd HH:mm:ss")
- };
- var result = JsonConvert.SerializeObject(data);
- await _serviceEtcd.PutValAsync(key, result, interval, false).ConfigureAwait(false);
- }
- }
-
- public static bool IsNowInTimeRanges()
- {
- var now = DateTime.Now.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);
- }
- 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);
- }
-
-
- private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
- {
- // 计算胎心=孕妇心率*系数
- /**
- var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!);
- fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出
- if (fetalHeartRate >= 220)
- {
- // 先使用最小系数计算
- var statMaxValueFprCoefficient = commonPHR?.StatMaxValueFprCoefficient!;
- var statMinValueFprCoefficient = commonPHR?.StatMinValueFprCoefficient!;
- var coefficient = statMaxValueFprCoefficient < statMinValueFprCoefficient ? statMaxValueFprCoefficient : statMinValueFprCoefficient;
- fetalHeartRate = SafeType.SafeInt(phrValue * coefficient);
- if (fetalHeartRate < 220)
- {
- _logger.LogWarning($"{heartRate.Serialno} 使用极值系数 {coefficient} ,建模数据可能出现异常,请检查");
- }
- else
- {
- fetalHeartRate = 220;
- _logger.LogWarning($"{heartRate.Serialno} 使用所有系数都不能放映实际,建模数据可能出现异常,请检查");
- }
- }
- */
-
- #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
-
- var fetalHeartRate = SafeType.SafeInt(heartRate.HeartRate! * coefficient);
- // 胎心的最大值调整为220,超过都按该值220输出
- fetalHeartRate = fetalHeartRate >= 220 ? 220 : fetalHeartRate;
-
- var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
- var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
- if (phrFreqstatus == null) isAbnormal = 0;
- var statsusDesc = (phrFreqstatus == null) ? "常规" : "高频";
- _logger.LogInformation($"{heartRate.Serialno} 在 {statsusDesc} 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
- //if (!isFreq)
- //{
- // statStartTime = heartRate.LastUpdate;
- //
- //}
- // 保存到 数据服务 MySQL 数据库
- HisGpsFetalHeartRate gpsFetalHeartRate = new()
- {
- FetalHeartRateId = Guid.NewGuid().ToString("D"),
- PersonId = commonPHR!.PersonId,
- Serialno = heartRate.Serialno,
- HeartRate = fetalHeartRate,
- SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : 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);
-
- // 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
- // 推送最后一条常规心率计算的胎心数据到iot设备
- #region 推送最后一条常规心率计算的胎心数据到iot设备
-
- // 高频(<=12)-常规
- var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(heartRate.Serialno);
- if (lastPhr.MessageId == heartRate.MessageId && phrFreqstatus == null)
- {
- await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- _logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(<=12)-常规");
- }
- // 高频(13)-常规-高频(13)
- if (phrFreqstatus != null)
- {
- var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 1);
- 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 <= 60)
- {
- freqCollection.Add(item);
- }
- }
- // 高频最后一条
- if (lastPhr.MessageId == item.MessageId)
- {
- freqCollection.Add(item);
- }
-
- previousItem = item;
- }
- //去除高频
- foreach (var item in freqCollection)
- {
- phr.Remove(item);
- }
- lastPhr = phr.FirstOrDefault();
- if (lastPhr?.MessageId == heartRate.MessageId)
- {
- await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- _logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(13)-常规-高频(13)");
- }
- }
-
- #endregion
-
- #region 高频心率计算胎心数据到iot设备
- // 高频(17) ,连续12个高频正常,也不停止且数据偏高和偏低也推送到iot
- if (phrFreqstatus != null && isAbnormal != 0)
- {
- await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- }
- #endregion
- 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);
-
- // 胎心数据推送到微信
- 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);
-
- }
- }
-
- /// <summary>
- /// 高频胎心处理
- /// 1. 高频数据触发连续12个值都是正常的的高频心率处理
- /// 2. 高频结束后的highFreqSampleTimes=0的高频心率处理
- /// 3. 高频结束后的在highFreqSampleTimes>0 正常心率触发的高频心率处理(常态)
- /// 4. 高频结束后的时间倒序的正常心率触发的高频心率处理
- /// 5. 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理
- /// 高频结束后超过9分钟且不在阈值内才告警
- /// </summary>
- /// <param name="heartRate"></param>
- /// <param name="commonPHR"></param>
- /// <param name="highFreqSampleTimes"></param>
- /// <param name="upperAlarmThreshold"></param>
- /// <param name="lowerAlarmThreshold"></param>
- /// <param name="sampleTime"></param>
- /// <param name="statStartTime"></param>
- /// <param name="statEndTime"></param>
- /// <returns></returns>
- private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
- {
- // 计算胎心=孕妇心率*系数
-
- #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
-
- var fetalHeartRate = SafeType.SafeInt(heartRate.HeartRate! * coefficient);
- // 胎心的最大值调整为220,超过都按该值220输出
- // fetalHeartRate = fetalHeartRate>= 220 ? 220 : fetalHeartRate;
-
- var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
- var isAbnormal = 0;
- #region 判断是否够highFreqSampleTimes,540s
- var ts = DateTimeUtil.GetTimeDifferenceInSeconds((DateTime)heartRate.LastUpdate!, phrFreqstatus!.LastUpdate);
- // 判断是否够highFreqSampleTimes,540s
- ///高频时长不足10分钟停止高频的胎心值生成说明:最近12个数据的最小值生成胎心值,
- ///对于小于高频下限阀值取高频下限阀值进行转换;
- ///对于高于高频上限阀值取高频上限阀值进行转换。并输出相关日志后续进行数据分析。
- if (ts < highFreqSampleTimes)
- {
- if (fetalHeartRate > upperAlarmThreshold)
- {
- _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,计算胎心值 {fetalHeartRate} 高于高频警告上限阀值{upperAlarmThreshold},最后胎心值{upperAlarmThreshold},并且不告警");
- fetalHeartRate = upperAlarmThreshold;
-
-
- }
- else if (fetalHeartRate < lowerAlarmThreshold)
- {
- _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,计算胎心值 {fetalHeartRate} 低于高频警告下限阀值 {lowerAlarmThreshold},最后胎心值{lowerAlarmThreshold},并且不告警");
- fetalHeartRate = lowerAlarmThreshold;
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,在高频警告下限阀值 {lowerAlarmThreshold} 和 高频警告上限阀值:{upperAlarmThreshold}之间,最后胎心值{fetalHeartRate},并且不告警");
- }
-
- }
- // 超过highFreqSampleTimes,540s
- else
- {
- 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")}");
- }
- isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
- }
- #endregion
-
-
-
- //if (phrFreqstatus == null) isAbnormal = 0;
- //var statsusDesc = (phrFreqstatus == null) ? "常规" : "高频";
- var statsusDesc = "高频";
- _logger.LogInformation($"{heartRate.Serialno} 在 {statsusDesc} 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
- // 保存到 数据服务 MySQL 数据库
- HisGpsFetalHeartRate gpsFetalHeartRate = new()
- {
- FetalHeartRateId = Guid.NewGuid().ToString("D"),
- PersonId = commonPHR!.PersonId,
- Serialno = heartRate.Serialno,
- HeartRate = fetalHeartRate,
- SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : 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);
-
- // 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
- // 推送最后一条常规心率计算的胎心数据到iot设备
- #region 推送最后一条常规心率计算的胎心数据到iot设备
-
- // 高频(<=12)-常规
- var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(heartRate.Serialno);
- if (lastPhr.MessageId == heartRate.MessageId && phrFreqstatus == null)
- {
- await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- _logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(<=12)-常规");
- }
- // 高频(13)-常规-高频(13)
- if (phrFreqstatus != null)
- {
- var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 1);
- 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 <= 60)
- {
- freqCollection.Add(item);
- }
- }
- // 高频最后一条
- if (lastPhr.MessageId == item.MessageId)
- {
- freqCollection.Add(item);
- }
-
- previousItem = item;
- }
- //去除高频
- foreach (var item in freqCollection)
- {
- phr.Remove(item);
- }
- lastPhr = phr.FirstOrDefault();
- if (lastPhr?.MessageId == heartRate.MessageId)
- {
- await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- _logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(13)-常规-高频(13)");
- }
- }
-
- #endregion
-
- #region 高频心率计算胎心数据到iot设备
- // 高频(17) ,连续12个高频正常,也不停止且数据偏高和偏低也推送到iot
- if (phrFreqstatus != null && isAbnormal != 0)
- {
- await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- }
- #endregion
- 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);
-
- // 胎心数据推送到微信
- 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);
-
- }
- }
-
-
- /// <summary>
- /// 去除高频数据
- /// </summary>
- /// <param name="phr"></param>
- /// <param name="highFreqSampleInterva"></param>
- /// <returns></returns>
- private static List<PregnancyHeartRateModel> GetNonFreqPregnancyHeartRate(List<PregnancyHeartRateModel> phr, int highFreqSampleInterval)
- {
- //phr = phr.OrderByDescending(i => i.LastUpdate).ToList();
- //var result = new List<PregnancyHeartRateModel>();
- //PregnancyHeartRateModel? previousItem = null;
-
- //foreach (var item in phr)
- //{
- // if (previousItem != null)
- // {
- // var timeNextDiff =(previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
- // if (timeNextDiff > highFreqSampleInterval)
- // {
- // result.Add(previousItem);
- // }
- // }
- // previousItem = item;
- //}
-
- //// 添加上一个
- //if (previousItem != null)
- //{
- // result.Add(previousItem);
- //}
-
- //return result;
-
- #region 反向
- var phr1 = phr.OrderByDescending(i => i.LastUpdate).ToList();
- var result = new List<PregnancyHeartRateModel>();
- PregnancyHeartRateModel? previousItem1 = null;
-
- foreach (var item in phr1)
- {
- if (previousItem1 != null)
- {
- var timeNextDiff = (previousItem1!.LastUpdate - item.LastUpdate).TotalSeconds;
- if (timeNextDiff > highFreqSampleInterval)
- {
- result.Add(previousItem1);
- }
- }
- previousItem1 = item;
- }
-
- // 添加上一个
- if (previousItem1 != null)
- {
- result.Add(previousItem1);
- }
- #endregion
-
- #region 正向
- var phr2 = phr.OrderByDescending(i => i.LastUpdate).ToList(); ;
- var freqCollection = new List<PregnancyHeartRateModel>();
- PregnancyHeartRateModel? previousItem = null;
- foreach (var item in phr2)
- {
- if (previousItem != null)
- {
- var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
- if (timeNextDiff <= highFreqSampleInterval)
- {
- freqCollection.Add(item);
- }
- }
- previousItem = item;
- }
- //去除高频
- foreach (var item in freqCollection)
- {
- phr2.Remove(item);
- }
- #endregion
-
- // 交集
- var commonElements = phr2.Intersect(result).ToList();
- return commonElements;
- }
-
-
- /// <summary>
- /// 获取高频数据
- /// </summary>
- /// <param name="phr"></param>
- /// <param name="highFreqSampleInterval"></param>
- /// <returns></returns>
- private static List<PregnancyHeartRateModel> GetFreqPregnancyHeartRate(List<PregnancyHeartRateModel> phr, int highFreqSampleInterval)
- {
- 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(previousItem);
- }
- }
- previousItem = item;
- }
-
- // 检查最后一条是否高频
- if (previousItem != null && (phr.Last().LastUpdate - previousItem.LastUpdate).TotalSeconds <= highFreqSampleInterval)
- {
- freqCollection.Add(previousItem);
- }
-
- return freqCollection;
- }
-
- public async Task CalculateNormalFetalHeartRateIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,int highFreqSampleInterval)
- {
- var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
- var now = DateTime.Now;
- var filteredPhr = daysPhr.Where(i => i.LastUpdate >= heartRate.LastUpdate && i.LastUpdate <= now).ToList();
- // 去除高频
- var normalPhr = GetNonFreqPregnancyHeartRate(filteredPhr, highFreqSampleInterval).OrderBy(i => i.LastUpdate);
-
- if (normalPhr.ToList().Count==0)
- {
- _logger.LogWarning($"{heartRate.Serialno} 时间段{heartRate.LastUpdate}-{now},去除高频心率数据后,没有常规数据,不计算常规胎心数据");
- return;
- }
-
- 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
- {
- //var CalNow = DateTime.Now;
- //var during = TimeSpan.FromSeconds(300); //5分钟
-
- var c = 0;
- while (true)
- {
-
- //if (DateTime.Now - CalNow > during)
- //{
- // _logger.LogInformation($"{heartRate.Serialno} 超过1分钟,迭代完成跳出循环 ");
- // break;
- //}
-
- await Task.Delay(TimeSpan.FromSeconds(1));
-
- 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.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
-
- if (statEndTime > boundaryStatEndTime)
- {
- _logger.LogInformation($"{heartRate.Serialno} 常规胎心统计超过时间边界,迭代完成跳出循环 ");
- break;
- }
-
- var segmentPhr = normalPhr
- .Where(i => i.LastUpdate <= statEndTime && i.LastUpdate >= statStartTime)
- .ToList();
-
- if (segmentPhr.Count == 0)
- {
- // 跳出当次迭代,进入下次迭代
- _logger.LogWarning($"{heartRate.Serialno} 统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")} 孕妇心率数据不足,{segmentPhr.Count}条记录,不处理");
- continue;
- }
-
- _logger.LogInformation($"{heartRate.Serialno} 当前统计周期{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")},对应的常规心率ID{string.Join(",", segmentPhr.Select(i=>i.MessageId))}");
-
-
-
- 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")} ,常规胎心已处理");
- }
- //await Task.Delay(TimeSpan.FromSeconds(1));
- // 跳出循环
- if (statEndTime.ToString("yyyyMMddHHmm") == boundaryStatEndTime.ToString("yyyyMMddHHmm"))
- {
- _logger.LogInformation($"{heartRate.Serialno} 迭代完成跳出循环 ");
- break;
- }
-
- //if (statEndTime>= boundaryStatEndTime)
- //{
- // _logger.LogInformation($"{heartRate.Serialno} 时间边界,迭代完成跳出循环 ");
- // 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;
- // }
- //}
- }
-
-
- public async Task CalculateFetalMovementIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,DateTime edoc)
- {
-
- var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
-
-
-
- DateTime fmNow = DateTime.Now;
- int fmNowHour = fmNow.Hour;
- DateTime startHour;
- DateTime endHour;
-
- if (fmNow.Subtract((DateTime)heartRate.LastUpdate!).Hours>2)
- {
- _logger.LogWarning($"{heartRate.Serialno} 当前计算时间与lastUpdate 时差超过2小时,将从当前触发心率到当天的所有心率计算对应的胎动");
- startHour = ((DateTime)heartRate.LastUpdate!).Date.AddHours(((DateTime)heartRate.LastUpdate!).Hour);
- endHour = ((DateTime)heartRate.LastUpdate!).Date.AddDays(1);
- }
- else
- {
- // 跨天
- if (fmNowHour == 1)
- {
- // last_update 23~0
- startHour = fmNow.Date.AddDays(-1).AddHours(((DateTime)heartRate.LastUpdate!).Hour);
- endHour = fmNow.Date;
- }
- else
- {
- // last_update 0~1->2,1~2->3,2~3->4...21~22->23
- startHour = fmNow.Date.AddHours(((DateTime)heartRate.LastUpdate!).Hour);
- endHour = fmNow.Date.AddHours(fmNowHour - 1);
- }
- }
-
- try
- {
-
-
- var filterPhr = daysPhr
- .Where(i => i.LastUpdate >= startHour && i.LastUpdate <= endHour)
- .OrderBy(i => i.LastUpdate).ToList();
-
-
- //if (filterPhr.Count < 2)
- //{
- // _logger.LogWarning($"{heartRate.Serialno} 胎动统计数据少于2条,不统计,{string.Join('-', filterPhr.Select(i=>i.LastUpdate))}");
- // return;
- //}
-
- if (filterPhr.Count < 1)
- {
- _logger.LogWarning($"{heartRate.Serialno} 胎动统计数据少于1条,不统计,{string.Join('-', filterPhr.Select(i => i.LastUpdate))}");
- return;
- }
-
- var startPhr = filterPhr.First();
- var endPhr = filterPhr.Last();
-
-
-
- // 数据统计边界
- var boundaryStatStartTime = startPhr.LastUpdate.Date.AddHours(startPhr.LastUpdate.Hour);
- var boundaryStatEndTime = endPhr.LastUpdate.Date.AddHours(endPhr.LastUpdate.Hour + 1);
-
- _logger.LogInformation($"{heartRate.Serialno} 胎动统计边界{boundaryStatStartTime}-{boundaryStatEndTime}");
-
-
-
- var c = 0;
- while (true)
- {
- await Task.Delay(TimeSpan.FromSeconds(1));
-
- var segmentStatStartTime = boundaryStatStartTime.AddHours(c * 1);
- var segmentStatEndTime = segmentStatStartTime.AddHours(1);
- c++;
-
- var statStartTime = segmentStatStartTime;
- var statEndTime = segmentStatEndTime;
-
- _logger.LogInformation($"{heartRate.Serialno} 当前胎动统计周期{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
-
-
- if (statEndTime > boundaryStatEndTime)
- {
- _logger.LogInformation($"{heartRate.Serialno} 常规胎心统计超过时间边界,迭代完成跳出循环 ");
- break;
- }
-
- var segmentPhr = filterPhr
- .Where(i => i.LastUpdate <= statEndTime && i.LastUpdate >= statStartTime)
- .ToList();
-
- if (segmentPhr.Count == 0)
- {
- // 跳出当次迭代,进入下次迭代
- _logger.LogWarning($"{heartRate.Serialno} 胎动统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")} 孕妇心率数据不足,{segmentPhr.Count}条记录,不处理");
- continue;
- }
-
- _logger.LogInformation($"{heartRate.Serialno} 当前胎动统计周期{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")},对应的常规心率ID{string.Join(",", segmentPhr.Select(i => i.MessageId))}");
- // 0~1 点的lastUpdate数据sample_time是1点,计算是2点
- var fetalMovementSampleTime = DateTimeUtil.ConvertToTimeStamp(statEndTime).ToString()[..10];
- var isFetalMovementExisted = await _deviceCacheMgr.FetalMovementIsExistedAsync(heartRate.Serialno, fetalMovementSampleTime);
-
- if (!isFetalMovementExisted)
- {
- /// 开始计算
- var phrRange = segmentPhr.OrderByDescending(i => i.LastUpdate)
- .Select(i => i.LastUpdate)
- .ToList();
- if (phrRange.Count >= 1)
- {
- // 读取胎心数据
- 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.GreaterEqual
- //},
- },
- OrderBys = new List<OrderByCondition>
- {
- new (){
- IsDesc=true,
- Key=nameof(HisGpsFetalHeartRate.SampleTime)
- }
- }
- };
- var fetalHeartRateIsAbnormal = 0;
- var fhr = await _hisFetalHeartApiClient.GetFirstAsync(param, heartRate.Serialno[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") });
-
- // 胎心数据时间与胎动时间一致
- var time = long.Parse(fhr.SampleTime.Length < 13 ? fhr.SampleTime.PadRight(13, '0') : fhr.SampleTime);
- var fhrSampleTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(time);
- // 胎心数据时间与胎动时间一致,最后一条胎心数据与胎动数据的小时差不大于2
- //if ((DateTime.Now.Hour - fhrSampleTime.Hour) <= 2)
- if(true)
- {
- var duringMins = Math.Abs((phrRange.First() - phrRange.Last()).TotalMinutes);
- //在餐后时间段(8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00)取中间值。其他时间段取正常起始值
- bool isInTimeRanges = IsLastUpdateInTimeRanges(phrRange.First());
-
- 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 fetalMovementTimeVar = (fetalMovementMapValue * duringMins * 2) / 120;
- #region 取消使用时间长度比例
- //var fetalMovementTimeVar = (fetalMovementMapValue * duringMins) / 60;
-
- //if (duringMins < 59)
- //{
- // // 取12小时胎动总数最小值
- // fetalMovementMapValue = fetalMovementMap
- // .Where(i => i.PregnancyPeriod![0] <= pregnancyWeeks && i.PregnancyPeriod[1] >= pregnancyWeeks)
- // .First()
- // .TwelveHourMovementRange[0];
- // //取12小时胎动总数最小值的平均值
- // fetalMovementTimeVar = fetalMovementMapValue / 12;
-
- // _logger.LogWarning($"{heartRate.Serialno} 佩戴不足1小时,12小时胎动总数最小值{fetalMovementMapValue},平均值{fetalMovementTimeVar}");
- //}
-
- #endregion
- var fetalMovementTimeVar = (double)fetalMovementMapValue;
-
- #region 生理健康与胎动的关系
- /// (步数)运动步数超过1500步则加1;
- /// (体温)低烧则胎动减1,高烧胎动减2;低烧是37.3~38.5,38.6以上是高烧。
- /// (血压)血压收缩压大于160则加1。
- /// (心理)心理压力高加2,压力中加1;
-
- var fetalMovementStepVar = 0;
- var fetalMovementTempVar = 0;
- var fetalMovementBpVar = 0;
- var fetalMovementPpVar = 0;
- var fetalMovementFhrVar = 0;
- // 步数
- if (false)
- {
- var step = await _personCacheMgr.GetStepPeriodicityAsync(heartRate.Serialno);
- if (step != null)
- {
- if (DateTime.Now.Hour - ((DateTime)step?.LastUpdate!).Hour <= 2)
- {
- if (step.Steps > 1500) fetalMovementStepVar = 1;
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期步数 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期步数无数据");
- }
-
- }
-
- // 体温
- if (true)
- {
- var temp = await _personCacheMgr.GetTemperaturePeriodicityAsync(heartRate.Serialno);
- if (temp != null)
- {
- if (DateTime.Now.Hour - ((DateTime)temp?.LastUpdate!).Hour <= 2)
- {
- // 中烧
- if (temp.Temperature >= 37.3M && temp.Temperature <= 38.5M)
- {
- fetalMovementTempVar = -1;
- }
- // 高烧
- if (temp.Temperature >= 38.6M)
- {
- fetalMovementTempVar = -2;
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期体温 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期体温无数据");
- }
-
- }
-
- // 血压
- if (true)
- {
- var bp = await _personCacheMgr.GetBloodPressPeriodicityAsync(heartRate.Serialno);
- if (bp != null)
- {
- if (DateTime.Now.Hour - ((DateTime)bp?.LastUpdate!).Hour <= 2)
- {
- if (bp.SystolicValue > 160)
- {
- fetalMovementBpVar = 1;
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期血压 时间无效");
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期血压无数据");
- }
-
- }
- // 心理
- if (false)
- {
- //-1 不处理,
- //0 正常,
- //1 轻度,
- //2 中度;
- //3 重度;
- GeneralParam psychResultParam = new()
- {
- Filters = new List<QueryFilterCondition>
- {
- new ()
- {
- Key=nameof(HisGpsPsychResult.Serialno),
- Value=heartRate.Serialno,
- 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(HisGpsPsychResult.Serialno)
- }
- }
- };
- var psych = await _hisPsychResultApiClient.GetFirstAsync(psychResultParam, heartRate.Serialno[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") });
- if (psych != null)
- {
- if (psych?.StressScore == 2)
- {
- fetalMovementPpVar = 1;
- }
-
- if (psych?.StressScore == 3)
- {
- fetalMovementPpVar = 2;
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 周期心理压力无数据");
- }
-
- }
-
- #endregion
-
- #region 胎心与胎动的关系
- /// 胎心值过缓时,则胎动数量减1;胎心值过速时,则胎动也加1。
- /// 此值允许在上限值上继续增加,在下限值上继续减少,最小值为0。
- /// 告警上限阀值
-
- //1表示偏高;2表示偏低
- if (true)
- {
- if (fhr.IsAbnormal == 2)
- {
- fetalMovementPpVar = -1;
- }
-
- if (fhr.IsAbnormal == 1)
- {
- fetalMovementPpVar = 1;
- }
- }
-
- #endregion
-
- _logger.LogInformation($"{heartRate.Serialno} 时间比例胎动值:{fetalMovementTimeVar}, 步数参数变动值:{fetalMovementStepVar},体温参数变动值:{fetalMovementTempVar},血压参数变动值:{fetalMovementBpVar},心理压力参数变动值:{fetalMovementPpVar},胎心参数变动值:{fetalMovementFhrVar}");
-
-
- var fetalMovementValue = fetalMovementTimeVar + fetalMovementStepVar + fetalMovementTempVar + fetalMovementBpVar + fetalMovementPpVar + fetalMovementFhrVar;
-
- // 四舍五入
- var fetalMovement = (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero);
-
- _logger.LogInformation($"{heartRate.Serialno} 孕周:{pregnancyWeeks},胎动数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 采样周期:{statStartTime}-{statEndTime}, 时间比例胎动值:{fetalMovementMapValue}, 佩戴时间 :{duringMins}|{phrRange.Last()}-{phrRange.First()}, 胎动计算值:{fetalMovementTimeVar}, 胎动四舍五入最终值:{fetalMovement} 已完成.");
-
- // 获取胎心数据状态与胎动数据状态一致
- //etalHeartRateIsAbnormal= fhr.IsAbnormal;
- var feltalMovementIsAbnormal = fetalHeartRateIsAbnormal;
-
- await _serviceIotApi.SetFetalMovementConfig(heartRate.Serialno, fetalMovement, fetalMovementSampleTime, feltalMovementIsAbnormal);
-
- // 保存到MySQL数据库
- HisGpsFetalMovement fm = new()
- {
- FetalMovementId = Guid.NewGuid().ToString("D"),
- PersonId = commonPHR!.PersonId,
- Serialno = heartRate.Serialno,
- CreateTime = DateTime.Now,
- IsAbnormal = feltalMovementIsAbnormal,
- FetalMovementValue = fetalMovement,
- SampleTime = fetalMovementSampleTime,
- Method = 1,
- IsDisplay = 1,
- DeviceKey = commonPHR!.DeviceKey
- };
- await _hisFetalMovementApiClient.AddAsync(fm).ConfigureAwait(false);
-
- var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false);
- var fmMsgId = $"{heartRate.Serialno}-{fetalMovementSampleTime}-{Guid.NewGuid().ToString("D")[^3..]}";
- var fmMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(fetalMovementSampleTime.Length < 13 ? fetalMovementSampleTime.PadRight(13, '0') : fetalMovementSampleTime)).ToString("yyyy-MM-dd HH:mm:ss");
- // 胎动数据推送到第三方
- var topic = "topic.push.third";
- var fmThridMsg = new
- {
- messageId = fmMsgId,
- topic = topic,
- time = fmMsgTime,
- data = new
- {
- imei = heartRate.Serialno,
- value = fetalMovement,
- isAbnormal = feltalMovementIsAbnormal,
- type = "fetalMovement"
- }
- };
- await _serviceMqProcess.ProcessIMEIEventMessageAsync(fmMsgId, topic, 31, fmThridMsg).ConfigureAwait(false);
-
- // 胎动数据推送到微信
- if (feltalMovementIsAbnormal != 0)
- {
- 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 = heartRate.Serialno,
- alarmTypeId = 12,
- alarmDeviceName = heartRate.Serialno,
- 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(heartRate.Serialno, fetalMovementSampleTime, fm);
-
-
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 孕周 {pregnancyWeeks},超出胎动计算范围");
- }
- }
- else
- {
- _logger.LogWarning($"{heartRate.Serialno} 最后一条胎心数据与胎动数据的小时差大于2,不计算胎动数据");
- }
- }
- else
- {
- _logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足1条,不能判断是否持续佩戴");
-
- }
- }
- else
- {
- _logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理");
- }
-
- // 跳出循环
- if (statEndTime.ToString("yyyyMMddHHmm") == boundaryStatEndTime.ToString("yyyyMMddHHmm"))
- {
- _logger.LogInformation($"{heartRate.Serialno} 胎动记录迭代完成跳出循环 ");
- break;
- }
- else
- {
- _logger.LogInformation($"{heartRate.Serialno} 胎动周期{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}计算完成, ");
- }
- }
- }
- catch (Exception ex)
- {
- _logger.LogError($"处理胎动数据时发生错误: {ex.Message}");
- }
-
- }
- //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;
- //}
-
- public static DateTime GetSampleTimeFromLastUpdate(DateTime lastUpdate, int interval)
- {
- // 获取当前的分钟
- int minute = lastUpdate.Minute;
-
- // 按 15 分钟为单位划分时间段
- int intervalStartMinute = (minute / interval) * interval;
-
- // 返回当前时间刻度下的 DateTime,保留小时和新计算的分钟,秒和毫秒设为0
- return new DateTime(lastUpdate.Year, lastUpdate.Month, lastUpdate.Day, lastUpdate.Hour, intervalStartMinute, 0, 0);
- }
-
- public static string ExtractImei(string input)
- {
- // 提取 'imei/' 后的数字
- string pattern = @"imei/(\d+)";
-
- Match match = Regex.Match(input, pattern);
-
- if (match.Success)
- {
- return match.Groups[1].Value;
- }
- else
- {
- return string.Empty;
- }
- }
- }
- }
|