Pārlūkot izejas kodu

样式统一,组件主题色

dsy 2 nedēļas atpakaļ
vecāks
revīzija
d4e5fc0ac6
46 mainītis faili ar 574 papildinājumiem un 278 dzēšanām
  1. BIN
      src/assets/preview-bg.png
  2. BIN
      src/assets/voice_matrix/pauseC-16-normal-blue copy.png
  3. 20 25
      src/components/CommonPreview.vue
  4. 1 1
      src/components/RichText.vue
  5. 6 0
      src/icons/svg/icon-card.svg
  6. 6 0
      src/icons/svg/icon-park.svg
  7. 6 0
      src/icons/svg/luyin-delete.svg
  8. 6 0
      src/icons/svg/luyin-play-back.svg
  9. 6 0
      src/icons/svg/luyin-radio-button.svg
  10. 6 0
      src/styles/common.scss
  11. 1 1
      src/styles/mixin.scss
  12. 8 2
      src/styles/variables.scss
  13. 5 4
      src/views/book/courseware/preview/CoursewarePreview.vue
  14. 123 29
      src/views/book/courseware/preview/common/SoundRecord.vue
  15. 1 1
      src/views/book/courseware/preview/components/article/PhraseModelChs.vue
  16. 1 1
      src/views/book/courseware/preview/components/article/WordModelChs.vue
  17. 2 2
      src/views/book/courseware/preview/components/article/index.vue
  18. 6 3
      src/views/book/courseware/preview/components/character_base/CharacterBasePreview.vue
  19. 6 4
      src/views/book/courseware/preview/components/character_base/components/AudioPlay.vue
  20. 22 4
      src/views/book/courseware/preview/components/character_base/components/FreewriteLettle.vue
  21. 4 4
      src/views/book/courseware/preview/components/character_base/components/Strockplayredline.vue
  22. 18 18
      src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue
  23. 4 4
      src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue
  24. 2 2
      src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue
  25. 2 2
      src/views/book/courseware/preview/components/dialogue_article/index.vue
  26. 8 2
      src/views/book/courseware/preview/components/fill/FillPreview.vue
  27. 21 8
      src/views/book/courseware/preview/components/fill/components/AudioFillPlay.vue
  28. 9 8
      src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue
  29. 69 52
      src/views/book/courseware/preview/components/image_text/components/MagazineSentence.vue
  30. 6 1
      src/views/book/courseware/preview/components/judge/JudgePreview.vue
  31. 2 1
      src/views/book/courseware/preview/components/matching/MatchingPreview.vue
  32. 51 24
      src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue
  33. 26 11
      src/views/book/courseware/preview/components/new_word/NewWordPreview.vue
  34. 8 3
      src/views/book/courseware/preview/components/new_word/components/Strockplayredline.vue
  35. 11 1
      src/views/book/courseware/preview/components/new_word/components/WordPhraseDetail.vue
  36. 3 3
      src/views/book/courseware/preview/components/notes/NotesPreview.vue
  37. 2 1
      src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue
  38. 2 1
      src/views/book/courseware/preview/components/select/SelectPreview.vue
  39. 12 1
      src/views/book/courseware/preview/components/table/TablePreview.vue
  40. 28 6
      src/views/book/courseware/preview/components/upload_preview/UploadPreviewPreview.vue
  41. 4 0
      src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue
  42. 16 5
      src/views/book/courseware/preview/components/voice_matrix/components/AudioCompareMatrix.vue
  43. 17 12
      src/views/book/courseware/preview/components/voice_matrix/components/AudioLine.vue
  44. 9 28
      src/views/book/courseware/preview/components/voice_matrix/components/AudioRed.vue
  45. 6 1
      src/views/book/courseware/preview/components/write/WritePreview.vue
  46. 2 2
      src/views/book/courseware/preview/components/write_base/WriteBasePreview.vue

BIN
src/assets/preview-bg.png


BIN
src/assets/voice_matrix/pauseC-16-normal-blue copy.png


+ 20 - 25
src/components/CommonPreview.vue

@@ -20,7 +20,7 @@
           </el-select>
         </span>
         <div class="operator">
-          <slot name="operator" :courseware="courseware_info"></slot>
+          <slot name="operator" :courseware="courseware_info" :project-id="projectId"></slot>
         </div>
       </div>
     </div>
@@ -28,10 +28,7 @@
     <div class="audit-content">
       <div ref="previewMain" class="main-container">
         <main :class="['preview-main', { 'no-audit': !isShowAudit }]">
-          <span class="title">
-            <SvgIcon icon-class="menu-2" size="24" />
-            <span>{{ courseware_info.name_path }}</span>
-          </span>
+          <div class="preview-left"></div>
           <CoursewarePreview
             v-if="courseware_info.book_name"
             ref="courserware"
@@ -47,6 +44,7 @@
             @computeScroll="computeScroll"
             @addRemark="addRemark"
           />
+          <div class="preview-right"></div>
         </main>
       </div>
       <div v-if="isShowAudit" class="remark-list">
