PWA课程日历跨月排序问题:如何实现[27,28,1,2,3]排序?
解决跨月周课程日历的日期排序问题
我开发了一个PWA课程日历,常规日期下课程显示正常,但遇到跨月的周时,会出现日期排序错误——比如周一的课程被显示到了周四。目前生成的日期键排序是[1,2,3,27,28],但实际需要按周的顺序排列成[27,28,1,2,3]。
现有JSON结构示例
{ "27": [ { "day": 27, "isLesson": true, "start": "16:00", "end": "17:00", "room": "myRoom", "prof": "myTeacher", "spe": "MySpe" }, { "day": 27, "isLesson": true, "start": "14:15", "end": "15:45", "room": "myRoom", "prof": "myTeacher", "spe": "MySpe" }, { "day": 27, "isLesson": true, "start": "13:45", "end": "14:15", "room": "myRoom", "prof": "myTeacher", "spe": "MySpe" } ], "28": [ { "day": 28, "isLesson": true, "start": "09:00", "end": "10:00", "room": "myRoom", "prof": "myTeacher", "spe": "MySpe" }, { "isLesson": false, "start": "10:00", "end": "13:45" }, { "day": 28, "isLesson": true, "start": "13:45", "end": "15:45", "room": "myRoom", "prof": "myTeacher", "spe": "MySpe" } ] }
现有arrange函数代码
function arrange(json) { let new_json = {}; let previousSession = {}; for (const [uid, session] of Object.entries(json)) { if (!uid.match(/^[\d-]*$/)) { continue; } let minMidi = new Date(session.start); minMidi.setHours(11, 15, 0); let maxMidi = new Date(session.start); maxMidi.setHours(12, 45, 0); let session_json = {}; session_json.day = new Date(session.dtstamp).getDate(); if (previousSession.end && minMidi >= previousSession.end && previousSession.start && maxMidi <= session.start) { let pause_json = {}; pause_json.isLesson = false; pause_json.start = previousSession.end.toLocaleTimeString('fr-FR', localStringOpt); pause_json.end = session.start.toLocaleTimeString('fr-FR', localStringOpt); new_json[session_json.day] = new_json[session_json.day] ?? []; new_json[session_json.day].push(pause_json); } session_json.isLesson = true; const start = new Date(session.start); previousSession.start = start; session_json.start = start.toLocaleTimeString('fr-FR', localStringOpt); const end = new Date(session.end); previousSession.end = end; session_json.end = end.toLocaleTimeString('fr-FR', localStringOpt); //[...] new_json[session_json.day] = new_json[session_json.day] ?? []; new_json[session_json.day].push(session_json); } console.log(new_json); return Object.values(new_json); }
解决思路与修改方案
问题出在Object.values(new_json)会按对象键的升序返回值,跨月时小日期(1、2、3)会排在大日期(27、28)前面,不符合周的实际顺序。
方案一:基于日期阈值的排序
通过判断日期范围识别跨月场景,调整排序逻辑:
// 替换原函数末尾的return Object.values(new_json);部分 // 获取所有日期键并转为数字 const dayKeys = Object.keys(new_json).map(Number); // 排序逻辑:处理跨月周 const sortedKeys = dayKeys.sort((a, b) => { // 判断是否是跨月场景:同时存在月初小日期(<=7)和月末大日期(>=25) const hasSmallDate = dayKeys.some(day => day <= 7); const hasLargeDate = dayKeys.some(day => day >= 25); if (hasSmallDate && hasLargeDate) { // 月末日期排前面,月初日期排后面 if (a >= 25 && b < 7) return -1; if (a < 7 && b >= 25) return 1; } // 非跨月场景正常升序排列 return a - b; }); // 按排序后的键生成结果数组 const sortedResult = sortedKeys.map(key => new_json[key]); console.log(sortedResult); return sortedResult;
方案二:基于实际月份的精准排序
如果需要更准确的判断,可以结合session.dtstamp获取完整月份信息,区分上月和下月的日期:
// 替换原函数末尾的return Object.values(new_json);部分 // 为每个日期键绑定对应的月份信息 const dayWithMonth = Object.entries(new_json).map(([key, data]) => { // 取该日期下第一个有效课程的dtstamp获取月份 const validSession = data.find(item => item.day !== undefined); const month = new Date(validSession?.dtstamp || session.dtstamp).getMonth(); return { day: Number(key), month, data }; }); // 按月份排序,同月内按日期升序;上月日期排前面,下月日期排后面 dayWithMonth.sort((a, b) => { if (a.month !== b.month) { return a.month - b.month; } return a.day - b.day; }); const sortedResult = dayWithMonth.map(item => item.data); console.log(sortedResult); return sortedResult;
说明
- 方案一的日期阈值(25和7)是常规跨月周的经验值,可根据实际日历规则调整。
- 方案二更精准,依赖实际月份信息,避免阈值判断的误差。
内容的提问来源于stack exchange,提问作者Alexis
相关产品推荐
相关产品推荐

