This commit is contained in:
2025-03-11 00:27:15 +08:00
parent 934a2ab4ef
commit 04263f304e
3 changed files with 252 additions and 112 deletions

View File

@@ -1,45 +1,106 @@
const app = getApp();
const math = require('../../utils/math.js');
// 添加正态分布相关的数学函数
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;
}
};
Page({
data: {
// 基础数据
age: '',
height: '',
gender: 'male',
// 计算结果
showResult: false,
sdsValue: null,
percentile: null,
calculationDetails: null,
growthEvaluation: '',
chartData: null
// 参考数据
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 }
]
}
},
// 输入年龄
// 输入处理
inputAge(e) {
this.setData({
age: Number(e.detail.value) // 确保age是数字
age: Number(e.detail.value)
});
},
// 输入身高
inputHeight(e) {
this.setData({
height: Number(e.detail.value) // 确保height是数字
height: Number(e.detail.value)
});
},
// 选择性别
selectGender(e) {
const gender = e.currentTarget.dataset.gender;
this.setData({ gender });
},
// 重置表单
reset() {
this.setData({
age: '',
height: '',
gender: 'male',
showResult: false
gender: e.currentTarget.dataset.gender
});
},
@@ -48,53 +109,45 @@ Page({
const { age, height, gender } = this.data;
// 输入验证
if (!age || !height) {
wx.showToast({
title: '请填写完整信息',
icon: 'none'
});
return;
}
if (!this.validateInput(age, height)) return;
// 直接使用本地生长数据
this.useLocalGrowthData();
},
// 处理生长数据
processGrowthData(growthData) {
try {
const { age, height, gender } = this.data;
// 获取标准数据
const standardData = this.getStandardData(age, gender);
if (!standardData) {
throw new Error('未找到对应年龄的标准数据');
}
// 计算SDS值并获取标准数据
const { sds, standard } = this.calculateSDS(height, age, gender, growthData);
console.log('SDS计算详情', {
height,
age,
gender,
mean: standard.mean,
sd: standard.sd,
sds
});
// 计算SDS
const sds = this.calculateSDS(
Number(height),
Number(standardData.mean),
Number(standardData.sd)
);
// 显示计算公式
console.log(`计算公式SDS = (${height} - ${standard.mean}) / ${standard.sd} = ${sds.toFixed(2)}`);
// 计算中间值,用于显示
const difference = Number(height) - Number(standardData.mean);
// 计算百分位数
const percentile = this.calculatePercentile(sds);
// 获取生长评价
// 获取评价
const evaluation = this.getGrowthEvaluation(sds);
// 更新结果
// 显示结果
this.setData({
showResult: true,
sdsValue: Number(sds.toFixed(2)), // 确保sdsValue是数字类型
percentile: percentile,
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)
},
growthEvaluation: evaluation
});
// 绘制生长曲线
this.drawGrowthChart(growthData);
} catch (error) {
wx.showToast({
title: error.message || '计算失败',
@@ -103,70 +156,118 @@ Page({
}
},
// 使用本地生长数据
useLocalGrowthData() {
try {
const localData = require('./growthData.js');
// 确保数据类型一致
const processedData = localData.map(item => ({
...item,
age: Number(item.age)
}));
this.processGrowthData(processedData);
} catch (error) {
// 输入验证
validateInput(age, height) {
if (!age || !height) {
wx.showToast({
title: '本地数据加载失败',
title: '请填写完整信息',
icon: 'none'
});
return false;
}
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);
},
// 计算SDS值
calculateSDS(height, age, gender, growthData) {
// 根据年龄和性别获取标准值
const standard = growthData.find(d =>
Number(d.age) === Number(age) &&
d.gender === gender
);
if (!standard) {
throw new Error('未找到对应年龄和性别的标准数据');
calculateSDS(height, mean, sd) {
// 输入验证
if (typeof height !== 'number' || typeof mean !== 'number' || typeof sd !== 'number') {
throw new Error('输入参数必须为数字');
}
// SDS = (实际值 - 平均) / 标准差
const sds = (height - standard.mean) / standard.sd;
return { sds, standard };
},
// SDS = (个体身高 - 平均身高) / 标准差
const sds = (height - mean) / sd;
// 计算百分位数
calculatePercentile(sds) {
// 使用标准正态分布计算百分位数
const percentile = 100 * (1 + math.erf(sds / Math.sqrt(2))) / 2;
return percentile.toFixed(1);
// 验证计算结果
if (isNaN(sds) || !isFinite(sds)) {
throw new Error('计算结果无效');
}
// 添加计算过程日志
console.log('SDS计算过程', {
个体身高: height.toFixed(1),
平均身高: mean.toFixed(1),
标准差: sd.toFixed(1),
计算公式: `(${height.toFixed(1)} - ${mean.toFixed(1)}) / ${sd.toFixed(1)}`,
计算结果: sds.toFixed(2)
});
return sds;
},
// 获取生长评价
getGrowthEvaluation(sds) {
// 根据标准更新评价标准
if (sds < -2) {
return '生长迟缓';
} else if (sds >= -2 && sds <= 2) {
return '正常范围';
return '可能存在生长迟缓';
} else if (sds > 2) {
return '可能存在生长过快';
} else {
return '生长过快';
return '正常范围';
}
},
// 绘制生长曲线
drawGrowthChart(growthData) {
const ctx = wx.createCanvasContext('growthChart');
// 绘制逻辑...
ctx.draw();
// 重置表单
reset() {
this.setData({
age: '',
height: '',
gender: 'male',
showResult: false,
sdsValue: null,
calculationDetails: null,
growthEvaluation: ''
});
},
// 返回
// 返回上一页
onClickLeft() {
wx.navigateBack();
},
// 修改计算百分位数的方法
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;
}
});

View File

@@ -61,21 +61,20 @@
<view class="result-container" wx:if="{{showResult}}">
<text class="result-title">计算结果</text>
<view class="result-item">
<text class="result-label">身高SDS值</text>
<text class="result-value {{sdsValue >= 0 ? 'green' : 'red'}}">
{{sdsValue.toFixed(2)}}
</text>
<!-- 计算过程 -->
<view class="calculation-process">
<text class="process-title">计算过程:</text>
<view class="process-steps">
<text>{{calculationDetails.formula}}</text>
<text>{{calculationDetails.calculation}}</text>
<text>{{calculationDetails.difference}}</text>
<text>{{calculationDetails.result}}</text>
</view>
</view>
<view class="result-item">
<text class="result-label">百分位数</text>
<text class="result-value">{{percentile}}%</text>
</view>
<view class="result-item">
<text class="result-label">生长评价</text>
<text class="result-value">{{growthEvaluation}}</text>
<!-- 结果解释 -->
<view class="result-interpretation">
<text class="interpretation-text">{{calculationDetails.interpretation}}</text>
</view>
<view class="tips">

View File

@@ -133,3 +133,43 @@
margin-top: 20rpx;
line-height: 1.6;
}
.calculation-process {
margin: 20rpx 0;
padding: 20rpx;
background-color: #f8f8f8;
border-radius: 10rpx;
}
.process-title {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
}
.process-steps {
display: flex;
flex-direction: column;
font-family: monospace;
font-size: 28rpx;
color: #666;
}
.process-steps text {
margin: 5rpx 0;
white-space: pre;
}
.result-interpretation {
margin: 20rpx 0;
padding: 20rpx;
background-color: #fff;
border-radius: 10rpx;
border: 1px solid #eee;
}
.interpretation-text {
font-size: 28rpx;
color: #333;
white-space: pre-line;
}