patents.vue 9.0 KB

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