feat: 完善教师端AI助教和个人中心页面;新增AI助教分析页面(AssistantDetail.vue);优化AI助教主页面(Assistant.vue)

This commit is contained in:
QDKF 2025-09-10 21:30:45 +08:00
parent 2a3e6ccd91
commit ec1a19d005
3 changed files with 529 additions and 3 deletions

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -11,7 +11,7 @@
<div class="sidebar-container" v-if="!hideSidebar">
<!-- 头像 -->
<div class="avatar-container">
<img src="https://picsum.photos/200/200" alt="头像" class="avatar">
<img src="/images/activity/5.png" alt="头像" class="avatar">
<div class="avatar-text">
用户昵称~
</div>

View File

@ -1,3 +1,529 @@
<template>
<div>查看分析页面</div>
</template>
<div class="ai-analysis-page">
<!-- 左侧视频区域 -->
<div class="video-section">
<!-- 视频播放器 -->
<div class="video-container">
<!-- 视频播放器区域 -->
<div class="video-player">
<DPlayerVideo :video-url="videoUrl" :poster="posterUrl" :title="videoTitle" :autoplay="false"
:show-controls="true" />
</div>
</div>
<!-- 视频内容/字幕 -->
<div class="video-content">
<div class="content-item">
<span class="timestamp">00:09</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">各位同学大家好</span>
</div>
<div class="content-item">
<span class="timestamp">00:11</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">欢迎大家来到智慧医疗创新体验课程</span>
</div>
<div class="content-item">
<span class="timestamp">00:13</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">我是主讲老师汪波</span>
</div>
<div class="content-item">
<span class="timestamp">00:14</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">我的专业背景是人工智能对于临床医学的实际结合</span>
</div>
<div class="content-item">
<span class="timestamp">00:17</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">所以我希望通过这种医工结合的方式</span>
</div>
<div class="content-item">
<span class="timestamp">00:19</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">给大家讲授智慧医疗这个交叉的学科</span>
</div>
<div class="content-item">
<span class="timestamp">00:21</span>
<img src="/images/aiAssistant/编组.png" alt="分隔符" class="separator-icon" />
<span class="content-text">我们这门课的教学目标主要是四个方面</span>
</div>
</div>
</div>
<!-- 右侧AI分析区域 -->
<div class="analysis-section">
<!-- 分析标签页 -->
<div class="analysis-tabs">
<div class="tab" :class="{ active: activeTab === '教学动作分析' }" @click="activeTab = '教学动作分析'">
<img src="/images/aiAssistant/教学动作分析.png" alt="教学动作分析" class="tab-icon" />
<span>教学动作分析</span>
</div>
<div class="tab" :class="{ active: activeTab === '教学语言分析' }" @click="activeTab = '教学语言分析'">
<img src="/images/aiAssistant/教学语言分析.png" alt="教学语言分析" class="tab-icon" />
<span>教学语言分析</span>
</div>
<div class="tab" :class="{ active: activeTab === '教学内容分析' }" @click="activeTab = '教学内容分析'">
<img src="/images/aiAssistant/教学内容分析.png" alt="教学内容分析" class="tab-icon" />
<span>教学内容分析</span>
</div>
<div class="tab" :class="{ active: activeTab === '教学情感分析' }" @click="activeTab = '教学情感分析'">
<img src="/images/aiAssistant/教学情感分析.png" alt="教学情感分析" class="tab-icon" />
<span>教学情感分析</span>
</div>
</div>
<!-- 子标签页 -->
<div class="sub-tabs">
<div class="sub-tab" :class="{ active: activeSubTab === '分析结果' }" @click="activeSubTab = '分析结果'">分析结果</div>
<div class="sub-tab" :class="{ active: activeSubTab === '教学动作' }" @click="activeSubTab = '教学动作'">教学动作</div>
<div class="sub-tab" :class="{ active: activeSubTab === '移动轨迹' }" @click="activeSubTab = '移动轨迹'">移动轨迹</div>
<div class="sub-tab" :class="{ active: activeSubTab === '仪表体态' }" @click="activeSubTab = '仪表体态'">仪表体态</div>
</div>
<!-- 分析指标 -->
<div class="analysis-metrics">
<div class="metric-item">
<span class="metric-label">腿部晃动/不直立时长</span>
<span class="metric-value">1%</span>
</div>
<div class="metric-item">
<span class="metric-label">左右肩不平稳时长</span>
<span class="metric-value">0%</span>
</div>
<div class="metric-item">
<span class="metric-label">姿态变化次数</span>
<span class="metric-value">3</span>
</div>
<div class="metric-item">
<span class="metric-label">姿态变化频率</span>
<span class="metric-value">0/</span>
</div>
<div class="metric-item">
<span class="metric-label">姿态语音同步变化</span>
<span class="metric-value">暂无数据</span>
</div>
<div class="metric-item">
<span class="metric-label">姿态语音配合度</span>
<span class="metric-value">93.2%</span>
</div>
</div>
<!-- 3D角色和手部腿部数据 -->
<div class="character-section">
<div class="character-container">
<img src="/images/aiAssistant/教师-男.png" alt="3D教师角色" class="character-3d" />
<div class="data-points">
<div class="data-point hand-stability">
<div class="line-box">
<div class="line-diagonal"></div>
<div class="line-horizontal"></div>
<span class="data-label">手部平稳</span>
<span class="data-value">98.6%</span>
</div>
</div>
<div class="data-point leg-stability">
<div class="line-box">
<div class="line-diagonal"></div>
<div class="line-horizontal"></div>
<span class="data-label">腿部平稳</span>
<span class="data-value">98.6%</span>
</div>
</div>
</div>
</div>
<!-- 点评区域 -->
<div class="review-section">
<div class="review-item">
<span class="review-label">着装点评</span>
<span class="review-text">衣着得体</span>
</div>
<div class="review-item">
<span class="review-label">动作点评</span>
<span class="review-text">动作稳定</span>
</div>
<div class="review-item">
<span class="review-label">整体点评</span>
<span class="review-text">暂无结果</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import DPlayerVideo from '@/components/DPlayerVideo.vue'
//
const activeTab = ref('教学动作分析')
const activeSubTab = ref('分析结果')
//
const videoUrl = ref('https://example.com/video.mp4') // URL
const posterUrl = ref('/images/aiCompanion/bg.png') //
const videoTitle = ref('AI教学分析 - 课堂实录')
// /no-padding
onMounted(() => {
const container = document.querySelector('.router-view-container') as HTMLElement | null
if (container) {
container.classList.add('no-padding')
}
})
onUnmounted(() => {
const container = document.querySelector('.router-view-container') as HTMLElement | null
if (container) {
container.classList.remove('no-padding')
}
})
</script>
<style scoped>
.ai-analysis-page {
display: flex;
height: 100vh;
background: #F6F6F6;
padding: 32px;
gap: 28px;
}
/* 左侧视频区域 */
.video-section {
width: 50%;
}
.video-container {
margin-bottom: 20px;
}
.video-player {
position: relative;
background: #000;
overflow: hidden;
margin-bottom: 15px;
height: 375px;
}
/* DPlayerVideo 组件样式 */
.video-player :deep(.dplayer-wrapper) {
height: 100%;
border-radius: 8px;
}
.video-player :deep(.dplayer-container) {
height: 100%;
min-height: unset;
}
.video-player :deep(.dplayer) {
height: 100% !important;
border-radius: 8px;
}
/* 视频内容/字幕 */
.video-content {
padding: 15px 0;
overflow-y: auto;
}
.content-item {
display: flex;
align-items: center;
margin-bottom: 6px;
padding: 5px 0;
}
.timestamp {
color: #333;
margin-right: 4px;
min-width: 40px;
font-size: 14px;
}
.separator-icon {
width: 8px;
height: 8px;
margin-right: 10px;
}
.content-text {
color: #333;
font-size: 14px;
}
/* 右侧分析区域 */
.analysis-section {
/* width: 47%; */
flex: 1;
}
.analysis-tabs {
display: flex;
margin-bottom: 15px;
background: #EAF2F5;
border-radius: 6px;
padding: 3px;
height: 40px;
gap: 2px;
}
.analysis-tabs .tab {
flex: 1;
padding: 8px 12px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
background: #EAF2F5;
color: #000000;
font-size: 12px;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
margin: 2px;
}
.analysis-tabs .tab.active {
background: white;
color: #000000;
}
.analysis-tabs .tab:hover:not(.active) {
background: rgba(255, 255, 255, 0.5);
}
.tab-icon {
width: 20px;
height: 20px;
object-fit: contain;
}
.sub-tabs {
display: flex;
margin-bottom: 20px;
gap: 48px;
}
.sub-tab {
background: transparent;
font-size: 13px;
color: #000000;
cursor: pointer;
position: relative;
transition: color 0.3s ease;
}
.sub-tab.active {
color: #0084CD;
}
.sub-tab.active::after {
content: '';
position: absolute;
bottom: -8px;
left: 0;
right: 0;
height: 2px;
background: #0088D1;
border-radius: 1px;
}
.analysis-metrics {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
margin-bottom: 20px;
}
.metric-item {
min-height: 72px;
padding: 16px;
background: rgba(255, 255, 255, 0.5);
border: 1.5px solid white;
border-radius: 2px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: left;
}
.metric-label {
font-size: 14px;
color: #000000;
margin-bottom: 8px;
line-height: 1.2;
}
.metric-value {
font-size: 14px;
color: #0088D1;
font-weight: 500;
}
.character-section {
background: white;
padding: 20px;
border-radius: 2px;
margin-bottom: 20px;
text-align: center;
position: relative;
}
.character-container {
position: relative;
display: inline-block;
}
.character-3d {
width: 334px;
height: auto;
}
.data-points {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.data-point {
position: absolute;
padding: 5px 10px;
font-size: 12px;
color: #1890ff;
}
.hand-stability {
top: 59%;
left: -5%;
transform: translate(-50%, -50%);
margin-top: -100px;
background: transparent;
border: none;
padding: 0;
}
.line-box {
min-width: 200px;
display: flex;
align-items: center;
gap: 4px;
font-size: 14px;
position: relative;
padding-bottom: 14px;
}
.line-diagonal {
position: absolute;
width: 35px;
height: 1.5px;
background: #979797;
transform: rotate(-45deg);
transform-origin: left center;
right: 0;
bottom: 0%;
margin-top: -1px;
}
.line-horizontal {
position: absolute;
width: 83%;
height: 1.5px;
background: #979797;
left: 0;
bottom: 0%;
margin-top: -1px;
}
.data-label {
font-size: 14px;
color: #000000;
}
.data-value {
font-size: 14px;
color: #2196f3;
font-weight: 500;
}
.leg-stability {
bottom: 36%;
right: -47%;
}
.leg-stability .line-box {
padding-right: 35px;
min-width: 200px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 4px;
font-size: 14px;
position: relative;
padding-bottom: 14px;
}
.leg-stability .line-diagonal {
position: absolute;
width: 35px;
height: 1.5px;
background: #979797;
transform: rotate(-45deg);
transform-origin: right center;
left: -17%;
bottom: 0%;
margin-top: -1px;
}
.leg-stability .line-horizontal {
position: absolute;
width: 83%;
height: 1.5px;
background: #979797;
left: 0;
bottom: 0%;
margin-top: -1px;
}
.review-section {
position: absolute;
bottom: 20px;
left: 20px;
background: transparent;
padding: 0;
margin: 0;
}
.review-item {
display: flex;
align-items: center;
font-size: 14px;
color: #000000;
}
.review-item:last-child {
margin-bottom: 0;
}
.review-label {
font-size: 12px;
color: #000000;
margin-right: 4px;
}
.review-text {
font-size: 14px;
color: #000000;
}
:global(.router-view-container.no-padding) {
padding: 0 !important;
}
</style>