jichoi / lms_front star
이은진 이은진 08-14
240814 이은진 단어장 1차 수정
@0dcca4f96e2bc04c7b07d0dc3a07884cf72cfd47
client/views/pages/AppRouter.js
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
@@ -116,6 +116,11 @@
                 name: "Dashboard",
                 component: Dashboard,
             },
+            {
+                path: "/AIDashboard.page",
+                name: "AIDashboard",
+                component: AIDashboard,
+            },
             { path: "/MyPage.page", name: "MyPage", component: MyPage },
             { path: "/MyPlan.page", name: "MyPlan", component: MyPlan },
             { path: "/MyPlan2.page", name: "MyPlan2", component: MyPlan2 },
client/views/pages/main/Chapter/Chapter2.vue
--- client/views/pages/main/Chapter/Chapter2.vue
+++ client/views/pages/main/Chapter/Chapter2.vue
@@ -1,115 +1,109 @@
 <template>
-    <div id="Chapter1_1" class="content-wrap">
-      <div style="margin: 30px 0px 50px">
-        <router-link to="/MyPlan.page">
-          <div class="logo mb25"><img src="../../../../resources/img/logo2.png" alt=""></div>
-        </router-link>
-      </div>
-      <div class="title-box mb25 flex align-center mt40">
-        <span class="title mr40">1. Hello WORLD</span>
-        <span class="subtitle">my name is dd</span>
-      </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">step2</p>
-          <div class="flex align-center mb30">
+  <div id="Chapter1_1" class="content-wrap">
+    <div style="margin: 30px 0px 50px">
+      <router-link to="/MyPlan.page">
+        <div class="logo mb25"><img src="../../../../resources/img/logo2.png" alt=""></div>
+      </router-link>
+    </div>
+    <div class="title-box mb25 flex align-center mt40">
+      <span class="title mr40">1. Hello WORLD</span>
+      <span class="subtitle">my name is dd</span>
+    </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">단어로 공부하는 영어</p>
+        <div class="flex align-center mb30">
           <p class="subtitle2 mr20"></p>
           <!-- <button><img src="../../../../resources/img/btn10_s.png" alt="">
           </button> -->
         </div>
-  
-          <div class="flex justify-center">
-              <div class="vocaGroup">
-                <div class="flex justify-between mb80">
-                    <article class="flex align-center">
-                        <div class="imgGroup mr30"><img src="../../../../resources/img/img40_s.png" data-num="1"></div>
-                        <div class="flex align-start">
-                            <button class="listen-btn mr30" data-video="1" tabindex="0" aria-label="음성 재생"><img src="../../../../resources/img/btn10_s.png"
-                                data-num="1"></button>
-                           <div>
-                                <h3>sidewalk</h3>
-                                   <div class="flex align-center mt10">
-                                      <p class="yellow-box">명</p>
-                                      <span class="title1">보도</span>
-                                   </div>
-                           </div>
-                        </div>
-                    </article>
-                    <article class="flex align-center">
-                        <div class="imgGroup mr30"><img src="../../../../resources/img/31img40_s.png" data-num="1"></div>
-                        <div class="flex align-start">
-                            <button class="listen-btn mr30" data-video="1" tabindex="0" aria-label="음성 재생"><img src="../../../../resources/img/btn10_s.png"
-                                data-num="1"></button>
-                           <div>
-                                <h3>sidewalk</h3>
-                                   <div class="flex align-center mt10">
-                                      <p class="yellow-box">명</p>
-                                      <span class="title1">보도</span>
-                                   </div>
-                           </div>
-                        </div>
-                    </article>
-                </div>
-                <div class="flex justify-between">
-                    <article class="flex align-center">
-                        <div class="imgGroup mr30"><img src="../../../../resources/img/img41_s.png" data-num="1"></div>
-                        <div class="flex align-start">
-                            <button class="listen-btn mr30" data-video="1" tabindex="0" aria-label="음성 재생"><img src="../../../../resources/img/btn10_s.png"
-                                data-num="1"></button>
-                           <div>
-                                <h3>sidewalk</h3>
-                                   <div class="flex align-center mt10">
-                                      <p class="yellow-box">명</p>
-                                      <span class="title1">보도</span>
-                                   </div>
-                           </div>
-                        </div>
-                    </article>
-                    <article class="flex align-center">
-                        <div class="imgGroup mr30"><img src="../../../../resources/img/img40_s.png" data-num="1"></div>
-                        <div class="flex align-start">
-                            <button class="listen-btn mr30" data-video="1" tabindex="0" aria-label="음성 재생"><img src="../../../../resources/img/btn10_s.png"
-                                data-num="1"></button>
-                           <div>
-                                <h3>sidewalk</h3>
-                                   <div class="flex align-center mt10">
-                                      <p class="yellow-box">명</p>
-                                      <span class="title1">보도</span>
-                                   </div>
-                           </div>
-                        </div>
-                    </article>
-                </div>
+
+        <div class="flex justify-center">
+          <div class="vocaGroup">
+            <div class="grid-container">
+              <div v-for="(item, index) in word" :key="index" class="grid-item">
+                <article class="flex align-center">
+                  <div class="imgGroup mr30">
+                    <img :src="item.pic" :alt="item.eng" />
+                  </div>
+                  <div class="flex align-start">
+                    <button class="listen-btn mr30" tabindex="0" aria-label="음성 재생">
+                      <img :src="item.sound" :alt="'Sound for ' + item.eng" />
+                    </button>
+                    <div>
+                      <h3>{{ item.eng }}</h3>
+                      <div class="flex align-center mt10">
+                        <p class="yellow-box">명</p>
+                        <span class="title1">{{ item.kor }}</span>
+                      </div>
+                    </div>
+                  </div>
+                </article>
               </div>
