Files
web-temp/layers/templates/GrBoard01/index.vue
2025-11-25 17:02:35 +09:00

184 lines
5.2 KiB
Vue

<script setup lang="ts">
import { SplideSlide } from '@splidejs/vue-splide'
import { globalDateFormat } from '@seed-next/date'
import { getComponentGroup } from '#layers/utils/dataUtil'
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
import type { CwmsArticleItem } from '#layers/types/api/cwmsArticle'
interface Props {
components: PageDataTemplateComponents
pageVerTmplSeq: number
}
const props = defineProps<Props>()
const gameDataStore = useGameDataStore()
const pageDataStore = usePageDataStore()
const { getCwmsArticle } = useCwmsArticle()
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
const { locale } = useI18n()
const { gameData } = storeToRefs(gameDataStore)
const { pageData } = storeToRefs(pageDataStore)
const boardId = computed(
() => getComponentGroup(props.components, 'boardId')?.display?.text
)
const paginationData = computed(() => {
return getComponentGroupAry(props.components, 'pagination')
})
const backgroundData = computed(() =>
getComponentGroup(props.components, 'background')
)
const mainTitleData = computed(() =>
getComponentGroup(props.components, 'mainTitle')
)
const buttonListData = ref(getComponentGroupAry(props.components, 'buttonList'))
const descriptionData = computed(() =>
getComponentGroup(props.components, 'description')
)
const { data: slideData } = await useAsyncData(
`gr-board-01-resources-${pageData.value?.page_seq}-${pageData.value?.page_ver}-${props.pageVerTmplSeq}`,
async () => {
if (!boardId.value) {
return []
}
const cwmsArticleData = await getCwmsArticle('BOARD', boardId.value, {
sortTypeCode: 'LATEST',
translationYn: true,
page: 1,
size: 20,
})
return cwmsArticleData?.list as CwmsArticleItem[]
},
{
default: () => [],
server: false,
}
)
const slideLength = computed(() => slideData.value.length ?? 0)
const splideOptions = computed(() => {
return {
gap: 20,
perPage: 4,
drag: false,
arrows: slideLength.value > 4,
pagination: slideLength.value > 4,
destroy: slideLength.value <= 4,
breakpoints: {
[BREAKPOINTS.lg - 1]: {
perPage: 2,
arrows: slideLength.value > 2,
pagination: slideLength.value > 2,
destroy: slideLength.value < 3,
},
[BREAKPOINTS.md - 1]: {
drag: true,
perPage: 1,
arrows: false,
pagination: false,
destroy: slideLength.value < 2,
padding: {
left: 40,
right: 40,
},
},
[BREAKPOINTS.sm - 1]: {
padding: {
left: 20,
right: 20,
},
},
},
}
})
const getArticleUrl = (articleId: string) => {
const communityUrl = gameData.value?.url_json?.community
if (!communityUrl || !articleId || !boardId.value) {
return ''
}
return `${communityUrl}/view/${articleId}?boardKey=${boardId.value}`
}
const onArrowClick = (direction, targetIndex) => {
const arrowGroupAry = getComponentGroupAry(props.components, 'arrow')
const logTracking = arrowGroupAry?.[direction === 'prev' ? 0 : 1]
sendLog(locale.value, useAnalyticsLogDataDirect(logTracking, 1))
}
</script>
<template>
<section
class="relative min-h-[483px] py-[80px] md:min-h-[684px] md:py-[120px]"
:style="getPaginationClass(paginationData)"
>
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
<div class="content-standard px-0">
<WidgetsMainTitle
v-if="mainTitleData"
:resources-data="mainTitleData"
class="title-md"
/>
<ClientOnly>
<BlocksSlideDefault
v-if="slideLength > 0"
:slide-item-length="slideLength"
v-bind="splideOptions"
class="w-full"
@arrow-click="onArrowClick"
>
<SplideSlide
v-for="(item, index) in slideData"
:key="item.article_id || `real-${index}`"
>
<div class="slide-inner">
<BlocksCardNews
:title="item.title"
:description="globalDateFormat(item.create_datetime, locale)"
:img-path="getResourceHost(item.media_thumbnail_url)"
:url="getArticleUrl(item.article_id)"
link-target="_blank"
/>
</div>
</SplideSlide>
</BlocksSlideDefault>
</ClientOnly>
<WidgetsButtonList
v-if="buttonListData"
:resources-data="buttonListData"
:page-ver-tmpl-seq="props.pageVerTmplSeq"
class="mt-[48px] md:mt-[64px]"
/>
<WidgetsDescription
v-if="descriptionData"
:resources-data="descriptionData"
class="mt-[32px] md:mt-[48px]"
/>
</div>
</section>
</template>
<style scoped>
.splide {
@apply mt-[24px] md:max-w-[776px] md:mt-[48px] md:mx-auto md:px-[72px] lg:max-w-[1428px];
}
.splide:deep(.arrow-prev) {
@apply top-[calc(50%-28px)] left-[0];
}
.splide:deep(.arrow-next) {
@apply top-[calc(50%-28px)] right-[0];
}
.slide-inner {
@apply w-[275px] aspect-[1/1] md:w-[306px];
}
/* destroy되었을 때 (슬라이드 비활성화) 중앙 정렬 */
.splide:not(.is-active):deep(.splide__list) {
@apply flex justify-center gap-5;
}
</style>