보드코맨트머지지
This commit is contained in:
parent
62c97e0a18
commit
e376e5ff59
@ -1,60 +1,105 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<BoardProfile :profileName="comment.author" :showDetail="false" :author="true" :isChild="isChild" />
|
<BoardProfile
|
||||||
|
:unknown="unknown"
|
||||||
|
:boardId="comment.boardId"
|
||||||
|
:profileName="comment.author"
|
||||||
|
:date="comment.createdAt"
|
||||||
|
:comment="comment"
|
||||||
|
:showDetail="false"
|
||||||
|
:author="true"
|
||||||
|
:isLike="!isLike"
|
||||||
|
:isPassword="isPassword"
|
||||||
|
@editClick="editClick"
|
||||||
|
@deleteClick="deleteClick"
|
||||||
|
@submitPassword="submitPassword"
|
||||||
|
@updateReaction="handleUpdateReaction"
|
||||||
|
@toggleEdit="emit('toggleEdit', comment.commentId, true)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<p class="m-0">{{ comment.content }}</p>
|
<template v-if="isEditTextarea">
|
||||||
|
<textarea v-model="editedContent" class="form-control"></textarea>
|
||||||
|
<div class="mt-2 d-flex justify-content-end">
|
||||||
|
<button class="btn btn-secondary me-2" @click="emit('toggleEdit', comment.commentId, false)">취소</button>
|
||||||
|
<button class="btn btn-primary" @click="submitEdit">수정 완료</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p class="m-0">{{ comment.content }}</p>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PlusButton v-if="isPlusButton" @click="toggleComment" class="mt-6"/>
|
<PlusButton v-if="isPlusButton" @click="toggleComment" class="mt-6"/>
|
||||||
<BoardComentArea v-if="isComment" @submit="submitComment"/>
|
<BoardCommentArea v-if="isComment" @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.id"
|
:key="child.commentId"
|
||||||
class="pt-8 ps-10"
|
class="mt-8 pt-6 ps-10 border-top"
|
||||||
>
|
>
|
||||||
<BoardComment :comment="child" :isPlusButton="false" :isChild="true" @submitComment="addChildComment" />
|
<BoardComment
|
||||||
|
:comment="child"
|
||||||
|
:unknown="unknown"
|
||||||
|
:isPlusButton="false"
|
||||||
|
:isLike="true"
|
||||||
|
@submitComment="submitComment"
|
||||||
|
@updateReaction="handleUpdateReaction"
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<!-- <ul class="list-unstyled twoDepth">
|
<!-- <ul class="list-unstyled twoDepth">
|
||||||
<li>
|
<li>
|
||||||
<BoardProfile profileName=곤데리2 :showDetail="false" />
|
<BoardProfile profileName=곤데리2 :showDetail="false" />
|
||||||
<div class="mt-2">저도 궁금합니다.</div>
|
<div class="mt-2">저도 궁금합니다.</div>
|
||||||
<BoardComentArea v-if="comment" />
|
<BoardCommentArea v-if="comment" />
|
||||||
</li>
|
</li>
|
||||||
</ul> -->
|
</ul> -->
|
||||||
<!-- <BoardProfile profileName=곤데리 :showDetail="false" />
|
<!-- <BoardProfile profileName=곤데리 :showDetail="false" />
|
||||||
<div class="mt-2">저도 궁금합니다.</div>
|
<div class="mt-2">저도 궁금합니다.</div>
|
||||||
<PlusButton @click="toggleComment"/>
|
<PlusButton @click="toggleComment"/>
|
||||||
<BoardComentArea v-if="comment" /> -->
|
<BoardCommentArea v-if="comment" /> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { defineProps, defineEmits, ref } from 'vue';
|
||||||
import BoardProfile from './BoardProfile.vue';
|
import BoardProfile from './BoardProfile.vue';
|
||||||
import BoardComentArea from './BoardComentArea.vue';
|
import BoardCommentArea from './BoardCommentArea.vue';
|
||||||
import PlusButton from '../button/PlusBtn.vue';
|
import PlusButton from '../button/PlusBtn.vue';
|
||||||
import { ref } from 'vue';
|
|
||||||
import { defineEmits } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
comment: {
|
comment: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
unknown: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
isPlusButton: {
|
isPlusButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
isChild: {
|
isLike: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
isEditTextarea: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isPassword: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// emits 정의
|
// emits 정의
|
||||||
const emit = defineEmits(['submitComment']);
|
const emit = defineEmits(['submitComment', 'updateReaction', 'toggleEdit', 'editClick']);
|
||||||
|
|
||||||
// 댓글 입력 창 토글
|
// 댓글 입력 창 토글
|
||||||
const isComment = ref(false);
|
const isComment = ref(false);
|
||||||
@ -63,29 +108,31 @@ const toggleComment = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 부모 컴포넌트에 대댓글 추가 요청
|
// 부모 컴포넌트에 대댓글 추가 요청
|
||||||
const addChildComment = (parentId, newComment) => {
|
const submitComment = (newComment) => {
|
||||||
emit('submitComment', parentId, newComment);
|
emit('submitComment', { parentId: props.comment.commentId, ...newComment });
|
||||||
|
|
||||||
|
isComment.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 좋아요, 싫어요
|
||||||
|
const handleUpdateReaction = (reactionData) => {
|
||||||
|
emit('updateReaction', {
|
||||||
|
boardId: props.comment.boardId,
|
||||||
|
commentId: props.comment.commentId,
|
||||||
|
...reactionData
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 수정
|
||||||
|
const editClick = (data) => {
|
||||||
|
emit('editClick', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 수정
|
||||||
|
const editedContent = ref(props.comment.content);
|
||||||
|
const submitEdit = () => {
|
||||||
|
emit('submitComment', { commentId: props.comment.commentId, content: editedContent.value });
|
||||||
|
emit('toggleEdit', props.comment.commentId, false); // 수정 모드 종료
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* .twoDepth {
|
|
||||||
margin-top: 10px;
|
|
||||||
padding-left: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-unstyled > li ~ li {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-text-primary {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
.btn-text-primary:hover,
|
|
||||||
.btn-text-primary:active,
|
|
||||||
.btn-text-primary:focus {
|
|
||||||
background-color: transparent
|
|
||||||
} */
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -2,47 +2,66 @@
|
|||||||
<ul class="list-unstyled mt-10">
|
<ul class="list-unstyled mt-10">
|
||||||
<li
|
<li
|
||||||
v-for="comment in comments"
|
v-for="comment in comments"
|
||||||
:key="comment.id"
|
:key="comment.commentId"
|
||||||
class="mt-8"
|
class="mt-6 border-bottom pb-6"
|
||||||
>
|
>
|
||||||
<BoardComment :comment="comment" @submitComment="addComment" />
|
<BoardComment
|
||||||
|
:unknown="unknown"
|
||||||
|
:comment="comment"
|
||||||
|
:isPassword="isPassword"
|
||||||
|
@editClick="editClick"
|
||||||
|
@deleteClick="deleteClick"
|
||||||
|
@submitPassword="submitPassword"
|
||||||
|
@submitComment="submitComment"
|
||||||
|
@updateReaction="(reactionData) => handleUpdateReaction(reactionData, comment.commentId)"
|
||||||
|
/>
|
||||||
|
<!-- @updateReaction="handleUpdateReaction" -->
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { defineProps, defineEmits } from 'vue';
|
||||||
import BoardComment from './BoardComment.vue'
|
import BoardComment from './BoardComment.vue'
|
||||||
|
|
||||||
const comments = ref([
|
const props = defineProps({
|
||||||
{
|
comments: {
|
||||||
id: 1,
|
type: Array,
|
||||||
author: '홍길동',
|
required: true,
|
||||||
content: '저도 궁금합니다.',
|
default: () => []
|
||||||
children: [
|
},
|
||||||
{
|
unknown: {
|
||||||
id: 2,
|
type: Boolean,
|
||||||
author: '사용자1',
|
default: true,
|
||||||
content: '저도요!',
|
},
|
||||||
},
|
isPassword: {
|
||||||
{
|
type: Boolean,
|
||||||
id: 3,
|
default: false,
|
||||||
author: '사용자2',
|
},
|
||||||
content: '저도..',
|
});
|
||||||
},
|
|
||||||
],
|
const emit = defineEmits(['submitComment', 'updateReaction', 'editClick']);
|
||||||
},
|
|
||||||
{
|
const submitComment = (replyData) => {
|
||||||
id: 4,
|
emit('submitComment', replyData);
|
||||||
author: '사용자4',
|
};
|
||||||
content: '흥미로운 주제네요.',
|
|
||||||
children: [],
|
const handleUpdateReaction = (reactionData, commentId) => {
|
||||||
},
|
// console.log('📢 BoardCommentList에서 이벤트 수신:', reactionData);
|
||||||
{
|
// console.log('📌 전달할 댓글 ID>>>>:', commentId);
|
||||||
id: 5,
|
|
||||||
author: '사용자5',
|
const updatedReactionData = {
|
||||||
content: '우오아아아아아앙',
|
...reactionData,
|
||||||
children: [],
|
commentId: commentId
|
||||||
},
|
};
|
||||||
]);
|
|
||||||
|
// console.log('🚀 최종 전달할 데이터:', updatedReactionData);
|
||||||
|
|
||||||
|
emit('updateReaction', updatedReactionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const editClick = (data) => {
|
||||||
|
emit('editClick', data);
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="d-flex align-items-center flex-wrap">
|
<div class="d-flex align-items-center flex-wrap">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<div class="avatar me-2" v-if="unknown">
|
<div v-if="!unknown" class="avatar me-2">
|
||||||
<img src="/img/avatars/2.png" alt="Avatar" class="rounded-circle" />
|
<img src="/img/avatars/2.png" alt="Avatar" class="rounded-circle" />
|
||||||
</div>
|
</div>
|
||||||
<div class="me-2">
|
<div class="me-2">
|
||||||
@ -13,73 +13,71 @@
|
|||||||
<i class="fa-regular fa-eye"></i> {{ views }}
|
<i class="fa-regular fa-eye"></i> {{ views }}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<i class="bx bx-comment"></i> {{ comments }}
|
<i class="bx bx-comment"></i> {{ commentNum }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto btn-area">
|
<!-- 버튼 영역 -->
|
||||||
<template v-if="showDetail">
|
<div class="ms-auto text-end">
|
||||||
<div class="text-end">
|
<!-- 수정, 삭제 버튼 -->
|
||||||
<EditButton @click="handleEdit" />
|
<template v-if="author || showDetail">
|
||||||
<DeleteButton @click="handleDelete" />
|
<EditButton @click.stop="editClick" />
|
||||||
|
<DeleteButton @click.stop="deleteClick" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<div class="mt-3" v-if="isPassword && unknown">
|
<!-- 좋아요, 싫어요 버튼 (댓글에서만 표시) -->
|
||||||
<div class="input-group">
|
<BoardRecommendBtn
|
||||||
<input
|
v-if="isLike"
|
||||||
type="password"
|
:boardId="boardId"
|
||||||
class="form-control"
|
:comment="props.comment"
|
||||||
v-model="password"
|
@updateReaction="handleUpdateReaction"
|
||||||
placeholder="비밀번호 입력"
|
/>
|
||||||
/>
|
|
||||||
<button class="btn btn-primary" type="button" @click="handleSubmit">확인</button>
|
<!-- 비밀번호 입력창 (익명일 경우) -->
|
||||||
</div>
|
<div v-if="isPassword && unknown" class="mt-3">
|
||||||
<span v-if="passwordAlert" class="invalid-feedback d-block text-start">{{ passwordAlert }}</span>
|
<div class="input-group">
|
||||||
</div>
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control"
|
||||||
|
v-model="password"
|
||||||
|
placeholder="비밀번호 입력"
|
||||||
|
/>
|
||||||
|
<button class="btn btn-primary" @click="$emit('submitPassword', password)">확인</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<span v-if="props.passwordAlert" class="invalid-feedback d-block text-start">{{ props.passwordAlert }}</span>
|
||||||
<template v-else>
|
</div>
|
||||||
<template v-if="author">
|
|
||||||
<EditButton />
|
|
||||||
<DeleteButton />
|
|
||||||
<!-- <button class="btn author btn-label-primary btn-icon" @click="handleEdit">
|
|
||||||
<i class='bx bx-edit-alt'></i>
|
|
||||||
</button>
|
|
||||||
<button class="btn author btn-label-primary btn-icon" @click="handleDelete">
|
|
||||||
<i class='bx bx-trash'></i>
|
|
||||||
</button> -->
|
|
||||||
</template>
|
|
||||||
<BoardRecommendBtn v-if="!isChild" :isRecommend="false" />
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, defineProps } from 'vue';
|
import { ref, defineProps, defineEmits } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import axios from '@api';
|
|
||||||
import DeleteButton from '../button/DeleteBtn.vue';
|
import DeleteButton from '../button/DeleteBtn.vue';
|
||||||
import EditButton from '../button/EditBtn.vue';
|
import EditButton from '../button/EditBtn.vue';
|
||||||
import BoardRecommendBtn from '../button/BoardRecommendBtn.vue';
|
import BoardRecommendBtn from '../button/BoardRecommendBtn.vue';
|
||||||
|
|
||||||
// Vue Router 인스턴스
|
// Vue Router 인스턴스
|
||||||
const router = useRouter();
|
|
||||||
const isPassword = ref(false);
|
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
const passwordAlert = ref(false);
|
|
||||||
const lastClickedButton = ref('');
|
|
||||||
|
|
||||||
// Props 정의
|
// Props 정의
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
comment: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
boardId: {
|
boardId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: false
|
||||||
|
},
|
||||||
|
commentId: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
profileName: {
|
profileName: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '익명',
|
default: '익명 사용자',
|
||||||
},
|
},
|
||||||
unknown: {
|
unknown: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -89,6 +87,7 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
||||||
author: {
|
author: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@ -101,113 +100,49 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
comments: {
|
commentNum: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
isChild: {
|
isLike: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
},
|
||||||
|
isPassword: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
passwordAlert: {
|
||||||
|
type: String,
|
||||||
|
default: false,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['togglePasswordInput']);
|
const emit = defineEmits(['togglePasswordInput', 'updateReaction', 'editClick', 'deleteClick', 'updatePasswordAlert']);
|
||||||
|
|
||||||
// 수정 버튼
|
// 수정
|
||||||
const handleEdit = () => {
|
const editClick = () => {
|
||||||
if (props.unknown) {
|
emit('editClick', props.unknown);
|
||||||
togglePassword('edit');
|
|
||||||
} else {
|
|
||||||
router.push({ name: 'BoardEdit', params: { id: props.boardId } });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 삭제 버튼
|
// 삭제
|
||||||
const handleDelete = () => {
|
const deleteClick = () => {
|
||||||
if (props.unknown) {
|
emit('deleteClick', props.unknown);
|
||||||
togglePassword('delete');
|
|
||||||
} else {
|
|
||||||
deletePost();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 비밀번호 입력 토글
|
const handleUpdateReaction = (reactionData) => {
|
||||||
const togglePassword = (button) => {
|
// console.log("🔥 BoardProfile에서 좋아요/싫어요 이벤트 발생");
|
||||||
if (lastClickedButton.value === button) {
|
// console.log("📌 게시글 ID:", props.boardId);
|
||||||
isPassword.value = !isPassword.value;
|
// console.log("📌 댓글 ID (수정 후):", props.comment?.commentId);
|
||||||
} else {
|
// console.log("📌 reactionData:", reactionData);
|
||||||
isPassword.value = true;
|
|
||||||
}
|
emit("updateReaction", {
|
||||||
lastClickedButton.value = button;
|
boardId: props.boardId,
|
||||||
|
commentId: props.comment?.commentId,
|
||||||
|
...reactionData,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 비밀번호 확인
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!password.value) {
|
|
||||||
passwordAlert.value = '비밀번호를 입력해주세요.';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const requestData = {
|
|
||||||
LOCBRDPWD: password.value,
|
|
||||||
LOCBRDSEQ: 288
|
|
||||||
}
|
|
||||||
|
|
||||||
const postResponse = await axios.post(`board/${props.boardId}/password`, requestData);
|
|
||||||
|
|
||||||
if (postResponse.data.code === 200) {
|
|
||||||
if (postResponse.data.data === true) {
|
|
||||||
isPassword.value = false;
|
|
||||||
|
|
||||||
|
|
||||||
if (lastClickedButton.value === 'edit') {
|
|
||||||
router.push({ name: 'BoardEdit', params: { id: props.boardId } });
|
|
||||||
} else if (lastClickedButton.value === 'delete') {
|
|
||||||
await deletePost();
|
|
||||||
}
|
|
||||||
|
|
||||||
lastClickedButton.value = null;
|
|
||||||
} else {
|
|
||||||
passwordAlert.value = '비밀번호가 일치하지 않습니다.';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
passwordAlert.value = '비밀번호가 일치하지 않습니다.';
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// 401 오류
|
|
||||||
if (error.response && error.response.status === 401) {
|
|
||||||
passwordAlert.value = '비밀번호가 일치하지 않습니다.';
|
|
||||||
} else if (error.response) {
|
|
||||||
alert(`오류 발생: ${error.response.data.message || '서버 오류'}`);
|
|
||||||
} else {
|
|
||||||
alert('네트워크 오류가 발생했습니다. 다시 시도해주세요.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const deletePost = async () => {
|
|
||||||
if (confirm('정말 삭제하시겠습니까?')) {
|
|
||||||
try {
|
|
||||||
const response = await axios.delete(`board/${props.boardId}`, {
|
|
||||||
data: { LOCBRDSEQ: props.boardId }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.code === 200) {
|
|
||||||
alert('게시물이 삭제되었습니다.');
|
|
||||||
router.push({ name: 'BoardList' });
|
|
||||||
} else {
|
|
||||||
alert('삭제 실패: ' + response.data.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response) {
|
|
||||||
alert(`삭제 실패: ${error.response.data.message || '서버 오류'}`);
|
|
||||||
} else {
|
|
||||||
alert('네트워크 오류가 발생했습니다. 다시 시도해주세요.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,17 @@
|
|||||||
<BoardProfile
|
<BoardProfile
|
||||||
:boardId="currentBoardId"
|
:boardId="currentBoardId"
|
||||||
:profileName="profileName"
|
:profileName="profileName"
|
||||||
|
:unknown="unknown"
|
||||||
|
:author="isAuthor"
|
||||||
:views="views"
|
:views="views"
|
||||||
:comments="comments"
|
:commentNum="commentNum"
|
||||||
:date="formattedBoardDate"
|
:date="formattedBoardDate"
|
||||||
|
:isLike="false"
|
||||||
|
:isPassword="isPassword"
|
||||||
|
:passwordAlert="passwordAlert"
|
||||||
|
@editClick="editClick"
|
||||||
|
@deleteClick="deleteClick"
|
||||||
|
@submitPassword="submitPassword"
|
||||||
class="pb-6 border-bottom"
|
class="pb-6 border-bottom"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -64,17 +72,28 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul> -->
|
</ul> -->
|
||||||
|
|
||||||
<!-- 댓글 영역 -->
|
<!-- 댓글 입력 영역 -->
|
||||||
<BoardComentArea />
|
<BoardCommentArea
|
||||||
|
:profileName="profileName"
|
||||||
<!-- 수정 버튼 -->
|
:unknown="unknown"
|
||||||
<!-- <button class="btn btn-primary" @click="goToEditPage">
|
@submitComment="handleCommentSubmit"
|
||||||
글 수정
|
/>
|
||||||
</button> -->
|
<!-- <BoardCommentArea :profileName="profileName" :unknown="unknown" /> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
|
||||||
<BoardCommentList/>
|
|
||||||
|
|
||||||
|
<!-- 댓글 목록 -->
|
||||||
|
<div class="card-footer">
|
||||||
|
<BoardCommentList
|
||||||
|
:unknown="unknown"
|
||||||
|
:comments="comments"
|
||||||
|
:isEditTextarea="isEditTextarea"
|
||||||
|
:isPassword="isPassword"
|
||||||
|
@editClick="editClick"
|
||||||
|
@deleteClick="deleteClick"
|
||||||
|
@submitPassword="submitPassword"
|
||||||
|
@updateReaction="handleUpdateReaction"
|
||||||
|
@submitComment="handleCommentReply"
|
||||||
|
/>
|
||||||
<Pagination/>
|
<Pagination/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -84,7 +103,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import BoardComentArea from '@c/board/BoardComentArea.vue';
|
import BoardCommentArea from '@/components/board/BoardCommentArea.vue';
|
||||||
import BoardProfile from '@c/board/BoardProfile.vue';
|
import BoardProfile from '@c/board/BoardProfile.vue';
|
||||||
import BoardCommentList from '@/components/board/BoardCommentList.vue';
|
import BoardCommentList from '@/components/board/BoardCommentList.vue';
|
||||||
import BoardRecommendBtn from '@/components/button/BoardRecommendBtn.vue';
|
import BoardRecommendBtn from '@/components/button/BoardRecommendBtn.vue';
|
||||||
@ -94,7 +113,7 @@ import { useRoute, useRouter } from 'vue-router';
|
|||||||
import axios from '@api';
|
import axios from '@api';
|
||||||
|
|
||||||
// 게시물 데이터 상태
|
// 게시물 데이터 상태
|
||||||
const profileName = ref('익명 사용자');
|
const profileName = ref('');
|
||||||
const boardTitle = ref('제목 없음');
|
const boardTitle = ref('제목 없음');
|
||||||
const boardContent = ref('');
|
const boardContent = ref('');
|
||||||
const date = ref('');
|
const date = ref('');
|
||||||
@ -103,17 +122,25 @@ const likes = ref(0);
|
|||||||
const dislikes = ref(0);
|
const dislikes = ref(0);
|
||||||
const likeClicked = ref(false);
|
const likeClicked = ref(false);
|
||||||
const dislikeClicked = ref(false);
|
const dislikeClicked = ref(false);
|
||||||
const comments = ref(0);
|
const commentNum = ref(0);
|
||||||
const attachment = ref(false);
|
const attachment = ref(false);
|
||||||
|
const comments = ref([]);
|
||||||
|
|
||||||
// 라우트에서 ID 가져오기
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const currentBoardId = ref(Number(route.params.id));
|
const currentBoardId = ref(Number(route.params.id));
|
||||||
|
const unknown = computed(() => profileName.value === '익명 사용자');
|
||||||
|
const currentUserId = ref('김자바'); // 현재 로그인한 사용자 id
|
||||||
|
const authorId = ref(null); // 작성자 id
|
||||||
|
|
||||||
|
const isAuthor = computed(() => currentUserId.value === authorId.value);
|
||||||
|
|
||||||
|
const isEditTextarea = ref({});
|
||||||
|
|
||||||
|
const passwordAlert = ref("");
|
||||||
|
const isPassword = ref(false);
|
||||||
|
const lastClickedButton = ref("");
|
||||||
|
|
||||||
// 글 수정 페이지로 이동
|
|
||||||
const goToEditPage = () => {
|
|
||||||
router.push({ name: 'BoardEdit', params: { id: currentBoardId.value } });
|
|
||||||
};
|
|
||||||
|
|
||||||
// 게시물 상세 데이터 불러오기
|
// 게시물 상세 데이터 불러오기
|
||||||
const fetchBoardDetails = async () => {
|
const fetchBoardDetails = async () => {
|
||||||
@ -125,6 +152,13 @@ const fetchBoardDetails = async () => {
|
|||||||
// const boardDetail = data.boardDetail || {};
|
// const boardDetail = data.boardDetail || {};
|
||||||
|
|
||||||
profileName.value = data.author || '익명 사용자';
|
profileName.value = data.author || '익명 사용자';
|
||||||
|
|
||||||
|
// 익명확인하고 싶을때
|
||||||
|
profileName.value = '익명 사용자';
|
||||||
|
|
||||||
|
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
||||||
|
authorId.value = data.author;
|
||||||
|
|
||||||
boardTitle.value = data.title || '제목 없음';
|
boardTitle.value = data.title || '제목 없음';
|
||||||
boardContent.value = data.content || '';
|
boardContent.value = data.content || '';
|
||||||
date.value = data.date || '';
|
date.value = data.date || '';
|
||||||
@ -132,10 +166,7 @@ const fetchBoardDetails = async () => {
|
|||||||
likes.value = data.likeCount || 0;
|
likes.value = data.likeCount || 0;
|
||||||
dislikes.value = data.dislikeCount || 0;
|
dislikes.value = data.dislikeCount || 0;
|
||||||
attachment.value = data.hasAttachment || null;
|
attachment.value = data.hasAttachment || null;
|
||||||
comments.value = data.commentCount || 0;
|
commentNum.value = data.commentCount || 0;
|
||||||
|
|
||||||
// const response2 = await axios.post(`board/${currentBoardId.value}/password`);
|
|
||||||
// console.log(response2)
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert('게시물 데이터를 불러오는 중 오류가 발생했습니다.');
|
alert('게시물 데이터를 불러오는 중 오류가 발생했습니다.');
|
||||||
@ -144,50 +175,215 @@ const fetchBoardDetails = async () => {
|
|||||||
|
|
||||||
// 좋아요, 싫어요
|
// 좋아요, 싫어요
|
||||||
const handleUpdateReaction = async ({ boardId, commentId, isLike, isDislike }) => {
|
const handleUpdateReaction = async ({ boardId, commentId, isLike, isDislike }) => {
|
||||||
// console.log(type, boardId)
|
|
||||||
try {
|
try {
|
||||||
|
const aa = await axios.post(`/board/${boardId}/${commentId}/reaction`, {
|
||||||
const requestData = {
|
LOCBRDSEQ: boardId, // 게시글 id
|
||||||
LOCBRDSEQ: boardId,
|
LOCCMTSEQ: commentId, //댓글 id
|
||||||
LOCCMTSEQ: commentId,
|
// MEMBERSEQ: 1, // 멤버아이디 지금은 1 나중에 수정해야함
|
||||||
MEMBERSEQ: 1, // 멤버아이디 지금은 1 나중에 수정해야함
|
|
||||||
LOCGOBGOD: isLike ? 'T' : 'F',
|
LOCGOBGOD: isLike ? 'T' : 'F',
|
||||||
LOCGOBBAD: isDislike ? 'T' : 'F'
|
LOCGOBBAD: isDislike ? 'T' : 'F'
|
||||||
};
|
});
|
||||||
|
console.log("좋아요 API 응답 데이터:", aa.data);
|
||||||
|
|
||||||
console.log(requestData)
|
|
||||||
|
|
||||||
const postResponse = await axios.post(`/board/${boardId}/${commentId}/reaction`, requestData);
|
|
||||||
// await axios.post(`board/${boardId}/${commentId}/reaction`, { type });
|
|
||||||
|
|
||||||
const response = await axios.get(`board/${boardId}`);
|
const response = await axios.get(`board/${boardId}`);
|
||||||
const updatedData = response.data.data;
|
const updatedData = response.data.data;
|
||||||
|
|
||||||
console.log('post요청 결과:', postResponse.data);
|
|
||||||
console.log('get요청 결과(좋아요):', response.data.data.likeCount);
|
|
||||||
|
|
||||||
likes.value = updatedData.likeCount;
|
likes.value = updatedData.likeCount;
|
||||||
dislikes.value = updatedData.dislikeCount;
|
dislikes.value = updatedData.dislikeCount;
|
||||||
|
|
||||||
likeClicked.value = isLike;
|
likeClicked.value = isLike;
|
||||||
dislikeClicked.value = isDislike;
|
dislikeClicked.value = isDislike;
|
||||||
|
// console.log(updatedData)
|
||||||
console.log('반응 결과:', postResponse.data);
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert('반응을 업데이트하는 중 오류 발생');
|
alert('반응을 업데이트하는 중 오류 발생');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 날짜
|
// 댓글 목록 조회
|
||||||
const formattedBoardDate = computed(() => {
|
const fetchComments = async () => {
|
||||||
const dateObj = new Date(date.value);
|
try {
|
||||||
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')}`;
|
const response = await axios.get(`board/${currentBoardId.value}/comments`, {
|
||||||
});
|
params: { LOCBRDSEQ: currentBoardId.value }
|
||||||
|
});
|
||||||
|
console.log("목록 API 응답 데이터:", response.data);
|
||||||
|
|
||||||
|
let allComments = response.data.data.list.map(comment => ({
|
||||||
|
commentId: comment.LOCCMTSEQ, // 댓글 id
|
||||||
|
boardId: comment.LOCBRDSEQ,
|
||||||
|
parentId: comment.LOCCMTPNT, // 부모 id
|
||||||
|
author: comment.author || "익명 사용자", // 작성자
|
||||||
|
content: comment.LOCCMTRPY, // 댓글 내용
|
||||||
|
createdAt: formattedDate(comment.LOCCMTRDT), // 생성 날짜
|
||||||
|
children: []
|
||||||
|
}));
|
||||||
|
|
||||||
|
allComments.sort((a, b) => b.commentId - a.commentId);
|
||||||
|
|
||||||
|
let commentMap = {};
|
||||||
|
let rootComments = [];
|
||||||
|
|
||||||
|
allComments.forEach(comment => {
|
||||||
|
commentMap[comment.commentId] = comment;
|
||||||
|
});
|
||||||
|
|
||||||
|
allComments.forEach(comment => {
|
||||||
|
if (comment.parentId && commentMap[comment.parentId]) {
|
||||||
|
commentMap[comment.parentId].children.push(comment);
|
||||||
|
} else {
|
||||||
|
rootComments.push(comment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
comments.value = rootComments;
|
||||||
|
|
||||||
|
// console.log("변환된 comments 데이터:", comments.value);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('댓글 목록 불러오기 오류:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 댓글 작성
|
||||||
|
const handleCommentSubmit = async ({ comment, password }) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`board/${currentBoardId.value}/comment`, {
|
||||||
|
LOCBRDSEQ: currentBoardId.value,
|
||||||
|
LOCCMTRPY: comment,
|
||||||
|
LOCCMTPWD: password || null,
|
||||||
|
LOCCMTPNT: 1
|
||||||
|
});
|
||||||
|
// console.log('📥 서버 응답 전체:', response.data);
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
console.log('댓글 작성 성공:', response.data.message);
|
||||||
|
await fetchComments();
|
||||||
|
} else {
|
||||||
|
console.error('댓글 작성 실패:', response.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('댓글 작성 중 오류 발생:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCommentReply = async (reply) => {
|
||||||
|
const response = await axios.post(`board/${currentBoardId.value}/comment`, {
|
||||||
|
LOCBRDSEQ: currentBoardId.value,
|
||||||
|
LOCCMTRPY: reply.comment,
|
||||||
|
LOCCMTPWD: reply.password || null,
|
||||||
|
LOCCMTPNT: reply.parentId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
console.log('대댓글 작성 성공:', response.data.message);
|
||||||
|
await fetchComments();
|
||||||
|
} else {
|
||||||
|
console.error('대댓글 작성 실패:', response.data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const editClick = (unknown) => {
|
||||||
|
|
||||||
|
if (unknown) {
|
||||||
|
togglePassword("edit");
|
||||||
|
} else {
|
||||||
|
router.push({ name: "BoardEdit", params: { id: currentBoardId.value } });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteClick = (unknown) => {
|
||||||
|
if (unknown) {
|
||||||
|
togglePassword("delete");
|
||||||
|
} else {
|
||||||
|
deletePost();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const togglePassword = (button) => {
|
||||||
|
if (lastClickedButton.value === button) {
|
||||||
|
isPassword.value = !isPassword.value;
|
||||||
|
} else {
|
||||||
|
isPassword.value = true;
|
||||||
|
}
|
||||||
|
lastClickedButton.value = button;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const submitPassword = async (inputPassword) => {
|
||||||
|
console.log(inputPassword)
|
||||||
|
if (!inputPassword) {
|
||||||
|
passwordAlert.value = "비밀번호를 입력해주세요.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const requestData = {
|
||||||
|
LOCBRDPWD: inputPassword,
|
||||||
|
LOCBRDSEQ: 288
|
||||||
|
};
|
||||||
|
|
||||||
|
const postResponse = await axios.post(`board/${currentBoardId.value}/password`, requestData);
|
||||||
|
|
||||||
|
if (postResponse.data.code === 200 && postResponse.data.data === true) {
|
||||||
|
isPassword.value = false;
|
||||||
|
passwordAlert.value = "";
|
||||||
|
|
||||||
|
if (lastClickedButton.value === "edit") {
|
||||||
|
router.push({ name: "BoardEdit", params: { id: currentBoardId.value } });
|
||||||
|
} else if (lastClickedButton.value === "delete") {
|
||||||
|
await deletePost();
|
||||||
|
}
|
||||||
|
lastClickedButton.value = null;
|
||||||
|
} else {
|
||||||
|
passwordAlert.value = "비밀번호가 일치하지 않습니다.";
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error.response && error.response.status === 401) {
|
||||||
|
passwordAlert.value = "비밀번호가 일치하지 않습니다.";
|
||||||
|
} else if (error.response) {
|
||||||
|
alert(`오류 발생: ${error.response.data.message || "서버 오류"}`);
|
||||||
|
} else {
|
||||||
|
alert("네트워크 오류가 발생했습니다. 다시 시도해주세요.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deletePost = async () => {
|
||||||
|
if (confirm("정말 삭제하시겠습니까?")) {
|
||||||
|
try {
|
||||||
|
const response = await axios.delete(`board/${currentBoardId.value}`, {
|
||||||
|
data: { LOCBRDSEQ: currentBoardId.value }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data.code === 200) {
|
||||||
|
alert("게시물이 삭제되었습니다.");
|
||||||
|
router.push({ name: "BoardList" });
|
||||||
|
} else {
|
||||||
|
alert("삭제 실패: " + response.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error.response) {
|
||||||
|
alert(`삭제 실패: ${error.response.data.message || "서버 오류"}`);
|
||||||
|
} else {
|
||||||
|
alert("네트워크 오류가 발생했습니다. 다시 시도해주세요.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 날짜
|
||||||
|
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')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const formattedBoardDate = computed(() => formattedDate(date.value));
|
||||||
|
|
||||||
// 컴포넌트 마운트 시 데이터 로드
|
// 컴포넌트 마운트 시 데이터 로드
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchBoardDetails();
|
fetchBoardDetails()
|
||||||
|
fetchComments()
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user