@yolanda-qn/indicator-library
v0.2.0
Published
## 核心方法
Downloads
1
Readme
@yolanda-qn/indicator-library
核心方法
reportItemBuildFunction
构建单个指标的方法
注意这里目前仅支持
protein
(蛋白质)与water
(体水分)两个指标( 已能满足构建节段指标的需求,详见后面的完整业务代码示例
)
参数
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :------------ | :-------------------------------------------- | :--: | :----: | :---------------------- | | key | EightElectrodesIndex | Y | | 需要计算的八电极指标key | | measureDetail | SourceMeasureDetail | Y | | 原始测量数据 | | option | CalculateOptions | Y | | 计算时的目标转换单位 |
返回值
| 类型 | 说明 | | :------------------------ | :----------- | | ReportItem | 指标报告对象 |
示例
import { reportItemBuildFunction } from '@yolanda-qn/indicator-library'
// 目标单位
const targetWeightUnit: WeightUnit = 'lb'
// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
birthday: '2000-01-01',
gender: 1,
height: 170,
protein: 100,
water: 35,
weight: 68,
// ...
}
// 构建出的报告
const waterMassReport = reportItemBuildFunction('water', mockSourceMeasureDetail, { targetWeightUnit })
subBodyFatIndexCalculator
专门用于构建四肢与躯干体脂指标的函数
参数
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :----- | :---------------------------------------------------------------------------- | :--: | :----: | :------- | | params | subBodyFatIndexCalculatorParams(下方表格) | Y | | 参数对象 |
subBodyFatIndexCalculatorParams
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :------------ | :------------------------------------------ | :--: | :----: | :-------------- | | measureDetail | SourceMeasureDetail | Y | | 原始测量数据 | | subIndexType | BodyFatSubIndex | Y | | 次级体脂指标key |
返回值
| 类型 | 说明 | | :------------------------ | :----------- | | ReportItem | 指标报告对象 |
示例
import {subBodyFatIndexCalculator} from '@yolanda-qn/indicator-library'
// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
birthday: '2000-01-01',
gender: 1,
height: 170,
protein: 100,
water: 35,
weight: 68,
// ...
}
// 构建出的报告
const bodyFatLeftArmReport = subBodyFatIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'bodyFatLeftArm',
})
subSinewIndexCalculator
专门用于构建四肢与躯干肌肉指标的函数
参数
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :----- | :------------------------------------------------------------------------ | :--: | :----: | :------- | | params | subSinewIndexCalculatorParams(下方表格) | Y | | 参数对象 |
subSinewIndexCalculatorParams
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :--------------- | :------------------------------------------ | :--: | :----: | :-------------- | | measureDetail | SourceMeasureDetail | Y | | 原始测量数据 | | subIndexType | SinewSubIndex | Y | | 次级肌肉指标key | | targetWeightUnit | WeightUnit | Y | | 目标体重单位 |
返回值
| 类型 | 说明 | | :------------------------ | :----------- | | ReportItem | 指标报告对象 |
示例
import { subSinewIndexCalculator } from '@yolanda-qn/indicator-library'
// 目标单位
const targetWeightUnit: WeightUnit = 'lb'
// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
birthday: '2000-01-01',
gender: 1,
height: 170,
protein: 100,
water: 35,
weight: 68,
// ...
}
// 构建出的报告
const sinewLeftArmReport = subSinewIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'sinewLeftArm',
targetWeightUnit,
})
NP
一个在js中安全进行小数数学运行的库的导出 详见其官方文档
generateGenerateFormatValueObjectForWeightFn
在本库中承担重量单位转换的函数 采用了柯里化的编写方式 具体使用可以参见下面
完整业务代码示例
中的构建肌肉平衡
相关内容
参数
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :----- | :-------------------------------------------------------------------------------------------- | :--: | :----: | :------- | | params | WeightUnitTransformForSingleValueParams(下方表格) | Y | | 参数对象 |
WeightUnitTransformForSingleValueParams
| 名称 | 类型 | 必须 | 默认值 | 说明 | | :--------------- | :------------------------ | :--: | :----: | :----------- | | targetWeightUnit | WeightUnit | Y | | 目标体重单位 |
返回值
| 类型 | 说明 | | :------------------------------------------------------ | :----------------- | | WeightFormatValueObjectFn | 用于转换单位的函数 |
示例
// 目标单位
const targetWeightUnit: WeightUnit = 'lb'
const formatValueObjectFn = generateGenerateFormatValueObjectForWeightFn({
targetWeightUnit,
})
const result = formatValueObjectFn(100) // 将100kg转换为目标单位
完整业务代码示例
以使用本库导出的方法与接口组装出构建
肌肉平衡
与节段脂肪
方法为示例
import {
boundariesAverage,
calcValuesLevelProcess,
generateGenerateFormatValueObjectForWeightFn,
NP,
reportItemBuildFunction,
SourceMeasureDetail,
subBodyFatIndexCalculator,
subSinewIndexCalculator,
WeightUnit,
} from '@yolanda-qn/indicator-library'
// 目标单位
const targetWeightUnit: WeightUnit = 'lb'
// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
birthday: '2000-01-01',
gender: 1,
height: 170,
protein: 100,
water: 35,
weight: 68,
// ...
}
// 自行组装用于构建肌肉平衡的方法
export const muscleBalanceIndicatorBuildFunction = (measureDetail: Partial<SourceMeasureDetail>) => {
const sinewLeftArm = measureDetail?.muscle_lh ?? 0
const sinewLeftLeg = measureDetail?.muscle_lf ?? 0
const sinewRightArm = measureDetail?.muscle_rh ?? 0
const sinewRightLeg = measureDetail?.muscle_rf ?? 0
const sinewTrunk = measureDetail?.muscle_t ?? 0
const sinewLeftArmReport = subSinewIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'sinewLeftArm',
targetWeightUnit,
})
const sinewRightArmReport = subSinewIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'sinewRightArm',
targetWeightUnit,
})
const sinewLeftLegReport = subSinewIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'sinewLeftLeg',
targetWeightUnit,
})
const sinewRightLegReport = subSinewIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'sinewRightLeg',
targetWeightUnit,
})
const sinewTrunkReport = subSinewIndexCalculator({
measureDetail: mockSourceMeasureDetail,
subIndexType: 'sinewTrunk',
targetWeightUnit,
})
const proteinMassReport = reportItemBuildFunction('protein', mockSourceMeasureDetail, { targetWeightUnit })
const waterMassReport = reportItemBuildFunction('water', mockSourceMeasureDetail, { targetWeightUnit })
// 上肢均衡百分比差值
const sinewArmPercent = Math.abs(
NP.minus(sinewLeftArmReport.formatValueObject.calcValue, sinewRightArmReport.formatValueObject.calcValue),
)
// 下肢均衡百分比差值
const sinewLegPercent = Math.abs(
NP.minus(sinewLeftLegReport.formatValueObject.calcValue, sinewRightLegReport.formatValueObject.calcValue),
)
const boundaries = [6, 9]
// 计算差值的等级
const sinewArmValueClc = calcValuesLevelProcess(sinewArmPercent, boundaries)
const sinewLegValueClc = calcValuesLevelProcess(sinewLegPercent, boundaries)
// 上肢均衡百分比平均值
const sinewArmAverage = boundariesAverage([
sinewLeftArmReport.formatValueObject.calcValue,
sinewRightArmReport.formatValueObject.calcValue,
])
// 下肢均衡百分比平均值
const sinewLegAverage = boundariesAverage([
sinewLeftLegReport.formatValueObject.calcValue,
sinewRightLegReport.formatValueObject.calcValue,
])
// 计算平均值的等级
const sinewArmAverageValueClc = calcValuesLevelProcess(sinewArmAverage, sinewLeftArmReport.standardValueArray)
const sinewLegAverageValueClc = calcValuesLevelProcess(sinewLegAverage, sinewLeftLegReport.standardValueArray)
// 肌肉总量的标准为:蛋白质的标准 + 水分的标准
// 肌肉量范围最小值 = 水分范围最小值+蛋白质范围最小值
// 肌肉量范围最大值 = 水分范围最大值 + 蛋白质范围最大值
const bodyMuscleBoundaries = [
NP.plus(
proteinMassReport.criticalFormatValueObjectArray[0].sourceValue,
waterMassReport.criticalFormatValueObjectArray[0].sourceValue,
),
NP.plus(
proteinMassReport.criticalFormatValueObjectArray[1].sourceValue,
waterMassReport.criticalFormatValueObjectArray[1].sourceValue,
),
]
const bodyMuscleValeClc = calcValuesLevelProcess(measureDetail?.sinew ?? 0, bodyMuscleBoundaries)
// 生成格式化原始值的方法
const formatValueObjectFn = generateGenerateFormatValueObjectForWeightFn({
targetWeightUnit,
})
/**
* @note
* 下面的数据结构根据需求来组装 这里仅作参考
*/
return {
swipeItem1: {
leftArm: {
levelIndex: sinewLeftArmReport.level,
percent: {
value: sinewLeftArmReport.formatValueObject.renderStringArray[0],
unit: sinewLeftArmReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(sinewLeftArm).renderStringArray.join(''),
},
},
rightArm: {
levelIndex: sinewRightArmReport.level,
percent: {
value: sinewRightArmReport.formatValueObject.renderStringArray[0],
unit: sinewRightArmReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(sinewRightArm).renderStringArray.join(''),
},
},
leftLeg: {
levelIndex: sinewLeftLegReport.level,
percent: {
value: sinewLeftLegReport.formatValueObject.renderStringArray[0],
unit: sinewLeftLegReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(sinewLeftLeg).renderStringArray.join(''),
},
},
rightLeg: {
levelIndex: sinewRightLegReport.level,
percent: {
value: sinewRightLegReport.formatValueObject.renderStringArray[0],
unit: sinewRightLegReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(sinewRightLeg).renderStringArray.join(''),
},
},
trunk: {
levelIndex: sinewTrunkReport.level,
percent: {
value: sinewTrunkReport.formatValueObject.renderStringArray[0],
unit: sinewTrunkReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(sinewTrunk).renderStringArray.join(''),
},
},
},
swipeItem2: {
muscleBalance: [
{
level: sinewArmValueClc.level,
key: 'arm',
levelList: ['MuscleBalance.1101', 'MuscleBalance.1102', 'MuscleBalance.1103'],
},
{
level: sinewLegValueClc.level,
key: 'leg',
levelList: ['MuscleBalance.1101', 'MuscleBalance.1102', 'MuscleBalance.1103'],
},
{
level: sinewLegValueClc.level,
key: 'armLeg',
levelList: ['MuscleBalance.1101', 'MuscleBalance.1102', 'MuscleBalance.1103'],
},
],
bodyStrength: [
{
level: sinewArmAverageValueClc.level,
key: 'arm',
levelList: ['MuscleBalance.1104', 'MuscleBalance.1105', 'MuscleBalance.1106'],
},
{
level: sinewLegAverageValueClc.level,
key: 'leg',
levelList: ['MuscleBalance.1104', 'MuscleBalance.1105', 'MuscleBalance.1106'],
},
{
level: bodyMuscleValeClc.level,
key: 'muscle',
levelList: ['MuscleBalance.1104', 'MuscleBalance.1105', 'MuscleBalance.1106'],
},
],
},
}
}
// 自行组装用于构建节段脂肪的方法
export const segmentalFatAnalysisIndicatorBuildFunction = (measureDetail: SourceMeasureDetail) => {
const weight = measureDetail?.weight ?? 0
const bodyFatLeftArm = measureDetail?.fat_lh ?? 0
const bodyFatLeftLeg = measureDetail?.fat_lf ?? 0
const bodyFatRightArm = measureDetail?.fat_rh ?? 0
const bodyFatRightLeg = measureDetail?.fat_rf ?? 0
const bodyFatTrunk = measureDetail?.fat_t ?? 0
const bodyFatLeftArmReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatLeftArm' })
const bodyFatRightArmReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatRightArm' })
const bodyFatLeftLegReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatLeftLeg' })
const bodyFatRightLegReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatRightLeg' })
const bodyFatTrunkReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatTrunk' })
const formatValueObjectFn = generateGenerateFormatValueObjectForWeightFn({
targetWeightUnit,
})
/**
* @note
* 下面的数据结构根据需求来组装 这里仅作参考
*/
return {
segmentalFatAnalysis: {
leftArm: {
levelIndex: bodyFatLeftArmReport.level,
percent: {
value: bodyFatLeftArmReport.formatValueObject.renderStringArray[0],
unit: bodyFatLeftArmReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(NP.divide(NP.times(bodyFatLeftArm, weight), 100)).renderStringArray.join(''),
},
},
rightArm: {
levelIndex: bodyFatRightArmReport.level,
percent: {
value: bodyFatRightArmReport.formatValueObject.renderStringArray[0],
unit: bodyFatRightArmReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(NP.divide(NP.times(bodyFatRightArm, weight), 100)).renderStringArray.join(''),
},
},
leftLeg: {
levelIndex: bodyFatLeftLegReport.level,
percent: {
value: bodyFatLeftLegReport.formatValueObject.renderStringArray[0],
unit: bodyFatLeftLegReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(NP.divide(NP.times(bodyFatLeftLeg, weight), 100)).renderStringArray.join(''),
},
},
rightLeg: {
levelIndex: bodyFatRightLegReport.level,
percent: {
value: bodyFatRightLegReport.formatValueObject.renderStringArray[0],
unit: bodyFatRightLegReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(NP.divide(NP.times(bodyFatRightLeg, weight), 100)).renderStringArray.join(''),
},
},
trunk: {
levelIndex: bodyFatTrunkReport.level,
percent: {
value: bodyFatTrunkReport.formatValueObject.renderStringArray[0],
unit: bodyFatTrunkReport.formatValueObject.renderStringArray[1],
},
mass: {
value: formatValueObjectFn(NP.divide(NP.times(bodyFatTrunk, weight), 100)).renderStringArray.join(''),
},
},
},
}
}
类型声明
SourceMeasureDetail
原始测量数据定义接口
这里与小程序插件中
onGetScaleData
方法回调对象中response
字段的内容保持一致命名 因此直接将其用于后续方法的调用
interface SourceMeasureDetail {
/**
* 体重
*/
weight: number
/**
* 身高
*/
stature: number
/**
* 体脂率
*/
bodyfat: number
/**
* 皮下脂肪
*/
subfat: number
/**
* 内脏脂肪等级
*/
visfat: number
/**
* 体水分
*/
water: number
/**
* 基础代谢量
*/
bmr: number
/**
* 骨骼肌率
*/
muscle: number
/**
* 骨量(无机盐)
*/
bone: number
/**
* 去脂体重
*/
fat_free_weight: number
/**
* 蛋白质
*/
protein: number
/**
* 肌肉率
*/
sinew: number
/**
* 得分
*/
score: number
/**
* 体年龄
*/
bodyage: number
/**
* bmi
*/
bmi: number
/**
* 体型
*/
body_shape: number
/**
* 心脏指数
*/
cardiac_index: number
/**
* 心率
*/
heart_rate: number
/**
* 肌肉量 右手
*/
muscle_rh: number
/**
* 肌肉量 左手
*/
muscle_lh: number
/**
* 肌肉量 躯干
*/
muscle_t: number
/**
* 肌肉量 右腿
*/
muscle_rf: number
/**
* 肌肉量 左腿
*/
muscle_lf: number
/**
* 脂肪率 右手
*/
fat_rh: number
/**
* 脂肪率 左手
*/
fat_lh: number
/**
* 脂肪率 躯干
*/
fat_t: number
/**
* 脂肪率 右腿
*/
fat_rf: number
/**
* 脂肪率 左腿
*/
fat_lf: number
/**
* 测量时间
*/
time: Date
/**
* 性别
*/
gender: number
/**
* 身高
*/
height: number
/**
* 生日(YYYY-MM-DD)
*/
birthday: string
/**
* 年龄
*/
age: number
}
WeightUnit
体重单位类型
type WeightUnit = 'kg' | 'lb' | 'st' | 'st+lb'
HeightUnit
身高单位类型
type HeightUnit = 'cm' | 'inch' | 'ft+in'
CalculateOptions
interface CalculateOptions {
/**
* 目标体重单位(默认为kg 即不发生转换)
*/
targetWeightUnit?: WeightUnit
/**
* 目标身高单位(默认为cm 即不发生转换)
*/
targetHeightUnit?: HeightUnit
}
FormatValueObject
/**
* 🌟该对象的含义需要重点理解一下
* 该设计中是使用了一个对象去替代了一个数值 这样可以把`原始值` `转换后的用于计算的值` `转换后用于展示的值`集成在一个对象中
* 对于大多数单位来说`转换后的用于计算的值`与`转换后用于展示的值`是没有什么分别的
* 但对于一些特殊的单位 例如`st:lb`单位 它在展示时是`1st1lb`的形式 但参与计算时需要以`lb`的形式参与 故这里做了区分
*/
interface FormatValueObject<SourceUnit extends string = string, CalcUnit extends string = string> {
/**
* **未经任何处理**的原始值
*/
sourceValue: number
/**
* 原始值的单位
*/
sourceUnit: SourceUnit
/**
* 用于计算的值
*/
calcValue: number
/**
* 用于计算的值的单位
*/
calcUnit: CalcUnit
/**
* 用于渲染的数组
*/
renderStringArray: string[]
}
ReportItem
/**
* 最终返回的单个指标的报告格式
* @note 注意到下面会出现`次级`相关的内容 目前`构建节段指标`中不会涉及到可以直接忽略
*/
interface ReportItem<Key extends string = string> {
key: Key
/**
* 标准值对象
*/
standardValueFormatValueObject?: FormatValueObject
/**
* 边界值数组
*/
standardValueArray: number[]
/**
* 次级边界值数组
*/
subStandardValueArray?: number[]
/**
* 最值
*/
minValue: number
subMixValue?: number
maxValue: number
subMaxValue?: number
/**
* 等级数值
*/
level: number
/**
* 次级等级数值
*/
subLevel?: number
/**
* 等级偏移百分比
*/
relativeProportion: number
/**
* 次级等级偏移百分比
*/
subRelativeProportion?: number
/**
* 展示值对象
*/
formatValueObject: FormatValueObject
/**
* 边界对象数组(基于standardValueArray运算)
*/
criticalFormatValueObjectArray: FormatValueObject[]
/**
* 次级对象数组(基于subStandardValueArray运算)
*/
subCriticalFormatValueObjectArray?: FormatValueObject[]
/**
* 是否为多单位(例如: 1st1lb 与 1lb 分别被认为是多单位与单单位)
*/
isMultiUnit: boolean
}
EightElectrodesIndex
// 八电极指标 目前仅支持蛋白质与体水分
type EightElectrodesIndex = 'protein' | 'water'
BodyFatSubIndex
// 四肢与躯干体脂指标(左上 右上 躯干 左下 右下)
type BodyFatSubIndex = 'bodyFatLeftArm' | 'bodyFatRightArm' | 'bodyFatTrunk' | 'bodyFatLeftLeg' | 'bodyFatRightLeg'
SinewSubIndex
// 四肢与躯干肌肉指标(左上 右上 躯干 左下 右下)
type SinewSubIndex = 'sinewLeftArm' | 'sinewRightArm' | 'sinewTrunk' | 'sinewLeftLeg' | 'sinewRightLeg'
WeightFormatValueObjectFn
type WeightFormatValueObjectFn = (sourceValue: number) => FormatValueObject