Merge branch 'khj'

This commit is contained in:
khj0414 2025-02-07 14:48:04 +09:00
commit 7d03da5097
3 changed files with 43 additions and 22 deletions

View File

@ -48,7 +48,7 @@
<div ref="editor"></div>
<!-- Alert 메시지 표시 -->
<div class="invalid-feedback" :class="isAlert ? 'd-block' : ''">내용을 확인해주세요.</div>
<div class="invalid-feedback" :class="isAlert ? 'd-block' : ''">내용을 확인해주세요.</div>
</div>
</template>
@ -57,25 +57,32 @@ import Quill from 'quill';
import 'quill/dist/quill.snow.css';
import { onMounted, ref, watch, defineEmits, defineProps } from 'vue';
import $api from '@api';
const props = defineProps({
isAlert: {
type: Boolean,
default: false,
},
});
const editor = ref(null);
const font = ref('nanum-gothic');
const fontSize = ref('16px');
const editor = ref(null); // DOM
const font = ref('nanum-gothic'); //
const fontSize = ref('16px'); //
const emit = defineEmits(['update:data']);
onMounted(() => {
//
const Font = Quill.import('formats/font');
Font.whitelist = ['nanum-gothic', 'd2coding', 'consolas', 'serif', 'monospace'];
Quill.register(Font, true);
//
const Size = Quill.import('attributors/style/size');
Size.whitelist = ['12px', '14px', '16px', '18px', '24px', '32px', '48px'];
Quill.register(Size, true);
// Quill
const quillInstance = new Quill(editor.value, {
theme: 'snow',
placeholder: '내용을 입력해주세요...',
@ -86,74 +93,84 @@ onMounted(() => {
syntax: true,
},
});
//
quillInstance.format('font', font.value);
quillInstance.format('size', fontSize.value);
//
quillInstance.on('text-change', () => {
const delta = quillInstance.getContents(); // Get Delta format
const delta = quillInstance.getContents(); // Delta
emit('update:data', delta);
});
//
watch([font, fontSize], () => {
quillInstance.format('font', font.value);
quillInstance.format('size', fontSize.value);
});
// Handle image upload
let imageUrls = new Set();
//
let imageUrls = new Set(); // URL
quillInstance.getModule('toolbar').addHandler('image', () => {
selectLocalImage();
selectLocalImage(); //
});
//
quillInstance.on('text-change', (delta, oldDelta, source) => {
// Emit Delta when content changes
emit('update:data', quillInstance.getContents());
delta.ops.forEach(op => {
if (op.insert && typeof op.insert === 'object' && op.insert.image) {
const imageUrl = op.insert.image;
imageUrls.add(imageUrl);
const imageUrl = op.insert.image; // URL
imageUrls.add(imageUrl); // URL
} else if (op.delete) {
checkForDeletedImages();
checkForDeletedImages(); //
}
});
});
//
async function selectLocalImage() {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.click(); //
input.onchange = () => {
const file = input.files[0];
if (file) {
const formData = new FormData();
formData.append('file', file);
// URL
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);
quillInstance.insertEmbed(range.index, 'image', fullImageUrl); //
imageUrls.add(fullImageUrl);
imageUrls.add(fullImageUrl); // URL
}).catch(e => {
toastStore.onToast('잠시후 다시 시도해주세요.', 'e');
});
}
};
}
//
async function uploadImageToServer(formData) {
try {
const response = await $api.post('quilleditor/upload', formData, { isFormData: true });
const imageUrl = response.data.data;
return imageUrl;
return imageUrl; // URL
} catch (error) {
toastStore.onToast('잠시후 다시 시도해주세요.', 'e');
throw error;
}
}
//
function checkForDeletedImages() {
const editorImages = document.querySelectorAll('#editor img');
const currentImages = new Set(Array.from(editorImages).map(img => img.src));
const currentImages = new Set(Array.from(editorImages).map(img => img.src)); //
imageUrls.forEach(url => {
if (!currentImages.has(url)) {

View File

@ -14,7 +14,7 @@
>
<img
class="rounded-circle user-avatar"
:src="`http://localhost:10325/upload/img/profile/${user.MEMBERPRF}`"
:src="`${baseUrl}upload/img/profile/${user.MEMBERPRF}`"
alt="user"
:style="{ borderColor: user.usercolor}"
/>
@ -25,10 +25,12 @@
<script setup>
import { onMounted, ref, nextTick } from 'vue';
import { useUserStore } from '@s/userList';
import $api from '@api';
const emit = defineEmits();
const userStore = useUserStore();
const userList = ref([]);
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
//
onMounted(async () => {

View File

@ -33,18 +33,20 @@
<script setup>
import EditBtn from '@/components/button/EditBtn.vue';
import $api from '@api';
// Props
defineProps({
// Props
const props = defineProps({
item: {
type: Object,
required: true,
},
});
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
//
const formatDate = (dateString) => new Date(dateString).toLocaleString();
//
const getProfileImage = (imagePath) =>
imagePath ? `/img/avatars/${imagePath}` : '/img/avatars/default-Profile.jpg';
</script>
imagePath ? `${baseUrl}upload/img/profile/${imagePath}` : '/img/avatars/default-Profile.jpg';
</script>