t
This commit is contained in:
@@ -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;
|
||||
|
||||
try {
|
||||
// 获取标准数据
|
||||
const standardData = this.getStandardData(age, gender);
|
||||
if (!standardData) {
|
||||
throw new Error('未找到对应年龄的标准数据');
|
||||
}
|
||||
|
||||
// 直接使用本地生长数据
|
||||
this.useLocalGrowthData();
|
||||
},
|
||||
// 计算SDS
|
||||
const sds = this.calculateSDS(
|
||||
Number(height),
|
||||
Number(standardData.mean),
|
||||
Number(standardData.sd)
|
||||
);
|
||||
|
||||
// 处理生长数据
|
||||
processGrowthData(growthData) {
|
||||
try {
|
||||
const { age, height, gender } = this.data;
|
||||
// 计算中间值,用于显示
|
||||
const difference = Number(height) - Number(standardData.mean);
|
||||
|
||||
// 计算SDS值并获取标准数据
|
||||
const { sds, standard } = this.calculateSDS(height, age, gender, growthData);
|
||||
console.log('SDS计算详情:', {
|
||||
height,
|
||||
age,
|
||||
gender,
|
||||
mean: standard.mean,
|
||||
sd: standard.sd,
|
||||
sds
|
||||
});
|
||||
|
||||
// 显示计算公式
|
||||
console.log(`计算公式:SDS = (${height} - ${standard.mean}) / ${standard.sd} = ${sds.toFixed(2)}`);
|
||||
|
||||
// 计算百分位数
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user