zhxy-jzd/src/pages/base/course-selection/club-selection.vue

1027 lines
25 KiB
Vue
Raw Normal View History

2025-05-07 09:44:23 +08:00
<template>
<view class="interest-course">
2025-05-16 16:16:41 +08:00
<!-- 选课信息头部 - 固定部分 -->
2025-05-07 09:44:23 +08:00
<view class="selection-header">
<view class="header-content">
2025-05-16 16:16:41 +08:00
<view class="title-section">
<view class="title">
<text v-if="kcData && kcData.xkmc">{{ kcData.xkmc }}</text>
<text v-else>选课信息</text>
2025-05-07 09:44:23 +08:00
</view>
2025-05-16 16:16:41 +08:00
<!-- <view class="subtitle">互动兴趣课程</view> -->
</view>
<!-- 学生选择部分 -->
<view class="student-selector-bar" @click="showStudentSelector">
<view class="user-avatar">
<image
:src="currentStudent.avatar || '/static/base/home/11222.png'"
class="w-full h-full"
></image>
</view>
<view class="student-info">
<text class="student-name">{{ currentStudent.xm }}</text>
<text class="student-class"
>{{ currentStudent.njmc }} {{ currentStudent.bjmc }}</text
>
</view>
<view class="switch-btn" v-if="studentList.length > 1">切换</view>
</view>
<view class="countdown-section">
<template v-if="!isEnrollmentEnded">
<view class="countdown-title">{{ countdownTitle }}</view>
<view class="countdown-timer">
<view class="time-block">
<text class="time-value">{{ countdownTime.hours }}</text>
<text class="time-unit"></text>
</view>
<text class="time-separator">:</text>
<view class="time-block">
<text class="time-value">{{ countdownTime.minutes }}</text>
<text class="time-unit"></text>
</view>
<text class="time-separator">:</text>
<view class="time-block">
<text class="time-value">{{ countdownTime.seconds }}</text>
<text class="time-unit"></text>
</view>
</view>
</template>
<template v-else>
<view class="enrollment-ended">
<u-icon name="info-circle" color="#FF9900" size="20"></u-icon>
<text>选课已经结束</text>
</view>
</template>
2025-05-07 09:44:23 +08:00
</view>
</view>
</view>
2025-05-16 16:16:41 +08:00
<!-- 可滚动的内容区域 -->
<view class="scrollable-content">
<!-- 课程网格列表 -->
<view class="course-grid" v-if="courseListData.length > 0">
<view
v-for="(course, index) in courseListData"
:key="course.id || index"
class="course-item"
:class="{ selected: course.isSelected }"
@click="toggleSelection(course)"
2025-05-07 09:44:23 +08:00
>
2025-05-16 16:16:41 +08:00
<view class="course-name">{{ course.kcmc }}</view>
<view class="register-info">
<text>报名情况</text>
<text class="register-count">{{ course.ybmr }}</text>
<text> | {{ course.maxNum }}</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 v-else class="empty-course-list">
<view class="empty-icon">
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
2025-05-07 09:44:23 +08:00
</view>
2025-05-16 16:16:41 +08:00
<view class="empty-text">暂无课程数据</view>
2025-05-07 09:44:23 +08:00
</view>
</view>
2025-05-16 16:16:41 +08:00
<!-- 底部报名按钮 - 固定部分 -->
2025-05-07 09:44:23 +08:00
<view class="register-btn-container">
2025-05-16 16:16:41 +08:00
<view class="selected-count-info" v-if="getSelectedCount > 0">
已选 {{ getSelectedCount }} 门课程
</view>
2025-05-07 09:44:23 +08:00
<view class="register-btn" @click="submitRegistration">点击报名</view>
</view>
2025-05-16 16:16:41 +08:00
<view>
<!-- 学生选择弹窗 -->
<u-popup
:show="showSelector"
@close="showSelector = false"
mode="bottom"
round="10"
>
<view class="student-selector">
<view class="selector-header">
<text class="selector-title">选择学生</text>
<u-icon
name="close"
size="20"
@click="showSelector = false"
></u-icon>
</view>
<view class="student-list">
<view
v-for="(student, index) in studentList"
:key="index"
class="student-item"
:class="{
'student-item-active': currentStudent.id === student.id,
}"
@click="switchStudent(student)"
>
<view class="student-avatar">
<image
:src="student.avatar || '/static/base/home/11222.png'"
class="w-full h-full"
></image>
</view>
<view class="student-info">
<text class="student-name">{{ student.xm }}</text>
<text class="student-class"
>{{ student.njmc }} {{ student.bjmc }}</text
>
</view>
<u-icon
v-if="currentStudent.id === student.id"
name="checkmark"
color="#409EFF"
size="20"
></u-icon>
</view>
</view>
</view>
</u-popup>
</view>
2025-05-07 09:44:23 +08:00
</view>
</template>
<script setup lang="ts">
import { navigateTo } from "@/utils/uniapp";
2025-05-16 16:16:41 +08:00
import { ref, computed, reactive, onBeforeUnmount, watch } from "vue";
import { useUserStore } from "@/store/modules/user";
import { useDataStore } from "@/store/modules/data";
import { xkAddXkqdApi, xkListApi, xkXkqdApi } from "@/api/base/server";
import dayjs from "dayjs";
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
const { getUser } = useUserStore();
const { getData, setKcData } = useDataStore();
const { sign_file } = getData;
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
// 倒计时相关
const countdownTime = reactive({
hours: "00",
minutes: "00",
seconds: "00",
});
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
// 倒计时标题文本
const countdownTitle = computed(() => {
return kcStatus.value ? "距离选课结束还剩" : "距离选课开始还剩";
2025-05-07 09:44:23 +08:00
});
2025-05-16 16:16:41 +08:00
// 当前选中的学生
let countdownTimer: number | null = null;
const remainTime = ref("00:00:00");
// 学生列表数据
const studentList = computed(() => {
return getUser.xsList;
});
const currentStudent = ref();
// 控制选择器显示状态
const showSelector = ref(false);
if (studentList.value.length > 1) {
showSelector.value = true;
}
const kcData = ref();
const kcStatus = ref(false);
// 添加选课是否已结束的标记
const isEnrollmentEnded = ref(false);
// 封装检查学生报名状态的通用方法
function checkStudentEnrollmentApi(student: any): Promise<boolean> {
return new Promise((resolve, reject) => {
if (!student || !student.id || !student.njId) {
console.error("学生信息不完整:", student);
resolve(false);
return;
}
// 调用选课签到接口检查学生是否已报名
xkXkqdApi({
njId: student.njId,
xsId: student.id,
xklxId: "962488654", // 课程类型ID
})
.then((res) => {
// 根据接口返回的result判断是否已报名
if (res && res.resultCode === 1) {
resolve(!!res.result); // 转换为布尔值返回
} else {
// 接口调用成功但返回错误
console.warn("检查报名状态接口返回错误:", res);
resolve(false);
}
})
.catch((error) => {
// 接口调用失败
console.error("调用检查报名状态接口失败:", error);
reject(error);
});
});
}
// 页面初始化时检查当前学生是否已报名
const checkInitialEnrollment = (currentStudent: any) => {
if (!currentStudent) return;
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
uni.showLoading({
title: "加载中...",
});
// 使用封装的API函数检查学生报名状态
checkStudentEnrollmentApi(currentStudent)
.then((isEnrolled) => {
if (isEnrolled) {
uni.hideLoading();
uni.reLaunch({
url: `/pages/base/course-selection/enrolled`,
});
} else {
loadCourseList(currentStudent);
}
})
.catch(() => {
uni.hideLoading();
loadCourseList(currentStudent);
});
2025-05-07 09:44:23 +08:00
};
2025-05-16 16:16:41 +08:00
if (studentList.value.length > 0 && studentList.value.length === 1) {
currentStudent.value = studentList.value[0];
// 检查当前学生是否已报名
checkInitialEnrollment(currentStudent.value);
}
// 加载课程列表
const loadCourseList = (currentStudent: any) => {
if (!currentStudent) {
uni.hideLoading();
return;
}
xkListApi({
njId: currentStudent.njId,
xklxId: "962488654",
})
.then((res) => {
uni.hideLoading();
if (res.resultCode == 1) {
if (res.result) {
kcData.value = res.result;
//获取当前时间
const now = dayjs().valueOf();
//获取选课开始时间
const xkkstime = dayjs(res.result.xkkstime).valueOf();
//获取选课结束时间
const xkjstime = dayjs(res.result.xkjstime).valueOf();
// 检查是否已经超过选课结束时间
if (now > xkjstime) {
kcStatus.value = true;
isEnrollmentEnded.value = true;
countdownTime.hours = "00";
countdownTime.minutes = "00";
countdownTime.seconds = "00";
}
//判断选课是否开始
else if (now < xkkstime) {
kcStatus.value = false;
startCountdown(xkkstime);
} else {
kcStatus.value = true;
startCountdown(xkjstime);
}
} else {
uni.reLaunch({
url: "/pages/base/course-selection/notopen",
});
}
}
})
.catch(() => {
uni.hideLoading();
});
};
// 显示学生选择器
function showStudentSelector() {
if (studentList.value.length > 1) {
showSelector.value = true;
}
}
// 切换学生
function switchStudent(student: any) {
currentStudent.value = student;
showSelector.value = false;
// 显示加载中
uni.showLoading({
title: "加载中...",
2025-05-07 09:44:23 +08:00
});
2025-05-16 16:16:41 +08:00
// 使用封装的API函数检查学生是否已报名
checkStudentEnrollmentApi(student)
.then((isEnrolled) => {
uni.hideLoading();
if (isEnrolled) {
// 如果已报名,跳转到已报名页面
uni.navigateTo({
url: `/pages/base/course-selection/enrolled?studentId=${student.id}`,
});
} else {
// 未报名,显示切换成功提示并刷新课程列表
uni.showToast({
title: `已切换到${student.xm}`,
icon: "none",
});
// 加载当前学生的课程列表
loadCourseList(student);
}
})
.catch((error) => {
uni.hideLoading();
uni.showToast({
title: `已切换到${student.xm}`,
icon: "none",
});
console.error("检查学生报名状态出错:", error);
// 出错时也加载课程列表
loadCourseList(student);
});
}
// 启动倒计时
const startCountdown = (endTimeStamp: number) => {
if (countdownTimer) {
clearInterval(countdownTimer);
}
const updateCountdown = () => {
const now = new Date().getTime();
const timeLeft = endTimeStamp - now;
if (timeLeft <= 0) {
// 倒计时结束
countdownTime.hours = "00";
countdownTime.minutes = "00";
countdownTime.seconds = "00";
remainTime.value = "00:00:00";
if (countdownTimer) {
clearInterval(countdownTimer);
countdownTimer = null;
}
// 判断当前倒计时是选课开始还是选课结束
if (!kcStatus.value && kcData.value) {
// 如果是选课开始倒计时结束,则切换到选课结束倒计时
kcStatus.value = true; // 更新状态为选课已开始
uni.showToast({
title: "选课已开始",
icon: "none",
});
// 开始选课结束倒计时
const xkjstime = dayjs(kcData.value.xkjstime).valueOf();
startCountdown(xkjstime);
} else {
// 如果是选课结束倒计时结束
isEnrollmentEnded.value = true; // 标记选课已结束
uni.showToast({
title: "选课已结束",
icon: "none",
});
}
return;
}
// 计算小时、分钟和秒
const hours = Math.floor(timeLeft / (1000 * 60 * 60));
const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
// 格式化显示
countdownTime.hours = hours < 10 ? `0${hours}` : `${hours}`;
countdownTime.minutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
countdownTime.seconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
// 更新remainTime(兼容原有逻辑)
remainTime.value = `${countdownTime.hours}:${countdownTime.minutes}:${countdownTime.seconds}`;
};
// 立即执行一次
updateCountdown();
// 每秒更新一次
countdownTimer = setInterval(updateCountdown, 1000) as unknown as number;
2025-05-07 09:44:23 +08:00
};
2025-05-16 16:16:41 +08:00
// 从课程数据中提取课程列表
const displayCourseList = computed(() => {
if (
!kcData.value ||
!kcData.value.xkkcs ||
!Array.isArray(kcData.value.xkkcs)
) {
return [];
}
// 获取本地存储的已选课程ID数组
const selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
// 为课程添加选中状态属性
return kcData.value.xkkcs.map((course: any) => ({
...course,
isSelected: selectedCourseIds.includes(course.id),
}));
});
// 可修改的课程列表数据
const courseListData = ref<any[]>([]);
// 监听计算属性变化,更新可修改的数据
watch(
displayCourseList,
(newVal) => {
courseListData.value = JSON.parse(JSON.stringify(newVal));
},
{ immediate: true }
);
// 选择或取消选择课程
2025-05-07 09:44:23 +08:00
const toggleSelection = (course: any) => {
2025-05-16 16:16:41 +08:00
// 只检查课程是否已满,不判断选课是否开始
if (course.ybmr >= course.maxNum) {
2025-05-07 09:44:23 +08:00
uni.showToast({
2025-05-16 16:16:41 +08:00
title: "该课程名额已满",
2025-05-07 09:44:23 +08:00
icon: "none",
});
return;
}
2025-05-16 16:16:41 +08:00
const courseIndex = courseListData.value.findIndex(
(item) => item.id === course.id
);
if (courseIndex === -1) return;
// 切换当前课程的选中状态
courseListData.value[courseIndex].isSelected =
!courseListData.value[courseIndex].isSelected;
// 获取本地存储的已选课程ID数组
let selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
if (courseListData.value[courseIndex].isSelected) {
// 添加到已选数组
if (!selectedCourseIds.includes(course.id)) {
selectedCourseIds.push(course.id);
}
} else {
// 从已选数组中移除
selectedCourseIds = selectedCourseIds.filter(
(id: string) => id !== course.id
);
}
// 更新本地存储
uni.setStorageSync("selectedCourseIds", selectedCourseIds);
};
// 查看课程详情
const viewCourseDetail = (course: any) => {
setKcData(course);
uni.navigateTo({
url: `/pages/base/course-selection/detail`,
2025-05-07 09:44:23 +08:00
});
};
// 提交报名
const submitRegistration = () => {
2025-05-16 16:16:41 +08:00
// 直接根据当前时间和选课时间判断是否可以报名
if (!kcData.value || !kcData.value.xkkstime || !kcData.value.xkjstime) {
uni.showToast({
title: "选课信息不完整,请联系校方!",
icon: "none",
});
return;
}
const now = dayjs().valueOf();
const xkkstime = dayjs(kcData.value.xkkstime).valueOf();
const xkjstime = dayjs(kcData.value.xkjstime).valueOf();
// 检查是否在选课时间范围内
if (now < xkkstime) {
uni.showToast({
title: "选课时间未开始,请等待!",
icon: "none",
});
return;
}
if (now > xkjstime) {
uni.showToast({
title: "选课已结束,请等待下一次选课!",
icon: "none",
});
return;
}
const selectedCourses = courseListData.value.filter(
(course: any) => course.isSelected
2025-05-07 09:44:23 +08:00
);
if (selectedCourses.length === 0) {
uni.showToast({
2025-05-16 16:16:41 +08:00
title: "请至少选择一门课程",
icon: "none",
});
return;
}
// 检查所有选中的课程是否有已满的
const fullCourses = selectedCourses.filter(
(course) => course.ybmr >= course.maxNum
);
if (fullCourses.length > 0) {
uni.showToast({
title: `"${fullCourses[0].kcmc}"名额已满,请重新选择!`,
2025-05-07 09:44:23 +08:00
icon: "none",
});
return;
}
2025-05-16 16:16:41 +08:00
// 构建课程名称列表用于显示
const courseNames = selectedCourses
.map((course) => `"${course.kcmc}"`)
.join("、");
2025-05-07 09:44:23 +08:00
uni.showModal({
title: "确认报名",
2025-05-16 16:16:41 +08:00
content: `您确定要为${currentStudent.value.xm}报名以下课程吗?\n${courseNames}`,
success: async (res) => {
2025-05-07 09:44:23 +08:00
if (res.confirm) {
uni.showLoading({
title: "报名中...",
});
2025-05-16 16:16:41 +08:00
try {
// 依次提交每个选中的课程
for (const course of selectedCourses) {
const result = await xkAddXkqdApi({
njId: currentStudent.value.njId,
xsId: currentStudent.value.id,
xklxId: course.id,
sign_file,
});
if (result.resultCode !== 1) {
throw new Error(
`课程"${course.kcmc}"报名失败: ${result.message || "未知错误"}`
);
}
}
// 全部成功报名
uni.hideLoading();
uni.showToast({
title: "报名成功!",
icon: "success",
duration: 2000,
});
// 清除选课记录
uni.removeStorageSync("selectedCourseIds");
// 延迟后跳转到已报名页面
setTimeout(() => {
uni.reLaunch({
url: `/pages/base/course-selection/enrolled`,
});
}, 2000);
} catch (error: any) {
2025-05-07 09:44:23 +08:00
uni.hideLoading();
2025-05-16 16:16:41 +08:00
uni.showToast({
title: error.message || "报名失败,请稍后重试",
icon: "none",
duration: 3000,
});
}
2025-05-07 09:44:23 +08:00
}
},
});
};
2025-05-16 16:16:41 +08:00
// 页面卸载前清除定时器
onBeforeUnmount(() => {
if (countdownTimer) {
clearInterval(countdownTimer);
countdownTimer = null;
}
});
// 计算已选课程数量
const getSelectedCount = computed(() => {
return courseListData.value.filter((course) => course.isSelected).length;
2025-05-07 09:44:23 +08:00
});
</script>
<style lang="scss" scoped>
.interest-course {
2025-05-16 16:16:41 +08:00
min-height: 100%;
2025-05-07 09:44:23 +08:00
background-color: #f5f7fa;
2025-05-16 16:16:41 +08:00
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
2025-05-07 09:44:23 +08:00
}
.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 {
2025-05-16 16:16:41 +08:00
background: linear-gradient(135deg, #4a90e2, #2879ff);
2025-05-07 09:44:23 +08:00
padding: 20px 15px;
2025-05-16 16:16:41 +08:00
color: #fff;
border-radius: 0 0 15px 15px;
box-shadow: 0 4px 12px rgba(40, 121, 255, 0.2);
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 10;
2025-05-07 09:44:23 +08:00
.header-content {
display: flex;
2025-05-16 16:16:41 +08:00
flex-direction: column;
gap: 15px;
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
.title-section {
.title {
font-size: 24px;
font-weight: bold;
}
.subtitle {
font-size: 14px;
opacity: 0.8;
}
2025-05-07 09:44:23 +08:00
}
2025-05-16 16:16:41 +08:00
// 学生选择栏样式
.student-selector-bar {
2025-05-07 09:44:23 +08:00
display: flex;
align-items: center;
2025-05-16 16:16:41 +08:00
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 10px;
2025-05-07 09:44:23 +08:00
2025-05-16 16:16:41 +08:00
.user-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #fff;
overflow: hidden;
2025-05-07 09:44:23 +08:00
margin-right: 10px;
}
2025-05-16 16:16:41 +08:00
.student-info {
flex: 1;
2025-05-07 09:44:23 +08:00
display: flex;
flex-direction: column;
2025-05-16 16:16:41 +08:00
.student-name {
2025-05-07 09:44:23 +08:00
font-size: 16px;
2025-05-16 16:16:41 +08:00
font-weight: 500;
margin-bottom: 2px;
2025-05-07 09:44:23 +08:00
}
2025-05-16 16:16:41 +08:00
.student-class {
font-size: 12px;
opacity: 0.8;
}
}
.switch-btn {
padding: 4px 12px;
background-color: rgba(255, 255, 255, 0.2);
color: #fff;
border-radius: 20px;
font-size: 13px;
}
}
.countdown-section {
.countdown-title {
font-size: 14px;
margin-bottom: 8px;
}
.countdown-timer {
display: flex;
align-items: center;
.time-block {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 6px;
min-width: 40px;
padding: 5px 8px;
text-align: center;
.time-value {
font-size: 20px;
font-weight: bold;
display: block;
}
.time-unit {
font-size: 12px;
opacity: 0.9;
}
}
.time-separator {
font-size: 20px;
font-weight: bold;
margin: 0 5px;
2025-05-07 09:44:23 +08:00
}
}
}
}
2025-05-16 16:16:41 +08:00
}
// 可滚动内容区域样式
.scrollable-content {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
2025-05-07 09:44:23 +08:00
}
.course-grid {
display: flex;
flex-wrap: wrap;
2025-05-16 16:16:41 +08:00
padding: 15px 15px 0 15px;
2025-05-07 09:44:23 +08:00
.course-item {
position: relative;
width: calc(50% - 10px);
margin-bottom: 15px;
background-color: #fff;
border-radius: 8px;
padding: 15px;
box-sizing: border-box;
2025-05-16 16:16:41 +08:00
border: 1px solid transparent;
transition: all 0.3s ease;
2025-05-07 09:44:23 +08:00
&:nth-child(odd) {
margin-right: 10px;
}
&:nth-child(even) {
margin-left: 10px;
}
&.selected {
border: 1px solid #3fbf72;
2025-05-16 16:16:41 +08:00
background-color: rgba(63, 191, 114, 0.05);
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
2025-05-07 09:44:23 +08:00
}
.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 {
2025-05-16 16:16:41 +08:00
position: sticky;
2025-05-07 09:44:23 +08:00
bottom: 0;
left: 0;
right: 0;
padding: 15px;
background-color: #fff;
2025-05-16 16:16:41 +08:00
z-index: 10;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
.selected-count-info {
2025-05-07 09:44:23 +08:00
font-size: 14px;
color: #666;
2025-05-16 16:16:41 +08:00
margin-bottom: 8px;
2025-05-07 09:44:23 +08:00
}
.register-btn {
height: 50px;
line-height: 50px;
text-align: center;
background-color: #2879ff;
color: #fff;
border-radius: 25px;
font-size: 16px;
font-weight: 500;
}
2025-05-16 16:16:41 +08:00
.multi-select-tip {
font-size: 12px;
color: #909399;
text-align: center;
}
}
/* 学生选择器弹窗样式 */
.student-selector {
background-color: #ffffff;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
padding-bottom: 20px;
.selector-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
border-bottom: 1px solid #f2f2f2;
.selector-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
}
.student-list {
padding: 0 15px;
.student-item {
display: flex;
align-items: center;
padding: 15px 0;
border-bottom: 1px solid #f2f2f2;
&:last-child {
border-bottom: none;
}
&-active {
background-color: rgba(64, 158, 255, 0.05);
}
.student-avatar {
width: 45px;
height: 45px;
border-radius: 50%;
background-color: #f0f0f0;
overflow: hidden;
flex-shrink: 0;
}
.student-info {
flex: 1;
margin-left: 12px;
.student-name {
font-size: 15px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
}
.student-class {
font-size: 13px;
color: #606266;
}
}
}
}
}
/* 全局图片样式 */
.w-full {
width: 100%;
}
.h-full {
height: 100%;
}
// 暂无数据样式
.empty-course-list {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 20px;
text-align: center;
.empty-icon {
margin-bottom: 20px;
background-color: #f5f6f7;
width: 80px;
height: 80px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.empty-text {
font-size: 18px;
font-weight: 500;
color: #303133;
margin-bottom: 8px;
}
.empty-desc {
font-size: 14px;
color: #909399;
max-width: 80%;
line-height: 1.5;
}
}
/* 选课已结束样式 */
.enrollment-ended {
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 12px 15px;
font-size: 16px;
font-weight: 500;
color: #fff;
gap: 8px;
2025-05-07 09:44:23 +08:00
}
</style>