using Furion.DependencyInjection; using Mapster; using Nirvana.Common; using Nirvana.Common.ApiBase; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using YBDevice.Body.BodyFatHelper; using YBDevice.Body.Level; using YBDevice.CommonService; using YBDevice.CommonService.DevTypeInfo; using YBDevice.Entity; using YBDevice.NApi.Application.Prescription; namespace YBDevice.NApi.Application.UserInfo { /// /// 儿童信息处理 /// public class ChildService : BaseService, IChildService, ITransient { private readonly ISqlSugarRepository repository; private readonly SqlSugarClient dbClient; private readonly IFamilyService _familyService; private readonly IDeviceTypeService _deviceTypeService; private readonly IBodyFatHelperService _bodyFatHelperService; private readonly IPrescriptionService _prescriptionService; private readonly ILevelService _levelService; private readonly ILevelService _abLevelService; /// /// 构造 /// /// /// /// /// /// /// public ChildService(ISqlSugarRepository sqlSugarRepository, IFamilyService familyService, IBodyFatHelperService bodyFatHelperService, IDeviceTypeService deviceTypeService, IPrescriptionService prescriptionService, Func resolveNamed) { repository = sqlSugarRepository; dbClient = repository.Context; _familyService = familyService; _bodyFatHelperService = bodyFatHelperService; _deviceTypeService = deviceTypeService; _prescriptionService = prescriptionService; _levelService = resolveNamed("LevelService", default) as ILevelService; _abLevelService = resolveNamed("AbLevelService", default) as ILevelService; } /// /// 获取儿童信息 /// /// /// 设备类型 /// 小程序appid /// public async Task GetInfoAsync(int familyid, int devtype, string appid) { var data = new ChildInfoModel(); var family = await dbClient.Queryable().Where(x => x.Id == familyid).FirstAsync(); if (family == null) { return new ResultInfo(ResultState.FAIL, "家庭成员未找到"); } YB_FamilyData familydata = await dbClient.Queryable().Where(x => x.FamilyId == family.Id).FirstAsync(); YB_FamilyRealData familyrealdata = await dbClient.Queryable().Where(x => x.FamilyId == family.Id && x.DevType == devtype).FirstAsync(); decimal height = (familyrealdata != null && familyrealdata.LastHeight > 0) ? familyrealdata.LastHeight : family.Height; decimal weight = (familyrealdata != null && familyrealdata.LastWeight > 0) ? familyrealdata.LastWeight.ToDecimal(1) : 0; decimal head = (familyrealdata != null && familyrealdata.LastHead > 0) ? familyrealdata.LastHead.ToDecimal(1) : 0; int age = family.Birthday.ToAge(); int month = family.Birthday.ToMonth(); //如果有测量数据,以最后一次测量时间为准 if (familyrealdata != null && familyrealdata.LastResultTime.HasValue) { month = family.Birthday.ToMonth(familyrealdata.LastResultTime.Value); } data = new ChildInfoModel { Height = height, Head = head, DadHeight = familydata != null ? familydata.DadHeight : 0, Time = familyrealdata != null ? familyrealdata.LastResultTime.ToYearDateTimes() : "", Weight = weight, MomHeight = familydata != null ? familydata.MomHeight : 0, HalfYearHeight = familydata != null ? (height - familydata.HalfYearHeight) : 0, YearHeight = familydata != null ? (height - familydata.YearHeight) : 0, Name = family.Name, HeadImg = !string.IsNullOrEmpty(family.HeadImg) ? family.HeadImg : DefaultService.HeadImg(family.Sex, family.Type), Age = family.Birthday.TomAge(), Sex = family.Sex, Birthday = family.Birthday.ToString("yyyy-MM-dd"), Id = family.Id, LastHeightTime = familyrealdata != null ? familyrealdata.LastResultHeightTime.ToYearDate() : "", BMI = _bodyFatHelperService.CalcBMi(height, weight), Type = family.Type, ResultId = familyrealdata != null ? familyrealdata.LastResultId : null, ReferList = GetReferList(), DataReferList = GetDataReferList(family.Birthday) }; var standdata = await _levelService.LevelAsync(family.Sex, family.Birthday, data.BMI, LevelType.BMI); data.BMILevel = standdata.Level; data.BMILevelColor = standdata.Color; data.BMILevelList = standdata.list; //如果是安邦小程序则使用安邦标准 if (appid == ABConst.MiniAppId) { standdata = await _abLevelService.LevelAsync(family.Sex, family.Birthday, data.Height, LevelType.Height); data.HeightLevel = standdata.Level; data.HeightLevelColor = standdata.Color; data.HeightLevelList = standdata.list; data.PredictHeight = age <= 16 ? standdata.Media : data.Height; standdata = await _abLevelService.LevelAsync(family.Sex, family.Birthday, data.Weight, LevelType.Weight); data.WeightLevel = standdata.Level; data.WeightLevelColor = standdata.Color; data.WeightLevelList = standdata.list; data.StandWeight = age <= 16 ? standdata.Media : _bodyFatHelperService.CalcStandWeight(height, family.Sex); } else { standdata = await _levelService.LevelAsync(family.Sex, family.Birthday, data.Height, LevelType.Height); data.HeightLevel = standdata.Level; data.HeightLevelColor = standdata.Color; data.HeightLevelList = standdata.list; data.PredictHeight = age <= 16 ? standdata.Media : data.Height; standdata = await _levelService.LevelAsync(family.Sex, family.Birthday, data.Weight, LevelType.Weight); data.WeightLevel = standdata.Level; data.WeightLevelColor = standdata.Color; data.WeightLevelList = standdata.list; data.StandWeight = age <= 16 ? standdata.Media : _bodyFatHelperService.CalcStandWeight(height, family.Sex); } standdata = await _levelService.LevelAsync(family.Sex, family.Birthday, data.Head, LevelType.Head); data.HeadLevel = standdata.Level; data.HeadLevelColor = standdata.Color; data.HeadLevelList = standdata.list; data.IsHeight = data.PredictHeight > data.Height; data.AlertType = AletType(data.Height, data.PredictHeight); data.GeneticHeight = AdultHeight(data.DadHeight, data.MomHeight, family.Sex); if (appid == ABConst.MiniAppId) { data.cplist = await _prescriptionService.AB_Child(new ChildPrescriptionS2SDto { Age = month, BMILevel = data.BMILevel, HeightLevel = data.HeightLevel, WeightLevel = data.WeightLevel }); } else { data.cplist = await _prescriptionService.Child(new ChildPrescriptionS2SDto { Age = month, BMILevel = data.BMILevel, HeightLevel = data.HeightLevel, WeightLevel = data.WeightLevel }); } return new ResultInfo(ResultState.SUCCESS, "success", data); } /// /// 获取文献引用列表 /// /// private List GetReferList() { var list = new List { "[1]华东师范大学专业硕士学位论文——跳跃运动对小学生身高和体质健康影响的实验研究", "[2]李之俊.运动与脂肪动员研究进展[J].中国运动医学杂志,2012.01.(01):69-72", "[3]曾捷.跳跃运动队青少年根骨骨密度与体质影响的实验研究[D].硕士论文华东师范大学,2013.10:16-18.", "[4]牟其林.跳跃运动对贵州小学生骨密度、体质健康和体成分影响的实验研究[D].硕士论文.华东师范大学.2016.10.", "[5]张玲莉,闫晓,邹军.运动训练与骨生长代谢的研究进展[J].中国骨质疏松杂志,2013,19(7):761-765." }; return list; } /// /// 获取数据参考列表 /// /// 出生年月 /// private List GetDataReferList(DateTime birthday) { var list = new List { "《2005年九省/市儿童体格发育调查数据研究》中华儿科杂志,2009年7期" }; double month = birthday.ToDMonth(); if (month >= 5 * 12 * 1.0 && month <= 19 * 12 * 1.0) { list.Add("《WHO 5~19岁身高/体重判定标准》"); } return list; } /// /// 获取成长曲线 /// /// 家庭成员ID /// public async Task GetGrowthCurveAsync(ChildGrowthQueryModel model) { DateTime nowtime = DateTime.Now.Date; if (model.StartTime.HasValue) { DateTime time = model.StartTime.Value.Date; model.StartTime = time.AddDays(-time.Day).AddDays(1); } else { DateTime monthtime = nowtime.AddDays(-nowtime.Day).AddDays(1);//月初 model.StartTime = monthtime.AddYears(-2);//两年前 } model.EndTime = model.EndTime.Date; //如果时间段包含今天则加载今日数据 List devtypes = await _deviceTypeService.GetDevTypesAsync(model.DevType); List glist = new List(); if (nowtime >= model.StartTime && nowtime <= model.EndTime) { var familyrealdatalist = await dbClient.Queryable().Where(x => x.FamilyId == model.familyid && x.DevType == model.DevType).FirstAsync(); if (familyrealdatalist != null && (familyrealdatalist.MonthWeight > 0 || familyrealdatalist.MonthHeight > 0)) { glist.Add(new YB_FamilyReportData { Head = familyrealdatalist.MonthHead, Weight = familyrealdatalist.MonthWeight, Height = familyrealdatalist.MonthHeight, CreateTime = nowtime }); } } var query = await dbClient.Queryable().Where(x => x.FamilyId == model.familyid && x.CreateTime >= model.StartTime && x.CreateTime <= model.EndTime && devtypes.Contains(x.DevType)).OrderBy(x => x.CreateTime, OrderByType.Desc) .GroupBy(x => new { x.CreateTime }) .Select(x => new YB_FamilyReportData { CreateTime = x.CreateTime, Height = SqlFunc.AggregateMax(x.Height), Weight = SqlFunc.AggregateMax(x.Weight), Head = SqlFunc.AggregateMax(x.Head) }) .ToListAsync(); glist.AddRange(query); var list = glist.Adapt>(); return new ResultInfo(ResultState.SUCCESS, "success", list); } /// /// 获取身高/体重成长测评报告,与标准身高进行对比 /// /// /// 设备类型 /// public async Task GetHWListAsync(int familyid, int devtype) { var family = await dbClient.Queryable().FirstAsync(x => x.Id == familyid); if (family == null) { return new ResultInfo(ResultState.FAIL, "家庭成员未找到"); } //如果时间段包含今天则加载今日数据 List devtypes = await _deviceTypeService.GetDevTypesAsync(devtype); List glist = new List(); DateTime nowtime = DateTime.Now.Date; DateTime starttime = nowtime.AddDays(-nowtime.Day).AddDays(1);//月初 DateTime endtime = starttime.AddYears(-1); var familyrealdatalist = await dbClient.Queryable().Where(x => x.FamilyId == familyid && x.DevType == devtype).FirstAsync(); if (familyrealdatalist != null && (familyrealdatalist.MonthHeight > 0 || familyrealdatalist.MonthWeight > 0)) { glist.Add(new YB_FamilyReportData { Head = familyrealdatalist.MonthHead, Weight = familyrealdatalist.MonthWeight, Height = familyrealdatalist.MonthHeight, CreateTime = nowtime }); } var tempquery = dbClient.Queryable() .Where(x => x.FamilyId == familyid && x.CreateTime < starttime && x.CreateTime >= endtime && x.DevType == devtype); var query = await tempquery .OrderBy(x => x.CreateTime, OrderByType.Desc) .ToListAsync(); glist.AddRange(query); var hlist = new List(); var wlist = new List(); var headlist = new List(); //如果年龄过大,则标准体重使用算法 int age = family.Birthday.ToAge(); if (age > 16) { glist.ForEach(x => { hlist.Add(new ChildWHModel { Time = x.CreateTime.ToYearMonth(), Value = x.Height, StandValue = x.Height }); wlist.Add(new ChildWHModel { Time = x.CreateTime.ToYearMonth(), Value = x.Weight.ToDecimal(1), StandValue = _bodyFatHelperService.CalcStandWeight(x.Height, (GenderType)family.Sex) }); headlist.Add(new ChildWHModel { Time = x.CreateTime.ToYearMonth(), Value = x.Head.ToDecimal(1), StandValue = 0 }); }); } else { var sheightlist = await dbClient.Queryable().Where(x => x.Sex == family.Sex).OrderBy(x => x.Month, OrderByType.Asc).ToListAsync(); var sweightlist = await dbClient.Queryable().Where(x => x.Sex == family.Sex).OrderBy(x => x.Month, OrderByType.Asc).ToListAsync(); var sheadlist = await dbClient.Queryable().Where(x => x.Sex == family.Sex).OrderBy(x => x.Month, OrderByType.Asc).ToListAsync(); glist.ForEach(x => { int month = family.Birthday.ToMonth(x.CreateTime); var standheight = sheightlist.Where(x => x.Month >= month).FirstOrDefault(); var standweight = sweightlist.Where(x => x.Month >= month).FirstOrDefault(); var standhead = sheadlist.Where(x => x.Month >= month).FirstOrDefault(); hlist.Add(new ChildWHModel { Time = x.CreateTime.ToYearMonth(), Value = x.Height, StandValue = standheight != null ? standheight.median.ToDecimal(1) : 0 }); wlist.Add(new ChildWHModel { Time = x.CreateTime.ToYearMonth(), Value = x.Weight.ToDecimal(1), StandValue = standweight != null ? standweight.median.ToDecimal(1) : 0 }); headlist.Add(new ChildWHModel { Time = x.CreateTime.ToYearMonth(), Value = x.Head.ToDecimal(1), StandValue = standhead != null ? standhead.median.ToDecimal(1) : 0 }); }); } return new ResultInfo(ResultState.SUCCESS, "success", new { hlist = hlist, wlist = wlist, headlist = headlist }); } /// /// 计算遗传身高和成年身高 /// /// /// public async Task PredictHeightAsync(ChildPredictHeightModel model) { var standdata = new LevelS2SDto(); //遗传/标准身高 decimal geneticheight = 0; //成年身高预测 decimal adultheight = 0; //如果是安邦小程序则使用安邦标准 if (model.AppId == ABConst.MiniAppId) { standdata = await _abLevelService.LevelAsync(model.sex, model.Birthday, model.Height, LevelType.Height); geneticheight = standdata.Media; adultheight = AbAdultHeight(model.DadHeight, model.MomHeight, model.sex); } else { standdata = await _levelService.LevelAsync(model.sex, model.Birthday, model.Height, LevelType.Height); geneticheight = standdata.Media; adultheight = AdultHeight(model.DadHeight, model.MomHeight, model.sex); } if (model.familyid > 0) { await dbClient.Updateable().SetColumns(x => new YB_FamilyData { DadHeight = model.DadHeight, MomHeight = model.MomHeight }) .Where(x => x.FamilyId == model.familyid) .ExecuteCommandAsync(); } return new ResultInfo(ResultState.SUCCESS, "success", new ChildPredictHeightReturnModel { GeneticHeight = geneticheight, AdultHeight = adultheight, ErrorValue = model.sex == GenderType.Male ? 7.5m : 6m }); } /// /// 获取儿童增量信息 /// /// /// 设备类型 /// 小程序appid /// public async Task GetYearHeightInfoAsync(int familyid, int devtype, string appid) { var family = await dbClient.Queryable().FirstAsync(x => x.Id == familyid); if (family == null) { return new ResultInfo(ResultState.FAIL, "成员未找到"); } var familydata = await dbClient.Queryable().FirstAsync(x => x.FamilyId == familyid && x.DevType == devtype); int month = family.Birthday.ToMonth(); int age = family.Birthday.ToAge(); LevelS2SDto standdata = new LevelS2SDto(); decimal height = (familydata != null && familydata.LastHeight > 0) ? familydata.LastHeight : family.Height; //如果是安邦小程序则使用安邦标准 if (appid == ABConst.MiniAppId) { standdata = await _abLevelService.LevelAsync(family.Sex, family.Birthday, height, LevelType.Height); } else { standdata = await _levelService.LevelAsync(family.Sex, family.Birthday, height, LevelType.Height); } var returndata = new ChildYearHeightModel { f1sd = standdata.Data != null ? standdata.Data.f1sd : 0, f2sd = standdata.Data != null ? standdata.Data.f2sd : 0, f3sd = standdata.Data != null ? standdata.Data.f3sd : 0, z1sd = standdata.Data != null ? standdata.Data.z1sd : 0, z2sd = standdata.Data != null ? standdata.Data.z2sd : 0, z3sd = standdata.Data != null ? standdata.Data.z3sd : 0, Height = height, HalfYearHeight = familydata != null && familydata.HalfYearHeight > 0 ? familydata.LastHeight - familydata.HalfYearHeight : 0, //如果半年前身高为0则表示未测量过,则增量为0 median = standdata.Data != null ? standdata.Data.median : 0, HalfYearStandHeight = HalfYearStandHeight(age), YearHeight = familydata != null && familydata.YearHeight > 0 ? familydata.LastHeight - familydata.YearHeight : 0, YearStandHeight = YearStandHeight(age), HeightLevel = standdata != null ? standdata.HeightLevel : ChildHeightLevel.Error, list = standdata.list }; returndata.HalfYearHeightLevel = HalfYearHeightLevel(returndata.HalfYearHeight, returndata.HalfYearStandHeight); returndata.YearHeightLevel = YearHeightLevel(returndata.YearHeight, returndata.YearStandHeight); return new ResultInfo(ResultState.SUCCESS, "success", returndata); } /// /// 半年增量标准身高值 /// /// 年龄 /// private decimal HalfYearStandHeight(int age) => (age) switch { _ when age < 10 => 2.5m, _ => 3m }; /// /// 半年增量标准 /// /// 半年增量 /// 标准增量 /// private int HalfYearHeightLevel(decimal height, decimal standheight) => (height, standheight) switch { _ when height >= standheight => (int)ChildYearHeightLevel.Normal, _ => (int)ChildHeightLevel.Low }; /// /// 一年的身高增量标准值 /// /// /// private decimal YearStandHeight(int age) => (age) switch { _ when age < 10 => 5m, _ => 6m }; /// /// 一年增量标准 /// /// 一年增量 /// 标准增量 /// private int YearHeightLevel(decimal height, decimal standheight) => (height, standheight) switch { _ when height >= standheight => (int)ChildYearHeightLevel.Normal, _ => (int)ChildHeightLevel.Low }; /// /// 成年身高预测,女孩的靶身高=(父亲身高+母亲身高-13cm)÷2 /// 男孩的靶身高=(父亲身高+母亲身高+13cm)÷2 /// /// 父亲身高 /// 母亲身高 /// 性别,1-男,2-女,0-未知 /// private static decimal AdultHeight(decimal dadheight, decimal momheight, GenderType sex) => (dadheight, momheight, sex) switch { _ when dadheight <= 0 || momheight <= 0 => 0, _ when (sex == GenderType.FeMale) => (37.85m + 0.75m * (dadheight + momheight) / 2).ToDecimal(1), _ => (45.99m + 0.78m * (dadheight + momheight) / 2).ToDecimal(1) }; /// /// 安邦成年身高预测,男孩=(爸爸+妈妈+13)➗2,,最终结果±7.5 /// 女孩:(爸爸+妈妈-13)➗2,,最终结果±6 /// /// /// /// /// private static decimal AbAdultHeight(decimal dadheight, decimal momheight, GenderType sex) => (dadheight, momheight, sex) switch { _ when dadheight <= 0 || momheight <= 0 => 0, _ when (sex == GenderType.FeMale) => (dadheight + momheight - 13) / 2.ToDecimal(1), _ => (dadheight + momheight + 13) / 2.ToDecimal(1) }; /// /// 智能追踪分析,该分析是基于标准身高与实测身高的对比,对孩子是否因为后天因素有利于长高进行判断 /// /// 实测身高 /// 标准身高 /// private static int AletType(decimal height, decimal standheight) => (height, standheight) switch { _ when (standheight - height > 6) => (int)ChildAlertType.RedAlert, _ when (standheight - height <= 6 && standheight - height > 3) => (int)ChildAlertType.OrangeAlert, _ when (standheight - height <= 3 && standheight - height > 0) => (int)ChildAlertType.YellowAlert, _ when (standheight - height <= 0 && standheight - height >= -4) => (int)ChildAlertType.BlueReward, _ => (int)ChildAlertType.GreenAlert }; } }