506 lines
11 KiB
Vue
506 lines
11 KiB
Vue
<template>
|
||
<view class="schedule-page">
|
||
<view class="week-selector" @click="openWeekPicker">
|
||
<text>{{ curZc.mc }}</text>
|
||
<uni-icons type="right" size="16" color="#fff"></uni-icons>
|
||
</view>
|
||
|
||
<view class="date-tabs" v-if="rqList.length > 0">
|
||
<view v-for="(day, index) in rqList" :key="index" :class="['date-tab-item', { active: curRqIndex === index }]"
|
||
@click="selectDay(index)">
|
||
<text class="weekday">{{ day.zjmc }}</text>
|
||
<text class="date">{{ day.rqmc }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="no-course-notice" v-else>
|
||
<text class="notice-text">本周处于节假日中,无课程信息</text>
|
||
</view>
|
||
|
||
<view class="schedule-body" v-if="rqList.length > 0 && sjList.length > 0">
|
||
<view v-for="(sj, index) in sjList" :key="index" class="schedule-row">
|
||
<view class="time-slot">
|
||
<text class="slot-name">{{ sj.mc }}</text>
|
||
<text class="slot-time">{{ sj.kssj }}-{{ sj.jssj }}</text>
|
||
</view>
|
||
|
||
<view class="course-container">
|
||
<template v-if="sj.pkkbList && sj.pkkbList.length > 0">
|
||
<view v-for="(pkkb, pkkbIndex) in sj.pkkbList" :key="pkkbIndex"
|
||
:class="['course-card', getCourseColorClass(pkkb.pkMc)]">
|
||
<text class="course-subject">{{ pkkb.pkMc }}</text>
|
||
<text class="course-class">{{ (pkkb.njmc || "无年级") + " " + (pkkb.bjmc || "无班级") }}</text>
|
||
</view>
|
||
</template>
|
||
<view v-else class="empty-course">
|
||
<text class="empty-text">暂无课程</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="isLoading" class="loading-overlay">
|
||
<text>加载中...</text>
|
||
</view>
|
||
|
||
<!-- 周选择弹窗 -->
|
||
<uni-popup ref="weekPopup" type="bottom" @change="popupChange">
|
||
<view class="week-picker-popup">
|
||
<view class="popup-header">
|
||
<text class="title">选择周</text>
|
||
</view>
|
||
<view class="week-list">
|
||
<scroll-view scroll-y style="max-height: 60vh" :scroll-top="targetScrollTop">
|
||
<view v-for="(zc, index) in zcList" :key="index" :class="[
|
||
'week-item',
|
||
{ active: zc.djz === curZc.djz },
|
||
]" @click="selectWeek(zc)">
|
||
<text>{{ zc.mc }}</text>
|
||
<text v-if="zc.dnDjz === dnDjz" class="current-tag">当前周</text>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, onMounted, nextTick } from "vue";
|
||
import { drpkkbApi } from "@/api/base/server";
|
||
import { useUserStore } from "@/store/modules/user";
|
||
import { useCommonStore } from "@/store/modules/common";
|
||
const { getJs } = useUserStore();
|
||
const { getDqPk } = useCommonStore();
|
||
import dayjs from "dayjs";
|
||
import "dayjs/locale/zh-cn";
|
||
import weekOfYear from "dayjs/plugin/weekOfYear";
|
||
import isoWeek from "dayjs/plugin/isoWeek";
|
||
|
||
dayjs.locale("zh-cn");
|
||
dayjs.extend(weekOfYear);
|
||
dayjs.extend(isoWeek);
|
||
|
||
let dqZc = 0;
|
||
let xqId = '';
|
||
|
||
// 这是当年的第几周
|
||
const dnDjz = ref(dayjs().isoWeek());
|
||
|
||
// 当前选中周次
|
||
const curZc = ref<any>({});
|
||
// 当前选中日期序号
|
||
const curRqIndex = ref(0)
|
||
// 周次列表
|
||
const zcList = ref<any>([])
|
||
// 日期列表
|
||
const rqList = computed(() => {
|
||
if (!curZc.value || !curZc.value.drList || !curZc.value.drList.length) {
|
||
return [];
|
||
}
|
||
return curZc.value.drList.filter((dr: any) => {
|
||
return (!dr.holiday && dr.zj <= 5) || (dr.holiday && dr.holiday.type != 2);
|
||
});
|
||
});
|
||
// 时间列表
|
||
const sjList = ref<any>([])
|
||
|
||
const isLoading = ref(false);
|
||
|
||
// 周选择相关
|
||
const showWeekPicker = ref(false);
|
||
const weekPopup = ref<any>(null);
|
||
|
||
const selectedWeekNumber = ref(0);
|
||
const targetScrollTop = ref(0); // 新增:用于绑定 scroll-top
|
||
|
||
|
||
// 打开周选择弹窗
|
||
const openWeekPicker = async () => {
|
||
// 周次不大于2,不用弹出弹窗
|
||
if (!zcList.value || zcList.value.length < 2) {
|
||
return;
|
||
}
|
||
showWeekPicker.value = true;
|
||
// 打开弹窗
|
||
await nextTick();
|
||
if (weekPopup.value) {
|
||
weekPopup.value.open("bottom");
|
||
} else {
|
||
console.error("Week popup ref is not available.");
|
||
}
|
||
}
|
||
|
||
// 关闭周选择弹窗
|
||
const closeWeekPicker = () => {
|
||
if (weekPopup.value) {
|
||
weekPopup.value.close();
|
||
}
|
||
};
|
||
|
||
// 弹窗状态变化
|
||
const popupChange = (e: { show: boolean }) => {
|
||
if (!e.show) {
|
||
showWeekPicker.value = false;
|
||
}
|
||
};
|
||
|
||
// 选择周
|
||
const selectWeek = (zc: any) => {
|
||
if (curZc.value && zc && zc.djz === curZc.value.djz) {
|
||
// 如果点击的是当前已选中的周,则只关闭弹窗
|
||
closeWeekPicker();
|
||
return;
|
||
}
|
||
// 复制
|
||
Object.assign(curZc.value, zc);
|
||
|
||
// 关闭弹窗
|
||
closeWeekPicker();
|
||
|
||
// 选中第一天
|
||
selectDay(0);
|
||
};
|
||
|
||
// 选择日期
|
||
const selectDay = (index: number) => {
|
||
curRqIndex.value = index;
|
||
if (!rqList.value.length) {
|
||
return;
|
||
}
|
||
const params = {
|
||
jsId: getJs.id,
|
||
bjId: "",
|
||
xqId: xqId,
|
||
zc: curZc.value.djz,
|
||
rq: rqList.value[index].rq, // 用于查询代课信息
|
||
zj: rqList.value[index].zj,
|
||
txDate: null
|
||
};
|
||
if (params.zj > 5) {
|
||
const holiday = rqList.value[index].holiday || {};
|
||
if (holiday && holiday.type === 3 && holiday.txDate) {
|
||
params.txDate = holiday.txDate;
|
||
const txZc = rqList.value[index].txZc;
|
||
if (txZc) {
|
||
params.zc = txZc;
|
||
}
|
||
}
|
||
}
|
||
|
||
console.log("查询课表参数:", params);
|
||
|
||
drpkkbApi(params).then(res => {
|
||
// 根据接口返回的result判断是否已报名
|
||
if (res && res.resultCode === 1) {
|
||
sjList.value = res.result;
|
||
} else {
|
||
// 接口调用成功但返回错误
|
||
console.warn("检查报名状态接口返回错误:", res);
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
// 接口调用失败
|
||
console.error("调用检查报名状态接口失败:", error);
|
||
});
|
||
};
|
||
|
||
// 判断课程颜色
|
||
const getCourseColorClass = (subject: string | undefined): string => {
|
||
if (!subject) return "";
|
||
if (subject.includes("语文")) return "color-lang";
|
||
if (subject.includes("体育")) return "color-phys";
|
||
if (subject.includes("数学")) return "color-math";
|
||
return "color-other";
|
||
};
|
||
|
||
onMounted(async () => {
|
||
const res = await getDqPk();
|
||
const result = res.result;
|
||
dqZc = res.result.zc;
|
||
xqId = res.result.xq.id;
|
||
zcList.value = result.zcList;
|
||
sjList.value = [];
|
||
let zc = zcList.value.find((item:any) => item.djz === dqZc);
|
||
if (!zc) {
|
||
zc = zcList.value[0];
|
||
}
|
||
selectWeek(zc);
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.schedule-page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
background-color: #f8f8f8;
|
||
}
|
||
|
||
.week-selector {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 12px 15px;
|
||
background-color: #4477ee;
|
||
color: #ffffff;
|
||
font-size: 15px;
|
||
}
|
||
|
||
.date-tabs {
|
||
display: flex;
|
||
background-color: #4477ee;
|
||
padding: 10px 15px 15px 15px;
|
||
gap: 10px;
|
||
overflow-x: auto;
|
||
|
||
.date-tab-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 16rpx 10rpx;
|
||
border-radius: 12rpx;
|
||
background-color: rgba(255, 255, 255, 0.1);
|
||
color: #ffffff;
|
||
flex: 1;
|
||
min-width: 100rpx;
|
||
max-width: 118rpx;
|
||
cursor: pointer;
|
||
transition: background-color 0.2s ease;
|
||
|
||
.weekday {
|
||
font-size: 13px;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.date {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
&.active {
|
||
background-color: #ffffff;
|
||
color: #4477ee;
|
||
|
||
.weekday {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.schedule-body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
background-color: #ffffff;
|
||
margin: 15px;
|
||
border-radius: 8px;
|
||
padding: 10px;
|
||
}
|
||
|
||
.schedule-row {
|
||
display: flex;
|
||
margin-bottom: 10px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
padding-bottom: 10px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.time-slot {
|
||
width: 75px;
|
||
min-width: 75px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #f9fafb;
|
||
border-radius: 6px;
|
||
padding: 8px 0;
|
||
|
||
.slot-name {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
|
||
.slot-time {
|
||
font-size: 11px;
|
||
color: #999;
|
||
margin-top: 3px;
|
||
}
|
||
}
|
||
|
||
.course-container {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
margin-left: 10px;
|
||
gap: 8px;
|
||
}
|
||
|
||
.course-card {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 6px;
|
||
padding: 8px 12px;
|
||
min-width: 120px;
|
||
text-align: center;
|
||
color: #333;
|
||
|
||
.course-subject {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.course-class {
|
||
font-size: 11px;
|
||
color: #666;
|
||
}
|
||
|
||
&.color-lang {
|
||
background-color: #ffebee;
|
||
border-left: 3px solid #f44336;
|
||
}
|
||
|
||
&.color-phys {
|
||
background-color: #e3f2fd;
|
||
border-left: 3px solid #2196f3;
|
||
}
|
||
|
||
&.color-math {
|
||
background-color: #e8f5e9;
|
||
border-left: 3px solid #4caf50;
|
||
}
|
||
|
||
&.color-other {
|
||
background-color: #f5f5f5;
|
||
border-left: 3px solid #9e9e9e;
|
||
}
|
||
}
|
||
|
||
.empty-course {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #f9f9f9;
|
||
border-radius: 6px;
|
||
min-height: 60px;
|
||
|
||
.empty-text {
|
||
color: #999;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
|
||
.loading-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(255, 255, 255, 0.7);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 10;
|
||
color: #333;
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* 周选择弹窗样式 */
|
||
.week-picker-popup {
|
||
background-color: #fff;
|
||
border-radius: 16px 16px 0 0;
|
||
padding-bottom: 20px;
|
||
|
||
.popup-header {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 15px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
position: relative;
|
||
|
||
.title {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.week-list {
|
||
padding: 10px 0;
|
||
|
||
.week-item {
|
||
height: 53.5px; // 设置固定高度
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center; // 确保垂直居中
|
||
padding: 0 15px; // 调整 padding 以适应固定高度,移除上下 padding
|
||
border-bottom: 1px solid #f5f5f5;
|
||
box-sizing: border-box;
|
||
|
||
&.active {
|
||
background-color: #f0f7ff;
|
||
color: #4477ee;
|
||
}
|
||
|
||
.current-tag {
|
||
font-size: 12px;
|
||
color: #fff;
|
||
background-color: #4477ee;
|
||
padding: 2px 6px;
|
||
border-radius: 10px;
|
||
white-space: nowrap; // 防止标签换行
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 年级班级选择器样式 - 调整为单个选择器 */
|
||
.class-selector {
|
||
display: flex;
|
||
justify-content: center; // 居中显示
|
||
align-items: center;
|
||
padding: 10px 15px;
|
||
background-color: #f8f8f8;
|
||
border-bottom: 1px solid #eee;
|
||
|
||
.picker-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 5px 15px; // 稍微调整padding
|
||
background-color: #fff;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
color: #333;
|
||
min-width: 150px; // 给个最小宽度
|
||
justify-content: space-between; // 让文字和图标分开
|
||
|
||
text {
|
||
margin-right: 8px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.no-course-notice {
|
||
margin: 15px;
|
||
background-color: #fff;
|
||
border-radius: 8px;
|
||
padding: 50px 15px;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||
text-align: center;
|
||
}
|
||
</style>
|