From 1f8b4267ee49f5a39f475d8ece3e6fae96ed68f2 Mon Sep 17 00:00:00 2001 From: khj0414 Date: Fri, 10 Jan 2025 15:10:28 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=ED=86=A0=EC=8A=A4=ED=8A=B8=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 2 + src/components/modal/ToastModal.vue | 58 +++++++++++++++++++++++++++++ src/main.js | 3 +- src/stores/toastStore.js | 28 ++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/components/modal/ToastModal.vue create mode 100644 src/stores/toastStore.js diff --git a/src/App.vue b/src/App.vue index 20d70e5..04bd0bd 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,6 +2,7 @@ @@ -10,6 +11,7 @@ import { computed } from 'vue'; import { useRoute } from 'vue-router'; import NormalLayout from './layouts/NormalLayout.vue'; import NoLayout from './layouts/NoLayout.vue'; +import ToastModal from '@c/modal/ToastModal.vue'; const route = useRoute(); diff --git a/src/components/modal/ToastModal.vue b/src/components/modal/ToastModal.vue new file mode 100644 index 0000000..b63c13f --- /dev/null +++ b/src/components/modal/ToastModal.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/main.js b/src/main.js index 14f4f3b..12ed27d 100644 --- a/src/main.js +++ b/src/main.js @@ -4,6 +4,7 @@ import piniaPersist from 'pinia-plugin-persist' import App from './App.vue' import router from '@/router' import dayjs from '@p/dayjs' +import ToastModal from '@c/modal/ToastModal.vue'; const pinia = createPinia() pinia.use(piniaPersist) @@ -12,9 +13,9 @@ const app = createApp(App) app.use(router) .use(pinia) .use(dayjs) + .component('ToastModal',ToastModal) .mount('#app') - if (import.meta.env.MODE === "prod") { const console = window.console || {}; console.log = function no_console() { }; // console log 막기 diff --git a/src/stores/toastStore.js b/src/stores/toastStore.js new file mode 100644 index 0000000..8822951 --- /dev/null +++ b/src/stores/toastStore.js @@ -0,0 +1,28 @@ +import { defineStore } from 'pinia'; + +export const useToastStore = defineStore('toastStore', { + state: () => ({ + toastModal: false, + toastMsg: '', + time: 2000, + toastType: 'success', // 'success' 또는 'error' + }), + actions: { + onToast(msg = '', time = 2000, type = 'success') { + this.toastModal = true; + this.toastMsg = msg; + this.time = time; + this.toastType = type; + + // 시간이 지난 후 토스트 숨기기 + setTimeout(() => { + this.offToast(); + }, this.time); + }, + offToast() { + this.toastModal = false; + this.toastMsg = ''; + this.toastType = 'success'; // 기본 상태로 초기화 + }, + }, +}); From e9dda8cbea8395c28e64df489d5089525c79810b Mon Sep 17 00:00:00 2001 From: khj0414 Date: Fri, 10 Jan 2025 15:21:47 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EB=AA=A8=EB=8B=AC=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/modal/ToastModal.vue | 2 +- src/stores/toastStore.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/modal/ToastModal.vue b/src/components/modal/ToastModal.vue index b63c13f..bf7afe2 100644 --- a/src/components/modal/ToastModal.vue +++ b/src/components/modal/ToastModal.vue @@ -32,7 +32,7 @@ const offToast = () => { }; const toastClass = computed(() => { - return toastStore.toastType === 'error' ? 'bg-danger' : 'bg-success'; // 에러일 경우 red, 정상일 경우 blue + return toastStore.toastType === 'e' ? 'bg-danger' : 'bg-success'; // 에러일 경우 red, 정상일 경우 blue }); diff --git a/src/stores/toastStore.js b/src/stores/toastStore.js index 8822951..e182216 100644 --- a/src/stores/toastStore.js +++ b/src/stores/toastStore.js @@ -4,25 +4,25 @@ export const useToastStore = defineStore('toastStore', { state: () => ({ toastModal: false, toastMsg: '', - time: 2000, - toastType: 'success', // 'success' 또는 'error' + time: 2000, + toastType: 's', }), actions: { - onToast(msg = '', time = 2000, type = 'success') { + onToast(msg = '', type = 's', time = 2000) { this.toastModal = true; this.toastMsg = msg; - this.time = time; this.toastType = type; + this.time = time; // 시간이 지난 후 토스트 숨기기 setTimeout(() => { this.offToast(); - }, this.time); + }, this.time); }, offToast() { this.toastModal = false; this.toastMsg = ''; - this.toastType = 'success'; // 기본 상태로 초기화 + this.toastType = 's'; }, }, }); From e1e071748ac01cc70a5c1668af0702c2bd706dbf Mon Sep 17 00:00:00 2001 From: khj0414 Date: Thu, 16 Jan 2025 13:18:54 +0900 Subject: [PATCH 3/3] =?UTF-8?q?q=20=EC=97=90=EB=94=94=ED=84=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/editor/QEditor.vue | 71 +++++++++++-------------------- 1 file changed, 26 insertions(+), 45 deletions(-) diff --git a/src/components/editor/QEditor.vue b/src/components/editor/QEditor.vue index c2776cf..8fb4538 100644 --- a/src/components/editor/QEditor.vue +++ b/src/components/editor/QEditor.vue @@ -79,7 +79,6 @@ onMounted(() => { syntax: true, }, }); - quillInstance.format('font', font.value); quillInstance.format('size', fontSize.value); @@ -91,15 +90,12 @@ onMounted(() => { quillInstance.format('font', font.value); quillInstance.format('size', fontSize.value); }); - - // 이미지 업로드 및 삭제 감지 로직 - // 아직 서버에 실험 안해봄 ***********처리부탁*********** + // 이미지 업로드 let imageUrls = new Set(); quillInstance.getModule('toolbar').addHandler('image', () => { selectLocalImage(); }); - quillInstance.on('text-change', (delta, oldDelta, source) => { emit('update:data', quillInstance.root.innerHTML); delta.ops.forEach(op => { @@ -112,7 +108,7 @@ onMounted(() => { }); }); - function selectLocalImage() { + async function selectLocalImage() { const input = document.createElement('input'); input.setAttribute('type', 'file'); input.setAttribute('accept', 'image/*'); @@ -121,24 +117,33 @@ onMounted(() => { input.onchange = () => { const file = input.files[0]; if (file) { - const reader = new FileReader(); - reader.onload = async (e) => { - const range = quillInstance.getSelection(); - const base64Image = e.target.result; + const formData = new FormData(); + formData.append('file', file); - try { - const serverImageUrl = await uploadImageToServer(base64Image); - quillInstance.insertEmbed(range.index, 'image', serverImageUrl); - imageUrls.add(serverImageUrl); - } catch (error) { - console.error('이미지 업로드 중 오류 발생:', error); - } - }; - reader.readAsDataURL(file); + uploadImageToServer(formData).then(serverImageUrl => { + const baseUrl = $api.defaults.baseURL.replace(/api\/$/, ''); + const fullImageUrl = `${baseUrl}${serverImageUrl.replace(/\\/g, '/')}`; + + const range = quillInstance.getSelection(); + quillInstance.insertEmbed(range.index, 'image', fullImageUrl); + + imageUrls.add(fullImageUrl); + }).catch(e => { + toastStore.onToast('잠시후 다시 시도해주세요.', 'e'); + }); } }; } - + async function uploadImageToServer(formData) { + try { + const response = await $api.post('img/upload', formData, { isFormData: true }); + const imageUrl = response.data.data; + return imageUrl; + } catch (error) { + toastStore.onToast('잠시후 다시 시도해주세요.', 'e'); + throw error; + } + } function checkForDeletedImages() { const editorImages = document.querySelectorAll('#editor img'); @@ -147,33 +152,9 @@ onMounted(() => { imageUrls.forEach(url => { if (!currentImages.has(url)) { imageUrls.delete(url); - removeImageFromServer(url); } }); } - - async function uploadImageToServer(base64Image) { - try { - const response = await $api.post('/img/upload', { - image: base64Image, - }); - return response.data.url; // 서버에서 반환한 이미지 URL - } catch (error) { - console.error('서버 업로드 중 오류 발생:', error); - throw error; - } - } - - async function removeImageFromServer(imageUrl) { - try { - await $api.delete('/img/delete', { - data: { url: imageUrl }, - }); - console.log(`서버에서 이미지 삭제: ${imageUrl}`); - } catch (error) { - console.error('서버 이미지 삭제 중 오류 발생:', error); - } - } }); @@ -185,4 +166,4 @@ onMounted(() => { min-height: 300px; font-family: 'Nanum Gothic', sans-serif; } - + \ No newline at end of file