Browse Source

1、笔记与收藏 2、移动端预览

dsy 3 months ago
parent
commit
f1d38cb077
30 changed files with 922 additions and 353 deletions
  1. 13 2
      src/views/book/courseware/preview/components/article/NormalModelChs.vue
  2. 87 9
      src/views/book/courseware/preview/components/article/PhraseModelChs.vue
  3. 6 2
      src/views/book/courseware/preview/components/article/Practicechs.vue
  4. 294 237
      src/views/book/courseware/preview/components/article/Voicefullscreen.vue
  5. 1 0
      src/views/book/courseware/preview/components/article/WordModelChs.vue
  6. 2 2
      src/views/book/courseware/preview/components/article/components/Freewrite.vue
  7. 7 2
      src/views/book/courseware/preview/components/article/components/Notecard.vue
  8. 1 1
      src/views/book/courseware/preview/components/article/components/Strockplay.vue
  9. 1 1
      src/views/book/courseware/preview/components/article/components/Strockplayredline.vue
  10. 2 2
      src/views/book/courseware/preview/components/article/components/Strockred.vue
  11. 9 3
      src/views/book/courseware/preview/components/article/components/Wordcard.vue
  12. 15 3
      src/views/book/courseware/preview/components/article/index.vue
  13. 3 1
      src/views/book/courseware/preview/components/dialogue_article/NormalModelChs.vue
  14. 6 4
      src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue
  15. 63 49
      src/views/book/courseware/preview/components/dialogue_article/Practicechs.vue
  16. 6 5
      src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue
  17. 7 0
      src/views/book/courseware/preview/components/dialogue_article/index.vue
  18. 22 7
      src/views/book/courseware/preview/components/drawing/DrawingPreview.vue
  19. 1 2
      src/views/book/courseware/preview/components/fill/FillPreview.vue
  20. 12 1
      src/views/book/courseware/preview/components/h5_games/H5GamesPreview.vue
  21. 24 2
      src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue
  22. 1 1
      src/views/book/courseware/preview/components/newWord_template/components/Strockplayredline.vue
  23. 16 2
      src/views/book/courseware/preview/components/new_word/NewWordPreview.vue
  24. 1 0
      src/views/book/courseware/preview/components/new_word/components/writeTableZoom.vue
  25. 1 1
      src/views/book/courseware/preview/components/notes/NotesPreview.vue
  26. 27 8
      src/views/book/courseware/preview/components/select/SelectPreview.vue
  27. 11 2
      src/views/book/courseware/preview/components/table/TablePreview.vue
  28. 8 1
      src/views/book/courseware/preview/components/upload_preview/UploadPreviewPreview.vue
  29. 7 1
      src/views/book/courseware/preview/components/video_interaction/VideoInteractionPreview.vue
  30. 268 2
      src/web_preview/index.vue

+ 13 - 2
src/views/book/courseware/preview/components/article/NormalModelChs.vue

@@ -1179,9 +1179,10 @@
         :style="{
           marginLeft: windowWidth > 642 ? '-321px' : '0px',
           left: windowWidth > 642 ? '' : '0px',
+          width: isMobile ? '100%' : '',
         }"
       >
-        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" />
+        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" :isMobile="isMobile" />
       </div>
     </template>
   </div>
@@ -1196,7 +1197,17 @@ export default {
     AudioLine,
     Notecard,
   },
-  props: ['curQue', 'noFont', 'config', 'NNPEAnnotationList', 'colLength', 'themeColor', 'multilingual', 'attrib'],
+  props: [
+    'curQue',
+    'noFont',
+    'config',
+    'NNPEAnnotationList',
+    'colLength',
+    'themeColor',
+    'multilingual',
+    'attrib',
+    'isMobile',
+  ],
   data() {
     return {
       resArr: [],

+ 87 - 9
src/views/book/courseware/preview/components/article/PhraseModelChs.vue

@@ -124,8 +124,30 @@
                                     : ''
                                   : '',
                             }"
-                            @click.stop="viewNotes($event, pItem.words ? pItem.words : pItem.chs)"
-                            >{{ pItem.chs }}</span
+                            ><span
+                              v-for="(wItem, wIndex) in pItem.leg"
+                              :key="'ci' + wIndex + pIndex + index"
+                              :class="[
+                                pItem.chstimeList &&
+                                pItem.chstimeList[wIndex] &&
+                                curTime >= pItem.chstimeList[wIndex].wordBg &&
+                                curTime < item.timeList[pItem.sentIndex].ed
+                                  ? 'wordActive'
+                                  : '',
+                              ]"
+                              :style="{
+                                color:
+                                  pItem.chstimeList &&
+                                  pItem.chstimeList[wIndex] &&
+                                  curTime >= pItem.chstimeList[wIndex].wordBg &&
+                                  curTime < item.timeList[pItem.sentIndex].ed &&
+                                  attrib
+                                    ? attrib.topic_color
+                                    : '',
+                              }"
+                              @click.stop="viewNotes($event, pItem.chs[wIndex], pItem.chs)"
+                              >{{ pItem.chs[wIndex] }}</span
+                            ></span
                           >
                           <span
                             v-if="curQue.property.pinyin_position == 'bottom' && config.isShowPY && item.dhaspinyin"
@@ -323,8 +345,30 @@
                                   : ''
                                 : '',
                           }"
-                          @click.stop="viewNotes($event, pItem.words ? pItem.words : pItem.chs)"
-                          >{{ pItem.chs }}</span
+                          ><span
+                            v-for="(wItem, wIndex) in pItem.leg"
+                            :key="'ci' + wIndex + pIndex + index"
+                            :class="[
+                              pItem.chstimeList &&
+                              pItem.chstimeList[wIndex] &&
+                              curTime >= pItem.chstimeList[wIndex].wordBg &&
+                              curTime < item.timeList[pItem.sentIndex].ed
+                                ? 'wordActive'
+                                : '',
+                            ]"
+                            :style="{
+                              color:
+                                pItem.chstimeList &&
+                                pItem.chstimeList[wIndex] &&
+                                curTime >= pItem.chstimeList[wIndex].wordBg &&
+                                curTime < item.timeList[pItem.sentIndex].ed &&
+                                attrib
+                                  ? attrib.topic_color
+                                  : '',
+                            }"
+                            @click.stop="viewNotes($event, pItem.chs[wIndex], pItem.chs)"
+                            >{{ pItem.chs[wIndex] }}</span
+                          ></span
                         >
                         <span
                           v-if="curQue.property.pinyin_position == 'bottom' && config.isShowPY && item.dhaspinyin"
@@ -451,7 +495,7 @@
                                 lineHeight:
                                   attrib && attrib.font_size ? attrib.font_size.replace('pt', '') * 1.4 + 'pt' : '28px',
                               }"
-                              @click.stop="viewNotes($event, pItem.words ? pItem.words : pItem.chs[wIndex])"
+                              @click.stop="viewNotes($event, pItem.words ? pItem.words : pItem.chs[wIndex], pItem.chs)"
                               >{{ pItem.chs[wIndex] }}</span
                             >
                           </template>
@@ -665,7 +709,7 @@
                               lineHeight:
                                 attrib && attrib.font_size ? attrib.font_size.replace('pt', '') * 1.4 + 'pt' : '28px',
                             }"
-                            @click.stop="viewNotes($event, pItem.words ? pItem.words : pItem.chs[wIndex])"
+                            @click.stop="viewNotes($event, pItem.words ? pItem.words : pItem.chs[wIndex], pItem.chs)"
                             >{{ pItem.chs[wIndex] }}</span
                           >
                         </template>
@@ -823,6 +867,7 @@
           :bg="activeWord ? activeWord.bg : null"
           :ed="activeWord ? activeWord.ed : null"
           :attrib="attrib"
+          :isMobile="isMobile"
           @changeCurQue="changeCurQue"
         />
       </div>
@@ -834,9 +879,10 @@
         :style="{
           marginLeft: windowWidth > 642 ? '-321px' : '0px',
           left: windowWidth > 642 ? '' : '0px',
+          width: isMobile ? '100%' : '',
         }"
       >
-        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" />
+        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" :isMobile="isMobile" />
       </div>
     </template>
   </div>
@@ -846,7 +892,6 @@
 import AudioLine from '../voice_matrix/components/AudioLine.vue';
 import Wordcard from './components/Wordcard.vue'; // 卡片
 import Notecard from './components/Notecard.vue'; // 注释
