From 3907e5aca91953e84837bec2439cb544e44bd051 Mon Sep 17 00:00:00 2001 From: H Vs Date: Sun, 25 Jun 2023 16:59:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=95=B0=E6=8D=AE=E8=AE=A2?= =?UTF-8?q?=E9=98=85=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HealthMonitor.Common/DateTimeUtil.cs | 710 ++++++++++++++++++ .../Dal/EfCoreImpl/EfCoreDataAccessor.cs | 11 + HealthMonitor.Core/Dal/IDataAccessor.cs | 2 + .../Biz/db/TDengineService.cs | 13 +- .../BloodPressReferenceValueCacheManager.cs | 43 +- .../Resolver/BloodpressResolver.cs | 37 + .../Resolver/Factory/ResolverFactory.cs | 24 + .../Resolver/Interface/IResolver.cs | 16 + .../Resolver/Interface/IResolverFactory.cs | 14 + .../Sub/TDengineDataSubcribe.cs | 259 ++++++- 10 files changed, 1100 insertions(+), 29 deletions(-) create mode 100644 HealthMonitor.Common/DateTimeUtil.cs create mode 100644 HealthMonitor.Service/Resolver/BloodpressResolver.cs create mode 100644 HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs create mode 100644 HealthMonitor.Service/Resolver/Interface/IResolver.cs create mode 100644 HealthMonitor.Service/Resolver/Interface/IResolverFactory.cs diff --git a/HealthMonitor.Common/DateTimeUtil.cs b/HealthMonitor.Common/DateTimeUtil.cs new file mode 100644 index 0000000..173e270 --- /dev/null +++ b/HealthMonitor.Common/DateTimeUtil.cs @@ -0,0 +1,710 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HealthMonitor.Common +{ + public class DateTimeUtil + { + + /// + /// 毫秒时间戳转本地时间 + /// + /// + /// + public static DateTime GetDateTimeFromUnixTimeMilliseconds(long milliseconds) + { + DateTimeOffset dt0 = DateTimeOffset.FromUnixTimeMilliseconds(milliseconds); + + //默认为UTC时间:{2019/11/14 1:53:26} + //DateTime dt1 = dt0.DateTime; + + //转为本地时区:{2019/11/14 9:53:26} + DateTime dt2 = dt0.LocalDateTime; + return dt2; + } + + /// + /// 判断给定的日期时间字符串是否符合相应的格式 + /// + /// 日期时间字符串 + /// 是否符合格式 + public static bool IsDateTime(string strDate) + { + if (strDate.Length != 19) + return false; + + try + { + DateTime dt = DateTime.Parse(strDate); + return true; + } + catch + { + return false; + } + } + + /// + /// 得到当前月的第一天 + /// + /// 当前月的第一天 + public static string ThisMonthFirstDate + { + get + { + DateTime dt = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); + return dt.ToString("yyyy-MM-dd HH:mm:ss"); + } + } + + /// + /// 得到当前月的最后一天 + /// + /// 当前月的最后一天 + public static string ThisMonthLastDate + { + get + { + DateTime dt = new DateTime(DateTime.Today.Year, DateTime.Today.Month + 1, 1); + dt = dt.AddDays(-1); + return dt.ToString("yyyy-MM-dd HH:mm:ss"); + } + } + + /// + /// 指定日期的该月第一天 + /// + /// 指定的日期 + /// 该月第一天 + public static string MonthFirstDate(string sThisDate) + { + int nYear = Year(sThisDate); + int nMonth = Month(sThisDate); + int nDay = 1; + + return EncodeDate(nYear, nMonth, nDay) + " 00:00:00"; + } + + /// + /// 指定日期的该月最后一天 + /// + /// 指定的日期 + /// 该月最后一天 + public static string MonthLastDate(string sThisDate) + { + int nYear = Year(sThisDate); + int nMonth = Month(sThisDate); + + nMonth++; + if (nMonth == 13) + { + nYear++; + nMonth = 1; + } + + DateTime dt = new DateTime(nYear, nMonth, 1); + dt = dt.AddDays(-1); + return dt.ToString("yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 转换字符串类型的时间至日期时间类型 + /// + /// 时间字符串 + /// 日期时间类型的值 + /// 如果格式不正确,则返回当前的时间 + public static DateTime ToDateTime(string strDateTime) + { + try + { + return DateTime.Parse(strDateTime); + } + catch + { + return DateTime.Now; + } + } + + /// + /// 转换时间类型的字符串至日期时间类型 + /// + /// 时间字符串 + /// 时间值 + /// 如果格式不正确,则返回的是"00:00:00"的时间值 + public static DateTime ToTime(string strTime) + { + try + { + return DateTime.Parse(strTime); + } + catch + { + return DateTime.Parse("00:00:00"); + } + } + + /// + /// 将时间值转换至时间字符串 + /// + /// 时间值 + /// 时间字符串 + public static string ToTimeStr(DateTime time) + { + return time.ToString("HH:mm:ss"); + } + + /// + /// 将对象转换为指定格式的字符串 + /// + /// 待转换的对象 + /// 指定的字符串格式 + /// 转换后的字符串 + /// 如果为空值,或非日期时间对象,则返回"" + public static string ToTimeStr(object time, string sFormat) + { + if (time == null || time == DBNull.Value) + return ""; + else + { + try + { + return ((DateTime)time).ToString(sFormat); + } + catch + { + return ""; + } + } + } + + /// + /// 将对象转换为字符串,格式为"HH:mm:ss" + /// + /// 待转换的对象 + /// 转换后的字符串 + public static string ToTimeStr(object time) + { + return ToTimeStr(time, "HH:mm:ss"); + } + + /// + /// 从秒数转换为时间字符串 + /// + /// 秒数 + /// 时间字符串 + public static string ToTimeStrFromSecond(int Second) + { + //=========== 1. 得到小时、分钟和秒数 =========== + string sTimeStr = ""; + + int NewSecond = 0; + int hour = Math.DivRem(Second, 3600, out NewSecond); //小时 + + Second = NewSecond; + NewSecond = 0; + int minute = Math.DivRem(Second, 60, out NewSecond); //分钟 + + //============ 2. 得到返回的字符串 ============ + if (hour < 10) + sTimeStr = sTimeStr + "0" + hour.ToString() + ":"; + else + sTimeStr = sTimeStr + hour.ToString() + ":"; + + if (minute < 10) + sTimeStr = sTimeStr + "0" + minute.ToString() + ":"; + else + sTimeStr = sTimeStr + minute.ToString() + ":"; + + if (NewSecond < 10) + sTimeStr = sTimeStr + "0" + NewSecond.ToString(); + else + sTimeStr = sTimeStr + NewSecond.ToString(); + + return sTimeStr; + } + + /// + /// 将时间字符串转换为秒数 + /// + /// 时间字符串 + /// 转换后的秒数 + public static int ToSecondsFromTimeStr(string timeStr) + { + DateTime dt = ToTime(timeStr); + return dt.Hour * 3600 + dt.Minute * 60 + dt.Second; + } + + /// + /// 将日期时间值转换为日期字符串 + /// + /// 日期时间值 + /// 日期字符串 + public static string ToDateStr(DateTime dt) + { + return dt.ToString("yyyy-MM-dd"); + } + + /// + /// 将对象转换为日期字符串 + /// + /// 对象 + /// 缺省字符串 + /// 转换后的字符串。如果为空值,则按缺省值返回 + public static string ToDateStr(object dt, string defaultStr) + { + if (dt == null || dt is System.DBNull) + return defaultStr; + else + return ((DateTime)dt).ToString("yyyy-MM-dd"); + } + + /// + /// 将对象转换为日期字符串 + /// + /// 对象 + /// 转换后的字符串。如果转换不成功,则返回"" + public static string ToDateStr(object dt) + { + return ToDateStr(dt, ""); + } + + /// + /// 将日期时间值转换为字符串 + /// + /// 日期时间值 + /// 字符串(len=19) + public static string ToDateTimeStr(DateTime dt) + { + return dt.ToString("yyyy-MM-dd HH:mm:ss"); + } + + public static string ToDateTimeStrWithMilliSeconds(DateTime dt) + { + int nMilliSeconds = dt.Millisecond; + return dt.ToString("yyyy-MM-dd HH:mm:ss") + "." + nMilliSeconds.ToString("000"); + } + + /// + /// 将对象转换为日期时间字符串 + /// + /// 对象 + /// 转换不成功时所取的缺省字符串 + /// 转换后的日期时间字符串(len=19) + public static string ToDateTimeStr(object dt, string defaultStr) + { + return ToDateTimeStr(dt, defaultStr, "yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 将对象转换为日期时间字符串 + /// + /// 对象 + /// 转换后的日期时间字符串(len=19) + /// 如果转换不成功,则返回"" + public static string ToDateTimeStr(object dt) + { + return ToDateTimeStr(dt, "", "yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 将对象转换为指定格式的日期时间字符串 + /// + /// 对象 + /// 缺省字符串 + /// 格式 + /// 转换后的字符串 + public static string ToDateTimeStr(object dt, string defaultStr, string sFormat) + { + if (dt == null || dt is System.DBNull) + return defaultStr; + else + return ((DateTime)dt).ToString(sFormat); + } + + + /// + /// 获取当前的时间 + /// + public static string Now + { + get + { + return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + } + } + + /// + /// 带毫秒部分的当前时间,示例为2003.07.22 10:02:52.136 + /// + public static string NowWithMilliSeconds + { + get + { + DateTime dtNow = DateTime.Now; + int nMilliSeconds = dtNow.Millisecond; + return dtNow.ToString("yyyy-MM-dd HH:mm:ss") + "." + nMilliSeconds.ToString("000"); + } + } + + /// + /// 获取当前的时间 + /// + public static string Today + { + get + { + return DateTime.Today.ToString("yyyy-MM-dd HH:mm:ss"); + } + } + + /// + /// 获取日期的年份 + /// + /// 日期时间串 + /// 年份 + public static int Year(string dtString) + { + int nYear; + + nYear = Convert.ToInt32(dtString.Substring(0, 4)); + + return nYear; + } + + /// + /// 获取日期的月份 + /// + /// 日期时间串 + /// 月份 + public static int Month(string dtString) + { + int nMonth; + + nMonth = Convert.ToInt32(dtString.Substring(5, 2)); + + return nMonth; + } + + /// + /// 获取日期中该月的第几天 + /// + /// 日期时间串 + /// 该月的第几天 + public static int Day(string dtString) + { + int nDay; + + nDay = Convert.ToInt32(dtString.Substring(8, 2)); + + return nDay; + } + + /// + /// 获取日期中的小时部分 + /// + /// 日期时间串 + /// 小时部分 + public static int Hour(string dtString) + { + int nHour; + + if (dtString.Length != 19 && dtString.Length != 23) + return 0; + + nHour = Convert.ToInt32(dtString.Substring(11, 2)); + + return nHour; + } + + /// + /// 获取日期中的分钟部分 + /// + /// 日期时间串 + /// 分钟部分 + public static int Minute(string dtString) + { + int nMinute; + + if (dtString.Length != 19 && dtString.Length != 23) + return 0; + + nMinute = Convert.ToInt32(dtString.Substring(14, 2)); + + return nMinute; + } + + /// + /// 获取日期中的秒部分 + /// + /// 日期时间串 + /// 秒部分 + public static int Second(string dtString) + { + int nSecond; + + if (dtString.Length != 19 && dtString.Length != 23) + return 0; + + nSecond = Convert.ToInt32(dtString.Substring(17, 2)); + + return nSecond; + } + + /// + /// 获取表示的日期是星期几 + /// + /// 日期时间串 + /// 星期几 + /// 返回值从0至6;星期日为0,星期六为6 + public static int DayOfWeek(string dtString) + { + DateTime dt = DateTime.Parse(dtString); + return (int)dt.DayOfWeek; + } + + /// + /// 获取表示的日期是一年中的第几天 + /// + /// 日期时间串 + /// 一年中的第几天 + public static int DayOfYear(string dtString) + { + DateTime dt = DateTime.Parse(dtString); + return dt.DayOfYear; + } + + /// + /// 将指定的月份数加到日期值上 + /// + /// 原来的日期 + /// 指定的月份数 + /// 得到的日期 + public static string AddMonths(string dtString, int nOffset) + { + DateTime dt = DateTime.Parse(dtString); + DateTime dtRes = dt.AddMonths(nOffset); + return dtRes.ToString("yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 将指定的天数加到日期值上 + /// + /// 原来的日期 + /// 指定的天数 + /// 得到的日期 + /// 天数可以为负数 + public static string AddDays(string dtString, int offset) + { + DateTime dt = DateTime.Parse(dtString); + DateTime dtRes = dt.AddDays(offset); + return dtRes.ToString("yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 将指定的秒数加到日期值上 + /// + /// 原来的日期时间 + /// 指定的秒数 + /// 得到的日期时间 + /// 秒数可以为负数 + public static string AddSeconds(string dtString, int offset) + { + DateTime dt = DateTime.Parse(dtString); + DateTime dtRes = dt.AddSeconds(offset); + return dtRes.ToString("yyyy-MM-dd HH:mm:ss"); + } + + public static string AddMilliSeconds(string dtString, int offset) + { + DateTime dt = DateTime.Parse(dtString); + DateTime dtRes = dt.AddMilliseconds(offset); + + int nMilliSeconds = dtRes.Millisecond; + return dtRes.ToString("yyyy-MM-dd HH:mm:ss") + "." + nMilliSeconds.ToString("000"); + } + + public static string AddMilliSeconds(string dtString, double offset) + { + DateTime dt = DateTime.Parse(dtString); + DateTime dtRes = dt.AddMilliseconds(offset); + + int nMilliSeconds = dtRes.Millisecond; + return dtRes.ToString("yyyy-MM-dd HH:mm:ss") + "." + nMilliSeconds.ToString("000"); + } + + /// + /// 得到两个日期时间之间相差的天数 + /// + /// 起始日期 + /// 终止日期 + /// 相差的天数 + /// + /// 不判断时间的情况。只判断日期是否切换,即使时间相差仅数分钟, + /// 只要切换了日期,也计算相差的天数。例如,2005-05-05 23:58:58和 + /// 2005-05-06 00:02:03之间所差的天数也是1。 + /// + public static int DaysAfter(string dtFromString, string dtToString) + { + DateTime dtFrom = DateTime.Parse(dtFromString).Date; + DateTime dtTo = DateTime.Parse(dtToString).Date; + TimeSpan timeSpan = dtTo - dtFrom; + return (int)timeSpan.TotalDays; + } + + /// + /// 得到两个日期时间之间相差的秒数 + /// + /// 起始日期时间 + /// 终止日期时间 + /// 相差的秒数 + public static int SecondsAfter(string dtFromString, string dtToString) + { + DateTime dtFrom = DateTime.Parse(dtFromString); + DateTime dtTo = DateTime.Parse(dtToString); + TimeSpan timeSpan = dtTo - dtFrom; + return (int)timeSpan.TotalSeconds; + } + + /// + /// 得到两个日期时间之间相差的毫秒数 + /// + /// 起始日期时间 + /// 终止日期时间 + /// 相差的毫秒数 + public static int MilliSecondsAfter(string dtFromString, string dtToString) + { + DateTime dtFrom = DateTime.Parse(dtFromString); + DateTime dtTo = DateTime.Parse(dtToString); + TimeSpan timeSpan = dtTo - dtFrom; + return (int)timeSpan.TotalMilliseconds; + } + + /// + /// 通过时、分、秒得到时间串 + /// + /// 小时 + /// 分钟 + /// 秒 + /// 时间部分 + public static string EncodeTime(int nHour, int nMinute, int nSecond) + { + string sResult = nHour.ToString("00") + ":" + nMinute.ToString("00") + + ":" + nSecond.ToString("00"); + return sResult; + } + + /// + /// 通过年、月、日得到日期部分 + /// + /// 年份 + /// 月份 + /// 日 + /// 日期部分 + public static string EncodeDate(int nYear, int nMonth, int nDay) + { + string sResult = nYear.ToString("0000") + "-" + nMonth.ToString("00") + + "-" + nDay.ToString("00"); + return sResult; + } + + /// + /// 得到日期部分 + /// + /// 日期时间 + /// 日期部分 + public static string GetDatePart(string sDatetime) + { + if (sDatetime.Length < 10) + return ""; + return sDatetime.Substring(0, 10); + } + + /// + /// 得到时间部分 + /// + /// 日期时间 + /// 时间部分 + public static string GetTimePart(string sDatetime) + { + if (sDatetime.Length == 19) + return sDatetime.Substring(11, 8); + else + return "00:00:00"; + } + + /// + /// 得到一天的起始时间 + /// + /// 日期 + /// 起始时间 + public static string BeginTimeOfDay(string sDate) + { + if (sDate.Length > 10) + sDate = sDate.Substring(0, 10); + return sDate + " 00:00:00"; + } + + /// + /// 得到一天的结束时间 + /// + /// 日期 + /// 结束时间 + public static string EndTimeOfDay(string sDate) + { + if (sDate.Length > 10) + sDate = sDate.Substring(0, 10); + return sDate + " 23:59:59.999"; + } + /// + /// 由19位的日期时间转到14位的日期时间 + /// + /// 19位的日期时间 + /// 14位的日期时间 + public static string ToDateTime14Str(string sDT) + { + if (sDT == "") + return ""; + + if (sDT.Length != 19) + throw new Exception("DateTimeUtil.ToDateTime14Str() error : 参数不是19位"); + + string sRet = sDT.Replace(":", "").Replace("-", "").Replace(" ", ""); + if (sRet.Length != 14) + throw new Exception("DateTimeUtil.ToDateTime14Str() error : 返回值不是14位"); + + return sRet; + } + + /// + /// 由14位的日期时间转到19位的日期时间 + /// + /// 14位的日期时间 + /// 19位的日期时间 + public static string FromDateTime14Str(string sDT14) + { + if (sDT14 == "") + return ""; + if (sDT14.Length != 14) + throw new Exception("DateTimeUtil.FromDateTime14Str() error : 参数不是14位"); + + string sRet = sDT14.Substring(0, 4) + "-" + sDT14.Substring(4, 2) + + "-" + sDT14.Substring(6, 2) + + " " + sDT14.Substring(8, 2) + ":" + sDT14.Substring(10, 2) + + ":" + sDT14.Substring(12, 2); + return sRet; + } + + ///// + ///// 是否为日期型字符串 + ///// + ///// 日期字符串(2008-05-08) + ///// + //public static bool IsDate(string StrSource) + //{ + // return Regex.IsMatch(StrSource, @"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-9]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$"); + //} + } +} diff --git a/HealthMonitor.Core/Dal/EfCoreImpl/EfCoreDataAccessor.cs b/HealthMonitor.Core/Dal/EfCoreImpl/EfCoreDataAccessor.cs index 9ff8363..c08dcff 100644 --- a/HealthMonitor.Core/Dal/EfCoreImpl/EfCoreDataAccessor.cs +++ b/HealthMonitor.Core/Dal/EfCoreImpl/EfCoreDataAccessor.cs @@ -72,6 +72,17 @@ namespace HealthMonitor.Core.Dal.EfCoreImpl return _context?.Set().AsNoTracking().FirstOrDefault(expression); } + public async Task GetFirstOrDefaultAsync(Expression> expression) where T : class + { + if (IsClose()) return default!; + + var entity = await _context!.Set().FirstOrDefaultAsync(expression); + //var entity = await _context.Set().FindAsync(values); + if (entity != null) _context.Entry(entity).State = EntityState.Detached; //取消实体跟踪 + + return entity!; + } + /// /// 根据主键值来查询某条记录,单主键的表可直接输入主键,多主键的表注意主键次序 /// diff --git a/HealthMonitor.Core/Dal/IDataAccessor.cs b/HealthMonitor.Core/Dal/IDataAccessor.cs index 89c094a..8b046a2 100644 --- a/HealthMonitor.Core/Dal/IDataAccessor.cs +++ b/HealthMonitor.Core/Dal/IDataAccessor.cs @@ -27,6 +27,8 @@ namespace HealthMonitor.Core.Dal /// T GetFirstOrDefault(Expression> expression) where T : class; + Task GetFirstOrDefaultAsync(Expression> expression) where T : class; + /// /// 根据主键值来查询某条记录,单主键的表可直接输入主键,多主键的表注意主键次序 /// diff --git a/HealthMonitor.Service/Biz/db/TDengineService.cs b/HealthMonitor.Service/Biz/db/TDengineService.cs index 6d767bc..e20e33d 100644 --- a/HealthMonitor.Service/Biz/db/TDengineService.cs +++ b/HealthMonitor.Service/Biz/db/TDengineService.cs @@ -196,18 +196,19 @@ namespace HealthMonitor.Service.Biz.db { var sql = $"SELECT MAX({field}), MIN({field}) FROM {_configTDengineService.DB}.{tbName} WHERE {condition}"; + var result = await GernalRestSqlResText(sql); var res = JsonConvert.DeserializeObject(result!); List data = res?.Data!; return new Aggregate { - Max = data[0][0], - Min = data[0][1], + Max = data.Count.Equals(0) ? 0 : data[0][0], + Min = data.Count.Equals(0) ? 0 : data[0][1], }; } - public async Task GetAvgExceptMaxMinValue(string field, string tbName, string? condition) + public async Task GetAvgExceptMaxMinValue(string field, string tbName, string? condition) { var sql = $"SELECT MAX({field}), MIN({field}) FROM {_configTDengineService.DB}.{tbName} WHERE {condition}"; @@ -216,12 +217,12 @@ namespace HealthMonitor.Service.Biz.db var res = JsonConvert.DeserializeObject(result!); List data = res?.Data!; - sql = $"SELECT AVG({field}) FROM {_configTDengineService.DB}.{tbName} WHERE {condition} AND {field} < { (data.Count.Equals(0)? 0: data[0][0]) } and {field} > {(data.Count.Equals(0) ? 0 : data[0][1])}"; - result = await GernalRestSqlResText(sql); + var sqlAvg = $"SELECT AVG({field}) FROM {_configTDengineService.DB}.{tbName} WHERE {condition} AND {field} < { (data.Count.Equals(0)? 0: data[0][0]) } and {field} > {(data.Count.Equals(0) ? 0 : data[0][1])}"; + result = await GernalRestSqlResText(sqlAvg); res = JsonConvert.DeserializeObject(result!); data = res?.Data!; - return data.Count.Equals(0)?0:data[0][0]; + return data.Count.Equals(0)?0:(int)data[0][0]; } diff --git a/HealthMonitor.Service/Cache/BloodPressReferenceValueCacheManager.cs b/HealthMonitor.Service/Cache/BloodPressReferenceValueCacheManager.cs index b64d7b8..4147eca 100644 --- a/HealthMonitor.Service/Cache/BloodPressReferenceValueCacheManager.cs +++ b/HealthMonitor.Service/Cache/BloodPressReferenceValueCacheManager.cs @@ -1,5 +1,8 @@ using HealthMonitor.Core.Dal; +using HealthMonitor.Core.Query; +using HealthMonitor.Core.Query.Extensions; using HealthMonitor.Util.Entities.HealthMonitor; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.Security.Cryptography; @@ -38,17 +41,39 @@ namespace HealthMonitor.Service.Cache var bpRef = await RedisHelper.GetAsync(cacheKey).ConfigureAwait(false); if (bpRef == null) { - bpRef = _dataAccessor - .GetFirstOrDefault( - i => - i.Age.Equals(age) && - i.Gender.Equals(gender) && - i.Hypertension.Equals(isHypertension) - ); - ; - await RedisHelper.SetAsync(cacheKey, JsonConvert.SerializeObject(bpRef)); + try + { + //bpRef = _dataAccessor + //.GetFirstOrDefault( + //i => + //i.Age.Equals(age) && + //i.Gender.Equals(gender) && + //i.Hypertension.Equals(isHypertension) + //); + bpRef = await _dataAccessor + .GetFirstOrDefaultAsync + ( + i => + i.Age.Equals(age) && + i.Gender.Equals(gender) && + i.Hypertension.Equals(isHypertension) + ); + await RedisHelper.SetAsync(cacheKey, JsonConvert.SerializeObject(bpRef)); + return bpRef; + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString() ); + return new HmBloodPressReferenceValue + { + Age = 0, + }; + } + } + return bpRef; + } diff --git a/HealthMonitor.Service/Resolver/BloodpressResolver.cs b/HealthMonitor.Service/Resolver/BloodpressResolver.cs new file mode 100644 index 0000000..3df1dbe --- /dev/null +++ b/HealthMonitor.Service/Resolver/BloodpressResolver.cs @@ -0,0 +1,37 @@ + +using HealthMonitor.Service.Resolver.Interface; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TDengineTMQ; + +namespace HealthMonitor.Service.Resolver +{ + + public class BloodpressResolver: IResolver + { + private readonly ILogger _logger; + public BloodpressResolver + ( + ILogger logger + ) + { + _logger = logger; + } + + public void SetResolveInfo(IConsumer msg) + { + throw new NotImplementedException(); + } + + public Task ExecuteMessageAsync() + { + throw new NotImplementedException(); + } + + + } +} diff --git a/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs b/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs new file mode 100644 index 0000000..2461b94 --- /dev/null +++ b/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs @@ -0,0 +1,24 @@ +using HealthMonitor.Service.Resolver.Interface; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TDengineTMQ; + +namespace HealthMonitor.Service.Resolver.Factory +{ + public class ResolverFactory : IResolverFactory + { + private readonly ILogger _logger; + public ResolverFactory(ILogger logger) + { + _logger = logger; + } + public void ParseAndWrap(IConsumer msg) + { + throw new NotImplementedException(); + } + } +} diff --git a/HealthMonitor.Service/Resolver/Interface/IResolver.cs b/HealthMonitor.Service/Resolver/Interface/IResolver.cs new file mode 100644 index 0000000..a494120 --- /dev/null +++ b/HealthMonitor.Service/Resolver/Interface/IResolver.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TDengineTMQ; + +namespace HealthMonitor.Service.Resolver.Interface +{ + public interface IResolver + { + void SetResolveInfo(IConsumer msg); + + Task ExecuteMessageAsync(); + } +} diff --git a/HealthMonitor.Service/Resolver/Interface/IResolverFactory.cs b/HealthMonitor.Service/Resolver/Interface/IResolverFactory.cs new file mode 100644 index 0000000..5a19a24 --- /dev/null +++ b/HealthMonitor.Service/Resolver/Interface/IResolverFactory.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TDengineTMQ; + +namespace HealthMonitor.Service.Resolver.Interface +{ + public interface IResolverFactory + { + void ParseAndWrap(IConsumer msg); + } +} diff --git a/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs b/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs index 8ca2903..3a1e21f 100644 --- a/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs +++ b/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs @@ -1,4 +1,8 @@ -using Microsoft.Extensions.Logging; +using HealthMonitor.Common; +using HealthMonitor.Core.Dal; +using HealthMonitor.Service.Biz.db; +using HealthMonitor.Service.Cache; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -6,6 +10,7 @@ using System.Text; using System.Threading.Tasks; using TDengineDriver; using TDengineTMQ; +using TelpoDataService.Util.Entities.GpsLocationHistory; namespace HealthMonitor.Service.Sub { @@ -14,11 +19,22 @@ namespace HealthMonitor.Service.Sub private readonly ILogger _logger; private IConsumer _consumer = default!; private IntPtr _conn = default!; + private readonly TDengineService _serviceTDengine; + private readonly PersonCacheManager _personCacheMgr; + private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager; + + private int cnt = 0; public TDengineDataSubcribe( + TDengineService serviceDengine, + PersonCacheManager personCacheMgr, + BloodPressReferenceValueCacheManager bpRefValCacheManager, ILogger logger ) { + _serviceTDengine = serviceDengine; + _personCacheMgr = personCacheMgr; + _bpRefValCacheManager = bpRefValCacheManager; _logger = logger; _conn = GetConnection(); } @@ -64,9 +80,9 @@ namespace HealthMonitor.Service.Sub TDConnectIp = "47.116.142.20", }; //IntPtr conn = GetConnection(); - string topic = "topic_name"; + string topic = "topic_hm_bp_stats"; //create topic - IntPtr res = TDengine.Query(_conn, $"create topic if not exists {topic} as select * from ctb1"); + IntPtr res = TDengine.Query(_conn, $"create topic if not exists {topic} as select * from health_monitor.hm_bloodpress"); if (TDengine.ErrorNo(res) != 0) { @@ -114,27 +130,242 @@ namespace HealthMonitor.Service.Sub // return consumer; //} - public void ProcessMsg() + //public void ProcessMsg() + //{ + // var consumerRes = _consumer.Consume(300); + // // process ConsumeResult + // foreach (KeyValuePair kv in consumerRes.Message) + // { + // Console.WriteLine("topic partitions:\n{0}", kv.Key.ToString()); + + // kv.Value.Metas.ForEach(meta => + // { + // Console.Write("{0} {1}({2}) \t|", meta.name, meta.TypeName(), meta.size); + // }); + // Console.WriteLine(""); + // kv.Value.Datas.ForEach(data => + // { + // Console.WriteLine(data.ToString()); + // }); + // } + + // _consumer.Commit(consumerRes); + // // Console.WriteLine("\n================ {0} done "); + //} + + + public async Task ProcessMsg() { var consumerRes = _consumer.Consume(300); + + Console.WriteLine(consumerRes.Message.Count); // process ConsumeResult foreach (KeyValuePair kv in consumerRes.Message) { - Console.WriteLine("topic partitions:\n{0}", kv.Key.ToString()); + //Console.WriteLine("topic partitions:\n{0}", kv.Key.ToString()); - kv.Value.Metas.ForEach(meta => - { - Console.Write("{0} {1}({2}) \t|", meta.name, meta.TypeName(), meta.size); - }); - Console.WriteLine(""); - kv.Value.Datas.ForEach(data => + //kv.Value.Metas.ForEach(meta => + //{ + // Console.Write("{0} {1}({2}) \t|", meta.name, meta.TypeName(), meta.size); + //}); + //Console.WriteLine("----------"); + //kv.Value.Datas.ForEach(data => + //{ + // Console.WriteLine(data.ToString()); + //}); + //Console.WriteLine("----------"); + for (int i = 0; i < kv.Value.Datas.Count; i++) { - Console.WriteLine(data.ToString()); - }); + // Console.Write($"|{kv.Value.Datas[i].ToString()} \t"); + //Console.WriteLine("{0},{1},{2}", i, resMeta.Count, (i) % resMeta.Count); + if (((i + 1) % kv.Value.Metas.Count == 0)) + { + + + try + { + cnt++; + string bloodpress_id = SafeType.SafeString(kv.Value.Datas[i - 8]); + string message_id = SafeType.SafeString(kv.Value.Datas[i - 7]); + string serialno = SafeType.SafeString(kv.Value.Datas[i - 6]); + int systolic_value = SafeType.SafeInt(kv.Value.Datas[i - 5]); + int diastolic_value = SafeType.SafeInt(kv.Value.Datas[i - 4]); + DateTime create_time = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(SafeType.SafeInt64(kv.Value.Datas[i - 3]) / 1000000); + DateTime last_update = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(SafeType.SafeInt64(kv.Value.Datas[i - 2]) / 1000000); + int method = SafeType.SafeInt(kv.Value.Datas[i - 1]); + bool is_display = SafeType.SafeBool(kv.Value.Datas[i]); + + + // Console.WriteLine("----------"); + HisGpsBloodPress bp = new() + { + //BloodPressId = (string)kv.Value.Datas[i -8], + //MessageId = (string)kv.Value.Datas[i -7], + //Serialno = (string)kv.Value.Datas[i -6], + //SystolicValue = (int)kv.Value.Datas[i -5], + //DiastolicValue = (int)kv.Value.Datas[i -4], + //CreateTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds((long)kv.Value.Datas[i -3]/1000000), + //LastUpdate = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds((long)kv.Value.Datas[i -2]/1000000), + //Method = (int)kv.Value.Datas[i -1], + //IsDisplay = (bool)kv.Value.Datas[i] ? 1 : 0, + + BloodPressId = bloodpress_id, + MessageId = message_id, + Serialno = serialno, + SystolicValue = systolic_value, + DiastolicValue = diastolic_value, + CreateTime = create_time, + LastUpdate = last_update, + Method = method, + IsDisplay = is_display ? 1 : 0, + }; + + + #region 获取个人信息 + + var person = await _personCacheMgr.GetDeviceGpsPersonCacheBySerialNoAsync(bp.MessageId, bp.Serialno).ConfigureAwait(false); + // 验证这个信息是否存在 + if (person == null || person?.Person.BornDate == null) + { + Console.WriteLine("验证这个信息是否存在"); + } + else + { + // 验证年龄是否在范围 (2 - 120) + + + var age = SafeType.SafeInt(DateTime.Today.Year - person?.Person.BornDate!.Value.Year!); + #endregion + if (age < 1 || age > 120) + { + Console.WriteLine("验证年龄是否在范围 (2 - 120)"); + } + else + { + 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!); + + + #region 插入当次BP数据 + // 保存到TDengine + + //var bpSql = $"INSERT INTO health_monitor.hm_bloodpress VALUES(" + + // $"'{bp.LastUpdate:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + // $"'{bp.BloodPressId}'," + + // $"'{bp.MessageId}'," + + // $"'{bp.Serialno}'," + + // $"{bp.SystolicValue}," + + // $"{bp.DiastolicValue}," + + // $"'{bp.CreateTime:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + // $"'{bp.LastUpdate:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + // $"{bp.Method}," + + // $"{bp.IsDisplay == 1})"; + + //await _serviceTDengine.GernalRestSql(bpSql); + + #endregion + + #region 计算增量值 + var bpRef = await _bpRefValCacheManager.GetBloodPressReferenceValueAsync(age, gender, isHypertension); + + var systolicRefValue = bpRef?.Systolic;//? + var diastolicRefValue = bpRef?.Diastolic;//? + int duration = 30; + // 获取历史数据 + //DateTime now = DateTime.Now; + DateTime now = (DateTime)bp.LastUpdate; //测试 + DateTime startTime = now.AddDays(-duration); + DateTime endTime = now; + + // + var systolicAggregate = await _serviceTDengine.GetAggregateValue("systolic_value", "hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{bp.Serialno}'"); + var diastolicAggregate = await _serviceTDengine.GetAggregateValue("diastolic_value", "hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{bp.Serialno}'"); + + // 最大值 + var systolicMax = systolicAggregate.Max; + var diastolicMax = diastolicAggregate.Max; + // 最小值 + var systolicMin = systolicAggregate.Min; + var diastolicMin = diastolicAggregate.Min; + + + // 计算去除最大值和最小值和异常值的平均值 + var systolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValue("systolic_value", "hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{bp.Serialno}' and systolic_value < {systolicRefValue} "); + var diastolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValue("diastolic_value", "hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{bp.Serialno}' and diastolic_value < {diastolicRefValue}"); + + // 偏移参数 + var avgOffset = 0.25M; + + var systolicAvgOffset = avgOffset; + var diastolicAvgOffset = avgOffset; + + + // 增量值=(标定值-平均值)* 0.25 + var systolicInc = systolicAvg.Equals(0M) ? 0 : (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!; + var diastolicInc = diastolicAvg.Equals(0M) ? 0 : (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; + + #endregion + + #region 插入BP增量值 + var sql = $"INSERT INTO health_monitor.hm_bloodpress_stats_inc VALUES(" + + $"'{bp.LastUpdate:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + $"'{bp.BloodPressId}'," + + $"'{bp.MessageId}'," + + $"'{bp.Serialno}'," + + $"{bp.SystolicValue}," + + $"{systolicRefValue}," + + $"{systolicAvg}," + + $"{systolicMax}," + + $"{systolicMin}," + + $"{systolicAvgOffset}," + + $"{systolicInc}," + + $"{bp.DiastolicValue}," + + $"{diastolicRefValue}," + + $"{diastolicAvg}," + + $"{diastolicMax}," + + $"{diastolicMin}," + + $"{diastolicAvgOffset}," + + $"{diastolicInc}," + + $"{gender}," + + $"{age}," + + $"{height}," + + $"{weight}," + + $"'{bp.LastUpdate:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + $"{duration}," + + $"'{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + $"'{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}'," + + $"'{string.Empty}')"; + var res = await _serviceTDengine.GernalRestSql(sql); + #endregion + + }; + // Console.WriteLine("----------"); + } + + + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + } + Console.WriteLine("++++++++++++++++++++++"); + + Console.Write($"总共增加{cnt}"); + } + + // Console.WriteLine(""); + + + + } _consumer.Commit(consumerRes); - Console.WriteLine("\n================ {0} done "); + // Console.WriteLine("\n================ {0} done "); } public IntPtr GetConnection()