浏览代码

教材资源

natasha 3 年之前
父节点
当前提交
c080a88d05

二进制
src/assets/common/Repeat-24-disable-Black.png


二进制
src/assets/common/Repeat-24-normal-red.png


二进制
src/assets/common/auto-24-disable-black.png


二进制
src/assets/common/download.png


二进制
src/assets/common/go-end-disabled.png


二进制
src/assets/common/go-end.png


二进制
src/assets/common/go-start-disabled.png


二进制
src/assets/common/go-start.png


二进制
src/assets/common/loading-red.png


二进制
src/assets/common/music-list.png


二进制
src/assets/common/pause-24-normal-red.png


二进制
src/assets/common/play-24-normal-red.png


二进制
src/assets/common/play-one.png


二进制
src/assets/textBookDetail/Group 3235.png


二进制
src/assets/textBookDetail/Group 3278.png


二进制
src/assets/textBookDetail/collect4.png


+ 552 - 0
src/components/inputModules/common/AudioLine.vue

@@ -0,0 +1,552 @@
+<template>
+  <div class="AudioNNPE">
+    <div class="audioLine" v-if="mp3List">
+      <span class="audioName">{{activeIndex+1}}.</span>
+      <div class="go-start" :class="[activeIndex===0?'disabled':'']" @click="handleActiveIndex('-')"></div>
+      <div class="playBox" @click="PlayAudio">
+        <div
+          class="play"
+          :class="[
+            audio.loading ? 'loadBtn' : audio.playing ? 'playBtn' : 'pauseBtn',
+          ]"
+        ></div>
+      </div>
+      <div class="go-end" :class="[activeIndex!=mp3List.length-1?'':'disabled']" @click="handleActiveIndex('+')"></div>
+      <div class="play-mode order" :class="[isRepeatAudio?'roll':'']" @click="handleRepeatAudio"></div>
+      <template>
+        <el-slider
+          v-model="playValue"
+          :style="{ width: sliderWidth + 'px', height: '2px' }"
+          :format-tooltip="formatProcessToolTip"
+          @change="changeCurrentTime"
+        />
+        <span class="time-box"
+          ><template v-if="audio.playing">-</template
+          >{{
+            audio.maxTime
+              ? realFormatSecond(audio.maxTime - audio.currentTime)
+              : ""
+          }}</span
+        >
+      </template>
+      <div class="common-btn audio-btn" :class="[mp3ListShow?'active':'']" @click="handleClickAudio">
+        <img src="../../../assets/common/music-list.png" class="music-list" />
+        <ul class="audioList" v-if="mp3ListShow">
+            <li v-for="(item,index) in mp3List" :key="index" :class="[activeIndex==index?'active':'']" @click="handleSelectAudio(index)">
+                <span>{{index+1}}.</span>
+                <p>{{realFormatSecond(item.media_duration)}}</p>
+            </li>
+        </ul>
+      </div>
+      <div class="common-btn download-btn" @click="download">
+        <img src="../../../assets/common/download.png" class="download" />
+      </div>
+    </div>
+    <audio
+      :ref="audioId"
+      :src="mp3List[activeIndex].file_url"
+      @loadedmetadata="onLoadedmetadata"
+      @timeupdate="onTimeupdate"
+      @canplaythrough="oncanplaythrough"
+      preload="meta"
+      :id="audioId"
+    />
+  </div>
+</template>
+
+<script>
+// 这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》from ‘《组件路径》';
+import { getToken } from "@/utils/auth";
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {},
+  props: [
+    "mp3List",
+    "audioId",
+    "type",
+  ],
+  data() {
+    // 这里存放数据
+    return {
+      playValue: 0,
+      audio: {
+        // 该字段是音频是否处于播放状态的属性
+        playing: false,
+        // 音频当前播放时长
+        currentTime: 0,
+        // 音频最大播放时长
+        maxTime: 0,
+        isPlaying: false,
+        loading: false,
+      },
+      audioAllTime: null, // 展示总时间
+      duioCurrentTime: null, // 剩余时间
+      count: 0,
+      isClick: false,
+      activeIndex:0,
+      mp3ListShow: false,
+      isRepeatAudio:false,
+    };
+  },
+  // 计算属性 类似于data概念
+  computed: {
+    sliderWidth() {
+      let width = 0;
+      if (this.width) {
+        width = this.width;
+      } else {
+        width = 696;
+      }
+      return width;
+    },
+  },
+  // 监控data中数据变化
+  watch: {
+    stopAudio: {
+      handler(val, oldVal) {
+        const _this = this;
+        if (val) {
+          _this.$refs[_this.audioId].pause();
+          _this.audio.playing = false;
+        }
+      },
+      // 深度观察监听
+      deep: true,
+    },
+    "audio.playing": {
+      handler(val) {
+        this.$emit("playChange", val);
+        if (val) this.$emit("handleChangeStopAudio");
+      },
+    },
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    let audioId = _this.audioId;
+    _this.$refs[audioId].addEventListener("loadstart", function () {
+      console.log("音频开始加载");
+    });
+    _this.$refs[audioId].addEventListener("play", function () {
+      console.log("音频开始播放了");
+      _this.audio.playing = true;
+      _this.audio.isPlaying = true;
+      _this.audio.loading = false;
+    });
+    _this.$refs[audioId].addEventListener("pause", function () {
+      _this.audio.playing = false;
+      if (_this.hideSlider && _this.audio.currentTime * 1000 + 500 > _this.ed) {
+        _this.$emit("sentPause", true);
+      }
+      _this.$emit("handleListenRead", false);
+    });
+    _this.$refs[audioId].addEventListener("ended", function () {
+      _this.audio.playing = false;
+      _this.audio.isPlaying = false;
+      _this.isClick = false;
+      _this.$emit("handleListenRead", false);
+      if(_this.isRepeatAudio){
+          _this.PlayAudio()
+      }
+    });
+
+    this.$nextTick(() => {
+      if (
+        document.getElementsByClassName("el-slider__button-wrapper") &&
+        document.getElementsByClassName("el-slider__button-wrapper")[0]
+      ) {
+        document
+          .getElementsByClassName("el-slider__button-wrapper")[0]
+          .addEventListener("mousedown", function () {
+            _this.$refs[audioId].pause();
+            _this.audio.playing = false;
+          });
+      }
+    });
+  },
+  // 生命周期-挂载之前
+  beforeMount() {},
+  // 生命周期-更新之后
+  updated() {},
+  // 如果页面有keep-alive缓存功能,这个函数会触发
+  activated() {},
+  // 方法集合
+  methods: {
+    PlayAudio() {
+      let audioId = this.audioId;
+      let audio = document.getElementsByTagName("audio");
+      audio.forEach((item) => {
+        if (item.src == this.mp3List[this.activeIndex]) {
+          if (item.id !== audioId) {
+            item.pause();
+          }
+        } else {
+          item.pause();
+        }
+      });
+
+      if (this.audio.playing) {
+        this.$refs[audioId].pause();
+        this.audio.playing = false;
+        this.$emit("handleListenRead", false);
+        this.isClick = false;
+      } else {
+        if (this.count == 0) {
+          this.audio.loading = true;
+          this.count++;
+        }
+        if (this.hideSlider) {
+          this.$refs[audioId].play();
+          this.onTimeupdateTime(this.bg / 1000);
+        } else {
+          this.$refs[audioId].play();
+        }
+
+        this.$emit("handleChangeStopAudio");
+        this.$emit("handleListenRead", true);
+        this.isClick = true;
+      }
+    },
+    oncanplaythrough() {
+      let _this = this;
+      //setTimeout(() => {
+      console.log("音频加载完成");
+      _this.audio.loading = false;
+      //}, 10000);
+    },
+    // 点击 拖拽播放音频
+    changeCurrentTime(value) {
+      let audioId = this.audioId;
+      this.$refs[audioId].play();
+      this.audio.playing = true;
+      this.$refs[audioId].currentTime = parseInt(
+        (value / 100) * this.audio.maxTime
+      );
+    },
+    mousedown() {
+      let audioId = this.audioId;
+      this.$refs[audioId].pause();
+      this.audio.playing = false;
+    },
+    // 进度条格式化toolTip
+    formatProcessToolTip(index) {
+      index = parseInt((this.audio.maxTime / 100) * index);
+      return this.realFormatSecond(index);
+    },
+    // 音频加载完之后
+    onLoadedmetadata(res) {
+    //   this.audio.maxTime = parseInt(res.target.duration);
+      this.audio.maxTime = this.mp3List[this.activeIndex].media_duration
+      this.audioAllTime = this.realFormatSecond(this.audio.maxTime);
+    },
+    // 当音频当前时间改变后,进度条也要改变
+    onTimeupdate(res) {
+      let audioId = this.audioId;
+      this.audio.currentTime = res.target.currentTime;
+      this.playValue = (this.audio.currentTime / this.audio.maxTime) * 100;
+      if (this.type == "audioLine") {
+        if (!this.isClick && this.audio.currentTime * 1000 > this.ed) {
+          this.$refs[audioId].pause();
+          this.$emit("emptyEd");
+        }
+      } else {
+        if (this.hideSlider) {
+          if (this.audio.currentTime * 1000 + 500 > this.ed) {
+            this.$refs[audioId].pause();
+          }
+        }
+      }
+    },
+    onTimeupdateTime(res, playFlag) {
+      if (!res && res !== 0) return;
+      let audioId = this.audioId;
+      this.$refs[audioId].currentTime = res;
+      this.playValue = (res / this.audio.maxTime) * 100;
+      if (playFlag) {
+        let audio = document.getElementsByTagName("audio");
+        audio.forEach((item) => {
+          if (item.id !== audioId) {
+            item.pause();
+          }
+        });
+        this.$refs[audioId].play();
+      }
+    },
+    // 将整数转换成 时:分:秒的格式
+    realFormatSecond(value) {
+      let theTime = parseInt(value); // 秒
+      let theTime1 = 0; // 分
+      let theTime2 = 0; // 小时
+      if (theTime > 60) {
+        theTime1 = parseInt(theTime / 60);
+        theTime = parseInt(theTime % 60);
+        if (theTime1 > 60) {
+          theTime2 = parseInt(theTime1 / 60);
+          theTime1 = parseInt(theTime1 % 60);
+        }
+      }
+      let result = String(parseInt(theTime));
+      if (result < 10) {
+        result = "0" + result;
+      }
+      if (theTime1 > 0) {
+        result = String(parseInt(theTime1)) + ":" + result;
+        if (theTime1 < 10) {
+          result = "0" + result;
+        }
+      } else {
+        result = "00:" + result;
+      }
+      if (theTime2 > 0) {
+        result = String(parseInt(theTime2)) + ":" + result;
+        if (theTime2 < 10) {
+          result = "0" + result;
+        }
+      } else {
+        // result = "00:" + result;
+      }
+      return result;
+    },
+    handleClickAudio(){
+        this.mp3ListShow = !this.mp3ListShow
+    },
+    handleRepeatAudio(){
+        this.isRepeatAudio = !this.isRepeatAudio
+    },
+    handleSelectAudio(index){
+        this.activeIndex = index
+        this.PlayAudio()
+    },
+    // 下载
+    download() {
+      let userInfor = JSON.parse(getToken());
+      let UserCode = "",
+        UserType = "",
+        SessionID = "";
+      if (userInfor) {
+        UserCode = userInfor.user_code;
+        UserType = userInfor.user_type;
+        SessionID = userInfor.session_id;
+      }
+      let FileID = this.mp3List[this.activeIndex].file_id
+      let data = {
+        SessionID,
+        UserCode,
+        UserType,
+        FileID,
+      };
+      location.href =
+        process.env.VUE_APP_BASE_API +
+        `/GCLSFileServer/WebFileDownload?UserCode=${data.UserCode}&UserType=${data.UserType}&SessionID=${data.SessionID}&FileID=${data.FileID}`;
+    },
+    handleActiveIndex(type){
+        if(type=='-'){
+            if(this.activeIndex!=0){
+                this.activeIndex -- 
+            }
+        }else{
+            if(this.activeIndex!=this.mp3List.length-1){
+                this.activeIndex ++
+            }
+        }
+    }
+  },
+  // 生命周期-创建之前
+  beforeCreated() {},
+  // 生命周期-更新之前
+  beforUpdate() {},
+  // 生命周期-销毁之前
+  beforeDestory() {},
+  // 生命周期-销毁完成
+  destoryed() {},
+};
+</script>
+<style lang="scss" scoped>
+/* @import url(); 引入css类 */
+.AudioNNPE {
+  width: 100%;
+  .audioLine {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    background: #ffffff;
+    box-sizing: border-box;
+    border-radius: 8px;
+    .playBox {
+      width: 24px;
+      height: 24px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      margin-right: 16px;
+      cursor: pointer;
+    }
+    .play {
+      width: 24px;
+      height: 24px;
+      cursor: pointer;
+      display: block;
+      &.playBtn {
+        background: url("../../../assets/common/pause-24-normal-red.png")
+          no-repeat left top;
+        background-size: 100% 100%;
+      }
+      &.pauseBtn {
+        background: url("../../../assets/common/play-24-normal-red.png")
+          no-repeat left top;
+        background-size: 100% 100%;
+      }
+    }
+    .audioName {
+      width: 24px;
+      margin-right: 16px;
+    }
+  }
+  .loadBtn {
+    background: url("../../../assets/common/loading-red.png") no-repeat left
+      top;
+    background-size: 100% 100%;
+  }
+  .go-start {
+    width: 24px;
+    height: 24px;
+    margin-right: 16px;
+    cursor: pointer;
+    display: block;
+    background: url("../../../assets/common/go-start.png") no-repeat left top;
+    background-size: 100% 100%;
+    &.disabled {
+      background: url("../../../assets/common/go-start-disabled.png")
+        no-repeat left top;
+      background-size: 100% 100%;
+      cursor: not-allowed;
+    }
+  }
+  .go-end {
+    width: 24px;
+    height: 24px;
+    margin-right: 16px;
+    cursor: pointer;
+    display: block;
+    background: url("../../../assets/common/go-end.png") no-repeat left top;
+    background-size: 100% 100%;
+    &.disabled {
+      background: url("../../../assets/common/go-end-disabled.png") no-repeat
+        left top;
+      background-size: 100% 100%;
+      cursor: not-allowed;
+    }
+  }
+  .play-mode {
+    width: 24px;
+    height: 24px;
+    margin-right: 16px;
+    cursor: pointer;
+    display: block;
+    &.order {
+      background: url("../../../assets/common/auto-24-disable-black.png")
+        no-repeat left top;
+      background-size: 100% 100%;
+    }
+    &.roll {
+      background: url("../../../assets/common/Repeat-24-normal-red.png")
+        no-repeat left top;
+      background-size: 100% 100%;
+    }
+  }
+  .time-box{
+      min-width: 60px;
+      text-align: right;
+      margin-right: 8px;
+  }
+  .common-btn {
+    width: 40px;
+    height: 40px;
+    margin: 0 8px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 8px;
+    position: relative;
+    cursor: pointer;
+    &.audio-btn.active {
+      background: #eeeeee;
+    }
+    > img {
+      width: 24px;
+      height: 24px;
+    }
+    .audioList{
+        position: absolute;
+        top: 63px;
+        left: -40px;
+        width: 120px;
+        max-height: 280px;
+        overflow: auto;
+        background: #FFFFFF;
+        box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.1);
+        border-radius: 8px;
+        z-index: 1;
+        li{
+            display: flex;
+            align-items: center;
+            padding: 8px 16px;
+            width: 100%;
+            :nth-child(1){
+                width: 24px;
+                color: #000000;
+                font-size: 16px;
+                line-height: 24px;
+            }
+            :nth-child(2){
+                color: rgba(0, 0, 0, 0.4);
+                font-size: 16px;
+                line-height: 24px;
+                flex: 1;
+                text-align: right;
+                margin: 0;
+            }
+            &:hover,&.active{
+                background: #EEEEEE;
+            }
+        }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.AudioNNPE {
+  .el-slider__button-wrapper {
+    position: relative;
+    z-index: 0;
+  }
+  .el-slider__button {
+    width: 8px;
+    height: 8px;
+    top: 12px;
+    position: absolute;
+  }
+  .el-slider__runway {
+    margin: 0;
+    padding: 0;
+    background: #e5e5e5;
+    border-radius: 0px;
+    height: 2px;
+  }
+  .el-slider {
+    position: relative;
+  }
+  .el-slider__bar {
+    height: 2px;
+    background: #DE4444;
+  }
+  .el-slider__button {
+    background: #DE4444;
+    border: none;
+  }
+}
+</style>

+ 2 - 1
src/components/inputModules/common/Catalog.vue

@@ -15,6 +15,7 @@
             onlySameLevelCanDrag
             ref="table"
             resize
+            v-if="treeData.list.length>0"
         >
             <template #selection="{ row }">{{ row.name }}</template>
         </dragTreeTable>
@@ -135,7 +136,7 @@ export default {
             getContent(MethodName, data).then(
                 (res) => {
                     this.handleData(res)
-                    this.treeData.lists = res.nodes
+                    this.treeData.lists = res.nodes?res.nodes:[]
                 }
             )
         },

+ 8 - 4
src/components/inputModules/common/HeaderOne.vue

@@ -5,10 +5,10 @@
         <img src="../../../assets/textBookDetail/Frame3.png" alt="" />
       </span>
       <span class="arrows" v-if="title"> > </span>
-      <span class="text" @click="gohome">{{ title }}</span>
+      <span class="text" @click="back">{{ title }}</span>
       <!-- <span class="text" v-if="type"> TEXTBOOK </span> -->
-      <span class="arrows" v-if="text"> > </span>
-      <span class="text" v-if="text">{{ name }}</span>
+      <span class="arrows" v-if="name"> > </span>
+      <span class="text" v-if="name">{{ name }}</span>
     </div>
     <div>
       <!-- <div :class="type ? 'Headseek' : 'seek'" @keydown="keyDownSeekData">
@@ -58,9 +58,13 @@ export default {
   },
   //方法集合
   methods: {
+    back() {
+      this.name?this.$router.go(-1):'';
+    },
     // 返回首页
     gohome() {
-      this.$router.push('/');
+        window.location.href='/GCLS-LC/#/EnterSys'
+    //   this.$router.push('/');
     },
     keyDownSeekData(e) {
       if (e.keyCode == 13) {

+ 212 - 199
src/router/index.js

@@ -30,219 +30,232 @@ Vue.use(Router)
  * all roles can be accessed
  */
 export const constantRoutes = [{
-  path: '/404',
-  component: () =>
-    import('@/views/404'),
-  hidden: true
-},
-{
-  path: '/login',
-  component: () =>
-    import('@/views/login'),
-  hidden: true
-},
-{
-  path: '/EnterSys',
-  beforeEnter: (to, from, next) => {
-    let loadingInstance = Loading.service({
-      text: '跳转中...'
-    });
-    let config = getConfig();
-    if (config) {
-      let configObj = JSON.parse(config);
-      let path = handleSysType(configObj.sys_type, 'home');
-      if (path) {
-        loadingInstance.close();
-        if (configObj.sys_type == 'GCLS') {
-          next(path);
-        } else {
-          window.location.href = path
+        path: '/404',
+        component: () =>
+            import ('@/views/404'),
+        hidden: true
+    },
+    {
+        path: '/login',
+        component: () =>
+            import ('@/views/login'),
+        hidden: true
+    },
+    {
+        path: '/EnterSys',
+        beforeEnter: (to, from, next) => {
+            let loadingInstance = Loading.service({
+                text: '跳转中...'
+            });
+            let config = getConfig();
+            if (config) {
+                let configObj = JSON.parse(config);
+                let path = handleSysType(configObj.sys_type, 'home');
+                if (path) {
+                    loadingInstance.close();
+                    if (configObj.sys_type == 'GCLS') {
+                        next(path);
+                    } else {
+                        window.location.href = path
+                    }
+                } else {
+                    loadingInstance.close();
+                    Message({
+                        message: '此路径不存在',
+                        type: 'error',
+                        showClose: true,
+                        duration: 0
+                    })
+                }
+            }
         }
-      } else {
-        loadingInstance.close();
-        Message({
-          message: '此路径不存在',
-          type: 'error',
-          showClose: true,
-          duration: 0
-        })
-      }
-    }
-  }
-},
-// {
-//   path: '/',
-//   redirect: '/EnterSys',
-//   hidden: true
-// },
-{
-  path: '/input',
-  component: () =>
-    import('@/views/input'),
-  hidden: true
-},
-{
-  path: '/input2',
-  component: () =>
-    import('@/views/input2'),
-  hidden: true
-},
-{
-  path: '/input3',
-  component: () =>
-    import('@/views/input3'),
-  hidden: true
-},
-{
-  path: '/',
-  component: () =>
-    import('@/views/courseList'),
+    },
+    // {
+    //   path: '/',
+    //   redirect: '/EnterSys',
+    //   hidden: true
+    // },
+    {
+        path: '/input',
+        component: () =>
+            import ('@/views/input'),
+        hidden: true
+    },
+    {
+        path: '/input2',
+        component: () =>
+            import ('@/views/input2'),
+        hidden: true
+    },
+    {
+        path: '/input3',
+        component: () =>
+            import ('@/views/input3'),
+        hidden: true
+    },
+    {
+        path: '/',
+        component: () =>
+            import ('@/views/courseList'),
 
-},
-{
-  path: '/preview',
-  component: () =>
-    import('@/views/preview')
-},
-{
-  path: '/login',
-  component: () =>
-    import('@/views/login')
-},
-{
-  path: '/courseView',
-  component: () =>
-    import('@/views/courseView')
-},
-{
-  path: '/bookView',
-  component: () =>
-    import('@/views/bookView')
-},
-{
-  path: '/GoodsDetail',
-  beforeEnter: (to, from, next) => {
-    let loadingInstance = Loading.service({
-      text: '跳转中...'
-    });
-    let config = getConfig();
-    if (config) {
-      let configObj = JSON.parse(config);
-      let path = handleSysType(configObj.sys_type, 'goods');
-      if (path) {
-        loadingInstance.close();
-        if (configObj.sys_type == 'GCLS') {
-          next(path);
-        } else {
-          if (configObj.sys_type == 'NPC' || configObj.sys_type == 'NNPE') {
-            if (path.indexOf('/curGoodsDetail') > -1) {
-              next(path);
-            } else {
-              window.location.href = path
-            }
-          } else {
-            window.location.href = path
-          }
+    },
+    {
+        path: '/preview',
+        component: () =>
+            import ('@/views/preview')
+    },
+    {
+        path: '/login',
+        component: () =>
+            import ('@/views/login')
+    },
+    {
+        path: '/courseView',
+        component: () =>
+            import ('@/views/courseView')
+    },
+    {
+        path: '/bookView',
+        component: () =>
+            import ('@/views/bookView')
+    },
+    {
+        path: '/GoodsDetail',
+        beforeEnter: (to, from, next) => {
+            let loadingInstance = Loading.service({
+                text: '跳转中...'
+            });
+            let config = getConfig();
+            if (config) {
+                let configObj = JSON.parse(config);
+                let path = handleSysType(configObj.sys_type, 'goods');
+                if (path) {
+                    loadingInstance.close();
+                    if (configObj.sys_type == 'GCLS') {
+                        next(path);
+                    } else {
+                        if (configObj.sys_type == 'NPC' || configObj.sys_type == 'NNPE') {
+                            if (path.indexOf('/curGoodsDetail') > -1) {
+                                next(path);
+                            } else {
+                                window.location.href = path
+                            }
+                        } else {
+                            window.location.href = path
+                        }
 
+                    }
+                } else {
+                    loadingInstance.close();
+                    Message({
+                        message: '此路径不存在',
+                        type: 'error',
+                        showClose: true,
+                        duration: 0
+                    })
+                }
+            }
         }
-      } else {
-        loadingInstance.close();
-        Message({
-          message: '此路径不存在',
-          type: 'error',
-          showClose: true,
-          duration: 0
-        })
-      }
-    }
-  }
-},
-{
-  path: '/curGoodsDetail',
-  component: () =>
-    import('@/views/TextbookDetail')
-},
-{
-  path: '/discountCodeList',
-  component: () =>
-    import('@/views/discountCodeList')
-},
-{
-  path: '/adultInput',
-  component: () =>
-    import('@/views/adultInput')
-},
-{
-  path: '/adultInput2',
-  component: () =>
-    import('@/views/adultInput2')
-},
-{
-  path: "/BookBrowsing",
-  name: "BookBrowsing",
-  component: () =>
-    import('@/views/BookView2')
-},
-// 404 page must be placed at the end !!!
-{ path: '*', redirect: '/', hidden: true }
+    },
+    {
+        path: '/curGoodsDetail',
+        component: () =>
+            import ('@/views/TextbookDetail')
+    },
+    {
+        path: '/discountCodeList',
+        component: () =>
+            import ('@/views/discountCodeList')
+    },
+    {
+        path: '/adultInput',
+        component: () =>
+            import ('@/views/adultInput')
+    },
+    {
+        path: '/adultInput2',
+        component: () =>
+            import ('@/views/adultInput2')
+    },
+    {
+        path: "/BookBrowsing",
+        name: "BookBrowsing",
+        component: () =>
+            import ('@/views/BookView2')
+    },
+    {
+        path: "/TextbookDetailPdf",
+        name: "TextbookDetailPdf",
+        component: () =>
+            import ('@/views/textbook-detail/TextbookDetailPdf')
+    },
+    {
+        path: "/TextbookDetailVideo",
+        name: "TextbookDetailVideo",
+        component: () =>
+            import ('@/views/textbook-detail/TextbookDetailVideo')
+    },
+
+    // 404 page must be placed at the end !!!
+    { path: '*', redirect: '/', hidden: true }
 ]
 
 const createRouter = () =>
-  new Router({
-    // mode: 'history', // require service support
-    scrollBehavior: () => ({ y: 0 }),
-    routes: constantRoutes
-  })
+    new Router({
+        // mode: 'history', // require service support
+        scrollBehavior: () => ({ y: 0 }),
+        routes: constantRoutes
+    })
 
 const router = createRouter()
 
 // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
 export function resetRouter() {
-  const newRouter = createRouter()
-  router.matcher = newRouter.matcher // reset router
+    const newRouter = createRouter()
+    router.matcher = newRouter.matcher // reset router
 }
 export function handleSysType(sys_type, path_type) {
-  let path = '';
-  let csArr = window.location.href.split('?');
-  let cs = csArr[1];
-  switch (sys_type) {
-    case 'GCLS':
-      console.log('全球汉语教学平台')
-      if (path_type == 'home') {
-        path = '/';
-      } else if (path_type == 'goods') {
-        path = '/curGoodsDetail?' + cs
-      }
-      break;
-    case 'NPC':
-      if (path_type == 'home') {
-        path = '/GCLS-Book-Component-NPC/#/EnterSys';
-      } else if (path_type == 'goods') {
-        //path = '/GCLS-Book-Component-NPC/#/GoodsDetail?' + cs
-        path = '/curGoodsDetail?' + cs
-      }
-      break;
-    case 'NNPE':
-      if (path_type == 'home') {
-        path = '/GCLS-Book-Component-NNPE/#/EnterSys';
-      } else if (path_type == 'goods') {
-        //path = '/GCLS-Book-Component-NNPE/#/GoodsDetail?' + cs;
-        path = '/curGoodsDetail?' + cs
-      }
-      break;
-    case 'AILP':
-      console.log('课后三点半')
-      if (path_type == 'home') {
-        path = '/GCLS-Book-AILP/#/EnterSys';
-      } else if (path_type == 'goods') {
-        path = '/GCLS-Book-AILP/#/GoodsDetail?' + cs;
-      }
-      break;
-    default:
-      path = '';
-      break;
-  }
-  return path;
+    let path = '';
+    let csArr = window.location.href.split('?');
+    let cs = csArr[1];
+    switch (sys_type) {
+        case 'GCLS':
+            console.log('全球汉语教学平台')
+            if (path_type == 'home') {
+                path = '/';
+            } else if (path_type == 'goods') {
+                path = '/curGoodsDetail?' + cs
+            }
+            break;
+        case 'NPC':
+            if (path_type == 'home') {
+                path = '/GCLS-Book-Component-NPC/#/EnterSys';
+            } else if (path_type == 'goods') {
+                //path = '/GCLS-Book-Component-NPC/#/GoodsDetail?' + cs
+                path = '/curGoodsDetail?' + cs
+            }
+            break;
+        case 'NNPE':
+            if (path_type == 'home') {
+                path = '/GCLS-Book-Component-NNPE/#/EnterSys';
+            } else if (path_type == 'goods') {
+                //path = '/GCLS-Book-Component-NNPE/#/GoodsDetail?' + cs;
+                path = '/curGoodsDetail?' + cs
+            }
+            break;
+        case 'AILP':
+            console.log('课后三点半')
+            if (path_type == 'home') {
+                path = '/GCLS-Book-AILP/#/EnterSys';
+            } else if (path_type == 'goods') {
+                path = '/GCLS-Book-AILP/#/GoodsDetail?' + cs;
+            }
+            break;
+        default:
+            path = '';
+            break;
+    }
+    return path;
 }
 
 export default router

+ 349 - 23
src/views/TextbookDetail.vue

@@ -6,6 +6,7 @@
       <Header />
       <div class="shade"></div>
     </div>
+    <HeaderOne text="123" title="教材详情" name="" />
     <div class="main" v-loading="loading">
       <div class="bookDetail" v-if="detailSHow">
         <div class="rightUp">
@@ -132,12 +133,13 @@
             <!-- 目录 -->{{ $t("Key612") }}
           </div>
           <!-- 资源 -->
-          <!-- <div
+          <div
             @click="SelectShowEvent('2')"
             :class="SelectShow == '1' ? '' : 'select'"
+            v-if="fileListVideo.length>0||fileListAudio.length>0||fileListOtheraudio.length>0||fileListDoc.length>0"
           >
             {{ $t("Key613") }}
-          </div> -->
+          </div>
         </div>
       </div>
       <div v-if="SelectShow == '1'" class="Catalogue">
@@ -154,6 +156,77 @@
           <span> 文件名 </span>
           <img src="../assets/textBookDetail/upload.png" alt="" />
         </div> -->
+        <div class="resource-content" v-if="fileListVideo.length>0">
+        <h2 class="video-title">视频资源</h2>
+        <ul class="video-list">
+          <li v-for="(item,index) in fileListVideo" :key="index" @click="handleJumpVideo(index)">
+            <div class="video-img" :style="{'background':'url('+item.preview_image_file_url+') no-repeat','background-size':'cover'}">
+              <img class="video" />
+              <img src="../assets/common/play-one.png" class="play-one" />
+            </div>
+            <p class="video-name">{{item.file_name}}</p>
+          </li>
+        </ul>
+      </div>
+      <div class="resource-content" v-if="fileListAudio.length>0||fileListOtheraudio.length>0">
+        <h2 class="video-title">音频资源</h2>
+        <div class="audio-content" v-if="fileListAudio.length>0">
+          <p class="audio-type">课文资源</p>
+          <div class="audio-line-box">
+            <AudioLine 
+                :audioId="'fileListAudio'"
+                :mp3List="fileListAudio"
+                type="audioLine"
+                ref="audioLine"
+            />
+          </div>
+        </div>
+        <div class="audio-content" v-if="fileListOtheraudio.length>0">
+          <p class="audio-type">自学音频</p>
+          <div class="audio-line-box">
+            <AudioLine 
+                :audioId="'fileListOtheraudio'"
+                :mp3List="fileListOtheraudio"
+                type="audioLine"
+                ref="audioLine"
+            />
+          </div>
+        </div>
+        <div class="audio-content">
+          <p class="audio-type">资源下载</p>
+          <div class="download">
+            <div class="book-open" @click="handleDownloadAudio">
+              <img
+                src="../assets/common/download.png"
+                class="book-open-img"
+              />
+              <span class="book-open-text">音频</span>
+            </div>
+            <!-- <div class="book-open">
+              <img
+                src="../assets/common/download.png"
+                class="book-open-img"
+              />
+              <span class="book-open-text">互动课件</span>
+            </div> -->
+          </div>
+        </div>
+      </div>
+        <div class="resource-content" v-if="fileListDoc.length>0">
+            <h2 class="video-title">试读PDF</h2>
+            <ul class="PDF-list">
+                <li v-for="(item,index) in fileListDoc" :key="index" @click="handleJumpPdf(index)">
+                    <b>{{index+1}}.</b>
+                    <p class="PDF-name">{{item.file_name}}</p>
+                    <span>{{item.fileSize}}</span>
+                    <img
+                        src="../assets/common/download.png"
+                        class="book-open-img"
+                        @click="handleDownload(item.file_id)"
+                    />
+                </li>
+            </ul>
+        </div>
       </div>
     </div>
     <!-- 商品详情 -->
@@ -192,11 +265,14 @@
 //例如:import 《组件名称》from ‘《组件路径》';
 import Header from "@/components/inputModules/common/Header";
 import HeaderOne from "@/components/inputModules/common/HeaderOne";
-import { TextbookAPI, LearnWebSI } from "@/api/ajax";
+import { TextbookAPI, LearnWebSI, getContent, getContentFile } from "@/api/ajax";
 import Confirmorder from "@/components/pyment/Confirmorder";
 import Payment from "@/components/pyment/Payment";
 import BookView from "@/views/bookView"; // 教材预览
 import { updateWordPack } from "@/utils/i18n";
+import AudioLine from "@/components/inputModules/common/AudioLine";
+import { getToken } from "@/utils/auth";
+import { Base64 } from 'js-base64';
 export default {
   //import引入的组件需要注入到对象中才能使用
   components: {
@@ -205,6 +281,7 @@ export default {
     Confirmorder,
     Payment,
     BookView,
+    AudioLine,
   },
   props: {},
   data() {
@@ -223,6 +300,10 @@ export default {
       detailSHow: true, // 除教材预览外其他内容是否显示
       bookIsBuy: "false", // 教材是否已购买
       isData: false,
+      fileListVideo: [], // 教材资源视频数组
+      fileListAudio: [], // 教材资源视频数组
+      fileListOtheraudio: [],
+      fileListDoc: [], // 教材资源视频数组
     };
   },
   //计算属性 类似于data概念
@@ -354,6 +435,122 @@ export default {
         });
       this.handleIsBuy();
       this.handleIsEnshrine();
+      this.getBookSource()
+    },
+    // 教材资源
+    getBookSource(){
+        let MethodNames = "book-resource_manager-GetBookResourceList";
+        let datas = {
+            book_id: this.TextBookId,
+        };
+        getContent(MethodNames, datas)
+            .then((res) => {
+                if(res.status==1){ 
+                    this.fileListVideo = res.video_list
+                    this.fileListAudio = res.audio_list
+                    this.fileListOtheraudio = res.otheraudio_list
+                    this.fileListDoc = res.doc_list
+                    this.fileListDoc.forEach(item => {
+                        if(item.file_size>1024*1024){
+                            if(item.file_size/1024/1024/1024>1){
+                                item.fileSize = (item.file_size/1024/1024/1024).toFixed(2)+'GB'
+                            }else{
+                                item.fileSize = (item.file_size/1024/1024).toFixed(2)+'MB'
+                            }
+                        }else{
+                            item.fileSize = (item.file_size/1024).toFixed(2)+'KB'
+                        }
+                    });
+                }   
+        })
+    },
+    // 打包下载全部音频
+    handleDownloadAudio(){
+      let _this = this;
+      _this.loading = true;
+      // 拿到当前课的所有文件id
+      let userInfor = JSON.parse(getToken());
+      let UserCode = "",
+        UserType = "",
+        SessionID = "";
+      if (userInfor) {
+        UserCode = userInfor.user_code;
+        UserType = userInfor.user_type;
+        SessionID = userInfor.session_id;
+      }
+      let FileID = null;
+      let data = {
+        SessionID,
+        UserCode,
+        UserType,
+        FileID,
+      };
+      let arr = [];
+      this.fileListAudio.forEach(item => {
+        arr.push(item.file_id)
+      });
+      this.fileListOtheraudio.forEach(item => {
+        arr.push(item.file_id)
+      });
+      let MethodName = "file_store_manager-StartCreateFileCompressPack";
+      getContentFile(MethodName, {
+        file_id_list: arr,
+      })
+        .then((res) => {
+          let MethodName2 = "file_store_manager-GetFileCompressTaskProgress";
+          let timer = setInterval(() => {
+            getContentFile(MethodName2, {
+              file_compress_task_id: res.file_compress_task_id,
+            })
+              .then((res) => {
+                if (res.is_finish == 'true') {
+                  data.FileID = res.compress_pack_file_id;
+                  clearInterval(timer);
+                  timer = null;
+                  location.href =
+                    process.env.VUE_APP_BASE_API +
+                    `/GCLSFileServer/WebFileDownload?UserCode=${data.UserCode}&UserType=${data.UserType}&SessionID=${data.SessionID}&FileID=${data.FileID}`;
+                  _this.loading = false;
+                }
+              })
+              .catch((res) => {
+                this.loading = false;
+              });
+          }, 1000);
+        })
+        .catch((res) => {
+          this.loading = false;
+        });
+    },
+    // 下载单个文件
+    handleDownload(fileId){
+      let userInfor = JSON.parse(getToken());
+      let UserCode = "",
+        UserType = "",
+        SessionID = "";
+      if (userInfor) {
+        UserCode = userInfor.user_code;
+        UserType = userInfor.user_type;
+        SessionID = userInfor.session_id;
+      }
+      let FileID = fileId;
+      let data = {
+        SessionID,
+        UserCode,
+        UserType,
+        FileID,
+      };
+      location.href =
+        process.env.VUE_APP_BASE_API +
+        `/GCLSFileServer/WebFileDownload?UserCode=${data.UserCode}&UserType=${data.UserType}&SessionID=${data.SessionID}&FileID=${data.FileID}`;
+    },
+    // 跳转预览PDF
+    handleJumpPdf(index){
+        this.$router.push("/TextbookDetailPdf?id=" + this.TextBookId+'&url='+Base64.encodeURL(this.fileListDoc[index].file_url)+'&invok_module='+this.$route.query.invok_module+'&fileId='+Base64.encodeURL(this.fileListDoc[index].file_id));
+    },
+    // 跳转预览视频
+    handleJumpVideo(index){
+        this.$router.push("/TextbookDetailVideo?id=" + this.TextBookId+'&invok_module='+this.$route.query.invok_module+'&activeIndex='+Base64.encodeURL(index));
     },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
@@ -752,34 +949,163 @@ export default {
     .Resources {
       margin: 24px auto;
       width: 1240px;
-      height: 710px;
-      background: #ffffff;
-      display: flex;
+      min-height: 710px;
+    //   background: #ffffff;
+    //   display: flex;
       box-sizing: border-box;
-      padding: 20px 24px;
+      padding: 20px 0;
       div {
-        height: 40px;
-        margin: 12px 8px;
-        border: 1px solid rgba(44, 44, 44, 0.15);
-        border-radius: 4px;
-        padding: 0 10px;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        cursor: pointer;
+        // height: 40px;
+        // margin: 12px 8px;
+        // border: 1px solid rgba(44, 44, 44, 0.15);
+        // border-radius: 4px;
+        // padding: 0 10px;
+        // display: flex;
+        // justify-content: center;
+        // align-items: center;
+        // cursor: pointer;
         img {
           width: 24px;
-          margin: 0 10px;
-        }
-        span {
-          width: 182px;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
+          margin-right: 10px;
         }
       }
     }
   }
+  .resource-content {
+      width: 100%;
+      margin: 0 auto;
+      box-sizing: border-box;
+      padding: 26px 24px 8px;
+      background: #ffffff;
+      border-radius: 8px;
+      margin-bottom: 24px;
+      .video-title {
+        font-size: 24px;
+        line-height: 32px;
+        font-weight: 700;
+        margin-bottom: 40px;
+        margin-top: 0;
+      }
+      .video-list {
+        padding: 0 36px;
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: flex-start;
+        list-style: none;
+        > li {
+          margin: 0 12px 16px 12px;
+          cursor: pointer;
+          .video-img {
+            // background: #ff9900;
+            position: relative;
+            width: 256px;
+            height: 144px;
+            border-radius: 8px;
+            margin-bottom: 8px;
+            overflow: hidden;
+            .video-bg {
+              width: 256px;
+              height: 144px;
+              border-radius: 8px;
+            }
+            .play-one {
+              position: absolute;
+              left: 108px;
+              top: 52px;
+              width: 40px;
+              height: 40px;
+              display: block;
+              margin: 0;
+            }
+          }
+          .video-name {
+            font-size: 16px;
+            line-height: 150%;
+            color: #000000;
+            word-break: break-all;
+            display: -webkit-box;
+            -webkit-box-orient: vertical;
+            -webkit-line-clamp: 2;
+            text-overflow: ellipsis;
+            overflow: hidden;
+          }
+        }
+      }
+      .PDF-list{
+          width: 1096px;
+          margin: 0 auto;
+          padding-bottom: 90px;
+          li{
+              border: 1px solid rgba(0, 0, 0, 0.1);
+              box-sizing: border-box;
+              border-radius: 8px;
+              display: flex;
+              padding: 8px 12px;
+              align-items: center;
+              margin-bottom: 8px;
+              b{
+                  width: 24px;
+                  font-size: 16px;
+                  line-height: 24px;
+                  font-weight: normal;
+                  margin-right: 16px;
+              }
+              p{
+                  margin: 0;
+                  width: 920px;
+                  cursor: pointer;
+                  font-size: 16px;
+                  line-height: 24px;
+              }
+              span{
+                  width: 80px;
+                  text-align: right;
+              }
+              img{
+                  width: 16px;
+                  margin-left: 16px;
+                  cursor: pointer;
+              }
+          }
+      }
+      .audio-content {
+        padding: 0 28px;
+        margin: 0 auto 24px auto;
+        width: 1152px;
+        .audio-type {
+          margin-bottom: 10px;
+        }
+        .download {
+          display: flex;
+          justify-content: flex-start;
+          align-items: center;
+          .book-open {
+            width: fit-content;
+            margin-right: 16px;
+            border: 1px solid rgba(0, 0, 0, 0.1);
+            box-sizing: border-box;
+            border-radius: 8px;
+            padding: 8px 16px;
+            display: flex;
+            align-items: center;
+            cursor: pointer;
+            .book-open-text{
+                line-height: 24px;
+            }
+          }
+        }
+      }
+      .audio-line-box {
+        width: 100%;
+        height: 56px;
+        box-sizing: border-box;
+        padding: 7px 12px;
+        background: #ffffff;
+        border: 1px solid rgba(0, 0, 0, 0.1);
+        box-sizing: border-box;
+        border-radius: 8px;
+      }
+    }
 }
 </style>
 <style lang="scss">

+ 1 - 1
src/views/bookView.vue

@@ -128,7 +128,7 @@ export default {
   },
   methods: {
     changeTreeData(val) {
-      this.FatherTreeData = JSON.parse(JSON.stringify(val));
+      this.FatherTreeData = val!=undefined?JSON.parse(JSON.stringify(val)):null;
     },
     changeId(id, name, free) {
       // if (

+ 377 - 0
src/views/textbook-detail/TextbookDetailPdf.vue

@@ -0,0 +1,377 @@
+<template>
+  <!-- 预览 -->
+  <div class="tarcer-dev-Preview" v-loading="loading" v-if="isData">
+    <Header />
+
+    <HeaderOne title="教材详情" name="试读PDF" />
+    <div class="main" v-if="data">
+      <div class="flassify">
+        <div class="text">
+          <p class="p1">{{ data.name }}</p>
+          <p class="p2">
+            <span >
+                {{data.author}}
+            </span>
+          </p>
+        </div>
+        <div class="pay_collect">
+          <div class="download">
+            <img @click="download" src="../../assets/common/download.png" alt="" />
+            <!-- <span>DOWNLOAD</span> -->
+          </div>
+          <div class="collect">
+            <img
+              @click="changeCollect"
+              v-show="!data.isFavorite"
+              src="../../assets/textBookDetail/collect4.png"
+              alt=""
+            />
+            <img
+              @click="changeCollect"
+              v-show="data.isFavorite"
+              src="../../assets/textBookDetail/enshrine1.png"
+              alt=""
+            />
+          </div>
+        </div>
+      </div>
+      <div v-if="attachment">
+        <pdf
+          ref="pdf"
+          :src="attachment"
+          v-for="i in numPages"
+          :key="i"
+          :page="i"
+        >
+          {{ i / numPages }}
+        </pdf>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import Header from "@/components/inputModules/common/Header";
+import HeaderOne from "@/components/inputModules/common/HeaderOne";
+import pdf from "vue-pdf";
+import { updateWordPack } from "@/utils/i18n";
+import { getToken } from "@/utils/auth";
+import { Base64 } from 'js-base64';
+
+import {
+  TextbookAPI,
+  LearnWebSI,
+} from "@/api/ajax";
+export default {
+  name: "TextbookDetailPdf",
+  components: {
+    Header,
+    HeaderOne,
+    pdf,
+  },
+  data() {
+    return {
+      numPages: null,
+      isCollect: false,
+      materialId: null,
+      data: null,
+      attachment: null,
+      loading: false,
+      Ispreview: "", // 是不是预览
+      NopymentShow: false, //添加订单弹窗
+      PymentShow: false, //支付订单弹窗
+      orderNumber: null, //订单号
+      IsDownload: false, //是否可以下载
+      allList: null,
+      isData: false,
+    };
+  },
+  computed: {},
+  methods: {
+    // 下载
+    download() {
+      let userInfor = JSON.parse(getToken());
+      let UserCode = "",
+        UserType = "",
+        SessionID = "";
+      if (userInfor) {
+        UserCode = userInfor.user_code;
+        UserType = userInfor.user_type;
+        SessionID = userInfor.session_id;
+      }
+      let FileID = Base64.decode(this.$route.query.fileId)
+      let data = {
+        SessionID,
+        UserCode,
+        UserType,
+        FileID,
+      };
+      location.href =
+        process.env.VUE_APP_BASE_API +
+        `/GCLSFileServer/WebFileDownload?UserCode=${data.UserCode}&UserType=${data.UserType}&SessionID=${data.SessionID}&FileID=${data.FileID}`;
+    },
+    // 获取pdf的页数
+    getNumPages() {
+      this.loading = true;
+      let _this = this;
+      let loadingTask = pdf.createLoadingTask(_this.attachment);
+
+      loadingTask.promise
+        .then((pdf) => {
+          if (_this.data.isPurchased) {
+            _this.numPages = pdf.numPages;
+          } else {
+            _this.numPages = 2;
+          }
+          _this.loading = false;
+        })
+        .catch((err) => {
+          console.error("Pdf Loading failed", err);
+        });
+    },
+    // 修改收藏状态
+    changeCollect() {
+      this.loading = true;
+      if (this.data.isFavorite) {
+        let Mname = "order-collection_manager-CancelMyGoodsCollection";
+        LearnWebSI(Mname, {
+          goods_id_list: [this.materialId],
+          goods_type: 401,
+        })
+          .then((res) => {
+            this.$message({
+              type: "success",
+              message: this.$t("Key396"), //"取消收藏成功",
+            });
+            this.data.isFavorite = false;
+
+            this.loading = false;
+            // this.getdetail();
+          })
+          .catch((res) => {
+            this.loading = false;
+          });
+      } else {
+        let Mname = "order-collection_manager-AddMyCollection";
+        LearnWebSI(Mname, {
+          goods_id: this.materialId,
+          goods_type: 401,
+          goods_name: this.data.name,
+          goods_person_name_desc: this.data.teacher,
+          goods_picture_id: this.data.coverFileId,
+          goods_price: this.data.price,
+        })
+          .then((res) => {
+            this.$message({
+              type: "success",
+              message: this.$t("Key575"), //"收藏成功",
+            });
+            this.data.isFavorite = true;
+
+            this.loading = false;
+            // this.getdetail();
+          })
+          .catch((res) => {
+            this.loading = false;
+          });
+      }
+    },
+    // 获取学习资料详情
+    getdetail() {
+      this.loading = true;
+      this.materialId = this.$route.query.id;
+      let Mname = "book-book_manager-GetBook";
+      // 获取课程详情
+      TextbookAPI(Mname, {
+        id: this.materialId,
+      })
+        .then((res) => {
+          this.data = res;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+        });
+    },
+  },
+  async created() {
+    await updateWordPack({
+      word_key_list: [
+        "Key5",
+        "Key8",
+        "Key9",
+        "Key39",
+        "Key43",
+        "Key52",
+        "Key53",
+        "Key54",
+        "Key55",
+        "Key58",
+        "Key72",
+        "Key94",
+        "Key107",
+        "Key109",
+        "Key214",
+        "Key232",
+        "Key108",
+        "Key396",
+        "Key472",
+        "Key473",
+        "Key474",
+        "Key572",
+        "Key574",
+        "Key575",
+        "Key576",
+      ],
+    });
+    this.isData = true;
+  },
+  mounted() {
+    this.materialId = this.$route.query.id;
+    this.attachment =
+                process.env.VUE_APP_PDF_API + Base64.decode(this.$route.query.url)
+      if (this.materialId) {
+        this.getdetail();
+        this.getNumPages();
+      }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.tarcer-dev-Preview {
+  height: 100%;
+
+  .main {
+    min-height: 543px;
+    background: #f6f6f6;
+    padding-bottom: 20px;
+    padding-top: 30px;
+    position: relative;
+  }
+  .flassify {
+    position: relative;
+    width: 1140px;
+    height: 154px;
+    margin: 0 auto;
+    background-color: #fff;
+    border-radius: 8px;
+    display: flex;
+    justify-content: space-between;
+    // align-items: center;
+    padding: 0 30px;
+    .text {
+      height: 100%;
+      padding-top: 24px;
+      .p1 {
+        font-weight: bold;
+        font-size: 30px;
+        color: #1f2127;
+      }
+      .p2 {
+        margin-top: 8px;
+        margin-bottom: 8px;
+        font-size: 16px;
+        color: #1f2127;
+      }
+    }
+    .pay_collect {
+      // position: absolute;
+      // right: 30px;
+      // bottom: 24px;
+      height: 100%;
+      padding-top: 90px;
+      display: flex;
+      align-content: center;
+      .price {
+        font-weight: bold;
+        font-size: 24px;
+        margin-right: 20px;
+        .price_2 {
+          font-size: 16px;
+        }
+      }
+      .pay {
+        width: 120px;
+        height: 40px;
+        background: #ff9900;
+        border-radius: 4px;
+        color: white;
+        font-weight: 600;
+        font-size: 20px;
+        text-align: center;
+        line-height: 40px;
+        cursor: pointer;
+        margin-right: 20px;
+      }
+      .collect {
+        display: flex;
+        align-items: center;
+        height: 40px;
+
+        font-weight: bold;
+        font-size: 24px;
+        color: #1f2127;
+        img {
+          width: 24px;
+          margin-right: 10px;
+          cursor: pointer;
+        }
+      }
+      .download {
+        height: 40px;
+        margin-right: 20px;
+        display: flex;
+        align-items: center;
+        font-weight: bold;
+        font-size: 24px;
+        color: #1f2127;
+        img {
+          width: 24px;
+          margin-right: 10px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+  .buy {
+    width: 1200px;
+    margin: 24px auto;
+    min-height: 1000px;
+    // filter: blur(8px);
+  }
+  .NObuy {
+    width: 1200px;
+    margin: 24px auto;
+    min-height: 1000px;
+    filter: blur(8px);
+  }
+  .buyBtn {
+    width: 284px;
+    height: 67px;
+    background: #ff9900;
+    border-radius: 8px;
+    text-align: center;
+    line-height: 67px;
+    color: white;
+    font-weight: bold;
+    font-size: 22px;
+    margin: 0 auto;
+    cursor: pointer;
+    position: relative;
+    top: -150px;
+  }
+  .dialogTitle {
+  }
+}
+</style>
+<style lang="scss">
+.tarcer-dev-Preview {
+  .el-dialog__body {
+    padding: 30px 32px;
+  }
+}
+.cui-ribbonTopBars {
+  display: none !important;
+}
+</style>

+ 400 - 0
src/views/textbook-detail/TextbookDetailVideo.vue

@@ -0,0 +1,400 @@
+<template>
+  <!-- 录播间 -->
+  <!-- 
+    v-loading="loading"
+    v-if="data && VideoList"
+   -->
+  <div class="RecordedBroadcast" v-loading="loading" v-if="isData">
+    <Header />
+
+    <div>
+      <HeaderOne
+        title="教材详情" name="视频资源"
+      />
+    </div>
+    <div class="main" v-if="data && VideoList">
+      <div class="main-top">
+        <div>
+          <p class="content1">{{ data.name }}({{ VideoIndex + 1 }})</p>
+          <p class="content2">
+            <!-- Professor Zhang -->
+              <span>
+                {{ data.author }}</span
+              >
+          </p>
+        </div>
+      </div>
+      <!-- 视频和视频列表 -->
+      <div class="videoAndList">
+        <div class="video" v-if="VideoList[VideoIndex]">
+          <!-- <video
+            controls
+            src="https://media.w3.org/2010/05/sintel/trailer.mp4"
+          ></video> -->
+          <video
+            v-if="VideoList[VideoIndex].file_url"
+            :poster="VideoList[VideoIndex].preview_image_file_url"
+            controls
+            :src="VideoList[VideoIndex].file_url"
+            controlslist="nodownload"
+            disablePictureInPicture
+          ></video>
+          <div class="Videofalse" v-else>
+            <img src="../../assets/textBookDetail/Group 3278.png" alt="" />
+            Video Corrupted
+          </div>
+        </div>
+        <div class="List">
+          <div class="title"><!-- 播放列表 -->{{ $t("Key583") }}</div>
+          <div class="playList">
+            <div v-for="(item, i) in VideoList" :key="i" @click="cutVideo(item, i)">
+              <div class="img">
+                <img src="../../assets/common/play-one.png" class="play-one" />
+                <img :src="item.preview_image_file_url" alt="" />
+              </div>
+              <div class="nameAndTime">
+                <p :class="VideoIndex == i ? 'select' : ''">{{ item.file_name }}</p>
+                <p class="time">
+                  <img src="../../assets/textBookDetail/Group 3235.png" alt="" />
+                  <span v-text="changeTime(item.media_duration)"></span>
+                </p>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import Header from "@/components/inputModules/common/Header";
+import HeaderOne from "@/components/inputModules/common/HeaderOne";
+import { getToken } from "@/utils/auth";
+import { updateWordPack } from "@/utils/i18n";
+
+import {
+  TextbookAPI,
+  getContent,
+} from "@/api/ajax";
+export default {
+  name:'TextbookDetailVideo',
+  components: {
+    Header,
+    HeaderOne,
+  },
+  data() {
+    return {
+      activeIndex: null,
+      playlist: [],
+      articleId: null, //查询课程或者专题 文章详情
+      data: null, //课程信息
+      VideoList: [], //播放列表
+      VideoIndex: Number(Base64.decode(this.$route.query.activeIndex)), //当前播放的分集
+      loading: false,
+      isData: false,
+    };
+  },
+  methods: {
+    // 点击视频列表切换视频
+    cutVideo(item, i) {
+      this.VideoIndex = i;
+    },
+    // 处理时间
+    changeTime(s) {
+      //计算分钟
+      //算法:将秒数除以60,然后下舍入,既得到分钟数
+      var h;
+      h = Math.floor(s / 60);
+      //计算秒
+      //算法:取得秒%60的余数,既得到秒数
+      s = s % 60;
+      //将变量转换为字符串
+      h += "";
+      s += "";
+      //如果只有一位数,前面增加一个0
+      h = h.length == 1 ? "0" + h : h;
+      s = s.length == 1 ? "0" + s : s;
+      return h + ":" + s;
+    },
+    // 获取学习资料详情
+    getdetail() {
+      this.loading = true;
+      let Mname = "book-book_manager-GetBook";
+      // 获取课程详情
+      TextbookAPI(Mname, {
+        id: this.articleId,
+      })
+        .then((res) => {
+          this.data = res;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+        });
+    },
+
+    // 教材资源
+    getBookSource(){
+        let MethodNames = "book-resource_manager-GetBookResourceList";
+        let datas = {
+            book_id: this.articleId,
+        };
+        getContent(MethodNames, datas)
+            .then((res) => {
+                if(res.status==1){ 
+                    this.VideoList = res.video_list
+                }   
+        })
+    },
+  },
+  async created() {
+    this.articleId = this.$route.query.id;
+    await updateWordPack({
+      word_key_list: ["Key150", "Key583", "Key584"],
+    });
+    this.getdetail()
+    this.getBookSource()
+    this.isData = true;
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.RecordedBroadcast {
+  background: #f6f6f6;
+  padding-bottom: 130px;
+  .main {
+    // width: 1170px;
+    background: #fff;
+    width: 1200px;
+    margin: 0 auto;
+    .main-top {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 30px;
+      padding: 20px;
+      .content1 {
+        font-weight: bold;
+        font-size: 30px;
+        color: #1f2127;
+      }
+      .content2 {
+        margin-top: 10px;
+        font-size: 16px;
+        color: #1f2127;
+      }
+      .content3 {
+        margin-top: 10px;
+        display: flex;
+        align-items: center;
+        span {
+          margin-left: 10px;
+        }
+      }
+      .price {
+        font-weight: bold;
+        font-size: 30px;
+        color: #1f2127;
+        margin-right: 20px;
+        .price_2 {
+          font-size: 16px;
+        }
+      }
+      button {
+        width: 128px;
+        height: 56px;
+        background: black;
+        font-size: 36px;
+        color: white;
+        border: none;
+        border-radius: 60px;
+        cursor: pointer;
+      }
+    }
+    .priceGet {
+      display: flex;
+      align-items: flex-end;
+      button {
+        width: 115px;
+        height: 40px;
+        background: #ff9900;
+        border-radius: 4px;
+        border: none;
+        outline: none;
+        font-size: 20px;
+      }
+    }
+    .videoAndList {
+      height: 495px;
+      display: flex;
+      .video {
+        width: 880px;
+        height: 100%;
+        position: relative;
+        flex-shrink: 0;
+        video {
+          width: 100%;
+          height: 100%;
+          object-fit: fill; //将视频标签填充整个元素
+          // background: url("../../assets/teacherTrain/Rectangle 1049.png");
+          // // background-size: 100% 100%;
+          // -webkit-background-size: cover;
+          // -moz-background-size: cover;
+          // -o-background-size: cover;
+          // background-size: cover;
+        }
+        .Videofalse {
+          position: absolute;
+          left: 40%;
+          top: 40%;
+          color: #ef3939;
+          background: rgba(255, 234, 234, 0.9);
+          border-radius: 8px;
+          padding: 10px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          img {
+            margin-right: 10px;
+          }
+        }
+      }
+      .List {
+        width: 320px;
+        height: 100%;
+        overflow-y: scroll;
+        background: #212229;
+        .title {
+          padding-top: 16px;
+          line-height: 1;
+          font-weight: bold;
+          font-size: 20px;
+          color: #ffffff;
+          padding-left: 16px;
+        }
+        .playList {
+          > div {
+            display: flex;
+            color: white;
+            margin-top: 18px;
+            > div {
+              margin-left: 16px;
+            }
+            .nameAndTime {
+              p {
+                height: 42px;
+                margin: 0;
+              }
+                .time {
+                margin-top: 6px;
+                height: 17px;
+                img {
+                    width: 10px;
+                    height: 10px;
+                }
+                span {
+                    margin-left: 10px;
+                }
+                }
+            }
+            .img {
+              position: relative;
+              cursor: pointer;
+              font-size: 0;
+              .time {
+                position: absolute;
+                right: 1px;
+                bottom: 1px;
+                font-size: 10px;
+              }
+            }
+            img {
+              width: 112px;
+              height: 63px;
+            }
+            p {
+              font-size: 10px;
+              cursor: pointer;
+            }
+            .select {
+              color: #ff9900;
+            }
+            .play-one {
+              position: absolute;
+              left: 36px;
+              top: 12px;
+              width: 40px;
+              height: 40px;
+              display: block;
+              margin: 0;
+            }
+          }
+        }
+      }
+    }
+  }
+  .courseMessage {
+    width: 960px;
+    margin: 0 auto;
+    // margin-top: 80px;
+    padding: 77px 20px 50px 20px;
+    margin-bottom: 100px;
+    background: #fff;
+    .el-menu.el-menu--horizontal {
+      border-bottom: none;
+    }
+    .description {
+      margin-top: 30px;
+      font-size: 16px;
+      color: #1f2127;
+    }
+    .allDownload {
+      // width: 128px;
+      padding: 0 16px;
+
+      height: 40px;
+      float: right;
+      display: flex;
+      align-items: center;
+      border: 1px solid rgba(44, 44, 44, 0.15);
+      box-sizing: border-box;
+      border-radius: 4px;
+      justify-content: center;
+      cursor: pointer;
+      margin-top: 11px;
+      img {
+        width: 24px;
+        margin-right: 8px;
+      }
+    }
+    .resource {
+      margin-top: 30px;
+      display: flex;
+      flex-wrap: wrap;
+      div {
+        margin: 10px;
+        border: 1px solid rgba(44, 44, 44, 0.15);
+        border-radius: 4px;
+        padding: 10px;
+        margin-left: 10px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        cursor: pointer;
+        img {
+          width: 24px;
+          margin: 0 10px;
+        }
+        span {
+          width: 182px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+      }
+    }
+  }
+}
+</style>