-import $ from 'jquery';
 export default {
   name: 'PhraseModelChs',
   components: {
@@ -867,6 +912,7 @@ export default {
     'colLength',
     'multilingual',
     'attrib',
+    'isMobile',
   ],
   data() {
     return {
@@ -1057,6 +1103,7 @@ export default {
               isShow: wItem.isShow,
               isNewWord: this.newWords.indexOf(wItem.chs) > -1,
               words,
+              leg: wItem.chs.length,
               config: {
                 fontFamily: wItem.fontFamily,
               },
@@ -1356,7 +1403,7 @@ export default {
         }
       }
     },
-    viewNotes(e, noteNum) {
+    viewNotes(e, noteNum, noteNums) {
       let _this = this;
       _this.clickType = 'note';
       _this.activeWord = null;
@@ -1400,6 +1447,37 @@ export default {
         } else {
           _this.left = left;
         }
+      } else if (this.newWordList.indexOf(noteNums) > -1) {
+        if (_this.oldHz != noteNums) {
+          this.isShow = false;
+          _this.NNPENewWordList.forEach((items) => {
+            // item.forEach((items) => {
+            if (items.new_word === noteNums) {
+              this.activeWord = items;
+            }
+            // });
+          });
+          setTimeout(() => {
+            _this.hz = noteNums;
+          }, 50);
+        }
+        _this.clientY = e.clientY;
+        let left = e.clientX;
+        let width = 0;
+
+        if (noteNums.length == 1 || noteNums.length == 2) {
+          width = 304;
+        } else if (noteNums.length == 3 || noteNums.length == 4) {
+          width = 432;
+        } else if (noteNums.length > 3) {
+          width = 560;
+        }
+
+        if (left - this.bodyLeft > this.contentWidth / 2) {
+          _this.left = left - width + 10;
+        } else {
+          _this.left = left;
+        }
       }
     },
     showNoteDetail(e, noteNum) {

+ 6 - 2
src/views/book/courseware/preview/components/article/Practicechs.vue

@@ -630,6 +630,7 @@
         :mp3="curQue.mp3_list && curQue.mp3_list[0] ? curQue.mp3_list[0].url : ''"
         :no-font="noFont"
         :NNPENewWordList="NNPENewWordList"
+        :NNPEAnnotationList="NNPEAnnotationList"
         :current-tree-i-d="currentTreeID"
         :config="config"
         :TaskModel="TaskModel"
@@ -662,6 +663,7 @@ export default {
     'noFont',
     'themeColor',
     'NNPENewWordList',
+    'NNPEAnnotationList',
     'currentTreeID',
     'config',
     'TaskModel',
@@ -1226,7 +1228,8 @@ export default {
       display: flex;
       align-items: center;
       justify-content: flex-start;
-      width: 304px;
+
+      // width: 304px;
       padding: 4px 12px;
       background: #fff;
       border: 1px solid rgba(0, 0, 0, 10%);
@@ -1234,7 +1237,8 @@ export default {
 
       .luyin-box {
         width: 280px;
-        max-width: 280px;
+
+        // max-width: 280px;
       }
 
       .compare-box {

+ 294 - 237
src/views/book/courseware/preview/components/article/Voicefullscreen.vue

@@ -1,126 +1,16 @@
 <!--  -->
 <template>
   <div v-if="sentList" :class="['voicefull', bgIndex == 0 ? 'bg1' : 'bg2']">
-    <div class="voicefull-top" @mouseover="setTopShow(true)" @mouseleave="setTopShow(false)">
-      <div :class="[isTopShow ? 'voicefull-top-show' : 'voicefull-top-hidden']">
-        <div class="top-left">
-          <div :class="['select-bg', bgIndex == 1 ? 'select-bg-blue' : '']">
-            <div :class="['bg-green-box', bgIndex == 1 ? 'active' : '']">
-              <span :class="['bg-green', bgIndex == 1 ? 'active' : '']" @click="changeBg(1)"></span>
-            </div>
-            <div :class="['bg-white-box', bgIndex == 0 ? 'active' : '']">
-              <span :class="['bg-white', bgIndex == 0 ? 'active' : '']" @click="changeBg(0)"></span>
-            </div>
-          </div>
-          <div :class="['set-fontSize', bgIndex == 1 ? 'set-fontSize-green' : '']">
-            <template v-if="hzSize >= 34">
-              <span
-                :class="['font-jian-black', bgIndex == 1 ? 'font-jian-yellow' : '']"
-                @click="setFontSize('-')"
-              ></span>
-            </template>
-            <template v-else>
-              <span
-                :class="['font-jian-black', bgIndex == 1 ? 'font-jian-yellow-disabled' : 'font-jian-white-disabled']"
-              ></span>
-            </template>
-            <span :class="['font-img-black', bgIndex == 1 ? 'font-img-yellow' : '']"></span>
-            <template v-if="hzSize <= 76">
-              <span :class="['font-jia-black', bgIndex == 1 ? 'font-jia-yellow' : '']" @click="setFontSize('+')"></span>
-            </template>
-            <template v-else>
-              <span
-                :class="['font-jia-black', bgIndex == 1 ? 'font-jia-yellow-disabled' : 'font-jia-white-disabled']"
-              ></span>
-            </template>
-          </div>
-          <div
-            :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']"
-            title="键盘控制开启后,可用方向键控制翻页,空格键播放暂停,回车键录音"
-            @click="changeStatus('isKeyboard')"
-          >
-            <span
-              :class="[
-                'keyboard-icon',
-                !isKeyboard ? 'disabled' : '',
-                isKeyboard && bgIndex == 1 ? 'keyboard-icon-yellow' : '',
-              ]"
-            ></span>
-          </div>
-        </div>
-        <div class="top-middle">
-          <template v-if="mp3">
-            <AudioLineSentence
-              :key="'sent' + curSentIndex"
-              ref="audioLineSent"
-              :mp3="mp3"
-              :get-cur-time="getCurTime"
-              :audio-id="'artPraAudioId' + curSentIndex"
-              :stop-audio="stopAudio"
-              :width="120"
-              :hide-slider="true"
-              :bg="bg"
-              :ed="ed"
-              :cur-time="curTime"
-              :max-time="maxTime"
-              :bg-index="bgIndex"
-              :is-repeat="isRepeat"
-              :is-auto="isAuto"
-              @playChange="playChange"
-              @rollSentence="rollSentence"
-            />
-          </template>
-          <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="setStatus">
-            <span
-              :class="[
-                'repeat-icon',
-                !isRepeat && !isAuto ? 'disabled' : '',
-                !isRepeat && isAuto ? 'auto-icon' : '',
-                isRepeat && bgIndex == 1 ? 'repeat-icon-yellow' : '',
-                !isRepeat && isAuto && bgIndex == 1 ? 'auto-icon-yellow' : '',
-              ]"
-            ></span>
-          </div>
-          <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="changePinyin">
-            <span
-              :class="[
-                'pinyin-icon',
-                !config.isShowPY ? 'disabled' : '',
-                config.isShowPY && bgIndex == 1 ? 'pinyin-icon-yellow' : '',
-              ]"
-            ></span>
-          </div>
-          <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="changeEN">
-            <span
-              :class="[
-                'en-icon',
-                !enwords ? 'disabled' : '',
-                !config.isShowEN ? 'disabled' : '',
-                config.isShowEN && bgIndex == 1 ? 'en-icon-yellow' : '',
-              ]"
-            ></span>
-          </div>
-          <!-- <div
-            :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']"
-            title="点击收藏后可在“个人中心”-“我的收藏”查看"
-            @click="handleColl"
-          >
-            <span
-              :class="[
-                'coll-icon',
-                !isCollArr[curSentIndex] ? 'disabled' : '',
-                isCollArr[curSentIndex] && bgIndex == 1 ? 'coll-icon-yellow' : '',
-              ]"
-            ></span>
-          </div> -->
-        </div>
-        <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="exitFullScreen">
-          <span :class="['close-icon', bgIndex == 1 ? 'close-icon-white' : '']"></span>
+    <div class="voicefull-bottom" @mouseover="setTopShow(true)" @mouseleave="setTopShow(false)">
+      <div :class="[isTopShow ? 'voicefull-bottom-show' : 'voicefull-bottom-hidden']">
+        <div :class="['bottom-left', TaskModel == 'ANSWER' ? 'bottom-left-margin' : '']"></div>
+        <div :class="['page-count', bgIndex == 0 ? 'page-count-white' : 'page-count-green']">
+          {{ curSentIndex + 1 }}/{{ sentList.length }}
         </div>
       </div>
     </div>
     <div v-if="item" class="voicefull-content">
-      <div class="vc-box" @mousemove="showPrevNext(true, 'isShowLeft')" @mouseleave="showPrevNext(false, 'isShowLeft')">
+      <div class="vc-box">
         <div
           :class="[
             'vc-left vc-left-grey',
@@ -152,7 +42,7 @@
             @dblclick="showWordDetail($event, pItem)"
             @click="playWord(pItem)"
           >
-            <template v-if="NumberList.indexOf(pItem.chs) == -1">
+            <template>
               <template v-if="!pItem.width">
                 <template v-if="pItem.isShow">
                   <template
@@ -172,7 +62,7 @@
                             fontSize: pySize + 'px',
                             height: pySize * 1.25 + 'px',
                           }"
-                          >{{ pItem.pinyin }}</span
+                          >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
                         >
                       </template>
                       <span
@@ -230,7 +120,7 @@
                             fontSize: pySize + 'px',
                             height: pySize * 1.25 + 'px',
                           }"
-                          >{{ pItem.pinyin }}</span
+                          >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
                         >
                       </template>
                     </span>
@@ -248,7 +138,7 @@
                             textAlign: left,
                             height: pySize * 1.25 + 'px',
                           }"
-                          >{{ item[pIndex + 1].pinyin }}</span
+                          >{{ NumberList.indexOf(item[pIndex + 1].pinyin) == -1 ? item[pIndex + 1].pinyin : '' }}</span
                         >
                       </template>
                       <span
@@ -301,7 +191,7 @@
                             textAlign: left,
                             height: pySize * 1.25 + 'px',
                           }"
-                          >{{ item[pIndex + 1].pinyin }}</span
+                          >{{ NumberList.indexOf(item[pIndex + 1].pinyin) == -1 ? item[pIndex + 1].pinyin : '' }}</span
                         >
                       </template>
                     </span>
@@ -322,7 +212,7 @@
                             textAlign: left,
                             height: pySize * 1.25 + 'px',
                           }"
-                          >{{ item[pIndex + 2].pinyin }}</span
+                          >{{ NumberList.indexOf(item[pIndex + 2].pinyin) == -1 ? item[pIndex + 2].pinyin : '' }}</span
                         >
                       </template>
                       <span
@@ -375,30 +265,28 @@
                             textAlign: left,
                             height: pySize * 1.25 + 'px',
                           }"
-                          >{{ item[pIndex + 2].pinyin }}</span
+                          >{{ NumberList.indexOf(item[pIndex + 2].pinyin) == -1 ? item[pIndex + 2].pinyin : '' }}</span
                         >
                       </template>
                     </span>
                   </template>
                   <template v-else>
                     <template v-if="curQue.property.pinyin_position == 'top'">
-                      <template v-if="NumberList.indexOf(pItem.pinyin) < 0">
-                        <span
-                          v-if="config.isShowPY"
-                          class="NNPE-pinyin"
-                          :class="[
-                            pItem.chs != '“' && pItem.padding ? 'padding' : '',
-                            pItem.className ? pItem.className : '',
-                            noFont.indexOf(pItem.pinyin) > -1 ? 'noFont' : '',
-                            bgIndex == 1 ? 'font-white' : '',
-                          ]"
-                          :style="{
-                            fontSize: pySize + 'px',
-                            height: pySize * 1.25 + 'px',
-                          }"
-                          >{{ pItem.pinyin }}</span
-                        >
-                      </template>
+                      <span
+                        v-if="config.isShowPY"
+                        class="NNPE-pinyin"
+                        :class="[
+                          pItem.chs != '“' && pItem.padding ? 'padding' : '',
+                          pItem.className ? pItem.className : '',
+                          noFont.indexOf(pItem.pinyin) > -1 ? 'noFont' : '',
+                          bgIndex == 1 ? 'font-white' : '',
+                        ]"
+                        :style="{
+                          fontSize: pySize + 'px',
+                          height: pySize * 1.25 + 'px',
+                        }"
+                        >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
+                      >
                     </template>
                     <span
                       v-if="pItem.chs != '#'"
