Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

PregnancyHeartRateResolver.cs 25KB

7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
7 meses atrás
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. using HealthMonitor.Common;
  2. using HealthMonitor.Common.helper;
  3. using HealthMonitor.Model.Service.Mapper;
  4. using HealthMonitor.Service.Biz;
  5. using HealthMonitor.Service.Biz.db;
  6. using HealthMonitor.Service.Cache;
  7. using HealthMonitor.Service.Etcd;
  8. using HealthMonitor.Service.Resolver.Interface;
  9. using HealthMonitor.Service.Sub;
  10. using HealthMonitor.Service.Sub.Topic.Model;
  11. using Microsoft.EntityFrameworkCore.Metadata;
  12. using Microsoft.Extensions.Logging;
  13. using Newtonsoft.Json;
  14. using SqlSugar;
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using System.Text;
  19. using System.Threading.Tasks;
  20. using TelpoDataService.Util.Clients;
  21. using TelpoDataService.Util.Entities.GpsLocationHistory;
  22. namespace HealthMonitor.Service.Resolver
  23. {
  24. public class PregnancyHeartRateResolver : IResolver
  25. {
  26. private readonly ILogger<PregnancyHeartRateResolver> _logger;
  27. private readonly TDengineService _serviceTDengine;
  28. private readonly DeviceCacheManager _deviceCacheMgr;
  29. private readonly IotApiService _serviceIotApi;
  30. private readonly AsyncLocal<string> _messageId = new();
  31. private readonly AsyncLocal<HisGpsHeartRate> _msgData = new();
  32. private readonly HttpHelper _httpHelper = default!;
  33. private readonly EtcdService _serviceEtcd;
  34. private readonly GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> _hisFetalHeartApiClient;
  35. public PregnancyHeartRateResolver(ILogger<PregnancyHeartRateResolver> logger,
  36. HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr,
  37. IotApiService iotApiService, TDengineService serviceDengine, GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> hisFetalHeartApiClient)
  38. {
  39. _logger = logger;
  40. _httpHelper = httpHelper;
  41. _serviceEtcd = serviceEtcd;
  42. _serviceTDengine = serviceDengine;
  43. _deviceCacheMgr = deviceCacheMgr;
  44. _serviceIotApi = iotApiService;
  45. _hisFetalHeartApiClient = hisFetalHeartApiClient;
  46. }
  47. public void SetResolveInfo(PackageMsgModel msg)
  48. {
  49. var topicHmPregnancyHeartRate = JsonConvert.DeserializeObject<TopicHmPregnancyHeartRate>(msg.DetailData.ToString()!);
  50. _messageId.Value = msg.MessageId;
  51. _msgData.Value = new HisGpsHeartRate()
  52. {
  53. HeartRateId = topicHmPregnancyHeartRate!.PregnancyHeartRateId,
  54. MessageId = topicHmPregnancyHeartRate!.MessageId,
  55. Serialno = topicHmPregnancyHeartRate!.Serialno,
  56. HeartRate= topicHmPregnancyHeartRate.PregnancyHeartRate,
  57. LastUpdate = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(SafeType.SafeInt64(topicHmPregnancyHeartRate.LastUpdate) / 1000000),
  58. CreateTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(SafeType.SafeInt64(topicHmPregnancyHeartRate.CreateTime) / 1000000),
  59. Method = topicHmPregnancyHeartRate!.Method,
  60. IsDisplay = topicHmPregnancyHeartRate!.IsDisplay ? 1 : 0
  61. };
  62. }
  63. public override string ToString()
  64. {
  65. return $"{nameof(PregnancyHeartRateResolver)}[{_messageId.Value}]";
  66. }
  67. public async Task ExecuteMessageAsync()
  68. {
  69. //throw new NotImplementedException();
  70. var messageId = _messageId.Value;
  71. var heartRate = _msgData.Value!;
  72. var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(heartRate.Serialno, "0067");
  73. var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;
  74. if (isFetalHeartEnable)
  75. {
  76. // 高频心率采样间隔
  77. var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]!;
  78. // 触发高频监测的心率上限值
  79. var triggerHighFreqHigh = (int)watchConfig["triggerHighFreqHigh"]!;
  80. // 触发高频监测的心率下限值
  81. var triggerHighFreqLow = (int)watchConfig["triggerHighFreqLow"]!;
  82. //停止高频心率采样心率连续正常次数
  83. var stopHighFreqSampleCount = (int)watchConfig["stopHighFreqSampleCount"]!;
  84. // 高频心率采集时长 0 为持续采集,非零为高频心率的采集时长
  85. var highFreqSampleTimes = (int)watchConfig["stopHighFreqSampleCount"]!;
  86. // 告警上限阀值
  87. var upperAlarmThreshold = (int)watchConfig["upperAlarmThreshold"]!;
  88. // 告警下限阀值
  89. var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!;
  90. var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
  91. if (phr.Count >= 30)
  92. {
  93. #region 高频心率计算
  94. // 获取最近的两个记录,并计算它们的 LastUpdate 时间差
  95. var firstTwoPhr = phr.OrderByDescending(i => i.LastUpdate).Take(2).Select(i => i.LastUpdate).ToList();
  96. var timeDiff = firstTwoPhr[0] - firstTwoPhr[1];
  97. // 如果需要,将时间差转换为秒
  98. var timeDiffInSeconds = timeDiff.TotalSeconds;
  99. // 高频心率启动
  100. if (timeDiffInSeconds<=highFreqSampleInterval)
  101. {
  102. var phrFreqstatus =await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
  103. if (phrFreqstatus == null)
  104. {
  105. /// 设置高频状态
  106. _logger.LogInformation($"进入高频心率启动状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
  107. // 设置高频状态
  108. var freqFirstPhr= phr.OrderByDescending(i => i.Timestamp).First();
  109. await _deviceCacheMgr.SetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno, freqFirstPhr);
  110. phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
  111. }
  112. /// phr PregnancyHeartRate 连续连续正常次数个值都是正常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
  113. /// 取连续正常次数正常值的平均值,推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
  114. #region 检查是否连续12个值都是正常的
  115. // 获取最近连续正常次数个心率记录
  116. var lastPhr = phr.OrderByDescending(i => i.Timestamp).Take(stopHighFreqSampleCount).ToList();
  117. // 检查是否连续12个值都是正常的
  118. if (lastPhr.All(i => i.PregnancyHeartRate >= triggerHighFreqLow && i.PregnancyHeartRate <= triggerHighFreqHigh))
  119. {
  120. var avgPhr = lastPhr.Select(i => i.PregnancyHeartRate).Average();
  121. // 计算一般心率得到胎心系数
  122. await SaveAndPushFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr);
  123. }
  124. #endregion
  125. }
  126. // 高频心率结束
  127. else
  128. {
  129. var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
  130. if (phrFreqstatus != null)
  131. {
  132. /// 在highFreqSampleTimes=0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
  133. /// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
  134. if (highFreqSampleTimes==0)
  135. {
  136. // if (phr.OrderByDescending(i => i.Timestamp)
  137. //.Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
  138. //.Skip(1) // 去除首条
  139. //.All(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHig))
  140. // {
  141. // var avgPhr = phr.Select(i => i.PregnancyHeartRate).Average();
  142. // // 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig
  143. // // 计算一般心率得到胎心系数
  144. // }
  145. var avgPhr = phr.OrderByDescending(i => i.Timestamp)
  146. .Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
  147. .Skip(1) // 去除首条
  148. .Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh)
  149. .Select(i => i.PregnancyHeartRate).Average();
  150. // 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig
  151. // 计算一般心率得到胎心系数
  152. await SaveAndPushFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr);
  153. }
  154. /// 在highFreqSampleTimes>0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
  155. /// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
  156. if (highFreqSampleTimes > 0 && heartRate.LastUpdate >= (phrFreqstatus?.LastUpdate + TimeSpan.FromSeconds(highFreqSampleTimes)))
  157. {
  158. var avgPhr = phr
  159. .Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
  160. .Skip(1) // 去除首条
  161. .Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh)
  162. .Select(i => i.PregnancyHeartRate).Average();
  163. // 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig
  164. // 计算一般心率得到胎心系数
  165. await SaveAndPushFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr);
  166. }
  167. // 删除高频状态的首条记录
  168. await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
  169. /// 设置高频状态
  170. _logger.LogInformation($"结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
  171. }
  172. }
  173. #endregion
  174. #region 计算胎心数据
  175. var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno);
  176. if (commonPHR != null)
  177. {
  178. #region 计算胎心数据
  179. // 上15分钟的数据
  180. // 获取当前时间
  181. DateTime nowQuarter = (DateTime)heartRate.LastUpdate!;
  182. // 计算last_update到上一刻钟的分钟数
  183. int minutesToSubtract = nowQuarter.Minute % 15;
  184. // 计算上一刻钟的时间
  185. DateTime previousQuarter = nowQuarter.AddMinutes(-minutesToSubtract).AddSeconds(-nowQuarter.Second).AddMilliseconds(-nowQuarter.Millisecond);
  186. // 使用 last_update 上一刻
  187. var sampleTime = DateTimeUtil.ConvertToTimeStamp(previousQuarter).ToString();
  188. // 计算last_update到下一刻钟的分钟数
  189. int minutesToAdd = 15 - (nowQuarter.Minute % 15);
  190. if (minutesToAdd == 15)
  191. {
  192. minutesToAdd = 0; // 如果已经是刻钟,则不需要增加分钟
  193. }
  194. // 计算下一刻钟的时间
  195. DateTime nextQuarter = nowQuarter.AddMinutes(minutesToAdd)
  196. .AddSeconds(-nowQuarter.Second)
  197. .AddMilliseconds(-nowQuarter.Millisecond);
  198. var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
  199. var filteredPhr = daysPhr
  200. // 使用 last_update 下一刻
  201. .Where(i => i.LastUpdate <= nextQuarter && i.LastUpdate >= nextQuarter.AddMinutes(-15))
  202. .ToList();
  203. var qarterPhrValue = filteredPhr.Count == 1
  204. ? filteredPhr.First().PregnancyHeartRate
  205. : filteredPhr.Average(i => i.PregnancyHeartRate);
  206. var fetalHeartRate = SafeType.SafeInt(qarterPhrValue * commonPHR?.StatModeAvgFprCoefficient!);
  207. var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
  208. HisGpsFetalHeartRate gpsFetalHeartRate = new()
  209. {
  210. FetalHeartRateId = Guid.NewGuid().ToString("D"),
  211. PersonId = commonPHR!.PersonId,
  212. Serialno = heartRate.Serialno,
  213. HeartRate = fetalHeartRate,
  214. SampleTime = sampleTime,
  215. IsAbnormal = isAbnormal,
  216. StatStartTime = filteredPhr.OrderBy(i => i.LastUpdate).First().LastUpdate,
  217. StatEndTime = filteredPhr.OrderBy(i => i.LastUpdate).Last().LastUpdate,
  218. CreateTime = DateTime.Now,
  219. Method = 1,
  220. IsDisplay = 1,
  221. DeviceKey = commonPHR!.DeviceKey
  222. };
  223. // 保存到 数据服务 MySQL 数据库
  224. await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false);
  225. // 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
  226. await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
  227. #endregion
  228. }
  229. #endregion
  230. #region 定时计算胎心数据触发器 {interval} 秒后
  231. //var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
  232. //await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, 60 * 15);
  233. #endregion
  234. #region 定时计算胎心数据触发器下一刻钟后
  235. //// 获取当前时间
  236. //DateTime nowQuarter = DateTime.Now;
  237. //// 计算下一个15分钟的刻钟
  238. //int minutesToAdd = 15 - (nowQuarter.Minute % 15);
  239. //if (minutesToAdd == 15)
  240. //{
  241. // minutesToAdd = 0; // 如果已经是刻钟,则不需要增加分钟
  242. //}
  243. //// 计算下一刻钟的时间
  244. //DateTime nextQuarter = nowQuarter.AddMinutes(minutesToAdd)
  245. // .AddSeconds(-nowQuarter.Second)
  246. // .AddMilliseconds(-nowQuarter.Millisecond);
  247. //// 计算时间差
  248. //TimeSpan timeDifference = nextQuarter - nowQuarter;
  249. //var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
  250. //await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, (long)timeDifference.TotalSeconds);
  251. #endregion
  252. #region 定时计算胎动数据触发器 0 点开始
  253. var fetalMovementKey = $"health_monitor/schedule_push/cal_fetal_movement/imei/{heartRate.Serialno}";
  254. /// 计算 0 点秒数
  255. DateTime now = DateTime.Now;
  256. var rand = new Random();
  257. var pushSec = rand.Next(59);
  258. int pushMin = int.TryParse(heartRate.Serialno.AsSpan(heartRate.Serialno.Length - 1), out pushMin) ? pushMin : 10;
  259. DateTime nextRunTime = new (now.Year, now.Month, now.Day, 0, pushMin, pushSec);
  260. TimeSpan timeUntilNextRun = nextRunTime - now;
  261. if (timeUntilNextRun < TimeSpan.Zero)
  262. {
  263. timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
  264. nextRunTime += timeUntilNextRun;
  265. }
  266. var ttl = (long)timeUntilNextRun.TotalSeconds;
  267. await SetIntervalTriggerAsync(fetalMovementKey, heartRate.Serialno, ttl);
  268. //var scheduleFetalMovementPush = await _serviceEtcd.GetValAsync(fetalMovementKey).ConfigureAwait(false);
  269. //if (string.IsNullOrWhiteSpace(scheduleFetalMovementPush))
  270. //{
  271. // var fetalMovementInterval = 60 * 15;
  272. // var fetalMovementNow = DateTime.Now;
  273. // var fetalMovementTimeNextRun = fetalMovementNow.Add(TimeSpan.FromSeconds(fetalMovementInterval));
  274. // var fetalMovementTTL = fetalMovementInterval;
  275. // var data = new
  276. // {
  277. // imei = heartRate.Serialno,
  278. // create_time = fetalMovementNow.ToString("yyyy-MM-dd HH:mm:ss"),
  279. // fetalMovementTTL,
  280. // next_run_time = fetalMovementTimeNextRun.ToString("yyyy-MM-dd HH:mm:ss")
  281. // };
  282. // var result = JsonConvert.SerializeObject(data);
  283. // await _serviceEtcd.PutValAsync(fetalKey, result, fetalMovementTTL, false).ConfigureAwait(false);
  284. //}
  285. #endregion
  286. }
  287. #region 定时下发触发器(定时建模)
  288. var key = $"health_monitor/schedule_push/pregnancy_heart_rate/imei/{heartRate.Serialno}";
  289. var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);
  290. if (string.IsNullOrWhiteSpace(schedule_push))
  291. {
  292. // 注册首次下推
  293. #if DEBUG
  294. // await _serviceEtcd.PutValAsync(key, result, 60*1, false).ConfigureAwait(false);
  295. var interval = 0;
  296. // 获取当前时间
  297. DateTime now = DateTime.Now;
  298. // 计算距离下一个$interval天后的8点的时间间隔
  299. DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 1, 58).AddDays(interval);
  300. TimeSpan timeUntilNextRun = nextRunTime - now;
  301. // 如果当前时间已经超过了8点,将等待到明天后的8点
  302. if (timeUntilNextRun < TimeSpan.Zero)
  303. {
  304. timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1));
  305. nextRunTime += timeUntilNextRun;
  306. }
  307. var ttl = (long)timeUntilNextRun.TotalSeconds;
  308. var data = new
  309. {
  310. imei = heartRate.Serialno,
  311. create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
  312. ttl,
  313. next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
  314. };
  315. var result = JsonConvert.SerializeObject(data);
  316. await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
  317. #else
  318. var interval = 0;
  319. // 获取当前时间
  320. DateTime now = DateTime.Now;
  321. var rand=new Random();
  322. var pushSec = rand.Next(59);
  323. int pushMin= int.TryParse(heartRate.Serialno.AsSpan(heartRate.Serialno.Length - 1), out pushMin) ? pushMin : 10;
  324. // 计算距离下一个$interval天后的8点的时间间隔
  325. DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 18, pushMin, pushSec).AddDays(interval);
  326. TimeSpan timeUntilNextRun = nextRunTime - now;
  327. if (timeUntilNextRun < TimeSpan.Zero)
  328. {
  329. timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
  330. nextRunTime += TimeSpan.FromDays(1);
  331. }
  332. var ttl =(long)timeUntilNextRun.TotalSeconds;
  333. var data = new
  334. {
  335. imei = heartRate.Serialno,
  336. create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
  337. ttl,
  338. next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
  339. };
  340. var result = JsonConvert.SerializeObject(data);
  341. await _serviceEtcd.PutValAsync(key, result,ttl, false).ConfigureAwait(false);
  342. #endif
  343. }
  344. #endregion
  345. }
  346. }
  347. private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, double avgPhr)
  348. {
  349. var commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno);
  350. if (commonPHR != null)
  351. {
  352. // 保存到TDengine数据库
  353. await _serviceTDengine.InsertAsync<PregnancyCommonHeartRateModel>("hm_pchr", commonPHR);
  354. // 计算胎心=孕妇心率*系数
  355. var fetalHeartRate = SafeType.SafeInt(avgPhr * commonPHR?.StatModeAvgFprCoefficient!);
  356. var sampleTime = DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString();
  357. var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
  358. // 保存到 数据服务 MySQL 数据库
  359. HisGpsFetalHeartRate gpsFetalHeartRate = new ()
  360. {
  361. FetalHeartRateId = Guid.NewGuid().ToString("D"),
  362. PersonId = commonPHR!.PersonId,
  363. Serialno = heartRate.Serialno,
  364. HeartRate = fetalHeartRate,
  365. SampleTime = sampleTime,
  366. IsAbnormal = isAbnormal,
  367. StatStartTime = commonPHR.StatStartTime,
  368. StatEndTime = commonPHR.StatEndTime,
  369. CreateTime = DateTime.Now,
  370. Method = 1,
  371. IsDisplay = 1,
  372. DeviceKey = commonPHR!.DeviceKey
  373. };
  374. await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false);
  375. // 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
  376. await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
  377. }
  378. }
  379. private async Task SetIntervalTriggerAsync(string key,string imei, long interval)
  380. {
  381. // var key = $"health_monitor/schedule_push/{type}/imei/{imei}";
  382. var schedulePush = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);
  383. if (string.IsNullOrWhiteSpace(schedulePush))
  384. {
  385. var now = DateTime.Now;
  386. var timeNextRun = now.Add(TimeSpan.FromSeconds(interval));
  387. var data = new
  388. {
  389. imei,
  390. create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
  391. ttl = interval,
  392. next_run_time = timeNextRun.ToString("yyyy-MM-dd HH:mm:ss")
  393. };
  394. var result = JsonConvert.SerializeObject(data);
  395. await _serviceEtcd.PutValAsync(key, result, interval, false).ConfigureAwait(false);
  396. }
  397. }
  398. }
  399. }