
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
2024-11-19
<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="phogo-popup 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 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;
console.log('>>>>>>>>>>>>>>>>>>>', this.$store.getters.currentDashboard);
},
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: 1;
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;
}
.popup-wrap {
z-index: 1;
}
</style>