From 5f42645a8525dbffcf1903324e98d164cf4f695b Mon Sep 17 00:00:00 2001 From: yuwangi Date: Fri, 10 Apr 2026 11:46:12 +0800 Subject: [PATCH] .3719011831386640:fcba79d62d76ce45176230013c3e31db_69d866fd59ede4fc2b1346c9.69d8672759ede4fc2b1346e5.69d867278102387d2c589ac5:Trae CN.T(2026/4/10 10:57:43) --- .../drizzle/0010_add_content_updated_at.sql | 4 ++++ apps/backend/drizzle/meta/_journal.json | 7 +++++++ apps/backend/src/database/schema.ts | 1 + apps/backend/src/queue/worker.ts | 1 + apps/backend/src/routes/chapter.routes.ts | 19 ++++++++++++++----- apps/frontend/app/stats/page.tsx | 6 ++++-- 6 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 apps/backend/drizzle/0010_add_content_updated_at.sql diff --git a/apps/backend/drizzle/0010_add_content_updated_at.sql b/apps/backend/drizzle/0010_add_content_updated_at.sql new file mode 100644 index 0000000..8effa99 --- /dev/null +++ b/apps/backend/drizzle/0010_add_content_updated_at.sql @@ -0,0 +1,4 @@ +ALTER TABLE "chapters" ADD COLUMN "content_updated_at" timestamp;--> statement-breakpoint + +-- Initialize content_updated_at with updated_at for existing chapters that have content +UPDATE "chapters" SET "content_updated_at" = "updated_at" WHERE "content" IS NOT NULL AND "content" != ''; diff --git a/apps/backend/drizzle/meta/_journal.json b/apps/backend/drizzle/meta/_journal.json index 8c72202..a7382cd 100644 --- a/apps/backend/drizzle/meta/_journal.json +++ b/apps/backend/drizzle/meta/_journal.json @@ -71,6 +71,13 @@ "when": 1772625679467, "tag": "0009_typical_thor_girl", "breakpoints": true + }, + { + "idx": 10, + "version": "5", + "when": 1775800000000, + "tag": "0010_add_content_updated_at", + "breakpoints": true } ] } diff --git a/apps/backend/src/database/schema.ts b/apps/backend/src/database/schema.ts index 73a44b6..d5a417c 100644 --- a/apps/backend/src/database/schema.ts +++ b/apps/backend/src/database/schema.ts @@ -262,6 +262,7 @@ export const chapters = pgTable("chapters", { status: chapterStatusEnum("status").default("pending"), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), + contentUpdatedAt: timestamp("content_updated_at"), // Only updates when content actually changes (for word count stats) }); // Chapter Snapshots table (Version History) diff --git a/apps/backend/src/queue/worker.ts b/apps/backend/src/queue/worker.ts index 352e493..09dcded 100644 --- a/apps/backend/src/queue/worker.ts +++ b/apps/backend/src/queue/worker.ts @@ -373,6 +373,7 @@ export function startWorker(io: Server) { wordCount: result.content.length, status: "completed", updatedAt: new Date(), + contentUpdatedAt: new Date(), }) .where(eq(schema.chapters.id, chapterId!)); break; diff --git a/apps/backend/src/routes/chapter.routes.ts b/apps/backend/src/routes/chapter.routes.ts index 2cbb9f4..3442389 100644 --- a/apps/backend/src/routes/chapter.routes.ts +++ b/apps/backend/src/routes/chapter.routes.ts @@ -98,6 +98,18 @@ router.patch("/:id", async (req: AuthRequest, res, next) => { const { id } = req.params; const { title, content, outline } = req.body; + const existingChapter = await db.query.chapters.findFirst({ + where: eq(schema.chapters.id, id), + }); + + if (!existingChapter) { + res.status(404).json({ error: "Chapter not found" }); + return; + } + + const contentChanged = + content !== undefined && content !== existingChapter.content; + const [chapter] = await db .update(schema.chapters) .set({ @@ -106,15 +118,11 @@ router.patch("/:id", async (req: AuthRequest, res, next) => { outline, wordCount: content ? content.length : undefined, updatedAt: new Date(), + ...(contentChanged && { contentUpdatedAt: new Date() }), }) .where(eq(schema.chapters.id, id)) .returning(); - if (!chapter) { - res.status(404).json({ error: "Chapter not found" }); - return; - } - res.json(chapter); } catch (error) { next(error); @@ -261,6 +269,7 @@ router.post( content: snapshot.content, wordCount: snapshot.wordCount, updatedAt: new Date(), + contentUpdatedAt: new Date(), }) .where(eq(schema.chapters.id, id)) .returning(); diff --git a/apps/frontend/app/stats/page.tsx b/apps/frontend/app/stats/page.tsx index 5bfbaad..ace79f9 100644 --- a/apps/frontend/app/stats/page.tsx +++ b/apps/frontend/app/stats/page.tsx @@ -31,6 +31,7 @@ interface Chapter { order: number; status: string; updatedAt: string; + contentUpdatedAt: string | null; } interface Volume { @@ -156,10 +157,11 @@ export default function StatsPage() { ).length; const totalNovels = novels.length; - // Calculate today's words from database (chapters updated today) + // Calculate today's words from database (chapters with content updated today) + // Use contentUpdatedAt to only count actual content changes, not just viewing const todayWords = useMemo(() => { return allChapters.reduce((sum, chapter) => { - if (chapter.updatedAt && isToday(chapter.updatedAt)) { + if (chapter.contentUpdatedAt && isToday(chapter.contentUpdatedAt)) { return sum + (chapter.wordCount || 0); } return sum;