jichoi / lms_front star
guntaek 09-19
Merge branch 'master' of http://210.180.118.83/jichoi/lms_front
@a59958c919c3085efa08a2cf7363f9aebe10449f
client/views/pages/main/Chapter/Chapter1_1.vue
--- client/views/pages/main/Chapter/Chapter1_1.vue
+++ client/views/pages/main/Chapter/Chapter1_1.vue
@@ -132,8 +132,9 @@
             this.$router.push({ name: page });
         },
         goToNextPage() {
-            alert('지문 학습 완료!');
-            this.complete();
+            this.goToPage('Chapter1_3');
+            // alert('지문 학습 완료!');
+            // this.complete();
         },
         // 대화 지문 API
         async fetchText() {
client/views/pages/main/Chapter/Chapter1_3.vue
--- client/views/pages/main/Chapter/Chapter1_3.vue
+++ client/views/pages/main/Chapter/Chapter1_3.vue
@@ -12,26 +12,37 @@
                 <span class="title mr40">1. Hello WORLD</span>
                 <span class="subtitle">my name is dd</span>
             </div>
-            <button class="completeBtn" @click="complete">학습 종료</button>
+            <div class="flex">
+                <TextToImage />
+                <button class="completeBtn" @click="complete">학습 종료</button>
+            </div>
         </div>
         <div class="flex justify-between align-center">
-            <div class="pre-btn" style="visibility: hidden" @click="goToPage('Chapter1_2')">
+            <div class="pre-btn" @click="goToPage('Chapter1_1')">
                 <img src="../../../../resources/img/left.png" alt="" />
             </div>
             <div class="content title-box">
-                <div class="listenGroup">
-                    <p class="title mt25 title-bg">step1. Hello WORLD</p>
-                    <!--
-                    <img class="bg" src="../../../../resources/img/img39_s.png" data-num="1" />
-                    -->
-                    <img class="bg" :src="img_src" />
+                <p class="title mt25 title-bg">step1. Hello WORLD</p>
+                <div class="flex align-center ml50 mb15" style="margin-top: -30px; gap: 10px">
+                    <h4>지문을 집중해서 듣고 읽어보세요</h4>
+                    <div class="listen-btn">
+                        <img src="../../../../resources/img/btn10_s.png" alt="" @click="generateTts('male')" />
+                        <audio id="tts-audio-player" preload="auto"></audio>
+                    </div>
+                </div>
+                <div class="flex listen-box">
+                    <div class="listenGroup">
+                        <p>{{ text_ttl }}</p>
+                        <div class="listen-cnt" v-for="(line, index) in text_cnt_list" :key="index">
+                            {{ line }}
+                        </div>
+                    </div>
                 </div>
             </div>
             <div class="next-btn" @click="goToNextPage">
                 <img src="../../../../resources/img/right.png" alt="" />
             </div>
         </div>
-        <TextToImage />
     </div>
 </template>
 
@@ -42,6 +53,9 @@
     data() {
         return {
             text_data: null,
+            text_ttl: null,
+            text_cnt: null, // 지문 내용
+            text_cnt_list: [],
             img_src: null,
             seq: this.$store.getters.seqNum,
         };
@@ -58,8 +72,9 @@
             this.$router.push({ name: page });
         },
         goToNextPage() {
-            alert('지문 학습 완료!');
-            this.complete();
+            this.goToPage('Chapter5');
+            // alert('지문 학습 완료!');
+            // this.complete();
         },
         // 지문 API
         async fetchText() {
@@ -70,11 +85,15 @@
                     'Content-Type': 'application/json; charset=UTF-8',
                 },
                 data: {
-                    textId: this.textId,
+                    // textId: this.textId,
+                    textId: 'TEXT_000000000005004',
                 },
             })
                 .then((response) => {
                     this.text_data = response.data[0];
+                    this.text_ttl = response.data[0].text_ttl;
+                    this.text_cnt = response.data[0].text_cnt;
+                    this.text_cnt_list = this.text_cnt.split('/').filter((text) => text.trim() !== '');
                     console.log('지문 데이터 : ', this.text_data);
                     this.img_src = this.fetchImage(this.text_data.file_rpath);
                 })
