Group12-AIInterview/static/script.js
2026-01-07 14:05:46 +08:00

450 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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');
}