@@ -696,39 +694,36 @@ export default {
     flex: 1;
     min-width: 1110px;
     overflow: auto;
+    background: url('@/assets/preview-bg.png') repeat;
   }
 
   main.preview-main {
     display: flex;
     flex: 1;
-    flex-direction: column;
-    row-gap: 5px;
-    width: 1100px;
-    min-width: 1100px;
+    width: calc($courseware-width + $courseware-left-margin + $courseware-right-margin);
+    min-width: calc($courseware-width + $courseware-left-margin + $courseware-right-margin);
     min-height: 100%;
-    padding: 5px;
     margin: 0 auto;
     background-color: #fff;
     border-radius: 4px;
     box-shadow: 0 2px 4px rgba(0, 0, 0, 10%);
 
-    &.no-audit {
-      margin: 0 auto;
+    .preview-left {
+      width: $courseware-left-margin;
+      min-width: $courseware-left-margin;
+      max-width: $courseware-left-margin;
+      background-color: #ecf0f1;
     }
 
-    .title {
-      display: inline-flex;
-      column-gap: 24px;
-      align-items: center;
-      width: 100%;
-      min-width: 280px;
-      height: 64px;
-      padding: 18px 24px;
-      font-size: 20px;
-      color: #fff;
-      background-color: #f44444;
-      border-top-left-radius: 12px;
-      border-top-right-radius: 16px;
+    .preview-right {
+      width: $courseware-right-margin;
+      min-width: $courseware-right-margin;
+      max-width: $courseware-right-margin;
+      background-color: #ecf0f1;
+    }
+
+    &.no-audit {
+      margin: 0 auto;
     }
   }
 

+ 1 - 1
src/components/RichText.vue

@@ -96,7 +96,7 @@ export default {
     },
     wordlimitNum: {
       type: [Number, Boolean],
-      default: 1000,
+      default: 1000000,
     },
     isFill: {
       type: Boolean,

+ 6 - 0
src/icons/svg/icon-card.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="36" height="36" style="" filter="none">
+    
+    <g>
+    <path d="M27.68 6.336h-23.36c-0.003 0-0.006-0-0.010-0-1.267 0-2.294 1.027-2.294 2.294 0 0.004 0 0.007 0 0.011v-0.001 14.72c0.006 1.27 1.034 2.298 2.303 2.304h23.361c1.28 0 2.336-1.024 2.336-2.304v-14.72c0-1.28-1.056-2.304-2.336-2.304zM15.104 15.36c0-0.192 0.16-0.384 0.352-0.384h7.232c0.192 0 0.352 0.192 0.352 0.384v0.96c0 0.192-0.16 0.384-0.352 0.384h-7.232c-0.192 0-0.352-0.16-0.352-0.384v-0.96zM13.504 19.136c0 0.192-0.16 0.352-0.352 0.352h-6.976c-0.192 0-0.384-0.16-0.384-0.352v-6.272c0-0.192 0.192-0.352 0.384-0.352h6.976c0.192 0 0.352 0.16 0.352 0.352v6.272zM24.672 19.136c0 0.192-0.16 0.352-0.352 0.352h-8.864c-0.194-0.002-0.35-0.158-0.352-0.352v-0.992c0-0.192 0.16-0.352 0.352-0.352h8.864c0.192 0 0.352 0.16 0.352 0.352v0.992zM26.208 13.856c0 0.192-0.16 0.352-0.384 0.352h-10.368c-0.194-0.002-0.35-0.158-0.352-0.352v-0.992c0-0.192 0.16-0.352 0.352-0.352h10.368c0.224 0 0.384 0.16 0.384 0.352v0.992z" fill="currentColor"></path>
+    </g>
+  </svg>

+ 6 - 0
src/icons/svg/icon-park.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" width="36" height="36" style="" filter="none">
+    
+    <g>
+    <rect width="48" height="48" fill="currentColor" fill-opacity="0.01" stroke="none"></rect><rect x="4" y="8" width="40" height="32" rx="2" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"></rect><path fill-rule="evenodd" clip-rule="evenodd" d="M4 29H44H4Z" fill="none"></path><path d="M4 29H44" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M4 19H44H4Z" fill="none"></path><path d="M4 19H44" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M17 40V19V40Z" fill="none"></path><path d="M17 40V19" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M4 38V17V38Z" fill="none"></path><path d="M4 38V17" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M44 38V17V38Z" fill="none"></path><path d="M44 38V17" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M31 40V19V40Z" fill="none"></path><path d="M31 40V19" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path d="M9 40H39" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path>
+    </g>
+  </svg>

+ 6 - 0
src/icons/svg/luyin-delete.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="24" height="24" style="" filter="none">
+    
+    <g>
+    <path d="M22.667 8h6.667v2.667h-2.667v17.333c0 0.736-0.597 1.333-1.333 1.333v0h-18.667c-0.736 0-1.333-0.597-1.333-1.333v0-17.333h-2.667v-2.667h6.667v-4c0-0.736 0.597-1.333 1.333-1.333v0h10.667c0.736 0 1.333 0.597 1.333 1.333v0 4zM24 10.667h-16v16h16v-16zM17.885 18.667l2.357 2.357-1.885 1.885-2.357-2.357-2.357 2.357-1.885-1.885 2.357-2.357-2.357-2.357 1.885-1.885 2.357 2.357 2.357-2.357 1.885 1.885-2.357 2.357zM12 5.333v2.667h8v-2.667h-8z" fill="currentColor"></path>
+    </g>
+  </svg>

+ 6 - 0
src/icons/svg/luyin-play-back.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="24" height="24" style="" filter="none">
+    
+    <g>
+    <path d="M16 29.333c-7.364 0-13.333-5.969-13.333-13.333s5.969-13.333 13.333-13.333 13.333 5.969 13.333 13.333-5.969 13.333-13.333 13.333zM16 26.667c5.891 0 10.667-4.776 10.667-10.667s-4.776-10.667-10.667-10.667v0c-5.891 0-10.667 4.776-10.667 10.667s4.776 10.667 10.667 10.667v0zM14.163 11.22l6.505 4.336c0.144 0.097 0.238 0.26 0.238 0.444s-0.094 0.347-0.236 0.443l-0.002 0.001-6.507 4.336c-0.083 0.056-0.185 0.089-0.295 0.089-0.294 0-0.532-0.238-0.533-0.531v-8.675c0.001-0.294 0.239-0.532 0.533-0.532 0.11 0 0.213 0.034 0.298 0.091l-0.002-0.001z" fill="currentColor"></path>
+    </g>
+  </svg>

+ 6 - 0
src/icons/svg/luyin-radio-button.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="24" height="24" style="" filter="none">
+    
+    <g>
+    <path d="M16 29.333c-7.364 0-13.333-5.969-13.333-13.333s5.969-13.333 13.333-13.333 13.333 5.969 13.333 13.333-5.969 13.333-13.333 13.333zM16 26.667c5.891 0 10.667-4.776 10.667-10.667s-4.776-10.667-10.667-10.667v0c-5.891 0-10.667 4.776-10.667 10.667s4.776 10.667 10.667 10.667v0zM16 22.667c-3.682 0-6.667-2.985-6.667-6.667s2.985-6.667 6.667-6.667v0c3.682 0 6.667 2.985 6.667 6.667s-2.985 6.667-6.667 6.667v0z" fill="currentColor"></path>
+    </g>
+  </svg>

+ 6 - 0
src/styles/common.scss

@@ -54,3 +54,9 @@
     margin-left: 8px;
   }
 }
+
+.icon-mask {
+  display: inline-block;
+  mask-repeat: no-repeat;
+  mask-size: 100% 100%;
+}

+ 1 - 1
src/styles/mixin.scss

@@ -41,7 +41,7 @@
 @mixin preview-base {
   display: grid;
   gap: 6px;
-  padding: 8px;
+  padding: $border-component-spacing;
 
   :deep .rich-text {
     @include rich-text;

+ 8 - 2
src/styles/variables.scss

@@ -21,5 +21,11 @@ $label-color: #076aff;
 $setting-active-color: #4176ff;
 
 // px
-$header-h: 64px;
-$courseware-width: 1100px;
+$header-h: 64px; // 顶部内容高度
+$courseware-width: 1000px; // 教材内容宽度
+$courseware-left-margin: 100px; // 教材左页边距
+$courseware-right-margin: 100px; // 教材右页边距
+$courseware-top-margin: 65px; // 教材顶部页边距
+$courseware-bottom-margin: 65px; // 教材底部页边距
+$component-spacing: 24px; // 组件间间距
+$border-component-spacing: 10px; // 组件边框与组件内容间距

+ 5 - 4
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -310,11 +310,12 @@ export default {
   position: relative;
   display: flex;
   flex-direction: column;
-  row-gap: 6px;
+  row-gap: $component-spacing;
   width: 100%;
   height: 100%;
   min-height: 500px;
-  padding: 24px;
+  margin-top: $courseware-top-margin;
+  margin-bottom: $courseware-bottom-margin;
   background-color: #fff;
   background-repeat: no-repeat;
   border-bottom-right-radius: 12px;
@@ -322,11 +323,11 @@ export default {
 
   .row {
     display: grid;
-    gap: 16px;
+    gap: $component-spacing;
 
     .col {
       display: grid;
-      gap: 16px;
+      gap: $component-spacing;
       overflow: hidden;
     }
 

+ 123 - 29
src/views/book/courseware/preview/common/SoundRecord.vue

@@ -1,7 +1,24 @@
 <template>
   <div class="record">
     <template v-if="type === 'normal' || type === 'mini'">
-      <div :class="['record', microphoneStatus ? 'active' : '']" @click="microphone"></div>
+      <div :class="['record', microphoneStatus ? 'active' : '']" @click="microphone">
+        <div
+          v-if="microphoneStatus"
+          :style="{
+            backgroundColor: attrib?.topic_color,
+            maskImage: `url(${require('@/assets/voice_matrix/luyin-active.png')})`,
+          }"
+          class="icon-mask"
+        ></div>
+        <SvgIcon
+          v-else
+          icon-class="luyin-radio-button"
+          size="24"
+          :style="{
+            color: attrib && attrib.topic_color ? attrib.topic_color : '',
+          }"
+        />
+      </div>
       <span
         v-if="type && type == 'normal'"
         :class="[
@@ -10,34 +27,88 @@
           selectIndex || selectIndex == 0 ? 'record-black' : '',
           type && type == 'normal' ? 'record-time-flex' : '',
         ]"
+        :style="{
+          fontSize: attrib && attrib.font_size ? attrib.font_size : '',
+          color: microphoneStatus && attrib && attrib.topic_color ? attrib.topic_color : '',
+        }"
         >{{ isPlaying ? '-' : '' }}{{ handleDateTime(recordtime) }}</span
       >
       <div
         :class="['playBack', hasMicro]"
         @click="playmicrophone(selectIndex || selectIndex == 0 ? recordList[selectIndex].toltime : '')"
-      ></div>
+      >
+        <!-- <SvgIcon icon-class="luyin-paly-back" size="24" /> -->
+      </div>
     </template>
 
     <template v-else-if="type === 'pro'">
-      <div :class="['record', microphoneStatus ? 'active' : '']" @click="microphone"></div>
+      <div :class="['record', microphoneStatus ? 'active' : '']" @click="microphone">
+        <div
+          v-if="microphoneStatus"
+          :style="{
+            backgroundColor: attrib?.topic_color,
+            maskImage: `url(${require('@/assets/voice_matrix/luyin-active.png')})`,
+          }"
+          class="icon-mask"
+        ></div>
+        <SvgIcon
+          v-else
+          icon-class="luyin-radio-button"
+          size="24"
+          :style="{
+            color: attrib && attrib.topic_color ? attrib.topic_color : '',
+          }"
+        />
+      </div>
       <el-select v-model="selectIndex" placeholder="无录音" class="proSelect" @change="handleChangeRecord">
         <el-option v-for="(item, i) in recordList" :key="i + item.id" :label="item.name" :value="i" />
       </el-select>
       <div
         :class="['playBack', hasMicro]"
         @click="playmicrophone(selectIndex || selectIndex == 0 ? recordList[selectIndex].toltime : '')"
-      ></div>
-      <a :class="['record-delete', hasMicro ? 'record-delete-has' : '']" @click="handleDelete"></a>
+      >
+        <!-- <SvgIcon icon-class="luyin-paly-back" size="24" /> -->
+      </div>
+      <a
+        :class="['record-delete', hasMicro ? 'record-delete-has' : '']"
+        :style="{
+          color: hasMicro && attrib && attrib.topic_color ? attrib.topic_color : '',
+        }"
+        @click="handleDelete"
+      >
+        <SvgIcon icon-class="luyin-delete" size="24" />
+      </a>
     </template>
 
     <template v-else>
-      <div :class="['record', microphoneStatus ? 'active' : '']" @click="microphone"></div>
+      <div :class="['record', microphoneStatus ? 'active' : '']" @click="microphone">
+        <div
+          v-if="microphoneStatus"
+          :style="{
+            backgroundColor: attrib?.topic_color,
+            maskImage: `url(${require('@/assets/voice_matrix/luyin-active.png')})`,
+          }"
+          class="icon-mask"
+        ></div>
+        <SvgIcon
+          v-else
+          icon-class="luyin-radio-button"
+          size="24"
+          :style="{
+            color: attrib && attrib.topic_color ? attrib.topic_color : '',
+          }"
+        />
+      </div>
       <span
         :class="[
           'record-time',
           microphoneStatus ? 'record-ing' : '',
           selectIndex || selectIndex == 0 ? 'record-black' : '',
         ]"
