|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048 |
- 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"] = $"FREQ-HR-{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"]!;
-
- // 触发高频监测的心率上限值
- var triggerHighFreqHigh = (int)watchConfig["triggerHighFreqHigh"]!;
- // 触发高频监测的心率下限值
- var triggerHighFreqLow = (int)watchConfig["triggerHighFreqLow"]!;
-
- // 高频心率采样间隔 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)
- {
- //triggerHeartRate.HeartRate = lastPhr.Select(i => i.PregnancyHeartRate).Min();
- /// 不够10分钟最近12个数据生成胎心值
-
- int selectedHrValue = SelectValueFromFreqHeartRate(triggerHeartRate, triggerHighFreqHigh, triggerHighFreqLow, lastPhr);
- triggerHeartRate.HeartRate = selectedHrValue;
- _logger.LogInformation($"{triggerHeartRate.Serialno} 不够10分钟最近12个数据数据中取 {triggerHeartRate.HeartRate} 生成胎心值");
- }
- else
- {
- //triggerHeartRate.HeartRate = lastPhr.Select(i => i.PregnancyHeartRate).Min();
- int selectedHrValue = SelectValueFromFreqHeartRate(triggerHeartRate, triggerHighFreqHigh, triggerHighFreqLow, lastPhr);
- triggerHeartRate.HeartRate = selectedHrValue;
- /// 超过10分钟最近12个数据生成胎心值
- _logger.LogInformation($"{triggerHeartRate.Serialno} 超过10分钟最近12个数据数据中取 {triggerHeartRate.HeartRate} 生成胎心值");
-
- }
-
-
- 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条连续正常,高频不停止,暂不处理" +
- $"\n 高频首条心率ID:{phrFreqstatus.MessageId}-时间:{phrFreqstatus.LastUpdate.ToString("yyyy-MM-dd HH:mm:ss")}" +
- $"\n 触发计算高频心率ID:{triggerHeartRate?.MessageId}-时间:{triggerHeartRate?.LastUpdate?.ToString("yyyy-MM-dd HH:mm:ss")}");
- await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(imeiDel);
- }
- }
- 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"] = $"NRML-HR-{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} 胎心监测功能没有启动");
- }
- }
- }
- }
- // 胎动计算
- //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);
- }
-
-
- /// <summary>
- /// 从高频心率数据中取心率值计算胎心值
- /// </summary>
- /// <param name="heartRate"></param>
- /// <param name="triggerHighFreqHigh"></param>
- /// <param name="triggerHighFreqLow"></param>
- /// <param name="lastPhr"></param>
- /// <returns></returns>
- private int SelectValueFromFreqHeartRate(HisGpsHeartRate heartRate, int triggerHighFreqHigh, int triggerHighFreqLow, List<PregnancyHeartRateModel> lastPhr)
- {
- // 连续12个心率的值的最小值
- var selectedHrValue = lastPhr.Select(i => i.PregnancyHeartRate).Min();
- _logger.LogInformation($"{heartRate.Serialno} 最近12个数据的最小值 {selectedHrValue}");
- /// 高频状态下,取值心率低于高频最小值阀值,则需要取最大值进行计算。刚好跟大于高频最大值阀值刚好相反
- if (selectedHrValue < triggerHighFreqLow)
- {
- // 低于高频最小值阀值,则需要取最大值
- var selectedHrMax = lastPhr.Select(i => i.PregnancyHeartRate).Max();
- _logger.LogInformation($"{heartRate.Serialno} 最近12个数据的最小值 {selectedHrValue},低于高频最小值阀值 {triggerHighFreqLow},取最近12个数据的最大值{selectedHrMax}作为心率");
- selectedHrValue = selectedHrMax;
- }
-
- if (selectedHrValue > triggerHighFreqHigh)
- {
- var selectedHrMin = lastPhr.Select(i => i.PregnancyHeartRate).Min();
- _logger.LogInformation($"{heartRate.Serialno} 最近12个数据的最小值 {selectedHrValue},低于高频最大值阀值 {triggerHighFreqHigh},最近12个数据的最小值{selectedHrMin}作为心率");
- selectedHrValue = selectedHrMin;
- }
-
- return selectedHrValue;
- }
-
- /// <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}");
- }
- */
-
-
- ///1、高频最小值>心率,取高频最小值系数
- ///2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
- ///3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
- ///4、心率 > 高频最大值,取高频最大值系数
-
- // 1、高频最小值>心率,取高频最小值系数
- if (commonPHR.MinValue > heartRate.HeartRate)
- {
- coefficient = commonPHR.StatMinValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 高频最小值>心率,取高频最小值系数 {coefficient}");
- }
-
- // 2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
- if (commonPHR.MinValue < heartRate.HeartRate && heartRate.HeartRate < commonPHR.Mode)
- {
- if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMinValueFprCoefficient)
- {
- coefficient = commonPHR.StatMinValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数大于最小值系数,使用最小值系数 {coefficient}");
- }
- else
- {
- coefficient = commonPHR.StatModeAvgFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数小于最小值系数,使用均值系数 {coefficient}");
- }
- }
-
- // 3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
- if (commonPHR.Mode < heartRate.HeartRate && heartRate.HeartRate < commonPHR.MaxValue)
- {
- if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMaxValueFprCoefficient)
- {
- coefficient = commonPHR.StatMaxValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 众数 < 心率 < 高频最大值,平均值系数大于最最大值系数,使用最大值系数 {coefficient}");
- }
- else
- {
- coefficient = commonPHR.StatModeAvgFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 众数 < 心率 < 高频最大值,平均值系数小于最小值系数,使用均值系数 {coefficient}");
- }
- }
-
- // 4、心率 > 高频最大值,取高频最大值系数
-
- if (heartRate.HeartRate > commonPHR.MaxValue)
- {
- coefficient = commonPHR.StatMaxValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 心率 > 高频最大值,取高频最大值系数 {coefficient}");
- }
-
- if (heartRate.HeartRate == commonPHR.Mode)
- {
- 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);
-
- #region 高频心率计算胎心数据到iot设备
-
- //if (phrFreqstatus != null && isAbnormal != 0)
- //{
- // await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
- //}
- // 高频有数据都推送到iot
-
- 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;
- }
-
- /// <summary>
- /// 周期性常规心率计算胎心值
- /// </summary>
- /// <param name="heartRate"></param>
- /// <param name="commonPHR"></param>
- /// <param name="highFreqSampleInterval"></param>
- /// <returns></returns>
- 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}");
- }
- */
-
-
- ///1、高频最小值>心率,取高频最小值系数
- ///2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
- ///3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
- ///4、心率 > 高频最大值,取高频最大值系数
-
- // 1、高频最小值>心率,取高频最小值系数
- if (commonPHR.MinValue > heartRate.HeartRate)
- {
- coefficient = commonPHR.StatMinValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 高频最小值>心率,取高频最小值系数 {coefficient}");
- }
-
- // 2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
- if (commonPHR.MinValue <heartRate.HeartRate && heartRate.HeartRate<commonPHR.Mode)
- {
- if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMinValueFprCoefficient)
- {
- coefficient = commonPHR.StatMinValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数大于最小值系数,使用最小值系数 {coefficient}");
- }
- else
- {
- coefficient = commonPHR.StatModeAvgFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数小于最小值系数,使用均值系数 {coefficient}");
- }
- }
-
- // 3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
- if (commonPHR.Mode < heartRate.HeartRate && heartRate.HeartRate < commonPHR.MaxValue)
- {
- if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMaxValueFprCoefficient)
- {
- coefficient = commonPHR.StatMaxValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 众数 < 心率 < 高频最大值,平均值系数大于最最大值系数,使用最大值系数 {coefficient}");
- }
- else
- {
- coefficient = commonPHR.StatModeAvgFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 众数 < 心率 < 高频最大值,平均值系数小于最小值系数,使用均值系数 {coefficient}");
- }
- }
-
- // 4、心率 > 高频最大值,取高频最大值系数
-
- if (heartRate.HeartRate > commonPHR.MaxValue)
- {
- coefficient = commonPHR.StatMaxValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 心率 > 高频最大值,取高频最大值系数 {coefficient}");
- }
-
- if (heartRate.HeartRate == commonPHR.Mode)
- {
- 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}");
- }
-
- }
-
- 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;
- }
- }
- }
- }
|