新增课程详情页面以及其他的页面

This commit is contained in:
username 2025-07-23 22:26:46 +08:00
parent 4c69fdf4fc
commit 11f10ca0c8
10 changed files with 3858 additions and 1112 deletions

125
docs/Activities-Page.md Normal file
View File

@ -0,0 +1,125 @@
# 活动页面 (Activities Page)
## 📋 概述
活动页面是在线学习平台的重要组成部分展示所有可用的学习活动和课程。页面设计完全按照提供的UI设计图实现包含蓝色横幅区域和活动卡片网格布局。
## 🎨 页面结构
### 1. 蓝色横幅区域 (Hero Banner)
- **背景**: 蓝色渐变背景 (#4A90E2#357ABD)
- **左侧内容**:
- 分类标签: "理工/消安/药师/中经"
- 主标题: "免费海量题库" + 橙色"小程序"标签
- 特色说明: "优质试题 | 无需下载 | 随时刷题"
- **右侧**: 插图占位区域(预留给后续图片)
- **装饰元素**: 网格背景纹理
### 2. 活动列表区域
- **标题**: "全部活动"
- **布局**: 3列网格布局响应式
- **活动卡片**: 6个相同样式的卡片
### 3. 活动卡片设计
每个卡片包含:
- **头部**: 蓝绿色渐变背景
- 年份标签: "2025"
- 课程标题: "计算机二级"
- 课程副标题: "C语言讲练综合班"
- **主体内容**:
- 特色标签: "系统备考"、"考点详解"、"题考刷题"
- 课程信息: 证书名称、开课时间、适合年级、报名人数、价格
- **底部**: 蓝色"查看详情"按钮
## 🎯 功能特性
### 1. 响应式设计
- **桌面端**: 3列网格布局
- **平板端**: 2列网格布局
- **移动端**: 1列网格布局
### 2. 交互效果
- **卡片悬停**: 阴影加深 + 向上移动
- **按钮悬停**: 颜色变化 + 轻微上移
- **加载动画**: 骨架屏效果
### 3. 动画效果
- **页面加载**: 左右滑入动画
- **卡片显示**: 渐入上移动画(错开延迟)
- **加载状态**: 闪烁骨架屏
## 🛠️ 技术实现
### 文件结构
```
src/views/Activities.vue # 活动页面主组件
src/router/index.ts # 路由配置
src/components/layout/AppHeader.vue # 导航栏更新
```
### 核心技术
- **Vue 3 Composition API**: 组件逻辑
- **TypeScript**: 类型安全
- **CSS Grid**: 响应式布局
- **CSS Animations**: 动画效果
- **Vue Router**: 路由导航
### 样式特点
- **渐变背景**: 多层次视觉效果
- **卡片设计**: 现代化卡片样式
- **颜色系统**: 蓝色主题 + 橙色点缀
- **字体层级**: 清晰的信息层次
## 🔗 导航集成
活动页面已集成到主导航栏中:
- 导航项: "活动" (带NEW标签)
- 路由路径: `/activities`
- 页面标题: "全部活动 - 在线学习平台"
## 📱 响应式断点
```css
/* 大屏幕 (>1024px) */
.activities-grid { grid-template-columns: repeat(3, 1fr); }
/* 平板 (≤1024px) */
.activities-grid { grid-template-columns: repeat(2, 1fr); }
/* 手机 (≤768px) */
.activities-grid { grid-template-columns: 1fr; }
```
## 🎨 设计规范
### 颜色规范
- **主色调**: #4A90E2 (蓝色)
- **辅助色**: #44A08D (蓝绿色)
- **强调色**: #FF6B35 (橙色)
- **文字色**: #333 (深灰)
- **次要文字**: #666 (中灰)
### 间距规范
- **容器边距**: 20px (移动端) / 30px (桌面端)
- **卡片间距**: 20px (移动端) / 30px (桌面端)
- **内容边距**: 16px-24px
### 圆角规范
- **卡片圆角**: 12px
- **按钮圆角**: 6px
- **标签圆角**: 4px
## 🚀 使用方法
1. **访问页面**: 点击导航栏"活动"或直接访问 `/activities`
2. **浏览活动**: 滚动查看所有可用活动
3. **查看详情**: 点击"查看详情"按钮(当前为演示功能)
4. **响应式体验**: 在不同设备上自动适配布局
## 📝 后续扩展
1. **图片集成**: 添加横幅插图和活动图片
2. **数据接口**: 连接后端API获取真实活动数据
3. **详情页面**: 实现活动详情页面跳转
4. **筛选功能**: 添加活动分类和筛选功能
5. **搜索功能**: 实现活动搜索功能

158
docs/Banner-Image-Setup.md Normal file
View File

@ -0,0 +1,158 @@
# 活动页面横幅图片设置指南
## 📋 概述
活动页面的横幅区域已经改为支持一整张图片的形式。目前显示占位内容,您可以按照以下步骤添加横幅图片。
## 🖼️ 当前状态
- ✅ 横幅区域已改为图片容器
- ✅ 响应式设计已适配
- ✅ 占位内容显示中
- ⏳ 等待提供横幅图片
## 📐 图片规格建议
### 推荐尺寸
- **桌面端**: 1200px × 400px
- **平板端**: 1024px × 350px
- **移动端**: 768px × 300px
### 文件格式
- **推荐**: JPG/JPEG (文件小,加载快)
- **支持**: PNG (支持透明背景)
- **支持**: WebP (现代浏览器,更小文件)
### 文件大小
- **建议**: < 500KB
- **最大**: < 1MB
## 🚀 添加图片的方法
### 方法一:直接替换(推荐)
1. **将图片文件放到项目中**
```
public/images/activities-banner.jpg
```
2. **修改 Activities.vue 文件**
```typescript
// 在 onMounted 中取消注释并设置图片路径
onMounted(() => {
setTimeout(() => {
loading.value = false
}, 800)
// 设置横幅图片路径
setBannerImage('/images/activities-banner.jpg')
})
```
### 方法二:直接设置变量
`src/views/Activities.vue` 中找到这一行:
```typescript
const bannerImageSrc = ref('')
```
改为:
```typescript
const bannerImageSrc = ref('/images/activities-banner.jpg')
```
## 📁 推荐的文件结构
```
public/
├── images/
│ ├── activities-banner.jpg # 横幅图片
│ ├── activities-banner-tablet.jpg # 平板版本(可选)
│ └── activities-banner-mobile.jpg # 移动版本(可选)
```
## 🎨 图片内容建议
根据原设计图,横幅图片应该包含:
- 蓝色渐变背景
- "理工/消安/药师/中经" 分类文字
- "免费海量题库" 主标题
- "小程序" 橙色标签
- "优质试题 | 无需下载 | 随时刷题" 特色说明
- 右侧人物和手机界面插图
## 🔧 技术实现细节
### 当前代码结构
```vue
<template>
<div class="hero-banner">
<div class="banner-image-container">
<!-- 实际图片 -->
<img
v-if="hasBannerImage"
:src="bannerImageSrc"
alt="活动横幅"
class="banner-image"
/>
<!-- 占位区域 -->
<div v-else class="banner-placeholder">
<!-- 占位内容 -->
</div>
</div>
</div>
</template>
```
### 响应式适配
- 桌面端400px 高度
- 平板端350px 高度
- 移动端300px 高度
- 小屏手机250px 高度
### CSS 样式
```css
.banner-image {
width: 100%;
height: 100%;
object-fit: cover; /* 保持比例,裁剪多余部分 */
object-position: center; /* 居中显示 */
}
```
## ⚡ 性能优化建议
1. **图片压缩**: 使用工具压缩图片文件
2. **懒加载**: 大图片可考虑懒加载
3. **多尺寸**: 为不同设备提供不同尺寸的图片
4. **WebP格式**: 现代浏览器使用WebP格式
## 🔄 更新步骤
当您准备好横幅图片时:
1. **准备图片文件**
- 确保图片符合推荐规格
- 压缩图片文件大小
2. **上传图片**
- 将图片放到 `public/images/` 目录
3. **更新代码**
- 按照上述方法一或方法二设置图片路径
4. **测试效果**
- 刷新浏览器查看效果
- 测试不同设备的显示效果
## 📞 需要帮助?
如果您在设置横幅图片时遇到任何问题,请:
1. 检查图片路径是否正确
2. 确认图片文件是否存在
3. 查看浏览器控制台是否有错误信息
4. 联系开发人员获取技术支持
---
**注意**: 当前页面显示占位内容,一旦您提供横幅图片并按照上述步骤设置,占位内容将自动被实际图片替换。

View File

@ -0,0 +1,175 @@
# 师资力量页面横幅图片设置指南
## 📋 概述
师资力量页面的横幅区域已经改为支持一整张图片的形式。目前显示占位内容,您可以按照以下步骤添加横幅图片。
## 🖼️ 当前状态
- ✅ 横幅区域已改为图片容器
- ✅ 响应式设计已适配
- ✅ 占位内容显示中
- ⏳ 等待提供横幅图片
## 📐 图片规格建议
### 推荐尺寸
- **桌面端**: 1200px × 400px
- **平板端**: 1024px × 350px
- **移动端**: 768px × 300px
- **小屏手机**: 480px × 250px
### 文件格式
- **推荐**: JPG/JPEG (文件小,加载快)
- **支持**: PNG (支持透明背景)
- **支持**: WebP (现代浏览器,更小文件)
### 文件大小
- **建议**: < 500KB
- **最大**: < 1MB
## 🚀 添加图片的方法
### 方法一:直接替换(推荐)
1. **将图片文件放到项目中**
```
public/images/faculty-banner.jpg
```
2. **修改 Faculty.vue 文件**
```typescript
// 在文件开头找到这一行
const bannerImageSrc = ref('')
// 改为
const bannerImageSrc = ref('/images/faculty-banner.jpg')
```
### 方法二:使用设置方法
`src/views/Faculty.vue` 中添加初始化代码:
```typescript
import { ref, computed, onMounted } from 'vue'
// 在组件挂载时设置图片
onMounted(() => {
setBannerImage('/images/faculty-banner.jpg')
})
```
## 📁 推荐的文件结构
```
public/
├── images/
│ ├── faculty-banner.jpg # 师资力量横幅图片
│ ├── faculty-banner-tablet.jpg # 平板版本(可选)
│ └── faculty-banner-mobile.jpg # 移动版本(可选)
```
## 🎨 图片内容建议
根据师资力量页面的特点,横幅图片应该包含:
- 专业的教育背景或学术氛围
- "师资力量"相关的标题文字
- 可能包含教师形象或教学场景
- 体现专业性和权威性的设计元素
- 与整体网站风格保持一致的色调
## 🔧 技术实现细节
### 当前代码结构
```vue
<template>
<div class="page-header">
<div class="banner-image-container">
<!-- 实际图片 -->
<img
v-if="hasBannerImage"
:src="bannerImageSrc"
alt="师资力量横幅"
class="banner-image"
/>
<!-- 占位区域 -->
<div v-else class="banner-placeholder">
<!-- 占位内容 -->
</div>
</div>
</div>
</template>
```
### 响应式适配
- **桌面端**: 400px 高度
- **平板端**: 350px 高度
- **移动端**: 300px 高度
- **小屏手机**: 250px 高度
### CSS 样式特点
```css
.banner-image {
width: 100%;
height: 100%;
object-fit: cover; /* 保持比例,裁剪多余部分 */
object-position: center; /* 居中显示 */
}
.banner-placeholder {
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
/* 蓝色渐变背景作为占位 */
}
```
## ⚡ 性能优化建议
1. **图片压缩**: 使用工具压缩图片文件
2. **适当尺寸**: 避免使用过大的图片
3. **格式选择**: 优先使用JPG格式
4. **懒加载**: 大图片可考虑懒加载
## 🔄 更新步骤
当您准备好师资力量横幅图片时:
1. **准备图片文件**
- 确保图片符合推荐规格
- 压缩图片文件大小
- 检查图片内容是否符合师资力量主题
2. **上传图片**
- 将图片放到 `public/images/` 目录
- 确保文件名清晰易懂
3. **更新代码**
- 按照上述方法设置图片路径
- 确保路径正确无误
4. **测试效果**
- 访问 `/faculty` 页面查看效果
- 测试不同设备的显示效果
- 检查图片加载速度
## 🎯 与活动页面的区别
师资力量页面与活动页面的横幅设置方法相同,但内容主题不同:
- **活动页面**: 侧重课程活动和学习资源
- **师资力量页面**: 侧重教师团队和专业实力
## 📞 需要帮助?
如果您在设置师资力量横幅图片时遇到任何问题,请:
1. 检查图片路径是否正确
2. 确认图片文件是否存在于 `public/images/` 目录
3. 查看浏览器控制台是否有错误信息
4. 确保图片格式被浏览器支持
5. 联系开发人员获取技术支持
## 🔗 相关页面
- [活动页面横幅设置指南](./Banner-Image-Setup.md)
- [师资力量页面功能说明](./Faculty-Page.md)
---
**注意**: 当前页面显示占位内容,一旦您提供师资力量横幅图片并按照上述步骤设置,占位内容将自动被实际图片替换。页面访问地址:`http://localhost:3000/faculty`

View File

@ -195,16 +195,13 @@ const handleMenuSelect = (key: string) => {
router.push('/') router.push('/')
break break
case 'faculty': case 'faculty':
// router.push('/faculty')
router.push('/')
break break
case 'resources': case 'resources':
// router.push('/resources')
router.push('/')
break break
case 'activities': case 'activities':
// router.push('/activities')
router.push('/')
break break
} }
} }

