321 lines
11 KiB
Vue
321 lines
11 KiB
Vue
<script setup lang="ts">
|
|
import { getComponentGroup } 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>()
|
|
|
|
const { handleTokenValidation } = useTokenValidation()
|
|
|
|
// Configuration
|
|
const runtimeConfig = useRuntimeConfig()
|
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
|
const stoveApiBaseUrl = runtimeConfig.public.stoveApiUrl
|
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
|
|
|
// Multilingual
|
|
const resultGetMultilingual = await useGetMultilingual({
|
|
baseApiUrl: dataResourcesUrl,
|
|
fileName: multilingualFileName,
|
|
})
|
|
const { tm }: any = useI18n({
|
|
useScope: 'local',
|
|
messages: Object(resultGetMultilingual?.value?.multilingual),
|
|
})
|
|
|
|
const isLogin = ref(false)
|
|
|
|
const secureSetting = ref({
|
|
otpLoginYn: 'N',
|
|
abroadLoginBlockYn: 'N',
|
|
pcRegisterYn: 'N',
|
|
})
|
|
|
|
// 회원 보안 설정 설정
|
|
const handleSecureSetting = (url: string) => {
|
|
window.open(url, '_blank')
|
|
}
|
|
|
|
// 로그인 유효성 체크
|
|
const checkLoginValidation = async () => {
|
|
const accessToken = useCookie('SUAT')
|
|
const validateTokenResult = await handleTokenValidation(
|
|
accessToken.value || ''
|
|
)
|
|
isLogin.value = validateTokenResult
|
|
}
|
|
|
|
// 회원 보안 설정 조회
|
|
const fnGetSecuritySetting = async () => {
|
|
const accessToken = useCookie('SUAT')
|
|
checkLoginValidation()
|
|
|
|
const apiBase = `${stoveApiBaseUrl}/auth-secure/v1.0`
|
|
const headers = {
|
|
Authorization: `Bearer ${accessToken.value}`,
|
|
'Content-Type': 'application/json;charset=UTF-8',
|
|
}
|
|
try {
|
|
const result = await commonFetch('GET', `${apiBase}/security/setting`, {
|
|
headers,
|
|
})
|
|
|
|
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'),
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
// Data
|
|
const backgroundData = computed(() =>
|
|
getComponentGroup(props.components, 'background')
|
|
)
|
|
|
|
// Computed
|
|
const secureCards = computed(() => {
|
|
return [
|
|
{
|
|
id: 'SECURE_CARD_0',
|
|
title: tm('Secure_Stove_otp') || '스토브 인증기 (OTP)',
|
|
description:
|
|
tm('Secure_Stove_otp_desc') ||
|
|
'스토브 앱으로 인증 후 안전하게 로그인하세요.',
|
|
status: secureSetting.value.otpLoginYn,
|
|
benefitTitle: tm('Secure_Stove_otp_benefits') || '스토브 OTP 혜택',
|
|
benefitDesc: tm('Secure_Defense_bonus_10') || '방어력 +10',
|
|
benefitIcon: '/images/common/img_OTP.png',
|
|
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: secureSetting.value.abroadLoginBlockYn,
|
|
benefitTitle: '',
|
|
benefitDesc: '',
|
|
benefitIcon: '',
|
|
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: secureSetting.value.pcRegisterYn,
|
|
benefitTitle: '',
|
|
benefitDesc: '',
|
|
benefitIcon: '',
|
|
buttonDisabled: false,
|
|
url: tm('Secure_PcRegister_Url'),
|
|
},
|
|
]
|
|
})
|
|
// 유의사항 내용 다국어 조회
|
|
const cautionText = computed(() => {
|
|
return tm('Secure_Notice_Content') || []
|
|
})
|
|
|
|
onMounted(() => {
|
|
fnGetSecuritySetting()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<WidgetsFixMainTitle
|
|
:title="tm('Secure_Page_Title') || '보안 강화 캠페인'"
|
|
:resources-data="backgroundData"
|
|
class="mx-auto"
|
|
/>
|
|
|
|
<div class="section-container static">
|
|
<section class="section-secure bg-[#F0F0F0] pb-50">
|
|
<div class="section-static content-standa md: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-gray-500 text-[14px] font-[400] leading-[24px] tracking-[-0.42px] text-left md:text-right"
|
|
>
|
|
{{
|
|
tm('Secure_Section_Description') ||
|
|
'*OTP / 해외 로그인 차단 / 지정 PC 관리 설정하고, 로드나인 계정을 보다 안전하게 보호하세요.'
|
|
}}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Secure Cards -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-3 w-full gap-3 md:gap-5 mb-6">
|
|
<div
|
|
v-for="card in secureCards"
|
|
:key="card.id"
|
|
class="flex-1 min-h-[308px] md:min-h-[384px] p-[10px] md:p-4 bg-[#FFFFFF] rounded-2xl flex flex-col gap-3 transition-all duration-300 ease-in-out"
|
|
>
|
|
<!-- Card Content -->
|
|
<div
|
|
class="flex-1 p-[10px] md:p-8 flex flex-col gap-[8px] md:gap-3 text-left"
|
|
>
|
|
<!-- Badge -->
|
|
<div class="inline-flex">
|
|
<span
|
|
:class="[
|
|
'px-1.5 md:px-2 py-0.5 md:py-1 rounded-full text-[12px] md:text-[14px] font-medium leading-5',
|
|
card.status === 'Y'
|
|
? 'bg-[#E2EAFF] text-[#3C75FF]'
|
|
: 'bg-[#EBEBEB] text-[#999999]',
|
|
]"
|
|
>
|
|
{{
|
|
card.status === 'Y'
|
|
? tm('Secure_Enabled')
|
|
: tm('Secure_Disabled')
|
|
}}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Title -->
|
|
<h4
|
|
class="text-[#1F1F1F] text-[18px] md:text-[24px] font-bold leading-[26px] md:leading-[34px] tracking-[-0.54px] md:tracking-[-0.72px]"
|
|
>
|
|
{{ card.title }}
|
|
</h4>
|
|
|
|
<!-- Description -->
|
|
<p
|
|
class="flex-1 text-[#999999] text-[14px] md:text-base font-[400] leading-[22px] md:leading-[26px] tracking-[-0.42px] md:tracking-[-0.48px]"
|
|
>
|
|
{{ card.description }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Benefit Section -->
|
|
<div
|
|
:class="[
|
|
'self-stretch p-[10px] md: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-[14px] md:text-[18px] font-bold leading-[22px] md:leading-[26px] tracking-[-0.42px] md:tracking-[-0.54px]"
|
|
>
|
|
{{ card.benefitTitle }}
|
|
</div>
|
|
<div
|
|
v-if="card.benefitDesc"
|
|
class="text-[#3C75FF] text-[12px] md:text-[13px] font-[400] leading-[18px] md:leading-[22px] tracking-[-0.325px] opacity-90"
|
|
>
|
|
{{ card.benefitDesc }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Button -->
|
|
<AtomsButton
|
|
v-if="card.status === 'N'"
|
|
type="external"
|
|
button-size="size-small md:size-large"
|
|
background-color="#000000"
|
|
text-color="#FFFFFF"
|
|
@click="
|
|
isLogin
|
|
? handleSecureSetting(card.url)
|
|
: checkLoginValidation()
|
|
"
|
|
>
|
|
<span>{{ tm('Secure_Action_setup') }}</span>
|
|
</AtomsButton>
|
|
<AtomsButton
|
|
v-else
|
|
type="action"
|
|
button-size="size-small md:size-large"
|
|
background-color="#EBEBEB"
|
|
text-color="#999999"
|
|
disabled
|
|
>
|
|
<span>{{ tm('Secure_Action_complete') }}</span>
|
|
<svg
|
|
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>
|