调整选课使用公共组件
This commit is contained in:
parent
c12aa5c773
commit
829508ba57
@ -3,343 +3,37 @@
|
|||||||
<!-- 选课信息头部 - 固定部分 -->
|
<!-- 选课信息头部 - 固定部分 -->
|
||||||
<view class="selection-header">
|
<view class="selection-header">
|
||||||
<view class="header-content">
|
<view class="header-content">
|
||||||
<view class="title-section" @click="clickShowXkSelector">
|
<!-- 选课类型选择部分 -->
|
||||||
<view class="title">
|
<XkPicker title="俱乐部信息" :is-xs="true" xklx-id="816059832" :xs-id="curXs.id" :nj-id="curXs.njId" @change="switchXk" />
|
||||||
<text v-if="xkData && xkData.xkmc">{{ xkData.xkmc }}</text>
|
|
||||||
<text v-else>选课信息</text>
|
|
||||||
</view>
|
|
||||||
<view class="switch-btn" v-if="xkList.length > 1">切换</view>
|
|
||||||
</view>
|
|
||||||
<!-- 学生选择部分 -->
|
<!-- 学生选择部分 -->
|
||||||
<view class="student-selector-bar" @click="clickShowXsSelector">
|
<XsPicker :is-bar="true" />
|
||||||
<view class="user-avatar">
|
|
||||||
<image
|
|
||||||
:src="curXs.xstxUrl || '/static/base/home/11222.png'"
|
|
||||||
class="w-full h-full"
|
|
||||||
></image>
|
|
||||||
</view>
|
|
||||||
<view class="student-info">
|
|
||||||
<text class="student-name">{{ curXs.xm }}</text>
|
|
||||||
<text class="student-class"
|
|
||||||
>{{ curXs.njmc }} {{ curXs.bjmc }}</text
|
|
||||||
>
|
|
||||||
</view>
|
|
||||||
<view class="switch-btn" v-if="xsList.length > 1">切换</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 可滚动的内容区域 -->
|
<!-- 可滚动的内容区域 -->
|
||||||
<view class="scrollable-content">
|
<view class="scrollable-content">
|
||||||
<!-- 课程网格列表 -->
|
<XkkcList :xk="curXk" :can-selected="false" />
|
||||||
<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 }"
|
|
||||||
>
|
|
||||||
<view class="course-name">{{ course.kcmc }}</view>
|
|
||||||
<view class="register-info">
|
|
||||||
<text>上课人数:</text>
|
|
||||||
<text class="register-count">{{ course.ybmr }}</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>
|
|
||||||
</view>
|
|
||||||
<view class="empty-text">暂无课程数据</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view>
|
|
||||||
<!-- 学生选择弹窗 -->
|
|
||||||
<u-popup
|
|
||||||
:show="showXsFlag"
|
|
||||||
@close="showXsFlag = 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="showXsFlag = false"
|
|
||||||
></u-icon>
|
|
||||||
</view>
|
|
||||||
<view class="student-list">
|
|
||||||
<view
|
|
||||||
v-for="(xs, index) in xsList"
|
|
||||||
:key="index"
|
|
||||||
class="student-item"
|
|
||||||
:class="{
|
|
||||||
'student-item-active': curXs.id === xs.id
|
|
||||||
}"
|
|
||||||
@click="switchXs(xs)"
|
|
||||||
>
|
|
||||||
<view class="student-avatar">
|
|
||||||
<image
|
|
||||||
:src="xs.xstxUrl || '/static/base/home/11222.png'"
|
|
||||||
class="w-full h-full"
|
|
||||||
></image>
|
|
||||||
</view>
|
|
||||||
<view class="student-info">
|
|
||||||
<text class="student-name">{{ xs.xm }}</text>
|
|
||||||
<text class="student-class"
|
|
||||||
>{{ xs.njmc }} {{ xs.bjmc }}</text
|
|
||||||
>
|
|
||||||
</view>
|
|
||||||
<u-icon
|
|
||||||
v-if="curXs.id === xs.id"
|
|
||||||
name="checkmark"
|
|
||||||
color="#409EFF"
|
|
||||||
size="20"
|
|
||||||
></u-icon>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</u-popup>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view>
|
|
||||||
<!-- 俱乐部选择弹窗 -->
|
|
||||||
<u-popup
|
|
||||||
:show="showXkFlag"
|
|
||||||
@close="showXkFlag = 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="showXkFlag = false"
|
|
||||||
></u-icon>
|
|
||||||
</view>
|
|
||||||
<view class="student-list">
|
|
||||||
<view
|
|
||||||
v-for="(xk, index) in xkList"
|
|
||||||
:key="index"
|
|
||||||
class="student-item"
|
|
||||||
:class="{
|
|
||||||
'student-item-active': xkData.id === xk.id
|
|
||||||
}"
|
|
||||||
@click="switchXk(xk)"
|
|
||||||
>
|
|
||||||
<view class="student-info">
|
|
||||||
<text class="student-name">{{ xk.xkmc }}</text>
|
|
||||||
</view>
|
|
||||||
<u-icon
|
|
||||||
v-if="xkData.id === xk.id"
|
|
||||||
name="checkmark"
|
|
||||||
color="#409EFF"
|
|
||||||
size="20"
|
|
||||||
></u-icon>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</u-popup>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||||
ref,
|
import XkPicker from "@/pages/base/components/XkPicker/index.vue"
|
||||||
computed,
|
import XkkcList from "@/pages/base/components/XkkcList/index.vue"
|
||||||
reactive,
|
|
||||||
onBeforeUnmount,
|
|
||||||
watch,
|
|
||||||
onMounted,
|
|
||||||
} from "vue";
|
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { useDataStore } from "@/store/modules/data";
|
|
||||||
import { xkListApi, xsXkListApi } from "@/api/base/server";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
const { getUser, getCurXs } = useUserStore();
|
const { getCurXs } = useUserStore();
|
||||||
const { getData, setKcData, setData } = useDataStore();
|
|
||||||
const { sign_file } = getData;
|
|
||||||
|
|
||||||
// 学生列表数据
|
const curXs = computed(() => getCurXs);
|
||||||
const xsList = computed(() => {
|
|
||||||
return getUser.xsList;
|
|
||||||
});
|
|
||||||
|
|
||||||
const curXs = ref<any>({});
|
const curXk = ref<any>({});
|
||||||
|
// 切换选课
|
||||||
// 控制选择器显示状态
|
const switchXk = (xk: any) => {
|
||||||
const showXsFlag = ref(false);
|
curXk.value = xk;
|
||||||
const showXkFlag = ref(false);
|
|
||||||
|
|
||||||
if (xsList.value.length > 1) {
|
|
||||||
showXsFlag.value = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const xkList = ref<any>([]);
|
|
||||||
|
|
||||||
const xkData = ref();
|
|
||||||
const kcStatus = ref(false);
|
|
||||||
|
|
||||||
const courseInfo = ref<any>({});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
curXs.value = getCurXs;
|
|
||||||
// 先加载课程列表,不立即检查报名状态
|
|
||||||
uni.showLoading({
|
|
||||||
title: "加载中...",
|
|
||||||
});
|
|
||||||
loadCourseList(curXs.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 加载课程列表
|
|
||||||
const loadCourseList = (xs: any) => {
|
|
||||||
if (!xs) {
|
|
||||||
uni.hideLoading();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xsXkListApi({
|
|
||||||
xsId: xs.id,
|
|
||||||
njId: xs.njId,
|
|
||||||
xklxId: "816059832",
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.resultCode == 1) {
|
|
||||||
if (res.result && res.result.length) {
|
|
||||||
xkList.value = res.result;
|
|
||||||
xkData.value = res.result[0];
|
|
||||||
} else {
|
|
||||||
xkList.value = [];
|
|
||||||
xkData.value = {};
|
|
||||||
}
|
|
||||||
uni.hideLoading();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
uni.hideLoading();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 显示学生选择器
|
|
||||||
function clickShowXsSelector() {
|
|
||||||
if (xsList.value.length > 1) {
|
|
||||||
showXsFlag.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示学生选择器
|
|
||||||
function clickShowXkSelector() {
|
|
||||||
if (xkList.value.length > 1) {
|
|
||||||
showXkFlag.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换学生
|
|
||||||
function switchXs(xs: any) {
|
|
||||||
curXs.value = xs;
|
|
||||||
showXsFlag.value = false;
|
|
||||||
|
|
||||||
// 显示加载中
|
|
||||||
uni.showLoading({
|
|
||||||
title: "加载中...",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 显示切换成功提示
|
|
||||||
uni.showToast({
|
|
||||||
title: `已切换到${xs.xm}`,
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 先加载当前学生的课程列表,课程数据加载完成后会自动检查报名状态
|
|
||||||
loadCourseList(xs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换学生
|
|
||||||
function switchXk(xk: any) {
|
|
||||||
xkData.value = xk;
|
|
||||||
showXkFlag.value = false;
|
|
||||||
|
|
||||||
// 显示切换成功提示
|
|
||||||
uni.showToast({
|
|
||||||
title: `已切换到${xk.xkmc}`,
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从课程数据中提取课程列表
|
|
||||||
const displayCourseList = computed(() => {
|
|
||||||
if (
|
|
||||||
!xkData.value ||
|
|
||||||
!xkData.value.xkkcs ||
|
|
||||||
!Array.isArray(xkData.value.xkkcs)
|
|
||||||
) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取本地存储的已选课程ID数组
|
|
||||||
const selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
|
|
||||||
|
|
||||||
// 为课程添加选中状态属性
|
|
||||||
return xkData.value.xkkcs.map((course: any) => ({
|
|
||||||
...course,
|
|
||||||
isSelected: selectedCourseIds.includes(course.id),
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
// 可修改的课程列表数据
|
|
||||||
const courseListData = ref<any[]>([]);
|
|
||||||
|
|
||||||
// 计算已选择的课程数量
|
|
||||||
const selectedCoursesCount = computed(() => {
|
|
||||||
return courseListData.value.filter((course: any) => course.isSelected).length;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听计算属性变化,更新可修改的数据
|
|
||||||
watch(
|
|
||||||
displayCourseList,
|
|
||||||
(newVal) => {
|
|
||||||
courseListData.value = JSON.parse(JSON.stringify(newVal));
|
|
||||||
|
|
||||||
// 初始化时,将已选课程的全部信息存入courseInfo
|
|
||||||
const selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
|
|
||||||
if (selectedCourseIds.length > 0) {
|
|
||||||
const selectedCourses = newVal.filter((course: any) =>
|
|
||||||
selectedCourseIds.includes(course.id)
|
|
||||||
);
|
|
||||||
courseInfo.value = selectedCourses;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 查看课程详情
|
|
||||||
const viewCourseDetail = (course: any) => {
|
|
||||||
setKcData(course);
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/base/course-selection/detail`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 页面卸载前清除定时器
|
// 页面卸载前清除定时器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
});
|
});
|
||||||
@ -400,108 +94,6 @@ onBeforeUnmount(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
|
|
||||||
.title-section {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
.title {
|
|
||||||
flex: 1 0 1px;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 14px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch-btn {
|
|
||||||
padding: 5px 15px;
|
|
||||||
background-color: rgba(255, 255, 255, 0.2);
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 15px;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 学生选择栏样式
|
|
||||||
.student-selector-bar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
.user-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #fff;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.student-info {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.student-name {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,211 +104,4 @@ onBeforeUnmount(() => {
|
|||||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 15px 15px 0 15px;
|
|
||||||
|
|
||||||
.course-item {
|
|
||||||
position: relative;
|
|
||||||
width: calc(50% - 10px);
|
|
||||||
margin-bottom: 15px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 15px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:nth-child(odd) {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(even) {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
border: 1px solid #3fbf72;
|
|
||||||
background-color: rgba(63, 191, 114, 0.05);
|
|
||||||
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.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: sticky;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 15px;
|
|
||||||
background-color: #fff;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
|
||||||
|
|
||||||
.register-btn {
|
|
||||||
height: 50px;
|
|
||||||
line-height: 50px;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #2879ff;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 25px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 学生选择器弹窗样式 */
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -83,14 +83,13 @@ const startCountdown = (endTimeStamp: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断当前倒计时是选课开始还是选课结束
|
// 判断当前倒计时是选课开始还是选课结束
|
||||||
if (!kcStatus.value && props.xk) {
|
if (!kcStatus.value) {
|
||||||
// 如果是选课开始倒计时结束,则切换到选课结束倒计时
|
// 如果是选课开始倒计时结束,则切换到选课结束倒计时
|
||||||
kcStatus.value = true; // 更新状态为选课已开始
|
kcStatus.value = true; // 更新状态为选课已开始
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "选课已开始",
|
title: "选课已开始",
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
|
|
||||||
// 开始选课结束倒计时
|
// 开始选课结束倒计时
|
||||||
const xkjstime = dayjs(props.xk.xkjstime).valueOf();
|
const xkjstime = dayjs(props.xk.xkjstime).valueOf();
|
||||||
startCountdown(xkjstime);
|
startCountdown(xkjstime);
|
||||||
@ -103,7 +102,6 @@ const startCountdown = (endTimeStamp: number) => {
|
|||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,10 +160,16 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听变更
|
||||||
watch(() => props.xk, (newVal) => {
|
watch(() => props.xk, (newVal) => {
|
||||||
changeXk(newVal);
|
changeXk(newVal);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
if (props.xk && props.xk.id) {
|
||||||
|
changeXk(props.xk);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -204,5 +208,20 @@ watch(() => props.xk, (newVal) => {
|
|||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 选课已结束样式 */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@ -3,7 +3,7 @@
|
|||||||
<view class="title-section" @click="showPicker">
|
<view class="title-section" @click="showPicker">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
<text v-if="curXk && curXk.xkmc">{{ curXk.xkmc }}</text>
|
<text v-if="curXk && curXk.xkmc">{{ curXk.xkmc }}</text>
|
||||||
<text v-else>选课信息</text>
|
<text v-else>{{ title }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="switch-btn" v-if="xkList.length > 1">切换</view>
|
<view class="switch-btn" v-if="xkList.length > 1">切换</view>
|
||||||
</view>
|
</view>
|
||||||
@ -31,15 +31,17 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { xsXkkcListApi } from "@/api/base/server";
|
import { xsXkListApi, xsXkkcListApi } from "@/api/base/server";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
const { getCurXs } = useUserStore();
|
const { getCurXs } = useUserStore();
|
||||||
|
|
||||||
// 接收外部传入属性
|
// 接收外部传入属性
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
isXs: boolean, // 是否是已经选的课程
|
||||||
xsId: string,
|
xsId: string,
|
||||||
njId: string,
|
njId: string,
|
||||||
xklxId: string; // 选课类型Id(962488654:兴趣课 / 816059832:俱乐部)
|
xklxId: string, // 选课类型Id(962488654:兴趣课 / 816059832:俱乐部)
|
||||||
|
title: string,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 定义一个上级传入的emit响应事件用于接收数据变更
|
// 定义一个上级传入的emit响应事件用于接收数据变更
|
||||||
@ -63,15 +65,26 @@ const loadXkList = async () => {
|
|||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: "加载中...",
|
title: "加载中...",
|
||||||
});
|
});
|
||||||
xsXkkcListApi(props)
|
const func = props.isXs ? xsXkListApi : xsXkkcListApi;
|
||||||
|
func({
|
||||||
|
xsId: props.xsId,
|
||||||
|
njId: props.njId,
|
||||||
|
xklxId: props.xklxId,
|
||||||
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.resultCode == 1) {
|
if (res.resultCode == 1) {
|
||||||
if (res.result && res.result.length) {
|
if (res.result && res.result.length) {
|
||||||
xkList.value = res.result;
|
xkList.value = res.result;
|
||||||
curXk.value = res.result[0];
|
curXk.value = res.result[0];
|
||||||
} else {
|
} else {
|
||||||
|
if (props.isXs) {
|
||||||
xkList.value = [];
|
xkList.value = [];
|
||||||
curXk.value = {};
|
curXk.value = {};
|
||||||
|
} else {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/course-selection/notopen",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switchXk(curXk.value);
|
switchXk(curXk.value);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
@ -86,11 +99,13 @@ const loadXkList = async () => {
|
|||||||
function switchXk(xk: any) {
|
function switchXk(xk: any) {
|
||||||
curXk.value = xk;
|
curXk.value = xk;
|
||||||
showFlag.value = false;
|
showFlag.value = false;
|
||||||
|
if (xk && xk.id) {
|
||||||
// 显示切换成功提示
|
// 显示切换成功提示
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: `已切换到${xk.xkmc}`,
|
title: `已切换到${xk.xkmc}`,
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
emit("change", xk);
|
emit("change", xk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
227
src/pages/base/components/XkkcList/index.vue
Normal file
227
src/pages/base/components/XkkcList/index.vue
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<!-- 课程网格列表 -->
|
||||||
|
<view class="course-grid" v-if="xkkcList.length > 0">
|
||||||
|
<view
|
||||||
|
v-for="(xkkc, index) in xkkcList"
|
||||||
|
:key="xkkc.id || index"
|
||||||
|
class="course-item"
|
||||||
|
:class="{ selected: xkkc.isSelected }"
|
||||||
|
@click="toggleSelection(xkkc)"
|
||||||
|
>
|
||||||
|
<view class="course-name">{{ xkkc.kcmc }}</view>
|
||||||
|
<view class="register-info">
|
||||||
|
<text>报名情况:</text>
|
||||||
|
<text class="register-count">{{ xkkc.hasNum || 0 }}</text>
|
||||||
|
<text> | {{ xkkc.maxNum || 0 }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="detail-btn" @click.stop="goToDetail(xkkc)"
|
||||||
|
>详情</view
|
||||||
|
>
|
||||||
|
<view v-if="xkkc.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>
|
||||||
|
</view>
|
||||||
|
<view class="empty-text">暂无课程数据</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
const { setKcData } = useDataStore();
|
||||||
|
|
||||||
|
// 接收外部传入属性
|
||||||
|
const props = defineProps<{
|
||||||
|
xk: any,
|
||||||
|
canSelected: boolean,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 定义一个上级传入的emit响应事件用于接收数据变更
|
||||||
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
|
// 学生列表数据
|
||||||
|
const xkkcList = ref<any>([]);
|
||||||
|
|
||||||
|
// 切换选课课程
|
||||||
|
const toggleSelection = (xkkc: any) => {
|
||||||
|
if (!props.canSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取本地存储的已选课程ID数组
|
||||||
|
let selectedXkkcIds = uni.getStorageSync("selectedXkkcIds") || [];
|
||||||
|
if (xkkc.isSelected) {
|
||||||
|
// 从已选数组中移除
|
||||||
|
selectedXkkcIds = selectedXkkcIds.filter(
|
||||||
|
(id: string) => id !== xkkc.id
|
||||||
|
);
|
||||||
|
xkkc.isSelected = false;
|
||||||
|
// xkkc.hasNum--;
|
||||||
|
} else {
|
||||||
|
// 如果是未选中,判断是否已选满
|
||||||
|
const maxNum = xkkc.maxNum || 0;
|
||||||
|
const hasNum = xkkc.hasNum || 0;
|
||||||
|
if (maxNum > hasNum) {
|
||||||
|
xkkc.isSelected = true;
|
||||||
|
// 添加到已选数组
|
||||||
|
if (!selectedXkkcIds.includes(xkkc.id)) {
|
||||||
|
selectedXkkcIds.push(xkkc.id);
|
||||||
|
// xkkc.hasNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新本地存储
|
||||||
|
uni.setStorageSync("selectedXkkcIds", selectedXkkcIds);
|
||||||
|
emit("change", selectedXkkcIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToDetail = (xkkc: any) => {
|
||||||
|
setKcData(xkkc);
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/base/course-selection/detail`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const switchXk = (xk: any) => {
|
||||||
|
xkkcList.value = xk.xkkcs;
|
||||||
|
if (!props.canSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取本地存储的已选课程ID数组
|
||||||
|
let selectedXkkcIds = uni.getStorageSync("selectedXkkcIds") || [];
|
||||||
|
let newSelectedXkkcIds = [];
|
||||||
|
for (let i = 0; i < xkkcList.value.length; i++) {
|
||||||
|
const xkkc = xkkcList.value[i];
|
||||||
|
if (selectedXkkcIds.includes(xkkc.id)) {
|
||||||
|
xkkc.isSelected = true;
|
||||||
|
newSelectedXkkcIds.push(xkkc.id);
|
||||||
|
} else {
|
||||||
|
xkkc.isSelected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uni.setStorageSync("selectedXkkcIds", newSelectedXkkcIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听当前学生信息变更
|
||||||
|
watch(() => props.xk, (newVal) => {
|
||||||
|
if (newVal && newVal.xkkcs) {
|
||||||
|
switchXk(newVal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
if (props.xk && props.xk.xkkcs) {
|
||||||
|
switchXk(props.xk);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.course-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 15px 15px 0 15px;
|
||||||
|
|
||||||
|
.course-item {
|
||||||
|
position: relative;
|
||||||
|
width: calc(50% - 10px);
|
||||||
|
margin-bottom: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(even) {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border: 1px solid #3fbf72;
|
||||||
|
background-color: rgba(63, 191, 114, 0.05);
|
||||||
|
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂无数据样式
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -94,7 +94,7 @@ const switchXs = (xs: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果是bar形式,则默认打开选择器
|
// 如果是bar形式,则默认打开选择器
|
||||||
if (props.isBar && getUser.xsList.length > 1) {
|
if (props.isBar && getUser.xsList.length > 1 && (getCurXs === null || !getCurXs.id)) {
|
||||||
showPicker();
|
showPicker();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -4,70 +4,41 @@
|
|||||||
<view class="selection-header">
|
<view class="selection-header">
|
||||||
<view class="header-content">
|
<view class="header-content">
|
||||||
<!-- 选课类型选择部分 -->
|
<!-- 选课类型选择部分 -->
|
||||||
<XkPicker xklx-id="816059832" :xs-id="curXs.id" :nj-id="curXs.njId" @change="switchXk" />
|
<XkPicker title="俱乐部信息" :is-xs="false" xklx-id="816059832" :xs-id="curXs.id" :nj-id="curXs.njId" @change="switchXk" />
|
||||||
<!-- 学生选择部分 -->
|
<!-- 学生选择部分 -->
|
||||||
<XsPicker :is-bar="true" />
|
<XsPicker :is-bar="true" />
|
||||||
<!-- 倒计时-->
|
<!-- 倒计时-->
|
||||||
<XkCountdown :xk="curXk" @over="xkTimeOver" />
|
<XkCountdown :xk="curXk" @over="xkTimeOver" v-if="curXk && curXk.id" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 可滚动的内容区域 -->
|
<!-- 可滚动的内容区域 -->
|
||||||
<view class="scrollable-content">
|
<view class="scrollable-content">
|
||||||
<!-- 课程网格列表 -->
|
<XkkcList :xk="curXk" :can-selected="true" @change="changeXkkc" />
|
||||||
<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 }"
|
|
||||||
>
|
|
||||||
<view class="course-name">{{ course.kcmc }}</view>
|
|
||||||
<view class="register-info">
|
|
||||||
<text>上课人数:</text>
|
|
||||||
<text class="register-count">{{ course.ybmr }}</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>
|
||||||
|
|
||||||
<!-- 暂无数据提示 -->
|
<!-- 底部报名按钮 - 固定部分 -->
|
||||||
<view v-else class="empty-course-list">
|
<view class="register-btn-container">
|
||||||
<view class="empty-icon">
|
<view class="selected-count-info" v-if="selectedXkkcIds && selectedXkkcIds.length > 0">
|
||||||
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
|
已选 {{ selectedXkkcIds.length }} 门课程
|
||||||
</view>
|
</view>
|
||||||
<view class="empty-text">暂无课程数据</view>
|
<view class="register-btn" @click="submit">点击报名</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||||
import XkPicker from "@/pages/base/components/XkPicker/index.vue"
|
import XkPicker from "@/pages/base/components/XkPicker/index.vue"
|
||||||
import XkCountdown from "@/pages/base/components/XkCountdown/index.vue"
|
import XkCountdown from "@/pages/base/components/XkCountdown/index.vue"
|
||||||
|
import XkkcList from "@/pages/base/components/XkkcList/index.vue"
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { useDataStore } from "@/store/modules/data";
|
|
||||||
|
|
||||||
const { getCurXs } = useUserStore();
|
const { getCurXs } = useUserStore();
|
||||||
const { setKcData } = useDataStore();
|
|
||||||
|
|
||||||
const curXs = computed(() => getCurXs);
|
const curXs = computed(() => getCurXs);
|
||||||
|
const curXk = ref<any>({});
|
||||||
const curXk = ref();
|
const selectedXkkcIds = ref<any>([]);
|
||||||
const kcStatus = ref(false);
|
|
||||||
|
|
||||||
const courseInfo = ref<any>({});
|
|
||||||
// 切换选课
|
// 切换选课
|
||||||
const switchXk = (xk: any) => {
|
const switchXk = (xk: any) => {
|
||||||
curXk.value = xk;
|
curXk.value = xk;
|
||||||
@ -78,63 +49,17 @@ const xkTimeOver = (val: any) => {
|
|||||||
console.log(val);
|
console.log(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从课程数据中提取课程列表
|
// 选中课程
|
||||||
const displayCourseList = computed(() => {
|
const changeXkkc = (ids: any) => {
|
||||||
if (
|
console.log(ids);
|
||||||
!curXk.value ||
|
selectedXkkcIds.value = ids;
|
||||||
!curXk.value.xkkcs ||
|
}
|
||||||
!Array.isArray(curXk.value.xkkcs)
|
|
||||||
) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取本地存储的已选课程ID数组
|
// 提交选课
|
||||||
const selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
|
const submit = () => {
|
||||||
|
console.log(selectedXkkcIds.value);
|
||||||
|
}
|
||||||
|
|
||||||
// 为课程添加选中状态属性
|
|
||||||
return curXk.value.xkkcs.map((course: any) => ({
|
|
||||||
...course,
|
|
||||||
isSelected: selectedCourseIds.includes(course.id),
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
// 可修改的课程列表数据
|
|
||||||
const courseListData = ref<any[]>([]);
|
|
||||||
|
|
||||||
// 计算已选择的课程数量
|
|
||||||
const selectedCoursesCount = computed(() => {
|
|
||||||
return courseListData.value.filter((course: any) => course.isSelected).length;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听计算属性变化,更新可修改的数据
|
|
||||||
watch(
|
|
||||||
displayCourseList,
|
|
||||||
(newVal) => {
|
|
||||||
courseListData.value = JSON.parse(JSON.stringify(newVal));
|
|
||||||
|
|
||||||
// 初始化时,将已选课程的全部信息存入courseInfo
|
|
||||||
const selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
|
|
||||||
if (selectedCourseIds.length > 0) {
|
|
||||||
const selectedCourses = newVal.filter((course: any) =>
|
|
||||||
selectedCourseIds.includes(course.id)
|
|
||||||
);
|
|
||||||
courseInfo.value = selectedCourses;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 查看课程详情
|
|
||||||
const viewCourseDetail = (course: any) => {
|
|
||||||
setKcData(course);
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/base/course-selection/detail`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 页面卸载前清除定时器
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -202,67 +127,6 @@ onBeforeUnmount(() => {
|
|||||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 15px 15px 0 15px;
|
|
||||||
|
|
||||||
.course-item {
|
|
||||||
position: relative;
|
|
||||||
width: calc(50% - 10px);
|
|
||||||
margin-bottom: 15px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 15px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:nth-child(odd) {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(even) {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
border: 1px solid #3fbf72;
|
|
||||||
background-color: rgba(63, 191, 114, 0.05);
|
|
||||||
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.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 {
|
.register-btn-container {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@ -270,9 +134,15 @@ onBeforeUnmount(() => {
|
|||||||
right: 0;
|
right: 0;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
z-index: 10;
|
z-index: 1;
|
||||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
.selected-count-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.register-btn {
|
.register-btn {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
@ -285,52 +155,4 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 暂无数据样式
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -3,308 +3,37 @@
|
|||||||
<!-- 选课信息头部 - 固定部分 -->
|
<!-- 选课信息头部 - 固定部分 -->
|
||||||
<view class="selection-header">
|
<view class="selection-header">
|
||||||
<view class="header-content">
|
<view class="header-content">
|
||||||
<view class="title-section">
|
<!-- 选课类型选择部分 -->
|
||||||
<view class="title">
|
<XkPicker title="兴趣课信息" :is-xs="true" xklx-id="962488654" :xs-id="curXs.id" :nj-id="curXs.njId" @change="switchXk" />
|
||||||
<text v-if="xkData && xkData.xkmc">{{ xkData.xkmc }}</text>
|
|
||||||
<text v-else>选课信息</text>
|
|
||||||
</view>
|
|
||||||
<!-- <view class="subtitle">互动兴趣课程</view> -->
|
|
||||||
</view>
|
|
||||||
<!-- 学生选择部分 -->
|
<!-- 学生选择部分 -->
|
||||||
<view class="student-selector-bar" @click="showStudentSelector">
|
<XsPicker :is-bar="true" />
|
||||||
<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>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 可滚动的内容区域 -->
|
<!-- 可滚动的内容区域 -->
|
||||||
<view class="scrollable-content">
|
<view class="scrollable-content">
|
||||||
<!-- 课程网格列表 -->
|
<XkkcList :xk="curXk" :can-selected="false" />
|
||||||
<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 }"
|
|
||||||
>
|
|
||||||
<view class="course-name">{{ course.kcmc }}</view>
|
|
||||||
<view class="register-info">
|
|
||||||
<text>上课人数:</text>
|
|
||||||
<text class="register-count">{{ course.ybmr }}</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>
|
||||||
|
|
||||||
<!-- 暂无数据提示 -->
|
|
||||||
<view v-else class="empty-course-list">
|
|
||||||
<view class="empty-icon">
|
|
||||||
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
|
|
||||||
</view>
|
|
||||||
<view class="empty-text">暂无课程数据</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { navigateTo } from "@/utils/uniapp";
|
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||||
import {
|
import XkPicker from "@/pages/base/components/XkPicker/index.vue"
|
||||||
ref,
|
import XkkcList from "@/pages/base/components/XkkcList/index.vue"
|
||||||
computed,
|
|
||||||
reactive,
|
|
||||||
onBeforeUnmount,
|
|
||||||
watch,
|
|
||||||
onMounted,
|
|
||||||
} from "vue";
|
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { useDataStore } from "@/store/modules/data";
|
|
||||||
import { xkListApi, xsXkListApi } from "@/api/base/server";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
const { getUser } = useUserStore();
|
const { getCurXs } = useUserStore();
|
||||||
const { getData, setKcData, setData } = useDataStore();
|
|
||||||
const { sign_file } = getData;
|
|
||||||
|
|
||||||
// 学生列表数据
|
const curXs = computed(() => getCurXs);
|
||||||
const studentList = computed(() => {
|
|
||||||
return getUser.xsList;
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentStudent = ref();
|
const curXk = ref<any>({});
|
||||||
|
// 切换选课
|
||||||
// 控制选择器显示状态
|
const switchXk = (xk: any) => {
|
||||||
const showSelector = ref(false);
|
curXk.value = xk;
|
||||||
|
|
||||||
if (studentList.value.length > 1) {
|
|
||||||
showSelector.value = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const xkData = ref();
|
|
||||||
const kcStatus = ref(false);
|
|
||||||
|
|
||||||
// 添加选课是否已结束的标记
|
|
||||||
const isEnrollmentEnded = ref(false);
|
|
||||||
|
|
||||||
// 添加轮询定时器变量
|
|
||||||
let pollTimer: number | null = null;
|
|
||||||
|
|
||||||
const courseInfo = ref({});
|
|
||||||
|
|
||||||
// 更新课程报名人数
|
|
||||||
const updateEnrollmentCount = (
|
|
||||||
data: Array<{ xkkcId: string; bmrs: number }>
|
|
||||||
) => {
|
|
||||||
if (!Array.isArray(courseListData.value) || courseListData.value.length === 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let hasUpdates = false;
|
|
||||||
|
|
||||||
courseListData.value.forEach((course) => {
|
|
||||||
const newCount = data.find((item) => item.xkkcId === course.id);
|
|
||||||
if (newCount && course.ybmr !== newCount.bmrs) {
|
|
||||||
course.ybmr = newCount.bmrs;
|
|
||||||
hasUpdates = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 如果有更新,强制重新渲染列表
|
|
||||||
if (hasUpdates) {
|
|
||||||
courseListData.value = [...courseListData.value];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 在组件挂载时开始轮询
|
|
||||||
onMounted(() => {
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// 加载课程列表
|
|
||||||
const loadCourseList = (currentStudent: any) => {
|
|
||||||
if (!currentStudent) {
|
|
||||||
uni.hideLoading();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xsXkListApi({
|
|
||||||
xsId: currentStudent.id,
|
|
||||||
njId: currentStudent.njId,
|
|
||||||
xklxId: "962488654",
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.resultCode == 1) {
|
|
||||||
if (res.result && res.result.length) {
|
|
||||||
xkData.value = res.result[0];
|
|
||||||
} else {
|
|
||||||
xkData.value = [];
|
|
||||||
}
|
|
||||||
uni.hideLoading();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
uni.hideLoading();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (studentList.value.length > 0 && studentList.value.length === 1) {
|
|
||||||
currentStudent.value = studentList.value[0];
|
|
||||||
// 先加载课程列表,不立即检查报名状态
|
|
||||||
uni.showLoading({
|
|
||||||
title: "加载中...",
|
|
||||||
});
|
|
||||||
loadCourseList(currentStudent.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示学生选择器
|
|
||||||
function showStudentSelector() {
|
|
||||||
if (studentList.value.length > 1) {
|
|
||||||
showSelector.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换学生
|
|
||||||
function switchStudent(student: any) {
|
|
||||||
currentStudent.value = student;
|
|
||||||
showSelector.value = false;
|
|
||||||
|
|
||||||
// 显示加载中
|
|
||||||
uni.showLoading({
|
|
||||||
title: "加载中...",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 显示切换成功提示
|
|
||||||
uni.showToast({
|
|
||||||
title: `已切换到${student.xm}`,
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 先加载当前学生的课程列表,课程数据加载完成后会自动检查报名状态
|
|
||||||
loadCourseList(student);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从课程数据中提取课程列表
|
|
||||||
const displayCourseList = computed(() => {
|
|
||||||
if (
|
|
||||||
!xkData.value ||
|
|
||||||
!xkData.value.xkkcs ||
|
|
||||||
!Array.isArray(xkData.value.xkkcs)
|
|
||||||
) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取本地存储的已选课程ID
|
|
||||||
const selectedCourseId = uni.getStorageSync("selectedCourseId");
|
|
||||||
|
|
||||||
// 为课程添加选中状态属性
|
|
||||||
return xkData.value.xkkcs.map((course: any) => ({
|
|
||||||
...course,
|
|
||||||
isSelected: selectedCourseId && course.id === selectedCourseId,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
// 可修改的课程列表数据
|
|
||||||
const courseListData = ref<any[]>([]);
|
|
||||||
|
|
||||||
// 监听计算属性变化,更新可修改的数据
|
|
||||||
watch(
|
|
||||||
displayCourseList,
|
|
||||||
(newVal) => {
|
|
||||||
courseListData.value = JSON.parse(JSON.stringify(newVal));
|
|
||||||
|
|
||||||
// 初始化时,将已选课程的全部信息存入courseInfo
|
|
||||||
const selectedCourseId = uni.getStorageSync("selectedCourseId");
|
|
||||||
if (selectedCourseId) {
|
|
||||||
const selectedCourse = newVal.find(
|
|
||||||
(course: any) => course.id === selectedCourseId
|
|
||||||
);
|
|
||||||
if (selectedCourse) {
|
|
||||||
courseInfo.value = selectedCourse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 查看课程详情
|
|
||||||
const viewCourseDetail = (course: any) => {
|
|
||||||
setKcData(course);
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/base/course-selection/detail`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 页面卸载前清除定时器
|
// 页面卸载前清除定时器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
});
|
});
|
||||||
@ -365,97 +94,6 @@ onBeforeUnmount(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
|
|
||||||
.title-section {
|
|
||||||
.title {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 14px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 学生选择栏样式
|
|
||||||
.student-selector-bar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
.user-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #fff;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.student-info {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.student-name {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,211 +104,4 @@ onBeforeUnmount(() => {
|
|||||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 15px 15px 0 15px;
|
|
||||||
|
|
||||||
.course-item {
|
|
||||||
position: relative;
|
|
||||||
width: calc(50% - 10px);
|
|
||||||
margin-bottom: 15px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 15px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:nth-child(odd) {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(even) {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
border: 1px solid #3fbf72;
|
|
||||||
background-color: rgba(63, 191, 114, 0.05);
|
|
||||||
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.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: sticky;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 15px;
|
|
||||||
background-color: #fff;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
|
||||||
|
|
||||||
.register-btn {
|
|
||||||
height: 50px;
|
|
||||||
line-height: 50px;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #2879ff;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 25px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 学生选择器弹窗样式 */
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user