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
<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>