Compare commits

...

6 Commits

5 changed files with 180 additions and 92 deletions

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<BoardProfile <BoardProfile
:unknown="unknown" :unknown="comment.author === '익명'"
:isCommentAuthor="isCommentAuthor" :isCommentAuthor="isCommentAuthor"
:boardId="comment.boardId" :boardId="comment.boardId"
:profileName="comment.author" :profileName="comment.author"
@ -11,7 +11,7 @@
:isLike="!isLike" :isLike="!isLike"
:isCommentPassword="comment.isCommentPassword" :isCommentPassword="comment.isCommentPassword"
:isCommentProfile="true" :isCommentProfile="true"
@editClick="$emit('editClick', comment)" @editClick="aaaa"
@deleteClick="$emit('deleteClick', comment)" @deleteClick="$emit('deleteClick', comment)"
@updateReaction="handleUpdateReaction" @updateReaction="handleUpdateReaction"
/> />
@ -29,8 +29,8 @@
</div> </div>
<span v-if="passwordCommentAlert" class="invalid-feedback d-block text-start">{{ passwordCommentAlert }}</span> <span v-if="passwordCommentAlert" class="invalid-feedback d-block text-start">{{ passwordCommentAlert }}</span>
</div> </div>
<p>authorId:{{ comment.authorId }}</p> <!-- <p>authorId:{{ comment.authorId }}</p>
<p>코멘트 비교: {{comment.isCommentAuthor}}</p> <p>코멘트 비교: {{comment.isCommentAuthor}}</p> -->
<div class="mt-6"> <div class="mt-6">
@ -47,20 +47,29 @@
</div> </div>
<PlusButton v-if="isPlusButton" @click="toggleComment" class="mt-6"/> <PlusButton v-if="isPlusButton" @click="toggleComment" class="mt-6"/>
<BoardCommentArea v-if="isComment" @submitComment="submitComment"/> <BoardCommentArea v-if="isComment" :unknown="unknown" @submitComment="submitComment"/>
<!-- 대댓글 --> <!-- 대댓글 -->
<ul v-if="comment.children && comment.children.length" class="list-unstyled"> <ul v-if="comment.children && comment.children.length" class="list-unstyled">
<li <li
v-for="child in comment.children" v-for="child in comment.children"
:key="child.commentId" :key="child.commentId"
class="mt-8 pt-6 ps-10 border-top" class="mt-8 pt-6 ps-10 border-top"
> >
<!-- <p>대댓글 데이터(JSON): {{ JSON.stringify(child, null, 2) }}</p> -->
<!-- <p>comment child: {{ comment.children }}</p> -->
<!-- :unknown="child.author === '익명'" -->
<BoardComment <BoardComment
:comment="child" :comment="child"
:unknown="unknown" :unknown="child.author === '익명'"
:isPlusButton="false" :isPlusButton="false"
:isLike="true" :isLike="true"
:isCommentProfile="true"
:isCommentAuthor="child.isCommentAuthor"
@editClick="$emit('editClick', $event)"
@deleteClick="$emit('deleteClick', child)"
@submitEdit="(comment, editedContent) => $emit('submitEdit', comment, editedContent)"
@cancelEdit="$emit('cancelEdit', child)"
@submitComment="submitComment" @submitComment="submitComment"
@updateReaction="handleUpdateReaction" @updateReaction="handleUpdateReaction"
/> />
@ -155,4 +164,8 @@ const submitEdit = () => {
emit('submitEdit', props.comment, localEditedContent.value); emit('submitEdit', props.comment, localEditedContent.value);
}; };
const aaaa = () => {
emit('editClick', props.comment);
}
</script> </script>

View File

