Spaces:
Sleeping
Sleeping
/** | |
* 统一评估系统 - 同时生成SarcoI和SarcoII建议 | |
*/ | |
let currentLanguage = 'zh'; | |
// DOM加载完成后初始化 | |
document.addEventListener('DOMContentLoaded', function() { | |
console.log('统一评估系统已加载'); | |
// 初始化语言 | |
initializeLanguage(); | |
// 初始化表单 | |
initializeForm(); | |
// 初始化自动计算 | |
initializeAutoCalculation(); | |
// 插入体力活动问卷 | |
insertPhysicalActivitySection(); | |
}); | |
/** | |
* 初始化语言功能 | |
*/ | |
function initializeLanguage() { | |
const savedLanguage = localStorage.getItem('language') || 'zh'; | |
currentLanguage = savedLanguage; | |
updateLanguageDisplay(); | |
} | |
function toggleLanguage() { | |
currentLanguage = currentLanguage === 'zh' ? 'en' : 'zh'; | |
localStorage.setItem('language', currentLanguage); | |
updateLanguageDisplay(); | |
} | |
function updateLanguageDisplay() { | |
const zhElements = document.querySelectorAll('.lang-zh'); | |
const enElements = document.querySelectorAll('.lang-en'); | |
const toggleText = document.getElementById('langToggleText'); | |
if (currentLanguage === 'zh') { | |
zhElements.forEach(el => el.style.display = ''); | |
enElements.forEach(el => el.style.display = 'none'); | |
if (toggleText) toggleText.textContent = 'English'; | |
} else { | |
zhElements.forEach(el => el.style.display = 'none'); | |
enElements.forEach(el => el.style.display = ''); | |
if (toggleText) toggleText.textContent = '中文'; | |
} | |
} | |
/** | |
* 初始化表单 | |
*/ | |
function initializeForm() { | |
const form = document.getElementById('unifiedForm'); | |
form.addEventListener('submit', handleSubmit); | |
// 添加输入验证 | |
const inputs = form.querySelectorAll('input[required], select[required]'); | |
inputs.forEach(input => { | |
input.addEventListener('input', updateSubmitButton); | |
}); | |
console.log('统一评估表单初始化完成'); | |
} | |
/** | |
* 初始化自动计算功能 | |
*/ | |
function initializeAutoCalculation() { | |
const heightInput = document.getElementById('height'); | |
const weightInput = document.getElementById('weight'); | |
const waistInput = document.getElementById('waist'); | |
function updateCalculations() { | |
const height = parseFloat(heightInput.value); | |
const weight = parseFloat(weightInput.value); | |
const waist = parseFloat(waistInput.value); | |
// 计算BMI | |
if (height && weight) { | |
const heightInMeters = height / 100; | |
const bmi = weight / (heightInMeters * heightInMeters); | |
document.getElementById('bmiDisplay').textContent = bmi.toFixed(1); | |
} else { | |
document.getElementById('bmiDisplay').textContent = '--'; | |
} | |
// 计算WWI | |
if (waist && weight) { | |
const wwi = waist / Math.sqrt(weight); | |
document.getElementById('wwiDisplay').textContent = wwi.toFixed(2); | |
} else { | |
document.getElementById('wwiDisplay').textContent = '--'; | |
} | |
} | |
heightInput.addEventListener('input', updateCalculations); | |
weightInput.addEventListener('input', updateCalculations); | |
waistInput.addEventListener('input', updateCalculations); | |
console.log('自动计算功能已初始化'); | |
} | |
/** | |
* 插入体力活动问卷部分 | |
*/ | |
function insertPhysicalActivitySection() { | |
const section = document.getElementById('physicalActivitySection'); | |
section.innerHTML = generatePhysicalActivityHTML(); | |
// 初始化活动详情切换 | |
initializeActivityToggles(); | |
} | |
/** | |
* 生成体力活动问卷HTML | |
*/ | |
function generatePhysicalActivityHTML() { | |
return ` | |
<div class="section-header mb-4"> | |
<h5 class="text-danger"> | |
<i class="fas fa-running me-2"></i> | |
<span class="lang-zh">NHANES 体力活动问卷</span> | |
<span class="lang-en">NHANES Physical Activity Questionnaire</span> | |
</h5> | |
<hr> | |
</div> | |
<!-- 工作相关活动 --> | |
<div class="mb-4"> | |
<h6 class="text-primary"> | |
<span class="lang-zh">工作相关体力活动</span> | |
<span class="lang-en">Work-related Physical Activity</span> | |
</h6> | |
<div class="mb-3"> | |
<label for="PAQ605" class="form-label"> | |
<span class="lang-zh">您的工作是否涉及高强度体力活动?</span> | |
<span class="lang-en">Does your work involve vigorous-intensity activity?</span> | |
<span class="text-danger">*</span> | |
</label> | |
<select class="form-select" id="PAQ605" name="PAQ605" required onchange="toggleActivityDetails('PAQ605', 'vigorous_work_details')"> | |
<option value="">请选择 / Please select</option> | |
<option value="1">是 / Yes</option> | |
<option value="2">否 / No</option> | |
</select> | |
<div class="form-text"> | |
<span class="lang-zh">如搬运重物、挖掘或建筑工作等,持续至少10分钟</span> | |
<span class="lang-en">Such as carrying heavy loads, digging, or construction work for at least 10 minutes</span> | |
</div> | |
</div> | |
<div id="vigorous_work_details"> | |
<div class="row mb-3"> | |
<div class="col-md-6"> | |
<label for="PAQ610" class="form-label"> | |
<span class="lang-zh">一周内有几天进行高强度工作活动?</span> | |
<span class="lang-en">How many days per week?</span> | |
</label> | |
<input type="number" class="form-control" id="PAQ610" name="PAQ610" min="0" max="7" step="1" value="0"> | |
</div> | |
<div class="col-md-6"> | |
<label for="PAD615" class="form-label"> | |
<span class="lang-zh">每次活动多长时间?(分钟)</span> | |
<span class="lang-en">Duration per day? (minutes)</span> | |
</label> | |
<input type="number" class="form-control" id="PAD615" name="PAD615" min="0" max="1440" step="1" value="0"> | |
</div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<label for="PAQ620" class="form-label"> | |
<span class="lang-zh">您的工作是否涉及中等强度体力活动?</span> | |
<span class="lang-en">Does your work involve moderate-intensity activity?</span> | |
<span class="text-danger">*</span> | |
</label> | |
<select class="form-select" id="PAQ620" name="PAQ620" required onchange="toggleActivityDetails('PAQ620', 'moderate_work_details')"> | |
<option value="">请选择 / Please select</option> | |
<option value="1">是 / Yes</option> | |
<option value="2">否 / No</option> | |
</select> | |
<div class="form-text"> | |
<span class="lang-zh">如快步走或搬运轻物等,持续至少10分钟</span> | |
<span class="lang-en">Such as brisk walking or carrying light loads for at least 10 minutes</span> | |
</div> | |
</div> | |
<div id="moderate_work_details"> | |
<div class="row mb-3"> | |
<div class="col-md-6"> | |
<label for="PAQ625" class="form-label"> | |
<span class="lang-zh">一周内有几天进行中等强度工作活动?</span> | |
<span class="lang-en">How many days per week?</span> | |
</label> | |
<input type="number" class="form-control" id="PAQ625" name="PAQ625" min="0" max="7" step="1" value="0"> | |
</div> | |
<div class="col-md-6"> | |
<label for="PAD630" class="form-label"> | |
<span class="lang-zh">每次活动多长时间?(分钟)</span> | |
<span class="lang-en">Duration per day? (minutes)</span> | |
</label> | |
<input type="number" class="form-control" id="PAD630" name="PAD630" min="0" max="1440" step="1" value="0"> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 交通相关活动 --> | |
<div class="mb-4"> | |
<h6 class="text-primary"> | |
<span class="lang-zh">交通相关活动</span> | |
<span class="lang-en">Transportation Activity</span> | |
</h6> | |
<div class="mb-3"> | |
<label for="PAQ635" class="form-label"> | |
<span class="lang-zh">您是否步行或骑自行车出行?</span> | |
<span class="lang-en">Do you walk or bicycle for transportation?</span> | |
<span class="text-danger">*</span> | |
</label> | |
<select class="form-select" id="PAQ635" name="PAQ635" required onchange="toggleActivityDetails('PAQ635', 'transport_details')"> | |
<option value="">请选择 / Please select</option> | |
<option value="1">是 / Yes</option> | |
<option value="2">否 / No</option> | |
</select> | |
<div class="form-text"> | |
<span class="lang-zh">如上学、购物、上班等出行方式,持续至少10分钟</span> | |
<span class="lang-en">Such as to school, shopping, work, etc. for at least 10 minutes</span> | |
</div> | |
</div> | |
<div id="transport_details"> | |
<div class="row mb-3"> | |
<div class="col-md-6"> | |
<label for="PAQ640" class="form-label"> | |
<span class="lang-zh">一周内有几天步行或骑车出行?</span> | |
<span class="lang-en">How many days per week?</span> | |
</label> | |
<input type="number" class="form-control" id="PAQ640" name="PAQ640" min="0" max="7" step="1" value="0"> | |
</div> | |
<div class="col-md-6"> | |
<label for="PAD645" class="form-label"> | |
<span class="lang-zh">每次出行多长时间?(分钟)</span> | |
<span class="lang-en">Duration per day? (minutes)</span> | |
</label> | |
<input type="number" class="form-control" id="PAD645" name="PAD645" min="0" max="1440" step="1" value="0"> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 休闲运动活动 --> | |
<div class="mb-4"> | |
<h6 class="text-primary"> | |
<span class="lang-zh">休闲运动活动</span> | |
<span class="lang-en">Recreational Physical Activity</span> | |
</h6> | |
<div class="mb-3"> | |
<label for="PAQ650" class="form-label"> | |
<span class="lang-zh">您是否参与高强度休闲运动?</span> | |
<span class="lang-en">Do you do vigorous-intensity sports or activities?</span> | |
<span class="text-danger">*</span> | |
</label> | |
<select class="form-select" id="PAQ650" name="PAQ650" required onchange="toggleActivityDetails('PAQ650', 'vigorous_rec_details')"> | |
<option value="">请选择 / Please select</option> | |
<option value="1">是 / Yes</option> | |
<option value="2">否 / No</option> | |
</select> | |
<div class="form-text"> | |
<span class="lang-zh">如跑步、篮球等引起大量喘息或心率增加的运动,持续至少10分钟</span> | |
<span class="lang-en">Such as running, basketball that cause large increases in breathing or heart rate for at least 10 minutes</span> | |
</div> | |
</div> | |
<div id="vigorous_rec_details"> | |
<div class="row mb-3"> | |
<div class="col-md-6"> | |
<label for="PAQ655" class="form-label"> | |
<span class="lang-zh">一周内有几天进行高强度休闲运动?</span> | |
<span class="lang-en">How many days per week?</span> | |
</label> | |
<input type="number" class="form-control" id="PAQ655" name="PAQ655" min="0" max="7" step="1" value="0"> | |
</div> | |
<div class="col-md-6"> | |
<label for="PAD660" class="form-label"> | |
<span class="lang-zh">每次运动多长时间?(分钟)</span> | |
<span class="lang-en">Duration per day? (minutes)</span> | |
</label> | |
<input type="number" class="form-control" id="PAD660" name="PAD660" min="0" max="1440" step="1" value="0"> | |
</div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<label for="PAQ665" class="form-label"> | |
<span class="lang-zh">您是否参与中等强度休闲运动?</span> | |
<span class="lang-en">Do you do moderate-intensity sports or activities?</span> | |
<span class="text-danger">*</span> | |
</label> | |
<select class="form-select" id="PAQ665" name="PAQ665" required onchange="toggleActivityDetails('PAQ665', 'moderate_rec_details')"> | |
<option value="">请选择 / Please select</option> | |
<option value="1">是 / Yes</option> | |
<option value="2">否 / No</option> | |
</select> | |
<div class="form-text"> | |
<span class="lang-zh">如快步走、骑车、游泳或排球等,持续至少10分钟</span> | |
<span class="lang-en">Such as brisk walking, bicycling, swimming, or volleyball for at least 10 minutes</span> | |
</div> | |
</div> | |
<div id="moderate_rec_details"> | |
<div class="row mb-3"> | |
<div class="col-md-6"> | |
<label for="PAQ670" class="form-label"> | |
<span class="lang-zh">一周内有几天进行中等强度休闲运动?</span> | |
<span class="lang-en">How many days per week?</span> | |
</label> | |
<input type="number" class="form-control" id="PAQ670" name="PAQ670" min="0" max="7" step="1" value="0"> | |
</div> | |
<div class="col-md-6"> | |
<label for="PAD675" class="form-label"> | |
<span class="lang-zh">每次运动多长时间?(分钟)</span> | |
<span class="lang-en">Duration per day? (minutes)</span> | |
</label> | |
<input type="number" class="form-control" id="PAD675" name="PAD675" min="0" max="1440" step="1" value="0"> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 久坐行为 --> | |
<div class="section-header mb-4"> | |
<h5 class="text-danger"> | |
<i class="fas fa-chair me-2"></i> | |
<span class="lang-zh">久坐行为</span> | |
<span class="lang-en">Sedentary Behavior</span> | |
</h5> | |
<hr> | |
</div> | |
<div class="mb-4"> | |
<label for="PAD680" class="form-label"> | |
<span class="lang-zh">您每天通常坐着多长时间?(分钟)</span> | |
<span class="lang-en">How much time do you usually spend sitting on a typical day? (minutes)</span> | |
<span class="text-danger">*</span> | |
</label> | |
<input type="number" class="form-control" id="PAD680" name="PAD680" min="0" max="1440" step="1" required value="480"> | |
<div class="form-text"> | |
<span class="lang-zh">包括在学校、家中、通勤、与朋友相处时的坐着时间,如办公、乘车、读书、看电视、使用电脑等(不包括睡觉时间)</span> | |
<span class="lang-en">Include time spent at school, home, commuting, and with friends. Include time spent sitting at a desk, traveling in a car or bus, reading, playing cards, watching television, or using a computer. Do not include time spent sleeping.</span> | |
</div> | |
</div> | |
`; | |
} | |
/** | |
* 初始化活动详情切换功能 | |
*/ | |
function initializeActivityToggles() { | |
// 为所有活动选择添加事件监听器 | |
const activitySelects = ['PAQ605', 'PAQ620', 'PAQ635', 'PAQ650', 'PAQ665']; | |
activitySelects.forEach(selectId => { | |
const select = document.getElementById(selectId); | |
if (select) { | |
select.addEventListener('change', function() { | |
const detailsMap = { | |
'PAQ605': 'vigorous_work_details', | |
'PAQ620': 'moderate_work_details', | |
'PAQ635': 'transport_details', | |
'PAQ650': 'vigorous_rec_details', | |
'PAQ665': 'moderate_rec_details' | |
}; | |
toggleActivityDetails(selectId, detailsMap[selectId]); | |
}); | |
} | |
}); | |
} | |
/** | |
* 切换活动详细信息显示/隐藏 | |
*/ | |
function toggleActivityDetails(selectId, detailsId) { | |
const select = document.getElementById(selectId); | |
const details = document.getElementById(detailsId); | |
if (select && details) { | |
if (select.value === '1') { | |
details.style.display = 'block'; | |
} else { | |
details.style.display = 'none'; | |
// 清除详细信息输入 | |
details.querySelectorAll('input').forEach(input => input.value = '0'); | |
} | |
} | |
} | |
/** | |
* 处理表单提交 | |
*/ | |
async function handleSubmit(event) { | |
event.preventDefault(); | |
console.log('开始统一评估...'); | |
// 收集表单数据 | |
const formData = collectFormData(); | |
// 显示加载状态 | |
showLoading(); | |
try { | |
// 添加语言参数 | |
formData.language = currentLanguage; | |
// 调用完整评估API | |
const result = await performAssessment(formData); | |
// 显示结果 | |
displayResults(result); | |
} catch (error) { | |
console.error('评估失败:', error); | |
hideLoading(); | |
showAlert('评估过程中出现错误:' + error.message, 'danger'); | |
} | |
} | |
/** | |
* 收集表单数据 | |
*/ | |
function collectFormData() { | |
const form = document.getElementById('unifiedForm'); | |
const formData = new FormData(form); | |
const data = {}; | |
// 收集所有表单数据 | |
for (let [key, value] of formData.entries()) { | |
if (value !== '' && value !== null && value !== undefined) { | |
// 转换数字类型 | |
if (['number'].includes(form.querySelector(`[name="${key}"]`).type)) { | |
data[key] = parseFloat(value); | |
} else { | |
data[key] = parseInt(value); | |
} | |
} | |
} | |
// 计算BMI和WWI | |
const height = data.height; | |
const weight = data.weight; | |
const waist = data.waist; | |
if (height && weight) { | |
const heightInMeters = height / 100; | |
data.body_mass_index = parseFloat((weight / (heightInMeters * heightInMeters)).toFixed(1)); | |
} | |
if (waist && weight) { | |
data.WWI = parseFloat((waist / Math.sqrt(weight)).toFixed(2)); | |
} | |
// 设置sedentary_minutes等同于PAD680 | |
data.sedentary_minutes = data.PAD680 || 480; | |
// 计算衍生特征 | |
const derivedFeatures = calculateDerivedFeatures(data); | |
const finalData = { ...data, ...derivedFeatures }; | |
console.log('收集的完整数据:', finalData); | |
return finalData; | |
} | |
/** | |
* 根据NHANES PAQ数据计算衍生特征 | |
*/ | |
function calculateDerivedFeatures(data) { | |
const derived = {}; | |
// 计算各类活动的MET-分钟 | |
const vigorousWorkMETs = 8.0 * (data.PAD615 || 0) * (data.PAQ610 || 0); | |
const moderateWorkMETs = 4.0 * (data.PAD630 || 0) * (data.PAQ625 || 0); | |
const transportationMETs = 4.0 * (data.PAD645 || 0) * (data.PAQ640 || 0); | |
const vigorousRecMETs = 8.0 * (data.PAD660 || 0) * (data.PAQ655 || 0); | |
const moderateRecMETs = 4.0 * (data.PAD675 || 0) * (data.PAQ670 || 0); | |
const totalMETMinutesWeek = vigorousWorkMETs + moderateWorkMETs + transportationMETs + vigorousRecMETs + moderateRecMETs; | |
// 计算活动分钟数 | |
const vigorousWorkMins = (data.PAD615 || 0) * (data.PAQ610 || 0); | |
const vigorousRecMins = (data.PAD660 || 0) * (data.PAQ655 || 0); | |
const totalVigorousMinutesWeek = vigorousWorkMins + vigorousRecMins; | |
const moderateWorkMins = (data.PAD630 || 0) * (data.PAQ625 || 0); | |
const transportationMins = (data.PAD645 || 0) * (data.PAQ640 || 0); | |
const moderateRecMins = (data.PAD675 || 0) * (data.PAQ670 || 0); | |
const totalModerateMinutesWeek = moderateWorkMins + transportationMins + moderateRecMins; | |
// 计算活动多样性指数 | |
let activityDiversityIndex = 0; | |
if ((data.PAQ605 || 0) == 1) activityDiversityIndex++; | |
if ((data.PAQ620 || 0) == 1) activityDiversityIndex++; | |
if ((data.PAQ635 || 0) == 1) activityDiversityIndex++; | |
if ((data.PAQ650 || 0) == 1) activityDiversityIndex++; | |
if ((data.PAQ665 || 0) == 1) activityDiversityIndex++; | |
// 计算比例特征 | |
const vigorousMETTotal = vigorousWorkMETs + vigorousRecMETs; | |
const vigorousMETRatio = totalMETMinutesWeek > 0 ? vigorousMETTotal / totalMETMinutesWeek : 0; | |
const totalActiveMinutesWeek = totalVigorousMinutesWeek + totalModerateMinutesWeek; | |
const totalSedentaryMinutesWeek = (data.PAD680 || 480) * 7; | |
const activitySedentaryRatio = totalSedentaryMinutesWeek > 0 ? totalActiveMinutesWeek / totalSedentaryMinutesWeek : 0; | |
// 设置衍生特征 | |
derived.Total_MET_minutes_week = parseFloat(totalMETMinutesWeek.toFixed(2)); | |
derived.Total_Vigorous_Minutes_week = parseFloat(totalVigorousMinutesWeek.toFixed(2)); | |
derived.Total_Moderate_Minutes_week = parseFloat(totalModerateMinutesWeek.toFixed(2)); | |
derived.Activity_Diversity_Index = activityDiversityIndex; | |
derived.Vigorous_MET_Ratio = parseFloat(vigorousMETRatio.toFixed(3)); | |
derived.Activity_Sedentary_Ratio = parseFloat(activitySedentaryRatio.toFixed(3)); | |
return derived; | |
} | |
/** | |
* 执行评估 | |
*/ | |
async function performAssessment(userData) { | |
console.log('调用完整评估API...'); | |
const controller = new AbortController(); | |
const timeoutId = setTimeout(() => { | |
controller.abort(); | |
}, 180000); // 3分钟超时 | |
try { | |
const response = await fetch('/api/full_assessment', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(userData), | |
signal: controller.signal | |
}); | |
clearTimeout(timeoutId); | |
if (!response.ok) { | |
let errorMessage = `HTTP ${response.status}: `; | |
try { | |
const errorData = await response.json(); | |
errorMessage += errorData.detail || JSON.stringify(errorData); | |
} catch { | |
errorMessage += response.statusText || '服务器错误'; | |
} | |
throw new Error(errorMessage); | |
} | |
const result = await response.json(); | |
console.log('评估结果:', result); | |
return result; | |
} catch (error) { | |
clearTimeout(timeoutId); | |
if (error.name === 'AbortError') { | |
throw new Error('评估超时,请稍后重试'); | |
} | |
throw error; | |
} | |
} | |
/** | |
* 显示加载状态 | |
*/ | |
function showLoading() { | |
document.getElementById('assessmentSection').style.display = 'none'; | |
document.getElementById('loadingSection').style.display = 'block'; | |
// 启动进度条动画 | |
startProgressAnimation(); | |
document.getElementById('loadingSection').scrollIntoView({ | |
behavior: 'smooth' | |
}); | |
} | |
/** | |
* 隐藏加载状态 | |
*/ | |
function hideLoading() { | |
document.getElementById('loadingSection').style.display = 'none'; | |
// 清除进度条动画 | |
if (window.progressInterval) { | |
clearInterval(window.progressInterval); | |
window.progressInterval = null; | |
} | |
} | |
/** | |
* 启动进度条动画 | |
*/ | |
function startProgressAnimation() { | |
let progress = 30; | |
const progressBar = document.getElementById('progressBar'); | |
const statusText = document.getElementById('statusText'); | |
const timeText = document.getElementById('timeText'); | |
const messages = [ | |
"🧠 AI正在分析您的特征数据...", | |
"🔍 SarcoI模型分析中...", | |
"⚙️ SarcoII模型分析中...", | |
"📊 DiCE生成个性化建议...", | |
"✨ 即将完成,请稍候..." | |
]; | |
let messageIndex = 0; | |
let startTime = Date.now(); | |
const interval = setInterval(() => { | |
const elapsed = (Date.now() - startTime) / 1000; | |
// 更新进度条 | |
if (elapsed < 120) { | |
progress = 30 + (elapsed / 120) * 60; | |
} else { | |
progress = Math.min(95, 90 + (elapsed - 120) / 60 * 5); | |
} | |
progressBar.style.width = progress + '%'; | |
// 更新消息 | |
if (Math.floor(elapsed / 30) > messageIndex && messageIndex < messages.length - 1) { | |
messageIndex++; | |
statusText.textContent = messages[messageIndex]; | |
} | |
// 更新时间 | |
if (elapsed < 60) { | |
timeText.textContent = `已运行 ${Math.floor(elapsed)} 秒`; | |
} else { | |
const minutes = Math.floor(elapsed / 60); | |
const seconds = Math.floor(elapsed % 60); | |
timeText.textContent = `已运行 ${minutes}分${seconds}秒`; | |
} | |
if (elapsed > 180) { | |
clearInterval(interval); | |
} | |
}, 1000); | |
window.progressInterval = interval; | |
} | |
/** | |
* 显示结果 | |
*/ | |
function displayResults(assessment) { | |
hideLoading(); | |
const html = buildResultsHTML(assessment); | |
document.getElementById('resultsContent').innerHTML = html; | |
document.getElementById('resultsSection').style.display = 'block'; | |
// 更新语言显示 | |
updateLanguageDisplay(); | |
document.getElementById('resultsSection').scrollIntoView({ | |
behavior: 'smooth' | |
}); | |
} | |
/** | |
* 构建结果HTML | |
*/ | |
function buildResultsHTML(assessment) { | |
const screening = assessment.screening; | |
const advisory = assessment.advisory; | |
return ` | |
<div class="alert alert-success"> | |
<h5 class="alert-heading"> | |
<i class="fas fa-check-circle me-2"></i> | |
<span class="lang-zh">双模型评估完成</span> | |
<span class="lang-en">Dual Model Assessment Completed</span> | |
</h5> | |
<p class="mb-0"> | |
<span class="lang-zh">基于SarcoI和SarcoII模型的综合评估结果</span> | |
<span class="lang-en">Comprehensive assessment results based on SarcoI and SarcoII models</span> | |
</p> | |
</div> | |
<!-- 筛查结果 --> | |
<div class="row mb-4"> | |
<div class="col-md-6"> | |
<div class="card border-primary"> | |
<div class="card-body text-center"> | |
<h6 class="card-title text-primary"> | |
<span class="lang-zh">SarcoI 筛查</span> | |
<span class="lang-en">SarcoI Screening</span> | |
</h6> | |
<div class="risk-level risk-${screening.sarcoI_risk} mb-2"> | |
<div><strong>${getRiskLevelText(screening.sarcoI_risk)}</strong></div> | |
<div class="small"> | |
<span class="lang-zh">概率: ${(screening.sarcoI_probability * 100).toFixed(1)}%</span> | |
<span class="lang-en">Probability: ${(screening.sarcoI_probability * 100).toFixed(1)}%</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="col-md-6"> | |
<div class="card border-primary"> | |
<div class="card-body text-center"> | |
<h6 class="card-title text-primary"> | |
<span class="lang-zh">SarcoII 筛查</span> | |
<span class="lang-en">SarcoII Screening</span> | |
</h6> | |
<div class="risk-level risk-${screening.sarcoII_risk} mb-2"> | |
<div><strong>${getRiskLevelText(screening.sarcoII_risk)}</strong></div> | |
<div class="small"> | |
<span class="lang-zh">概率: ${(screening.sarcoII_probability * 100).toFixed(1)}%</span> | |
<span class="lang-en">Probability: ${(screening.sarcoII_probability * 100).toFixed(1)}%</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 建议结果 --> | |
${advisory && advisory.recommendations ? ` | |
<div class="mt-4"> | |
<h6 class="text-success"> | |
<i class="fas fa-lightbulb me-2"></i> | |
<span class="lang-zh">个性化建议</span> | |
<span class="lang-en">Personalized Recommendations</span> | |
</h6> | |
<div class="card"> | |
<div class="card-body"> | |
${advisory.recommendations.map((rec, index) => ` | |
<div class="recommendation-item mb-3 p-3 border rounded"> | |
<h6 class="text-primary">${rec.title}</h6> | |
<p class="mb-1">${rec.description}</p> | |
<small class="text-muted"> | |
<span class="lang-zh">优先级: ${rec.priority} | 预期效果: ${rec.expected_impact}</span> | |
<span class="lang-en">Priority: ${rec.priority} | Expected Impact: ${rec.expected_impact}</span> | |
</small> | |
</div> | |
`).join('')} | |
</div> | |
</div> | |
</div> | |
` : `<div class="alert alert-info"> | |
<span class="lang-zh">暂无个性化建议生成</span> | |
<span class="lang-en">No personalized recommendations generated</span> | |
</div>`} | |
<div class="mt-4 text-center"> | |
<button class="btn btn-outline-primary" onclick="location.reload()"> | |
<i class="fas fa-redo me-2"></i> | |
<span class="lang-zh">重新评估</span> | |
<span class="lang-en">Re-assess</span> | |
</button> | |
</div> | |
`; | |
} | |
/** | |
* 工具函数 | |
*/ | |
function updateSubmitButton() { | |
const form = document.getElementById('unifiedForm'); | |
const submitBtn = document.getElementById('submitBtn'); | |
const inputs = form.querySelectorAll('input[required], select[required]'); | |
let allValid = true; | |
inputs.forEach(input => { | |
if (!input.value || !input.checkValidity()) { | |
allValid = false; | |
} | |
}); | |
submitBtn.disabled = !allValid; | |
} | |
function getRiskLevelText(level) { | |
const levelTexts = { | |
'zh': { | |
'low': '低风险', | |
'medium': '中风险', | |
'high': '高风险' | |
}, | |
'en': { | |
'low': 'Low Risk', | |
'medium': 'Medium Risk', | |
'high': 'High Risk' | |
} | |
}; | |
return levelTexts[currentLanguage][level] || level; | |
} | |
function showAlert(message, type) { | |
alert(message); | |
} | |