diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 2c69f74..7f1ce9b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -36,10 +36,13 @@ model Event { content String? // Only for reminders date DateTime // For anniversaries: the date; For reminders: the reminder date is_lunar Boolean @default(false) - repeat_type String @default("none") // 'yearly' | 'monthly' | 'none' (String for SQLite) - is_holiday Boolean @default(false) // Only for anniversaries - is_completed Boolean @default(false) // Only for reminders + repeat_type String @default("none") // 'yearly' | 'monthly' | 'none' (String for SQLite) + repeat_interval Int? // Weekly interval (only for weekly type) + is_holiday Boolean @default(false) // Only for anniversaries + is_completed Boolean @default(false) // Only for reminders priority String @default("none") // 'none' | 'red' | 'green' | 'yellow' (String for SQLite) + next_reminder_date DateTime? // Next reminder date (calculated) + reminder_times String? // JSON array of reminder timestamps (ISO strings) created_at DateTime @default(now()) updated_at DateTime @updatedAt diff --git a/src/routes/events.ts b/src/routes/events.ts index 1857399..ce4de35 100644 --- a/src/routes/events.ts +++ b/src/routes/events.ts @@ -4,7 +4,7 @@ import db, { dbPath } from '../lib/db'; import { authenticateToken, AuthenticatedRequest } from '../middleware/auth'; import { asyncHandler } from '../middleware/errorHandler'; -// Initialize database: Add priority column if it doesn't exist +// Initialize database: Add columns if they don't exist const initDb = async () => { try { await db.execute({ @@ -18,6 +18,19 @@ const initDb = async () => { console.error('Error adding priority column:', error.message); } } + + try { + await db.execute({ + sql: `ALTER TABLE events ADD COLUMN reminder_times TEXT DEFAULT NULL`, + }); + console.log('✓ Reminder times column added to events table'); + } catch (error: any) { + if (error.message?.includes('duplicate column name') || error.message?.includes('already exists')) { + console.log('✓ Reminder times column already exists'); + } else { + console.error('Error adding reminder_times column:', error.message); + } + } }; // Run initialization @@ -31,7 +44,7 @@ const createEventSchema = z.object({ type: z.enum(['anniversary', 'reminder']), title: z.string().min(1, 'Title is required').max(200), content: z.string().optional(), - date: z.string().optional(), // Can be empty for reminders + date: z.string().optional(), // Can be empty string for reminders is_lunar: z.boolean().default(false), repeat_type: z.enum(['daily', 'weekly', 'monthly', 'yearly', 'none']).default('none'), repeat_interval: z.number().int().positive().optional().nullable(), // 自定义间隔(周数) @@ -39,6 +52,7 @@ const createEventSchema = z.object({ is_holiday: z.boolean().default(false), is_completed: z.boolean().default(false), priority: z.enum(['none', 'red', 'green', 'yellow']).default('none'), + reminder_times: z.array(z.string()).optional(), // 提醒时间点数组(JSON) }); const updateEventSchema = createEventSchema.partial(); @@ -61,6 +75,7 @@ interface EventRow { is_holiday: number; is_completed: number; priority: string; // 优先级:none, red, green, yellow + reminder_times: string | null; // 提醒时间点数组(JSON 字符串) created_at: string; updated_at: string; } @@ -80,6 +95,7 @@ function formatEvent(event: EventRow) { is_holiday: Boolean(event.is_holiday), is_completed: Boolean(event.is_completed), priority: event.priority as 'none' | 'red' | 'green' | 'yellow', + reminder_times: event.reminder_times ? JSON.parse(event.reminder_times) : undefined, created_at: event.created_at, updated_at: event.updated_at, }; @@ -139,11 +155,13 @@ router.post( const repeatInterval = data.repeat_type === 'weekly' ? (data.repeat_interval || 1) : null; // 如果前端传了 next_reminder_date 就使用它,否则根据 repeat_type 计算 const nextReminderDate = data.next_reminder_date || null; + // 存储 reminder_times 为 JSON 字符串 + const reminderTimesValue = data.reminder_times ? JSON.stringify(data.reminder_times) : null; await db.execute({ - sql: `INSERT INTO events (id, user_id, type, title, content, date, is_lunar, repeat_type, repeat_interval, next_reminder_date, is_holiday, is_completed, priority, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, datetime('now'), datetime('now'))`, - args: [eventId, req.user!.userId, data.type, data.title, data.content || null, dateValue, data.is_lunar ? 1 : 0, data.repeat_type, repeatInterval, nextReminderDate, data.is_holiday ? 1 : 0, data.priority], + sql: `INSERT INTO events (id, user_id, type, title, content, date, is_lunar, repeat_type, repeat_interval, next_reminder_date, is_holiday, is_completed, priority, reminder_times, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, datetime('now'), datetime('now'))`, + args: [eventId, req.user!.userId, data.type, data.title, data.content || null, dateValue, data.is_lunar ? 1 : 0, data.repeat_type, repeatInterval, nextReminderDate, data.is_holiday ? 1 : 0, data.priority, reminderTimesValue], }); const result = await db.execute({ @@ -228,6 +246,12 @@ router.put( args.push(data.priority); } + // 处理 reminder_times 更新 + if (data.reminder_times !== undefined) { + updates.push('reminder_times = ?'); + args.push(data.reminder_times === null ? null : JSON.stringify(data.reminder_times)); + } + if (updates.length > 0) { updates.push('updated_at = datetime(\'now\')'); args.push(req.params.id);