335 lines
12 KiB
Vue
335 lines
12 KiB
Vue
<template>
|
|
<div class="container-xxl flex-grow-1 container-p-y d-flex">
|
|
<!-- 메인 컨텐츠 -->
|
|
<div class="flex-grow-1">
|
|
<!-- 타이틀, 검색 -->
|
|
<SearchBar @update:data="search"/>
|
|
<div class="d-flex">
|
|
<!-- 단어 갯수, 작성하기 -->
|
|
<!-- 왼쪽 사이드바 -->
|
|
<div class="sidebar position-sticky" style="top: 100px; max-width: 250px; min-width: 250px;">
|
|
<WriteButton ref="writeButton" @click="writeStore.toggleItem(999999)" :isToggleEnabled="true"
|
|
:isActive="writeStore.activeItemId === 999999"/>
|
|
<!-- ㄱ ㄴ ㄷ ㄹ -->
|
|
<DictAlphabetFilter @update:data="handleSelectedAlphabetChange" :indexCategory="indexCategory" :selectedAl="selectedAlphabet" />
|
|
<!-- 카테고리 -->
|
|
<div v-if="cateList.length" class="mt-3">
|
|
<CategoryBtn :lists="cateList" @update:data="handleSelectedCategoryChange" :showAll="true" :selectedCategory="selectedCategory" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 용어 리스트 컨텐츠 -->
|
|
<div class="flex-grow-1">
|
|
<!-- 작성 -->
|
|
<div v-if="writeStore.isItemActive(999999)" class="ms-3 card p-5 mb-2">
|
|
<DictWrite @close="writeStore.closeAll()" :dataList="cateList" @addWord="addWord"/>
|
|
</div>
|
|
<!-- 용어 리스트 -->
|
|
<div>
|
|
<!-- 에러 메시지 -->
|
|
<div v-if="error" class="fw-bold text-danger">{{ error }}</div>
|
|
<!-- 단어 목록 -->
|
|
<ul v-if="total > 0" class="ms-3 list-unstyled" style="overflow-x: hidden; word-wrap: break-word;">
|
|
<DictCard
|
|
v-for="item in wordList"
|
|
:key="item.WRDDICSEQ"
|
|
:item="item"
|
|
v-model:cateList="cateList"
|
|
@refreshWordList="refreshWordList"
|
|
@updateChecked="updateCheckedItems"
|
|
/>
|
|
</ul>
|
|
<!-- 데이터가 없을 때 -->
|
|
|
|
<div v-if="total == 0" class="text-center mt-5">{{ searchText ? '검색된 목록이 없습니다.':'용어를 선택 / 작성해 주세요' }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button v-if="isAnyChecked" class="btn btn-danger admin-del-btn" @click="deleteCheckedItems">
|
|
<i class="bx bx-trash"></i>
|
|
</button>
|
|
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted, getCurrentInstance, toRaw } from 'vue';
|
|
import axios from '@api';
|
|
import SearchBar from '@c/search/SearchBar.vue';
|
|
import WriteButton from '@c/button/WriteBtn.vue';
|
|
import CategoryBtn from '@/components/category/CategoryBtn.vue';
|
|
import DictCard from '@/components/wordDict/DictCard.vue';
|
|
import DictWrite from '@/components/wordDict/DictWrite.vue';
|
|
import DictAlphabetFilter from '@/components/wordDict/DictAlphabetFilter.vue';
|
|
import commonApi from '@/common/commonApi';
|
|
import { useToastStore } from '@s/toastStore';
|
|
import { useWriteVisibleStore } from '@s/writeVisible';
|
|
import LoadingSpinner from "@v/LoadingPage.vue";
|
|
import { useRoute } from 'vue-router';
|
|
|
|
const route = useRoute();
|
|
|
|
// 작성창 구분
|
|
const writeStore = useWriteVisibleStore();
|
|
const writeButton = ref(null);
|
|
|
|
const { appContext } = getCurrentInstance();
|
|
const $common = appContext.config.globalProperties.$common;
|
|
|
|
const toastStore = useToastStore();
|
|
|
|
// 공통
|
|
const error = ref('');
|
|
|
|
// 용어집
|
|
const wordList = ref([]);
|
|
|
|
//용어집 총개수
|
|
const total = ref(0);
|
|
|
|
// 카테고리
|
|
const { cateList } = commonApi({
|
|
loadCateList: true
|
|
});
|
|
|
|
const selectedCategory = ref('');
|
|
|
|
// 체크박스 체크된 갯수
|
|
const checkedItems = ref([]);
|
|
// 체크박스의 name
|
|
const checkedNames = ref([]);
|
|
|
|
|
|
//선택된 알파벳
|
|
const selectedAlphabet = ref('');
|
|
|
|
// 검색
|
|
const searchText = ref('');
|
|
|
|
//검색 정렬
|
|
const indexCategory = ref([]);
|
|
|
|
// 데이터 로드
|
|
onMounted(() => {
|
|
getIndex();
|
|
writeStore.closeAll();
|
|
const mainindexKeyword = route.query.indexKeyword || '';
|
|
const maincategory = route.query.category || '';
|
|
selectedAlphabet.value = mainindexKeyword;
|
|
selectedCategory.value = maincategory;
|
|
if(mainindexKeyword){
|
|
getwordList('', selectedAlphabet.value, selectedCategory.value );
|
|
}
|
|
});
|
|
|
|
const refreshWordList = (category) => {
|
|
selectedCategory.value = category;
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
};
|
|
|
|
//용어 목록
|
|
const getwordList = (searchKeyword='', indexKeyword='', category='') => {
|
|
axios.get('worddict/getWordList',{
|
|
//목록조회시 파라미터 전달
|
|
params: {
|
|
searchKeyword : searchKeyword,
|
|
indexKeyword :indexKeyword,
|
|
category : category
|
|
}
|
|
})
|
|
.then(res => {
|
|
// 용어 목록 저장
|
|
wordList.value = res.data.data.data;
|
|
// 총 개수 저장
|
|
total.value = res.data.data.data.length;
|
|
})
|
|
.catch(err => {
|
|
console.error('데이터 로드 오류:', err);
|
|
error.value = '데이터를 가져오는 중 문제가 발생했습니다.';
|
|
});
|
|
};
|
|
//정렬 목록
|
|
const getIndex = () => {
|
|
axios.get('worddict/getIndexCategory').then(res=>{
|
|
if(res.data.status ="OK"){
|
|
indexCategory.value = res.data.data;
|
|
}
|
|
})
|
|
}
|
|
|
|
// 검색
|
|
const search = (e) => {
|
|
searchText.value = e.trim();
|
|
if(searchText.value){
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
}else{
|
|
if( selectedCategory.value !== '' && selectedCategory.value !== null){
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
}
|
|
else if( selectedAlphabet.value !== '' && selectedAlphabet.value !== null){
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
}else{
|
|
wordList.value = [];
|
|
total.value = 0;
|
|
}
|
|
};
|
|
}
|
|
|
|
// 알파벳 선택
|
|
const handleSelectedAlphabetChange = (newAlphabet) => {
|
|
selectedAlphabet.value = newAlphabet;
|
|
if (newAlphabet !== null) {
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
} else {
|
|
if( selectedCategory.value !== '' && selectedCategory.value !== null){
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
}
|
|
wordList.value = [];
|
|
total.value = 0;
|
|
}
|
|
};
|
|
|
|
// 카테고리 선택
|
|
const handleSelectedCategoryChange = (category) => {
|
|
selectedCategory.value = category;
|
|
if (category !== null ) {
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
if(category == 'all'){
|
|
getwordList(searchText.value, selectedAlphabet.value, '');
|
|
}
|
|
} else {
|
|
if( selectedAlphabet.value !== '' && selectedAlphabet.value !== null){
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
}
|
|
wordList.value = [];
|
|
total.value = 0;
|
|
}
|
|
}
|
|
|
|
// 용어집 등록
|
|
const addWord = (wordData, data) => {
|
|
let category = null;
|
|
let newCodName = '';
|
|
// 카테고리 체크
|
|
if(typeof(data) == 'number'){
|
|
category = data;
|
|
newCodName = '';
|
|
}else{
|
|
const lastCategory = cateList.value[cateList.value.length - 1];
|
|
category = lastCategory ? lastCategory.value + 1 : 600101;
|
|
newCodName = data.trim();
|
|
}
|
|
sendWordRequest(category, wordData, newCodName);
|
|
};
|
|
const sendWordRequest = (category, wordData, data) => {
|
|
|
|
const payload = {
|
|
WRDDICCAT: category,
|
|
WRDDICTTL: wordData.title,
|
|
WRDDICCON: $common.deltaAsJson(wordData.content),
|
|
};
|
|
payload.CMNCODNAM = data;
|
|
axios.post('worddict/insertWord', payload).then(res => {
|
|
if (res.data.status === 'OK') {
|
|
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
|
writeStore.closeAll();
|
|
if (writeButton.value) {
|
|
writeButton.value.resetButton();
|
|
}
|
|
selectedCategory.value = category;
|
|
const firstChar = getFirstCharacter(wordData.title[0]); // 첫 글자 변환
|
|
selectedAlphabet.value = firstChar;
|
|
|
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
|
getIndex();
|
|
if(res.data.data == '2'){
|
|
const newCategory = { label: data, value: category };
|
|
cateList.value = [...cateList.value,newCategory];
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
// 체크 상태 업데이트
|
|
const updateCheckedItems = (checked, id, name) => {
|
|
if (checked) {
|
|
checkedItems.value.push(id);
|
|
checkedNames.value.push(Number(name));
|
|
} else {
|
|
checkedItems.value = checkedItems.value.filter(item => item !== id);
|
|
checkedNames.value = checkedNames.value.filter(item => item !== name);
|
|
}
|
|
};
|
|
|
|
const isAnyChecked = computed(() => checkedItems.value.length > 0);
|
|
|
|
// 용어집 삭제
|
|
const deleteCheckedItems = () => {
|
|
|
|
axios.patch('worddict/deleteword', {
|
|
idList: Object.values(checkedNames.value)
|
|
})
|
|
.then(res => {
|
|
if (res.data.status == 'OK') {
|
|
toastStore.onToast('용어 삭제가 완료되었습니다.', 's');
|
|
writeStore.closeAll();
|
|
getwordList();
|
|
|
|
// 삭제 후 초기화
|
|
checkedItems.value = [];
|
|
checkedNames.value = [];
|
|
}
|
|
})
|
|
.catch(error => {
|
|
toastStore.onToast('오류가 발생했습니다. 다시 시도해주세요.', 'e');
|
|
});
|
|
|
|
};
|
|
|
|
//초성 /알파벳 변환
|
|
const getFirstCharacter = (char) => {
|
|
const CHOSUNG_LIST = [
|
|
'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ',
|
|
'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
|
|
];
|
|
|
|
if (!char || char.length === 0) return '';
|
|
|
|
const code = char.charCodeAt(0);
|
|
|
|
// 한글 범위 (가~힣) → 초성 변환
|
|
if (code >= 0xAC00 && code <= 0xD7A3) {
|
|
const index = Math.floor((code - 0xAC00) / (21 * 28));
|
|
return CHOSUNG_LIST[index];
|
|
}
|
|
|
|
// 영어 소문자 → 대문자로 변환
|
|
if (char.match(/[a-zA-Z]/)) {
|
|
return char.toLowerCase();
|
|
}
|
|
|
|
// 기타 문자 (숫자, 특수문자) 그대로 반환
|
|
return char;
|
|
};
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
.admin-del-btn {
|
|
position: fixed;
|
|
right: 1.5rem;
|
|
bottom: 1.5rem;
|
|
width: 3rem;
|
|
height: 3rem;
|
|
}
|
|
|
|
.sidebar {
|
|
position: sticky;
|
|
top: 5px;
|
|
height: fit-content;
|
|
}
|
|
|
|
</style>
|