Browse Source

全屏 取词

natasha 1 year ago
parent
commit
3a86c109fd

+ 132 - 0
src/components/common/AudioCompare.vue

@@ -0,0 +1,132 @@
+<!--  -->
+<template>
+  <div class="compara-content">
+    <template v-if="wavblob">
+      <div
+        :class="type == 'full' ? 'compare-box-big' : 'compare-box'"
+        v-if="!isR"
+      >
+        <AudioLine
+          :mp3="url"
+          :getCurTime="getCurTime"
+          :ref="'audioLine' + index"
+          :audioId="'artPraAudioId' + index"
+          :stopAudio="stopAudio"
+          :width="555"
+          :hideSlider="true"
+          :bg="bg"
+          :ed="ed"
+          @handleChangeStopAudio="handleChangeStopAudio"
+          @sentPause="sentPause"
+          @playChange="getPlayStatus"
+          :type="type"
+        />
+      </div>
+      <div :class="type == 'full' ? 'compare-box-big' : 'compare-box'" v-else>
+        <audio-red
+          v-if="sentIndex == index"
+          :mp3="wavblob"
+          :isCompare="true"
+          :themeColor="themeColor"
+          @sentPause="sentPause"
+          @getPlayStatus="getPlayStatus"
+          :type="type"
+        />
+      </div>
+    </template>
+    <template v-else>
+      <!-- <img
+        :src="
+          type == 'full'
+            ? require('../../../assets/NPC/compare-disable-24.png')
+            : require('../../../assets/NPC/compare-disable.png')
+        "
+        :class="[
+          'compare-disable',
+          type == 'full' ? 'compare-disable-big' : '',
+        ]"
+      /> -->
+    </template>
+  </div>
+</template>
+
+<script>
+import AudioLine from "./AudioLine.vue";
+import AudioRed from "./AudioRed.vue";
+export default {
+  components: {
+    AudioLine,
+    AudioRed,
+  },
+  props: [
+    "isRecord",
+    "wavblob",
+    "url",
+    "bg",
+    "ed",
+    "index",
+    "sentIndex",
+    "getCurTime",
+    "sentPause",
+    "stopAudio",
+    "handleChangeStopAudio",
+    "themeColor",
+    "type",
+    "getPlayStatus",
+  ],
+  data() {
+    return {
+      isR: false,
+    };
+  },
+  computed: {},
+  watch: {
+    isRecord: {
+      handler(newVal, oldVal) {
+        if (this.sentIndex == this.index) {
+          this.isR = newVal;
+        }
+      },
+      deep: true,
+    },
+  },
+  //方法集合
+  methods: {},
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.compare-box {
+  width: 16px;
+  height: 16px;
+  margin-left: 8px;
+  &-big {
+    width: 24px;
+    height: 24px;
+    margin-left: 0px;
+  }
+}
+.compare-disable {
+  width: 16px;
+  height: 16px;
+  display: block;
+  margin-left: 8px;
+  &-big {
+    width: 24px;
+    height: 24px;
+    display: block;
+    margin-left: 0px;
+  }
+}
+</style>

+ 126 - 0
src/components/common/AudioRed.vue

@@ -0,0 +1,126 @@
+<!--  -->
+<template>
+  <div v-if="mp3" class="content-voices" @click="handlePlayVoice">
+    <img :src="voiceSrc" :class="type == 'full' ? 'icon-big' : ''" />
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  props: ["seconds", "mp3", "wav", "themeColor", "isCompare", "type"],
+  data() {
+    return {
+      audio: new Audio(),
+      voiceSrc: "",
+      voicePauseSrc: '',
+      voicePlaySrc: '',
+    };
+  },
+  computed: {
+    comparePauseSrc() {
+      
+    },
+    comparePlaySrc() {
+      
+    },
+  },
+  watch: {},
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    let that = this;
+    window.stopAudioVoice = function () {
+      if (that.audio) {
+        that.audio.pause();
+      }
+    };
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    _this.voiceSrc = _this.isCompare
+      ? _this.comparePlaySrc
+      : _this.voicePauseSrc;
+    if (_this.isCompare) {
+      _this.audio.pause();
+      _this.audio.load();
+      _this.audio.src = _this.mp3;
+      _this.audio.loop = false;
+      _this.audio.play();
+    }
+    _this.audio.addEventListener("play", function () {
+      _this.voiceSrc = _this.isCompare
+        ? _this.comparePlaySrc
+        : _this.voicePlaySrc;
+      _this.$emit("getPlayStatus", true);
+    });
+    _this.audio.addEventListener("pause", function () {
+      _this.voiceSrc = _this.isCompare
+        ? _this.comparePauseSrc
+        : _this.voicePauseSrc;
+      _this.$emit("getPlayStatus", false);
+    });
+    _this.audio.addEventListener("ended", function () {
+      _this.voiceSrc = _this.isCompare
+        ? _this.comparePauseSrc
+        : _this.voicePauseSrc;
+      _this.$emit("sentPause", false);
+      _this.$emit("getPlayStatus", false);
+    });
+  },
+  // 方法集合
+  methods: {
+    handlePlayVoice() {
+      let _this = this;
+      console.log(this.audio.paused);
+      if (!_this.audio.paused) {
+        _this.audio.pause();
+      } else if (_this.isCompare) {
+        _this.audio.pause();
+        _this.audio.play();
+      } else {
+        _this.audio.pause();
+        _this.audio.load();
+        _this.audio.src = _this.mp3;
+        _this.audio.loop = false;
+        _this.audio.play();
+      }
+    },
+    stopAudio() {
+      if (this.audio) {
+        this.audio.pause();
+      }
+    },
+  },
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.content-voices {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  font-size: 0;
+  cursor: pointer;
+  span {
+    color: #2c2c2c;
+    font-size: 24px;
+    line-height: 30px;
+    float: left;
+    font-family: sourceR;
+    &.noMp3 {
+      margin-left: 0px;
+    }
+  }
+  img {
+    width: 16px;
+    height: 16px;
+    float: left;
+  }
+  .icon-big {
+    width: 24px;
+    height: 24px;
+  }
+}
+</style>