View File

@ -10,6 +10,9 @@ import Profile from '@/views/Profile.vue'
import Login from '@/views/Login.vue' import Login from '@/views/Login.vue'
import Register from '@/views/Register.vue' import Register from '@/views/Register.vue'
import LearningPaths from '@/views/LearningPaths.vue' import LearningPaths from '@/views/LearningPaths.vue'
import Faculty from '@/views/Faculty.vue'
import Resources from '@/views/Resources.vue'
import Activities from '@/views/Activities.vue'
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
{ {
@ -78,6 +81,30 @@ const routes: RouteRecordRaw[] = [
title: '学习路径' title: '学习路径'
} }
}, },
{
path: '/faculty',
name: 'Faculty',
component: Faculty,
meta: {
title: '师资力量'
}
},
{
path: '/resources',
name: 'Resources',
component: Resources,
meta: {
title: '精选资源'
}
},
{
path: '/activities',
name: 'Activities',
component: Activities,
meta: {
title: '全部活动'
}
},
{ {
path: '/:pathMatch(.*)*', path: '/:pathMatch(.*)*',
name: 'NotFound', name: 'NotFound',

630
src/views/Activities.vue Normal file
View File

@ -0,0 +1,630 @@
<template>
<div class="activities-page">
<!-- 横幅图片区域 -->
<div class="hero-banner">
<div class="banner-image-container">
<!-- 实际图片 -->
<img
v-if="hasBannerImage"
:src="bannerImageSrc"
alt="活动横幅"
class="banner-image"
/>
<!-- 图片占位区域 -->
<div v-else class="banner-placeholder">
<div class="placeholder-content">
<div class="placeholder-icon">🖼</div>
<div class="placeholder-text">横幅图片占位</div>
<div class="placeholder-desc">请提供横幅图片</div>
</div>
</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<div class="container">
<!-- 全部活动区域 -->
<section class="all-activities">
<h2 class="section-title">全部活动</h2>
<!-- 活动网格 -->
<div v-if="loading" class="loading-grid">
<div v-for="i in 6" :key="i" class="loading-card">
<div class="loading-shimmer"></div>
</div>
</div>
<div v-else class="activities-grid">
<div
v-for="activity in activities"
:key="activity.id"
class="activity-card"
>
<div class="card-header">
<div class="card-background">
<div class="year-badge">2025</div>
<div class="course-title">{{ activity.title }}</div>
<div class="course-subtitle">{{ activity.subtitle }}</div>
</div>
</div>
<div class="card-body">
<!-- 特色标签 -->
<div class="feature-tags">
<span
v-for="tag in activity.tags"
:key="tag"
class="feature-tag"
>
<i class="tag-icon"></i>
{{ tag }}
</span>
</div>
<!-- 课程信息 -->
<div class="course-info">
<div class="info-row">
<span class="info-label">{{ activity.courseTitle }}</span>
</div>
<div class="info-row">
<span class="info-text">{{ activity.schedule }}</span>
</div>
<div class="info-row">
<span class="info-text">{{ activity.duration }}</span>
</div>
<div class="info-row">
<span class="info-text">{{ activity.students }}</span>
</div>
<div class="info-row">
<span class="price">{{ activity.price }}</span>
</div>
</div>
<!-- 查看详情按钮 -->
<div class="card-footer">
<button class="detail-btn" @click="viewDetail(activity.id)">
查看详情
</button>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
//
const loading = ref(true)
// -
const bannerImageSrc = ref('')
//
const hasBannerImage = computed(() => bannerImageSrc.value.trim() !== '')
//
const activities = ref([
{
id: 1,
title: '计算机二级',
subtitle: 'C语言讲练综合班',
tags: ['系统备考', '考点详解', '题考刷题'],
courseTitle: '计算机二级C语言程序设计证书',
schedule: '开课时间2025.07.26-2025.09.28',
duration: '适合年级:高校本科生',
students: '已报名1468/2000',
price: '免费'
},
{
id: 2,
title: '计算机二级',
subtitle: 'C语言讲练综合班',
tags: ['系统备考', '考点详解', '题考刷题'],
courseTitle: '计算机二级C语言程序设计证书',
schedule: '开课时间2025.07.26-2025.09.28',
duration: '适合年级:高校本科生',
students: '已报名1468/2000',
price: '免费'
},
{
id: 3,
title: '计算机二级',
subtitle: 'C语言讲练综合班',
tags: ['系统备考', '考点详解', '题考刷题'],
courseTitle: '计算机二级C语言程序设计证书',
schedule: '开课时间2025.07.26-2025.09.28',
duration: '适合年级:高校本科生',
students: '已报名1468/2000',
price: '免费'
},
{
id: 4,
title: '计算机二级',
subtitle: 'C语言讲练综合班',
tags: ['系统备考', '考点详解', '题考刷题'],
courseTitle: '计算机二级C语言程序设计证书',
schedule: '开课时间2025.07.26-2025.09.28',
duration: '适合年级:高校本科生',
students: '已报名1468/2000',
price: '免费'
},
{
id: 5,
title: '计算机二级',
subtitle: 'C语言讲练综合班',
tags: ['系统备考', '考点详解', '题考刷题'],
courseTitle: '计算机二级C语言程序设计证书',
schedule: '开课时间2025.07.26-2025.09.28',
duration: '适合年级:高校本科生',
students: '已报名1468/2000',
price: '免费'
},
{
id: 6,
title: '计算机二级',
subtitle: 'C语言讲练综合班',
tags: ['系统备考', '考点详解', '题考刷题'],
courseTitle: '计算机二级C语言程序设计证书',
schedule: '开课时间2025.07.26-2025.09.28',
duration: '适合年级:高校本科生',
students: '已报名1468/2000',
price: '免费'
}
])
//
const viewDetail = (id: number) => {
console.log('查看活动详情:', id)
//
// router.push(`/activity/${id}`)
}
// 使
const setBannerImage = (imagePath: string) => {
bannerImageSrc.value = imagePath
}
//
onMounted(() => {
setTimeout(() => {
loading.value = false
}, 800)
//
// setBannerImage('/images/activities-banner.jpg')
})
</script>
<style scoped>
.activities-page {
min-height: 100vh;
background: #f8f9fa;
}
/* 横幅图片区域 */
.hero-banner {
width: 100%;
position: relative;
overflow: hidden;
}
.banner-image-container {
width: 100%;
height: 400px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.banner-image {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.banner-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.banner-placeholder::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
opacity: 0.3;
}
.placeholder-content {
text-align: center;
color: white;
position: relative;
z-index: 1;
}
.placeholder-icon {
font-size: 48px;
margin-bottom: 16px;
opacity: 0.8;
}
.placeholder-text {
font-size: 24px;
font-weight: 600;
margin-bottom: 8px;
}
.placeholder-desc {
font-size: 16px;
opacity: 0.8;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 主要内容区域 */
.main-content {
padding: 80px 0;
}
.section-title {
font-size: 28px;
font-weight: 600;
color: #333;
text-align: center;
margin: 0 0 50px 0;
}
/* 活动网格 */
.activities-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px;
}
.activity-card {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
cursor: pointer;
}
.activity-card:hover {
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
transform: translateY(-4px);
}
/* 卡片头部 */
.card-header {
position: relative;
height: 120px;
overflow: hidden;
}
.card-background {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #4ECDC4 0%, #44A08D 100%);
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
}
.card-background::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 80px;
height: 80px;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
transform: translate(30px, -30px);
}
.card-background::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 60px;
height: 60px;
background: rgba(255, 255, 255, 0.08);
border-radius: 50%;
transform: translate(-20px, 20px);
}
.year-badge {
position: absolute;
top: 15px;
left: 20px;
background: rgba(255, 255, 255, 0.9);
color: #44A08D;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
}
.course-title {
font-size: 18px;
font-weight: 600;
color: white;
margin-bottom: 4px;
position: relative;
z-index: 1;
}
.course-subtitle {
font-size: 16px;
color: rgba(255, 255, 255, 0.9);
position: relative;
z-index: 1;
}
/* 卡片主体 */
.card-body {
padding: 20px;
}
.feature-tags {
display: flex;
gap: 8px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.feature-tag {
display: flex;
align-items: center;
gap: 4px;
background: #FFF2E6;
color: #FF6B35;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.tag-icon {
font-size: 10px;
font-style: normal;
}
.course-info {
margin-bottom: 20px;
}
.info-row {
margin-bottom: 8px;
font-size: 13px;
color: #666;
line-height: 1.4;
}
.info-row:first-child {
margin-bottom: 12px;
}
.info-label {
font-weight: 600;
color: #333;
font-size: 14px;
}
.info-text {
color: #666;
}
.price {
color: #FF6B35;
font-weight: 600;
font-size: 14px;
}
/* 卡片底部 */
.card-footer {
text-align: center;
}
.detail-btn {
width: 100%;
padding: 10px 20px;
background: #4A90E2;
color: white;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.detail-btn:hover {
background: #357ABD;
transform: translateY(-1px);
}
/* 加载状态 */
.loading-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px;
}
.loading-card {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
height: 320px;
}
.loading-shimmer {
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
/* 动画效果 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.banner-image-container {
animation: fadeInUp 0.8s ease-out;
}
.activity-card {
animation: fadeInUp 0.6s ease-out;
animation-fill-mode: both;
}
.activity-card:nth-child(1) { animation-delay: 0.1s; }
.activity-card:nth-child(2) { animation-delay: 0.2s; }
.activity-card:nth-child(3) { animation-delay: 0.3s; }
.activity-card:nth-child(4) { animation-delay: 0.4s; }
.activity-card:nth-child(5) { animation-delay: 0.5s; }
.activity-card:nth-child(6) { animation-delay: 0.6s; }
/* 响应式设计 */
@media (max-width: 1024px) {
.activities-grid {
grid-template-columns: repeat(2, 1fr);
gap: 24px;
}
.banner-image-container {
height: 350px;
}
.placeholder-icon {
font-size: 40px;
}
.placeholder-text {
font-size: 20px;
}
}
@media (max-width: 768px) {
.activities-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.banner-image-container {
height: 300px;
}
.placeholder-icon {
font-size: 36px;
}
.placeholder-text {
font-size: 18px;
}
.placeholder-desc {
font-size: 14px;
}
.main-content {
padding: 40px 0;
}
.container {
padding: 0 16px;
}
}
@media (max-width: 480px) {
.banner-image-container {
height: 250px;
}
.placeholder-icon {
font-size: 32px;
}
.placeholder-text {
font-size: 16px;
}
.placeholder-desc {
font-size: 12px;
}
.feature-tags {
justify-content: center;
}
}
</style>

File diff suppressed because it is too large Load Diff

606
src/views/Faculty.vue Normal file
View File

@ -0,0 +1,606 @@
<template>
<div class="faculty-page">
<!-- 横幅图片区域 -->
<div class="page-header">
<div class="banner-image-container">
<!-- 实际图片 -->
<img
v-if="hasBannerImage"
:src="bannerImageSrc"
alt="师资力量横幅"
class="banner-image"
/>
<!-- 图片占位区域 -->
<div v-else class="banner-placeholder">
<div class="placeholder-content">
<div class="placeholder-icon">🖼</div>
<div class="placeholder-text">师资力量横幅图片占位</div>
<div class="placeholder-desc">请提供横幅图片</div>
</div>
</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<div class="container">
<!-- 筛选标签栏 -->
<div class="filter-tabs">
<button
v-for="tab in filterTabs"
:key="tab.id"
:class="['filter-tab', { active: activeTab === tab.id }]"
@click="activeTab = tab.id"
>
{{ tab.name }}
</button>
</div>
<!-- 师资卡片网格 -->
<div class="faculty-grid">
<div
v-for="teacher in paginatedTeachers"
:key="teacher.id"
class="faculty-card"
>
<div class="card-header">
<div class="avatar-container">
<!-- 头像占位 -->
<div class="avatar-placeholder"></div>
<div v-if="teacher.featured" class="featured-badge">金牌讲师</div>
</div>
<div class="card-arrow">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</div>
<div class="card-content">
<h3 class="teacher-name">{{ teacher.name }}</h3>
<p class="teacher-title">{{ teacher.title }}</p>
<p class="teacher-description">{{ teacher.description }}</p>
<div class="teacher-tags">
<span v-for="tag in teacher.tags" :key="tag" class="tag">{{ tag }}</span>
</div>
</div>
</div>
</div>
<!-- 分页组件 -->
<div class="pagination">
<button class="page-btn" :disabled="currentPage === 1" @click="goToPage(currentPage - 1)">
上一页
</button>
<button
v-for="page in visiblePages"
:key="page"
:class="['page-btn', { active: currentPage === page }]"
@click="typeof page === 'number' ? goToPage(page) : null"
:disabled="typeof page !== 'number'"
>
{{ page }}
</button>
<button class="page-btn" :disabled="currentPage === totalPages" @click="goToPage(currentPage + 1)">
下一页
</button>
<span class="page-info">{{ totalPages }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
//
const bannerImageSrc = ref('')
const hasBannerImage = computed(() => bannerImageSrc.value.trim() !== '')
// 使
const setBannerImage = (imagePath: string) => {
bannerImageSrc.value = imagePath
}
//
const filterTabs = ref([
{ id: 'all', name: '全部讲师' },
{ id: 'main', name: '主讲' },
{ id: 'international', name: '注册国际讲师' },
{ id: 'consultant', name: '咨询师' },
{ id: 'expert', name: '专家顾问' },
{ id: 'senior', name: '资深讲师' },
{ id: 'featured', name: '金牌讲师' },
{ id: 'enterprise', name: '企业导师' }
])
const activeTab = ref('all')
//
const teachers = ref([
{
id: 1,
name: '黄天羽',
title: '注册国际人才测评师资格认证',
description: '注册国际企业学习设计师 认证',
tags: ['主讲', '资深人才测评师'],
featured: true
},
{
id: 2,
name: '蓝天',
title: '北京理工大学MBA企业文化专家顾问',
description: '多家知名上市企业高管',
tags: ['主讲', 'MBA企业文化专家']
},
{
id: 3,
name: '万精云',
title: '中国人事科学',
description: '中国科学院博士',
tags: ['主讲', '人事专家']
},
{
id: 4,
name: '张庆勋',
title: '北京大学博士',
description: '内蒙古财经大学',
tags: ['主讲', '金牌讲师']
},
{
id: 5,
name: '程毅',
title: '中国科技大学博士研究生',
description: '',
tags: ['主讲', '科技专家']
},
{
id: 6,
name: '王德华',
title: '数字经济与金融研究中心专家',
description: '多家知名上市企业高级管理顾问',
tags: ['主讲', '数字经济专家']
},
{
id: 7,
name: '马前程',
title: '清华大学管理学院',
description: '多家一线互联网企业高级管理顾问',
tags: ['主讲', '清华大学管理专家']
},
{
id: 8,
name: '陈宇',
title: '知名上市企业高级管理顾问专家',
description: '多家一线互联网企业高级管理顾问',
tags: ['主讲', '企业管理专家']
}
])
//
const currentPage = ref(1)
const pageSize = 8
const totalPages = computed(() => Math.ceil(teachers.value.length / pageSize))
const paginatedTeachers = computed(() => {
const start = (currentPage.value - 1) * pageSize
const end = start + pageSize
return teachers.value.slice(start, end)
})
const visiblePages = computed(() => {
const pages = []
const total = totalPages.value
const current = currentPage.value
if (total <= 7) {
for (let i = 1; i <= total; i++) {
pages.push(i)
}
} else {
if (current <= 4) {
for (let i = 1; i <= 5; i++) {
pages.push(i)
}
pages.push('...')
pages.push(total)
} else if (current >= total - 3) {
pages.push(1)
pages.push('...')
for (let i = total - 4; i <= total; i++) {
pages.push(i)
}
} else {
pages.push(1)
pages.push('...')
for (let i = current - 1; i <= current + 1; i++) {
pages.push(i)
}
pages.push('...')
pages.push(total)
}
}
return pages
})
const goToPage = (page: number) => {
if (page >= 1 && page <= totalPages.value) {
currentPage.value = page
}
}
</script>
<style scoped>
.faculty-page {
min-height: 100vh;
background: #f6f6f6;
}
/* 横幅图片区域 */
.page-header {
width: 100%;
position: relative;
overflow: hidden;
}
.banner-image-container {
width: 100%;
height: 400px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.banner-image {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.banner-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.banner-placeholder::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
opacity: 0.3;
}
.placeholder-content {
text-align: center;
color: white;
position: relative;
z-index: 1;
}
.placeholder-icon {
font-size: 48px;
margin-bottom: 16px;
opacity: 0.8;
}
.placeholder-text {
font-size: 24px;
font-weight: 600;
margin-bottom: 8px;
}
.placeholder-desc {
font-size: 16px;
opacity: 0.8;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 主要内容区域 */
.main-content {
padding: 40px 0 80px;
}
/* 筛选标签栏 */
.filter-tabs {
display: flex;
gap: 0;
margin-bottom: 40px;
background: white;
border-radius: 8px;
padding: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.filter-tab {
padding: 12px 24px;
border: none;
background: transparent;
color: #666;
font-size: 14px;
cursor: pointer;
border-radius: 6px;
transition: all 0.3s;
white-space: nowrap;
}
.filter-tab:hover {
background: #f8f9fa;
color: #333;
}
.filter-tab.active {
background: #4A90E2;
color: white;
}
/* 师资卡片网格 */
.faculty-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
margin-bottom: 40px;
}
.faculty-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
cursor: pointer;
}
.faculty-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.card-header {
position: relative;
height: 200px;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
}
.avatar-container {
position: relative;
width: 100%;
height: 100%;
}
.avatar-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #e0e0e0 0%, #f0f0f0 100%);
display: flex;
align-items: center;
justify-content: center;
}
.avatar-placeholder::after {
content: '头像占位';
color: #999;
font-size: 14px;
}
.featured-badge {
position: absolute;
top: 12px;
left: 12px;
background: #FF6B35;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.card-arrow {
position: absolute;
top: 50%;
right: 16px;
transform: translateY(-50%);
color: #4A90E2;
background: white;
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-content {
padding: 20px;
}
.teacher-name {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
}
.teacher-title {
font-size: 14px;
color: #666;
margin: 0 0 8px 0;
line-height: 1.4;
}
.teacher-description {
font-size: 13px;
color: #999;
margin: 0 0 12px 0;
line-height: 1.4;
min-height: 18px;
}
.teacher-tags {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.tag {
background: #f0f8ff;
color: #4A90E2;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
border: 1px solid #e6f3ff;
}
/* 分页组件 */
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
margin-top: 40px;
}
.page-btn {
padding: 8px 16px;
border: 1px solid #ddd;
background: white;
color: #666;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
min-width: 40px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
}
.page-btn:hover:not(:disabled) {
background: #f8f9fa;
border-color: #4A90E2;
color: #4A90E2;
}
.page-btn.active {
background: #4A90E2;
border-color: #4A90E2;
color: white;
}
.page-btn:disabled {
background: #f5f5f5;
color: #ccc;
cursor: not-allowed;
border-color: #eee;
}
.page-info {
margin-left: 16px;
color: #666;
font-size: 14px;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.faculty-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 1024px) {
.banner-image-container {
height: 350px;
}
.placeholder-icon {
font-size: 40px;
}
.placeholder-text {
font-size: 20px;
}
}
@media (max-width: 768px) {
.faculty-grid {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.filter-tabs {
flex-wrap: wrap;
gap: 8px;
}
.filter-tab {
padding: 8px 16px;
font-size: 13px;
}
.banner-image-container {
height: 300px;
}
.placeholder-icon {
font-size: 36px;
}
.placeholder-text {
font-size: 18px;
}
.placeholder-desc {
font-size: 14px;
}
}
@media (max-width: 480px) {
.faculty-grid {
grid-template-columns: 1fr;
}
.container {
padding: 0 16px;
}
.main-content {
padding: 20px 0 40px;
}
.banner-image-container {
height: 250px;
}
.placeholder-icon {
font-size: 32px;
}
.placeholder-text {
font-size: 16px;
}
.placeholder-desc {
font-size: 12px;
}
}
</style>

610
src/views/Resources.vue Normal file
View File

@ -0,0 +1,610 @@
<template>
<div class="resources-page">
<!-- 轮播图区域 -->
<div class="banner-section">
<div class="banner-container">
<div class="banner-slide active">
<div class="banner-image">
<!-- 轮播图占位 -->
<div class="banner-placeholder"></div>
</div>
<div class="banner-content">
<h2 class="banner-title">海量资源聚合您的一站式数字资源库</h2>
</div>
</div>
<!-- 轮播指示器 -->
<div class="banner-indicators">
<span class="indicator active"></span>
<span class="indicator"></span>
<span class="indicator"></span>
</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<div class="container">
<!-- 精选视频区域 -->
<section class="featured-videos">
<h2 class="section-title">精选视频</h2>
<div class="featured-grid">
<div
v-for="video in featuredVideos"
:key="video.id"
class="featured-card"
>
<div class="card-image">
<div class="image-placeholder"></div>
<div class="play-button">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path d="M8 5V19L19 12L8 5Z" fill="white"/>
</svg>
</div>
</div>
<div class="card-content">
<h3 class="card-title">{{ video.title }}</h3>
</div>
</div>
</div>
</section>
<!-- 全部视频区域 -->
<section class="all-videos">
<h2 class="section-title">全部视频</h2>
<!-- 筛选标签 -->
<div class="filter-tabs">
<button
v-for="tab in videoTabs"
:key="tab.id"
:class="['filter-tab', { active: activeVideoTab === tab.id }]"
@click="activeVideoTab = tab.id"
>
{{ tab.name }}
</button>
</div>
<!-- 视频网格 -->
<div class="video-grid">
<div
v-for="video in allVideos"
:key="video.id"
class="video-card"
>
<div class="card-image">
<div class="image-placeholder"></div>
<div class="play-button">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
<path d="M8 5V19L19 12L8 5Z" fill="white"/>
</svg>
</div>
</div>
<div class="card-content">
<h3 class="card-title">{{ video.title }}</h3>
</div>
</div>
</div>
<div class="load-more">
<button class="load-more-btn">查看更多</button>
</div>
</section>
<!-- 全部图片区域 -->
<section class="all-images">
<h2 class="section-title">全部图片</h2>
<!-- 筛选标签 -->
<div class="filter-tabs">
<button
v-for="tab in imageTabs"
:key="tab.id"
:class="['filter-tab', { active: activeImageTab === tab.id }]"
@click="activeImageTab = tab.id"
>
{{ tab.name }}
</button>
</div>
<!-- 图片网格 -->
<div class="image-grid">
<div
v-for="image in allImages"
:key="image.id"
class="image-card"
>
<div class="card-image">
<div class="image-placeholder"></div>
</div>
<div class="card-content">
<h3 class="card-title">{{ image.title }}</h3>
</div>
</div>
</div>
<div class="load-more">
<button class="load-more-btn">查看更多</button>
</div>
</section>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
//
const featuredVideos = ref([
{ id: 1, title: '西安工业大学内部资源之一' },
{ id: 2, title: '华南工业大学内部资源之一' },
{ id: 3, title: '西安工业大学内部资源之一' }
])
//
const videoTabs = ref([
{ id: 'all', name: '全部' },
{ id: 'educational', name: '中小学教育资源' },
{ id: 'training', name: '师资培训' },
{ id: 'technology', name: '技术资源' },
{ id: 'management', name: '管理资源' }
])
const activeVideoTab = ref('all')
//
const allVideos = ref([
{ id: 1, title: '北京工业大学内部资源之一' },
{ id: 2, title: '北京工业大学内部资源之一' },
{ id: 3, title: '西安工业大学内部资源之一' },
{ id: 4, title: '北京工业大学内部资源之一' },
{ id: 5, title: '中国工业大学内部资源之一' },
{ id: 6, title: '西安工业大学内部资源之一' },
{ id: 7, title: '西安工业大学内部资源之一' },
{ id: 8, title: '内蒙古工业大学内部资源之一' }
])
//
const imageTabs = ref([
{ id: 'all', name: '全部' },
{ id: 'educational', name: '中小学教育资源' },
{ id: 'training', name: '师资培训' },
{ id: 'technology', name: '技术资源' },
{ id: 'management', name: '管理资源' }
])
const activeImageTab = ref('all')
//
const allImages = ref([
{ id: 1, title: '中国工业大学内部资源之一' },
{ id: 2, title: '西安工业大学内部资源之一' },
{ id: 3, title: '西安工业大学内部资源之一' },
{ id: 4, title: '内蒙古工业大学内部资源之一' },
{ id: 5, title: '北京工业大学内部资源之一' },
{ id: 6, title: '北京工业大学内部资源之一' },
{ id: 7, title: '西安工业大学内部资源之一' },
{ id: 8, title: '内蒙古工业大学内部资源之一' }
])
</script>
<style scoped>
.resources-page {
min-height: 100vh;
background: #f8f9fa;
}
/* 轮播图区域 */
.banner-section {
position: relative;
height: 400px;
overflow: hidden;
}
.banner-container {
position: relative;
width: 100%;
height: 100%;
}
.banner-slide {
position: relative;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.banner-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.banner-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
}
.banner-placeholder::after {
content: '轮播图占位';
color: rgba(255, 255, 255, 0.7);
font-size: 18px;
}
.banner-content {
position: relative;
z-index: 2;
text-align: center;
color: white;
max-width: 800px;
padding: 0 20px;
}
.banner-title {
font-size: 32px;
font-weight: 600;
margin: 0;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.banner-indicators {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 3;
}
.indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
cursor: pointer;
transition: all 0.3s;
}
.indicator.active {
background: white;
}
/* 主要内容区域 */
.main-content {
padding: 60px 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.section-title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0 0 30px 0;
}
/* 精选视频区域 */
.featured-videos {
margin-bottom: 80px;
}
.featured-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.featured-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
cursor: pointer;
}
.featured-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.card-image {
position: relative;
height: 180px;
background: #f5f5f5;
overflow: hidden;
}
.image-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #e0e0e0 0%, #f0f0f0 100%);
display: flex;
align-items: center;
justify-content: center;
}
.image-placeholder::after {
content: '图片占位';
color: #999;
font-size: 14px;
}
.play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 48px;
height: 48px;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
}
.play-button:hover {
background: rgba(0, 0, 0, 0.8);
transform: translate(-50%, -50%) scale(1.1);
}
.card-content {
padding: 16px;
}
.card-title {
font-size: 14px;
font-weight: 500;
color: #333;
margin: 0;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* 筛选标签 */
.filter-tabs {
display: flex;
gap: 0;
margin-bottom: 30px;
background: white;
border-radius: 8px;
padding: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
width: fit-content;
}
.filter-tab {
padding: 8px 20px;
border: none;
background: transparent;
color: #666;
font-size: 14px;
cursor: pointer;
border-radius: 6px;
transition: all 0.3s;
white-space: nowrap;
}
.filter-tab:hover {
background: #f8f9fa;
color: #333;
}
.filter-tab.active {
background: #4A90E2;
color: white;
}
/* 全部视频区域 */
.all-videos {
margin-bottom: 80px;
}
.video-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 40px;
}
.video-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
cursor: pointer;
}
.video-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.video-card .card-image {
height: 140px;
}
.video-card .play-button {
width: 40px;
height: 40px;
}
/* 全部图片区域 */
.all-images {
margin-bottom: 40px;
}
.image-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 40px;
}
.image-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
cursor: pointer;
}
.image-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.image-card .card-image {
height: 140px;
}
/* 查看更多按钮 */
.load-more {
text-align: center;
}
.load-more-btn {
padding: 12px 32px;
background: white;
border: 1px solid #ddd;
color: #666;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.load-more-btn:hover {
background: #f8f9fa;
border-color: #4A90E2;
color: #4A90E2;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.container {
padding: 0 16px;
}
.featured-grid {
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.video-grid,
.image-grid {
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.banner-title {
font-size: 28px;
}
}
@media (max-width: 768px) {
.banner-section {
height: 300px;
}
.banner-title {
font-size: 24px;
}
.main-content {
padding: 40px 0;
}
.featured-grid {
grid-template-columns: 1fr;
gap: 16px;
}
.video-grid,
.image-grid {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.section-title {
font-size: 20px;
margin-bottom: 20px;
}
.filter-tabs {
overflow-x: auto;
padding: 4px;
gap: 4px;
}
.filter-tab {
padding: 6px 16px;
font-size: 13px;
flex-shrink: 0;
}
.featured-videos,
.all-videos {
margin-bottom: 60px;
}
}
@media (max-width: 480px) {
.banner-section {
height: 250px;
}
.banner-title {
font-size: 20px;
padding: 0 16px;
}
.container {
padding: 0 12px;
}
.video-grid,
.image-grid {
grid-template-columns: 1fr;
gap: 12px;
}
.card-image {
height: 160px;
}
.video-card .card-image,
.image-card .card-image {
height: 120px;
}
.section-title {
font-size: 18px;
}
.filter-tabs {
margin-bottom: 20px;
}
.filter-tab {
padding: 6px 12px;
font-size: 12px;
}
}
</style>

0
v1.txt
View File