@ -17,6 +17,7 @@
rows="3" rows="3"
v-model="comment" v-model="comment"
></textarea> ></textarea>
<span v-if="commentAlert" class="invalid-feedback d-block text-start ms-2">{{ commentAlert }}</span>
</div> </div>
</div> </div>
@ -42,6 +43,7 @@
id="basic-default-password" id="basic-default-password"
class="form-control flex-grow-1" class="form-control flex-grow-1"
v-model="password" v-model="password"
placeholder="비밀번호 입력"
/> />
<span v-if="passwordAlert" class="invalid-feedback d-block text-start ms-2">{{ passwordAlert }}</span> <span v-if="passwordAlert" class="invalid-feedback d-block text-start ms-2">{{ passwordAlert }}</span>
</div> </div>
@ -74,6 +76,10 @@ const props = defineProps({
passwordAlert: { passwordAlert: {
type: String, type: String,
default: false default: false
},
commentAlert: {
type: String,
default: false
} }
}); });
@ -83,19 +89,21 @@ const isCheck = ref(props.unknown);
const emit = defineEmits(['submitComment']); const emit = defineEmits(['submitComment']);
watch(() => props.unknown, (newVal) => {
isCheck.value = newVal;
});
function handleCommentSubmit() { function handleCommentSubmit() {
emit('submitComment', { emit('submitComment', {
comment: comment.value, comment: comment.value,
password: isCheck.value ? password.value : '', password: isCheck.value ? password.value : '',
isCheck: isCheck.value,
// authorId: isCheck.value ? null : currentUserId.value, // ID null
}); });
comment.value = '';
password.value = '';
} }
watch(() => props.passwordAlert, () => {
if (!props.passwordAlert) {
comment.value = '';
password.value = '';
}
});
</script> </script>

View File

