localhost-front/src/components/wordDict/DictWrite.vue

230 lines
6.9 KiB
Vue

<template>
<div v-if="dataList.length > 0">
<FormSelect
name="cate"
title="카테고리"
:data="dataList"
:is-common="true"
@update:data="selectCategory = $event"
@change="onChange"
:value="formValue"
:is-essential="false"
:is-btn="true"
>
<template v-slot:append>
<div>
<PlusBtn v-if="!showInput && !isDisabled" @click="toggleInput" />
<EditBtn
v-if="showEditBtn"
@click="$emit('toggleEdit')"
:isToggleEnabled="true"
:isActive="writeStore.isItemActive(NumValue)"
/>
</div>
</template>
</FormSelect>
</div>
<div v-if="dataList.length === 0 || showInput">
<FormInput
class="justify-content-end"
ref="categoryInputRef"
title="새 카테고리"
:isLabel="dataList.length === 0 ? true : false"
name="새 카테고리"
@update:modelValue="addCategory = $event"
:is-cate-alert="addCategoryAlert"
@focusout="handleCategoryFocusout(addCategory)"
/>
</div>
<FormInput
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:deleteImgIndexList="$emit('update:deleteImgIndexList', $event)"
@update:uploadedImgList="$emit('update:uploadedImgList', $event)"
@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';
import EditBtn from '../button/EditBtn.vue';
import { useWriteVisibleStore } from '@s/writeVisible';
const writeStore = useWriteVisibleStore();
const emit = defineEmits(['close', 'addCategory', 'addWord', 'toggleEdit', 'update:deleteImgIndexList', 'update:uploadedImgList']);
//용어제목
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,
},
showEditBtn: {
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>