Переглянути джерело

Merge branch 'master' into gcj

guanchunjie 3 роки тому
батько
коміт
b925ffe5d0
38 змінених файлів з 1230 додано та 313 видалено
  1. BIN
      src/assets/icon/EN-14-disable-Black.png
  2. BIN
      src/assets/icon/EN-14-normal-Black.png
  3. BIN
      src/assets/icon/EN-14-normal-Blue.png
  4. BIN
      src/assets/icon/EN-14-normal-Brown.png
  5. BIN
      src/assets/icon/EN-14-normal-Green.png
  6. BIN
      src/assets/icon/EN-14-normal-Orange.png
  7. BIN
      src/assets/icon/EN-14-normal-Purple.png
  8. BIN
      src/assets/icon/EN-14-normal-White.png
  9. BIN
      src/assets/icon/EN-14-normal-red.png
  10. BIN
      src/assets/icon/EN-16-disable-Black.png
  11. BIN
      src/assets/icon/EN-16-normal-Black.png
  12. BIN
      src/assets/icon/EN-16-normal-Blue.png
  13. BIN
      src/assets/icon/EN-16-normal-Brown.png
  14. BIN
      src/assets/icon/EN-16-normal-Green.png
  15. BIN
      src/assets/icon/EN-16-normal-Orange.png
  16. BIN
      src/assets/icon/EN-16-normal-Purple.png
  17. BIN
      src/assets/icon/EN-16-normal-White.png
  18. BIN
      src/assets/icon/EN-16-normal-red.png
  19. 93 64
      src/components/Adult/Preview.vue
  20. 10 0
      src/components/Adult/common/NewordPhraseModule.vue
  21. 1 1
      src/components/Adult/common/UploadView.vue
  22. 4 0
      src/components/Adult/common/data.js
  23. 8 0
      src/components/Adult/inputModules/Neword.vue
  24. 16 4
      src/components/Adult/inputModules/PurePreview.vue
  25. 273 0
      src/components/Adult/inputModules/ToneSelect.vue
  26. 172 0
      src/components/Adult/inputModules/UploadPdf.vue
  27. 72 0
      src/components/Adult/preview/ArticleViewChs/NormalModelChs.vue
  28. 59 0
      src/components/Adult/preview/ArticleViewChs/Practicechs.vue
  29. 11 2
      src/components/Adult/preview/DialogueArticleViewChs/Practicechs.vue
  30. 2 1
      src/components/Adult/preview/InputHasRecord.vue
  31. 78 62
      src/components/Adult/preview/NewWordShow.vue
  32. 2 2
      src/components/Adult/preview/Notes.vue
  33. 81 0
      src/components/Adult/preview/PdfView.vue
  34. 181 84
      src/components/Adult/preview/SelectTone.vue
  35. 6 2
      src/components/Adult/preview/WordPhrase.vue
  36. 2 2
      src/components/Adult/preview/components/Practice.vue
  37. 91 69
      src/styles/index.scss
  38. 68 20
      src/views/adultInput.vue

BIN
src/assets/icon/EN-14-disable-Black.png


BIN
src/assets/icon/EN-14-normal-Black.png


BIN
src/assets/icon/EN-14-normal-Blue.png


BIN
src/assets/icon/EN-14-normal-Brown.png


BIN
src/assets/icon/EN-14-normal-Green.png


BIN
src/assets/icon/EN-14-normal-Orange.png


BIN
src/assets/icon/EN-14-normal-Purple.png


BIN
src/assets/icon/EN-14-normal-White.png


BIN
src/assets/icon/EN-14-normal-red.png


BIN
src/assets/icon/EN-16-disable-Black.png


BIN
src/assets/icon/EN-16-normal-Black.png


BIN
src/assets/icon/EN-16-normal-Blue.png


BIN
src/assets/icon/EN-16-normal-Brown.png


BIN
src/assets/icon/EN-16-normal-Green.png


BIN
src/assets/icon/EN-16-normal-Orange.png


BIN
src/assets/icon/EN-16-normal-Purple.png


BIN
src/assets/icon/EN-16-normal-White.png


BIN
src/assets/icon/EN-16-normal-red.png


+ 93 - 64
src/components/Adult/Preview.vue

@@ -13,30 +13,30 @@
           :key="index"
           class="NNPE-title-item"
         >
-          <template v-if="item.wordsList.length == 0">
+          <template v-if="item.detail.wordsList.length == 0">
             <p
-              v-if="item.sentence"
+              v-if="item.detail.sentence"
               :class="[
                 'content-con',
-                /^[\u4e00-\u9fa5]/.test(item.sentence) ? 'hasCn' : '',
+                /^[\u4e00-\u9fa5]/.test(item.detail.sentence) ? 'hasCn' : '',
               ]"
+              v-html="item.detail.sentence"
             >
-              {{ item.sentence }}
             </p>
           </template>
           <template v-else>
             <div class="con-box">
               <div
-                v-for="(itemCon, indexCon) in item.resArr"
+                v-for="(itemCon, indexCon) in item.detail.resArr"
                 v-show="itemCon.isShow"
                 :key="indexCon"
                 :class="['con-item', indexCon === 0 ? 'con-item-0' : '']"
               >
                 <template
                   v-if="
-                    item.wordsList[indexCon + 1] &&
-                    item.wordsList[indexCon + 1].chs &&
-                    chsFhList.indexOf(item.wordsList[indexCon + 1].chs) > -1
+                    item.detail.wordsList[indexCon + 1] &&
+                    item.detail.wordsList[indexCon + 1].chs &&
+                    chsFhList.indexOf(item.detail.wordsList[indexCon + 1].chs) > -1
                   "
                 >
                   <div class="synthesis-box">
@@ -55,15 +55,15 @@
                         class="pinyin"
                         :class="[
                           noFont.indexOf(
-                            items.detail.wordsList[indexCon + 1].pinyin
+                            item.detail.wordsList[indexCon + 1].pinyin
                           ) > -1
                             ? 'noFont'
                             : '',
                         ]"
-                        >{{ item.wordsList[indexCon + 1].pinyin }}</span
+                        >{{ item.detail.wordsList[indexCon + 1].pinyin }}</span
                       >
                       <span class="hanzi content-con">{{
-                        item.wordsList[indexCon + 1].chs
+                        item.detail.wordsList[indexCon + 1].chs
                       }}</span>
                     </div>
                   </div>
@@ -81,6 +81,7 @@
               </div>
             </div>
           </template>
+          <p class="NNPE-title-item-en" v-html="item.en"></p>
         </div>
       </div>
       <div class="NNPE-operate" v-if="isShowTitle">
@@ -104,11 +105,13 @@
     </div>
     <div v-if="cur" class="NNPE-Book-content-inner">
       <div v-for="(item, index) in cur.cur_fn_data" :key="index">
-        <h2 v-if="item.z_title || item.number">
-          <b v-if="item.number">{{ item.number }}</b
-          >{{ item.z_title }}
-        </h2>
-        <h3 v-if="item.f_title" v-html="item.f_title"></h3>
+        <div class="title-box" v-if="item.number||item.z_title||item.f_title">
+            <b v-if="item.number">{{ item.number }}</b>
+            <div class="title-box-right">
+                <h2 v-if="item.z_title" v-html="item.z_title"></h2>
+                <h3 v-if="item.f_title" v-html="item.f_title" :style="{'marginTop':item.z_title?'8px':'0'}"></h3>
+            </div>
+        </div>
         <div
           :class="['NNPE-tableList', item.is_bg ? 'NNPE-tableList-hasBg' : '']"
         >
@@ -386,6 +389,14 @@
                     v-if="refresh"
                   />
                 </template>
+                <template v-if="itemss.type == 'upload_pdf_chs'">
+                  <PdfView
+                    :cur-que="itemss.data"
+                    :type="itemss.type"
+                    :theme-color="themeColor"
+                    v-if="refresh"
+                  />
+                </template>
               </template>
             </div>
           </div>
@@ -426,6 +437,7 @@ import CourseStart from "./preview/CourseStart.vue"; // 封面
 import Tinydemo from "./preview/TinyModule.vue"; // 富文本
 import VideoControl from "./preview/VideoControl.vue"; // 视频控件
 import TableView from "./preview/TableView.vue"; // 视频控件
