게시판 댓글삭제제

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,65 +51,78 @@
</template>
<script setup>
import { ref, defineEmits, defineProps, computed, watch, inject } from 'vue';
import SaveBtn from '../button/SaveBtn.vue';
import { ref, defineEmits, defineProps, watch, inject } from 'vue';
import SaveBtn from '../button/SaveBtn.vue';
const props = defineProps({
unknown: {
type: Boolean,
default: true,
},
parentId: {
type: Number,
default: 0,
},
passwordAlert: {
type: String,
default: '',
},
commentAlert: {
type: String,
default: '',
},
});
const $common = inject('common');
const comment = ref('');
const password = ref('');
const isCheck = ref(false);
const textAlert = ref('');
const passwordAlert2 = ref('');
const props = defineProps({
unknown: {
type: Boolean,
default: true,
},
parentId: {
type: Number,
default: 0,
},
passwordAlert: {
type: String,
default: '',
},
commentAlert: {
type: String,
default: '',
},
});
const emit = defineEmits(['submitComment']);
const LOCBRDTYP = isCheck.value ? '300102' : null;
function handleCommentSubmit() {
if (!$common.isNotEmpty(comment.value)) {
textAlert.value = '댓글을 입력하세요';
return false;
} else {
textAlert.value = '';
}
if (isCheck.value && !$common.isNotEmpty(password.value)) {
passwordAlert2.value = '비밀번호를 입력하세요';
return false;
} else {
passwordAlert2.value = '';
}
const $common = inject('common');
const comment = ref('');
const password = ref('');
const isCheck = ref(false);
const textAlert = ref('');
const passwordAlert2 = ref('');
emit('submitComment', {
comment: comment.value,
password: isCheck.value ? password.value : '',
isCheck: isCheck.value,
LOCBRDTYP, // '300102'
});
const emit = defineEmits(['submitComment']);
const handleCommentSubmit = () => {
if (!$common.isNotEmpty(comment.value)) {
textAlert.value = '댓글을 입력하세요';
return false;
} else {
textAlert.value = '';
}
watch(
() => props.passwordAlert,
() => {
if (!props.passwordAlert) {
comment.value = '';
password.value = '';
}
},
);
if (isCheck.value && !$common.isNotEmpty(password.value)) {
passwordAlert2.value = '비밀번호를 입력하세요';
return false;
} else {
passwordAlert2.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>

View File

@ -2,7 +2,7 @@
<div class="d-flex align-items-center flex-wrap">
<div class="d-flex align-items-center">
<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 class="me-2">
@ -23,8 +23,7 @@
<!-- 버튼 영역 -->
<div class="ms-auto text-end">
<!-- 수정, 삭제 버튼 -->
<!-- <template v-if="isAuthor || showDetail"> -->
<template v-if="unknown || isCommentAuthor || isAuthor">
<template v-if="!isDeletedComment && (unknown || isCommentAuthor || isAuthor)">
<EditButton @click.stop="editClick" />
<DeleteButton @click.stop="deleteClick" />
</template>
@ -35,18 +34,23 @@
:boardId="boardId"
:comment="comment"
@updateReaction="handleUpdateReaction"
>
</BoardRecommendBtn>
/>
</div>
</div>
</template>
<script setup>
import { ref, defineProps, defineEmits } from 'vue';
import { computed, defineProps, defineEmits } from 'vue';
import DeleteButton from '../button/DeleteBtn.vue';
import EditButton from '../button/EditBtn.vue';
import BoardRecommendBtn from '../button/BoardRecommendBtn.vue';
//
const defaultProfile = "/img/icons/icon.png";
// (Vue )
const baseUrl = "http://localhost:10325/"; // API URL
// Props
const props = defineProps({
comment: {
@ -65,6 +69,10 @@ const props = defineProps({
type: String,
default: '',
},
profilePath: {
type: String,
default: '',
},
unknown: {
type: Boolean,
default: true,
@ -73,13 +81,12 @@ const props = defineProps({
type: Boolean,
default: true,
},
// :
isAuthor: {
type: Boolean,
default: false,
},
isCommentAuthor: Boolean, //
isCommentProfile: Boolean, //
isCommentAuthor: Boolean,
isCommentProfile: Boolean,
date: {
type: String,
required: '',
@ -100,6 +107,11 @@ const props = defineProps({
const emit = defineEmits(['updateReaction', 'editClick', 'deleteClick']);
const isDeletedComment = computed(() => {
return props.comment?.content === '삭제된 댓글입니다' &&
props.comment?.updateAtRaw !== props.comment?.createdAtRaw;
});
//
const editClick = () => {
emit('editClick', { ...props.comment, unknown: props.unknown });
@ -110,42 +122,19 @@ const deleteClick = () => {
emit('deleteClick', { ...props.comment, unknown: props.unknown });
};
// /
const handleUpdateReaction = (reactionData) => {
emit("updateReaction", {
boardId: props.boardId,
commentId: props.comment?.commentId,
commentId: props.comment?.commentId,
...reactionData,
});
};
//
const getProfileImage = (profilePath) => {
return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile;
};
return profilePath && profilePath.trim()
? `${baseUrl}upload/img/profile/${profilePath}`
: defaultProfile;
};
</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">
<a
class="dropdown-item"
:href="getFileDownloadUrl(attachment)"
:download="attachment.originalName + '.' + attachment.extension"
href="#"
@click.prevent="downloadFile(attachment)"
>
{{ attachment.originalName }}.{{ attachment.extension }}
</a>
@ -157,8 +157,26 @@ const commentsWithAuthStatus = computed(() => {
const attachments = ref([]);
// URL
const getFileDownloadUrl = (attachment) => {
return `board/files/download?path=${encodeURIComponent(attachment.path)}`;
const downloadFile = async (attachment) => {
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 {
const response = await axios.get(`board/${currentBoardId.value}`);
const data = response.data.data;
console.log(data)
// API
// const boardDetail = data.boardDetail || {};
profileName.value = data.author || '익명';
authorId.value = data.authorId; // id
authorId.value = data.authorId;
boardTitle.value = data.title || '제목 없음';
boardContent.value = data.content || '';
date.value = data.date || '';
@ -277,7 +292,6 @@ const fetchComments = async (page = 1) => {
page
}
});
const commentsList = response.data.data.list.map(comment => ({
commentId: comment.LOCCMTSEQ, // ID
boardId: comment.LOCBRDSEQ,
@ -292,6 +306,7 @@ const fetchComments = async (page = 1) => {
createdAtRaw: new Date(comment.LOCCMTRDT), //
createdAt: formattedDate(comment.LOCCMTRDT), //
children: [], //
updateAtRaw: new Date(comment.LOCCMTUDT),
}));
commentsList.sort((a, b) => b.createdAtRaw - a.createdAtRaw);