diff --git a/public/css/custom.css b/public/css/custom.css index 182e491..2ac47f0 100644 --- a/public/css/custom.css +++ b/public/css/custom.css @@ -3,22 +3,33 @@ /* 휴가 */ -.fc-daygrid-day-events { - max-height: 100px !important; - overflow-y: auto !important; -} + /* 이벤트 선 없게 */ .fc-event { border: none; } -/* 오전전반차 그래프 */ +/* 오전 반차 그래프 (왼쪽 절반) */ .fc-daygrid-event.half-day-am { - width: calc(50% - 4px) !important; + width: 50% !important; + height: 8px !important; + border-radius: 2px !important; + font-size: 0px !important; } -/* 오후반차 그래프프 */ +/* 오후 반차 그래프 (오른쪽 절반) */ .fc-daygrid-event.half-day-pm { - width: calc(50% - 4px) !important; - margin-left: auto !important + width: 50% !important; + height: 8px !important; + margin-left: auto !important; + border-radius: 2px !important; + font-size: 0px !important; +} +/* 연차 그래프 (풀풀) */ +.fc-daygrid-event.full-day { + width: 100% !important; + height: 8px !important; + margin-left: auto !important; + border-radius: 2px !important; + font-size: 0px !important; } /* 공휴일,일요일 색상 */ .fc-day-sun .fc-daygrid-day-number, @@ -39,8 +50,8 @@ .flatpickr-calendar:after { display: none !important; } - /* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */ - .fc-toolbar-title { +/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */ +.fc-toolbar-title { cursor: pointer; } /* 클릭 가능한 날짜 (오늘 + 미래) */ @@ -84,7 +95,6 @@ opacity: 0.6; /* 흐려 보이게 */ /* 본인 모달 */ - /* 닫기 버튼 */ .close-btn { position: absolute; @@ -109,7 +119,6 @@ opacity: 0.6; /* 흐려 보이게 */ /* 선물하기 모달 */ - /* 연차 개수 버튼 */ .count-btn { font-size: 18px; @@ -127,7 +136,6 @@ opacity: 0.6; /* 흐려 보이게 */ background: #cccccc; cursor: not-allowed; } - /* 버튼 컨테이너 (우측 정렬) */ .custom-button-container { display: flex; @@ -141,18 +149,17 @@ opacity: 0.6; /* 흐려 보이게 */ padding: 10px; /* 크기 조정 */ cursor: pointer; /* 클릭 가능하도록 변경 */ } - /* 아이콘 색상 변경 (기본) */ .custom-button i { color: #282538; /* 기본 아이콘 색상 */ font-size: 25px; /* 아이콘 크기 */ } - /* 버튼 호버 효과 */ .custom-button:hover i { color: #ff0800; /* 호버 시 아이콘 색상 변경 */ } + .grayscaleImg { filter: grayscale(100%); } diff --git a/public/img/mbti/enfj.png b/public/img/mbti/enfj.png new file mode 100644 index 0000000..2d85491 Binary files /dev/null and b/public/img/mbti/enfj.png differ diff --git a/public/img/mbti/enfp.png b/public/img/mbti/enfp.png new file mode 100644 index 0000000..abc6c69 Binary files /dev/null and b/public/img/mbti/enfp.png differ diff --git a/public/img/mbti/entj.png b/public/img/mbti/entj.png new file mode 100644 index 0000000..7ef1341 Binary files /dev/null and b/public/img/mbti/entj.png differ diff --git a/public/img/mbti/entp.png b/public/img/mbti/entp.png new file mode 100644 index 0000000..84b2a11 Binary files /dev/null and b/public/img/mbti/entp.png differ diff --git a/public/img/mbti/esfj.png b/public/img/mbti/esfj.png new file mode 100644 index 0000000..0548975 Binary files /dev/null and b/public/img/mbti/esfj.png differ diff --git a/public/img/mbti/esfp.png b/public/img/mbti/esfp.png new file mode 100644 index 0000000..a3932e6 Binary files /dev/null and b/public/img/mbti/esfp.png differ diff --git a/public/img/mbti/est.png b/public/img/mbti/est.png new file mode 100644 index 0000000..720aa00 Binary files /dev/null and b/public/img/mbti/est.png differ diff --git a/public/img/mbti/estp.png b/public/img/mbti/estp.png new file mode 100644 index 0000000..036e95f Binary files /dev/null and b/public/img/mbti/estp.png differ diff --git a/public/img/mbti/infj.png b/public/img/mbti/infj.png new file mode 100644 index 0000000..4660186 Binary files /dev/null and b/public/img/mbti/infj.png differ diff --git a/public/img/mbti/infp.png b/public/img/mbti/infp.png new file mode 100644 index 0000000..442b8dd Binary files /dev/null and b/public/img/mbti/infp.png differ diff --git a/public/img/mbti/intj.png b/public/img/mbti/intj.png new file mode 100644 index 0000000..39b06a2 Binary files /dev/null and b/public/img/mbti/intj.png differ diff --git a/public/img/mbti/intp.png b/public/img/mbti/intp.png new file mode 100644 index 0000000..8dbb981 Binary files /dev/null and b/public/img/mbti/intp.png differ diff --git a/public/img/mbti/isfj.png b/public/img/mbti/isfj.png new file mode 100644 index 0000000..7dad009 Binary files /dev/null and b/public/img/mbti/isfj.png differ diff --git a/public/img/mbti/isfp.png b/public/img/mbti/isfp.png new file mode 100644 index 0000000..61e4bad Binary files /dev/null and b/public/img/mbti/isfp.png differ diff --git a/public/img/mbti/istj.png b/public/img/mbti/istj.png new file mode 100644 index 0000000..4924396 Binary files /dev/null and b/public/img/mbti/istj.png differ diff --git a/public/img/mbti/istp.png b/public/img/mbti/istp.png new file mode 100644 index 0000000..276f39c Binary files /dev/null and b/public/img/mbti/istp.png differ diff --git a/src/components/board/BoardComment.vue b/src/components/board/BoardComment.vue index ded58dc..205d5a6 100644 --- a/src/components/board/BoardComment.vue +++ b/src/components/board/BoardComment.vue @@ -11,35 +11,29 @@ :isLike="!isLike" :isCommentPassword="isCommentPassword" :isCommentProfile="true" - @editClick="aaaa" + @editClick="handleEditClick" @deleteClick="$emit('deleteClick', comment)" @updateReaction="handleUpdateReaction" - /> - - + /> -
+
{{ passwordCommentAlert }}
- -
@@ -58,10 +52,6 @@ :key="child.commentId" class="mt-8 pt-6 ps-10 border-top" > - - - -

child.isCommentPassword: {{ child.isCommentPassword }}

@@ -120,14 +115,19 @@ const props = defineProps({ }, passwordCommentAlert: { type: String, - default: false - } + default: '' + }, + currentPasswordCommentId: { + type: Number + }, + password:{ + type: String + }, }); // emits 정의 -const emit = defineEmits(['submitComment', 'updateReaction', 'editClick', 'deleteClick', 'submitPassword', 'submitEdit', 'cancelEdit']); +const emit = defineEmits(['submitComment', 'updateReaction', 'editClick', 'deleteClick', 'submitPassword', 'submitEdit', 'cancelEdit', 'update:password']); -const password = ref(''); const localEditedContent = ref(props.comment.content); // 댓글 입력 창 토글 @@ -154,8 +154,8 @@ const handleUpdateReaction = (reactionData) => { // 비밀번호 확인 const logPasswordAndEmit = () => { - emit('submitPassword', props.comment, password.value); - password.value = ""; + console.log('비밀번호 확인',props.password) + emit('submitPassword', props.comment, props.password); }; watch(() => props.comment.isEditTextarea, (newVal) => { @@ -169,8 +169,12 @@ const submitEdit = () => { emit('submitEdit', props.comment, localEditedContent.value); }; -const aaaa = () => { +const handleEditClick = () => { emit('editClick', props.comment); } +const handleReplyEditClick = (comment) => { + emit('editClick', comment); +} + diff --git a/src/components/board/BoardCommentArea.vue b/src/components/board/BoardCommentArea.vue index 4f2fca2..ed153ab 100644 --- a/src/components/board/BoardCommentArea.vue +++ b/src/components/board/BoardCommentArea.vue @@ -51,10 +51,7 @@
- +
@@ -63,6 +60,7 @@ diff --git a/src/components/board/BoardProfile.vue b/src/components/board/BoardProfile.vue index c3c4f91..71c1c2e 100644 --- a/src/components/board/BoardProfile.vue +++ b/src/components/board/BoardProfile.vue @@ -4,6 +4,7 @@
Avatar
+
{{ profileName }}
@@ -81,7 +82,7 @@ const props = defineProps({ isCommentProfile: Boolean, // 현재 컴포넌트가 댓글용인지 여부 date: { type: String, - required: true, + required: '', }, views: { type: Number, @@ -117,6 +118,10 @@ const handleUpdateReaction = (reactionData) => { }); }; +const getProfileImage = (profilePath) => { + return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile; +}; + diff --git a/src/components/button/BoardRecommendBtn.vue b/src/components/button/BoardRecommendBtn.vue index e297eb7..8ffa805 100644 --- a/src/components/button/BoardRecommendBtn.vue +++ b/src/components/button/BoardRecommendBtn.vue @@ -13,7 +13,7 @@ import { ref, computed } from 'vue'; const props = defineProps({ comment: { type: Object, - required: true, + default: () => ({}), }, likeClicked : { type : Boolean, @@ -36,7 +36,7 @@ const props = defineProps({ required: true, }, commentId: { - type: Number, + type: [Number, null], default: null, }, likeCount: { diff --git a/src/components/button/HalfDayButtons.vue b/src/components/button/HalfDayButtons.vue index 9bb125f..36739fc 100644 --- a/src/components/button/HalfDayButtons.vue +++ b/src/components/button/HalfDayButtons.vue @@ -28,10 +28,11 @@ \ No newline at end of file + + +const selected = computed(() => { + const selectedItem = props.data.find(item => + props.isCommon ? item.value === selectData.value : props.data.indexOf(item) === selectData.value + ); + return selectedItem ? selectedItem.label : null; +}); + + diff --git a/src/components/user/FindPassword.vue b/src/components/user/FindPassword.vue index 0260908..09866eb 100644 --- a/src/components/user/FindPassword.vue +++ b/src/components/user/FindPassword.vue @@ -68,20 +68,21 @@ :is-alert="passwordcheckAlert" @update:data="passwordcheck = $event" @update:alert="passwordcheckAlert = $event" - @blur="checkPw" + @input="checkPw" :value="passwordcheck" /> {{ passwordcheckError }} -
- -

{{ pwErrMsg }}

+
+ +
+

{{ pwErrMsg }}

diff --git a/src/components/user/RegisterForm.vue b/src/components/user/RegisterForm.vue index 2953ea3..5a5b557 100644 --- a/src/components/user/RegisterForm.vue +++ b/src/components/user/RegisterForm.vue @@ -92,6 +92,7 @@ :is-row="false" :is-label="true" :is-common="true" + :is-color="true" :data="colorList" @update:data="color = $event" class="w-50" @@ -118,6 +119,7 @@ :is-row="false" :is-label="true" :is-common="true" + :is-mbti="true" :data="mbtiList" @update:data="mbti = $event" class="w-50" diff --git a/src/views/board/BoardList.vue b/src/views/board/BoardList.vue index 095e5e3..3ac8ef0 100644 --- a/src/views/board/BoardList.vue +++ b/src/views/board/BoardList.vue @@ -195,10 +195,7 @@ const fetchGeneralPosts = async (page = 1) => { }); if (data?.data) { - // console.log(data) - const totalPosts = data.data.total; // 전체 게시물 개수 받아오기 - - // console.log('📌 API 응답 데이터:', data.data); + const totalPosts = data.data.total; generalList.value = data.data.list.map((post, index) => ({ realId: post.id, diff --git a/src/views/board/BoardView.vue b/src/views/board/BoardView.vue index 3edd703..08411aa 100644 --- a/src/views/board/BoardView.vue +++ b/src/views/board/BoardView.vue @@ -27,6 +27,7 @@ class="form-control" v-model="password" placeholder="비밀번호 입력" + @input="password = password.replace(/\s/g, '')" />
@@ -76,13 +77,7 @@ @updateReaction="handleUpdateReaction" />
- - - - - + @@ -106,9 +100,11 @@ { isCommentAuthor: reply.authorId === currentUserId.value, })) })); - // console.log("✅ commentsWithAuthStatus 업데이트됨:", updatedComments); return updatedComments; }); @@ -183,10 +179,15 @@ const passwordAlert = ref(""); const passwordCommentAlert = ref(""); const isPassword = ref(false); const isCommentPassword = ref(false); +const currentPasswordCommentId = ref(null); const lastClickedButton = ref(""); const lastCommentClickedButton = ref(""); const isEditTextarea = ref(false); -const commentAlert = ref('') +const commentAlert = ref(''); + +const updatePassword = (newPassword) => { + password.value = newPassword; +}; const pagination = ref({ currentPage: 1, @@ -210,20 +211,12 @@ const fetchBoardDetails = async () => { const response = await axios.get(`board/${currentBoardId.value}`); const data = response.data.data; - // console.log(data) // API 응답 데이터 반영 // const boardDetail = data.boardDetail || {}; profileName.value = data.author || '익명'; - // 익명확인하고 싶을때 - // profileName.value = '익명'; - - // console.log("📌 게시글 작성자:", profileName.value); // 작성자 이름 출력 - // console.log("🔍 익명 여부 (unknown.value):", unknown.value); // 익명 여부 확인 - - authorId.value = data.authorId; //게시글 작성자 id boardTitle.value = data.title || '제목 없음'; boardContent.value = data.content || ''; @@ -245,7 +238,6 @@ const handleUpdateReaction = async ({ boardId, commentId, isLike, isDislike }) = await axios.post(`/board/${boardId}/${commentId}/reaction`, { LOCBRDSEQ: boardId, // 게시글 id LOCCMTSEQ: commentId, //댓글 id - // MEMBERSEQ: 1, // 멤버아이디 지금은 1 나중에 수정해야함 LOCGOBGOD: isLike ? 'T' : 'F', LOCGOBBAD: isDislike ? 'T' : 'F' }); @@ -258,13 +250,9 @@ const handleUpdateReaction = async ({ boardId, commentId, isLike, isDislike }) = likeClicked.value = isLike; dislikeClicked.value = isDislike; - // console.log(updatedData) - - // console.log("갱신된 데이터:", updatedData); } catch (error) { alert('오류가 발생했습니다.'); - // console.log('반응을 업데이트하는 중 오류가 발생했습니다.'); } }; @@ -281,13 +269,10 @@ const handleCommentReaction = async ({ boardId, commentId, isLike, isDislike }) LOCGOBBAD: isDislike ? 'T' : 'F' }); - // console.log("댓글 좋아요 API 응답 데이터:", response.data); - await fetchComments(); } catch (error) { alert('오류가 발생했습니다.'); - // console.log('댓글 반응을 업데이트하는 중 오류 발생'); } }; @@ -302,8 +287,6 @@ const fetchComments = async (page = 1) => { } }); - // console.log(response.data.data) - const commentsList = response.data.data.list.map(comment => ({ commentId: comment.LOCCMTSEQ, // 댓글 ID boardId: comment.LOCBRDSEQ, @@ -320,6 +303,8 @@ const fetchComments = async (page = 1) => { children: [], // 대댓글을 담을 배열 })); + commentsList.sort((a, b) => b.createdAtRaw - a.createdAtRaw); + for (const comment of commentsList) { if (!comment.commentId) continue; @@ -327,8 +312,6 @@ const fetchComments = async (page = 1) => { params: { LOCCMTPNT: comment.commentId } }); - // console.log(`대댓글 데이터 (${comment.commentId}의 대댓글):`, replyResponse.data); - if (replyResponse.data.data) { comment.children = replyResponse.data.data.map(reply => ({ author: reply.author || '익명', @@ -368,23 +351,19 @@ const fetchComments = async (page = 1) => { navigateLastPage: response.data.data.navigateLastPage // 페이지네이션에서 마지막 페이지 번호 }; - // console.log("📌 댓글 목록:", comments.value); - } catch (error) { alert('오류가 발생했습니다.'); - // alert('댓글 목록 불러오기 오류:', error); } }; // 댓글 작성 -const handleCommentSubmit = async (data, isCheck) => { +const handleCommentSubmit = async (data) => { if (!data) { - console.error("handleCommentSubmit: data가 undefined입니다."); return; } - const { comment, password } = data; + const { comment, password, isCheck } = data; if (!comment || comment.trim() === "") { commentAlert.value = '댓글을 입력해주세요.'; @@ -404,25 +383,22 @@ const handleCommentSubmit = async (data, isCheck) => { LOCCMTRPY: comment, LOCCMTPWD: isCheck ? password : '', LOCCMTPNT: 1, - LOCBRDTYP: unknown.value ? "300102" : null + LOCBRDTYP: isCheck ? "300102" : null }); if (response.status === 200) { - // console.log('댓글 작성 성공:', response.data.message); passwordAlert.value = ''; commentAlert.value = ''; await fetchComments(); } else { - // console.error('댓글 작성 실패:', response.data.message); alert("댓글 작성을 실패했습니다.") } } catch (error) { - // console.error('댓글 작성 중 오류 발생:', error); alert("오류가 발생했습니다.") } }; -// 대댓글 추가 (부모 `BoardCommentList`로부터 이벤트 받아서 처리) +// 대댓글 추가 const handleCommentReply = async (reply) => { try { const response = await axios.post(`board/${currentBoardId.value}/comment`, { @@ -434,22 +410,17 @@ const handleCommentReply = async (reply) => { }); if (response.status === 200) { - if (response.data.code === 200) { // 서버 응답 코드도 확인 - // console.log('대댓글 작성 성공:', response.data); - await fetchComments(); // 댓글 목록 새로고침 + if (response.data.code === 200) { + await fetchComments(); } else { - // console.log('대댓글 작성 실패 - 서버 응답:', response.data); alert('대댓글 작성을 실패했습니다.'); } } } catch (error) { - // console.error('대댓글 작성 중 오류 발생:', error); if (error.response) { - // console.error('서버 응답 에러:', error.response.data); alert("오류가 발생했습니다."); } alert("오류가 발생했습니다."); - } } @@ -486,45 +457,41 @@ const findCommentById = (commentId, commentsList) => { return null; }; -// 댓글 수정 버튼 클릭 +// 댓글 수정(대댓글 포함) const editComment = (comment) => { - - // 부모 또는 대댓글을 찾아서 가져오기 + password.value = ''; + passwordCommentAlert.value = ''; + currentPasswordCommentId.value = null; + const targetComment = findCommentById(comment.commentId, comments.value); if (!targetComment) { return; } - // 댓글 작성자가 현재 로그인한 사용자와 동일한지 확인 const isMyComment = comment.authorId === currentUserId.value; const isAnonymous = comment.author === "익명"; if (isMyComment) { - // 본인 댓글이면 바로 수정 모드 활성화 - targetComment.isEditTextarea = true; + targetComment.isEditTextarea = !targetComment.isEditTextarea; + lastCommentClickedButton.value = "edit"; } else if (isAnonymous) { - // 익명 댓글이면 비밀번호 입력창 띄우기 + if (targetComment.isEditTextarea) return; toggleCommentPassword(comment, "edit"); - } else { - // console.log("다른 사용자 댓글 - 수정 불가"); alert("수정이 불가능합니다"); } } // 댓글 삭제 버튼 클릭 const deleteComment = async (comment) => { - // 익명 사용자인 경우 const isMyComment = comment.authorId === currentUserId.value; if (unknown.value && !isMyComment) { if (comment.isEditTextarea) { - // 현재 수정 중이라면 수정 모드를 끄고, 삭제 비밀번호 입력창을 띄움 comment.isEditTextarea = false; comment.isCommentPassword = true; } else { - // 수정 중이 아니면 기존의 삭제 비밀번호 입력창을 띄우는 로직 실행 toggleCommentPassword(comment, "delete"); } } else { @@ -532,19 +499,21 @@ const deleteComment = async (comment) => { } }; -// 익명 비밀번호 창 토글 +// 익명 댓글 비밀번호 창 토글 const toggleCommentPassword = (comment, button) => { - if (lastCommentClickedButton.value === button && isCommentPassword.value === comment.commentId) { - isCommentPassword.value = false; // 비밀번호 창 닫기 + if (lastCommentClickedButton.value === button && currentPasswordCommentId.value === comment.commentId) { + currentPasswordCommentId.value = null; // 비밀번호 창 닫기 + password.value = ''; + passwordCommentAlert.value = ''; } else { - isCommentPassword.value = comment.commentId; // 비밀번호 창 열기 + currentPasswordCommentId.value = comment.commentId; // 비밀번호 창 열기 + password.value = ''; + passwordCommentAlert.value = ''; } lastCommentClickedButton.value = button; }; - - const togglePassword = (button) => { if (lastClickedButton.value === button) { isPassword.value = !isPassword.value; @@ -556,16 +525,15 @@ const togglePassword = (button) => { // 게시글 비밀번호 제출 const submitPassword = async () => { - if (!password.value) { + if (!password.value.trim()) { passwordAlert.value = "비밀번호를 입력해주세요."; return; } - // console.log("📌 요청 시작: submitPassword 실행됨"); try { const response = await axios.post(`board/${currentBoardId.value}/password`, { LOCBRDPWD: password.value, - LOCBRDSEQ: 288, // 나중에 현재 게시글 ID 사용해야함 + LOCBRDSEQ: 288, }); if (response.data.code === 200 && response.data.data === true) { @@ -582,8 +550,6 @@ const submitPassword = async () => { passwordAlert.value = "비밀번호가 일치하지 않습니다."; } } catch (error) { - // console.log("📌 전체 오류:", error); - if (error.response) { if (error.response.status === 401) { passwordAlert.value = "비밀번호가 일치하지 않습니다."; @@ -598,34 +564,38 @@ const submitPassword = async () => { } }; -// 댓글 삭제 (비밀번호 확인 후) +// 댓글 (비밀번호 확인 후) const submitCommentPassword = async (comment, password) => { - - // console.log("비밀번호 :", password); - // console.log("댓글 ID:", comment.commentId); - if (!password) { passwordCommentAlert.value = "비밀번호를 입력해주세요."; return; } + const targetComment = findCommentById(comment.commentId, comments.value); + try { - // console.log('서버로 비밀번호 확인 요청') const response = await axios.post(`board/comment/${comment.commentId}/password`, { LOCCMTPWD: password, LOCCMTSEQ: comment.commentId, }); - // console.log("✅ 서버 응답 데이터:", response.data); if (response.data.code === 200 && response.data.data === true) { passwordCommentAlert.value = ""; comment.isCommentPassword = false; + // 수정 if (lastCommentClickedButton.value === "edit") { - comment.isEditTextarea = true; - passwordCommentAlert.value = ""; - // handleSubmitEdit(comment, comment.content); + if (targetComment) { + //여기서 input 창 닫혀야함 + targetComment.isEditTextarea = true; + passwordCommentAlert.value = ""; + currentPasswordCommentId.value = null; + + } else { + alert("수정 취소를 실패했습니다."); + } + //삭제 } else if (lastCommentClickedButton.value === "delete") { passwordCommentAlert.value = ""; @@ -633,14 +603,12 @@ const submitCommentPassword = async (comment, password) => { } lastCommentClickedButton.value = null; } else { - // console.log("❌ 비밀번호가 틀림"); passwordCommentAlert.value = "비밀번호가 일치하지 않습니다."; } } catch (error) { - // console.log("🚨 서버 요청 중 오류 발생:", error.response?.data || error); - // if (error.response?.status === 401) { - // console.log("❌ 401 오류: 인증 실패 (비밀번호 불일치)"); - // } + if (error.response?.status === 401) { + passwordCommentAlert.value = "비밀번호가 일치하지 않습니다"; + } passwordCommentAlert.value = "비밀번호가 일치하지 않습니다"; } }; @@ -672,24 +640,18 @@ const deletePost = async () => { // 댓글 삭제 (대댓글 포함) const deleteReplyComment = async (comment) => { if (!confirm("정말 이 댓글을 삭제하시겠습니까?")) return; - // console.log("댓글 ID:", comment); try { const response = await axios.delete(`board/comment/${comment.commentId}`, { data: { LOCCMTSEQ: comment.commentId } }); - // console.log("서버 응답:", response.data); - if (response.data.code === 200) { - // console.log("댓글 삭제 성공!"); await fetchComments(); } else { - // console.log("댓글 삭제 실패:", response.data.message); alert("댓글 삭제에 실패했습니다."); } } catch (error) { - // console.log("댓글 삭제 중 오류 발생:", error); alert("댓글 삭제 중 오류가 발생했습니다."); } }; @@ -702,9 +664,6 @@ const handleSubmitEdit = async (comment, editedContent) => { LOCCMTRPY: editedContent }); - // 수정 성공 시 업데이트 - // comment.content = editedContent; - // comment.isEditTextarea = false; f if (response.status === 200) { const targetComment = findCommentById(comment.commentId, comments.value); @@ -712,15 +671,12 @@ const handleSubmitEdit = async (comment, editedContent) => { targetComment.content = editedContent; // 댓글 내용 업데이트 targetComment.isEditTextarea = false; // 수정 모드 닫기 } else { - // console.warn("❌ 수정할 댓글을 찾을 수 없음"); alert("수정할 댓글을 찾을 수 없습니다."); } } else { - // console.log("❌ 댓글 수정 실패:", response.data); alert("댓글 수정 실패했습니다."); } } catch (error) { - // console.error("댓글 수정 중 오류 발생:", error); alert("댓글 수정 중 오류 발생했습니다."); } }; @@ -730,10 +686,8 @@ const handleCancelEdit = (comment) => { const targetComment = findCommentById(comment.commentId, comments.value); if (targetComment) { - // console.log("✅ 원본 데이터 찾음, 수정 취소 처리 가능:", targetComment); targetComment.isEditTextarea = false; } else { - // console.error("❌ 원본 데이터 찾을 수 없음, 수정 취소 실패"); alert("수정 취소를 실패했습니다."); } }; @@ -756,7 +710,7 @@ const handleCommentDeleted = (deletedCommentId) => { return; } - // 2대댓글 삭제 + // 대댓글 삭제 for (let parent of comments.value) { const childIndex = parent.children.findIndex(child => child.commentId === deletedCommentId); if (childIndex !== -1) { @@ -764,11 +718,8 @@ const handleCommentDeleted = (deletedCommentId) => { return; } } - - // console.error("❌ 삭제할 댓글을 찾을 수 없음:", deletedCommentId); }; - // 날짜 const formattedDate = (dateString) => { if (!dateString) return "날짜 없음"; diff --git a/src/views/board/BoardWrite.vue b/src/views/board/BoardWrite.vue index b337d6c..45d2657 100644 --- a/src/views/board/BoardWrite.vue +++ b/src/views/board/BoardWrite.vue @@ -9,12 +9,15 @@
+ @@ -32,16 +35,19 @@ :id="`category-${index}`" :value="category.CMNCODVAL" v-model="categoryValue" + @change="categoryAlert = false" />
-
카테고리를 선택해주세요.
+
+ 카테고리를 선택해주세요. +
- +
@@ -61,14 +69,16 @@ @update:isValid="isFileValid = $event" /> +
-
@@ -115,10 +125,9 @@ const fetchCategories = async () => { try { const response = await axios.get('board/categories'); categoryList.value = response.data.data; - // "자유" 카테고리 찾기 (CMNCODNAM이 '자유'인 것 선택) const freeCategory = categoryList.value.find(category => category.CMNCODNAM === '자유'); if (freeCategory) { - categoryValue.value = freeCategory.CMNCODVAL; // 기본 선택값 설정 + categoryValue.value = freeCategory.CMNCODVAL; } } catch (error) { console.error('카테고리 불러오기 오류:', error); @@ -129,15 +138,44 @@ onMounted(() => { fetchCategories(); }); +// 제목 유효성 검사: 공백만 입력하면 경고 유지, 문자 포함 시 정상 +const validateTitle = () => { + titleAlert.value = title.value.trim().length === 0; +}; + +// 비밀번호 유효성 검사: 공백 입력 방지 +const validatePassword = () => { + password.value = password.value.replace(/\s/g, ""); // 공백 제거 + passwordAlert.value = password.value.length === 0; +}; + +// 에디터에서 업데이트된 데이터를 반영하는 함수 +const updateContent = (data) => { + let rawText = ''; + + if (typeof data === 'object' && data.ops) { + rawText = data.ops.map(op => (typeof op.insert === 'string' ? op.insert : '')).join('').trim(); + } else if (typeof data === 'string') { + rawText = data.replace(/(<([^>]+)>)/gi, "").trim(); + } else { + rawText = ''; + } + + content.value = rawText.length > 0 ? data : ""; + contentAlert.value = rawText.length === 0; +}; + +/** 페이지 이동 (목록으로 이동) */ const goList = () => { router.push('/board'); }; const write = async () => { - titleAlert.value = !title.value; - passwordAlert.value = categoryValue.value === 300102 && !password.value; - contentAlert.value = !content.value; + validateTitle(); + validatePassword(); + categoryAlert.value = !categoryValue.value; + contentAlert.value = content.value.length === 0; if (titleAlert.value || passwordAlert.value || contentAlert.value || categoryAlert.value || !isFileValid.value) { return; @@ -154,26 +192,6 @@ const write = async () => { const { data: boardResponse } = await axios.post('board', boardData); const boardId = boardResponse.data; - if (attachFiles.value && attachFiles.value.length > 0) { - for (const file of attachFiles.value) { - const formData = new FormData(); - const fileNameWithoutExt = file.name.replace(/\.[^/.]+$/, ''); - - formData.append('CMNBRDSEQ', boardId); - formData.append('CMNFLEORG', fileNameWithoutExt); - formData.append('CMNFLEEXT', file.name.split('.').pop()); - formData.append('CMNFLESIZ', file.size); - formData.append('CMNFLEPAT', 'boardfile'); - formData.append('file', file); - - await axios.post(`board/${boardId}/attachments`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }); - } - } - toastStore.onToast('게시물이 작성되었습니다.', 's'); goList(); } catch (error) { diff --git a/src/views/vacation/VacationManagement.vue b/src/views/vacation/VacationManagement.vue index f61dba6..c8ac838 100644 --- a/src/views/vacation/VacationManagement.vue +++ b/src/views/vacation/VacationManagement.vue @@ -7,9 +7,11 @@