+            </div>
           </div>
         </div>
-        <div class="next-btn" @click="goToPage('Chapter2_3')"><img src="../../../../resources/img/right.png" alt=""></div>
       </div>
+      <div class="next-btn" @click="goToPage('Chapter2_3')"><img src="../../../../resources/img/right.png" alt=""></div>
     </div>
-  </template>
-  
-  <script>
-  export default {
-    data() {
-      return {
-      }
-    },
-    methods: {
-      goToPage(page) {
-        this.$router.push({ name: page });
-      }
-    },
-    watch: {
-  
-    },
-    computed: {
-  
-    },
-    components: {
-    },
-    mounted() {
-      
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      word: [
+        {
+          eng: "apple",
+          kor: "사과",
+          pic: require("../../../../resources/img/img40_s.png").default,
+          sound: require("../../../../resources/img/btn10_s.png").default
+        },
+        {
+          eng: "cloud",
+          kor: "구름",
+          pic: require("../../../../resources/img/img42_31s.png").default,
+          sound: require("../../../../resources/img/btn10_s.png").default
+        },
+        {
+          eng: "log",
+          kor: "통나무",
+          pic: require("../../../../resources/img/31img40_s.png").default,
+          sound: require("../../../../resources/img/btn10_s.png").default
+        },
+        {
+          eng: "guitar",
+          kor: "기타",
+          pic: require("../../../../resources/img/img41_s.png").default,
+          sound: require("../../../../resources/img/btn10_s.png").default
+        }
+      ]
     }
+  },
+  methods: {
+    goToPage(page) {
+      this.$router.push({ name: page });
+    }
+  },
+  watch: {
+
+  },
+  computed: {
+
+  },
+  components: {
+  },
+  mounted() {
+
   }
-  </script>
(파일 끝에 줄바꿈 문자 없음)
+}
+</script>
+<style scoped>
+.grid-container {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 20px;
+}
+</style>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/main/Chapter/Chapter2_2.vue
--- client/views/pages/main/Chapter/Chapter2_2.vue
+++ client/views/pages/main/Chapter/Chapter2_2.vue
@@ -13,11 +13,17 @@
          <div class="pre-btn" @click="goToPage('Chapter2_3')"><img src="../../../../resources/img/left.png" alt="">
          </div>
          <div class="content title-box">
-            <p class="title mt25 title-bg">step2</p>
+            <p class="title mt25 title-bg">단어로 공부하는 영어</p>
             <div class="flex align-center mb30">
                <p class="subtitle2 mr20">카드를 뒤집어 보세요.</p>
                <!-- <button><img src="../../../../resources/img/btn10_s.png" alt="">
-          </button> -->
+          </button> --></div><div class="time-bg">
+            <div>
+              <div class="time">
+                <p class="second">{{timer}}</p>
+                <p class="text">sec</p>
+              </div>
+            </div>
             </div>
 
             <div class="imgGroup">
@@ -36,7 +42,7 @@
                </div>
             </div>
          </div>
-         <div class="next-btn" @click="goToPage('Chapter2_1')"><img src="../../../../resources/img/right.png" alt="">
+         <div class="next-btn" @click="goToPage('Chapter2_9')"><img src="../../../../resources/img/right.png" alt="">
          </div>
       </div>
    </div>
