Procházet zdrojové kódy

生词卡片全屏

dsy před 2 měsíci
rodič
revize
a6681773af

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

@@ -9,24 +9,38 @@
             backgroundColor:
               data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
           }" -->
-        <div class="topTitle">
+        <div v-if="data.title_con" 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">
               {{ titleTrans[getLang()] }}
             </span>
           </div>
+        </div>
+        <div class="topTitle">
+          <div class="NPC-top-left">
+            <SvgIcon
+              icon-class="icon-full"
+              size="24"
+              :style="{
+                color:
+                  data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '#de4444',
+                cursor: 'pointer',
+              }"
+              @click="showCard = true"
+            />
+          </div>
 
           <div class="NPC-top-right">
             <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',
               }"
+              @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" /> -->
@@ -34,11 +48,11 @@
               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',
               }"
+              @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" />
@@ -672,6 +686,28 @@
         <audio ref="newwordAudio"></audio>
       </div>
     </div>
+    <el-dialog title="" :visible.sync="showCard" width="100%" class="wordCard-dialog" top="0">
+      <i class="el-icon-arrow-left" :class="[showIndex === 0 ? 'disabled' : '']" @click="changeShowIndex('-')"></i>
+      <writeTableZoom
+        ref="writeTableZoom"
+        :edit-cardflag="false"
+        :data="data.new_word_list[showIndex]"
+        :page-number="showIndex"
+        :total-number="0"
+        :is-preview="true"
+        :filt-cardflag="false"
+        :attrib="data.unified_attrib"
+        :url="data.audio_data.url"
+      />
+      <p style="width: 100%; font-size: 20px; color: #fff; text-align: center">
+        {{ showIndex + 1 }} / {{ data.new_word_list.length }}
+      </p>
+      <i
+        class="el-icon-arrow-right"
+        :class="[showIndex === data.new_word_list.length - 1 ? 'disabled' : '']"
+        @click="changeShowIndex('+')"
+      ></i>
+    </el-dialog>
   </div>
 </template>
 
@@ -688,6 +724,7 @@ import Strockplay from './components/Strockplay.vue';
 import Vue from 'vue';
 import Plugin from 'v-fit-columns';
 Vue.use(Plugin);
+import writeTableZoom from './components/writeTableZoom.vue';
 
 export default {
   name: 'NewWordPreview',
@@ -698,6 +735,7 @@ export default {
     WordPhraseDetail,
     AudioPlay,
     Strockplay,
+    writeTableZoom,
   },
   mixins: [PreviewMixin],
   inject: ['bookInfo'],
@@ -728,6 +766,8 @@ export default {
       multilingualTextList: {}, // 多语言对应的切割后的翻译
       titleTrans: {},
       width: 0,
+      showCard: false, // 卡片放大
+      showIndex: 0, // 卡片放大索引
     };
   },
   watch: {
@@ -973,6 +1013,16 @@ export default {
       item.show_left = !item.show_left;
       item.isFlipped = !item.isFlipped;
     },
+    changeShowIndex(type) {
+      if (type === '+') {
+        if (this.showIndex !== this.data.new_word_list.length - 1) {
+          this.showIndex++;
+        }
+      } else if (this.showIndex !== 0) {
+        this.showIndex--;
+      }
+      this.$refs.writeTableZoom.changeRota();
+    },
   },
 };
 </script>
@@ -1054,7 +1104,8 @@ export default {
 
           > span {
             font-size: 16px;
-            line-height: 150%;
+
+            // line-height: 150%;
             color: #000;
           }
         }
@@ -1702,6 +1753,53 @@ export default {
     display: none;
   }
 }
