From 310b1d09499bc76c15f23dd9a7657a1c61b9bf7a Mon Sep 17 00:00:00 2001 From: ngthanhvu Date: Thu, 30 Jul 2026 12:06:17 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20fix=20l=E1=BA=A1i=20m=E1=BA=A5y=20c?= =?UTF-8?q?=C3=A1i=20=E1=BB=9F=20comuniti=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/icons.ts | 2 + app/pages/index.vue | 63 +++++++++++++++++--------------- server/api/home/sections.get.ts | 65 ++++++++++++++++++++------------- 3 files changed, 75 insertions(+), 55 deletions(-) diff --git a/app/lib/icons.ts b/app/lib/icons.ts index a648259..ec28c8b 100644 --- a/app/lib/icons.ts +++ b/app/lib/icons.ts @@ -1,5 +1,6 @@ import { faArrowLeft, + faArrowUp, faArrowTurnDown, faArrowTrendDown, faArrowTrendUp, @@ -92,6 +93,7 @@ import { library } from '@fortawesome/fontawesome-svg-core' library.add( faArrowLeft, + faArrowUp, faArrowTurnDown, faArrowTrendDown, faArrowTrendUp, diff --git a/app/pages/index.vue b/app/pages/index.vue index 6409061..db94e4d 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -617,17 +617,18 @@ useHead({
-
- -

Bình luận mới

+
+ +

Bình luận mới

-
+
+ class="group relative h-48 min-w-[82%] snap-start overflow-hidden rounded-xl bg-[#181a22] + transition-all duration-800 ease-in-out sm:h-50 sm:min-w-60 sm:rounded-2xl md:min-w-65 + lg:min-w-67.5 xl:min-w-72.5 2xl:min-w-77.5">
+ class="mt-auto size-10 shrink-0 rounded-full object-cover shadow-md ring-2 ring-white/20 sm:size-12"> -
+
{{ (comment.user?.name || 'A').charAt(0).toUpperCase() }}
-
+
-
+
-
+

@@ -751,10 +755,10 @@ useHead({ : index === 2 ? 'minus' : 'trending-down'" :class="index < 2 - ? 'text-green-400' - : index === 2 - ? 'text-slate-400' - : 'text-red-400'" class="size-3.5 shrink-0" /> + ? 'text-green-400' + : index === 2 + ? 'text-slate-400' + : 'text-red-400'" class="size-3.5 shrink-0" /> @@ -773,8 +777,8 @@ useHead({

-
+

@@ -795,10 +799,10 @@ useHead({ : index === 2 ? 'minus' : 'trending-down'" :class="index < 2 - ? 'text-green-400' - : index === 2 - ? 'text-slate-400' - : 'text-red-400'" class="size-3.5 shrink-0" /> + ? 'text-green-400' + : index === 2 + ? 'text-slate-400' + : 'text-red-400'" class="size-3.5 shrink-0" /> @@ -817,7 +821,8 @@ useHead({

-
+

@@ -837,10 +842,10 @@ useHead({ : index === 2 ? 'minus' : 'trending-down'" :class="index < 2 - ? 'text-green-400' - : index === 2 - ? 'text-slate-400' - : 'text-red-400'" class="size-3.5 shrink-0" /> + ? 'text-green-400' + : index === 2 + ? 'text-slate-400' + : 'text-red-400'" class="size-3.5 shrink-0" />
diff --git a/server/api/home/sections.get.ts b/server/api/home/sections.get.ts index 61f439a..653b5d0 100644 --- a/server/api/home/sections.get.ts +++ b/server/api/home/sections.get.ts @@ -4,8 +4,28 @@ import { comments, users, movies } from '../../database/schema' export default defineEventHandler(async () => { const db = useDb() - const [recentComments, trending, mostRated, allCategories] = await Promise.all([ - // Recent comments (top-level only) with user and movie info + // Comment counts per movie (top-level only) + const commentCountsRows = await db + .select({ + source: comments.source, + slug: comments.slug, + cCount: count(), + }) + .from(comments) + .where(isNull(comments.parentId)) + .groupBy(comments.source, comments.slug) + + const commentCountMap = new Map() + for (const row of commentCountsRows) { + commentCountMap.set(`${row.source}:${row.slug}`, Number(row.cCount)) + } + + function getCommentCount(movie: any) { + return commentCountMap.get(`${movie.source}:${movie.slug}`) || 0 + } + + const [recentComments, rawMovies, allCategories] = await Promise.all([ + // Recent comments db .select({ id: comments.id, @@ -31,7 +51,7 @@ export default defineEventHandler(async () => { .orderBy(desc(comments.createdAt)) .limit(10), - // Trending by views + // All active movies (used for trending + most rated in JS) db .select({ source: movies.source, @@ -44,34 +64,27 @@ export default defineEventHandler(async () => { rating: movies.rating, }) .from(movies) - .where(eq(movies.active, true)) - .orderBy(desc(movies.views), desc(movies.rating)) - .limit(5), + .where(eq(movies.active, true)), - // Most rated / favorite - db - .select({ - source: movies.source, - slug: movies.slug, - name: movies.name, - originName: movies.originName, - thumb: movies.thumb, - poster: movies.poster, - views: movies.views, - rating: movies.rating, - }) - .from(movies) - .where(eq(movies.active, true)) - .orderBy(desc(movies.rating), desc(movies.views)) - .limit(5), - - // All categories for hot genres calculation + // Categories for hot genres db .select({ categories: movies.categories }) .from(movies) .where(eq(movies.active, true)), ]) + // Trending: views + commentCount * 50 + const trendingWithScore = rawMovies.map(m => ({ + ...m, + _score: Number(m.views) + getCommentCount(m) * 50, + })).sort((a, b) => b._score - a._score).slice(0, 5) + + // Most rated: rating + commentCount * 2 + const mostRatedWithScore = rawMovies.map(m => ({ + ...m, + _score: Number(m.rating) + getCommentCount(m) * 2, + })).sort((a, b) => b._score - a._score).slice(0, 5) + // Count replies for each recent comment const commentIds = recentComments.map(c => c.id) let replyCounts: Record = {} @@ -124,7 +137,7 @@ export default defineEventHandler(async () => { } : null, })), - trending: trending.map(m => ({ + trending: trendingWithScore.map(m => ({ source: m.source, slug: m.slug, name: m.name, @@ -134,7 +147,7 @@ export default defineEventHandler(async () => { views: m.views, rating: m.rating, })), - mostRated: mostRated.map(m => ({ + mostRated: mostRatedWithScore.map(m => ({ source: m.source, slug: m.slug, name: m.name,