|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268 |
- 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. 高频15分钟不停止的高频心率处理
- /// 2. 高频结束后的highFreqSampleTimes=0的高频心率处理
- /// 3. 高频结束后的在highFreqSampleTimes>0 正常心率触发的高频心率处理(常态)
- /// 4. 高频结束后的时间倒序的正常心率触发的高频心率处理
- /// * 5. 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理
- /// </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);
-
- #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")}");
- }
-
- }
- #endregion
-
-
- var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
- 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>
- /// 去除高频数据
- /// </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;
- }
- }
- }
- }
|