|
|
|
@ -56,97 +56,31 @@ |
|
|
|
|
|
|
|
<!-- 课程表主体 --> |
|
|
|
<view class="schedule-main"> |
|
|
|
<!-- 左侧冻结列 --> |
|
|
|
<view class="frozen-column"> |
|
|
|
<!-- 左上角标题 --> |
|
|
|
<view class="time-header-cell"> |
|
|
|
<template v-if="activeFilter === 'time' || activeFilter === ''">时间</template> |
|
|
|
<template v-else-if="activeFilter === 'teacher'">教练</template> |
|
|
|
<template v-else-if="activeFilter === 'classroom'">教室</template> |
|
|
|
<template v-else-if="activeFilter === 'class'">班级</template> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 左侧冻结内容 --> |
|
|
|
<scroll-view |
|
|
|
class="frozen-content-scroll" |
|
|
|
scroll-y |
|
|
|
:scroll-top="scrollTop" |
|
|
|
:enable-flex="true" |
|
|
|
:scroll-anchoring="false" |
|
|
|
:enhanced="true" |
|
|
|
:bounces="false" |
|
|
|
:scroll-with-animation="false" |
|
|
|
> |
|
|
|
<view class="frozen-content"> |
|
|
|
<!-- 时间模式 --> |
|
|
|
<template v-if="activeFilter === 'time' || activeFilter === ''"> |
|
|
|
<view |
|
|
|
:class="['frozen-cell', !timeSlot.available ? 'time-unavailable' : '']" |
|
|
|
v-for="(timeSlot, timeIndex) in timeSlots" |
|
|
|
:key="timeIndex" |
|
|
|
:ref="`frozenCell_${timeIndex}`" |
|
|
|
> |
|
|
|
{{ timeSlot.time }} |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 教练模式 --> |
|
|
|
<template v-else-if="activeFilter === 'teacher'"> |
|
|
|
<view |
|
|
|
class="frozen-cell" |
|
|
|
v-for="(teacher, index) in teacherOptions" |
|
|
|
:key="teacher.id" |
|
|
|
:ref="`frozenCell_${index}`" |
|
|
|
> |
|
|
|
{{ teacher.name }} |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 教室模式 --> |
|
|
|
<template v-else-if="activeFilter === 'classroom'"> |
|
|
|
<view |
|
|
|
class="frozen-cell" |
|
|
|
v-for="(venue, index) in venues" |
|
|
|
:key="venue.id" |
|
|
|
:ref="`frozenCell_${index}`" |
|
|
|
> |
|
|
|
{{ venue.name }} |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 班级模式 --> |
|
|
|
<template v-else-if="activeFilter === 'class'"> |
|
|
|
<view |
|
|
|
class="frozen-cell" |
|
|
|
v-for="(cls, index) in classOptions" |
|
|
|
:key="cls.id" |
|
|
|
:ref="`frozenCell_${index}`" |
|
|
|
> |
|
|
|
{{ cls.name }} |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 右侧内容区域 --> |
|
|
|
<view class="schedule-content-area"> |
|
|
|
<!-- 合并的滚动区域(表头+内容) --> |
|
|
|
<!-- 统一滚动区域 --> |
|
|
|
<scroll-view |
|
|
|
class="schedule-scroll" |
|
|
|
scroll-x |
|
|
|
scroll-y |
|
|
|
:scroll-top="scrollTop" |
|
|
|
:style="{ height: scrollViewHeight + 'px' }" |
|
|
|
:enable-flex="true" |
|
|
|
:enhanced="isH5" |
|
|
|
:scroll-anchoring="false" |
|
|
|
:enhanced="true" |
|
|
|
:bounces="false" |
|
|
|
:scroll-with-animation="false" |
|
|
|
:show-scrollbar="false" |
|
|
|
@scroll="onScroll" |
|
|
|
> |
|
|
|
<view class="schedule-container-inner" :style="{ width: tableWidth + 'rpx', minWidth: '1260rpx' }"> |
|
|
|
<!-- 表头 --> |
|
|
|
<view class="date-header-container"> |
|
|
|
<view class="schedule-container-inner" :style="{ width: (tableWidth + 120) + 'rpx', minWidth: '1380rpx' }"> |
|
|
|
<!-- 表头行 --> |
|
|
|
<view class="schedule-header-row"> |
|
|
|
<!-- 左上角标题 --> |
|
|
|
<view class="time-header-cell"> |
|
|
|
<template v-if="activeFilter === 'time' || activeFilter === ''">时间</template> |
|
|
|
<template v-else-if="activeFilter === 'teacher'">教练</template> |
|
|
|
<template v-else-if="activeFilter === 'classroom'">教室</template> |
|
|
|
<template v-else-if="activeFilter === 'class'">班级</template> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 日期列 --> |
|
|
|
<view |
|
|
|
class="date-header-cell" |
|
|
|
@ -169,6 +103,12 @@ |
|
|
|
:key="timeIndex" |
|
|
|
:ref="`scheduleRow_${timeIndex}`" |
|
|
|
> |
|
|
|
<!-- 左侧时间列 --> |
|
|
|
<view :class="['left-column-cell', !timeSlot.available ? 'time-unavailable' : '']"> |
|
|
|
{{ timeSlot.time }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 课程单元格 --> |
|
|
|
<view |
|
|
|
:class="['course-cell',!timeSlot.available ? 'cell-unavailable' : '']" |
|
|
|
v-for="(date, dateIndex) in weekDates" |
|
|
|
@ -234,6 +174,12 @@ |
|
|
|
:key="teacher.id" |
|
|
|
:ref="`scheduleRow_${teacherIndex}`" |
|
|
|
> |
|
|
|
<!-- 左侧教练列 --> |
|
|
|
<view class="left-column-cell"> |
|
|
|
{{ teacher.name }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 课程单元格 --> |
|
|
|
<view |
|
|
|
class="course-cell" |
|
|
|
v-for="(date, dateIndex) in weekDates" |
|
|
|
@ -299,6 +245,12 @@ |
|
|
|
:key="venue.id" |
|
|
|
:ref="`scheduleRow_${venueIndex}`" |
|
|
|
> |
|
|
|
<!-- 左侧教室列 --> |
|
|
|
<view class="left-column-cell"> |
|
|
|
{{ venue.name }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 课程单元格 --> |
|
|
|
<view |
|
|
|
class="course-cell" |
|
|
|
v-for="(date, dateIndex) in weekDates" |
|
|
|
@ -364,6 +316,12 @@ |
|
|
|
:key="cls.id" |
|
|
|
:ref="`scheduleRow_${clsIndex}`" |
|
|
|
> |
|
|
|
<!-- 左侧班级列 --> |
|
|
|
<view class="left-column-cell"> |
|
|
|
{{ cls.name }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 课程单元格 --> |
|
|
|
<view |
|
|
|
class="course-cell" |
|
|
|
v-for="(date, dateIndex) in weekDates" |
|
|
|
@ -424,7 +382,6 @@ |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 筛选弹窗 --> |
|
|
|
<fui-modal |
|
|
|
@ -554,11 +511,10 @@ export default { |
|
|
|
selectedClasses: [], |
|
|
|
|
|
|
|
// 滚动相关 |
|
|
|
scrollTop: 0, |
|
|
|
scrollTimer: null, // 滚动防抖定时器 |
|
|
|
|
|
|
|
// 表格配置 |
|
|
|
tableWidth: 1500, // 表格总宽度,确保7天都能显示 (7*180+120=1380rpx) |
|
|
|
// 表格配置 - 统一滚动后不包含左侧列宽度 |
|
|
|
tableWidth: 1260, // 7天内容宽度 (7*180=1260rpx),左侧120rpx在容器内部 |
|
|
|
|
|
|
|
// 时间段配置(动态生成,支持场地时间限制) |
|
|
|
timeSlots: [], |
|
|
|
@ -591,6 +547,12 @@ export default { |
|
|
|
selectedScheduleId: null, |
|
|
|
showScheduleDetail: false, |
|
|
|
|
|
|
|
// 平台识别 |
|
|
|
isH5: false, |
|
|
|
|
|
|
|
// 滚动视图高度 |
|
|
|
scrollViewHeight: 0, |
|
|
|
|
|
|
|
// 筛选参数 |
|
|
|
filterParams: { |
|
|
|
start_date: '', |
|
|
|
@ -644,12 +606,20 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
mounted() { |
|
|
|
// 检测平台 |
|
|
|
// #ifdef H5 |
|
|
|
this.isH5 = true |
|
|
|
// #endif |
|
|
|
|
|
|
|
this.initCurrentWeek() |
|
|
|
this.initTimeSlots() |
|
|
|
|
|
|
|
// 初始化响应式布局 |
|
|
|
this.handleResize() |
|
|
|
|
|
|
|
// 计算scroll-view高度 |
|
|
|
this.calculateScrollViewHeight() |
|
|
|
|
|
|
|
// 先加载筛选选项,然后加载课程安排列表 |
|
|
|
this.loadFilterOptions().then(() => { |
|
|
|
this.loadScheduleList() |
|
|
|
@ -679,6 +649,72 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
methods: { |
|
|
|
// 时间标准化函数 - 统一时间格式为 HH:mm |
|
|
|
normalizeTime(timeStr) { |
|
|
|
if (!timeStr) return ''; |
|
|
|
|
|
|
|
// 移除空格并转换为字符串 |
|
|
|
const cleanTime = String(timeStr).trim(); |
|
|
|
|
|
|
|
// 如果已经是 HH:mm 格式,直接返回 |
|
|
|
if (/^\d{2}:\d{2}$/.test(cleanTime)) { |
|
|
|
return cleanTime; |
|
|
|
} |
|
|
|
|
|
|
|
// 如果是 H:mm 格式,补零 |
|
|
|
if (/^\d{1}:\d{2}$/.test(cleanTime)) { |
|
|
|
return '0' + cleanTime; |
|
|
|
} |
|
|
|
|
|
|
|
// 如果是 HH:m 格式,补零 |
|
|
|
if (/^\d{2}:\d{1}$/.test(cleanTime)) { |
|
|
|
return cleanTime.slice(0, 3) + '0' + cleanTime.slice(3); |
|
|
|
} |
|
|
|
|
|
|
|
// 如果是 H:m 格式,都补零 |
|
|
|
if (/^\d{1}:\d{1}$/.test(cleanTime)) { |
|
|
|
const [hour, minute] = cleanTime.split(':'); |
|
|
|
return `0${hour}:0${minute}`; |
|
|
|
} |
|
|
|
|
|
|
|
// 其他格式尝试解析 |
|
|
|
try { |
|
|
|
const [hour, minute] = cleanTime.split(':'); |
|
|
|
const h = parseInt(hour).toString().padStart(2, '0'); |
|
|
|
const m = parseInt(minute || 0).toString().padStart(2, '0'); |
|
|
|
return `${h}:${m}`; |
|
|
|
} catch (e) { |
|
|
|
console.warn('时间格式解析失败:', timeStr); |
|
|
|
return cleanTime; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 时间匹配函数 - 支持时间段内匹配 |
|
|
|
isTimeInSlot(courseTime, slotTime) { |
|
|
|
const normalizedCourseTime = this.normalizeTime(courseTime); |
|
|
|
const normalizedSlotTime = this.normalizeTime(slotTime); |
|
|
|
|
|
|
|
if (!normalizedCourseTime || !normalizedSlotTime) return false; |
|
|
|
|
|
|
|
// 精确匹配 |
|
|
|
if (normalizedCourseTime === normalizedSlotTime) return true; |
|
|
|
|
|
|
|
// 查找时间段匹配 - 课程开始时间在这个时间段内 |
|
|
|
const slotIndex = this.timeSlots.findIndex(slot => |
|
|
|
this.normalizeTime(slot.time) === normalizedSlotTime |
|
|
|
); |
|
|
|
|
|
|
|
if (slotIndex >= 0 && slotIndex < this.timeSlots.length - 1) { |
|
|
|
const currentSlotTime = this.normalizeTime(this.timeSlots[slotIndex].time); |
|
|
|
const nextSlotTime = this.normalizeTime(this.timeSlots[slotIndex + 1].time); |
|
|
|
|
|
|
|
// 检查课程时间是否在当前时间段内(包含开始时间,不包含结束时间) |
|
|
|
return normalizedCourseTime >= currentSlotTime && normalizedCourseTime < nextSlotTime; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
}, |
|
|
|
|
|
|
|
// 初始化当前周 |
|
|
|
initCurrentWeek() { |
|
|
|
const today = new Date() |
|
|
|
@ -857,8 +893,8 @@ export default { |
|
|
|
getCoursesByTimeAndDate(time, date) { |
|
|
|
const matchedCourses = this.courses.filter(course => { |
|
|
|
if (course.date !== date) return false |
|
|
|
// 只在课程开始时间显示课程,不在后续时间段重复显示 |
|
|
|
return course.time === time |
|
|
|
// 使用改进的时间匹配算法 |
|
|
|
return this.isTimeInSlot(course.time, time) |
|
|
|
}) |
|
|
|
return matchedCourses |
|
|
|
}, |
|
|
|
@ -933,8 +969,7 @@ export default { |
|
|
|
this.filterParams.venue_id = ''; |
|
|
|
this.filterParams.class_id = ''; |
|
|
|
|
|
|
|
// 如果切换了模式,重置滚动位置 |
|
|
|
this.scrollTop = 0; |
|
|
|
// 模式切换完成 |
|
|
|
|
|
|
|
// 切换模式后重新加载课程安排 |
|
|
|
this.loadScheduleList(); |
|
|
|
@ -956,9 +991,8 @@ export default { |
|
|
|
this.applyFilters() |
|
|
|
this.closeFilterModal() |
|
|
|
|
|
|
|
// 重新加载数据后,重置滚动位置 |
|
|
|
// 重新加载数据 |
|
|
|
await this.loadScheduleList() |
|
|
|
this.scrollTop = 0 |
|
|
|
|
|
|
|
// 如果筛选改变了时间段,需要重新生成时间列 |
|
|
|
if (this.selectedTimeRange !== '' || this.selectedVenueId !== null) { |
|
|
|
@ -1146,10 +1180,15 @@ export default { |
|
|
|
|
|
|
|
if (res.code === 1) { |
|
|
|
// 转换数据格式 |
|
|
|
this.courses = res.data.list.map(item => ({ |
|
|
|
this.courses = res.data.list.map(item => { |
|
|
|
// 提取并标准化时间 |
|
|
|
const rawTime = item.time_info?.start_time || item.time_slot?.split('-')[0] || ''; |
|
|
|
const normalizedTime = this.normalizeTime(rawTime); |
|
|
|
|
|
|
|
return { |
|
|
|
id: item.id, |
|
|
|
date: item.course_date, |
|
|
|
time: item.time_info?.start_time || item.time_slot?.split('-')[0], |
|
|
|
time: normalizedTime, // 使用标准化后的时间 |
|
|
|
courseName: item.course_name || '未命名课程', |
|
|
|
students: `已报名${item.enrolled_count || 0}人`, |
|
|
|
teacher: item.coach_name || '待分配', |
|
|
|
@ -1164,16 +1203,12 @@ export default { |
|
|
|
duration: item.time_info?.duration || 60, |
|
|
|
time_slot: item.time_slot, |
|
|
|
raw: item, // 保存原始数据 |
|
|
|
})) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
// 根据当前视图模式动态更新左侧列数据 |
|
|
|
this.updateLeftColumnData(); |
|
|
|
|
|
|
|
// 同步左右高度 |
|
|
|
this.$nextTick(() => { |
|
|
|
this.syncRowHeights(); |
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
uni.showToast({ |
|
|
|
title: res.msg || '加载课程安排列表失败', |
|
|
|
@ -1266,61 +1301,18 @@ export default { |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// 同步左右行高度 |
|
|
|
syncRowHeights() { |
|
|
|
this.$nextTick(() => { |
|
|
|
try { |
|
|
|
let itemCount = 0; |
|
|
|
|
|
|
|
// 根据当前筛选模式确定行数 |
|
|
|
if (this.activeFilter === 'time' || this.activeFilter === '') { |
|
|
|
itemCount = this.timeSlots.length; |
|
|
|
} else if (this.activeFilter === 'teacher') { |
|
|
|
itemCount = this.teacherOptions.length; |
|
|
|
} else if (this.activeFilter === 'classroom') { |
|
|
|
itemCount = this.venues.length; |
|
|
|
} else if (this.activeFilter === 'class') { |
|
|
|
itemCount = this.classOptions.length; |
|
|
|
} |
|
|
|
|
|
|
|
// 同步每一行的高度 |
|
|
|
for (let i = 0; i < itemCount; i++) { |
|
|
|
const scheduleRow = this.$refs[`scheduleRow_${i}`]; |
|
|
|
const frozenCell = this.$refs[`frozenCell_${i}`]; |
|
|
|
|
|
|
|
if (scheduleRow && scheduleRow[0] && frozenCell && frozenCell[0]) { |
|
|
|
// 获取右侧行的实际高度 |
|
|
|
const rightRowHeight = scheduleRow[0].$el ? |
|
|
|
scheduleRow[0].$el.offsetHeight : |
|
|
|
scheduleRow[0].offsetHeight; |
|
|
|
|
|
|
|
// 设置左侧冻结单元格的高度 |
|
|
|
if (frozenCell[0].$el) { |
|
|
|
frozenCell[0].$el.style.minHeight = rightRowHeight + 'px'; |
|
|
|
} else if (frozenCell[0].style) { |
|
|
|
frozenCell[0].style.minHeight = rightRowHeight + 'px'; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.warn('高度同步失败:', error); |
|
|
|
} |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
// 滚动事件处理函数 - 优化垂直滚动同步 |
|
|
|
// 滚动事件处理函数 - 简化版本 |
|
|
|
onScroll(e) { |
|
|
|
// 使用防抖优化滚动同步性能 |
|
|
|
// 统一滚动区域后不需要同步滚动位置 |
|
|
|
// 只保留防抖逻辑以优化性能 |
|
|
|
if (this.scrollTimer) { |
|
|
|
clearTimeout(this.scrollTimer) |
|
|
|
} |
|
|
|
|
|
|
|
this.scrollTimer = setTimeout(() => { |
|
|
|
// 只需要同步垂直滚动位置给左侧时间列 |
|
|
|
if (e.detail.scrollTop !== undefined && e.detail.scrollTop !== this.scrollTop) { |
|
|
|
this.scrollTop = e.detail.scrollTop |
|
|
|
} |
|
|
|
}, 16) // 约60fps的更新频率 |
|
|
|
// 可以在这里添加其他滚动相关的处理逻辑 |
|
|
|
// 例如懒加载、滚动到顶部/底部的处理等 |
|
|
|
}, 16) |
|
|
|
}, |
|
|
|
|
|
|
|
// 单元格点击 |
|
|
|
@ -1523,6 +1515,36 @@ export default { |
|
|
|
// 暂时只显示提示信息,具体API调用可以后续实现 |
|
|
|
}, |
|
|
|
|
|
|
|
// 计算scroll-view高度 |
|
|
|
calculateScrollViewHeight() { |
|
|
|
uni.getSystemInfo({ |
|
|
|
success: (res) => { |
|
|
|
// 获取屏幕高度 |
|
|
|
let screenHeight = res.screenHeight || res.windowHeight |
|
|
|
|
|
|
|
// 计算其他元素占用的高度 |
|
|
|
// 筛选区域 + 日期导航 + 统计信息 + 状态栏等 |
|
|
|
let otherHeight = 0 |
|
|
|
|
|
|
|
// #ifdef H5 |
|
|
|
otherHeight = 200 // H5端大约200px |
|
|
|
// #endif |
|
|
|
|
|
|
|
// #ifdef MP-WEIXIN |
|
|
|
otherHeight = 160 // 小程序端大约160px (rpx转换) |
|
|
|
// #endif |
|
|
|
|
|
|
|
// 设置scroll-view高度 |
|
|
|
this.scrollViewHeight = screenHeight - otherHeight |
|
|
|
|
|
|
|
// 最小高度限制 |
|
|
|
if (this.scrollViewHeight < 300) { |
|
|
|
this.scrollViewHeight = 300 |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 响应式调整 |
|
|
|
handleResize() { |
|
|
|
// 根据窗口宽度调整表格尺寸 |
|
|
|
@ -1545,12 +1567,15 @@ export default { |
|
|
|
// #endif |
|
|
|
|
|
|
|
if (width <= 375) { |
|
|
|
this.tableWidth = 1220 // 7*160+100=1220rpx |
|
|
|
this.tableWidth = 1120 // 7*160=1120rpx (小屏幕每列160rpx) |
|
|
|
} else if (width <= 768) { |
|
|
|
this.tableWidth = 1400 |
|
|
|
this.tableWidth = 1260 // 7*180=1260rpx |
|
|
|
} else { |
|
|
|
this.tableWidth = 1500 |
|
|
|
this.tableWidth = 1260 // 7*180=1260rpx |
|
|
|
} |
|
|
|
|
|
|
|
// 重新计算scroll-view高度 |
|
|
|
this.calculateScrollViewHeight() |
|
|
|
}, |
|
|
|
|
|
|
|
// 初始化模拟数据 |
|
|
|
@ -1666,24 +1691,32 @@ export default { |
|
|
|
.schedule-main { |
|
|
|
flex: 1; |
|
|
|
position: relative; |
|
|
|
display: flex; |
|
|
|
overflow: hidden; |
|
|
|
height: 0; /* 配合flex: 1 确保高度计算正确 */ |
|
|
|
} |
|
|
|
|
|
|
|
// 左侧冻结列 |
|
|
|
.frozen-column { |
|
|
|
width: 120rpx; |
|
|
|
position: relative; |
|
|
|
z-index: 3; |
|
|
|
background-color: #292929; |
|
|
|
// 统一滚动区域内部容器 |
|
|
|
.schedule-container-inner { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
box-shadow: 4rpx 0 8rpx rgba(0, 0, 0, 0.1); |
|
|
|
flex-shrink: 0; |
|
|
|
min-width: 1380rpx; /* 左列120rpx + 7天 * 180rpx = 1380rpx */ |
|
|
|
} |
|
|
|
|
|
|
|
// 表头行 |
|
|
|
.schedule-header-row { |
|
|
|
display: flex; |
|
|
|
background: #434544; |
|
|
|
border-bottom: 2px solid #29d3b4; |
|
|
|
position: sticky; |
|
|
|
top: 0; |
|
|
|
z-index: 10; |
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3); |
|
|
|
} |
|
|
|
|
|
|
|
// 左上角标题单元格 |
|
|
|
.time-header-cell { |
|
|
|
width: 120rpx; |
|
|
|
min-width: 120rpx; |
|
|
|
min-height: 120rpx; |
|
|
|
padding: 20rpx 10rpx; |
|
|
|
color: #29d3b4; |
|
|
|
@ -1691,75 +1724,13 @@ export default { |
|
|
|
font-weight: 500; |
|
|
|
text-align: center; |
|
|
|
border-right: 1px solid #555; |
|
|
|
border-bottom: 2px solid #29d3b4; |
|
|
|
background-color: #434544; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
word-wrap: break-word; |
|
|
|
overflow-wrap: break-word; |
|
|
|
} |
|
|
|
|
|
|
|
.frozen-content-scroll { |
|
|
|
flex: 1; |
|
|
|
overflow: hidden; |
|
|
|
/* 优化滚动性能 */ |
|
|
|
-webkit-overflow-scrolling: touch; |
|
|
|
scroll-behavior: auto; |
|
|
|
overscroll-behavior: none; |
|
|
|
} |
|
|
|
|
|
|
|
.frozen-content { |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.frozen-cell { |
|
|
|
width: 120rpx; |
|
|
|
min-height: 120rpx; |
|
|
|
padding: 20rpx 10rpx; |
|
|
|
color: #999; |
|
|
|
font-size: 24rpx; |
|
|
|
text-align: center; |
|
|
|
border-right: 1px solid #434544; |
|
|
|
border-bottom: 1px solid #434544; |
|
|
|
background: #3a3a3a; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
word-wrap: break-word; |
|
|
|
overflow-wrap: break-word; |
|
|
|
|
|
|
|
&.time-unavailable { |
|
|
|
background: #2a2a2a; |
|
|
|
color: #555; |
|
|
|
opacity: 0.5; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 右侧内容区域 |
|
|
|
.schedule-content-area { |
|
|
|
flex: 1; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
overflow: hidden; |
|
|
|
} |
|
|
|
|
|
|
|
// 合并滚动区域内部容器 |
|
|
|
.schedule-container-inner { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
min-width: 1260rpx; /* 7天 * 180rpx = 1260rpx */ |
|
|
|
} |
|
|
|
|
|
|
|
.date-header-container { |
|
|
|
display: flex; |
|
|
|
background: #434544; |
|
|
|
border-bottom: 2px solid #29d3b4; |
|
|
|
position: sticky; |
|
|
|
top: 0; |
|
|
|
z-index: 10; |
|
|
|
/* 确保完全覆盖下方内容 */ |
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3); |
|
|
|
flex-shrink: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.date-header-cell { |
|
|
|
@ -1796,16 +1767,23 @@ export default { |
|
|
|
// 内容滚动区域 |
|
|
|
.schedule-scroll { |
|
|
|
flex: 1; |
|
|
|
overflow: scroll; |
|
|
|
height: 100%; |
|
|
|
width: 100%; |
|
|
|
min-height: 0; /* 关键:允许flex子项收缩 */ |
|
|
|
/* 优化滚动性能 */ |
|
|
|
-webkit-overflow-scrolling: touch; |
|
|
|
scroll-behavior: auto; |
|
|
|
overscroll-behavior: none; |
|
|
|
|
|
|
|
/* 小程序端专用优化 */ |
|
|
|
// #ifdef MP-WEIXIN |
|
|
|
scroll-behavior: smooth; |
|
|
|
// #endif |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-grid { |
|
|
|
width: 100%; |
|
|
|
min-width: 1260rpx; /* 7天 * 180rpx = 1260rpx */ |
|
|
|
min-width: 1380rpx; /* 左列120rpx + 7天 * 180rpx = 1380rpx */ |
|
|
|
} |
|
|
|
|
|
|
|
// 行布局 |
|
|
|
@ -1815,6 +1793,32 @@ export default { |
|
|
|
border-bottom: 1px solid #434544; |
|
|
|
} |
|
|
|
|
|
|
|
// 左侧列单元格 (时间/教练/教室/班级) |
|
|
|
.left-column-cell { |
|
|
|
width: 120rpx; |
|
|
|
min-width: 120rpx; |
|
|
|
min-height: 120rpx; |
|
|
|
padding: 20rpx 10rpx; |
|
|
|
color: #999; |
|
|
|
font-size: 24rpx; |
|
|
|
text-align: center; |
|
|
|
border-right: 1px solid #434544; |
|
|
|
border-bottom: 1px solid #434544; |
|
|
|
background: #3a3a3a; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
word-wrap: break-word; |
|
|
|
overflow-wrap: break-word; |
|
|
|
flex-shrink: 0; |
|
|
|
|
|
|
|
&.time-unavailable { |
|
|
|
background: #2a2a2a; |
|
|
|
color: #555; |
|
|
|
opacity: 0.5; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.course-cell { |
|
|
|
width: 180rpx; |
|
|
|
min-width: 180rpx; |
|
|
|
@ -1849,12 +1853,15 @@ export default { |
|
|
|
|
|
|
|
// 响应式适配 |
|
|
|
@media screen and (max-width: 375px) { |
|
|
|
.time-column-fixed { |
|
|
|
.left-column-cell { |
|
|
|
width: 100rpx; |
|
|
|
min-width: 100rpx; |
|
|
|
font-size: 22rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.time-header-cell, .time-cell { |
|
|
|
.time-header-cell { |
|
|
|
width: 100rpx; |
|
|
|
min-width: 100rpx; |
|
|
|
font-size: 22rpx; |
|
|
|
} |
|
|
|
|
|
|
|
|