选课调整
This commit is contained in:
parent
c0b8773e57
commit
5f220a6f07
369
src/pages/base/xk/components/XkkcList/indexMore.vue
Normal file
369
src/pages/base/xk/components/XkkcList/indexMore.vue
Normal file
@ -0,0 +1,369 @@
|
||||
<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="goToDetail(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="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="xkkc.isDisabled ? 'locked' : '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, getQk } = useDataStore();
|
||||
|
||||
// 接收外部传入属性并设置默认值
|
||||
const props = withDefaults(defineProps<{
|
||||
xk: any,
|
||||
canSelected: boolean,
|
||||
}>(), {
|
||||
xk: () => ({}),
|
||||
canSelected: false,
|
||||
});
|
||||
|
||||
// 定义一个上级传入的emit响应事件用于接收数据变更
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
// 学生列表数据
|
||||
const xkkcList = ref<any>([]);
|
||||
|
||||
// 已经选课的清单数据
|
||||
const xkQdList = ref<any>([]);
|
||||
|
||||
// 切换选课课程
|
||||
const toggleSelection = (xkkc: any) => {
|
||||
if (!props.canSelected || xkkc.isDisabled) {
|
||||
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 || [];
|
||||
// 对课程列表进行排序:先按课程名称,再按课程名称中的序号,最后按上课时间
|
||||
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;
|
||||
}
|
||||
|
||||
let newSelectedXkkcIds: string[] = [];
|
||||
if (xkQdList.value.length > 0) {
|
||||
for (let i = 0; i < xkkcList.value.length; i++) {
|
||||
const xkkc = xkkcList.value[i];
|
||||
// 只检查本地存储的已选课程
|
||||
if (xkQdList.value.includes(xkkc.id)) {
|
||||
xkkc.isSelected = true;
|
||||
xkkc.isDisabled = true;
|
||||
} else {
|
||||
xkkc.isSelected = false;
|
||||
xkkc.isDisabled = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 获取本地存储的已选课程ID数组
|
||||
let selectedXkkcIds = uni.getStorageSync("selectedXkkcIds") || [];
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const qk = getQk || {};
|
||||
const qkQdList = qk.xkqdList || [];
|
||||
xkQdList.value = [];
|
||||
qkQdList.forEach((qd: any) => {
|
||||
xkQdList.value.push(qd.xkkcId);
|
||||
});
|
||||
// 初始化
|
||||
if (props.xk && (props.xk.xkkcs || props.xk.xkkcList)) {
|
||||
switchXk(props.xk);
|
||||
}
|
||||
});
|
||||
|
||||
// 暴露接口给外部调用
|
||||
defineExpose({
|
||||
switchXk
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.course-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 15px 15px 0 15px;
|
||||
|
||||
.course-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.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>
|
||||
@ -21,7 +21,7 @@
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import XkPicker from "@/pages/base/xk/components/XkPicker/index.vue"
|
||||
import XkkcList from "@/pages/base/xk/components/XkkcList/index.vue"
|
||||
import XkkcList from "@/pages/base/xk/components/XkkcList/indexMore.vue"
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
@click="goBack"
|
||||
/>
|
||||
<u-button v-if="showFlag"
|
||||
text="补选报名"
|
||||
text="新增报名"
|
||||
class="ml-7 mr-15"
|
||||
:plain="true"
|
||||
color="#2879ff"
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import XkPicker from "@/pages/base/xk/components/XkPicker/index.vue"
|
||||
import XkkcList from "@/pages/base/xk/components/XkkcList/index.vue"
|
||||
import XkkcList from "@/pages/base/xk/components/XkkcList/indexMore.vue"
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user