@@ -444,22 +332,20 @@
                       </template>
                     </span>
                     <template v-if="curQue.property.pinyin_position == 'bottom'">
-                      <template v-if="NumberList.indexOf(pItem.pinyin) < 0">
-                        <span
-                          v-if="config.isShowPY"
-                          class="NNPE-pinyin bottom"
-                          :class="[
-                            pItem.chs != '“' && pItem.padding ? 'padding' : '',
-                            pItem.className ? pItem.className : '',
-                            bgIndex == 1 ? 'font-white' : '',
-                          ]"
-                          :style="{
-                            fontSize: pySize + 'px',
-                            height: pySize * 1.25 + 'px',
-                          }"
-                          >{{ pItem.pinyin }}</span
-                        >
-                      </template>
+                      <span
+                        v-if="config.isShowPY"
+                        class="NNPE-pinyin bottom"
+                        :class="[
+                          pItem.chs != '“' && pItem.padding ? 'padding' : '',
+                          pItem.className ? pItem.className : '',
+                          bgIndex == 1 ? 'font-white' : '',
+                        ]"
+                        :style="{
+                          fontSize: pySize + 'px',
+                          height: pySize * 1.25 + 'px',
+                        }"
+                        >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
+                      >
                     </template>
                   </template>
                 </template>
@@ -487,11 +373,7 @@
           {{ enwords }}
         </div>
       </div>
-      <div
-        class="vc-box-right"
-        @mousemove="showPrevNext(true, 'isShowRight')"
-        @mouseleave="showPrevNext(false, 'isShowRight')"
-      >
+      <div class="vc-box-right">
         <div
           :class="[
             'vc-left vc-right-grey',
@@ -503,48 +385,121 @@
         ></div>
       </div>
     </div>
-    <div class="voicefull-bottom" @mouseover="setBottomShow(true)" @mouseleave="setBottomShow(false)">
-      <div :class="[isBottomShow ? 'voicefull-bottom-show' : 'voicefull-bottom-hidden']">
-        <div :class="['bottom-left', TaskModel == 'ANSWER' ? 'bottom-left-margin' : '']">
-          <Soundrecorddiff
-            ref="Soundrecorddiff"
-            :bg-index="bgIndex"
-            :TaskModel="TaskModel"
-            :answer-record-list="
-              curQue.Bookanswer.practiceModel[curSentIndex] && curQue.Bookanswer.practiceModel[curSentIndex].recordList
-            "
-            :tm-index="curSentIndex"
-            @handleWav="handleWav"
-            :key="'Soundrecorddiff' + curSentIndex"
-            @getWavblob="getWavblob"
-            @handleParentPlay="handleParentPlay"
-            @sentPause="sentPause"
-            @getRerordStatus="getRerordStatus"
-            @getMicrophoneStatus="getMicrophoneStatus"
-            @getPlayStatus="getPlayStatus"
-          />
-          <div v-if="isShowCompare" :class="['compare-box', bgIndex == 1 ? 'compare-box-white' : '']">
-            <Audio-compare
-              :bg-index="bgIndex"
-              type="full"
-              :theme-color="themeColor"
-              :index="curSentIndex"
-              :sent-index="curSentIndex"
-              :key="'mp3Compare' + curSentIndex"
-              :url="curQue.mp3_list[0].id"
+    <div class="voicefull-top" @mouseover="setBottomShow(true)" @mouseleave="setBottomShow(false)">
+      <div :class="[isBottomShow ? 'voicefull-top-show' : 'voicefull-top-hidden']">
+        <div class="top-left">
+          <div :class="['select-bg', bgIndex == 1 ? 'select-bg-blue' : '']">
+            <div :class="['bg-green-box', bgIndex == 1 ? 'active' : '']">
+              <span :class="['bg-green', bgIndex == 1 ? 'active' : '']" @click="changeBg(1)"></span>
+            </div>
+            <div :class="['bg-white-box', bgIndex == 0 ? 'active' : '']">
+              <span :class="['bg-white', bgIndex == 0 ? 'active' : '']" @click="changeBg(0)"></span>
+            </div>
+          </div>
+          <div :class="['set-fontSize', bgIndex == 1 ? 'set-fontSize-green' : '']">
+            <template v-if="hzSize >= 34">
+              <span
+                :class="['font-jian-black', bgIndex == 1 ? 'font-jian-yellow' : '']"
+                @click="setFontSize('-')"
+              ></span>
+            </template>
+            <template v-else>
+              <span
+                :class="['font-jian-black', bgIndex == 1 ? 'font-jian-yellow-disabled' : 'font-jian-white-disabled']"
+              ></span>
+            </template>
+            <span :class="['font-img-black', bgIndex == 1 ? 'font-img-yellow' : '']"></span>
+            <template v-if="hzSize <= 76">
+              <span :class="['font-jia-black', bgIndex == 1 ? 'font-jia-yellow' : '']" @click="setFontSize('+')"></span>
+            </template>
+            <template v-else>
+              <span
+                :class="['font-jia-black', bgIndex == 1 ? 'font-jia-yellow-disabled' : 'font-jia-white-disabled']"
+              ></span>
+            </template>
+          </div>
+          <div
+            :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']"
+            title="键盘控制开启后,可用方向键控制翻页,空格键播放暂停,回车键录音"
+            @click="changeStatus('isKeyboard')"
+          >
+            <span
+              :class="[
+                'keyboard-icon',
+                !isKeyboard ? 'disabled' : '',
+                isKeyboard && bgIndex == 1 ? 'keyboard-icon-yellow' : '',
+              ]"
+            ></span>
+          </div>
+        </div>
+        <div class="top-middle">
+          <template v-if="mp3">
+            <AudioLineSentence
+              :key="'sent' + curSentIndex"
+              ref="audioLineSent"
+              :mp3="mp3"
+              :get-cur-time="getCurTime"
+              :audio-id="'artPraAudioId' + curSentIndex"
+              :stop-audio="stopAudio"
+              :width="120"
+              :hide-slider="true"
               :bg="bg"
               :ed="ed"
-              :wavblob="wavblob"
-              :get-cur-time="getCurCompareTime"
-              :sent-pause="sentPause"
-              :is-record="isRecord"
-              :handle-change-stop-audio="handleChangeStopAudio"
-              :get-play-status="getPlayStatus"
+              :cur-time="curTime"
+              :max-time="maxTime"
+              :bg-index="bgIndex"
+              :is-repeat="isRepeat"
+              :is-auto="isAuto"
+              @playChange="playChange"
+              @rollSentence="rollSentence"
             />
+          </template>
+          <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="setStatus">
+            <span
+              :class="[
+                'repeat-icon',
+                !isRepeat && !isAuto ? 'disabled' : '',
+                !isRepeat && isAuto ? 'auto-icon' : '',
+                isRepeat && bgIndex == 1 ? 'repeat-icon-yellow' : '',
+                !isRepeat && isAuto && bgIndex == 1 ? 'auto-icon-yellow' : '',
+              ]"
+            ></span>
+          </div>
+          <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="changePinyin">
+            <span
+              :class="[
+                'pinyin-icon',
+                !config.isShowPY ? 'disabled' : '',
+                config.isShowPY && bgIndex == 1 ? 'pinyin-icon-yellow' : '',
+              ]"
+            ></span>
           </div>
+          <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="changeEN">
+            <span
+              :class="[
+                'en-icon',
+                !enwords ? 'disabled' : '',
+                !config.isShowEN ? 'disabled' : '',
+                config.isShowEN && bgIndex == 1 ? 'en-icon-yellow' : '',
+              ]"
+            ></span>
+          </div>
+          <!-- <div
+            :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']"
+            title="点击收藏后可在“个人中心”-“我的收藏”查看"
+            @click="handleColl"
+          >
+            <span
+              :class="[
+                'coll-icon',
+                !isCollArr[curSentIndex] ? 'disabled' : '',
+                isCollArr[curSentIndex] && bgIndex == 1 ? 'coll-icon-yellow' : '',
+              ]"
+            ></span>
+          </div> -->
         </div>
-        <div :class="['page-count', bgIndex == 0 ? 'page-count-white' : 'page-count-green']">
-          {{ curSentIndex + 1 }}/{{ sentList.length }}
+        <div :class="['op-btn', bgIndex == 1 ? 'op-btn-green' : '']" @click="exitFullScreen">
+          <span :class="['close-icon', bgIndex == 1 ? 'close-icon-white' : '']"></span>
         </div>
       </div>
     </div>
@@ -559,6 +514,9 @@
           :mp3-url="wordPlayMp3"
           :bg="wordbgs"
           :ed="wordeds"
+          :attrib="attrib"
+          :isMobile="isMobile"
+          :isFull="true"
         />
       </div>
     </template>
@@ -580,6 +538,19 @@
         @changePlayStatus="changePlayStatus"
       />
     </div>
+    <template v-if="isNoteShow">
+      <div
+        ref="notecard"
+        class="NNPE-wordDetail"
+        :style="{
+          marginLeft: windowWidth > 642 ? '-321px' : '0px',
+          left: windowWidth > 642 ? '' : '0px',
+          width: isMobile ? '100%' : '',
+        }"
+      >
+        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" :isMobile="isMobile" />
+      </div>
+    </template>
   </div>
 </template>
 
@@ -588,8 +559,9 @@ import AudioLineSentence from './components/AudioLineSentence.vue';
 import Soundrecorddiff from './components/Soundrecorddiff.vue';
 import AudioCompare from './components/AudioCompare.vue';
 import Wordcard from './components/Wordcard.vue';
+import Notecard from './components/Notecard.vue'; // 注释
 import { LearnWebSI } from '@/api/app';
