macbook 에서 리눅스로 이동
This commit is contained in:
238
frontend/app/stores/variants.ts
Normal file
238
frontend/app/stores/variants.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export interface PageVariant {
|
||||
id: string
|
||||
pageId: string
|
||||
name: string
|
||||
description: string
|
||||
trafficWeight: number
|
||||
isActive: boolean
|
||||
leadCount: number
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface CreateVariantInput {
|
||||
pageId: string
|
||||
name: string
|
||||
description: string
|
||||
trafficWeight: number
|
||||
}
|
||||
|
||||
export interface UpdateVariantInput {
|
||||
id: string
|
||||
pageId: string
|
||||
name?: string
|
||||
description?: string
|
||||
trafficWeight?: number
|
||||
isActive?: boolean
|
||||
leadCount?: number
|
||||
}
|
||||
|
||||
type VariantMap = Record<string, PageVariant[]>
|
||||
|
||||
const toVariantIso = (value = 0) => {
|
||||
const date = new Date()
|
||||
date.setSeconds(date.getSeconds() + value)
|
||||
|
||||
return date.toISOString()
|
||||
}
|
||||
|
||||
const variantSeed: VariantMap = {
|
||||
lp01: [
|
||||
{
|
||||
id: 'v-lp01-a',
|
||||
pageId: 'lp01',
|
||||
name: '일반형',
|
||||
description: '현재 운영 중인 기본 랜딩 버전',
|
||||
trafficWeight: 70,
|
||||
isActive: true,
|
||||
leadCount: 76,
|
||||
updatedAt: toVariantIso(-1200)
|
||||
},
|
||||
{
|
||||
id: 'v-lp01-b',
|
||||
pageId: 'lp01',
|
||||
name: '강한 메시지형',
|
||||
description: 'CTA 문구를 자극적으로 강화한 변형',
|
||||
trafficWeight: 30,
|
||||
isActive: true,
|
||||
leadCount: 48,
|
||||
updatedAt: toVariantIso(-900)
|
||||
}
|
||||
],
|
||||
lp02: [
|
||||
{
|
||||
id: 'v-lp02-a',
|
||||
pageId: 'lp02',
|
||||
name: '기본 오퍼',
|
||||
description: '초안 상태 테스트용 템플릿',
|
||||
trafficWeight: 100,
|
||||
isActive: true,
|
||||
leadCount: 16,
|
||||
updatedAt: toVariantIso(-2000)
|
||||
}
|
||||
],
|
||||
lp03: [
|
||||
{
|
||||
id: 'v-lp03-a',
|
||||
pageId: 'lp03',
|
||||
name: '구글 버전 A',
|
||||
description: '광고 채널별로 분기되는 기본 버전',
|
||||
trafficWeight: 50,
|
||||
isActive: true,
|
||||
leadCount: 58,
|
||||
updatedAt: toVariantIso(-1300)
|
||||
},
|
||||
{
|
||||
id: 'v-lp03-b',
|
||||
pageId: 'lp03',
|
||||
name: '구글 버전 B',
|
||||
description: '강조 문구/이미지를 변경한 실험군',
|
||||
trafficWeight: 30,
|
||||
isActive: true,
|
||||
leadCount: 22,
|
||||
updatedAt: toVariantIso(-800)
|
||||
},
|
||||
{
|
||||
id: 'v-lp03-c',
|
||||
pageId: 'lp03',
|
||||
name: '구글 버전 C',
|
||||
description: '폼 위치를 상단으로 이동한 변형',
|
||||
trafficWeight: 20,
|
||||
isActive: true,
|
||||
leadCount: 8,
|
||||
updatedAt: toVariantIso(-500)
|
||||
}
|
||||
],
|
||||
lp04: [
|
||||
{
|
||||
id: 'v-lp04-a',
|
||||
pageId: 'lp04',
|
||||
name: '저녁 타겟형',
|
||||
description: '기본 버전',
|
||||
trafficWeight: 100,
|
||||
isActive: false,
|
||||
leadCount: 22,
|
||||
updatedAt: toVariantIso(-700)
|
||||
}
|
||||
],
|
||||
lp05: [
|
||||
{
|
||||
id: 'v-lp05-a',
|
||||
pageId: 'lp05',
|
||||
name: '리타겟 기본형',
|
||||
description: '리마케팅 유입용 기본 템플릿',
|
||||
trafficWeight: 100,
|
||||
isActive: true,
|
||||
leadCount: 0,
|
||||
updatedAt: toVariantIso(-1000)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const clampTrafficWeight = (value: number) => {
|
||||
if (!Number.isFinite(value)) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (value < 1) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (value > 100) {
|
||||
return 100
|
||||
}
|
||||
|
||||
return Math.round(value)
|
||||
}
|
||||
|
||||
export const useVariantsStore = defineStore('admin-variants', {
|
||||
state: () => ({
|
||||
variantsByPage: variantSeed as VariantMap
|
||||
}),
|
||||
getters: {
|
||||
listByPage: (state) => (pageId: string) => {
|
||||
const list = state.variantsByPage[pageId] ?? []
|
||||
return [...list].sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())
|
||||
},
|
||||
countByPage: (state) => (pageId: string) => {
|
||||
return state.variantsByPage[pageId]?.length ?? 0
|
||||
},
|
||||
totalLeadsByPage: (state) => (pageId: string) => {
|
||||
return (state.variantsByPage[pageId] ?? []).reduce((sum, item) => sum + item.leadCount, 0)
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
createVariant(payload: CreateVariantInput) {
|
||||
const normalizedName = payload.name.trim()
|
||||
const pageId = payload.pageId.trim()
|
||||
const description = payload.description.trim()
|
||||
|
||||
if (pageId.length === 0 || normalizedName.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const pageVariants = this.variantsByPage[pageId] ?? []
|
||||
const newVariant: PageVariant = {
|
||||
id: `v-${Date.now().toString(36)}`,
|
||||
pageId,
|
||||
name: normalizedName,
|
||||
description,
|
||||
trafficWeight: clampTrafficWeight(payload.trafficWeight),
|
||||
isActive: true,
|
||||
leadCount: 0,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
this.variantsByPage[pageId] = [newVariant, ...pageVariants]
|
||||
},
|
||||
updateVariant(payload: UpdateVariantInput) {
|
||||
const pageId = payload.pageId.trim()
|
||||
const variants = this.variantsByPage[pageId]
|
||||
|
||||
if (!variants) {
|
||||
return
|
||||
}
|
||||
|
||||
const idx = variants.findIndex((item) => item.id === payload.id)
|
||||
if (idx === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
const target = variants[idx]
|
||||
variants[idx] = {
|
||||
...target,
|
||||
...payload,
|
||||
updatedAt: new Date().toISOString(),
|
||||
pageId
|
||||
}
|
||||
},
|
||||
toggleActive(pageId: string, variantId: string) {
|
||||
const variants = this.variantsByPage[pageId]
|
||||
|
||||
if (!variants) {
|
||||
return
|
||||
}
|
||||
|
||||
const idx = variants.findIndex((item) => item.id === variantId)
|
||||
if (idx === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
variants[idx] = {
|
||||
...variants[idx],
|
||||
isActive: !variants[idx].isActive,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
},
|
||||
removeVariant(pageId: string, variantId: string) {
|
||||
const variants = this.variantsByPage[pageId]
|
||||
|
||||
if (!variants) {
|
||||
return
|
||||
}
|
||||
|
||||
this.variantsByPage[pageId] = variants.filter((variant) => variant.id !== variantId)
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user