|
@@ -1,130 +1,132 @@
|
|
|
<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 class="interview-header">
|
|
|
+ <div class="logo">AI面试官</div>
|
|
|
+ <div class="timer">
|
|
|
+ <i class="fas fa-clock"></i>
|
|
|
+ 剩余时间: {{ remainingTime }}
|
|
|
+ <span *ngIf="remainingMinutes === 0 && remainingSeconds <= 30" class="time-warning">
|
|
|
+ (即将结束)
|
|
|
+ </span>
|
|
|
</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="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="dialog-container" #dialogContainer>
|
|
|
- @for (message of messages; track message) {
|
|
|
- <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>}
|
|
|
+ <div class="avatar-expression">
|
|
|
+ <span class="expression-dot"></span>
|
|
|
+ <span>{{ expressionText }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 对话区域 -->
|
|
|
+ <div class="dialog-container" #dialogContainer>
|
|
|
+ @for (message of messages; track message) {
|
|
|
+ <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>}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 问题卡片 -->
|
|
|
+ @if (showQuestionCard) {
|
|
|
+ <div class="question-card">
|
|
|
+ <div class="question-text">
|
|
|
+ {{ currentQuestion }}
|
|
|
+ </div>
|
|
|
+ <div class="question-progress">
|
|
|
+ <span>问题 {{ currentQuestionIndex + 1 }}/{{ questions.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">
|
|
|
+ <div class="voice-controls">
|
|
|
+ <button class="voice-btn"
|
|
|
+ (mousedown)="startVoiceInput()"
|
|
|
+ (mouseup)="stopVoiceInput()"
|
|
|
+ [class.active]="isListening">
|
|
|
+ <i class="fas fa-microphone"></i>
|
|
|
+ <div class="voice-wave"></div>
|
|
|
+ </button>
|
|
|
+ <button class="voice-btn"
|
|
|
+ (click)="playQuestion()"
|
|
|
+ style="background: linear-gradient(135deg, #48BB78, #38A169);">
|
|
|
+ <i class="fas fa-play"></i>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ @if (showSubmitButton) {
|
|
|
+ <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>
|
|
|
+ }
|
|
|
+ <div class="voice-hint">
|
|
|
+ 点击播放按钮可重复听取问题<br>
|
|
|
+ 按住麦克风按钮开始回答
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分析仪表盘 -->
|
|
|
+ <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>
|
|
|
|
|
|
- <!-- 问题卡片 (保留但隐藏) -->
|
|
|
- @if (showQuestionCard) {
|
|
|
- <div class="question-card">
|
|
|
- <div class="question-text">
|
|
|
- {{ currentQuestion }}
|
|
|
+ <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="question-progress">
|
|
|
- <span>问题 {{ currentQuestionIndex + 1 }}/{{ questions.length }}</span>
|
|
|
- <div class="progress-bar">
|
|
|
- <div class="progress-fill" [style.width]="progress + '%'"></div>
|
|
|
- </div>
|
|
|
- <span>{{ progress }}%</span>
|
|
|
+ <div class="metric-bar">
|
|
|
+ <div class="metric-fill" [style.width]="metrics.expressiveness + '%'"></div>
|
|
|
</div>
|
|
|
- </div>}
|
|
|
-
|
|
|
- <!-- 语音输入区域 -->
|
|
|
- <div class="voice-input-section">
|
|
|
- <div class="voice-controls">
|
|
|
- <button class="voice-btn"
|
|
|
- (mousedown)="startVoiceInput()"
|
|
|
- (mouseup)="stopVoiceInput()"
|
|
|
- [class.active]="isListening">
|
|
|
- <i class="fas fa-microphone"></i>
|
|
|
- <div class="voice-wave"></div>
|
|
|
- </button>
|
|
|
- <button class="voice-btn"
|
|
|
- (click)="playQuestion()"
|
|
|
- style="background: linear-gradient(135deg, #48BB78, #38A169);">
|
|
|
- <i class="fas fa-play"></i>
|
|
|
- </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="metric-item professionalism">
|
|
|
+ <div class="metric-header">
|
|
|
+ <span class="metric-name">专业度</span>
|
|
|
+ <span class="metric-value">{{ metrics.professionalism }}/100</span>
|
|
|
</div>
|
|
|
- @if (showSubmitButton) {
|
|
|
- <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>
|
|
|
- }
|
|
|
- <div class="voice-hint">
|
|
|
- 点击播放按钮可重复听取问题<br>
|
|
|
- 按住麦克风按钮开始回答
|
|
|
+ <div class="metric-bar">
|
|
|
+ <div class="metric-fill" [style.width]="metrics.professionalism + '%'"></div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 分析仪表盘 -->
|
|
|
- <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="metric-item relevance">
|
|
|
+ <div class="metric-header">
|
|
|
+ <span class="metric-name">岗位匹配度</span>
|
|
|
+ <span class="metric-value">{{ metrics.relevance }}/100</span>
|
|
|
</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 class="metric-bar">
|
|
|
+ <div class="metric-fill" [style.width]="metrics.relevance + '%'"></div>
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- 雷达图容器 -->
|
|
|
- @if (showRadarChart){
|
|
|
- <div id="radarChart" class="radar-chart" *ngIf="showRadarChart"></div>
|
|
|
- }
|
|
|
-
|
|
|
+ </div>
|
|
|
</div>
|
|
|
-</div>
|
|
|
+
|
|
|
+ @if (showRadarChart){
|
|
|
+ <div id="radarChart" class="radar-chart"></div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+</div>
|