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
};
}
}