419 lines
8.2 KiB
Vue
419 lines
8.2 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="interest-course">
|
|||
|
|
<!-- 选课信息头部 -->
|
|||
|
|
<view class="selection-header">
|
|||
|
|
<view class="header-content">
|
|||
|
|
<view class="title">2023年秋季俱乐部选课</view>
|
|||
|
|
<view class="countdown">
|
|||
|
|
<text class="time-text">{{ remainTime }}</text>
|
|||
|
|
<view class="time-icon">
|
|||
|
|
<text class="time-value">90</text>
|
|||
|
|
<text class="time-unit">mins</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<!-- 多选提示 -->
|
|||
|
|
<view class="selection-tip">
|
|||
|
|
<text>可选择多个俱乐部({{ selectedCount }}/{{ maxSelectCount }})</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 课程网格列表 -->
|
|||
|
|
<view class="course-grid">
|
|||
|
|
<view
|
|||
|
|
v-for="(course, index) in courseList"
|
|||
|
|
:key="index"
|
|||
|
|
class="course-item"
|
|||
|
|
:class="{ selected: course.isSelected }"
|
|||
|
|
@click="toggleSelection(course)"
|
|||
|
|
>
|
|||
|
|
<view class="course-name">{{ course.title }}</view>
|
|||
|
|
<view class="register-info">
|
|||
|
|
<text>报名情况:</text>
|
|||
|
|
<text class="register-count">{{ course.registeredCount }}</text>
|
|||
|
|
<text> | {{ course.maxCount }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="detail-btn" @click.stop="viewCourseDetail(course)"
|
|||
|
|
>详情</view
|
|||
|
|
>
|
|||
|
|
<view v-if="course.isSelected" class="selected-mark">
|
|||
|
|
<uni-icons
|
|||
|
|
type="checkbox-filled"
|
|||
|
|
color="#3FBF72"
|
|||
|
|
size="22"
|
|||
|
|
></uni-icons>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 底部报名按钮 -->
|
|||
|
|
<view class="register-btn-container">
|
|||
|
|
<view class="selected-count">已选择:{{ selectedCount }}/{{ maxSelectCount }}</view>
|
|||
|
|
<view class="register-btn" @click="submitRegistration">点击报名</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup lang="ts">
|
|||
|
|
import { navigateTo } from "@/utils/uniapp";
|
|||
|
|
import { ref, computed, onMounted } from "vue";
|
|||
|
|
|
|||
|
|
// 剩余时间
|
|||
|
|
const remainTime = ref("89:57");
|
|||
|
|
|
|||
|
|
// 最大可选课程数
|
|||
|
|
const maxSelectCount = ref(3);
|
|||
|
|
|
|||
|
|
// 计算已选课程数量
|
|||
|
|
const selectedCount = computed(() => {
|
|||
|
|
return courseList.value.filter(course => course.isSelected).length;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 课程列表数据
|
|||
|
|
const courseList = ref([
|
|||
|
|
{
|
|||
|
|
id: 1,
|
|||
|
|
title: "少儿声乐",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 2,
|
|||
|
|
title: "机器人创客",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 3,
|
|||
|
|
title: "科学实践",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 4,
|
|||
|
|
title: "趣味手工",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 5,
|
|||
|
|
title: "动画制作",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 6,
|
|||
|
|
title: "趣味英语",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 7,
|
|||
|
|
title: "篮球",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 8,
|
|||
|
|
title: "足球",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 9,
|
|||
|
|
title: "羽毛球",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 10,
|
|||
|
|
title: "主持人",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 11,
|
|||
|
|
title: "心育课堂",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 12,
|
|||
|
|
title: "童戏皮影",
|
|||
|
|
registeredCount: 23,
|
|||
|
|
maxCount: 30,
|
|||
|
|
isSelected: false,
|
|||
|
|
},
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// 返回上一页
|
|||
|
|
const goBack = () => {
|
|||
|
|
uni.navigateBack();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 查看课程详情
|
|||
|
|
const viewCourseDetail = (course: any) => {
|
|||
|
|
uni.navigateTo({
|
|||
|
|
url: `/pages/base/course-selection/detail?id=${course.id}`,
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 选择或取消选择课程(改为多选)
|
|||
|
|
const toggleSelection = (course: any) => {
|
|||
|
|
// 如果当前课程未选中,且已达到最大选择数量,则提示
|
|||
|
|
if (!course.isSelected && selectedCount.value >= maxSelectCount.value) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: `最多可选择${maxSelectCount.value}个俱乐部`,
|
|||
|
|
icon: "none",
|
|||
|
|
duration: 2000,
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 直接切换当前课程的选中状态
|
|||
|
|
course.isSelected = !course.isSelected;
|
|||
|
|
|
|||
|
|
uni.vibrateShort({
|
|||
|
|
success: () => {
|
|||
|
|
// 震动反馈成功
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
uni.showToast({
|
|||
|
|
title: course.isSelected ? "已选择" : "已取消选择",
|
|||
|
|
icon: "none",
|
|||
|
|
duration: 500,
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 提交报名
|
|||
|
|
const submitRegistration = () => {
|
|||
|
|
const selectedCourses = courseList.value.filter(
|
|||
|
|
(course) => course.isSelected
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (selectedCourses.length === 0) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: "请至少选择一个俱乐部",
|
|||
|
|
icon: "none",
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uni.showModal({
|
|||
|
|
title: "确认报名",
|
|||
|
|
content: `您确定要报名已选择的${selectedCourses.length}个俱乐部吗?`,
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.confirm) {
|
|||
|
|
uni.showLoading({
|
|||
|
|
title: "报名中...",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 模拟提交报名
|
|||
|
|
setTimeout(() => {
|
|||
|
|
uni.hideLoading();
|
|||
|
|
navigateTo("/pages/base/course-selection/payment");
|
|||
|
|
}, 1500);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 页面加载
|
|||
|
|
onMounted(() => {
|
|||
|
|
// 实际应用中,可以从后端获取课程列表和倒计时信息
|
|||
|
|
// fetchCourseList();
|
|||
|
|
// startCountdown();
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.interest-course {
|
|||
|
|
min-height: 100vh;
|
|||
|
|
background-color: #f5f7fa;
|
|||
|
|
padding-bottom: 80px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-bar {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 15px;
|
|||
|
|
height: 44px;
|
|||
|
|
background-color: #fff;
|
|||
|
|
|
|||
|
|
.nav-left {
|
|||
|
|
width: 40px;
|
|||
|
|
height: 40px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-title {
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-right {
|
|||
|
|
width: 40px;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: flex-end;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.selection-header {
|
|||
|
|
background-color: #eef4ff;
|
|||
|
|
padding: 20px 15px;
|
|||
|
|
|
|||
|
|
.header-content {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
|
|||
|
|
.title {
|
|||
|
|
font-size: 22px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.countdown {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
|
|||
|
|
.time-text {
|
|||
|
|
font-size: 22px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #ff4d4f;
|
|||
|
|
margin-right: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.time-icon {
|
|||
|
|
position: relative;
|
|||
|
|
width: 52px;
|
|||
|
|
height: 52px;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
background-color: #2879ff;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
border: 2px solid #fff;
|
|||
|
|
|
|||
|
|
.time-value {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.time-unit {
|
|||
|
|
font-size: 10px;
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.selection-tip {
|
|||
|
|
margin-top: 10px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #666;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.course-grid {
|
|||
|
|
display: flex;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
padding: 15px;
|
|||
|
|
|
|||
|
|
.course-item {
|
|||
|
|
position: relative;
|
|||
|
|
width: calc(50% - 10px);
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
background-color: #fff;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 15px;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
|
|||
|
|
&:nth-child(odd) {
|
|||
|
|
margin-right: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&:nth-child(even) {
|
|||
|
|
margin-left: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.selected {
|
|||
|
|
border: 1px solid #3fbf72;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.course-name {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #333;
|
|||
|
|
margin-bottom: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.register-info {
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #666;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
|
|||
|
|
.register-count {
|
|||
|
|
color: #2879ff;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.detail-btn {
|
|||
|
|
display: inline-block;
|
|||
|
|
color: #2879ff;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.selected-mark {
|
|||
|
|
position: absolute;
|
|||
|
|
top: -6px;
|
|||
|
|
right: -6px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.register-btn-container {
|
|||
|
|
position: fixed;
|
|||
|
|
bottom: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
padding: 15px;
|
|||
|
|
background-color: #fff;
|
|||
|
|
|
|||
|
|
.selected-count {
|
|||
|
|
text-align: center;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #666;
|
|||
|
|
margin-bottom: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.register-btn {
|
|||
|
|
height: 50px;
|
|||
|
|
line-height: 50px;
|
|||
|
|
text-align: center;
|
|||
|
|
background-color: #2879ff;
|
|||
|
|
color: #fff;
|
|||
|
|
border-radius: 25px;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|