- 修复路由配置:移除 top-level await,改用手动路由配置
- 修复响应拦截器:正确解包 { code, message, data } 格式的 API 响应
- 更新开发日志和变更日志,记录浏览器功能测试结果
- 添加教师端重构设计文档
修复的问题:
1. 登录功能无法正常工作(响应数据解包问题)
2. 页面无法加载(路由配置问题)
测试结果:
- 管理员登录: ✓ 成功
- 教师登录: ✓ 成功
- 主要页面导航: ✓ 正常
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
37 KiB
37 KiB
展播模式优化设计文档
文档版本: v1.0 创建日期: 2026-03-11 目标: 将授课内容以儿童友好的方式展示,方便儿童直接观看
📋 目录
1. 设计目标
1.1 核心目标
| 目标 | 说明 |
|---|---|
| 儿童友好 | 界面色彩活泼、操作简单、视觉清晰 |
| 资源陈列 | 三类课程的数字资源美观展示、易于选择 |
| 播放体验 | 资源播放流畅、控制方便、观赏舒适 |
| 互动趣味 | 加入动画、音效、奖励机制,增强参与感 |
1.2 使用场景
| 场景 | 设备 | 观看距离 | 特点 |
|---|---|---|---|
| 课堂投屏 | 智能屏/投影仪 | 2-5米 | 大屏显示、多人观看 |
| 一对一教学 | 平板 | 0.5-1米 | 触摸操作、近距离观看 |
| 家庭学习 | TV/平板 | 1-3米 | 家庭环境、家长陪同 |
1.3 用户特点
- 年龄范围:3-6岁幼儿
- 认知特点:视觉主导、注意力易分散、喜爱动画和鲜艳色彩
- 操作能力:大动作协调,精细动作发展中
2. 视觉风格设计
2.1 配色方案
┌─────────────────────────────────────────────────────────────┐
│ 主色系统 │
├─────────────────────────────────────────────────────────────┤
│ 主色:温暖橙 #FF8C42 (RGB: 255, 140, 66) │
│ 辅助色: │
│ - 天空蓝 #74B9FF (RGB: 116, 185, 255) │
│ - 薄荷绿 #00D9A5 (RGB: 0, 217, 165) │
│ - 珊瑚粉 #FF7675 (RGB: 255, 118, 117) │
│ - 柠檬黄 #FFD93D (RGB: 255, 217, 61) │
│ │
│ 中性色: │
│ - 背景浅 #FFF9F0 (RGB: 255, 249, 240) │
│ - 背景深 #FFF4E6 (RGB: 255, 244, 230) │
│ - 文字主 #2D3436 (RGB: 45, 52, 54) │
│ - 文字辅 #636E72 (RGB: 99, 110, 114) │
│ │
│ 功能色: │
│ - 成功 #52C41A (RGB: 82, 196, 26) │
│ - 警告 #FFA940 (RGB: 255, 169, 64) │
│ - 错误 #FF4D4F (RGB: 255, 77, 79) │
└─────────────────────────────────────────────────────────────┘
2.2 背景设计
2.2.1 渐变背景
主背景:从顶部到底部的柔和渐变
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
顶部:#FFE8D6 (温暖桃色)
↓
中部:#FFF9F0 (奶油色)
↓
底部:#F0F9FF (淡蓝色)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2.2.2 装饰元素
选项A:云朵装饰
位置:顶部和底部随机分布
大小:80-120px
透明度:60%
动画:缓慢飘动(20秒循环)
选项B:星星装饰
位置:背景随机分布
大小:20-40px
颜色:柠檬黄 #FFD93D
动画:闪烁效果(3秒循环)
选项C:几何图形
元素:圆形、三角形、正方形
颜色:辅助色(半透明)
分布:背景点缀
动画:缓慢旋转
2.3 字体设计
| 用途 | 字号 | 字重 | 行高 | 说明 |
|---|---|---|---|---|
| 主标题 | 32-40px | 600 | 1.2 | 课程/环节名称 |
| 正文 | 18-22px | 400 | 1.5 | 内容说明 |
| 按钮 | 16-18px | 500 | - | 操作按钮 |
2.4 圆角设计
// 统一圆角规范
$radius-sm: 12px; // 小卡片、按钮
$radius-md: 16px; // 中等卡片
$radius-lg: 24px; // 大卡片
$radius-xl: 32px; // 容器
3. 资源陈列优化
3.1 整体布局结构
┌──────────────────────────────────────────────────────────────────┐
│ 展播模式主界面 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 主内容区 │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 资源播放区(大屏显示) │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 底部导航栏 │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │ 环节 │ │ 资源 │ │ 进度 │ │ 延伸 │ │ │
│ │ │ 导航 │ │ 快速 │ │ 显示 │ │ 活动 │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
3.2 课程级资源展示区
位置: 主内容区顶部(自动收起)
<!-- 课程资源横幅 -->
<div class="course-resources-banner" v-if="showCourseResources">
<div class="resource-cards">
<!-- 视频资源 -->
<div v-if="courseVideos.length" class="resource-card video-card">
<div class="card-icon">🎬</div>
<div class="card-info">
<span class="card-title">课程视频</span>
<span class="card-count">{{ courseVideos.length }}个</span>
</div>
<button class="play-btn" @click="playCourseVideo">
<PlayIcon /> 播放
</button>
</div>
<!-- PPT资源 -->
<div v-if="coursePpts.length" class="resource-card ppt-card">
<div class="card-icon">📊</div>
<div class="card-info">
<span class="card-title">教学课件</span>
<span class="card-count">{{ coursePpts.length }}个</span>
</div>
<button class="play-btn" @click="showCoursePpts">
<ViewIcon /> 预览
</button>
</div>
<!-- 文档资源 -->
<div v-if="courseDocs.length" class="resource-card doc-card">
<div class="card-icon">📄</div>
<div class="card-info">
<span class="card-title">教学文档</span>
<span class="card-count">{{ courseDocs.length }}个</span>
</div>
<button class="play-btn" @click="showCourseDocs">
<ReadIcon /> 查看
</button>
</div>
</div>
</div>
样式规范:
.course-resources-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
padding: 16px 24px;
background: linear-gradient(180deg, #FFF9F0 0%, rgba(255, 249, 240, 0) 100%);
display: flex;
justify-content: center;
animation: slideDown 0.3s ease;
.resource-cards {
display: flex;
gap: 16px;
}
.resource-card {
display: flex;
align-items: center;
gap: 12px;
padding: 16px 24px;
background: white;
border-radius: 24px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
.card-icon {
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
background: #FFF4E6;
border-radius: 12px;
}
.play-btn {
padding: 10px 20px;
border-radius: 20px;
background: linear-gradient(135deg, #FF8C42, #E67635);
color: white;
font-size: 16px;
font-weight: 500;
border: none;
cursor: pointer;
transition: transform 0.2s;
&:hover {
transform: scale(1.05);
}
}
}
}
3.3 环节资源卡片
设计: 横向滚动的卡片式布局
┌────────────────────────────────────────────────────────────┐
│ 教学环节 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 1️⃣ 导入 │ │ 2️⃣ 共读 │ │ 3️⃣ 讨论 │ │ 4️⃣ 活动 │ │
│ │ │ │ │ │ │ │ │ │
│ │ [资源] │ │ [资源] │ │ [资源] │ │ [资源] │ │
│ │ [资源] │ │ [资源] │ │ │ │ [资源] │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ⭐ ⭐ ⭐ ⬜ │
└────────────────────────────────────────────────────────────┘
实现规范:
<!-- 环节资源卡片 -->
<div class="step-resources-section">
<div class="section-title">
<span class="title-text">教学环节</span>
<span class="title-badge">{{ currentStepIndex + 1 }}/{{ steps.length }}</span>
</div>
<div class="step-cards-container">
<div
v-for="(step, index) in steps"
:key="step.id"
class="step-card"
:class="{
active: currentStepIndex === index,
completed: index < currentStepIndex
}"
@click="selectStep(index)"
>
<!-- 环节头部 -->
<div class="step-header">
<div class="step-number">{{ index + 1 }}</div>
<div class="step-info">
<div class="step-name">{{ step.name }}</div>
<div class="step-duration">{{ step.duration }}分钟</div>
</div>
<div class="step-status">
<StarIcon v-if="index < currentStepIndex" class="completed-star" />
</div>
</div>
<!-- 环节资源 -->
<div class="step-resources">
<!-- 图片资源 -->
<div
v-for="(img, idx) in step.images.slice(0, 2)"
:key="`img-${idx}`"
class="resource-thumb image-thumb"
@click.stop="showResource('image', img)"
>
<img :src="getResourceUrl(img.path)" :alt="img.name" />
</div>
<!-- 视频资源 -->
<div
v-if="step.videos.length > 0"
class="resource-thumb video-thumb"
@click.stop="showResource('video', step.videos[0])"
>
<div class="thumb-icon">🎬</div>
<span class="thumb-label">视频</span>
</div>
<!-- 音频资源 -->
<div
v-if="step.audioList.length > 0"
class="resource-thumb audio-thumb"
@click.stop="showResource('audio', step.audioList[0])"
>
<div class="thumb-icon">🎵</div>
<span class="thumb-label">音频</span>
</div>
<!-- 更多资源提示 -->
<div
v-if="getStepResourceCount(step) > 3"
class="resource-thumb more-thumb"
@click.stop="showResourceList(step)"
>
<div class="thumb-icon">➕</div>
<span class="thumb-label">{{ getStepResourceCount(step) - 2 }}+</span>
</div>
</div>
</div>
</div>
</div>
样式规范:
.step-cards-container {
display: flex;
gap: 20px;
overflow-x: auto;
padding: 8px 4px;
scroll-snap-type: x mandatory;
&::-webkit-scrollbar {
height: 8px;
}
&::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background: rgba(255, 140, 66, 0.3);
border-radius: 4px;
&:hover {
background: rgba(255, 140, 66, 0.5);
}
}
}
.step-card {
flex: 0 0 280px;
scroll-snap-align: start;
background: white;
border-radius: 20px;
padding: 16px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
cursor: pointer;
transition: all 0.3s ease;
border: 3px solid transparent;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
&.active {
border-color: #FF8C42;
background: linear-gradient(135deg, #FFF9F0 0%, #FFF4E6 100%);
}
&.completed {
opacity: 0.7;
.completed-star {
color: #FFD93D;
font-size: 24px;
animation: starPop 0.5s ease;
}
}
.step-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
.step-number {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #FF8C42, #E67635);
color: white;
border-radius: 12px;
font-size: 18px;
font-weight: 600;
}
.step-info {
flex: 1;
.step-name {
font-size: 18px;
font-weight: 600;
color: #2D3436;
margin-bottom: 2px;
}
.step-duration {
font-size: 13px;
color: #636E72;
}
}
}
.step-resources {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.resource-thumb {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 8px 12px;
border-radius: 12px;
background: #F8F8F8;
cursor: pointer;
transition: all 0.2s;
&:hover {
background: #FFE8D6;
transform: scale(1.05);
}
.thumb-icon {
font-size: 24px;
}
.thumb-label {
font-size: 11px;
color: #636E72;
}
&.image-thumb {
img {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 8px;
}
}
}
}
4. 播放体验设计
4.1 主内容区布局
┌──────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────┐ │
│ │ │ │
│ │ 资源播放区 │ │
│ │ │ │
│ │ (视频/绘本) │ │
│ │ │ │
│ │ │ │
│ └─────────────────┘ │
│ │
│ ← [ 1/5 ] → │
│ │
└──────────────────────────────────────────────────────────────┘
4.2 视频播放器设计
自定义播放器控件:
┌──────────────────────────────────────────────────────────────┐
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 视频内容 │ │
│ │ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌──────┐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┌──────┐ │
│ │ ⏮ │ ◐━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ ⏸ │ │
│ └──────┘ 00:00 / 05:32 └──────┘ │
│ │
│ [ 🔊 ] [ 🔍 ] [ ⛶ ] [ 📺 ] [ ⚙️ ] │
│ │
└──────────────────────────────────────────────────────────────┘
按钮尺寸规范:
- 播放/暂停:64x64px
- 音量:48x48px
- 全屏:48x48px
- 其他:40x40px
4.3 绘本阅读器设计
翻页效果:
<EbookViewer>
<!-- 当前页面 -->
<div class="ebook-page" :style="{ transform: pageTransform }">
<img :src="currentPage.url" :alt="currentPage.name" />
</div>
<!-- 翻页控件 -->
<div class="ebook-controls">
<button class="nav-btn prev" @click="prevPage">
<ChevronLeft :size="48" />
</button>
<!-- 页面指示器 -->
<div class="page-indicator">
<div
v-for="(page, index) in pages"
:key="index"
class="page-dot"
:class="{ active: currentPageIndex === index }"
></div>
</div>
<button class="nav-btn next" @click="nextPage">
<ChevronRight :size="48" />
</button>
</div>
<!-- 缩略图条带 -->
<div class="thumbnail-strip">
<div
v-for="(page, index) in pages"
:key="index"
class="thumbnail"
:class="{ active: currentPageIndex === index }"
@click="jumpToPage(index)"
>
<img :src="page.thumbnail" />
<span class="page-num">{{ index + 1 }}</span>
</div>
</div>
</EbookViewer>
翻页动画:
@keyframes pageTurn {
0% {
transform: rotateY(0deg);
opacity: 1;
}
50% {
transform: rotateY(-90deg);
opacity: 0.5;
}
100% {
transform: rotateY(0deg);
opacity: 1;
}
}
.ebook-page {
animation: pageTurn 0.6s ease-in-out;
transform-style: preserve-3d;
}
4.4 PPT/挂图查看器设计
布局:
┌──────────────────────────────────────────────────────────────┐
│ [X] 教学课件 - PPT1 │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ PPT 页面 │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌─────┐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┌─────┐ │
│ │ ◀│ ●────────●────────────────────● │ ▶ │ │
│ └─────┘ 1 / 15 └─────┘ │
│ │
│ [ 🔍 ] [ ⛶ ] [ 📤 ] │
└──────────────────────────────────────────────────────────────┘
缩略图条带:
<div class="slides-viewer">
<!-- 缩略图条带 -->
<div class="thumbnail-strip">
<div
v-for="(slide, index) in slides"
:key="index"
class="slide-thumbnail"
:class="{ active: currentSlide === index }"
@click="goToSlide(index)"
>
<img :src="slide.thumbnail" />
</div>
</div>
</div>
5. 互动元素设计
5.1 音效系统
音效清单:
| 交互 | 音效 | 音量 | 说明 |
|---|---|---|---|
| 环节切换 | 轻柔"嗖"声 | 50% | 过渡提示 |
| 资源点击 | "波"音 | 40% | 点击反馈 |
| 完成环节 | 鼓掌声 | 60% | 正向强化 |
| 全部完成 | 欢呼声 + 钟声 | 70% | 庆祝 |
| 错误操作 | 轻柔"唔"声 | 30% | 提示纠正 |
实现方式:
// 音效管理类
class SoundEffectManager {
private audioContext: AudioContext;
playSound(soundName: string) {
const sounds = {
'stepChange': '/assets/sounds/whoosh.mp3',
'click': '/assets/sounds/bloop.mp3',
'complete': '/assets/sounds/applause.mp3',
'celebrate': '/assets/sounds/celebrate.mp3',
'error': '/assets/sounds/hmm.mp3',
};
const audio = new Audio(sounds[soundName]);
audio.volume = this.getVolume(soundName);
audio.play().catch(err => console.log('Sound play error:', err));
}
private getVolume(soundName: string): number {
const volumes = {
'stepChange': 0.5,
'click': 0.4,
'complete': 0.6,
'celebrate': 0.7,
'error': 0.3,
};
return volumes[soundName] || 0.5;
}
}
5.2 动画效果
环节切换动画:
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-enter-active {
animation: fadeInUp 0.4s ease-out;
}
资源卡片动画:
@keyframes popIn {
0% {
transform: scale(0.8);
opacity: 0;
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
opacity: 1;
}
}
.resource-card {
animation: popIn 0.3s ease-out;
}
星星收集动画:
@keyframes starCollect {
0% {
transform: scale(0) rotate(0deg);
opacity: 0;
}
50% {
transform: scale(1.3) rotate(180deg);
}
100% {
transform: scale(1) rotate(360deg);
opacity: 1;
}
}
.star-animation {
animation: starCollect 0.6s ease-out;
}
庆祝动画:
@keyframes confetti {
0% {
transform: translateY(-100%) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(720deg);
opacity: 0;
}
}
.confetti-piece {
position: fixed;
width: 10px;
height: 10px;
animation: confetti 3s ease-out forwards;
}
5.3 奖励机制
星星收集系统:
完成环节 → 收集星星 → 全部完成 → 庆祝动画
┌──────────────────────────────────────────────────────────────┐
│ ★ ★ ★ ★ ★ │
│ 已完成 4 个环节,继续加油! │
└──────────────────────────────────────────────────────────────┘
等级徽章:
- 3颗星:铜牌学员 🥉
- 5颗星:银牌学员 🥈
- 7颗星:金牌学员 🥇
- 全部完成:超级小英雄 🦸♂️
庆祝画面:
┌──────────────────────────────────────────────────────────────┐
│ │
│ 🎉 太棒了!🎉 │
│ │
│ 你完成了所有教学环节! │
│ │
│ 🏆 超级小英雄 🏆 │
│ │
│ [ 再来一次 ] [ 返回首页 ] │
│ │
└──────────────────────────────────────────────────────────────┘
6. 导航控制设计
6.1 底部导航栏设计
完整布局:
┌──────────────────────────────────────────────────────────────┐
│ 🎯 教学环节 │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ 1️⃣ │ │ 2️⃣ │ │ 3️⃣ │ │ 4️⃣ │ ... │
│ │导入│ │共读│ │讨论│ │活动│ │
│ └────┘ └────┘ └────┘ └────┘ │
│ ⭐ ⭐ ⭐ ⬜ │
│ │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
│ 1/4 环节 │ │
│ 05:32 │ │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
│ │
│ 🎨 延伸活动 (可选) │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 🎨 │ │ 🎮 │ │ 🎵 │ │
│ │美工│ │游戏│ │音乐│ │
│ └──────┘ └──────┘ └──────┘ │
│ │
│ [ ◀️ 上一环节 ] [ ▶️ 下一环节 ] [ ❌ 退出展播 ] │
│ │
└──────────────────────────────────────────────────────────────┘
6.2 控制按钮规范
.ctrl-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 14px 28px;
border-radius: 28px;
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(0, 0, 0, 0.1);
color: #2D3436;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
&:hover:not(:disabled) {
background: white;
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}
&:active:not(:disabled) {
transform: translateY(0);
}
&:disabled {
opacity: 0.4;
cursor: not-allowed;
}
// 主要按钮(下一环节)
&.primary {
background: linear-gradient(135deg, #FF8C42, #E67635);
border: none;
color: white;
font-size: 18px;
padding: 14px 32px;
box-shadow: 0 6px 20px rgba(255, 140, 66, 0.3);
&:hover:not(:disabled) {
background: linear-gradient(135deg, #FF7A2A, #E67635);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(255, 140, 66, 0.4);
}
}
// 退出按钮
&.exit {
background: rgba(255, 77, 79, 0.1);
border-color: rgba(255, 77, 79, 0.3);
color: #ff4d4f;
&:hover {
background: rgba(255, 77, 79, 0.2);
}
}
}
6.3 快捷键设计
| 快捷键 | 功能 | 说明 |
|---|---|---|
| ← / A | 上一环节 | 方便左右手操作 |
| → / D | 下一环节 | 方便左右手操作 |
| 空格 | 暂停/播放 | 大按钮,易操作 |
| ESC | 退出展播 | 紧急退出 |
| F11 | 全屏切换 | 沉浸式体验 |
| ↑ / ↓ | 音量调节 | 便于控制 |
7. 响应式设计
7.1 屏幕适配
┌─────────────────────────────────────────────────────────────┐
│ 屏幕类型 | 比例 | 设计重点 │
├─────────────────────────────────────────────────────────────┤
│ 智能屏/投影仪 | 16:9 | 大屏显示、多人观看 │
│ 传统投影仪 | 4:3 | 居中显示、边缘裁剪 │
│ 平板横屏 | 16:9 | 触摸优化、手势支持 │
│ 平板竖屏 | 9:16 | 调整布局、上下滚动 │
└─────────────────────────────────────────────────────────────┘
7.2 断点规范
// 响应式断点
$breakpoint-sm: 768px; // 平板
$breakpoint-md: 1024px; // 小桌面
$breakpoint-lg: 1280px; // 桌面
$breakpoint-xl: 1536px; // 大屏
// 响应式 mixins
@mixin respond-to($breakpoint) {
@media (min-width: $breakpoint) {
@content;
}
}
// 针对不同屏幕尺寸调整
.broadcast-view {
@include respond-to($breakpoint-lg) {
// 大屏:显示完整资源
.resource-card {
flex: 0 0 280px;
}
}
@include respond-to($breakpoint-md) {
// 中屏:缩小资源卡片
.resource-card {
flex: 0 0 240px;
}
}
@include respond-to($breakpoint-sm) {
// 小屏:横向滚动
.resource-card {
flex: 0 0 200px;
}
}
}
7.3 字体缩放
// 根据屏幕尺寸调整字体
html {
font-size: 16px;
@media (max-width: 768px) {
font-size: 14px;
}
@media (min-width: 1536px) {
font-size: 18px;
}
}
8. 技术实现
8.1 组件结构
BroadcastView.vue (展播入口)
├─ KidsMode.vue (儿童友好界面)
│ ├─ EbookViewer.vue (绘本阅读器)
│ ├─ VideoPlayer.vue (视频播放器)
│ ├─ AudioPlayer.vue (音频播放器)
│ └─ SlidesViewer.vue (PPT/挂图查看器)
8.2 状态管理
interface BroadcastState {
// 课程数据
course: Course | null;
lessons: Lesson[];
activities: Activity[];
// 当前位置
currentLessonIndex: number;
currentStepIndex: number;
// 资源状态
currentResourceType: 'ebook' | 'video' | 'audio' | 'ppt' | 'poster' | '';
currentResourceUrl: string;
showingResource: Resource | null;
// UI状态
controlsVisible: boolean;
activityModalVisible: boolean;
// 进度
progressPercent: number;
timerSeconds: number;
}
8.3 资源处理
资源URL处理:
const getFileUrl = (filePath: string): string => {
if (!filePath) return '';
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
return filePath;
}
const SERVER_BASE = import.meta.env.VITE_SERVER_BASE_URL || 'http://localhost:3000';
return `${SERVER_BASE}${filePath}`;
};
资源类型图标映射:
const resourceIconMap: Record<string, Component> = {
'image': PictureOutlined,
'video': VideoCameraOutlined,
'audio': AudioOutlined,
'ppt': FilePptOutlined,
'poster: FileImageOutlined,
'ebook': BookOutlined,
};
8.4 动画库选择
推荐使用:
- Vue Transition - 内置过渡动画
- Animate.css - CSS动画库(可选)
- Lottie - JSON动画(高级)
9. 设计规范
9.1 间距规范
$spacing-xs: 4px;
$spacing-sm: 8px;
$spacing-md: 12px;
$spacing-lg: 16px;
$spacing-xl: 20px;
$spacing-xxl: 24px;
$spacing-xxxl: 32px;
9.2 阴影规范
// 卡片阴影
$shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
$shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08);
$shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
// 按钮阴影
$shadow-button: 0 4px 12px rgba(255, 140, 66, 0.3);
$shadow-button-hover: 0 6px 16px rgba(255, 140, 66, 0.4);
9.3 动画时长
$duration-fast: 0.2s;
$duration-normal: 0.3s;
$duration-slow: 0.5s;
$duration-slower: 0.8s;
9.4 Z-index 层级
$z-modal: 1000;
$z-dropdown: 1050;
$z-sticky: 1020;
$z-fixed: 1030;
$z-tooltip: 1060;
附录:三类课程特色展示
A. 导入课
主题图标: 🔍 (放大镜)
配色: 温暖橙 #FF8C42
特色元素:
- 强调"认识"和"发现"
- 大图标、清晰指引
- 温馨鼓励语
B. 集体课
主题图标: 📖 (打开的书)
配色: 天空蓝 #74B9FF
特色元素:
- 突出"共读"主题
- 绘本封面展示
- 互动问题提示
C. 领域课
配色方案:
- 语言:📝 天空蓝 #74B9FF
- 健康:❤️ 珊瑚粉 #FF7675
- 科学:🔬 紫罗兰 #9B59B6
- 社会:👥 青色 #00D9A5
- 艺术:🎨 粉色 #FF7675
特色元素:
- 按领域区分的图标和配色
- 领域特定的教学目标
- 专业活动指导
总结
本设计文档提供了展播模式优化的完整方案,包括:
- 儿童友好的视觉风格 - 温暖配色、圆润设计、活泼装饰
- 美观的资源陈列 - 卡片式布局、清晰分类、易于选择
- 流畅的播放体验 - 大按钮、自定义控件、动画过渡
- 丰富的互动元素 - 音效反馈、动画效果、奖励机制
- 简化的导航控制 - 大按钮、快捷键、儿童易操作
按照此设计实现,将为幼儿提供更加友好、有趣的展播体验!🎉
下一步:
- 审阅设计文档,确认优化方向
- 开始技术实现,按优先级逐步推进
- 边实现边测试,收集用户反馈
文档创建于 2026-03-11