patents.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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="isModalOpen"
  51. title="특허 / 인증 크게보기"
  52. :close="false"
  53. >
  54. <UButton @click="openModal(patent.image)" 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="isModalOpen = false" class="modal--close--btn"></UButton>
  62. <div class="modal--img--container">
  63. <img :src="selectedImage" alt="" />
  64. </div>
  65. </template>
  66. </UModal>
  67. <UModal
  68. v-model:open="isModalOpen"
  69. title="특허 / 인증 크게보기"
  70. :close="false"
  71. >
  72. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  73. <div class="img--wrap">
  74. <img src="/img/top_ban_technology.jpg" alt="" />
  75. </div>
  76. <h4>플라스틱 감축 소재 인증서</h4>
  77. </UButton>
  78. <template #content>
  79. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  80. <div class="modal--img--container">
  81. <img :src="selectedImage" alt="" />
  82. </div>
  83. </template>
  84. </UModal>
  85. <UModal
  86. v-model:open="isModalOpen"
  87. title="특허 / 인증 크게보기"
  88. :close="false"
  89. >
  90. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  91. <div class="img--wrap">
  92. <img src="/img/top_ban_technology.jpg" alt="" />
  93. </div>
  94. <h4>플라스틱 감축 소재 인증서</h4>
  95. </UButton>
  96. <template #content>
  97. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  98. <div class="modal--img--container">
  99. <img :src="selectedImage" alt="" />
  100. </div>
  101. </template>
  102. </UModal>
  103. <UModal
  104. v-model:open="isModalOpen"
  105. title="특허 / 인증 크게보기"
  106. :close="false"
  107. >
  108. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  109. <div class="img--wrap">
  110. <img src="/img/top_ban_technology.jpg" alt="" />
  111. </div>
  112. <h4>플라스틱 감축 소재 인증서</h4>
  113. </UButton>
  114. <template #content>
  115. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  116. <div class="modal--img--container">
  117. <img :src="selectedImage" alt="" />
  118. </div>
  119. </template>
  120. </UModal>
  121. <UModal
  122. v-model:open="isModalOpen"
  123. title="특허 / 인증 크게보기"
  124. :close="false"
  125. >
  126. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  127. <div class="img--wrap">
  128. <img src="/img/top_ban_technology.jpg" alt="" />
  129. </div>
  130. <h4>플라스틱 감축 소재 인증서</h4>
  131. </UButton>
  132. <template #content>
  133. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  134. <div class="modal--img--container">
  135. <img :src="selectedImage" alt="" />
  136. </div>
  137. </template>
  138. </UModal>
  139. <UModal
  140. v-model:open="isModalOpen"
  141. title="특허 / 인증 크게보기"
  142. :close="false"
  143. >
  144. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  145. <div class="img--wrap">
  146. <img src="/img/top_ban_technology.jpg" alt="" />
  147. </div>
  148. <h4>플라스틱 감축 소재 인증서</h4>
  149. </UButton>
  150. <template #content>
  151. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  152. <div class="modal--img--container">
  153. <img :src="selectedImage" alt="" />
  154. </div>
  155. </template>
  156. </UModal>
  157. <UModal
  158. v-model:open="isModalOpen"
  159. title="특허 / 인증 크게보기"
  160. :close="false"
  161. >
  162. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  163. <div class="img--wrap">
  164. <img src="/img/top_ban_technology.jpg" alt="" />
  165. </div>
  166. <h4>플라스틱 감축 소재 인증서</h4>
  167. </UButton>
  168. <template #content>
  169. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  170. <div class="modal--img--container">
  171. <img :src="selectedImage" alt="" />
  172. </div>
  173. </template>
  174. </UModal>
  175. <UModal
  176. v-model:open="isModalOpen"
  177. title="특허 / 인증 크게보기"
  178. :close="false"
  179. >
  180. <UButton @click="openModal('/img/top_ban_technology.jpg')" class="patents">
  181. <div class="img--wrap">
  182. <img src="/img/top_ban_technology.jpg" alt="" />
  183. </div>
  184. <h4>플라스틱 감축 소재 인증서</h4>
  185. </UButton>
  186. <template #content>
  187. <UButton @click="isModalOpen = false" class="modal--close--btn"></UButton>
  188. <div class="modal--img--container">
  189. <img :src="selectedImage" alt="" />
  190. </div>
  191. </template>
  192. </UModal>
  193. </div>
  194. <div class="pagination--wrap">
  195. <UButton
  196. @click="prevPage"
  197. class="prev--btn"
  198. :disabled="currentPage === 1"
  199. ></UButton>
  200. <div class="numbs">
  201. <UButton
  202. v-for="page in totalPages"
  203. :key="page"
  204. @click="goToPage(page)"
  205. :class="{ active: currentPage === page }"
  206. >
  207. {{ page }}
  208. </UButton>
  209. </div>
  210. <UButton
  211. @click="nextPage"
  212. class="next--btn"
  213. :disabled="currentPage === totalPages"
  214. ></UButton>
  215. </div>
  216. </div>
  217. </div>
  218. </section>
  219. </main>
  220. </template>
  221. <script setup>
  222. import { ref, computed, onMounted } from "vue";
  223. import TopVisual from "~/components/topVisual.vue";
  224. const className = ref("technology");
  225. const title = ref("Technology");
  226. const isModalOpen = ref(false);
  227. const loading = ref(true);
  228. const patentsData = ref([]);
  229. const totalCount = ref(0);
  230. const selectedCategory = ref("all");
  231. const allPatentsData = ref([]); // 전체 데이터 저장용
  232. const navigation = ref([
  233. {
  234. name: "Technology",
  235. link: "/technology/patents",
  236. gnbList: [
  237. { name: "Company", link: "/company/intro" },
  238. { name: "Product", link: "/products/materials" },
  239. { name: "Technology", link: "/technology/facilities" },
  240. { name: "Media", link: "/media/news" },
  241. { name: "Contact", link: "/contact/notice" },
  242. ],
  243. },
  244. {
  245. name: "특허 / 인증",
  246. link: "/technology/patents",
  247. gnbList: [
  248. { name: "시설", link: "/technology/facilities" },
  249. { name: "특허 / 인증", link: "/technology/patents" },
  250. ],
  251. },
  252. ]);
  253. const selectedImage = ref("/img/img--patents.png");
  254. // 전체 데이터 가져오기 (4개 API 합쳐서)
  255. const fetchAllPatents = async () => {
  256. try {
  257. loading.value = true;
  258. const apis = ["technology1", "technology2", "technology3", "technology4"];
  259. let allData = [];
  260. for (const api of apis) {
  261. const response = await $postForm(`/board_list/${api}`, {
  262. boardId: api,
  263. page: 1,
  264. searchKind: "",
  265. searchKeyword: "",
  266. });
  267. if (response && response.success && response.list) {
  268. const categoryName = getCategoryName(api);
  269. const categoryData = response.list.map((item, index) => ({
  270. id: `${api}_${item.board_idx || index}`,
  271. title: item.title,
  272. category: categoryName,
  273. image: item.main_file1
  274. ? `http://green.interscope.co.kr/backend${item.main_file1}`
  275. : "/img/img--patents.png",
  276. }));
  277. allData = [...allData, ...categoryData];
  278. }
  279. }
  280. patentsData.value = allData;
  281. totalCount.value = allData.length;
  282. } catch (error) {
  283. console.error("전체 데이터 로드 실패:", error);
  284. setDefaultPatentsData();
  285. } finally {
  286. loading.value = false;
  287. }
  288. };
  289. // 카테고리별 데이터 가져오기
  290. const fetchPatentsByCategory = async (category) => {
  291. try {
  292. loading.value = true;
  293. const response = await $postForm(`/board_list/${category}`, {
  294. boardId: category,
  295. page: 1,
  296. searchKind: "",
  297. searchKeyword: "",
  298. });
  299. if (response && typeof response === "object") {
  300. if (response.success && response.list) {
  301. totalCount.value = response.totalCount || response.list.length;
  302. const categoryName = getCategoryName(category);
  303. patentsData.value = response.list.map((item, index) => ({
  304. id: `${category}_${item.board_idx || index}`,
  305. title: item.title,
  306. category: categoryName,
  307. image: item.main_file1
  308. ? `http://green.interscope.co.kr/backend${item.main_file1}`
  309. : "/img/img--patents.png",
  310. }));
  311. } else {
  312. console.error("JSON 응답 형식이 올바르지 않습니다:", response);
  313. setDefaultPatentsData();
  314. }
  315. } else {
  316. console.error("예상하지 못한 응답 형식:", typeof response, response);
  317. setDefaultPatentsData();
  318. }
  319. } catch (error) {
  320. console.error("특허/인증 데이터 로드 실패:", error);
  321. setDefaultPatentsData();
  322. } finally {
  323. loading.value = false;
  324. }
  325. };
  326. // 카테고리 이름 맵핑
  327. const getCategoryName = (apiName) => {
  328. const categoryMap = {
  329. technology1: "특허증",
  330. technology2: "인증서",
  331. technology3: "성적서",
  332. technology4: "MSD&TDS",
  333. };
  334. return categoryMap[apiName] || "기타";
  335. };
  336. // 기본 더미 데이터 설정
  337. const setDefaultPatentsData = () => {
  338. patentsData.value = [
  339. {
  340. id: 1,
  341. title: "플라스틱 감축 소재 인증서",
  342. image: "/img/img--patents.png",
  343. },
  344. {
  345. id: 2,
  346. title: "플라스틱 감축 소재 인증서",
  347. image: "/img/top_ban_technology.jpg",
  348. },
  349. ];
  350. };
  351. // 카테고리별 필터링 함수
  352. const filterByCategory = async (category) => {
  353. selectedCategory.value = category;
  354. currentPage.value = 1;
  355. if (category === "all") {
  356. await fetchAllPatents();
  357. } else {
  358. await fetchPatentsByCategory(category);
  359. }
  360. };
  361. // 페이지네이션 로직
  362. const currentPage = ref(1);
  363. const itemsPerPage = 8;
  364. const backendPageSize = 20;
  365. const totalPages = computed(() => Math.ceil(totalCount.value / itemsPerPage));
  366. const paginatedPatents = computed(() => {
  367. const start = (currentPage.value - 1) * itemsPerPage;
  368. const end = start + itemsPerPage;
  369. return patentsData.value.slice(start, end);
  370. });
  371. const needToFetchData = (targetPage) => {
  372. const startIndex = (targetPage - 1) * itemsPerPage;
  373. const endIndex = startIndex + itemsPerPage - 1;
  374. return (
  375. endIndex >= patentsData.value.length && patentsData.value.length < totalCount.value
  376. );
  377. };
  378. const goToPage = (page) => {
  379. if (page >= 1 && page <= totalPages.value) {
  380. currentPage.value = page;
  381. }
  382. };
  383. const nextPage = async () => {
  384. if (currentPage.value < totalPages.value) {
  385. await goToPage(currentPage.value + 1);
  386. }
  387. };
  388. const prevPage = async () => {
  389. if (currentPage.value > 1) {
  390. await goToPage(currentPage.value - 1);
  391. }
  392. };
  393. const openModal = (imagePath) => {
  394. selectedImage.value = imagePath;
  395. isModalOpen.value = true;
  396. };
  397. // 컴포넌트 마운트 시 데이터 로드
  398. onMounted(() => {
  399. fetchAllPatents(); // 초기에는 전체 데이터 로드
  400. });
  401. </script>