3
This commit is contained in:
@@ -20,6 +20,8 @@ export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const startParam = searchParams.get('start')
|
||||
const endParam = searchParams.get('end')
|
||||
const mode = (searchParams.get('mode') || 'items').toLowerCase()
|
||||
const interval = (searchParams.get('interval') || 'day').toLowerCase() as 'day' | 'week' | 'month'
|
||||
|
||||
const start = parseIsoDate(startParam)
|
||||
const end = parseIsoDate(endParam)
|
||||
@@ -68,6 +70,94 @@ export async function GET(request: Request) {
|
||||
where.content = { handleId: { in: handleIds } }
|
||||
}
|
||||
|
||||
// 시계열(기간별) 모드: day/week/month로 버킷팅해 합계 반환
|
||||
if (mode === 'series') {
|
||||
const contentIdsParam = searchParams.get('contentIds')
|
||||
let contentIdsFilter: string[] | null = null
|
||||
if (contentIdsParam) contentIdsFilter = contentIdsParam.split(',').map(s => s.trim()).filter(Boolean)
|
||||
|
||||
const seriesRows = await prisma.contentDayView.findMany({
|
||||
where: {
|
||||
...where,
|
||||
...(contentIdsFilter && contentIdsFilter.length > 0 ? { contentId: { in: contentIdsFilter } } : {}),
|
||||
},
|
||||
select: {
|
||||
date: true,
|
||||
views: true,
|
||||
validViews: true,
|
||||
premiumViews: true,
|
||||
watchTime: true,
|
||||
content: { select: { handle: { select: { costPerView: true } } } },
|
||||
},
|
||||
orderBy: { date: 'asc' },
|
||||
})
|
||||
|
||||
// 버킷 키 생성기
|
||||
const makeKey = (d: Date): string => {
|
||||
const y = d.getUTCFullYear()
|
||||
const m = String(d.getUTCMonth() + 1).padStart(2, '0')
|
||||
const dd = String(d.getUTCDate()).padStart(2, '0')
|
||||
if (interval === 'day') return `${y}-${m}-${dd}`
|
||||
if (interval === 'month') return `${y}-${m}`
|
||||
// week: ISO 주 시작(월요일)로 버킷팅
|
||||
const date = new Date(Date.UTC(y, d.getUTCMonth(), d.getUTCDate()))
|
||||
const day = date.getUTCDay() || 7 // 1..7, 월=1, 일=7
|
||||
const monday = new Date(date)
|
||||
monday.setUTCDate(date.getUTCDate() - (day - 1))
|
||||
const my = String(monday.getUTCMonth() + 1).padStart(2, '0')
|
||||
const md = String(monday.getUTCDate()).padStart(2, '0')
|
||||
return `${monday.getUTCFullYear()}-${my}-${md}`
|
||||
}
|
||||
|
||||
const bucket = new Map<string, { views: number, validViews: number, premiumViews: number, watchTime: number, expectedRevenue: number }>()
|
||||
for (const r of seriesRows) {
|
||||
const key = makeKey(new Date(r.date))
|
||||
const cpv = Number(r.content?.handle?.costPerView ?? 0) || 0
|
||||
const cur = bucket.get(key) || { views: 0, validViews: 0, premiumViews: 0, watchTime: 0, expectedRevenue: 0 }
|
||||
cur.views += r.views || 0
|
||||
cur.validViews += r.validViews || 0
|
||||
cur.premiumViews += r.premiumViews || 0
|
||||
cur.watchTime += r.watchTime || 0
|
||||
cur.expectedRevenue += Math.max(0, Math.round((r.validViews || 0) * cpv))
|
||||
bucket.set(key, cur)
|
||||
}
|
||||
// 빈 버킷 채우기 (연속 타임라인)
|
||||
const addZeroIfMissing = (d: Date) => {
|
||||
const k = makeKey(d)
|
||||
if (!bucket.has(k)) bucket.set(k, { views: 0, validViews: 0, premiumViews: 0, watchTime: 0, expectedRevenue: 0 })
|
||||
}
|
||||
if (interval === 'day') {
|
||||
let d = new Date(Date.UTC(startDay.getUTCFullYear(), startDay.getUTCMonth(), startDay.getUTCDate()))
|
||||
const end = new Date(Date.UTC(endDay.getUTCFullYear(), endDay.getUTCMonth(), endDay.getUTCDate()))
|
||||
while (d.getTime() <= end.getTime()) {
|
||||
addZeroIfMissing(d)
|
||||
d = new Date(d.getTime() + 24*60*60*1000)
|
||||
}
|
||||
} else if (interval === 'week') {
|
||||
const mkMonday = (d0: Date) => {
|
||||
const t = new Date(Date.UTC(d0.getUTCFullYear(), d0.getUTCMonth(), d0.getUTCDate()))
|
||||
const wd = t.getUTCDay() || 7
|
||||
t.setUTCDate(t.getUTCDate() - (wd - 1))
|
||||
return t
|
||||
}
|
||||
let d = mkMonday(startDay)
|
||||
const end = new Date(Date.UTC(endDay.getUTCFullYear(), endDay.getUTCMonth(), endDay.getUTCDate()))
|
||||
while (d.getTime() <= end.getTime()) {
|
||||
addZeroIfMissing(d)
|
||||
d = new Date(d.getTime() + 7*24*60*60*1000)
|
||||
}
|
||||
} else if (interval === 'month') {
|
||||
let d = new Date(Date.UTC(startDay.getUTCFullYear(), startDay.getUTCMonth(), 1))
|
||||
const end = new Date(Date.UTC(endDay.getUTCFullYear(), endDay.getUTCMonth(), 1))
|
||||
while (d.getTime() <= end.getTime()) {
|
||||
addZeroIfMissing(d)
|
||||
d = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1))
|
||||
}
|
||||
}
|
||||
const items = Array.from(bucket.entries()).sort((a,b) => a[0] < b[0] ? -1 : 1).map(([period, agg]) => ({ period, ...agg }))
|
||||
return NextResponse.json({ success: true, mode: 'series', interval, start: startDay.toISOString(), end: endDay.toISOString(), count: items.length, items })
|
||||
}
|
||||
|
||||
const grouped = await prisma.contentDayView.groupBy({
|
||||
by: ['contentId'],
|
||||
where,
|
||||
|
||||
Reference in New Issue
Block a user