게시판 댓글삭제제

This commit is contained in:
dyhj625 2025-03-04 17:42:46 +09:00
parent 4dc807c452
commit 0cfeb2fc1d
3 changed files with 122 additions and 105 deletions

View File

@ -51,7 +51,7 @@
</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({
@ -72,6 +72,7 @@
default: '', default: '',
}, },
}); });
const $common = inject('common'); const $common = inject('common');
const comment = ref(''); const comment = ref('');
const password = ref(''); const password = ref('');
@ -80,14 +81,15 @@
const passwordAlert2 = ref(''); const passwordAlert2 = ref('');
const emit = defineEmits(['submitComment']); const emit = defineEmits(['submitComment']);
const LOCBRDTYP = isCheck.value ? '300102' : null;
function handleCommentSubmit() { const handleCommentSubmit = () => {
if (!$common.isNotEmpty(comment.value)) { if (!$common.isNotEmpty(comment.value)) {
textAlert.value = '댓글을 입력하세요'; textAlert.value = '댓글을 입력하세요';
return false; return false;
} else { } else {
textAlert.value = ''; textAlert.value = '';
} }
if (isCheck.value && !$common.isNotEmpty(password.value)) { if (isCheck.value && !$common.isNotEmpty(password.value)) {
passwordAlert2.value = '비밀번호를 입력하세요'; passwordAlert2.value = '비밀번호를 입력하세요';
return false; return false;
@ -95,21 +97,32 @@
passwordAlert2.value = ''; passwordAlert2.value = '';
} }
//
emit('submitComment', { emit('submitComment', {
comment: comment.value, comment: comment.value,
password: isCheck.value ? password.value : '', password: isCheck.value ? password.value : '',
isCheck: isCheck.value, isCheck: isCheck.value,
LOCBRDTYP, // '300102' LOCBRDTYP: isCheck.value ? '300102' : null, // '300102'
}); });
}
//
resetCommentForm();
};
//
const resetCommentForm = () => {
comment.value = '';
password.value = '';
isCheck.value = false;
};
watch( watch(
() => props.passwordAlert, () => props.passwordAlert,
() => { () => {
if (!props.passwordAlert) { if (!props.passwordAlert) {
comment.value = ''; resetCommentForm();
password.value = ''; }
} }
},
); );
</script> </script>

View File

@ -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,6 +122,7 @@ 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,
@ -118,34 +131,10 @@ const handleUpdateReaction = (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>

View File

@ -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);