Browse Source

Merge branch 'master' of http://gcls-git.helxsoft.cn/GCLS/eep_page

zq 1 tuần trước cách đây
mục cha
commit
c3b76f1130
19 tập tin đã thay đổi với 349 bổ sung160 xóa
  1. 11 5
      src/components/CommonPreview.vue
  2. 1 1
      src/styles/variables.scss
  3. 34 15
      src/views/book/courseware/preview/CoursewarePreview.vue
  4. 2 1
      src/views/book/courseware/preview/common/SoundRecord.vue
  5. 18 10
      src/views/book/courseware/preview/components/article/NormalModelChs.vue
  6. 18 11
      src/views/book/courseware/preview/components/article/PhraseModelChs.vue
  7. 17 10
      src/views/book/courseware/preview/components/article/Practicechs.vue
  8. 18 11
      src/views/book/courseware/preview/components/article/WordModelChs.vue
  9. 22 7
      src/views/book/courseware/preview/components/article/components/Notecard.vue
  10. 11 0
      src/views/book/courseware/preview/components/article/components/WordPhraseDetail.vue
  11. 28 16
      src/views/book/courseware/preview/components/article/index.vue
  12. 7 2
      src/views/book/courseware/preview/components/dialogue_article/NormalModelChs.vue
  13. 7 2
      src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue
  14. 6 1
      src/views/book/courseware/preview/components/dialogue_article/Practicechs.vue
  15. 7 2
      src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue
  16. 28 16
      src/views/book/courseware/preview/components/dialogue_article/index.vue
  17. 102 36
      src/views/book/courseware/preview/components/new_word/NewWordPreview.vue
  18. 1 1
      src/views/book/courseware/preview/components/new_word/components/AudioPlay.vue
  19. 11 13
      src/views/book/courseware/preview/components/notes/NotesPreview.vue

+ 11 - 5
src/components/CommonPreview.vue

@@ -29,7 +29,7 @@
             <img v-if="project.cover_image_file_url.length > 0" :src="project.cover_image_file_url" alt="cover-image" />
           </div>
           <div class="info-content">
-            <div class="catalogue-icon">
+            <div class="catalogue-icon" @click="toggleNavigationShow">
               <SvgIcon icon-class="catalogue" size="54" />
             </div>
             <div class="courseware">
@@ -58,8 +58,13 @@
         </div>
       </aside>
 
-      <div ref="previewMain" class="main-container" :style="{ paddingRight: sidebarShow ? '15px' : '315px' }">
-        <div v-if="!navigationShow" class="catalogue-bar">
+      <div
+        ref="previewMain"
+        class="main-container"
+        :style="{ paddingLeft: navigationShow ? '15px' : '315px', paddingRight: sidebarShow ? '15px' : '315px' }"
+      >
+        <!-- 左侧菜单栏 - 收缩 -->
+        <div v-if="!navigationShow" class="catalogue-bar" @click="toggleNavigationShow">
           <SvgIcon icon-class="catalogue" size="54" />
         </div>
 
@@ -77,6 +82,7 @@
             :can-remark="isTrue(courseware_info.is_my_audit_task) && isTrue(courseware_info.is_can_add_audit_remark)"
             :show-remark="isShowAudit"
             :component-remark-obj="remark_list_obj"
+            :project="project"
             @computeScroll="computeScroll"
             @addRemark="addRemark"
           />
@@ -888,8 +894,8 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
 
     .catalogue-bar {
       position: absolute;
-      top: 0;
-      left: 240px;
+      top: 15px;
+      left: 0;
       display: flex;
       align-items: center;
       justify-content: center;

+ 1 - 1
src/styles/variables.scss

@@ -19,7 +19,7 @@ $right-color: #30a47d;
 $right-bc-color: #e8f7f2;
 $label-color: #076aff;
 $setting-active-color: #4176ff;
-$courseware-bgColor: #fdfdfd; // 教材内容背景色
+$courseware-bgColor: #fff; // 教材内容背景色
 
 // px
 $header-h: 64px; // 顶部内容高度

+ 34 - 15
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -1,19 +1,5 @@
 <template>
-  <div
-    ref="courserware"
-    class="courserware"
-    :style="[
-      {
-        backgroundImage: background.background_image_url ? `url(${background.background_image_url})` : '',
-        backgroundSize: background.background_image_url
-          ? `${background.background_position.width}% ${background.background_position.height}%`
-          : '',
-        backgroundPosition: background.background_image_url
-          ? `${background.background_position.left}% ${background.background_position.top}%`
-          : '',
-      },
-    ]"
-  >
+  <div ref="courserware" class="courserware" :style="computedCourserwareStyle()">
     <template v-for="(row, i) in data.row_list">
       <div v-show="computedRowVisibility(row.row_id)" :key="i" class="row" :style="getMultipleColStyle(i)">
         <el-checkbox
