localhost-front/src/components/wordDict/DictWrite.vue
2025-03-20 10:52:19 +09:00

227 lines
5.7 KiB
Vue

<template>
<div v-if="dataList.length > 0">
<FormSelect
class="me-5"
name="cate"
title="카테고리"
:data="dataList"
:is-common="true"
@update:data="selectCategory = $event"
@change="onChange"
:value="formValue"
:is-essential="false"
/>
<div v-if="!isDisabled" class="add-btn">
<PlusBtn @click="toggleInput"/>
</div>
</div>
<div v-if="dataList.length === 0 || showInput">
<FormInput
class="me-5 parent-class "
ref="categoryInputRef"
title="새 카테고리"
:isLabel="dataList.length === 0 ?true : false"
name="새 카테고리"
@update:modelValue="addCategory = $event"
:is-cate-alert="addCategoryAlert"
@focusout="handleCategoryFocusout(addCategory)"
/>
</div>
<FormInput class="me-5"
title="용어"
type="text"
name="word"
:is-essential="true"
:is-alert="wordTitleAlert"
:modelValue="titleValue"
@update:modelValue="wordTitle = $event"
:disabled="isDisabled"
@keyup="ValidHandler('title')"
/>
<div>
<QEditor class="" @keyup="ValidHandler('content')" @update:data="handleContentUpdate" @update:imageUrls="imageUrls = $event" :is-alert="wordContentAlert" :initialData="contentValue"/>
<div class="text-end mt-5">
<button class="btn btn-primary" @click="saveWord">
<i class="bx bx-check"></i>
</button>
</div>
</div>
</template>
<script setup>
import { defineProps, computed, ref, defineEmits } from 'vue';
import QEditor from '@/components/editor/QEditor.vue';
import FormInput from '@/components/input/FormInput.vue';
import FormSelect from '@/components/input/FormSelect.vue';
import PlusBtn from '../button/PlusBtn.vue';
const emit = defineEmits(['close','addCategory','addWord']);
//용어제목
const wordTitle = ref('');
const addCategory = ref('');
const content = ref('');
const imageUrls = ref([]);
//용어 Vaildation용
const wordTitleAlert = ref(false);
const wordContentAlert = ref(false);
const addCategoryAlert = ref(false);
//선택 카테고리
const selectCategory = ref('');
// 제목 상태
const computedTitle = computed(() =>
wordTitle.value === '' ? props.titleValue : wordTitle.value
);
// 카테고리 상태
const selectedCategory = computed(() =>
selectCategory.value === '' ? props.formValue : selectCategory.value
);
// 카테고리 입력 중복 ref
const categoryInputRef = ref(null);
const props = defineProps({
dataList: {
type: Array,
default: () => []
},
NumValue : {
type: Number
},
formValue : {
type:[String, Number]
},
titleValue : {
type:String,
},contentValue : {
type:String,
},
isDisabled: {
type: Boolean,
default: false
}
});
// 카테고리 입력 창
const showInput = ref(false);
// 카테고리 입력 토글
const toggleInput = () => {
showInput.value = !showInput.value;
};
const onChange = (newValue) => {
selectCategory.value = newValue.target.value;
};
const ValidHandler = (field) => {
if(field == 'title'){
wordTitleAlert.value = false;
}
if(field == 'content'){
wordContentAlert.value = false;
}
}
const handleContentUpdate = (newContent) => {
content.value = newContent;
ValidHandler("content"); // 유효성 검사 실행
};
//용어 등록
const saveWord = () => {
let valid = true;
//validation
let computedTitleTrim;
if(computedTitle.value != undefined){
computedTitleTrim = computedTitle.value.trim()
}
// 용어 체크
if(computedTitleTrim == undefined || computedTitleTrim == ''){
wordTitleAlert.value = true;
valid = false;
} else {
wordTitleAlert.value = false;
}
// 내용 확인
let inserts = [];
if (inserts.length === 0 && content.value?.ops?.length > 0) {
inserts = content.value.ops.map(op =>
typeof op.insert === 'string' ? op.insert.trim() : op.insert
);
}
// 내용 체크
if(content.value == '' || inserts.join('') === ''){
wordContentAlert.value = true;
valid = false;
}else{
wordContentAlert.value = false;
}
const wordData = {
id: props.NumValue || null,
title: computedTitle.value.trim(),
category: selectedCategory.value,
content: content.value,
};
if(valid){
emit('addWord', wordData, addCategory.value.trim() === ''
? (isNaN(selectedCategory.value) ? selectedCategory.value : Number(selectedCategory.value))
: addCategory.value);
}
}
// 카테고리 focusout 이벤트 핸들러 추가
const handleCategoryFocusout = (value) => {
if (!value || value.trim() === '') {
return;
}
const valueTrim = value.trim();
const existingCategory = props.dataList.find(item => item.label === valueTrim);
if (existingCategory) {
addCategoryAlert.value = true;
// 중복 시 강제 focus
setTimeout(() => {
const inputElement = categoryInputRef.value?.$el?.querySelector('input');
if (inputElement) {
inputElement.focus();
}
}, 0);
} else {
addCategoryAlert.value = false;
}
};
</script>
<style scoped>
.dict-w {
width: 83%;
}
@media (max-width: 768px) {
.btn-margin {
margin-top: 2.5rem
}
}
.add-btn {
position: absolute;
right: 0.7rem;
top: 1.2rem;
}
.parent-class {
justify-content: flex-end;
}
</style>