Files
child-learning/src/components/ExternalLearningArea.vue
2026-03-02 22:40:49 +08:00

820 lines
18 KiB
Vue
Raw 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.

<template>
<div class="external-learning-area">
<div class="learning-header">
<div class="header-icon">📚</div>
<h2 class="header-title">课外学习天地</h2>
<p class="header-subtitle">点击链接开启知识探索之旅</p>
</div>
<!-- 学习资源分类 -->
<div class="learning-categories">
<button
v-for="category in categories"
:key="category.id"
class="category-btn"
:class="{ active: activeCategory === category.id }"
@click="setActiveCategory(category.id)"
>
<span class="category-icon">{{ category.icon }}</span>
<span class="category-name">{{ category.name }}</span>
</button>
</div>
<!-- 学习资源列表 -->
<div class="resources-container">
<div
v-for="resource in filteredResources"
:key="resource.id"
class="resource-card"
@click="openResource(resource)"
>
<div class="resource-icon">{{ resource.icon }}</div>
<div class="resource-content">
<h3 class="resource-title">{{ resource.title }}</h3>
<p class="resource-description">{{ resource.description }}</p>
<div class="resource-meta">
<span class="resource-age">{{ resource.ageRange }}</span>
<span class="resource-tag">{{ resource.tag }}</span>
</div>
</div>
<div class="resource-action">
<div class="go-btn">
<span>去学习</span>
<span>🚀</span>
</div>
</div>
</div>
</div>
<!-- 提示信息 -->
<div class="learning-tips">
<div class="tips-icon">💡</div>
<div class="tips-content">
<h4>温馨提示</h4>
<ul>
<li>每次学习时间建议控制在15-30分钟</li>
<li>学习后可以回来记录学习心得获得额外星星能量</li>
<li>学习过程中有家长陪同效果更好哦</li>
</ul>
</div>
</div>
<!-- 学习记录弹窗 -->
<div v-if="showRecordModal" class="modal-overlay" @click="closeRecordModal">
<div class="modal-content learning-record-modal" @click.stop>
<div class="modal-emoji">📝</div>
<h3 class="modal-title">记录学习成果</h3>
<p class="modal-message">你今天学习了什么</p>
<div class="record-inputs">
<div class="input-group">
<label>学习内容</label>
<textarea
v-model="recordContent"
class="record-textarea"
placeholder="说说你学到了什么..."
rows="3"
></textarea>
</div>
<div class="learning-duration">
<label>学习时长</label>
<div class="duration-options">
<button
v-for="duration in durationOptions"
:key="duration.value"
class="duration-btn"
:class="{ active: selectedDuration === duration.value }"
@click="selectedDuration = duration.value"
>
{{ duration.label }}
</button>
</div>
</div>
</div>
<div class="modal-buttons">
<button class="modal-btn" @click="submitRecord">提交记录</button>
<button class="modal-btn secondary" @click="closeRecordModal">稍后再说</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { useStarEnergyStore } from '../stores/starEnergy';
const starEnergyStore = useStarEnergyStore();
// 当前选中的分类
const activeCategory = ref('all');
// 学习记录相关
const showRecordModal = ref(false);
const recordContent = ref('');
const selectedDuration = ref(15);
const currentResource = ref<any>(null);
// 学习时长选项
const durationOptions = [
{ value: 10, label: '10分钟' },
{ value: 15, label: '15分钟' },
{ value: 20, label: '20分钟' },
{ value: 30, label: '30分钟' }
];
// 学习资源分类
const categories = [
{ id: 'all', name: '全部', icon: '🌟' },
{ id: 'english', name: '英语学习', icon: '🔤' },
{ id: 'science', name: '科学实验', icon: '🔬' },
{ id: 'geography', name: '地理知识', icon: '🌍' },
{ id: 'math', name: '趣味数学', icon: '🔢' },
{ id: 'art', name: '艺术创作', icon: '🎨' },
{ id: 'history', name: '历史文化', icon: '📜' }
];
// 学习资源数据
const resources = ref([
// 英语学习
{
id: 'en1',
category: 'english',
title: '六一儿童网-英文儿歌',
description: '海量英文儿歌动画边听边学适合3-12岁孩子启蒙',
url: 'http://www.61ertong.com/zt/etywgq/',
icon: '🎵',
ageRange: '3-12岁',
tag: '儿歌'
},
{
id: 'en2',
category: 'english',
title: '国家中小学智慧教育平台',
description: '教育部官方平台,小学英语课程教学资源',
url: 'https://basic.smartedu.cn/',
icon: '📚',
ageRange: '6-12岁',
tag: '官网'
},
// 科学实验
{
id: 'sc1',
category: 'science',
title: '儿童趣味科学实验',
description: '适合7岁以上儿童的科学实验视频孩子绝对爱看且能看懂',
url: 'https://www.bilibili.com/video/BV1734y1x7No',
icon: '🧪',
ageRange: '7-12岁',
tag: '视频'
},
{
id: 'sc2',
category: 'science',
title: '科学趣味动画片',
description: '小学生科学趣味动画,用动画形式讲科学,孩子一看就懂',
url: 'https://www.bilibili.com/video/BV1XJUKYPEtw',
icon: '🎬',
ageRange: '6-10岁',
tag: '动画'
},
{
id: 'sc3',
category: 'science',
title: '中国数字科技馆',
description: '中国科协、教育部、中科院共建,适合儿童的科普内容',
url: 'http://www.cdstm.cn/',
icon: '🔬',
ageRange: '6-12岁',
tag: '官网'
},
// 地理知识
{
id: 'geo1',
category: 'geography',
title: '地球科学趣味动画',
description: '小学生科学趣味动画片,从地球形成到火山地震,孩子爱看',
url: 'https://www.bilibili.com/search?keyword=小学生科学趣味动画片',
icon: '🌍',
ageRange: '6-10岁',
tag: '动画'
},
{
id: 'geo2',
category: 'geography',
title: '中国国家地理',
description: '国家级地理杂志网站,适合家长带孩子一起看',
url: 'https://www.dili360.com/',
icon: '🏔️',
ageRange: '8-12岁',
tag: '官网'
},
// 趣味数学
{
id: 'math1',
category: 'math',
title: '数学游乐场',
description: '免费免注册的数学学习网站融合游戏和学习适合3-8岁儿童',
url: 'https://www.mathplayground.com/',
icon: '🎮',
ageRange: '3-8岁',
tag: '网站'
},
{
id: 'math2',
category: 'math',
title: '免费数独游戏在线',
description: '经典数独游戏,提供多种难度,可免费在线玩',
url: 'https://sj.qq.com/topic/200076907',
icon: '🧩',
ageRange: '6-12岁',
tag: '游戏'
},
{
id: 'math3',
category: 'math',
title: '国家中小学智慧教育平台-数学',
description: '教育部官方小学数学课程资源',
url: 'https://basic.smartedu.cn/',
icon: '🧮',
ageRange: '6-12岁',
tag: '官网'
},
// 艺术创作
{
id: 'art1',
category: 'art',
title: '六一儿童网',
description: '适合1-6岁宝宝的儿童网站有儿歌、故事、绘画等内容',
url: 'http://www.61ertong.com/',
icon: '🎨',
ageRange: '3-8岁',
tag: '官网'
},
{
id: 'art2',
category: 'art',
title: '中国少儿艺教网',
description: '少儿美术教育网站,提供绘画教程、比赛、展览等活动',
url: 'http://www.art-child.com/',
icon: '🖌️',
ageRange: '5-12岁',
tag: '官网'
},
// 历史文化
{
id: 'his1',
category: 'history',
title: '故宫博物院青少网站',
description: '故宫博物院青少年专题网站,寓教于乐学习传统文化',
url: 'http://young.dpm.org.cn/',
icon: '🏛️',
ageRange: '6-15岁',
tag: '青少年'
},
{
id: 'his2',
category: 'history',
title: '国家图书馆少儿数字图书馆',
description: '海量电子书,双语绘本、科普书、动漫图书,还有有声读物',
url: 'https://kids.nlc.cn/',
icon: '📖',
ageRange: '6-12岁',
tag: '官网'
},
{
id: 'his3',
category: 'history',
title: '语文迷',
description: '专业儿童语文学习网站,成语故事、睡前故事、国学启蒙',
url: 'https://www.yuwenmi.com/',
icon: '📜',
ageRange: '6-12岁',
tag: '官网'
}
]);
// 过滤资源
const filteredResources = computed(() => {
if (activeCategory.value === 'all') {
return resources.value;
}
return resources.value.filter(r => r.category === activeCategory.value);
});
// 设置分类
const setActiveCategory = (categoryId: string) => {
activeCategory.value = categoryId;
};
// 打开学习资源
const openResource = (resource: any) => {
currentResource.value = resource;
// 询问是否记录学习
showRecordModal.value = true;
// 在新窗口打开链接
window.open(resource.url, '_blank');
};
// 提交学习记录
const submitRecord = () => {
if (!recordContent.value.trim()) {
alert('请写点什么吧!比如学到了什么,有什么收获...');
return;
}
// 根据学习时长计算奖励星星
const energyReward = Math.floor(selectedDuration.value / 10);
// 增加星星能量
starEnergyStore.addEnergy(energyReward);
alert(`太棒了!你学习了 ${selectedDuration.value} 分钟,获得 ${energyReward} 颗星星能量!⭐`);
// 重置表单
recordContent.value = '';
selectedDuration.value = 15;
showRecordModal.value = false;
currentResource.value = null;
};
// 关闭学习记录弹窗
const closeRecordModal = () => {
showRecordModal.value = false;
recordContent.value = '';
selectedDuration.value = 15;
currentResource.value = null;
};
</script>
<style scoped>
.external-learning-area {
padding: 20px;
max-width: 1400px;
margin: 0 auto;
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 标题区域 */
.learning-header {
text-align: center;
margin-bottom: 30px;
position: relative;
}
.header-icon {
font-size: 80px;
margin-bottom: 15px;
animation: bounce 2s ease-in-out infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-15px); }
}
.header-title {
font-size: 32px;
font-weight: bold;
color: #FF6B6B;
margin: 0 0 10px 0;
text-shadow: 2px 2px 0 #FFD700;
}
.header-subtitle {
font-size: 18px;
color: #666;
margin: 0;
}
/* 分类按钮 */
.learning-categories {
display: flex;
flex-wrap: wrap;
gap: 12px;
justify-content: center;
margin-bottom: 30px;
}
.category-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 20px;
border: 3px solid #E0E0E0;
border-radius: 25px;
background: white;
cursor: pointer;
transition: all 0.3s ease;
font-size: 16px;
font-weight: bold;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
}
.category-btn:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
.category-btn.active {
background: linear-gradient(135deg, #FF6B6B, #4ECDC4);
color: white;
border-color: #FFD700;
box-shadow: 0 6px 20px rgba(255, 107, 107, 0.4);
}
.category-icon {
font-size: 20px;
}
/* 资源卡片 */
.resources-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.resource-card {
display: flex;
align-items: center;
gap: 15px;
padding: 20px;
background: white;
border: 4px solid #E0E0E0;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.resource-card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.4), transparent);
transform: rotate(45deg);
animation: shine 3s ease-in-out infinite;
}
@keyframes shine {
0% { transform: translateX(-100%) rotate(45deg); }
100% { transform: translateX(100%) rotate(45deg); }
}
.resource-card:hover {
transform: translateY(-8px) scale(1.03);
border-color: #FFD700;
box-shadow: 0 12px 35px rgba(0, 0, 0, 0.2), 0 0 30px rgba(255, 215, 0, 0.3);
}
.resource-icon {
font-size: 48px;
flex-shrink: 0;
animation: floatUp 3s ease-in-out infinite;
}
@keyframes floatUp {
0%, 100% { transform: translateY(0) translateX(0); }
25% { transform: translateY(-3px) translateX(2px); }
50% { transform: translateY(-6px) translateX(0); }
75% { transform: translateY(-3px) translateX(-2px); }
}
.resource-content {
flex: 1;
min-width: 0;
}
.resource-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin: 0 0 8px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.resource-description {
font-size: 14px;
color: #666;
margin: 0 0 10px 0;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.resource-meta {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.resource-age {
font-size: 12px;
padding: 4px 10px;
background: linear-gradient(135deg, #FFD700, #FFA500);
color: #333;
border-radius: 12px;
font-weight: bold;
}
.resource-tag {
font-size: 12px;
padding: 4px 10px;
background: linear-gradient(135deg, #4ECDC4, #44A08D);
color: white;
border-radius: 12px;
font-weight: bold;
}
.resource-action {
flex-shrink: 0;
}
.go-btn {
display: flex;
align-items: center;
gap: 5px;
padding: 10px 15px;
background: linear-gradient(135deg, #FF6B6B, #4ECDC4);
color: white;
border-radius: 15px;
font-weight: bold;
font-size: 14px;
transition: all 0.3s ease;
}
.resource-card:hover .go-btn {
transform: scale(1.1);
}
/* 温馨提示 */
.learning-tips {
background: linear-gradient(135deg, #FFF9C4, #FFE082);
border: 4px solid #FFD700;
border-radius: 20px;
padding: 20px;
display: flex;
gap: 15px;
align-items: flex-start;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.tips-icon {
font-size: 48px;
flex-shrink: 0;
animation: bounce 2s ease-in-out infinite;
}
.tips-content h4 {
font-size: 18px;
color: #FF6B6B;
margin: 0 0 10px 0;
}
.tips-content ul {
list-style: none;
padding: 0;
margin: 0;
}
.tips-content li {
font-size: 14px;
color: #555;
margin-bottom: 8px;
padding-left: 25px;
position: relative;
}
.tips-content li::before {
content: '⭐';
position: absolute;
left: 0;
}
/* 学习记录弹窗 */
.learning-record-modal {
max-width: 500px;
width: 90%;
}
.record-inputs {
margin: 20px 0;
}
.input-group {
margin-bottom: 20px;
}
.input-group label {
display: block;
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.record-textarea {
width: 100%;
padding: 12px;
border: 3px solid #E0E0E0;
border-radius: 12px;
font-size: 14px;
font-family: inherit;
resize: vertical;
transition: all 0.3s ease;
}
.record-textarea:focus {
outline: none;
border-color: #4ECDC4;
box-shadow: 0 0 15px rgba(78, 205, 196, 0.3);
}
.learning-duration {
margin-bottom: 15px;
}
.learning-duration label {
display: block;
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.duration-options {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.duration-btn {
padding: 10px 20px;
border: 3px solid #E0E0E0;
border-radius: 15px;
background: white;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
font-weight: bold;
}
.duration-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
}
.duration-btn.active {
background: linear-gradient(135deg, #4ECDC4, #44A08D);
color: white;
border-color: #4ECDC4;
}
/* Modal 通用样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(5px);
}
.modal-content {
background: white;
border-radius: 25px;
padding: 30px;
text-align: center;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
border: 5px solid #FFD700;
animation: modalIn 0.3s ease-out;
}
@keyframes modalIn {
from {
opacity: 0;
transform: scale(0.8) translateY(-20px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.modal-emoji {
font-size: 64px;
margin-bottom: 15px;
animation: bounce 2s ease-in-out infinite;
}
.modal-title {
font-size: 28px;
font-weight: bold;
color: #FF6B6B;
margin: 0 0 10px 0;
text-shadow: 2px 2px 0 #FFD700;
}
.modal-message {
font-size: 16px;
color: #666;
margin: 0 0 20px 0;
}
.modal-buttons {
display: flex;
gap: 15px;
justify-content: center;
margin-top: 20px;
}
.modal-btn {
padding: 12px 30px;
border: none;
border-radius: 20px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.modal-btn {
background: linear-gradient(135deg, #FF6B6B, #4ECDC4);
color: white;
}
.modal-btn:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.modal-btn.secondary {
background: linear-gradient(135deg, #E0E0E0, #BDBDBD);
color: #333;
}
.modal-btn.secondary:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
}
/* 响应式 */
@media (max-width: 768px) {
.header-title {
font-size: 24px;
}
.header-subtitle {
font-size: 14px;
}
.resources-container {
grid-template-columns: 1fr;
}
.resource-card {
padding: 15px;
}
.category-btn {
padding: 10px 15px;
font-size: 14px;
}
}
</style>