You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

338 satır
15KB

  1. using GpsCardGatewayPosition.Model.Config;
  2. using GpsCardGatewayPosition.Model.Enum;
  3. using GpsCardGatewayPosition.Service.Cache;
  4. using GpsCardGatewayPosition.Service.MqProducer;
  5. using GpsCardGatewayPosition.Service.Resolver.Property.Dto;
  6. using Microsoft.Extensions.Logging;
  7. using Microsoft.Extensions.Options;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using TelpoDataService.Util.Clients;
  14. using TelpoDataService.Util.Entities.GpsLocationHistory;
  15. namespace GpsCardGatewayPosition.Service.Biz.Health
  16. {
  17. public class HealthLogic
  18. {
  19. public enum TemperatureStatusType : int
  20. {
  21. /// <summary>
  22. /// 不存在
  23. /// </summary>
  24. NotExisted = 0,
  25. /// <summary>
  26. /// 不完整,已填写内容
  27. /// </summary>
  28. FilledContent = 1,
  29. /// <summary>
  30. /// 不完整,已填写地址
  31. /// </summary>
  32. FilledAddress = 2,
  33. /// <summary>
  34. /// 信息已完整
  35. /// </summary>
  36. Complete = 3,
  37. /// <summary>
  38. ///
  39. /// </summary>
  40. Reserved
  41. }
  42. private const string KEY_CACHE_TEMPERATURE_STATUS = "Temperature_Status";
  43. private const int KEY_CACHE_SECONDS = 600;
  44. private readonly ServiceConfig _configService;
  45. private readonly MqProcessLogic _serviceMqProcess;
  46. private readonly PersonCacheManager _personCacheMgr;
  47. private readonly DeviceCacheManager _deviceCacheMgr;
  48. //private readonly StepCacheManager _stepCacheMgr;
  49. private readonly GpsLocationHistoryAccessorClient<HisGpsTemperature> _hisTemperatureApiClient;
  50. private readonly GpsLocationHistoryAccessorClient<HisGpsStep> _hisStepApiClient;
  51. private readonly GpsLocationHistoryAccessorClient<HisGpsHeartRate> _hisHeartApiClient;
  52. private readonly GpsLocationHistoryAccessorClient<HisGpsSpo2> _hisSpo2ApiClient;
  53. private readonly GpsLocationHistoryAccessorClient<HisGpsBloodPress> _hisBloodPressApiClient;
  54. private readonly GpsLocationHistoryAccessorClient<HisGpsDrownReport> _hisDrownReportApiClient;
  55. private readonly GpsLocationHistoryAccessorClient<HisGpsWearStatus> _hisWearStatusApiClient;
  56. private readonly GpsLocationHistoryAccessorClient<HisGpsSportResult> _hisSportResultApiClient;
  57. private readonly ILogger<HealthLogic> _logger;
  58. public HealthLogic(IOptions<ServiceConfig> optConfigService, MqProcessLogic serviceMqProcess,
  59. // StepCacheManager stepCacheMgr,
  60. PersonCacheManager personCacheMgr,
  61. DeviceCacheManager deviceCacheMgr,
  62. GpsLocationHistoryAccessorClient<HisGpsTemperature> temperatureApiClient,
  63. GpsLocationHistoryAccessorClient<HisGpsStep> stepApiClient,
  64. GpsLocationHistoryAccessorClient<HisGpsHeartRate> hisHeartApiClient,
  65. GpsLocationHistoryAccessorClient<HisGpsSpo2> hisSpo2ApiClient,
  66. GpsLocationHistoryAccessorClient<HisGpsBloodPress> hisBloodPressApiClient,
  67. GpsLocationHistoryAccessorClient<HisGpsDrownReport> hisDrownReportApiClient,
  68. GpsLocationHistoryAccessorClient<HisGpsWearStatus> hisWearStatusApiClient,
  69. GpsLocationHistoryAccessorClient<HisGpsSportResult> hisSportResultApiClient,
  70. ILogger<HealthLogic> logger)
  71. {
  72. _configService = optConfigService.Value;
  73. _serviceMqProcess = serviceMqProcess;
  74. _deviceCacheMgr = deviceCacheMgr;
  75. _personCacheMgr = personCacheMgr;
  76. //_stepCacheMgr = stepCacheMgr;
  77. _hisTemperatureApiClient = temperatureApiClient;
  78. _hisStepApiClient = stepApiClient;
  79. _logger = logger;
  80. _hisHeartApiClient = hisHeartApiClient;
  81. _hisSpo2ApiClient = hisSpo2ApiClient;
  82. _hisDrownReportApiClient = hisDrownReportApiClient;
  83. _hisWearStatusApiClient = hisWearStatusApiClient;
  84. _hisBloodPressApiClient = hisBloodPressApiClient;
  85. _hisSportResultApiClient = hisSportResultApiClient;
  86. }
  87. #region 体温相关
  88. /// <summary>
  89. /// 处理测温事件消息(内容部分)
  90. /// </summary>
  91. /// <param name="messageId"></param>
  92. /// <param name="tempId">和serialno组合的tempId</param>
  93. /// <param name="factoryToAdd">返回测温对象用于插入数据库</param>
  94. /// <param name="factoryToUpdate">返回测温对象用于更新数据库</param>
  95. /// <param name="handleFollowup">后续处理</param>
  96. /// <param name="type">定位类型</param> // 2022/11/10 增加 type 参数判断定位类型
  97. /// <returns></returns>
  98. public async Task<bool> HandleTemperatureContent(string messageId, string tempId,
  99. Func<HisGpsTemperature> factoryToAdd, Func<HisGpsTemperature, HisGpsTemperature> factoryToUpdate,
  100. Action handleFollowup = null, LocationType type = default)
  101. {
  102. if (factoryToAdd == null || factoryToUpdate == null) throw new ArgumentNullException();
  103. HisGpsTemperature temperature = null;
  104. var status = await GetTemperatureStatusAsync(tempId).ConfigureAwait(false);
  105. if (status == TemperatureStatusType.Complete || status == TemperatureStatusType.FilledContent)
  106. {
  107. _logger.LogWarning($"TEMPERATURE事件[{tempId}]已处理(内容部分)|事件");
  108. return false;
  109. }
  110. if (status == TemperatureStatusType.NotExisted)
  111. {
  112. temperature = factoryToAdd.Invoke();
  113. await AddTemperatureAsync(messageId, temperature).ConfigureAwait(false);
  114. SetTemperatureStatus(tempId, TemperatureStatusType.FilledContent);
  115. // 对应无地址也要推送测温情况,创建一个线程,并让该线程休眠 60 秒
  116. Thread thread = new Thread(async () =>
  117. {
  118. _logger.LogInformation($"messageId:[{messageId}],TEMPERATURE事件[{tempId}] 无地址测温推送延时60s,判断入库后gps_temperature表中address是否为空,若为空也推送");
  119. Task.Delay(TimeSpan.FromSeconds(60)).Wait();
  120. var temperatureLate = await GetTemperatureAsync(messageId, tempId).ConfigureAwait(false);
  121. if (string.IsNullOrEmpty(temperatureLate.Address))
  122. {
  123. PushWxTemperature(messageId, temperatureLate);
  124. _logger.LogInformation($"messageId:[{messageId}],TEMPERATURE事件[{tempId}]延时60s,无地址已推送");
  125. }
  126. _logger.LogInformation($"messageId:[{messageId}],TEMPERATURE事件[{tempId}]延时60s,在HandleTemperatureAddressAsync地址已推送");
  127. });
  128. thread.Start();
  129. }
  130. else
  131. {
  132. temperature = await GetTemperatureAsync(messageId, tempId).ConfigureAwait(false);
  133. if (temperature != null)
  134. {
  135. temperature = factoryToUpdate.Invoke(temperature);
  136. await UpdateTemperatureAsync(messageId, temperature).ConfigureAwait(false);
  137. SetTemperatureStatus(tempId, TemperatureStatusType.Complete);
  138. //推送微信公众号
  139. await PushWxTemperature(messageId, temperature, type);
  140. }
  141. }
  142. handleFollowup?.Invoke();
  143. return true;
  144. }
  145. /// <summary>
  146. /// 处理测温事件消息(地址信息部分)
  147. /// </summary>
  148. /// <param name="messageId"></param>
  149. /// <param name="tempId">和serialno组合的tempId</param>
  150. /// <param name="factoryToAdd">返回测温对象用于插入数据库</param>
  151. /// <param name="factoryToUpdate">返回测温对象用于更新数据库</param>
  152. /// <param name="handleFollowup">后续处理</param>
  153. /// <param name="type">定位类型</param> // 2022/11/10 增加 type 参数判断定位类型
  154. /// <returns></returns>
  155. public async Task<bool> HandleTemperatureAddressAsync(string messageId, string tempId,
  156. Func<HisGpsTemperature> factoryToAdd, Func<HisGpsTemperature, HisGpsTemperature> factoryToUpdate,
  157. Action handleFollowup = null, LocationType type = default)
  158. {
  159. if (factoryToAdd == null || factoryToUpdate == null) throw new ArgumentNullException();
  160. HisGpsTemperature temperature = null;
  161. var status = await GetTemperatureStatusAsync(tempId).ConfigureAwait(false);
  162. if (status == TemperatureStatusType.Complete || status == TemperatureStatusType.FilledAddress)
  163. {
  164. _logger.LogWarning($"TEMPERATURE事件[{tempId}]已处理(地址信息内容部分)");
  165. return false;
  166. }
  167. if (status == TemperatureStatusType.NotExisted)
  168. {
  169. temperature = factoryToAdd.Invoke();
  170. await AddTemperatureAsync(messageId, temperature).ConfigureAwait(false);
  171. SetTemperatureStatus(tempId, TemperatureStatusType.FilledAddress);
  172. // 2023/02/02 新增测温数据 没有匹配定位信息,也推送给第三方平台。
  173. // if (temperature.Temperature != null)
  174. // {
  175. // PushWxTemperature(messageId, temperature);
  176. // }
  177. }
  178. else
  179. {
  180. temperature = await GetTemperatureAsync(messageId, tempId).ConfigureAwait(false);
  181. if (temperature != null)
  182. {
  183. temperature = factoryToUpdate.Invoke(temperature);
  184. await UpdateTemperatureAsync(messageId, temperature).ConfigureAwait(false);
  185. SetTemperatureStatus(tempId, TemperatureStatusType.Complete);
  186. //推送微信公众号
  187. PushWxTemperature(messageId, temperature, type);
  188. }
  189. }
  190. handleFollowup?.Invoke();
  191. return true;
  192. }
  193. // 2022/11/10 增加 type 参数判断定位类型
  194. private async Task PushWxTemperature(string messageId, HisGpsTemperature temperature, LocationType type = default)
  195. {
  196. var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(messageId, temperature.Serialno);
  197. if (device == null) return;
  198. string deviceName = temperature.Serialno;
  199. var person = await _personCacheMgr.GetPersonBySerialNoAsync(messageId, temperature.Serialno).ConfigureAwait(false);
  200. if (person != null) deviceName = person.NickName;
  201. MethodType method = MethodType.Manual;
  202. //if (temperature.Method == 0) method = MethodType.Manual;
  203. if (temperature.Method == 1) method = MethodType.Period;
  204. await _serviceMqProcess.ProcessWxTemperatureAsync(messageId, new TemperatureInfoModel
  205. {
  206. DeviceId = device.DeviceId,
  207. DeviceName = deviceName,
  208. TempId = temperature.TempId,
  209. TempTime = temperature.LastUpdate,
  210. Imei = temperature.Serialno,
  211. Temperature = temperature.Temperature,
  212. Province = temperature.Province,
  213. City = temperature.City,
  214. District = temperature.District,
  215. Address = temperature.Address
  216. }, type, method);
  217. }
  218. private async Task<TemperatureStatusType> GetTemperatureStatusAsync(string tempId)
  219. {
  220. var key = $"{KEY_CACHE_TEMPERATURE_STATUS}_{tempId}";
  221. var result = await RedisHelper.GetAsync<TemperatureStatusType?>(key);
  222. if (result == null) return TemperatureStatusType.NotExisted;
  223. if (result > TemperatureStatusType.Reserved || result < TemperatureStatusType.NotExisted) return TemperatureStatusType.NotExisted;
  224. return result.Value;
  225. }
  226. private void SetTemperatureStatus(string sosId, TemperatureStatusType status)
  227. {
  228. var key = $"{KEY_CACHE_TEMPERATURE_STATUS}_{sosId}";
  229. RedisHelper.SetAsync(key, (int)status, KEY_CACHE_SECONDS);
  230. }
  231. public async Task<HisGpsTemperature> GetTemperatureAsync(string messageId, string temperatureId)
  232. {
  233. try
  234. {
  235. //var param = new GeneralParam
  236. //{
  237. // Filters = new List<QueryFilterCondition>
  238. // {
  239. // new QueryFilterCondition
  240. // {
  241. // Key=nameof(HisGpsTemperature.TempId),
  242. // Value=tempId,
  243. // ValueType=QueryValueTypeEnum.String,
  244. // Operator=QueryOperatorEnum.Equal
  245. // },
  246. // new QueryFilterCondition
  247. // {
  248. // Key=nameof(HisGpsTemperature.Serialno),
  249. // Value=serialno,
  250. // ValueType=QueryValueTypeEnum.String,
  251. // Operator=QueryOperatorEnum.Equal
  252. // }
  253. // }
  254. //};
  255. //var temperature = await _hisTemperatureApiClient.GetFirstAsync(param, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  256. //return temperature;
  257. var temperature = await _hisTemperatureApiClient.GetByIdAsync(temperatureId, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  258. return temperature;
  259. }
  260. catch (Exception ex)
  261. {
  262. _logger.LogError($"根据{temperatureId}获取指定测温信息失败, {ex.Message}, {ex.StackTrace}");
  263. return null;
  264. }
  265. }
  266. public async Task<bool> AddTemperatureAsync(string messageId, HisGpsTemperature temperature)
  267. {
  268. try
  269. {
  270. // 体温gps_temperature,步数gps_step,血压gps_bloodpress,心率gps_heart_rate,血氧gps_spo2 五个表新增 person_id 字段
  271. var person = await _personCacheMgr.GetDeviceGpsPersonCacheBySerialNoAsync(messageId, temperature.Serialno).ConfigureAwait(false);
  272. var persnId = string.Empty;
  273. if (person != null && person.Person != null) persnId = person.Person.PersonId;
  274. temperature.PersonId = persnId;
  275. await _hisTemperatureApiClient.AddAsync(temperature, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  276. return true;
  277. }
  278. catch (Exception ex)
  279. {
  280. _logger.LogError($"新增体温信息发生异常:{ex.Message}, {ex.StackTrace}");
  281. }
  282. return false;
  283. }
  284. public async Task<bool> UpdateTemperatureAsync(string messageId, HisGpsTemperature temperature)
  285. {
  286. try
  287. {
  288. await _hisTemperatureApiClient.UpdateAsync(temperature, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  289. return true;
  290. }
  291. catch (Exception ex)
  292. {
  293. _logger.LogError($"更新体温信息发生异常:{ex.Message}, {ex.StackTrace}");
  294. }
  295. return false;
  296. }
  297. #endregion
  298. }
  299. }