2025-03-07 22:27:18 +08:00
|
|
|
|
const app = getApp();
|
2025-03-11 00:27:15 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加正态分布相关的数学函数
|
|
|
|
|
|
const normalDistribution = {
|
|
|
|
|
|
// 误差函数的近似计算
|
|
|
|
|
|
erf(x) {
|
|
|
|
|
|
// 误差函数的系数
|
|
|
|
|
|
const a1 = 0.254829592;
|
|
|
|
|
|
const a2 = -0.284496736;
|
|
|
|
|
|
const a3 = 1.421413741;
|
|
|
|
|
|
const a4 = -1.453152027;
|
|
|
|
|
|
const a5 = 1.061405429;
|
|
|
|
|
|
const p = 0.3275911;
|
|
|
|
|
|
|
|
|
|
|
|
// 取绝对值
|
|
|
|
|
|
const sign = (x >= 0) ? 1 : -1;
|
|
|
|
|
|
x = Math.abs(x);
|
|
|
|
|
|
|
|
|
|
|
|
// 误差函数近似公式的计算
|
|
|
|
|
|
const t = 1.0 / (1.0 + p * x);
|
|
|
|
|
|
const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
|
|
|
|
|
|
|
|
|
|
|
|
return sign * y;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 计算百分位数
|
|
|
|
|
|
calculatePercentile(sds) {
|
|
|
|
|
|
return (1 + this.erf(sds / Math.sqrt(2))) / 2 * 100;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-03-07 22:27:18 +08:00
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 基础数据
|
2025-03-07 22:27:18 +08:00
|
|
|
|
age: '',
|
|
|
|
|
|
height: '',
|
|
|
|
|
|
gender: 'male',
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 计算结果
|
2025-03-07 22:27:18 +08:00
|
|
|
|
showResult: false,
|
|
|
|
|
|
sdsValue: null,
|
2025-03-11 00:27:15 +08:00
|
|
|
|
calculationDetails: null,
|
2025-03-07 22:27:18 +08:00
|
|
|
|
growthEvaluation: '',
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 参考数据
|
|
|
|
|
|
standardData: {
|
|
|
|
|
|
male: [
|
|
|
|
|
|
{ age: 1, mean: 76.5, sd: 3.0 },
|
|
|
|
|
|
{ age: 2, mean: 88.5, sd: 3.5 },
|
|
|
|
|
|
{ age: 3, mean: 96.8, sd: 3.8 },
|
|
|
|
|
|
{ age: 4, mean: 103.5, sd: 4.2 },
|
|
|
|
|
|
{ age: 5, mean: 110.0, sd: 4.5 },
|
|
|
|
|
|
{ age: 6, mean: 116.5, sd: 4.8 },
|
|
|
|
|
|
{ age: 7, mean: 124.0, sd: 5.0 },
|
|
|
|
|
|
{ age: 8, mean: 129.5, sd: 5.2 },
|
|
|
|
|
|
{ age: 9, mean: 134.5, sd: 5.5 },
|
|
|
|
|
|
{ age: 10, mean: 138.5, sd: 5.8 },
|
|
|
|
|
|
{ age: 11, mean: 143.0, sd: 6.0 },
|
|
|
|
|
|
{ age: 12, mean: 150.0, sd: 6.5 },
|
|
|
|
|
|
{ age: 13, mean: 156.5, sd: 7.0 },
|
|
|
|
|
|
{ age: 14, mean: 163.0, sd: 7.2 },
|
|
|
|
|
|
{ age: 15, mean: 168.0, sd: 6.2 },
|
|
|
|
|
|
{ age: 16, mean: 171.5, sd: 5.8 },
|
|
|
|
|
|
{ age: 17, mean: 173.5, sd: 5.5 },
|
|
|
|
|
|
{ age: 18, mean: 174.5, sd: 5.2 }
|
|
|
|
|
|
],
|
|
|
|
|
|
female: [
|
|
|
|
|
|
{ age: 1, mean: 75.0, sd: 2.9 },
|
|
|
|
|
|
{ age: 2, mean: 87.2, sd: 3.4 },
|
|
|
|
|
|
{ age: 3, mean: 95.6, sd: 3.7 },
|
|
|
|
|
|
{ age: 4, mean: 102.5, sd: 4.0 },
|
|
|
|
|
|
{ age: 5, mean: 108.5, sd: 4.3 },
|
|
|
|
|
|
{ age: 6, mean: 115.0, sd: 4.6 },
|
|
|
|
|
|
{ age: 7, mean: 122.5, sd: 4.8 },
|
|
|
|
|
|
{ age: 8, mean: 127.5, sd: 5.0 },
|
|
|
|
|
|
{ age: 9, mean: 132.5, sd: 5.2 },
|
|
|
|
|
|
{ age: 10, mean: 137.0, sd: 5.5 },
|
|
|
|
|
|
{ age: 11, mean: 142.0, sd: 5.8 },
|
|
|
|
|
|
{ age: 12, mean: 148.0, sd: 6.0 },
|
|
|
|
|
|
{ age: 13, mean: 154.0, sd: 6.2 },
|
|
|
|
|
|
{ age: 14, mean: 158.5, sd: 5.8 },
|
|
|
|
|
|
{ age: 15, mean: 160.5, sd: 5.5 },
|
|
|
|
|
|
{ age: 16, mean: 161.5, sd: 5.2 },
|
|
|
|
|
|
{ age: 17, mean: 162.0, sd: 5.0 },
|
|
|
|
|
|
{ age: 18, mean: 162.5, sd: 4.8 }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2025-03-07 22:27:18 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 输入处理
|
2025-03-07 22:27:18 +08:00
|
|
|
|
inputAge(e) {
|
|
|
|
|
|
this.setData({
|
2025-03-11 00:27:15 +08:00
|
|
|
|
age: Number(e.detail.value)
|
2025-03-07 22:27:18 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
inputHeight(e) {
|
|
|
|
|
|
this.setData({
|
2025-03-11 00:27:15 +08:00
|
|
|
|
height: Number(e.detail.value)
|
2025-03-07 22:27:18 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
selectGender(e) {
|
|
|
|
|
|
this.setData({
|
2025-03-11 00:27:15 +08:00
|
|
|
|
gender: e.currentTarget.dataset.gender
|
2025-03-07 22:27:18 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 计算SDS
|
|
|
|
|
|
calculate() {
|
|
|
|
|
|
const { age, height, gender } = this.data;
|
|
|
|
|
|
|
|
|
|
|
|
// 输入验证
|
2025-03-11 00:27:15 +08:00
|
|
|
|
if (!this.validateInput(age, height)) return;
|
2025-03-07 22:27:18 +08:00
|
|
|
|
|
|
|
|
|
|
try {
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 获取标准数据
|
|
|
|
|
|
const standardData = this.getStandardData(age, gender);
|
|
|
|
|
|
if (!standardData) {
|
|
|
|
|
|
throw new Error('未找到对应年龄的标准数据');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算SDS
|
|
|
|
|
|
const sds = this.calculateSDS(
|
|
|
|
|
|
Number(height),
|
|
|
|
|
|
Number(standardData.mean),
|
|
|
|
|
|
Number(standardData.sd)
|
|
|
|
|
|
);
|
2025-03-07 22:27:18 +08:00
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 计算中间值,用于显示
|
|
|
|
|
|
const difference = Number(height) - Number(standardData.mean);
|
2025-03-07 22:27:18 +08:00
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 获取评价
|
2025-03-07 22:27:18 +08:00
|
|
|
|
const evaluation = this.getGrowthEvaluation(sds);
|
2025-03-11 00:27:15 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示结果
|
2025-03-07 22:27:18 +08:00
|
|
|
|
this.setData({
|
|
|
|
|
|
showResult: true,
|
2025-03-11 00:27:15 +08:00
|
|
|
|
sdsValue: Number(sds.toFixed(2)),
|
|
|
|
|
|
calculationDetails: {
|
|
|
|
|
|
height: Number(height).toFixed(1),
|
|
|
|
|
|
mean: Number(standardData.mean).toFixed(1),
|
|
|
|
|
|
sd: Number(standardData.sd).toFixed(1),
|
|
|
|
|
|
formula: `身高SDS = (${height} - ${standardData.mean}) / ${standardData.sd}`,
|
|
|
|
|
|
calculation: ` = (${height} - ${standardData.mean}) / ${standardData.sd}`,
|
|
|
|
|
|
difference: ` = ${difference.toFixed(1)} / ${standardData.sd}`,
|
|
|
|
|
|
result: ` = ${sds.toFixed(2)}`,
|
|
|
|
|
|
interpretation: this.getInterpretation(sds)
|
|
|
|
|
|
},
|
2025-03-07 22:27:18 +08:00
|
|
|
|
growthEvaluation: evaluation
|
|
|
|
|
|
});
|
2025-03-11 00:27:15 +08:00
|
|
|
|
|
2025-03-07 22:27:18 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
wx.showToast({
|
|
|
|
|
|
title: error.message || '计算失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 输入验证
|
|
|
|
|
|
validateInput(age, height) {
|
|
|
|
|
|
if (!age || !height) {
|
2025-03-07 22:27:18 +08:00
|
|
|
|
wx.showToast({
|
2025-03-11 00:27:15 +08:00
|
|
|
|
title: '请填写完整信息',
|
2025-03-07 22:27:18 +08:00
|
|
|
|
icon: 'none'
|
|
|
|
|
|
});
|
2025-03-11 00:27:15 +08:00
|
|
|
|
return false;
|
2025-03-07 22:27:18 +08:00
|
|
|
|
}
|
2025-03-11 00:27:15 +08:00
|
|
|
|
|
|
|
|
|
|
if (age < 1 || age > 18) {
|
|
|
|
|
|
wx.showToast({
|
|
|
|
|
|
title: '年龄必须在1-18岁之间',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
});
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (height <= 0) {
|
|
|
|
|
|
wx.showToast({
|
|
|
|
|
|
title: '身高必须大于0',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
});
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取标准数据
|
|
|
|
|
|
getStandardData(age, gender) {
|
|
|
|
|
|
return this.data.standardData[gender].find(item => item.age === age);
|
2025-03-07 22:27:18 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 计算SDS值
|
2025-03-11 00:27:15 +08:00
|
|
|
|
calculateSDS(height, mean, sd) {
|
|
|
|
|
|
// 输入验证
|
|
|
|
|
|
if (typeof height !== 'number' || typeof mean !== 'number' || typeof sd !== 'number') {
|
|
|
|
|
|
throw new Error('输入参数必须为数字');
|
2025-03-07 22:27:18 +08:00
|
|
|
|
}
|
2025-03-11 00:27:15 +08:00
|
|
|
|
|
|
|
|
|
|
// SDS = (个体身高 - 平均身高) / 标准差
|
|
|
|
|
|
const sds = (height - mean) / sd;
|
2025-03-07 22:27:18 +08:00
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 验证计算结果
|
|
|
|
|
|
if (isNaN(sds) || !isFinite(sds)) {
|
|
|
|
|
|
throw new Error('计算结果无效');
|
|
|
|
|
|
}
|
2025-03-07 22:27:18 +08:00
|
|
|
|
|
2026-01-06 15:59:20 +08:00
|
|
|
|
// 计算过程已隐藏
|
2025-03-11 00:27:15 +08:00
|
|
|
|
|
|
|
|
|
|
return sds;
|
2025-03-07 22:27:18 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取生长评价
|
|
|
|
|
|
getGrowthEvaluation(sds) {
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 根据标准更新评价标准
|
2025-03-07 22:27:18 +08:00
|
|
|
|
if (sds < -2) {
|
2025-03-11 00:27:15 +08:00
|
|
|
|
return '可能存在生长迟缓';
|
|
|
|
|
|
} else if (sds > 2) {
|
|
|
|
|
|
return '可能存在生长过快';
|
2025-03-07 22:27:18 +08:00
|
|
|
|
} else {
|
2025-03-11 00:27:15 +08:00
|
|
|
|
return '正常范围';
|
2025-03-07 22:27:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 重置表单
|
|
|
|
|
|
reset() {
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
age: '',
|
|
|
|
|
|
height: '',
|
|
|
|
|
|
gender: 'male',
|
|
|
|
|
|
showResult: false,
|
|
|
|
|
|
sdsValue: null,
|
|
|
|
|
|
calculationDetails: null,
|
|
|
|
|
|
growthEvaluation: ''
|
|
|
|
|
|
});
|
2025-03-07 22:27:18 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2025-03-11 00:27:15 +08:00
|
|
|
|
// 返回上一页
|
2025-03-07 22:27:18 +08:00
|
|
|
|
onClickLeft() {
|
|
|
|
|
|
wx.navigateBack();
|
2025-03-11 00:27:15 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 修改计算百分位数的方法
|
|
|
|
|
|
calculatePercentile(sds) {
|
|
|
|
|
|
const percentile = normalDistribution.calculatePercentile(sds);
|
|
|
|
|
|
return percentile.toFixed(1);
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取解释文本
|
|
|
|
|
|
getInterpretation(sds) {
|
|
|
|
|
|
const percentile = this.calculatePercentile(sds);
|
|
|
|
|
|
let interpretation = `身高SDS值:${sds.toFixed(2)}\n`;
|
|
|
|
|
|
interpretation += `该儿童身高位于同年龄同性别儿童的第${percentile}百分位\n`;
|
|
|
|
|
|
|
|
|
|
|
|
// 根据SDS值添加解释
|
|
|
|
|
|
if (sds === 0) {
|
|
|
|
|
|
interpretation += '身高等于平均值';
|
|
|
|
|
|
} else if (sds > 0) {
|
|
|
|
|
|
interpretation += `高于平均值${(Math.abs(sds) * 100).toFixed(1)}%`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
interpretation += `低于平均值${(Math.abs(sds) * 100).toFixed(1)}%`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return interpretation;
|
2025-03-07 22:27:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|