게시판 댓글삭제제
This commit is contained in:
parent
4dc807c452
commit
0cfeb2fc1d
@ -51,65 +51,78 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, defineEmits, defineProps, computed, watch, inject } from 'vue';
|
import { ref, defineEmits, defineProps, watch, inject } from 'vue';
|
||||||
import SaveBtn from '../button/SaveBtn.vue';
|
import SaveBtn from '../button/SaveBtn.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
unknown: {
|
unknown: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
parentId: {
|
parentId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
passwordAlert: {
|
passwordAlert: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
commentAlert: {
|
commentAlert: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const $common = inject('common');
|
|
||||||
const comment = ref('');
|
|
||||||
const password = ref('');
|
|
||||||
const isCheck = ref(false);
|
|
||||||
const textAlert = ref('');
|
|
||||||
const passwordAlert2 = ref('');
|
|
||||||
|
|
||||||
const emit = defineEmits(['submitComment']);
|
const $common = inject('common');
|
||||||
const LOCBRDTYP = isCheck.value ? '300102' : null;
|
const comment = ref('');
|
||||||
function handleCommentSubmit() {
|
const password = ref('');
|
||||||
if (!$common.isNotEmpty(comment.value)) {
|
const isCheck = ref(false);
|
||||||
textAlert.value = '댓글을 입력하세요';
|
const textAlert = ref('');
|
||||||
return false;
|
const passwordAlert2 = ref('');
|
||||||
} else {
|
|
||||||
textAlert.value = '';
|
|
||||||
}
|
|
||||||
if (isCheck.value && !$common.isNotEmpty(password.value)) {
|
|
||||||
passwordAlert2.value = '비밀번호를 입력하세요';
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
passwordAlert2.value = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('submitComment', {
|
const emit = defineEmits(['submitComment']);
|
||||||
comment: comment.value,
|
|
||||||
password: isCheck.value ? password.value : '',
|
const handleCommentSubmit = () => {
|
||||||
isCheck: isCheck.value,
|
if (!$common.isNotEmpty(comment.value)) {
|
||||||
LOCBRDTYP, // 익명일 경우 '300102' 설정
|
textAlert.value = '댓글을 입력하세요';
|
||||||
});
|
return false;
|
||||||
|
} else {
|
||||||
|
textAlert.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
if (isCheck.value && !$common.isNotEmpty(password.value)) {
|
||||||
() => props.passwordAlert,
|
passwordAlert2.value = '비밀번호를 입력하세요';
|
||||||
() => {
|
return false;
|
||||||
if (!props.passwordAlert) {
|
} else {
|
||||||
comment.value = '';
|
passwordAlert2.value = '';
|
||||||
password.value = '';
|
}
|
||||||
}
|
|
||||||
},
|
// 댓글 제출
|
||||||
);
|
emit('submitComment', {
|
||||||
|
comment: comment.value,
|
||||||
|
password: isCheck.value ? password.value : '',
|
||||||
|
isCheck: isCheck.value,
|
||||||
|
LOCBRDTYP: isCheck.value ? '300102' : null, // 익명일 경우 '300102' 설정
|
||||||
|
});
|
||||||
|
|
||||||
|
// 제출 후 입력 필드 리셋
|
||||||
|
resetCommentForm();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 입력 필드 리셋 함수 추가
|
||||||
|
const resetCommentForm = () => {
|
||||||
|
comment.value = '';
|
||||||
|
password.value = '';
|
||||||
|
isCheck.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.passwordAlert,
|
||||||
|
() => {
|
||||||
|
if (!props.passwordAlert) {
|
||||||
|
resetCommentForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<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 v-if="!unknown" class="avatar me-2">
|
<div v-if="!unknown" class="avatar me-2">
|
||||||
<img src="/img/avatars/2.png" alt="Avatar" class="rounded-circle" />
|
<img :src="getProfileImage(profilePath)" alt="Avatar" class="rounded-circle" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="me-2">
|
<div class="me-2">
|
||||||
@ -23,8 +23,7 @@
|
|||||||
<!-- 버튼 영역 -->
|
<!-- 버튼 영역 -->
|
||||||
<div class="ms-auto text-end">
|
<div class="ms-auto text-end">
|
||||||
<!-- 수정, 삭제 버튼 -->
|
<!-- 수정, 삭제 버튼 -->
|
||||||
<!-- <template v-if="isAuthor || showDetail"> -->
|
<template v-if="!isDeletedComment && (unknown || isCommentAuthor || isAuthor)">
|
||||||
<template v-if="unknown || isCommentAuthor || isAuthor">
|
|
||||||
<EditButton @click.stop="editClick" />
|
<EditButton @click.stop="editClick" />
|
||||||
<DeleteButton @click.stop="deleteClick" />
|
<DeleteButton @click.stop="deleteClick" />
|
||||||
</template>
|
</template>
|
||||||
@ -35,18 +34,23 @@
|
|||||||
:boardId="boardId"
|
:boardId="boardId"
|
||||||
:comment="comment"
|
:comment="comment"
|
||||||
@updateReaction="handleUpdateReaction"
|
@updateReaction="handleUpdateReaction"
|
||||||
>
|
/>
|
||||||
</BoardRecommendBtn>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, defineProps, defineEmits } from 'vue';
|
import { computed, defineProps, defineEmits } from 'vue';
|
||||||
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';
|
||||||
|
|
||||||
|
// 기본 프로필 이미지 경로
|
||||||
|
const defaultProfile = "/img/icons/icon.png";
|
||||||
|
|
||||||
|
// 서버의 이미지 경로 (Vue 환경 변수 사용 가능)
|
||||||
|
const baseUrl = "http://localhost:10325/"; // API 서버 URL
|
||||||
|
|
||||||
// Props 정의
|
// Props 정의
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
comment: {
|
comment: {
|
||||||
@ -65,6 +69,10 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
profilePath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
unknown: {
|
unknown: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
@ -73,13 +81,12 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
|
||||||
isAuthor: {
|
isAuthor: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
isCommentAuthor: Boolean, // 댓글 작성자인지 여부
|
isCommentAuthor: Boolean,
|
||||||
isCommentProfile: Boolean, // 현재 컴포넌트가 댓글용인지 여부
|
isCommentProfile: Boolean,
|
||||||
date: {
|
date: {
|
||||||
type: String,
|
type: String,
|
||||||
required: '',
|
required: '',
|
||||||
@ -100,6 +107,11 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['updateReaction', 'editClick', 'deleteClick']);
|
const emit = defineEmits(['updateReaction', 'editClick', 'deleteClick']);
|
||||||
|
|
||||||
|
const isDeletedComment = computed(() => {
|
||||||
|
return props.comment?.content === '삭제된 댓글입니다' &&
|
||||||
|
props.comment?.updateAtRaw !== props.comment?.createdAtRaw;
|
||||||
|
});
|
||||||
|
|
||||||
// 수정
|
// 수정
|
||||||
const editClick = () => {
|
const editClick = () => {
|
||||||
emit('editClick', { ...props.comment, unknown: props.unknown });
|
emit('editClick', { ...props.comment, unknown: props.unknown });
|
||||||
@ -110,42 +122,19 @@ const deleteClick = () => {
|
|||||||
emit('deleteClick', { ...props.comment, unknown: props.unknown });
|
emit('deleteClick', { ...props.comment, unknown: props.unknown });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 좋아요/싫어요 업데이트
|
||||||
const handleUpdateReaction = (reactionData) => {
|
const handleUpdateReaction = (reactionData) => {
|
||||||
emit("updateReaction", {
|
emit("updateReaction", {
|
||||||
boardId: props.boardId,
|
boardId: props.boardId,
|
||||||
commentId: props.comment?.commentId,
|
commentId: props.comment?.commentId,
|
||||||
...reactionData,
|
...reactionData,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 프로필 이미지 경로 설정
|
||||||
const getProfileImage = (profilePath) => {
|
const getProfileImage = (profilePath) => {
|
||||||
return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile;
|
return profilePath && profilePath.trim()
|
||||||
};
|
? `${baseUrl}upload/img/profile/${profilePath}`
|
||||||
|
: defaultProfile;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.profile-detail span ~ span {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ms-auto button + button {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.author {
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 450px) {
|
|
||||||
.btn-area {
|
|
||||||
margin-top: 10px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.author {
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -39,8 +39,8 @@
|
|||||||
<li v-for="(attachment, index) in attachments" :key="index">
|
<li v-for="(attachment, index) in attachments" :key="index">
|
||||||
<a
|
<a
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
:href="getFileDownloadUrl(attachment)"
|
href="#"
|
||||||
:download="attachment.originalName + '.' + attachment.extension"
|
@click.prevent="downloadFile(attachment)"
|
||||||
>
|
>
|
||||||
{{ attachment.originalName }}.{{ attachment.extension }}
|
{{ attachment.originalName }}.{{ attachment.extension }}
|
||||||
</a>
|
</a>
|
||||||
@ -157,8 +157,26 @@ const commentsWithAuthStatus = computed(() => {
|
|||||||
|
|
||||||
const attachments = ref([]);
|
const attachments = ref([]);
|
||||||
// 첨부파일 다운로드 URL 생성
|
// 첨부파일 다운로드 URL 생성
|
||||||
const getFileDownloadUrl = (attachment) => {
|
const downloadFile = async (attachment) => {
|
||||||
return `board/files/download?path=${encodeURIComponent(attachment.path)}`;
|
try {
|
||||||
|
const response = await axios.get(`board/download`, {
|
||||||
|
params: { path: attachment.path },
|
||||||
|
responseType: 'blob'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Blob에서 파일 다운로드 링크 생성
|
||||||
|
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.setAttribute('download', attachment.originalName + '.' + attachment.extension);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
link.remove();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('파일 다운로드 오류:', error);
|
||||||
|
alert('파일 다운로드 중 오류가 발생했습니다.');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -200,14 +218,11 @@ const fetchBoardDetails = async () => {
|
|||||||
try {
|
try {
|
||||||
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)
|
|
||||||
|
|
||||||
// API 응답 데이터 반영
|
|
||||||
// const boardDetail = data.boardDetail || {};
|
|
||||||
|
|
||||||
profileName.value = data.author || '익명';
|
profileName.value = data.author || '익명';
|
||||||
|
|
||||||
authorId.value = data.authorId; //게시글 작성자 id
|
authorId.value = data.authorId;
|
||||||
boardTitle.value = data.title || '제목 없음';
|
boardTitle.value = data.title || '제목 없음';
|
||||||
boardContent.value = data.content || '';
|
boardContent.value = data.content || '';
|
||||||
date.value = data.date || '';
|
date.value = data.date || '';
|
||||||
@ -277,7 +292,6 @@ const fetchComments = async (page = 1) => {
|
|||||||
page
|
page
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const commentsList = response.data.data.list.map(comment => ({
|
const commentsList = response.data.data.list.map(comment => ({
|
||||||
commentId: comment.LOCCMTSEQ, // 댓글 ID
|
commentId: comment.LOCCMTSEQ, // 댓글 ID
|
||||||
boardId: comment.LOCBRDSEQ,
|
boardId: comment.LOCBRDSEQ,
|
||||||
@ -292,6 +306,7 @@ const fetchComments = async (page = 1) => {
|
|||||||
createdAtRaw: new Date(comment.LOCCMTRDT), // 정렬용
|
createdAtRaw: new Date(comment.LOCCMTRDT), // 정렬용
|
||||||
createdAt: formattedDate(comment.LOCCMTRDT), // 표시용
|
createdAt: formattedDate(comment.LOCCMTRDT), // 표시용
|
||||||
children: [], // 대댓글을 담을 배열
|
children: [], // 대댓글을 담을 배열
|
||||||
|
updateAtRaw: new Date(comment.LOCCMTUDT),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commentsList.sort((a, b) => b.createdAtRaw - a.createdAtRaw);
|
commentsList.sort((a, b) => b.createdAtRaw - a.createdAtRaw);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user