notice.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <main>
  3. <TopVisual :className="className" :title="title" :navigation="navigation" />
  4. <section class="notice--section">
  5. <div class="sub--container type2">
  6. <div class="title--wrap">
  7. <h2 class="title">공지사항</h2>
  8. </div>
  9. <div class="search--wrap">
  10. <USelect v-model="searchValue" :items="searchItems" />
  11. <UInput v-model="searchKeyword" placeholder="검색어를 입력해주세요." />
  12. <UButton class="search--btn"></UButton>
  13. </div>
  14. <div class="notice--wrap">
  15. <div class="notice--list">
  16. <NuxtLink
  17. v-for="news in paginatedNews"
  18. :key="news.id"
  19. :to="news.link"
  20. class="notice"
  21. >
  22. <span class="news--index">{{ news.id }}</span>
  23. <h4>{{ news.title }}</h4>
  24. <span class="news--date">{{ news.date }}</span>
  25. </NuxtLink>
  26. </div>
  27. <div class="pagination--wrap">
  28. <UButton
  29. @click="prevPage"
  30. class="prev--btn"
  31. :disabled="currentPage === 1"
  32. ></UButton>
  33. <div class="numbs">
  34. <UButton
  35. v-for="page in totalPages"
  36. :key="page"
  37. @click="goToPage(page)"
  38. :class="{ active: currentPage === page }"
  39. >
  40. {{ page }}
  41. </UButton>
  42. </div>
  43. <UButton
  44. @click="nextPage"
  45. class="next--btn"
  46. :disabled="currentPage === totalPages"
  47. ></UButton>
  48. </div>
  49. </div>
  50. </div>
  51. </section>
  52. </main>
  53. </template>
  54. <script setup>
  55. import { ref, computed, onMounted } from "vue";
  56. import TopVisual from "~/components/topVisual.vue";
  57. const searchItems = ref(["제목"]);
  58. const searchValue = ref("선택");
  59. const searchKeyword = ref("");
  60. const loading = ref(true);
  61. const className = ref("contact");
  62. const title = ref("Contact");
  63. const navigation = ref([
  64. {
  65. name: "Contact",
  66. link: "/contact/notice",
  67. gnbList: [
  68. { name: "Company", link: "/company/intro" },
  69. { name: "Product", link: "/products/materials" },
  70. { name: "Technology", link: "/technology/facilities" },
  71. { name: "Media", link: "/media/news" },
  72. { name: "Contact", link: "/contact/notice" },
  73. ],
  74. },
  75. {
  76. name: "공지사항",
  77. link: "/contact/notice",
  78. gnbList: [
  79. { name: "공지사항", link: "/contact/notice" },
  80. { name: "FAQ", link: "/contact/faq" },
  81. { name: "고객센터", link: "/contact/support" },
  82. { name: "오시는길", link: "/contact/location" },
  83. ],
  84. },
  85. ]);
  86. // 뉴스 데이터 배열 - API에서 받아올 것
  87. const newsData = ref([]);
  88. // API에서 공지사항 데이터 가져오기
  89. const fetchNoticeList = async (page = 1) => {
  90. try {
  91. loading.value = true;
  92. // CodeIgniter 방식으로 호출 (/controller/method/param)
  93. const response = await $get(`/board_list/notice`, {
  94. page: page,
  95. searchKind: searchValue.value,
  96. searchKeyword: searchKeyword.value,
  97. });
  98. // 백엔드가 JSON으로 응답하는지 확인
  99. if (response && typeof response === "object") {
  100. // JSON 응답인 경우
  101. if (response.success && response.list) {
  102. // 전체 개수와 현재 페이지를 기준으로 번호 계산
  103. const totalCount = response.totalCount || 0;
  104. const currentPageNum = page || 1;
  105. const pageSize = 20; // 백엔드의 페이지 사이즈와 동일
  106. newsData.value = response.list.map((item, index) => {
  107. // 번호 = 전체개수 - ((현재페이지-1) * 페이지크기 + 인덱스)
  108. const displayNumber = totalCount - ((currentPageNum - 1) * pageSize + index);
  109. return {
  110. id: displayNumber, // 순차적인 번호로 표시
  111. title: item.title,
  112. date: item.regdate,
  113. link: `/contact/noticeView?idx=${item.board_idx}`, // 실제 링크는 board_idx 사용
  114. };
  115. });
  116. } else {
  117. console.error("JSON 응답 형식이 올바르지 않습니다:", response);
  118. newsData.value = [];
  119. }
  120. } else if (typeof response === "string") {
  121. // HTML 응답인 경우 (백엔드에서 AJAX 감지 실패시)
  122. console.warn("HTML 응답을 받았습니다. AJAX 감지가 실패했을 수 있습니다.");
  123. console.log("HTML 내용:", response.substring(0, 200) + "...");
  124. newsData.value = [];
  125. } else {
  126. console.error("예상하지 못한 응답 형식:", typeof response, response);
  127. newsData.value = [];
  128. }
  129. } catch (error) {
  130. console.error("공지사항 데이터 로드 실패:", error);
  131. // 에러시 기본 더미 데이터 사용
  132. } finally {
  133. loading.value = false;
  134. }
  135. };
  136. // 페이지네이션 로직
  137. const currentPage = ref(1);
  138. const itemsPerPage = 10;
  139. const totalPages = computed(() => Math.ceil(newsData.value.length / itemsPerPage));
  140. const paginatedNews = computed(() => {
  141. const start = (currentPage.value - 1) * itemsPerPage;
  142. const end = start + itemsPerPage;
  143. return newsData.value.slice(start, end);
  144. });
  145. const goToPage = (page) => {
  146. if (page >= 1 && page <= totalPages.value) {
  147. currentPage.value = page;
  148. fetchNoticeList(page);
  149. }
  150. };
  151. const nextPage = () => {
  152. if (currentPage.value < totalPages.value) {
  153. currentPage.value++;
  154. fetchNoticeList(currentPage.value);
  155. }
  156. };
  157. const prevPage = () => {
  158. if (currentPage.value > 1) {
  159. currentPage.value--;
  160. fetchNoticeList(currentPage.value);
  161. }
  162. };
  163. // 컴포넌트 마운트 시 데이터 로드
  164. onMounted(() => {
  165. fetchNoticeList(1);
  166. });
  167. </script>