수정 에디터
This commit is contained in:
parent
d47ee95f56
commit
9035d339ac
@ -55,7 +55,7 @@
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<QEditor
|
<QEditor
|
||||||
v-if="contentLoaded"
|
v-if="contentLoaded"
|
||||||
@update:data="content = $event"
|
@update:data="handleEditorDataUpdate"
|
||||||
@update:imageUrls="imageUrls = $event"
|
@update:imageUrls="imageUrls = $event"
|
||||||
@update:uploadedImgList="handleUpdateEditorImg"
|
@update:uploadedImgList="handleUpdateEditorImg"
|
||||||
@update:deleteImgIndexList="handleDeleteEditorImg"
|
@update:deleteImgIndexList="handleDeleteEditorImg"
|
||||||
@ -89,6 +89,7 @@
|
|||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
import { useBoardAccessStore } from '@s/useBoardAccessStore';
|
import { useBoardAccessStore } from '@s/useBoardAccessStore';
|
||||||
import axios from '@api';
|
import axios from '@api';
|
||||||
|
import Quill from 'quill';
|
||||||
|
|
||||||
// 공통
|
// 공통
|
||||||
const $common = inject('common');
|
const $common = inject('common');
|
||||||
@ -121,25 +122,60 @@
|
|||||||
const editorDeleteImgList = ref([]);
|
const editorDeleteImgList = ref([]);
|
||||||
|
|
||||||
const originalTitle = ref('');
|
const originalTitle = ref('');
|
||||||
const originalPlainText = ref('');
|
const originalContent = ref({});
|
||||||
const originalFiles = ref([]);
|
const originalFiles = ref([]);
|
||||||
|
const contentInitialized = ref(false);
|
||||||
|
// 최초 업데이트 감지 여부
|
||||||
|
const isFirstContentUpdate = ref(true);
|
||||||
|
|
||||||
|
// 에디터에서 데이터 업데이트 시
|
||||||
|
const handleEditorDataUpdate = (data) => {
|
||||||
|
content.value = data;
|
||||||
|
|
||||||
|
if (isFirstContentUpdate.value) {
|
||||||
|
originalContent.value = structuredClone(data);
|
||||||
|
isFirstContentUpdate.value = false;
|
||||||
|
contentInitialized.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function extractPlainText(delta) {
|
function isDeltaChanged(current, original) {
|
||||||
if (!delta || !Array.isArray(delta.ops)) return '';
|
const Delta = Quill.import('delta');
|
||||||
return delta.ops
|
const currentDelta = new Delta(current || []);
|
||||||
|
const originalDelta = new Delta(original || []);
|
||||||
|
|
||||||
|
const diff = originalDelta.diff(currentDelta);
|
||||||
|
if (!diff || diff.ops.length === 0) return false;
|
||||||
|
|
||||||
|
// 텍스트만 비교해서 완전 동일한지 확인
|
||||||
|
const getPlainText = (delta) =>
|
||||||
|
(delta.ops || [])
|
||||||
.filter(op => typeof op.insert === 'string')
|
.filter(op => typeof op.insert === 'string')
|
||||||
.map(op => op.insert.trim())
|
.map(op => op.insert)
|
||||||
.join(' ')
|
.join('');
|
||||||
.trim();
|
|
||||||
|
const getImages = (delta) =>
|
||||||
|
(delta.ops || [])
|
||||||
|
.filter(op => typeof op.insert === 'object' && op.insert.image)
|
||||||
|
.map(op => op.insert.image);
|
||||||
|
|
||||||
|
const textCurrent = getPlainText(currentDelta);
|
||||||
|
const textOriginal = getPlainText(originalDelta);
|
||||||
|
|
||||||
|
const imgsCurrent = getImages(currentDelta);
|
||||||
|
const imgsOriginal = getImages(originalDelta);
|
||||||
|
|
||||||
|
const textEqual = textCurrent === textOriginal;
|
||||||
|
const imageEqual = JSON.stringify(imgsCurrent) === JSON.stringify(imgsOriginal);
|
||||||
|
|
||||||
|
return !(textEqual && imageEqual); // 둘 다 같아야 false
|
||||||
}
|
}
|
||||||
|
|
||||||
const isChanged = computed(() => {
|
const isChanged = computed(() => {
|
||||||
|
if (!contentInitialized.value) return false;
|
||||||
const isTitleChanged = title.value !== originalTitle.value;
|
const isTitleChanged = title.value !== originalTitle.value;
|
||||||
const currentPlainText = extractPlainText(content.value);
|
const isContentChanged = isDeltaChanged(content.value, originalContent.value);
|
||||||
const isContentChanged = currentPlainText !== originalPlainText.value;
|
|
||||||
|
|
||||||
const currentAttachedFiles = attachFiles.value.filter(f => f.id);
|
|
||||||
const isFilesChanged =
|
const isFilesChanged =
|
||||||
attachFiles.value.some(f => !f.id) || // id 없는 새 파일이 있는 경우
|
attachFiles.value.some(f => !f.id) || // id 없는 새 파일이 있는 경우
|
||||||
delFileIdx.value.length > 0 || // 삭제된 파일이 있는 경우
|
delFileIdx.value.length > 0 || // 삭제된 파일이 있는 경우
|
||||||
@ -147,12 +183,9 @@
|
|||||||
attachFiles.value.filter(f => f.id), // 기존 파일(id 있는 것만)
|
attachFiles.value.filter(f => f.id), // 기존 파일(id 있는 것만)
|
||||||
originalFiles.value
|
originalFiles.value
|
||||||
);
|
);
|
||||||
|
|
||||||
return isTitleChanged || isContentChanged || isFilesChanged ;
|
return isTitleChanged || isContentChanged || isFilesChanged ;
|
||||||
});
|
});
|
||||||
watch(isChanged, (val) => {
|
|
||||||
//console.log('🔄 isChanged changed:', val);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// 파일 비교 함수
|
// 파일 비교 함수
|
||||||
function isSameFiles(current, original) {
|
function isSameFiles(current, original) {
|
||||||
@ -197,15 +230,11 @@
|
|||||||
title.value = boardData.title || '제목 없음';
|
title.value = boardData.title || '제목 없음';
|
||||||
content.value = boardData.content || '내용 없음';
|
content.value = boardData.content || '내용 없음';
|
||||||
originalTitle.value = title.value;
|
originalTitle.value = title.value;
|
||||||
|
originalContent.value = structuredClone(boardData.content);
|
||||||
|
contentInitialized.value = true;
|
||||||
contentLoaded.value = true;
|
contentLoaded.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(content, (val) => {
|
|
||||||
if (contentLoaded.value && !originalPlainText.value) {
|
|
||||||
originalPlainText.value = extractPlainText(val);
|
|
||||||
}
|
|
||||||
}, { immediate: true });
|
|
||||||
|
|
||||||
const handleUpdateEditorImg = item => {
|
const handleUpdateEditorImg = item => {
|
||||||
editorUploadedImgList.value = item;
|
editorUploadedImgList.value = item;
|
||||||
};
|
};
|
||||||
@ -359,6 +388,7 @@
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (currentBoardId.value) {
|
if (currentBoardId.value) {
|
||||||
fetchBoardDetails();
|
fetchBoardDetails();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.error('잘못된 게시물 ID:', currentBoardId.value);
|
console.error('잘못된 게시물 ID:', currentBoardId.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,7 +80,7 @@
|
|||||||
></div>
|
></div>
|
||||||
|
|
||||||
<!-- 좋아요 버튼 -->
|
<!-- 좋아요 버튼 -->
|
||||||
<div v-if="unknown" class="row justify-content-center my-10">
|
<div v-if="unknown || authorId" class="row justify-content-center my-10">
|
||||||
<BoardRecommendBtn
|
<BoardRecommendBtn
|
||||||
:bigBtn="true"
|
:bigBtn="true"
|
||||||
:boardId="currentBoardId"
|
:boardId="currentBoardId"
|
||||||
@ -92,7 +92,7 @@
|
|||||||
@updateReaction="handleUpdateReaction"
|
@updateReaction="handleUpdateReaction"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="unknown" >
|
<div v-if="unknown || authorId" >
|
||||||
<!-- 댓글 입력 영역 -->
|
<!-- 댓글 입력 영역 -->
|
||||||
<BoardCommentArea
|
<BoardCommentArea
|
||||||
:profileName="profileName"
|
:profileName="profileName"
|
||||||
@ -106,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 댓글 목록 -->
|
<!-- 댓글 목록 -->
|
||||||
<div v-if="unknown" class="card-footer">
|
<div v-if="unknown || authorId" class="card-footer">
|
||||||
<BoardCommentList
|
<BoardCommentList
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
:comments="commentsWithAuthStatus"
|
:comments="commentsWithAuthStatus"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user