+        :style="{
+          fontSize: attrib && attrib.font_size ? attrib.font_size : '',
+          color: microphoneStatus && attrib && attrib.topic_color ? attrib.topic_color : '',
+        }"
         >{{ isPlaying ? '-' : '' }}{{ handleDateTime(recordtime) }}</span
       >
       <el-select v-model="selectIndex" placeholder="无录音" @change="handleChangeRecord">
@@ -46,8 +117,18 @@
       <div
         :class="['playBack', hasMicro]"
         @click="playmicrophone(selectIndex || selectIndex == 0 ? recordList[selectIndex].toltime : '')"
-      ></div>
-      <a :class="['record-delete', hasMicro ? 'record-delete-has' : '']" @click="handleDelete"></a>
+      >
+        <!-- <SvgIcon icon-class="luyin-paly-back" size="24" /> -->
+      </div>
+      <a
+        :class="['record-delete', hasMicro ? 'record-delete-has' : '']"
+        :style="{
+          color: hasMicro && attrib && attrib.topic_color ? attrib.topic_color : '',
+        }"
+        @click="handleDelete"
+      >
+        <SvgIcon icon-class="luyin-delete" size="24" />
+      </a>
     </template>
   </div>
 </template>
@@ -330,9 +411,14 @@ export default {
   max-width: 160px;
   height: 32px;
 
+  .icon-mask {
+    width: 24px;
+    height: 24px;
+  }
+
   .playBack {
-    width: 16px;
-    height: 16px;
+    width: 20px;
+    height: 20px;
     margin-left: 8px;
     cursor: pointer;
     background: url('@/assets/voice_matrix/luyin-play.png') center no-repeat;
@@ -358,21 +444,27 @@ export default {
   }
 
   .record {
-    width: 16px;
-    height: 16px;
+    width: 24px;
+    height: 24px;
     cursor: pointer;
-    background: url('@/assets/voice_matrix/luyin.png') center no-repeat;
-    background-size: 100%;
 
-    &.active {
-      background: url('@/assets/voice_matrix/luyin-active.png') center no-repeat;
-      background-size: 100%;
+    img {
+      width: 24px;
+      height: 24px;
     }
 
-    &.active:hover {
-      background: url('@/assets/voice_matrix/luyin-stop.png') center no-repeat;
-      background-size: 100%;
-    }
+    // background: url('@/assets/voice_matrix/luyin.png') center no-repeat;
+    // background-size: 100%;
+
+    // &.active {
+    //   background: url('@/assets/voice_matrix/luyin-active.png') center no-repeat;
+    //   background-size: 100%;
+    // }
+
+    // &.active:hover {
+    //   background: url('@/assets/voice_matrix/luyin-stop.png') center no-repeat;
+    //   background-size: 100%;
+    // }
   }
 
   .record-time {
@@ -401,17 +493,19 @@ export default {
 
   .record-delete {
     display: block;
-    width: 16px;
-    height: 16px;
+    width: 24px;
+    height: 24px;
     margin-left: 8px;
-    background: url('@/assets/voice_matrix/luyin-delete.png') center no-repeat;
-    background-size: 100%;
+    color: #000;
+
+    // background: url('@/assets/voice_matrix/luyin-delete.png') center no-repeat;
+    // background-size: 100%;
 
     &.record-delete-has {
-      &:hover {
-        background: url('@/assets/voice_matrix/luyin-delete-active.png') center no-repeat;
-        background-size: 100%;
-      }
+      // &:hover {
+      //   background: url('@/assets/voice_matrix/luyin-delete-active.png') center no-repeat;
+      //   background-size: 100%;
+      // }
     }
   }
 }

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

@@ -1192,7 +1192,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwnProperty(hz)) {
+        if (writeModel.hasOwn(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

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

@@ -1041,7 +1041,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwnProperty(hz)) {
+        if (writeModel.hasOwn(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

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

@@ -256,7 +256,7 @@ export default {
             let trans_arr = item.translation.split('\n');
             this.data.detail.forEach((items) => {
               let items_trans_arr = [];
-              if (!items.hasOwnProperty('multilingualTextList')) {
+              if (!items.hasOwn('multilingualTextList')) {
                 this.$set(items, 'multilingualTextList', {});
               }
               if (items.para) {
@@ -435,7 +435,7 @@ export default {
           let trans_arr = item.translation.split('\n');
           this.data.detail.forEach((items) => {
             let items_trans_arr = [];
-            if (!items.hasOwnProperty('multilingualTextList')) {
+            if (!items.hasOwn('multilingualTextList')) {
               this.$set(items, 'multilingualTextList', {});
             }
             if (items.para) {

+ 6 - 3
src/views/book/courseware/preview/components/character_base/CharacterBasePreview.vue

@@ -5,7 +5,11 @@
 
     <div class="main">
       <div class="main-top" :style="{ width: data.hz_strokes_list.length * 64 + 'px' }">
-        <AudioPlay v-if="isEnable(data.property.is_enable_voice)" :file-id="data.audio_file_id" theme-color="gray" />
+        <AudioPlay
+          v-if="isEnable(data.property.is_enable_voice)"
+          :file-id="data.audio_file_id"
+          :theme-color="data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : ''"
+        />
         <span v-if="isEnable(data.property.view_pinyin)" class="pinyin">{{ data.pinyin }}</span>
       </div>
       <div class="strock-chinese-box">
@@ -19,7 +23,7 @@
             :book-strokes="items.strokes"
             :class="['strock-chinese', indexs !== data.hz_strokes_list.length - 1 ? 'border-right-none' : '']"
             :bg-type="data.property.frame_type"
-            :frame-color="data.property.frame_color"
+            :play-color="data.property.frame_color"
           />
         </template>
         <template v-else>
@@ -191,7 +195,6 @@ export default {
       show_preview: false,
       miao_arr: [],
       if_miao_show: false, // 描红模块
-      show_preview: false,
       hanzi_color: '#404040', // 描红汉字底色
     };
   },

+ 6 - 4
src/views/book/courseware/preview/components/character_base/components/AudioPlay.vue

@@ -7,17 +7,19 @@
         width: showSlider ? '230px' : '',
         justifyContent: showSlider && !showProgress ? 'space-between' : 'center',
         backgroundColor: themeColor ? '' : bookInfo.theme_color,
+        color: themeColor ? themeColor : '#000',
       }"
       @click="playAudio"
     >
-      <SvgIcon v-if="audio.paused" :size="audio.paused ? 20 : 14" :icon-class="iconClass" />
-      <img
+      <SvgIcon size="24" :icon-class="iconClass" />
+
+      <!-- <img
         v-else
         :src="
           themeColor === 'gray' ? require('@/assets/voice-play-gray.png') : require('@/assets/voice-play-white.png')
         "
         class="voice-play"
-      />
+      /> -->
 
       <template v-if="showSlider">
         <template v-if="showProgress">
@@ -91,7 +93,7 @@ export default {
   },
   computed: {
     iconClass() {
-      return this.audio.paused ? 'audio' : 'audio-stop';
+      return this.audio.paused ? 'play-btn' : 'animated';
     },
   },
   watch: {

+ 22 - 4
src/views/book/courseware/preview/components/character_base/components/FreewriteLettle.vue

@@ -2,8 +2,8 @@
   <div class="practice practiceSingleNPC">
     <i class="el-icon-close close-icon" @click="changePraShow()"></i>
     <div class="right-content">
-      <SvgIcon icon-class="hanzi-writer-bg" class="character-target-bg" v-if="bgType === 'tian'" />
-      <svg-icon icon-class="mi" class="character-target-bg" v-else-if="bgType === 'mi'" />
+      <SvgIcon v-if="bgType === 'tian'" icon-class="hanzi-writer-bg" class="character-target-bg" />
+      <svg-icon v-else-if="bgType === 'mi'" icon-class="mi" class="character-target-bg" />
       <div class="right-strockred">
         <template v-if="!hasPlay && data && data.strokes_image">
           <img class="img" :src="data.strokes_image" alt="" />
@@ -25,10 +25,24 @@
         </a>
       </div>
       <ul class="nav-list" :class="[showPlay ? '' : 'nav-list-line']">
-        <li v-if="showPlay" :class="currenHzData && currenHzData.strokes_content ? '' : 'disabled'" @click="play()">
+        <li
+          v-if="showPlay"
+          :class="currenHzData && currenHzData.strokes_content ? '' : 'disabled'"
+          :style="{
+            backgroundColor:
+              currenHzData && currenHzData.strokes_content && attrib && attrib.topic_color ? attrib.topic_color : '',
+          }"
+          @click="play()"
+        >
           播放
         </li>
-        <li :class="disabled ? 'disabled' : ''" @click="handleWriteImg">保存</li>
+        <li
+          :class="disabled ? 'disabled' : ''"
+          :style="{ backgroundColor: attrib && attrib.topic_color ? attrib.topic_color : '#de4444' }"
+          @click="handleWriteImg"
+        >
+          保存
+        </li>
       </ul>
     </div>
   </div>
@@ -76,6 +90,10 @@ export default {
       type: String,
       default: 'tian',
     },
+    attrib: {
+      type: Object,
+      default: {},
+    },
   },
   data() {
     return {

+ 4 - 4
src/views/book/courseware/preview/components/character_base/components/Strockplayredline.vue

@@ -2,14 +2,14 @@
   <div
     v-if="bookText"
     class="strockplay-redInner"
-    :style="{ borderColor: frameColor, borderWidth: bgType === 'none' ? '0px' : '1px' }"
+    :style="{ borderColor: playColor, borderWidth: bgType === 'none' ? '0px' : '1px' }"
   >
-    <div v-if="playStorkes" :class="['strock-play-box']" :style="{ color: frameColor }" @click="playHanzi">
+    <div v-if="playStorkes" :class="['strock-play-box']" :style="{ color: playColor }" @click="playHanzi">
       <SvgIcon icon-class="hanzi-strock-play" class="strock-play-btn" />
     </div>
     <div class="character-target-box">
       <SvgIcon v-if="bgType === 'tian'" icon-class="hanzi-writer-bg" class="character-target-bg" />
-      <svg-icon icon-class="mi" class="character-target-bg" v-else-if="bgType === 'mi'" />
+      <svg-icon v-else-if="bgType === 'mi'" icon-class="mi" class="character-target-bg" />
       <div :id="targetDiv" :ref="targetDiv" class="character-target-div"></div>
     </div>
   </div>
@@ -44,7 +44,7 @@ export default {
       type: String,
       default: 'tian',
     },
-    frameColor: {
+    playColor: {
       type: String,
       default: '#F13232',
     },

+ 18 - 18
src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue

@@ -13,15 +13,15 @@
         <draggable
           v-model="SortArr"
           animation="300"
-          @start="onStart($event)"
-          @end="onEnd($event)"
-          @choose="choose($event)"
           group="site"
           class="content-box"
           :disabled="disabled"
+          @start="onStart($event)"
+          @end="onEnd($event)"
+          @choose="choose($event)"
         >
           <transition-group>
-            <div class="option_one" :id="item.id" v-for="(item, i) in data.structure_select_list" :key="'op' + i">
+            <div v-for="(item, i) in data.structure_select_list" :id="item.id" :key="'op' + i" class="option_one">
               <img
                 :src="item.type === 'local' ? require('@/assets/structure/' + item.value) : item.value"
                 class="small-img"
@@ -48,8 +48,8 @@
           </div>
           <div class="hzpinyin">
             <div
-              class="pinyin"
               v-if="isEnable(data.property.view_pinyin)"
+              class="pinyin"
               :style="{
                 fontSize: data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
               }"
@@ -78,7 +78,7 @@
                   :paly-width="'18px'"
                   :BoxbgType="'0'"
                   :cur-item="items.hz_info[0].hzDetail.hz_json"
-                  :target-div="'writeTops-item-' + '-' + items.hz_info[0].con"
+                  :target-div="'writeTops-item-' + '-' + items.hz_info[0].con + row"
                   class="writeTop-item"
                   :style="{
                     borderColor:
@@ -129,10 +129,10 @@
                   />
                 </div>
                 <div
+                  v-if="answer.answer_list[row].answer_list.length == 0"
+                  :key="row"
                   class="option_one"
                   :class="[isJudgingRightWrong && items.answer ? 'wrong' : '']"
-                  :key="row"
-                  v-if="answer.answer_list[row].answer_list.length == 0"
                   :style="{
                     borderColor:
                       data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
@@ -163,7 +163,7 @@
               {{ row + 1 }}
             </div>
             <div class="hzpinyin">
-              <div class="pinyin" v-if="isEnable(data.property.view_pinyin)">
+              <div v-if="isEnable(data.property.view_pinyin)" class="pinyin">
                 {{ items.pinyin }}
               </div>
               <template v-if="items.hz_info.length > 0">
@@ -259,7 +259,7 @@ export default {
       correctArr: [],
     };
   },
-  //计算属性 类似于data概念
+  // 计算属性 类似于data概念
   computed: {},
   watch: {
     'data.option_list': {
@@ -280,22 +280,22 @@ export default {
       let index = e.item.outerHTML.indexOf('id');
       let formIndex = e.item.outerHTML[index + 4];
       let formIndex2 = e.item.outerHTML[index + 5];
-      if (formIndex * 1 != NaN) {
-        this.currentId = formIndex * 1;
+      if (Number(formIndex) != NaN) {
+        this.currentId = Number(formIndex);
       }
-      if (formIndex2 * 1 != NaN) {
-        this.currentId = (this.currentId + '' + formIndex2) * 1;
+      if (Number(formIndex2) != NaN) {
+        this.currentId = (String(this.currentId) + formIndex2) * 1;
       }
     },
-    //开始拖拽事件
+    // 开始拖拽事件
     onStart() {
       this.drag = true;
       this.dragData = JSON.parse(JSON.stringify(this.SortArr));
     },
-    //拖拽结束事件
+    // 拖拽结束事件
     onEnd(e) {
       this.drag = false;
-      let formIndex = e.to.firstChild.attributes[1].value[4] * 1;
+      let formIndex = Number(e.to.firstChild.attributes[1].value[4]);
       if (`${formIndex}` != 'NaN') {
         if (this.answer.answer_list[formIndex].answer_list.length > 1) {
           let arr = [];
@@ -328,7 +328,7 @@ export default {
                 ? this.data.structure_select_list.find((p) => p.file_id === items.answer)
                   ? this.data.structure_select_list.find((p) => p.file_id === items.answer).value
                   : ''
-                : require('@/assets/structure/structure-' + items.answer + '.png'),
+                : require(`@/assets/structure/structure-${items.answer}.png`),
             userAnswerJudge: 'example',
           };
           this.single.push({

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

@@ -702,8 +702,8 @@ export default {
       }
     },
     findLightWord(wItem, startIndex, sentence, sItem) {
-      let endIndex = 0,
-        words = '';
+      let endIndex = 0;
+      let words = '';
       this.newWordList.forEach((item) => {
         if (item.length == 1) {
           if (item == wItem.chs && !wItem.banLight) {
@@ -899,7 +899,7 @@ export default {
       if (_this.NumberList.indexOf(noteNum) > -1) {
         for (let i = 0; i < _this.NumberList.length; i++) {
           if (_this.NumberList[i] == noteNum) {
-            noteIndex = String(i) + '';
+            noteIndex = `${String(i)}`;
             break;
           }
         }
@@ -970,7 +970,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwnProperty(hz)) {
+        if (writeModel.hasOwn(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

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

@@ -817,7 +817,7 @@ export default {
       if (_this.NumberList.indexOf(noteNum) > -1) {
         for (let i = 0; i < _this.NumberList.length; i++) {
           if (_this.NumberList[i] == noteNum) {
-            noteIndex = String(i) + '';
+            noteIndex = `${String(i)}`;
             break;
           }
         }
@@ -864,7 +864,7 @@ export default {
       if (answer) {
         let writeModel = this.curQue.Bookanswer.writeModel;
         let hz = answer.hz;
-        if (writeModel.hasOwnProperty(hz)) {
+        if (writeModel.hasOwn(hz)) {
           writeModel[hz].push(answer);
         } else {
           writeModel[hz] = [answer];

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

@@ -241,7 +241,7 @@ export default {
             let trans_arr = item.translation.split('\n');
             this.data.detail.forEach((items) => {
               let items_trans_arr = [];
-              if (!items.hasOwnProperty('multilingualTextList')) {
+              if (!items.hasOwn('multilingualTextList')) {
                 this.$set(items, 'multilingualTextList', {});
               }
               if (items.para) {
@@ -419,7 +419,7 @@ export default {
           let trans_arr = item.translation.split('\n');
           this.data.detail.forEach((items) => {
             let items_trans_arr = [];
-            if (!items.hasOwnProperty('multilingualTextList')) {
+            if (!items.hasOwn('multilingualTextList')) {
               this.$set(items, 'multilingualTextList', {});
             }
             if (items.para) {

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

@@ -4,7 +4,11 @@
     <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
 
     <div class="main" :style="getMainStyle()">
-      <AudioFill v-if="data.audio_file_id.length > 0" :file-id="data.audio_file_id" />
+      <AudioFill
+        v-if="data.audio_file_id.length > 0"
+        :color="data.unified_attrib.topic_color"
+        :file-id="data.audio_file_id"
+      />
       <div class="fill-wrapper">
         <p v-for="(item, i) in modelEssay" :key="i">
           <template v-for="(li, j) in item">
@@ -31,7 +35,7 @@
               </template>
 
               <template v-else-if="data.property.fill_type === fillTypeList[1].value">
-                <el-popover :key="j" placement="top" trigger="click" class="popper-list">
+                <el-popover :key="j" placement="top" trigger="click">
                   <div class="word-list">
                     <span
                       v-for="{ content, mark } in data.word_list"
@@ -72,6 +76,7 @@
                   type="mini"
                   :many-times="false"
                   class="record-box"
+                  :attrib="data.unified_attrib"
                   :answer-record-list="data.audio_answer_list"
                   :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
                   @handleWav="handleMiniWav($event, li.mark)"
@@ -90,6 +95,7 @@
         ref="record"
         type="normal"
         class="record-box"
+        :attrib="data.unified_attrib"
         :answer-record-list="data.record_list"
         :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
         @handleWav="handleWav"

+ 21 - 8
src/views/book/courseware/preview/components/fill/components/AudioFillPlay.vue

@@ -1,10 +1,6 @@
 <template>
   <div class="audio-fill">
-    <img
-      :src="audio.paused ? require('@/assets/fill/voice-pause-red.png') : require('@/assets/fill/voice-play-red.png')"
-      class="audio-play"
-      @click="playAudio"
-    />
+    <span class="audio-play icon-mask" :style="maskStyle" @click="playAudio"></span>
     <audio
       :id="fileId"
       :ref="fileId"
@@ -28,6 +24,11 @@ export default {
       type: String,
       required: true,
     },
+    // 指定想要的颜色
+    color: {
+      type: String,
+      default: '#E84F4F',
+    },
   },
   data() {
     return {
@@ -36,16 +37,28 @@ export default {
       audio: {
         paused: true,
         playing: false,
-        // 音频当前播放时长
         current_time: 0,
-        // 音频最大播放时长
         max_time: 0,
         loading: false,
       },
       play_value: 0,
-      audio_allTime: null, // 展示总时间
+      audio_allTime: null,
     };
   },
+  computed: {
+    iconSrc() {
+      return this.audio.paused
+        ? require('@/assets/fill/voice-pause-red.png')
+        : require('@/assets/fill/voice-play-red.png');
+    },
+    // 通过 mask 把图标着成指定颜色
+    maskStyle() {
+      return {
+        backgroundColor: this.color,
+        maskImage: `url(${this.iconSrc})`,
+      };
+    },
+  },
   watch: {
     fileId: {
       handler(val) {

+ 9 - 8
src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue

@@ -90,25 +90,26 @@
       </div>
     </div>
     <el-dialog
+      v-if="mageazineDetailShow"
       :visible.sync="mageazineDetailShow"
       :show-close="false"
       :close-on-click-modal="false"
       width="80%"
       class="login-dialog magazine-detail-dialog"
       :modal="false"
-      v-if="mageazineDetailShow"
     >
       <magazine-sentence
-        :fontSize="fontSize"
-        :sentenceTheme="sentenceTheme"
+        :font-size="fontSize"
+        :sentence-theme="sentenceTheme"
         :data="data.word_time"
-        :activeIndex="sentIndex"
+        :active-index="sentIndex"
+        :mp3-url="mp3_url"
+        :multilingual-text-list="showLang && multilingualTextList[getLang()] ? multilingualTextList[getLang()] : []"
+        :property="data.property"
+        :attrib="data.unified_attrib"
         @closeWord="closeMagazineSentence"
         @changeTheme="changeTheme"
-        :mp3Url="mp3_url"
-        :multilingualTextList="showLang && multilingualTextList[getLang()] ? multilingualTextList[getLang()] : []"
-        :property="data.property"
-      ></magazine-sentence>
+      />
     </el-dialog>
   </div>
 </template>

+ 69 - 52
src/views/book/courseware/preview/components/image_text/components/MagazineSentence.vue

@@ -1,14 +1,14 @@
 <template>
   <div class="sentence-box" :style="{ background: themeList[sentenceTheme].bg }">
     <div class="sentence-top">
-      <a class="play-btn" @click="handlePlay" :style="{ background: themeList[sentenceTheme].playBtnBg }">
-        <svg-icon v-if="isPlay" icon-class="pause" size="24"></svg-icon>
-        <svg-icon v-else icon-class="play" size="24"></svg-icon>
+      <a class="play-btn" :style="{ background: themeList[sentenceTheme].playBtnBg }" @click="handlePlay">
+        <svg-icon v-if="isPlay" icon-class="pause" size="24" />
+        <svg-icon v-else icon-class="play" size="24" />
       </a>
       <div class="sentence-right" :style="{ color: themeList[sentenceTheme].rightBtnColor }">
-        <a class="btn" @click="handlePage('-')"><svg-icon icon-class="arrow-left-s-line" size="24"></svg-icon></a>
+        <a class="btn" @click="handlePage('-')"><svg-icon icon-class="arrow-left-s-line" size="24" /></a>
         <span>{{ sentenceActive + 1 + '/' + data.length }}</span>
-        <a class="btn" @click="handlePage('+')"><svg-icon icon-class="arrow-right-s-line" size="24"></svg-icon></a>
+        <a class="btn" @click="handlePage('+')"><svg-icon icon-class="arrow-right-s-line" size="24" /></a>
         <i class="el-icon-close" @click="closeWord"></i>
       </div>
     </div>
@@ -189,7 +189,7 @@
           </template>
         </div>
       </template>
-      <div class="NPC-notes-note" v-if="multilingualTextList[sentenceActive]">
+      <div v-if="multilingualTextList[sentenceActive]" class="NPC-notes-note">
         {{ multilingualTextList[sentenceActive] }}
       </div>
     </div>
@@ -234,13 +234,13 @@
       </div>
       <ul class="article-color" :style="{ background: themeList[sentenceTheme].bottomBg }">
         <li
-          :class="['color-item', sentenceTheme === indexC ? 'active' : '']"
           v-for="(itemC, indexC) in themeList"
           :key="indexC"
-          @click="handleChangeBgColor(indexC, 'theme')"
+          :class="['color-item', sentenceTheme === indexC ? 'active' : '']"
           :style="{
             borderColor: sentenceTheme === indexC ? itemC.boxBorder : '',
           }"
+          @click="handleChangeBgColor(indexC, 'theme')"
         >
           <a
             :style="{
@@ -255,15 +255,15 @@
 </template>
 
 <script>
-//这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
-//例如:import 《组件名称》from ‘《组件路径》';
+// 这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》from ‘《组件路径》';
 
 export default {
-  //import引入的组件需要注入到对象中才能使用
+  // import引入的组件需要注入到对象中才能使用
   components: {},
-  props: ['fontSize', 'sentenceTheme', 'data', 'activeIndex', 'mp3Url', 'multilingualTextList', 'property'],
+  props: ['fontSize', 'sentenceTheme', 'data', 'activeIndex', 'mp3Url', 'multilingualTextList', 'property', 'attrib'],
   data() {
-    //这里存放数据
+    // 这里存放数据
     return {
       isPlay: false, // 音频是否在播放
       sentenceActive: this.activeIndex,
@@ -345,11 +345,54 @@ export default {
       noFont: ['~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '/'],
     };
   },
-  //计算属性 类似于data概念
+  // 计算属性 类似于data概念
   computed: {},
-  //监控data中数据变化
+  // 监控data中数据变化
   watch: {},
-  //方法集合
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    if (this.attrib) {
+      this.themeList[0] = {
+        type: 'white',
+        bg: '#E5E6EB',
+        playBtnBg: this.attrib.topic_color, // 播放按钮背景色
+        rightBtnColor: 'rgba(0, 0, 0, 0.96)', // 右侧按钮颜色
+        contentBg: '#F7F8FA',
+        sentenceColor: 'rgba(0, 0, 0, 0.96)',
+        sentenceActiveColor: this.attrib.topic_color,
+        bottomBg: '#F2F3F5',
+        bottomBarActiveBtnBg: '#FFFFFF',
+        bottomBarColor: '#4E5969',
+        bottomBarActive: this.attrib.topic_color,
+        bottomBarBorder: '#E5E6EB',
+        themeBg: '#FFFFFF',
+        themeActiveBorder: '#E5E6EB',
+        boxBorder: this.attrib.topic_color, // 选中时高亮的外圈边框
+      };
+    }
+    this.handleData();
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    _this.audio.addEventListener('timeupdate', function () {
+      _this.currentTime = _this.audio.currentTime;
+      const currentTime = _this.audio.currentTime;
+      if (_this.ed && currentTime >= _this.ed) {
+        _this.audio.pause();
+        _this.isPlay = false;
+        _this.currentTime = 0;
+        _this.activeWordIndex = null;
+      }
+    });
+  },
+  // 生命周期-挂载之前
+  beforeMount() {},
+  // 生命周期-更新之后
+  updated() {},
+  // 如果页面有keep-alive缓存功能,这个函数会触发
+  activated() {},
+  // 方法集合
   methods: {
     // 播放、暂停
     handlePlay() {
@@ -397,15 +440,13 @@ export default {
         } else {
           this.$message.warning('已经是第一句');
         }
+      } else if (this.sentenceActive < this.data.length - 1) {
+        this.audio.pause();
+        this.isPlay = false;
+        this.currentTime = 0;
+        this.sentenceActive++;
       } else {
-        if (this.sentenceActive < this.data.length - 1) {
-          this.audio.pause();
-          this.isPlay = false;
-          this.currentTime = 0;
-          this.sentenceActive++;
-        } else {
-          this.$message.warning('已经是最后一句');
-        }
+        this.$message.warning('已经是最后一句');
       }
     },
     // 切换主题颜色
@@ -433,38 +474,14 @@ export default {
       }
     },
   },
-  //生命周期 - 创建完成(可以访问当前this实例)
-  created() {
-    this.handleData();
-  },
-  //生命周期 - 挂载完成(可以访问DOM元素)
-  mounted() {
-    let _this = this;
-    _this.audio.addEventListener('timeupdate', function () {
-      _this.currentTime = _this.audio.currentTime;
-      const currentTime = _this.audio.currentTime;
-      if (_this.ed && currentTime >= _this.ed) {
-        _this.audio.pause();
-        _this.isPlay = false;
-        _this.currentTime = 0;
-        _this.activeWordIndex = null;
-      }
-    });
-  },
-  //生命周期-创建之前
+  // 生命周期-创建之前
   beforeCreated() {},
-  //生命周期-挂载之前
-  beforeMount() {},
-  //生命周期-更新之前
+  // 生命周期-更新之前
   beforUpdate() {},
-  //生命周期-更新之后
-  updated() {},
-  //生命周期-销毁之前
+  // 生命周期-销毁之前
   beforeDestory() {},
-  //生命周期-销毁完成
+  // 生命周期-销毁完成
   destoryed() {},
-  //如果页面有keep-alive缓存功能,这个函数会触发
-  activated() {},
 };
 </script>
 <style lang="scss" scoped>

+ 6 - 1
src/views/book/courseware/preview/components/judge/JudgePreview.vue

@@ -10,7 +10,10 @@
           :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
           :class="['option-item', { active: isAnswer(mark) }]"
         >
-          <div :class="['option-content', computedIsJudgeRight(mark)]">
+          <div
+            :style="{ borderColor: data.unified_attrib.topic_color }"
+            :class="['option-content', computedIsJudgeRight(mark)]"
+          >
             <span class="serial-number">{{ convertNumberToLetter(i) }}.</span>
             <PinyinText
               v-if="isEnable(data.property.view_pinyin)"
@@ -166,6 +169,8 @@ export default {
         align-items: center;
         padding: 12px 24px;
         background-color: $content-color;
+        border-style: solid;
+        border-width: 1px;
         border-radius: 40px;
 
         &.right {

+ 2 - 1
src/views/book/courseware/preview/components/matching/MatchingPreview.vue

@@ -337,7 +337,8 @@ export default {
     setPathAttr(path) {
       path.setAttribute('stroke-width', '2'); // 设置线条宽度
       path.setAttribute('stroke-linecap', 'round'); // 设置线段的两端样式
-      path.setAttribute('stroke', '#306eff'); // 设置填充颜色
+      const assistColor = this.data?.unified_attrib?.topic_color || '#306eff';
+      path.setAttribute('stroke', assistColor); // 设置填充颜色
       path.setAttribute('transform', `translate(2, 2)`); // 设置偏移量
     },
     /**

+ 51 - 24
src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue

@@ -2,7 +2,6 @@
 <template>
   <div class="newWord-template-preview" :style="getAreaStyle()">
     <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
-
     <div class="main">
       <div
         v-for="(item, index) in data.option_list"
@@ -49,9 +48,12 @@
               :text-align="'center'"
               :class="[classNameJudge(userAnswer[index].answer_pinyin, item.answer_pinyin, item.is_example)]"
               :style="{
-                fontSize: data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                fontSize:
+                  data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '16px',
                 background:
-                  data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                  data.unified_attrib && data.unified_attrib.assist_color
+                    ? data.unified_attrib.assist_color
+                    : '#deebff',
               }"
               @input="changeAnswer(item, index)"
             />
@@ -93,9 +95,11 @@
                   ]"
                   :style="{
                     fontSize:
-                      data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                      data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '16px',
                     background:
-                      data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                      data.unified_attrib && data.unified_attrib.assist_color
+                        ? data.unified_attrib.assist_color
+                        : '#deebff',
                   }"
                   @input="changeAnswer(item, index, indexs)"
                 />
@@ -128,7 +132,7 @@
                       : null
                   "
                   :type="data.property.model === 'input' ? 'newWord-template-input' : data.type"
-                  :target-div="'newWordTemplate' + items.con + index + indexs + Math.random().toString(36)"
+                  :target-div="'newWordTemplate-answer' + items.con + index + indexs + randomId"
                   :hz_json="items.hz_info[0].hzDetail.hz_json"
                   class="hanzi-storck"
                   :class="[
@@ -160,9 +164,11 @@
                   :class="[classNameJudge(userAnswer[index].item[indexs].answer, items.answer, items.is_example)]"
                   :style="{
                     fontSize:
-                      data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                      data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '16px',
                     background:
-                      data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                      data.unified_attrib && data.unified_attrib.assist_color
+                        ? data.unified_attrib.assist_color
+                        : '#deebff',
                   }"
                   @input="changeAnswer(items, index, indexs)"
                 />
@@ -177,9 +183,12 @@
               :text-align="'center'"
               :class="[classNameJudge(userAnswer[index].answer_en, item.answer_en, item.is_example)]"
               :style="{
-                fontSize: data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                fontSize:
+                  data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '16px',
                 background:
-                  data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                  data.unified_attrib && data.unified_attrib.assist_color
+                    ? data.unified_attrib.assist_color
+                    : '#deebff',
               }"
               @input="changeAnswer(item, index)"
             />
@@ -208,7 +217,14 @@
                   : '',
             }"
           >
-            <span class="number">{{ index + 1 }}</span>
+            <span
+              class="number"
+              :style="{
+                background:
+                  data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
+              }"
+              >{{ index + 1 }}</span
+            >
           </div>
           <div class="pinyin-en" :class="[item.is_example ? 'item-example' : '']">
             <div
@@ -231,9 +247,11 @@
                 :text-align="'center'"
                 :style="{
                   fontSize:
-                    data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                    data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '16px',
                   background:
-                    data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                    data.unified_attrib && data.unified_attrib.assist_color
+                      ? data.unified_attrib.assist_color
+                      : '#deebff',
                 }"
                 @input="changeAnswer(item, index)"
               />
@@ -271,9 +289,13 @@
                     :text-align="'center'"
                     :style="{
                       fontSize:
-                        data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                        data.unified_attrib && data.unified_attrib.pinyin_size
+                          ? data.unified_attrib.pinyin_size
+                          : '16px',
                       background:
-                        data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                        data.unified_attrib && data.unified_attrib.assist_color
+                          ? data.unified_attrib.assist_color
+                          : '#deebff',
                     }"
                     @input="changeAnswer(item, index, indexs)"
                   />
@@ -306,7 +328,7 @@
                         : null
                     "
                     :type="data.property.model === 'input' ? 'newWord-template-input' : data.type"
-                    :target-div="'newWordTemplatez' + items.con + index + indexs + Math.random().toString(36)"
+                    :target-div="'newWordTemplatez' + items.con + index + indexs + randomId"
                     :hz_json="items.hz_info[0].hzDetail.hz_json"
                     class="hanzi-storck"
                     :class="[
@@ -337,9 +359,13 @@
                     :text-align="'center'"
                     :style="{
                       fontSize:
-                        data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                        data.unified_attrib && data.unified_attrib.pinyin_size
+                          ? data.unified_attrib.pinyin_size
+                          : '16px',
                       background:
-                        data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                        data.unified_attrib && data.unified_attrib.assist_color
+                          ? data.unified_attrib.assist_color
+                          : '#deebff',
                     }"
                     @input="changeAnswer(items, index, indexs)"
                   />
@@ -357,9 +383,11 @@
                 :text-align="'center'"
                 :style="{
                   fontSize:
-                    data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '',
+                    data.unified_attrib && data.unified_attrib.pinyin_size ? data.unified_attrib.pinyin_size : '16px',
                   background:
-                    data.unified_attrib && data.unified_attrib.assist_color ? data.unified_attrib.assist_color : '',
+                    data.unified_attrib && data.unified_attrib.assist_color
+                      ? data.unified_attrib.assist_color
+                      : '#deebff',
                 }"
                 @input="changeAnswer(item, index)"
               />
@@ -387,6 +415,7 @@ export default {
     return {
       data: getNewWordTemplateData(),
       userAnswer: [],
+      randomId: Math.random().toString(36).substring(2, 12),
     };
   },
   watch: {
@@ -547,7 +576,8 @@ export default {
 
     :deep .edit-div {
       min-height: 32px;
-      font-size: 16px;
+
+      // font-size: 16px;
       line-height: 30px;
       color: #000;
 
@@ -619,9 +649,6 @@ export default {
   .pinyin-common {
     margin-bottom: 5px;
 
-    &.pinyin-common-isExample {
-    }
-
     :deep .edit-div {
       font-family: 'League';
     }

+ 26 - 11
src/views/book/courseware/preview/components/new_word/NewWordPreview.vue

@@ -20,8 +20,10 @@
           </div>
 
           <div class="NPC-top-right">
-            <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-if="is_list" icon-class="icon-card" size="24" @click="is_list = false" />
+            <!-- <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>
             <img v-if="wordShow" src="@/assets/down.png" alt="" @click="handleChangeTab" />
             <img v-else class="rotate" src="@/assets/down.png" alt="" @click="handleChangeTab" />
@@ -72,12 +74,12 @@
                       <SvgIcon
                         v-if="curTime >= sItem.bg && curTime < sItem.ed && stopAudioS"
                         icon-class="animated"
+                        size="24"
                         :style="{
                           color:
                             data.unified_attrib && data.unified_attrib.topic_color
                               ? data.unified_attrib.topic_color
                               : '',
-                          marginTop: '4px',
                         }"
                         @click="handleChangeTime(sItem.bg, sItem.ed)"
                       />
@@ -101,12 +103,12 @@
                         <SvgIcon
                           v-if="playClass && mp3_index === sItem.sIndex"
                           icon-class="animated"
+                          size="24"
                           :style="{
                             color:
                               data.unified_attrib && data.unified_attrib.topic_color
                                 ? data.unified_attrib.topic_color
                                 : '',
-                            marginTop: '4px',
                           }"
                         />
                         <SvgIcon
@@ -125,7 +127,7 @@
                     </template>
 
                     <template v-else>
-                      <span style="flex-shrink: 0; width: 16px; height: 16px"></span>
+                      <span style="flex-shrink: 0; width: 24px; height: 24px"></span>
                     </template>
                     <div class="tabNum-box">
                       <template v-if="sItem.mIndex == 0">
@@ -481,6 +483,10 @@
                               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"
                         >
@@ -495,6 +501,10 @@
                                   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] : '' }}
@@ -594,6 +604,7 @@
             :bg="dataWord && dataWord.bg ? dataWord.bg : null"
             :ed="dataWord && dataWord.ed ? dataWord.ed : null"
             type="newWordDetail"
+            :attrib="data.unified_attrib"
           />
         </div>
         <audio ref="newwordAudio"></audio>
@@ -1024,9 +1035,9 @@ export default {
 
   .play-btn {
     display: block;
-    width: 16px;
-    height: 16px;
-    margin-top: 4px;
+    flex-shrink: 0;
+    width: 24px;
+    height: 24px;
 
     // background: url('@/assets/fill/voice-pause-red.png') no-repeat left top;
     // background-size: 100% 100%;
@@ -1656,15 +1667,19 @@ export default {
       cursor: pointer;
 
       &-text {
-        font-size: 14px;
+        font-size: 16px;
         font-weight: normal;
         line-height: 16px;
         color: #fff;
       }
 
       img {
-        width: 16px;
-        height: 16px;
+        width: 20px;
+        height: 20px;
+      }
+
+      .svg-icon {
+        color: #fff;
       }
     }
 

+ 8 - 3
src/views/book/courseware/preview/components/new_word/components/Strockplayredline.vue

@@ -2,7 +2,13 @@
 <template>
   <div class="strockplay-redInner">
     <div v-if="playStorkes" :class="['strock-play-box']" @click="playHanzi">
-      <SvgIcon icon-class="hanzi-strock-play" class="strock-play-btn" />
+      <SvgIcon
+        icon-class="hanzi-strock-play"
+        class="strock-play-btn"
+        :style="{
+          color: attrib && attrib.topic_color ? attrib.topic_color : '',
+        }"
+      />
     </div>
     <div class="character-target-box">
       <SvgIcon icon-class="hanzi-writer-bg" class="character-target-bg" />
@@ -16,7 +22,7 @@ import { GetStaticResources } from '@/api/app';
 const HanziWriter = require('hanzi-writer');
 export default {
   components: {},
-  props: ['targetDiv', 'Book_text', 'playStorkes', 'strokeColor', 'wordNum', 'themeColor'],
+  props: ['targetDiv', 'Book_text', 'playStorkes', 'strokeColor', 'wordNum', 'attrib'],
   data() {
     return {
       writer: null,
@@ -83,7 +89,6 @@ export default {
 };
 </script>
 <style lang="scss" scoped>
-//@import url(); 引入公共css类
 .strockplay-redInner {
   position: relative;
   box-sizing: border-box;

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

@@ -39,6 +39,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
@@ -47,11 +50,14 @@
                 :play-storkes="true"
                 :target-div="'bwcHanziIntp' + conItem + 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>
@@ -61,6 +67,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>
@@ -178,6 +187,7 @@ export default {
     'type',
     'bg',
     'ed',
+    'attrib',
   ],
   data() {
     // 这里存放数据

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

@@ -259,15 +259,15 @@ export default {
         cursor: pointer;
 
         &-text {
-          font-size: 14px;
+          font-size: 16px;
           font-weight: normal;
           line-height: 16px;
           color: #fff;
         }
 
         img {
-          width: 16px;
-          height: 16px;
+          width: 20px;
+          height: 20px;
           margin-left: 4px;
         }
       }

+ 2 - 1
src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue

@@ -12,6 +12,7 @@
           <AudioPlay
             v-if="data.audio_file_id && data.property.audio_position === 'front'"
             :file-id="data.audio_file_id"
+            :theme-color="data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : ''"
           />
           <div
             class="option-content"
@@ -140,8 +141,8 @@
             class="record-box"
             :answer-record-list="data.record_list"
             :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
-            @handleWav="handleWav"
             :attrib="data.unified_attrib"
+            @handleWav="handleWav"
           />
         </template>
       </div>

+ 2 - 1
src/views/book/courseware/preview/components/select/SelectPreview.vue

@@ -11,7 +11,7 @@
         <li
           v-for="({ content, mark, multilingual, paragraph_list }, i) in data.option_list"
           :key="mark"
-          :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
+          :style="{ cursor: disabled ? 'not-allowed' : 'pointer', borderColor: data.unified_attrib.topic_color }"
           :class="['option-item', { active: isAnswer(mark) }, ...computedAnswerClass(mark)]"
           @click="selectAnswer(mark)"
         >
@@ -133,6 +133,7 @@ export default {
       color: #706f78;
       cursor: pointer;
       background-color: $content-color;
+      border: 1px solid $content-color;
       border-radius: 40px;
 
       .lang {

+ 12 - 1
src/views/book/courseware/preview/components/table/TablePreview.vue

@@ -111,6 +111,7 @@
                             class="record-box"
                             :answer-record-list="data.audio_answer_list"
                             :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
+                            :attrib="data.unified_attrib"
                             @handleWav="handleMiniWav($event, item)"
                           />
                         </template>
@@ -131,7 +132,16 @@
                   </template>
                   <template v-else>
                     <p v-for="(item, index) in col.model_essay" :key="index" :style="[tdStyle]">
-                      <span v-if="item.type === 'text'" :key="index" v-html="sanitizeHTML(item.value)"></span>
+                      <span
+                        v-if="item.type === 'text'"
+                        :key="index"
+                        :style="{
+                          fontSize:
+                            data.unified_attrib && data.unified_attrib.font_size ? data.unified_attrib.font_size : '',
+                          fontFamily: data.unified_attrib && data.unified_attrib.font ? data.unified_attrib.font : '',
+                        }"
+                        v-html="sanitizeHTML(item.value)"
+                      ></span>
                       <template v-if="item.type === 'input'">
                         <template v-if="data.property.fill_type === fillTypeList[0].value">
                           <el-input
@@ -185,6 +195,7 @@
                             class="record-box"
                             :answer-record-list="data.audio_answer_list"
                             :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
+                            :attrib="data.unified_attrib"
                             @handleWav="handleMiniWav($event, item)"
                           />
                         </template>

+ 28 - 6
src/views/book/courseware/preview/components/upload_preview/UploadPreviewPreview.vue

@@ -24,6 +24,12 @@
             v-for="(label, index) in label_list"
             :key="index"
             :class="[index === active_index ? 'active' : '']"
+            :style="{
+              color:
+                index === active_index && data.unified_attrib && data.unified_attrib.topic_color
+                  ? data.unified_attrib.topic_color
+                  : '',
+            }"
             @click="active_index = index"
             >{{ label }}</span
           >
@@ -32,9 +38,15 @@
           <li v-for="(file, i) in source_list[active_index]" :key="i">
             <div class="file-name">
               <span>
-                <SvgIcon :icon-class="icon_list[active_index]" size="16" />
+                <SvgIcon :icon-class="icon_list[active_index]" size="24" />
                 <p>
-                  <span>{{ data.file_info[file.file_id].xuhao + data.file_info[file.file_id].file_name }} </span
+                  <span
+                    :style="{
+                      fontSize:
+                        data.unified_attrib && data.unified_attrib.font_size ? data.unified_attrib.font_size : '',
+                      fontFamily: data.unified_attrib && data.unified_attrib.font ? data.unified_attrib.font : '',
+                    }"
+                    >{{ data.file_info[file.file_id].xuhao + data.file_info[file.file_id].file_name }} </span
                   ><span
                     >{{
                       multilingualTextList[getLang()] && multilingualTextList[getLang()][i]
@@ -44,10 +56,11 @@
                   </span>
                 </p>
               </span>
-              <SvgIcon v-show="file.file_id" icon-class="uploadPreview" size="16" @click="viewDialog(file)" />
+              <SvgIcon v-show="file.file_id" icon-class="uploadPreview" size="24" @click="viewDialog(file)" />
+
               <img
-                v-if="isEnable(data.is_enable_download)"
-                style="width: 16px; height: 16px"
+                v-if="isEnable(data.property.is_enable_download)"
+                style="width: 24px; height: 24px; cursor: pointer"
                 src="@/assets/download.png"
                 alt="download"
                 @click="downLoad(file)"
@@ -55,7 +68,16 @@
             </div>
           </li>
         </ul>
-        <p v-else class="label-tips">暂无本类型文件,看看其他类型吧</p>
+        <p
+          v-else
+          class="label-tips"
+          :style="{
+            fontSize: data.unified_attrib && data.unified_attrib.font_size ? data.unified_attrib.font_size : '',
+            fontFamily: data.unified_attrib && data.unified_attrib.font ? data.unified_attrib.font : '',
+          }"
+        >
+          暂无本类型文件,看看其他类型吧
+        </p>
       </template>
     </div>
     <el-dialog

+ 4 - 0
src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue

@@ -29,6 +29,7 @@
           :stop-audio="stopAudio"
           :mp3-source="mp3Source"
           :audio-data="data"
+          :attrib="data.unified_attrib"
           @handleChangeStopAudio="handleChangeStopAudio"
           @playChange="playChange"
         />
@@ -182,6 +183,7 @@
           type="promax"
           class="luyin-box"
           :answer-record-list="data.record_list"
+          :attrib="data.unified_attrib"
           @getWavblob="getWavblob"
           @getSelectData="getSelectData"
           @handleParentPlay="pauseOtherAudio"
@@ -192,6 +194,8 @@
           :style="{ flex: 1 }"
           :theme-color="themeColor"
           :wavblob="wavblob"
+          type="full"
+          :attrib="data.unified_attrib"
           :url="mp3Url"
           :is-record="isRecord"
           :sent-pause="sentPause"

+ 16 - 5
src/views/book/courseware/preview/components/voice_matrix/components/AudioCompareMatrix.vue

@@ -6,13 +6,14 @@
         :class="[type == 'full' ? 'compare-box-big' : 'compare-box']"
         @click.stop.capture="playAudio"
       >
-        <audio-line
+        <AudioLine
           ref="audioLine"
           :mp3="url"
           :get-cur-time="getCurTime"
           audio-id="audioCompareMatrix"
           :stop-audio="stopAudio"
           :hide-slider="true"
+          :attrib="attrib"
           :type="type"
           @handleChangeStopAudio="handleChangeStopAudio"
           @sentPause="sentPause"
@@ -20,11 +21,11 @@
         />
       </div>
       <div v-else :class="[type == 'full' ? 'compare-box-big' : 'compare-box']">
-        <audio-red
+        <AudioRed
           ref="audioRed"
           :mp3="wavblob"
           :is-compare="true"
-          :theme-color="themeColor"
+          :attrib="attrib"
           :type="type"
           @sentPause="sentPause"
         />
@@ -52,7 +53,18 @@ export default {
     AudioLine,
     AudioRed,
   },
-  props: ['themeColor', 'isRecord', 'wavblob', 'url', 'type', 'sentPause', 'matrixSelectLrc', 'getCurTime', 'curTime'],
+  props: [
+    'themeColor',
+    'isRecord',
+    'wavblob',
+    'url',
+    'type',
+    'sentPause',
+    'matrixSelectLrc',
+    'getCurTime',
+    'curTime',
+    'attrib',
+  ],
   data() {
     return {
       playing: false,
@@ -83,7 +95,6 @@ export default {
     playAudio() {
       if (this.playing) return this.handleParentPlay();
       if (this.unWatch) return this.$refs.audioLine.PlayAudio();
-      console.log(this.matrixSelectLrc);
       if (this.matrixSelectLrc === null) {
         this.sentPause(true);
         this.playChange(false);

+ 17 - 12
src/views/book/courseware/preview/components/voice_matrix/components/AudioLine.vue

@@ -4,15 +4,20 @@
     <div v-if="!hideSlider" class="audioLine">
       <div class="playBox" @click="PlayAudio">
         <div class="play" :class="[audio.loading ? 'loadBtn' : audio.playing ? 'playBtn' : 'pauseBtn']">
-          <SvgIcon v-if="audio.playing" icon-class="pause-large-fill" :style="{ color: bookInfo.theme_color }" />
-          <SvgIcon v-else icon-class="play-large-fill" :style="{ color: bookInfo.theme_color }" />
+          <SvgIcon
+            v-if="audio.playing"
+            size="24px"
+            icon-class="pause-large-fill"
+            :style="{ color: attrib.topic_color }"
+          />
+          <SvgIcon v-else size="24px" icon-class="play-large-fill" :style="{ color: attrib.topic_color }" />
         </div>
       </div>
 
       <template v-if="!isRepeat">
         <el-slider
           v-model="playValue"
-          :style="{ width: sliderWidth + 'px', height: '2px', '--slider-color': bookInfo.theme_color }"
+          :style="{ width: sliderWidth + 'px', height: '2px', '--slider-color': attrib.topic_color }"
           :format-tooltip="formatProcessToolTip"
           @change="changeCurrentTime"
         />
@@ -53,7 +58,9 @@
     <div v-else class="audioLine2">
       <div
         class="play-icon"
+        :style="{ backgroundColor: attrib.topic_color }"
         :class="[
+          'icon-mask',
           audio.loading ? 'loadBtn' : audio.playing ? 'playBtn-icon' : 'pauseBtn-icon',
           type == 'full' ? 'play-icon-big' : '',
         ]"
@@ -100,6 +107,7 @@
 
 <script>
 export default {
+  name: 'VoiceMatrixAudioLine',
   inject: ['bookInfo'],
   props: [
     'mp3',
@@ -115,6 +123,7 @@ export default {
     'audioId',
     'type',
     'audioData',
+    'attrib',
   ],
   data() {
     // 这里存放数据
@@ -375,7 +384,6 @@ export default {
     .play {
       display: block;
       width: 16px;
-      height: 16px;
       font-size: 0;
       cursor: pointer;
     }
@@ -403,20 +411,17 @@ export default {
       }
 
       &.playBtn-icon {
-        background: url('@/assets/voice_matrix/pauseC-16-normal-blue.png') no-repeat left top;
-        background-size: 100% 100%;
+        mask-image: url('@/assets/voice_matrix/pauseC-16-normal-blue.png');
       }
 
       &.pauseBtn-icon {
-        background: url('@/assets/voice_matrix/compare-pause-blue.png') no-repeat left top;
-        background-size: 100% 100%;
+        mask-image: url('@/assets/voice_matrix/compare-pause-blue.png');
       }
     }
   }
 
   .loadBtn {
-    background: url('@/assets/voice_matrix/loading-blue.png') no-repeat left top;
-    background-size: 100% 100%;
+    mask: url('@/assets/voice_matrix/loading-blue.png') no-repeat left top;
   }
 
   &.Audio-tts {
@@ -446,7 +451,7 @@ export default {
     top: 12px;
     width: 8px;
     height: 8px;
-    background: #1d2129;
+    background: var(--slider-color);
     border: none;
   }
 
@@ -464,7 +469,7 @@ export default {
 
   .el-slider__bar {
     height: 2px;
-    background: #1d2129;
+    background: var(--slider-color);
   }
 }
 </style>

+ 9 - 28
src/views/book/courseware/preview/components/voice_matrix/components/AudioRed.vue

@@ -1,14 +1,17 @@
 <!--  -->
 <template>
-  <div v-if="mp3" class="content-voices" @click="handlePlayVoice">
-    <img :src="voiceSrc" :class="type == 'full' ? 'icon-big' : ''" />
-  </div>
+  <div
+    v-if="mp3"
+    class="content-voices icon-mask"
+    :style="{ backgroundColor: attrib.topic_color, maskImage: `url(${voiceSrc})` }"
+    @click="handlePlayVoice"
+  ></div>
 </template>
 
 <script>
 export default {
   components: {},
-  props: ['seconds', 'mp3', 'wav', 'isCompare', 'type'],
+  props: ['seconds', 'mp3', 'wav', 'isCompare', 'type', 'attrib'],
   data() {
     return {
       audio: new Audio(),
@@ -85,31 +88,9 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  width: 100%;
+  width: 24px;
+  height: 24px;
   font-size: 0;
   cursor: pointer;
-
-  span {
-    float: left;
-    font-family: 'sourceR';
-    font-size: 24px;
-    line-height: 30px;
-    color: #2c2c2c;
-
-    &.noMp3 {
-      margin-left: 0;
-    }
-  }
-
-  img {
-    float: left;
-    width: 16px;
-    height: 16px;
-  }
-
-  .icon-big {
-    width: 24px;
-    height: 24px;
-  }
 }
 </style>

+ 6 - 1
src/views/book/courseware/preview/components/write/WritePreview.vue

@@ -23,7 +23,12 @@
               }"
             >
               <div class="words-left" :style="{ width: '64' * item.hz_strokes_list.length + 'px' }">
-                <AudioPlay :file-id="item.audio_file_id" theme-color="gray" />
+                <AudioPlay
+                  :file-id="item.audio_file_id"
+                  :theme-color="
+                    data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : ''
+                  "
+                />
                 <span class="pinyin">{{ item.pinyin }}</span>
               </div>
             </div>

+ 2 - 2
src/views/book/courseware/preview/components/write_base/WriteBasePreview.vue

@@ -17,8 +17,8 @@
           :bg-color.sync="bgColor"
         />
         <div class="btn-box">
-          <SvgIcon icon-class="clear" size="16" title="清除" @click="handleReset" />
-          <SvgIcon icon-class="camera" size="16" title="保存" @click="handleGenerate" />
+          <SvgIcon icon-class="clear" size="24" title="清除" @click="handleReset" />
+          <SvgIcon icon-class="camera" size="24" title="保存" @click="handleGenerate" />
         </div>
       </div>
       <template v-if="data.write_base64[0]">