fix(server): 修复排课发布唯一约束冲突并更正默认时段模板

发布时按日期+起止时间匹配已有时段,避免幽灵预览重复 create;默认课表改为上午整点与下午 13:30 起每小时至 21:30。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
richarjiang
2026-09-14 14:26:43 +08:00
parent d91282ecbd
commit b72357030d
6 changed files with 170 additions and 27 deletions

View File

@@ -15,11 +15,15 @@ export const DEFAULT_SLOT_CAPACITY = 1
/** 自动生成时段的天数范围 */
export const SLOT_GENERATION_DAYS = 14
/** 默认排课时间表:第一节 08:00-09:00之后从 09:30 起每小时一节至 21:30 */
/** 默认排课:上午整点 08:0012:0089、910、1011、1112下午 13:30 起每小时至 21:30 结束 */
export const DEFAULT_SCHEDULE_START_TIME = '08:00'
export const DEFAULT_SCHEDULE_END_TIME = '21:30'
/** 第一节课后的半点课表起点 */
export const DEFAULT_SCHEDULE_OFFSET_START_TIME = '09:30'
/** 上午时段结束时刻(不含):最后一节为 11:0012:00 */
export const DEFAULT_SCHEDULE_MORNING_END_TIME = '12:00'
/** 下午时段起点13:3014:30 起,之后每小时一节 */
export const DEFAULT_SCHEDULE_AFTERNOON_START_TIME = '13:30'
/** @deprecated 使用 DEFAULT_SCHEDULE_AFTERNOON_START_TIME */
export const DEFAULT_SCHEDULE_OFFSET_START_TIME = DEFAULT_SCHEDULE_AFTERNOON_START_TIME
/** 排课时间选择步长:仅整点与半点 */
export const SCHEDULE_MINUTE_STEP = 30
@@ -37,14 +41,13 @@ function formatMinutesToTime(totalMinutes: number): string {
/** 生成默认时段列表 (startTime, endTime) */
export function getDefaultTimeSlots(): ReadonlyArray<{ readonly startTime: string; readonly endTime: string }> {
const duration = 60
const slots: Array<{ startTime: string; endTime: string }> = [
{ startTime: DEFAULT_SCHEDULE_START_TIME, endTime: '09:00' },
]
const endMinutes = parseTimeToMinutes(DEFAULT_SCHEDULE_END_TIME)
const slots: Array<{ startTime: string; endTime: string }> = []
const morningEnd = parseTimeToMinutes(DEFAULT_SCHEDULE_MORNING_END_TIME)
const dayEnd = parseTimeToMinutes(DEFAULT_SCHEDULE_END_TIME)
for (
let t = parseTimeToMinutes(DEFAULT_SCHEDULE_OFFSET_START_TIME);
t + duration <= endMinutes;
let t = parseTimeToMinutes(DEFAULT_SCHEDULE_START_TIME);
t + duration <= morningEnd;
t += duration
) {
slots.push({
@@ -52,6 +55,18 @@ export function getDefaultTimeSlots(): ReadonlyArray<{ readonly startTime: strin
endTime: formatMinutesToTime(t + duration),
})
}
for (
let t = parseTimeToMinutes(DEFAULT_SCHEDULE_AFTERNOON_START_TIME);
t + duration <= dayEnd;
t += duration
) {
slots.push({
startTime: formatMinutesToTime(t),
endTime: formatMinutesToTime(t + duration),
})
}
return slots
}

View File

@@ -38,6 +38,8 @@ export {
SLOT_GENERATION_DAYS,
DEFAULT_SCHEDULE_START_TIME,
DEFAULT_SCHEDULE_END_TIME,
DEFAULT_SCHEDULE_MORNING_END_TIME,
DEFAULT_SCHEDULE_AFTERNOON_START_TIME,
DEFAULT_SCHEDULE_OFFSET_START_TIME,
SCHEDULE_MINUTE_STEP,
getDefaultTimeSlots,