인기 페이지 통계와 추천 사이트 메타데이터 추가 v1.5.9
This commit is contained in:
@@ -45,6 +45,9 @@ let currentPath = ''
|
||||
/** @type {string} 현재 추적 게시물 slug */
|
||||
let currentPostSlug = ''
|
||||
|
||||
/** @type {string} 현재 추적 페이지 slug */
|
||||
let currentPageSlug = ''
|
||||
|
||||
/** @type {number} 현재 페이지 체류 시작 시각 */
|
||||
let pageStartedAt = 0
|
||||
|
||||
@@ -85,6 +88,21 @@ const extractPostSlugFromRoute = (route) => {
|
||||
return match?.[1] ? decodeURIComponent(match[1]).trim() : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 고정 페이지 경로에서 slug를 추출한다.
|
||||
* @param {import('vue-router').RouteLocationNormalizedLoaded} route - 현재 라우트
|
||||
* @returns {string} slug 또는 빈 문자열
|
||||
*/
|
||||
const extractPageSlugFromRoute = (route) => {
|
||||
const paramSlug = String(route.params?.slug || '').trim()
|
||||
if (paramSlug && String(route.path || '').startsWith('/pages/')) {
|
||||
return paramSlug
|
||||
}
|
||||
|
||||
const match = String(route.path || '').match(/^\/pages\/([^/?#]+)/)
|
||||
return match?.[1] ? decodeURIComponent(match[1]).trim() : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 문서 스크롤 진행 비율(0~1)을 반환한다.
|
||||
* @returns {number} 스크롤 비율
|
||||
@@ -148,6 +166,7 @@ const clearPageTracking = () => {
|
||||
readStartedAt = 0
|
||||
currentPath = ''
|
||||
currentPostSlug = ''
|
||||
currentPageSlug = ''
|
||||
pageStartedAt = 0
|
||||
maxScrollRatio = 0
|
||||
}
|
||||
@@ -182,26 +201,28 @@ const sendAnalyticsPayload = (endpoint, payload) => {
|
||||
|
||||
/**
|
||||
* pageview 이벤트를 전송한다.
|
||||
* @param {{ path: string, postSlug?: string, read?: boolean }} payload - 전송 본문
|
||||
* @param {{ path: string, postSlug?: string, pageSlug?: string, read?: boolean }} payload - 전송 본문
|
||||
* @returns {void}
|
||||
*/
|
||||
const sendPageviewEvent = (payload) => {
|
||||
sendAnalyticsPayload('/api/analytics/pageview', {
|
||||
path: payload.path,
|
||||
postSlug: payload.postSlug || '',
|
||||
pageSlug: payload.pageSlug || '',
|
||||
read: Boolean(payload.read)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* heartbeat 이벤트를 전송한다.
|
||||
* @param {{ path: string, postSlug?: string, durationSeconds: number, maxScrollRatio: number }} payload - 전송 본문
|
||||
* @param {{ path: string, postSlug?: string, pageSlug?: string, durationSeconds: number, maxScrollRatio: number }} payload - 전송 본문
|
||||
* @returns {void}
|
||||
*/
|
||||
const sendHeartbeatEvent = (payload) => {
|
||||
sendAnalyticsPayload('/api/analytics/heartbeat', {
|
||||
path: payload.path,
|
||||
postSlug: payload.postSlug || '',
|
||||
pageSlug: payload.pageSlug || '',
|
||||
clientSessionId: getClientSessionId(),
|
||||
durationSeconds: payload.durationSeconds,
|
||||
maxScrollRatio: payload.maxScrollRatio
|
||||
@@ -222,6 +243,7 @@ const sendCurrentHeartbeat = () => {
|
||||
sendHeartbeatEvent({
|
||||
path: currentPath,
|
||||
postSlug: currentPostSlug,
|
||||
pageSlug: currentPageSlug,
|
||||
durationSeconds: getCurrentDurationSeconds(),
|
||||
maxScrollRatio
|
||||
})
|
||||
@@ -308,13 +330,15 @@ const trackRouteAnalytics = (route) => {
|
||||
sendCurrentHeartbeat()
|
||||
|
||||
const postSlug = extractPostSlugFromRoute(route)
|
||||
const viewKey = `view:${path}:${postSlug}`
|
||||
const pageSlug = postSlug ? '' : extractPageSlugFromRoute(route)
|
||||
const viewKey = `view:${path}:${postSlug}:${pageSlug}`
|
||||
|
||||
if (!sentViewKeys.has(viewKey)) {
|
||||
sentViewKeys.add(viewKey)
|
||||
sendPageviewEvent({
|
||||
path,
|
||||
postSlug,
|
||||
pageSlug,
|
||||
read: false
|
||||
})
|
||||
}
|
||||
@@ -323,6 +347,7 @@ const trackRouteAnalytics = (route) => {
|
||||
|
||||
currentPath = path
|
||||
currentPostSlug = postSlug
|
||||
currentPageSlug = pageSlug
|
||||
pageStartedAt = Date.now()
|
||||
maxScrollRatio = getDocumentScrollRatio()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user