+import PdfView from "./preview/PdfView.vue"; // 视频控件
 
 export default {
   name: "Preview",
@@ -460,6 +472,7 @@ export default {
     Tinydemo,
     VideoControl,
     TableView,
+    PdfView,
   },
   props: [
     "context",
@@ -555,7 +568,7 @@ export default {
       let curQue = JSON.parse(JSON.stringify(this.cur));
       curQue.detailList.forEach((dItem, dIndex) => {
         let paraArr = [];
-        dItem.wordsList.forEach((sItem, sIndex) => {
+        dItem.detail.wordsList.forEach((sItem, sIndex) => {
           let obj = {
             pinyin: sItem.pinyin,
             chs: sItem.chs,
@@ -563,7 +576,7 @@ export default {
           };
           paraArr.push(obj);
         });
-        this.$set(_this.cur.detailList[dIndex], "resArr", paraArr);
+        this.$set(_this.cur.detailList[dIndex].detail, "resArr", paraArr);
       });
     },
     initContextData() {
@@ -708,14 +721,14 @@ export default {
     .NNPE-title-left {
       display: flex;
       color: #ffffff;
-      font-size: 20px;
-      line-height: 28px;
-      align-items: flex-end;
+      font-size: 18px;
+      line-height: 18px;
+      align-items: center;
       .NNPE-title-item {
         margin-right: 12px;
       }
       .content-con {
-        margin: 0;
+        margin: 4px 0;
         font-family: "robot";
         &.hasCn,
         &.hanzi {
@@ -724,9 +737,16 @@ export default {
       }
       .content-en {
         font-weight: normal;
-        line-height: 28px;
+        line-height: 18px;
         font-family: "robot";
       }
+      .NNPE-title-item-en{
+          font-weight: normal;
+          line-height: 12px;
+          font-family: "robot";
+          font-size: 12px;
+          margin: 0;
+      }
       .con-box {
         display: flex;
         flex-flow: wrap;
@@ -740,9 +760,9 @@ export default {
         }
         .pinyin {
           font-family: "GB-PINYINOK-B";
-          font-size: 14px;
-          line-height: 22px;
-          height: 22px;
+          font-size: 12px;
+          line-height: 12px;
+          height: 12px;
           &.noFont {
             font-family: initial;
           }
@@ -806,40 +826,45 @@ export default {
     padding: 0 40px;
     > div {
       padding-top: 32px;
-      > h2 {
-        color: #e35454;
-        font-size: 16px;
-        line-height: 150%;
-        font-weight: bold;
-        margin: 0;
-        b {
-          min-width: 48px;
-          height: 24px;
-          background: #e35454;
-          border-radius: 8px;
-          color: #ffffff;
-          font-family: "robot";
-          display: inline-block;
-          text-align: center;
-          font-size: 16px;
-          margin-right: 14px;
-          padding: 0 4px;
+      .title-box{
+          display: flex;
+          margin-bottom: 24px;
+          b {
+            min-width: 39px;
+            height: 24px;
+            background: #e35454;
+            border-radius: 8px;
+            color: #ffffff;
+            font-family: "robot";
+            display: inline-block;
+            text-align: center;
+            font-size: 16px;
+            line-height: 150%;
+            margin-right: 12px;
+            padding: 0 4px;
+          }
+          h2 {
+            color: #e35454;
+            font-size: 16px;
+            line-height: 150%;
+            font-weight: bold;
+            margin: 0;
+        }
+          h3 {
+            color: #000000;
+            font-size: 16px;
+            line-height: 150%;
+            font-weight: normal;
+            margin: 0;
+            white-space: pre-wrap;
+            word-break: break-word;
         }
       }
-      > h3 {
-        color: #000000;
-        font-size: 16px;
-        line-height: 150%;
-        font-weight: normal;
-        margin: 8px 0 0 0;
-        white-space: pre-wrap;
-        word-break: break-word;
-      }
+      
     }
     .NNPE-tableList {
       background: #fff;
       border-radius: 8px;
-      margin-top: 24px;
       //   padding: 12px 8px;
       &.NNPE-tableList-hasBg {
         background: #f7f7f7;
@@ -901,12 +926,14 @@ export default {
   }
   .NNPE-Book-content-inner {
     > div {
-      > h2 {
-        color: #24b99e;
-        b {
-          background: #24b99e;
+        .title-box{
+            b {
+                background: #24b99e;
+            }
+            h2 {
+                color: #24b99e;
+            }
         }
-      }
     }
   }
 }
@@ -937,12 +964,14 @@ export default {
   }
   .NNPE-Book-content-inner {
     > div {
-      > h2 {
-        color: #bd8865;
-        b {
-          background: #bd8865;
+      .title-box{
+            b {
+                background: #bd8865;
+            }
+            h2 {
+                color: #bd8865;
+            }
         }
-      }
     }
   }
 }

+ 10 - 0
src/components/Adult/common/NewordPhraseModule.vue

@@ -30,6 +30,13 @@
           >
         </div>
         <div class="adult-book-input-item">
+          <span class="adult-book-lable">拼音位置:</span>
+          <el-radio-group v-model="curQueItem.pinyin_site" @change="forupdata">
+            <el-radio label="first">前面</el-radio>
+            <el-radio label="last">后面</el-radio>
+          </el-radio-group>
+        </div>
+        <div class="adult-book-input-item">
           <span class="adult-book-lable">词性:</span>
           <el-input
             placeholder="请输入词性"
@@ -102,6 +109,9 @@ export default {
   watch: {},
   //方法集合
   methods: {
+    forupdata() {
+      this.$forceUpdate();
+    },
     onBlur(item, field) {
       item[field] = item[field] ? item[field].trim() : "";
     },

+ 1 - 1
src/components/Adult/common/UploadView.vue

@@ -94,7 +94,7 @@ export default {
   created() {
     this.currentfileList = this.fileList || [];
     // this.showList = this.fileList ? true : false;
-    if (this.type == "upload_control_preview_chs") {
+    if (this.type == "upload_control_preview_chs"||this.type=='upload_pdf_chs') {
       this.showList = true;
     } else {
       this.showList = false;

+ 4 - 0
src/components/Adult/common/data.js

@@ -727,6 +727,10 @@ let fnData = [{
         type: "play_record_chs",
         name: "播放音频控件",
     },
+    {
+        type: "upload_pdf_chs",
+        name: "上传pdf",
+    },
 ]
 
 

+ 8 - 0
src/components/Adult/inputModules/Neword.vue

@@ -92,6 +92,7 @@ export default {
               pinyin: "",
               img_list: [],
               mp3_list: [],
+              pinyin_site: "first", //拼音位置
             },
           ],
         ],
@@ -148,6 +149,13 @@ export default {
       if (!this.curQue.hasOwnProperty("titleBg")) {
         this.$set(this.curQue, "titleBg", "themeColor");
       }
+      // let data = JSON.parse(JSON.stringify(this.curQue));
+      this.curQue.option.forEach((item) => {
+        if (!item[0].pinyin_site) {
+          item[0].pinyin_site = "first"; //拼音位置
+        }
+      });
+      // this.curQue = JSON.parse(JSON.stringify(data));
     }
   },
   beforeCreate() {}, //生命周期 - 创建之前

+ 16 - 4
src/components/Adult/inputModules/PurePreview.vue

@@ -137,10 +137,14 @@
             </template>
             <div class="adult-book-input-item">
               <span class="adult-book-lable">配置:</span>
-              <el-radio-group v-model="item.type" @change="forupdata">
+              <el-checkbox-group v-model="item.type" @change="forupdata">
+                <el-checkbox label="mh">描红</el-checkbox>
+                <el-checkbox label="lm">临摹</el-checkbox>
+              </el-checkbox-group>
+              <!-- <el-radio-group v-model="item.type" @change="forupdata">
                 <el-radio label="mh">描红</el-radio>
                 <el-radio label="lm">临摹</el-radio>
-              </el-radio-group>
+              </el-radio-group> -->
             </div>
           </template>
         </div>
@@ -240,6 +244,14 @@ export default {
     return {
       checkList: [],
       mp3Number: 1,
+      list: [
+        {
+          con: "临摹",
+        },
+        {
+          con: "描红",
+        },
+      ],
       form: {
         stem: {
           con: "",
@@ -285,7 +297,7 @@ export default {
             con: "", //生字
             en: "",
             pinyin: "", //拼音
-            type: "lm",
+            type: ["lm"],
           },
         ],
         numberList: {
@@ -520,7 +532,7 @@ export default {
         this.$set(this.curQue, "numberList", obj);
         this.curQue.option.forEach((item) => {
           if (!item.type) {
-            item.type = "lm";
+            item.type = ["lm"];
           }
         });
       }

+ 273 - 0
src/components/Adult/inputModules/ToneSelect.vue

@@ -13,6 +13,36 @@
           @blur="onBlur(curQue, 'title')"
         ></el-input>
       </div>
+      <div class="adult-book-input-item">
+        <span class="adult-book-lable">题目音频:</span>
+        <Upload
+          :changeFillId="timuchangeMp3"
+          :datafileList="curQue.mp3_list"
+          :filleNumber="mp3Number"
+          :uploadType="'mp3'"
+          :handleMp3Base64="handleChange"
+        />
+      </div>
+      <div class="adult-book-input-item">
+        <span class="adult-book-lable">题目lrc:</span>
+        <Upload
+          :changeFillId="changeLrc"
+          :datafileList="curQue.lrc_list"
+          :filleNumber="mp3Number"
+          :uploadType="'lrc'"
+        />
+      </div>
+      <div class="adult-book-input-item">
+        <span class="adult-book-lable"></span>
+        <el-button
+          type="primary"
+          size="small"
+          class="distribution"
+          @click="parseLrcFile"
+        >
+          分配lrc
+        </el-button>
+      </div>
       <div
         v-for="(curQueItem, index) in curQue.option"
         :key="'curQueItem' + index"
@@ -30,6 +60,7 @@
             :class="'tinydemo' + index"
             v-model="curQueItem.con"
             :init="init"
+            @change="changeCon(curQueItem)"
           />
           <img
             @click="deleteGroup"
@@ -39,6 +70,15 @@
           />
         </div>
         <div class="adult-book-input-item">
+          <span class="adult-book-lable"></span>
+          <span v-if="curQue.wordTime.length > 0" class="lrc">
+            <el-input v-model="curQue.wordTime[index].bg" size="small" />
+            <span> ~ </span>
+            <el-input v-model="curQue.wordTime[index].ed" size="small" />
+            {{ curQue.wordTime[index].text }}
+          </span>
+        </div>
+        <div class="adult-book-input-item">
           <span class="adult-book-lable">答案:</span>
           <div class="toneList">
             <div
@@ -76,6 +116,28 @@
         </div>
       </div>
       <div class="addoption" @click="addoption">增加拼音</div>
+      <div class="adult-book-input-item">
+        <span class="adult-book-lable">文字类型</span>
+        <el-radio-group v-model="curQue.sentenceType">
+          <el-radio label="chinese">中文</el-radio>
+          <el-radio label="pinyin">拼音</el-radio>
+        </el-radio-group>
+      </div>
+      <div class="lrc-box">
+        <div
+          v-if="this.curQue.wordTime && this.curQue.wordTime.length > 0"
+          class="lrc-box"
+        >
+          <span>已有字幕时间节点</span>
+          <el-button type="text" @click="againWordTime">重新生成</el-button>
+        </div>
+        <template v-else>
+          <el-button v-if="!isWordTime" size="medium" @click="createWordTime"
+            >自动生成字幕节点</el-button
+          >
+          <p v-else>字幕节点生成中...请等待</p>
+        </template>
+      </div>
     </div>
   </div>
 </template>
@@ -105,6 +167,14 @@ import "tinymce/plugins/preview";
 import "tinymce/plugins/contextmenu";
 import "tinymce/plugins/textcolor";
 import "tinymce/plugins/colorpicker";
+import {
+  segSentences,
+  BatchSegContent,
+  createPinyin,
+  prepareTranscribe,
+  getWordTime,
+  getContentFile,
+} from "@/api/ajax";
 export default {
   name: "ToneSelect",
   props: ["curQue", "changeCurQue"],
@@ -143,6 +213,12 @@ export default {
         type: "toneSelect_chs",
         name: "音调选择",
         title: "",
+        mp3_list: [],
+        lrc_list: [],
+        wordTime: [],
+        taskId: "",
+        sentenceType: "pinyin",
+        detail: [],
         option: [
           {
             con: "", //内容
@@ -162,12 +238,125 @@ export default {
         toolbar: " forecolor",
         branding: false,
       }, //富文本初始化
+      isWordTime: false,
     };
   },
   computed: {},
   watch: {},
   //方法集合
   methods: {
+    changeCon(item) {
+      console.log(item);
+    },
+    createWordTime() {
+      this.curQue.option.forEach((item) => {
+        let node = document.createElement("p");
+        node.innerHTML = item.con;
+        let text = node.innerText;
+        item.pinyin = text;
+      });
+
+      this.curQue.detail = [];
+      this.curQue.option.forEach((item) => {
+        this.curQue.detail.push(item);
+      });
+
+      if (this.curQue.taskId) {
+        let verseList = [];
+        let numberArr = [];
+        this.curQue.detail.forEach((item, i) => {
+          numberArr.push(this.numberToChinese(i + 1));
+        });
+        for (let i = 0; i < this.curQue.detail.length; i++) {
+          verseList = verseList.concat(this.curQue.detail[i].pinyin);
+        }
+        if (verseList.length > 0) {
+          this.isWordTime = true;
+          let data = {
+            taskId: this.curQue.taskId,
+            verseList: JSON.stringify(verseList),
+            matchType: this.curQue.sentenceType,
+            language: "ch",
+          };
+          getWordTime(data).then((res) => {
+            this.curQue.wordTime = res.data.result;
+            this.isWordTime = false;
+          });
+        }
+      } else {
+        this.$message.warning("请先上传音频");
+      }
+    },
+    againWordTime() {
+      this.isWordTime = false;
+      this.$set(this.curQue, "wordTime", []);
+    },
+    numberToChinese(num) {
+      var AA = new Array(
+        "ling",
+        "yi",
+        "er",
+        "san",
+        "si",
+        "wu",
+        "liu",
+        "qi",
+        "ba",
+        "jiu",
+        "shi"
+      );
+      var BB = new Array("", "shi", "bai", "qian", "wan", "yi", "dian", "");
+      var a = ("" + num).replace(/(^0*)/g, "").split("."),
+        k = 0,
+        re = "";
+      for (var i = a[0].length - 1; i >= 0; i--) {
+        switch (k) {
+          case 0:
+            re = BB[7] + re;
+            break;
+          case 4:
+            if (
+              !new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$").test(a[0])
+            )
+              re = BB[4] + re;
+            break;
+          case 8:
+            re = BB[5] + re;
+            BB[7] = BB[5];
+            k = 0;
+            break;
+        }
+        if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
+          re = AA[0] + re;
+        if (a[0].charAt(i) != 0) re = AA[a[0].charAt(i)] + BB[k % 4] + re;
+        k++;
+      }
+
+      if (a.length > 1) {
+        // 加上小数部分(如果有小数部分)
+        re += BB[6];
+        for (var i = 0; i < a[1].length; i++) re += AA[a[1].charAt(i)];
+      }
+      if (re == "yishi") re = "shi";
+      if (re.match(/^一/) && re.length == 3) re = re.replace("yi", "");
+      return re;
+    },
+    changeLrc(fileList) {
+      let lrc_list = [];
+      fileList.forEach(({ response, name }) => {
+        if (response) {
+          let fileList = response.file_info_list[0];
+          lrc_list.push({
+            name,
+            duration: fileList.media_duration,
+            url: fileList.file_url,
+            id: "[FID##" + fileList.file_id + "##FID]",
+            file_id: fileList.file_id,
+          });
+        }
+      });
+      this.curQue.lrc_list = lrc_list;
+    },
     ConInput(e) {},
     //   选择声调
     selectTone(oindex, aindex) {
@@ -202,6 +391,22 @@ export default {
         JSON.stringify(articleImgRes)
       );
     },
+    timuchangeMp3(fileList, item) {
+      const articleImgList = JSON.parse(JSON.stringify(fileList));
+      const articleImgRes = [];
+      articleImgList.forEach((item) => {
+        if (item.response) {
+          const obj = {
+            name: item.name,
+            url: item.response.file_info_list[0].file_url,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "##FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
+          };
+          articleImgRes.push(obj);
+        }
+      });
+      this.curQue.mp3_list = JSON.parse(JSON.stringify(articleImgRes));
+    },
     addoption() {
       let leg = this.curQue.option.length;
       let last = this.curQue.option[leg - 1];
@@ -220,6 +425,58 @@ export default {
       }
       this.curQue.option.splice(index, 1);
     },
+    // 上传音频文件
+    handleChange(file, fileList) {
+      let _this = this;
+      _this.getBase64(file.raw).then((res) => {
+        let base_res = res.split("base64,");
+        let data = {
+          fileName: file.raw.name,
+          speechBase64: base_res[1],
+          language: "ch",
+        };
+        prepareTranscribe(data).then((res) => {
+          _this.$set(_this.curQue, "taskId", res.data.taskId);
+        });
+      });
+    },
+    // 根据lrc文件id 获取内容和起始和结束时间
+    parseLrcFile() {
+      let lrcList = this.curQue.lrc_list;
+      if (lrcList.length === 0) {
+        return this.$message.warning("请先上传lrc文件");
+      }
+      getContentFile("tool-ParseLRCFile", {
+        content_type: "FILE",
+        file_id: this.curQue.lrc_list[0].file_id,
+      }).then(({ lrc_list }) => {
+        let lrc_list_res = [];
+        lrc_list.forEach((item) => {
+          let obj = {
+            bg: item.begin_time,
+            ed: item.end_time,
+          };
+          lrc_list_res.push(obj);
+        });
+        this.curQue.wordTime = lrc_list_res;
+      });
+    },
+    getBase64(file) {
+      return new Promise(function (resolve, reject) {
+        let reader = new FileReader();
+        let imgResult = "";
+        reader.readAsDataURL(file);
+        reader.onload = function () {
+          imgResult = reader.result;
+        };
+        reader.onerror = function (error) {
+          reject(error);
+        };
+        reader.onloadend = function () {
+          resolve(imgResult);
+        };
+      });
+    },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {},
@@ -239,6 +496,18 @@ export default {
           editor_selector: `tinydemo${i}`,
         });
       });
+      if (!this.curQue.lrc_list) {
+        this.curQue.lrc_list = [];
+      }
+      if (!this.curQue.sentenceType) {
+        this.curQue.sentenceType = "pinyin";
+      }
+      if (!this.curQue.taskId) {
+        this.curQue.taskId = "";
+      }
+      if (!this.curQue.wordTime) {
+        this.curQue.wordTime = [];
+      }
     }
   },
   beforeCreate() {}, //生命周期 - 创建之前
@@ -291,6 +560,10 @@ export default {
       margin-left: 10px;
     }
   }
+  .lrc {
+    display: flex;
+    align-items: center;
+  }
 }
 </style>
 <style lang="scss">

+ 172 - 0
src/components/Adult/inputModules/UploadPdf.vue

@@ -0,0 +1,172 @@
+<!--  -->
+<template>
+  <div class="Big-Book-prev-Textdes Tinydemo" v-if="curQue">
+    <UploadView
+      :changeFillId="changeFillId"
+      :accept="accept"
+      :filleNumber="1"
+      :fileList="curQue.fileList"
+      :type="type"
+    />
+  </div>
+</template>
+
+<script>
+import UploadView from "../common/UploadView.vue";
+import pdf from "vue-pdf";
+export default {
+  components: {
+    UploadView,
+    pdf,
+  },
+  props: ["curQue", "changeCurQue", "type"],
+  data() {
+    return {
+      uploadType: "",
+      fileList: [],
+      data: null,
+      numPages: null,
+      accept: ".pdf",
+      data_structure: {
+        type: "upload_pdf_chs",
+        name: "上传pdf",
+        title: "",
+        fileList: [],
+      },
+      loading: false,
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    remove() {
+      // this.data = null;
+      // this.curQue.data = null;
+      // this.curQue.fileList = [];
+      // this.$message.success("删除成功");
+    },
+    changeFillId(fileList, item, index) {
+      this.curQue.fileList = JSON.parse(JSON.stringify(fileList));
+      if (fileList.length > 0) {
+        this.curQue.data = fileList[0]?.response?.file_info_list[0];
+        this.curQue.data.fileRelativePath =
+          process.env.VUE_APP_BASE_API + this.curQue.data.file_relative_path;
+          this.getNumPages()
+      }
+    },
+    // 获取pdf的页数
+    getNumPages() {
+      let _this = this;
+      let loadingTask = pdf.createLoadingTask(
+        _this.curQue.data.fileRelativePath
+      );
+      loadingTask.promise
+        .then((pdff) => {
+          _this.numPages = pdff.numPages;
+          _this.curQue.data.numPages = pdff.numPages;
+          this.$forceUpdate();
+        })
+        .catch((err) => {
+          this.$message.success("pdf 加载失败", err);
+          this.data = null;
+          this.curQue.data = null;
+          this.curQue.fileList = [];
+        });
+    },
+
+    initcurQue() {
+      let data;
+      data = JSON.parse(JSON.stringify(this.data_structure));
+      this.changeCurQue(data);
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    if (!this.curQue) {
+      this.initcurQue();
+    }
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.Big-Book-prev-Textdes {
+  padding: 24px 0 24px 24px;
+  background: #f7f7f7;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  .dv {
+    display: flex;
+    align-items: center;
+    .remove {
+      width: 40px;
+      height: 39px;
+      background: #ffffff;
+      border: 1px solid rgba(0, 0, 0, 0.1);
+      box-sizing: border-box;
+      border-radius: 8px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-left: 32px;
+      cursor: pointer;
+      img {
+        width: 24px;
+        height: 24px;
+      }
+    }
+  }
+  .uploadBtn {
+    width: 141px;
+    height: 39px;
+    background: #ffffff;
+    border: 1px solid rgba(0, 0, 0, 0.1);
+    box-sizing: border-box;
+    box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
+    border-radius: 4px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 16px;
+    line-height: 150%;
+    color: #000000;
+
+    img {
+      margin-right: 13px;
+    }
+  }
+  .main {
+    margin-top: 23px;
+    width: 477px;
+    height: 292px;
+    background: #ffffff;
+    border: 1px solid rgba(0, 0, 0, 0.1);
+    box-sizing: border-box;
+    border-radius: 8px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    .content {
+      width: 445px;
+      height: 260px;
+      border-radius: 4px;
+      box-sizing: border-box;
+      background: linear-gradient(0deg, #ebebeb, #ebebeb);
+      overflow-y: scroll;
+      img {
+        max-width: 100%;
+        max-height: 100%;
+      }
+    }
+  }
+}
+</style>

+ 72 - 0
src/components/Adult/preview/ArticleViewChs/NormalModelChs.vue

@@ -566,4 +566,76 @@ export default {
     }
   }
 }
+.NPC-Big-Book-preview-green {
+    .NNPE-ArticleView {
+        .NNPE-detail {
+            .NNPE-words {
+                &-box {
+                    > span {
+                        &.NNPE-chs {
+                            &.active {
+                                background: rgba(36, 185, 158, 0.15);
+                            }
+                            &.wordActive {
+                                color: rgba(36, 185, 158, 1);
+                            }
+                            .wordActive {
+                                color: rgba(36, 185, 158, 1);
+                            }
+                        }
+                    }
+                }
+                > span {
+                    &.NNPE-chs {
+                        &.active {
+                            background: rgba(36, 185, 158, 0.15);
+                        }
+                        &.wordActive {
+                            color: rgba(36, 185, 158, 1);
+                        }
+                        .wordActive {
+                            color: rgba(36, 185, 158, 1);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+.NPC-Big-Book-preview-brown {
+    .NNPE-ArticleView {
+        .NNPE-detail {
+            .NNPE-words {
+                &-box {
+                    > span {
+                        &.NNPE-chs {
+                            &.active {
+                                background: rgba(189, 136, 101, 0.15);
+                            }
+                            &.wordActive {
+                                color: rgba(189, 136, 101, 1);
+                            }
+                            .wordActive {
+                                color: rgba(189, 136, 101, 1);
+                            }
+                        }
+                    }
+                }
+                > span {
+                    &.NNPE-chs {
+                        &.active {
+                            background: rgba(189, 136, 101, 0.15);
+                        }
+                        &.wordActive {
+                            color: rgba(189, 136, 101, 1);
+                        }
+                        .wordActive {
+                            color: rgba(189, 136, 101, 1);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
 </style>

+ 59 - 0
src/components/Adult/preview/ArticleViewChs/Practicechs.vue

@@ -663,4 +663,63 @@ export default {
     }
   }
 }
+.NPC-Big-Book-preview-green {
+    .NNPE-ArticleView {
+        .NNPE-detail-box {
+            &.active {
+                background: rgba(36, 185, 158, 0.15);
+            }
+        }
+        .NNPE-detail {
+            .NNPE-words {
+                &-box {
+                    > span {
+                        &.NNPE-chs {
+                            .active {
+                                color: #24B99E;
+                            }
+                        }
+                    }
+                }
+                > span {
+                    &.NNPE-chs {
+                        .active {
+                            color: #24B99E;
+                        }
+                    }
+                }
+            }
+        }
+    }
+  
+}
+.NPC-Big-Book-preview-brown {
+    .NNPE-ArticleView {
+        .NNPE-detail-box {
+            &.active {
+                background: rgba(189, 136, 101, 0.15);
+            }
+        }
+        .NNPE-detail {
+            .NNPE-words {
+                &-box {
+                    > span {
+                        &.NNPE-chs {
+                            .active {
+                                color: #BD8865;
+                            }
+                        }
+                    }
+                }
+                > span {
+                    &.NNPE-chs {
+                        .active {
+                            color: #BD8865;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
 </style>

+ 11 - 2
src/components/Adult/preview/DialogueArticleViewChs/Practicechs.vue

@@ -29,6 +29,10 @@
           :class="['pinyin-16', isShowPY ? '' : 'disabled']"
           @click="changePinyin"
         ></span>
+        <span
+          :class="['EN-16', isShowEN ? '' : 'disabled']"
+          @click="changeEN"
+        ></span>
       </div>
     </div>
 
@@ -311,7 +315,7 @@
                 </div>
                 <div style="clear: both; overflow: hidden"></div>
                 <div
-                  v-if="item.enwords"
+                  v-if="item.enwords && isShowEN"
                   :class="['enwords', sentIndex == index ? 'wordBlank' : '']"
                 >
                   {{ item.enwords }}
@@ -423,6 +427,7 @@ export default {
       stopAudio: false,
       sentIndex: 0,
       isShowPY: true,
+      isShowEN: true,
       isRepeat: false,
       currSent: null, //当前句子的时间
       isRecord: false,
@@ -634,6 +639,10 @@ export default {
     changePinyin() {
       this.isShowPY = !this.isShowPY;
     },
+    // 英文的显示和隐藏
+    changeEN(){
+        this.isShowEN = !this.isShowEN;
+    },
     // 单句是否重复播放
     changeRepeat() {
       let _this = this;
@@ -676,7 +685,7 @@ export default {
       display: flex;
       justify-content: space-between;
       align-items: center;
-      width: 72px;
+      width: 92px;
       height: 40px;
       box-sizing: border-box;
       padding: 0 12px;

+ 2 - 1
src/components/Adult/preview/InputHasRecord.vue

@@ -375,11 +375,12 @@ export default {
     margin-right: 8px;
   }
   .inputInner {
+    max-width: 520px;
     border-radius: 8px;
     border: 1px solid rgba(0, 0, 0, 0.1);
     background: #fff;
     overflow: hidden;
-    margin: 8px 0 16px 23px;
+    margin: 8px 0 36px 23px;
     > div.luyin-inner {
       border-top: 1px solid rgba(0, 0, 0, 0.1);
     }

+ 78 - 62
src/components/Adult/preview/NewWordShow.vue

@@ -3,62 +3,70 @@
   <div class="Big-Book-prev-Textdes NewWordShow" v-if="curQue">
     <h2 v-if="curQue.title">{{ curQue.title }}</h2>
     <div class="item-box">
-      <div
-        class="item"
-        v-for="(item, index) in curQue.option"
-        :key="index"
-        :style="{
-          width: curQue.numberList ? 100 / curQue.numberList.con + '%' : 'auto',
-        }"
-      >
-        <p v-if="item.pinyin || item.en">
-          <span>{{ item.pinyin }}</span>
-          <span>{{ item.en }}</span>
-        </p>
-        <div class="con-box">
-          <template v-if="item.imgOrText == 'text'">
-            <template v-if="item.con">
-              <div
-                :key="conindex"
-                class="strockplay-newWord"
-                v-for="(conItem, conindex) in item.con"
-                @click="writeWord(conItem, item.pinyin)"
-              >
-                <Strockplayredline
-                  :Book_text="conItem"
-                  :playStorkes="true"
-                  :targetDiv="
-                    'bwcHanziIntp' + index + conItem + conindex + indexStr
-                  "
-                />
-                <div
-                  class="bwc-line"
-                  v-if="conindex < item.con.length - 1"
-                ></div>
-              </div>
-            </template>
-            <template v-else>
-              <div class="blank-item" @click="freeWrite('', index)">
-                <img :src="freeImg[index]" v-if="freeImg[index]" />
-              </div>
-            </template>
-          </template>
-          <template v-else>
+        <div class="item-pre"
+              v-for="(item, index) in curQue.option"
+              :key="index">
             <div
-              class="img-box"
-              v-for="(imgItem, imgIndex) in item.img_list"
-              :key="imgIndex"
-              @click="freeWrite(imgItem.url, imgIndex)"
+                class="item"
+                style="margin-right:20px"
             >
-              <el-image :src="imgItem.url" fit="scale-down" class="img_url">
-                <div slot="placeholder" class="image-slot">
-                  <img src="../../../assets/common/icon-imgloading.png" />
+                <p v-if="item.pinyin || item.en">
+                    <span>{{ item.pinyin }}</span>
+                    <span>{{ item.en }}</span>
+                </p>
+                <div class="con-box">
+                <template v-if="item.imgOrText == 'text'">
+                    <template v-if="item.con">
+                    <div
+                        :key="conindex"
+                        class="strockplay-newWord"
+                        v-for="(conItem, conindex) in item.con"
+                        @click="writeWord(conItem, item.pinyin)"
+                    >
+                        <Strockplayredline
+                        :Book_text="conItem"
+                        :playStorkes="true"
+                        :targetDiv="
+                            'bwcHanziIntp' + index + conItem + conindex + indexStr
+                        "
+                        />
+                        <div
+                        class="bwc-line"
+                        v-if="conindex < item.con.length - 1"
+                        ></div>
+                    </div>
+                    </template>
+                    <template v-else>
+                    <div class="blank-item" @click="freeWrite('', index, 0)">
+                        <img :src="freeImg[index][0]" v-if="freeImg[index][0]" />
+                    </div>
+                    </template>
+                </template>
+                <template v-else>
+                    <div
+                    class="img-box"
+                    v-for="(imgItem, imgIndex) in item.img_list"
+                    :key="imgIndex"
+                    @click="freeWrite(imgItem.url, imgIndex, 0)"
+                    >
+                    <el-image :src="imgItem.url" fit="scale-down" class="img_url">
+                        <div slot="placeholder" class="image-slot">
+                        <img src="../../../assets/common/icon-imgloading.png" />
+                        </div>
+                    </el-image>
+                    </div>
+                </template>
                 </div>
-              </el-image>
             </div>
-          </template>
+            <template v-if="item.type&&item.type.indexOf('lm')>-1">
+                <div class="con-box" v-for="indexs in 6" :key="indexs">
+                    <div class="blank-item" @click="freeWrite('', index, indexs+1)">
+                        <img :src="freeImg[index][indexs+1]" v-if="freeImg[index][indexs+1]" />
+                    </div>
+                </div>
+            </template>
         </div>
-      </div>
+      
     </div>
     <div class="practiceBox practiceBoxStrock" v-if="isPraShow">
       <Practice
@@ -93,6 +101,7 @@ export default {
       ifFreeShow: false,
       freeImg: [],
       activeIndex: null,
+      activeColIndex: null,
     };
   },
   computed: {},
@@ -103,17 +112,19 @@ export default {
     handleData() {
       let _this = this;
       _this.freeImg = [];
-      _this.curQue.option.forEach((item) => {
-        _this.freeImg.push("");
+      _this.curQue.option.forEach((item,index) => {
+          let itemImg = ['','','','','','','']
+          _this.$set(_this.freeImg,index,itemImg)
       });
     },
     changePraShow() {
       this.isPraShow = false;
       this.ifFreeShow = false;
-      this.freeImg[this.activeIndex] = this.$refs.freePaint.imgSrc;
+      this.freeImg[this.activeIndex][this.activeColIndex] = this.$refs.freePaint.imgSrc;
     },
     async writeWord(words, pinyin) {
       this.activeIndex = null;
+      this.activeColIndex = null
       const MethodName = "tool-ChineseSCConvert";
       const data = {
         text: words,
@@ -132,14 +143,17 @@ export default {
       };
       this.isPraShow = true;
     },
-    freeWrite(imgUrl, index) {
+    freeWrite(imgUrl, index, indexs) {
       this.ifFreeShow = true;
       this.curDataImg = imgUrl;
       this.activeIndex = imgUrl ? null : index;
+      this.activeColIndex = imgUrl ? null : indexs;
     },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
-  created() {},
+  created() {
+      this.handleData()
+  },
   //生命周期 - 挂载完成(可以访问DOM元素)
   mounted() {},
   beforeCreate() {}, //生命周期 - 创建之前
@@ -164,16 +178,18 @@ export default {
     color: #000000;
   }
   .item-box {
-    display: flex;
-    flex-flow: wrap;
     padding-bottom: 8px;
     padding: 0 4px;
     background: #f7f7f7;
     border: 1px solid rgba(0, 0, 0, 0.1);
     border-radius: 8px;
-    align-items: flex-end;
+    .item-pre{
+        display: flex;
+        flex-flow: wrap;
+        align-items: flex-end;
+        padding: 9px 20px;
+    }
     .item {
-      padding: 9px 20px;
       box-sizing: border-box;
       // width: 66px;
       cursor: pointer;
@@ -226,7 +242,8 @@ export default {
           height: 64px;
         }
       }
-      .blank-item {
+    }
+    .blank-item {
         width: 64px;
         height: 64px;
         background: #fff url("../../../assets/NPC/chinaTianRed.png") center
@@ -236,7 +253,6 @@ export default {
           width: 100%;
           height: 100%;
         }
-      }
     }
   }
   .practiceBox {

+ 2 - 2
src/components/Adult/preview/Notes.vue

@@ -158,7 +158,7 @@ export default {
         display: flex;
         justify-content: flex-start;
         align-items: center;
-        margin-bottom: 8px;
+        margin-bottom: 12px;
         > span {
           font-style: normal;
           font-weight: normal;
@@ -182,7 +182,7 @@ export default {
         font-size: 14px;
         line-height: 150%;
         color: #000000;
-        margin-bottom: 8px;
+        margin-bottom: 12px;
         padding-left: 27px;
       }
       .NPC-notes-note {

+ 81 - 0
src/components/Adult/preview/PdfView.vue

@@ -0,0 +1,81 @@
+<template>
+  <div class="pdfView">
+    <pdf
+      ref="pdf"
+      :src="curQue.data.fileRelativePath"
+      v-for="i in curQue.data.numPages"
+      :key="i"
+      :page="i"
+    >
+    </pdf>
+  </div>
+</template>
+
+<script>
+//这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+//例如:import 《组件名称》from ‘《组件路径》';
+import pdf from "vue-pdf";
+
+export default {
+  //import引入的组件需要注入到对象中才能使用
+  components: { pdf },
+  props: ["curQue", "fn_data", "type"],
+
+  data() {
+    //这里存放数据
+    return {
+      numPages: null,
+    };
+  },
+  //计算属性 类似于data概念
+  computed: {},
+  //监控data中数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    getNumPages() {
+      let _this = this;
+      let loadingTask = pdf.createLoadingTask(
+        _this.curQue.data.fileRelativePath
+      );
+      this.$forceUpdate();
+
+      loadingTask.promise
+        .then((pdff) => {
+          console.log("拿到结果");
+          _this.numPages = pdff.numPages;
+          _this.curQue.data.numPages = pdff.numPages;
+          this.$forceUpdate();
+        })
+        .catch((err) => {
+          console.error("pdf 加载失败", err);
+        });
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  //生命周期-创建之前
+  beforeCreated() {},
+  //生命周期-挂载之前
+  beforeMount() {},
+  //生命周期-更新之前
+  beforUpdate() {},
+  //生命周期-更新之后
+  updated() {},
+  //生命周期-销毁之前
+  beforeDestory() {},
+  //生命周期-销毁完成
+  destoryed() {},
+  //如果页面有keep-alive缓存功能,这个函数会触发
+  activated() {},
+};
+</script>
+<style scoped>
+/* @import url(); 引入css类 */
+.pdfView {
+  width: 100%;
+}
+</style>

+ 181 - 84
src/components/Adult/preview/SelectTone.vue

@@ -1,59 +1,103 @@
 <!--  -->
 <template>
   <div class="Big-Book-prev-Textdes SelectTone" v-if="curQue">
-      <ul>
-          <li v-for="(item,index) in curQue.option" :key="index">
-              <Audio
-                    :mp3="
-                    item.mp3_list.length > 0 ? item.mp3_list[0].url : ''"
-                    :themeColor="themeColor"
-                    class="audio-play"
-                />
-                <div v-html="item.con" class="con"></div>
-                <a v-for="(itmes,indexs) in toneList" :key="indexs" :class="['tone-item',userSelect[index]===indexs?'active':'']" @click="handleClick(index,indexs)">
-                    <img :src="itmes">
-                </a>
-          </li>
-      </ul>
+    <div
+      class="aduioLine-box"
+      v-if="
+        curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url
+      "
+    >
+      <AudioLine
+        audioId="sentenceListenAudio"
+        :mp3="curQue.mp3_list[0].url"
+        :getCurTime="getCurTime"
+        :themeColor="themeColor"
+        ref="audioLine"
+        @handleListenRead="handleListenRead"
+      />
+    </div>
+    <ul>
+      <li v-for="(item, index) in curQue.option" :key="index">
+        <a
+          :class="[
+            'play-btn',
+            curTime >= curQue.wordTime[index].bg &&
+            curTime < curQue.wordTime[index].ed &&
+            stopAudio
+              ? 'active'
+              : '',
+          ]"
+          @click="handleChangeTime(curQue.wordTime[index].bg)"
+        ></a>
+        <!-- <Audio
+          :mp3="item.mp3_list.length > 0 ? item.mp3_list[0].url : ''"
+          :themeColor="themeColor"
+          class="audio-play"
+        /> -->
+        <div v-html="item.con" class="con"></div>
+        <a
+          v-for="(itmes, indexs) in toneList"
+          :key="indexs"
+          :class="['tone-item', userSelect[index] === indexs ? 'active' : '']"
+          @click="handleClick(index, indexs)"
+        >
+          <img :src="itmes" />
+        </a>
+      </li>
+    </ul>
   </div>
 </template>
 
 <script>
 import Audio from "../preview/components/AudioRed.vue"; // 音频播放
+import AudioLine from "../preview/AudioLine.vue";
+
 export default {
-  components: {Audio},
-  props: ["curQue","themeColor"],
+  components: { Audio, AudioLine },
+  props: ["curQue", "themeColor"],
   data() {
     return {
-        toneList: [
-            require('../../../assets/NPC/tone1.png'),
-            require('../../../assets/NPC/tone2.png'),
-            require('../../../assets/NPC/tone3.png'),
-            require('../../../assets/NPC/tone4.png'),
-            require('../../../assets/NPC/tone0.png')
-        ],
-        userSelect:[]
+      toneList: [
+        require("../../../assets/NPC/tone1.png"),
+        require("../../../assets/NPC/tone2.png"),
+        require("../../../assets/NPC/tone3.png"),
+        require("../../../assets/NPC/tone4.png"),
+        require("../../../assets/NPC/tone0.png"),
+      ],
+      userSelect: [],
+      curTime: "",
+      stopAudio: false,
     };
   },
   computed: {},
   watch: {},
   //方法集合
   methods: {
-      // 处理数据
-      handleData(){
-          let _this = this
-          _this.userSelect = []
-          _this.curQue.option.forEach(item => {
-              _this.userSelect.push('')
-          });
-      },
-      handleClick(index,indexs){
-          this.$set(this.userSelect,index,indexs)
-      }
+    // 处理数据
+    handleData() {
+      let _this = this;
+      _this.userSelect = [];
+      _this.curQue.option.forEach((item) => {
+        _this.userSelect.push("");
+      });
+    },
+    handleClick(index, indexs) {
+      this.$set(this.userSelect, index, indexs);
+    },
+    handleChangeTime(time) {
+      let _this = this;
+      _this.curTime = time;
+      _this.$refs.audioLine.onTimeupdateTime(time / 1000, true);
+    },
+    getCurTime(curTime) {
+      this.curTime = curTime * 1000;
+    },
+    handleListenRead(playFlag) {
+      this.stopAudio = playFlag;
+    },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
-  created() {
-  },
+  created() {},
   //生命周期 - 挂载完成(可以访问DOM元素)
   mounted() {},
   beforeCreate() {}, //生命周期 - 创建之前
@@ -67,59 +111,112 @@ export default {
 </script>
 <style lang='scss' scoped>
 //@import url(); 引入公共css类
-.Big-Book-prev-Textdes{
-    width: 100%;
-    ul{
-        display: flex;
-        flex-flow: wrap;
-        justify-content: space-between;
-        align-items: flex-start;
-        li{
-            width: 363px;
-            background: #FFFFFF;
-            border: 1px solid rgba(0, 0, 0, 0.1);
-            box-sizing: border-box;
-            border-radius: 8px;
-            display: flex;
-            align-items: center;
-            padding: 8px 12px 8px 16px;
-            margin: 8px 0;
-            .audio-play{
-                width: 16px;
-                margin-right: 12px;
-            }
-            >div.con{
-                font-size: 16px;
-                line-height: 1.5;
-                flex: 1;
-                margin: 0;
-            }
-            a{
-                margin-left: 8px;
-                font-size: 0;
-                &.active{
-                    background: #98D1EB;
-                    border-radius: 4px;
-                }
-                img{
-                    width: 24px;
-                }
-            }
+.Big-Book-prev-Textdes {
+  width: 100%;
+  background: #f7f7f7;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  box-sizing: border-box;
+  border-radius: 8px;
+  overflow: hidden;
+  ul {
+    display: flex;
+    flex-flow: wrap;
+    justify-content: space-between;
+    align-items: flex-start;
+    padding: 24px 12px;
+
+    li {
+      width: 363px;
+      background: #ffffff;
+      border: 1px solid rgba(0, 0, 0, 0.1);
+      box-sizing: border-box;
+      border-radius: 8px;
+      display: flex;
+      align-items: center;
+      padding: 8px 12px 8px 16px;
+      margin: 8px 0;
+      .play-btn {
+        width: 16px;
+        height: 16px;
+        background: url("../../../assets/NPC/play-red.png") center no-repeat;
+        background-size: cover;
+        margin-right: 8px;
+
+        &.active {
+          background-image: url("../../../assets/NPC/icon-voice-play-red.png");
+          background-size: cover;
+        }
+      }
+      .audio-play {
+        width: 16px;
+        margin-right: 12px;
+      }
+      > div.con {
+        font-size: 16px;
+        line-height: 1.5;
+        flex: 1;
+        margin: 0;
+      }
+      a {
+        margin-left: 8px;
+        font-size: 0;
+        &.active {
+          background: #98d1eb;
+          border-radius: 4px;
+        }
+        img {
+          width: 24px;
+        }
+      }
+    }
+  }
+}
+.NPC-Big-Book-preview-green {
+  .Big-Book-prev-Textdes {
+    li {
+      b {
+        background: #24b99e;
+      }
+      .play-btn {
+        background: url("../../../assets/NPC/play-green.png") center no-repeat;
+        background-size: cover;
+        &.active {
+          background-image: url("../../../assets/NPC/icon-voice-play-green.png");
+          background-size: cover;
         }
+      }
     }
+  }
+}
+.NPC-Big-Book-preview-brown {
+  .Big-Book-prev-Textdes {
+    li {
+      b {
+        background: #bd8865;
+      }
+      .play-btn {
+        background: url("../../../assets/NPC/play-brown.png") center no-repeat;
+        background-size: cover;
+        &.active {
+          background-image: url("../../../assets/NPC/icon-voice-play-brown.png");
+          background-size: cover;
+        }
+      }
+    }
+  }
 }
 </style>
 <style lang="scss">
-.SelectTone.Big-Book-prev-Textdes{
-    ul{
-        li{
-            div.con{
-                margin: 0 ;
-                >p{
-                    margin: 0;
-                }
-            }
+.SelectTone.Big-Book-prev-Textdes {
+  ul {
+    li {
+      div.con {
+        margin: 0;
+        > p {
+          margin: 0;
         }
+      }
     }
+  }
 }
 </style>

+ 6 - 2
src/components/Adult/preview/WordPhrase.vue

@@ -78,13 +78,15 @@
                 v-else
                 style="width: 16px; height: 16px; margin-left: 8px"
               ></div>
-
-              <span class="NPC-word-tab-common NPC-word-tab-pinyin">
+              <span class="NPC-word-tab-common NPC-word-tab-pinyin" v-if="!sItem.pinyin_site||sItem.pinyin_site=='first'">
                 {{ sItem.pinyin }}
               </span>
               <span class="NPC-word-tab-common NPC-word-tab-word">
                 {{ sItem.new_word }}
               </span>
+              <span class="NPC-word-tab-common NPC-word-tab-pinyin" v-if="sItem.pinyin_site=='last'">
+                {{ sItem.pinyin }}
+              </span>
               <span
                 class="NPC-word-tab-common NPC-word-tab-cixing"
                 v-html="sItem.cixing"
@@ -412,6 +414,7 @@ export default {
         width: 48px;
         box-sizing: border-box;
         text-align: left;
+        font-style:italic;
       }
       .NPC-word-tab-def {
         flex: 1;
@@ -515,6 +518,7 @@ export default {
         color: #fff;
         font-weight: bold;
         margin-right: 8px;
+        white-space: pre;
       }
       .NPC-play-all {
         width: 16px;

+ 2 - 2
src/components/Adult/preview/components/Practice.vue

@@ -115,7 +115,7 @@
                   :class="navIndex == 1 ? 'active' : ''"
                   @click="changeNav(1)"
                 >
-                  默写
+                  临摹
                 </li>
               </ul>
             </div>
@@ -205,7 +205,7 @@
                   :class="navIndex == 1 ? 'active' : ''"
                   @click="changeNav(1)"
                 >
-                  默写
+                  临摹
                 </li>
               </ul>
             </div>

+ 91 - 69
src/styles/index.scss

@@ -232,11 +232,11 @@ input:-ms-input-placeholder {
             display: block;
         }
     }
-    .adult-book-main{
-      min-height: 32px;
-      display:flex;
-      justify-content: flex-start;
-      align-items:center;
+    .adult-book-main {
+        min-height: 32px;
+        display: flex;
+        justify-content: flex-start;
+        align-items: center;
     }
     .adult-book-input {
         width: 500px;
@@ -277,18 +277,18 @@ input:-ms-input-placeholder {
                 width: 25px;
             }
         }
-      &.Audio-tts{
-        .audioLine {
-          .playBtn {
-              background: url("../assets/NPC/tts-play-red.png") no-repeat left top;
-              background-size: 100% 100%;
-          }
-          .pauseBtn {
-              background: url("../assets/NPC/tts-red.png") no-repeat left top;
-              background-size: 100% 100%;
-          }
-      }
-      }
+        &.Audio-tts {
+            .audioLine {
+                .playBtn {
+                    background: url("../assets/NPC/tts-play-red.png") no-repeat left top;
+                    background-size: 100% 100%;
+                }
+                .pauseBtn {
+                    background: url("../assets/NPC/tts-red.png") no-repeat left top;
+                    background-size: 100% 100%;
+                }
+            }
+        }
     }
     .Repeat-16 {
         background: url("../assets/icon/Repeat-16-normal-red.png") no-repeat left top;
@@ -306,6 +306,14 @@ input:-ms-input-placeholder {
             background-size: 100% 100%;
         }
     }
+    .EN-16 {
+        background: url("../assets/icon/EN-16-normal-red.png") no-repeat left top;
+        background-size: 100% 100%;
+        &.disabled {
+            background: url("../assets/icon/EN-16-disable-Black.png") no-repeat left top;
+            background-size: 100% 100%;
+        }
+    }
     &.NPC-Big-Book-preview-green {
         .Audio {
             .audioLine {
@@ -321,36 +329,43 @@ input:-ms-input-placeholder {
                     width: 25px;
                 }
             }
-            &.Audio-tts{
-              .audioLine {
-                .playBtn {
-                    background: url("../assets/NPC/tts-play-green.png") no-repeat left top;
-                    background-size: 100% 100%;
+            &.Audio-tts {
+                .audioLine {
+                    .playBtn {
+                        background: url("../assets/NPC/tts-play-green.png") no-repeat left top;
+                        background-size: 100% 100%;
+                    }
+                    .pauseBtn {
+                        background: url("../assets/NPC/tts-green.png") no-repeat left top;
+                        background-size: 100% 100%;
+                    }
                 }
-                .pauseBtn {
-                    background: url("../assets/NPC/tts-green.png") no-repeat left top;
-                    background-size: 100% 100%;
-                }
-                
-            }
             }
         }
         .Repeat-16 {
-          background: url("../assets/icon/Repeat-16-normal-Green.png") no-repeat left top;
-          background-size: 100% 100%;
-          &.disabled {
-              background: url("../assets/icon/Repeat-16-disable-Black.png") no-repeat left top;
-              background-size: 100% 100%;
-          }
-      }
-      .pinyin-16 {
-          background: url("../assets/icon/pinyin-16-normal-Green.png") no-repeat left top;
-          background-size: 100% 100%;
-          &.disabled {
-              background: url("../assets/icon/pinyin-16-disable-Black.png") no-repeat left top;
-              background-size: 100% 100%;
-          }
-      }
+            background: url("../assets/icon/Repeat-16-normal-Green.png") no-repeat left top;
+            background-size: 100% 100%;
+            &.disabled {
+                background: url("../assets/icon/Repeat-16-disable-Black.png") no-repeat left top;
+                background-size: 100% 100%;
+            }
+        }
+        .pinyin-16 {
+            background: url("../assets/icon/pinyin-16-normal-Green.png") no-repeat left top;
+            background-size: 100% 100%;
+            &.disabled {
+                background: url("../assets/icon/pinyin-16-disable-Black.png") no-repeat left top;
+                background-size: 100% 100%;
+            }
+        }
+        .EN-16 {
+            background: url("../assets/icon/EN-16-normal-Green.png") no-repeat left top;
+            background-size: 100% 100%;
+            &.disabled {
+                background: url("../assets/icon/EN-16-disable-Black.png") no-repeat left top;
+                background-size: 100% 100%;
+            }
+        }
     }
     &.NPC-Big-Book-preview-brown {
         .Audio {
@@ -367,36 +382,43 @@ input:-ms-input-placeholder {
                     width: 25px;
                 }
             }
-            &.Audio-tts{
-              .audioLine {
-                .playBtn {
-                    background: url("../assets/NPC/tts-play-brown.png") no-repeat left top;
-                    background-size: 100% 100%;
-                }
-                .pauseBtn {
-                    background: url("../assets/NPC/tts-brown.png") no-repeat left top;
-                    background-size: 100% 100%;
+            &.Audio-tts {
+                .audioLine {
+                    .playBtn {
+                        background: url("../assets/NPC/tts-play-brown.png") no-repeat left top;
+                        background-size: 100% 100%;
+                    }
+                    .pauseBtn {
+                        background: url("../assets/NPC/tts-brown.png") no-repeat left top;
+                        background-size: 100% 100%;
+                    }
                 }
-                
-            }
             }
         }
         .Repeat-16 {
-          background: url("../assets/icon/Repeat-16-normal-Brown.png") no-repeat left top;
-          background-size: 100% 100%;
-          &.disabled {
-              background: url("../assets/icon/Repeat-16-disable-Black.png") no-repeat left top;
-              background-size: 100% 100%;
-          }
-      }
-      .pinyin-16 {
-          background: url("../assets/icon/pinyin-16-normal-Brown.png") no-repeat left top;
-          background-size: 100% 100%;
-          &.disabled {
-              background: url("../assets/icon/pinyin-16-disable-Black.png") no-repeat left top;
-              background-size: 100% 100%;
-          }
-      }
+            background: url("../assets/icon/Repeat-16-normal-Brown.png") no-repeat left top;
+            background-size: 100% 100%;
+            &.disabled {
+                background: url("../assets/icon/Repeat-16-disable-Black.png") no-repeat left top;
+                background-size: 100% 100%;
+            }
+        }
+        .pinyin-16 {
+            background: url("../assets/icon/pinyin-16-normal-Brown.png") no-repeat left top;
+            background-size: 100% 100%;
+            &.disabled {
+                background: url("../assets/icon/pinyin-16-disable-Black.png") no-repeat left top;
+                background-size: 100% 100%;
+            }
+        }
+        .EN-16 {
+            background: url("../assets/icon/EN-16-normal-Brown.png") no-repeat left top;
+            background-size: 100% 100%;
+            &.disabled {
+                background: url("../assets/icon/EN-16-disable-Black.png") no-repeat left top;
+                background-size: 100% 100%;
+            }
+        }
     }
 }
 

+ 68 - 20
src/views/adultInput.vue

@@ -36,7 +36,7 @@
           v-for="(fc, fcIndex) in question_list.detailList"
           :key="'fc' + fcIndex"
         >
-          <SentenceSegwordChs :curQue="fc" type="adultinput" />
+          <SentenceSegwordChs :curQue="fc.detail" type="adultinput" />
           <img
             style="position: absolute; right: 683px; top: 2px"
             @click="deleteDetail(fcIndex)"
@@ -44,6 +44,17 @@
             src="../assets/adult/del-close.png"
             alt=""
           />
+          <div class="Big-Book-top" style="margin: 10px 0">
+            <span>英文</span>
+            <el-input
+              v-model="fc.en"
+              style="width: 80%"
+              type="textarea"
+              autosize
+              placeholder="请输入英文"
+              @blur="onBlur(fc, 'en')"
+            />
+          </div>
         </div>
         <div class="addoption" @click="addDetail">添加分句</div>
         <div
@@ -574,13 +585,24 @@
                     />
                   </template>
                 </template>
+                <template v-if="topicIitem.type == 'upload_pdf_chs'">
+                  <template v-if="topicIitem.is_edit">
+                    <UploadPdf
+                      :curQue="topicIitem.data"
+                      :type="topicIitem.type"
+                      :fn_data="fn_data"
+                      :changeCurQue="changeCurQue"
+                    />
+                  </template>
+                  <template v-else> </template>
+                </template>
               </div>
               <div
                 v-if="topicIitem.data && topicIitem.is_edit"
                 class="addoption"
                 @click="remoeModule(toindex, rowIndex, lineIndex, topicIitem)"
               >
-                删除模板 {{topicIitem.type}}
+                删除模板 {{ topicIitem.type }}
               </div>
               <div
                 v-else-if="
@@ -734,6 +756,8 @@ import Tinydemo from "@/components/Adult/inputModules/Tinydemo.vue";
 import VideoControl from "@/components/Adult/inputModules/VideoControl.vue";
 import Table from "@/components/Adult/inputModules/Table.vue";
 import PlayRecord from "@/components/Adult/inputModules/PlayRecord.vue";
+import UploadPdf from "@/components/Adult/inputModules/UploadPdf.vue";
+
 
 import Textdes from "@/components/Adult/inputModules/Textdes.vue";
 import Record from "@/components/Adult/inputModules/Record.vue";
@@ -825,6 +849,7 @@ export default {
     TableView,
     PlayRecord,
     PlayRecordView,
+    UploadPdf,
   },
   data() {
     return {
@@ -838,12 +863,15 @@ export default {
       org_question_list: {
         detailList: [
           {
-            type: "detail",
-            pyPosition: "top", //top 拼音在上面;bottom 拼音在下面
-            sentence: "", //句子
-            segList: [], //分词结果
-            seg_words: "",
-            wordsList: [],
+            detail: {
+              type: "detail",
+              pyPosition: "top", //top 拼音在上面;bottom 拼音在下面
+              sentence: "", //句子
+              segList: [], //分词结果
+              seg_words: "",
+              wordsList: [],
+            },
+            en: "",
           },
         ], //目录分词
         classTopic: [
@@ -858,12 +886,15 @@ export default {
       question_list: {
         detailList: [
           {
-            type: "detail",
-            pyPosition: "top", //top 拼音在上面;bottom 拼音在下面
-            sentence: "", //句子
-            segList: [], //分词结果
-            seg_words: "",
-            wordsList: [],
+            detail: {
+              type: "detail",
+              pyPosition: "top", //top 拼音在上面;bottom 拼音在下面
+              sentence: "", //句子
+              segList: [], //分词结果
+              seg_words: "",
+              wordsList: [],
+            },
+            en: "",
           },
         ], //目录分词
         classTopic: [
@@ -957,6 +988,9 @@ export default {
   activated() {},
   // 方法集合
   methods: {
+    forupdata() {
+      this.$forceUpdate();
+    },
     // 增加列
     addCol(tyoe, rowindex, colindex, toindex) {},
     // 添加行
@@ -1029,12 +1063,15 @@ export default {
     // 增加当前页的分词
     addDetail() {
       let obj = {
-        type: "detail",
-        pyPosition: "top", //top 拼音在上面;bottom 拼音在下面
-        sentence: "", //句子
-        segList: [], //分词结果
-        seg_words: "",
-        wordsList: [],
+        detail: {
+          type: "detail",
+          pyPosition: "top", //top 拼音在上面;bottom 拼音在下面
+          sentence: "", //句子
+          segList: [], //分词结果
+          seg_words: "",
+          wordsList: [],
+        },
+        en: "",
       };
       this.question_list.detailList.push(obj);
     },
@@ -1159,6 +1196,17 @@ export default {
           this.question_list = res.content
             ? JSON.parse(res.content)
             : JSON.parse(JSON.stringify(this.org_question_list));
+          let data = JSON.parse(JSON.stringify(this.question_list));
+          data.detailList.forEach((item) => {
+            if (!item.detail) {
+              let obj = JSON.parse(JSON.stringify(item));
+              item.detail = obj;
+            }
+            if (!item.en) {
+              item.en = "";
+            }
+          });
+          this.question_list = JSON.parse(JSON.stringify(data));
           if (this.previewVisible) {
             this.onPreview();
           }