+
+.wordCard-dialog {
+  display: flex;
+  align-items: center;
+
+  :deep .el-dialog {
+    box-shadow: none;
+  }
+
+  .el-icon-arrow-left,
+  .el-icon-arrow-right {
+    position: fixed;
+    top: 50%;
+    left: 200px;
+    margin-top: -20px;
+    font-size: 50px;
+    font-weight: bold;
+    color: #f2f2f2;
+    cursor: pointer;
+
+    &.disabled {
+      color: darkgrey;
+      cursor: not-allowed;
+    }
+  }
+
+  .el-icon-arrow-right {
+    right: 200px;
+    left: auto;
+  }
+
+  :deep .el-dialog {
+    background: transparent;
+  }
+
+  :deep .el-dialog__headerbtn {
+    position: fixed;
+    top: 20px;
+    right: 20px;
+  }
+
+  :deep .el-dialog__headerbtn .el-dialog__close {
+    font-size: 34px;
+    font-weight: bold;
+    color: #f2f3f5;
+  }
+}
 </style>
 <style lang="scss">
 .NPC-zhedie {
@@ -1710,8 +1808,6 @@ export default {
     justify-content: space-between;
     width: 100%;
     height: 48px;
-    padding-right: 16px;
-    padding-left: 24px;
     overflow: hidden;
 
     // background: #e35454;

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

@@ -0,0 +1,876 @@
+<template>
+  <div v-if="data" :class="['writeTable', editCardflag ? '' : 'writeTable-preview writeTable-preview-' + totalNumber]">
+    <div class="writeTop" :class="{ flipped: isFlipped }">
+      <div
+        v-if="(isPreview && showLeft) || !isPreview"
+        class="left left-preview"
+        :class="[data.file_list[0] ? '' : 'left-big']"
+        :style="{
+          borderColor: attrib && attrib.topic_color ? attrib.topic_color : '',
+          padding:
+            data.new_word && (data.header_con || data.label)
+              ? ''
+              : !data.new_word && (data.header_con || data.label)
+                ? '40px 12px 0 12px'
+                : '12px',
+        }"
+      >
+        <div class="header-info-preview">
+          <h5 :style="{ textAlign: 'left' }">{{ data.header_con }}</h5>
+          <label :style="{ background: attrib && attrib.topic_color ? attrib.topic_color : '' }">{{
+            data.label
+          }}</label>
+        </div>
+        <div v-if="data.file_list[0]" class="item-image">
+          <el-image
+            :style="{
+              width: '568px',
+              height:
+                data.new_word && (data.header_con || data.label)
+                  ? '340px'
+                  : !data.new_word || data.header_con || data.label
+                    ? '382px'
+                    : '410px',
+            }"
+            :src="data.pic_url"
+            :preview-src-list="[data.pic_url]"
+            fit="contain"
+          />
+        </div>
+        <h2 v-if="data.new_word" :class="['con-preview', data.file_list[0] ? '' : 'con-preview-big']">
+          {{ data.new_word }}
+        </h2>
+
+        <a v-if="isPreview" class="overturn-btn" @click="changeShowLeft"><i class="el-icon-refresh"></i></a>
+      </div>
+      <div
+        v-if="(isPreview && !showLeft) || !isPreview"
+        class="right right-preview left-preview"
+        :class="[isPreview ? 'right-preview-rota' : '']"
+        :style="{
+          borderColor: attrib && attrib.topic_color ? attrib.topic_color : '',
+          paddingTop: data.collocation || data.liju_list || data.definition_list ? '' : '80px',
+        }"
+      >
+        <div class="header-info-preview">
+          <h5 :style="{ textAlign: 'left' }">{{ data.header_con }}</h5>
+          <label :style="{ background: attrib && attrib.topic_color ? attrib.topic_color : '' }">{{
+            data.label
+          }}</label>
+        </div>
+        <div
+          :style="{
+            display: 'flex',
+            justifyContent: !(data.collocation && data.liju_list) && data.new_word.length < 4 ? 'center' : 'auto',
+            columnGap: '16px',
+          }"
+        >
+          <div v-if="data.hz_info.length > 0" style="width: max-content">
+            <AudioPlay
+              v-if="data.mp3_list"
+              :style="{
+                background: attrib && attrib.topic_color ? attrib.topic_color : '',
+              }"
+              :file-id="data.mp3_list_url"
+            />
+            <template v-else-if="data.bg || data.ed">
+              <div
+                class="audio-wrapper"
+                :style="{
+                  background: attrib && attrib.topic_color ? attrib.topic_color : '',
+                  display: 'flex',
+                  alignItems: 'center',
+                  justifyContent: 'center',
+                }"
+                @click="handleChangeTime(data.bg, data.ed)"
+              >
+                <SvgIcon
+                  v-if="curTime >= data.bg && curTime < data.ed && stopAudioS"
+                  icon-class="animated"
+                  size="30"
+                  :style="{
+                    color: '#fff',
+                  }"
+                />
+                <SvgIcon
+                  v-else
+                  icon-class="play-btn"
+                  size="30"
+                  :style="{
+                    color: '#fff',
+                    width: '30px',
+                    height: '30px',
+                  }"
+                />
+              </div>
+            </template>
+            <p
+              v-if="data.pinyin && data.pinyin.split(' ').length === 1"
+              :style="{ color: attrib && attrib.topic_color ? attrib.topic_color : '' }"
+              class="pinyin-box"
+            >
+              {{ data.pinyin }}
+            </p>
+            <div class="hz-box">
+              <div v-for="(itemh, indexh) in data.hz_info" :key="indexh" class="hz-item">
+                <p
+                  v-if="data.pinyin && data.pinyin.split(' ').length > 1"
+                  :style="{ color: attrib && attrib.topic_color ? attrib.topic_color : '' }"
+                >
+                  {{ data.pinyin.split(' ')[indexh] ? data.pinyin.split(' ')[indexh] : '' }}
+                </p>
+                <Strockplay
+                  class-name="adult-strockplay"
+                  :Book_text="itemh.con"
+                  :play-storkes="true"
+                  :stroke-play-color="attrib && attrib.topic_color ? attrib.topic_color : '#f44444'"
+                  :stroke-color="'#000000'"
+                  :paly-width="'24px'"
+                  :BoxbgType="'0'"
+                  :cur-item="itemh.hzDetail.hz_json"
+                  :target-div="'writeTops-item-zoom-' + pageNumber + '-' + indexh + '-' + itemh.con + '-' + totalNumber"
+                  :class="[indexh !== 0 ? 'writeTop-item-noLeft' : '']"
+                  class="writeTop-item"
+                  :style="{ borderColor: attrib && attrib.topic_color ? attrib.topic_color : '#f44444' }"
+                />
+              </div>
+            </div>
+          </div>
+
+          <div
+            v-if="(data.collocation || data.liju_list) && data.new_word.length < 4"
+            class="definition-box"
+            :style="{
+              flex: '1',
+              marginTop: data.mp3_list ? '104px' : '36px',
+            }"
+          >
+            <div v-if="data.cixing">
+              <label class="card-label">词性:</label>
+              <p v-html="data.cixing"></p>
+            </div>
+            <div v-if="data.definition_list">
+              <label class="card-label">释义:</label>
+              <p v-html="data.definition_list"></p>
+            </div>
+          </div>
+        </div>
+        <div
+          v-if="data.collocation || data.liju_list || data.definition_list || data.cixing"
+          class="definition-box"
+          :style="{
+            width:
+              !(data.collocation || data.liju_list) && data.new_word.length < 4 ? data.hz_info.length * 98 + 'px' : '',
+            margin: !(data.collocation || data.liju_list) && data.new_word.length < 4 ? '16px auto 0 auto' : '',
+          }"
+        >
+          <template v-if="!(data.collocation || data.liju_list) || data.new_word.length >= 4">
+            <div v-if="data.cixing">
+              <label class="card-label">词性:</label>
+              <p v-html="data.cixing"></p>
+            </div>
+            <div v-if="data.definition_list">
+              <label class="card-label">释义:</label>
+              <p v-html="data.definition_list"></p>
+            </div>
+          </template>
+          <div v-if="data.collocation">
+            <label class="card-label">搭配:</label>
+            <p v-html="data.collocation"></p>
+          </div>
+          <div v-if="data.liju_list">
+            <label class="card-label">例句:</label>
+            <p v-html="data.liju_list"></p>
+          </div>
+        </div>
+        <a v-if="isPreview" class="overturn-btn" @click="changeShowLeft"><i class="el-icon-refresh"></i></a>
+      </div>
+    </div>
+    <div v-if="url" class="aduioLine-box" style="height: 0; margin: 0; overflow: hidden">
+      <AudioLine
+        ref="audioLine"
+        :audio-id="'newWordAudioZoom'"
+        :mp3="url"
+        :get-cur-time="getCurTime"
+        :ed="ed"
+        type="audioLine"
+        :attrib="attrib"
+        @handleListenRead="handleListenRead"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+import AudioPlay from './AudioPlay.vue';
+import Strockplay from './Strockplay.vue';
+import AudioLine from '../../voice_matrix/components/AudioLine.vue';
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    Strockplay,
+    AudioPlay,
+    AudioLine,
+  },
+  props: [
+    'isPreview',
+    'data',
+    'pageNumber',
+    'totalNumber',
+    'editCardflag',
+    'is_preview',
+    'filtCardflag',
+    'attrib',
+    'url',
+  ],
+  data() {
+    // 这里存放数据
+    return {
+      loading: false,
+      isFlipped: false,
+      showLeft: true,
+      curTime: 0,
+      stopAudioS: false,
+    };
+  },
+  // 计算属性 类似于data概念
+  computed: {},
+  // 监控data中数据变化
+  watch: {
+    editCardflag: {
+      handler(val, oldVal) {
+        if (val != oldVal) {
+          this.showLeft = true;
+          this.isFlipped = false;
+        }
+      },
+      deep: true,
+    },
+    filtCardflag: {
+      handler(val, oldVal) {
+        this.showLeft = true;
+        this.isFlipped = false;
+      },
+      deep: true,
+    },
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  // 生命周期-挂载之前
+  beforeMount() {},
+  // 生命周期-更新之后
+  updated() {},
+  // 如果页面有keep-alive缓存功能,这个函数会触发
+  activated() {},
+  // 方法集合
+  methods: {
+    // 翻面
+    changeShowLeft() {
+      this.showLeft = !this.showLeft;
+      this.isFlipped = !this.isFlipped;
+    },
+    // 点击播放某个句子
+    handleChangeTime(time, edTime) {
+      this.curTime = time;
+      this.stopAudioS = true;
+      this.$refs.audioLine.onTimeupdateTime(time / 1000, true);
+      this.ed = edTime;
+    },
+    handleListenRead(playFlag) {
+      this.stopAudioS = playFlag;
+    },
+    getCurTime(curTime) {
+      this.curTime = curTime * 1000;
+    },
+  },
+  // 生命周期-创建之前
+  beforeCreated() {},
+  // 生命周期-更新之前
+  beforUpdate() {},
+  // 生命周期-销毁之前
+  beforeDestory() {},
+  // 生命周期-销毁完成
+  destoryed() {},
+};
+</script>
+<style lang="scss" scoped>
+.writeTable {
+  // height: 842px;
+  box-sizing: border-box;
+  width: 1208px;
+  margin: 40px auto 19px;
+  perspective: 1000px;
+
+  &-preview {
+    width: 600px;
+  }
+
+  .writeTop {
+    position: relative;
+    display: flex;
+    column-gap: 8px;
+    min-height: 450px;
+    transition: 0.6s;
+    perspective: 1000px;
+    transform-style: preserve-3d;
+
+    .left,
+    .right {
+      position: relative;
+      box-sizing: border-box;
+      width: 100%;
+      min-height: 270px;
+      padding: 8px 12px 18px;
+      overflow: hidden;
+      background: #fff;
+      border: 4px solid #fff;
+      border-radius: 24px;
+
+      .header-info {
+        display: flex;
+        justify-content: space-between;
+        width: 100%;
+        margin-bottom: 12px;
+
+        :deep .el-input__inner {
+          height: 24px;
+          padding: 0;
+          font-size: 24px;
+          font-weight: 400;
+          line-height: 100%;
+          color: rgba(0, 0, 0, 100%);
+          border: none;
+        }
+
+        .label {
+          :deep .el-input__inner {
+            text-align: right;
+          }
+        }
+      }
+    }
+
+    .left-preview {
+      padding-top: 40px;
+
+      // padding-bottom: 32px;
+      // position: absolute;
+      backface-visibility: hidden;
+    }
+
+    .header-info-preview {
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: 1;
+      width: 100%;
+
+      h5 {
+        padding: 0 12px;
+        margin: 0;
+        font-size: 24px;
+        font-weight: 400;
+        line-height: 32px;
+        color: #000;
+      }
+
+      label {
+        position: absolute;
+        top: -4px;
+        right: -4px;
+        padding: 0 16px 0 8px;
+        font-size: 24px;
+        font-weight: 500;
+        line-height: 150%;
+        color: #fff;
+        background: #fff;
+        border-radius: 0 8px;
+      }
+    }
+
+    .left-big {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+
+    .del-btn {
+      position: absolute;
+      right: 8px;
+      bottom: 8px;
+      padding: 5px 8px;
+      font-size: 24px;
+      color: #fff;
+      cursor: pointer;
+      background: #f56767;
+      border-radius: 40px;
+    }
+
+    .overturn-btn {
+      position: absolute;
+      right: 8px;
+      bottom: 8px;
+      width: 40px;
+      height: 40px;
+      padding: 8px;
+      font-size: 24px;
+      line-height: 1;
+      color: #fff;
+      cursor: pointer;
+      background: #e0e0e0;
+      border-radius: 8px;
+    }
+
+    .el-icon-zoom-in,
+    .filt-check {
+      position: absolute;
+      bottom: 8px;
+      left: 8px;
+      width: 30px;
+      height: 30px;
+      font-size: 24px;
+      cursor: pointer;
+
+      :deep .el-checkbox__inner {
+        width: 24px;
+        height: 24px;
+      }
+
+      :deep .el-checkbox__inner::after {
+        left: 8px;
+        width: 6px;
+        height: 14px;
+      }
+    }
+
+    .right {
+      display: flex;
+      flex-flow: wrap;
+      row-gap: 8px;
+      align-items: center;
+      padding: 16px 24px 26px;
+
+      .card-label {
+        width: 100%;
+        height: 22px;
+        font-size: 14px;
+        font-weight: 400;
+        line-height: 22px;
+        color: #4e5969;
+      }
+
+      :deep .el-textarea {
+        height: 64px;
+      }
+
+      .config-box {
+        display: flex;
+        align-items: center;
+        width: 100%;
+
+        span {
+          margin-right: 8px;
+          font-size: 14px;
+          line-height: 20px;
+          color: #000;
+        }
+
+        .el-color-picker {
+          height: 32px;
+        }
+
+        :deep .el-color-picker__trigger {
+          height: 32px;
+        }
+
+        .el-radio {
+          margin-right: 8px;
+        }
+
+        .el-radio-group {
+          display: flex;
+        }
+
+        :deep .el-radio__input.is-checked .el-radio__inner {
+          background: #000;
+          border-color: #000;
+        }
+
+        :deep .el-radio__input.is-checked + .el-radio__label {
+          color: #000;
+        }
+      }
+    }
+
+    .right-preview {
+      display: block;
+      padding: 36px;
+
+      .pinyin-box {
+        margin-bottom: 8px;
+        font-family: 'League';
+        font-size: 22px;
+        font-feature-settings: 'cv01' on;
+        line-height: 120%;
+        color: #de4444;
+        text-align: center;
+      }
+
+      .hz-box {
+        width: 100%;
+
+        .hz-item {
+          text-align: center;
+
+          :deep .strockplayInner {
+            width: 98px;
+            height: 98px;
+          }
+
+          p {
+            margin-bottom: 12px;
+            font-family: 'League';
+            font-size: 22px;
+            font-feature-settings: 'cv01' on;
+            line-height: 120%;
+            color: #de4444;
+          }
+        }
+      }
+
+      :deep .audio-wrapper {
+        box-sizing: border-box;
+        width: 60px;
+        height: 60px;
+        padding: 18px;
+        margin: 0 auto 8px;
+        cursor: pointer;
+        background: #f3f3f3;
+        border-radius: 40px;
+
+        .voice-play {
+          width: 30px;
+          height: 30px;
+        }
+      }
+
+      .definition-box {
+        margin-top: 16px;
+        white-space: pre;
+
+        > div {
+          display: flex;
+          margin-bottom: 8px;
+
+          label,
+          p {
+            width: 40px;
+            font-size: 20px;
+            font-weight: 400;
+            line-height: 150%;
+            color: #000;
+          }
+
+          label {
+            width: 54px;
+          }
+
+          p {
+            flex: 1;
+            word-break: break-word;
+            white-space: pre-wrap;
+          }
+        }
+      }
+
+      :deep p {
+        margin: 0;
+
+        span,
+        b,
+        p {
+          text-align: left !important; // 有的富文本里设置了居中对齐
+        }
+      }
+    }
+
+    .right-preview-rota {
+      transform: rotateY(180deg);
+    }
+
+    .item-image {
+      position: relative;
+      overflow: hidden;
+      font-size: 0;
+
+      // background: #f2f3f5;
+      border-radius: 8px;
+
+      .item-image-del {
+        position: absolute;
+        top: 8px;
+        right: 8px;
+        display: block;
+        width: 16px;
+        height: 16px;
+        padding: 8px;
+        font-size: 16px;
+        color: #ee3232;
+        cursor: pointer;
+        background-color: #fff;
+        border-radius: 50%;
+        box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 25%);
+      }
+    }
+
+    .item-con {
+      display: flex;
+      align-items: center;
+      width: 50%;
+      margin-top: 16px;
+
+      label {
+        width: 44px;
+        font-size: 14px;
+        font-weight: 400;
+        line-height: 22px;
+        color: #4e5969;
+      }
+
+      :deep .el-input__inner {
+        width: 235px;
+        height: 32px;
+        font-family: '楷体';
+        font-size: 14px;
+        font-weight: 400;
+        line-height: 22px;
+        background: #f2f3f5;
+        border: none;
+        border-radius: 2px;
+      }
+
+      .pinyin {
+        :deep .el-input__inner {
+          font-family: 'League';
+        }
+      }
+    }
+
+    .con-preview {
+      margin-top: 8px;
+      font-family: '楷体';
+      font-size: 46px;
+      font-weight: 400;
+      line-height: 100%;
+      color: #000;
+      text-align: center;
+
+      &-big {
+        margin: 0;
+        font-size: 86px;
+      }
+    }
+
+    .writeTop-row {
+      display: flex;
+      justify-content: center;
+    }
+  }
+
+  .writeTop-nopadding {
+    height: 842px;
+    padding-top: 0;
+  }
+
+  .item-info {
+    box-sizing: border-box;
+    display: flex;
+    column-gap: 16px;
+    width: 100%;
+    padding: 0 46px 8px;
+
+    &-left {
+      .writeTop-item {
+        width: 98px;
+        height: 98px;
+
+        :deep .strock-play-box {
+          width: 18px !important;
+          height: 18px !important;
+        }
+
+        :deep .playStorkes-btn {
+          width: 18px !important;
+          height: 18px !important;
+        }
+
+        &-small {
+          width: 62px;
+          height: 62px;
+
+          :deep .strock-play-box {
+            width: 11px !important;
+            height: 11px !important;
+          }
+
+          :deep .playStorkes-btn {
+            width: 11px !important;
+            height: 11px !important;
+          }
+        }
+      }
+
+      &-long {
+        width: 100%;
+      }
+    }
+
+    &-right {
+      flex: 1;
+    }
+
+    :deep .el-textarea__inner {
+      resize: none;
+      background-color: #f3f3f3;
+      border: none;
+      outline: none;
+    }
+
+    .voice-box {
+      display: flex;
+      column-gap: 4px;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 32px;
+
+      img {
+        width: 24px;
+        height: 24px;
+      }
+
+      span {
+        font-family: 'League';
+        font-size: 16px;
+        font-weight: 400;
+        color: #de4444;
+      }
+    }
+
+    .item-info-row {
+      display: flex;
+      column-gap: 11px;
+      margin-bottom: 6px;
+
+      :deep .el-input__inner {
+        height: 32px;
+        background-color: #f3f3f3;
+        border: none;
+        outline: none;
+      }
+    }
+
+    .item-info-half,
+    .item-info-all {
+      display: flex;
+      width: 50%;
+      height: 22px;
+      font-size: 14px;
+      line-height: 22px;
+    }
+
+    .item-info-all {
+      width: 100%;
+    }
+  }
+
+  .hz-box {
+    display: flex;
+    width: max-content;
+  }
+
+  .writeTop-item {
+    border: 1px solid #de4444;
+  }
+
+  .writeTop-item-noLeft {
+    border-left: none;
+  }
+
+  .tian-div {
+    position: relative;
+    width: 100%;
+    height: 100%;
+
+    .tian {
+      width: 100%;
+      height: 100%;
+    }
+
+    img {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .flipped {
+    transform: rotateY(180deg);
+  }
+
+  .flipped-back {
+    transform: rotateY(180deg);
+  }
+}
+</style>
+<style lang="scss">
+.writeTable {
+  input::placeholder {
+    font-family: initial;
+  }
+
+  input::input-placeholder {
+    font-family: initial;
+  }
+
+  input::placeholder {
+    font-family: initial;
+  }
+
+  input:placeholder {
+    font-family: initial;
+  }
+
+  input:input-placeholder {
+    font-family: initial;
+  }
+
+  .header-info {
+    input::placeholder {
+      font-size: 16px;
+    }
+
+    input::input-placeholder {
+      font-size: 16px;
+    }
+
+    input::placeholder {
+      font-size: 16px;
+    }
+
+    input:placeholder {
+      font-size: 16px;
+    }
+
+    input:input-placeholder {
+      font-size: 16px;
+    }
+  }
+}
+</style>

+ 132 - 101
src/web_preview/index.vue

@@ -132,56 +132,58 @@
             <img :src="require(`@/assets/icon/arrow-up.png`)" alt="伸缩" />
           </div>
         </aside>
-        <div class="content"></div>
+        <div class="content">
+          <el-drawer
+            custom-class="custom-drawer"
+            :visible="drawerType.length > 0"
+            :with-header="false"
+            :modal="false"
+            size="240"
+            direction="ltr"
+            :style="drawerStyle"
+          >
+            <div class="infinite-list-wrapper">
+              <h5>{{ drawerTitle }}</h5>
+              <ul
+                v-infinite-scroll="loadMore"
+                class="scroll-container"
+                infinite-scroll-disabled="disabled"
+                :infinite-scroll-immediate="false"
+              >
+                <li
+                  v-for="(item, index) in file_list"
+                  :key="index"
+                  class="list-item"
+                  @click="handleFileClick(item?.courseware_id, item?.component_id)"
+                >
+                  <template v-if="parseInt(drawerType) === 0">
+                    <el-image :src="item.file_url" fit="contain" />
+                    <!-- <span class="text-box">{{ item.file_name.slice(0, item.file_name.lastIndexOf('.')) }}</span> -->
+                  </template>
+                  <template v-else-if="parseInt(drawerType) === 1">
+                    <AudioPlay
+                      view-size="middle"
+                      :file-id="item.file_id"
+                      :file-name="item.file_name.slice(0, item.file_name.lastIndexOf('.'))"
+                      :show-slider="true"
+                      :audio-index="index"
+                    />
+                  </template>
+                  <template v-else-if="parseInt(drawerType) === 2">
+                    <VideoPlay view-size="small" :file-id="item.file_id" :video-index="index" />
+                    <!-- <span class="text-box">{{ item.file_name.slice(0, item.file_name.lastIndexOf('.')) }}</span> -->
+                  </template>
+                </li>
+              </ul>
+              <p v-if="loading">加载中...</p>
+              <p v-if="noMore">没有更多了</p>
+            </div>
+          </el-drawer>
+        </div>
 
         <div class="back-top" @click="backTop">
           <img :src="require(`@/assets/icon/back-top.png`)" alt="返回顶部" />
         </div>
-
-        <el-drawer
-          custom-class="custom-drawer"
-          :visible="drawerType.length > 0"
-          :with-header="false"
-          :modal="false"
-          size="25%"
-          :style="drawerStyle"
-        >
-          <div class="infinite-list-wrapper">
-            <ul
-              v-infinite-scroll="loadMore"
-              class="scroll-container"
-              infinite-scroll-disabled="disabled"
-              :infinite-scroll-immediate="false"
-            >
-              <li
-                v-for="(item, index) in file_list"
-                :key="index"
-                class="list-item"
-                @click="handleFileClick(item?.courseware_id, item?.component_id)"
-              >
-                <template v-if="parseInt(drawerType) === 0">
-                  <el-image :src="item.file_url" fit="contain" />
-                  <span class="text-box">{{ item.file_name.slice(0, item.file_name.lastIndexOf('.')) }}</span>
-                </template>
-                <template v-else-if="parseInt(drawerType) === 1">
-                  <AudioPlay
-                    view-size="middle"
-                    :file-id="item.file_id"
-                    :file-name="item.file_name.slice(0, item.file_name.lastIndexOf('.'))"
-                    :show-slider="true"
-                    :audio-index="index"
-                  />
-                </template>
-                <template v-else-if="parseInt(drawerType) === 2">
-                  <VideoPlay view-size="big" :file-id="item.file_id" :video-index="index" />
-                  <span class="text-box">{{ item.file_name.slice(0, item.file_name.lastIndexOf('.')) }}</span>
-                </template>
-              </li>
-            </ul>
-            <p v-if="loading">加载中...</p>
-            <p v-if="noMore">没有更多了</p>
-          </div>
-        </el-drawer>
       </aside>
     </div>
 
@@ -331,6 +333,14 @@ export default {
       const result = this.file_list.length >= this.total_count;
       return result;
     },
+    drawerTitle() {
+      const titleMap = {
+        0: '图片资源',
+        1: '音频资源',
+        2: '视频资源',
+      };
+      return titleMap[this.drawerType] || '资源列表';
+    },
   },
   watch: {
     isJudgeCorrect(newVal) {
@@ -519,7 +529,7 @@ export default {
         this.drawerStyle = {
           top: `${rect.top}px`,
           height: `${rect.height}px`,
-          right: `${window.innerWidth - rect.left + 1}px`,
+          left: `${rect.right - 240}px`,
         };
       }
     },
@@ -677,7 +687,6 @@ export default {
   },
 };
 </script>
-
 <style lang="scss" scoped>
 @use '@/styles/mixin.scss' as *;
 
@@ -1025,6 +1034,70 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
       .content {
         flex: 1;
         background-color: #fff;
+
+        :deep .el-drawer {
+          width: 240px !important;
+          border: 1px solid #e5e5e5;
+          transition: none !important;
+          animation: none !important;
+
+          .el-drawer__body {
+            height: calc(100vh - 200px);
+            overflow-y: auto;
+
+            h5 {
+              padding: 0 5px;
+              margin: 0;
+              font-size: 18px;
+              line-height: 40px;
+              background: #f2f3f5;
+            }
+
+            .scroll-container {
+              display: flex;
+              flex-direction: column;
+              row-gap: 8px;
+              margin: 6px;
+
+              .list-item {
+                display: flex;
+                align-items: center;
+                cursor: pointer;
+                border: 1px solid #ccc;
+                border-radius: 8px;
+
+                :deep .el-slider {
+                  .el-slider__runway {
+                    background-color: #eee;
+                  }
+                }
+
+                .el-image {
+                  display: flex;
+                  width: 100%;
+                  min-width: 100%;
+                  height: 90px;
+                  background-color: #ccc;
+                  border-radius: 8px;
+                }
+
+                .video-play {
+                  width: 100%;
+                  min-width: 100%;
+                }
+
+                .text-box {
+                  word-break: break-word;
+                }
+              }
+            }
+          }
+
+          p {
+            color: #999;
+            text-align: center;
+          }
+        }
       }
 
       .back-top {
@@ -1040,62 +1113,20 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
       }
     }
   }