@@ -132,6 +118,10 @@ export default {
       type: Boolean,
       default: true,
     },
+    project: {
+      type: Object,
+      default: () => ({}),
+    },
   },
   data() {
     return {
@@ -320,6 +310,35 @@ export default {
         gridTemplateRows,
       };
     },
+
+    /**
+     * 计算课件背景样式
+     * @returns {Object} 课件背景样式对象
+     */
+    computedCourserwareStyle() {
+      const { background_image_url: bcImgUrl = '', background_position: pos = {} } = this.background || {};
+      const hasNoRows = !Array.isArray(this.data?.row_list) || this.data.row_list.length === 0;
+      const projectCover = this.project?.cover_image_file_url || '';
+
+      // 优先在空行时使用背景图或项目封面
+      const backgroundImage = hasNoRows ? bcImgUrl || projectCover : '';
+
+      // 保护性读取位置/大小值,避免 undefined 导致字符串 "undefined%"
+      const widthPct = typeof pos.width === 'undefined' ? '' : pos.width;
+      const heightPct = typeof pos.height === 'undefined' ? '' : pos.height;
+      const leftPct = typeof pos.left === 'undefined' ? '' : pos.left;
+      const topPct = typeof pos.top === 'undefined' ? '' : pos.top;
+
+      const hasBcImg = Boolean(bcImgUrl);
+      const backgroundSize = hasBcImg ? `${widthPct}% ${heightPct}%` : hasNoRows ? 'contain' : '';
+      const backgroundPosition = hasBcImg ? `${leftPct}% ${topPct}%` : hasNoRows ? 'center' : '';
+
+      return {
+        backgroundImage: backgroundImage ? `url(${backgroundImage})` : '',
+        backgroundSize,
+        backgroundPosition,
+      };
+    },
     handleContextMenu(event, id) {
       if (this.canRemark) {
         event.preventDefault(); // 阻止默认的上下文菜单显示

+ 2 - 1
src/views/book/courseware/preview/common/SoundRecord.vue

@@ -519,7 +519,8 @@ export default {
     width: 24px;
     height: 24px;
     margin-left: 8px;
-    color: #000;
+    color: rgba(0, 0, 0, 30%);
+    cursor: pointer;
 
     // background: url('@/assets/voice_matrix/luyin-delete.png') center no-repeat;
     // background-size: 100%;

+ 18 - 10
src/views/book/courseware/preview/components/article/NormalModelChs.vue

@@ -1106,19 +1106,26 @@
         </div>
       </template>
     </template>
-    <div v-for="(items, indexs) in curQue.detail" :key="indexs" class="multilingual">
+    <template v-for="(items, indexs) in curQue.detail">
       <div
-        v-if="curQue.property.multilingual_position === 'all'"
-        class="multilingual-para"
-        :class="[items.isTitle ? 'multilingual-para-center' : '']"
+        v-if="
+          curQue.property.multilingual_position === 'all' &&
+          items.multilingualTextList &&
+          items.multilingualTextList[multilingual] &&
+          items.multilingualTextList[multilingual].length > 0
+        "
+        :key="indexs"
+        class="multilingual"
       >
-        {{
-          items.multilingualTextList && items.multilingualTextList[multilingual]
-            ? items.multilingualTextList[multilingual].join(' ')
-            : ''
-        }}
+        <div class="multilingual-para" :class="[items.isTitle ? 'multilingual-para-center' : '']">
+          {{
+            items.multilingualTextList && items.multilingualTextList[multilingual]
+              ? items.multilingualTextList[multilingual].join(' ')
+              : ''
+          }}
+        </div>
       </div>
-    </div>
+    </template>
     <div
       v-if="
         ((curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url) ||
@@ -1806,6 +1813,7 @@ export default {
     max-width: 100%;
     margin-top: -196px;
     overflow: auto;
+    box-shadow: 0 4px 16px rgba(0, 0, 0, 15%);
   }
 
   .NNPE-detail-box {

+ 18 - 11
src/views/book/courseware/preview/components/article/PhraseModelChs.vue

@@ -731,19 +731,26 @@
         </div>
       </template>
     </template>
-    <div v-for="(items, indexs) in curQue.detail" :key="indexs" class="multilingual">
+    <template v-for="(items, indexs) in curQue.detail">
       <div
-        v-if="curQue.property.multilingual_position === 'all'"
-        class="multilingual-para"
-        :class="[items.isTitle ? 'multilingual-para-center' : '']"
+        v-if="
+          curQue.property.multilingual_position === 'all' &&
+          items.multilingualTextList &&
+          items.multilingualTextList[multilingual] &&
+          items.multilingualTextList[multilingual].length > 0
+        "
+        :key="indexs"
+        class="multilingual"
       >
-        {{
-          items.multilingualTextList && items.multilingualTextList[multilingual]
-            ? items.multilingualTextList[multilingual].join(' ')
-            : ''
-        }}
+        <div class="multilingual-para" :class="[items.isTitle ? 'multilingual-para-center' : '']">
+          {{
+            items.multilingualTextList && items.multilingualTextList[multilingual]
+              ? items.multilingualTextList[multilingual].join(' ')
+              : ''
+          }}
+        </div>
       </div>
-    </div>
+    </template>
     <div
       v-if="
         ((curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url) ||
@@ -1342,7 +1349,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwn(hz)) {
+        if (writeModel.hasOwnProperty(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

+ 17 - 10
src/views/book/courseware/preview/components/article/Practicechs.vue

@@ -515,19 +515,26 @@
         </div> -->
       </div>
     </template>
-    <div v-for="(items, indexs) in curQue.detail" :key="indexs" class="multilingual">
+    <template v-for="(items, indexs) in curQue.detail">
       <div
-        v-if="curQue.property.multilingual_position === 'all'"
-        class="multilingual-para"
-        :class="[items.isTitle ? 'multilingual-para-center' : '']"
+        v-if="
+          curQue.property.multilingual_position === 'all' &&
+          items.multilingualTextList &&
+          items.multilingualTextList[multilingual] &&
+          items.multilingualTextList[multilingual].length > 0
+        "
+        :key="indexs"
+        class="multilingual"
       >
-        {{
-          items.multilingualTextList && items.multilingualTextList[multilingual]
-            ? items.multilingualTextList[multilingual].join(' ')
-            : ''
-        }}
+        <div class="multilingual-para" :class="[items.isTitle ? 'multilingual-para-center' : '']">
+          {{
+            items.multilingualTextList && items.multilingualTextList[multilingual]
+              ? items.multilingualTextList[multilingual].join(' ')
+              : ''
+          }}
+        </div>
       </div>
-    </div>
+    </template>
     <div
       v-if="
         ((curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url) ||

+ 18 - 11
src/views/book/courseware/preview/components/article/WordModelChs.vue

@@ -727,19 +727,26 @@
         </div>
       </template>
     </template>
-    <div v-for="(items, indexs) in curQue.detail" :key="indexs" class="multilingual">
+    <template v-for="(items, indexs) in curQue.detail">
       <div
-        v-if="curQue.property.multilingual_position === 'all'"
-        class="multilingual-para"
-        :class="[items.isTitle ? 'multilingual-para-center' : '']"
+        v-if="
+          curQue.property.multilingual_position === 'all' &&
+          items.multilingualTextList &&
+          items.multilingualTextList[multilingual] &&
+          items.multilingualTextList[multilingual].length > 0
+        "
+        :key="indexs"
+        class="multilingual"
       >
-        {{
-          items.multilingualTextList && items.multilingualTextList[multilingual]
-            ? items.multilingualTextList[multilingual].join(' ')
-            : ''
-        }}
+        <div class="multilingual-para" :class="[items.isTitle ? 'multilingual-para-center' : '']">
+          {{
+            items.multilingualTextList && items.multilingualTextList[multilingual]
+              ? items.multilingualTextList[multilingual].join(' ')
+              : ''
+          }}
+        </div>
       </div>
-    </div>
+    </template>
     <div
       v-if="
         ((curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url) ||
@@ -1215,7 +1222,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwn(hz)) {
+        if (writeModel.hasOwnProperty(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

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

@@ -6,12 +6,23 @@
     </div>
     <div class="NPC-notes">
       <div class="NPC-notes-con">
-        <span class="NPC-notes-con-number">{{ item.number }}</span>
-        <span class="NPC-notes-con-text">{{ item.con }}</span>
-      </div>
-      <div class="NPC-notes-trans">
-        {{ item.interpret }}
+        <span
+          class="NPC-notes-con-number"
+          :style="{
+            color: attrib && attrib.topic_color ? attrib.topic_color : '',
+          }"
+          >{{ item.number }}</span
+        >
+        <span
+          class="NPC-notes-con-text"
+          v-html="item.con"
+          :style="{
+            color: attrib && attrib.topic_color ? attrib.topic_color : '',
+            fontSize: attrib && attrib.font_size ? attrib.font_size : '',
+          }"
+        ></span>
       </div>
+      <div class="NPC-notes-trans" v-html="item.interpret"></div>
       <div v-if="item.note" class="NPC-notes-note" v-html="item.note"></div>
       <div v-if="item.img_list && item.img_list.length > 0" class="NPC-notes-note-img">
         <div v-for="(imgItem, imgIndex) in item.img_list" :key="'imgList' + imgIndex">
@@ -25,7 +36,7 @@
 <script>
 export default {
   components: {},
-  props: ['item', 'changeCard'],
+  props: ['item', 'changeCard', 'attrib'],
   data() {
     return {};
   },
@@ -54,7 +65,7 @@ export default {
   max-height: 261px;
   padding: 16px;
   overflow-y: auto;
-  background: #fff;
+  background: rgb(236, 238, 243);
   border-radius: 8px;
   box-shadow: 0 2px 8px rgba(0, 0, 0, 15%);
 
@@ -134,5 +145,9 @@ export default {
       }
     }
   }
+
+  :deep p {
+    margin: 0;
+  }
 }
 </style>

+ 11 - 0
src/views/book/courseware/preview/components/article/components/WordPhraseDetail.vue

@@ -29,6 +29,9 @@
               'bwc-Strockplay',
               themeColor == 'green' ? 'green-border' : themeColor == 'red' ? 'red-border' : 'brown-border',
             ]"
+            :style="{
+              borderColor: attrib && attrib.topic_color ? attrib.topic_color : '',
+            }"
           >
             <div v-for="(conItem, conindex) in data.new_word_str" :key="'new_word_' + conindex" class="strockplay">
               <Strockplayredline
@@ -38,10 +41,14 @@
                 :target-div="'bwcHanziIntp' + conItem + detailIndex + conindex"
                 :word-num="data.new_word_str.length"
                 :theme-color="themeColor"
+                :attrib="attrib"
               />
               <div
                 v-if="conindex < data.new_word_str.length - 1"
                 :class="['bwc-line', themeColor == 'green' ? 'green-bg' : themeColor == 'red' ? 'red-bg' : 'brown-bg']"
+                :style="{
+                  background: attrib && attrib.topic_color ? attrib.topic_color : '',
+                }"
               ></div>
             </div>
           </div>
@@ -51,6 +58,9 @@
               'bwc-tolength',
               themeColor == 'green' ? 'green-border' : themeColor == 'red' ? 'red-border' : 'brown-border',
             ]"
+            :style="{
+              borderColor: attrib && attrib.topic_color ? attrib.topic_color : '',
+            }"
           >
             <span v-for="(item, index) in data.new_word_str" :key="index">{{ item }}</span>
           </p>
@@ -248,6 +258,7 @@ export default {
     'type',
     'bg',
     'ed',
+    'attrib',
   ],
   data() {
     // 这里存放数据

+ 28 - 16
src/views/book/courseware/preview/components/article/index.vue

@@ -77,8 +77,8 @@
                     ? data.unified_attrib.topic_color
                     : '',
               }"
-              ><svg-icon icon-class="icon-article-ci" size="24" />本课生词</a
-            >
+              ><svg-icon icon-class="icon-article-ci" size="24"
+            /></a>
             <a
               v-if="data.property.is_enable_read === 'true'"
               @click="handleSwitchChange('showPhrases', 'showWord', 'showPractice')"
@@ -88,8 +88,8 @@
                     ? data.unified_attrib.topic_color
                     : '',
               }"
-              ><svg-icon icon-class="icon-article-practice" size="24" />语音练习</a
-            >
+              ><svg-icon icon-class="icon-article-practice" size="24"
+            /></a>
             <a
               v-if="data.property.is_enable_word === 'true'"
               @click="handleSwitchChange('showPhrases', 'showPractice', 'showWord')"
@@ -99,8 +99,8 @@
                     ? data.unified_attrib.topic_color
                     : '',
               }"
-              ><svg-icon icon-class="icon-article-phrase" size="24" />取词</a
-            >
+              ><svg-icon icon-class="icon-article-phrase" size="24"
+            /></a>
           </div>
           <!-- <div class="setting-fontsize">
         <a @click="handleFontsize('-')"
@@ -209,13 +209,19 @@
           />
         </div>
       </div>
-      <template v-if="data.new_word_list.new_word_list.length > 0">
+      <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" />
       </template>
-      <template v-if="data.other_word_list.new_word_list.length > 0">
+      <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" />
       </template>
-      <template v-if="data.notes_list.option.length > 0">
+      <template v-if="data.notes_list && data.notes_list.option && data.notes_list.option.length > 0">
         <NotesPreview :notes-data="data.notes_list" />
       </template>
     </div>
@@ -299,10 +305,10 @@ export default {
       handler(val) {
         if (val) {
           this.data.multilingual.forEach((item) => {
-            let trans_arr = item.translation.split('\n');
+            let trans_arr = item.translation ? item.translation.split('\n') : [];
             this.data.detail.forEach((items) => {
               let items_trans_arr = [];
-              if (!items.hasOwn('multilingualTextList')) {
+              if (!items.hasOwnProperty('multilingualTextList')) {
                 this.$set(items, 'multilingualTextList', {});
               }
               if (items.para) {
@@ -479,10 +485,10 @@ export default {
 
       if (this.showLang) {
         this.data.multilingual.forEach((item) => {
-          let trans_arr = item.translation.split('\n');
+          let trans_arr = item.translation ? item.translation.split('\n') : [];
           this.data.detail.forEach((items) => {
             let items_trans_arr = [];
-            if (!items.hasOwn('multilingualTextList')) {
+            if (!items.hasOwnProperty('multilingualTextList')) {
               this.$set(items, 'multilingualTextList', {});
             }
             if (items.para) {
@@ -500,9 +506,15 @@ export default {
       this.NNPENewWordList = (
         this.data.new_word_list_other_component_input ? this.data.new_word_list_other_component_input : []
       )
-        .concat(this.data.new_word_list.new_word_list)
-        .concat(this.data.other_word_list.new_word_list);
-      this.NNPEAnnotationList = this.data.notes_list.option;
+        .concat(
+          this.data.new_word_list && this.data.new_word_list.new_word_list ? this.data.new_word_list.new_word_list : [],
+        )
+        .concat(
+          this.data.other_word_list && this.data.other_word_list.new_word_list
+            ? this.data.other_word_list.new_word_list
+            : [],
+        );
+      this.NNPEAnnotationList = this.data.notes_list && this.data.notes_list.option ? this.data.notes_list.option : [];
       let resArr = [];
       let sentArrTotal = [];
       let timeArr = [];

+ 7 - 2
src/views/book/courseware/preview/components/dialogue_article/NormalModelChs.vue

@@ -591,10 +591,14 @@
           <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
           <div class="empty-right"></div>
         </div>
-
         <template v-for="(items, indexs) in curQue.detail">
           <div
-            v-if="curQue.property.multilingual_position === 'all' && items.multilingualTextList[multilingual]"
+            v-if="
+              curQue.property.multilingual_position === 'all' &&
+              items.multilingualTextList &&
+              items.multilingualTextList[multilingual] &&
+              items.multilingualTextList[multilingual].length > 0
+            "
             :key="indexs"
             class="multilingual"
           >
@@ -1397,6 +1401,7 @@ export default {
     padding: 8px;
     margin-top: -130px;
     overflow: auto;
+    box-shadow: 0 4px 16px rgba(0, 0, 0, 15%);
   }
 
   .multilingual {

+ 7 - 2
src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue

@@ -411,7 +411,12 @@
         </div>
         <template v-for="(items, indexs) in curQue.detail">
           <div
-            v-if="curQue.property.multilingual_position === 'all' && items.multilingualTextList[multilingual]"
+            v-if="
+              curQue.property.multilingual_position === 'all' &&
+              items.multilingualTextList &&
+              items.multilingualTextList[multilingual] &&
+              items.multilingualTextList[multilingual].length > 0
+            "
             :key="indexs"
             class="multilingual"
           >
@@ -1052,7 +1057,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwn(hz)) {
+        if (writeModel.hasOwnProperty(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

+ 6 - 1
src/views/book/courseware/preview/components/dialogue_article/Practicechs.vue

@@ -648,7 +648,12 @@
     </template>
     <template v-for="(items, indexs) in curQue.detail">
       <div
-        v-if="curQue.property.multilingual_position === 'all' && items.multilingualTextList[multilingual]"
+        v-if="
+          curQue.property.multilingual_position === 'all' &&
+          items.multilingualTextList &&
+          items.multilingualTextList[multilingual] &&
+          items.multilingualTextList[multilingual].length > 0
+        "
         :key="indexs"
         class="multilingual"
       >

+ 7 - 2
src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue

@@ -389,7 +389,12 @@
         </div>
         <template v-for="(items, indexs) in curQue.detail">
           <div
-            v-if="curQue.property.multilingual_position === 'all' && items.multilingualTextList[multilingual]"
+            v-if="
+              curQue.property.multilingual_position === 'all' &&
+              items.multilingualTextList &&
+              items.multilingualTextList[multilingual] &&
+              items.multilingualTextList[multilingual].length > 0
+            "
             :key="indexs"
             class="multilingual"
           >
@@ -947,7 +952,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwn(hz)) {
+        if (writeModel.hasOwnProperty(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

+ 28 - 16
src/views/book/courseware/preview/components/dialogue_article/index.vue

@@ -79,8 +79,8 @@
                     ? data.unified_attrib.topic_color
                     : '',
               }"
-              ><svg-icon icon-class="icon-article-ci" size="24" />本课生词</a
-            >
+              ><svg-icon icon-class="icon-article-ci" size="24"
+            /></a>
             <a
               v-if="data.property.is_enable_read === 'true'"
               @click="handleSwitchChange('showPhrases', 'showWord', 'showPractice')"
@@ -90,8 +90,8 @@
                     ? data.unified_attrib.topic_color
                     : '',
               }"
-              ><svg-icon icon-class="icon-article-practice" size="24" />语音练习</a
-            >
+              ><svg-icon icon-class="icon-article-practice" size="24"
+            /></a>
             <a
               v-if="data.property.is_enable_word === 'true'"
               @click="handleSwitchChange('showPhrases', 'showPractice', 'showWord')"
@@ -101,8 +101,8 @@
                     ? data.unified_attrib.topic_color
                     : '',
               }"
-              ><svg-icon icon-class="icon-article-phrase" size="24" />取词</a
-            >
+              ><svg-icon icon-class="icon-article-phrase" size="24"
+            /></a>
           </div>
         </div>
         <div ref="ArticleViewbody" class="ArticleView-body">
@@ -194,13 +194,19 @@
           />
         </div>
       </div>
-      <template v-if="data.new_word_list.new_word_list.length > 0">
+      <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" />
       </template>
-      <template v-if="data.other_word_list.new_word_list.length > 0">
+      <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" />
       </template>
-      <template v-if="data.notes_list.option.length > 0">
+      <template v-if="data.notes_list && data.notes_list.option && data.notes_list.option.length > 0">
         <NotesPreview :notes-data="data.notes_list" />
       </template>
     </div>
@@ -286,10 +292,10 @@ export default {
       handler(val) {
         if (val) {
           this.data.multilingual.forEach((item) => {
-            let trans_arr = item.translation.split('\n');
+            let trans_arr = item.translation ? item.translation.split('\n') : [];
             this.data.detail.forEach((items) => {
               let items_trans_arr = [];
-              if (!items.hasOwn('multilingualTextList')) {
+              if (items && !items.hasOwnProperty('multilingualTextList')) {
                 this.$set(items, 'multilingualTextList', {});
               }
               if (items.para) {
@@ -465,10 +471,10 @@ export default {
       }
       if (this.showLang) {
         this.data.multilingual.forEach((item) => {
-          let trans_arr = item.translation.split('\n');
+          let trans_arr = item.translation ? item.translation.split('\n') : [];
           this.data.detail.forEach((items) => {
             let items_trans_arr = [];
-            if (!items.hasOwn('multilingualTextList')) {
+            if (!items.hasOwnProperty('multilingualTextList')) {
               this.$set(items, 'multilingualTextList', {});
             }
             if (items.para) {
@@ -488,9 +494,15 @@ export default {
       this.NNPENewWordList = (
         this.data.new_word_list_other_component_input ? this.data.new_word_list_other_component_input : []
       )
-        .concat(this.data.new_word_list.new_word_list)
-        .concat(this.data.other_word_list.new_word_list);
-      this.NNPEAnnotationList = this.data.notes_list.option;
+        .concat(
+          this.data.new_word_list && this.data.new_word_list.new_word_list ? this.data.new_word_list.new_word_list : [],
+        )
+        .concat(
+          this.data.other_word_list && this.data.other_word_list.new_word_list
+            ? this.data.other_word_list.new_word_list
+            : [],
+        );
+      this.NNPEAnnotationList = this.data.notes_list && this.data.notes_list.option ? this.data.notes_list.option : [];
       let resArr = [];
       let sentArrTotal = [];
       let timeArr = [];

+ 102 - 36
src/views/book/courseware/preview/components/new_word/NewWordPreview.vue

@@ -5,13 +5,11 @@
 
     <div v-if="data" class="main">
       <div class="NPC-zhedie" :style="{ width: width }">
-        <div
-          class="topTitle"
-          :style="{
+        <!-- :style="{
             backgroundColor:
               data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
-          }"
-        >
+          }" -->
+        <div class="topTitle">
           <div class="NPC-top-left">
             <span class="NPC-topTitle-text" v-html="data.title_con"></span>
             <span v-if="showLang" class="NPC-topTitle-text">
@@ -20,13 +18,31 @@
           </div>
 
           <div class="NPC-top-right">
-            <SvgIcon v-if="is_list" icon-class="icon-card" size="24" @click="is_list = false" />
+            <SvgIcon
+              v-if="is_list"
+              icon-class="icon-card"
+              size="24"
+              @click="is_list = false"
+              :style="{
+                color:
+                  data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '#de4444',
+              }"
+            />
             <!-- <img v-if="is_list" src="@/assets/newWord_list.png" alt="" @click="is_list = false" /> -->
             <!-- <img v-else src="@/assets/newWord_tile.png" alt="" @click="is_list = true" /> -->
-            <SvgIcon v-else icon-class="icon-park" size="24" @click="is_list = true" />
-            <span class="NPC-top-right-text" @click="handleChangeTab">{{ wordShow ? '收起' : '展开' }}</span>
+            <SvgIcon
+              v-else
+              icon-class="icon-park"
+              size="24"
+              @click="is_list = true"
+              :style="{
+                color:
+                  data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '#de4444',
+              }"
+            />
+            <!-- <span class="NPC-top-right-text" @click="handleChangeTab">{{ wordShow ? '收起' : '展开' }}</span>
             <img v-if="wordShow" src="@/assets/down.png" alt="" @click="handleChangeTab" />
-            <img v-else class="rotate" src="@/assets/down.png" alt="" @click="handleChangeTab" />
+            <img v-else class="rotate" src="@/assets/down.png" alt="" @click="handleChangeTab" /> -->
           </div>
         </div>
         <el-collapse-transition>
@@ -86,6 +102,7 @@
                       <SvgIcon
                         v-else
                         icon-class="play-btn"
+                        size="24"
                         :style="{
                           color:
                             data.unified_attrib && data.unified_attrib.topic_color
@@ -114,6 +131,7 @@
                         <SvgIcon
                           v-else
                           icon-class="play-btn"
+                          size="24"
                           :style="{
                             color:
                               data.unified_attrib && data.unified_attrib.topic_color
@@ -138,6 +156,10 @@
                               data.unified_attrib && data.unified_attrib.topic_color
                                 ? data.unified_attrib.topic_color
                                 : '',
+                            marginTop:
+                              data.unified_attrib && data.unified_attrib.font_size
+                                ? (((data.unified_attrib.font_size.replace('pt', '') * 1.5) / 3) * 4 - 16) / 2 + 'px'
+                                : '',
                           }"
                           >{{ index + 1 }}</b
                         >
@@ -385,6 +407,18 @@
           </template>
           <template v-else>
             <div v-if="data.new_word_list && data.new_word_list.length > 0" v-show="wordShow" class="NPC-word-tile">
+              <div v-if="data.audio_data.file_id" class="aduioLine-box" style="height: 0; margin: 0; overflow: hidden">
+                <AudioLine
+                  ref="audioLine"
+                  :audio-id="'newWordAudio' + indexStr"
+                  :mp3="data.audio_data.url"
+                  :get-cur-time="getCurTime"
+                  :ed="ed"
+                  type="audioLine"
+                  :attrib="data.unified_attrib"
+                  @handleListenRead="handleListenRead"
+                />
+              </div>
               <div v-for="(item, index) in data.new_word_list" :key="index" class="NPC-word-tile-item">
                 <div class="writeTop" :class="{ flipped: item.isFlipped }">
                   <div
@@ -474,8 +508,43 @@
                                 ? data.unified_attrib.topic_color
                                 : '',
                           }"
-                          :file-id="item.mp3_list"
+                          :file-id="item.mp3_list_url"
                         />
+                        <template v-else-if="item.bg || item.ed">
+                          <div
+                            class="audio-wrapper"
+                            :style="{
+                              background:
+                                data.unified_attrib && data.unified_attrib.topic_color
+                                  ? data.unified_attrib.topic_color
+                                  : '',
+                              display: 'flex',
+                              alignItems: 'center',
+                              justifyContent: 'center',
+                            }"
+                            @click="handleChangeTime(item.bg, item.ed)"
+                          >
+                            <SvgIcon
+                              v-if="curTime >= item.bg && curTime < item.ed && stopAudioS"
+                              icon-class="animated"
+                              size="14"
+                              :style="{
+                                color: '#fff',
+                              }"
+                            />
+                            <SvgIcon
+                              v-else
+                              icon-class="play-btn"
+                              size="14"
+                              :style="{
+                                color: '#fff',
+                                width: '14px',
+                                height: '14px',
+                              }"
+                            />
+                          </div>
+                        </template>
+
                         <p
                           v-if="item.pinyin && item.pinyin.split(' ').length === 1"
                           :style="{
@@ -483,10 +552,6 @@
                               data.unified_attrib && data.unified_attrib.topic_color
                                 ? data.unified_attrib.topic_color
                                 : '',
-                            fontSize:
-                              data.unified_attrib && data.unified_attrib.pinyin_size
-                                ? data.unified_attrib.pinyin_size
-                                : '',
                           }"
                           class="pinyin-box"
                         >
@@ -501,10 +566,6 @@
                                   data.unified_attrib && data.unified_attrib.topic_color
                                     ? data.unified_attrib.topic_color
                                     : '',
-                                fontSize:
-                                  data.unified_attrib && data.unified_attrib.pinyin_size
-                                    ? data.unified_attrib.pinyin_size
-                                    : '',
                               }"
                             >
                               {{ item.pinyin.split(' ')[indexh] ? item.pinyin.split(' ')[indexh] : '' }}
@@ -554,14 +615,15 @@
                         </div>
                       </div>
                     </div>
+                    <!-- width:
+                          !(item.collocation || item.liju_list) && item.new_word.length < 4
+                            ? item.hz_info.length * 86 + 'px'
+                            : '', -->
                     <div
                       v-if="item.collocation || item.liju_list || item.definition_list || item.cixing"
                       class="definition_list-box"
                       :style="{
-                        width:
-                          !(item.collocation || item.liju_list) && item.new_word.length < 4
-                            ? item.hz_info.length * 86 + 'px'
-                            : '',
+                        width: !(item.collocation || item.liju_list) && item.new_word.length < 4 ? '160px' : '',
                         margin:
                           !(item.collocation || item.liju_list) && item.new_word.length < 4 ? '16px auto 0 auto' : '',
                       }"
@@ -1010,8 +1072,7 @@ export default {
   .NPC-word-list {
     padding: 20px 24px;
     border: 1px solid rgba(0, 0, 0, 10%);
-    border-top: none;
-    border-radius: 0 0 8px 8px;
+    border-radius: 8px;
   }
 
   .detail-icon {
@@ -1224,7 +1285,6 @@ export default {
     display: flex;
     flex-flow: wrap;
     gap: 20px;
-    padding: 20px 0;
   }
 
   .writeTop {
@@ -1459,9 +1519,9 @@ export default {
           }
 
           p {
-            margin: 0 0 8px;
+            margin: 0;
             font-family: 'League';
-            font-size: 18px;
+            font-size: 14px;
             font-feature-settings: 'cv01' on;
             line-height: 120%;
             color: #de4444;
@@ -1471,17 +1531,16 @@ export default {
 
       :deep .audio-wrapper {
         box-sizing: border-box;
-        width: 50px;
-        height: 50px;
-        padding: 13px;
+        width: 24px;
+        height: 24px;
         margin: 0 auto 8px;
         cursor: pointer;
         background: #f3f3f3;
         border-radius: 40px;
 
         .voice-play {
-          width: 24px;
-          height: 24px;
+          width: 14px;
+          height: 14px;
         }
       }
 
@@ -1508,7 +1567,8 @@ export default {
 
           p {
             flex: 1;
-            line-height: 0;
+
+            // line-height: 0;
             word-break: break-word;
             white-space: pre-wrap;
           }
@@ -1517,7 +1577,13 @@ export default {
 
       :deep p {
         margin: 0;
-        line-height: 1.2;
+
+        span,
+        b,
+        p {
+          font-size: 14px !important;
+          text-align: left !important; // 有的富文本里设置了居中对齐
+        }
       }
     }
 
@@ -1647,8 +1713,8 @@ export default {
     padding-right: 16px;
     padding-left: 24px;
     overflow: hidden;
-    background: #e35454;
-    border: 1px solid rgba(0, 0, 0, 10%);
+
+    // background: #e35454;
     border-radius: 8px 8px 0 0;
 
     .NPC-top-left {

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

@@ -6,7 +6,7 @@
         class="voice-play"
       />
     </span>
-    <audio :id="fileId" :ref="fileId" :src="url" preload="metadata"></audio>
+    <audio :id="fileId" :ref="fileId" :src="fileId" preload="metadata"></audio>
   </div>
 </template>
 

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

@@ -5,24 +5,22 @@
 
     <div class="main">
       <div class="NPC-zhedie">
-        <div
-          class="topTitle"
-          :style="{
+        <!-- :style="{
             backgroundColor:
               data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
-          }"
-        >
+          }" -->
+        <div class="topTitle-note" v-if="data.title_con">
           <div class="NPC-top-left">
             <span class="NPC-topTitle-text" v-html="data.title_con"></span>
             <span v-if="showLang" class="NPC-topTitle-text">
               {{ titleTrans[getLang()] }}
             </span>
           </div>
-          <div class="NPC-top-right" @click="handleChangeTab">
+          <!-- <div class="NPC-top-right" @click="handleChangeTab">
             <span class="NPC-top-right-text">{{ wordShow ? '收起' : '展开' }}</span>
             <img v-if="wordShow" src="@/assets/down.png" alt="" />
             <img v-else class="rotate" src="@/assets/down.png" alt="" />
-          </div>
+          </div> -->
         </div>
         <el-collapse-transition>
           <div v-show="wordShow" class="NPC-notes-list">
@@ -222,7 +220,7 @@ export default {
   .NPC-zhedie {
     // margin-bottom: 24px;
 
-    .topTitle {
+    .topTitle-note {
       display: flex;
       justify-content: space-between;
       width: 100%;
@@ -230,9 +228,10 @@ export default {
       padding-right: 16px;
       padding-left: 24px;
       overflow: hidden;
-      background: #e35454;
-      border: 1px solid rgba(0, 0, 0, 10%);
-      border-radius: 8px 8px 0 0;
+
+      // background: #e35454;
+      // border: 1px solid rgba(0, 0, 0, 10%);
+      // border-radius: 8px 8px 0 0;
 
       :deep p {
         margin: 0;
@@ -283,8 +282,7 @@ export default {
     .NPC-notes-list {
       padding: 24px 24px 5px;
       border: 1px solid rgba(0, 0, 0, 10%);
-      border-top: none;
-      border-radius: 0 0 8px 8px;
+      border-radius: 8px;
 
       .NPC-notes {
         width: 100%;