fix. main 컴포넌트 변경, 수정된 api 구조에 맞춰 코드 수정
This commit is contained in:
141
app/app.vue
141
app/app.vue
@@ -1,73 +1,134 @@
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<h1 class="sr-only">dddd</h1>
|
||||
<NuxtPage />
|
||||
|
||||
<LoadingFull />
|
||||
<LoadingLocal />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useNuxtApp } from 'nuxt/app'
|
||||
import LoadingFull from '#layers/components/blocks/loading/Full.vue'
|
||||
import LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import { useGameColors } from '#layers/composables/useGameColors'
|
||||
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
||||
import type {
|
||||
GameDataMetaTag,
|
||||
GameDataValue,
|
||||
GameDataFaviconPath,
|
||||
} from '#layers/types/api/gameData'
|
||||
|
||||
const nuxtApp = useNuxtApp()
|
||||
const getGameData = ref<GameDataValue | null>(null)
|
||||
const metaData = ref<GameDataMetaTag | null>(null)
|
||||
|
||||
const { setGameData } = useGameDataStore()
|
||||
const { applyGameColors } = useGameColors()
|
||||
const { applyGameKeyCodeColors } = useGameKeyCodeColors()
|
||||
|
||||
// SSR에서만 접근 가능
|
||||
const gameDataFromServer = import.meta.server
|
||||
? nuxtApp.ssrContext?.event.context.gameData
|
||||
: null
|
||||
const gameData = ref<GameDataValue | null>(null)
|
||||
const metaData = ref<GameDataMetaTag | null>(null)
|
||||
|
||||
if (gameDataFromServer) {
|
||||
getGameData.value = gameDataFromServer
|
||||
setGameData(gameDataFromServer)
|
||||
// SSR에서 게임 데이터 가져오기
|
||||
const getGameDataFromServer = (): GameDataValue | null => {
|
||||
return import.meta.server
|
||||
? (nuxtApp.ssrContext?.event.context.gameData ?? null)
|
||||
: null
|
||||
}
|
||||
|
||||
if (import.meta.client) {
|
||||
const gameDataStore = useGameDataStore()
|
||||
// 클라이언트에서 색상 코드 적용
|
||||
const applyColorsOnClient = () => {
|
||||
if (import.meta.client) {
|
||||
const gameDataStore = useGameDataStore()
|
||||
const keyCodeCodes = gameDataStore.gameData?.key_code_codes
|
||||
|
||||
if (gameDataStore.gameData?.key_color_codes) {
|
||||
applyGameColors(gameDataStore.gameData.key_color_codes)
|
||||
if (keyCodeCodes) {
|
||||
applyGameKeyCodeColors(keyCodeCodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const meta = gameDataFromServer?.meta_tag ?? null
|
||||
const theme = gameDataFromServer?.design_theme === 1 ? 'dark' : 'light'
|
||||
|
||||
if (gameDataFromServer && meta) {
|
||||
metaData.value = meta
|
||||
// SEO 메타 태그 설정
|
||||
const setupSeoMeta = (meta: GameDataMetaTag) => {
|
||||
useSeoMeta({
|
||||
title: meta.page_title,
|
||||
description: meta.page_desc,
|
||||
ogTitle: meta.og_title,
|
||||
ogImage: meta.og_image,
|
||||
ogDescription: meta.og_desc,
|
||||
ogUrl: meta.og_url,
|
||||
twitterImage: meta.x_image,
|
||||
twitterTitle: meta.x_title,
|
||||
twitterDescription: meta.x_desc,
|
||||
})
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
'data-game': gameDataFromServer.game_name || '',
|
||||
'data-theme': theme || '',
|
||||
lang: gameDataFromServer.default_lang_code,
|
||||
}
|
||||
|
||||
// 파비콘 설정
|
||||
const setupFavicon = (faviconPath: GameDataFaviconPath) => {
|
||||
const faviconLinks = [
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/x-icon',
|
||||
sizes: '16x16',
|
||||
href: faviconPath['16_16'],
|
||||
},
|
||||
//meta: [...(updatedMetaTags.value || [])],
|
||||
//link: [...(links.value || [])]
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/x-icon',
|
||||
sizes: '32x32',
|
||||
href: faviconPath['32_32'],
|
||||
},
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/png',
|
||||
sizes: '72x72',
|
||||
href: faviconPath['72_72'],
|
||||
},
|
||||
{
|
||||
rel: 'apple-touch-icon',
|
||||
sizes: '180x180',
|
||||
href: faviconPath['180_180'],
|
||||
},
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/png',
|
||||
sizes: '192x192',
|
||||
href: faviconPath['192_192'],
|
||||
},
|
||||
]
|
||||
|
||||
useHead({
|
||||
link: faviconLinks,
|
||||
})
|
||||
}
|
||||
|
||||
// HTML 속성 설정
|
||||
const setupHtmlAttributes = (data: GameDataValue) => {
|
||||
const theme = data.design_theme === 1 ? 'dark' : 'light'
|
||||
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
'data-game': data.game_name || '',
|
||||
'data-theme': theme,
|
||||
lang: data.default_lang_code || 'ko',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 메타 데이터 설정
|
||||
const setupMetaData = (data: GameDataValue) => {
|
||||
metaData.value = data.meta_tag
|
||||
setupSeoMeta(metaData.value)
|
||||
setupHtmlAttributes(data)
|
||||
setupFavicon(data.favicon_path)
|
||||
}
|
||||
|
||||
// 초기화 로직 실행
|
||||
const serverGameData = getGameDataFromServer()
|
||||
|
||||
if (serverGameData) {
|
||||
gameData.value = serverGameData
|
||||
setGameData(serverGameData)
|
||||
setupMetaData(serverGameData)
|
||||
applyColorsOnClient()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1 class="sr-only">{{ gameData?.game_name }}</h1>
|
||||
<NuxtPage />
|
||||
|
||||
<!-- 로딩 컴포넌트들 -->
|
||||
<LoadingFull />
|
||||
<LoadingLocal />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@import '#layers/assets/css/app.css';
|
||||
</style>
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
definePageMeta({
|
||||
layout: false, // 기본 레이아웃 비활성화
|
||||
})
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
watchEffect(() => {
|
||||
if (pageData.value?.meta_tag) {
|
||||
useSeoMeta({
|
||||
title: pageData.value.meta_tag.page_title ?? '',
|
||||
description: pageData.value.meta_tag.page_desc ?? '',
|
||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
||||
})
|
||||
}
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="layout">
|
||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
definePageMeta({
|
||||
layout: false, // 기본 레이아웃 비활성화
|
||||
})
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
watchEffect(() => {
|
||||
if (pageData.value?.meta_tag) {
|
||||
useSeoMeta({
|
||||
title: pageData.value.meta_tag.page_title ?? '',
|
||||
description: pageData.value.meta_tag.page_desc ?? '',
|
||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
||||
})
|
||||
}
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="layout">
|
||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
definePageMeta({
|
||||
layout: false, // 기본 레이아웃 비활성화
|
||||
})
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
watchEffect(() => {
|
||||
if (pageData.value?.meta_tag) {
|
||||
useSeoMeta({
|
||||
title: pageData.value.meta_tag.page_title ?? '',
|
||||
description: pageData.value.meta_tag.page_desc ?? '',
|
||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
||||
})
|
||||
}
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="layout">
|
||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,46 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// 동적 i18n 라우트 설정
|
||||
// const { getI18nRouteConfig } = useDynamicI18nRoutes();
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
definePageMeta({
|
||||
layout: false, // 기본 레이아웃 비활성화
|
||||
})
|
||||
|
||||
// // gameData.lang_codes를 기반으로 동적 언어 제외 설정
|
||||
// const i18nRouteConfig = getI18nRouteConfig();
|
||||
// if (i18nRouteConfig) {
|
||||
// defineI18nRoute(i18nRouteConfig);
|
||||
// }
|
||||
|
||||
// SEO 메타 태그 설정 - pageData가 로드된 후에만 실행
|
||||
watchEffect(() => {
|
||||
if (pageData.value?.meta_tag) {
|
||||
useSeoMeta({
|
||||
title: pageData.value.meta_tag.page_title ?? '',
|
||||
description: pageData.value.meta_tag.page_desc ?? '',
|
||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
||||
})
|
||||
}
|
||||
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout :name="layout">
|
||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
||||
<NuxtLayout :name="currentLayout">
|
||||
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<div class="p-8">
|
||||
<h1 class="text-2xl font-bold mb-4">{{ t('messages.title_test_lang') }}</h1>
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-lg font-semibold mb-2">{{ t('messages.welcome') }}</h2>
|
||||
<p>
|
||||
<strong>{{ t('messages.GameData_load_status') }}:</strong>
|
||||
<span :class="isGameDataLoaded ? 'text-green-600' : 'text-red-600'">
|
||||
{{ isGameDataLoaded ? '로드됨' : '로드되지 않음' }}
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<strong>{{ t('messages.current_language') }}:</strong>
|
||||
{{ $i18n.locale }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>{{ t('messages.default_language') }}:</strong>
|
||||
{{ gameDataStore.gameData?.default_lang_code || 'N/A' }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>{{ t('messages.available_languages') }}:</strong>
|
||||
{{
|
||||
Array.isArray(availableLanguages)
|
||||
? availableLanguages.join(', ')
|
||||
: availableLanguages
|
||||
}}
|
||||
</p>
|
||||
<p>
|
||||
<strong>{{ t('messages.current_url') }}:</strong>
|
||||
{{ $route.path }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-lg font-semibold mb-2">언어 전환:</h2>
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-lg font-semibold mb-2">직접 링크 테스트:</h2>
|
||||
<div class="space-x-4">
|
||||
<NuxtLink
|
||||
v-for="lang in availableLanguages"
|
||||
:key="lang"
|
||||
:to="`/${lang}/test-lang`"
|
||||
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||
>
|
||||
{{ lang.toUpperCase() }} 페이지로 이동
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
:to="`/ja/test-lang`"
|
||||
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||
>
|
||||
ja 페이지로 이동
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-lg font-semibold mb-2">GameData 정보:</h2>
|
||||
<div v-if="isGameDataLoaded" class="space-y-2">
|
||||
<p>
|
||||
<strong>게임 ID:</strong>
|
||||
{{ gameDataStore.gameData?.game_id }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>게임 코드:</strong>
|
||||
{{ gameDataStore.gameData?.game_code }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>S3 폴더명:</strong>
|
||||
{{ gameDataStore.gameData?.s3_folder_name }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>디자인 테마:</strong>
|
||||
{{ gameDataStore.gameData?.design_theme }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>전체:</strong>
|
||||
{{
|
||||
Array.isArray(gameDataStore.gameData?.key_color_codes)
|
||||
? gameDataStore.gameData?.key_color_codes.join(', ')
|
||||
: gameDataStore.gameData?.key_color_codes
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<pre class="bg-gray-100 p-4 rounded text-sm overflow-auto max-h-80">{{
|
||||
gameDataInfo
|
||||
}}</pre>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-lg font-semibold mb-2">동적 언어 설정 테스트:</h2>
|
||||
<div class="space-y-2">
|
||||
<p><strong>현재 i18n 설정:</strong></p>
|
||||
<ul class="list-disc list-inside ml-4">
|
||||
<li>
|
||||
사용 가능한 언어:
|
||||
{{ $i18n.availableLocales.map((l: any) => l.code || l).join(', ') }}
|
||||
</li>
|
||||
<li>기본 언어: {{ $i18n.defaultLocale }}</li>
|
||||
<li>현재 언어: {{ $i18n.locale }}</li>
|
||||
</ul>
|
||||
<p class="text-sm text-gray-600 mt-2">
|
||||
GameData에서 가져온 lang_codes가 동적으로 i18n 설정에 반영되었는지
|
||||
확인하세요.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import LanguageSwitcher from '#layers/components/blocks/LanguageSwitcher.vue'
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
// 사용 가능한 언어 목록
|
||||
const availableLanguages = computed(() => {
|
||||
return gameDataStore.gameData?.lang_codes || ['ko']
|
||||
})
|
||||
|
||||
// GameData가 로드되었는지 확인
|
||||
const isGameDataLoaded = computed(() => {
|
||||
return !!gameDataStore.gameData
|
||||
})
|
||||
|
||||
// GameData 정보를 JSON으로 표시
|
||||
const gameDataInfo = computed(() => {
|
||||
if (!gameDataStore.gameData) {
|
||||
return 'GameData가 로드되지 않았습니다.'
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
{
|
||||
game_id: gameDataStore.gameData.game_id,
|
||||
game_code: gameDataStore.gameData.game_code,
|
||||
s3_folder_name: gameDataStore.gameData.s3_folder_name,
|
||||
default_lang_code: gameDataStore.gameData.default_lang_code || 'ko',
|
||||
lang_codes: gameDataStore.gameData.lang_codes,
|
||||
design_theme: gameDataStore.gameData.design_theme,
|
||||
key_color_codes: gameDataStore.gameData.key_color_codes,
|
||||
use_game_font: gameDataStore.gameData.use_game_font,
|
||||
ga_code: gameDataStore.gameData.ga_code,
|
||||
favicon_path: gameDataStore.gameData.favicon_path,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
})
|
||||
|
||||
// 페이지 메타 설정
|
||||
useHead({
|
||||
title: `언어 테스트 - ${locale.value.toUpperCase()}`,
|
||||
})
|
||||
</script>
|
||||
@@ -4,8 +4,8 @@ import type {
|
||||
ButtonConfig,
|
||||
ButtonProps,
|
||||
} from '#layers/types/components/button'
|
||||
import type { GameDataKeyCodeCodes } from '#layers/types/api/gameData'
|
||||
|
||||
// Props 정의
|
||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
size: 'medium',
|
||||
backgroundColor: 'var(--primary)',
|
||||
@@ -14,6 +14,15 @@ const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
disabled: false,
|
||||
})
|
||||
|
||||
// 색상 코드 키 목록 key_code_codes
|
||||
const PARSED_KEY_CODE_CODES_KEYS: (keyof GameDataKeyCodeCodes)[] = [
|
||||
'primary',
|
||||
'text-primary',
|
||||
'text-secondary',
|
||||
'alternative-01',
|
||||
'alternative-02',
|
||||
]
|
||||
|
||||
// 버튼 크기별 설정 상수
|
||||
const BUTTON_CONFIGS: Record<ButtonSize, ButtonConfig> = {
|
||||
large: {
|
||||
@@ -42,6 +51,12 @@ const BUTTON_CONFIGS: Record<ButtonSize, ButtonConfig> = {
|
||||
},
|
||||
} as const
|
||||
|
||||
// 색상 값을 CSS 변수로 변환하는 헬퍼 함수
|
||||
const getColorValue = (color: string) =>
|
||||
PARSED_KEY_CODE_CODES_KEYS.includes(color as keyof GameDataKeyCodeCodes)
|
||||
? `var(--${color})`
|
||||
: color
|
||||
|
||||
const currentConfig = computed(() => BUTTON_CONFIGS[props.size])
|
||||
const buttonClasses = computed(() => [
|
||||
'group relative inline-flex items-center justify-center font-medium border border-gray-600/30 overflow-hidden',
|
||||
@@ -49,8 +64,8 @@ const buttonClasses = computed(() => [
|
||||
props.disabled ? 'cursor-default' : 'cursor-pointer',
|
||||
])
|
||||
const buttonStyles = computed(() => ({
|
||||
backgroundColor: props.backgroundColor,
|
||||
color: props.textColor,
|
||||
backgroundColor: getColorValue(props.backgroundColor),
|
||||
color: getColorValue(props.textColor),
|
||||
}))
|
||||
const overlayClasses = computed(() => [
|
||||
'absolute inset-0 -m-px transition-opacity duration-200',
|
||||
|
||||
@@ -1,34 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import { templateRegistry } from '#layers/registry'
|
||||
import type {
|
||||
PageDataValue,
|
||||
PageDataTemplate,
|
||||
TemplateComponent,
|
||||
PageDataTemplateComponent,
|
||||
PageDataMetaTag,
|
||||
} from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{ templates: PageDataTemplate[] }>()
|
||||
interface Props {
|
||||
pageData: PageDataValue
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// 템플릿 레지스트리 타입 캐스팅
|
||||
const registry = templateRegistry as unknown as Record<
|
||||
string,
|
||||
{ component: TemplateComponent }
|
||||
{ component: PageDataTemplateComponent }
|
||||
>
|
||||
|
||||
const isShowTemplate = (template: PageDataTemplate) => {
|
||||
// 개별 메타 태그 표시 여부 확인
|
||||
const shouldShowMetaTag = computed(() => props.pageData.meta_tag_type === 2)
|
||||
|
||||
// 템플릿 표시 여부 확인
|
||||
const isTemplateVisible = (template: PageDataTemplate): boolean => {
|
||||
return Boolean(
|
||||
template?.components && Object.keys(template.components ?? {}).length > 0
|
||||
template?.components_ && Object.keys(template.components_).length > 0
|
||||
)
|
||||
}
|
||||
|
||||
// 템플릿 목록 계산
|
||||
const visibleTemplates = computed(() =>
|
||||
Object.values(props.pageData.templates).filter(isTemplateVisible)
|
||||
)
|
||||
|
||||
// SEO 메타 태그 설정
|
||||
const setupSeoMeta = (metaTag: PageDataMetaTag) => {
|
||||
useSeoMeta({
|
||||
title: metaTag.page_title ?? '',
|
||||
description: metaTag.page_desc ?? '',
|
||||
ogTitle: metaTag.og_title ?? '',
|
||||
ogDescription: metaTag.og_desc ?? '',
|
||||
ogImage: metaTag.og_image ?? '',
|
||||
twitterTitle: metaTag.x_title ?? '',
|
||||
twitterImage: metaTag.x_image ?? '',
|
||||
twitterDescription: metaTag.x_desc ?? '',
|
||||
})
|
||||
}
|
||||
|
||||
// 메타 태그 설정 감시
|
||||
watchEffect(() => {
|
||||
if (shouldShowMetaTag.value && props.pageData.meta_tag) {
|
||||
setupSeoMeta(props.pageData.meta_tag)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<template
|
||||
v-for="(template, index) in props.templates"
|
||||
v-for="(template, index) in visibleTemplates"
|
||||
:key="template.template_code ?? index"
|
||||
>
|
||||
<component
|
||||
:is="registry[template.template_code]?.component"
|
||||
v-if="isShowTemplate(template)"
|
||||
:components="template.components"
|
||||
:components="template.components_"
|
||||
/>
|
||||
</template>
|
||||
</main>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { ParsedKeyColorCodes } from '#layers/types/api/gameData'
|
||||
|
||||
/**
|
||||
* 게임 데이터의 key_color_codes를 CSS 커스텀 프로퍼티로 적용하는 기능을 제공합니다.
|
||||
*/
|
||||
export const useGameColors = () => {
|
||||
/**
|
||||
* @param keyColorCodes
|
||||
*/
|
||||
const applyGameColors = (keyColorCodes: ParsedKeyColorCodes | null) => {
|
||||
if (!keyColorCodes || import.meta.server) {
|
||||
return
|
||||
}
|
||||
|
||||
const root = document.documentElement
|
||||
|
||||
Object.entries(keyColorCodes).forEach(([key, value]) => {
|
||||
const cssVarName = `--${key}`
|
||||
root.style.setProperty(cssVarName, String(value))
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
applyGameColors,
|
||||
}
|
||||
}
|
||||
28
layers/composables/useGameKeyCodeColors.ts
Normal file
28
layers/composables/useGameKeyCodeColors.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { GameDataKeyCodeCodes } from '#layers/types/api/gameData'
|
||||
|
||||
/**
|
||||
* 게임 데이터의 key_code_codes를 CSS 커스텀 프로퍼티로 적용하는 기능을 제공합니다.
|
||||
*/
|
||||
export const useGameKeyCodeColors = () => {
|
||||
/**
|
||||
* @param keyColorCodes
|
||||
*/
|
||||
const applyGameKeyCodeColors = (
|
||||
keyColorCodes: GameDataKeyCodeCodes | null
|
||||
) => {
|
||||
if (!keyColorCodes || import.meta.server) {
|
||||
return
|
||||
}
|
||||
|
||||
const root = document.documentElement
|
||||
|
||||
Object.entries(keyColorCodes).forEach(([key, value]) => {
|
||||
const cssVarName = `--${key}`
|
||||
root.style.setProperty(cssVarName, String(value))
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
applyGameKeyCodeColors,
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<LayoutsHeader />
|
||||
<slot />
|
||||
<LayoutsFooter />
|
||||
</div>
|
||||
<LayoutsHeader />
|
||||
<slot />
|
||||
<LayoutsFooter />
|
||||
</template>
|
||||
|
||||
@@ -1,29 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import YouTubeModal from '#layers/components/blocks/modal/YouTube.vue'
|
||||
|
||||
interface Props {
|
||||
components: Record<string, any>
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// YouTube 모달 상태 관리
|
||||
const isYouTubeModalOpen = ref(false)
|
||||
const youtubeVideoId = ref('')
|
||||
|
||||
// 비디오 플레이 버튼 클릭 핸들러
|
||||
const handleVideoPlayClick = () => {
|
||||
// TODO: 실제 YouTube 비디오 ID를 설정해야 합니다
|
||||
// 예시: 'dQw4w9WgXcQ' (Rick Astley - Never Gonna Give You Up)
|
||||
youtubeVideoId.value = 'UKVsZYHxYTc' // 임시로 설정
|
||||
isYouTubeModalOpen.value = true
|
||||
}
|
||||
|
||||
// 모달 닫기 핸들러
|
||||
const handleCloseModal = () => {
|
||||
isYouTubeModalOpen.value = false
|
||||
youtubeVideoId.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -48,16 +28,7 @@ const handleCloseModal = () => {
|
||||
<WidgetsVideoPlay
|
||||
v-if="props.components.videoPlay"
|
||||
:component-data="props.components.videoPlay"
|
||||
@click="handleVideoPlayClick"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- YouTube 모달 -->
|
||||
<YouTubeModal
|
||||
:is-open="isYouTubeModalOpen"
|
||||
:youtube-id="youtubeVideoId"
|
||||
@close="handleCloseModal"
|
||||
@update:is-open="(value: boolean) => (isYouTubeModalOpen = value)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -21,54 +21,93 @@ export interface GameDataValue {
|
||||
game_name: string
|
||||
ga_code: string
|
||||
design_theme: number
|
||||
lang_codes: string // JSON 문자열로 변경
|
||||
key_color_codes: ParsedKeyColorCodes
|
||||
lang_codes: string[]
|
||||
key_code_codes: GameDataKeyCodeCodes
|
||||
use_game_font: boolean
|
||||
comm_sns_bg_color_code: string
|
||||
comm_multilang_filename: string
|
||||
footer_dev_ci_img_yn: boolean
|
||||
footer_dev_ci_img_path: string
|
||||
default_lang_code?: string // 기본 언어 코드 추가
|
||||
game_font: string // JSON 문자열로 변경
|
||||
globals: GameDataGlobal[] // 배열로 변경
|
||||
default_lang_code?: string
|
||||
game_font: GameDataGameFont
|
||||
globals: GameDataGlobal[]
|
||||
gnb: GameDataGnb
|
||||
intro: GameDataIntro
|
||||
inspection: Record<string, any> // 동적 객체
|
||||
stove_gnb: GameDataStoveGnb // JSON 문자열로 변경
|
||||
favicon_path: string // JSON 문자열로 변경
|
||||
meta_tag: string // JSON 문자열로 변경
|
||||
sns: string // JSON 문자열로 변경
|
||||
inspection: Record<string, any>
|
||||
stove_gnb: GameDataStoveGnb
|
||||
favicon_path: GameDataFaviconPath
|
||||
meta_tag: GameDataMetaTag
|
||||
sns: GameDataSns
|
||||
footer: string // JSON 문자열로 변경
|
||||
}
|
||||
|
||||
// ===== 세부 데이터 타입들 =====
|
||||
|
||||
// 키 코드 코드 타입
|
||||
export interface GameDataKeyCodeCodes {
|
||||
primary: string
|
||||
'text-primary': string
|
||||
'text-secondary': string
|
||||
'alternative-01': string
|
||||
'alternative-02': string
|
||||
}
|
||||
|
||||
// 게임 폰트 타입
|
||||
export interface GameDataGameFont {
|
||||
font_family: string
|
||||
font_weight: string
|
||||
font_style: string
|
||||
}
|
||||
|
||||
// 파비콘 경로 타입
|
||||
export interface GameDataFaviconPath {
|
||||
'16_16': string
|
||||
'32_32': string
|
||||
'72_72': string
|
||||
'180_180': string
|
||||
'192_192': string
|
||||
}
|
||||
|
||||
// 메타 태그 타입
|
||||
export interface GameDataMetaTag {
|
||||
x_desc: string
|
||||
og_desc: string
|
||||
x_image: string
|
||||
x_title: string
|
||||
og_image: string
|
||||
og_title: string
|
||||
page_desc: string
|
||||
page_title: string
|
||||
}
|
||||
|
||||
// SNS 아이템 타입
|
||||
export interface GameDataSnsItem {
|
||||
use_yn: number
|
||||
url: string | null
|
||||
}
|
||||
|
||||
// SNS 설정 타입
|
||||
export interface GameDataSns {
|
||||
kakao: GameDataSnsItem
|
||||
twitter: GameDataSnsItem
|
||||
discord: GameDataSnsItem
|
||||
youtube: GameDataSnsItem
|
||||
instagram: GameDataSnsItem
|
||||
facebook: GameDataSnsItem
|
||||
tiktok: GameDataSnsItem
|
||||
}
|
||||
|
||||
// Global 설정 타입
|
||||
export interface GameDataGlobal {
|
||||
system_font: string // JSON 문자열로 변경
|
||||
lang: string // JSON 문자열로 변경
|
||||
}
|
||||
|
||||
// 폰트 타입
|
||||
export interface GameDataFont {
|
||||
'font-family': string
|
||||
}
|
||||
|
||||
// 언어 설정 타입
|
||||
export interface GameDataLang {
|
||||
dir: string
|
||||
iso: string
|
||||
code: string
|
||||
name: string
|
||||
}
|
||||
|
||||
// GNB 설정 타입
|
||||
export interface GameDataGnb {
|
||||
game_gnb_ver: string
|
||||
display_start_dt: string // ISO 문자열로 변경
|
||||
theme_type: string
|
||||
bi_path: string
|
||||
lang_codes: string // JSON 문자열로 변경
|
||||
buttons: GameDataButton[]
|
||||
menus: Record<string, GameDataMenu> // 동적 객체로 변경
|
||||
// 트래킹 타입
|
||||
export interface GameDataTracking {
|
||||
viewType: string
|
||||
actionType: string
|
||||
clickSarea: string
|
||||
}
|
||||
|
||||
// 버튼 타입
|
||||
@@ -90,35 +129,22 @@ export interface GameDataMenu {
|
||||
tracking: string | GameDataTracking // JSON 문자열 또는 객체로 변경
|
||||
}
|
||||
|
||||
// GNB 설정 타입
|
||||
export interface GameDataGnb {
|
||||
game_gnb_ver: string
|
||||
theme_type: string
|
||||
bi_path: string
|
||||
lang_codes: string // JSON 문자열로 변경
|
||||
buttons: GameDataButton[]
|
||||
menus: Record<string, GameDataMenu> // 동적 객체로 변경
|
||||
}
|
||||
|
||||
// 인트로 타입
|
||||
export interface GameDataIntro {
|
||||
seq: number
|
||||
display_start_dt: string
|
||||
display_end_dt: string
|
||||
page_url: string
|
||||
}
|
||||
|
||||
// 트래킹 타입
|
||||
export interface GameDataTracking {
|
||||
viewType: string
|
||||
actionType: string
|
||||
clickSarea: string
|
||||
}
|
||||
|
||||
// 퀵 메뉴 타입
|
||||
export interface GameDataQuickMenu {
|
||||
banner_seq: number
|
||||
promotion_name: string
|
||||
thumbnail: string
|
||||
page_url_type: number
|
||||
page_url: string
|
||||
link_type: number
|
||||
display_start_dt: string
|
||||
display_end_dt: string
|
||||
sort_order: number
|
||||
banner_title: string
|
||||
}
|
||||
|
||||
// Stove GNB Skin Type
|
||||
export type StoveGnbSkinType =
|
||||
| 'gnb-default'
|
||||
@@ -136,103 +162,7 @@ export interface GameDataStoveGnb {
|
||||
stove_install_button_visible: string
|
||||
}
|
||||
|
||||
// 파비콘 경로 타입
|
||||
export interface GameDataFaviconPath {
|
||||
'16_16': string
|
||||
'32_32': string
|
||||
'72_72': string
|
||||
'180_180': string
|
||||
'192_192': string
|
||||
}
|
||||
|
||||
// 공통 이미지 타입
|
||||
export interface GameDataCommImg {
|
||||
groups: GameDataCommImgGroup[]
|
||||
}
|
||||
|
||||
// 공통 이미지 그룹 타입
|
||||
export interface GameDataCommImgGroup {
|
||||
img_path: GameDataImgPath
|
||||
required: boolean
|
||||
img_scope: string
|
||||
group_code: string
|
||||
group_label: string
|
||||
}
|
||||
|
||||
// 이미지 경로 타입
|
||||
export interface GameDataImgPath {
|
||||
comm: string
|
||||
}
|
||||
|
||||
// 메타 태그 타입
|
||||
export interface GameDataMetaTag {
|
||||
x_desc: string
|
||||
og_desc: string
|
||||
x_image: string
|
||||
x_title: string
|
||||
og_image: string
|
||||
og_title: string
|
||||
page_desc: string
|
||||
page_title: string
|
||||
}
|
||||
|
||||
// YouTube 설정 타입
|
||||
export interface GameDataYoutube {
|
||||
use_yn: number
|
||||
api_key: string
|
||||
}
|
||||
|
||||
// SNS 설정 타입
|
||||
export interface GameDataSns {
|
||||
kakao: GameDataSnsItem
|
||||
tiktok: GameDataSnsItem
|
||||
discord: GameDataSnsItem
|
||||
twitter: GameDataSnsItem
|
||||
youtube: GameDataSnsItem
|
||||
facebook: GameDataSnsItem
|
||||
instagram: GameDataSnsItem
|
||||
}
|
||||
|
||||
// SNS 아이템 타입
|
||||
export interface GameDataSnsItem {
|
||||
url: string | null
|
||||
use_yn: number
|
||||
}
|
||||
|
||||
// 마켓 설정 타입
|
||||
export interface GameDataMarket {
|
||||
pc: GameDataMarketItem
|
||||
app_store: GameDataMarketItem
|
||||
google_play: GameDataMarketItem
|
||||
}
|
||||
|
||||
// 마켓 아이템 타입
|
||||
export interface GameDataMarketItem {
|
||||
url: string | null
|
||||
use_yn: number
|
||||
}
|
||||
|
||||
// 푸터 설정 타입
|
||||
export interface GameDataFooter {
|
||||
dev_ci_url: string
|
||||
use_dev_ci_url: boolean
|
||||
fund_display_yn: boolean
|
||||
use_game_rating: boolean
|
||||
fund_display_url: string
|
||||
game_rating_info: GameDataGameRatingInfo
|
||||
}
|
||||
|
||||
// 게임 등급 정보 타입
|
||||
export interface GameDataGameRatingInfo {
|
||||
title: string
|
||||
reg_no: string
|
||||
prod_date: string
|
||||
rating_type: string
|
||||
company_name: string
|
||||
content_info: string
|
||||
rating_grade: string
|
||||
rating_class_no: string
|
||||
}
|
||||
// ===== API 관련 타입들 =====
|
||||
|
||||
// API 에러 응답 타입
|
||||
export interface GameDataErrorResponse {
|
||||
@@ -262,70 +192,3 @@ export interface GameDataApiResult {
|
||||
data: GameDataResponse | null
|
||||
error: string | null
|
||||
}
|
||||
|
||||
// JSON 문자열 파싱을 위한 유틸리티 타입들
|
||||
export interface ParsedKeyColorCodes {
|
||||
'alternative-01': string
|
||||
'alternative-02': string
|
||||
primary: string
|
||||
'text-primary': string
|
||||
'text-secondary': string
|
||||
}
|
||||
|
||||
export interface ParsedGameFont {
|
||||
'font-family': string
|
||||
}
|
||||
|
||||
export interface ParsedGlobal {
|
||||
system_font: ParsedGameFont
|
||||
lang: GameDataLang
|
||||
}
|
||||
|
||||
export interface ParsedButton {
|
||||
google_play: {
|
||||
label: Record<string, string>
|
||||
url: string
|
||||
tracking: GameDataTracking
|
||||
}
|
||||
app_store: {
|
||||
label: Record<string, string>
|
||||
url: string
|
||||
tracking: GameDataTracking
|
||||
}
|
||||
}
|
||||
|
||||
export interface ParsedStoveGnb {
|
||||
skin_type: StoveGnbSkinType
|
||||
stove_install_button_visible: string
|
||||
}
|
||||
|
||||
export interface ParsedSns {
|
||||
kakao: GameDataSnsItem
|
||||
twitter: GameDataSnsItem
|
||||
discord: GameDataSnsItem
|
||||
youtube: GameDataSnsItem
|
||||
instagram: GameDataSnsItem
|
||||
facebook: GameDataSnsItem
|
||||
tiktok: GameDataSnsItem
|
||||
}
|
||||
|
||||
export interface ParsedFooter {
|
||||
use_game_rating: boolean
|
||||
game_rating_info: GameDataGameRatingInfo
|
||||
use_dev_ci_url: boolean
|
||||
dev_ci_url: string
|
||||
fund_display_yn: boolean
|
||||
fund_display_url: string
|
||||
}
|
||||
|
||||
// 파비콘 경로 파싱 타입
|
||||
export interface ParsedFaviconPath {
|
||||
'16_16': string
|
||||
'32_32': string
|
||||
'72_72': string
|
||||
'180_180': string
|
||||
'192_192': string
|
||||
}
|
||||
|
||||
// 기존 gameData 타입과의 호환성을 위한 별칭
|
||||
export type gameData = GameDataValue
|
||||
|
||||
@@ -28,19 +28,20 @@ export interface PageDataValue {
|
||||
page_name: string
|
||||
page_name_en: string
|
||||
page_ver: number
|
||||
display_start_dt: string
|
||||
lang_codes: string // JSON string
|
||||
is_login_required: boolean
|
||||
meta_tag_type: number
|
||||
fit_page_height: boolean
|
||||
use_top_btn: boolean
|
||||
use_sns_btn: boolean
|
||||
use_lnb: boolean
|
||||
lnb_text_color_code_active: string
|
||||
lnb_text_color_code_deactive: string
|
||||
lnb_menus: PageDataLnbMenu[]
|
||||
templates: PageDataTemplate[]
|
||||
meta_tag: PageDataMetaTag // JSON string
|
||||
templates: Record<string, PageDataTemplate>
|
||||
meta_tag: PageDataMetaTag
|
||||
}
|
||||
|
||||
// ===== 세부 데이터 타입들 =====
|
||||
|
||||
// 메타 태그 타입
|
||||
export interface PageDataMetaTag {
|
||||
x_desc: string
|
||||
@@ -53,10 +54,22 @@ export interface PageDataMetaTag {
|
||||
page_title: string
|
||||
}
|
||||
|
||||
// 리소스 타입
|
||||
export interface PageDataResource {
|
||||
resource_sort_order: number
|
||||
resource_name: string
|
||||
resource_type: string
|
||||
groups: Record<string, any>
|
||||
group_sets: Record<string, any>
|
||||
}
|
||||
|
||||
// 컴포넌트 타입
|
||||
export interface PageDataComponent {
|
||||
resources: PageDataResource[]
|
||||
}
|
||||
|
||||
// LNB 메뉴 타입
|
||||
export interface PageDataLnbMenu {
|
||||
text_color_code_active: string
|
||||
text_color_code_deactive: string
|
||||
path_code: string
|
||||
depth: number
|
||||
sort_order: number
|
||||
@@ -68,72 +81,21 @@ export interface PageDataLnbMenu {
|
||||
|
||||
// 템플릿 타입
|
||||
export interface PageDataTemplate {
|
||||
page_ver_tmpl_seq: number
|
||||
tmpl_sort_order: number
|
||||
page_ver_tmpl_name: string
|
||||
page_ver_tmpl_name_en: string
|
||||
template_code: string
|
||||
components_: PageDataTemplateComponent
|
||||
// components: string // JSON string
|
||||
}
|
||||
|
||||
// 템플릿 컴포넌트 타입
|
||||
export interface PageDataTemplateComponent {
|
||||
components: Record<string, PageDataComponent>
|
||||
}
|
||||
|
||||
// 컴포넌트 타입
|
||||
export interface PageDataComponent {
|
||||
component_sort_order: number
|
||||
set_count: number
|
||||
component_name: string
|
||||
has_operational_resource: boolean
|
||||
resources: PageDataResource[]
|
||||
list_resources: PageDataListResource[]
|
||||
flag_resources: PageDataFlagResource[]
|
||||
}
|
||||
|
||||
// 리소스 타입
|
||||
export interface PageDataResource {
|
||||
resource_sort_order: number
|
||||
resource_name: string
|
||||
resource_type: string
|
||||
groups: Record<string, any>
|
||||
group_sets: Record<string, any>
|
||||
}
|
||||
|
||||
// 리스트 리소스 타입
|
||||
export interface PageDataListResource {
|
||||
seq: number
|
||||
title: string
|
||||
img_path: string
|
||||
url: string
|
||||
link_target: string
|
||||
display_start_dt: string
|
||||
display_end_dt: string
|
||||
is_display_status: number
|
||||
display_status: number
|
||||
option01: number
|
||||
option02: number
|
||||
option03: string
|
||||
}
|
||||
|
||||
// 플래그 리소스 타입
|
||||
export interface PageDataFlagResource {
|
||||
seq: number
|
||||
flag_type: number
|
||||
option01: number
|
||||
option02: number
|
||||
option03: string
|
||||
}
|
||||
|
||||
// 운영 리소스 타입 (기존 호환성 유지)
|
||||
export interface PageDataOperateResource {
|
||||
seq: number
|
||||
col: string
|
||||
col2: string
|
||||
col3: string
|
||||
col4: string
|
||||
col5: string
|
||||
col6: string
|
||||
col7: string
|
||||
resource_control_type: number
|
||||
resource_type: string
|
||||
[key: string]: any // Additional Properties
|
||||
}
|
||||
// ===== API 관련 타입들 =====
|
||||
|
||||
// API 에러 응답 타입
|
||||
export interface PageDataErrorResponse {
|
||||
@@ -165,11 +127,3 @@ export interface PageDataApiResult {
|
||||
data: PageDataResponse | null
|
||||
error: string | null
|
||||
}
|
||||
|
||||
// 페이지 데이터 별칭 (기존 호환성)
|
||||
export type pageData = PageDataValue
|
||||
|
||||
// Vue 컴포넌트 타입 정의
|
||||
export interface TemplateComponent {
|
||||
components: Record<string, PageDataComponent>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user