230 lines
6.9 KiB
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>
|