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-ai">
<div class="race-box">
<div class="rabbit-start">
<img src="../../../resources/img/new_img/rabbit.png" alt="" />
</div>
<!-- 1번째줄 -->
<div
class="rcon flex justify-end mb5"
style="position: relative; top: 24px"
>
<!-- 1 -->
<div class="race-btn" @click="goToPage('Chapter1')">
<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/ai_board/racebtn_1.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
지문1
</p>
</button>
<!-- <p>지문1</p> -->
</div>
<!-- 2 -->
<div class="race-btn" @click="goToPage('Chapter2')">
<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/ai_board/racebtn_2.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
style="position: absolute; left: 16px"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
단어장
</p>
</button>
<!-- <p>단어장</p> -->
</div>
</div>
<!-- 2번째 줄 -->
<div class="lcon flex justify-between mb5">
<!-- 7 -->
<div class="race-btn" @click="goToPage('Chapter7')">
<button
class="popTxt"
v-for="(item, index) in items"
:key="index"
@click="toggleImage(index)"
data-num="7"
>
<div class="image-container">
<img
src="../../../resources/img/new_img/ai_board/racebtn_7.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
style="position: absolute; top: 85px"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
문제1
</p>
</button>
<!-- <p>문제1</p> -->
</div>
<!-- 6 -->
<div class="race-btn" @click="goToPage('Chapter6')">
<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/ai_board/racebtn_6.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
단어장
</p>
</button>
<!-- <p>단어장</p> -->
</div>
<!-- 5 -->
<div
class="race-btn"
@click="goToPage('Chapter5')"
style="position: relative; left: -31px"
>
<button
class="popTxt"
v-for="(item, index) in items"
:key="index"
@click="toggleImage(index)"
data-num="5"
style="position: absolute; top: -77px; left: 30px"
>
<div class="image-container">
<img
src="../../../resources/img/new_img/ai_board/racebtn_5.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
지문2
</p>
</button>
<!-- <p>지문2</p> -->
</div>
<!-- 4 -->
<div class="race-btn" @click="goToPage('Chapter4')">
<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/ai_board/racebtn_4.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
문제2
</p>
</button>
<!-- <p>문제2</p> -->
</div>
<!-- 3 -->
<div
class="race-btn"
@click="goToPage('Chapter3')"
style="right: 12px"
>
<button
class="popTxt"
v-for="(item, index) in items"
:key="index"
@click="toggleImage(index)"
data-num="3"
style="top: -46px; position: relative"
>
<div class="image-container">
<img
src="../../../resources/img/new_img/ai_board/racebtn_3.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
문제1
</p>
</button>
<!-- <p>문제1</p> -->
</div>
</div>
<!-- 3번째 줄 -->
<div class="rcon flex" style="position: relative; top: -23px">
<!-- 8 -->
<div class="race-btn" @click="goToPage('Chapter8')">
<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/ai_board/racebtn_8.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
중간 평가
</p>
</button>
<!-- <p class="long">중간 평가</p> -->
</div>
<!-- 9 -->
<div class="race-btn" @click="goToPage('Chapter9')">
<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/ai_board/racebtn_9.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
지문3
</p>
</button>
<!-- <p>지문3</p> -->
</div>
<!-- 10 -->
<div class="race-btn" @click="goToPage('Chapter10')">
<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/ai_board/racebtn_10.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
단어장
</p>
</button>
<!-- <p>단어장</p> -->
</div>
<!-- 11 -->
<div class="race-btn">
<button
class="popTxt"
v-for="(item, index) in items"
:key="index"
@click="toggleImage(index)"
data-num="11"
>
<div class="image-container">
<img
src="../../../resources/img/new_img/ai_board/racebtn_11.png"
/>
<img
src="../../../resources/img/new_img/icon/clear_img.png"
:style="{
display: item.isSecondImageVisible ? 'block' : 'none',
}"
class="clear-img"
/>
</div>
<p :class="!item.isSecondImageVisible ? 'before-clear' : 'clear'">
<img
v-if="item.isSecondImageVisible"
src="../../../resources/img/new_img/icon/complete_icon.png"
alt="Complete Icon"
class="complete-icon"
/>
최종 평가
</p>
</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; 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">
<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, // 카메라 모달창
photoTaken: false,
photo: null, //캡쳐 사진
stream: null,
isHidden: false,
images: [],
};
},
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://165.229.169.113: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;
//스트림 종료
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: 100%;
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%;
}
.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;
}
.race-btn p.before-clear {
/* width: auto; */
font-size: 20px;
line-height: 1.6;
color: #ffffff;
background-color: rgba(48, 48, 48, 0.562);
padding: 6px;
border-radius: 8px;
/* border: 1px solid rgba(255, 255, 255, 0.2); */
margin-bottom: 20px;
/* box-shadow: none; */
position: static;
}
.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-box .lcon {
display: flex;
align-items: center;
}
</style>