Commit Graph

5 Commits

Author SHA1 Message Date
richarjiang
b72357030d fix(server): 修复排课发布唯一约束冲突并更正默认时段模板
发布时按日期+起止时间匹配已有时段,避免幽灵预览重复 create;默认课表改为上午整点与下午 13:30 起每小时至 21:30。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:26:43 +08:00
richarjiang
b8c0dd6781 fix(server): hide CLOSED rows from preview for legacy mini-program compatibility
The previous fix made publishDaySlots CLOSE rows instead of DELETE them.
That works correctly on the server, but the live mini-program still ships
the old schedule.vue which only knows about isPublished (no status
field). It would re-render the CLOSED rows with the '已发布' badge,
making it look like 'clear day' did nothing.

Hide CLOSED rows from getSchedulePreview so the legacy client shows
'当日暂无排课' for rest days — the same UX it had before this fix
shipped. All-CLOSED days return []; days with a mix return only the
non-CLOSED rows; days the cron hasn't touched still return the ghost
template.

The republished mini-program (with status-aware rendering) will see the
same [] for rest days, which is consistent. Tests: 4 new specs covering
all-OPEN / all-CLOSED / mixed / empty-day cases.
2026-09-10 22:36:41 +08:00
richarjiang
806f3ee770 fix(server): preserve admin 'rest day' intent across cron runs
publishDaySlots used to DELETE the TimeSlot rows of a day that an admin
just 'cleared', which made the nightly slot-generation cron resurrect
the default schedule the next morning — a real production bug where
classes would reappear on a teacher's rest day.

Changes:
- publishDaySlots now CLOSEs (never DELETEs) orphaned rows, and materializes
  the default template for days with no rows so an empty publish still
  records intent. update on existing rows preserves their current status,
  so re-publishing the page cannot silently reopen a CLOSED rest day.
- SlotGeneratorService.generateSlots pre-fetches dates that already have any
  TimeSlot row and skips them, so the cron no longer overwrites admin-touched
  days even when admin only set status without changing times.
- SlotGeneratorService.prunePastClosedSlots (new) deletes past CLOSED slots
  with no bookings, scheduled nightly at 02:35, so the 'no DELETE' rule
  above does not leak rows forever.
- schedule.vue surfaces the CLOSED state with a grey '已关闭' badge and
  card style.

Tests: 12 new specs across time-slot.service.spec.ts (publishDaySlots
behaviour) and slot-generator.service.spec.ts (skip touched dates +
prune conditions). Full suite: 315 / 315 passing.
2026-09-10 22:32:32 +08:00
richarjiang
6cee28bf66 feat: 支持管理员消息推送 2026-04-12 22:18:34 +08:00
richarjiang
593a6e5453 feat(server): add membership and time-slot modules
Membership: card type CRUD, deduction/restore logic, valid card lookup (15 tests)
TimeSlot: slot generation from week templates, availability query with booking
status, admin management, cleanup tasks (26 tests)
65 total tests passing
2026-04-02 12:24:07 +08:00