용어집 에디터 이미지 매핑 및 삭제 로직 추가
This commit is contained in:
parent
52d520f5e4
commit
51793fcde3
@ -2,7 +2,7 @@
|
|||||||
<li class="card p-5 mb-2">
|
<li class="card p-5 mb-2">
|
||||||
<DictWrite
|
<DictWrite
|
||||||
v-if="writeStore.isItemActive(item.WRDDICSEQ)"
|
v-if="writeStore.isItemActive(item.WRDDICSEQ)"
|
||||||
@close="writeStore.closeAll();"
|
@close="writeStore.closeAll()"
|
||||||
:dataList="cateList"
|
:dataList="cateList"
|
||||||
@addWord="editWord"
|
@addWord="editWord"
|
||||||
:NumValue="item.WRDDICSEQ"
|
:NumValue="item.WRDDICSEQ"
|
||||||
@ -12,6 +12,8 @@
|
|||||||
:isDisabled="true"
|
:isDisabled="true"
|
||||||
:showEditBtn="true"
|
:showEditBtn="true"
|
||||||
@toggleEdit="toggleEdit"
|
@toggleEdit="toggleEdit"
|
||||||
|
@update:deleteImgIndexList="handleDeleteEditorImg"
|
||||||
|
@update:uploadedImgList="handleUpdateEditorImg"
|
||||||
/>
|
/>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
@ -19,11 +21,7 @@
|
|||||||
<span class="btn btn-primary pe-none">{{ item.category }}</span>
|
<span class="btn btn-primary pe-none">{{ item.category }}</span>
|
||||||
<strong class="mx-2 w-75">{{ item.WRDDICTTL }}</strong>
|
<strong class="mx-2 w-75">{{ item.WRDDICTTL }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<EditBtn
|
<EditBtn @click="toggleEdit" :isToggleEnabled="true" :isActive="writeStore.isItemActive(item.WRDDICSEQ)" />
|
||||||
@click="toggleEdit"
|
|
||||||
:isToggleEnabled="true"
|
|
||||||
:isActive="writeStore.isItemActive(item.WRDDICSEQ)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-5 dict-content-wrap" v-html="$common.contentToHtml(item.WRDDICCON)"></p>
|
<p class="mt-5 dict-content-wrap" v-html="$common.contentToHtml(item.WRDDICCON)"></p>
|
||||||
<div class="d-flex align-items-start">
|
<div class="d-flex align-items-start">
|
||||||
@ -44,10 +42,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 최근 작성자 (조건부) -->
|
<!-- 최근 작성자 (조건부) -->
|
||||||
<div
|
<div v-if="item.author.createdAt !== item.lastEditor.updatedAt" class="d-flex flex-wrap align-items-center">
|
||||||
v-if="item.author.createdAt !== item.lastEditor.updatedAt"
|
|
||||||
class="d-flex flex-wrap align-items-center"
|
|
||||||
>
|
|
||||||
<div class="avatar avatar-sm me-2">
|
<div class="avatar avatar-sm me-2">
|
||||||
<img
|
<img
|
||||||
class="rounded-circle user-avatar"
|
class="rounded-circle user-avatar"
|
||||||
@ -67,115 +62,137 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import axios from "@api";
|
import axios from '@api';
|
||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
import { getCurrentInstance, nextTick, ref } from 'vue';
|
import { getCurrentInstance, nextTick, ref } from 'vue';
|
||||||
import EditBtn from '@/components/button/EditBtn.vue';
|
import EditBtn from '@/components/button/EditBtn.vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
import DictWrite from './DictWrite.vue';
|
import DictWrite from './DictWrite.vue';
|
||||||
import { useUserInfoStore } from '@s/useUserInfoStore';
|
import { useUserInfoStore } from '@s/useUserInfoStore';
|
||||||
import { useWriteVisibleStore } from '@s/writeVisible';
|
import { useWriteVisibleStore } from '@s/writeVisible';
|
||||||
|
|
||||||
const writeStore = useWriteVisibleStore();
|
const writeStore = useWriteVisibleStore();
|
||||||
const writeButton = ref(null);
|
const writeButton = ref(null);
|
||||||
|
const editorDeleteImgList = ref([]);
|
||||||
|
const editorUploadedImgList = ref([]);
|
||||||
|
|
||||||
// 유저 구분
|
// 유저 구분
|
||||||
const userStore = useUserInfoStore();
|
const userStore = useUserInfoStore();
|
||||||
|
|
||||||
const toastStore = useToastStore();
|
const toastStore = useToastStore();
|
||||||
|
|
||||||
const { appContext } = getCurrentInstance();
|
const { appContext } = getCurrentInstance();
|
||||||
const $common = appContext.config.globalProperties.$common;
|
const $common = appContext.config.globalProperties.$common;
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
cateList: {
|
cateList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// cateList emit
|
// cateList emit
|
||||||
const emit = defineEmits(['update:cateList','refreshWordList', 'updateChecked']);
|
const emit = defineEmits(['update:cateList', 'refreshWordList', 'updateChecked', 'update:deleteImgIndexList']);
|
||||||
|
|
||||||
|
|
||||||
// 용어집 수정
|
|
||||||
const editWord = (data) => {
|
|
||||||
|
|
||||||
|
// 용어집 수정
|
||||||
|
const editWord = data => {
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
console.error('❌ 수정할 데이터의 ID가 없습니다.');
|
console.error('❌ 수정할 데이터의 ID가 없습니다.');
|
||||||
toastStore.onToast('수정할 용어의 ID가 필요합니다.', 'e');
|
toastStore.onToast('수정할 용어의 ID가 필요합니다.', 'e');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.patch('worddict/updateWord', {
|
const param = {
|
||||||
WRDDICSEQ: data.id,
|
WRDDICSEQ: data.id,
|
||||||
WRDDICCAT: data.category,
|
WRDDICCAT: data.category,
|
||||||
WRDDICTTL: data.title,
|
WRDDICTTL: data.title,
|
||||||
WRDDICCON: $common.deltaAsJson(data.content),
|
WRDDICCON: $common.deltaAsJson(data.content),
|
||||||
})
|
};
|
||||||
.then((res) => {
|
|
||||||
|
// 에디터에 업로드 된 이미지 인덱스 목록
|
||||||
|
if (editorUploadedImgList.value && editorUploadedImgList.value.length > 0) {
|
||||||
|
param.editorUploadedImgList = [...editorUploadedImgList.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 삭제할 에디터 이미지 인덱스
|
||||||
|
if (editorDeleteImgList.value && editorDeleteImgList.value.length > 0) {
|
||||||
|
param.editorDeleteImgList = [...editorDeleteImgList.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
axios
|
||||||
|
.patch('worddict/updateWord', param)
|
||||||
|
.then(res => {
|
||||||
if (res.data.data === 1) {
|
if (res.data.data === 1) {
|
||||||
toastStore.onToast('용어가 수정되었습니다.', 's');
|
toastStore.onToast('용어가 수정되었습니다.', 's');
|
||||||
writeStore.closeAll();
|
writeStore.closeAll();
|
||||||
if (writeButton.value) {
|
if (writeButton.value) {
|
||||||
writeButton.value.resetButton();
|
writeButton.value.resetButton();
|
||||||
}
|
}
|
||||||
emit('refreshWordList',data.category);
|
emit('refreshWordList', data.category);
|
||||||
} else {
|
} else {
|
||||||
console.warn('⚠️ 서버 응답이 예상과 다릅니다:', res.data);
|
console.warn('⚠️ 서버 응답이 예상과 다릅니다:', res.data);
|
||||||
toastStore.onToast('용어 수정이 정상적으로 처리되지 않았습니다.', 'e');
|
toastStore.onToast('용어 수정이 정상적으로 처리되지 않았습니다.', 'e');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(err => {
|
||||||
console.error('❌ 용어 수정 중 오류 발생:', err.response?.data || err.message);
|
console.error('❌ 용어 수정 중 오류 발생:', err.response?.data || err.message);
|
||||||
toastStore.onToast(`용어 수정 실패: ${err.response?.data?.message || '알 수 없는 오류'}`, 'e');
|
toastStore.onToast(`용어 수정 실패: ${err.response?.data?.message || '알 수 없는 오류'}`, 'e');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
// 에디터 이미지 수정, 삭제시 반영
|
||||||
|
const handleDeleteEditorImg = item => {
|
||||||
|
editorDeleteImgList.value = item;
|
||||||
|
};
|
||||||
|
|
||||||
// 프로필 이미지
|
// 에디터 이미지 추가 시 반영
|
||||||
const defaultProfile = "/img/icons/icon.png";
|
const handleUpdateEditorImg = item => {
|
||||||
|
editorUploadedImgList.value = item;
|
||||||
|
};
|
||||||
|
|
||||||
const getProfileImage = (profilePath) => {
|
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||||
|
|
||||||
|
// 프로필 이미지
|
||||||
|
const defaultProfile = '/img/icons/icon.png';
|
||||||
|
|
||||||
|
const getProfileImage = profilePath => {
|
||||||
return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile;
|
return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setDefaultImage = (event) => {
|
const setDefaultImage = event => {
|
||||||
event.target.src = defaultProfile;
|
event.target.src = defaultProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleEdit = async () => {
|
const toggleEdit = async () => {
|
||||||
writeStore.toggleItem(props.item.WRDDICSEQ);
|
writeStore.toggleItem(props.item.WRDDICSEQ);
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.avatar {
|
.avatar {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
border: 3px solid;
|
border: 3px solid;
|
||||||
padding: 0.1px;
|
padding: 0.1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-btn {
|
.edit-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0.7rem;
|
right: 0.7rem;
|
||||||
top: 1.2rem;
|
top: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-chk {
|
.admin-chk {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -0.5rem;
|
left: -0.5rem;
|
||||||
top: -0.5rem;
|
top: -0.5rem;
|
||||||
--bs-form-check-bg: #fff;
|
--bs-form-check-bg: #fff;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="dataList.length > 0" >
|
<div v-if="dataList.length > 0">
|
||||||
<FormSelect
|
<FormSelect
|
||||||
name="cate"
|
name="cate"
|
||||||
title="카테고리"
|
title="카테고리"
|
||||||
@ -13,7 +13,7 @@
|
|||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<div>
|
<div>
|
||||||
<PlusBtn v-if="!showInput && !isDisabled" @click="toggleInput"/>
|
<PlusBtn v-if="!showInput && !isDisabled" @click="toggleInput" />
|
||||||
<EditBtn
|
<EditBtn
|
||||||
v-if="showEditBtn"
|
v-if="showEditBtn"
|
||||||
@click="$emit('toggleEdit')"
|
@click="$emit('toggleEdit')"
|
||||||
@ -29,12 +29,11 @@
|
|||||||
class="justify-content-end"
|
class="justify-content-end"
|
||||||
ref="categoryInputRef"
|
ref="categoryInputRef"
|
||||||
title="새 카테고리"
|
title="새 카테고리"
|
||||||
:isLabel="dataList.length === 0 ?true : false"
|
:isLabel="dataList.length === 0 ? true : false"
|
||||||
name="새 카테고리"
|
name="새 카테고리"
|
||||||
@update:modelValue="addCategory = $event"
|
@update:modelValue="addCategory = $event"
|
||||||
:is-cate-alert="addCategoryAlert"
|
:is-cate-alert="addCategoryAlert"
|
||||||
@focusout="handleCategoryFocusout(addCategory)"
|
@focusout="handleCategoryFocusout(addCategory)"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<FormInput
|
<FormInput
|
||||||
@ -49,7 +48,16 @@
|
|||||||
@keyup="ValidHandler('title')"
|
@keyup="ValidHandler('title')"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<QEditor class="" @keyup="ValidHandler('content')" @update:data="handleContentUpdate" @update:imageUrls="imageUrls = $event" :is-alert="wordContentAlert" :initialData="contentValue"/>
|
<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">
|
<div class="text-end mt-5">
|
||||||
<button class="btn btn-primary" @click="saveWord">
|
<button class="btn btn-primary" @click="saveWord">
|
||||||
<i class="bx bx-check"></i>
|
<i class="bx bx-check"></i>
|
||||||
@ -59,111 +67,106 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, computed, ref, defineEmits } from 'vue';
|
import { defineProps, computed, ref, defineEmits } from 'vue';
|
||||||
|
|
||||||
import QEditor from '@/components/editor/QEditor.vue';
|
import QEditor from '@/components/editor/QEditor.vue';
|
||||||
import FormInput from '@/components/input/FormInput.vue';
|
import FormInput from '@/components/input/FormInput.vue';
|
||||||
import FormSelect from '@/components/input/FormSelect.vue';
|
import FormSelect from '@/components/input/FormSelect.vue';
|
||||||
import PlusBtn from '../button/PlusBtn.vue';
|
import PlusBtn from '../button/PlusBtn.vue';
|
||||||
import EditBtn from '../button/EditBtn.vue';
|
import EditBtn from '../button/EditBtn.vue';
|
||||||
import { useWriteVisibleStore } from '@s/writeVisible';
|
import { useWriteVisibleStore } from '@s/writeVisible';
|
||||||
|
|
||||||
const writeStore = useWriteVisibleStore();
|
const writeStore = useWriteVisibleStore();
|
||||||
|
|
||||||
const emit = defineEmits(['close','addCategory','addWord', 'toggleEdit']);
|
const emit = defineEmits(['close', 'addCategory', 'addWord', 'toggleEdit', 'update:deleteImgIndexList', 'update:uploadedImgList']);
|
||||||
|
|
||||||
//용어제목
|
//용어제목
|
||||||
const wordTitle = ref('');
|
const wordTitle = ref('');
|
||||||
const addCategory = ref('');
|
const addCategory = ref('');
|
||||||
const content = ref('');
|
const content = ref('');
|
||||||
const imageUrls = ref([]);
|
const imageUrls = ref([]);
|
||||||
|
|
||||||
//용어 Vaildation용
|
//용어 Vaildation용
|
||||||
const wordTitleAlert = ref(false);
|
const wordTitleAlert = ref(false);
|
||||||
const wordContentAlert = ref(false);
|
const wordContentAlert = ref(false);
|
||||||
const addCategoryAlert = ref(false);
|
const addCategoryAlert = ref(false);
|
||||||
|
|
||||||
//선택 카테고리
|
//선택 카테고리
|
||||||
const selectCategory = ref('');
|
const selectCategory = ref('');
|
||||||
|
|
||||||
// 제목 상태
|
// 제목 상태
|
||||||
const computedTitle = computed(() =>
|
const computedTitle = computed(() => (wordTitle.value === '' ? props.titleValue : wordTitle.value));
|
||||||
wordTitle.value === '' ? props.titleValue : wordTitle.value
|
|
||||||
);
|
|
||||||
|
|
||||||
// 카테고리 상태
|
// 카테고리 상태
|
||||||
const selectedCategory = computed(() =>
|
const selectedCategory = computed(() => (selectCategory.value === '' ? props.formValue : selectCategory.value));
|
||||||
selectCategory.value === '' ? props.formValue : selectCategory.value
|
|
||||||
|
|
||||||
);
|
// 카테고리 입력 중복 ref
|
||||||
|
const categoryInputRef = ref(null);
|
||||||
|
|
||||||
// 카테고리 입력 중복 ref
|
const props = defineProps({
|
||||||
const categoryInputRef = ref(null);
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
dataList: {
|
dataList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => [],
|
||||||
},
|
},
|
||||||
NumValue : {
|
NumValue: {
|
||||||
type: Number
|
type: Number,
|
||||||
},
|
},
|
||||||
formValue : {
|
formValue: {
|
||||||
type:[String, Number]
|
type: [String, Number],
|
||||||
},
|
},
|
||||||
titleValue : {
|
titleValue: {
|
||||||
type:String,
|
type: String,
|
||||||
},contentValue : {
|
},
|
||||||
type:String,
|
contentValue: {
|
||||||
|
type: String,
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
showEditBtn: {
|
showEditBtn: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 카테고리 입력 창
|
// 카테고리 입력 창
|
||||||
const showInput = ref(false);
|
const showInput = ref(false);
|
||||||
|
|
||||||
// 카테고리 입력 토글
|
// 카테고리 입력 토글
|
||||||
const toggleInput = () => {
|
const toggleInput = () => {
|
||||||
showInput.value = !showInput.value;
|
showInput.value = !showInput.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChange = (newValue) => {
|
const onChange = newValue => {
|
||||||
selectCategory.value = newValue.target.value;
|
selectCategory.value = newValue.target.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ValidHandler = (field) => {
|
const ValidHandler = field => {
|
||||||
if(field == 'title'){
|
if (field == 'title') {
|
||||||
wordTitleAlert.value = false;
|
wordTitleAlert.value = false;
|
||||||
}
|
}
|
||||||
if(field == 'content'){
|
if (field == 'content') {
|
||||||
wordContentAlert.value = false;
|
wordContentAlert.value = false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
const handleContentUpdate = newContent => {
|
||||||
const handleContentUpdate = (newContent) => {
|
|
||||||
content.value = newContent;
|
content.value = newContent;
|
||||||
ValidHandler("content"); // 유효성 검사 실행
|
ValidHandler('content'); // 유효성 검사 실행
|
||||||
};
|
};
|
||||||
|
|
||||||
//용어 등록
|
//용어 등록
|
||||||
const saveWord = () => {
|
const saveWord = () => {
|
||||||
let valid = true;
|
let valid = true;
|
||||||
//validation
|
//validation
|
||||||
let computedTitleTrim;
|
let computedTitleTrim;
|
||||||
|
|
||||||
if(computedTitle.value != undefined){
|
if (computedTitle.value != undefined) {
|
||||||
computedTitleTrim = computedTitle.value.trim()
|
computedTitleTrim = computedTitle.value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 용어 체크
|
// 용어 체크
|
||||||
if(computedTitleTrim == undefined || computedTitleTrim == ''){
|
if (computedTitleTrim == undefined || computedTitleTrim == '') {
|
||||||
wordTitleAlert.value = true;
|
wordTitleAlert.value = true;
|
||||||
valid = false;
|
valid = false;
|
||||||
} else {
|
} else {
|
||||||
@ -173,15 +176,13 @@ const saveWord = () => {
|
|||||||
// 내용 확인
|
// 내용 확인
|
||||||
let inserts = [];
|
let inserts = [];
|
||||||
if (inserts.length === 0 && content.value?.ops?.length > 0) {
|
if (inserts.length === 0 && content.value?.ops?.length > 0) {
|
||||||
inserts = content.value.ops.map(op =>
|
inserts = content.value.ops.map(op => (typeof op.insert === 'string' ? op.insert.trim() : op.insert));
|
||||||
typeof op.insert === 'string' ? op.insert.trim() : op.insert
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// 내용 체크
|
// 내용 체크
|
||||||
if(content.value == '' || inserts.join('') === ''){
|
if (content.value == '' || inserts.join('') === '') {
|
||||||
wordContentAlert.value = true;
|
wordContentAlert.value = true;
|
||||||
valid = false;
|
valid = false;
|
||||||
}else{
|
} else {
|
||||||
wordContentAlert.value = false;
|
wordContentAlert.value = false;
|
||||||
}
|
}
|
||||||
const wordData = {
|
const wordData = {
|
||||||
@ -190,15 +191,21 @@ const saveWord = () => {
|
|||||||
category: selectedCategory.value,
|
category: selectedCategory.value,
|
||||||
content: content.value,
|
content: content.value,
|
||||||
};
|
};
|
||||||
if(valid){
|
if (valid) {
|
||||||
emit('addWord', wordData, addCategory.value.trim() === ''
|
emit(
|
||||||
? (isNaN(selectedCategory.value) ? selectedCategory.value : Number(selectedCategory.value))
|
'addWord',
|
||||||
: addCategory.value);
|
wordData,
|
||||||
|
addCategory.value.trim() === ''
|
||||||
|
? isNaN(selectedCategory.value)
|
||||||
|
? selectedCategory.value
|
||||||
|
: Number(selectedCategory.value)
|
||||||
|
: addCategory.value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 카테고리 focusout 이벤트 핸들러 추가
|
// 카테고리 focusout 이벤트 핸들러 추가
|
||||||
const handleCategoryFocusout = (value) => {
|
const handleCategoryFocusout = value => {
|
||||||
if (!value || value.trim() === '') {
|
if (!value || value.trim() === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -218,6 +225,5 @@ const handleCategoryFocusout = (value) => {
|
|||||||
} else {
|
} else {
|
||||||
addCategoryAlert.value = false;
|
addCategoryAlert.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,20 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container-xxl flex-grow-1 container-p-y d-flex">
|
<div class="container-xxl flex-grow-1 container-p-y d-flex">
|
||||||
<!-- 메인 컨텐츠 -->
|
<!-- 메인 컨텐츠 -->
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<!-- 타이틀, 검색 -->
|
<!-- 타이틀, 검색 -->
|
||||||
<SearchBar @update:data="search"/>
|
<SearchBar @update:data="search" />
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<!-- 단어 갯수, 작성하기 -->
|
<!-- 단어 갯수, 작성하기 -->
|
||||||
<!-- 왼쪽 사이드바 -->
|
<!-- 왼쪽 사이드바 -->
|
||||||
<div class="sidebar position-sticky" style="top: 100px; max-width: 250px; min-width: 250px;">
|
<div class="sidebar position-sticky" style="top: 100px; max-width: 250px; min-width: 250px">
|
||||||
<WriteButton ref="writeButton" @click="writeStore.toggleItem(999999)" :isToggleEnabled="true"
|
<WriteButton
|
||||||
:isActive="writeStore.activeItemId === 999999"/>
|
ref="writeButton"
|
||||||
|
@click="writeStore.toggleItem(999999)"
|
||||||
|
:isToggleEnabled="true"
|
||||||
|
:isActive="writeStore.activeItemId === 999999"
|
||||||
|
/>
|
||||||
<!-- ㄱ ㄴ ㄷ ㄹ -->
|
<!-- ㄱ ㄴ ㄷ ㄹ -->
|
||||||
<DictAlphabetFilter @update:data="handleSelectedAlphabetChange" :indexCategory="indexCategory" :selectedAl="selectedAlphabet" />
|
<DictAlphabetFilter
|
||||||
|
@update:data="handleSelectedAlphabetChange"
|
||||||
|
:indexCategory="indexCategory"
|
||||||
|
:selectedAl="selectedAlphabet"
|
||||||
|
/>
|
||||||
<!-- 카테고리 -->
|
<!-- 카테고리 -->
|
||||||
<div v-if="cateList.length" class="mt-3">
|
<div v-if="cateList.length" class="mt-3">
|
||||||
<CategoryBtn :lists="cateList" @update:data="handleSelectedCategoryChange" :showAll="true" :selectedCategory="selectedCategory" />
|
<CategoryBtn
|
||||||
|
:lists="cateList"
|
||||||
|
@update:data="handleSelectedCategoryChange"
|
||||||
|
:showAll="true"
|
||||||
|
:selectedCategory="selectedCategory"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -22,7 +35,13 @@
|
|||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<!-- 작성 -->
|
<!-- 작성 -->
|
||||||
<div v-if="writeStore.isItemActive(999999)" class="ms-3 card p-5 mb-2">
|
<div v-if="writeStore.isItemActive(999999)" class="ms-3 card p-5 mb-2">
|
||||||
<DictWrite @close="writeStore.closeAll()" :dataList="cateList" @addWord="addWord"/>
|
<DictWrite
|
||||||
|
@close="writeStore.closeAll()"
|
||||||
|
:dataList="cateList"
|
||||||
|
@addWord="addWord"
|
||||||
|
@update:deleteImgIndexList="handleDeleteEditorImg"
|
||||||
|
@update:uploadedImgList="handleUpdateEditorImg"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 용어 리스트 -->
|
<!-- 용어 리스트 -->
|
||||||
<div>
|
<div>
|
||||||
@ -45,11 +64,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button v-if="isAnyChecked" class="btn btn-danger admin-del-btn" @click="deleteCheckedItems">
|
<button v-if="isAnyChecked" class="btn btn-danger admin-del-btn" @click="deleteCheckedItems">
|
||||||
<i class="bx bx-trash"></i>
|
<i class="bx bx-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -64,7 +82,7 @@
|
|||||||
import commonApi from '@/common/commonApi';
|
import commonApi from '@/common/commonApi';
|
||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
import { useWriteVisibleStore } from '@s/writeVisible';
|
import { useWriteVisibleStore } from '@s/writeVisible';
|
||||||
import LoadingSpinner from "@v/LoadingPage.vue";
|
import LoadingSpinner from '@v/LoadingPage.vue';
|
||||||
|
|
||||||
// 작성창 구분
|
// 작성창 구분
|
||||||
const writeStore = useWriteVisibleStore();
|
const writeStore = useWriteVisibleStore();
|
||||||
@ -86,7 +104,7 @@
|
|||||||
|
|
||||||
// 카테고리
|
// 카테고리
|
||||||
const { cateList } = commonApi({
|
const { cateList } = commonApi({
|
||||||
loadCateList: true
|
loadCateList: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedCategory = ref('');
|
const selectedCategory = ref('');
|
||||||
@ -96,7 +114,6 @@
|
|||||||
// 체크박스의 name
|
// 체크박스의 name
|
||||||
const checkedNames = ref([]);
|
const checkedNames = ref([]);
|
||||||
|
|
||||||
|
|
||||||
//선택된 알파벳
|
//선택된 알파벳
|
||||||
const selectedAlphabet = ref('');
|
const selectedAlphabet = ref('');
|
||||||
|
|
||||||
@ -106,26 +123,40 @@
|
|||||||
//검색 정렬
|
//검색 정렬
|
||||||
const indexCategory = ref([]);
|
const indexCategory = ref([]);
|
||||||
|
|
||||||
|
const editorDeleteImgList = ref([]);
|
||||||
|
const editorUploadedImgList = ref([]);
|
||||||
|
|
||||||
// 데이터 로드
|
// 데이터 로드
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getIndex();
|
getIndex();
|
||||||
writeStore.closeAll();
|
writeStore.closeAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshWordList = (category) => {
|
// 에디터 이미지 수정, 삭제시 반영
|
||||||
|
const handleDeleteEditorImg = item => {
|
||||||
|
editorDeleteImgList.value = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 에디터 이미지 추가 시 반영
|
||||||
|
const handleUpdateEditorImg = item => {
|
||||||
|
editorUploadedImgList.value = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshWordList = category => {
|
||||||
selectedCategory.value = category;
|
selectedCategory.value = category;
|
||||||
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
//용어 목록
|
//용어 목록
|
||||||
const getwordList = (searchKeyword='', indexKeyword='', category='') => {
|
const getwordList = (searchKeyword = '', indexKeyword = '', category = '') => {
|
||||||
axios.get('worddict/getWordList',{
|
axios
|
||||||
|
.get('worddict/getWordList', {
|
||||||
//목록조회시 파라미터 전달
|
//목록조회시 파라미터 전달
|
||||||
params: {
|
params: {
|
||||||
searchKeyword : searchKeyword,
|
searchKeyword: searchKeyword,
|
||||||
indexKeyword :indexKeyword,
|
indexKeyword: indexKeyword,
|
||||||
category : category
|
category: category,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
// 용어 목록 저장
|
// 용어 목록 저장
|
||||||
@ -140,21 +171,21 @@
|
|||||||
};
|
};
|
||||||
//정렬 목록
|
//정렬 목록
|
||||||
const getIndex = () => {
|
const getIndex = () => {
|
||||||
axios.get('worddict/getIndexCategory').then(res=>{
|
axios.get('worddict/getIndexCategory').then(res => {
|
||||||
if(res.data.status ="OK"){
|
if ((res.data.status = 'OK')) {
|
||||||
indexCategory.value = res.data.data;
|
indexCategory.value = res.data.data;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// 검색
|
// 검색
|
||||||
const search = (e) => {
|
const search = e => {
|
||||||
searchText.value = e.trim();
|
searchText.value = e.trim();
|
||||||
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 알파벳 선택
|
// 알파벳 선택
|
||||||
const handleSelectedAlphabetChange = (newAlphabet) => {
|
const handleSelectedAlphabetChange = newAlphabet => {
|
||||||
selectedAlphabet.value = newAlphabet;
|
selectedAlphabet.value = newAlphabet;
|
||||||
if (newAlphabet !== null) {
|
if (newAlphabet !== null) {
|
||||||
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
@ -165,28 +196,28 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 카테고리 선택
|
// 카테고리 선택
|
||||||
const handleSelectedCategoryChange = (category) => {
|
const handleSelectedCategoryChange = category => {
|
||||||
selectedCategory.value = category;
|
selectedCategory.value = category;
|
||||||
if (category !== null ) {
|
if (category !== null) {
|
||||||
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
if(category == 'all'){
|
if (category == 'all') {
|
||||||
getwordList(searchText.value, selectedAlphabet.value, '');
|
getwordList(searchText.value, selectedAlphabet.value, '');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wordList.value = [];
|
wordList.value = [];
|
||||||
total.value = 0;
|
total.value = 0;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 용어집 등록
|
// 용어집 등록
|
||||||
const addWord = (wordData, data) => {
|
const addWord = (wordData, data) => {
|
||||||
let category = null;
|
let category = null;
|
||||||
let newCodName = '';
|
let newCodName = '';
|
||||||
// 카테고리 체크
|
// 카테고리 체크
|
||||||
if(typeof(data) == 'number'){
|
if (typeof data == 'number') {
|
||||||
category = data;
|
category = data;
|
||||||
newCodName = '';
|
newCodName = '';
|
||||||
}else{
|
} else {
|
||||||
const lastCategory = cateList.value[cateList.value.length - 1];
|
const lastCategory = cateList.value[cateList.value.length - 1];
|
||||||
category = lastCategory ? lastCategory.value + 1 : 600101;
|
category = lastCategory ? lastCategory.value + 1 : 600101;
|
||||||
newCodName = data.trim();
|
newCodName = data.trim();
|
||||||
@ -194,13 +225,24 @@
|
|||||||
sendWordRequest(category, wordData, newCodName);
|
sendWordRequest(category, wordData, newCodName);
|
||||||
};
|
};
|
||||||
const sendWordRequest = (category, wordData, data) => {
|
const sendWordRequest = (category, wordData, data) => {
|
||||||
console.log(category,'category')
|
console.log(category, 'category');
|
||||||
const payload = {
|
const payload = {
|
||||||
WRDDICCAT: category,
|
WRDDICCAT: category,
|
||||||
WRDDICTTL: wordData.title,
|
WRDDICTTL: wordData.title,
|
||||||
WRDDICCON: $common.deltaAsJson(wordData.content),
|
WRDDICCON: $common.deltaAsJson(wordData.content),
|
||||||
};
|
};
|
||||||
payload.CMNCODNAM = data;
|
payload.CMNCODNAM = data;
|
||||||
|
|
||||||
|
// 에디터에 업로드 된 이미지 인덱스 목록
|
||||||
|
if (editorUploadedImgList.value && editorUploadedImgList.value.length > 0) {
|
||||||
|
payload.editorUploadedImgList = [...editorUploadedImgList.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 삭제할 에디터 이미지 인덱스
|
||||||
|
if (editorDeleteImgList.value && editorDeleteImgList.value.length > 0) {
|
||||||
|
payload.editorDeleteImgList = [...editorDeleteImgList.value];
|
||||||
|
}
|
||||||
|
|
||||||
axios.post('worddict/insertWord', payload).then(res => {
|
axios.post('worddict/insertWord', payload).then(res => {
|
||||||
if (res.data.status === 'OK') {
|
if (res.data.status === 'OK') {
|
||||||
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
||||||
@ -211,16 +253,15 @@
|
|||||||
selectedCategory.value = category;
|
selectedCategory.value = category;
|
||||||
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
getIndex();
|
getIndex();
|
||||||
if(res.data.data == '2'){
|
if (res.data.data == '2') {
|
||||||
const newCategory = { label: data, value: category };
|
const newCategory = { label: data, value: category };
|
||||||
cateList.value = [...cateList.value,newCategory];
|
cateList.value = [...cateList.value, newCategory];
|
||||||
}
|
}
|
||||||
selectedAlphabet.value = '';
|
selectedAlphabet.value = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 체크 상태 업데이트
|
// 체크 상태 업데이트
|
||||||
const updateCheckedItems = (checked, id, name) => {
|
const updateCheckedItems = (checked, id, name) => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
@ -236,9 +277,9 @@
|
|||||||
|
|
||||||
// 용어집 삭제
|
// 용어집 삭제
|
||||||
const deleteCheckedItems = () => {
|
const deleteCheckedItems = () => {
|
||||||
|
axios
|
||||||
axios.patch('worddict/deleteword', {
|
.patch('worddict/deleteword', {
|
||||||
idList: Object.values(checkedNames.value)
|
idList: Object.values(checkedNames.value),
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.data.status == 'OK') {
|
if (res.data.status == 'OK') {
|
||||||
@ -254,29 +295,27 @@
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
toastStore.onToast('오류가 발생했습니다. 다시 시도해주세요.', 'e');
|
toastStore.onToast('오류가 발생했습니다. 다시 시도해주세요.', 'e');
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.admin-del-btn {
|
.admin-del-btn {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 1.5rem;
|
right: 1.5rem;
|
||||||
bottom: 1.5rem;
|
bottom: 1.5rem;
|
||||||
width: 3rem;
|
width: 3rem;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.DictCard {
|
.DictCard {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user