zhxy-jsd/src/pages/view/homeSchool/JiaoShiKeBiao.vue
2025-09-30 14:40:32 +08:00

506 lines
11 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 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>