OL-LearnPlatform-Frontend/src/views/SpecialTraining.vue
2025-08-12 16:58:22 +08:00

525 lines
11 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="special-training-page">
<!-- 页面标题区域 -->
<div class="page-header">
<div class="container">
<h1 class="page-title">专题训练</h1>
<p class="page-subtitle">开展各类专题训练活动提升学习效果</p>
</div>
</div>
<!-- 筛选标签区域 -->
<div class="filter-section">
<div class="container">
<div class="filter-tabs">
<span>专题分类:</span>
<button v-for="tab in filterTabs" :key="tab.id" class="filter-tab" :class="{ 'active': activeTab === tab.id }"
@click="setActiveTab(tab.id)">
{{ tab.name }}
</button>
</div>
</div>
</div>
<!-- 训练项目列表 -->
<div class="training-content">
<div class="container">
<div class="training-grid">
<div v-for="training in paginatedTrainings" :key="training.id" class="training-card">
<div class="card-content">
<h3 class="training-title">{{ training.title }}</h3>
<p class="training-description">{{ training.description }}</p>
<div class="training-info">
<span class="training-time">
时间2025年07月13日-2025年8月16日23
</span>
</div>
<div class="card-footer">
<button class="btn-join" @click="joinTraining(training.id)">
立即参与
</button>
<span class="participant-count">已有{{ training.participants }}人参与</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" :class="{ 'active': currentPage === page }"
@click="goToPage(page)">
{{ 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, onMounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
// 筛选标签
const filterTabs = ref([
{ id: 'all', name: '全部' },
{ id: 'interview', name: '公务员面试' },
{ id: 'writing', name: '公文写作' },
{ id: 'law', name: '法律法规' },
{ id: 'management', name: '基本素质' },
{ id: 'communication', name: '专业能力' },
{ id: 'leadership', name: '专业素养' }
])
const activeTab = ref('all')
// 分页相关
const currentPage = ref(1)
const pageSize = ref(9) // 每页9个3x3布局
// 训练项目数据
const trainings = ref([
{
id: 1,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容,提升教师专业素养和教学能力。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: 1234,
category: 'all'
},
{
id: 2,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: 1234,
category: 'all'
},
{
id: 3,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: 1234,
category: 'all'
},
{
id: 4,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: 1234,
category: 'all'
},
{
id: 5,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: 1234,
category: 'all'
},
{
id: 6,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: 1234,
category: 'all'
}
])
// 生成更多数据以支持分页
for (let i = 7; i <= 30; i++) {
trainings.value.push({
id: i,
title: '全国教师网络研修班',
description: '针对中小学教师开展的专业能力提升培训,包含教学方法、课程设计、学生管理等多个方面的内容。',
startDate: '2024年7月1日',
endDate: '2024年8月1日',
participants: Math.floor(Math.random() * 2000) + 500,
category: 'all'
})
}
// 计算属性
const filteredTrainings = computed(() => {
if (activeTab.value === 'all') {
return trainings.value
}
return trainings.value.filter(training => training.category === activeTab.value)
})
const totalPages = computed(() => {
return Math.ceil(filteredTrainings.value.length / pageSize.value)
})
const paginatedTrainings = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
return filteredTrainings.value.slice(start, end)
})
const visiblePages = computed(() => {
const pages = []
const total = totalPages.value
const current = currentPage.value
// 显示当前页前后2页
const start = Math.max(1, current - 2)
const end = Math.min(total, current + 2)
for (let i = start; i <= end; i++) {
pages.push(i)
}
return pages
})
// 方法
const setActiveTab = (tabId: string) => {
activeTab.value = tabId
currentPage.value = 1 // 切换标签时重置到第一页
}
const goToPage = (page: number) => {
if (page >= 1 && page <= totalPages.value) {
currentPage.value = page
}
}
const joinTraining = (trainingId: number) => {
// 跳转到专题训练详细页面
console.log('参与训练:', trainingId)
router.push(`/special-training/${trainingId}`)
}
onMounted(() => {
console.log('专题训练页面加载完成')
})
</script>
<style scoped>
/* 基础样式 */
.special-training-page {
min-height: 100vh;
background: #f5f5f5;
}
.container {
margin: 0 auto;
padding: 0 24px;
}
/* 页面标题 */
.page-header {
background: white;
padding: 40px 0;
text-align: center;
border-bottom: 1px solid #e8e8e8;
background-image: url('/images/special/special-bg.png');
background-size: 100% 100%;
}
.page-title {
font-size: 32px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
}
.page-subtitle {
font-size: 14px;
color: #000;
margin: 0;
}
/* 筛选标签 */
.filter-section {
background: white;
padding: 0;
}
.filter-tabs {
padding: 40px 0;
display: flex;
gap: 24px;
flex-wrap: wrap;
border-bottom: 1px solid #e8e8e8;
align-items: center;
}
.filter-tab {
background: none;
border: none;
padding: 7px 12px;
font-size: 14px;
color: #666;
cursor: pointer;
border-radius: 4px;
transition: all 0.2s;
}
.filter-tab:hover {
color: #1890ff;
background: #f0f8ff;
}
.filter-tab.active {
color: #1890ff;
background: #e6f7ff;
font-weight: 500;
}
/* 训练内容区域 */
.training-content {
padding: 40px 0;
background-color: #fff;
}
.training-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 40px;
}
/* 训练卡片 */
.training-card {
background: linear-gradient(135deg, #e8f4fd 0%, #d1e9f6 50%, #b8ddf0 100%);
overflow: hidden;
transition: all 0.3s ease;
cursor: pointer;
border: 1px solid rgba(255, 255, 255, 0.3);
background-image: url('/images/special/special-box.png');
background-repeat: no-repeat;
background-size: 100% 100%;
}
.training-card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(24, 144, 255, 0.15);
}
.card-content {
padding:40px 40px 30px 40px;
height: 100%;
display: flex;
flex-direction: column;
min-height: 250px
}
.training-title {
font-size: 24px;
color: #1a1a1a;
margin: 0 0 10px 0;
line-height: 1.4;
}
.training-description {
font-size: 14px;
color: #999;
line-height: 1.5;
margin: 0 0 16px 0;
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.training-info {
margin-bottom: 16px;
}
.training-time {
font-size: 14px;
color: #004A8F;
display: block;
line-height: 1.4;
}
.card-footer {
display: flex;
justify-content: left;
align-items: end;
margin-top: 10px;
gap: 20px;
}
.btn-join {
background: #0088D1;
color: white;
border: none;
padding: 12px 38px;
font-size: 13px;
cursor: pointer;
transition: background 0.2s;
font-weight: 500;
}
.btn-join:hover {
background: #40a9ff;
}
.participant-count {
font-size: 12px;
color: #333;
}
/* 分页器 */
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
margin-top: 40px;
}
.page-btn {
background: white;
border: 1px solid #d9d9d9;
color: #666;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
min-width: 40px;
}
.page-btn:hover:not(:disabled) {
border-color: #0088D1;
color: #0088D1;
}
.page-btn.active {
background: #0088D1;
border-color: #0088D1;
color: white;
}
.page-btn:disabled {
background: #f5f5f5;
border-color: #d9d9d9;
color: #ccc;
cursor: not-allowed;
}
.page-info {
font-size: 14px;
color: #666;
margin-left: 16px;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.training-grid {
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
}
@media (max-width: 768px) {
.container {
padding: 0 16px;
}
.page-header {
padding: 30px 0;
}
.page-title {
font-size: 24px;
}
.filter-tabs {
gap: 12px;
}
.filter-tab {
padding: 6px 12px;
font-size: 13px;
}
.training-content {
padding: 30px 0;
}
.training-grid {
grid-template-columns: 1fr;
gap: 16px;
}
.card-content {
padding: 20px;
}
.training-title {
font-size: 16px;
}
.pagination {
flex-wrap: wrap;
gap: 4px;
}
.page-btn {
padding: 6px 10px;
font-size: 13px;
min-width: 36px;
}
.page-info {
margin-left: 8px;
font-size: 13px;
}
}
@media (max-width: 480px) {
.filter-tabs {
justify-content: flex-start;
overflow-x: auto;
padding-bottom: 8px;
}
.filter-tab {
white-space: nowrap;
flex-shrink: 0;
}
.card-footer {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.btn-join {
width: 100%;
text-align: center;
}
.participant-count {
text-align: center;
}
}
</style>