@ -60,26 +60,51 @@
< el -icon > < Calendar / > < / e l - i c o n >
< el -icon > < Calendar / > < / e l - i c o n >
添加日程
添加日程
< / e l - b u t t o n >
< / e l - b u t t o n >
< el -button @click ="createTestSchedule" type = "warning" plain >
< el -icon > < Calendar / > < / e l - i c o n >
创建测试日程
< / e l - b u t t o n >
< / div >
< / div >
< / div >
< / div >
<!-- 学期选择 -- >
<!-- 学期选择 -- >
< div class = "semester-selector" >
< div class = "semester-selector" >
< el -select v-model ="currentSemester" placeholder="选择学期" size="default" @change="loadCourses" >
< el -select v-model ="currentSemester" placeholder="选择学期" size="default" @change="handleSemesterChange" >
< el -option label = "2024春季学期" value = "2024-1" / >
< el -option
< el -option label = "2024秋季学期" value = "2024-2" / >
v - for = "(config, key) in semesterConfig"
< el -option label = "2023秋季学期" value = "2023-2" / >
: key = "key"
< el -option label = "2023春季学期" value = "2023-1" / >
: label = "config.name"
: value = "key"
/ >
< / e l - s e l e c t >
< / e l - s e l e c t >
< div class = "week-selector" >
< div class = "week-selector" >
< el -button @click ="previousWeek" circle size = "small" >
< el -button @click ="previousWeek" circle size = "small" >
< el -icon > < ArrowLeft / > < / e l - i c o n >
< el -icon > < ArrowLeft / > < / e l - i c o n >
< / e l - b u t t o n >
< / e l - b u t t o n >
< span class = "current-week" > 第 { { currentWeek } } 周 < / span >
< el -select
v - model = "currentWeek"
placeholder = "选择周数"
size = "small"
style = "width: 120px;"
>
< el -option
v - for = "week in getCurrentSemesterConfig().totalWeeks"
: key = "week"
: label = "`第 ${week} 周`"
: value = "week"
/ >
< / e l - s e l e c t >
< el -button @click ="nextWeek" circle size = "small" >
< el -button @click ="nextWeek" circle size = "small" >
< el -icon > < ArrowRight / > < / e l - i c o n >
< el -icon > < ArrowRight / > < / e l - i c o n >
< / e l - b u t t o n >
< / e l - b u t t o n >
< el -button @click ="goToCurrentWeek" size = "small" type = "primary" plain >
< el -icon > < Calendar / > < / e l - i c o n >
回到今天
< / e l - b u t t o n >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
@ -92,10 +117,16 @@
v - for = "(day, index) in weekDays"
v - for = "(day, index) in weekDays"
: key = "index"
: key = "index"
class = "day-column"
class = "day-column"
: class = "{ today: isToday(index) }"
: class = " {
today : getDayDate ( index ) . isToday ,
'current-day' : getDayDate ( index ) . isToday
} "
>
>
< div class = "day-name" > { { day } } < / div >
< div class = "day-name" > { { day } } < / div >
< div class = "day-date" > { { getDayDate ( index ) } } < / div >
< div class = "day-date" : class = "{ 'today-date': getDayDate(index).isToday }" >
{ { getDayDate ( index ) . month } } / { { getDayDate ( index ) . date } }
< span v-if ="getDayDate(index).isToday" class="today-indicator" > 今 天 < / span >
< / div >
< / div >
< / div >
< / div >
< / div >
@ -106,27 +137,44 @@
class = "time-row"
class = "time-row"
>
>
< div class = "time-cell" >
< div class = "time-cell" >
< div class = "time-period" > 第 { { timeIndex + 1 } } 节 < / div >
< div class = "time-period" > { { timeSlot } } < / div >
< div class = "time-range" > { { timeSlot } } < / div >
< / div >
< / div >
< div
< div
v - for = "dayIndex in 7"
v - for = "dayIndex in 7"
: key = "dayIndex"
: key = "dayIndex"
class = "course-cell"
class = "course-cell"
@ click = "addCourseToSlot(timeIndex, dayIndex )"
@ click = "addCourseToSlot(timeIndex, dayIndex - 1 )"
>
>
<!-- 显示所有项目 ( 课程和日程 ) -- >
< div v-if ="getItemsForSlot(timeIndex, dayIndex - 1).length > 0" class="slot-items" >
< div
< div
v - if = "getCourseForSlot(timeIndex, dayIndex)"
v - for = "(item, itemIndex) in getItemsForSlot(timeIndex, dayIndex - 1)"
class = "course-item"
: key = "itemIndex"
: style = "{ backgroundColor: getCourseForSlot(timeIndex, dayIndex)?.color }"
: class = "item.type === 'course' ? 'course-item' : 'schedule-item'"
@ click . stop = "editCourse(getCourseForSlot(timeIndex, dayIndex)!)"
: style = "{ backgroundColor: item.data.color }"
@ click . stop = "item.type === 'course' ? editCourse(item.data) : editSchedule(item.data)"
>
>
< div class = "course-name" > { { getCourseForSlot ( timeIndex , dayIndex ) ? . name } } < / div >
<!-- 课程内容 -- >
< div class = "course-location" > { { getCourseForSlot ( timeIndex , dayIndex ) ? . location } } < / div >
< template v-if ="item.type === 'course'" >
< div class = "course-teacher" > { { getCourseForSlot ( timeIndex , dayIndex ) ? . teacher } } < / div >
< div class = "course-name" > { { item . data . name } } < / div >
< div class = "course-location" > { { item . data . location } } < / div >
< div class = "course-teacher" > { { item . data . teacher } } < / div >
< / template >
<!-- 日程内容 -- >
< template v-else >
< div class = "schedule-name" > { { item . data . title } } < / div >
< div class = "schedule-location" > { { item . data . location } } < / div >
< div class = "schedule-time" v-if ="item.data.isAllDay !== 1" >
{ { formatTime ( item . data . startTime ) } }
< / div >
< div class = "schedule-time" v-else > 全 天 < / div >
< / template >
< / div >
< / div >
< / div >
<!-- 空白时间段 -- >
< div v -else class = "empty-slot" >
< div v -else class = "empty-slot" >
< el -icon class = "add-icon" > < Plus / > < / e l - i c o n >
< el -icon class = "add-icon" > < Plus / > < / e l - i c o n >
< / div >
< / div >
@ -221,21 +269,33 @@
< div class = "form-row" >
< div class = "form-row" >
< el -form -item label = "开始时间" prop = "startTime" >
< el -form -item label = "开始时间" prop = "startTime" >
< el - time-picker
< el - select
v - model = "courseForm.startTime"
v - model = "courseForm.startTime"
format = "HH:mm"
placeholder = "选择开始时间"
placeholder = "选择开始时间"
style = "width: 100%"
style = "width: 100%"
>
< el -option
v - for = "option in startTimeOptions"
: key = "option.value"
: label = "option.label"
: value = "option.value"
/ >
/ >
< / e l - s e l e c t >
< / e l - f o r m - i t e m >
< / e l - f o r m - i t e m >
< el -form -item label = "结束时间" prop = "endTime" >
< el -form -item label = "结束时间" prop = "endTime" >
< el -time -picker
< el - select
v - model = "courseForm.endTime"
v - model = "courseForm.endTime"
format = "HH:mm"
placeholder = "选择结束时间"
placeholder = "选择结束时间"
style = "width: 100%"
style = "width: 100%"
>
< el -option
v - for = "option in endTimeOptions"
: key = "option.value"
: label = "option.label"
: value = "option.value"
/ >
/ >
< / e l - s e l e c t >
< / e l - f o r m - i t e m >
< / e l - f o r m - i t e m >
< / div >
< / div >
@ -409,7 +469,7 @@ const savingCourse = ref(false)
const savingSchedule = ref ( false )
const savingSchedule = ref ( false )
const showAddCourse = ref ( false )
const showAddCourse = ref ( false )
const showAddSchedule = ref ( false )
const showAddSchedule = ref ( false )
const currentSemester = ref ( '2024- 1')
const currentSemester = ref ( '2024- 2025- 1')
const currentWeek = ref ( 1 )
const currentWeek = ref ( 1 )
/ / 编 辑 状 态
/ / 编 辑 状 态
@ -438,7 +498,17 @@ const courseForm = reactive({
} )
} )
/ / 日 程 表 单
/ / 日 程 表 单
const scheduleForm = reactive ( {
const scheduleForm = reactive < {
title : string
description : string
location : string
startTime : string | Date
endTime : string | Date
date : string
isAllDay : boolean
reminder : number
color : string
} > ( {
title : '' ,
title : '' ,
description : '' ,
description : '' ,
location : '' ,
location : '' ,
@ -489,13 +559,71 @@ const scheduleRules: FormRules = {
/ / 常 量 数 据
/ / 常 量 数 据
const weekDays = [ '周一' , '周二' , '周三' , '周四' , '周五' , '周六' , '周日' ]
const weekDays = [ '周一' , '周二' , '周三' , '周四' , '周五' , '周六' , '周日' ]
const timeSlots = [
const timeSlots = [
'08:00-09:40' ,
'08:00-08:50' , / / 第 1 节 课
'10:00-11:40' ,
'08:50-09:40' , / / 第 2 节 课
'14:00-15:40' ,
'09:50-10:40' , / / 第 3 节 课
'16:00-17:40' ,
'10:40-11:30' , / / 第 4 节 课
'19:00-20:40'
'11:30-12:20' , / / 第 5 节 课
'14:05-14:55' , / / 第 6 节 课
'14:55-15:45' , / / 第 7 节 课
'15:45-16:35' , / / 第 8 节 课
'16:40-17:30' , / / 第 9 节 课
'17:30-18:20' , / / 第 1 0 节 课
'18:30-19:20' , / / 第 1 1 节 课
'19:20-20:10' , / / 第 1 2 节 课
'20:10-21:00' / / 第 1 3 节 课
]
]
/ / 课 程 时 间 选 项
const courseTimeOptions = [
{ label : '第1节课 08:00-08:50' , value : '08:00' , endValue : '08:50' } ,
{ label : '第2节课 08:50-09:40' , value : '08:50' , endValue : '09:40' } ,
{ label : '第3节课 09:50-10:40' , value : '09:50' , endValue : '10:40' } ,
{ label : '第4节课 10:40-11:30' , value : '10:40' , endValue : '11:30' } ,
{ label : '第5节课 11:30-12:20' , value : '11:30' , endValue : '12:20' } ,
{ label : '第6节课 14:05-14:55' , value : '14:05' , endValue : '14:55' } ,
{ label : '第7节课 14:55-15:45' , value : '14:55' , endValue : '15:45' } ,
{ label : '第8节课 15:45-16:35' , value : '15:45' , endValue : '16:35' } ,
{ label : '第9节课 16:40-17:30' , value : '16:40' , endValue : '17:30' } ,
{ label : '第10节课 17:30-18:20' , value : '17:30' , endValue : '18:20' } ,
{ label : '第11节课 18:30-19:20' , value : '18:30' , endValue : '19:20' } ,
{ label : '第12节课 19:20-20:10' , value : '19:20' , endValue : '20:10' } ,
{ label : '第13节课 20:10-21:00' , value : '20:10' , endValue : '21:00' }
]
/ / 开 始 时 间 选 项 ( 显 示 开 始 时 间 )
const startTimeOptions = courseTimeOptions . map ( option => ( {
label : ` ${ option . value } ( ${ option . label . split ( ' ' ) [ 0 ] } 开始) ` ,
value : option . value + ':00' / / 添 加 秒 数 , 符 合 后 端 H H : m m : s s 格 式
} ) )
/ / 结 束 时 间 选 项 ( 显 示 结 束 时 间 )
const endTimeOptions = courseTimeOptions . map ( option => ( {
label : ` ${ option . endValue } ( ${ option . label . split ( ' ' ) [ 0 ] } 结束) ` ,
value : option . endValue + ':00' / / 添 加 秒 数 , 符 合 后 端 H H : m m : s s 格 式
} ) )
/ / 课 程 颜 色 预 设
const courseColors = [
'#409EFF' , / / 蓝 色
'#67C23A' , / / 绿 色
'#E6A23C' , / / 橙 色
'#F56C6C' , / / 红 色
'#909399' , / / 灰 色
'#9C27B0' , / / 紫 色
'#FF5722' , / / 深 橙 色
'#4CAF50' , / / 深 绿 色
'#2196F3' , / / 深 蓝 色
'#FF9800' , / / 琥 珀 色
'#795548' , / / 棕 色
'#607D8B' / / 蓝 灰 色
]
/ / 生 成 随 机 颜 色
const getRandomColor = ( ) => {
return courseColors [ Math . floor ( Math . random ( ) * courseColors . length ) ]
}
/ / 计 算 属 性
/ / 计 算 属 性
const todayCourses = computed ( ( ) => {
const todayCourses = computed ( ( ) => {
const today = new Date ( ) . getDay ( )
const today = new Date ( ) . getDay ( )
@ -504,47 +632,295 @@ const todayCourses = computed(() => {
} )
} )
const todaySchedules = computed ( ( ) => {
const todaySchedules = computed ( ( ) => {
/ / 获 取 真 实 的 今 天 日 期
const today = new Date ( )
const today = new Date ( )
const todayStr = today . toISOString ( ) . split ( 'T' ) [ 0 ]
const todayStr = today . toISOString ( ) . split ( 'T' ) [ 0 ]
return schedules . value . filter ( schedule => {
const scheduleDate = new Date ( schedule . startTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
console . log ( '=== 今日日程调试信息 ===' )
return scheduleDate === todayStr
console . log ( '今天日期:' , todayStr )
console . log ( '所有日程数据:' , schedules . value )
const filteredSchedules = schedules . value . filter ( schedule => {
const startDate = new Date ( schedule . startTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
const endDate = new Date ( schedule . endTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
/ / 检 查 今 天 是 否 在 日 程 的 时 间 范 围 内 ( 包 括 跨 天 日 程 )
const isInRange = todayStr >= startDate && todayStr <= endDate
console . log ( '日程:' , schedule . title )
console . log ( '开始日期:' , startDate , '结束日期:' , endDate )
console . log ( '今天是否在范围内:' , isInRange )
return isInRange
} )
} )
console . log ( '筛选后的今日日程:' , filteredSchedules )
console . log ( '=== 调试信息结束 ===' )
return filteredSchedules
} )
} )
/ / 方 法
/ / 方 法
/ / 学 期 配 置
const semesterConfig = {
'2024-2025-1' : {
name : '2024-2025第一学期' ,
startDate : new Date ( 2024 , 8 , 2 ) , / / 2 0 2 4 年 9 月 2 日 ( 周 一 )
endDate : new Date ( 2025 , 0 , 19 ) , / / 2 0 2 5 年 1 月 1 9 日
totalWeeks : 20
} ,
'2024-2025-2' : {
name : '2024-2025第二学期' ,
startDate : new Date ( 2025 , 1 , 24 ) , / / 2 0 2 5 年 2 月 2 4 日 ( 周 一 )
endDate : new Date ( 2025 , 5 , 29 ) , / / 2 0 2 5 年 6 月 2 9 日
totalWeeks : 18
} ,
'2023-2024-1' : {
name : '2023-2024第一学期' ,
startDate : new Date ( 2023 , 8 , 4 ) , / / 2 0 2 3 年 9 月 4 日 ( 周 一 )
endDate : new Date ( 2024 , 0 , 21 ) , / / 2 0 2 4 年 1 月 2 1 日
totalWeeks : 20
} ,
'2023-2024-2' : {
name : '2023-2024第二学期' ,
startDate : new Date ( 2024 , 1 , 26 ) , / / 2 0 2 4 年 2 月 2 6 日 ( 周 一 )
endDate : new Date ( 2024 , 5 , 30 ) , / / 2 0 2 4 年 6 月 3 0 日
totalWeeks : 18
} ,
'2022-2023-1' : {
name : '2022-2023第一学期' ,
startDate : new Date ( 2022 , 8 , 5 ) , / / 2 0 2 2 年 9 月 5 日 ( 周 一 )
endDate : new Date ( 2023 , 0 , 15 ) , / / 2 0 2 3 年 1 月 1 5 日
totalWeeks : 20
} ,
'2022-2023-2' : {
name : '2022-2023第二学期' ,
startDate : new Date ( 2023 , 1 , 27 ) , / / 2 0 2 3 年 2 月 2 7 日 ( 周 一 )
endDate : new Date ( 2023 , 6 , 2 ) , / / 2 0 2 3 年 7 月 2 日
totalWeeks : 18
}
}
/ / 获 取 当 前 应 该 显 示 的 学 期
const getCurrentSemester = ( ) => {
const now = new Date ( )
/ / 按 时 间 顺 序 检 查 学 期 , 找 到 当 前 日 期 所 在 的 学 期
const sortedSemesters = Object . entries ( semesterConfig ) . sort ( ( a , b ) => {
return b [ 1 ] . startDate . getTime ( ) - a [ 1 ] . startDate . getTime ( ) / / 按 开 始 时 间 倒 序 排 列
} )
for ( const [ semesterKey , config ] of sortedSemesters ) {
if ( now >= config . startDate && now <= config . endDate ) {
return semesterKey
}
}
/ / 如 果 当 前 时 间 不 在 任 何 学 期 范 围 内 , 找 最 接 近 的 学 期
let closestSemester = '2024-2025-1'
let minDistance = Infinity
for ( const [ semesterKey , config ] of Object . entries ( semesterConfig ) ) {
/ / 计 算 到 学 期 开 始 时 间 的 距 离
const distanceToStart = Math . abs ( now . getTime ( ) - config . startDate . getTime ( ) )
/ / 计 算 到 学 期 结 束 时 间 的 距 离
const distanceToEnd = Math . abs ( now . getTime ( ) - config . endDate . getTime ( ) )
/ / 取 较 小 的 距 离
const distance = Math . min ( distanceToStart , distanceToEnd )
if ( distance < minDistance ) {
minDistance = distance
closestSemester = semesterKey
}
}
console . log ( '当前时间不在任何学期范围内,选择最接近的学期:' , closestSemester )
return closestSemester
}
/ / 获 取 指 定 学 期 的 当 前 周 数
const getCurrentWeekInSemester = ( semester : string ) => {
const config = semesterConfig [ semester as keyof typeof semesterConfig ]
if ( ! config ) return 1
const now = new Date ( )
/ / 如 果 当 前 时 间 不 在 学 期 范 围 内 , 返 回 第 1 周
if ( now < config . startDate || now > config . endDate ) {
return 1
}
/ / 计 算 从 学 期 开 始 到 现 在 的 周 数
const diffTime = now . getTime ( ) - config . startDate . getTime ( )
const diffWeeks = Math . floor ( diffTime / ( 7 * 24 * 60 * 60 * 1000 ) ) + 1
return Math . max ( 1 , Math . min ( diffWeeks , config . totalWeeks ) )
}
/ / 获 取 指 定 学 期 和 周 数 的 周 一 日 期
const getWeekMondayDate = ( semester : string , week : number ) => {
const config = semesterConfig [ semester as keyof typeof semesterConfig ]
if ( ! config ) return new Date ( )
const mondayDate = new Date ( config . startDate )
mondayDate . setDate ( config . startDate . getDate ( ) + ( week - 1 ) * 7 )
return mondayDate
}
/ / 获 取 当 前 学 期 配 置
const getCurrentSemesterConfig = ( ) => {
return semesterConfig [ currentSemester . value as keyof typeof semesterConfig ] || semesterConfig [ '2024-2025-1' ]
}
/ / 处 理 学 期 切 换
const handleSemesterChange = ( newSemester : string ) => {
console . log ( '学期切换到:' , newSemester )
/ / 重 置 周 数 到 第 1 周
currentWeek . value = 1
/ / 重 新 加 载 课 程
loadCourses ( )
}
const isToday = ( dayIndex : number ) => {
const isToday = ( dayIndex : number ) => {
const today = new Date ( ) . getDay ( )
const now = new Date ( )
const currentSemesterKey = getCurrentSemester ( )
/ / 只 有 在 当 前 学 期 才 显 示 " 今 天 "
if ( currentSemester . value !== currentSemesterKey ) {
return false
}
/ / 只 有 在 当 前 周 才 显 示 " 今 天 "
const currentWeekInSemester = getCurrentWeekInSemester ( currentSemester . value )
if ( currentWeek . value !== currentWeekInSemester ) {
return false
}
const today = now . getDay ( )
const targetDay = dayIndex + 1
const targetDay = dayIndex + 1
return today === 0 ? targetDay === 7 : today === targetDay
return today === 0 ? targetDay === 7 : today === targetDay
}
}
const getDayDate = ( dayIndex : number ) => {
const getDayDate = ( dayIndex : number ) => {
const today = new Date ( )
const monday = getWeekMondayDate ( currentSemester . value , currentWeek . value )
const currentDayOfWeek = today . getDay ( )
const monday = new Date ( today )
monday . setDate ( today . getDate ( ) - ( currentDayOfWeek === 0 ? 6 : currentDayOfWeek - 1 ) )
const targetDate = new Date ( monday )
const targetDate = new Date ( monday )
targetDate . setDate ( monday . getDate ( ) + dayIndex )
targetDate . setDate ( monday . getDate ( ) + dayIndex )
return targetDate . getDate ( )
/ / 检 查 是 否 是 今 天
const now = new Date ( )
const isCurrentDay = (
targetDate . getFullYear ( ) === now . getFullYear ( ) &&
targetDate . getMonth ( ) === now . getMonth ( ) &&
targetDate . getDate ( ) === now . getDate ( )
)
return {
date : targetDate . getDate ( ) ,
month : targetDate . getMonth ( ) + 1 ,
isToday : isCurrentDay ,
fullDate : targetDate
}
}
}
const getCourseForSlot = ( timeIndex : number , dayIndex : number ) => {
const getCourseForSlot = ( timeIndex : number , dayIndex : number ) => {
return courses . value . find ( course => {
return courses . value . find ( course => {
/ / d a y I n d e x 现 在 是 0 - 6 , 需 要 转 换 为 1 - 7 来 匹 配 数 据 库
if ( course . dayOfWeek !== dayIndex + 1 ) return false
if ( course . dayOfWeek !== dayIndex + 1 ) return false
/ / 简 化 时 间 匹 配 逻 辑
/ / 检 查 当 前 周 是 否 在 课 程 的 周 数 范 围 内
const courseStart = course . startTime
if ( currentWeek . value < course . startWeek || currentWeek . value > course . endWeek ) {
const courseEnd = course . endTime
return false
const slotTime = timeSlots [ timeIndex ]
}
/ / 获 取 当 前 时 间 段 的 开 始 和 结 束 时 间
const slotTimes = timeSlots [ timeIndex ] . split ( '-' )
const slotStart = slotTimes [ 0 ] / / 例 如 : " 0 8 : 0 0 "
const slotEnd = slotTimes [ 1 ] / / 例 如 : " 0 8 : 5 0 "
/ / 这 里 需 要 根 据 实 际 需 求 进 行 时 间 匹 配
/ / 获 取 课 程 的 开 始 和 结 束 时 间 ( 移 除 秒 数 部 分 进 行 比 较 )
return slotTime . includes ( courseStart . substring ( 0 , 5 ) )
const courseStart = course . startTime . substring ( 0 , 5 ) / / " 0 8 : 0 0 : 0 0 " - > " 0 8 : 0 0 "
const courseEnd = course . endTime . substring ( 0 , 5 ) / / " 0 9 : 4 0 : 0 0 " - > " 0 9 : 4 0 "
/ / 判 断 当 前 时 间 段 是 否 在 课 程 的 时 间 范 围 内
/ / 课 程 开 始 时 间 < = 时 间 段 开 始 时 间 & & 时 间 段 结 束 时 间 < = 课 程 结 束 时 间
return courseStart <= slotStart && slotEnd <= courseEnd
} )
} )
}
}
/ / 获 取 指 定 时 间 段 和 日 期 的 日 程
const getScheduleForSlot = ( timeIndex : number , dayIndex : number ) => {
/ / 获 取 指 定 日 期
const targetDate = getDayDate ( dayIndex )
const targetDateStr = ` ${ targetDate . fullDate . getFullYear ( ) } - ${ String ( targetDate . fullDate . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) } - ${ String ( targetDate . fullDate . getDate ( ) ) . padStart ( 2 , '0' ) } `
/ / 获 取 当 前 时 间 段 的 开 始 和 结 束 时 间
const slotTimes = timeSlots [ timeIndex ] . split ( '-' )
const slotStart = slotTimes [ 0 ] / / 例 如 : " 0 8 : 0 0 "
const slotEnd = slotTimes [ 1 ] / / 例 如 : " 0 8 : 5 0 "
return schedules . value . find ( schedule => {
/ / 检 查 指 定 日 期 是 否 在 日 程 的 时 间 范 围 内 ( 支 持 跨 天 日 程 )
const startDate = new Date ( schedule . startTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
const endDate = new Date ( schedule . endTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
/ / 检 查 目 标 日 期 是 否 在 日 程 的 日 期 范 围 内
const isDateInRange = targetDateStr >= startDate && targetDateStr <= endDate
if ( ! isDateInRange ) return false
/ / 如 果 是 全 天 日 程 , 在 第 一 个 时 间 段 显 示
if ( schedule . isAllDay === 1 ) {
return timeIndex === 0
}
/ / 对 于 跨 天 的 非 全 天 日 程 , 需 要 特 殊 处 理 时 间 检 查
if ( startDate !== endDate ) {
/ / 跨 天 日 程 : 如 果 是 开 始 日 期 , 检 查 时 间 段 是 否 在 开 始 时 间 之 后
if ( targetDateStr === startDate ) {
const scheduleStart = new Date ( schedule . startTime ) . toTimeString ( ) . substring ( 0 , 5 )
return slotStart >= scheduleStart
}
/ / 跨 天 日 程 : 如 果 是 结 束 日 期 , 检 查 时 间 段 是 否 在 结 束 时 间 之 前
else if ( targetDateStr === endDate ) {
const scheduleEnd = new Date ( schedule . endTime ) . toTimeString ( ) . substring ( 0 , 5 )
return slotEnd <= scheduleEnd
}
/ / 跨 天 日 程 : 如 果 是 中 间 日 期 , 整 天 都 显 示
else {
return true
}
} else {
/ / 同 一 天 的 日 程 : 检 查 时 间 段 是 否 重 叠
const scheduleStart = new Date ( schedule . startTime ) . toTimeString ( ) . substring ( 0 , 5 ) / / " 0 8 : 0 0 "
const scheduleEnd = new Date ( schedule . endTime ) . toTimeString ( ) . substring ( 0 , 5 ) / / " 0 9 : 4 0 "
/ / 判 断 时 间 段 是 否 重 叠
return scheduleStart < slotEnd && scheduleEnd > slotStart
}
} )
}
/ / 获 取 指 定 时 间 段 的 所 有 项 目 ( 课 程 和 日 程 )
const getItemsForSlot = ( timeIndex : number , dayIndex : number ) => {
const items : Array < { type : 'course' | 'schedule' , data : any } > = [ ]
/ / 获 取 课 程
const course = getCourseForSlot ( timeIndex , dayIndex )
if ( course ) {
items . push ( { type : 'course' , data : course } )
}
/ / 获 取 日 程
const schedule = getScheduleForSlot ( timeIndex , dayIndex )
if ( schedule ) {
items . push ( { type : 'schedule' , data : schedule } )
}
return items
}
const previousWeek = ( ) => {
const previousWeek = ( ) => {
if ( currentWeek . value > 1 ) {
if ( currentWeek . value > 1 ) {
currentWeek . value --
currentWeek . value --
@ -552,17 +928,53 @@ const previousWeek = () => {
}
}
const nextWeek = ( ) => {
const nextWeek = ( ) => {
if ( currentWeek . value < 20 ) {
const maxWeeks = getCurrentSemesterConfig ( ) . totalWeeks
if ( currentWeek . value < maxWeeks ) {
currentWeek . value ++
currentWeek . value ++
}
}
}
}
/ / 回 到 当 前 周
const goToCurrentWeek = ( ) => {
/ / 获 取 当 前 真 实 日 期 对 应 的 学 期
const currentRealSemester = getCurrentSemester ( )
const currentRealWeek = getCurrentWeekInSemester ( currentRealSemester )
/ / 检 查 是 否 已 经 在 当 前 学 期 和 周 数
if ( currentSemester . value === currentRealSemester && currentWeek . value === currentRealWeek ) {
const config = getCurrentSemesterConfig ( )
ElMessage . info ( ` 当前已经是 ${ config . name } 第 ${ currentRealWeek } 周 ` )
return
}
/ / 如 果 当 前 选 择 的 学 期 不 是 真 实 的 当 前 学 期 , 则 切 换 学 期
if ( currentSemester . value !== currentRealSemester ) {
console . log ( '切换到当前学期:' , currentRealSemester )
currentSemester . value = currentRealSemester
/ / 学 期 切 换 会 触 发 h a n d l e S e m e s t e r C h a n g e , 重 新 加 载 课 程
loadCourses ( )
}
/ / 设 置 到 当 前 学 期 的 当 前 周
currentWeek . value = currentRealWeek
console . log ( '回到今天 - 学期:' , currentRealSemester , '周数:' , currentRealWeek )
/ / 显 示 提 示 信 息
const config = getCurrentSemesterConfig ( )
ElMessage . success ( ` 已切换到 ${ config . name } 第 ${ currentRealWeek } 周 ` )
}
const addCourseToSlot = ( timeIndex : number , dayIndex : number ) => {
const addCourseToSlot = ( timeIndex : number , dayIndex : number ) => {
/ / 预 设 时 间 和 星 期
/ / 预 设 时 间 和 星 期
courseForm . dayOfWeek = dayIndex + 1
courseForm . dayOfWeek = dayIndex + 1
const timeSlot = timeSlots [ timeIndex ] . split ( '-' )
if ( timeIndex < courseTimeOptions . length ) {
courseForm . startTime = timeSlot [ 0 ]
courseForm . startTime = courseTimeOptions [ timeIndex ] . value + ':00'
courseForm . endTime = timeSlot [ 1 ]
/ / 不 自 动 设 置 结 束 时 间 , 让 用 户 自 己 选 择
courseForm . endTime = ''
}
/ / 预 设 随 机 颜 色
courseForm . color = getRandomColor ( )
showAddCourse . value = true
showAddCourse . value = true
}
}
@ -668,11 +1080,22 @@ const handleSaveSchedule = async () => {
let startTime , endTime
let startTime , endTime
if ( scheduleForm . isAllDay ) {
if ( scheduleForm . isAllDay ) {
startTime = ` ${ scheduleForm . date } T00:00:00 `
/ / 全 天 日 程 : 使 用 选 择 的 日 期 , 时 间 设 为 0 0 : 0 0 : 0 0 到 2 3 : 5 9 : 5 9
endTime = ` ${ scheduleForm . date } T23:59:59 `
const dateStr = scheduleForm . date
startTime = ` ${ dateStr } T00:00:00 `
endTime = ` ${ dateStr } T23:59:59 `
} else {
} else {
/ / 非 全 天 日 程 : 处 理 日 期 时 间 格 式
startTime = scheduleForm . startTime
startTime = scheduleForm . startTime
endTime = scheduleForm . endTime
endTime = scheduleForm . endTime
/ / 如 果 是 D a t e 对 象 , 转 换 为 I S O 字 符 串 格 式
if ( startTime && typeof startTime === 'object' ) {
startTime = ( startTime as any ) . toISOString ( ) . slice ( 0 , 19 )
}
if ( endTime && typeof endTime === 'object' ) {
endTime = ( endTime as any ) . toISOString ( ) . slice ( 0 , 19 )
}
}
}
const scheduleData = {
const scheduleData = {
@ -686,6 +1109,8 @@ const handleSaveSchedule = async () => {
color : scheduleForm . color
color : scheduleForm . color
}
}
console . log ( '保存日程数据:' , scheduleData )
let response
let response
if ( editingSchedule . value ) {
if ( editingSchedule . value ) {
response = await updateSchedule ( editingSchedule . value . id , scheduleData ) as any as ApiResponse < null >
response = await updateSchedule ( editingSchedule . value . id , scheduleData ) as any as ApiResponse < null >
@ -715,8 +1140,12 @@ const editCourse = (course: Course) => {
courseForm . teacher = course . teacher
courseForm . teacher = course . teacher
courseForm . location = course . location
courseForm . location = course . location
courseForm . dayOfWeek = course . dayOfWeek
courseForm . dayOfWeek = course . dayOfWeek
courseForm . startTime = course . startTime
courseForm . startTime = course . startTime . includes ( ':' ) && course . startTime . split ( ':' ) . length === 3
courseForm . endTime = course . endTime
? course . startTime
: course . startTime + ':00'
courseForm . endTime = course . endTime . includes ( ':' ) && course . endTime . split ( ':' ) . length === 3
? course . endTime
: course . endTime + ':00'
courseForm . startWeek = course . startWeek
courseForm . startWeek = course . startWeek
courseForm . endWeek = course . endWeek
courseForm . endWeek = course . endWeek
courseForm . color = course . color
courseForm . color = course . color
@ -733,10 +1162,15 @@ const editSchedule = (schedule: Schedule) => {
scheduleForm . color = schedule . color
scheduleForm . color = schedule . color
if ( schedule . isAllDay === 1 ) {
if ( schedule . isAllDay === 1 ) {
/ / 全 天 日 程 : 只 设 置 日 期
scheduleForm . date = new Date ( schedule . startTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
scheduleForm . date = new Date ( schedule . startTime ) . toISOString ( ) . split ( 'T' ) [ 0 ]
scheduleForm . startTime = ''
scheduleForm . endTime = ''
} else {
} else {
scheduleForm . startTime = schedule . startTime
/ / 非 全 天 日 程 : 设 置 开 始 和 结 束 时 间
scheduleForm . endTime = schedule . endTime
scheduleForm . date = ''
scheduleForm . startTime = new Date ( schedule . startTime )
scheduleForm . endTime = new Date ( schedule . endTime )
}
}
showAddSchedule . value = true
showAddSchedule . value = true
@ -816,7 +1250,7 @@ const resetCourseForm = () => {
courseForm . endTime = ''
courseForm . endTime = ''
courseForm . startWeek = 1
courseForm . startWeek = 1
courseForm . endWeek = 16
courseForm . endWeek = 16
courseForm . color = '#409EFF'
courseForm . color = getRandomColor ( )
courseFormRef . value ? . clearValidate ( )
courseFormRef . value ? . clearValidate ( )
}
}
@ -830,7 +1264,7 @@ const resetScheduleForm = () => {
scheduleForm . date = ''
scheduleForm . date = ''
scheduleForm . isAllDay = false
scheduleForm . isAllDay = false
scheduleForm . reminder = 30
scheduleForm . reminder = 30
scheduleForm . color = '#67C23A'
scheduleForm . color = getRandomColor ( )
scheduleFormRef . value ? . clearValidate ( )
scheduleFormRef . value ? . clearValidate ( )
}
}
@ -870,18 +1304,69 @@ watch(showAddSchedule, (newVal) => {
}
}
} )
} )
/ / 监 听 当 前 周 数 变 化 , 触 发 课 程 表 重 新 渲 染
watch ( currentWeek , ( ) => {
console . log ( '当前周数变化为:' , currentWeek . value )
/ / 由 于 g e t C o u r s e F o r S l o t 方 法 中 使 用 了 c u r r e n t W e e k . v a l u e ,
/ / V u e 的 响 应 式 系 统 会 自 动 重 新 渲 染 课 程 表
} )
/ / 页 面 加 载 时 获 取 数 据
/ / 页 面 加 载 时 获 取 数 据
onMounted ( async ( ) => {
onMounted ( async ( ) => {
console . log ( '课程表页面加载完成' )
console . log ( '课程表页面加载完成' )
/ / 自 动 选 择 当 前 学 期
currentSemester . value = getCurrentSemester ( )
console . log ( '自动选择学期:' , currentSemester . value )
/ / 自 动 定 位 到 当 前 周
currentWeek . value = getCurrentWeekInSemester ( currentSemester . value )
console . log ( '自动定位到当前周:' , currentWeek . value )
console . log ( '开始加载课程和日程数据...' )
await loadCourses ( )
await loadCourses ( )
await loadSchedules ( )
await loadSchedules ( )
/ / 设 置 当 前 周 ( 简 化 计 算 )
console . log ( '数据加载完成,当前日程数据:' , schedules . value )
const now = new Date ( )
console . log ( '今日日程计算结果:' , todaySchedules . value )
const startOfYear = new Date ( now . getFullYear ( ) , 0 , 1 )
const weekNumber = Math . ceil ( ( now . getTime ( ) - startOfYear . getTime ( ) ) / ( 7 * 24 * 60 * 60 * 1000 ) )
currentWeek . value = Math . min ( weekNumber , 20 )
} )
} )
const createTestSchedule = async ( ) => {
console . log ( '开始创建测试日程' )
const today = new Date ( )
const todayStr = today . toISOString ( ) . split ( 'T' ) [ 0 ]
const testScheduleData = {
title : '测试日程' ,
description : '这是一个测试日程,用于验证今日日程显示功能' ,
location : '测试地点' ,
startTime : ` ${ todayStr } T10:00:00 ` ,
endTime : ` ${ todayStr } T11:00:00 ` ,
isAllDay : 0 ,
reminder : 30 ,
color : '#67C23A'
}
console . log ( '测试日程数据:' , testScheduleData )
try {
const response = await createSchedule ( testScheduleData ) as any as ApiResponse < { scheduleId : number } >
if ( response . code === 200 ) {
ElMessage . success ( '测试日程创建成功!' )
await loadSchedules ( ) / / 重 新 加 载 日 程 列 表
console . log ( '重新加载后的日程数据:' , schedules . value )
console . log ( '重新计算的今日日程:' , todaySchedules . value )
} else {
ElMessage . error ( response . message || '创建测试日程失败' )
console . error ( '创建测试日程失败:' , response )
}
} catch ( error ) {
console . error ( '创建测试日程出错:' , error )
ElMessage . error ( '创建测试日程出错' )
}
}
< / script >
< / script >
< style scoped >
< style scoped >
@ -1058,6 +1543,12 @@ onMounted(async () => {
color : var ( -- primary - 700 ) ;
color : var ( -- primary - 700 ) ;
}
}
. day - column . current - day {
background : linear - gradient ( 135 deg , var ( -- primary - 100 ) , var ( -- primary - 200 ) ) ;
border : 2 px solid var ( -- primary - 400 ) ;
border - radius : 8 px 8 px 0 0 ;
}
. day - name {
. day - name {
font - size : 14 px ;
font - size : 14 px ;
margin - bottom : 4 px ;
margin - bottom : 4 px ;
@ -1066,6 +1557,24 @@ onMounted(async () => {
. day - date {
. day - date {
font - size : 12 px ;
font - size : 12 px ;
opacity : 0.8 ;
opacity : 0.8 ;
position : relative ;
}
. day - date . today - date {
opacity : 1 ;
font - weight : 700 ;
color : var ( -- primary - 700 ) ;
}
. today - indicator {
display : block ;
font - size : 10 px ;
color : var ( -- primary - 600 ) ;
background : var ( -- primary - 200 ) ;
padding : 1 px 4 px ;
border - radius : 4 px ;
margin - top : 2 px ;
font - weight : 600 ;
}
}
. table - body {
. table - body {
@ -1109,6 +1618,34 @@ onMounted(async () => {
background : var ( -- primary - 50 ) ;
background : var ( -- primary - 50 ) ;
}
}
. slot - items {
height : 100 % ;
display : flex ;
flex - direction : column ;
gap : 2 px ;
}
. slot - items . course - item ,
. slot - items . schedule - item {
flex : 1 ;
min - height : 0 ;
padding : 4 px 6 px ;
}
. slot - items . course - name ,
. slot - items . schedule - name {
font - size : 10 px ;
margin - bottom : 1 px ;
}
. slot - items . course - location ,
. slot - items . course - teacher ,
. slot - items . schedule - location ,
. slot - items . schedule - time {
font - size : 8 px ;
line - height : 1.1 ;
}
. course - item {
. course - item {
height : 100 % ;
height : 100 % ;
padding : 8 px ;
padding : 8 px ;
@ -1293,4 +1830,51 @@ onMounted(async () => {
grid - template - columns : 1 fr 1 fr ;
grid - template - columns : 1 fr 1 fr ;
gap : 16 px ;
gap : 16 px ;
}
}
. course - item {
height : 100 % ;
padding : 8 px ;
border - radius : 8 px ;
border - left : 4 px solid rgba ( 0 , 0 , 0 , 0.2 ) ;
cursor : pointer ;
transition : var ( -- transition - base ) ;
}
. course - item : hover {
transform : translateY ( - 1 px ) ;
box - shadow : var ( -- shadow - md ) ;
}
. schedule - item {
height : 100 % ;
padding : 8 px ;
border - radius : 8 px ;
border - left : 4 px dashed rgba ( 0 , 0 , 0 , 0.3 ) ;
cursor : pointer ;
transition : var ( -- transition - base ) ;
opacity : 0.9 ;
}
. schedule - item : hover {
transform : translateY ( - 1 px ) ;
box - shadow : var ( -- shadow - md ) ;
opacity : 1 ;
}
. course - name ,
. schedule - name {
font - size : 12 px ;
font - weight : 600 ;
color : var ( -- gray - 800 ) ;
margin - bottom : 2 px ;
}
. course - location ,
. course - teacher ,
. schedule - location ,
. schedule - time {
font - size : 10 px ;
color : var ( -- gray - 600 ) ;
line - height : 1.2 ;
}
< / style >
< / style >