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>
<p class="title1" v-if="state === 'finish'">오늘 공부를 다했어요! 너무 고생했어요!</p>
<p class="title1" v-else-if="state === 'notRegistered'">지금은 학습 루트가 등록이 안됐어요! 학습 일정에서 학습루트를 등록해볼까요?</p>
<p class="title1" v-else-if="state === 'noProblem'">교재에 등록된 문제가 없습니다.</p>
<div v-else class="main">
<div class="race-wrap">
<div class="title-box">
<p class="title" style="margin-top: 7rem">{{ titleUnitName }}</p>
<p class="subtitle">{{ titleBookName }}</p>
</div>
<div class="race-box">
<div class="rabbit-start"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[0] ? 'block' : 'none' }" /></div>
<div class="rcon flex justify-end mb5">
<div class="race-btn" @click="[storeLearningId(labeledItems[0])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[1] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="1">
<img :src="labeledItems[0].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[1] ? 'block' : 'none' }" />
<img :src="labeledItems[0].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[1] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[0].label }}</p>
</div>
<div class="race-btn" @click="[storeLearningId(labeledItems[1])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[2] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="2">
<img :src="labeledItems[1].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[2] ? 'block' : 'none' }" />
<img :src="labeledItems[1].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[2] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[1].label }}</p>
</div>
</div>
<div class="lcon flex justify-between mb5">
<div class="race-btn" @click="[storeLearningId(labeledItems[6])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[7] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="7">
<img :src="labeledItems[6].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[7] ? 'block' : 'none' }" />
<img :src="labeledItems[6].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[7] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[6].label }}</p>
</div>
<div class="race-btn" @click="[goToPage('Chapter2_8'), storeLearningId(labeledItems[5].learning_id)]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[6] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="6">
<img :src="labeledItems[5].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[6] ? 'block' : 'none' }" />
<img :src="labeledItems[5].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[6] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[5].label }}</p>
</div>
<div class="race-btn" @click="[storeLearningId(labeledItems[4])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[5] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="5">
<img :src="labeledItems[4].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[5] ? 'block' : 'none' }" />
<img :src="labeledItems[4].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[5] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[4].label }}</p>
</div>
<div class="race-btn" @click="[storeLearningId(labeledItems[3])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[4] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="4">
<img :src="labeledItems[3].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[4] ? 'block' : 'none' }" />
<img :src="labeledItems[3].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[4] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[3].label }}</p>
</div>
<div class="race-btn" @click="[storeLearningId(labeledItems[2])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[3] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="3">
<img :src="labeledItems[2].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[3] ? 'block' : 'none' }" />
<img :src="labeledItems[2].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[3] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[2].label }}</p>
</div>
</div>
<div class="rcon flex">
<div class="race-btn" @click="[goToPage('Chapter8'), storeLearningId(labeledItems[7].learning_id)]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[8] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="8">
<img :src="labeledItems[7].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[8] ? 'block' : 'none' }" />
<img :src="labeledItems[7].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[8] ? 'block' : 'none' }" />
</button>
<p class="long">{{ labeledItems[7].label }}</p>
</div>
<div class="race-btn" @click="[storeLearningId(labeledItems[8])]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[9] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="9">
<img :src="labeledItems[8].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[9] ? 'block' : 'none' }" />
<img :src="labeledItems[8].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[9] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[8].label }}</p>
</div>
<div class="race-btn" @click="[goToPage('Chapter10'), storeLearningId(labeledItems[9].learning_id)]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[10] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)" data-num="10">
<img :src="labeledItems[9].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[10] ? 'block' : 'none' }" />
<img :src="labeledItems[9].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[10] ? 'block' : 'none' }" />
</button>
<p>{{ labeledItems[9].label }}</p>
</div>
<div class="race-btn" @click="[goToPage('Chapter2_8'), storeLearningId(labeledItems[10].learning_id)]">
<div class="rabbit-running"><img src="../../../resources/img/img09_s.png" alt="" :style="{ display: rabbitPos[11] ? 'block' : 'none' }" /></div>
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImageAndShowPopup(index, '11')" data-num="11">
<img :src="labeledItems[10].label.length >= 4 ? item.imgSrc3 : item.imgSrc1" :style="{ display: !rabbitCompl[11] ? 'block' : 'none' }" />
<img :src="labeledItems[10].label.length >= 4 ? item.imgSrc4 : item.imgSrc2" :style="{ display: rabbitCompl[11] ? 'block' : 'none' }" />
</button>
<p class="long">{{ labeledItems[10].label }}</p>
</div>
</div>
<div class="race-btn">
<div class="rabbit-running" style="display: flex">
<img class="rabbit-end" src="../../../resources/img/img138_72s.png" alt="" :style="{ display: rabbitEnd ? 'block' : 'none' }" />
<img class="fireworks-end" src="../../../resources/img/fireworks.gif" alt="" :style="{ display: rabbitEnd ? 'block' : 'none' }" />
</div>
</div>
</div>
<!-- 팝업 -->
<div v-show="searchOpen2" class="popup-wrap">
<div class="popup-box">
<button type="button" class="popup-close-btn" style="position: absolute; top: 10px; right: 10px" @click="closeModal">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
<div class="mb30 text-ct">
<p class="title1 mb20">1단원이 끝났습니다!</p>
<p class="title1"><em class="yellow">기념사진</em>을 촬영하러 가요</p>
</div>
<div class="flex justify-center">
<button type="button" title="사진촬영" class="new-btn" @click="openCameraModal">사진 촬영</button>
</div>
</div>
</div>
<!-- 카메라 모달 -->
<article v-show="showCameraModal" class="popup-wrap">
<div class="popup-box" style="top: 500px; left: 500px">
<div class="flex mb10 justify-between">
<p class="popup-title">사진 촬영</p>
<button type="button" class="popup-close-btn" @click="closeModal">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
</div>
<div class="box">
<div style="width: 100%">
<div id="container" ref="container">
<video v-if="!photoTaken" autoplay="true" ref="modalVideoElement" class="mirrored" @canplay="onVideoLoaded" style="position: absolute; height: 100%"></video>
<img src="../../../resources/img/camera-rabbit.png" class="camera-rabbit" style="position: absolute" />
<canvas ref="canvas" style="pointer-events: none"></canvas>
</div>
</div>
</div>
<div class="flex justify-center mt20">
<button class="new-btn" @click="takePhoto">사진 찍기</button>
</div>
</div>
</article>
</div>
<div class="complete-wrap myphoto">
<button class="login-btn mt10" type="submit" style="width: 100%" @click="finishSchedule">
<img src="../../../resources/img/btn07_s.png" alt="" style="width: 100%; height: 100px" />
<p>학습 종료하기</p>
</button>
<h2 class="mb40 mt10">이 단원을 끝낸 친구들</h2>
<article class="flex-column">
<div class="flex-row">
<div class="flex" style="gap: 5px; flex-wrap: wrap">
<div v-for="(image, index) in images" :key="image.fileId" @click="buttonSearch(image)" class="photo" style="margin-bottom: 5px">
<img :src="image.url" :alt="image.fileNm" reloadable="true" style="height: 100%" />
</div>
</div>
</div>
</article>
<article class="popup-wrap" v-show="searchOpen">
<div class="popup-box" style="top: 50%">
<div class="flex mb10 justify-between">
<button type="button" class="popup-close-btn" @click="closeModal">
<svg-icon type="mdi" :path="mdiWindowClose" class="close-btn"></svg-icon>
</button>
</div>
<div class="box">
<div style="width: 910px; height: 680px">
<img :src="selectedImage.image" alt="Image" @error="onImageError" reloadable="true" />
</div>
</div>
<div class="flex justify-between mt20">
<div class="text flex">
<p class="title2 date ml30">{{ selectedImage.date }}</p>
<span class="title1 ml30"
>{{ selectedImage.unit }}을 마친 <em class="yellow">{{ selectedImage.name }}</em
>친구</span
>
</div>
<div class="title2 flex align-center" style="gap: 10px">
<svg-icon
v-if="!isHeartFilled"
type="mdi"
:path="mdiHeartOutline"
@click="toggleHeart(selectedImage.heart, selectedImage.fileMngId)"
style="color: #ffba08; cursor: pointer"
></svg-icon>
<svg-icon
v-if="isHeartFilled"
type="mdi"
:path="mdiHeart"
@click="toggleHeart(selectedImage.heart, selectedImage.fileMngId)"
style="color: #ffba08; cursor: pointer"
></svg-icon>
<p>
<em class="yellow">{{ selectedImage.heart }}</em>
</p>
</div>
</div>
</div>
</article>
</div>
</div>
</template>
<script>
import SvgIcon from "@jamescoyle/vue-icon";
import { mdiMagnify, mdiHeart, mdiWindowClose } from "@mdi/js";
import { mdiHeartOutline } from "@mdi/js";
import axios from "axios";
import { call } from "file-loader";
import { name } from "file-loader";
import { mapGetters } from "vuex";
import { mapActions } from "vuex";
export default {
data() {
return {
items: [
{
imgSrc1: "client/resources/img/img11_1_s.png",
imgSrc2: "client/resources/img/img12_1_s.png",
imgSrc3: "client/resources/img/img11_2_s.png",
imgSrc4: "client/resources/img/img12_2_s.png",
isSecondImageVisible: false,
},
],
mdiMagnify: mdiMagnify,
mdiWindowClose: mdiWindowClose,
mdiHeart: mdiHeart,
mdiHeartOutline: mdiHeartOutline,
showModal: false,
searchOpen: false, // 사진 상세보기 모달창
searchOpen2: false, // 단원 마친 후, 사진 촬영 여부 선택 모달창
showCameraModal: false, // 카메라 모달창
photoTaken: false,
photo: null, //캡쳐 사진
stream: null,
roadmapData: [],
labeledItems: [],
problemCounter: 0,
wordCounter: 0,
textCounter: 0,
evalCounter: 0,
book_id: null,
unit_id: null,
schedules: [],
nowSchedule: "",
state: "",
rabbitPos: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
rabbitCompl: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
rabbitEnd: false,
titleUnitName: "",
titleBookName: "",
images: [],
unit_id: "",
book_id: "",
selectedImage: [
{
image: "",
unit: "",
date: "",
name: "",
heart: "",
fileMngId: "",
},
],
isHeartFilled: false, // 하트가 채워졌는지 여부
problemType: null,
wordBookType: null,
wordContentList: [],
};
},
methods: {
toggleHeart(heart, fileMngId) {
this.isHeartFilled = !this.isHeartFilled; // 하트 상태 토글
if (this.isHeartFilled) var calHeart = heart + 1;
else var calHeart = heart - 1;
// 하트 수를 증가시키기 위한 API 요청
axios
.post("/photo/likeUpdate.json", {
likeData: calHeart,
fileMngId: fileMngId,
})
.then((response) => {
this.selectedImage.heart = calHeart;
})
.catch((error) => {
console.error("Error updating heart:", error);
});
},
checkAndFetchData() {
console.log("받은 Book ID:", this.getBookId);
console.log("받은 Unit ID:", this.getUnitId);
const book_id = this.getBookId;
const unit_id = this.getUnitId;
if (!book_id || !unit_id) {
console.error("book_id 또는 unit_id가 설정되지 않았습니다.");
return;
}
this.fetchImage(unit_id);
this.fetchSchedule(unit_id, book_id);
this.fetchRoadmapData(unit_id, book_id);
this.fetchRabbit();
this.unit_id = unit_id;
this.book_id = book_id;
if (this.$route.query.reCapture == "true") {
this.openCameraModal();
}
},
//은진
buttonSearch(image) {
this.isHeartFilled = false;
this.selectedImage.name = image.stdId;
this.selectedImage.image = image.url;
this.selectedImage.unit = this.titleUnitName;
this.selectedImage.date = image.fileRegDate.split(" ")[0];
this.selectedImage.heart = image.likeData;
this.selectedImage.fileMngId = image.fileMngId;
this.searchOpen = true;
},
fetchImage(unit_id) {
axios({
url: "/photo/photoUnitList.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
unitId: unit_id,
sclsId: "1",
},
})
.then((response) => {
this.file = response.data;
const findFilePromises = this.file.map((f) => this.findFile(f.file_mng_id));
return Promise.all(findFilePromises);
})
.then((fileResults) => {
this.images = this.file
.map((file, index) => {
const result = fileResults[index];
if (result) {
return {
url: "http://165.229.169.113:9080/" + `${result.fileRpath}`,
fileId: result.fileId,
fileNm: result.fileNm,
fileRegDate: result.regDt,
likeData: file.like_data,
stdId: file.user_nm,
fileMngId: result.fileMngId,
};
}
return null;
})
.filter((image) => image !== null);
})
.catch((error) => {
console.error("Error fetching images:", error);
});
},
async findFile(file_mng_id) {
try {
const res = await axios({
url: "/file/find.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
file_mng_id: file_mng_id,
},
});
return res.data.list[0];
} catch (error) {
console.log("result - error : ", error);
return null;
}
},
goToPageImg(page) {
const canvas = document.querySelector("canvas");
const dataURL = canvas.toDataURL("image/png");
this.$router.push({ name: page, query: { image: encodeURIComponent(dataURL) } });
},
fetchRabbit() {
for (var i = 0; i < 12; i++) {
this.rabbitPos[i] = false;
}
if (this.$route.query.value) {
this.rabbitPos[parseInt(this.$route.query.value, 10) + 1] = true;
for (var i = 0; i < this.$route.query.value; i++) {
this.rabbitCompl[i + 1] = true;
}
if (this.$route.query.value === "11") {
this.rabbitEnd = true;
setTimeout(() => {
this.searchOpen2 = true;
}, 1000);
}
} else this.rabbitPos[0] = true;
},
fetchSchedule(unit_id, book_id) {
axios({
url: "/schedule/selectSchedule.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
stdId: "2",
},
})
.then((response) => {
this.schedules = response.data;
if (this.schedules.length == 0) {
this.state = "notRegistered";
} else {
const allFinished = this.schedules.every((schedule) => schedule.finish === "T");
if (allFinished) {
this.state = "finish";
} else {
this.nowSchedule = this.schedules.find((schedule) => schedule.finish === null || schedule.finish === "F");
if (this.nowSchedule) {
this.fetchRoadmapData(unit_id, book_id);
this.state = "studying";
} else {
this.state = "notRegistered";
}
}
}
})
.catch((error) => {
console.error("Error fetching roadmap data:", error);
});
},
finishSchedule() {
axios({
url: "/schedule/scheduleUpdate.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
scheduleId: this.nowSchedule.schdl_id,
finish: "T",
},
})
.then((response) => {
const nextSchedule = this.schedules.find((schedule) => schedule.schdl_id > this.nowSchedule.schdl_id);
alert("학습을 완료했습니다!");
if (nextSchedule) {
this.nowSchedule = nextSchedule;
this.fetchSchedule(nextSchedule.unit_id, nextSchedule.book_id);
this.fetchRoadmapData(nextSchedule.unit_id, nextSchedule.book_id);
this.$router.push({ name: "Dashboard", query: { unit_id: nextSchedule.unit_id, book_id: nextSchedule.book_id } });
} else {
alert("모든 학습을 완료했습니다!");
this.state = "finish";
}
})
.catch((error) => {
console.error("Error updating schedule:", error);
});
},
fetchRoadmapData(unit_id, book_id) {
axios({
url: "/unitLearning/find.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
unit_id: unit_id,
book_id: book_id,
},
})
.then((response) => {
if (response.data.length != 0) {
this.roadmapData = response.data;
this.titleUnitName = this.roadmapData[0].unit_nm;
this.titleBookName = this.roadmapData[0].book_nm;
this.labeledItems = this.processedRoadmap;
} else {
this.state = "noProblem";
}
})
.catch((error) => {
this.state = "noProblem";
console.error("Error fetching roadmap data:", error);
});
},
toggleImage(index) {
this.items[index].isSecondImageVisible = !this.items[index].isSecondImageVisible;
},
ShowPopup() {
this.searchOpen2 = true; // 촬영 여부 묻는 모달창 열기
},
goToPage(page) {
// const { unit_id, book_id } = this.$route.query;
// this.$router.push({ name: page, query: { unit_id, book_id } });
this.$router.push({ name: page });
},
storeLearningId(labeledItems) {
this.$store.dispatch("updateLearningData", labeledItems);
this.$store.dispatch("updateLearningId", labeledItems.learning_id); // 단어장에 사용중..
console.log("레이블된 아이템: ", labeledItems);
if (labeledItems.label.startsWith("문제")) {
this.handleProblemDetail(this.$store.getters.currentLearningId);
this.goToPage(this.problemType);
} else if (labeledItems.label.startsWith("단어장")) {
this.handleWordBookContent(this.$store.getters.getLearningId);
}
if (labeledItems.label.startsWith("지문")) {
//console.log("지문 아이디 : ", labeledItems.learning_id);
this.$store.dispatch("updateTextId", labeledItems.learning_id);
this.fetchTextType(labeledItems.learning_id);
}
},
handleWordBookContent(item) {
console.log("처리할 단어장 콘텐츠 id: ", item);
// 단어장 ID 가져오기
axios
.post("/wordContent/selectWordContent.json", {
wordContentId: item,
})
.then((response) => {
this.wordContentList = response.data;
this.$store.dispatch('updateWdBookIdList', this.wordContentList.map(content => content.wd_book_id));
this.$store.dispatch('updateCurrentWdBkIndex', 0);
console.log("저장한 단어장 id 리스트: ", this.$store.getters.getWdBookIdList);
// 단어장 ID 리스트에서 첫 번째 단어장 ID를 사용
const wdBookId = this.wordContentList[0].wd_book_id;
// 단어장 정보 가져오기
return axios.post("/wordbook/find.json", {
wdBookId: wdBookId,
});
})
.then((response) => {
const wordbookData = response.data;
// 단어장 타입에 따라 페이지 설정
if (wordbookData && wordbookData.wdBookTypeId) {
switch (wordbookData.wdBookTypeId) {
case "1":
this.wordBookType = "Chapter2";
break;
case "2":
this.wordBookType = "Chapter2_3";
break;
case "3":
this.wordBookType = "Chapter2_2";
break;
case "4":
this.wordBookType = "Chapter2_9";
break;
case "5":
this.wordBookType = "Chapter2_4";
break;
default:
this.wordBookType = null;
}
} else {
console.error("wdBookTypeId가 없습니다.");
this.wordBookType = null;
}
console.log("현재 단어장 타입: ", this.wordBookType);
this.goToPage(this.wordBookType);
})
.catch((error) => {
console.error("단어장 정보를 불러오는 중 오류 발생:", error);
this.wordBookType = null;
});
},
// 지문 type 불러오기
fetchTextType(text_id) {
axios({
url: "/text/selectOneText.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
textId: text_id,
},
})
.then((response) => {
const text_type_id = response.data[0].text_type_id;
// console.log("지문 유형 아이디 : ", text_type_id);
if (text_type_id === "2") {
this.goToPage("Chapter1_2");
} else if (text_type_id === "3") {
this.goToPage("Chapter1_3");
}
})
.catch((err) => {
console.log("지문 에러 : ", err);
});
},
handleProblemDetail(item) {
if (item.prblm_type_id === "prblm_type_001") {
this.problemType = "Chapter3";
} else if (item.prblm_type_id === "prblm_type_002") {
this.problemType = "Chapter3_1";
} else if (item.prblm_type_id === "prblm_type_003") {
this.problemType = "Chapter3_2";
} else if (item.prblm_type_id === "prblm_type_004") {
this.problemType = "Chapter3_3";
} else if (item.prblm_type_id === "prblm_type_005") {
this.problemType = "Chapter3_3_1";
} else if (item.prblm_type_id === "prblm_type_006") {
this.problemType = "Chapter3_4";
} else if (item.prblm_type_id === "prblm_type_007") {
this.problemType = "Chapter3_5";
} else if (item.prblm_type_id === "prblm_type_008") {
this.problemType = "Chapter3_6";
} else if (item.prblm_type_id === "prblm_type_009") {
this.problemType = "Chapter3_7";
} else if (item.prblm_type_id === "prblm_type_010") {
this.problemType = "Chapter3_8";
} else if (item.prblm_type_id === "prblm_type_011") {
this.problemType = "Chapter3_9";
} else if (item.prblm_type_id === "prblm_type_012") {
this.problemType = "Chapter3_10";
} else if (item.prblm_type_id === "prblm_type_013") {
this.problemType = "Chapter3_11";
} else if (item.prblm_type_id === "prblm_type_014") {
this.problemType = "Chapter3_12";
} else if (item.prblm_type_id === "prblm_type_015") {
this.problemType = "Chapter3_13";
} else if (item.prblm_type_id === "prblm_type_016") {
this.problemType = "Chapter3_14";
} else if (item.prblm_type_id === "prblm_type_017") {
this.problemType = "Chapter3_15";
} else if (item.prblm_type_id === "prblm_type_018") {
this.problemType = "Chapter2_8";
} else if (item.prblm_type_id === "prblm_type_019") {
this.problemType = "Chapter2_7";
} else if (item.prblm_type_id === "prblm_type_020") {
this.problemType = "Chapter2_5";
} else if (item.prblm_type_id === "prblm_type_021") {
this.problemType = "Chapter2_6";
} else if (item.prblm_type_id === "prblm_type_022") {
this.problemType = "Chapter2_10";
} else if (item.prblm_type_id === "prblm_type_023") {
this.problemType = "Chapter2_11";
} else if (item.prblm_type_id === "prblm_type_024") {
this.problemType = "Chapter2_13";
}
},
openCameraModal() {
this.closeModal();
this.showCameraModal = true;
navigator.mediaDevices
.getUserMedia({ video: true })
.then((stream) => {
const modalVideo = this.$refs.modalVideoElement;
modalVideo.srcObject = stream;
this.stream = stream;
})
.catch((error) => {
console.log("error>>>>>>>>", error);
alert("웹캠이 필요한 기능입니다!");
this.closeModal(); // 모달창을 닫음
});
},
closeModal() {
this.searchOpen = false;
this.searchOpen2 = false;
this.showCameraModal = false;
this.photoTaken = false;
this.photo = null;
//스트림 종료
if (this.stream) {
let tracks = this.stream.getTracks();
tracks.forEach((track) => track.stop());
this.stream = null;
}
},
onVideoLoaded() {
const video = this.$refs.modalVideoElement;
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
},
takePhoto() {
const video = this.$refs.modalVideoElement;
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");
ctx.save(); // 현재 상태 저장
// 캔버스 좌우 반전
ctx.scale(-1, 1);
ctx.drawImage(video, -canvas.width, 0, canvas.width, canvas.height);
ctx.restore();
const overlayImg = new Image();
overlayImg.src = "client/resources/img/camera-rabbit.png";
overlayImg.onload = () => {
const overlayWidth = canvas.width * 0.4;
const overlayHeight = (overlayImg.height / overlayImg.width) * overlayWidth;
const overlayX = canvas.width - overlayWidth;
const overlayY = canvas.height - overlayHeight;
// 오버레이 이미지 그리기
ctx.drawImage(overlayImg, overlayX, overlayY, overlayWidth, overlayHeight);
// 사진 저장 함수 호출
const dataURL = canvas.toDataURL("image/png");
this.$router.push({ name: "PhotoEdit", query: { image: encodeURIComponent(dataURL), unit_id: this.unit_id, book_id: this.book_id } });
};
},
buttonSearch2() {
this.searchOpen2 = true;
},
closeBtn() {
this.searchOpen = false;
},
},
components: {
SvgIcon,
},
mounted() {
console.log("main mounted");
this.checkAndFetchData();
// const { book_id, unit_id } = this.$route.query;
},
watch: {
getBookId(newBookId) {
this.checkAndFetchData();
},
getUnitId(newUnitId) {
this.checkAndFetchData();
},
},
computed: {
...mapGetters(["getBookId", "getUnitId"]),
processedRoadmap() {
let problemCounter = 0;
let wordCounter = 0;
let textCounter = 0;
let evalCounter = 0;
return this.roadmapData.map((item) => {
if (item.wd_cnt_id !== null) {
wordCounter++;
return { label: `단어장${wordCounter}`, learning_id: item.wd_cnt_id };
} else if (item.text_id !== null) {
textCounter++;
return { label: `지문${textCounter}`, learning_id: item.text_id };
} else if (item.eval_id !== null) {
evalCounter++;
return { label: evalCounter === 1 ? "중간평가" : "최종평가", learning_id: item.eval_id };
} else {
problemCounter++;
return { label: `문제${problemCounter}`, learning_id: item.prblm_id };
}
});
},
},
beforeDestroy() {
// 컴포넌트가 파괴되기 전에 리스너 제거
window.removeEventListener("resize", this.updateCanvasRect);
this.$refs.canvas.removeEventListener("click", this.handleCanvasClick);
},
};
</script>
<style scoped>
.body {
width: 1435px;
height: auto;
margin: 0 auto;
}
#container {
position: relative;
margin: auto;
border: 10px #333 solid;
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
}
video {
width: 100%;
height: auto;
background-color: #666;
}
.mirrored {
transform: scaleX(-1);
}
.new-btn:disabled {
background-color: #fff3d7;
cursor: not-allowed;
}
.sticker {
position: absolute;
cursor: move;
}
.sticker-handle {
width: 15px;
height: 15px;
background: rgba(255, 255, 255, 0.521);
position: absolute;
bottom: 0;
right: 0;
cursor: nwse-resize;
font-size: 13px;
font-weight: bolder;
color: rgb(63, 63, 63);
}
.sticker-delete {
position: absolute;
top: 0;
right: 0;
background: rgba(255, 0, 0, 0.425);
color: white;
padding: 5px;
cursor: pointer;
}
.toolbar {
display: flex;
justify-content: center;
margin-top: 10px;
}
.toolbar button {
margin: 5px;
padding: 5px 10px;
cursor: pointer;
}
.toolbar input {
margin: 5px;
}
.rabbit-end {
cursor: pointer;
display: block;
position: absolute;
bottom: 0px;
left: -15px;
z-index: 10000;
}
.rabbit-running {
position: absolute;
bottom: 40px;
right: 110px;
z-index: 10000;
transform: scaleX(-1);
transition: all 0.5s ease-in-out;
}
.fireworks-end {
position: absolute;
bottom: 70px;
left: -40px;
width: 20rem;
}
.camera-rabbit {
position: absolute;
right: 0;
bottom: 0;
width: 40%;
}
.race-btn p {
width: auto;
}
</style>