diff --git a/src/common/axios-interceptor.js b/src/common/axios-interceptor.js index c4163dd..3dd170d 100644 --- a/src/common/axios-interceptor.js +++ b/src/common/axios-interceptor.js @@ -37,14 +37,11 @@ $api.interceptors.response.use( }, function (error) { const toastStore = useToastStore(); - const currentPage = error.config.headers['X-Page-Route']; // 오류 응답 처리 if (error.response) { switch (error.response.status) { case 401: - if (currentPage === '/login') { - toastStore.onToast('아이디 혹은 비밀번호가 틀렸습니다.', 'e'); - } else { + if (!error.config.headers.isLogin) { toastStore.onToast('인증이 필요합니다.', 'e'); } break; diff --git a/src/common/common.js b/src/common/common.js index 5436651..e2f7f2d 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -1,18 +1,18 @@ /* 작성자 : 공현지 작성일 : 2025-01-17 - 수정자 : - 수정일 : + 수정자 : + 수정일 : 설명 : 공통 스크립트 */ import Quill from 'quill'; /* - *템플릿 사용법 : $common.변수 + *템플릿 사용법 : $common.변수 *setup() 사용법 : const { appContext } = getCurrentInstance(); - const $common = appContext.config.globalProperties.$common; - $common.변수 + const $common = appContext.config.globalProperties.$common; + $common.변수 */ const common = { // JSON 문자열로 Delta 타입을 변환 @@ -40,39 +40,39 @@ const common = { return null; // Delta 객체가 아니거나 ops가 없을 경우 null 반환 }, - /** - * Date 타입 문자열 포멧팅 - * - * @param {string} dateStr - * @return - * 1. Date type 인 경우 예시 '25-02-24 12:02' - * 2. Date type 이 아닌 경우 입력값 리턴 - * - */ - dateFormatter(dateStr) { - const date = new Date(dateStr); - const dateCheck = date.getTime(); +// /** +// * Date 타입 문자열 포멧팅 +// * +// * @param {string} dateStr +// * @return +// * 1. Date type 인 경우 예시 '25-02-24 12:02' +// * 2. Date type 이 아닌 경우 입력값 리턴 +// * +// */ +// dateFormatter(dateStr) { +// const date = new Date(dateStr); +// const dateCheck = date.getTime(); - if (isNaN(dateCheck)) { - return dateStr; - } else { - const { year, month, day, hours, minutes } = this.formatDateTime(date); - return `${year}-${month}-${day} ${hours}:${minutes}`; - } - }, +// if (isNaN(dateCheck)) { +// return dateStr; +// } else { +// const { year, month, day, hours, minutes } = this.formatDateTime(date); +// return `${year}-${month}-${day} ${hours}:${minutes}`; +// } +// }, - formatDateTime(date) { - const zeroFormat = num => (num < 10 ? `0${num}` : num); +// formatDateTime(date) { +// const zeroFormat = num => (num < 10 ? `0${num}` : num); - return { - year: date.getFullYear(), - month: zeroFormat(date.getMonth() + 1), - day: zeroFormat(date.getDate()), - hours: zeroFormat(date.getHours()), - minutes: zeroFormat(date.getMinutes()), - seconds: zeroFormat(date.getSeconds()), - }; - }, +// return { +// year: date.getFullYear(), +// month: zeroFormat(date.getMonth() + 1), +// day: zeroFormat(date.getDate()), +// hours: zeroFormat(date.getHours()), +// minutes: zeroFormat(date.getMinutes()), +// seconds: zeroFormat(date.getSeconds()), +// }; +// }, }; export default { diff --git a/src/components/board/BoardComment.vue b/src/components/board/BoardComment.vue index 2d0c784..3518e55 100644 --- a/src/components/board/BoardComment.vue +++ b/src/components/board/BoardComment.vue @@ -124,7 +124,7 @@ const toggleComment = () => { // 부모 컴포넌트에 대댓글 추가 요청 const submitComment = (newComment) => { - emit('submitComment', { parentId: props.comment.commentId, ...newComment }); + emit('submitComment', { parentId: props.comment.commentId, ...newComment, LOCBRDTYP: newComment.LOCBRDTYP }); isComment.value = false; }; diff --git a/src/components/board/BoardCommentArea.vue b/src/components/board/BoardCommentArea.vue index 30e9084..76b93b0 100644 --- a/src/components/board/BoardCommentArea.vue +++ b/src/components/board/BoardCommentArea.vue @@ -76,26 +76,26 @@ const props = defineProps({ default: false } }); - const comment = ref(''); const password = ref(''); -const isCheck = ref(props.unknown); - +const isCheck = ref(false); const emit = defineEmits(['submitComment']); -watch(() => props.unknown, (newVal) => { - isCheck.value = newVal; -}); - function handleCommentSubmit() { + if (props.unknown && isCheck.value && !password.value) { + alert('익명 댓글을 작성하려면 비밀번호를 입력해야 합니다.'); + return; + } + const LOCBRDTYP = isCheck.value ? '300102' : null; emit('submitComment', { comment: comment.value, password: isCheck.value ? password.value : '', + LOCBRDTYP, + isCheck: isCheck.value }); comment.value = ''; password.value = ''; + isCheck.value = false; // 초기화 } - - diff --git a/src/components/board/BoardProfile.vue b/src/components/board/BoardProfile.vue index dd23985..f23c730 100644 --- a/src/components/board/BoardProfile.vue +++ b/src/components/board/BoardProfile.vue @@ -62,11 +62,8 @@ const props = defineProps({ }, profileName: { type: String, -<<<<<<< HEAD default: '익명', -======= default: '', ->>>>>>> board-comment }, unknown: { type: Boolean, diff --git a/src/views/board/BoardView.vue b/src/views/board/BoardView.vue index 5919576..8514b98 100644 --- a/src/views/board/BoardView.vue +++ b/src/views/board/BoardView.vue @@ -76,9 +76,9 @@ @updateReaction="handleUpdateReaction" /> -

현재 로그인한 사용자 ID: {{ currentUserId }}

+ @@ -94,6 +94,7 @@ @@ -139,6 +140,7 @@ import { ref, onMounted, computed } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { useUserInfoStore } from '@/stores/useUserInfoStore'; import axios from '@api'; +import { formattedDate } from '@/common/formattedDate.js'; // 게시물 데이터 상태 const profileName = ref(''); @@ -158,22 +160,19 @@ const route = useRoute(); const router = useRouter(); const userStore = useUserInfoStore(); const currentBoardId = ref(Number(route.params.id)); -<<<<<<< HEAD const unknown = computed(() => profileName.value === '익명'); -const currentUserId = ref('김자바'); // 현재 로그인한 사용자 id -const authorId = ref(null); // 작성자 id -======= -// const unknown = computed(() => profileName.value === '익명'); const currentUserId = computed(() => userStore.user.id); // 현재 로그인한 사용자 id const authorId = ref(''); // 작성자 id ->>>>>>> board-comment const isAuthor = computed(() => currentUserId.value === authorId.value); -// const isCommentAuthor = const commentsWithAuthStatus = computed(() => { const updatedComments = comments.value.map(comment => ({ ...comment, - isCommentAuthor: comment.authorId === currentUserId.value + isCommentAuthor: comment.authorId === currentUserId.value, + children: comment.children.map(reply => ({ + ...reply, + isCommentAuthor: reply.authorId === currentUserId.value + })) })); // console.log("✅ commentsWithAuthStatus 업데이트됨:", updatedComments); return updatedComments; @@ -188,6 +187,7 @@ const isCommentPassword = ref(false); const lastClickedButton = ref(""); const lastCommentClickedButton = ref(""); const isEditTextarea = ref(false); +const commentAlert = ref('') const pagination = ref({ currentPage: 1, @@ -211,29 +211,21 @@ const fetchBoardDetails = async () => { const response = await axios.get(`board/${currentBoardId.value}`); const data = response.data.data; - console.log(data) + // console.log(data) // API 응답 데이터 반영 // const boardDetail = data.boardDetail || {}; -<<<<<<< HEAD profileName.value = data.author || '익명'; - // 익명확인하고 싶을때 - // profileName.value = 'null; - - // 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부 - authorId.value = data.author; - -======= - profileName.value = data.author; - // 익명확인하고 싶을때 // profileName.value = '익명'; + console.log("📌 게시글 작성자:", profileName.value); // 작성자 이름 출력 + console.log("🔍 익명 여부 (unknown.value):", unknown.value); // 익명 여부 확인 + authorId.value = data.authorId; //게시글 작성자 id ->>>>>>> board-comment boardTitle.value = data.title || '제목 없음'; boardContent.value = data.content || ''; date.value = data.date || ''; @@ -309,20 +301,14 @@ const fetchComments = async (page = 1) => { } }); -<<<<<<< HEAD -======= - console.log(response.data.data) + // console.log(response.data.data) ->>>>>>> board-comment const commentsList = response.data.data.list.map(comment => ({ commentId: comment.LOCCMTSEQ, // 댓글 ID boardId: comment.LOCBRDSEQ, parentId: comment.LOCCMTPNT, // 부모 ID author: comment.author || '익명', -<<<<<<< HEAD -======= authorId: comment.authorId, ->>>>>>> board-comment content: comment.LOCCMTRPY, likeCount: comment.likeCount || 0, dislikeCount: comment.dislikeCount || 0, @@ -340,10 +326,12 @@ const fetchComments = async (page = 1) => { params: { LOCCMTPNT: comment.commentId } }); - console.log(`대댓글 데이터 (${comment.commentId}의 대댓글):`, replyResponse.data); + // console.log(`대댓글 데이터 (${comment.commentId}의 대댓글):`, replyResponse.data); if (replyResponse.data.data) { comment.children = replyResponse.data.data.map(reply => ({ + author: reply.author || '익명', + authorId: reply.authorId, commentId: reply.LOCCMTSEQ, boardId: reply.LOCBRDSEQ, parentId: reply.LOCCMTPNT, // 부모 댓글 ID @@ -386,29 +374,19 @@ const fetchComments = async (page = 1) => { console.log('댓글 목록 불러오기 오류:', error); } }; -// const isSubmitting = ref(false); // 댓글 작성 -const handleCommentSubmit = async ({ comment, password }) => { - console.log('댓글') - //비밀번호 입력 안했을시 - // if (!password) { - // passwordAlert.value = "비밀번호를 입력해야 합니다."; - // return; - // } - - // console.log('비밀번호 눌렀음') - - // 중복 실행 방지 - // if (isSubmitting.value) return; - // isSubmitting.value = true; +const handleCommentSubmit = async (data) => { + const { comment, password } = data; + const LOCBRDTYP = data.LOCBRDTYP || null; // undefined 방지 try { const response = await axios.post(`board/${currentBoardId.value}/comment`, { LOCBRDSEQ: currentBoardId.value, LOCCMTRPY: comment, LOCCMTPWD: password, - LOCCMTPNT: 1 + LOCCMTPNT: 1, + LOCBRDTYP // 익명 여부 전달 }); if (response.status === 200) { @@ -426,48 +404,41 @@ const handleCommentSubmit = async ({ comment, password }) => { // 대댓글 추가 (부모 `BoardCommentList`로부터 이벤트 받아서 처리) const handleCommentReply = async (reply) => { try { - // console.log('대댓글 작성 요청 데이터:', { - // LOCBRDSEQ: currentBoardId.value, - // LOCCMTRPY: reply.comment, - // LOCCMTPWD: reply.password || null, - // LOCCMTPNT: reply.parentId - // }); + // 익명 여부 체크 (체크박스가 체크되었을 경우 LOCBRDTYP을 300102로 설정) - const response = await axios.post(`board/${currentBoardId.value}/comment`, { + const requestBody = { LOCBRDSEQ: currentBoardId.value, LOCCMTRPY: reply.comment, LOCCMTPWD: reply.password || null, - LOCCMTPNT: reply.parentId - }); - - // 응답 데이터를 자세히 로그로 확인 - // console.log('대댓글 작성 응답:', { - // status: response.status, - // data: response.data, - // headers: response.headers - // }); + LOCCMTPNT: reply.parentId, + LOCBRDTYP: reply.isCheck ? "300102" : null + }; + console.log(requestBody) + const response = await axios.post(`board/${currentBoardId.value}/comment`, requestBody); if (response.status === 200) { - if (response.data.code === 200) { // 서버 응답 코드도 확인 - console.log('대댓글 작성 성공:', response.data); - await fetchComments(); // 댓글 목록 새로고침 + if (response.data.code === 200) { + console.log('✅ 대댓글 작성 성공:', response.data); + await fetchComments(); } else { - console.log('대댓글 작성 실패 - 서버 응답:', response.data); + console.log('❌ 대댓글 작성 실패 - 서버 응답:', response.data); alert('대댓글 작성에 실패했습니다.'); } } } catch (error) { - console.error('대댓글 작성 중 오류 발생:', error); + console.error('🚨 대댓글 작성 중 오류 발생:', error); if (error.response) { - console.error('서버 응답 에러:', error.response.data); + console.error('📌 서버 응답 에러:', error.response.data); } - alert('대댓글 작성 중 오류가 발생했습니다.'); + alert('❌ 대댓글 작성 중 오류가 발생했습니다.'); } -} +}; // 게시글 수정 버튼 클릭 const editClick = (unknown) => { - if (unknown) { + const isUnknown = unknown?.unknown ?? false; + + if (isUnknown) { togglePassword("edit"); } else { router.push({ name: "BoardEdit", params: { id: currentBoardId.value } }); @@ -483,47 +454,50 @@ const deleteClick = (unknown) => { } }; +const findCommentById = (commentId, commentsList) => { + for (const comment of commentsList) { + if (comment.commentId === commentId) { + return comment; // 부모 댓글일 경우 + } + if (comment.children && comment.children.length) { + const found = findCommentById(commentId, comment.children); + if (found) return found; // 대댓글일 경우 + } + } + return null; +}; + // 댓글 수정 버튼 클릭 const editComment = (comment) => { - const targetComment = comments.value.find(c => c.commentId === comment.commentId); + console.log('대댓글 수정 버튼 클릭') + + // 부모 또는 대댓글을 찾아서 가져오기 + const targetComment = findCommentById(comment.commentId, comments.value); if (!targetComment) { + console.log("대댓글을 찾을 수 없음:", comment.commentId); return; } - // 수정 text창 열림, 닫힘 유무 - if (targetComment.isEditTextarea) { - targetComment.isEditTextarea = false; - } else { - targetComment.isEditTextarea = true; - } + // 수정 text창 열림, 닫힘 유무 토글 + targetComment.isEditTextarea = !targetComment.isEditTextarea; - // 익명일때 + // 익명일 경우 비밀번호 입력창 활성화 if (unknown.value) { toggleCommentPassword(comment, "edit"); - } else { - comment.isEditTextarea = true; } -<<<<<<< HEAD - - // comments.value.forEach(c => { - // c.isEditTextarea = false; - // c.isCommentPassword = false; - // }); - - // if (comment.unknown) { - // comment.isCommentPassword = true; - // } else { - // comment.isEditTextarea = true; - // } -======= ->>>>>>> board-comment } // 댓글 삭제 버튼 클릭 const deleteComment = async (comment) => { + console.log('🗑 댓글 삭제 시도:', comment); + // 익명 사용자인 경우 - if (unknown.value) { + const isMyComment = comment.authorId === currentUserId.value; + + if (unknown.value && !isMyComment) { + console.log('🛑 익명 사용자의 댓글 삭제 시도 (비밀번호 필요)'); + if (comment.isEditTextarea) { // 현재 수정 중이라면 수정 모드를 끄고, 삭제 비밀번호 입력창을 띄움 comment.isEditTextarea = false; @@ -533,8 +507,8 @@ const deleteComment = async (comment) => { toggleCommentPassword(comment, "delete"); } } else { - // 로그인 사용자인 경우 (바로 삭제) - deleteReplyComment(comment) + console.log('✅ 로그인 사용자 댓글 삭제 진행'); + deleteReplyComment(comment); } }; @@ -626,11 +600,8 @@ const submitCommentPassword = async (comment, password) => { if (lastCommentClickedButton.value === "edit") { comment.isEditTextarea = true; -<<<<<<< HEAD -======= passwordCommentAlert.value = ""; ->>>>>>> board-comment // handleSubmitEdit(comment, comment.content); } else if (lastCommentClickedButton.value === "delete") { passwordCommentAlert.value = ""; @@ -704,19 +675,20 @@ const handleSubmitEdit = async (comment, editedContent) => { }); // 수정 성공 시 업데이트 -<<<<<<< HEAD - comment.content = editedContent; - comment.isEditTextarea = false; -======= // comment.content = editedContent; - // comment.isEditTextarea = false; + // comment.isEditTextarea = false; f if (response.status === 200) { - // 댓글 목록 새로고침 - await fetchComments(); + + const targetComment = findCommentById(comment.commentId, comments.value); + if (targetComment) { + targetComment.content = editedContent; // 댓글 내용 업데이트 + targetComment.isEditTextarea = false; // 수정 모드 닫기 + } else { + console.warn("❌ 수정할 댓글을 찾을 수 없음"); + } } else { console.log("❌ 댓글 수정 실패:", response.data); } ->>>>>>> board-comment } catch (error) { console.error("댓글 수정 중 오류 발생:", error); } @@ -724,13 +696,10 @@ const handleSubmitEdit = async (comment, editedContent) => { // 댓글 수정 취소 (대댓글 포함) const handleCancelEdit = (comment) => { - console.log("BoardView.vue - 댓글 수정 취소:", comment); - - // 원본 comments 배열에서 동일한 comment 찾기 - const targetComment = comments.value.find(c => c.commentId === comment.commentId); + const targetComment = findCommentById(comment.commentId, comments.value); if (targetComment) { - console.log("✅ 원본 데이터 찾음, 수정 취소 처리 가능"); + console.log("✅ 원본 데이터 찾음, 수정 취소 처리 가능:", targetComment); targetComment.isEditTextarea = false; } else { console.error("❌ 원본 데이터 찾을 수 없음, 수정 취소 실패"); @@ -745,15 +714,26 @@ const handlePageChange = (page) => { } }; +// 댓글 삭제 (대댓글 포함) const handleCommentDeleted = (deletedCommentId) => { - comments.value = comments.value.filter(comment => comment.commentId !== deletedCommentId); -}; + // 댓글 삭제 + const parentIndex = comments.value.findIndex(comment => comment.commentId === deletedCommentId); -// 날짜 -const formattedDate = (dateString) => { - if (!dateString) return "날짜 없음"; - const dateObj = new Date(dateString); - return `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, '0')}-${String(dateObj.getDate()).padStart(2, '0')} ${String(dateObj.getHours()).padStart(2, '0')}:${String(dateObj.getMinutes()).padStart(2, '0')}`; + if (parentIndex !== -1) { + comments.value.splice(parentIndex, 1); + return; + } + + // 2대댓글 삭제 + for (let parent of comments.value) { + const childIndex = parent.children.findIndex(child => child.commentId === deletedCommentId); + if (childIndex !== -1) { + parent.children.splice(childIndex, 1); + return; + } + } + + console.error("❌ 삭제할 댓글을 찾을 수 없음:", deletedCommentId); }; const formattedBoardDate = computed(() => formattedDate(date.value));