refactor: 페이지 데이터 처리 개선 및 로딩 컴포넌트 수정
This commit is contained in:
@@ -101,6 +101,7 @@ if (serverGameData) {
|
||||
setupMetaData(serverGameData)
|
||||
}
|
||||
|
||||
// Google Analytics 설정
|
||||
const { gtag, initialize } = useGtag()
|
||||
initialize(gameData.value?.ga_code)
|
||||
gtag('event', 'screen_view', {
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
const getPageData = ref<PageDataValue | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
getPageData.value = pageData.value
|
||||
})
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(getPageData.value))
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
@@ -15,6 +22,6 @@ definePageMeta({
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
<LayoutsMain v-if="getPageData" :page-data="getPageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
const getPageData = ref<PageDataValue | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
getPageData.value = pageData.value
|
||||
})
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(getPageData.value))
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
@@ -15,6 +22,6 @@ definePageMeta({
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
<LayoutsMain v-if="getPageData" :page-data="getPageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
const getPageData = ref<PageDataValue | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
getPageData.value = pageData.value
|
||||
})
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(getPageData.value))
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
@@ -15,6 +22,6 @@ definePageMeta({
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
<LayoutsMain v-if="getPageData" id="page-content" :page-data="getPageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
const getPageData = ref<PageDataValue | null>(null)
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
onMounted(() => {
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
getPageData.value = pageData.value
|
||||
})
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(getPageData.value))
|
||||
|
||||
|
||||
definePageMeta({
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
middleware: ['inspection'],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
<LayoutsMain v-if="getPageData" :page-data="getPageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -3,12 +3,13 @@ import { useLoadingStore } from '#layers/stores/useLoadingStore'
|
||||
|
||||
const loadingStore = useLoadingStore()
|
||||
const { fullLoading } = storeToRefs(loadingStore)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Transition name="fade">
|
||||
<div v-if="fullLoading" class="spinner-container">
|
||||
<div class="spinner-line"></div>
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
@@ -16,7 +16,7 @@ const canTeleport = (localId: string) => {
|
||||
<Teleport v-if="canTeleport(localId)" :to="`#${localId}`">
|
||||
<Transition name="fade">
|
||||
<div v-if="loadingInfo.active" class="spinner-container">
|
||||
<div class="spinner-line"></div>
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
|
||||
29
layers/components/atoms/loading/Simple.vue
Normal file
29
layers/components/atoms/loading/Simple.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
isLoading?: boolean
|
||||
}
|
||||
|
||||
const { isLoading = false } = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="isLoading" class="spinner-container">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.spinner-container {
|
||||
@apply absolute inset-0 flex items-center justify-center z-[90];
|
||||
}
|
||||
.spinner {
|
||||
@apply w-[80px] h-[80px] bg-cover bg-center bg-no-repeat bg-[url('/images/common/publisning_template_loader_black.png')];
|
||||
}
|
||||
|
||||
[data-theme='light'] {
|
||||
.spinner {
|
||||
@apply bg-[url('/images/common/publisning_template_loader_white.png')];
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<div
|
||||
class="inner relative max-w-7xl mx-auto px-5 md:px-10 py-4 text-[12px] text-gray-400 md:px-4 md:py-9 md:text-[12px]"
|
||||
>
|
||||
<ClientOnly>
|
||||
|
||||
<div class="menu-area py-4 pb-4">
|
||||
<ul class="flex items-center flex-wrap gap-x-6 gap-y-2">
|
||||
<li
|
||||
@@ -80,7 +82,6 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="address-area mt-4 hidden sm:block">
|
||||
<address class="not-italic text-white/50">
|
||||
<div class="row my-1.5 leading-5">
|
||||
@@ -91,19 +92,19 @@
|
||||
</div>
|
||||
</address>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="language-area static md:absolute bottom-7 right-10 text-white mt-5 md:mt-0 md:bottom-5.5 md:right-4">
|
||||
<BlocksLanguageSwitcher />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-6 md:mt-6 hidden sm:block">
|
||||
<div v-dompurify-html="tm('Footer_caution')" class="text-xs text-white/30"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="copyright-area mt-6 text-[13px] text-white/50 md:mt-4">
|
||||
<span v-dompurify-html="tm('Footer_Copyright')"></span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="logo-area flex mt-6 md:mt-6">
|
||||
<a
|
||||
href="https://www.smilegate.com"
|
||||
@@ -129,8 +130,8 @@
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
</ClientOnly>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
@@ -62,7 +62,7 @@ watchEffect(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main ref="mainRef" class="main">
|
||||
<div ref="mainRef" class="main">
|
||||
<template
|
||||
v-for="(template, index) in visibleTemplates"
|
||||
:key="template.template_code ?? index"
|
||||
@@ -78,12 +78,12 @@ watchEffect(() => {
|
||||
:is-show-top-btn="pageData.use_top_btn ?? false"
|
||||
:is-show-sns-btn="pageData.use_sns_btn ?? false"
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.main {
|
||||
@apply relative min-h-[200px] pt-[48px] md:min-h-[300px] md:pt-[64px];
|
||||
@apply relative min-h-[200px] pt-[48px] md:min-h-[600px] md:pt-[64px] z-[91];
|
||||
}
|
||||
|
||||
[data-theme='light'] {
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
const isLoading = ref(true)
|
||||
|
||||
onMounted(() => {
|
||||
isLoading.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutsHeader />
|
||||
<slot />
|
||||
<main id="LayoutMain" class="min-h-screen relative">
|
||||
<AtomsLoadingSimple :is-loading="isLoading" />
|
||||
<slot />
|
||||
</main>
|
||||
<LayoutsFooter />
|
||||
</template>
|
||||
|
||||
@@ -24,6 +24,10 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
const langCode = ssrGetFinalLocale(to.path, headers, gameData?.lang_codes, gameData?.default_lang_code)
|
||||
|
||||
try {
|
||||
// 서버 사이드에서는 스킵
|
||||
if (import.meta.server) {
|
||||
return
|
||||
}
|
||||
if (to.path.includes('inspection')) {
|
||||
return
|
||||
}
|
||||
@@ -58,7 +62,6 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
|
||||
if (response?.code === 0 && 'value' in response) {
|
||||
store.setPageData(response.value)
|
||||
console.log('🚀 ~ pageData:', response.value)
|
||||
} else {
|
||||
store.clearPageData()
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import type { AnalyticsDetailType } from '../types/AnalyticsType'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
// 공통 함수 정의
|
||||
const createEventHandler = (eventName: string, sendFunction: Function) => {
|
||||
return (el: any, binding: any) => {
|
||||
const eventHandler = (event: Event) => {
|
||||
const bindingValue = binding.value
|
||||
if (bindingValue) {
|
||||
sendFunction(bindingValue)
|
||||
}
|
||||
// 기존의 @click 핸들러 호출
|
||||
if (typeof binding.value === 'function') {
|
||||
binding.value(event)
|
||||
}
|
||||
}
|
||||
|
||||
el.addEventListener(eventName, eventHandler)
|
||||
el[`__${eventName}EventHandler__`] = eventHandler
|
||||
}
|
||||
}
|
||||
|
||||
const removeEventHandler = (eventName: string) => {
|
||||
return (el: any) => {
|
||||
if (el[`__${eventName}EventHandler__`]) {
|
||||
el.removeEventListener(eventName, el[`__${eventName}EventHandler__`])
|
||||
delete el[`__${eventName}EventHandler__`]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// analytics
|
||||
nuxtApp.vueApp.directive('analytics', {
|
||||
mounted: createEventHandler('click', (bindingValue: AnalyticsDetailType) => {
|
||||
const { sendLog } = useAnalytics()
|
||||
const i18n = nuxtApp.$i18n as { locale: { value: string } }
|
||||
|
||||
sendLog(i18n.locale.value, bindingValue)
|
||||
}),
|
||||
beforeUnmount: removeEventHandler('click')
|
||||
})
|
||||
})
|
||||
@@ -85,6 +85,11 @@ function setFinalLocaleCookie(event: any, finalLocale: string, baseDomain: strin
|
||||
* @param finalLocale - 최종 언어
|
||||
*/
|
||||
function fnLocaleMiddleware(event: any, finalLocale: string) {
|
||||
// 이미 응답이 종료되었는지 확인
|
||||
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||
return
|
||||
}
|
||||
|
||||
const path = event?.node.req.url || ''
|
||||
let arrPath = []
|
||||
let queryString = ''
|
||||
@@ -122,6 +127,15 @@ function fnLocaleMiddleware(event: any, finalLocale: string) {
|
||||
}
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
// HMR 요청 필터링 (개발 모드에서 중복 실행 방지)
|
||||
if (event.path.startsWith('/_nuxt/') || event.path.startsWith('/__nuxt')) {
|
||||
return
|
||||
}
|
||||
|
||||
// 이미 응답이 종료되었는지 확인 (리다이렉트 등으로 인한 중복 실행 방지)
|
||||
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||
return
|
||||
}
|
||||
|
||||
// const runType = `${config.public.runType}`
|
||||
// console.log("🚀 ~ baseDomain:", config.public.baseDomain)
|
||||
@@ -150,7 +164,7 @@ export default defineEventHandler(async event => {
|
||||
const stoveApiUrlBaseServer = config.public.stoveApiUrlServer
|
||||
const apiUrl = `${stoveApiUrlBaseServer}/pub-comm/v1.0/template/game`
|
||||
|
||||
const initGameData: GameDataResponse | null = null
|
||||
let initGameData: GameDataResponse | null = null
|
||||
let initLangCodes: string[] | null = null
|
||||
let finalLocale
|
||||
let cleanHost
|
||||
@@ -174,8 +188,9 @@ export default defineEventHandler(async event => {
|
||||
const initResponse = (await $fetch(apiUrl, {
|
||||
query: queryParams,
|
||||
})) as GameDataResponse | null
|
||||
// initGameData = initResponse || null
|
||||
initGameData = initResponse || null
|
||||
// console.log("🚀 ~ 00000 initGameData:", initGameData)
|
||||
|
||||
initLangCodes = initResponse?.value?.lang_codes || null
|
||||
initDefaultLocale = initResponse?.value?.default_lang_code || null
|
||||
console.log("🚀 ~ 000111 initLangCodes:", initLangCodes)
|
||||
@@ -214,10 +229,13 @@ export default defineEventHandler(async event => {
|
||||
const cacheKey = 'inspection'
|
||||
|
||||
try {
|
||||
// 이미 응답이 종료되었는지 확인
|
||||
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||
return
|
||||
}
|
||||
|
||||
// 2. 언어 코드 추출
|
||||
finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers, initLangCodes, initDefaultLocale)
|
||||
console.log("🚀 222 finalLocale:", finalLocale)
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
game_domain: cleanHost || '',
|
||||
@@ -290,9 +308,11 @@ export default defineEventHandler(async event => {
|
||||
// 허용된 IP 목록 확인
|
||||
if (!inspectionData?.ip_filter_list?.includes(clientIP)) {
|
||||
// 허용되지 않은 IP인 경우 점검 페이지로 이동
|
||||
event.node.res.statusCode = 302
|
||||
event.node.res.setHeader('Location', inspectionPath)
|
||||
event.node.res.end()
|
||||
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
|
||||
event.node.res.statusCode = 302
|
||||
event.node.res.setHeader('Location', inspectionPath)
|
||||
event.node.res.end()
|
||||
}
|
||||
} else {
|
||||
// 화이트 리스트인 경우
|
||||
// -------------------------------------------------------------------------------
|
||||
@@ -301,9 +321,11 @@ export default defineEventHandler(async event => {
|
||||
fnLocaleMiddleware(event, finalLocale)
|
||||
}
|
||||
} else {
|
||||
event.node.res.statusCode = 302
|
||||
event.node.res.setHeader('Location', inspectionPath)
|
||||
event.node.res.end()
|
||||
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
|
||||
event.node.res.statusCode = 302
|
||||
event.node.res.setHeader('Location', inspectionPath)
|
||||
event.node.res.end()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user