| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- <script setup>
- const route = useRoute();
- const { getMediaUrl } = useImage();
- const config = useRuntimeConfig();
- const { apiBase } = useCompany();
- const events = ref([]);
- const currentPage = ref(1);
- const itemsPerPage = 9;
- const totalPages = ref(1);
- const loading = ref(false);
- // 현재 사이트 (ford 또는 lincoln)
- const currentSite = computed(() => {
- return route.path.includes("lincoln") ? "lincoln" : "ford";
- });
- // API에서 이벤트 데이터 가져오기
- const fetchEvents = async () => {
- loading.value = true;
- try {
- const response = await fetch(
- `${apiBase.value}/api/event/public?page=${currentPage.value}&per_page=${itemsPerPage}&site=${currentSite.value}`
- );
- const result = await response.json();
- if (result.success) {
- events.value = result.data.items || [];
- totalPages.value = result.data.total_pages || 1;
- }
- } catch (error) {
- console.error("이벤트 데이터를 불러오는데 실패했습니다:", error);
- } finally {
- loading.value = false;
- }
- };
- // file_urls에 유효한 썸네일이 있는지 확인
- const hasValidThumbnail = (event) => {
- if (!event.file_urls || event.file_urls.length === 0) {
- return false;
- }
- const firstFile = event.file_urls[0];
- // 객체 형태일 경우 url 속성 확인
- if (typeof firstFile === "object" && firstFile.url) {
- return true;
- }
- // 문자열일 경우
- if (typeof firstFile === "string") {
- return true;
- }
- return false;
- };
- // 썸네일 이미지 URL 가져오기 (file_urls의 첫 번째 항목만)
- const getThumbnail = (event) => {
- // file_urls의 첫 번째 항목만 사용
- if (event.file_urls && event.file_urls.length > 0) {
- const firstFile = event.file_urls[0];
- let imageUrl = null;
- // file_urls가 객체 형태일 경우 url 속성 사용
- if (typeof firstFile === "object" && firstFile.url) {
- imageUrl = firstFile.url;
- }
- // 문자열일 경우 그대로 사용
- else if (typeof firstFile === "string") {
- imageUrl = firstFile;
- }
- // 상대 경로면 도메인 붙이기
- if (imageUrl && imageUrl.startsWith("/")) {
- return apiBase.value + imageUrl;
- }
- if (imageUrl) {
- return imageUrl;
- }
- }
- // file_urls가 없으면 기본 이미지
- return "/img/stories/technology/img--tech1.jpg";
- };
- // 표시할 페이지 번호 (최대 5개)
- const displayPages = computed(() => {
- const pages = [];
- const maxDisplay = 5;
- let startPage = Math.max(1, currentPage.value - 2);
- let endPage = Math.min(totalPages.value, startPage + maxDisplay - 1);
- if (endPage - startPage < maxDisplay - 1) {
- startPage = Math.max(1, endPage - maxDisplay + 1);
- }
- for (let i = startPage; i <= endPage; i++) {
- pages.push(i);
- }
- return pages;
- });
- // 페이지 이동
- const goToPage = async (page) => {
- if (page >= 1 && page <= totalPages.value) {
- currentPage.value = page;
- await fetchEvents();
- // 페이지 이동 시 스크롤 최상단으로
- window.scrollTo({ top: 0, behavior: "smooth" });
- }
- };
- // 이벤트 종료 여부 확인 (end_date가 오늘보다 작으면 종료)
- const isEventEnded = (endDate) => {
- if (!endDate) return false;
- const today = new Date();
- const end = new Date(endDate);
- today.setHours(0, 0, 0, 0);
- end.setHours(0, 0, 0, 0);
- return end < today;
- };
-
- const isLincolnPage = computed(() => {
- return route.path.includes("lincoln");
- });
- // 샘플 데이터 (computed로 반응형 유지)
- const breadcrumbData = computed(() => ({
- mainMenu: "OWNER",
- currentSubMenu: "프로모션",
- subMenuItems: [
- { label: "프로모션", to: isLincolnPage.value ? "/lincoln/owner/event" : "/ford/owner/event", active: false },
- ],
- }));
-
- // 컴포넌트 마운트 시 데이터 로드
- onMounted(() => {
- fetchEvents();
- });
- </script>
- <template>
- <div>
- <breadCrumbs
- :main-menu="breadcrumbData.mainMenu"
- :current-sub-menu="breadcrumbData.currentSubMenu"
- :sub-menu-items="breadcrumbData.subMenuItems"
- />
- <div class="ovwner--wrapper">
- <div class="title--visual">
- <h2>PROMOTION</h2>
- </div>
- <div class="detail--container">
- <div class="content--wrap">
- <div v-if="loading" class="loading--wrap">
- <p>로딩 중...</p>
- </div>
- <div v-else class="event--wrap">
- <!-- API에서 가져온 이벤트 표시 -->
- <div v-for="event in events" :key="event.id" class="event--card">
- <NuxtLink :to="`${isLincolnPage == false ? '/ford' : '/lincoln'}/owner/event/${event.id}`">
- <div
- class="img--wrap"
- :class="{ 'no--image': !hasValidThumbnail(event) }"
- style="object-position: top"
- >
- <img
- v-if="hasValidThumbnail(event)"
- :src="getThumbnail(event)"
- :alt="event.title"
- style="object-position: top"
- />
- <svg
- v-else
- xmlns="http://www.w3.org/2000/svg"
- width="69"
- height="24"
- viewBox="0 0 69 24"
- fill="none"
- >
- <path
- d="M57.0623 21.3142C54.9409 21.3142 52.9856 20.5922 51.422 19.3822C53.0087 17.3448 53.9585 14.7826 53.9585 12C53.9585 9.21768 53.0087 6.65544 51.422 4.61784C52.9856 3.408 54.9409 2.68584 57.0623 2.68584C62.1714 2.68584 66.3281 6.86424 66.3281 12C66.3281 17.136 62.1714 21.3142 57.0623 21.3142ZM36.3802 19.3822C37.9672 17.3448 38.917 14.7826 38.917 12C38.917 9.21768 37.9672 6.65544 36.3804 4.61784C37.9438 3.408 39.8997 2.68584 42.0208 2.68584C44.1421 2.68584 46.0975 3.408 47.6611 4.61784C46.0743 6.65544 45.1246 9.21768 45.1246 12C45.1246 14.7826 46.0743 17.3448 47.6611 19.3822C46.0975 20.5922 44.1421 21.3142 42.0208 21.3142C39.8997 21.3142 37.9438 20.5922 36.3802 19.3822ZM21.3387 19.3822C22.9257 17.3448 23.8754 14.7826 23.8754 12C23.8754 9.21768 22.9257 6.65544 21.3389 4.61784C22.9023 3.408 24.8581 2.68584 26.9792 2.68584C29.1003 2.68584 31.0562 3.408 32.6196 4.61784C31.0328 6.65544 30.083 9.21768 30.083 12C30.083 14.7826 31.0328 17.3448 32.6196 19.3822C31.0562 20.5922 29.1003 21.3142 26.9792 21.3142C24.8581 21.3142 22.9023 20.5922 21.3387 19.3822ZM2.6719 12C2.6719 6.86424 6.82861 2.68584 11.9377 2.68584C14.0588 2.68584 16.0147 3.408 17.578 4.61784C15.9913 6.65544 15.0415 9.21768 15.0415 12C15.0415 14.7826 15.9913 17.3448 17.578 19.3822C16.0147 20.5922 14.0588 21.3142 11.9377 21.3142C6.82861 21.3142 2.6719 17.136 2.6719 12ZM19.4585 17.4305C18.3619 15.9005 17.7134 14.0256 17.7134 12C17.7134 9.97464 18.3619 8.09952 19.4585 6.56952C20.5551 8.09952 21.2035 9.97464 21.2035 12C21.2035 14.0256 20.5551 15.9005 19.4585 17.4305ZM34.5 17.4305C33.4034 15.9005 32.7549 14.0256 32.7549 12C32.7549 9.97464 33.4034 8.09952 34.5 6.56952C35.5966 8.09952 36.2451 9.97464 36.2451 12C36.2451 14.0256 35.5966 15.9005 34.5 17.4305ZM49.5415 17.4305C48.4449 15.9005 47.7965 14.0256 47.7965 12C47.7965 9.97464 48.4449 8.09952 49.5415 6.56952C50.6381 8.09952 51.2866 9.97464 51.2866 12C51.2866 14.0256 50.6381 15.9005 49.5415 17.4305ZM57.0623 0C54.2135 0 51.5958 1.00968 49.5415 2.68968C47.4873 1.00968 44.8696 0 42.0208 0C39.1719 0 36.5542 1.00968 34.5 2.68968C32.4458 1.00968 29.8278 0 26.9792 0C24.1304 0 21.5127 1.00968 19.4585 2.68968C17.4042 1.00968 14.7863 0 11.9377 0C5.35526 0 0 5.3832 0 12C0 18.617 5.35526 24 11.9377 24C14.7863 24 17.4042 22.9906 19.4585 21.3103C21.5127 22.9906 24.1304 24 26.9792 24C29.8278 24 32.4458 22.9906 34.5 21.3103C36.5542 22.9906 39.1719 24 42.0208 24C44.8696 24 47.4873 22.9906 49.5415 21.3103C51.5958 22.9906 54.2135 24 57.0623 24C63.6447 24 69 18.617 69 12C69 5.3832 63.6447 0 57.0623 0Z"
- fill="white"
- ></path>
- </svg>
- <div v-if="isEventEnded(event.end_date)" class="event--end">
- <span>이벤트<br />종료</span>
- </div>
- </div>
- <div class="desc">
- <h3 class="ellipsis2">{{ event.title }}</h3>
- <div class="date--context">
- {{ event.start_date }} ~ {{ event.end_date }}
- </div>
- </div>
- </NuxtLink>
- </div>
- </div>
- <!-- 페이지네이션 -->
- <div class="pagination--wrap">
- <button
- class="pagination--btn first"
- @click="goToPage(1)"
- :disabled="currentPage === 1"
- title="처음"
- >
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- width="24px"
- height="24px"
- >
- <use href="/img/ico--back--s.svg#main"></use>
- </svg>
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- width="24px"
- height="24px"
- style="margin-left: -12px"
- >
- <use href="/img/ico--back--s.svg#main"></use>
- </svg>
- </button>
- <button
- class="pagination--btn prev"
- @click="goToPage(currentPage - 1)"
- :disabled="currentPage === 1"
- title="이전"
- >
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- width="24px"
- height="24px"
- >
- <use href="/img/ico--back--s.svg#main"></use>
- </svg>
- </button>
- <div class="pagination--numbers">
- <button
- v-for="page in displayPages"
- :key="page"
- class="pagination--number"
- :class="{ active: page === currentPage }"
- @click="goToPage(page)"
- >
- {{ page }}
- </button>
- </div>
- <button
- class="pagination--btn next"
- @click="goToPage(currentPage + 1)"
- :disabled="currentPage === totalPages"
- title="다음"
- >
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- width="24px"
- height="24px"
- >
- <use href="/img/ico--forward--s.svg#main"></use>
- </svg>
- </button>
- <button
- class="pagination--btn last"
- @click="goToPage(totalPages)"
- :disabled="currentPage === totalPages"
- title="끝"
- >
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- width="24px"
- height="24px"
- style="margin-right: -12px"
- >
- <use href="/img/ico--forward--s.svg#main"></use>
- </svg>
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- width="24px"
- height="24px"
- >
- <use href="/img/ico--forward--s.svg#main"></use>
- </svg>
- </button>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
|