noticeView.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <template>
  2. <main>
  3. <section class="">
  4. <div class="sub--container type4">
  5. <div class="view--wrap" v-if="!loading">
  6. <div class="view--title">
  7. <h3>{{ noticeData.title }}</h3>
  8. <div class="view--info">
  9. <p>{{ noticeData.name }}</p>
  10. <span class="bar mobile"></span>
  11. <p>{{ noticeData.regdate }}</p>
  12. <span class="bar"></span>
  13. <p>조회수 : {{ noticeData.viewcnt }}</p>
  14. </div>
  15. </div>
  16. <div class="view--cont">
  17. <div v-html="noticeData.contents"></div>
  18. </div>
  19. <div class="btn--wrap">
  20. <NuxtLink to="/contact/notice">목록</NuxtLink>
  21. </div>
  22. <div class="link--wrap">
  23. <NuxtLink
  24. v-if="prevData && prevData.board_idx"
  25. :to="`/contact/noticeView?idx=${prevData.board_idx}`"
  26. class="link"
  27. >
  28. <p>이전글</p>
  29. <h5>{{ prevData.title }}</h5>
  30. <span>{{ prevData.regdate || "-" }}</span>
  31. </NuxtLink>
  32. <div v-if="!prevData || !prevData.board_idx" class="link">
  33. <p>이전글</p>
  34. <h5>이전글이 없습니다.</h5>
  35. <span>-</span>
  36. </div>
  37. <NuxtLink
  38. v-if="nextData && nextData.board_idx"
  39. :to="`/contact/noticeView?idx=${nextData.board_idx}`"
  40. class="link"
  41. >
  42. <p>다음글</p>
  43. <h5>{{ nextData.title }}</h5>
  44. <span>{{ nextData.regdate || "-" }}</span>
  45. </NuxtLink>
  46. <div v-if="!nextData || !nextData.board_idx" class="link">
  47. <p>다음글</p>
  48. <h5>다음글이 없습니다.</h5>
  49. <span>-</span>
  50. </div>
  51. </div>
  52. </div>
  53. <div v-else class="loading">
  54. <p>로딩 중...</p>
  55. </div>
  56. </div>
  57. </section>
  58. </main>
  59. </template>
  60. <script setup>
  61. import { ref, onMounted, onUnmounted, watch } from "vue";
  62. const route = useRoute();
  63. const idx = route.query.idx;
  64. console.log("현재 라우트:", route);
  65. console.log("받은 idx:", idx);
  66. const loading = ref(true);
  67. const noticeData = ref({
  68. title: "",
  69. name: "",
  70. regdate: "",
  71. viewcnt: 0,
  72. contents: "",
  73. });
  74. const nextData = ref(null);
  75. const prevData = ref(null);
  76. let scrollObserver = null;
  77. // 공지사항 상세 데이터 가져오기
  78. const fetchNoticeDetail = async () => {
  79. try {
  80. loading.value = true;
  81. const currentIdx = route.query.idx;
  82. if (!currentIdx) {
  83. throw new Error("게시글 ID가 없습니다.");
  84. }
  85. // POST 방식으로 파라미터 전달 (수정됨 - 2025-01-17)
  86. console.log("POST 요청 전송 중:", { boardId: "notice", boardIdx: currentIdx });
  87. const response = await $postForm("/board_view", {
  88. boardId: "notice",
  89. boardIdx: currentIdx,
  90. });
  91. console.log("받은 상세 데이터:", response);
  92. if (response && response.success && response.view) {
  93. noticeData.value = {
  94. title: response.view.title || "",
  95. name: response.view.name || "그린웨일글로벌(주)",
  96. regdate: response.view.regdate || "",
  97. viewcnt: response.view.viewcnt || 0,
  98. contents: response.view.contents || "",
  99. };
  100. // 이전글/다음글 데이터
  101. nextData.value = response.next;
  102. prevData.value = response.prev;
  103. console.log("nextData:", nextData.value);
  104. console.log("prevData:", prevData.value);
  105. } else {
  106. throw new Error("게시글을 찾을 수 없습니다.");
  107. }
  108. } catch (error) {
  109. console.error("공지사항 상세 데이터 로드 실패:", error);
  110. alert("게시글을 불러올 수 없습니다.");
  111. navigateTo("/contact/notice");
  112. } finally {
  113. loading.value = false;
  114. }
  115. };
  116. // URL 파라미터 변경 감지를 위한 watcher 추가
  117. watch(
  118. () => route.query.idx,
  119. (newIdx) => {
  120. if (newIdx) {
  121. fetchNoticeDetail();
  122. }
  123. }
  124. );
  125. onMounted(() => {
  126. // 데이터 로드
  127. fetchNoticeDetail();
  128. // 헤더 스타일 처리
  129. const header = document.querySelector(".header--wrap");
  130. if (header) {
  131. header.classList.add("white");
  132. // MutationObserver로 클래스 변경 감지 및 방지
  133. scrollObserver = new MutationObserver((mutations) => {
  134. mutations.forEach((mutation) => {
  135. if (mutation.type === "attributes" && mutation.attributeName === "class") {
  136. if (!header.classList.contains("white")) {
  137. header.classList.add("white");
  138. }
  139. }
  140. });
  141. });
  142. scrollObserver.observe(header, {
  143. attributes: true,
  144. attributeFilter: ["class"],
  145. });
  146. }
  147. });
  148. onUnmounted(() => {
  149. const header = document.querySelector(".header--wrap");
  150. if (header) {
  151. header.classList.remove("white");
  152. }
  153. if (scrollObserver) {
  154. scrollObserver.disconnect();
  155. }
  156. });
  157. </script>