2025-06-29 21:31:05 +08:00
|
|
|
|
<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)"
|
|
|
|
|
|
>
|
2025-08-04 15:23:50 +08:00
|
|
|
|
<view class="course-header">
|
|
|
|
|
|
<view class="course-name">{{ xkkc.kcmc }}</view>
|
|
|
|
|
|
<view class="detail-btn" @click.stop="goToDetail(xkkc)">
|
|
|
|
|
|
<image src="/static/base/home/details.svg" class="detail-icon" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-06-29 21:31:05 +08:00
|
|
|
|
<view class="register-info">
|
|
|
|
|
|
<text>报名情况:</text>
|
|
|
|
|
|
<text class="register-count">{{ xkkc.hasNum || 0 }}</text>
|
|
|
|
|
|
<text> | {{ xkkc.maxNum || 0 }}</text>
|
|
|
|
|
|
</view>
|
2025-08-11 21:14:06 +08:00
|
|
|
|
<view class="study-time-info" v-if="xkkc.studyTime">
|
|
|
|
|
|
<text></text>
|
|
|
|
|
|
<text class="study-time">{{ xkkc.studyTime }}</text>
|
|
|
|
|
|
</view>
|
2025-06-29 21:31:05 +08:00
|
|
|
|
<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();
|
|
|
|
|
|
|
2025-06-30 23:44:07 +08:00
|
|
|
|
// 接收外部传入属性并设置默认值
|
|
|
|
|
|
const props = withDefaults(defineProps<{
|
2025-06-29 21:31:05 +08:00
|
|
|
|
xk: any,
|
|
|
|
|
|
canSelected: boolean,
|
2025-06-30 23:44:07 +08:00
|
|
|
|
multiple: boolean,
|
|
|
|
|
|
}>(), {
|
|
|
|
|
|
xk: () => ({}),
|
|
|
|
|
|
canSelected: false,
|
|
|
|
|
|
multiple: false,
|
|
|
|
|
|
});
|
2025-06-29 21:31:05 +08:00
|
|
|
|
|
|
|
|
|
|
// 定义一个上级传入的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) {
|
|
|
|
|
|
xkkc.isSelected = false;
|
2025-06-30 23:44:07 +08:00
|
|
|
|
if (props.multiple) {
|
|
|
|
|
|
// 如果是多选,则从已选数组中移除
|
|
|
|
|
|
selectedXkkcIds = selectedXkkcIds.filter(
|
|
|
|
|
|
(id: string) => id !== xkkc.id
|
|
|
|
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果是单选,则清空已选数组
|
|
|
|
|
|
selectedXkkcIds = [];
|
|
|
|
|
|
}
|
2025-06-29 21:31:05 +08:00
|
|
|
|
// xkkc.hasNum--;
|
|
|
|
|
|
} else {
|
2025-08-11 21:14:06 +08:00
|
|
|
|
// 选择课程时的验证逻辑
|
2025-06-29 21:31:05 +08:00
|
|
|
|
const maxNum = xkkc.maxNum || 0;
|
|
|
|
|
|
const hasNum = xkkc.hasNum || 0;
|
2025-08-11 21:14:06 +08:00
|
|
|
|
|
|
|
|
|
|
if (maxNum <= hasNum) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '该课程已满员',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 2000
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查上课时间是否重复
|
|
|
|
|
|
if (xkkc.studyTime && props.multiple) {
|
|
|
|
|
|
const hasTimeConflict = xkkcList.value.some((item: any) => {
|
|
|
|
|
|
// 检查已选课程中是否有相同上课时间
|
|
|
|
|
|
return item.isSelected &&
|
|
|
|
|
|
item.id !== xkkc.id &&
|
|
|
|
|
|
item.studyTime === xkkc.studyTime;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (hasTimeConflict) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '上课时间重复,请重新选择!',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 3000
|
2025-06-30 23:44:07 +08:00
|
|
|
|
});
|
2025-08-11 21:14:06 +08:00
|
|
|
|
return;
|
2025-06-29 21:31:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-11 21:14:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 通过验证,可以选课
|
|
|
|
|
|
if (props.multiple) {
|
|
|
|
|
|
// 如果是多选,则添加到已选数组
|
|
|
|
|
|
if (!selectedXkkcIds.includes(xkkc.id)) {
|
|
|
|
|
|
selectedXkkcIds.push(xkkc.id);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果是单选,则清空已选数组并添加当前课程
|
|
|
|
|
|
selectedXkkcIds = [xkkc.id];
|
|
|
|
|
|
// 清理选中状态
|
|
|
|
|
|
xkkcList.value.forEach((item: any) => {
|
|
|
|
|
|
item.isSelected = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
xkkc.isSelected = true;
|
2025-06-29 21:31:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 更新本地存储
|
|
|
|
|
|
uni.setStorageSync("selectedXkkcIds", selectedXkkcIds);
|
|
|
|
|
|
emit("change", selectedXkkcIds);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const goToDetail = (xkkc: any) => {
|
|
|
|
|
|
setKcData(xkkc);
|
|
|
|
|
|
uni.navigateTo({
|
2025-08-06 12:57:01 +08:00
|
|
|
|
url: `/pages/base/xk/detail`,
|
2025-06-29 21:31:05 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const switchXk = (xk: any) => {
|
|
|
|
|
|
xkkcList.value = xk.xkkcs;
|
|
|
|
|
|
if (!props.canSelected) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-08-06 12:57:01 +08:00
|
|
|
|
|
2025-06-29 21:31:05 +08:00
|
|
|
|
// 获取本地存储的已选课程ID数组
|
|
|
|
|
|
let selectedXkkcIds = uni.getStorageSync("selectedXkkcIds") || [];
|
2025-08-06 12:57:01 +08:00
|
|
|
|
let newSelectedXkkcIds: string[] = [];
|
|
|
|
|
|
|
2025-06-29 21:31:05 +08:00
|
|
|
|
for (let i = 0; i < xkkcList.value.length; i++) {
|
|
|
|
|
|
const xkkc = xkkcList.value[i];
|
2025-08-06 12:57:01 +08:00
|
|
|
|
|
|
|
|
|
|
// 只检查本地存储的已选课程
|
2025-06-29 21:31:05 +08:00
|
|
|
|
if (selectedXkkcIds.includes(xkkc.id)) {
|
|
|
|
|
|
xkkc.isSelected = true;
|
|
|
|
|
|
newSelectedXkkcIds.push(xkkc.id);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
xkkc.isSelected = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-06 12:57:01 +08:00
|
|
|
|
|
2025-06-29 21:31:05 +08:00
|
|
|
|
uni.setStorageSync("selectedXkkcIds", newSelectedXkkcIds);
|
2025-06-30 23:44:07 +08:00
|
|
|
|
emit("change", newSelectedXkkcIds);
|
2025-06-29 21:31:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 监听当前学生信息变更
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-04 15:23:50 +08:00
|
|
|
|
.course-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: flex-start;
|
2025-06-29 21:31:05 +08:00
|
|
|
|
margin-bottom: 10px;
|
2025-08-04 15:23:50 +08:00
|
|
|
|
|
|
|
|
|
|
.course-name {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-btn {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
padding: 4px;
|
|
|
|
|
|
|
|
|
|
|
|
.detail-icon {
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-29 21:31:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.register-info {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #666;
|
2025-08-11 21:14:06 +08:00
|
|
|
|
margin-bottom: 8px;
|
2025-06-29 21:31:05 +08:00
|
|
|
|
|
|
|
|
|
|
.register-count {
|
|
|
|
|
|
color: #2879ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 21:14:06 +08:00
|
|
|
|
.study-time-info {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
|
|
|
|
|
|
.study-time {
|
|
|
|
|
|
color: #ff6b35;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-29 21:31:05 +08:00
|
|
|
|
.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>
|