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'" style="position: absolute; top: 50%; transform: translate(0, -50%)">
오늘 공부를 다했어요! 너무 고생했어요!
</p>
<div class="title1" v-else-if="state === 'notRegistered'"
style="position: absolute;top: 50%;transform: translate(-50%, -50%);left: 50%;">
<div class="title-box" style="text-align: center;">
<img src="../../../resources/img/new_img/dashboard/rabbit.png">
<h3 class="title" style=" margin-top: 1em; letter-spacing: 2px; line-height: 42px; font-size: 30px">
지금은 학습 루트가 등록이 안됐어요! <br> 학습 일정에서 학습루트를
등록해볼까요?
</h3>
<div @click="goToPage2('MyPlan2')" style="cursor: pointer; margin-top: 2em;">
<img src="../../../resources/img/new_img/dashboard/btn.png">
</div>
</div>
</div>
<p class="title1" v-else-if="state === 'noProblem'"
style="position: absolute; top: 50%; transform: translate(0, -50%)">
교재에 등록된 문제가 없습니다.
</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/new_img/rabbit.png" alt=""
:style="{ display: rabbitPos[0] ? 'block' : 'none' }" />
</div>
<!-- 1번째줄 -->
<div class="rcon flex justify-end mb5" style="position: relative; top: 24px">
<!-- 1 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[0])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_1.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[1]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[1] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[1]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[0].label }}
</p>
</div>
<!-- 2 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[1])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_2.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[2]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" style="position: absolute; left: 16px" />
</div>
</button>
<p :class="!rabbitCompl[2] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[2]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[1].label }}
</p>
</div>
</div>
<!-- 2번째줄 -->
<div class="lcon flex justify-between mb5">
<!-- 7 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[6])]">
<div class="rabbit-running" style="top: -71px">
<img src="../../../resources/img/new_img/rabbit.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"
style="top: -53px; position: relative">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_7.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[7]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" style="position: absolute; top: 85px" />
</div>
</button>
<p :class="!rabbitCompl[7] ? 'before-clear' : 'clear'" style="position: relative; top: -53px; left: -10px">
<img v-if="rabbitCompl[7]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[6].label }}
</p>
</div>
<!-- 6 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[5])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_6.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[6]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[6] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[6]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[5].label }}
</p>
</div>
<!-- 5 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[4])]" style="position: relative; left: -31px">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_5.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[5]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[5] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[5]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[4].label }}
</p>
</div>
<!-- 4 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[3])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_4.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[4]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[4] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[4]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[3].label }}
</p>
</div>
<!-- 3 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[2])]" style="right: 12px">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_3.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[3]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[3] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[3]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[2].label }}
</p>
</div>
</div>
<!-- 3번째줄 -->
<div class="rcon flex" style="position: relative; top: -23px">
<!-- 8 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[7])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_8.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[8]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[8] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[8]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[7].label }}
</p>
</div>
<!-- 9 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[8])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_9.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[9]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[9] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[9]" src="../../../resources/img/new_img/icon/complete_icon.png" alt="Complete Icon"
class="complete-icon" />
{{ labeledItems[8].label }}
</p>
</div>
<!-- 10 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[9])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_10.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[10]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[10] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[10]" src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon" class="complete-icon" />
{{ labeledItems[9].label }}
</p>
</div>
<!-- 11 -->
<div class="race-btn" @click="[storeLearningId(labeledItems[10])]">
<div class="rabbit-running">
<img src="../../../resources/img/new_img/rabbit.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">
<div class="image-container">
<img src="../../../resources/img/new_img/board/racebtn_11.png" alt="Race Button" class="base-img" />
<img v-if="rabbitCompl[11]" src="../../../resources/img/new_img/icon/clear_img.png" alt="Clear Icon"
class="clear-img" />
</div>
</button>
<p :class="!rabbitCompl[11] ? 'before-clear' : 'clear'">
<img v-if="rabbitCompl[11]" src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon" class="complete-icon" />
{{ labeledItems[10].label }}
</p>
</div>
</div>
<div class="race-btn">
<div class="rabbit-running" style="display: flex">
<img class="rabbit-end" src="../../../resources/img/new_img/rabbit.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="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, 0],
rabbitCompl: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
rabbitEnd: false,
titleUnitName: "",
titleBookName: "",
images: [],
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가 설정되지 않았습니다.");
this.state = "notRegistered";
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();
}
this.searchStdId();
},
//은진
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;
console.log(this.roadmapData, this.labeledItems);
} 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 });
},
goToPage2(page, unit_id) {
this.$router.push({
name: page,
query: {
unit_id: unit_id,
},
});
},
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);
console.log(">>>>>>>>>>", this.$store.getters.currentLearningId)
this.goToPage(this.problemType);
} else if (labeledItems.label.startsWith("단어장")) {
this.handleWordBookContent(this.$store.getters.getLearningId);
} else if (labeledItems.label.startsWith("지문")) {
//console.log("지문 아이디 : ", labeledItems.learning_id);
this.$store.dispatch("updateTextId", labeledItems.learning_id);
this.fetchTextType(labeledItems.learning_id);
} else if (labeledItems.label.startsWith("중간평가")) {
this.fetchEvalData(labeledItems);
} else if (labeledItems.label.startsWith("최종평가")) {
this.fetchEvalData(labeledItems);
}
},
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);
});
},
// 평가 정보를 통해서 관련 문제 가져오기
fetchEvalData(evaldata) {
axios({
url: "/evalProblem/selectEvalProblem.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
evalId: evaldata.learning_id,
},
})
.then((response) => {
const payload = {
learning_id: response.data,
label: evaldata.label,
seqNum: evaldata.seqNum,
};
// Vuex 뮤테이션 호출
this.$store.commit("setLearningData", payload);
this.handleProblemDetail(response.data[0]);
this.goToPage(this.problemType);
})
.catch((error) => {
console.error("fetchData - error: ", error);
return [];
});
},
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") {
console.log(item);
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;
},
// 유저 아이디를 unit 아이디를 통해 가져오기
searchStdId() {
const userInfo = this.$store.getters.getUserInfo;
axios({
url: "/userclass/searchStdId.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
userId: userInfo.userId,
unitId: this.unit_id,
},
})
.then((response) => {
this.$store.commit("setStdId", response.data);
})
.catch((err) => {
console.log("지문 에러 : ", err);
});
},
},
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,
seqNum: item.seq,
};
} else if (item.text_id !== null) {
textCounter++;
return {
label: `지문${textCounter}`,
learning_id: item.text_id,
seqNum: item.seq,
};
} else if (item.eval_id !== null) {
evalCounter++;
return {
label: evalCounter === 1 ? "중간평가" : "최종평가",
learning_id: item.eval_id,
seqNum: item.seq,
};
} else {
problemCounter++;
return {
label: `문제${problemCounter}`,
learning_id: item.prblm_id,
seqNum: item.seq,
};
}
});
},
},
beforeDestroy() {
// 컴포넌트가 파괴되기 전에 리스너 제거
window.removeEventListener("resize", this.updateCanvasRect);
this.$refs.canvas.removeEventListener("click", this.handleCanvasClick);
},
};
</script>
<style scoped>
.complete-wrap img {
width: auto;
}
.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; */
top: -118px;
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.clear {
/* width: auto; */
font-size: 20px;
line-height: 1.6;
color: #333;
background-color: #f9f9f9;
padding: 6px;
border-radius: 8px;
/* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); */
margin-bottom: 20px;
position: static;
display: flex;
align-items: center;
gap: 0.5rem;
}
.race-btn p.before-clear {
/* width: auto; */
font-size: 20px;
line-height: 1.6;
color: #ffffff;
background-color: rgba(119, 119, 119, 0.815);
padding: 6px;
border-radius: 8px;
/* border: 1px solid rgba(255, 255, 255, 0.2); */
margin-bottom: 20px;
/* box-shadow: none; */
position: static;
}
.race-box .lcon {
display: flex;
align-items: center;
}
.lcon .race-btn .rabbit-running {
transform: scaleX(1);
}
.rabbit-start img {
transform: scaleX(-1);
}
.image-container {
position: relative;
display: inline-block;
}
.clear-img {
position: absolute;
top: -27px;
left: 0;
width: 100px;
height: 100px;
z-index: 1;
}
</style>