@ -5,6 +5,8 @@
:key="comment.commentId" :key="comment.commentId"
class="mt-6 border-bottom pb-6" class="mt-6 border-bottom pb-6"
> >
<!-- <p>comment데이터 확인: {{ comment }}</p> -->
<!-- 여기 부분 수정 확인 부분 부터 해야함 -->
<BoardComment <BoardComment
:unknown="unknown" :unknown="unknown"
:comment="comment" :comment="comment"
@ -12,13 +14,13 @@
:isCommentPassword="comment.isCommentPassword" :isCommentPassword="comment.isCommentPassword"
:isEditTextarea="comment.isEditTextarea" :isEditTextarea="comment.isEditTextarea"
:passwordCommentAlert="passwordCommentAlert" :passwordCommentAlert="passwordCommentAlert"
@editClick="$emit('editClick', comment)" @editClick="handleEditClick"
@deleteClick="$emit('deleteClick', comment)" @deleteClick="handleDeleteClick"
@submitPassword="submitPassword" @submitPassword="submitPassword"
@submitComment="submitComment" @submitComment="submitComment"
@commentDeleted="handleCommentDeleted" @commentDeleted="handleCommentDeleted"
@submitEdit="(comment, editedContent) => $emit('submitEdit', comment, editedContent)" @submitEdit="handleSubmitEdit"
@cancelEdit="$emit('cancelEdit', comment)" @cancelEdit="handleCancelEdit"
@updateReaction="(reactionData) => handleUpdateReaction(reactionData, comment.commentId, comment.boardId)" @updateReaction="(reactionData) => handleUpdateReaction(reactionData, comment.commentId, comment.boardId)"
/> />
</li> </li>
@ -76,4 +78,29 @@ const handleUpdateReaction = (reactionData, commentId, boardId) => {
const submitPassword = (comment, password) => { const submitPassword = (comment, password) => {
emit('submitPassword', comment, password); emit('submitPassword', comment, password);
}; };
const handleEditClick = (comment) => {
emit('editClick', comment);
};
const handleSubmitEdit = (comment, editedContent) => {
emit("submitEdit", comment, editedContent);
};
const handleDeleteClick = (comment) => {
if (comment.parentId) {
emit('deleteClick', comment); //
} else {
emit('deleteClick', comment); //
}
};
const handleCancelEdit = (comment) => {
if (comment.parentId) {
emit('cancelEdit', comment); //
} else {
emit('cancelEdit', comment); //
}
};
</script> </script>

View File

@ -21,9 +21,8 @@
</div> </div>
<!-- 버튼 영역 --> <!-- 버튼 영역 -->
<div class="ms-auto text-end"> <div class="ms-auto text-end">
<!-- 수정, 삭제 버튼 --> <!-- 수정, 삭제 버튼 - 익명일때 본인일때 (게시글, 댓글)-->
<!-- <template v-if="isAuthor || showDetail"> --> <template v-if="unknown || isCommentAuthor || isAuthor">
<template v-if="isCommentProfile ? isCommentAuthor : isAuthor">
<EditButton @click.stop="editClick" /> <EditButton @click.stop="editClick" />
<DeleteButton @click.stop="deleteClick" /> <DeleteButton @click.stop="deleteClick" />
</template> </template>
@ -62,7 +61,7 @@ const props = defineProps({
}, },
profileName: { profileName: {
type: String, type: String,
default: '', default: '익명',
}, },
unknown: { unknown: {
type: Boolean, type: Boolean,
@ -101,13 +100,12 @@ const emit = defineEmits(['updateReaction', 'editClick', 'deleteClick']);
// //
const editClick = () => { const editClick = () => {
console.log('클릭 확인') emit('editClick', { ...props.comment, unknown: props.unknown });
emit('editClick', props.unknown);
}; };
// //
const deleteClick = () => { const deleteClick = () => {
emit('deleteClick', props.unknown); emit('deleteClick', { ...props.comment, unknown: props.unknown });
}; };
const handleUpdateReaction = (reactionData) => { const handleUpdateReaction = (reactionData) => {

View File

@ -76,9 +76,9 @@
@updateReaction="handleUpdateReaction" @updateReaction="handleUpdateReaction"
/> />
</div> </div>
<p>현재 로그인한 사용자 ID: {{ currentUserId }}</p> <!-- <p>현재 로그인한 사용자 ID: {{ currentUserId }}</p>
<p>게시글 작성자: {{ authorId }}</p> <p>게시글 작성자: {{ authorId }}</p>
<p>isAuthor : {{ isAuthor }}</p> <p>isAuthor : {{ isAuthor }}</p> -->
<!-- <p>use이미지:{{userStore.user.img}}</p> --> <!-- <p>use이미지:{{userStore.user.img}}</p> -->
<!-- <img :src="`http://localhost:10325/upload/img/profile/${userStore.user.profile}`" alt="Profile Image" class="w-px-40 h-auto rounded-circle"/> --> <!-- <img :src="`http://localhost:10325/upload/img/profile/${userStore.user.profile}`" alt="Profile Image" class="w-px-40 h-auto rounded-circle"/> -->
@ -94,6 +94,7 @@
<BoardCommentArea <BoardCommentArea
:profileName="profileName" :profileName="profileName"
:unknown="unknown" :unknown="unknown"
:commentAlert="commentAlert"
:passwordAlert="passwordAlert" :passwordAlert="passwordAlert"
@submitComment="handleCommentSubmit" @submitComment="handleCommentSubmit"
/> />
@ -158,16 +159,19 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
const userStore = useUserInfoStore(); const userStore = useUserInfoStore();
const currentBoardId = ref(Number(route.params.id)); const currentBoardId = ref(Number(route.params.id));
// const unknown = computed(() => profileName.value === ''); const unknown = computed(() => profileName.value === '익명');
const currentUserId = computed(() => userStore.user.id); // id const currentUserId = computed(() => userStore.user.id); // id
const authorId = ref(''); // id const authorId = ref(''); // id
const isAuthor = computed(() => currentUserId.value === authorId.value); const isAuthor = computed(() => currentUserId.value === authorId.value);
// const isCommentAuthor =
const commentsWithAuthStatus = computed(() => { const commentsWithAuthStatus = computed(() => {
const updatedComments = comments.value.map(comment => ({ const updatedComments = comments.value.map(comment => ({
...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); // console.log(" commentsWithAuthStatus :", updatedComments);
return updatedComments; return updatedComments;
@ -182,6 +186,7 @@ const isCommentPassword = ref(false);
const lastClickedButton = ref(""); const lastClickedButton = ref("");
const lastCommentClickedButton = ref(""); const lastCommentClickedButton = ref("");
const isEditTextarea = ref(false); const isEditTextarea = ref(false);
const commentAlert = ref('')
const pagination = ref({ const pagination = ref({
currentPage: 1, currentPage: 1,
@ -205,16 +210,19 @@ const fetchBoardDetails = async () => {
const response = await axios.get(`board/${currentBoardId.value}`); const response = await axios.get(`board/${currentBoardId.value}`);
const data = response.data.data; const data = response.data.data;
console.log(data) // console.log(data)
// API // API
// const boardDetail = data.boardDetail || {}; // const boardDetail = data.boardDetail || {};
profileName.value = data.author; profileName.value = data.author || '익명';
// //
// profileName.value = ''; // profileName.value = '';
console.log("📌 게시글 작성자:", profileName.value); //
console.log("🔍 익명 여부 (unknown.value):", unknown.value); //
authorId.value = data.authorId; // id authorId.value = data.authorId; // id
boardTitle.value = data.title || '제목 없음'; boardTitle.value = data.title || '제목 없음';
@ -292,7 +300,7 @@ const fetchComments = async (page = 1) => {
} }
}); });
console.log(response.data.data) // console.log(response.data.data)
const commentsList = response.data.data.list.map(comment => ({ const commentsList = response.data.data.list.map(comment => ({
commentId: comment.LOCCMTSEQ, // ID commentId: comment.LOCCMTSEQ, // ID
@ -317,10 +325,12 @@ const fetchComments = async (page = 1) => {
params: { LOCCMTPNT: comment.commentId } params: { LOCCMTPNT: comment.commentId }
}); });
console.log(`대댓글 데이터 (${comment.commentId}의 대댓글):`, replyResponse.data); // console.log(` (${comment.commentId} ):`, replyResponse.data);
if (replyResponse.data.data) { if (replyResponse.data.data) {
comment.children = replyResponse.data.data.map(reply => ({ comment.children = replyResponse.data.data.map(reply => ({
author: reply.author || '익명',
authorId: reply.authorId,
commentId: reply.LOCCMTSEQ, commentId: reply.LOCCMTSEQ,
boardId: reply.LOCBRDSEQ, boardId: reply.LOCBRDSEQ,
parentId: reply.LOCCMTPNT, // ID parentId: reply.LOCCMTPNT, // ID
@ -363,33 +373,37 @@ const fetchComments = async (page = 1) => {
console.log('댓글 목록 불러오기 오류:', error); console.log('댓글 목록 불러오기 오류:', error);
} }
}; };
// const isSubmitting = ref(false);
// //
const handleCommentSubmit = async ({ comment, password }) => { const handleCommentSubmit = async ({ comment, password, isCheck }) => {
console.log('댓글')
//
if (comment.trim() === "") {
commentAlert.value = '댓글을 입력해주세요.';
return;
} else {
commentAlert.value = '';
}
// //
// if (!password) { if (unknown.value && isCheck && !password) {
// passwordAlert.value = " ."; passwordAlert.value = "비밀번호를 입력해야 합니다.";
// return; return;
// } }
// console.log(' ')
//
// if (isSubmitting.value) return;
// isSubmitting.value = true;
try { try {
const response = await axios.post(`board/${currentBoardId.value}/comment`, { const response = await axios.post(`board/${currentBoardId.value}/comment`, {
LOCBRDSEQ: currentBoardId.value, LOCBRDSEQ: currentBoardId.value,
LOCCMTRPY: comment, LOCCMTRPY: comment,
LOCCMTPWD: password, LOCCMTPWD: isCheck ? password : '', //
LOCCMTPNT: 1 LOCCMTPNT: 1
}); });
console.log('여기',response)
if (response.status === 200) { if (response.status === 200) {
console.log('댓글 작성 성공:', response.data.message); console.log('댓글 작성 성공:', response.data.message);
passwordAlert.value = '';
commentAlert.value = '';
await fetchComments(); await fetchComments();
} else { } else {
console.log('댓글 작성 실패:', response.data.message); console.log('댓글 작성 실패:', response.data.message);
@ -403,13 +417,6 @@ const handleCommentSubmit = async ({ comment, password }) => {
// ( `BoardCommentList` ) // ( `BoardCommentList` )
const handleCommentReply = async (reply) => { const handleCommentReply = async (reply) => {
try { try {
// console.log(' :', {
// LOCBRDSEQ: currentBoardId.value,
// LOCCMTRPY: reply.comment,
// LOCCMTPWD: reply.password || null,
// LOCCMTPNT: reply.parentId
// });
const response = await axios.post(`board/${currentBoardId.value}/comment`, { const response = await axios.post(`board/${currentBoardId.value}/comment`, {
LOCBRDSEQ: currentBoardId.value, LOCBRDSEQ: currentBoardId.value,
LOCCMTRPY: reply.comment, LOCCMTRPY: reply.comment,
@ -417,13 +424,6 @@ const handleCommentReply = async (reply) => {
LOCCMTPNT: reply.parentId LOCCMTPNT: reply.parentId
}); });
//
// console.log(' :', {
// status: response.status,
// data: response.data,
// headers: response.headers
// });
if (response.status === 200) { if (response.status === 200) {
if (response.data.code === 200) { // if (response.data.code === 200) { //
console.log('대댓글 작성 성공:', response.data); console.log('대댓글 작성 성공:', response.data);
@ -444,7 +444,9 @@ const handleCommentReply = async (reply) => {
// //
const editClick = (unknown) => { const editClick = (unknown) => {
if (unknown) { const isUnknown = unknown?.unknown ?? false;
if (isUnknown) {
togglePassword("edit"); togglePassword("edit");
} else { } else {
router.push({ name: "BoardEdit", params: { id: currentBoardId.value } }); router.push({ name: "BoardEdit", params: { id: currentBoardId.value } });
@ -460,33 +462,51 @@ 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 editComment = (comment) => {
const targetComment = comments.value.find(c => c.commentId === comment.commentId); console.log('대댓글 수정 버튼 클릭')
//
const targetComment = findCommentById(comment.commentId, comments.value);
if (!targetComment) { if (!targetComment) {
console.log("대댓글을 찾을 수 없음:", comment.commentId);
return; return;
} }
// text , // text ,
if (targetComment.isEditTextarea) { targetComment.isEditTextarea = !targetComment.isEditTextarea;
targetComment.isEditTextarea = false;
} else {
targetComment.isEditTextarea = true;
}
// //
if (unknown.value) { if (unknown.value) {
console.log('익명 코멘트인가?')
toggleCommentPassword(comment, "edit"); toggleCommentPassword(comment, "edit");
} else {
comment.isEditTextarea = true;
} }
} }
// //
const deleteComment = async (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) { if (comment.isEditTextarea) {
// , // ,
comment.isEditTextarea = false; comment.isEditTextarea = false;
@ -496,8 +516,8 @@ const deleteComment = async (comment) => {
toggleCommentPassword(comment, "delete"); toggleCommentPassword(comment, "delete");
} }
} else { } else {
// ( ) console.log('✅ 로그인 사용자 댓글 삭제 진행');
deleteReplyComment(comment) deleteReplyComment(comment);
} }
}; };
@ -665,10 +685,16 @@ const handleSubmitEdit = async (comment, editedContent) => {
// //
// comment.content = editedContent; // comment.content = editedContent;
// comment.isEditTextarea = false; // comment.isEditTextarea = false; f
if (response.status === 200) { 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 { } else {
console.log("❌ 댓글 수정 실패:", response.data); console.log("❌ 댓글 수정 실패:", response.data);
} }
@ -679,13 +705,10 @@ const handleSubmitEdit = async (comment, editedContent) => {
// ( ) // ( )
const handleCancelEdit = (comment) => { const handleCancelEdit = (comment) => {
console.log("BoardView.vue - 댓글 수정 취소:", comment); const targetComment = findCommentById(comment.commentId, comments.value);
// comments comment
const targetComment = comments.value.find(c => c.commentId === comment.commentId);
if (targetComment) { if (targetComment) {
console.log("✅ 원본 데이터 찾음, 수정 취소 처리 가능"); console.log("✅ 원본 데이터 찾음, 수정 취소 처리 가능:", targetComment);
targetComment.isEditTextarea = false; targetComment.isEditTextarea = false;
} else { } else {
console.error("❌ 원본 데이터 찾을 수 없음, 수정 취소 실패"); console.error("❌ 원본 데이터 찾을 수 없음, 수정 취소 실패");
@ -700,10 +723,29 @@ const handlePageChange = (page) => {
} }
}; };
// ( )
const handleCommentDeleted = (deletedCommentId) => { const handleCommentDeleted = (deletedCommentId) => {
comments.value = comments.value.filter(comment => comment.commentId !== deletedCommentId); //
const parentIndex = comments.value.findIndex(comment => comment.commentId === deletedCommentId);
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 formattedDate = (dateString) => { const formattedDate = (dateString) => {
if (!dateString) return "날짜 없음"; if (!dateString) return "날짜 없음";