Group12-AIInterview/static/script.js

450 lines
14 KiB
JavaScript
Raw Permalink Normal View History

2026-01-07 14:05:46 +08:00
// AI帮你面试 - 核心JavaScript功能
// 全局变量
let currentQuestionId = 1;
const totalQuestions = 4;
// API配置
const API_CONFIG = {
// 开发环境API密钥实际生产环境应使用更安全的方式管理
apiKey: 'sk-0944c102849e45d9ab3f24d5169de289',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'sk-0944c102849e45d9ab3f24d5169de289'
}
};
// 面试流程数据(与后端保持一致)
const interviewProcess = [
{"id": 1, "title": "自我介绍", "description": "请简要介绍您自己,包括教育背景和工作经验", "duration": "3分钟"},
{"id": 2, "title": "技术能力评估", "description": "回答技术相关问题,展示专业知识", "duration": "15分钟"},
{"id": 3, "title": "项目经验分享", "description": "分享您参与的重要项目和成果", "duration": "10分钟"},
{"id": 4, "title": "问题与解答", "description": "您可以向面试官提问", "duration": "7分钟"}
];
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
// 初始化面试流程界面
initInterviewProcess();
// 绑定事件监听器
bindEventListeners();
});
// 初始化面试流程界面
function initInterviewProcess() {
// 高亮第一个步骤
updateStepHighlight(currentQuestionId);
// 更新当前问题显示
updateCurrentQuestion(currentQuestionId);
}
// 绑定事件监听器
function bindEventListeners() {
// 分析按钮
const analyzeBtn = document.getElementById('analyze-btn');
if (analyzeBtn) {
analyzeBtn.addEventListener('click', handleAnalyzeAnswer);
}
// 下一题按钮
const nextBtn = document.getElementById('next-question-btn');
if (nextBtn) {
nextBtn.addEventListener('click', handleNextQuestion);
}
// 返回修改按钮
const backBtn = document.getElementById('back-to-question-btn');
if (backBtn) {
backBtn.addEventListener('click', handleBackToQuestion);
}
// 完成面试按钮
const finishBtn = document.getElementById('finish-interview-btn');
if (finishBtn) {
finishBtn.addEventListener('click', handleFinishInterview);
}
// 关闭结果弹窗按钮
const closeModalBtn = document.querySelector('.close');
if (closeModalBtn) {
closeModalBtn.addEventListener('click', closeResultsModal);
}
// 点击弹窗外部关闭
const modal = document.getElementById('results-modal');
if (modal) {
modal.addEventListener('click', function(event) {
if (event.target === modal) {
closeResultsModal();
}
});
}
// 点击流程步骤切换问题
const processSteps = document.querySelectorAll('.process-step');
processSteps.forEach(step => {
step.addEventListener('click', function() {
const stepId = parseInt(this.dataset.stepId);
if (stepId <= currentQuestionId) {
switchToQuestion(stepId);
}
});
});
}
// 处理AI分析回答
function handleAnalyzeAnswer() {
const answerText = document.getElementById('answer-text').value;
if (!answerText.trim()) {
alert('请先输入您的回答!');
return;
}
// 显示加载状态
const analyzeBtn = document.getElementById('analyze-btn');
const originalText = analyzeBtn.textContent;
analyzeBtn.textContent = '分析中...';
analyzeBtn.disabled = true;
// 模拟AI分析过程实际项目中这里会调用后端API
setTimeout(() => {
// 调用AI分析API
analyzeAnswerAPI(currentQuestionId, answerText)
.then(data => {
// 显示分析结果
displayAnalysisResults(data);
// 更新UI
document.getElementById('question-stage').classList.add('hidden');
document.getElementById('analysis-stage').classList.remove('hidden');
})
.catch(error => {
console.error('分析失败:', error);
alert('分析失败,请稍后重试!');
})
.finally(() => {
// 恢复按钮状态
analyzeBtn.textContent = originalText;
analyzeBtn.disabled = false;
});
}, 1500);
}
// 调用AI分析API
async function analyzeAnswerAPI(questionId, answer) {
try {
const response = await fetch('/analyze_answer', {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify({
question_id: questionId,
answer: answer
})
});
if (!response.ok) {
throw new Error('分析请求失败');
}
return await response.json();
} catch (error) {
console.error('API调用错误:', error);
throw error;
}
}
// 显示AI分析结果
function displayAnalysisResults(data) {
// 更新综合评分
document.getElementById('overall-score').textContent = data.overall_score;
// 更新内容分析进度条
updateProgressBar('completeness-bar', 'completeness-value', data.content_analysis.completeness);
updateProgressBar('relevance-bar', 'relevance-value', data.content_analysis.relevance);
updateProgressBar('depth-bar', 'depth-value', data.content_analysis.depth);
// 更新建议列表
const suggestionsList = document.getElementById('suggestions-list');
suggestionsList.innerHTML = '';
data.suggestions.forEach(suggestion => {
const li = document.createElement('li');
li.textContent = suggestion;
suggestionsList.appendChild(li);
});
}
// 更新进度条
function updateProgressBar(barId, valueId, percentage) {
const bar = document.getElementById(barId);
const value = document.getElementById(valueId);
bar.style.width = `${percentage}%`;
value.textContent = `${percentage}%`;
}
// 处理下一题按钮点击
function handleNextQuestion() {
if (currentQuestionId < totalQuestions) {
currentQuestionId++;
switchToQuestion(currentQuestionId);
} else {
alert('这是最后一个问题!');
}
}
// 切换到指定问题
function switchToQuestion(questionId) {
currentQuestionId = questionId;
// 更新当前问题显示
updateCurrentQuestion(questionId);
// 更新步骤高亮
updateStepHighlight(questionId);
// 切换到问题阶段
document.getElementById('question-stage').classList.remove('hidden');
document.getElementById('analysis-stage').classList.add('hidden');
// 清空回答输入
document.getElementById('answer-text').value = '';
}
// 更新当前问题显示
function updateCurrentQuestion(questionId) {
const question = interviewProcess.find(q => q.id === questionId);
if (question) {
document.getElementById('current-question-title').textContent = question.title;
document.getElementById('current-question-description').textContent = question.description;
}
}
// 更新步骤高亮
function updateStepHighlight(questionId) {
const steps = document.querySelectorAll('.process-step');
steps.forEach(step => {
const stepId = parseInt(step.dataset.stepId);
if (stepId === questionId) {
step.classList.add('active');
} else if (stepId < questionId) {
step.classList.add('completed');
step.classList.remove('active');
} else {
step.classList.remove('active', 'completed');
}
});
}
// 处理返回修改按钮
function handleBackToQuestion() {
document.getElementById('analysis-stage').classList.add('hidden');
document.getElementById('question-stage').classList.remove('hidden');
}
// 处理完成面试按钮
function handleFinishInterview() {
// 显示确认对话框
if (confirm('确定要完成面试吗?')) {
// 调用获取面试结果API
getInterviewResults()
.then(results => {
displayInterviewResults(results);
openResultsModal();
})
.catch(error => {
console.error('获取结果失败:', error);
alert('获取面试结果失败,请稍后重试!');
});
}
}
// 获取面试结果
async function getInterviewResults() {
try {
const response = await fetch('/get_results', {
headers: API_CONFIG.headers
});
if (!response.ok) {
throw new Error('获取结果请求失败');
}
return await response.json();
} catch (error) {
console.error('API调用错误:', error);
throw error;
}
}
// 显示面试结果
function displayInterviewResults(results) {
const container = document.getElementById('results-container');
container.innerHTML = `
<div class="score-card">
<h3>最终评分</h3>
<div class="score-value">${results.overall_score}</div>
</div>
<div class="results-details">
<h3>分类评分</h3>
<div class="category-scores">
<div class="score-item">
<label>专业知识</label>
<div class="progress">
<div class="progress-fill" style="width: ${results.category_scores.professional_knowledge}%"></div>
</div>
<span>${results.category_scores.professional_knowledge}%</span>
</div>
<div class="score-item">
<label>沟通能力</label>
<div class="progress">
<div class="progress-fill" style="width: ${results.category_scores.communication_skills}%"></div>
</div>
<span>${results.category_scores.communication_skills}%</span>
</div>
<div class="score-item">
<label>解决问题</label>
<div class="progress">
<div class="progress-fill" style="width: ${results.category_scores.problem_solving}%"></div>
</div>
<span>${results.category_scores.problem_solving}%</span>
</div>
<div class="score-item">
<label>经验相关性</label>
<div class="progress">
<div class="progress-fill" style="width: ${results.category_scores.experience_relevance}%"></div>
</div>
<span>${results.category_scores.experience_relevance}%</span>
</div>
</div>
</div>
<div class="strengths-improvements">
<div class="strengths">
<h3>👍 优点</h3>
<ul>
${results.strengths.map(strength => `<li>${strength}</li>`).join('')}
</ul>
</div>
<div class="improvements">
<h3>📈 需要改进的地方</h3>
<ul>
${results.improvement_areas.map(area => `<li>${area}</li>`).join('')}
</ul>
</div>
</div>
<div class="final-recommendation">
<h3>💡 最终建议</h3>
<p class="recommendation-text">${results.final_recommendation}</p>
</div>
`;
// 添加结果页面样式
addResultsStyles();
}
// 添加结果页面样式
function addResultsStyles() {
// 动态添加结果页面需要的CSS样式
const style = document.createElement('style');
style.textContent = `
.results-details {
margin: 30px 0;
}
.category-scores {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
.score-item {
background: white;
padding: 15px;
border-radius: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.score-item label {
display: block;
margin-bottom: 10px;
font-weight: bold;
color: #555;
}
.strengths-improvements {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
margin: 30px 0;
}
.strengths, .improvements {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.strengths h3, .improvements h3 {
margin-bottom: 15px;
color: #333;
border-bottom: 2px solid #eee;
padding-bottom: 10px;
}
.strengths ul, .improvements ul {
list-style: none;
}
.strengths li, .improvements li {
padding: 10px 0;
border-bottom: 1px solid #f0f0f0;
color: #555;
}
.strengths li:last-child, .improvements li:last-child {
border-bottom: none;
}
.final-recommendation {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
border-radius: 10px;
text-align: center;
}
.final-recommendation h3 {
margin-bottom: 20px;
font-size: 1.5rem;
}
.recommendation-text {
font-size: 1.2rem;
font-weight: bold;
line-height: 1.6;
}
`;
document.head.appendChild(style);
}
// 打开结果弹窗
function openResultsModal() {
document.getElementById('results-modal').classList.remove('hidden');
}
// 关闭结果弹窗
function closeResultsModal() {
document.getElementById('results-modal').classList.add('hidden');
}