123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <div class="interview-container">
- <!-- 头部区域 -->
- <div class="interview-header">
- <div class="logo">AI面试官</div>
- <div class="timer">
- <i class="fas fa-clock"></i> 剩余时间: {{ remainingTime }}
- </div>
- </div>
-
- <!-- 数字人区域 -->
- <div class="avatar-section">
- <div class="avatar-container">
- <img [src]="avatarImage" alt="AI头像" class="avatar-img"
- (error)="avatarImage = 'assets/default-avatar.svg'">
- <div class="voice-wave" [style.animation]="isListening ? 'wave 2s infinite' : 'none'"></div>
- </div>
- <div class="avatar-expression">
- <span class="expression-dot"></span>
- <span>{{ expressionText }}</span>
- </div>
- </div>
-
- <!-- 修改后的对话区域 -->
- <div class="dialog-container" #dialogContainer>
- @for (message of messages; track $index) {
- <div class="message" [ngClass]="{'message-ai': message.sender === 'ai', 'message-user': message.sender === 'user'}">
- <div class="message-bubble" [ngClass]="{'ai-bubble': message.sender === 'ai', 'user-bubble': message.sender === 'user'}">
- {{ message.text }}
- </div>
- <div class="message-meta" [ngClass]="{'ai-meta': message.sender === 'ai', 'user-meta': message.sender === 'user'}">
- <i [class]="message.sender === 'ai' ? 'fas fa-robot' : 'fas fa-user'"></i>
- {{ message.sender === 'ai' ? 'AI面试官' : '您' }}
- </div>
- </div>
- }
- <!-- 实时语音转文字显示 -->
- @if (isListening && interimTranscript) {
- <div class="message message-user">
- <div class="message-bubble user-bubble">
- {{ interimTranscript }}
- <div class="recording-indicator">
- <span class="dot"></span>
- <span class="dot"></span>
- <span class="dot"></span>
- </div>
- </div>
- <div class="message-meta user-meta">
- <i class="fas fa-user"></i> 您 (正在说话)
- </div>
- </div>
- }
- </div>
-
- <!-- 问题卡片 -->
- @if (showQuestionCard && !interviewEnded) {
- <div class="question-card">
- <div class="question-text">
- {{ currentQuestion }}
- </div>
- <div class="question-progress">
- <span>问题 {{ currentQuestionIndex + 1 }}/{{ mainQuestions.length }}</span>
- <div class="progress-bar">
- <div class="progress-fill" [style.width]="progress + '%'"></div>
- </div>
- <span>{{ progress }}%</span>
- </div>
- </div>
- }
-
- <!-- 语音输入区域 -->
- <div class="voice-input-section">
- @if (!interviewEnded) {
- <div class="voice-controls">
- <!-- 麦克风按钮 -->
- <button class="voice-btn"
- (touchstart)="startVoiceInput()" (touchend)="stopVoiceInput()"
- (mousedown)="startVoiceInput()" (mouseup)="stopVoiceInput()"
- (mouseleave)="stopVoiceInput()"
- [class.active]="isListening">
- <i class="fas fa-microphone"></i>
- <div class="voice-wave"></div>
- <span class="press-hint">长按说话</span>
- </button>
-
- <!-- 播放问题按钮 -->
- <button class="voice-btn"
- (click)="playQuestion()"
- [disabled]="isListening || isAnalyzing"
- style="background: linear-gradient(135deg, #48BB78, #38A169);">
- <i class="fas fa-play"></i>
- </button>
- </div>
-
- <!-- 确认/取消按钮 -->
- @if (showSubmitButton || showCancelButton) {
- <div class="answer-confirm-buttons">
- <button class="submit-btn" (click)="submitAnswer()" [disabled]="isAnalyzing">
- <svg class="check-icon" viewBox="0 0 24 24" width="16" height="16">
- <path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" style="color: burlywood;"/>
- </svg>
- <div style="color: black;">确认回答</div>
- </button>
- <button class="cancel-btn" (click)="cancelAnswer()" [disabled]="isAnalyzing">
- <i class="fas fa-times"></i>
- 取消回答
- </button>
- </div>
- }
-
- <!-- 操作提示 -->
- <div class="voice-hint">
- @if (isListening) {
- 正在聆听,请回答问题...
- } @else if (isSpeaking) {
- 正在播报问题...
- } @else if (isAnalyzing) {
- 正在分析您的回答...
- } @else {
- 按住麦克风按钮开始回答,点击播放按钮重复听取问题
- }
- </div>
- } @else {
- <!-- 面试结束状态 -->
- <div class="interview-ended">
- <h3>面试已结束</h3>
- <p>感谢您参与本次AI面试</p>
- <button class="restart-btn" (click)="restartInterview()">
- <i class="fas fa-redo"></i> 重新开始面试
- </button>
- </div>
- }
- </div>
-
- @if (isListening && silenceDuration > 0) {
- <div class="silence-timer">
- 思考时间: {{ MAX_SILENCE - silenceDuration }}秒
- </div>
- }
- <!-- 分析仪表盘 -->
- @if (!interviewEnded) {
- <div class="dashboard-section">
- <div class="dashboard-title">
- <h3>实时分析面板</h3>
- <button class="toggle-btn" (click)="toggleRadarChart()">
- <i [class]="showRadarChart ? 'fas fa-chart-bar' : 'fas fa-chart-radar'"></i>
- {{ showRadarChart ? '隐藏雷达图' : '显示雷达图' }}
- </button>
- </div>
-
- <div class="dashboard-content">
- <div class="metric-item expressiveness">
- <div class="metric-header">
- <span class="metric-name">表达能力</span>
- <span class="metric-value">{{ metrics.expressiveness }}/100</span>
- </div>
- <div class="metric-bar">
- <div class="metric-fill" [style.width]="metrics.expressiveness + '%'"></div>
- </div>
- </div>
-
- <div class="metric-item professionalism">
- <div class="metric-header">
- <span class="metric-name">专业度</span>
- <span class="metric-value">{{ metrics.professionalism }}/100</span>
- </div>
- <div class="metric-bar">
- <div class="metric-fill" [style.width]="metrics.professionalism + '%'"></div>
- </div>
- </div>
-
- <div class="metric-item relevance">
- <div class="metric-header">
- <span class="metric-name">岗位匹配度</span>
- <span class="metric-value">{{ metrics.relevance }}/100</span>
- </div>
- <div class="metric-bar">
- <div class="metric-fill" [style.width]="metrics.relevance + '%'"></div>
- </div>
- </div>
- </div>
-
- <!-- 雷达图容器 -->
- @if (showRadarChart) {
- <div id="radarChart" class="radar-chart"></div>
- }
- </div>
- }
- </div>
|