client/views/pages/main/Chapter/Chapter2_3.vue
--- client/views/pages/main/Chapter/Chapter2_3.vue
+++ client/views/pages/main/Chapter/Chapter2_3.vue
@@ -1,71 +1,106 @@
 <template>
-  <div id="Chapter2_2" class="content-wrap">
+   <div id="Chapter2_2" class="content-wrap">
       <div style="margin: 30px 0px 50px">
          <router-link to="/MyPlan.page">
             <div class="logo mb25"><img src="../../../../resources/img/logo2.png" alt=""></div>
          </router-link>
       </div>
-     <div class="title-box mb25 flex align-center mt40">
-        <span class="title mr40">1. Hello WORLD</span>
-        <span class="subtitle">my name is dd</span>
-     </div>
-     <div class="flex justify-between align-center">
-        <div class="pre-btn" @click="goToPage('Chapter2')"><img src="../../../../resources/img/left.png" alt=""></div>
-        <div class="content title-box">
-           <p class="subtitle2 "></p><p class="title mt25 title-bg">step2</p>
-          <div class="flex align-center mb30">
-          <p class="subtitle2 mr20">다음을 듣고 따라 말하세요.</p>
-          <!-- <button><img src="../../../../resources/img/btn10_s.png" alt="">
+      <div class="title-box mb25 flex align-center mt40">
+         <span class="title mr40">1. Hello WORLD</span>
+         <span class="subtitle">my name is dd</span>
+      </div>
+      <div class="flex justify-between align-center">
+         <div class="pre-btn" @click="goToPage('Chapter2')"><img src="../../../../resources/img/left.png" alt=""></div>
+         <div class="content title-box">
+            <p class="subtitle2 "></p>
+            <p class="title mt25 title-bg">단어로 공부하는 영어</p>
+            <div class="flex align-center mb30">
+               <p class="subtitle2 mr20">다음을 듣고 따라 말하세요.</p>
+               <!-- <button><img src="../../../../resources/img/btn10_s.png" alt="">
           </button> -->
-        </div><div class="time-bg">
-            <div>
-              <div class="time">
-                <p class="second">{{timer}}</p>
-                <p class="text">sec</p>
-              </div>
             </div>
-           </div>
 
-           <div class="imgGroup">
-             <div class="con">
-               <img :src="currentCon.imgSrc" alt="">
-               <p class="title3"><em class="yellow">{{ currentCon.titleEm }}</em>{{ currentCon.title }}</p>
-               <div class="flex align-center justify-center mt10">
-                  <p class="yellow-box-big">{{ currentCon.boxText }}</p>
-                  <span class="subtitle3">{{ currentCon.subtitle }}</span>
+            <div class="imgGroup">
+               <div class="con">
+                  <img :src="currentCon.imgSrc" alt="">
+                  <p class="title3"><em class="yellow">{{ currentCon.titleEm }}</em>{{ currentCon.title }}</p>
+                  <div class="flex align-center justify-center mt10">
+                     <p class="yellow-box-big">{{ currentCon.boxText }}</p>
+                     <span class="subtitle3">{{ currentCon.subtitle }}</span>
+                  </div>
+               </div>
+
+
+               <div class="flex justify-center">
+                  <div class="readGroup">
+                      <section>
+                          <div class="imgGroup flex justify-center">
+                              <!-- 녹음 버튼 -->
+                              <div :class="['mic-btn', { notRecording: !isRecording }]" @click="toggleRecording">
+                                  <img src="../../../../resources/img/btn11_s.png" alt="" />
+                              </div>
+                          </div>
+                          <article>
+                              <p class="speakText mb25">
+                                  <span v-if="transcription === null"
+                                      >위의 버튼을 누른 후 오늘 배운 단어를 말해보세요!</span
+                                  >
+                                  <span v-else-if="!transcription || transcription.trim() === ''"
+                                      >다시 말해보세요!</span
+                                  >
+                                  <span v-else>{{ transcription }}</span>
+                              </p>
+                              <p class="read-ai">
+                                  <img style="margin-top: -5px" src="../../../../resources/img/img43_s.png" alt="" />
+                              </p>
+                          </article>
+                      </section>
+                  </div>
+              </div>
+               <div class="flex justify-center">
+                  <div class="btnGroup mt50 flex justify-between">
+                     <button class="popTxt" v-for="(item, index) in items" :key="index" @click="updateContent(index)"
+                        :class="{ active: selectedIndex === index }">
+                        <img :src="item.imgSrc1">
+                        <img :src="item.imgSrc2" v-if="selectedIndex === index" style="display: block;">
+                     </button>
+                  </div>
                </div>
             </div>