-import $ from 'jquery';
+
 export default {
   name: 'VoiceFullScreen',
   components: {
@@ -597,6 +569,7 @@ export default {
     Soundrecorddiff,
     AudioCompare,
     Wordcard,
+    Notecard,
   },
   props: [
     'sentList',
@@ -607,11 +580,13 @@ export default {
     'noFont',
     'themeColor',
     'NNPENewWordList',
+    'NNPEAnnotationList',
     'currentTreeID',
     'config',
     'TaskModel',
     'NpcNewWordMp3',
     'attrib',
+    'isMobile',
   ],
   data() {
     return {
@@ -632,8 +607,8 @@ export default {
       stopAudio: false,
       isRecord: false,
       isShowCompare: false,
-      isShowRight: false,
-      isShowLeft: false,
+      isShowRight: true,
+      isShowLeft: true,
       curSentIndex: 0,
       oldHz: '',
       hz: '',
@@ -664,6 +639,10 @@ export default {
       enwords: '',
       screenHeight: 0,
       wordPlayMp3: '',
+      curNoteCon: null,
+      isNoteShow: false,
+      oldNoteNum: '',
+      windowWidth: window.innerWidth,
     };
   },
   computed: {
@@ -727,6 +706,23 @@ export default {
       // 深度观察监听
       deep: true,
     },
+    isNoteShow: {
+      handler(val, oldVal) {
+        let _this = this;
+        if (val) {
+          setTimeout(() => {
+            _this.cardHeight = _this.$refs.notecard.offsetHeight;
+            if (_this.screenHeight - _this.clientY > _this.cardHeight) {
+              _this.top = _this.clientY + 20;
+            } else {
+              _this.top = _this.clientY - _this.cardHeight - 30;
+            }
+          }, 50);
+        }
+      },
+      // 深度观察监听
+      deep: true,
+    },
   },
   // 生命周期 - 创建完成(可以访问当前this实例)
   created() {},
@@ -1166,47 +1162,80 @@ export default {
     },
     showWordDetail(e, item) {
       let _this = this;
+
+      let noteIndex = '';
       if (_this.TaskModel == 'ANSWER') {
         return;
       }
       if (_this.chsFhList.indexOf(item.chs) > -1 || /^[a-zA-Z0-9]/.test(item.chs)) {
         return;
       }
-      if (_this.oldHz != item.chs) {
-        this.isShow = false;
+      if (_this.NumberList.indexOf(item.chs) > -1) {
+        for (let i = 0; i < _this.NumberList.length; i++) {
+          if (_this.NumberList[i] == item.chs) {
+            noteIndex = `${String(i)}`;
+            break;
+          }
+        }
+
+        this.showNoteDetail(e, noteIndex);
+      } else if (this.newWordList.indexOf(item.chs) > -1) {
+        if (_this.oldHz != item.chs) {
+          this.isShow = false;
 
+          setTimeout(() => {
+            _this.hz = item.words ? item.words : item.chs;
+            _this.pinyin = item.pinyin;
+            _this.wordIndex = item.wordIndex;
+          }, 50);
+        }
+        _this.clientY = e.clientY;
+        let new_word = item.words ? item.words : item.chs;
+        _this.wordPlayMp3 = '';
+        _this.NNPENewWordList.forEach((itemn) => {
+          // items.forEach((itemn) => {
+          if (itemn.new_word === new_word) {
+            _this.wordbgs = itemn.bg;
+            _this.wordeds = itemn.ed;
+            _this.wordPlayMp3 = itemn.newWordMp3;
+          }
+          // });
+        });
+        let left = e.clientX;
+        let width = 0;
+        if (item.chs.length == 1 || item.chs.length == 2) {
+          width = 304;
+        } else if (item.chs.length == 3 || item.chs.length == 4) {
+          width = 432;
+        } else if (item.chs.length > 3) {
+          width = 560;
+        }
+        // if (left - this.bodyLeft > this.contentWidth / 2) {
+        //   _this.left = left - width + 10;
+        // } else {
+        _this.left = left - width / 2;
+        // }
+      }
+    },
+    showNoteDetail(e, noteNum) {
+      let _this = this;
+      if (_this.oldNoteNum !== noteNum) {
+        this.isNoteShow = false;
         setTimeout(() => {
-          _this.hz = item.words ? item.words : item.chs;
-          _this.pinyin = item.pinyin;
-          _this.wordIndex = item.wordIndex;
+          _this.noteNum = noteNum;
+          _this.handleNote(noteNum);
         }, 50);
       }
       _this.clientY = e.clientY;
-      let new_word = item.words ? item.words : item.chs;
-      _this.wordPlayMp3 = '';
-      _this.NNPENewWordList.forEach((itemn) => {
-        // items.forEach((itemn) => {
-        if (itemn.new_word === new_word) {
-          _this.wordbgs = itemn.bg;
-          _this.wordeds = itemn.ed;
-          _this.wordPlayMp3 = itemn.newWordMp3;
-        }
-        // });
-      });
       let left = e.clientX;
-      let width = 0;
-      if (item.chs.length == 1 || item.chs.length == 2) {
-        width = 304;
-      } else if (item.chs.length == 3 || item.chs.length == 4) {
-        width = 432;
-      } else if (item.chs.length > 3) {
-        width = 560;
+      let width = 642;
+      if (left - this.bodyLeft > this.contentWidth / 2) {
+        _this.left = left - width + 10;
+      } else if (left - 200 > 500) {
+        _this.left = 500;
+      } else {
+        _this.left = left - 200;
       }
-      // if (left - this.bodyLeft > this.contentWidth / 2) {
-      //   _this.left = left - width + 10;
-      // } else {
-      _this.left = left - width / 2;
-      // }
     },
     changeWordCard(isShow) {
       let _this = this;
@@ -1220,17 +1249,13 @@ export default {
       let _this = this;
       _this.isShow = true;
       _this.word = null;
-
       if (_this.newWordList.indexOf(val) > -1) {
         for (let i = 0; i < this.NNPENewWordList.length; i++) {
           let pItem = this.NNPENewWordList[i];
-          for (let j = 0; j < pItem.length; j++) {
-            let item = pItem[j];
-            if (item.new_word.trim() == val.trim()) {
-              let wordlist = val.split('');
-              this.word = { list: wordlist, detail: item };
-              break;
-            }
+          if (pItem.new_word.trim() == val.trim()) {
+            let wordlist = val.split('');
+            this.word = { list: wordlist, detail: pItem };
+            break;
           }
         }
       } else {
@@ -1257,6 +1282,22 @@ export default {
     getScreenHeight() {
       this.screenHeight = window.innerHeight;
     },
+    // 处理注释数据
+    handleNote(val) {
+      let _this = this;
+      _this.isNoteShow = true;
+      _this.oldNoteNum = val;
+      let noteIndex = Number(val);
+      if (_this.NNPEAnnotationList && _this.NNPEAnnotationList.length > 0) {
+        _this.curNoteCon = _this.NNPEAnnotationList[noteIndex] ? _this.NNPEAnnotationList[noteIndex] : null;
+      }
+    },
+    changeCard(isShow) {
+      let _this = this;
+      _this.isNoteShow = isShow;
+      _this.oldNoteNum = '';
+      _this.noteNum = '';
+    },
   }, // 如果页面有keep-alive缓存功能,这个函数会触发
 };
 </script>
@@ -1945,6 +1986,22 @@ export default {
   position: absolute;
   left: -1000px;
 }
+
+.NNPE-wordDetail {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  z-index: 116;
+  max-width: 100%;
+  margin-top: -196px;
+  overflow: auto;
+
+  // box-shadow: 0 4px 16px rgba(0, 0, 0, 15%);
+
+  //   width: 260px;
+  //   height: 200px;
+  //   background: #cc0;
+}
 </style>
 <style lang="scss">
 .NPC-Big-Book-preview-green {

+ 1 - 0
src/views/book/courseware/preview/components/article/WordModelChs.vue

@@ -824,6 +824,7 @@
           :TaskModel="TaskModel"
           :write-list="curQue.Bookanswer.writeModel"
           :attrib="attrib"
+          :isMobile="isMobile"
           @changeCurQue="changeCurQue"
         />
       </div>

+ 2 - 2
src/views/book/courseware/preview/components/article/components/Freewrite.vue

@@ -187,7 +187,7 @@ export default {
         .generate()
         .then((res) => {
           let Book_img = res.replace('data:image/png;base64,', '');
-          let write_img = `data:image/png;base64,${  Book_img}`;
+          let write_img = `data:image/png;base64,${Book_img}`;
           let answer = {};
           answer = {
             hz,
@@ -315,7 +315,7 @@ export default {
     margin: 0 auto;
 
     .character-target-div {
-      z-index: 99999;
+      z-index: 1;
       display: flex;
       align-items: center;
       justify-content: center;

+ 7 - 2
src/views/book/courseware/preview/components/article/components/Notecard.vue

@@ -1,6 +1,6 @@
 <!--  -->
 <template>
-  <div v-if="item" class="NoteCard">
+  <div v-if="item" class="NoteCard" :class="[isMobile ? 'NoteCard-phone' : '']">
     <div class="closeBox">
       <i class="el-icon-close" @click="changeCard(false)"></i>
     </div>
@@ -36,7 +36,7 @@
 <script>
 export default {
   components: {},
-  props: ['item', 'changeCard', 'attrib'],
+  props: ['item', 'changeCard', 'attrib', 'isMobile'],
   data() {
     return {};
   },
@@ -150,5 +150,10 @@ export default {
   :deep p {
     margin: 0;
   }
+
+  &-phone {
+    width: 100%;
+    margin: 0;
+  }
 }
 </style>

+ 1 - 1
src/views/book/courseware/preview/components/article/components/Strockplay.vue

@@ -86,7 +86,7 @@ export default {
 }
 
 .character-target-div {
-  z-index: 99999;
+  z-index: 1;
   display: flex;
   align-items: center;
   justify-content: center;

+ 1 - 1
src/views/book/courseware/preview/components/article/components/Strockplayredline.vue

@@ -103,7 +103,7 @@ export default {
 }
 
 .character-target-div {
-  z-index: 99999;
+  z-index: 1;
   display: flex;
   align-items: center;
   justify-content: center;

+ 2 - 2
src/views/book/courseware/preview/components/article/components/Strockred.vue

@@ -63,7 +63,7 @@ export default {
     initHanziwrite() {
       let _this = this;
       let options = {
-        charDataLoader (char, onComplete) {
+        charDataLoader(char, onComplete) {
           let MethodName = 'hz_resource_manager-GetHZStrokesContent';
           let data = {
             hz: char,
@@ -108,7 +108,7 @@ export default {
 
   //chinawrite220.png
   .character-target-div {
-    z-index: 99999;
+    z-index: 1;
     display: flex;
     align-items: center;
     justify-content: center;

+ 9 - 3
src/views/book/courseware/preview/components/article/components/Wordcard.vue

@@ -239,6 +239,7 @@ export default {
     'bg',
     'ed',
     'attrib',
+    'isMobile',
   ],
   data() {
     return {
@@ -253,6 +254,7 @@ export default {
       collFlag: false,
       praMp3: '',
       isPhone: false, // 是否是移动端打开
+      NumberList: ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩', '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳'],
     };
   },
   computed: {},
@@ -276,6 +278,8 @@ export default {
       }
     }
     this.word.detail.new_word = new_word_str;
+    const regex = new RegExp(`[${this.NumberList.join('')}]`, 'g');
+    this.word.detail.pinyin = this.word.detail.pinyin.replace(regex, '');
   },
   // 生命周期 - 挂载完成(可以访问DOM元素)
   mounted() {
@@ -640,12 +644,14 @@ export default {
 
     > span {
       width: 100%;
-      overflow: hidden;
+
+      // overflow: hidden;
       font-size: 14px;
       line-height: 22px;
       color: rgba(0, 0, 0, 85%);
-      text-overflow: ellipsis;
-      white-space: nowrap;
+
+      // text-overflow: ellipsis;
+      // white-space: nowrap;
 
       :deep p {
         margin: 0;

+ 15 - 3
src/views/book/courseware/preview/components/article/index.vue

@@ -122,6 +122,7 @@
             :col-length="colLength"
             :multilingual="showLang && getLang() ? getLang() : ''"
             :attrib="data.unified_attrib"
+            :isMobile="isMobile"
             @changeConfig="changeConfig"
           />
           <PhraseModel
@@ -141,6 +142,7 @@
             :NpcNewWordMp3="NpcNewWordMp3"
             :multilingual="showLang && getLang() ? getLang() : ''"
             :attrib="data.unified_attrib"
+            :isMobile="isMobile"
             @changeConfig="changeConfig"
           />
           <Practice
@@ -151,6 +153,7 @@
             :theme-color="bookInfo.theme_color"
             :no-font="noFont"
             :NNPENewWordList="NNPENewWordList"
+            :NNPEAnnotationList="NNPEAnnotationList"
             :current-tree-i-d="courseware_id"
             :config="config"
             :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
@@ -159,6 +162,7 @@
             :is-full="isFull"
             :multilingual="showLang && getLang() ? getLang() : ''"
             :attrib="data.unified_attrib"
+            :isMobile="isMobile"
             @changeConfig="changeConfig"
           />
           <WordModel
@@ -177,6 +181,7 @@
             :col-length="colLength"
             :multilingual="showLang && getLang() ? getLang() : ''"
             :attrib="data.unified_attrib"
+            :isMobile="isMobile"
             @changeConfig="changeConfig"
           />
         </div>
@@ -190,12 +195,14 @@
             :mp3="data.mp3_list && data.mp3_list[0] ? data.mp3_list[0].url : ''"
             :no-font="noFont"
             :NNPENewWordList="NNPENewWordList"
+            :NNPEAnnotationList="NNPEAnnotationList"
             :current-tree-i-d="courseware_id"
             :is-full="isFull"
             :config="config"
             :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
             :NpcNewWordMp3="NpcNewWordMp3"
             :attrib="data.unified_attrib"
+            :isMobile="isMobile"
             @handleWav="handleWav"
             @changePinyin="changePinyins"
             @changeEN="changeENs"
@@ -207,17 +214,17 @@
       <template
         v-if="data.new_word_list && data.new_word_list.new_word_list && data.new_word_list.new_word_list.length > 0"
       >
-        <NewWordPreview :new-data="data.new_word_list" />
+        <NewWordPreview :new-data="data.new_word_list" :isMobile="isMobile" />
       </template>
       <template
         v-if="
           data.other_word_list && data.other_word_list.new_word_list && data.other_word_list.new_word_list.length > 0
         "
       >
-        <NewWordPreview :new-data="data.other_word_list" />
+        <NewWordPreview :new-data="data.other_word_list" :isMobile="isMobile" />
       </template>
       <template v-if="data.notes_list && data.notes_list.option && data.notes_list.option.length > 0">
-        <NotesPreview :notes-data="data.notes_list" />
+        <NotesPreview :notes-data="data.notes_list" :isMobile="isMobile" />
       </template>
     </div>
   </div>
@@ -867,5 +874,10 @@ export default {
       border-bottom: none !important;
     }
   }
+
+  .el-slider {
+    flex: 1;
+    width: auto !important;
+  }
 }
 </style>

+ 3 - 1
src/views/book/courseware/preview/components/dialogue_article/NormalModelChs.vue

@@ -690,9 +690,10 @@
         :style="{
           marginLeft: windowWidth > 642 ? '-321px' : '0px',
           left: windowWidth > 642 ? '' : '0px',
+          width: isMobile ? '100%' : '',
         }"
       >
-        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" />
+        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" :isMobile="isMobile" />
       </div>
     </template>
   </div>
@@ -751,6 +752,7 @@ export default {
     'isPhone',
     'multilingual',
     'attrib',
+    'isMobile',
   ],
   data() {
     return {

+ 6 - 4
src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue

@@ -18,7 +18,7 @@
             :mp3="curQue.mp3_list[0].url"
             :get-cur-time="getCurTime"
             :mp3-source="curQue.mp3_list[0].source"
-            :width="colLength == 2 ? 200 : isPhone ? 200 : 790"
+            :width="colLength == 2 ? 200 : isMobile ? 200 : 790"
             :attrib="attrib"
           />
         </template>
@@ -455,7 +455,7 @@
             :mp3="curQue.mp3_list[0].url"
             :get-cur-time="getCurTime"
             :mp3-source="curQue.mp3_list[0].source"
-            :width="colLength == 2 ? 200 : isPhone ? 200 : 790"
+            :width="colLength == 2 ? 200 : isMobile ? 200 : 790"
             :attrib="attrib"
           />
         </template>
@@ -504,6 +504,7 @@
           :bg="wordbgs"
           :ed="wordeds"
           :attrib="attrib"
+          :isMobile="isMobile"
           @changeCurQue="changeCurQue"
         />
       </div>
@@ -515,9 +516,10 @@
         :style="{
           marginLeft: windowWidth > 642 ? '-321px' : '0px',
           left: windowWidth > 642 ? '' : '0px',
+          width: isMobile ? '100%' : '',
         }"
       >
-        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" />
+        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" :isMobile="isMobile" />
       </div>
     </template>
   </div>
@@ -578,7 +580,7 @@ export default {
     'TaskModel',
     'colLength',
     'NpcNewWordMp3',
-    'isPhone',
+    'isMobile',
     'multilingual',
   ],
   data() {

+ 63 - 49
src/views/book/courseware/preview/components/dialogue_article/Practicechs.vue

@@ -211,7 +211,7 @@
                                       ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
                                       : '22px',
                                 }"
-                                >{{ pItem.pinyin }}</span
+                                >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
                               >
                             </template>
                             <span
@@ -281,7 +281,7 @@
                                       ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
                                       : '22px',
                                 }"
-                                >{{ pItem.pinyin }}</span
+                                >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
                               >
                             </template>
                           </span>
@@ -302,7 +302,11 @@
                                       ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
                                       : '22px',
                                 }"
-                                >{{ item.sentArr[pIndex + 1].pinyin }}</span
+                                >{{
+                                  NumberList.indexOf(item.sentArr[pIndex + 1].pinyin) == -1
+                                    ? item.sentArr[pIndex + 1].pinyin
+                                    : ''
+                                }}</span
                               >
                             </template>
                             <span class="NNPE-chs" style="text-align: left">
@@ -365,7 +369,11 @@
                                       ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
                                       : '22px',
                                 }"
-                                >{{ item.sentArr[pIndex + 1].pinyin }}</span
+                                >{{
+                                  NumberList.indexOf(item.sentArr[pIndex + 1].pinyin) == -1
+                                    ? item.sentArr[pIndex + 1].pinyin
+                                    : ''
+                                }}</span
                               >
                             </template>
                           </span>
@@ -393,7 +401,11 @@
                                       ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
                                       : '22px',
                                 }"
-                                >{{ item.sentArr[pIndex + 2].pinyin }}</span
+                                >{{
+                                  NumberList.indexOf(item.sentArr[pIndex + 2].pinyin) == -1
+                                    ? item.sentArr[pIndex + 2].pinyin
+                                    : ''
+                                }}</span
                               >
                             </template>
                             <span class="NNPE-chs" style="text-align: left">
@@ -456,33 +468,35 @@
                                       ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
                                       : '22px',
                                 }"
-                                >{{ item.sentArr[pIndex + 2].pinyin }}</span
+                                >{{
+                                  NumberList.indexOf(item.sentArr[pIndex + 2].pinyin) == -1
+                                    ? item.sentArr[pIndex + 2].pinyin
+                                    : ''
+                                }}</span
                               >
                             </template>
                           </span>
                         </template>
                         <template v-else>
                           <template v-if="curQue.property.pinyin_position == 'top'">
-                            <template v-if="NumberList.indexOf(pItem.pinyin) < 0">
-                              <span
-                                v-if="config.isShowPY && item.dhaspinyin"
-                                class="NNPE-pinyin"
-                                :class="[
-                                  pItem.chs != '“' && pItem.padding ? 'padding' : '',
-                                  pItem.className ? pItem.className : '',
-                                  sentIndex == index ? 'wordBlank' : '',
-                                  noFont.indexOf(item.pinyin) > -1 ? 'noFont' : '',
-                                ]"
-                                :style="{
-                                  fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
-                                  height:
-                                    attrib && attrib.pinyin_size
-                                      ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
-                                      : '22px',
-                                }"
-                                >{{ pItem.pinyin }}</span
-                              >
-                            </template>
+                            <span
+                              v-if="config.isShowPY && item.dhaspinyin"
+                              class="NNPE-pinyin"
+                              :class="[
+                                pItem.chs != '“' && pItem.padding ? 'padding' : '',
+                                pItem.className ? pItem.className : '',
+                                sentIndex == index ? 'wordBlank' : '',
+                                noFont.indexOf(item.pinyin) > -1 ? 'noFont' : '',
+                              ]"
+                              :style="{
+                                fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
+                                height:
+                                  attrib && attrib.pinyin_size
+                                    ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
+                                    : '22px',
+                              }"
+                              >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
+                            >
                           </template>
                           <span
                             v-if="pItem.chs != '#'"
@@ -531,30 +545,28 @@
                                       ? attrib.topic_color
                                       : '',
                                 }"
-                                >{{ pItem.chs[wIndex] }}</span
+                                >{{ NumberList.indexOf(pItem.chs[wIndex]) == -1 ? pItem.chs[wIndex] : '' }}</span
                               >
                             </template>
                           </span>
                           <template v-if="curQue.property.pinyin_position == 'bottom'">
-                            <template v-if="NumberList.indexOf(pItem.pinyin) < 0">
-                              <span
-                                v-if="config.isShowPY && item.dhaspinyin"
-                                class="NNPE-pinyin"
-                                :class="[
-                                  pItem.chs != '“' && pItem.padding ? 'padding' : '',
-                                  pItem.className ? pItem.className : '',
-                                  sentIndex == index ? 'wordBlank' : '',
-                                ]"
-                                :style="{
-                                  fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
-                                  height:
-                                    attrib && attrib.pinyin_size
-                                      ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
-                                      : '22px',
-                                }"
-                                >{{ pItem.pinyin }}</span
-                              >
-                            </template>
+                            <span
+                              v-if="config.isShowPY && item.dhaspinyin"
+                              class="NNPE-pinyin"
+                              :class="[
+                                pItem.chs != '“' && pItem.padding ? 'padding' : '',
+                                pItem.className ? pItem.className : '',
+                                sentIndex == index ? 'wordBlank' : '',
+                              ]"
+                              :style="{
+                                fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
+                                height:
+                                  attrib && attrib.pinyin_size
+                                    ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
+                                    : '22px',
+                              }"
+                              >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
+                            >
                           </template>
                         </template>
                       </template>
@@ -738,6 +750,7 @@
         :mp3="curQue.mp3_list && curQue.mp3_list[0] ? curQue.mp3_list[0].id : ''"
         :no-font="noFont"
         :NNPENewWordList="NNPENewWordList"
+        :NNPEAnnotationList="NNPEAnnotationList"
         :current-tree-i-d="currentTreeID"
         :is-full="isFull"
         :config="config"
@@ -801,6 +814,7 @@ export default {
     'attrib',
     'config',
     'NNPENewWordList',
+    'NNPEAnnotationList',
     'currentTreeID',
     'TaskModel',
     'colLength',
@@ -1052,7 +1066,6 @@ export default {
       if (wordTimeList && wordTimeList.length > 0) {
         this.mergeWordTime(sentArrTotal, wordTimeList);
       }
-
       this.resObj = { sentList: resArr };
     },
     // 获取角色
@@ -1083,7 +1096,7 @@ export default {
     },
     // 词和标点合一起
     mergeWordSymbol(wItem) {
-      if (this.chsFhList.indexOf(wItem.chs) > -1 || this.NumberList.indexOf(wItem.pinyin) > -1) {
+      if (this.chsFhList.indexOf(wItem.chs) > -1) {
         wItem.isShow = false;
       } else {
         wItem.isShow = true;
@@ -1473,7 +1486,8 @@ export default {
       display: flex;
       align-items: center;
       justify-content: flex-start;
-      width: 304px;
+
+      // width: 304px;
       padding: 4px 12px;
       background: #fff;
       border: 1px solid rgba(0, 0, 0, 10%);

+ 6 - 5
src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue

@@ -18,7 +18,7 @@
             :mp3="curQue.mp3_list[0].url"
             :get-cur-time="getCurTime"
             :mp3-source="curQue.mp3_list[0].source"
-            :width="colLength == 2 ? 200 : isPhone ? 200 : 790"
+            :width="colLength == 2 ? 200 : isMobile ? 200 : 790"
             :attrib="attrib"
           />
         </template>
@@ -431,7 +431,7 @@
             :mp3="curQue.mp3_list[0].url"
             :get-cur-time="getCurTime"
             :mp3-source="curQue.mp3_list[0].source"
-            :width="colLength == 2 ? 200 : isPhone ? 200 : 790"
+            :width="colLength == 2 ? 200 : isMobile ? 200 : 790"
           />
         </template>
       </div>
@@ -476,6 +476,7 @@
           :TaskModel="TaskModel"
           :write-list="curQue.Bookanswer.writeModel"
           :attrib="attrib"
+          :isMobile="isMobile"
           @changeCurQue="changeCurQue"
         />
       </div>
@@ -487,9 +488,10 @@
         :style="{
           marginLeft: windowWidth > 642 ? '-321px' : '0px',
           left: windowWidth > 642 ? '' : '0px',
+          width: isMobile ? '100%' : '',
         }"
       >
-        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" />
+        <Notecard :item="curNoteCon" :change-card="changeCard" :attrib="attrib" :isMobile="isMobile" />
       </div>
     </template>
   </div>
@@ -548,7 +550,7 @@ export default {
     'config',
     'TaskModel',
     'colLength',
-    'isPhone',
+    'isMobile',
     'multilingual',
   ],
   data() {
@@ -953,7 +955,6 @@ export default {
         } else {
           writeModel[hz] = [answer];
         }
-        console.log(this.curQue.Bookanswer);
       }
     },
   }, // 如果页面有keep-alive缓存功能,这个函数会触发

+ 7 - 0
src/views/book/courseware/preview/components/dialogue_article/index.vue

@@ -144,6 +144,7 @@
             :attrib="data.unified_attrib"
             :no-font="noFont"
             :NNPENewWordList="NNPENewWordList"
+            :NNPEAnnotationList="NNPEAnnotationList"
             :config="config"
             :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
             :col-length="colLength"
@@ -179,6 +180,7 @@
             :mp3="data.mp3_list && data.mp3_list[0] ? data.mp3_list[0].url : ''"
             :no-font="noFont"
             :NNPENewWordList="NNPENewWordList"
+            :NNPEAnnotationList="NNPEAnnotationList"
             :is-full="isFull"
             :config="config"
             :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
@@ -861,5 +863,10 @@ export default {
       border-bottom: none;
     }
   }
+
+  .el-slider {
+    flex: 1;
+    width: auto !important;
+  }
 }
 </style>

+ 22 - 7
src/views/book/courseware/preview/components/drawing/DrawingPreview.vue

@@ -1,14 +1,14 @@
 <!-- eslint-disable vue/no-v-html -->
 <template>
-  <div class="imageText-preview" :style="getAreaStyle()">
+  <div class="drawimg-preview" :style="getAreaStyle()">
     <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
 
     <div
       class="img-box"
       :style="{
         background: image_url ? '' : '#DCDFE6',
-        width: data.image_width + 'px',
-        height: data.image_height + 'px',
+        width: isMobile ? '100%' : data.image_width + 'px',
+        height: isMobile ? mobileHeight + 'px' : data.image_height + 'px',
         border: '1px dotted #DCDFE6',
       }"
     >
@@ -21,7 +21,10 @@
           :src="image_url"
           draggable="false"
           alt="背景图"
-          :style="{ width: `${data.imgData.width}px`, height: `${data.imgData.height}px` }"
+          :style="{
+            width: isMobile ? '100%' : `${data.imgData.width}px`,
+            height: isMobile ? mobileHeight + 'px' : `${data.imgData.height}px`,
+          }"
         />
       </div>
       <!-- 如果是查看答案模式 v-if 下面画画的vue-esign不显示 -->
@@ -37,8 +40,8 @@
       /> -->
       <VueSignaturePad
         class="esign-canvas"
-        :width="data.image_width + 'px'"
-        :height="data.image_height + 'px'"
+        :width="isMobile ? '100%' : data.image_width + 'px'"
+        :height="isMobile ? mobileHeight + 'px' : data.image_height + 'px'"
         ref="signaturePad"
         :options="options"
       />
@@ -67,7 +70,12 @@ import { GetFileURLMap } from '@/api/app';
 import vueEsign from 'vue-esign';
 export default {
   name: 'DrawingPreview',
-
+  props: {
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
+  },
   components: { vueEsign },
   mixins: [PreviewMixin],
   data() {
@@ -99,6 +107,7 @@ export default {
       isActive3: false,
       imgSrc: '',
       signData: null,
+      mobileHeight: 0,
     };
   },
   created() {
@@ -168,6 +177,12 @@ export default {
         //   this.image_url = url_map[item.file_id];
         // });
       });
+      if (this.isMobile) {
+        setTimeout(() => {
+          let totalWidth = document.querySelector('.drawimg-preview').offsetWidth;
+          this.mobileHeight = (totalWidth / this.data.image_width) * this.data.image_height;
+        }, 50);
+      }
     },
     // 保存图片
     handleGenerate() {

+ 1 - 2
src/views/book/courseware/preview/components/fill/FillPreview.vue

@@ -6,7 +6,7 @@
     <div class="main" :style="getMainStyle()">
       <AudioFill
         v-if="data.audio_file_id.length > 0"
-        :color="data.unified_attrib.topic_color"
+        :color="data.unified_attrib?.topic_color"
         :file-id="data.audio_file_id"
       />
       <div class="fill-wrapper">
@@ -279,7 +279,6 @@ export default {
       if (!isHasAudio) {
         _list[0].value = '0px';
       }
-      console.log(_list);
 
       if (!isFront) {
         _list = _list.reverse();

+ 12 - 1
src/views/book/courseware/preview/components/h5_games/H5GamesPreview.vue

@@ -16,7 +16,12 @@
         @click="toggleFullScreen"
         >{{ full_type ? '退出全屏' : '进入全屏' }}</el-button
       >
-      <iframe :src="games_url" width="100%" :height="full_type ? '100%' : '580px'" style="border: none"></iframe>
+      <iframe
+        :src="games_url"
+        width="100%"
+        :height="full_type ? '100%' : isMobile ? '400px' : '580px'"
+        style="border: none"
+      ></iframe>
     </div>
   </div>
 </template>
@@ -27,6 +32,12 @@ import { getH5GamesData } from '@/views/book/courseware/data/h5Games';
 import { H5StartupFile } from '@/api/app';
 export default {
   name: 'H5GamesPreview',
+  props: {
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
+  },
 
   components: {},
   mixins: [PreviewMixin],

+ 24 - 2
src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue

@@ -95,8 +95,9 @@
       :visible.sync="mageazineDetailShow"
       :show-close="false"
       :close-on-click-modal="false"
-      width="80%"
+      :width="isMobile ? '100%' : '80%'"
       class="login-dialog magazine-detail-dialog"
+      :class="[isMobile ? 'magazine-detail-dialog-phone' : '']"
       :modal="false"
     >
       <magazine-sentence
@@ -123,7 +124,12 @@ import { GetFileURLMap } from '@/api/app';
 import MagazineSentence from './components/MagazineSentence.vue';
 export default {
   name: 'ImageTextPreview',
-
+  props: {
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
+  },
   components: { AudioLine, MagazineSentence },
   mixins: [PreviewMixin],
   data() {
@@ -252,6 +258,11 @@ export default {
 <style lang="scss" scoped>
 @use '@/styles/mixin.scss' as *;
 
+.imageText-preview {
+  max-width: 100%;
+  overflow: auto;
+}
+
 .position-item {
   position: absolute;
   z-index: 1;
@@ -307,6 +318,11 @@ export default {
     margin: 24px 0;
   }
 }
+
+:deep .el-slider {
+  flex: 1;
+  width: auto !important;
+}
 </style>
 <style lang="scss">
 .magazine-detail-dialog {
@@ -327,5 +343,11 @@ export default {
       0 16px 24px 2px rgba(0, 0, 0, 4%),
       0 8px 10px -5px rgba(0, 0, 0, 8%);
   }
+
+  &-phone {
+    .el-dialog {
+      margin-left: -50%;
+    }
+  }
 }
 </style>

+ 1 - 1
src/views/book/courseware/preview/components/newWord_template/components/Strockplayredline.vue

@@ -178,7 +178,7 @@ export default {
 
 .character-target-div {
   position: absolute;
-  z-index: 999;
+  z-index: 1;
   display: flex;
   align-items: center;
   justify-content: center;

+ 16 - 2
src/views/book/courseware/preview/components/new_word/NewWordPreview.vue

@@ -444,7 +444,12 @@
                   @handleListenRead="handleListenRead"
                 />
               </div>
-              <div v-for="(item, index) in data.new_word_list" :key="index" class="NPC-word-tile-item">
+              <div
+                v-for="(item, index) in data.new_word_list"
+                :key="index"
+                class="NPC-word-tile-item"
+                :class="[isMobile ? 'NPC-word-tile-item-phone' : '']"
+              >
                 <div class="writeTop" :class="{ flipped: item.isFlipped }">
                   <div
                     v-if="item.show_left"
@@ -971,7 +976,6 @@ export default {
         this.$set(item, 'isFlipped', false);
         this.$set(item, 'pyhz', flag);
       });
-      console.log(this.data.new_word_list);
       option_list.forEach((item, index) => {
         optionRes = optionRes.concat(item);
         Bookanswer.push([]);
@@ -1728,6 +1732,15 @@ export default {
     }
   }
 
+  .NPC-word-tile-item-phone {
+    width: calc(50% - 10px);
+
+    .writeTop {
+      width: 100%;
+      min-height: 160px;
+    }
+  }
+
   .flipped {
     transform: rotateY(180deg);
   }
@@ -1738,6 +1751,7 @@ export default {
 
   .hz-box {
     display: flex;
+    flex-flow: wrap;
     width: max-content;
   }
 

+ 1 - 0
src/views/book/courseware/preview/components/new_word/components/writeTableZoom.vue

@@ -794,6 +794,7 @@ export default {
 
   .hz-box {
     display: flex;
+    flex-flow: wrap;
     width: max-content;
   }
 

+ 1 - 1
src/views/book/courseware/preview/components/notes/NotesPreview.vue

@@ -170,7 +170,7 @@ export default {
   name: 'NotesPreview',
   components: {},
   mixins: [PreviewMixin],
-  props: ['notesData'],
+  props: ['notesData', 'isMobile'],
   data() {
     return {
       data: this.notesData ? this.notesData : getNotesData(),

+ 27 - 8
src/views/book/courseware/preview/components/select/SelectPreview.vue

@@ -15,7 +15,7 @@
           :class="['option-item', { active: isAnswer(mark) }, ...computedAnswerClass(mark)]"
           @click="selectAnswer(mark)"
         >
-          <span class="checkbox">
+          <span :class="[isSingle ? 'radio' : 'checkbox']">
             <SvgIcon icon-class="check-mark" width="10" height="7" />
           </span>
           <span class="serial-number"> {{ computedOptionNumber(i) }}. </span>
@@ -44,7 +44,7 @@
 <script>
 import PreviewMixin from '../common/PreviewMixin';
 
-import { getSelectData, arrangeTypeList } from '@/views/book/courseware/data/select';
+import { getSelectData, arrangeTypeList, selectTypeList } from '@/views/book/courseware/data/select';
 import { serialNumberTypeList, computeOptionMethods } from '@/views/book/courseware/data/common';
 
 export default {
@@ -56,6 +56,11 @@ export default {
       arrangeTypeList,
     };
   },
+  computed: {
+    isSingle() {
+      return this.data.property?.select_type === selectTypeList[0].value;
+    },
+  },
   watch: {
     'answer.answer_list': {
       handler(val) {
@@ -83,13 +88,16 @@ export default {
     },
     selectAnswer(mark) {
       if (this.disabled) return;
+-
+      const list = this.answer.answer_list || [];
+      const isSelected = list.includes(mark);
 
-      const index = this.answer.answer_list.indexOf(mark);
-      if (index === -1) {
-        this.answer.answer_list.push(mark);
-      } else {
-        this.answer.answer_list.splice(index, 1);
+      if (this.isSingle) {
+        this.answer.answer_list = isSelected ? [] : [mark];
+        return;
       }
+
+      this.answer.answer_list = isSelected ? list.filter((item) => item !== mark) : list.concat(mark);
     },
     computedAnswerClass(mark) {
       if (!this.isJudgingRightWrong && !this.isShowRightAnswer) {
@@ -104,7 +112,7 @@ export default {
       }
       // 判断是否是正确答案
       if (isHas && this.isJudgingRightWrong) {
-        answerClass = isRight ? ['right'] : ['wrong'];
+        answerClass = isRight ? ['answer-right'] : ['wrong'];
       }
       return answerClass;
     },
@@ -141,6 +149,7 @@ export default {
         padding-left: 52px;
       }
 
+      .radio,
       .checkbox {
         display: flex;
         align-items: center;
@@ -158,6 +167,10 @@ export default {
         }
       }
 
+      .radio {
+        border-radius: 50%;
+      }
+
       .serial-number {
         font-size: 16pt;
       }
@@ -178,6 +191,11 @@ export default {
             display: block;
           }
         }
+
+        .radio {
+          background-color: #fff;
+          box-shadow: inset 0 0 0 4px $light-main-color;
+        }
       }
 
       &.answer-right {
@@ -192,6 +210,7 @@ export default {
       }
 
       &.wrong {
+        margin: 1px 0;
         background-color: $content-color;
         box-shadow: 0 0 0 1px $error-color;
 

+ 11 - 2
src/views/book/courseware/preview/components/table/TablePreview.vue

@@ -7,13 +7,15 @@
       <div
         class="table-box"
         :style="{
-          width: data.property.width + 'px',
+          width: isMobile ? '100%' : data.property.width + 'px',
+
           height: data.property.height + 'px',
         }"
       >
         <table
           :style="{
-            width: table_width + 'px',
+            width: isMobile ? '100%' : table_width + 'px',
+
             height: data.property.height + 'px',
           }"
         >
@@ -240,6 +242,13 @@ export default {
   name: 'TablePreview',
   components: { SoundRecordBox, WriteDialog },
   mixins: [PreviewMixin],
+  props: {
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
+  },
+
   data() {
     return {
       data: getTableData(),

+ 8 - 1
src/views/book/courseware/preview/components/upload_preview/UploadPreviewPreview.vue

@@ -88,7 +88,7 @@
       :modal-append-to-body="true"
       :append-to-body="true"
       :lock-scroll="true"
-      width="80%"
+      :width="isMobile ? '100%' : '80%'"
       top="0"
     >
       <iframe v-if="visible" :src="newpath" width="100%" :height="iframeHeight" frameborder="0"></iframe>
@@ -107,6 +107,13 @@ import { getUploadPreviewData } from '@/views/book/courseware/data/uploadPreview
 export default {
   name: 'UploadPreviewPreview',
   mixins: [PreviewMixin],
+  props: {
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
+  },
+
   data() {
     return {
       data: getUploadPreviewData(),

+ 7 - 1
src/views/book/courseware/preview/components/video_interaction/VideoInteractionPreview.vue

@@ -46,7 +46,7 @@
       :modal-append-to-body="true"
       :append-to-body="true"
       :lock-scroll="true"
-      width="80%"
+      :width="isMobile ? '100%' : '80%'"
       @close="handleClose"
     >
       <Report
@@ -68,6 +68,12 @@ import { getVideoInteractionData } from '@/views/book/courseware/data/videoInter
 import { getConfig } from '@/utils/auth';
 export default {
   name: 'VideoInteractionPreview',
+  props: {
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
+  },
 
   components: { ExercisePreview, Report },
   mixins: [PreviewMixin],

+ 268 - 2
src/web_preview/index.vue

@@ -81,6 +81,7 @@
             :group-show-all="groupShowAll"
             :group-row-list="content_group_row_list"
             :data="data"
+            :courseware-id="curSelectId"
             :component-list="component_list"
             :background="background"
             :can-remark="isTrue(courseware_info.is_my_audit_task) && isTrue(courseware_info.is_can_add_audit_remark)"
@@ -88,6 +89,8 @@
             :project="project"
             :component-remark-obj="remark_list_obj"
             @computeScroll="computeScroll"
+            @editNote="handEditNote"
+            @saveCollect="saveCollect"
           />
           <div class="preview-right"></div>
         </main>
@@ -172,6 +175,40 @@
             <p v-if="loading">加载中...</p>
             <p v-if="noMore">没有更多了</p>
           </div>
+          <div v-if="curToolbarIcon === 'note'" class="resource_box">
+            <h5>{{ drawerTitle }}</h5>
+            <div style="height: 40px"></div>
+            <ul v-if="allNoteList.length > 0" class="card-box">
+              <li v-for="item in allNoteList" :key="item.id">
+                <span class="el-icon-notebook-2"> 原文</span>
+                <span>{{ item.text }}</span>
+                <el-divider class="mt10" />
+                <span v-html="item.note"></span>
+                <div class="remark-bottom">
+                  <el-button type="text" class="el-icon-edit" @click="handEditNote(item)"> 编辑</el-button>
+                  <el-divider direction="vertical" />
+                  <el-button type="text" class="el-icon-delete" @click="handDelNote(item.id)"> 删除</el-button>
+                  <el-divider direction="vertical" />
+                  <el-button type="text" class="el-icon-place" @click="handLocation(item, 1)"> 定位</el-button>
+                </div>
+              </li>
+            </ul>
+          </div>
+          <div v-if="curToolbarIcon === 'collect'" class="resource_box">
+            <h5>{{ drawerTitle }}</h5>
+            <div style="height: 40px"></div>
+            <ul v-if="allCottectList.length > 0" class="card-box">
+              <li v-for="item in allCottectList" :key="item.id">
+                <span class="el-icon-notebook-2"> 原文</span>
+                <span>{{ item.text }}</span>
+                <div class="remark-bottom">
+                  <el-button type="text" class="el-icon-delete" @click="handDelCollect(item.id)"> 删除</el-button>
+                  <el-divider direction="vertical" />
+                  <el-button type="text" class="el-icon-place" @click="handLocation(item, 2)"> 定位</el-button>
+                </div>
+              </li>
+            </ul>
+          </div>
         </div>
 
         <div class="back-top" @click="backTop">
@@ -189,6 +226,15 @@
         @child-click="handleNodeClick"
       />
     </el-dialog>
+
+    <ExplanatoryNoteDialog
+      ref="explanatoryNote"
+      :open.sync="editDialogOpen"
+      :init-data="oldRichData"
+      title-text="笔记"
+      @confirm="saveNote"
+      @cancel="delNote"
+    />
   </div>
 </template>
 
@@ -198,6 +244,7 @@ import { isTrue } from '@/utils/validate';
 import MindMap from '@/components/MindMap.vue';
 import VideoPlay from '@/views/book/courseware/preview/components/common/VideoPlay.vue';
 import AudioPlay from '@/views/book/courseware/preview/components/common/AudioPlay.vue';
+import ExplanatoryNoteDialog from '@/components/ExplanatoryNoteDialog.vue';
 import * as OpenCC from 'opencc-js';
 
 import { GetBookCoursewareInfo, GetCoursewareAuditRemarkList, GetProjectInfo } from '@/api/project';
@@ -209,6 +256,13 @@ import {
   PageQueryBookResourceList,
   GetLanguageTypeList,
   GetBookUnifiedAttrib,
+  GetMyNoteList,
+  DeleteMyNote,
+  AddMyNote,
+  UpdateMyNote,
+  AddMyCollect,
+  GetMyCollectList,
+  DeleteMyCollect,
 } from '@/api/book';
 
 export default {
@@ -218,6 +272,7 @@ export default {
     MindMap,
     VideoPlay,
     AudioPlay,
+    ExplanatoryNoteDialog,
   },
   provide() {
     return {
@@ -235,11 +290,11 @@ export default {
       { icon: 'mindmap', title: '思维导图', handle: 'openMindMap', param: {} },
       // { icon: 'knowledge', title: '知识图谱', handle: '', param: {} },
       // { icon: 'totalResources', title: '总资源', handle: '', param: {} },
-      // { icon: 'collect', title: '收藏', handle: '', param: {} },
+      { icon: 'collect', title: '收藏', handle: 'getCollect', param: { type: '3' } },
       { icon: 'audio', title: '音频', handle: 'openDrawer', param: { type: '1' } },
       { icon: 'image', title: '图片', handle: 'openDrawer', param: { type: '0' } },
       { icon: 'video', title: '视频', handle: 'openDrawer', param: { type: '2' } },
-      // { icon: 'note', title: '笔记', handle: '', param: {} },
+      { icon: 'note', title: '笔记', handle: 'getNote', param: { type: '4' } },
       // { icon: 'translate', title: '翻译', handle: '', param: {} },
       // { icon: 'setting', title: '设置', handle: '', param: {} },
     ];
@@ -317,6 +372,11 @@ export default {
         cover_image_file_id: null, // 封面图片ID
         cover_image_file_url: '', // 封面图片URL
       },
+      allNoteList: [],
+      editDialogOpen: false,
+      oldRichData: {},
+      newSelectedInfo: null,
+      allCottectList: [],
     };
   },
   computed: {
@@ -333,6 +393,8 @@ export default {
         0: '图片资源',
         1: '音频资源',
         2: '视频资源',
+        3: '收藏列表',
+        4: '笔记列表',
       };
       return titleMap[this.drawerType] || '资源列表';
     },
@@ -347,6 +409,13 @@ export default {
     isShowAnswer() {
       this.simulateAnswer();
     },
+    curSelectId() {
+      if (this.curToolbarIcon === 'note') {
+        this.getNote();
+      } else if (this.curToolbarIcon === 'collect') {
+        this.getCollect();
+      }
+    },
   },
   mounted() {
     this.calcDrawerPosition();
@@ -692,6 +761,186 @@ export default {
         behavior: 'smooth',
       });
     },
+
+    handLocation(item, type) {
+      if (this.$refs.courserware && this.$refs.courserware.handLocation) {
+        item.type = type;
+        this.$refs.courserware.handLocation(item);
+      }
+    },
+    async getNote() {
+      this.drawerType = 4;
+      this.allNoteList = [];
+      await GetMyNoteList({ courseware_id: this.curSelectId }).then((res) => {
+        if (res.status === 1) {
+          res.note_list.forEach((x) => {
+            if (x.note_desc) {
+              let n = JSON.parse(x.note_desc);
+              let obj = {
+                coursewareId: x.courseware_id,
+                id: x.id,
+                blockId: n.blockId,
+                startIndex: n.startIndex,
+                endIndex: n.endIndex,
+                text: n.text,
+                note: n.note,
+              };
+              this.allNoteList.push(obj);
+            }
+          });
+        }
+      });
+    },
+    async handEditNote(note) {
+      this.oldRichData = {};
+      if (this.allNoteList.length === 0) {
+        await this.getNote();
+      }
+      let old = this.allNoteList.find(
+        (x) =>
+          x.coursewareId === note.coursewareId &&
+          x.blockId === note.blockId &&
+          x.startIndex === note.startIndex &&
+          x.endIndex === note.endIndex,
+      );
+      if (old) {
+        this.oldRichData = old;
+      }
+      this.newSelectedInfo = note;
+      this.editDialogOpen = true;
+    },
+    saveNote(note) {
+      let noteInfo = {
+        blockId: this.newSelectedInfo.blockId,
+        startIndex: this.newSelectedInfo.startIndex,
+        endIndex: this.newSelectedInfo.endIndex,
+        note: note.note,
+        text: this.newSelectedInfo.text,
+      };
+
+      let reqData = {
+        courseware_id: this.newSelectedInfo.coursewareId, // 课件 ID
+        component_id: 'WHOLE',
+        note_desc: JSON.stringify(noteInfo), // 位置描述
+      };
+      if (note.id) {
+        if (!noteInfo.note) {
+          this.delNote(note.id);
+          return;
+        }
+        let upDate = {
+          id: note.id,
+          note_desc: reqData.note_desc,
+        };
+        UpdateMyNote(upDate).then(() => {
+          this.getNote();
+        });
+      } else {
+        AddMyNote(reqData).then(() => {
+          this.getNote();
+        });
+      }
+      this.editDialogOpen = false;
+      this.newSelectedInfo = null;
+      this.selectedInfo = null;
+    },
+    handDelNote(id) {
+      this.$confirm('确定要删除此条笔记吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.delNote(id);
+        })
+        .catch(() => {});
+    },
+    delNote(id) {
+      const noteId = id || (this.oldRichData && this.oldRichData.id);
+      if (!noteId) return;
+      DeleteMyNote({ id: noteId }).then(() => {
+        this.allNoteList = this.allNoteList.filter((x) => x.id !== noteId);
+      });
+    },
+
+    async getCollect() {
+      this.drawerType = 3;
+      this.allCottectList = [];
+      await GetMyCollectList({ courseware_id: this.curSelectId }).then((res) => {
+        if (res.status === 1) {
+          res.collect_list.forEach((x) => {
+            if (x.collect_desc) {
+              let n = JSON.parse(x.collect_desc);
+              let obj = {
+                coursewareId: x.courseware_id,
+                id: x.id,
+                blockId: n.blockId,
+                startIndex: n.startIndex,
+                endIndex: n.endIndex,
+                text: n.text,
+              };
+              this.allCottectList.push(obj);
+            }
+          });
+        }
+      });
+    },
+    async saveCollect(collect) {
+      if (this.allCottectList.length === 0) {
+        await this.getCollect();
+      }
+
+      let old = this.allCottectList.find(
+        (x) =>
+          x.coursewareId === collect.coursewareId &&
+          x.blockId === collect.blockId &&
+          x.startIndex === collect.startIndex &&
+          x.endIndex === collect.endIndex,
+      );
+      if (old) {
+        this.$message({
+          dangerouslyUseHTMLString: true,
+          message: "<i class='el-icon-check' />已收藏",
+        });
+        return;
+      }
+      this.newSelectedInfo = collect;
+      let collectInfo = {
+        blockId: this.newSelectedInfo.blockId,
+        startIndex: this.newSelectedInfo.startIndex,
+        endIndex: this.newSelectedInfo.endIndex,
+        text: this.newSelectedInfo.text,
+      };
+
+      let reqData = {
+        courseware_id: this.newSelectedInfo.coursewareId, // 课件 ID
+        component_id: 'WHOLE',
+        collect_desc: JSON.stringify(collectInfo), // 位置描述
+      };
+      AddMyCollect(reqData)
+        .then(() => {
+          this.getCollect();
+        })
+        .then(() => {
+          this.$message({
+            dangerouslyUseHTMLString: true,
+            message: "<i class='el-icon-check' />已收藏",
+          });
+        });
+    },
+    handDelCollect(id) {
+      this.$confirm('确定要删除此条收藏吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          DeleteMyCollect({ id }).then(() => {
+            this.allCottectList = this.allCottectList.filter((x) => x.id !== id);
+          });
+        })
+        .catch(() => {});
+    },
   },
 };
 </script>
@@ -1119,6 +1368,18 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
             color: #999;
             text-align: center;
           }
+
+          .card-box li {
+            padding: 10px;
+            border-bottom: 1px solid #ccc;
+
+            .el-icon-notebook-2 {
+              display: block;
+              margin-bottom: 4px;
+              font-size: 12px;
+              color: grey;
+            }
+          }
         }
       }
 
@@ -1172,6 +1433,11 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
     }
   }
 }
+
+.mt10 {
+  margin: 10px 0 0 !important;
+  background-color: #eee;
+}
 </style>
 
 <style lang="scss">