2025-09-02 20:57:37 +08:00

355 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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-header">
<view class="course-name">{{ xkkc.kcmc }}{{ xkkc.jsName ? '-' + xkkc.jsName : '' }}</view>
<view class="detail-btn" @click.stop="goToDetail(xkkc)">
<image src="/static/base/home/details.svg" class="detail-icon" />
</view>
</view>
<view class="register-info">
<text>报名情况</text>
<text class="register-count">{{ xkkc.hasNum || 0 }}</text>
<text> | {{ xkkc.maxNum || 0 }}</text>
</view>
<view class="study-time-info" v-if="xkkc.studyTime">
<text></text>
<text class="study-time">{{ xkkc.studyTime }}</text>
</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 = withDefaults(defineProps<{
xk: any,
canSelected: boolean,
}>(), {
xk: () => ({}),
canSelected: false,
});
// 定义一个上级传入的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;
selectedXkkcIds = selectedXkkcIds.filter(
(id: string) => id !== xkkc.id
);
} else {
// 选择课程时的验证逻辑
const maxNum = xkkc.maxNum || 0;
const hasNum = xkkc.hasNum || 0;
if (maxNum <= hasNum) {
uni.showToast({
title: '课程名额已经被抢光,是否重新选课',
icon: 'none',
duration: 2000
});
return;
}
// 检查上课时间是否重复
if (xkkc.studyTime && props.xk.kxNum > 1) {
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
});
return;
}
}
// 判断判断数量,如果是多选,需要再次判断一个逻辑
if (props.xk.kxNum > 1) {
if (selectedXkkcIds.length >= props.xk.kxNum) {
uni.showToast({
title: '已选课程数量已达上限!请取消其他课程再选择!',
icon: 'none',
duration: 2000
});
return;
}
// 如果是多选,则添加到已选数组
if (!selectedXkkcIds.includes(xkkc.id)) {
selectedXkkcIds.push(xkkc.id);
}
} else {
// 如果是单选,则清空已选数组并添加当前课程
selectedXkkcIds = [xkkc.id];
// 清理选中状态
xkkcList.value.forEach((item: any) => {
item.isSelected = false;
});
}
xkkc.isSelected = true;
}
// 更新本地存储
uni.setStorageSync("selectedXkkcIds", selectedXkkcIds);
emit("change", selectedXkkcIds);
}
const goToDetail = (xkkc: any) => {
setKcData(xkkc);
uni.navigateTo({
url: `/pages/base/xk/detail`,
});
};
const switchXk = (xk: any) => {
xkkcList.value = xk.xkkcs || xk.xkkcList || [];
console.log('switchXk', xk)
// 对课程列表进行排序:先按课程名称,再按课程名称中的序号,最后按上课时间
xkkcList.value.sort((a: any, b: any) => {
// 提取课程名称(去掉序号部分)
const getCourseName = (kcmc: string) => {
return kcmc.replace(/\d+$/, '');
};
// 提取课程名称中的序号
const getCourseNumber = (kcmc: string) => {
const match = kcmc.match(/(\d+)$/);
return match ? parseInt(match[1]) : 0;
};
const aCourseName = getCourseName(a.kcmc);
const bCourseName = getCourseName(b.kcmc);
// 首先按课程名称排序(最高优先级)
if (aCourseName !== bCourseName) {
return aCourseName.localeCompare(bCourseName, 'zh-CN');
}
// 如果课程名称相同,则按课程名称中的序号排序(按数值大小,不是字符串)
const aNumber = getCourseNumber(a.kcmc);
const bNumber = getCourseNumber(b.kcmc);
// 如果都有序号,按数值大小排序
if (aNumber > 0 && bNumber > 0) {
if (aNumber !== bNumber) {
return aNumber - bNumber; // 数值排序3 < 14
}
}
// 如果序号相同或没有序号,则按上课时间排序
if (a.studyTime && b.studyTime) {
return a.studyTime.localeCompare(b.studyTime, 'zh-CN');
}
// 如果某个没有上课时间,则排在后面
if (a.studyTime && !b.studyTime) return -1;
if (!a.studyTime && b.studyTime) return 1;
return 0;
});
if (!props.canSelected) {
return;
}
// 获取本地存储的已选课程ID数组
let selectedXkkcIds = uni.getStorageSync("selectedXkkcIds") || [];
let newSelectedXkkcIds: string[] = [];
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);
emit("change", newSelectedXkkcIds);
}
// 监听当前学生信息变更
watch(() => props.xk, (newVal) => {
if (newVal && (newVal.xkkcs || newVal.xkkcList)) {
switchXk(newVal);
}
});
// 初始化
if (props.xk && (props.xk.xkkcs || props.xk.xkkcList)) {
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-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 10px;
.course-name {
font-size: 16px;
font-weight: 500;
color: #333;
flex: 1;
margin-right: 10px;
line-height: 1.4;
min-height: 44px; /* 统一两行高度16px * 1.4 * 2 ≈ 44px */
display: flex;
align-items: flex-start;
word-break: break-all;
overflow: hidden;
}
.detail-btn {
flex-shrink: 0;
padding: 4px;
.detail-icon {
width: 20px;
height: 20px;
}
}
}
.register-info {
font-size: 14px;
color: #666;
margin-bottom: 8px;
.register-count {
color: #2879ff;
}
}
.study-time-info {
font-size: 14px;
color: #666;
margin-bottom: 8px;
.study-time {
color: #ff6b35;
font-weight: 500;
}
}
.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>