+ 553 - 0
src/components/common/Soundrecorddiff.vue

@@ -0,0 +1,553 @@
+<!--  -->
+<template>
+  <div class="NNPE-Book-record">
+    <div
+      :class="['record-main', microphoneStatus ? 'active' : '']"
+    >
+      <div class="record-main-inner" @click="microphone">
+        <div class="record" />
+        <span v-if="microphoneStatus" class="record-time">{{
+          handleDateTime(recordtime)
+        }}</span>
+      </div>
+    </div>
+
+    <div
+      v-if="
+        !microphoneStatus && recordList.length > 0
+      "
+      :class="[
+        'hasRecord',
+        bgIndex == 1 ? 'hasRecord-white' : '',
+      ]"
+    >
+      <div
+        :class="[bgIndex == 1 ? 'playBack-white' : 'playBack', hasMicro]"
+        @click="
+          playmicrophone(
+            selectIndex || selectIndex == 0
+              ? recordList[selectIndex].toltime
+              : ''
+          )
+        "
+      >
+        <svg-icon icon-class="play-fill" className="icon-svg"></svg-icon>
+      </div>
+      <span
+        class="record-time"
+        >{{ isPlaying ? "-" : "" }}{{ handleDateTime(recordtime) }}</span
+      >
+      <el-select
+        v-model="selectIndex"
+        placeholder="No recording"
+        no-data-text="No recording"
+        :popper-append-to-body="false"
+        @change="handleChangeRecord"
+      >
+        <el-option
+          v-for="(item, index) in recordList"
+          :key="'recordList' + index"
+          :label="item.name"
+          :value="index"
+        />
+      </el-select>
+      <a
+        class="record-delete"
+        @click="handleDelete"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import Recorder from "js-audio-recorder"; // 录音插件
+export default {
+  components: {},
+  props: [
+    "wavData",
+    "type",
+    "fileName",
+    "selectData",
+    "bgIndex",
+    "tmIndex",
+    "answerRecordList",
+  ],
+  data() {
+    return {
+      recorder: new Recorder({
+        sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
+        sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
+        numChannels: 1, // 声道,支持 1 或 2, 默认是1
+      }),
+      microphoneStatus: false,
+      hasMicro: "", // 录音后的样式class
+      wavblob: null,
+      audio: new window.Audio(),
+      recordList: [], // 录音文件数组
+      recordtime: 0, // 录音时长
+      timer: null, // 计时器
+      recordFile: 1, // 录音文件名
+      selectIndex: null, // 选中的录音索引
+      oldIndex: null, // 存储播放录音索引
+      playtime: 0, // 播放时间
+      isPlaying: false,
+    };
+  },
+  watch: {},
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.handleActive();
+    let that = this;
+    window.stopAudioSound = function () {
+      if (that.audio) {
+        that.audio.pause();
+      }
+    };
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    _this.recordList = _this.answerRecordList
+      ? JSON.parse(JSON.stringify(_this.answerRecordList))
+      : [];
+    if (_this.recordList.length > 0) {
+      _this.selectIndex = 0;
+      this.$emit("getSelectData", this.recordList[0].selectData);
+      _this.recordFile = _this.recordList.length + 1;
+      _this.handleChangeRecord(0);
+      _this.$emit(
+          "getRerordStatus",
+          !_this.microphoneStatus && _this.recordList.length > 0
+        );
+      _this.$forceUpdate();
+    }
+    _this.audio.addEventListener("play", function () {
+      _this.changeStatus("active");
+      _this.isPlaying = true;
+      _this.$emit("getPlayStatus", true);
+    });
+    _this.audio.addEventListener("pause", function () {
+      _this.changeStatus("normal");
+      _this.$emit("getPlayStatus", false);
+    });
+    _this.audio.addEventListener("ended", function () {
+      _this.changeStatus("normal");
+      _this.isPlaying = false;
+      _this.$emit("getPlayStatus", false);
+    });
+  },
+  beforeCreate() {}, // 生命周期 - 创建之前
+  beforeMount() {}, // 生命周期 - 挂载之前
+  beforeUpdate() {}, // 生命周期 - 更新之前
+  updated() {}, // 生命周期 - 更新之后
+  beforeDestroy() {}, // 生命周期 - 销毁之前
+  destroyed() {}, // 生命周期 - 销毁完成
+  activated() {},
+  // 方法集合
+  methods: {
+    // 开始录音
+    microphone() {
+      let _this = this;
+      if (!this.microphoneStatus) {
+        _this.hasMicro = "";
+        _this.$emit("getWavblob", null);
+        this.$emit("getSelectData", { type: "" });
+        // 开始录音
+        this.recorder.start();
+        this.microphoneStatus = true;
+        this.recordtime = 0;
+        this.isPlaying = false;
+        clearInterval(_this.timer);
+        _this.timer = setInterval(() => {
+          _this.recordtime++;
+        }, 1000);
+        this.$emit("handleParentPlay");
+        let obj = {
+          name: _this.fileName
+            ? _this.fileName + _this.recordFile
+            : "Recording " + _this.recordFile,
+          id: _this.recordFile + Math.round(Math.random() * 10),
+        };
+        console.log(this.selectData);
+        if (this.selectData) obj.selectData = this.selectData;
+        _this.recordList.push(obj);
+        _this.recordFile++;
+        _this.selectIndex = _this.recordList.length - 1;
+      } else {
+        this.hasMicro = "normal";
+        this.recorder.stop();
+        clearInterval(_this.timer);
+        let toltime = this.recorder.duration; // 录音总时长
+        let fileSize = this.recorder.fileSize; // 录音总大小
+        // 录音结束,获取取录音数据
+        let wav = this.recorder.getWAVBlob(); // 获取 WAV 数据
+        // this.wavblob = wav;
+        this.microphoneStatus = false;
+        let reader = new window.FileReader();
+        reader.readAsDataURL(wav);
+        reader.onloadend = () => {
+          _this.recordList[_this.selectIndex].wavData = reader.result;
+          _this.recordList[_this.selectIndex].toltime = Math.floor(toltime);
+          _this.recordList[_this.selectIndex].fileSize = fileSize;
+
+          _this.wavblob = _this.recordList[_this.selectIndex].wavData;
+          _this.$emit("getWavblob", _this.wavblob);
+          _this.$emit(
+            "handleWav",
+            JSON.parse(JSON.stringify(_this.recordList)),
+            _this.tmIndex
+          );
+          if (this.recordList[this.selectIndex].selectData) {
+            this.$emit(
+              "getSelectData",
+              this.recordList[this.selectIndex].selectData
+            );
+          }
+        };
+      }
+      _this.$emit(
+        "getRerordStatus",
+        !_this.microphoneStatus && _this.recordList.length > 0
+      );
+      _this.$emit("getMicrophoneStatus", _this.microphoneStatus);
+    },
+    playmicrophone(totalTimes) {
+      if (this.hasMicro) {
+        this.isPlaying = true;
+        if (this.selectIndex || this.selectIndex == 0) {
+          let totalTime = totalTimes;
+          let _this = this;
+          if (!this.audio.paused) {
+            this.audio.pause();
+            clearInterval(_this.timer);
+          } else if (this.audio.paused && _this.oldIndex == _this.selectIndex) {
+            _this.audio.play();
+            if (_this.recordtime == 0) {
+              _this.recordtime = totalTimes;
+              _this.playtime = 0;
+            }
+            _this.timer = setInterval(() => {
+              if (_this.playtime < totalTime) {
+                _this.playtime++;
+                _this.recordtime = totalTime - _this.playtime;
+              } else {
+                clearInterval(_this.timer);
+              }
+            }, 1000);
+          } else {
+            _this.audio.pause();
+            _this.audio.load();
+            _this.audio.src = _this.wavblob;
+            _this.oldIndex = _this.selectIndex;
+            _this.audio.play();
+            _this.playtime = 0;
+            _this.recordtime = totalTime;
+            clearInterval(_this.timer);
+            _this.timer = setInterval(() => {
+              if (_this.playtime < totalTime) {
+                _this.playtime++;
+                _this.recordtime = totalTime - _this.playtime;
+              } else {
+                clearInterval(_this.timer);
+              }
+            }, 1000);
+          }
+        }
+      }
+    },
+    // 高亮初始值
+    handleActive() {
+      if (this.wavData) {
+        // this.hasMicro = "normal";
+      } else {
+        this.hasMicro = "";
+      }
+    },
+    changeStatus(status) {
+      this.hasMicro = status;
+    },
+    // 格式化录音时长
+    handleDateTime(time) {
+      if (parseInt(time / 60) < 10) {
+        time =
+          ("0" + parseInt(time / 60)).substring(
+            ("0" + parseInt(time / 60)).length - 2
+          ) +
+          ":" +
+          ("0" + (time % 60)).substring(("0" + (time % 60)).length - 2);
+      } else {
+        time =
+          parseInt(time / 60) +
+          ":" +
+          ("0" + (time % 60)).substring(("0" + (time % 60)).length - 2);
+      }
+      return time;
+    },
+    handleChangeRecord(index) {
+      this.recordtime = this.recordList[index].toltime;
+      this.wavblob = this.recordList[index].wavData;
+      this.hasMicro = "normal";
+      clearInterval(this.timer);
+      this.audio.pause();
+      this.oldIndex = null;
+      this.$emit("getWavblob", this.wavblob);
+      if (this.recordList[index].selectData) {
+        this.$emit("getSelectData", this.recordList[index].selectData);
+      }
+      this.$emit("sentPause", false);
+    },
+    handleDelete() {
+      if (this.hasMicro) {
+        if (this.selectIndex || this.selectIndex == 0) {
+          this.recordList.splice(this.selectIndex, 1);
+          this.$emit(
+            "handleWav",
+            JSON.parse(JSON.stringify(this.recordList)),
+            this.tmIndex
+          );
+          this.selectIndex =
+            this.recordList.length > 0 ? this.recordList.length - 1 : null;
+          this.hasMicro = this.recordList.length > 0 ? "normal" : "";
+          this.recordtime =
+            this.recordList.length > 0
+              ? this.recordList[this.selectIndex].toltime
+              : 0;
+          this.audio.pause();
+          this.audio = new window.Audio();
+          this.wavblob =
+            this.recordList.length > 0
+              ? this.recordList[this.selectIndex].wavData
+              : null;
+          this.oldIndex = null;
+          this.isPlaying = false;
+          clearInterval(this.timer);
+        }
+        this.$emit("getRerordStatus", this.recordList.length > 0);
+      }
+    },
+  }, // 如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang="scss" scoped>
+//@import url(); 引入公共css类
+.NNPE-Book-record {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  // max-width: 292px;
+  height: 32px;
+  // border: 1px solid rgba(0, 0, 0, 0.1);
+  // border-radius: 8px;
+  .playBack {
+    width: 24px;
+    height: 24px;
+    margin-left: 8px;
+    // background: url("../../../assets/icon/play-24-normal-Black.png") center
+    //   no-repeat;
+    // background-size: 100%;
+    cursor: pointer;
+    // &.normal {
+    //   background: url("../../../assets/icon/play-24-normal-Black.png") center
+    //     no-repeat;
+    //   background-size: 100%;
+    // }
+    // &.active {
+    //   background: url("../../../assets/icon/pause-24-normal-Black.png") center
+    //     no-repeat;
+    //   background-size: 100%;
+    // }
+  }
+  .playBack-white {
+    width: 24px;
+    height: 24px;
+    margin-left: 8px;
+    // background: url("../../../assets/icon/play-24-normal-white.png") center
+    //   no-repeat;
+    // background-size: 100%;
+    cursor: pointer;
+    // &.normal {
+    //   background: url("../../../assets/icon/play-24-normal-white.png") center
+    //     no-repeat;
+    //   background-size: 100%;
+    // }
+    // &.active {
+    //   background: url("../../../assets/icon/pause-24-normal-white.png") center
+    //     no-repeat;
+    //   background-size: 100%;
+    // }
+    // &.disabled {
+    //   background: url("../../../assets/icon/play-16-disable-Black.png") center
+    //     no-repeat;
+    //   background-size: 100%;
+    // }
+    .record-time {
+      color: #fff;
+      &.disabled {
+        color: rgba(0, 0, 0, 0.3);
+      }
+    }
+  }
+  .line {
+    width: 1px;
+    height: 16px;
+    background: rgba(0, 0, 0, 0.85);
+    opacity: 0.2;
+    margin-left: 8px;
+  }
+  .record-main {
+    width: 162px;
+    height: 136px;
+    box-sizing: border-box;
+    padding: 40px 8px 40px 40px;
+    &.active {
+    //   background: url("../../../assets/NPC/vocie-gif.png") no-repeat left top;
+      background-size: 100% 100%;
+    }
+    &-inner {
+      padding: 16px 16px;
+      box-sizing: border-box;
+      width: fit-content;
+      height: 56px;
+      border-radius: 40px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      box-sizing: border-box;
+      background: #de4444;
+      border: 1px solid rgba(0, 0, 0, 0.1);
+      cursor: pointer;
+    }
+  }
+
+  .record {
+    width: 24px;
+    height: 24px;
+    // background: url("../../../assets/NPC/voice-24.png") center no-repeat;
+    background-size: 100%;
+  }
+  .record-time {
+    color: #fff;
+    font-size: 16px;
+    line-height: 150%;
+    margin-left: 8px;
+    font-family: "robot";
+    font-weight: bold;
+    font-size: 16px;
+    line-height: 24px;
+    margin-left: 16px;
+    &.disabled {
+      color: rgba(0, 0, 0, 0.3);
+    }
+  }
+  .hasRecord {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 56px;
+    padding: 16px 0 16px 16px;
+    border-radius: 40px 0 0 40px;
+    border: 1px solid rgba(0, 0, 0, 0.1);
+    border-right: 0px solid rgba(0, 0, 0, 0.1);
+    box-sizing: border-box;
+
+    .record-time {
+      width: 46px;
+      color: #000000;
+      text-align: center;
+      &.disabled {
+        color: rgba(0, 0, 0, 0.3);
+      }
+    }
+
+    .el-select {
+      margin-left: 16px;
+    }
+    .record-delete {
+      width: 24px;
+      height: 24px;
+      margin-left: 16px;
+    //   background: url("../../../assets/NPC/del-24.png") center no-repeat;
+      background-size: 100%;
+      display: block;
+      &-disabled {
+        // background: url("../../../assets/NPC/del-24.png") center no-repeat;
+        background-size: 100%;
+      }
+    }
+    &-white {
+      background: rgba(255, 255, 255, 0.1);
+      border: 1px solid rgba(0, 0, 0, 0.1);
+      border-right: 0;
+      .record-time {
+        color: #fff;
+      }
+    }
+    &-answer {
+      padding: 16px;
+      border-radius: 40px;
+    }
+  }
+}
+</style>
+<style lang="scss">
+.NNPE-Book-record {
+  .hasRecord {
+    .el-select {
+      flex: 1;
+      height: 24px;
+      &.proSelect {
+        width: 78px;
+      }
+      .el-input__inner {
+        width: 115px;
+        box-sizing: border-box;
+        height: 24px;
+        line-height: 22px;
+        border: 0px solid rgba(0, 0, 0, 0.1);
+        box-sizing: border-box;
+        border-radius: 4px;
+        padding: 0px 11px;
+        font-size: 14px;
+        color: rgba(0, 0, 0, 0.85);
+      }
+      .el-input {
+        .el-select__caret {
+          color: #000;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+        }
+      }
+      .el-input__icon {
+        width: 16px;
+      }
+      .el-input__suffix {
+        right: 3px;
+      }
+    }
+    &-white {
+      .el-select {
+        .el-input__inner {
+          background: rgba(255, 255, 255, 0.1);
+          border-radius: 4px;
+          color: #fff;
+        }
+        .el-input {
+          .el-select__caret {
+            color: #000;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+          }
+        }
+        .el-input__icon {
+          width: 16px;
+        }
+        .el-input__suffix {
+          right: 3px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 5 - 5
src/views/bookShelf/articleDetail.vue

@@ -20,12 +20,12 @@
         <div class="artricle-inner" :style="{background:bgColorList[activeIndex].contentInnerBg}">
             <!-- 文章 -->
             <div class="atricle-data">
-                <normal-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='original'" :articleInfo="articleInfo" :likeSentencelist="likeSentencelist"></normal-model>
+                <normal-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='original'" :articleInfo="articleInfo" :likeSentencelist="likeSentencelist" :likeWord="likeWordList"></normal-model>
                 <phrase-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='newWord'" :articleInfo="articleInfo" :likePhraseList="likePhraseList" :likeWord="likeWordList" @changeLike="changeLike" :likeSentencelist="likeSentencelist"></phrase-model>
-                <practice-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='practice'" :articleInfo="articleInfo" :likeSentencelist="likeSentencelist"></practice-model>
-                <inner-text-search :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='search'" :articleInfo="articleInfo" ref="innerTextSearchs" :likeSentencelist="likeSentencelist"></inner-text-search>
-                <lexical-type :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='filtrate'" :articleInfo="articleInfo" ref="lexicalType" :likeSentencelist="likeSentencelist"></lexical-type>
-                <notes-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='notebook'" :articleInfo="articleInfo" :likeSentencelist="likeSentencelist"></notes-model>
+                <practice-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='practice'" :articleInfo="articleInfo" :likeSentencelist="likeSentencelist" :likeWord="likeWordList"></practice-model>
+                <inner-text-search :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='search'" :articleInfo="articleInfo" ref="innerTextSearchs" :likeSentencelist="likeSentencelist" :likeWord="likeWordList"></inner-text-search>
+                <lexical-type :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='filtrate'" :articleInfo="articleInfo" ref="lexicalType" :likeSentencelist="likeSentencelist" :likeWord="likeWordList"></lexical-type>
+                <notes-model :titleFontsize="wordFontsize+30" :wordFontsize="wordFontsize" :colorObj="bgColorList[activeIndex]" :articleType="articleType" :style="{'padding':'0 40px'}" v-if="menuType==='notebook'" :articleInfo="articleInfo" :likeSentencelist="likeSentencelist" :likeWord="likeWordList"></notes-model>
                 <div class="article-btn" v-if="this.$route.query.iss_id&&menuType!=='practice'">
                     <div class="left">
                         <span :class="['support colloct-article',!noRead?'active':'']" @click="changeStatus('noRead')"><svg-icon icon-class="like-line" :style="{marginRight:articleNumber?'8px':'0px'}"></svg-icon>{{articleNumber?articleNumber:''}}</span>

+ 11 - 0
src/views/bookShelf/components/HistoryRecordList.vue

@@ -226,6 +226,17 @@ export default {
     recordDetail(index){
         this.activeIndex = index
         this.showItem = true
+        let MethodName = "/PaperServer/Client/UserSentRec/FindById";
+        let data = {
+            id: this.showList[this.activeIndex].id,
+            got_rec_data_flag: true
+        }
+        getLogin(MethodName, data)
+        .then((res) => {
+            if(res.status===1){
+                this.showList[this.activeIndex].rec_sound_data = res.data.rec_sound_data
+            }
+        })
     },
     changePlaySent(type){
         if (!this.audio.paused) {

+ 2 - 1
src/views/bookShelf/components/InnerTextSearch.vue

@@ -166,6 +166,7 @@
         :likeSentencelist="likeSentencelist"
         @exitFullscreen="exitFullscreen"
         @changeIsFull="changeIsFull"
+        :likeWord="likeWord"
       />
     </div>
   </div>
@@ -176,7 +177,7 @@ import AudioLine from "@/components/common/AudioLine.vue"
 import Voicefullscreen from './Voicefullscreen.vue';
 export default {
   name: "ArticleView",
-  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist"],
+  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist","likeWord"],
   components: {
     AudioLine,
     Voicefullscreen

+ 2 - 1
src/views/bookShelf/components/LexicalType.vue

@@ -177,6 +177,7 @@
         :likeSentencelist="likeSentencelist"
         @exitFullscreen="exitFullscreen"
         @changeIsFull="changeIsFull"
+        :likeWord="likeWord"
       />
     </div>
   </div>
@@ -187,7 +188,7 @@ import AudioLine from "@/components/common/AudioLine.vue"
 import Voicefullscreen from './Voicefullscreen.vue';
 export default {
   name: "ArticleView",
-  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist"],
+  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist","likeWord"],
   components: {
     AudioLine,
     Voicefullscreen

+ 2 - 1
src/views/bookShelf/components/NormalModel.vue

@@ -186,6 +186,7 @@
         :likeSentencelist="likeSentencelist"
         @exitFullscreen="exitFullscreen"
         @changeIsFull="changeIsFull"
+        :likeWord="likeWord"
       />
     </div>
   </div>
@@ -196,7 +197,7 @@ import AudioLine from "@/components/common/AudioLine.vue"
 import Voicefullscreen from './Voicefullscreen.vue';
 export default {
   name: "ArticleView",
-  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist"],
+  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist","likeWord"],
   components: {
     AudioLine,
     Voicefullscreen

+ 2 - 1
src/views/bookShelf/components/NotesModel.vue

@@ -80,6 +80,7 @@
         :likeSentencelist="likeSentencelist"
         @exitFullscreen="exitFullscreen"
         @changeIsFull="changeIsFull"
+        :likeWord="likeWord"
       />
     </div>
   </div>
@@ -92,7 +93,7 @@ import Highlighter from 'web-highlighter';
 import { getLogin } from "@/api/ajax";
 export default {
   name: "ArticleView",
-  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist"],
+  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist","likeWord"],
   components: {
     AudioLine,
     Voicefullscreen

+ 1 - 1
src/views/bookShelf/components/PhraseModel.vue

@@ -161,6 +161,7 @@
         :likeSentencelist="likeSentencelist"
         @exitFullscreen="exitFullscreen"
         @changeIsFull="changeIsFull"
+        :likeWord="likeWord"
       />
     </div>
   </div>
@@ -253,7 +254,6 @@ export default {
       handler(val, oldVal) {
         const _this = this;
         if (val) {
-            debugger
             this.phraseList.forEach(item=>{
                 item.type='phrase'
                 item.collect = this.likePhraseList.indexOf(item.exp_title)>-1?true:false

+ 4 - 3
src/views/bookShelf/components/PracticeModel.vue

@@ -236,6 +236,7 @@
       <Voicefullscreen
         v-if="isFull"
         :curQue="articleInfo"
+        :likeWord="likeWord"
         :sentIndex="playSentIndex===-1?0:playSentIndex"
         :mp3="articleInfo.art_sound_url"
         :likeSentencelist="likeSentencelist"
@@ -254,7 +255,7 @@ import { getLogin } from "@/api/ajax";
 import Voicefullscreen from './Voicefullscreen.vue';
 export default {
   name: "ArticleView",
-  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist"],
+  props: [ "titleFontsize", "wordFontsize", "colorObj","articleType","articleInfo","likeSentencelist","likeWord"],
   components: {
     AudioLine,
     HistoryRecordList,
@@ -307,7 +308,7 @@ export default {
       paraIndex: -1, //段落索引
       sentIndex: -1, // 句子索引
       repeatAfter: false,
-      singleModel: true,
+      singleModel: false,
       autoNextSent: false,
       recorder: new Recorder({
         sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
@@ -450,7 +451,7 @@ export default {
       this.resArr = resArr;
       console.log(this.resArr)
     },
-    handleChangeTime(time,ed,flag) {
+    handleChangeTime(time,ed,flag,type) {
       this.audio.pause();
       this.audioc.pause();
       if(flag){

+ 99 - 42
src/views/bookShelf/components/Voicefullscreen.vue

@@ -231,7 +231,7 @@
               :themeColor="''"
               :index="curSentIndex"
               :sentIndex="curSentIndex"
-              :url="curQue.mp3_list[0].id"
+              :url="curQue.art_sound_url"
               :bg="bg"
               :ed="ed"
               :wavblob="wavblob"
@@ -255,20 +255,16 @@
       </div>
     </div>
 
-    <template v-if="isShow">
-      <div
-        ref="wordcard"
-        class="NNPE-wordDetail"
-        :style="{ left: left + 'px' }"
-      >Wordcard
-        <!-- <Wordcard
-          :word="word"
-          :changeWordCard="changeWordCard"
-          :themeColor="themeColor"
-          :currentTreeID="currentTreeID"
-        /> -->
-      </div>
-    </template>
+      <el-dialog
+        :visible.sync="isShow"
+        :show-close="false"
+        :close-on-click-modal="false"
+        width="570px"
+        class="login-dialog"
+        :modal="false"
+        v-if="isShow">
+        <WordCard @closeWord="changeWordCard" :dataObj="showObj" @changeLike="changeLike" :likePhrase="likeWord"/>
+    </el-dialog>
     <div class="word-play-audio" v-if="isWordPlay">
       <AudioLineSentence
         :mp3="mp3"
@@ -294,20 +290,21 @@
 import AudioLineSentence from "../../../components/common/AudioLineSentence.vue";
 import Soundrecorddiff from "../../../components/common/Soundrecorddiff.vue";
 import AudioCompare from "../../../components/common/AudioCompare.vue";
-// import Wordcard from "./components/Wordcard.vue";
+import WordCard from "../../personalCenter/components/WordCard.vue"
 import { getLogin } from "@/api/ajax";
 export default {
   components: {
     AudioLineSentence,
     Soundrecorddiff,
     AudioCompare,
-    // Wordcard,
+    WordCard,
   },
   props: [
     "sentIndex",
     "mp3",
     "curQue",
-    "likeSentencelist"
+    "likeSentencelist",
+    "likeWord"
   ],
   data() {
     return {
@@ -394,7 +391,12 @@ export default {
         "‘ll",
         "”",
       ],
-      setFontSizeFlag: false
+      setFontSizeFlag: false,
+      showObj:null,
+      wordLit:[],
+      sentenceList:[],
+      left:0,
+      top:0
     };
   },
   computed: {
@@ -722,24 +724,50 @@ export default {
     },
     showWordDetail(e, item) {
       let _this = this;
-    //   if (_this.TaskModel == "ANSWER") {
-    //     return;
-    //   }
-    //   if (_this.chsFhList.indexOf(item.chs) > -1) {
-    //     return;
-    //   }
-    //   if (_this.oldHz != item.chs) {
-    //     this.isShow = false;
-    //     setTimeout(() => {
-    //       _this.hz = item.chs;
-    //       _this.pinyin = item.pinyin;
-    //       _this.wordIndex = item.wordIndex;
-    //     }, 50);
-    //   }
-    //   _this.clientY = e.clientY;
+      if (_this.enFhList.indexOf(item.tokens[2]) > -1) {
+        return;
+      }
+      if (_this.oldHz != item.tokens[2]) {
+        this.isShow = false;
+        setTimeout(() => {
+          _this.hz = item.tokens[2];
+          _this.wordIndex = item.wIndex;
+          if(item.type==='newWord'){
+                this.wordLit.forEach(itemi=>{
+                    if(item.word_id===itemi.id){
+                        let obj = {
+                            src: itemi.ph_file_url?itemi.ph_file_url:'',
+                            word: itemi.word_name,
+                            symbol: itemi.word_explain.ph?itemi.word_explain.ph:'',
+                            paraList: itemi.word_explain.word_para_list,
+                            type: itemi.word_explain.vl_level?itemi.word_explain.vl_level:'',
+                            typeCn: itemi.word_explain.vl_level_name?itemi.word_explain.vl_level_name:'',
+                            rate: itemi.word_explain.star?itemi.word_explain.star:null,
+                            originalObj: itemi,
+                            hasVoice: itemi.word_explain.ph_mp3_id||itemi.word_explain.ph_file_url?true:false,
+                            id: itemi.id,
+                            collect: this.likeWord.indexOf(itemi.word_name)>-1?true:false,
+                            isNew: true
+                        }
+                        this.showObj = obj
+                    }
+                })
+                this.showWordFlag = true
+            }else{
+                let obj = {
+                    word: item.tokens[2],
+                    isNew: false
+                }
+                this.showObj = obj
+                this.showWordFlag = true
+            }
+            console.log(this.showObj)
+        }, 50);
+      }
+      _this.clientY = e.clientY;
 
-    //   let left = e.clientX;
-    //   let width = 0;
+      let left = e.clientX;
+      let width = 0;
     //   if (item.chs.length == 1 || item.chs.length == 2) {
     //     width = 304;
     //   } else if (item.chs.length == 3 || item.chs.length == 4) {
@@ -747,11 +775,11 @@ export default {
     //   } else if (item.chs.length > 3) {
     //     width = 560;
     //   }
-      // if (left - this.bodyLeft > this.contentWidth / 2) {
-      //   _this.left = left - width + 10;
-      // } else {
+      if (left - this.bodyLeft > this.contentWidth / 2) {
+        _this.left = left - width + 10;
+      } else {
       _this.left = left - width / 2;
-      //}
+      }
     },
     changeWordCard(isShow) {
       let _this = this;
@@ -799,6 +827,9 @@ export default {
     //   });
     //   this.newWordList = JSON.parse(JSON.stringify(NewWordList));
     },
+    changeLike(){
+
+    },
     getScreenHeight() {
       this.screenHeight = window.innerHeight;
     },
@@ -808,9 +839,33 @@ export default {
             timeList: [],
         };
       let articleInfo = JSON.parse(JSON.stringify(this.curQue));
+      this.sentenceList = articleInfo.art_corpus_data?articleInfo.art_corpus_data.sentList:[]
+      this.wordLit = articleInfo.art_voc_data?articleInfo.art_voc_data:[]
+      this.wordLit.forEach(item=>{
+            item.type='newWord'
+            item.exp_title = item.word_name
+            let paraStr = ''
+            if(item.word_explain&&item.word_explain.word_para_list){
+                item.word_explain.word_para_list.forEach(items=>{
+                    paraStr += items.para
+                })
+            }
+            item.exp_content = paraStr
+            item.collect = this.likeWord.indexOf(item.word_name)>-1?true:false
+        })
       articleInfo.art_corpus_data.sentList.forEach((item,index) => {
         let wordlist = []
         item.tokens.forEach((items,indexs)=>{
+            let type=''
+            let word_id = ''
+            for(let i=0;i<this.wordLit.length;i++){
+                this.wordLit[i].bind_sent_data.bind_sents.forEach(items=>{
+                    if(items.sent_id===item.id&&items.sel_token_idxes.indexOf(indexs)>-1){
+                        type='newWord'
+                        word_id = this.wordLit[i].id
+                    }
+                })
+            }
             let obj = {
                 sent_id:item.id,
                 sno: item.sno-1,
@@ -819,7 +874,9 @@ export default {
                 tokens: items,
                 wIndex: indexs,
                 isShow: this.enFhList.indexOf(items[2])==-1,
-                marginRight: indexs===item.tokens.length-1
+                marginRight: indexs===item.tokens.length-1,
+                type:type,
+                word_id:word_id
             }
             wordlist.push(obj)
         })
@@ -1317,7 +1374,7 @@ export default {
       display: flex;
       justify-content: space-between;
       align-items: center;
-      visibility: hidden;
+    //   visibility: hidden;
     }
     .bottom-left {
       display: flex;