From 7130313bfca57bb5b12a5fb8f5d752f7e2831eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chyeonggkim=E2=80=9D?= <“hyeonggkim@smilegate.com”> Date: Tue, 4 Nov 2025 19:19:58 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor:=20i18n=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i18n/locales/de.ts | 44 ++++---- i18n/locales/en.ts | 44 ++++---- i18n/locales/es.ts | 44 ++++---- i18n/locales/fr.ts | 44 ++++---- i18n/locales/ja.ts | 44 ++++---- i18n/locales/ko.ts | 29 +++-- i18n/locales/pt.ts | 44 ++++---- i18n/locales/th.ts | 44 ++++---- i18n/locales/zh-cn.ts | 47 ++++---- i18n/locales/zh-tw.ts | 29 +++-- layers/components/layouts/Footer.vue | 158 ++++++++++----------------- 11 files changed, 263 insertions(+), 308 deletions(-) diff --git a/i18n/locales/de.ts b/i18n/locales/de.ts index e7f3c28..ae011fa 100644 --- a/i18n/locales/de.ts +++ b/i18n/locales/de.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/de' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['de'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/en.ts b/i18n/locales/en.ts index e7f3c28..c575f26 100644 --- a/i18n/locales/en.ts +++ b/i18n/locales/en.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/en' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['en'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/es.ts b/i18n/locales/es.ts index e7f3c28..af54510 100644 --- a/i18n/locales/es.ts +++ b/i18n/locales/es.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/es' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['es'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/fr.ts b/i18n/locales/fr.ts index e7f3c28..1d9e195 100644 --- a/i18n/locales/fr.ts +++ b/i18n/locales/fr.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/fr' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['fr'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/ja.ts b/i18n/locales/ja.ts index e7f3c28..5f22c6b 100644 --- a/i18n/locales/ja.ts +++ b/i18n/locales/ja.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/ja' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['ja'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/ko.ts b/i18n/locales/ko.ts index 9f08531..c73dcde 100644 --- a/i18n/locales/ko.ts +++ b/i18n/locales/ko.ts @@ -1,17 +1,24 @@ +import fallback from './fallback/ko' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const result = (await commonFetch('GET', `${translationApi}`)) as any - if(import.meta.client) { - console.log("🚀 ~ result:", result[locale]) + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, + }) + + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['ko'] || {} + return localeData } - return result[locale] + + return {} } catch (e) { console.error('[Exception] ko.defineI18nLocale: ', e) return fallback diff --git a/i18n/locales/pt.ts b/i18n/locales/pt.ts index e7f3c28..0d969ce 100644 --- a/i18n/locales/pt.ts +++ b/i18n/locales/pt.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/pt' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['pt'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/th.ts b/i18n/locales/th.ts index e7f3c28..fa815ee 100644 --- a/i18n/locales/th.ts +++ b/i18n/locales/th.ts @@ -1,29 +1,27 @@ +import fallback from './fallback/th' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['th'] || {} + return localeData + } + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/zh-cn.ts b/i18n/locales/zh-cn.ts index 1f3ef75..67ff6a9 100644 --- a/i18n/locales/zh-cn.ts +++ b/i18n/locales/zh-cn.ts @@ -1,34 +1,27 @@ +import fallback from './fallback/zh-cn' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const { data } = await useFetch(translationApi, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, }) - - if(locale === 'zh-cn') { - locale = 'zh-CN' + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['zh-cn'] || {} + return localeData } - - // API 데이터에서 locale에 맞는 데이터를 추출 - const apiData = data.value?.[locale] || {} // locale에 맞는 데이터가 없으면 빈 객체 반환 - - // API 데이터와 common.json 데이터를 병합 (common.json이 우선순위) - const finalResult = { ...apiData } - - return finalResult - } catch (error) { - console.error('Error fetching translation data:', error) - // 에러 발생 시 common.json 데이터라도 반환 - return commonData[locale] || {} + + return {} + } catch (e) { + console.error('[Exception] ko.defineI18nLocale: ', e) + return fallback } }) + diff --git a/i18n/locales/zh-tw.ts b/i18n/locales/zh-tw.ts index 9f08531..1a9c011 100644 --- a/i18n/locales/zh-tw.ts +++ b/i18n/locales/zh-tw.ts @@ -1,17 +1,24 @@ +import fallback from './fallback/zh-tw' + export default defineI18nLocale(async (locale: string) => { - //https://static-pubcomm.gate8.com/dev/test/multilingual/test_common_template.json?20251021185116 - const config = useRuntimeConfig() - const rootPath = config.public.staticUrl - const runType = config.public.runType - - const translationApi = `${rootPath}/${runType}/test/multilingual/test_common_template.json` - + const runtimeConfig = useRuntimeConfig() + const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string + const multilingualFileName = 'test_common_template.json' try { - const result = (await commonFetch('GET', `${translationApi}`)) as any - if(import.meta.client) { - console.log("🚀 ~ result:", result[locale]) + const resultGetMultilingual = await useGetMultilingual({ + baseApiUrl: dataResourcesUrl, + fileName: multilingualFileName, + }) + + // multilingual 객체에서 현재 locale에 해당하는 데이터 추출 + const multilingualData = resultGetMultilingual?.value?.multilingual + if (multilingualData && typeof multilingualData === 'object') { + // locale이 'ko'이므로 'ko' 키의 데이터를 반환 + const localeData = multilingualData[locale] || multilingualData['zh-tw'] || {} + return localeData } - return result[locale] + + return {} } catch (e) { console.error('[Exception] ko.defineI18nLocale: ', e) return fallback diff --git a/layers/components/layouts/Footer.vue b/layers/components/layouts/Footer.vue index 936d456..b87b21a 100644 --- a/layers/components/layouts/Footer.vue +++ b/layers/components/layouts/Footer.vue @@ -1,20 +1,20 @@ @@ -141,20 +138,20 @@ From 28cae8c18ba1151496df1eeecea8698b4412b4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chyeonggkim=E2=80=9D?= <“hyeonggkim@smilegate.com”> Date: Tue, 4 Nov 2025 21:01:18 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=20=EB=B3=B4=EC=95=88=EA=B0=95?= =?UTF-8?q?=ED=99=94=20FxSecure01=20=EC=9E=91=EC=97=85=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- layers/composables/useTemplateRegistry.ts | 2 + layers/templates/FxSecure01/index.vue | 257 ++++++++++++++++++++++ public/images/common/img_OTP.png | Bin 0 -> 6975 bytes 3 files changed, 259 insertions(+) create mode 100644 layers/templates/FxSecure01/index.vue create mode 100644 public/images/common/img_OTP.png diff --git a/layers/composables/useTemplateRegistry.ts b/layers/composables/useTemplateRegistry.ts index 61e93bd..4396f48 100644 --- a/layers/composables/useTemplateRegistry.ts +++ b/layers/composables/useTemplateRegistry.ts @@ -10,6 +10,7 @@ import GrDetail03 from '#layers/templates/GrDetail03/index.vue' import GrBoard01 from '#layers/templates/GrBoard01/index.vue' import GrContents01 from '#layers/templates/GrContents01/index.vue' import FxDownload01 from '#layers/templates/FxDownload01/index.vue' +import FxSecure01 from '#layers/templates/FxSecure01/index.vue' const templateRegistry = { GR_VISUAL_01: { component: GrVisual01 }, @@ -24,6 +25,7 @@ const templateRegistry = { GR_DETAIL_03: { component: GrDetail03 }, GR_CONTENTS_01: { component: GrContents01 }, FX_DOWNLOAD_01: { component: FxDownload01 }, + FX_SECURE_01: { component: FxSecure01 }, } as const type TemplateKey = keyof typeof templateRegistry diff --git a/layers/templates/FxSecure01/index.vue b/layers/templates/FxSecure01/index.vue new file mode 100644 index 0000000..5632d27 --- /dev/null +++ b/layers/templates/FxSecure01/index.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/public/images/common/img_OTP.png b/public/images/common/img_OTP.png new file mode 100644 index 0000000000000000000000000000000000000000..22ef70bf594fb1c1f04aac155c2280a16dc7758a GIT binary patch literal 6975 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 literal 0 HcmV?d00001 From 940a495cbe8ca190c62301b6581145a9c6dc9837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chyeonggkim=E2=80=9D?= <“hyeonggkim@smilegate.com”> Date: Thu, 6 Nov 2025 10:49:47 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=86=B1GNB=20theme?= =?UTF-8?q?=20=EC=88=98=EC=A0=95,=20=EC=96=B8=EC=96=B4=20=EC=A0=95?= =?UTF-8?q?=EC=B1=85=20=EC=88=98=EC=A0=95,=20=EB=B3=B4=EC=95=88=EA=B0=95?= =?UTF-8?q?=ED=99=94=ED=8E=98=EC=9D=B4=EC=A7=80=20API=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- layers/components/blocks/StoveGnbNew.vue | 4 +- layers/composables/useApiData.ts | 22 -- layers/composables/useGetGameDataExternal.ts | 4 +- layers/composables/useSecure.ts | 44 +++ layers/middleware/inspection.ts | 6 +- layers/middleware/pageData.global.ts | 14 +- layers/server/middleware/gameData.ts | 74 +++-- layers/templates/FxSecure01/index.vue | 182 ++++++++---- layers/utils/localeUtil.ts | 38 ++- temp/middleware.ts | 286 ------------------- 10 files changed, 258 insertions(+), 416 deletions(-) delete mode 100644 layers/composables/useApiData.ts create mode 100644 layers/composables/useSecure.ts delete mode 100644 temp/middleware.ts diff --git a/layers/components/blocks/StoveGnbNew.vue b/layers/components/blocks/StoveGnbNew.vue index 60b31e6..694e30b 100644 --- a/layers/components/blocks/StoveGnbNew.vue +++ b/layers/components/blocks/StoveGnbNew.vue @@ -8,6 +8,7 @@ onMounted(() => { const langCodes = gameData?.lang_codes const defaultLangCode = gameData?.default_lang_code const stoveGnbData = gameData?.stove_gnb_json + const designTheme = gameData?.design_theme const currentDomain = window.location.protocol + '//' + window.location.hostname @@ -39,10 +40,11 @@ onMounted(() => { mode: { theme: { default: - stoveGnbData?.skin_type === 'gnb-dark-mini' ? 'dark' : 'light', + designTheme === 1 ? 'light' : 'dark', support: ['dark', 'light'], }, mini: true, + layout: 'wide', fixed: false, }, }) diff --git a/layers/composables/useApiData.ts b/layers/composables/useApiData.ts deleted file mode 100644 index cc5277c..0000000 --- a/layers/composables/useApiData.ts +++ /dev/null @@ -1,22 +0,0 @@ - -interface ReqApiData { - baseApiUrl: string - url: string - } - - export const useApiData = async (req: ReqApiData): Promise => { - const dataUrl = `${req.baseApiUrl}/${req.url}` // 정상 URL 경로 - try { - const fetch = await $fetch(dataUrl, { - method: 'GET', - headers: { - 'Content-Type': 'application/json;charset=UTF-8' - } - }) - return fetch - } catch (error) { - console.log('error', error) - return [] - } - } - \ No newline at end of file diff --git a/layers/composables/useGetGameDataExternal.ts b/layers/composables/useGetGameDataExternal.ts index 63bc0fb..b06de02 100644 --- a/layers/composables/useGetGameDataExternal.ts +++ b/layers/composables/useGetGameDataExternal.ts @@ -12,8 +12,8 @@ export const useGetGameDataExternal = () => { console.log("🚀 ~ getGameDataExternal ~ req:", req) // const config = useRuntimeConfig() const config = useRuntimeConfig() - const stoveApiUrl = `${config.public.stoveApiUrl}` - const apiUrl = `${stoveApiUrl}/pub-comm/v1.0/template/game?game_domain=${req.gameDomain}&lang_code=${req.langCode}` + const stoveApiBaseUrl = config.public.stoveApiUrl + const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/game?game_domain=${req.gameDomain}&lang_code=${req.langCode}` try { const response = (await commonFetch('GET', apiUrl)) as GameDataResponse diff --git a/layers/composables/useSecure.ts b/layers/composables/useSecure.ts new file mode 100644 index 0000000..1d6f8fe --- /dev/null +++ b/layers/composables/useSecure.ts @@ -0,0 +1,44 @@ +/** + * [보안 캠페인] 보안 캠페인 - 회원 보안 설정 정보 조회 + */ +export const getSecuritySetting = async (accessToken: string) => { + const config = useRuntimeConfig() + const stoveApiBaseUrl = config.public.stoveApiUrl + const apiBase = `${stoveApiBaseUrl}/auth-secure/v1.0` + const headers = { + 'caller-id': String(config.public.stoveCallerId), + Authorization: `Bearer ${accessToken}`, + 'Content-Type': 'application/json;charset=UTF-8' + } + + try { + return await commonFetch('GET', `${apiBase}/security/setting`, { headers }) + } catch (error) { + console.error(error) + return null + } +} + +// 로그인 모달 표시 +const showLoginModal = () => { + modalStore.handleOpenConfirm({ + contentText: '로그인이 필요합니다.', + confirmButtonText: '스토브 로그인', + modalName: 'modal-login', + confirmButtonEvent: () => { + csrGoStoveLogin() + }, + }) +} + +// 토큰 유효성 체크 +const { validateToken } = useTokenValidation() +const validateTokenResult = await validateToken(accessTokenSub.value || '') + +// 토큰 유효성 체크 실패 시 로그인 모달 표시 +if (!validateTokenResult) { + showLoginModal() + isProcessing.value = false + return +} + diff --git a/layers/middleware/inspection.ts b/layers/middleware/inspection.ts index 21e6936..36ccf8d 100644 --- a/layers/middleware/inspection.ts +++ b/layers/middleware/inspection.ts @@ -7,8 +7,8 @@ export default defineNuxtRouteMiddleware(async (to) => { const config = useRuntimeConfig() // const baseDomain = `${config.public.baseDomain}` - const stoveApiUrl = `${config.public.stoveApiUrl}` - const stoveGameId = `${gameData.value.game_id}` + const stoveApiBaseUrl = config.public.stoveApiUrl + const stoveGameId = gameData.value.game_id // const stoveMaintenanceApiUrl = `${config.public.stoveMaintenanceApiUrl}` // const localeCookie = useCookie('LOCALE', { @@ -20,7 +20,7 @@ export default defineNuxtRouteMiddleware(async (to) => { // 웹 점검 ----- const { isWebInspection, getInspectionDataExternal } = useGetInspectionDataExternal() - await getInspectionDataExternal({ baseApiUrl: stoveApiUrl, gameId: stoveGameId }) + await getInspectionDataExternal({ baseApiUrl: stoveApiBaseUrl, gameId: stoveGameId }) // 게임 점검 ----- diff --git a/layers/middleware/pageData.global.ts b/layers/middleware/pageData.global.ts index fae74cd..795261a 100644 --- a/layers/middleware/pageData.global.ts +++ b/layers/middleware/pageData.global.ts @@ -3,17 +3,25 @@ import { usePageDataStore } from '#layers/stores/usePageDataStore' import { useGetGameDomain } from '#layers/composables/useGetGameDomain' import { usePathResolver } from '#layers/composables/usePathResolver' import type { PageDataResponse } from '#layers/types/api/pageData' +import type { + GameDataValue, +} from '#layers/types/api/gameData' export default defineNuxtRouteMiddleware(async (to, _from) => { + if (!import.meta.client) return + const config = useRuntimeConfig() + const stoveApiBaseUrl = config.public.stoveApiUrl + const apiUrl = `${stoveApiBaseUrl}/pub-comm/v2.0/template/page` + const store = usePageDataStore() const gameDomain = useGetGameDomain() const { getPathAfterLanguage } = usePathResolver() const headers = useRequestHeaders() - const langCode = ssrGetFinalLocale(to.path, headers) + const gameDataStore = useGameDataStore() + const gameData = gameDataStore.gameData as GameDataValue - const stoveApiBaseUrl = config.public.stoveApiUrl - const apiUrl = `${stoveApiBaseUrl}/pub-comm/v2.0/template/page` + const langCode = ssrGetFinalLocale(to.path, headers, gameData?.lang_codes, gameData?.default_lang_code) try { if(to.path.includes('inspection')) { diff --git a/layers/server/middleware/gameData.ts b/layers/server/middleware/gameData.ts index 87a96be..47d2399 100644 --- a/layers/server/middleware/gameData.ts +++ b/layers/server/middleware/gameData.ts @@ -3,7 +3,6 @@ import { getHeader, getRequestHost, defineEventHandler, - getRequestURL, } from 'h3' import { ssrGetFinalLocale } from '../../utils/localeUtil' import type { GameDataResponse } from '../../types/api/gameData' @@ -123,10 +122,7 @@ function fnLocaleMiddleware(event: any, finalLocale: string) { export default defineEventHandler(async event => { - const config = useRuntimeConfig() // const runType = `${config.public.runType}` - const iBaseApiUrl = `${config.public.stoveApiUrlServer}` - const baseDomain = `${config.public.baseDomain}` // console.log("🚀 ~ baseDomain:", config.public.baseDomain) // const url = getRequestURL(event) @@ -147,6 +143,45 @@ export default defineEventHandler(async event => { // } // } + const config = useRuntimeConfig() + const iBaseApiUrl = `${config.public.stoveApiUrlServer}` + const baseDomain = `${config.public.baseDomain}` + const stoveApiUrlBaseServer = config.public.stoveApiUrlServer + const apiUrl = `${stoveApiUrlBaseServer}/pub-comm/v1.0/template/game` + + const initGameData: GameDataResponse | null = null + let initLangCodes: string[] | null = null + let finalLocale + let cleanHost + let initDefaultLocale + + const host = + (getHeader(event, 'host') || getRequestHost(event)).toString() || '' + const isGameDomainExtractable = host.includes(baseDomain) + + if (isGameDomainExtractable) { + cleanHost = host.split(':')[0] + event.context.gameDomain = cleanHost + } + + try { + + const queryParams: Record = { + game_domain: cleanHost || '', + lang_code: '', + } + const initResponse = (await $fetch(apiUrl, { + query: queryParams, + })) as GameDataResponse | 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) + } catch (error) { + console.error('init gameData load error:', error) + } + const fullPath = event.path // 1-1. 정적 파일 패스 @@ -157,8 +192,8 @@ export default defineEventHandler(async event => { // 1-2. /inspection 패스 if (fullPath.includes('/inspection')) { // 리턴 되기 전 언어 쿠키 세팅 - // const finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers) - // setFinalLocaleCookie(event, finalLocale, baseDomain) + finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers, initLangCodes, initDefaultLocale) + setFinalLocaleCookie(event, finalLocale, baseDomain) return } @@ -178,30 +213,16 @@ export default defineEventHandler(async event => { const cacheKey = 'inspection' // console.log("🚀 11111 ~ cacheKey:", cacheKey) - const host = - (getHeader(event, 'host') || getRequestHost(event)).toString() || '' - const isGameDomainExtractable = host.includes(baseDomain) - - if (isGameDomainExtractable) { - const cleanHost = host.split(':')[0] - event.context.gameDomain = cleanHost - } // gameData를 직접 가져와서 context에 저장 (API 호출 없이) try { - const config = useRuntimeConfig() - const stoveApiUrlServer = config.public.stoveApiUrlServer - const apiUrl = `${stoveApiUrlServer}/pub-comm/v1.0/template/game` - // console.log("🚀 ~ apiUrl:", apiUrl) - // 2. 언어 코드 추출 - // const finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers) - - const finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers) + finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers, initLangCodes, initDefaultLocale) + console.log("🚀 222 finalLocale:", finalLocale) const queryParams: Record = { - game_domain: event.context.gameDomain || '', + game_domain: cleanHost || '', lang_code: finalLocale, } const response = (await $fetch(apiUrl, { @@ -209,10 +230,9 @@ export default defineEventHandler(async event => { })) as GameDataResponse | null // 언어패스 쿠키 굽기 - 장기방안에서는 굽지않음 - // const langCoverages = response?.value?.lang_codes || [] - // if(langCoverages.includes(finalLocale)) { - // setFinalLocaleCookie(event, finalLocale, baseDomain) - // } + if(initLangCodes?.includes(finalLocale)) { + setFinalLocaleCookie(event, finalLocale, baseDomain) + } diff --git a/layers/templates/FxSecure01/index.vue b/layers/templates/FxSecure01/index.vue index 5632d27..a7f2d8b 100644 --- a/layers/templates/FxSecure01/index.vue +++ b/layers/templates/FxSecure01/index.vue @@ -9,6 +9,7 @@ interface Props { pageVerTmplSeq: number } const props = defineProps() +const modalStore = useModalStore() // Configuration const runtimeConfig = useRuntimeConfig() @@ -25,36 +26,73 @@ const { tm }: any = useI18n({ messages: Object(resultGetMultilingual?.value?.multilingual), }) +const secureSetting = ref({ + otpLoginYn: 'N', + abroadLoginBlockYn: 'N', + pcRegisterYn: 'N' +}) + // Functions -const handleSecureSetting = (_cardId: string) => { - // TODO: 보안 설정 페이지로 이동하거나 설정 로직 구현 - // 예: window.open('https://stove.kr/security', '_blank') +const handleSecureSetting = (url: string) => { + window.open(url, '_blank') +} + +// 회원 보안 설정 조회 +const fnGetSecuritySetting = async () => { + try { + const accessToken = csrGetAccessToken() ?? '' + const result = (await getSecuritySetting(accessToken)) as { code: number; message: string; value: any[] } + console.log("🚀 ~ fnGetSecuritySetting ~ result:", result) + + if (result?.code === 0 && Array.isArray(result.value)) { + const arrSecure = result.value + const getValue = (key: string) => arrSecure.find((f: any) => f.key === key)?.value ?? 'N' + + secureSetting.value = { + otpLoginYn: getValue('OTP_LOGIN_YN'), + abroadLoginBlockYn: getValue('ABROAD_LOGIN_BLOCK_YN'), + pcRegisterYn: getValue('PC_REGISTER_YN') + } + } else { + secureSetting.value = { + otpLoginYn: 'N', + abroadLoginBlockYn: 'N', + pcRegisterYn: 'N' + } + } + } catch (e) { + console.error(e) + secureSetting.value = { + otpLoginYn: 'N', + abroadLoginBlockYn: 'N', + pcRegisterYn: 'N' + } + } } // Data const backgroundData = computed(() => getComponentGroup(props.components, 'background') ) -console.log("🚀 ~ backgroundData:", backgroundData) -const secureCardsData = computed(() => - getComponentGroupAry(props.components, 'secureCard') -) +// const secureCardsData = computed(() => +// getComponentGroup(props.components, 'secureCard') +// ) // Computed const secureCards = computed(() => { - if (secureCardsData.value && secureCardsData.value.length > 0) { - return secureCardsData.value.map((card, index) => ({ - id: `SECURE_CARD_${index}`, - title: card?.display?.text || '', - description: card?.display?.description || '', - status: card?.display?.status || 'off', // 'on' | 'off' - benefitTitle: card?.display?.benefitTitle || '', - benefitDesc: card?.display?.benefitDesc || '', - benefitIcon: card?.display?.benefitIcon || '', - buttonText: card?.display?.buttonText || '설정하기', - buttonDisabled: card?.display?.buttonDisabled || false, - })) - } + // if (secureCardsData.value && secureCardsData.value.length > 0) { + // return secureCardsData.value.map((card, index) => ({ + // id: `SECURE_CARD_${index}`, + // title: card?.display?.text || '', + // description: card?.display?.description || '', + // status: card?.display?.status || 'off', // 'on' | 'off' + // benefitTitle: card?.display?.benefitTitle || '', + // benefitDesc: card?.display?.benefitDesc || '', + // benefitIcon: card?.display?.benefitIcon || '', + // buttonText: card?.display?.buttonText || '설정하기', + // buttonDisabled: card?.display?.buttonDisabled || false, + // })) + // } // 기본 데이터 (Figma 디자인 기반) @@ -63,92 +101,118 @@ const secureCards = computed(() => { id: 'SECURE_CARD_0', title: tm('Secure_Stove_otp') || '스토브 인증기 (OTP)', description: tm('Secure_Stove_otp_desc') || '스토브 앱으로 인증 후 안전하게 로그인하세요.', - status: 'off', + status: secureSetting.value.otpLoginYn, benefitTitle: tm('Secure_Stove_otp_benefits') || '스토브 OTP 혜택', benefitDesc: tm('Secure_Defense_bonus_10') || '방어력 +10', benefitIcon: '/images/common/img_OTP.png', - buttonText: tm('Secure_Action_setup') || '설정하기', buttonDisabled: false, + url: tm('Secure_OtpLogin_Url'), }, { id: 'SECURE_CARD_1', title: tm('Secure_Block_foreign_login') || '해외 로그인 차단', description: tm('Secure_Block_foreign_login_desc') || '접속 국가를 제한하여 의심 로그인을 차단해요.', - status: 'on', + status: secureSetting.value.abroadLoginBlockYn, benefitTitle: '', benefitDesc: '', benefitIcon: '', - buttonText: tm('Secure_Action_complete') || '설정완료', buttonDisabled: true, + url: tm('Secure_AbroadLogin_Url'), }, { id: 'SECURE_CARD_2', title: tm('Secure_Trusted_pc_management') || '지정 PC 관리', description: tm('Secure_Trusted_pc_desc') || '지정 PC에서만 로그인할 수 있게 설정해 보세요.', - status: 'off', + status: secureSetting.value.pcRegisterYn, benefitTitle: '', benefitDesc: '', benefitIcon: '', - buttonText: tm('Secure_Action_setup') || '설정하기', buttonDisabled: false, + url: tm('Secure_PcRegister_Url'), }, ] }) - +console.log("🚀 ~ secureCards:", secureCards) +// 유의사항 내용 다국어 조회 const cautionText = computed(() => { return tm('Secure_Notice_Content') || [] }) +const isLogin = () => { + const accessToken = csrGetAccessToken() ?? '' + return Boolean(accessToken) +} + + // 로그인 모달 표시 + const showLoginModal = () => { + modalStore.handleOpenConfirm({ + contentText: '로그인이 필요합니다.', + confirmButtonText: '스토브 로그인', + modalName: 'modal-login', + + confirmButtonEvent: () => { + csrGoStoveLogin() + }, + }) + } +onMounted(async () => { + if (!isLogin()) { + showLoginModal() + } else { + await fnGetSecuritySetting() + } +}) - - + \ No newline at end of file diff --git a/public/images/common/logo_smilegate.png b/public/images/common/logo_smilegate.png new file mode 100644 index 0000000000000000000000000000000000000000..2a408a4c22644e292d9d5629282e1d7bfceff2e5 GIT binary patch literal 1883 zcmV-h2c-CkP)`z>@#ATO|TX@pFu%@sfU327gMLD(Nbx+mO$rQTq!dZ5{Zd zl#OoxVV_FsDT~&481OpK185oXHwF#??gZWf8a41=s;WFN&IPV7qF^WBDd4nq)R8nS3{OSG`zX9uI^8u5*pG(9p}?ew-WT|E zE$i$KoCkaftSkeX0QWkj$AOcv(|eDT^(1qG8Unuo?SYBF``D(N+JNn?4|u;|^;*_f ziCMZQF$*xI9OwWvkCdJR`b6}Lz@NZ1!0$jc@JA7iZ4^43uhW}^deblq=u$)*g;0)d z+G6^;F0ctUR&Q0((9_Z17Ez`tP)quJHp4c{_rNYdO&PGAQ<{}ha4>dyE3pZGCGZab zMgb#%5!hn32c}@=bOA6PI56l}0gnN{1o_v%(3JKr3U%ItS(DB34mTI)0Plph7XmYZ z2Z6l`l-Uos8<+;n0Gr~ z86EVzCEO|0F$-7}>aPYabb2*FD{S7z02d(XK<8=JN*W?*e@W$acwZN|veT6x10^lV zBb(vso#y0Kfj`{wPl(F2kn}-;_9f{W<&NQ|0{XKZeQZ>2H%asIlv^fgzT+W_E(&36 zRDZuZbia~Rq3p37BdNQj&I#kYJcSoXs+LXYQOcc^UUf8HAKVnxJ1*j{lvJtoh3y)Z z`NYXqg#LSUiOLM9XCDs_`(YFFEF!%pRU~VM4JG`3%!(BbofkD7+ zz_OHflJM%rP=A8IfPt82Ixx^N8e@0T7{N0ShO`MzYz!VZc_Q&5@C;9r@NS zTIIteeOkosdsq2S>^Qe`UUu?fPX1#gTP&$e^*gbhm1}XP``xSDlZm7rjyK7bsg(4K z(`grEa~!{eE4zoJRgrwTq?VChJD!+VE_w=?EsERG)UtW=Wg2wmamdE|zH$ti9V z@g@WBI=wG}S0h?v$J{Nm)!9D!?%-q(kUf^Un4^@SiWDRXie^AZUX`4s9C0Mvn z8~C%yo!qO*J+r_H=C?0UTYR-+tcW1M-fOEdm~Oyel#5F`n!LmqE&9ElD3sx+7fjPp8QH zDBXFw%w6I`o%|3de=U;Dm(*DGbDmBN{IeW?rlh{Ixb9L(OCwpWGEUmql(7{;67F1= zA{#8Jr=&qCvSqS3I~lhh$23WINjfgbe{%8%Wb1T-q(_`=kW!qda=HqSPg?ZGLZYr%@?jb9Y$Sgk+xY#lJ9~#PKQ+KhSfau^um7NtRI2}~ z*BUot3H$`-W6Aggy~sXQHCT*X64;Ozwj*ZpVob+OTpP^H#ps763rYeT^1^~;q;4%j z?*+`vmkic6K~U-#2AoYMF85f2`4A