Compare commits
No commits in common. "e44183e3e01d5cfc3629aa0495dfc6bc5cd052a5" and "96da6b6e42e27d215183d08d813a28a4d0b0be91" have entirely different histories.
e44183e3e0
...
96da6b6e42
2
.env
2
.env
@ -8,7 +8,7 @@ JWT_EXPIRES_IN=7d
|
|||||||
JWT_REFRESH_EXPIRES_IN=30d
|
JWT_REFRESH_EXPIRES_IN=30d
|
||||||
|
|
||||||
# Database (SQLite for local development, PostgreSQL for production)
|
# Database (SQLite for local development, PostgreSQL for production)
|
||||||
DATABASE_URL=file:./prisma/dev.db
|
DATABASE_URL=E:/qia/server/prisma/dev.db
|
||||||
|
|
||||||
# PostgreSQL (for production - Tencent Cloud)
|
# PostgreSQL (for production - Tencent Cloud)
|
||||||
# DATABASE_URL=postgresql://qia_admin:your-password@postgres.ap-shanghai.myqcloud.com:5432/qia
|
# DATABASE_URL=postgresql://qia_admin:your-password@postgres.ap-shanghai.myqcloud.com:5432/qia
|
||||||
|
|||||||
7
package-lock.json
generated
7
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "qia-server",
|
"name": "qia-server",
|
||||||
"version": "0.2.0-alpha",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "qia-server",
|
"name": "qia-server",
|
||||||
"version": "0.2.0-alpha",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@libsql/client": "^0.17.0",
|
"@libsql/client": "^0.17.0",
|
||||||
"@prisma/adapter-libsql": "^7.3.0",
|
"@prisma/adapter-libsql": "^7.3.0",
|
||||||
@ -19,6 +19,7 @@
|
|||||||
"express-validator": "^7.1.0",
|
"express-validator": "^7.1.0",
|
||||||
"helmet": "^8.0.0",
|
"helmet": "^8.0.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"sql.js": "^1.13.0",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -30,7 +31,6 @@
|
|||||||
"@types/jsonwebtoken": "^9.0.7",
|
"@types/jsonwebtoken": "^9.0.7",
|
||||||
"@types/node": "^22.5.5",
|
"@types/node": "^22.5.5",
|
||||||
"prisma": "^5.22.0",
|
"prisma": "^5.22.0",
|
||||||
"sql.js": "^1.13.0",
|
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.6.2"
|
"typescript": "^5.6.2"
|
||||||
}
|
}
|
||||||
@ -2321,7 +2321,6 @@
|
|||||||
"version": "1.13.0",
|
"version": "1.13.0",
|
||||||
"resolved": "https://registry.npmmirror.com/sql.js/-/sql.js-1.13.0.tgz",
|
"resolved": "https://registry.npmmirror.com/sql.js/-/sql.js-1.13.0.tgz",
|
||||||
"integrity": "sha512-RJbVP1HRDlUUXahJ7VMTcu9Rm1Nzw+EBpoPr94vnbD4LwR715F3CcxE2G2k45PewcaZ57pjetYa+LoSJLAASgA==",
|
"integrity": "sha512-RJbVP1HRDlUUXahJ7VMTcu9Rm1Nzw+EBpoPr94vnbD4LwR715F3CcxE2G2k45PewcaZ57pjetYa+LoSJLAASgA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
"express-validator": "^7.1.0",
|
"express-validator": "^7.1.0",
|
||||||
"helmet": "^8.0.0",
|
"helmet": "^8.0.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"sql.js": "^1.13.0",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -35,7 +36,6 @@
|
|||||||
"@types/jsonwebtoken": "^9.0.7",
|
"@types/jsonwebtoken": "^9.0.7",
|
||||||
"@types/node": "^22.5.5",
|
"@types/node": "^22.5.5",
|
||||||
"prisma": "^5.22.0",
|
"prisma": "^5.22.0",
|
||||||
"sql.js": "^1.13.0",
|
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.6.2"
|
"typescript": "^5.6.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,13 +36,10 @@ model Event {
|
|||||||
content String? // Only for reminders
|
content String? // Only for reminders
|
||||||
date DateTime // For anniversaries: the date; For reminders: the reminder date
|
date DateTime // For anniversaries: the date; For reminders: the reminder date
|
||||||
is_lunar Boolean @default(false)
|
is_lunar Boolean @default(false)
|
||||||
repeat_type String @default("none") // 'yearly' | 'monthly' | 'none' (String for SQLite)
|
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_holiday Boolean @default(false) // Only for anniversaries
|
is_completed Boolean @default(false) // Only for reminders
|
||||||
is_completed Boolean @default(false) // Only for reminders
|
|
||||||
priority String @default("none") // 'none' | 'red' | 'green' | 'yellow' (String for SQLite)
|
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())
|
created_at DateTime @default(now())
|
||||||
updated_at DateTime @updatedAt
|
updated_at DateTime @updatedAt
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
const initSqlJs = require('sql.js');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const SQL = await initSqlJs();
|
|
||||||
const db = new SQL.Database('e:/qia/server/prisma/dev.db');
|
|
||||||
|
|
||||||
try {
|
|
||||||
db.run("ALTER TABLE events ADD COLUMN reminder_times TEXT DEFAULT NULL");
|
|
||||||
console.log('reminder_times column added successfully');
|
|
||||||
} catch (error) {
|
|
||||||
if (error.message.includes('duplicate column name') || error.message.includes('already exists')) {
|
|
||||||
console.log('reminder_times column already exists');
|
|
||||||
} else {
|
|
||||||
console.error('Error:', error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = db.export();
|
|
||||||
const buffer = Buffer.from(data);
|
|
||||||
fs.writeFileSync('e:/qia/server/prisma/dev.db', buffer);
|
|
||||||
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(console.error);
|
|
||||||
@ -4,7 +4,7 @@ import db, { dbPath } from '../lib/db';
|
|||||||
import { authenticateToken, AuthenticatedRequest } from '../middleware/auth';
|
import { authenticateToken, AuthenticatedRequest } from '../middleware/auth';
|
||||||
import { asyncHandler } from '../middleware/errorHandler';
|
import { asyncHandler } from '../middleware/errorHandler';
|
||||||
|
|
||||||
// Initialize database: Add columns if they don't exist
|
// Initialize database: Add priority column if it doesn't exist
|
||||||
const initDb = async () => {
|
const initDb = async () => {
|
||||||
try {
|
try {
|
||||||
await db.execute({
|
await db.execute({
|
||||||
@ -18,19 +18,6 @@ const initDb = async () => {
|
|||||||
console.error('Error adding priority column:', error.message);
|
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
|
// Run initialization
|
||||||
@ -44,7 +31,7 @@ const createEventSchema = z.object({
|
|||||||
type: z.enum(['anniversary', 'reminder']),
|
type: z.enum(['anniversary', 'reminder']),
|
||||||
title: z.string().min(1, 'Title is required').max(200),
|
title: z.string().min(1, 'Title is required').max(200),
|
||||||
content: z.string().optional(),
|
content: z.string().optional(),
|
||||||
date: z.string().optional(), // Can be empty string for reminders
|
date: z.string().optional(), // Can be empty for reminders
|
||||||
is_lunar: z.boolean().default(false),
|
is_lunar: z.boolean().default(false),
|
||||||
repeat_type: z.enum(['daily', 'weekly', 'monthly', 'yearly', 'none']).default('none'),
|
repeat_type: z.enum(['daily', 'weekly', 'monthly', 'yearly', 'none']).default('none'),
|
||||||
repeat_interval: z.number().int().positive().optional().nullable(), // 自定义间隔(周数)
|
repeat_interval: z.number().int().positive().optional().nullable(), // 自定义间隔(周数)
|
||||||
@ -52,7 +39,6 @@ const createEventSchema = z.object({
|
|||||||
is_holiday: z.boolean().default(false),
|
is_holiday: z.boolean().default(false),
|
||||||
is_completed: z.boolean().default(false),
|
is_completed: z.boolean().default(false),
|
||||||
priority: z.enum(['none', 'red', 'green', 'yellow']).default('none'),
|
priority: z.enum(['none', 'red', 'green', 'yellow']).default('none'),
|
||||||
reminder_times: z.array(z.string()).optional(), // 提醒时间点数组(JSON)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateEventSchema = createEventSchema.partial();
|
const updateEventSchema = createEventSchema.partial();
|
||||||
@ -75,7 +61,6 @@ interface EventRow {
|
|||||||
is_holiday: number;
|
is_holiday: number;
|
||||||
is_completed: number;
|
is_completed: number;
|
||||||
priority: string; // 优先级:none, red, green, yellow
|
priority: string; // 优先级:none, red, green, yellow
|
||||||
reminder_times: string | null; // 提醒时间点数组(JSON 字符串)
|
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
@ -95,7 +80,6 @@ function formatEvent(event: EventRow) {
|
|||||||
is_holiday: Boolean(event.is_holiday),
|
is_holiday: Boolean(event.is_holiday),
|
||||||
is_completed: Boolean(event.is_completed),
|
is_completed: Boolean(event.is_completed),
|
||||||
priority: event.priority as 'none' | 'red' | 'green' | 'yellow',
|
priority: event.priority as 'none' | 'red' | 'green' | 'yellow',
|
||||||
reminder_times: event.reminder_times ? JSON.parse(event.reminder_times) : undefined,
|
|
||||||
created_at: event.created_at,
|
created_at: event.created_at,
|
||||||
updated_at: event.updated_at,
|
updated_at: event.updated_at,
|
||||||
};
|
};
|
||||||
@ -155,13 +139,11 @@ router.post(
|
|||||||
const repeatInterval = data.repeat_type === 'weekly' ? (data.repeat_interval || 1) : null;
|
const repeatInterval = data.repeat_type === 'weekly' ? (data.repeat_interval || 1) : null;
|
||||||
// 如果前端传了 next_reminder_date 就使用它,否则根据 repeat_type 计算
|
// 如果前端传了 next_reminder_date 就使用它,否则根据 repeat_type 计算
|
||||||
const nextReminderDate = data.next_reminder_date || null;
|
const nextReminderDate = data.next_reminder_date || null;
|
||||||
// 存储 reminder_times 为 JSON 字符串
|
|
||||||
const reminderTimesValue = data.reminder_times ? JSON.stringify(data.reminder_times) : null;
|
|
||||||
|
|
||||||
await db.execute({
|
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, reminder_times, created_at, updated_at)
|
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'))`,
|
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],
|
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],
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await db.execute({
|
const result = await db.execute({
|
||||||
@ -246,12 +228,6 @@ router.put(
|
|||||||
args.push(data.priority);
|
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) {
|
if (updates.length > 0) {
|
||||||
updates.push('updated_at = datetime(\'now\')');
|
updates.push('updated_at = datetime(\'now\')');
|
||||||
args.push(req.params.id);
|
args.push(req.params.id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user