
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
2024-11-19
2024-11-19
<template>
<div class="title-box flex justify-between mb40">
<label for="" class="title2 ">로드맵 등록</label>
<select name="" id="" v-model="selectedBook" @change="fetchUnits">
<option value="" disabled selected>교재를 선택하세요</option>
<option v-for="book in books" :key="book.book_id" :value="book.book_id">
{{ book.book_nm }}
</option>
</select>
</div>
<div class="board-wrap" style="height: calc(100% - 13rem);">
<div class="content-t">
<label for="" class="title2">단원</label>
<div class="unit-pagination flex mt10 mb20" style="gap: 10px;">
<button v-for="(unit, index) in units" :key="index"
:class="{ 'selected-btn': selectedUnit === unit.unitId }" @click="selectUnit(unit.unitId)">
{{ unit.unitName }}
</button>
</div>
<hr>
<div class="search-wrap flex mb20 mt30">
<!--
<select v-model="selectedSearchOption" class="mr10 data-wrap">
<option value="bbsTtl">제목</option>
<option value="bbsCnt">내용</option>
<option value="userNm">작성자</option>
<option value="bbsCls">카테고리</option>
</select>
<input v-model="searchKeyword" type="text" placeholder="검색하세요." @keyup.enter="boardDataSearch" />
<button type="button" @click="boardDataSearch()" title="게시글 검색">
<img src="../../../resources/img/look_t.png" alt="" />
</button>
-->
</div>
<div class="flex justify-between align-center mypage mt10">
<div class="textbook big book-gray">
<div class="text ">
<p class="title1">학습 로드맵</p>
</div>
<div class="box flex-column" style="gap: 10px;">
<!-- 지문 -->
<div class="textbook book-red">
<div class="text ">
<p class="title1" style="color: #fff;">지문 1</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('0')">
지문 추가
</button>
<table>
<thead>
<tr>
<td>지문</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(text, index) in RoadMap[0]" :key="text.textId">
<td>
<P class="title2 mt10">{{ text.textTtl }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('0', text.textId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 단어 -->
<div class="textbook ">
<div class="text ">
<p class="title1" style="color: #fff;">단어장 1</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('1')">
단어장 추가
</button>
<table>
<thead>
<tr>
<td>단어장</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(wordBook, index) in RoadMap[1]" :key="wordBook.wdBookId">
<td>
<P class="title2 mt10">{{ wordBook.textTtl }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('1', wordBook.wdBookId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 문제 -->
<div class="textbook book-blue">
<div class="text ">
<p class="title1" style="color: #fff;">문제 1</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('2')">
문제 추가
</button>
<table>
<thead>
<tr>
<td>문제</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(prblm, index) in RoadMap[2]" :key="prblm.prblmId">
<td>
<P class="title2 mt10">{{ prblm.prblmExpln }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('2', prblm.prblmId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook book-blue">
<div class="text ">
<p class="title1" style="color: #fff;">문제 2</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('3')">
문제 추가
</button>
<table>
<thead>
<tr>
<td>문제</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(prblm, index) in RoadMap[3]" :key="prblm.prblmId">
<td>
<P class="title2 mt10">{{ prblm.prblmExpln }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('3', prblm.prblmId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook book-red">
<div class="text ">
<p class="title1" style="color: #fff;">지문 2</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('4')">
지문 추가
</button>
<table>
<thead>
<tr>
<td>지문</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(text, index) in RoadMap[4]" :key="text.textId">
<td>
<P class="title2 mt10">{{ text.textTtl }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('4', text.textId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook ">
<div class="text ">
<p class="title1" style="color: #fff;">단어장 2</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('5')">
단어장 추가
</button>
<table>
<thead>
<tr>
<td>단어장</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(wordBook, index) in RoadMap[5]" :key="wordBook.wdBookId">
<td>
<P class="title2 mt10">{{ wordBook.textTtl }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('5', wordBook.wdBookId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook book-blue">
<div class="text ">
<p class="title1" style="color: #fff;">문제 3</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('6')">
문제 추가
</button>
<table>
<thead>
<tr>
<td>문제</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(prblm, index) in RoadMap[6]" :key="prblm.prblmId">
<td>
<P class="title2 mt10">{{ prblm.prblmExpln }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('6', prblm.prblmId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 평가 -->
<div class="textbook book-navy">
<div class="text ">
<p class="title1" style="color: #fff;">중간 평가</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('7')">
중간평가 추가
</button>
<table>
<thead>
<tr>
<td>중간 평가 문항 갯수</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(evaluation, index) in RoadMap[7]" :key="evaluation.evalId">
<td>
<P class="title2 mt10">{{ evaluation.problemCount }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('7', evaluation.evalId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook book-red">
<div class="text ">
<p class="title1" style="color: #fff;">지문 3</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('8')">
지문 추가
</button>
<table>
<thead>
<tr>
<td>지문</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(text, index) in RoadMap[8]" :key="text.textId">
<td>
<P class="title2 mt10">{{ text.textTtl }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('8', text.textId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook ">
<div class="text ">
<p class="title1" style="color: #fff;">단어장 3</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('9')">
단어장 추가
</button>
<table>
<thead>
<tr>
<td>단어장</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(wordBook, index) in RoadMap[9]" :key="wordBook.wdBookId">
<td>
<P class="title2 mt10">{{ wordBook.textTtl }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('9', wordBook.wdBookId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="textbook book-navy">
<div class="text ">
<p class="title1" style="color: #fff;">최종 평가</p>
</div>
<div class="box">
<button type="button" title="글쓰기" class="new-btn ml10" @click="buttonSearch('10')">
최종평가 추가
</button>
<table>
<thead>
<tr>
<td>최종 평가 문항 갯수</td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(evaluation, index) in RoadMap[10]" :key="evaluation.evalId">
<td>
<P class="title2 mt10">{{ evaluation.problemCount }}</P>
</td>
<td><button type="button" title="글쓰기" class="new-btn"
@click="deleteRoadMap('10', evaluation.evalId)">
삭제
</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!--
<div class="textbook big book-gray">
<div class="text ">
<p class="title1">로드맵</p>
</div>
<div class="box flex-column" style="gap: 10px;">
<div class="dropbox"><P class="title2">여기로 드래그 하세요</P></div>
<div class="text-ct"><svg-icon type="mdi" :path="mdilArrowDown" style="width: 40px; height: 40px; color: #8C8E92;"></svg-icon></div>
<div class="dropbox"><P class="title2">여기로 드래그 하세요</P></div>
<div class="text-ct"><svg-icon type="mdi" :path="mdilArrowDown" style="width: 40px; height: 40px; color: #8C8E92;"></svg-icon></div>
<div class="dropbox"><P class="title2">여기로 드래그 하세요</P></div>
</div>
</div>
-->
</div>
</div>
<div class="flex justify-end mt30" style="gap: 10px;">
<!-- <button type="button" title="" class="new-btn" @click="showConfirm('delete')">
추가
</button> -->
<button type="button" title="" class="new-btn" @click="goToPage('TextBookDetail')">
취소
</button>
<button type="button" title="" class="new-btn" @click="postRoadMaps">
등록
</button>
</div>
</div>
<!--지문 등록 팝업-->
<div v-show="searchTextOpen" class="popup-wrap">
<div class="popup-box ">
<div class="flex justify-between mb30">
<p class="popup-title">지문 검색</p>
<button type="button" class="popup-close-btn" @click="closeBtn">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
</div>
<div class="search-wrap mb30">
<input type="text" class="data-wrap" placeholder="" v-model="searchKeyword">
<button type="button" @click="fetchText">
<img src="../../../resources/img/look_t.png" alt="">
</button>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<td></td>
<td>No.</td>
<td>제목</td>
<td>내용</td>
<td>등록일</td>
</tr>
</thead>
<tbody>
<tr v-for="(post, index) in posts" :key="index" class="post">
<td><input type="checkbox" :checked="post.check" @change="selectText(post)"></td>
<td>{{ index + 1 }}</td>
<td>{{ post.textTtl.slice(0, 20) }}{{ post.textTtl.length > 20 ? '...' : '' }}</td>
<td>{{ post.textCnt.slice(0, 20) }}{{ post.textCnt.length > 20 ? '...' : '' }}</td>
<td>{{ post.regDt }}</td>
</tr>
</tbody>
</table>
<article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;">
<button @click="changePage(currentPage - 1)" :disabled="currentPage === 1">
<img src="../../../resources/img/btn27_90t_normal.png" alt="Previous">
</button>
<button v-for="page in paginationButtons" :key="page" @click="changePage(page)"
:class="{ 'selected-btn': currentPage === page }">
{{ page }}
</button>
<button @click="changePage(currentPage + 1)" :disabled="currentPage === totalPages">
<img src="../../../resources/img/btn28_90t_normal.png" alt="Next">
</button>
</article>
</div>
<div class="flex justify-end ">
<button type="button" title="" class="new-btn mr10" @click="closeBtn">
취소
</button>
<button type="button" title="" class="new-btn" @click="insertRoadMap2">
등록
</button>
</div>
</div>
</div>
<!--문제 등록 팝업-->
<div v-show="searchPrblmOpen" class="popup-wrap">
<div class="popup-box ">
<div class="flex justify-between mb30">
<p class="popup-title">문제 검색</p>
<button type="button" class="popup-close-btn" @click="closeBtn">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
</div>
<div class="search-wrap mb30">
<input type="text" class="data-wrap" placeholder="" v-model="searchKeyword">
<button type="button" @click="fetchProblems">
<img src="../../../resources/img/look_t.png" alt="">
</button>
</div>
<div class="table-wrap">
<table>
<colgroup>
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 30%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 20%;">
</colgroup>
<thead>
<tr>
<td></td>
<td>No.</td>
<td>문제</td>
<td>유형</td>
<td>점수</td>
<td>작성자</td>
<td>등록일</td>
</tr>
</thead>
<tbody>
<tr v-for="(problem, index) in problems" :key="problem.prblmId">
<td><input type="checkbox" v-model="problem.check"></td>
<td>{{ index + 1 }}</td>
<td>{{ problem.prblmExpln }}</td>
<td>{{ problem.prblmTypeNm }}</td>
<td>{{ problem.prblmScr }}</td>
<td>{{ problem.userId }}</td>
<td>{{ problem.regDt }}</td>
</tr>
</tbody>
</table>
<article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;">
<button @click="changePage(currentPage - 1)" :disabled="currentPage === 1">
<img src="../../../resources/img/btn27_90t_normal.png" alt="Previous">
</button>
<button v-for="page in paginationButtons" :key="page" @click="changePage(page)"
:class="{ 'selected-btn': currentPage === page }">
{{ page }}
</button>
<button @click="changePage(currentPage + 1)" :disabled="currentPage === totalPages">
<img src="../../../resources/img/btn28_90t_normal.png" alt="Next">
</button>
</article>
</div>
<div class="flex justify-end ">
<button type="button" title="" class="new-btn mr10" @click="closeBtn">
취소
</button>
<button type="button" title="" class="new-btn" @click="insertRoadMap">
등록
</button>
</div>
</div>
</div>
<!--단어장 등록 팝업-->
<div v-show="searchWordOpen" class="popup-wrap">
<div class="popup-box ">
<div class="flex justify-between mb30">
<p class="popup-title">단어장 검색</p>
</div>
<button type="button" class="popup-close-btn" @click="closeBtn">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
<select v-model="searchType" class="mr10 data-wrap">
<option value="text">지문</option>
<option value="word">단어</option>
</select>
<div class="search-wrap mb30">
<input type="text" class="data-wrap" placeholder="" v-model="searchKeyword">
<button type="button" @click="searchWordBooks">
<img src="../../../resources/img/look_t.png" alt="">
</button>
</div>
<div class="table-wrap">
<table>
<thead>
<td></td>
<td>No.</td>
<td>지문</td>
<td>단어 목록</td>
<td>작성자</td>
</thead>
<tbody>
<tr v-for="(wordBook, index) in wordBooks" :key="wordBook.wdBookId">
<td><input type="checkbox" v-model="wordBook.check"></td>
<td>{{ index + 1 }}</td>
<td>{{ wordBook.textTtl }}</td>
<td>{{ wordBook.wordsPreview }}</td>
<td>{{ wordBook.userNm }}</td>
</tr>
</tbody>
</table>
<article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;">
<button @click="changePage(currentPage - 1)" :disabled="currentPage === 1">
<img src="../../../resources/img/btn27_90t_normal.png" alt="Previous">
</button>
<button v-for="page in paginationButtons" :key="page" @click="changePage(page)"
:class="{ 'selected-btn': currentPage === page }">
{{ page }}
</button>
<button @click="changePage(currentPage + 1)" :disabled="currentPage === totalPages">
<img src="../../../resources/img/btn28_90t_normal.png" alt="Next">
</button>
</article>
</div>
<div class="flex justify-end ">
<button type="button" title="" class="new-btn mr10" @click="closeBtn">
취소
</button>
<button type="button" title="" class="new-btn" @click="insertRoadMap3">
등록
</button>
</div>
</div>
</div>
<!--평가 등록 팝업-->
<div v-show="searchEvalOpen" class="popup-wrap">
<div class="popup-box ">
<div class="flex justify-between mb30">
<p class="popup-title">문제 검색</p>
<button type="button" class="popup-close-btn" @click="closeBtn">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<td></td>
<td>No.</td>
<td>중간/최종</td>
<td>문항 갯수</td>
</tr>
</thead>
<tbody>
<tr v-for="(evaluation, index) in evals" :key="evaluation.evalId">
<td><input type="checkbox" :checked="evaluation.check"
@change="selectEvaluation(evaluation)">
</td>
<td>{{ index + 1 }}</td>
<td>{{ evaluation.evalType }}</td>
<td>{{ evaluation.problemCount }}</td>
</tr>
</tbody>
</table>
<article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;">
<button @click="changePage(currentPage - 1)" :disabled="currentPage === 1">
<img src="../../../resources/img/btn27_90t_normal.png" alt="Previous">
</button>
<button v-for="page in paginationButtons" :key="page" @click="changePage(page)"
:class="{ 'selected-btn': currentPage === page }">
{{ page }}
</button>
<button @click="changePage(currentPage + 1)" :disabled="currentPage === totalPages">
<img src="../../../resources/img/btn28_90t_normal.png" alt="Next">
</button>
</article>
</div>
<div class="flex justify-end ">
<button type="button" title="" class="new-btn mr10" @click="closeBtn">
취소
</button>
<button type="button" title="" class="new-btn" @click="insertRoadMap4">
등록
</button>
</div>
</div>
</div>
</template>
<script>
import SvgIcon from '@jamescoyle/vue-icon';
import { mdiAccountTieHat, mdiMagnify, mdilArrowRight } from '@mdi/js';
import { mdilArrowDown } from '@mdi/light-js';
import ProgressBar from '../../component/ProgressBar.vue';
import axios from 'axios';
export default {
data() {
return {
mdilArrowDown: mdilArrowDown,
mdiMagnify: mdiMagnify,
mdilArrowRight: mdilArrowRight,
timer: "00:00",
progress: 20,
books: [],
units: [],
posts: [],
RoadMap: [],
OrginRoadMap: [],
problems: [],
wordBooks: [],
evals: [],
selectedBook: "",
selectedUnit: null,
wordContentId1: "",
wordContentId2: "",
wordContentId3: "",
learningId1: "",
learningId2: "",
learningId3: "",
currentPage: 1,
pageSize: 5,
totalPosts: 0,
searchOption: '',
searchKeyword: '',
searchType: 'text',
searchPrblmOpen: false,
searchTextOpen: false,
searchWordOpen: false,
searchEvalOpen: false,
selectedPop: 0,
isFirst: false,
insertRoadId: ''
}
},
methods: {
goToPage(page) {
this.$router.push({ name: page, query: { unit_id: this.selectedUnit, book_id: this.selectedBook } });
},
increaseProgress() {
if (this.progress < 100) {
this.progress += 10;
}
},
showConfirm(type) {
let message = '';
if (type === 'delete') {
message = '삭제하시겠습니까?';
} else if (type === 'reset') {
message = '초기화하시겠습니까?';
} else if (type === 'save') {
message = '등록하시겠습니까?';
}
if (confirm(message)) {
this.goBack();
}
},
// 모달 열기
buttonSearch(page) {
this.selectedPop = page;
if (this.selectedPop === '2' || this.selectedPop === '3' || this.selectedPop === '6') {
this.searchPrblmOpen = true;
this.fetchProblems();
} else if (this.selectedPop === '0' || this.selectedPop === '4' || this.selectedPop === '8') {
this.searchTextOpen = true;
this.fetchText();
} else if (this.selectedPop === '1' || this.selectedPop === '5' || this.selectedPop === '9') {
this.searchWordOpen = true;
this.fetchWords();
} else if (this.selectedPop === '7') {
this.searchEvalOpen = true;
this.fetchEval('중간평가');
} else if (this.selectedPop === '10') {
this.searchEvalOpen = true;
this.fetchEval('최종평가');
}
},
// 모달 닫기
closeBtn() {
this.problems = [];
this.posts = [];
this.wordBooks = [];
this.evals = [];
this.selectedPop = '';
this.currentPage = 1;
this.pageSize = 5;
this.totalPosts = 0;
this.searchPrblmOpen = false;
this.searchTextOpen = false;
this.searchWordOpen = false;
this.searchEvalOpen = false;
},
// 로드맵 지정된 것 삭제
deleteRoadMap(page, id) {
if (page === '2' || page === '3' || page === '6') {
this.RoadMap[page] = this.RoadMap[page].filter(prblm => prblm.prblmId !== id);
} else if (page === '0' || page === '4' || page === '8') {
this.RoadMap[page] = this.RoadMap[page].filter(text => text.textId !== id);
} else if (page === '1' || page === '5' || page === '9') {
this.RoadMap[page] = this.RoadMap[page].filter(wordBook => wordBook.wdBookId !== id);
} else if (page === '7' || page === '10') {
this.RoadMap[page] = this.RoadMap[page].filter(evaluation => evaluation.evalId !== id);
}
},
fetchBooks() {
axios({
url: "/book/findAll.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
})
.then(response => {
console.log(response.data)
this.books = response.data;
})
.catch(error => {
console.error("fetchBooks - error: ", error);
alert("교재 목록을 불러오는 중 오류가 발생했습니다.");
});
},
fetchUnits() {
if (!this.selectedBook) return;
axios({
url: "/unit/unitList.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
"bookId": this.selectedBook
},
})
.then(response => {
console.log(response.data)
this.units = response.data;
})
.catch(error => {
console.error("fetchUnits - error: ", error);
alert("단원 목록을 불러오는 중 오류가 발생했습니다.");
});
},
// 단원을 선택했을 때 호출되는 메서드
selectUnit(unitId) {
this.selectedUnit = unitId;
this.fetchRoadmapData();
},
// 문제 가져오기
async fetchProblems(page = 1) {
try {
const response = await axios.post('/problem/problemList.json', {
option: this.searchOption,
keyword: this.searchKeyword,
unitId: this.selectedUnit,
pageSize: this.pageSize,
startIndex: (page - 1) * 5
});
this.problems = response.data.problems;
this.totalPosts = response.data.totalProblem;
this.currentPage = page;
} catch (error) {
console.error('문제 목록을 불러오는 중 오류가 발생했습니다.', error);
}
},
changePage(page) {
if (page < 1 || page > this.totalPages) return;
this.currentPage = page;
this.fetchProblems(page);
},
// 지문 가져오기
fetchText() {
const idx = (this.currentPage - 1) * this.pageSize;
axios({
url: "/text/textSearch.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
"option": this.option,
"keyword": this.keyword,
"pageSize": this.pageSize,
"startIndex": idx,
"unitId": this.selectedUnit
},
})
.then(response => {
this.posts = response.data.list;
if (!this.searching || this.keyword === "") {
this.totalPosts = response.data.totalText;
} else if (this.searching) {
this.totalPosts = response.data.resultCount;
}
})
.catch(error => {
console.error("fetchData - error: ", error);
alert("검색 중 오류가 발생했습니다.");
});
},
// 단어장 목록 가져오기
fetchWords() {
const vm = this;
axios({
url: "/wordbook/findByUnitId.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
unitId: vm.selectedUnit,
page: vm.currentPage,
pageSize: vm.pageSize
},
})
.then(function (response) {
console.log("dataList - response: ", response.data);
const wordBooks = response.data.wordBooks;
vm.totalPosts = response.data.totalWordBooks;
// 지문 제목 및 단어 목록 가져오기
const fetchDataPromises = wordBooks.map(wordBook => {
const textTitlePromise = axios.post("/text/selectOneText.json", {
textId: wordBook.textId
}).then(textResponse => {
wordBook.textTtl = textResponse.data[0].text_ttl;
}).catch(error => {
console.error(`${wordBook.textId}으로 지문 제목 가져오기 실패: `, error);
wordBook.textTtl = '제목값없음'; // 오류 시 기본값 설정
});
const wordsPromise = axios.post("/word/getWordsByBookId.json", {
wdBookId: wordBook.wdBookId
}).then(wordsResponse => {
const words = wordsResponse.data.map(word => word.wdNm);
wordBook.wordsPreview = vm.generateWordsPreview(words);
}).catch(error => {
console.error(`${wordBook.wdBookId}으로 단어 목록 가져오기 실패: `, error);
wordBook.wordsPreview = '단어값없음'; // 오류 시 기본값 설정
});
return Promise.all([textTitlePromise, wordsPromise]);
});
// 모든 데이터 가져오기 작업이 완료되면 dataList에 데이터 설정
Promise.all(fetchDataPromises).then(() => {
vm.wordBooks = wordBooks;
});
})
.catch(function (error) {
console.log("dataList - error: ", error);
alert("단어장 목록 조회에 오류가 발생했습니다.");
});
},
// 단어장 검색
searchWordBooks() {
const vm = this;
let url = '';
let data = {};
if (this.searchType === 'text') {
// 지문으로 검색
url = '/wordbook/findByTextTitle.json';
data = {
unitId: vm.selectedUnit,
textTitle: vm.searchKeyword,
page: vm.currentPage,
pageSize: vm.pageSize
};
} else if (this.searchType === 'word') {
// 단어로 검색
url = '/wordbook/findByWord.json';
data = {
unitId: vm.selectedUnit,
word: vm.searchKeyword,
page: vm.currentPage,
pageSize: vm.pageSize
};
}
axios.post(url, data)
.then(function (response) {
console.log("searchWordBooks - response: ", response.data);
const wordBooks = response.data.wordBooks;
vm.totalPosts = response.data.totalWordBooks;
// 지문 제목 및 단어 목록 가져오기
const fetchDataPromises = wordBooks.map(wordBook => {
const textTitlePromise = axios.post("/text/selectOneText.json", {
textId: wordBook.textId
}).then(textResponse => {
wordBook.textTtl = textResponse.data[0].text_ttl;
}).catch(error => {
wordBook.textTtl = '제목값없음'; // 오류 시 기본값 설정
});
const wordsPromise = axios.post("/word/getWordsByBookId.json", {
wdBookId: wordBook.wdBookId
}).then(wordsResponse => {
const words = wordsResponse.data.map(word => word.wdNm);
wordBook.wordsPreview = vm.generateWordsPreview(words);
}).catch(error => {
wordBook.wordsPreview = '단어값없음'; // 오류 시 기본값 설정
});
return Promise.all([textTitlePromise, wordsPromise]);
});
// 모든 데이터 가져오기 작업이 완료되면 dataList에 데이터 설정
Promise.all(fetchDataPromises).then(() => {
vm.wordBooks = wordBooks;
});
})
.catch(function (error) {
console.log("searchWordBooks - error: ", error);
alert("단어장 검색에 오류가 발생했습니다.");
});
},
// 단어 목록 생략 String 생성 메서드
generateWordsPreview(words) {
const maxLength = 20; // 최대 표시 길이 설정
const wordString = words.join(', ');
if (wordString.length > maxLength) {
return wordString.substring(0, maxLength) + '...';
} else {
return wordString;
}
},
// 평가 정보 가져오기
fetchEval(evalType) {
const idx = (this.currentPage - 1) * this.pageSize;
let option = null;
let searchKeyword = null;
if (evalType !== '') {
option = 'eval_type';
searchKeyword = evalType;
}
axios({
url: "/evaluation/evaluationUnitList.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
"option": option,
"keyword": searchKeyword,
"pageSize": this.pageSize,
"startIndex": idx,
"unitId": this.selectedUnit
},
})
.then(response => {
this.evals = response.data;
})
.catch(error => {
console.error("fetchData - error: ", error);
alert("검색 중 오류가 발생했습니다.");
});
},
// 평가는 1개만 선택되도록 제한
selectEvaluation(selectedEvaluation) {
this.evals.forEach(evaluation => {
evaluation.check = false; // 모든 체크 해제
});
selectedEvaluation.check = true; // 선택한 항목만 체크
},
// 지문은 1개만 선택되도록 제한
selectText(selectedText) {
this.posts.forEach(text => {
text.check = false; // 모든 체크 해제
});
selectedText.check = true; // 선택한 항목만 체크
},
// 팝업 문제 데이터 가져오기
insertRoadMap() {
const selectedProblems = this.problems.filter(problem => problem.check);
// RoadMap의 해당 인덱스가 초기화되어 있는지 확인
if (!this.RoadMap[this.selectedPop]) {
this.RoadMap[this.selectedPop] = []; // 초기화
}
// 이미 있는 데이터인지 확인
selectedProblems.forEach(problem => {
const exists = this.RoadMap[this.selectedPop].some(existingProblem => existingProblem.prblmId === problem.prblmId);
if (!exists) {
// isFirst가 true일 경우, 기존 learningId를 유지하도록 처리
const learningId = this.isFirst ? (this.RoadMap[this.selectedPop][0]?.learningId || null) : null;
this.RoadMap[this.selectedPop].push({
prblmId: problem.prblmId,
prblmExpln: problem.prblmExpln,
learningId: learningId
});
}
});
this.closeBtn();
},
// 팝업 지문 데이터 가져오기
insertRoadMap2() {
const selectedTexts = this.posts.filter(post => post.check);
if (selectedTexts.length > 0) {
const selectedText = selectedTexts[0];
const learningId = this.isFirst ? (this.RoadMap[this.selectedPop][0]?.learningId || null) : null;
this.RoadMap[this.selectedPop] = [{
textId: selectedText.textId,
textTtl: selectedText.textTtl,
learningId: learningId
}];
}
this.closeBtn();
},
// 팝업 단어장 데이터 가져오기
insertRoadMap3() {
const selectedBooks = this.wordBooks.filter(wordBook => wordBook.check);
if (!this.RoadMap[this.selectedPop]) {
this.RoadMap[this.selectedPop] = [];
}
// 이미 있는 데이터인지 확인
selectedBooks.forEach(wordBook => {
const exists = this.RoadMap[this.selectedPop].some(existingBook => existingBook.wdBookId === wordBook.wdBookId);
if (!exists) {
const existingItem = this.RoadMap[this.selectedPop][0] || {};
const learningId = this.isFirst ? existingItem.learningId : null;
this.RoadMap[this.selectedPop].push({
wdBookId: wordBook.wdBookId,
learningId: learningId,
textTtl: wordBook.textTtl
});
}
});
this.closeBtn();
},
// 평가 데이터 가져오기
insertRoadMap4() {
const selectedEval = this.evals.filter(evaluation => evaluation.check);
if (selectedEval.length > 0) {
const evalData = selectedEval[0];
const learningId = this.isFirst ? (this.RoadMap[this.selectedPop][0]?.learningId || null) : null;
this.RoadMap[this.selectedPop] = [{
evalId: evalData.evalId,
problemCount: evalData.problemCount,
learningId: learningId
}];
}
this.closeBtn();
},
// 로드맵 정보 가져오기
fetchRoadmapData() {
axios({
url: "/unitLearning/find.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
unit_id: this.selectedUnit,
book_id: this.selectedBook
}
})
.then(response => {
if (response.data.length != 0) {
// RoadMap을 초기화
this.RoadMap = Array.from({ length: 11 }, () => []);
// RoadMap을 구성하는 데이터 삽입
response.data.forEach(item => {
const seqIndex = item.seq - 1;
if (item.text_id && item.text_ttl) {
this.RoadMap[seqIndex].push({
learningId: item.learning_id,
textId: item.text_id,
textTtl: item.text_ttl
});
}
if (item.wd_cnt_id) {
if (seqIndex === 1) {
this.wordContentId1 = item.wd_cnt_id;
}
if (seqIndex === 5) {
this.wordContentId2 = item.wd_cnt_id;
}
if (seqIndex === 9) {
this.wordContentId3 = item.wd_cnt_id;
}
this.RoadMap[seqIndex].push(...item.wordBooks.map(wb => ({
wdCntId: item.wd_cnt_id,
learningId: item.learning_id,
wdBookId: wb.wd_book_id,
textTtl: wb.text_ttl2
})));
}
if (item.prblm_id && item.prblm_id.length > 0) {
item.prblm_id.forEach(prblm => {
if (seqIndex === 2) {
this.learningId1 = item.learning_id;
}
if (seqIndex === 3) {
this.learningId2 = item.learning_id;
}
if (seqIndex === 6) {
this.learningId3 = item.learning_id;
}
this.RoadMap[seqIndex].push({
learningId: item.learning_id,
prblmId: prblm.prblm_id,
prblmExpln: prblm.prblm_expln
});
});
}
if (item.eval_id) {
this.RoadMap[seqIndex].push({
learningId: item.learning_id,
evalId: item.eval_id,
problemCount: item.problem_count
});
}
});
// 완성된 RoadMap을 OrginRoadMap에 깊은 복사하여 저장
this.isFirst = true;
this.OrginRoadMap = JSON.parse(JSON.stringify(this.RoadMap));
} else {
this.RoadMap = [];
this.OrginRoadMap = [];
this.isFirst = false;
}
})
.catch(error => {
console.error("Error fetching roadmap data:", error);
});
},
// wordcontent 처리하기
async postWordContent() {
const validPositions = [1, 5, 9];
for (const position of validPositions) {
const currentSeq = this.RoadMap[position];
const originalSeq = this.OrginRoadMap[position] || [];
const insertList = [];
const insertExistList = [];
// currentSeq와 originalSeq 비교
const isEqual = currentSeq.length === originalSeq.length && currentSeq.every((currentItem, index) => {
const originalItem = originalSeq[index];
return currentItem.wdCntId === originalItem.wdCntId && currentItem.wdBookId === originalItem.wdBookId;
});
// 동일할 경우 아무 작업도 하지 않음
if (isEqual) {
console.log(`Position ${position}: currentSeq and originalSeq are identical. No action taken.`);
continue; // 다음 위치로 넘어감
}
currentSeq.forEach(currentItem => {
const { wdBookId, wdCntId } = currentItem;
if (!this.isFirst) {
insertList.push({ wordBookId: wdBookId });
} else {
let cntId = null;
if (position === 1) {
cntId = this.wordContentId1;
} else if (position === 5) {
cntId = this.wordContentId2;
} else if (position === 9) {
cntId = this.wordContentId3;
}
insertExistList.push({ wordBookId: wdBookId, wordContentId: cntId });
}
});
// ID 생성 및 삽입 요청
if (insertList.length > 0) {
const insertedId = await this.sendInsertRequest(insertList);
currentSeq.forEach(currentItem => {
if (!currentItem.wdCntId) {
if (position === 1) {
this.wordContentId1 = insertedId;
} else if (position === 5) {
this.wordContentId2 = insertedId;
} else if (position === 9) {
this.wordContentId3 = insertedId;
}
}
});
}
if (insertExistList.length > 0) {
await this.sendInsertExistRequest(insertExistList);
}
}
},
// 데이터 삽입 요청 보내기
async sendInsertRequest(insertList) {
try {
const response = await axios.post("/wordContent/insertContent.json", insertList);
console.log("Insert response:", response.data);
return response.data; // 응답에서 새로 생성된 ID 반환
} catch (error) {
console.error("Error inserting data:", error);
throw error; // 오류 발생 시 재던지기
}
},
// 존재하는 데이터 삽입 요청 보내기
async sendInsertExistRequest(insertExistList) {
try {
const response = await axios.post("/wordContent/insertContentExist.json", insertExistList);
console.log("Insert Exist response:", response.data);
} catch (error) {
console.error("Error inserting existing data:", error);
}
},
// 로드맵 데이터 사용
async postRoadMaps() {
console.log("로드맵", this.RoadMap);
// RoadMap 배열의 각 요소 체크
let isEmpty = false;
this.RoadMap.forEach((item, index) => {
if (!item) {
isEmpty = true;
}
});
// 배열이 비어있으면 함수 종료
if (isEmpty) {
alert(`학습 로드맵에 비어있는 데이터가 존재합니다.`);
return;
}
// 먼저 워드 콘텐츠 등록
await this.postWordContent();;
if (this.isFirst) {
this.updateRoadData();
} else {
this.insertRoadData();
}
},
// 로드맵 등록하기
insertRoadData() {
const unitLearningList = this.RoadMap.map((item, index) => {
// item이 배열인 경우 첫 번째 요소를 가져옵니다.
let firstItem = item.length > 0 ? item[0] : {};
// RoadMap의 인덱스에 따라 wordContentId 설정
let wd_cnt_id;
if (index === 1) {
wd_cnt_id = this.wordContentId1;
firstItem.textId = null;
} else if (index === 5) {
wd_cnt_id = this.wordContentId2;
firstItem.textId = null;
} else if (index === 9) {
wd_cnt_id = this.wordContentId3;
firstItem.textId = null;
} else {
wd_cnt_id = null; // 다른 인덱스에 대해선 null 설정
}
return {
unit_id: this.selectedUnit,
wd_cnt_id: wd_cnt_id, // wordContentId
text_id: firstItem.textId || null, // 텍스트 ID
eval_id: firstItem.evalId || null, // 평가 ID
seq: index + 1 // seq는 1부터 시작
};
});
axios.post("/unitLearning/insert.json", unitLearningList)
.then(response => {
console.log(`Insert successful:`, response.data);
if (response.data) {
const learningIds = response.data;
learningIds.forEach(item => {
if (item.seq === 3) {
this.learningId1 = item.learning_id;
} else if (item.seq === 4) {
this.learningId2 = item.learning_id;
} else if (item.seq === 7) {
this.learningId3 = item.learning_id;
}
});
this.postPrblmBook();
}
})
.catch(error => {
console.error(`Error during insert`, error);
});
},
// 로드맵 업데이트하기
updateRoadData() {
const unitLearningList = this.RoadMap.map((item, index) => {
// item이 배열인 경우 첫 번째 요소를 가져옵니다.
let firstItem = item.length > 0 ? item[0] : {};
// RoadMap의 인덱스에 따라 wordContentId 설정
let wd_cnt_id;
if (index === 1) {
wd_cnt_id = this.wordContentId1;
firstItem.textId = null;
} else if (index === 5) {
wd_cnt_id = this.wordContentId2;
firstItem.textId = null;
} else if (index === 9) {
wd_cnt_id = this.wordContentId3;
firstItem.textId = null;
} else {
wd_cnt_id = null; // 다른 인덱스에 대해선 null 설정
}
return {
learning_id: firstItem.learningId, // 기존 학습 ID를 사용
wd_cnt_id: wd_cnt_id, // wordContentId
text_id: firstItem.textId || null, // 텍스트 ID
eval_id: firstItem.evalId || null, // 평가 ID
seq: index + 1 // seq는 1부터 시작
};
});
// 업데이트 요청 보내기
axios.post("/unitLearning/update.json", unitLearningList)
.then(response => {
console.log(`Update successful:`, response.data);
if (response.data > 0) {
this.postPrblmBookExist();
}
})
.catch(error => {
console.error(`Error during update`, error);
});
},
// prblmbook 만들어 id 가져오기
postPrblmBook() {
const problemList = [];
// RoadMap에서 문제 ID 가져오기
const roadMapIndices = [2, 3, 6];
if (this.learningId1) {
this.RoadMap[roadMapIndices[0]].forEach(prblm => {
problemList.push({
learningId: this.learningId1,
prblmId: prblm.prblmId // RoadMap에서 가져온 문제 ID
});
});
}
// learningId2에 대해 문제 등록
if (this.learningId2) {
this.RoadMap[roadMapIndices[1]].forEach(prblm => {
problemList.push({
learningId: this.learningId2,
prblmId: prblm.prblmId // RoadMap에서 가져온 문제 ID
});
});
}
// learningId3에 대해 문제 등록
if (this.learningId3) {
this.RoadMap[roadMapIndices[2]].forEach(prblm => {
problemList.push({
learningId: this.learningId3,
prblmId: prblm.prblmId // RoadMap에서 가져온 문제 ID
});
});
}
// 문제 등록 API 호출
axios.post("/problemBook/register.json", problemList)
.then(response => {
console.log("Problems registered successfully:", response.data);
this.fetchRoadmapData();
alert("학습로드맵 등록이 완료되었습니다!");
})
.catch(error => {
console.error("Error during registering problems:", error);
});
},
// 로드맵 문제 수정
postPrblmBookExist() {
const changedProblemList = [];
const validPositions = [2, 3, 6]; // prblm_id가 있는 인덱스들
validPositions.forEach(position => {
const currentSeq = this.RoadMap[position] || [];
const originalSeq = this.OrginRoadMap[position] || [];
console.log('currentSeq:', currentSeq);
console.log('originalSeq:', originalSeq);
// 크기가 다를 경우, 모든 currentSeq 항목을 변경된 것으로 처리
if (currentSeq.length !== originalSeq.length) {
currentSeq.forEach(currentItem => {
let learningId = null;
if (position === 2) {
learningId = this.learningId1;
} else if (position === 3) {
learningId = this.learningId2;
} else if (position === 6) {
learningId = this.learningId3;
}
changedProblemList.push({
learningId: learningId,
prblmId: currentItem.prblmId,
});
});
} else {
// 크기가 같은 경우, 기존 비교 로직을 그대로 적용
currentSeq.forEach(currentItem => {
const originalItem = originalSeq.find(item => item.prblmId === currentItem.prblmId);
if (!originalItem || JSON.stringify(originalItem) !== JSON.stringify(currentItem)) {
let learningId = null;
if (position === 2) {
learningId = this.learningId1;
} else if (position === 3) {
learningId = this.learningId2;
} else if (position === 6) {
learningId = this.learningId3;
}
changedProblemList.push({
learningId: learningId,
prblmId: currentItem.prblmId,
});
}
});
}
});
// 변경된 문제가 있다면, 서버에 업데이트 요청
if (changedProblemList.length > 0) {
axios.post("/problemBook/registerExist.json", changedProblemList)
.then(response => {
console.log("Problems updated successfully:", response.data);
})
.catch(error => {
console.error("Error during updating problems:", error);
});
} else {
console.log("No changes detected in prblm_id.");
}
alert("학습 로드맵 문제 수정이 완료되었습니다!");
this.fetchRoadmapData();
},
},
watch: {
},
computed: {
totalPages() {
return Math.ceil(this.totalPosts / this.pageSize);
},
paginationButtons() {
let start = Math.max(0, this.currentPage - 2);
let end = Math.min(start + 5, this.totalPages);
if (end - start < 5) {
start = Math.max(0, end - 5);
}
return Array.from({ length: end - start }, (_, i) => start + i + 1);
},
startIndex() {
return this.currentPage * this.itemsPerPage;
}
},
components: {
SvgIcon,
ProgressBar
},
mounted() {
this.selectedUnit = this.$route.query.unit_id || '';
this.selectedBook = this.$route.query.book_id || '';
this.fetchBooks();
this.fetchUnits();
this.fetchRoadmapData();
}
}
</script>
<style scoped>
.search-wrap button {
right: 83rem;
}
</style>