Compare commits

...

6 Commits

5 changed files with 180 additions and 92 deletions

View File

@ -1,7 +1,7 @@
<template>
<div>
<BoardProfile
:unknown="unknown"
:unknown="comment.author === '익명'"
:isCommentAuthor="isCommentAuthor"
:boardId="comment.boardId"
:profileName="comment.author"
@ -11,7 +11,7 @@
:isLike="!isLike"
:isCommentPassword="comment.isCommentPassword"
:isCommentProfile="true"
@editClick="$emit('editClick', comment)"
@editClick="aaaa"
@deleteClick="$emit('deleteClick', comment)"
@updateReaction="handleUpdateReaction"
/>
@ -29,8 +29,8 @@
</div>
<span v-if="passwordCommentAlert" class="invalid-feedback d-block text-start">{{ passwordCommentAlert }}</span>
</div>
<p>authorId:{{ comment.authorId }}</p>
<p>코멘트 비교: {{comment.isCommentAuthor}}</p>
<!-- <p>authorId:{{ comment.authorId }}</p>
<p>코멘트 비교: {{comment.isCommentAuthor}}</p> -->
<div class="mt-6">
@ -47,7 +47,7 @@
</div>
<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">
@ -56,11 +56,20 @@
:key="child.commentId"
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
:comment="child"
:unknown="unknown"
:unknown="child.author === '익명'"
:isPlusButton="false"
: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"
@updateReaction="handleUpdateReaction"
/>
@ -155,4 +164,8 @@ const submitEdit = () => {
emit('submitEdit', props.comment, localEditedContent.value);
};
const aaaa = () => {
emit('editClick', props.comment);
}
</script>

View File

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

View File

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

View File

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

View File

@ -76,9 +76,9 @@
@updateReaction="handleUpdateReaction"
/>
</div>
<p>현재 로그인한 사용자 ID: {{ currentUserId }}</p>
<!-- <p>현재 로그인한 사용자 ID: {{ currentUserId }}</p>
<p>게시글 작성자: {{ authorId }}</p>
<p>isAuthor : {{ isAuthor }}</p>
<p>isAuthor : {{ isAuthor }}</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"/> -->
@ -94,6 +94,7 @@
<BoardCommentArea
:profileName="profileName"
:unknown="unknown"
:commentAlert="commentAlert"
:passwordAlert="passwordAlert"
@submitComment="handleCommentSubmit"
/>
@ -158,16 +159,19 @@ const route = useRoute();
const router = useRouter();
const userStore = useUserInfoStore();
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 authorId = ref(''); // id
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;
@ -182,6 +186,7 @@ const isCommentPassword = ref(false);
const lastClickedButton = ref("");
const lastCommentClickedButton = ref("");
const isEditTextarea = ref(false);
const commentAlert = ref('')
const pagination = ref({
currentPage: 1,
@ -205,16 +210,19 @@ 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 || {};
profileName.value = data.author;
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 || '제목 없음';
@ -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 => ({
commentId: comment.LOCCMTSEQ, // ID
@ -317,10 +325,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
@ -363,33 +373,37 @@ const fetchComments = async (page = 1) => {
console.log('댓글 목록 불러오기 오류:', error);
}
};
// const isSubmitting = ref(false);
//
const handleCommentSubmit = async ({ comment, password }) => {
console.log('댓글')
const handleCommentSubmit = async ({ comment, password, isCheck }) => {
//
if (comment.trim() === "") {
commentAlert.value = '댓글을 입력해주세요.';
return;
} else {
commentAlert.value = '';
}
//
// if (!password) {
// passwordAlert.value = " .";
// return;
// }
// console.log(' ')
//
// if (isSubmitting.value) return;
// isSubmitting.value = true;
if (unknown.value && isCheck && !password) {
passwordAlert.value = "비밀번호를 입력해야 합니다.";
return;
}
try {
const response = await axios.post(`board/${currentBoardId.value}/comment`, {
LOCBRDSEQ: currentBoardId.value,
LOCCMTRPY: comment,
LOCCMTPWD: password,
LOCCMTPWD: isCheck ? password : '', //
LOCCMTPNT: 1
});
console.log('여기',response)
if (response.status === 200) {
console.log('댓글 작성 성공:', response.data.message);
passwordAlert.value = '';
commentAlert.value = '';
await fetchComments();
} else {
console.log('댓글 작성 실패:', response.data.message);
@ -403,13 +417,6 @@ 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
// });
const response = await axios.post(`board/${currentBoardId.value}/comment`, {
LOCBRDSEQ: currentBoardId.value,
LOCCMTRPY: reply.comment,
@ -417,13 +424,6 @@ const handleCommentReply = async (reply) => {
LOCCMTPNT: reply.parentId
});
//
// console.log(' :', {
// status: response.status,
// data: response.data,
// headers: response.headers
// });
if (response.status === 200) {
if (response.data.code === 200) { //
console.log('대댓글 작성 성공:', response.data);
@ -444,7 +444,9 @@ const handleCommentReply = async (reply) => {
//
const editClick = (unknown) => {
if (unknown) {
const isUnknown = unknown?.unknown ?? false;
if (isUnknown) {
togglePassword("edit");
} else {
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 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) {
console.log('익명 코멘트인가?')
toggleCommentPassword(comment, "edit");
} else {
comment.isEditTextarea = true;
}
}
//
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;
@ -496,8 +516,8 @@ const deleteComment = async (comment) => {
toggleCommentPassword(comment, "delete");
}
} else {
// ( )
deleteReplyComment(comment)
console.log('✅ 로그인 사용자 댓글 삭제 진행');
deleteReplyComment(comment);
}
};
@ -665,10 +685,16 @@ const handleSubmitEdit = async (comment, editedContent) => {
//
// 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);
}
@ -679,13 +705,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("❌ 원본 데이터 찾을 수 없음, 수정 취소 실패");
@ -700,10 +723,29 @@ const handlePageChange = (page) => {
}
};
// ( )
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) => {
if (!dateString) return "날짜 없음";