-
-            <div class="flex justify-center">
-              <div class="btnGroup mt50 flex justify-between">
-                    <button class="popTxt" v-for="(item, index) in items" :key="index" @click="updateContent(index)" :class="{ active: selectedIndex === index }">
-                       <img :src="item.imgSrc1" >
-                       <img :src="item.imgSrc2" v-if="selectedIndex === index" style="display: block;">
-                    </button>
-              </div>
-            </div>
-           </div>
-        </div>
-        <div class="next-btn" @click="goToPage('Chapter2_2')"><img src="../../../../resources/img/right.png" alt=""></div>
-     </div>
-  </div>
+         </div>
+         <div class="next-btn" @click="goToPage('Chapter2_2')"><img src="../../../../resources/img/right.png" alt="">
+         </div>
+      </div>
+   </div>
 </template>
 
 <script>
+import axios from 'axios'; 
+import { mdiStop } from '@mdi/js';
 export default {
    data() {
       return {
          items: [
             {imgSrc1: 'client/resources/img/img53_6_35s.png', imgSrc2: 'client/resources/img/img53_1_35s.png', con: { imgSrc: 'client/resources/img/img54_s.png', titleEm: 'c', title: 'loud', boxText: '명', subtitle: '구름' } },
-            {imgSrc1: 'client/resources/img/img53_7_35s.png', imgSrc2: 'client/resources/img/img53_2_35s.png', con: { imgSrc: 'client/resources/img/img54_s.png', titleEm: 's', title: 'un', boxText: '명', subtitle: '태양' } },
-            {imgSrc1: 'client/resources/img/img53_8_35s.png', imgSrc2: 'client/resources/img/img53_3_35s.png', con: { imgSrc: 'client/resources/img/img54_s.png', titleEm: 'r', title: 'ain', boxText: '명', subtitle: '비' } },
-            {imgSrc1: 'client/resources/img/img53_9_35s.png', imgSrc2: 'client/resources/img/img53_4_35s.png', con: { imgSrc: 'client/resources/img/img54_s.png', titleEm: 's', title: 'now', boxText: '명', subtitle: '눈' } },
-            {imgSrc1: 'client/resources/img/img53_10_35s.png', imgSrc2: 'client/resources/img/img53_5_35s.png', con: { imgSrc: 'client/resources/img/img54_s.png', titleEm: 'w', title: 'ind', boxText: '명', subtitle: '바람' } }
+            {imgSrc1: 'client/resources/img/img53_7_35s.png', imgSrc2: 'client/resources/img/img53_2_35s.png', con: { imgSrc: 'client/resources/img/img40_s.png', titleEm: 'a', title: 'pple', boxText: '명', subtitle: '사과' } },
+            {imgSrc1: 'client/resources/img/img53_8_35s.png', imgSrc2: 'client/resources/img/img53_3_35s.png', con: { imgSrc: 'client/resources/img/31img40_s.png', titleEm: 'l', title: 'og', boxText: '명', subtitle: '통나무' } },
+            {imgSrc1: 'client/resources/img/img53_9_35s.png', imgSrc2: 'client/resources/img/img53_4_35s.png', con: { imgSrc: 'client/resources/img/img41_s.png', titleEm: 'g', title: 'uitar', boxText: '명', subtitle: '기타' } },
+            {imgSrc1: 'client/resources/img/img53_10_35s.png', imgSrc2: 'client/resources/img/img53_5_35s.png', con: { imgSrc: 'client/resources/img/img76_41s.png', titleEm: 'w', title: 'ater melon', boxText: '명', subtitle: '수박' } }
          ],
          currentCon: { imgSrc: 'client/resources/img/img54_s.png', titleEm: 'c', title: 'loud', boxText: '명', subtitle: '구름' },
          selectedIndex: 0,
          timer: "00",
          intervalId: null,
+
+
+         isRecording: false, // 녹음 중 여부
+         mediaRecorder: null,
+         audioChunks: [], // 녹음된 오디오 데이터
+         audioBlob: null, // 오디오 Blob 객체
+         transcription: null, // 서버에서 받아온 텍스트 결과
+         stream: null, // MediaStream 객체
+
+         path: mdiStop,
       };
    },
    methods: {
@@ -89,7 +124,67 @@
                clearInterval(this.intervalId);
             }
          }, 1000);
