게시판 동영상 수정
This commit is contained in:
parent
5c7f7c6346
commit
ba9a752250
@ -99,7 +99,7 @@
|
|||||||
|
|
||||||
// 상태 변수
|
// 상태 변수
|
||||||
const title = ref('');
|
const title = ref('');
|
||||||
const content = ref('');
|
const content = ref({ ops: [] });
|
||||||
const autoIncrement = ref(0);
|
const autoIncrement = ref(0);
|
||||||
|
|
||||||
// 경고 상태
|
// 경고 상태
|
||||||
@ -130,10 +130,9 @@
|
|||||||
// 최초 업데이트 감지 여부
|
// 최초 업데이트 감지 여부
|
||||||
const isFirstContentUpdate = ref(true);
|
const isFirstContentUpdate = ref(true);
|
||||||
|
|
||||||
// 에디터에서 데이터 업데이트 시
|
// 에디터 데이터 업데이트 시 처리 (최초 데이터 저장)
|
||||||
const handleEditorDataUpdate = data => {
|
const handleEditorDataUpdate = data => {
|
||||||
content.value = data;
|
content.value = data;
|
||||||
|
|
||||||
if (isFirstContentUpdate.value) {
|
if (isFirstContentUpdate.value) {
|
||||||
originalContent.value = structuredClone(data);
|
originalContent.value = structuredClone(data);
|
||||||
isFirstContentUpdate.value = false;
|
isFirstContentUpdate.value = false;
|
||||||
@ -141,23 +140,28 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// isDeltaChanged 함수 수정 (내장 diff 대신 텍스트, 이미지, 비디오 각각을 직접 비교)
|
||||||
function isDeltaChanged(current, original) {
|
function isDeltaChanged(current, original) {
|
||||||
const Delta = Quill.import('delta');
|
const Delta = Quill.import('delta');
|
||||||
const currentDelta = new Delta(current || []);
|
const currentDelta = new Delta(current || []);
|
||||||
const originalDelta = new Delta(original || []);
|
const originalDelta = new Delta(original || []);
|
||||||
|
|
||||||
const diff = originalDelta.diff(currentDelta);
|
// 텍스트 추출
|
||||||
if (!diff || diff.ops.length === 0) return false;
|
|
||||||
|
|
||||||
// 텍스트만 비교해서 완전 동일한지 확인
|
|
||||||
const getPlainText = delta =>
|
const getPlainText = delta =>
|
||||||
(delta.ops || [])
|
(delta.ops || [])
|
||||||
.filter(op => typeof op.insert === 'string')
|
.filter(op => typeof op.insert === 'string')
|
||||||
.map(op => op.insert)
|
.map(op => op.insert)
|
||||||
.join('');
|
.join('');
|
||||||
|
// 이미지 URL 추출
|
||||||
const getImages = delta =>
|
const getImages = delta =>
|
||||||
(delta.ops || []).filter(op => typeof op.insert === 'object' && op.insert.image).map(op => op.insert.image);
|
(delta.ops || [])
|
||||||
|
.filter(op => typeof op.insert === 'object' && op.insert.image)
|
||||||
|
.map(op => op.insert.image);
|
||||||
|
// 비디오 URL 추출
|
||||||
|
const getVideos = delta =>
|
||||||
|
(delta.ops || [])
|
||||||
|
.filter(op => typeof op.insert === 'object' && op.insert.video)
|
||||||
|
.map(op => op.insert.video);
|
||||||
|
|
||||||
const textCurrent = getPlainText(currentDelta);
|
const textCurrent = getPlainText(currentDelta);
|
||||||
const textOriginal = getPlainText(originalDelta);
|
const textOriginal = getPlainText(originalDelta);
|
||||||
@ -165,22 +169,27 @@
|
|||||||
const imgsCurrent = getImages(currentDelta);
|
const imgsCurrent = getImages(currentDelta);
|
||||||
const imgsOriginal = getImages(originalDelta);
|
const imgsOriginal = getImages(originalDelta);
|
||||||
|
|
||||||
const textEqual = textCurrent === textOriginal;
|
const vidsCurrent = getVideos(currentDelta);
|
||||||
const imageEqual = JSON.stringify(imgsCurrent) === JSON.stringify(imgsOriginal);
|
const vidsOriginal = getVideos(originalDelta);
|
||||||
|
|
||||||
return !(textEqual && imageEqual); // 둘 다 같아야 false
|
const textEqual = textCurrent === textOriginal;
|
||||||
|
const imageEqual = imgsCurrent.length === imgsOriginal.length && imgsCurrent.every((val, idx) => val === imgsOriginal[idx]);
|
||||||
|
const videoEqual = vidsCurrent.length === vidsOriginal.length && vidsCurrent.every((val, idx) => val === vidsOriginal[idx]);
|
||||||
|
|
||||||
|
return !(textEqual && imageEqual && videoEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 게시물 변경 여부 계산
|
||||||
const isChanged = computed(() => {
|
const isChanged = computed(() => {
|
||||||
if (!contentInitialized.value) return false;
|
if (!contentInitialized.value) return false;
|
||||||
const isTitleChanged = title.value !== originalTitle.value;
|
const isTitleChanged = title.value !== originalTitle.value;
|
||||||
const isContentChanged = isDeltaChanged(content.value, originalContent.value);
|
const isContentChanged = isDeltaChanged(content.value, originalContent.value);
|
||||||
const isFilesChanged =
|
const isFilesChanged =
|
||||||
attachFiles.value.some(f => !f.id) || // id 없는 새 파일이 있는 경우
|
attachFiles.value.some(f => !f.id) || // 신규 파일 존재
|
||||||
delFileIdx.value.length > 0 || // 삭제된 파일이 있는 경우
|
delFileIdx.value.length > 0 || // 삭제된 파일이 있는 경우
|
||||||
!isSameFiles(
|
!isSameFiles(
|
||||||
attachFiles.value.filter(f => f.id), // 기존 파일(id 있는 것만)
|
attachFiles.value.filter(f => f.id), // 기존 파일만 비교
|
||||||
originalFiles.value,
|
originalFiles.value
|
||||||
);
|
);
|
||||||
return isTitleChanged || isContentChanged || isFilesChanged;
|
return isTitleChanged || isContentChanged || isFilesChanged;
|
||||||
});
|
});
|
||||||
@ -188,10 +197,8 @@
|
|||||||
// 파일 비교 함수
|
// 파일 비교 함수
|
||||||
function isSameFiles(current, original) {
|
function isSameFiles(current, original) {
|
||||||
if (current.length !== original.length) return false;
|
if (current.length !== original.length) return false;
|
||||||
|
|
||||||
const sortedCurrent = [...current].sort((a, b) => a.id - b.id);
|
const sortedCurrent = [...current].sort((a, b) => a.id - b.id);
|
||||||
const sortedOriginal = [...original].sort((a, b) => a.id - b.id);
|
const sortedOriginal = [...original].sort((a, b) => a.id - b.id);
|
||||||
|
|
||||||
return sortedCurrent.every((file, idx) => {
|
return sortedCurrent.every((file, idx) => {
|
||||||
return file.id === sortedOriginal[idx].id && file.name === sortedOriginal[idx].name;
|
return file.id === sortedOriginal[idx].id && file.name === sortedOriginal[idx].name;
|
||||||
});
|
});
|
||||||
@ -199,31 +206,24 @@
|
|||||||
|
|
||||||
// 게시물 데이터 로드
|
// 게시물 데이터 로드
|
||||||
const fetchBoardDetails = async () => {
|
const fetchBoardDetails = async () => {
|
||||||
// 수정 데이터 전송
|
|
||||||
let password = accessStore.password;
|
let password = accessStore.password;
|
||||||
const params = {
|
const params = {
|
||||||
password: `${password}` || '',
|
password: `${password}` || '',
|
||||||
};
|
};
|
||||||
//const response = await axios.get(`board/${currentBoardId.value}`);
|
|
||||||
const { data } = await axios.post(`board/${currentBoardId.value}`, params);
|
const { data } = await axios.post(`board/${currentBoardId.value}`, params);
|
||||||
|
|
||||||
if (data.code !== 200) {
|
if (data.code !== 200) {
|
||||||
//toastStore.onToast(data.message, 'e');
|
|
||||||
alert(data.message, 'e');
|
alert(data.message, 'e');
|
||||||
router.back();
|
router.back();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const boardData = data.data;
|
const boardData = data.data;
|
||||||
// 기존 첨부파일 추가
|
|
||||||
if (boardData.hasAttachment && boardData.attachments.length > 0) {
|
if (boardData.hasAttachment && boardData.attachments.length > 0) {
|
||||||
const formatted = addDisplayFileName([...boardData.attachments]);
|
const formatted = addDisplayFileName([...boardData.attachments]);
|
||||||
attachFiles.value = formatted;
|
attachFiles.value = formatted;
|
||||||
originalFiles.value = formatted;
|
originalFiles.value = formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 데이터 설정
|
|
||||||
title.value = boardData.title || '제목 없음';
|
title.value = boardData.title || '제목 없음';
|
||||||
content.value = boardData.content || '내용 없음';
|
content.value = boardData.content || { ops: [] };
|
||||||
originalTitle.value = title.value;
|
originalTitle.value = title.value;
|
||||||
originalContent.value = structuredClone(boardData.content);
|
originalContent.value = structuredClone(boardData.content);
|
||||||
contentInitialized.value = true;
|
contentInitialized.value = true;
|
||||||
@ -242,38 +242,34 @@
|
|||||||
const addDisplayFileName = fileInfos =>
|
const addDisplayFileName = fileInfos =>
|
||||||
fileInfos.map(file => ({
|
fileInfos.map(file => ({
|
||||||
...file,
|
...file,
|
||||||
name: `${file.originalName}.${file.extension}`,
|
name: `${file.originalName}.${file.extension}`
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 상세 페이지로 이동
|
// 상세 페이지 이동
|
||||||
const goList = () => {
|
const goList = () => {
|
||||||
accessStore.$reset();
|
accessStore.$reset();
|
||||||
|
|
||||||
// 목록으로 바로 이동시 필터 유지
|
|
||||||
// const getFilter = localStorage.getItem(`boardList_${currentBoardId.value}`);
|
|
||||||
// if (getFilter) {
|
|
||||||
// router.push({
|
|
||||||
// path: '/board',
|
|
||||||
// query: JSON.parse(getFilter),
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// router.push('/board');
|
|
||||||
// }
|
|
||||||
|
|
||||||
router.back();
|
router.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 전 페이지로 이동
|
// 전 페이지 이동
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
accessStore.$reset();
|
accessStore.$reset();
|
||||||
router.back();
|
router.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 유효성 확인
|
// 로컬 유효성 검사 함수 (에디터 내용: 텍스트, 이미지, 비디오 중 하나라도 있으면 유효)
|
||||||
const checkValidation = () => {
|
const isNotValidContent = delta => {
|
||||||
contentAlert.value = $common.isNotValidContent(content);
|
if (!delta?.ops?.length) return true;
|
||||||
titleAlert.value = $common.isNotValidInput(title.value);
|
const hasText = delta.ops.some(op => typeof op.insert === 'string' && op.insert.trim().length > 0);
|
||||||
|
const hasImage = delta.ops.some(op => op.insert && typeof op.insert === 'object' && op.insert.image);
|
||||||
|
const hasVideo = delta.ops.some(op => op.insert && typeof op.insert === 'object' && op.insert.video);
|
||||||
|
return !(hasText || hasImage || hasVideo);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 유효성 확인 함수
|
||||||
|
const checkValidation = () => {
|
||||||
|
contentAlert.value = isNotValidContent(content.value);
|
||||||
|
titleAlert.value = $common.isNotValidInput(title.value);
|
||||||
if (titleAlert.value || contentAlert.value || !isFileValid.value) {
|
if (titleAlert.value || contentAlert.value || !isFileValid.value) {
|
||||||
if (titleAlert.value) {
|
if (titleAlert.value) {
|
||||||
title.value = '';
|
title.value = '';
|
||||||
@ -289,7 +285,6 @@
|
|||||||
|
|
||||||
const handleFileUpload = files => {
|
const handleFileUpload = files => {
|
||||||
const validFiles = files.filter(file => file.size <= maxSize);
|
const validFiles = files.filter(file => file.size <= maxSize);
|
||||||
|
|
||||||
if (files.some(file => file.size > maxSize)) {
|
if (files.some(file => file.size > maxSize)) {
|
||||||
fileError.value = '파일 크기가 10MB를 초과할 수 없습니다.';
|
fileError.value = '파일 크기가 10MB를 초과할 수 없습니다.';
|
||||||
return;
|
return;
|
||||||
@ -300,13 +295,11 @@
|
|||||||
}
|
}
|
||||||
fileError.value = '';
|
fileError.value = '';
|
||||||
attachFiles.value = [...attachFiles.value, ...validFiles].slice(0, maxFiles);
|
attachFiles.value = [...attachFiles.value, ...validFiles].slice(0, maxFiles);
|
||||||
|
|
||||||
autoIncrement.value++;
|
autoIncrement.value++;
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeFile = (index, file) => {
|
const removeFile = (index, file) => {
|
||||||
if (file.id) delFileIdx.value.push(file.id);
|
if (file.id) delFileIdx.value.push(file.id);
|
||||||
|
|
||||||
attachFiles.value.splice(index, 1);
|
attachFiles.value.splice(index, 1);
|
||||||
if (attachFiles.value.length <= maxFiles) {
|
if (attachFiles.value.length <= maxFiles) {
|
||||||
fileError.value = '';
|
fileError.value = '';
|
||||||
@ -324,55 +317,41 @@
|
|||||||
};
|
};
|
||||||
////////////////// fileSection[E] ////////////////////
|
////////////////// fileSection[E] ////////////////////
|
||||||
|
|
||||||
/** `content` 변경 감지하여 자동 유효성 검사 실행 */
|
/** content 변경 감지 (deep 옵션 추가) */
|
||||||
watch(content, () => {
|
watch(content, () => {
|
||||||
contentAlert.value = $common.isNotValidContent(content);
|
contentAlert.value = isNotValidContent(content.value);
|
||||||
});
|
}, { deep: true });
|
||||||
|
|
||||||
// 글 제목 유효성
|
// 글 제목 유효성 검사
|
||||||
const validateTitle = () => {
|
const validateTitle = () => {
|
||||||
titleAlert.value = title.value.trim().length === 0;
|
titleAlert.value = title.value.trim().length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 게시물 수정
|
// 게시물 수정 함수
|
||||||
const updateBoard = async () => {
|
const updateBoard = async () => {
|
||||||
if (checkValidation()) return;
|
if (checkValidation()) return;
|
||||||
|
|
||||||
// 수정 데이터 전송
|
|
||||||
const boardData = {
|
const boardData = {
|
||||||
LOCBRDTTL: title.value.trim(),
|
LOCBRDTTL: title.value.trim(),
|
||||||
LOCBRDCON: JSON.stringify(content.value),
|
LOCBRDCON: JSON.stringify(content.value),
|
||||||
LOCBRDSEQ: currentBoardId.value,
|
LOCBRDSEQ: currentBoardId.value
|
||||||
};
|
};
|
||||||
|
|
||||||
// 업로드 된 첨부파일의 삭제목록
|
|
||||||
if (delFileIdx.value && delFileIdx.value.length > 0) {
|
if (delFileIdx.value && delFileIdx.value.length > 0) {
|
||||||
boardData.delFileIdx = [...delFileIdx.value];
|
boardData.delFileIdx = [...delFileIdx.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 에디터에 업로드 된 이미지 인덱스 목록
|
|
||||||
if (editorUploadedImgList.value && editorUploadedImgList.value.length > 0) {
|
if (editorUploadedImgList.value && editorUploadedImgList.value.length > 0) {
|
||||||
boardData.editorUploadedImgList = [...editorUploadedImgList.value];
|
boardData.editorUploadedImgList = [...editorUploadedImgList.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 삭제할 에디터 이미지 인덱스
|
|
||||||
if (editorDeleteImgList.value && editorDeleteImgList.value.length > 0) {
|
if (editorDeleteImgList.value && editorDeleteImgList.value.length > 0) {
|
||||||
boardData.editorDeleteImgList = [...editorDeleteImgList.value];
|
boardData.editorDeleteImgList = [...editorDeleteImgList.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileArray = newFileFilter(attachFiles);
|
const fileArray = newFileFilter(attachFiles);
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
// formData에 boardData 추가
|
|
||||||
Object.entries(boardData).forEach(([key, value]) => {
|
Object.entries(boardData).forEach(([key, value]) => {
|
||||||
formData.append(key, value);
|
formData.append(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
// formData에 새로 추가한 파일 추가
|
|
||||||
fileArray.forEach((file, idx) => {
|
fileArray.forEach((file, idx) => {
|
||||||
formData.append('files', file);
|
formData.append('files', file);
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data } = await axios.put(`board/${currentBoardId.value}`, formData, { isFormData: true });
|
const { data } = await axios.put(`board/${currentBoardId.value}`, formData, { isFormData: true });
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
toastStore.onToast('게시물이 수정되었습니다.', 's');
|
toastStore.onToast('게시물이 수정되었습니다.', 's');
|
||||||
|
|||||||
@ -37,7 +37,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback" :class="categoryAlert ? 'd-block' : 'd-none'">카테고리를 선택해주세요.</div>
|
<div class="invalid-feedback" :class="categoryAlert ? 'd-block' : 'd-none'">
|
||||||
|
카테고리를 선택해주세요.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 비밀번호 필드 (익명게시판 선택 시 활성화) -->
|
<!-- 비밀번호 필드 (익명게시판 선택 시 활성화) -->
|
||||||
@ -101,11 +103,14 @@
|
|||||||
@update:deleteImgIndexList="handleDeleteEditorImg"
|
@update:deleteImgIndexList="handleDeleteEditorImg"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback mt-1" :class="contentAlert ? 'd-block' : 'd-none'">내용을 입력해주세요.</div>
|
<div class="invalid-feedback mt-1" :class="contentAlert ? 'd-block' : 'd-none'">
|
||||||
|
내용을 입력해주세요.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4 d-flex justify-content-end">
|
<div class="mb-4 d-flex justify-content-end">
|
||||||
<BackButton @click="goList" />
|
<BackButton @click="goList" />
|
||||||
|
<!-- 저장 버튼은 항상 활성화 -->
|
||||||
<SaveButton @click="write" :isEnabled="isFileValid" />
|
<SaveButton @click="write" :isEnabled="isFileValid" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -115,7 +120,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, getCurrentInstance, watch, computed } from 'vue';
|
import { ref, onMounted, watch, computed } from 'vue';
|
||||||
import QEditor from '@c/editor/QEditor.vue';
|
import QEditor from '@c/editor/QEditor.vue';
|
||||||
import FormInput from '@c/input/FormInput.vue';
|
import FormInput from '@c/input/FormInput.vue';
|
||||||
import FormFile from '@c/input/FormFile.vue';
|
import FormFile from '@c/input/FormFile.vue';
|
||||||
@ -169,10 +174,12 @@
|
|||||||
|
|
||||||
const fileCount = computed(() => attachFiles.value.length);
|
const fileCount = computed(() => attachFiles.value.length);
|
||||||
|
|
||||||
|
// 업데이트된 에디터 이미지 목록 업데이트
|
||||||
const handleUpdateEditorImg = item => {
|
const handleUpdateEditorImg = item => {
|
||||||
editorUploadedImgList.value = item;
|
editorUploadedImgList.value = item;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 삭제된 에디터 이미지 목록 업데이트
|
||||||
const handleDeleteEditorImg = item => {
|
const handleDeleteEditorImg = item => {
|
||||||
editorDeleteImgList.value = item;
|
editorDeleteImgList.value = item;
|
||||||
};
|
};
|
||||||
@ -187,10 +194,8 @@
|
|||||||
fileError.value = `최대 ${maxFiles}개의 파일만 업로드할 수 있습니다.`;
|
fileError.value = `최대 ${maxFiles}개의 파일만 업로드할 수 있습니다.`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileError.value = '';
|
fileError.value = '';
|
||||||
attachFiles.value = [...attachFiles.value, ...validFiles].slice(0, maxFiles);
|
attachFiles.value = [...attachFiles.value, ...validFiles].slice(0, maxFiles);
|
||||||
|
|
||||||
autoIncrement.value++;
|
autoIncrement.value++;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -213,7 +218,7 @@
|
|||||||
const validateNickname = () => {
|
const validateNickname = () => {
|
||||||
if (categoryValue.value === 300102) {
|
if (categoryValue.value === 300102) {
|
||||||
nickname.value = nickname.value.replace(/\s/g, ''); // 공백 제거
|
nickname.value = nickname.value.replace(/\s/g, ''); // 공백 제거
|
||||||
nicknameAlert.value = nickname.value.length === 0 ;
|
nicknameAlert.value = nickname.value.length === 0;
|
||||||
} else {
|
} else {
|
||||||
nicknameAlert.value = false;
|
nicknameAlert.value = false;
|
||||||
}
|
}
|
||||||
@ -228,19 +233,28 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validateContent:
|
||||||
|
* - 내용이 없으면 contentAlert를 true로 설정
|
||||||
|
* - 텍스트, 이미지, 비디오 중 하나라도 존재하면 유효한 콘텐츠로 판단
|
||||||
|
*/
|
||||||
const validateContent = () => {
|
const validateContent = () => {
|
||||||
if (!content.value?.ops?.length) {
|
if (!content.value?.ops?.length) {
|
||||||
contentAlert.value = true;
|
contentAlert.value = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 이미지 포함 여부 확인
|
const hasText = content.value.ops.some(
|
||||||
const hasImage = content.value.ops.some(op => op.insert && typeof op.insert === 'object' && op.insert.image);
|
op => typeof op.insert === 'string' && op.insert.trim().length > 0
|
||||||
// 텍스트 포함 여부 확인
|
);
|
||||||
const hasText = content.value.ops.some(op => typeof op.insert === 'string' && op.insert.trim().length > 0);
|
const hasImage = content.value.ops.some(
|
||||||
|
op => op.insert && typeof op.insert === 'object' && op.insert.image
|
||||||
|
);
|
||||||
|
const hasVideo = content.value.ops.some(
|
||||||
|
op => op.insert && typeof op.insert === 'object' && op.insert.video
|
||||||
|
);
|
||||||
|
|
||||||
// 텍스트 또는 이미지가 하나라도 있으면 유효한 내용
|
contentAlert.value = !(hasText || hasImage || hasVideo);
|
||||||
contentAlert.value = !(hasText || hasImage);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 글쓰기 */
|
/** 글쓰기 */
|
||||||
@ -294,10 +308,10 @@
|
|||||||
formData.append('CMNFLEORG', fileNameWithoutExt);
|
formData.append('CMNFLEORG', fileNameWithoutExt);
|
||||||
formData.append('CMNFLEEXT', file.name.split('.').pop());
|
formData.append('CMNFLEEXT', file.name.split('.').pop());
|
||||||
formData.append('CMNFLESIZ', file.size);
|
formData.append('CMNFLESIZ', file.size);
|
||||||
formData.append('file', file); // 📌 실제 파일 추가
|
formData.append('file', file);
|
||||||
|
|
||||||
await axios.post(`board/${boardId}/attachments`, formData, { isFormData: true });
|
await axios.post(`board/${boardId}/attachments`, formData, { isFormData: true });
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,8 +327,8 @@
|
|||||||
router.push('/board');
|
router.push('/board');
|
||||||
};
|
};
|
||||||
|
|
||||||
/** `content` 변경 감지하여 자동 유효성 검사 실행 */
|
/** content 변경 감지 (deep 옵션 추가) */
|
||||||
watch(content, () => {
|
watch(content, () => {
|
||||||
validateContent();
|
validateContent();
|
||||||
});
|
}, { deep: true });
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user