您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

356 行
18KB

  1. using Google.Protobuf.WellKnownTypes;
  2. using Grpc.Core;
  3. using HealthMonitor.Common;
  4. using HealthMonitor.Common.helper;
  5. using HealthMonitor.Core.Dal;
  6. using HealthMonitor.Core.Pipeline;
  7. using HealthMonitor.Service.Biz.db;
  8. using HealthMonitor.Service.Cache;
  9. using HealthMonitor.Service.Etcd;
  10. using HealthMonitor.Service.Resolver;
  11. using HealthMonitor.Util.Entities.HealthMonitor;
  12. using HealthMonitor.WebApi.Configs;
  13. using HealthMonitor.WebApi.Model.Request;
  14. using Microsoft.AspNetCore.DataProtection.KeyManagement;
  15. using Microsoft.AspNetCore.Http;
  16. using Microsoft.AspNetCore.Mvc;
  17. using Microsoft.AspNetCore.Mvc.ViewFeatures;
  18. using Microsoft.EntityFrameworkCore.Metadata;
  19. using Microsoft.EntityFrameworkCore.Metadata.Internal;
  20. using Newtonsoft.Json;
  21. using Newtonsoft.Json.Linq;
  22. using TelpoDataService.Util.Entities.GpsCard;
  23. using TelpoDataService.Util.Clients;
  24. using System;
  25. using System.Collections.Generic;
  26. using System.ComponentModel.DataAnnotations;
  27. using TelpoDataService.Util;
  28. using TelpoDataService.Util.Models;
  29. using TelpoDataService.Util.QueryObjects;
  30. using HealthMonitor.WebApi.Controllers.Api;
  31. using HealthMonitor.Service.Biz;
  32. using HealthMonitor.Model.Service;
  33. using HealthMonitor.Model.Service.Mapper;
  34. using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
  35. namespace HealthMonitor.WebApi.Controllers.HealthMonitor
  36. {
  37. [ApiExplorerSettings(GroupName = AppConsts.SWAGGER_DOC_HealthMonitor)]
  38. [Produces("application/json")]
  39. [Route("api/HealthMonitor/[controller]/[action]")]
  40. [ApiController]
  41. public class HmBloodPressConfigManualCalibrationController : ControllerBase
  42. {
  43. private readonly ILogger<HmBloodPressConfigManualCalibrationController> _logger;
  44. private readonly PersonCacheManager _personCacheMgr;
  45. private readonly TDengineService _serviceTDengine;
  46. private readonly HttpHelper _httpHelper = default!;
  47. private readonly IotWebApiService _serviceIotWebApi;
  48. private readonly GpsCardAccessorClient<GpsDevice> _deviceApiClient;
  49. private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient;
  50. public HmBloodPressConfigManualCalibrationController
  51. (
  52. TDengineService serviceDengine,
  53. PersonCacheManager personCacheMgr, HttpHelper httpHelper,
  54. GpsCardAccessorClient<GpsPerson> gpsPersonApiClient,
  55. GpsCardAccessorClient<GpsDevice> deviceApiClient,
  56. ILogger<HmBloodPressConfigManualCalibrationController> logger,
  57. IotWebApiService iotWebApiService
  58. )
  59. {
  60. _serviceTDengine = serviceDengine;
  61. _logger = logger;
  62. _httpHelper = httpHelper;
  63. _gpsPersonApiClient = gpsPersonApiClient;
  64. _deviceApiClient = deviceApiClient;
  65. _personCacheMgr = personCacheMgr;
  66. _serviceIotWebApi = iotWebApiService;
  67. }
  68. [HttpPost]
  69. public async Task<ApiResponse<object>> Put([FromBody] BloodPressManualCalibration model, [FromHeader] string requestId)
  70. {
  71. try
  72. {
  73. var imei = model.Imei;
  74. #region 设备合法性
  75. #if DEBUG
  76. #else
  77. var param = new GeneralParam
  78. {
  79. Filters = new List<QueryFilterCondition>
  80. {
  81. new QueryFilterCondition
  82. {
  83. Key=nameof(GpsDevice.Serialno),
  84. Value=model.Imei,
  85. ValueType=QueryValueTypeEnum.String,
  86. Operator=QueryOperatorEnum.Equal
  87. }
  88. }
  89. };
  90. var device = await _deviceApiClient.GetFirstAsync(param, new RequestHeader { RequestId = requestId }).ConfigureAwait(false);
  91. if (device == null)
  92. {
  93. _logger.LogError($"非法设备:{model.Imei}");
  94. return ApiResponse<object>.Fail(500, $"非法设备:{model.Imei}");
  95. }
  96. #endif
  97. #endregion
  98. #region 重置设备
  99. if (model.ManualSystolicRefValue.Equals(0) && model.ManualDiastolicRefValue.Equals(0))
  100. {
  101. //return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, 0, 0, 0, 0).ConfigureAwait(false);
  102. var statNow = DateTime.Now;
  103. _logger.LogInformation($"{imei} 重置设备");
  104. return await IotSetBloodPressCalibrationConfigResponseAsync(imei, 0, 0, 0, 0, 0, 0, 0, 0, statNow, statNow).ConfigureAwait(false);
  105. //return ApiResponse<object>.Success(new
  106. //{
  107. // imei = model.Imei,
  108. // systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效
  109. // diastolicCalibrationValue = 0, //舒张压标定值,值为0表示不生效
  110. // systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效
  111. // diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效
  112. //});
  113. }
  114. #endregion
  115. #region 只下发标定值,不计算增量值,保存数据库(修改个人信息)
  116. if (model.IsPushRefOnly)
  117. {
  118. var statNow = DateTime.Now;
  119. _logger.LogInformation($"{imei}:只下发标定值,不计算增量值,保存数据库(修改个人信息)");
  120. return await IotSetBloodPressCalibrationConfigResponseAsync(imei, model.ManualSystolicRefValue, model.ManualDiastolicRefValue, 0, 0, 0, 0, 0, 0, statNow, statNow).ConfigureAwait(false);
  121. }
  122. #endregion
  123. #region 数据合法性
  124. if (model.ManualSystolicRefValue.Equals(0) || model.ManualDiastolicRefValue.Equals(0))
  125. {
  126. return ApiResponse<object>.Fail(501, $"数据非法,{JsonConvert.SerializeObject(model)}");
  127. }
  128. #endregion
  129. #region 计算增量值
  130. // 计算增量值
  131. int systolicRefValue = model.ManualSystolicRefValue;//?
  132. int diastolicRefValue = model.ManualDiastolicRefValue;//?
  133. // 没有血压数据时增量值为0
  134. int systolicInc;
  135. int diastolicInc;
  136. decimal systolicAvg;
  137. decimal diastolicAvg;
  138. // 最后一次下发值
  139. int lastPushSystolicInc = 0;
  140. int lastPushDiastolicInc = 0;
  141. // 偏移参数
  142. var avgOffset = 0.25M;
  143. var systolicAvgOffset = avgOffset;
  144. var diastolicAvgOffset = avgOffset;
  145. //int duration = 7;
  146. long duration = 7 * 24 * 3600 * 1000;
  147. TimeSpan ts = TimeSpan.FromMilliseconds(duration);
  148. DateTime endTime = DateTime.Now; //测试
  149. DateTime startTime = endTime - ts;
  150. var lastPushResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bp_push_ref_inc_value", $"serialno='{imei}' order by ts desc", "last_row(*)");
  151. var lastPushParser = JsonConvert.DeserializeObject<ParseTDengineRestResponse<BloodPressurePushRefIncModel>>(lastPushResponse!);
  152. var lastPush = lastPushParser!.Select().FirstOrDefault();
  153. // 上次下推增量
  154. lastPushSystolicInc = lastPush!.SystolicIncValue;
  155. lastPushDiastolicInc = lastPush!.DiastolicIncValue;
  156. startTime = lastPush!.Timestamp;
  157. var condition = $"ts between '{startTime:yyyy-MM-dd HH:mm:ss.fff}' and '{endTime:yyyy-MM-dd HH:mm:ss.fff}'" +
  158. $" and serialno='{imei}'" +
  159. $" and is_display = true";
  160. var hmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition);
  161. var hmBpParser = JsonConvert.DeserializeObject<ParseTDengineRestResponse<BloodPressureModel>>(hmBpResponse!);
  162. if (hmBpParser!.Rows >= 5)
  163. {
  164. //systolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.SystolicValue, SafeType.SafeInt(systolicRefValue!)))!;
  165. //diastolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.DiastolicValue, SafeType.SafeInt(diastolicRefValue!)))!;
  166. var avgs = _serviceTDengine.AverageAfterRemovingOneMinMaxRef(SafeType.SafeInt(systolicRefValue!), hmBpParser!);
  167. systolicAvg = avgs[0];
  168. diastolicAvg = avgs[1];
  169. // 平均值为0,说明数据不足,不能计算增量值
  170. // 数据不足等同进行初始化,只下发标定值,增量值为0;remarks恢复到未校准状态,需要基于第一个测量值生成增量值。
  171. if (systolicAvg.Equals(0))
  172. {
  173. _logger.LogInformation($"测量数据样本不足,将进行标定值初始,只下发标定值,增量值为0;remarks恢复到未校准状态。");
  174. // 重置设备
  175. var statNow = DateTime.Now;
  176. await IotSetBloodPressCalibrationConfigResponseAsync(imei, 0, 0, 0, 0, 0, 0, 0, 0, statNow, statNow).ConfigureAwait(false);
  177. _logger.LogInformation($"1.测量数据样本不足,重置设备");
  178. var initRemarksFlag = await _serviceIotWebApi.UpdatePersonRemarksAsync(imei, 0, 0, 0, 0, true).ConfigureAwait(false);
  179. if (initRemarksFlag)
  180. {
  181. _logger.LogInformation($"2.测量数据样本不足,remarks恢复到未校准状态(remarks设置为空),成功");
  182. }
  183. else
  184. {
  185. _logger.LogInformation($"2.测量数据样本不足,remarks恢复到未校准状态(remarks设置为空),失败");
  186. }
  187. _logger.LogInformation($"3.测量数据样本不足,只下发手动标定值systolicRefValue:{systolicRefValue} -- diastolicRefValue:{diastolicRefValue},增量值为0");
  188. statNow = DateTime.Now.AddSeconds(3);
  189. return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, 0, 0, 0, 0, 0, 0, statNow, statNow).ConfigureAwait(false);
  190. }
  191. // 增量值=(标定值-平均值)* 0.25
  192. var currentSystolicInc = (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!;
  193. var currentDiastolicInc = (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!;
  194. // 累计增量
  195. systolicInc = currentSystolicInc + lastPushSystolicInc;
  196. diastolicInc = currentDiastolicInc + lastPushDiastolicInc;
  197. _logger.LogInformation($"{imei}--{nameof(Put)}--计算增量值" +
  198. $"\n {imei}-- systolicAvg:{systolicAvg}--systolicInc:{systolicInc}-- currentSystolicInc:{currentSystolicInc} -- lastPushSystolicInc:{lastPushSystolicInc}" +
  199. $"\n {imei}-- diastolicAvg:{diastolicAvg}--diastolicInc:{diastolicInc} --currentDiastolicInc:{currentDiastolicInc} -- lastPushDiastolicInc:{lastPushDiastolicInc}");
  200. _logger.LogInformation($"{imei},手工校准,发给设备的绝对增量值=(上次绝对增量值+新数据的增量值)");
  201. return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, systolicInc, diastolicInc, systolicAvg, diastolicAvg, systolicAvgOffset, diastolicAvgOffset, startTime, endTime).ConfigureAwait(false);
  202. }
  203. else
  204. {
  205. _logger.LogInformation($"没有符合条件的测试量数据,将进行标定值初始,只下发标定值,增量值为0;remarks恢复到未校准状态。");
  206. var statNow = DateTime.Now;
  207. await IotSetBloodPressCalibrationConfigResponseAsync(imei, 0, 0, 0, 0, 0, 0, 0, 0, statNow, statNow).ConfigureAwait(false);
  208. _logger.LogInformation($"1.没有符合条件的测试量数据,重置设备");
  209. var initRemarksFlag = await _serviceIotWebApi.UpdatePersonRemarksAsync(imei, 0, 0, 0, 0, true).ConfigureAwait(false);
  210. if (initRemarksFlag)
  211. {
  212. _logger.LogInformation($"2.没有符合条件的测试量数据,remarks恢复到未校准状态(remarks设置为空),成功");
  213. }
  214. else
  215. {
  216. _logger.LogInformation($"2.没有符合条件的测试量数据,remarks恢复到未校准状态(remarks设置为空),失败");
  217. }
  218. _logger.LogInformation($"3.没有符合条件的测试量数据,只下发手动标定值systolicRefValue:{systolicRefValue} -- diastolicRefValue:{diastolicRefValue},增量值为0");
  219. statNow = DateTime.Now.AddSeconds(3);
  220. return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, 0, 0, 0, 0, 0, 0, statNow, statNow).ConfigureAwait(false);
  221. }
  222. #endregion
  223. }
  224. catch
  225. ( Exception ex )
  226. {
  227. return ApiResponse<object>.Fail(500, $" 接口出错:{ex.Message}\n{ex.StackTrace}");
  228. }
  229. }
  230. private async Task<ApiResponse<object>> IotSetBloodPressCalibrationConfigResponseAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicInc, int diastolicInc)
  231. {
  232. BloodPressCalibrationConfigModel bpIncData = new()
  233. {
  234. Imei = imei,
  235. SystolicRefValue = systolicRefValue, //收缩压标定值,值为0 表示不生效
  236. DiastolicRefValue = diastolicRefValue, //舒张压标定值,值为0表示不生效
  237. SystolicIncValue = systolicInc, //收缩压显示增量,值为0 表示不生效
  238. DiastolicIncValue = diastolicInc //舒张压显示增量,值为0 表示不生效
  239. };
  240. // 下发 IOT 增量值
  241. var flagIot = await _serviceIotWebApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false);
  242. if (flagIot)
  243. {
  244. #region 保存下推记录 stb_hm_bp_push_ref_inc_value
  245. var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imei.Substring(imei.Length - 2)} " +
  246. $"USING health_monitor.stb_hm_bp_push_ref_inc_value " +
  247. $"TAGS ('{imei.Substring(imei.Length - 2)}') " +
  248. $"VALUES(" +
  249. $"'{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}'," +
  250. $"'{imei}'," +
  251. $"{systolicRefValue}," +
  252. $"{diastolicRefValue}," +
  253. $"{systolicInc}," +
  254. $"{diastolicInc}," +
  255. $"{true})";
  256. _serviceTDengine.ExecuteInsertSQL(sql);
  257. #endregion
  258. // 返回结果
  259. return ApiResponse<object>.Success(bpIncData);
  260. }
  261. else
  262. {
  263. return ApiResponse<object>.Fail(500, "业务出错!下发指令失败");
  264. }
  265. }
  266. private async Task<ApiResponse<object>> IotSetBloodPressCalibrationConfigResponseAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicInc, int diastolicInc,int systolicAvgValue,int diastolicAvgValue,decimal systolicAvgOffset, decimal diastolicAvgOffset, DateTime statStartTime,DateTime statEndTime)
  267. {
  268. BloodPressCalibrationConfigModel bpIncData = new()
  269. {
  270. Imei = imei,
  271. SystolicRefValue = systolicRefValue, //收缩压标定值,值为0 表示不生效
  272. DiastolicRefValue = diastolicRefValue, //舒张压标定值,值为0表示不生效
  273. SystolicIncValue = systolicInc, //收缩压显示增量,值为0 表示不生效
  274. DiastolicIncValue = diastolicInc //舒张压显示增量,值为0 表示不生效
  275. };
  276. // 下发 IOT 增量值
  277. var flagIot = await _serviceIotWebApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false);
  278. if (flagIot)
  279. {
  280. #region 保存下推记录 stb_hm_bp_push_ref_inc_value
  281. var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imei.Substring(imei.Length - 2)} " +
  282. $"USING health_monitor.stb_hm_bp_push_ref_inc_value " +
  283. $"TAGS ('{imei.Substring(imei.Length - 2)}') " +
  284. $"VALUES(" +
  285. $"'{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}'," +
  286. $"'{imei}'," +
  287. $"{systolicRefValue}," +
  288. $"{diastolicRefValue}," +
  289. $"{systolicInc}," +
  290. $"{diastolicInc}," +
  291. $"{true}," +
  292. $"{systolicAvgValue}," +
  293. $"{diastolicAvgValue}," +
  294. $"{systolicAvgOffset}," +
  295. $"{diastolicAvgOffset}," +
  296. $"'{statStartTime:yyyy-MM-dd HH:mm:ss.fff}'," +
  297. $"'{statEndTime:yyyy-MM-dd HH:mm:ss.fff}'" +
  298. $")";
  299. _serviceTDengine.ExecuteInsertSQL(sql);
  300. #endregion
  301. // 返回结果
  302. return ApiResponse<object>.Success(bpIncData);
  303. }
  304. else
  305. {
  306. return ApiResponse<object>.Fail(500, "业务出错!下发指令失败");
  307. }
  308. }
  309. }
  310. }