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-show="isHidden">오늘 공부를 다했어요! 너무 고생했어요!</p>
<div class="main" v-show="!isHidden">
<div class="race-wrap">
<div class="title-box">
<p class="title" style="margin-top: 8rem;">AI 학습 보드</p>
</div>
<div class="race-box">
<div class="rabbit-start"><img src="../../../resources/img/img09_s.png" alt=""></div>
<div class="rcon flex justify-end mb5">
<div class="race-btn" @click="goToPage('Chapter1')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="1">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>지문1</p>
</div>
<div class="race-btn" @click="goToPage('Chapter2')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="2">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>단어장</p>
</div>
</div>
<div class="lcon flex justify-between mb5">
<div class="race-btn" @click="goToPage('Chapter7')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="7">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>문제1</p>
</div>
<div class="race-btn" @click="goToPage('Chapter6')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="6">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>단어장</p>
</div>
<div class="race-btn" @click="goToPage('Chapter5')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="5">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>지문2</p>
</div>
<div class="race-btn" @click="goToPage('Chapter4')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="4">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>문제2</p>
</div>
<div class="race-btn" @click="goToPage('Chapter3')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="3">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>문제1</p>
</div>
</div>
<div class="rcon flex">
<div class="race-btn" @click="goToPage('Chapter8')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="8">
<img :src="item.imgSrc3">
<img :src="item.imgSrc4" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p class="long">중간 평가</p>
</div>
<div class="race-btn" @click="goToPage('Chapter9')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="9">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>지문3</p>
</div>
<div class="race-btn" @click="goToPage('Chapter10')">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="10">
<img :src="item.imgSrc1">
<img :src="item.imgSrc2" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p>단어장</p>
</div>
<div class="race-btn">
<button class="popTxt" v-for="(item, index) in items" :key="index" @click="toggleImage(index)"
data-num="11">
<img :src="item.imgSrc3">
<img :src="item.imgSrc4" :style="{ display: item.isSecondImageVisible ? 'block' : 'none' }">
</button>
<p class="long">최종 평가</p>
</div>
</div>
<div class="rabbit-end" @click="ShowPopup"><img src="../../../resources/img/img138_72s.png" alt="">
</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;">
</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" style="gap: 5px;">
<div class="flex" style="gap: 5px;">
<div v-for="(image, index) in images" :key="image.fileId" @click="buttonSearch(image)"
class="photo">
<img :src="image.url" :alt="image.fileNm" reloadable="true" />
</div>
</div>
</article>
<article class="popup-wrap" v-show="searchOpen">
<div class="popup-box ">
<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: 910px;"><img src="../../../resources/img/img140_747s.png" alt=""></div>
</div>
<div class="flex justify-between mt20">
<div class="text flex">
<p class="title2 date ml30">2024-08-06</p>
<span class=" title1 ml30">1단원을 마친 <em class="yellow">가나다</em>친구</span>
</div>
<div class="title2 flex align-center" style="gap: 10px;"><svg-icon type="mdi" :path="mdiHeart"
style="color: #FFBA08;"></svg-icon>
<p><em class="yellow">1</em></p>
</div>
</div>
</div>
</article>
</div>
</div>
</template>
<script>
import SvgIcon from '@jamescoyle/vue-icon';
import { mdiMagnify, mdiHeart, mdiWindowClose } from '@mdi/js';
import axios from 'axios';
//은진
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
},
],
mdiWindowClose: mdiWindowClose,
mdiHeart: mdiHeart,
showModal: false,
searchOpen: false, // 사진 상세보기 모달창
searchOpen2: false, // 단원 마친 후, 사진 촬영 여부 선택 모달창
showCameraModal: false, // 카메라 모달창
showPhotoModal: false, // 사진꾸미기 모달창
photoTaken: false,
photo: null, //캡쳐 사진
stream: null,
isHidden: false,
images: [],
photoTaken: false
}
},
methods: {
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;
}
},
fetchImage() {
axios({
url: "/photo/photoUnitList.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
unitId: "UNIT_000000000000001",
sclsId: "1"
}
})
.then(response => {
this.file_mng_id = response.data;
const findFilePromises = this.file_mng_id.map(id =>
this.findFile(id.file_mng_id)
);
return Promise.all(findFilePromises);
})
.then(fileResults => {
// Format file results to include image URL
this.images = fileResults.map(file => {
if (file) {
return {
url: "http://localhost:9080/" + `${file.fileRpath}`,
fileId: file.fileId,
fileNm: file.fileNm,
// Add any other properties you need here
};
}
return null;
}).filter(image => image !== null);
})
.catch(error => {
console.error("Error fetching images:", error);
});
},
goToPageImg(page) {
const canvas = document.querySelector('canvas');
const dataURL = canvas.toDataURL('image/png');
this.$router.push({ name: page, query: { image: encodeURIComponent(dataURL) } });
},
finishSchedule() {
this.isHidden = true;
},
toggleImage(index) {
this.items[index].isSecondImageVisible = !this.items[index].isSecondImageVisible;
},
ShowPopup() {
this.searchOpen2 = true;
},
goToPage(page) {
this.$router.push({ name: page });
},
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);
});
},
closeModal() { //웹캠 및 모든 팝업 닫기
// this.showModal = false;
this.searchOpen = false;
this.searchOpen2 = false;
this.showCameraModal = false;
this.photoTaken = false;
this.photo = null;
this.showPhotoModal = false;
//스트림 종료
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);
// 사진 저장 함수 호출
// this.savePhoto('PhotoEdit');
const dataURL = canvas.toDataURL('image/png');
this.$router.push({ name: 'PhotoEdit', query: { image: encodeURIComponent(dataURL) } });
};
},
buttonSearch() {
this.searchOpen = true;
},
buttonSearch2() {
this.searchOpen2 = true;
},
closeBtn() {
this.searchOpen = false;
},
},
components: {
SvgIcon,
},
mounted() {
console.log('main mounted');
this.onVideoLoaded();
this.fetchImage();
if (this.$route.query.reCapture == 'true') {
this.openCameraModal()
}
},
computed() {
},
}
</script>
<style>
.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;
}
/* button {
margin: auto;
padding: 5px 10px;
font-size: 13px;
cursor: pointer;
display: flex;
justify-content: center;
text-align: center;
} */
.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;
}
.camera-rabbit {
position: absolute;
right: 0;
bottom: 0;
width: 40%;
}
</style>