fix. 운영 api 수정된 구조에 맞춰 코드 수정

This commit is contained in:
clkim
2025-10-16 19:11:36 +09:00
parent 7b72319377
commit 2b2d33734e
9 changed files with 89 additions and 70 deletions

View File

@@ -16,8 +16,12 @@
.splide-pagination-bullet.is-active { .splide-pagination-bullet.is-active {
@apply after:opacity-0; @apply after:opacity-0;
} }
.splide-arrows {
@apply hidden md:block;
}
.splide-arrow { .splide-arrow {
@apply hidden absolute top-1/2 w-[48px] h-[48px] bg-cover bg-center bg-no-repeat -translate-y-1/2 cursor-pointer z-[5] md:block @apply absolute top-1/2 w-[48px] h-[48px] bg-cover bg-center bg-no-repeat -translate-y-1/2 cursor-pointer z-[5]
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:rounded-full after:bg-white after:transition-opacity after:duration-300 after:ease-in-out after:opacity-0 after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:rounded-full after:bg-white after:transition-opacity after:duration-300 after:ease-in-out after:opacity-0
hover:after:opacity-10; hover:after:opacity-10;
} }

View File

@@ -125,19 +125,27 @@ const handleMoved = (
width: var(--banner-width-mo); width: var(--banner-width-mo);
height: var(--banner-height-mo-active); height: var(--banner-height-mo-active);
margin-right: var(--banner-gap-mo); margin-right: var(--banner-gap-mo);
opacity: 0.5;
} }
.center-highlight:deep(.splide__slide) .slide-inner { .center-highlight:deep(.splide__slide) .slide-inner {
width: var(--banner-width-mo); width: var(--banner-width-mo);
height: var(--banner-height-mo); height: var(--banner-height-mo);
opacity: 0.5;
} }
.center-highlight:deep(.splide__slide.is-active) { .center-highlight:deep(.splide__slide.is-active) {
width: var(--banner-width-mo-container); width: var(--banner-width-mo-container);
opacity: 1;
} }
.center-highlight:deep(.splide__slide.is-active) .slide-inner { .center-highlight:deep(.splide__slide.is-active) .slide-inner {
width: var(--banner-width-mo-active); width: var(--banner-width-mo-active);
height: var(--banner-height-mo-active); height: var(--banner-height-mo-active);
opacity: 1;
transition: all 0.45s cubic-bezier(0.4, 0, 0.2, 1); transition: all 0.45s cubic-bezier(0.4, 0, 0.2, 1);
} }
.center-highlight:deep(.splide__slide.is-next),
.center-highlight:deep(.splide__slide.is-prev) {
opacity: 1;
}
/* PC 스타일 */ /* PC 스타일 */
@media (min-width: 1024px) { @media (min-width: 1024px) {

View File

@@ -212,6 +212,7 @@ onBeforeUnmount(() => {
class="hidden md:block" class="hidden md:block"
/> />
</BlocksHybridLink> </BlocksHybridLink>
<Transition name="fade">
<div v-if="gnbItem.children" class="nav-2depth"> <div v-if="gnbItem.children" class="nav-2depth">
<ul> <ul>
<li <li
@@ -230,6 +231,7 @@ onBeforeUnmount(() => {
</li> </li>
</ul> </ul>
</div> </div>
</Transition>
</div> </div>
</div> </div>
<div v-if="gnbData?.menus && overflowNam > 0" class="more"> <div v-if="gnbData?.menus && overflowNam > 0" class="more">
@@ -351,7 +353,7 @@ onBeforeUnmount(() => {
.nav-area { .nav-area {
@apply flex flex-col w-[100vw] max-w-[360px] min-w-[320px] bg-theme-foreground-10 translate-x-[-100%] @apply flex flex-col w-[100vw] max-w-[360px] min-w-[320px] bg-theme-foreground-10 translate-x-[-100%]
md:inline-flex md:flex-row md:w-auto md:h-full md:pl-[40px] md:items-center md:bg-transparent md:transform-none; md:inline-flex md:flex-row md:w-auto md:max-w-none md:h-full md:pl-[40px] md:items-center md:bg-transparent md:transform-none;
} }
.nav-logo { .nav-logo {

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { SplideSlide } from '@splidejs/vue-splide' import { SplideSlide } from '@splidejs/vue-splide'
import type { ListOperateGroupItem } from '#layers/types/api/resourcesData' import type { OperateGroupItem } from '#layers/types/api/resourcesData'
import type { SlideItemSize } from '#layers/types/components/slide' import type { SlideItemSize } from '#layers/types/components/slide'
interface BannerListProps { interface BannerListProps {
resourcesData: ListOperateGroupItem[] resourcesData: OperateGroupItem[]
slideItemSize: SlideItemSize slideItemSize: SlideItemSize
arrows?: boolean arrows?: boolean
pagination?: boolean pagination?: boolean

View File

@@ -1,18 +1,18 @@
import type { import type {
GetResourcesDataParams, GetResourcesDataParams,
ResourcesDataResponse, ResourcesDataResponse,
ResourcesDataValue, OperateComponents,
} from '#layers/types/api/resourcesData' } from '#layers/types/api/resourcesData'
export const useResourcesData = () => { export const useResourcesData = () => {
const getResourcesData = async ( const getResourcesData = async (
params: GetResourcesDataParams params: GetResourcesDataParams
): Promise<ResourcesDataValue | null> => { ): Promise<OperateComponents | null> => {
const { pageSeq, pageVer, pageVerTmplSeq, langCode, q, qc } = params const { pageSeq, pageVer, pageVerTmplSeq, langCode, q, qc } = params
const config = useRuntimeConfig() const config = useRuntimeConfig()
const stoveApiBaseUrl = config.public.stoveApiUrl const stoveApiBaseUrl = config.public.stoveApiUrl
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/resources` const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/operateResources`
const queryParams: Record<string, string> = { const queryParams: Record<string, string> = {
page_seq: pageSeq, page_seq: pageSeq,

View File

@@ -91,3 +91,10 @@ const handleChange = (
</div> </div>
</section> </section>
</template> </template>
<style scoped>
.section-container {
@apply before:hidden md:before:block before:content-[''] before:absolute before:top-0 before:left-0 before:w-[104px] before:h-full before:bg-gradient-to-l from-transparent to-[rgba(0,0,0,0.7)]
after:hidden md:after:block after:content-[''] after:absolute after:top-0 after:right-0 after:w-[104px] after:h-full after:bg-gradient-to-r from-transparent to-[rgba(0,0,0,0.7)];
}
</style>

View File

@@ -1,6 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { SplideSlide } from '@splidejs/vue-splide' import { SplideSlide } from '@splidejs/vue-splide'
import { getComponentGroup, getComponentGroupAry } from '#layers/utils/dataUtil' import {
getComponentGroup,
getComponentGroupAry,
ensureMinimumSlideOperateData,
} from '#layers/utils/dataUtil'
import type { PageDataTemplateComponents } from '#layers/types/api/pageData' import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
interface Props { interface Props {
@@ -49,20 +53,10 @@ const { data: resourcesData } = await useLazyAsyncData(
) )
const slideData = computed(() => { const slideData = computed(() => {
const operateComponents = resourcesData.value?.operate_components if (!resourcesData.value) return []
if (!operateComponents) { const data = getComponentGroupAry(resourcesData.value, 'bannerList')
return [] return ensureMinimumSlideOperateData(data)
}
const firstKey = Object.keys(operateComponents)[0]
const data = operateComponents[firstKey]?.list_operate_groups || []
if (data.length < 3) {
return [...data, ...data]
}
return data
}) })
const slideItemSize = { const slideItemSize = {

View File

@@ -3,8 +3,9 @@
*/ */
// 리스트 운영 그룹 아이템 // 리스트 운영 그룹 아이템
export interface ListOperateGroupItem { export interface OperateGroupItem {
seq: number seq: number
flag_type?: number
title: string title: string
img_path: string img_path: string
url: string url: string
@@ -16,36 +17,19 @@ export interface ListOperateGroupItem {
option03: string option03: string
} }
// 플래그 운영 그룹 아이템 export interface OperateGroupList {
export interface FlagOperateGroupItem { groups: OperateGroupItem[]
seq: number
flag_type: number
option01: number
option02: number
option03: string
} }
// 운영 컴포넌트 그룹
export interface OperateComponentGroup {
list_operate_groups: ListOperateGroupItem[]
flag_operate_groups: FlagOperateGroupItem[]
}
// 운영 컴포넌트 목록 (동적 키)
export interface OperateComponents { export interface OperateComponents {
[key: string]: OperateComponentGroup [key: string]: OperateGroupList
}
// Resources Data 응답 값
export interface ResourcesDataValue {
operate_components: OperateComponents
} }
// Resources Data API 응답 // Resources Data API 응답
export interface ResourcesDataResponse { export interface ResourcesDataResponse {
code: number code: number
message: string message: string
value: ResourcesDataValue value: OperateComponents
} }
// getResourcesData 함수 파라미터 // getResourcesData 함수 파라미터

View File

@@ -10,6 +10,10 @@ import type {
PageDataTemplateComponentSet, PageDataTemplateComponentSet,
PageDataResourceGroupType, PageDataResourceGroupType,
} from '#layers/types/api/pageData' } from '#layers/types/api/pageData'
import type {
OperateComponents,
OperateGroupItem,
} from '#layers/types/api/resourcesData'
/** /**
* 페이지 데이터를 기반으로 레이아웃 타입을 결정합니다. * 페이지 데이터를 기반으로 레이아웃 타입을 결정합니다.
@@ -93,7 +97,7 @@ export const hasComponentGroup = (
* @returns 첫 번째 그룹 데이터 또는 null * @returns 첫 번째 그룹 데이터 또는 null
*/ */
export const getComponentGroup = ( export const getComponentGroup = (
components: PageDataTemplateComponents, components: PageDataTemplateComponents | OperateComponents,
componentName: string componentName: string
) => { ) => {
if (!components) return null if (!components) return null
@@ -109,7 +113,7 @@ export const getComponentGroup = (
* @returns 그룹 배열 데이터 * @returns 그룹 배열 데이터
*/ */
export const getComponentGroupAry = ( export const getComponentGroupAry = (
components: PageDataTemplateComponents, components: PageDataTemplateComponents | OperateComponents,
componentName: string componentName: string
) => { ) => {
if (!components) return [] if (!components) return []
@@ -118,7 +122,7 @@ export const getComponentGroupAry = (
} }
/** /**
* 슬라이드 데이터를 최소 개수로 보장합니다. * 슬라이드 데이터를 최소 개수로 보장합니다. (페이지 데이터용)
* @param components 원본 데이터 배열 또는 객체 * @param components 원본 데이터 배열 또는 객체
* @param minCount 최소 보장할 개수 (기본값: 3) * @param minCount 최소 보장할 개수 (기본값: 3)
* @returns 최소 개수가 보장된 데이터 배열 * @returns 최소 개수가 보장된 데이터 배열
@@ -133,18 +137,34 @@ export const ensureMinimumSlideData = (
? components.group_sets ? components.group_sets
: [] : []
if (arrayData.length === 0) return [] // 빈 배열이거나 이미 최소 개수를 만족하면 그대로 반환
if (arrayData.length === 0 || arrayData.length >= minCount) {
if (arrayData.length >= minCount) {
return arrayData return arrayData
} }
const result = [...arrayData] // 최소 개수를 보장하기 위해 데이터 반복
while (result.length < minCount) { const repeatTimes = Math.ceil(minCount / arrayData.length)
result.push(...arrayData) return Array(repeatTimes).fill(arrayData).flat()
} }
return result /**
* 슬라이드 데이터를 최소 개수로 보장합니다. (운영 그룹용)
* @param data 원본 데이터 배열
* @param minCount 최소 보장할 개수 (기본값: 3)
* @returns 최소 개수가 보장된 데이터 배열
*/
export const ensureMinimumSlideOperateData = (
data: OperateGroupItem[],
minCount: number = 3
): OperateGroupItem[] => {
// 빈 배열이거나 이미 최소 개수를 만족하면 그대로 반환
if (data.length === 0 || data.length >= minCount) {
return data
}
// 최소 개수를 보장하기 위해 데이터 반복
const repeatTimes = Math.ceil(minCount / data.length)
return Array(repeatTimes).fill(data).flat()
} }
/** /**