515 lines
15 KiB
JavaScript
Executable File
515 lines
15 KiB
JavaScript
Executable File
// 身体健康分析 JavaScript 功能
|
|
|
|
// DOM 元素获取
|
|
const healthForm = document.getElementById('healthForm');
|
|
const analyzeBtn = document.getElementById('analyzeBtn');
|
|
const btnText = analyzeBtn.querySelector('.btn-text');
|
|
const loadingSpinner = analyzeBtn.querySelector('.loading-spinner');
|
|
const resultSection = document.getElementById('resultSection');
|
|
const errorSection = document.getElementById('errorSection');
|
|
const resetBtn = document.getElementById('resetBtn');
|
|
const retryBtn = document.getElementById('retryBtn');
|
|
|
|
// API 配置
|
|
const API_BASE_URL = 'https://60s.api.shumengya.top/v2/health';
|
|
|
|
// 表单验证规则
|
|
const validationRules = {
|
|
height: {
|
|
min: 100,
|
|
max: 250,
|
|
message: '身高应在100-250cm之间'
|
|
},
|
|
weight: {
|
|
min: 30,
|
|
max: 200,
|
|
message: '体重应在30-200kg之间'
|
|
},
|
|
age: {
|
|
min: 1,
|
|
max: 120,
|
|
message: '年龄应在1-120岁之间'
|
|
}
|
|
};
|
|
|
|
// 初始化
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeEventListeners();
|
|
setupFormValidation();
|
|
});
|
|
|
|
// 事件监听器初始化
|
|
function initializeEventListeners() {
|
|
healthForm.addEventListener('submit', handleFormSubmit);
|
|
resetBtn.addEventListener('click', resetForm);
|
|
retryBtn.addEventListener('click', retryAnalysis);
|
|
|
|
// 输入框实时验证
|
|
const inputs = healthForm.querySelectorAll('input, select');
|
|
inputs.forEach(input => {
|
|
input.addEventListener('blur', validateField);
|
|
input.addEventListener('input', clearFieldError);
|
|
});
|
|
}
|
|
|
|
// 表单验证设置
|
|
function setupFormValidation() {
|
|
const inputs = healthForm.querySelectorAll('input[type="number"]');
|
|
inputs.forEach(input => {
|
|
input.addEventListener('input', function() {
|
|
// 移除非数字字符
|
|
this.value = this.value.replace(/[^0-9.]/g, '');
|
|
|
|
// 防止多个小数点
|
|
const parts = this.value.split('.');
|
|
if (parts.length > 2) {
|
|
this.value = parts[0] + '.' + parts.slice(1).join('');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// 表单提交处理
|
|
async function handleFormSubmit(event) {
|
|
event.preventDefault();
|
|
|
|
if (!validateForm()) {
|
|
return;
|
|
}
|
|
|
|
const formData = getFormData();
|
|
|
|
try {
|
|
setLoadingState(true);
|
|
hideAllSections();
|
|
|
|
const result = await callHealthAPI(formData);
|
|
displayResults(result);
|
|
|
|
} catch (error) {
|
|
console.error('分析失败:', error);
|
|
displayError(error.message || '分析失败,请稍后重试');
|
|
} finally {
|
|
setLoadingState(false);
|
|
}
|
|
}
|
|
|
|
// 获取表单数据
|
|
function getFormData() {
|
|
return {
|
|
height: parseInt(document.getElementById('height').value),
|
|
weight: parseInt(document.getElementById('weight').value),
|
|
age: parseInt(document.getElementById('age').value),
|
|
gender: document.getElementById('gender').value
|
|
};
|
|
}
|
|
|
|
// 表单验证
|
|
function validateForm() {
|
|
let isValid = true;
|
|
const inputs = healthForm.querySelectorAll('input, select');
|
|
|
|
inputs.forEach(input => {
|
|
if (!validateField({ target: input })) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
return isValid;
|
|
}
|
|
|
|
// 单个字段验证
|
|
function validateField(event) {
|
|
const field = event.target;
|
|
const value = field.value.trim();
|
|
const fieldName = field.name;
|
|
|
|
// 清除之前的错误状态
|
|
clearFieldError(event);
|
|
|
|
// 必填验证
|
|
if (!value) {
|
|
showFieldError(field, '此字段为必填项');
|
|
return false;
|
|
}
|
|
|
|
// 数值范围验证
|
|
if (validationRules[fieldName]) {
|
|
const numValue = parseFloat(value);
|
|
const rule = validationRules[fieldName];
|
|
|
|
if (numValue < rule.min || numValue > rule.max) {
|
|
showFieldError(field, rule.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// 显示字段错误
|
|
function showFieldError(field, message) {
|
|
field.classList.add('error');
|
|
|
|
// 移除已存在的错误消息
|
|
const existingError = field.parentNode.querySelector('.error-message');
|
|
if (existingError) {
|
|
existingError.remove();
|
|
}
|
|
|
|
// 添加错误消息
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.className = 'error-message';
|
|
errorDiv.textContent = message;
|
|
errorDiv.style.color = '#dc3545';
|
|
errorDiv.style.fontSize = '0.875rem';
|
|
errorDiv.style.marginTop = '5px';
|
|
|
|
field.parentNode.appendChild(errorDiv);
|
|
}
|
|
|
|
// 清除字段错误
|
|
function clearFieldError(event) {
|
|
const field = event.target;
|
|
field.classList.remove('error');
|
|
|
|
const errorMessage = field.parentNode.querySelector('.error-message');
|
|
if (errorMessage) {
|
|
errorMessage.remove();
|
|
}
|
|
}
|
|
|
|
// 调用健康分析API
|
|
async function callHealthAPI(data) {
|
|
const params = new URLSearchParams({
|
|
height: data.height,
|
|
weight: data.weight,
|
|
age: data.age,
|
|
gender: data.gender
|
|
});
|
|
|
|
const response = await fetch(`${API_BASE_URL}?${params}`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.code !== 200) {
|
|
throw new Error(result.message || '分析失败');
|
|
}
|
|
|
|
return result.data;
|
|
}
|
|
|
|
// 显示分析结果
|
|
function displayResults(data) {
|
|
// 基本信息
|
|
displayBasicInfo(data.basic_info);
|
|
|
|
// BMI 分析
|
|
displayBMIInfo(data.bmi);
|
|
|
|
// 体重评估
|
|
displayWeightAssessment(data.weight_assessment);
|
|
|
|
// 代谢分析
|
|
displayMetabolism(data.metabolism);
|
|
|
|
// 体脂分析
|
|
displayBodyFat(data.body_fat);
|
|
|
|
// 理想三围
|
|
displayMeasurements(data.ideal_measurements);
|
|
|
|
// 健康建议
|
|
displayHealthAdvice(data.health_advice);
|
|
|
|
// 免责声明
|
|
displayDisclaimer(data.disclaimer);
|
|
|
|
// 显示结果区域
|
|
resultSection.style.display = 'block';
|
|
resultSection.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
// 显示基本信息
|
|
function displayBasicInfo(basicInfo) {
|
|
const container = document.getElementById('basicInfo');
|
|
container.innerHTML = '';
|
|
|
|
const infoItems = [
|
|
{ label: basicInfo.height_desc, value: basicInfo.height },
|
|
{ label: basicInfo.weight_desc, value: basicInfo.weight },
|
|
{ label: basicInfo.age_desc, value: basicInfo.age },
|
|
{ label: basicInfo.gender_desc, value: basicInfo.gender }
|
|
];
|
|
|
|
infoItems.forEach(item => {
|
|
const itemDiv = createInfoItem(item.label, item.value);
|
|
container.appendChild(itemDiv);
|
|
});
|
|
}
|
|
|
|
// 显示BMI信息
|
|
function displayBMIInfo(bmiData) {
|
|
const container = document.getElementById('bmiContent');
|
|
container.innerHTML = `
|
|
<div class="bmi-value">${bmiData.value}</div>
|
|
<div class="bmi-category">${bmiData.category}</div>
|
|
<div class="info-grid">
|
|
${createInfoItem(bmiData.evaluation_desc, bmiData.evaluation).outerHTML}
|
|
${createInfoItem(bmiData.risk_desc, bmiData.risk).outerHTML}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// 显示体重评估
|
|
function displayWeightAssessment(weightData) {
|
|
const container = document.getElementById('weightContent');
|
|
container.innerHTML = '';
|
|
|
|
const items = [
|
|
{ label: weightData.ideal_weight_range_desc, value: weightData.ideal_weight_range },
|
|
{ label: weightData.standard_weight_desc, value: weightData.standard_weight },
|
|
{ label: weightData.status_desc, value: weightData.status },
|
|
{ label: weightData.adjustment_desc, value: weightData.adjustment }
|
|
];
|
|
|
|
const grid = document.createElement('div');
|
|
grid.className = 'info-grid';
|
|
|
|
items.forEach(item => {
|
|
const itemDiv = createInfoItem(item.label, item.value);
|
|
grid.appendChild(itemDiv);
|
|
});
|
|
|
|
container.appendChild(grid);
|
|
}
|
|
|
|
// 显示代谢分析
|
|
function displayMetabolism(metabolismData) {
|
|
const container = document.getElementById('metabolismContent');
|
|
container.innerHTML = '';
|
|
|
|
const items = [
|
|
{ label: metabolismData.bmr_desc, value: metabolismData.bmr },
|
|
{ label: metabolismData.tdee_desc, value: metabolismData.tdee },
|
|
{ label: metabolismData.recommended_calories_desc, value: metabolismData.recommended_calories },
|
|
{ label: metabolismData.weight_loss_calories_desc, value: metabolismData.weight_loss_calories },
|
|
{ label: metabolismData.weight_gain_calories_desc, value: metabolismData.weight_gain_calories }
|
|
];
|
|
|
|
const grid = document.createElement('div');
|
|
grid.className = 'info-grid';
|
|
|
|
items.forEach(item => {
|
|
const itemDiv = createInfoItem(item.label, item.value);
|
|
grid.appendChild(itemDiv);
|
|
});
|
|
|
|
container.appendChild(grid);
|
|
}
|
|
|
|
// 显示体脂分析
|
|
function displayBodyFat(bodyFatData) {
|
|
const container = document.getElementById('bodyFatContent');
|
|
container.innerHTML = '';
|
|
|
|
const items = [
|
|
{ label: bodyFatData.percentage_desc, value: bodyFatData.percentage },
|
|
{ label: bodyFatData.category_desc, value: bodyFatData.category },
|
|
{ label: bodyFatData.fat_weight_desc, value: bodyFatData.fat_weight },
|
|
{ label: bodyFatData.lean_weight_desc, value: bodyFatData.lean_weight }
|
|
];
|
|
|
|
const grid = document.createElement('div');
|
|
grid.className = 'info-grid';
|
|
|
|
items.forEach(item => {
|
|
const itemDiv = createInfoItem(item.label, item.value);
|
|
grid.appendChild(itemDiv);
|
|
});
|
|
|
|
container.appendChild(grid);
|
|
}
|
|
|
|
// 显示理想三围
|
|
function displayMeasurements(measurementsData) {
|
|
const container = document.getElementById('measurementsContent');
|
|
container.innerHTML = '';
|
|
|
|
const items = [
|
|
{ label: measurementsData.chest_desc, value: measurementsData.chest },
|
|
{ label: measurementsData.waist_desc, value: measurementsData.waist },
|
|
{ label: measurementsData.hip_desc, value: measurementsData.hip }
|
|
];
|
|
|
|
const grid = document.createElement('div');
|
|
grid.className = 'info-grid';
|
|
|
|
items.forEach(item => {
|
|
const itemDiv = createInfoItem(item.label, item.value);
|
|
grid.appendChild(itemDiv);
|
|
});
|
|
|
|
// 添加说明
|
|
const note = document.createElement('p');
|
|
note.style.marginTop = '15px';
|
|
note.style.fontSize = '0.9rem';
|
|
note.style.color = '#4a7c59';
|
|
note.style.textAlign = 'center';
|
|
note.textContent = measurementsData.note;
|
|
|
|
container.appendChild(grid);
|
|
container.appendChild(note);
|
|
}
|
|
|
|
// 显示健康建议
|
|
function displayHealthAdvice(adviceData) {
|
|
const container = document.getElementById('adviceContent');
|
|
container.innerHTML = '';
|
|
|
|
// 饮水量建议
|
|
const waterDiv = createAdviceSection(adviceData.daily_water_intake_desc, adviceData.daily_water_intake);
|
|
container.appendChild(waterDiv);
|
|
|
|
// 运动建议
|
|
const exerciseDiv = createAdviceSection(adviceData.exercise_recommendation_desc, adviceData.exercise_recommendation);
|
|
container.appendChild(exerciseDiv);
|
|
|
|
// 营养建议
|
|
const nutritionDiv = createAdviceSection(adviceData.nutrition_advice_desc, adviceData.nutrition_advice);
|
|
container.appendChild(nutritionDiv);
|
|
|
|
// 健康提示
|
|
const tipsDiv = document.createElement('div');
|
|
tipsDiv.innerHTML = `
|
|
<h4 style="color: #2d5a3d; margin-bottom: 10px;">${adviceData.health_tips_desc}</h4>
|
|
<ul class="health-tips"></ul>
|
|
`;
|
|
|
|
const tipsList = tipsDiv.querySelector('.health-tips');
|
|
adviceData.health_tips.forEach(tip => {
|
|
const li = document.createElement('li');
|
|
li.textContent = tip;
|
|
tipsList.appendChild(li);
|
|
});
|
|
|
|
container.appendChild(tipsDiv);
|
|
}
|
|
|
|
// 创建建议区块
|
|
function createAdviceSection(title, content) {
|
|
const div = document.createElement('div');
|
|
div.style.marginBottom = '20px';
|
|
div.innerHTML = `
|
|
<h4 style="color: #2d5a3d; margin-bottom: 8px;">${title}</h4>
|
|
<p style="background: #f8fff8; padding: 12px; border-radius: 8px; border-left: 4px solid #4caf50; line-height: 1.6;">${content}</p>
|
|
`;
|
|
return div;
|
|
}
|
|
|
|
// 显示免责声明
|
|
function displayDisclaimer(disclaimer) {
|
|
const container = document.getElementById('disclaimer');
|
|
container.textContent = disclaimer;
|
|
}
|
|
|
|
// 创建信息项
|
|
function createInfoItem(label, value) {
|
|
const div = document.createElement('div');
|
|
div.className = 'info-item';
|
|
div.innerHTML = `
|
|
<div class="info-label">${label}</div>
|
|
<div class="info-value">${value}</div>
|
|
`;
|
|
return div;
|
|
}
|
|
|
|
// 显示错误信息
|
|
function displayError(message) {
|
|
const errorMessage = document.getElementById('errorMessage');
|
|
errorMessage.textContent = message;
|
|
errorSection.style.display = 'block';
|
|
errorSection.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
// 设置加载状态
|
|
function setLoadingState(isLoading) {
|
|
if (isLoading) {
|
|
analyzeBtn.disabled = true;
|
|
btnText.style.display = 'none';
|
|
loadingSpinner.style.display = 'block';
|
|
} else {
|
|
analyzeBtn.disabled = false;
|
|
btnText.style.display = 'block';
|
|
loadingSpinner.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// 隐藏所有结果区域
|
|
function hideAllSections() {
|
|
resultSection.style.display = 'none';
|
|
errorSection.style.display = 'none';
|
|
}
|
|
|
|
// 重置表单
|
|
function resetForm() {
|
|
healthForm.reset();
|
|
hideAllSections();
|
|
|
|
// 清除所有错误状态
|
|
const errorInputs = healthForm.querySelectorAll('.error');
|
|
errorInputs.forEach(input => {
|
|
input.classList.remove('error');
|
|
});
|
|
|
|
const errorMessages = healthForm.querySelectorAll('.error-message');
|
|
errorMessages.forEach(msg => msg.remove());
|
|
|
|
// 滚动到表单顶部
|
|
healthForm.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
// 重试分析
|
|
function retryAnalysis() {
|
|
hideAllSections();
|
|
healthForm.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
// 工具函数:防抖
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// 添加CSS样式到错误输入框
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
.form-input.error,
|
|
.form-select.error {
|
|
border-color: #dc3545 !important;
|
|
box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1) !important;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
|
|
// 页面可见性变化处理(用户切换标签页时暂停动画等)
|
|
document.addEventListener('visibilitychange', function() {
|
|
if (document.hidden) {
|
|
// 页面隐藏时的处理
|
|
document.body.style.animationPlayState = 'paused';
|
|
} else {
|
|
// 页面显示时的处理
|
|
document.body.style.animationPlayState = 'running';
|
|
}
|
|
}); |