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