블로그 통계 위젯 확장 v1.7.6
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { getSiteSettings } from '../repositories/content-repository'
|
||||
import { getAnalyticsSummary } from '../repositories/analytics-repository'
|
||||
import { getPublicBlogStatistics } from '../repositories/blog-statistics-repository'
|
||||
|
||||
/**
|
||||
* 초 단위 체류 시간을 짧은 한국어 문자열로 변환한다.
|
||||
@@ -32,9 +33,10 @@ const formatNumberLabel = (value, unit) => `${Number(value || 0).toLocaleString(
|
||||
* @returns {Promise<Object>} 위젯 데이터
|
||||
*/
|
||||
export default defineEventHandler(async () => {
|
||||
const [settings, summary] = await Promise.all([
|
||||
const [settings, summary, statistics] = await Promise.all([
|
||||
getSiteSettings(),
|
||||
getAnalyticsSummary({ days: 1 })
|
||||
getAnalyticsSummary({ days: 1 }),
|
||||
getPublicBlogStatistics()
|
||||
])
|
||||
const avgEngagedSeconds = summary.todayAvgEngagedSeconds || summary.avgEngagedSeconds || 0
|
||||
|
||||
@@ -42,10 +44,19 @@ export default defineEventHandler(async () => {
|
||||
title: settings.title || 'sori.studio',
|
||||
updatedAt: new Date().toISOString(),
|
||||
todayVisitors: summary.todayVisitors,
|
||||
totalVisitors: statistics.totalVisitors,
|
||||
todayPageViews: summary.todayPageViews,
|
||||
totalPageViews: statistics.totalPageViews,
|
||||
onlineNow: summary.onlineNow,
|
||||
loggedInNow: summary.loggedInNow,
|
||||
avgEngagedSeconds,
|
||||
visitorsLast7Days: summary.visitorsLast7Days,
|
||||
pageViewsLast30Days: summary.pageViewsLast30Days,
|
||||
totalPosts: statistics.totalPosts,
|
||||
totalComments: statistics.totalComments,
|
||||
totalPages: statistics.totalPages,
|
||||
totalTags: statistics.totalTags,
|
||||
totalMembers: statistics.totalMembers,
|
||||
items: [
|
||||
{
|
||||
name: '오늘 방문자',
|
||||
@@ -66,6 +77,21 @@ export default defineEventHandler(async () => {
|
||||
name: '평균 체류',
|
||||
label: formatDuration(avgEngagedSeconds),
|
||||
value: avgEngagedSeconds
|
||||
},
|
||||
{
|
||||
name: '누적 방문자',
|
||||
label: formatNumberLabel(statistics.totalVisitors, '명'),
|
||||
value: statistics.totalVisitors
|
||||
},
|
||||
{
|
||||
name: '전체 게시글',
|
||||
label: formatNumberLabel(statistics.totalPosts, '개'),
|
||||
value: statistics.totalPosts
|
||||
},
|
||||
{
|
||||
name: '전체 댓글',
|
||||
label: formatNumberLabel(statistics.totalComments, '개'),
|
||||
value: statistics.totalComments
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
80
server/repositories/blog-statistics-repository.js
Normal file
80
server/repositories/blog-statistics-repository.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import { getSamplePosts } from '../utils/sample-content.js'
|
||||
import { getPostgresClient } from './postgres-client.js'
|
||||
|
||||
/**
|
||||
* 공개 블로그 누적 통계를 조회한다.
|
||||
* @returns {Promise<{
|
||||
* totalVisitors: number,
|
||||
* totalPageViews: number,
|
||||
* totalPosts: number,
|
||||
* totalComments: number,
|
||||
* totalPages: number,
|
||||
* totalTags: number,
|
||||
* totalMembers: number
|
||||
* }>} 공개 블로그 누적 통계
|
||||
*/
|
||||
export const getPublicBlogStatistics = async () => {
|
||||
const sql = getPostgresClient()
|
||||
|
||||
if (!sql) {
|
||||
return {
|
||||
totalVisitors: 0,
|
||||
totalPageViews: 0,
|
||||
totalPosts: getSamplePosts().filter((post) => post.status === 'published').length,
|
||||
totalComments: 0,
|
||||
totalPages: 0,
|
||||
totalTags: 0,
|
||||
totalMembers: 0
|
||||
}
|
||||
}
|
||||
|
||||
const rows = await sql`
|
||||
SELECT
|
||||
(
|
||||
SELECT COALESCE(SUM(visitors), 0)::int
|
||||
FROM site_analytics_daily
|
||||
) AS "totalVisitors",
|
||||
(
|
||||
SELECT COALESCE(SUM(page_views), 0)::int
|
||||
FROM site_analytics_daily
|
||||
) AS "totalPageViews",
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM posts
|
||||
WHERE status = 'published'
|
||||
AND (published_at IS NULL OR published_at <= now())
|
||||
) AS "totalPosts",
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM comments
|
||||
INNER JOIN posts ON posts.id = comments.post_id
|
||||
WHERE comments.status = 'published'
|
||||
AND posts.status = 'published'
|
||||
AND (posts.published_at IS NULL OR posts.published_at <= now())
|
||||
) AS "totalComments",
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM pages
|
||||
WHERE status = 'published'
|
||||
) AS "totalPages",
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM tags
|
||||
) AS "totalTags",
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM users
|
||||
) AS "totalMembers"
|
||||
`
|
||||
const row = rows[0] || {}
|
||||
|
||||
return {
|
||||
totalVisitors: Number(row.totalVisitors || 0),
|
||||
totalPageViews: Number(row.totalPageViews || 0),
|
||||
totalPosts: Number(row.totalPosts || 0),
|
||||
totalComments: Number(row.totalComments || 0),
|
||||
totalPages: Number(row.totalPages || 0),
|
||||
totalTags: Number(row.totalTags || 0),
|
||||
totalMembers: Number(row.totalMembers || 0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user