Sarco-Monitor / static /unified_assessment.js
Ning311's picture
Upload 40 files
ad05511 verified
/**
* 统一评估系统 - 同时生成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);
}