选课调整

This commit is contained in:
hebo 2025-09-09 21:57:17 +08:00
parent c0b8773e57
commit 5f220a6f07
4 changed files with 372 additions and 3 deletions

View 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>

View File

@ -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();

View File

@ -42,7 +42,7 @@
@click="goBack"
/>
<u-button v-if="showFlag"
text="补选报名"
text="新增报名"
class="ml-7 mr-15"
:plain="true"
color="#2879ff"

View File

@ -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();