patents.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <template>
  2. <main>
  3. <TopVisual :className="className" :title="title" :navigation="navigation" />
  4. <section class="title--section">
  5. <div class="sub--container type2">
  6. <div class="title--wrap">
  7. <h2 class="title">
  8. 그린웨일글로벌은 까다롭기로 유명한 <br />
  9. <strong>친환경 플라스틱 관련 미국 특허 및 유럽 인증을 획득</strong>하여
  10. <br />그 기술력을 입증받았습니다.
  11. </h2>
  12. </div>
  13. <div class="tab--wrap patents">
  14. <a
  15. @click="filterByCategory('all')"
  16. :class="{ active: selectedCategory === 'all' }"
  17. href="javascript:void(0)"
  18. >전체</a
  19. >
  20. <a
  21. @click="filterByCategory('technology1')"
  22. :class="{ active: selectedCategory === 'technology1' }"
  23. href="javascript:void(0)"
  24. >특허증</a
  25. >
  26. <a
  27. @click="filterByCategory('technology2')"
  28. :class="{ active: selectedCategory === 'technology2' }"
  29. href="javascript:void(0)"
  30. >인증서</a
  31. >
  32. <a
  33. @click="filterByCategory('technology3')"
  34. :class="{ active: selectedCategory === 'technology3' }"
  35. href="javascript:void(0)"
  36. >성적서</a
  37. >
  38. <a
  39. @click="filterByCategory('technology4')"
  40. :class="{ active: selectedCategory === 'technology4' }"
  41. href="javascript:void(0)"
  42. >MSD&TDS</a
  43. >
  44. </div>
  45. <div class="patents--wrap">
  46. <div class="patents--list">
  47. <UModal
  48. v-for="patent in paginatedPatents"
  49. :key="patent.id"
  50. v-model:open="patent.isOpen"
  51. title="특허 / 인증 크게보기"
  52. :close="false"
  53. >
  54. <UButton @click="openModal(patent)" class="patents">
  55. <div class="img--wrap">
  56. <img :src="patent.image" alt="" />
  57. </div>
  58. <h4>{{ patent.title }}</h4>
  59. </UButton>
  60. <template #content>
  61. <UButton
  62. @click="patent.isOpen = false"
  63. class="modal--close--btn"
  64. ></UButton>
  65. <div class="modal--img--container">
  66. <img :src="patent.image" alt="" />
  67. </div>
  68. </template>
  69. </UModal>
  70. </div>
  71. <div class="pagination--wrap">
  72. <UButton
  73. @click="prevPage"
  74. class="prev--btn"
  75. :disabled="currentPage === 1"
  76. ></UButton>
  77. <div class="numbs">
  78. <UButton
  79. v-for="page in totalPages"
  80. :key="page"
  81. @click="goToPage(page)"
  82. :class="{ active: currentPage === page }"
  83. >
  84. {{ page }}
  85. </UButton>
  86. </div>
  87. <UButton
  88. @click="nextPage"
  89. class="next--btn"
  90. :disabled="currentPage === totalPages"
  91. ></UButton>
  92. </div>
  93. </div>
  94. </div>
  95. </section>
  96. </main>
  97. </template>
  98. <script setup>
  99. import { ref, computed, onMounted } from "vue";
  100. import TopVisual from "~/components/topVisual.vue";
  101. const className = ref("technology");
  102. const title = ref("Technology");
  103. const loading = ref(true);
  104. const patentsData = ref([]);
  105. const totalCount = ref(0);
  106. const selectedCategory = ref("all");
  107. const allPatentsData = ref([]); // 전체 데이터 저장용
  108. const navigation = ref([
  109. {
  110. name: "Technology",
  111. link: "/technology/patents",
  112. gnbList: [
  113. { name: "Company", link: "/company/intro" },
  114. { name: "Product", link: "/products/materials" },
  115. { name: "Technology", link: "/technology/facilities" },
  116. { name: "Media", link: "/media/news" },
  117. { name: "Contact", link: "/contact/notice" },
  118. ],
  119. },
  120. {
  121. name: "특허 / 인증",
  122. link: "/technology/patents",
  123. gnbList: [
  124. { name: "시설", link: "/technology/facilities" },
  125. { name: "특허 / 인증", link: "/technology/patents" },
  126. ],
  127. },
  128. ]);
  129. // 전체 데이터 가져오기 (4개 API 합쳐서)
  130. const fetchAllPatents = async () => {
  131. try {
  132. loading.value = true;
  133. const apis = ["technology1", "technology2", "technology3", "technology4"];
  134. let allData = [];
  135. for (const api of apis) {
  136. const response = await $postForm(`/board_list/${api}`, {
  137. boardId: api,
  138. page: 1,
  139. searchKind: "",
  140. searchKeyword: "",
  141. });
  142. if (response && response.success && response.list) {
  143. const categoryName = getCategoryName(api);
  144. const categoryData = response.list.map((item, index) => ({
  145. id: `${api}_${item.board_idx || index}`,
  146. title: item.title,
  147. category: categoryName,
  148. image: item.main_file1
  149. ? `https://www.greenwhaleglobal.com/backend${item.main_file1}`
  150. : "/img/img--patents.png",
  151. isOpen: false, // 각 항목별 모달 상태
  152. }));
  153. allData = [...allData, ...categoryData];
  154. }
  155. }
  156. patentsData.value = allData;
  157. totalCount.value = allData.length;
  158. } catch (error) {
  159. console.error("전체 데이터 로드 실패:", error);
  160. setDefaultPatentsData();
  161. } finally {
  162. loading.value = false;
  163. }
  164. };
  165. // 카테고리별 데이터 가져오기
  166. const fetchPatentsByCategory = async (category) => {
  167. try {
  168. loading.value = true;
  169. const response = await $postForm(`/board_list/${category}`, {
  170. boardId: category,
  171. page: 1,
  172. searchKind: "",
  173. searchKeyword: "",
  174. });
  175. if (response && typeof response === "object") {
  176. if (response.success && response.list) {
  177. totalCount.value = response.totalCount || response.list.length;
  178. const categoryName = getCategoryName(category);
  179. patentsData.value = response.list.map((item, index) => ({
  180. id: `${category}_${item.board_idx || index}`,
  181. title: item.title,
  182. category: categoryName,
  183. image: item.main_file1
  184. ? `https://www.greenwhaleglobal.com/backend${item.main_file1}`
  185. : "/img/img--patents.png",
  186. isOpen: false, // 각 항목별 모달 상태
  187. }));
  188. } else {
  189. console.error("JSON 응답 형식이 올바르지 않습니다:", response);
  190. setDefaultPatentsData();
  191. }
  192. } else {
  193. console.error("예상하지 못한 응답 형식:", typeof response, response);
  194. setDefaultPatentsData();
  195. }
  196. } catch (error) {
  197. console.error("특허/인증 데이터 로드 실패:", error);
  198. setDefaultPatentsData();
  199. } finally {
  200. loading.value = false;
  201. }
  202. };
  203. // 카테고리 이름 맵핑
  204. const getCategoryName = (apiName) => {
  205. const categoryMap = {
  206. technology1: "특허증",
  207. technology2: "인증서",
  208. technology3: "성적서",
  209. technology4: "MSD&TDS",
  210. };
  211. return categoryMap[apiName] || "기타";
  212. };
  213. // 기본 더미 데이터 설정
  214. const setDefaultPatentsData = () => {
  215. patentsData.value = [
  216. {
  217. id: 1,
  218. title: "플라스틱 감축 소재 인증서",
  219. image: "/img/img--patents.png",
  220. isOpen: false,
  221. },
  222. {
  223. id: 2,
  224. title: "플라스틱 감축 소재 인증서",
  225. image: "/img/top_ban_technology.jpg",
  226. isOpen: false,
  227. },
  228. ];
  229. };
  230. // 카테고리별 필터링 함수
  231. const filterByCategory = async (category) => {
  232. selectedCategory.value = category;
  233. currentPage.value = 1;
  234. if (category === "all") {
  235. await fetchAllPatents();
  236. } else {
  237. await fetchPatentsByCategory(category);
  238. }
  239. };
  240. // 페이지네이션 로직
  241. const currentPage = ref(1);
  242. const itemsPerPage = 8;
  243. const backendPageSize = 20;
  244. const totalPages = computed(() => Math.ceil(totalCount.value / itemsPerPage));
  245. const paginatedPatents = computed(() => {
  246. const start = (currentPage.value - 1) * itemsPerPage;
  247. const end = start + itemsPerPage;
  248. return patentsData.value.slice(start, end);
  249. });
  250. const needToFetchData = (targetPage) => {
  251. const startIndex = (targetPage - 1) * itemsPerPage;
  252. const endIndex = startIndex + itemsPerPage - 1;
  253. return (
  254. endIndex >= patentsData.value.length && patentsData.value.length < totalCount.value
  255. );
  256. };
  257. const goToPage = (page) => {
  258. if (page >= 1 && page <= totalPages.value) {
  259. currentPage.value = page;
  260. }
  261. };
  262. const nextPage = async () => {
  263. if (currentPage.value < totalPages.value) {
  264. await goToPage(currentPage.value + 1);
  265. }
  266. };
  267. const prevPage = async () => {
  268. if (currentPage.value > 1) {
  269. await goToPage(currentPage.value - 1);
  270. }
  271. };
  272. const openModal = (patent) => {
  273. patent.isOpen = true;
  274. };
  275. // 컴포넌트 마운트 시 데이터 로드
  276. onMounted(() => {
  277. fetchAllPatents(); // 초기에는 전체 데이터 로드
  278. });
  279. </script>