-      }
+      },
+      // 녹음 시작/중지 토글
+      async toggleRecording() {
+          if (this.isRecording) {
+              console.log('녹음 그만!');
+              this.stopRecording(); // 녹음 중이면 중지
+          } else {
+              console.log('녹음 시작!');
+              await this.startRecording(); // 녹음 중이 아니면 녹음 시작
+          }
+      },
+      // 녹음 시작
+      async startRecording() {
+          this.audioChunks = []; // 오디오 초기화
+          this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
+          this.mediaRecorder = new MediaRecorder(this.stream);
+          this.mediaRecorder.ondataavailable = (event) => {
+              this.audioChunks.push(event.data); // 녹음 데이터 저장
+          };
+          this.mediaRecorder.onstop = () => {
+              this.audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
+
+              /******************************/
+              // this.audioURL = URL.createObjectURL(this.audioBlob); // 오디오 URL 생성
+              // console.log('Audio URL:', this.audioURL);
+              /******************************/
+
+              console.log('Recorded Audio Blob:', this.audioBlob); // 콘솔에 Blob 확인
+              this.sendAudioToServer(); // 서버로 오디오 전송
+          };
+          this.mediaRecorder.start(); // 녹음 시작
+          this.isRecording = true; // 녹음 상태 변경
+      },
+
+      // 녹음 중지
+      stopRecording() {
+          this.mediaRecorder.stop(); // 녹음 중단
+
+          if (this.stream) {
+              this.stream.getTracks().forEach((track) => track.stop()); // 스트림의 모든 트랙 중지
+          }
+
+          this.isRecording = false; // 녹음 상태 변경
+      },
+
+      // 오디오 전송
+      async sendAudioToServer() {
+          const formData = new FormData();
+          formData.append('file', this.audioBlob, 'recording.wav');
+          try {
+              const resposne = await axios.post('/api/speechToText.json', formData, {
+                  headers: {
+                      'Content-Type': 'multipart/form-data',
+                  },
+              });
+              this.transcription = resposne.data;
+              console.log(`받은 데이터 : ${this.transcription}`);
+          } catch (error) {
+              console.log('파일 전송 실패 : ', error);
+          }
+      },
    },
    beforeDestroy() {
       if (this.intervalId) {
client/views/pages/main/Chapter/Chapter2_4.vue
--- client/views/pages/main/Chapter/Chapter2_4.vue
+++ client/views/pages/main/Chapter/Chapter2_4.vue
@@ -10,7 +10,7 @@
          <span class="subtitle">my name is dd</span>
       </div>
       <div class="flex justify-between align-center">
-         <div class="pre-btn" @click="goToPage('Chapter2_1')"><img src="../../../../resources/img/left.png" alt="">
+         <div class="pre-btn" @click="goToPage('Chapter2_9')"><img src="../../../../resources/img/left.png" alt="">
          </div>
          <div class="content title-box">
             <p class="title mt25 title-bg">step2</p>
@@ -42,7 +42,7 @@
                <div class="look-text"> <button ><img src="../../../../resources/img/btn08_s.png" alt=""><p>정답확인</p></button></div>
             </div>
          </div>
-         <div class="next-btn" @click="goToPage('Chapter2_9')"><img src="../../../../resources/img/right.png" alt="">
+         <div class="next-btn" @click="goToPage('Chapter2_8')"><img src="../../../../resources/img/right.png" alt="">
          </div>
       </div>
    </div>
client/views/pages/main/Chapter/Chapter2_9.vue
--- client/views/pages/main/Chapter/Chapter2_9.vue
+++ client/views/pages/main/Chapter/Chapter2_9.vue
@@ -10,7 +10,7 @@
       <span class="subtitle">my name is dd</span>
     </div>
     <div class="flex justify-between align-center">
-      <div class="pre-btn" @click="goToPage('Chapter2_4')"><img src="../../../../resources/img/left.png" alt=""></div>
+      <div class="pre-btn" @click="goToPage('Chapter2_2')"><img src="../../../../resources/img/left.png" alt=""></div>
       <div class="content title-box">
         <p class="title mt25 title-bg">step2</p>
         <div class="flex align-center mb30">
@@ -106,7 +106,7 @@
           </div>
         </div>
       </div>
-      <div class="next-btn" @click="goToPage('Chapter2_8')"><img src="../../../../resources/img/right.png" alt=""></div>
+      <div class="next-btn" @click="goToPage('Chapter2_4')"><img src="../../../../resources/img/right.png" alt=""></div>
     </div>
   </div>
 </template>
Add a comment
List