feat: 보안강화 FxSecure01 작업 중
This commit is contained in:
@@ -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
|
||||
|
||||
257
layers/templates/FxSecure01/index.vue
Normal file
257
layers/templates/FxSecure01/index.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<script setup lang="ts">
|
||||
import { getComponentGroup, getComponentGroupAry } from '#layers/utils/dataUtil'
|
||||
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
|
||||
import { getImageHost } from '#layers/utils/styleUtil'
|
||||
|
||||
// Props
|
||||
interface Props {
|
||||
components: PageDataTemplateComponents
|
||||
pageVerTmplSeq: number
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// Configuration
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||
const multilingualFileName = 'test_homepage_brand_secure.json'
|
||||
|
||||
// Multilingual
|
||||
const resultGetMultilingual = await useGetMultilingual({
|
||||
baseApiUrl: dataResourcesUrl,
|
||||
fileName: multilingualFileName,
|
||||
})
|
||||
const { tm }: any = useI18n({
|
||||
useScope: 'local',
|
||||
messages: Object(resultGetMultilingual?.value?.multilingual),
|
||||
})
|
||||
|
||||
// Functions
|
||||
const handleSecureSetting = (_cardId: string) => {
|
||||
// TODO: 보안 설정 페이지로 이동하거나 설정 로직 구현
|
||||
// 예: window.open('https://stove.kr/security', '_blank')
|
||||
}
|
||||
|
||||
// Data
|
||||
const backgroundData = computed(() =>
|
||||
getComponentGroup(props.components, 'background')
|
||||
)
|
||||
console.log("🚀 ~ backgroundData:", backgroundData)
|
||||
const secureCardsData = computed(() =>
|
||||
getComponentGroupAry(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,
|
||||
}))
|
||||
}
|
||||
// 기본 데이터 (Figma 디자인 기반)
|
||||
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'SECURE_CARD_0',
|
||||
title: tm('Secure_Stove_otp') || '스토브 인증기 (OTP)',
|
||||
description: tm('Secure_Stove_otp_desc') || '스토브 앱으로 인증 후 안전하게 로그인하세요.',
|
||||
status: 'off',
|
||||
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,
|
||||
},
|
||||
{
|
||||
id: 'SECURE_CARD_1',
|
||||
title: tm('Secure_Block_foreign_login') || '해외 로그인 차단',
|
||||
description: tm('Secure_Block_foreign_login_desc') || '접속 국가를 제한하여 의심 로그인을 차단해요.',
|
||||
status: 'on',
|
||||
benefitTitle: '',
|
||||
benefitDesc: '',
|
||||
benefitIcon: '',
|
||||
buttonText: tm('Secure_Action_complete') || '설정완료',
|
||||
buttonDisabled: true,
|
||||
},
|
||||
{
|
||||
id: 'SECURE_CARD_2',
|
||||
title: tm('Secure_Trusted_pc_management') || '지정 PC 관리',
|
||||
description: tm('Secure_Trusted_pc_desc') || '지정 PC에서만 로그인할 수 있게 설정해 보세요.',
|
||||
status: 'off',
|
||||
benefitTitle: '',
|
||||
benefitDesc: '',
|
||||
benefitIcon: '',
|
||||
buttonText: tm('Secure_Action_setup') || '설정하기',
|
||||
buttonDisabled: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
const cautionText = computed(() => {
|
||||
return tm('Secure_Notice_Content') || []
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WidgetsFixMainTitle
|
||||
:title="tm('Secure_Page_Title') || '보안 강화 캠페인'"
|
||||
:resources-data="backgroundData"
|
||||
/>
|
||||
|
||||
<div class="section-container static">
|
||||
<section class="section-secure bg-[#F0F0F0] px-10 pb-50">
|
||||
<div class="content-standard max-w-[1300px] mx-auto">
|
||||
<!-- Title Section -->
|
||||
<div class="flex flex-col md:flex-row w-full md:items-end justify-between gap-5 mb-6">
|
||||
<h3 class="text-[#1F1F1F] text-2xl font-bold leading-8 tracking-[-0.72px]">
|
||||
{{ tm('Secure_Section_Title') || '보안 서비스' }}
|
||||
</h3>
|
||||
<p class="text-[#666666] text-[14px] font-[400] leading-[24px] tracking-[-0.42px] text-right">
|
||||
{{ tm('Secure_Section_Description') || '*OTP / 해외 로그인 차단 / 지정 PC 관리 설정하고, 로드나인 계정을 보다 안전하게 보호하세요.' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Secure Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 w-full gap-[20px] mb-[24px]">
|
||||
<div
|
||||
v-for="card in secureCards"
|
||||
:key="card.id"
|
||||
class="flex-1 min-h-[384px] p-[16px] bg-[#FFFFFF] rounded-2xl flex flex-col gap-[12px]"
|
||||
>
|
||||
<!-- Card Content -->
|
||||
<div class="flex-1 p-8 flex flex-col gap-[12px] text-left">
|
||||
<!-- Badge -->
|
||||
<div class="inline-flex">
|
||||
<span
|
||||
:class="[
|
||||
'px-2 py-1 rounded-full text-[14px] font-medium leading-5',
|
||||
card.status === 'on'
|
||||
? 'bg-[#E2EAFF] text-[#3C75FF]'
|
||||
: 'bg-[#EBEBEB] text-[#999999]',
|
||||
]"
|
||||
>
|
||||
{{ card.status === 'on' ? tm('Secure_Enabled') : tm('Secure_Disabled') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<h4 class="text-[#1F1F1F] text-[24px] font-bold leading-[34px] tracking-[-0.72px]">
|
||||
{{ card.title }}
|
||||
</h4>
|
||||
|
||||
<!-- Description -->
|
||||
<p class="flex-1 text-[#999999] text-[16px] font-[400] leading-[26px] tracking-[-0.48px]">
|
||||
{{ card.description }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Benefit Section -->
|
||||
<div
|
||||
:class="[
|
||||
'self-stretch p-4 rounded-2xl flex flex-col gap-4',
|
||||
card.benefitTitle ? 'bg-[#F0F4FF]' : '',
|
||||
]"
|
||||
>
|
||||
<!-- Benefit Info -->
|
||||
<div
|
||||
v-if="card.benefitTitle"
|
||||
class="flex items-center gap-[12px]"
|
||||
>
|
||||
<div
|
||||
v-if="card.benefitIcon"
|
||||
class="w-[48px] h-[48px] bg-[#3C75FF] rounded-[8px] flex items-center justify-center"
|
||||
>
|
||||
<img
|
||||
:src="getImageHost(card.benefitIcon, { imageType: 'common' })"
|
||||
:alt="card.benefitTitle"
|
||||
class="w-[48px] h-[48px] object-contain rounded-2xl"
|
||||
loading="lazy"
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-1 flex flex-col text-left">
|
||||
<div class="text-[#3C75FF] text-[18px] font-bold leading-[26px] tracking-[-0.54px]">
|
||||
{{ card.benefitTitle }}
|
||||
</div>
|
||||
<div
|
||||
v-if="card.benefitDesc"
|
||||
class="text-[#3C75FF] text-[13px] font-[400] leading-[22px] tracking-[-0.325px] opacity-90"
|
||||
>
|
||||
{{ card.benefitDesc }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<AtomsButton
|
||||
type="action"
|
||||
button-size="size-small"
|
||||
:background-color="card.buttonDisabled ? '#EBEBEB' : '#383838'"
|
||||
:text-color="card.buttonDisabled ? '#999999' : '#FFFFFF'"
|
||||
:disabled="card.buttonDisabled"
|
||||
class="w-full h-14 px-10 rounded-2 border border-solid border-black/10 backdrop-blur-10"
|
||||
@click="handleSecureSetting(card.id)"
|
||||
>
|
||||
<span>{{ card.buttonText }}</span>
|
||||
<AtomsIconsLongArrowRightLine
|
||||
v-if="!card.buttonDisabled"
|
||||
:size="20"
|
||||
color="#FFFFFF"
|
||||
class="ml-[4px]"
|
||||
/>
|
||||
<svg v-else width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.4298 2.80644L6.84645 0.240655C7.52385 -0.0802185 8.30948 -0.0802184 8.98688 0.240655L14.4035 2.80645C15.2767 3.22003 15.8333 4.09952 15.8333 5.06564V7.65038C15.8333 13.399 10.6191 16.1288 8.65401 16.9535C8.18024 17.1523 7.6531 17.1523 7.17932 16.9535C5.21423 16.1288 -0.000131724 13.399 2.49573e-09 7.65038L1.11287e-05 5.06566C6.95637e-06 4.09953 0.556675 3.22002 1.4298 2.80644ZM11.4226 7.4063C11.748 7.08086 11.748 6.55323 11.4226 6.22779C11.0972 5.90235 10.5695 5.90235 10.2441 6.22779L7.5 8.97187L6.00592 7.47779C5.68049 7.15235 5.15285 7.15235 4.82741 7.47779C4.50197 7.80323 4.50197 8.33086 4.82741 8.6563L6.91074 10.7396C7.23618 11.0651 7.76382 11.0651 8.08926 10.7396L11.4226 7.4063Z" fill="#999999"/>
|
||||
</svg>
|
||||
|
||||
</AtomsButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Caution Section -->
|
||||
<div class="self-stretch p-8 bg-[#FAFAFA] rounded-2xl flex flex-col gap-3 text-left">
|
||||
<h5 class="text-[#333333] text-[20px] font-bold leading-[30px] tracking-[-0.6px]">
|
||||
{{ tm('Secure_Notice') }}
|
||||
</h5>
|
||||
<ul class="relative flex flex-col items-start justify-start w-full">
|
||||
<li
|
||||
v-for="caution in cautionText"
|
||||
:key="caution"
|
||||
v-dompurify-html="caution"
|
||||
class="relative pl-[22px] before:content-[''] before:absolute before:top-[10px] before:left-[9px] before:w-[3px] before:h-[3px] before:rounded-full before:bg-[#999999] text-[#999999] text-[14px] font-[400] leading-[24px] tracking-[-0.42px]"
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 고정형 페이지 Table Style */
|
||||
table {
|
||||
@apply w-full h-auto border-collapse border-spacing-0 table-fixed;
|
||||
}
|
||||
table th {
|
||||
@apply py-[8px] px-[12px] border border-[#D9D9D9] bg-[#FAFAFA] text-[#1F1F1F] text-[14px] font-bold leading-[24px] tracking-[-0.42px]
|
||||
md:py-[11px] md:px-[20px] md:text-[16px] md:leading-[26px] md:tracking-[-0.48px];
|
||||
}
|
||||
table td {
|
||||
@apply h-[64px] py-[8px] px-[12px] border border-[#D9D9D9] bg-[#FFFFFF] text-[#666666] text-[14px] font-[400] leading-[24px] tracking-[-0.42px]
|
||||
md:h-[80px] md:py-[14px] md:px-[20px] md:text-[16px] md:leading-[26px] md:tracking-[-0.48px];
|
||||
}
|
||||
|
||||
/* 플랫폼별 다운로드 Mobile Overflow Visible 처리 */
|
||||
.splide :deep(.splide__track) {
|
||||
overflow: visible !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user