@@ -85,6 +104,32 @@
         // 이미지 불러오기
         fetchImage(fileRpath) {
             return 'http://165.229.169.113:9080/' + fileRpath;
+        },
+        // 대화 지문 재생
+        generateTts(gender) {
+            axios({
+                url: 'http://165.229.169.32:35716/generate_tts',
+                method: 'post',
+                headers: {
+                    'Content-Type': 'application/json; charset=UTF-8',
+                },
+                responseType: 'blob',
+                data: {
+                    gender: gender,
+                    input_text: this.text_cnt,
+                },
+            })
+                .then((response) => {
+                    console.log('tts 응답 : ', response);
+                    const audioBlob = new Blob([response.data], { type: 'audio/mpeg' });
+                    const audioUrl = URL.createObjectURL(audioBlob); // 오디오 url 생성
+                    const audioPlayer = document.getElementById('tts-audio-player');
+                    audioPlayer.src = audioUrl;
+                    audioPlayer.play();
+                })
+                .catch((err) => {
+                    console.log('tts 에러 : ', err);
+                });
         },
     },
     watch: {},
@@ -115,4 +160,27 @@
     font-size: 28px;
     font-family: 'ONEMobilePOPOTF';
 }
+
+.listen-box {
+    gap: 50px;
+    width: 1282px;
+    height: 500px;
+    overflow: scroll;
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+
+.listenGroup {
+    margin-left: 5rem;
+}
+
+.listenGroup p {
+    font-size: 40px;
+    font-weight: bold;
+}
+
+.listen-cnt {
+    font-size: 24px;
+    margin-top: 30px;
+}
 </style>
client/views/pages/main/Chapter/Chapter5.vue
--- client/views/pages/main/Chapter/Chapter5.vue
+++ client/views/pages/main/Chapter/Chapter5.vue
@@ -1,0 +1,345 @@
+<template>
+    <div id="Chapter1" class="content-wrap">
+        <div style="margin: 30px 0px 50px; width: 20%">
+            <router-link to="/MyPlan.page">
+                <div class="logo mb25">
+                    <img src="../../../../resources/img/new_img/logo_v2.png" alt="" />
+                </div>
+            </router-link>
+        </div>
+        <div class="title-box mb25 flex align-center mt40" style="justify-content: space-between">
+            <div>
+                <span class="title mr40">1. Hello WORLD</span>
+                <span class="subtitle">my name is dd</span>
+            </div>
+            <div class="flex">
+                <TextToImage />
+                <button class="completeBtn" @click="complete">학습 종료</button>
+            </div>
+        </div>
+        <div class="flex justify-between align-center">
+            <div class="pre-btn" @click="goToPage('Chapter1_3')">
+                <img src="../../../../resources/img/left.png" alt="" />
+            </div>
+            <div class="content title-box">
+                <p class="title mt25 title-bg">step1. Hello WORLD</p>
+                <div class="flex align-center ml50 mb15" style="margin-top: -30px; gap: 10px">
+                    <h4>지문을 집중해서 듣고 읽어보세요</h4>
+                    <div class="listen-btn">
+                        <img src="../../../../resources/img/btn10_s.png" alt="" @click="generateTts('male')" />
+                        <audio id="tts-audio-player" preload="auto"></audio>
+                    </div>
+                </div>
+                <div class="flex listen-box">
+                    <div class="listenGroup">
+                        <p>{{ text_ttl }}</p>
+                        <div class="listen-cnt" v-for="(line, index) in text_cnt_list" :key="index">
+                            <p @click="handleSelectLine(line)" :style="getStyle(line)">{{ line }}</p>
+                        </div>
+                    </div>
+                    <div class="button-box mr50">
+                        <button class="word" @click="wordQuestion">단어 설명</button>
+                        <button class="passage" @click="passageQuestion">문장 설명</button>
+                    </div>
+                </div>
+            </div>
+            <div class="next-btn" @click="goToNextPage">
+                <img src="../../../../resources/img/right.png" alt="" />
+            </div>
+        </div>
+        <div class="popup-wrap" v-if="popupOpen">
+            <div class="popup-container flex-column">
+                <div class="popup-header flex align-center">
+                    <p>선생님의 한 마디</p>
+                    <img
+                        class="look-btn"
+                        @click="handlePopupClose"
+                        src="../../../../resources/img/btn25_93t_normal.png"
+                        alt=""
+                    />
+                </div>
+                <div>
+                    <p class="popup-content mt30" v-html="formattedExplanation"></p>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import TextToImage from '../../../component/TextToImage.vue';
+import axios from 'axios';
+export default {
+    data() {
+        return {
+            text_data: null,
+            text_ttl: null,
+            text_cnt: null, // 지문 내용
+            text_cnt_list: [],
+            img_src: null,
+            seq: this.$store.getters.seqNum,
+
+            popupOpen: false,
+            selectedLine: null, // 선택한 지문
+            explanation_response: null, // 설명 응답
+        };
+    },
+    methods: {
+        complete() {
+            const { unit_id, book_id } = this.$route.query;
+            this.$router.push({
+                name: 'Dashboard',
+                query: { value: this.seq, unit_id, book_id },
+            });
+        },
+        goToPage(page) {
+            this.$router.push({ name: page });
+        },
+        goToNextPage() {
+            // this.goToPage('Chapter5');
+            alert('지문 학습 완료!');
+            this.complete();
+        },
+        // 지문 API
+        async fetchText() {
+            axios({
+                url: '/text/selectOneText.json',
+                method: 'post',
+                headers: {
+                    'Content-Type': 'application/json; charset=UTF-8',
+                },
+                data: {
+                    // textId: this.textId,
+                    textId: 'TEXT_000000000005004',
+                },
+            })
+                .then((response) => {
+                    this.text_data = response.data[0];
+                    this.text_ttl = response.data[0].text_ttl;
+                    this.text_cnt = response.data[0].text_cnt;
+                    this.text_cnt_list = this.text_cnt.split('/').filter((text) => text.trim() !== '');
+                    console.log('지문 데이터 : ', this.text_data);
+                    this.img_src = this.fetchImage(this.text_data.file_rpath);
+                })
+                .catch((err) => {
+                    console.log('지문 에러 : ', err);
+                });
+        },
+        // 이미지 불러오기
+        fetchImage(fileRpath) {
+            return 'http://165.229.169.113:9080/' + fileRpath;
+        },
+        // 대화 지문 재생
+        generateTts(gender) {
+            axios({
+                url: 'http://165.229.169.32:35716/generate_tts',
+                method: 'post',
+                headers: {
+                    'Content-Type': 'application/json; charset=UTF-8',
+                },
+                responseType: 'blob',
+                data: {
+                    gender: gender,
+                    input_text: this.text_cnt,
+                },
+            })
+                .then((response) => {
+                    console.log('tts 응답 : ', response);
+                    const audioBlob = new Blob([response.data], { type: 'audio/mpeg' });
+                    const audioUrl = URL.createObjectURL(audioBlob); // 오디오 url 생성
+                    const audioPlayer = document.getElementById('tts-audio-player');
+                    audioPlayer.src = audioUrl;
+                    audioPlayer.play();
+                })
+                .catch((err) => {
+                    console.log('tts 에러 : ', err);
+                });
+        },
+        // 검색할 지문 선택
+        handleSelectLine(line) {
+            this.selectedLine = line;
+            console.log('선택된 지문 : ', this.selectedLine);
+        },
+        // 단어 설명
+        wordQuestion() {
+            console.log('line : ', this.selectedLine);
+            if (this.selectedLine === null) {
+                alert('궁금한 대화문을 선택해주세요');
+                return;
+            }
+            axios({
+                url: 'http://165.229.169.32:35716/word_question',
+                method: 'post',
+                headers: {
+                    'Content-Type': 'application/json; charset=UTF-8',
+                },
+                data: {
+                    word: this.selectedLine,
+                },
+            })
+                .then((response) => {
+                    // console.log('word 지문 응답 : ', response.data.explanation);
+                    this.explanation_response = response.data.explanation;
+                    this.handlePopupOpen();
+                })
+                .catch((err) => {
+                    console.log('word 지문 에러 : ', err);
+                });
+        },
+
+        // 지문 설명
+        passageQuestion() {
+            console.log('line : ', this.selectedLine);
+            if (this.selectedLine === null) {
+                alert('궁금한 대화문을 선택해주세요');
+                return;
+            }
+            axios({
+                url: 'http://165.229.169.32:35716/passage_question',
+                method: 'post',
+                headers: {
+                    'Content-Type': 'application/json; charset=UTF-8',
+                },
+                data: {
+                    passage: this.selectedLine,
+                },
+            })
+                .then((response) => {
+                    // console.log('passage 지문 응답 : ', response.data.explanation);
+                    this.explanation_response = response.data.explanation;
+                    this.handlePopupOpen();
+                })
+                .catch((err) => {
+                    console.log('passage 지문 에러 : ', err);
+                });
+        },
+        /* 팝업 */
+        handlePopupOpen() {
+            this.popupOpen = true;
+        },
+
+        handlePopupClose() {
+            this.popupOpen = false;
+            this.explanation_response = null;
+            this.selectedLine = null;
+        },
+        getStyle(line) {
+            return {
+                backgroundColor: this.selectedLine === line ? '#ffc980' : '',
+                fontSize: this.selectedLine === line ? '40px' : '',
+                boxShadow: this.selectedLine === line ? 'rgba(0, 0, 0, 0.24) 0px 3px 8px' : '',
+                fontWeight: this.selectedLine === line ? 'bold' : '',
+                cursor: 'pointer',
+            };
+        },
+    },
+    watch: {},
+    computed: {
+        textId() {
+            //console.log("지문 화면 아이디 : ", this.$store.getters.getTextId);
+            return this.$store.getters.getTextId;
+        },
+        // 지문 포맷팅
+        formattedExplanation() {
+            return this.explanation_response.replace(/\n/g, '<br>').replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
+        },
+    },
+    components: {
+        TextToImage: TextToImage,
+    },
+    mounted() {
+        this.fetchText();
+    },
+};
+</script>
+<style scoped>
+.listenGroup .textbox {
+    width: 900px;
+}
+
+.completeBtn {
+    margin-right: 100px;
+    background-color: #ffba08;
+    padding: 10px 30px;
+    border-radius: 10px;
+    font-size: 28px;
+    font-family: 'ONEMobilePOPOTF';
+}
+
+.listen-box {
+    gap: 50px;
+    justify-content: space-between;
+    height: 500px;
+}
+
+.listenGroup {
+    margin-left: 5rem;
+    width: 1282px;
+    overflow: scroll;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding: 0px 20px 0px 0px;
+}
+
+.listenGroup p {
+    font-size: 40px;
+    font-weight: bold;
+}
+
+.listen-cnt p {
+    font-size: 24px;
+    margin-top: 30px;
+    font-weight: normal;
+}
+
+.button-box {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-evenly;
+}
+
+.button-box button {
+    font-family: 'ONEMobilePOPOTF';
+    font-size: 25px;
+    color: #fff;
+    padding: 20px 70px;
+    border-radius: 15px;
+    box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
+}
+.word {
+    background-color: #28b863;
+}
+
+.passage {
+    background-color: #9528b7;
+}
+
+.popup-container {
+    background-color: #fff;
+    position: absolute;
+    width: 120rem;
+    height: 60rem;
+    padding: 30px;
+    border-radius: 10px;
+    top: 25rem;
+    left: 40rem;
+    overflow: scroll;
+    overflow-x: hidden;
+}
+
+.popup-header {
+    justify-content: space-between;
+}
+
+.popup-header p {
+    font-size: 30px;
+    font-family: 'ONEMobilePOPOTF';
+    color: #6327b9;
+}
+
+.popup-content {
+    font-size: 24px;
+    padding: 20px;
+}
+</style>
client/views/pages/main/Main_c.vue
--- client/views/pages/main/Main_c.vue
+++ client/views/pages/main/Main_c.vue
@@ -4,7 +4,7 @@
         <router-view></router-view>
 
         <!-- Footer that re-renders on route change -->
-        <FooterComponent :key="$route.fullPath" />
+        <!-- <FooterComponent :key="$route.fullPath" /> -->
     </div>
 </template>
 
Add a comment
List