diff --git a/doc/副本课程协议—月卡篮球(1).docx b/doc/副本课程协议—月卡篮球(1).docx
index 6d1ee5bb..525d3291 100644
Binary files a/doc/副本课程协议—月卡篮球(1).docx and b/doc/副本课程协议—月卡篮球(1).docx differ
diff --git a/uniapp/common/config.js b/uniapp/common/config.js
index c98a2253..2459f37b 100644
--- a/uniapp/common/config.js
+++ b/uniapp/common/config.js
@@ -1,6 +1,6 @@
// 环境变量配置
-const env = 'development'
-// const env = 'prod'
+// const env = 'development'
+const env = 'prod'
const isMockEnabled = false // 默认禁用Mock优先模式,仅作为回退
const isDebug = false // 默认启用调试模式
const devurl = 'http://localhost:20080/api'
diff --git a/uniapp/pages-coach/coach/schedule/schedule_table.vue b/uniapp/pages-coach/coach/schedule/schedule_table.vue
index f4662dbd..5aaac5a6 100644
--- a/uniapp/pages-coach/coach/schedule/schedule_table.vue
+++ b/uniapp/pages-coach/coach/schedule/schedule_table.vue
@@ -56,111 +56,45 @@
-
-
-
-
-
-
-
-
-
-
-
- {{ timeSlot.time }}
-
-
-
-
-
-
- {{ teacher.name }}
-
-
-
-
-
-
- {{ venue.name }}
-
-
-
-
-
-
- {{ cls.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -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,34 +1180,35 @@ export default {
if (res.code === 1) {
// 转换数据格式
- this.courses = res.data.list.map(item => ({
- id: item.id,
- date: item.course_date,
- time: item.time_info?.start_time || item.time_slot?.split('-')[0],
- courseName: item.course_name || '未命名课程',
- students: `已报名${item.enrolled_count || 0}人`,
- teacher: item.coach_name || '待分配',
- teacher_id: item.coach_id, // 保存教练ID
- status: item.status_text || '待定',
- type: this.getCourseType(item),
- venue: item.venue_name || '待分配',
- venue_id: item.venue_id, // 保存场地ID
- campus_name: item.campus_name || '', // 添加校区名称
- class_id: item.class_id, // 保存班级ID
- class_name: item.class_name || '', // 添加班级名称
- duration: item.time_info?.duration || 60,
- time_slot: item.time_slot,
- raw: 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: normalizedTime, // 使用标准化后的时间
+ courseName: item.course_name || '未命名课程',
+ students: `已报名${item.enrolled_count || 0}人`,
+ teacher: item.coach_name || '待分配',
+ teacher_id: item.coach_id, // 保存教练ID
+ status: item.status_text || '待定',
+ type: this.getCourseType(item),
+ venue: item.venue_name || '待分配',
+ venue_id: item.venue_id, // 保存场地ID
+ campus_name: item.campus_name || '', // 添加校区名称
+ class_id: item.class_id, // 保存班级ID
+ class_name: item.class_name || '', // 添加班级名称
+ 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;
}
diff --git a/uniapp/pages-market/clue/add_clues.vue b/uniapp/pages-market/clue/add_clues.vue
index 7f99c75b..dce862aa 100644
--- a/uniapp/pages-market/clue/add_clues.vue
+++ b/uniapp/pages-market/clue/add_clues.vue
@@ -353,7 +353,7 @@
+ @click="openDate(`promised_visit_time`)">
{{ (formData.promised_visit_time) ? formData.promised_visit_time : '点击选择' }}
{
- this.datetime_picker_show = true
+ this.date_picker_show = true
})
},
//选择跟进时间
diff --git a/uniapp/pages/common/home/index.vue b/uniapp/pages/common/home/index.vue
index a65f0292..e66df791 100644
--- a/uniapp/pages/common/home/index.vue
+++ b/uniapp/pages/common/home/index.vue
@@ -106,12 +106,12 @@
path: '/pages/common/dashboard/webview',
params: { type: 'campus_data' }
},
- {
- title: '报销管理',
- icon: 'wallet-filled',
- path: '/pages-market/reimbursement/list',
- params: { type: 'reimbursement' }
- }
+ // {
+ // title: '报销管理',
+ // icon: 'wallet-filled',
+ // path: '/pages-market/reimbursement/list',
+ // params: { type: 'reimbursement' }
+ // }
]
}
},