+}
 
-  .el-drawer__body {
-    height: calc(100vh - 200px);
-    overflow-y: auto;
-
-    .scroll-container {
-      display: flex;
-      flex-direction: column;
-      row-gap: 8px;
-      margin: 6px;
-
-      .list-item {
-        display: flex;
-        align-items: center;
-        cursor: pointer;
-        border: 1px solid #ccc;
-        border-radius: 8px;
-
-        :deep .el-slider {
-          .el-slider__runway {
-            background-color: #eee;
-          }
-        }
-
-        :deep .audio-middle {
-          width: calc(25vw - 110px);
-          border: none;
-          border-radius: 8px;
-        }
-
-        .el-image {
-          display: flex;
-          width: 30%;
-          min-width: 30%;
-          height: 90px;
-          margin: 6px;
-          background-color: #ccc;
-          border-radius: 8px;
-        }
-
-        .video-play {
-          width: 30%;
-          min-width: 30%;
-          margin: 6px;
-        }
+:deep .audio-wrapper .audio-middle {
+  width: 210px !important;
+  padding: 6px 8px !important;
+  border: none;
+  border-radius: 8px;
 
-        .text-box {
-          word-break: break-word;
-        }
-      }
-    }
+  .audio-name {
+    text-align: left;
+  }
 
-    p {
-      color: #999;
-      text-align: center;
-    }
+  .slider-area {
+    column-gap: 8px !important;
   }
 }