Bladeren bron

文章取词

natasha 3 jaren geleden
bovenliggende
commit
c4c9f95ed4

+ 201 - 183
src/api/ajax.js

@@ -1,227 +1,245 @@
 import request from '@/utils/request'
 import { getToken } from '@/utils/auth'
 export function getContent(MethodName, data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSBookWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSBookWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 
 export function getYinbiao(data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    // /GCLSHMToolsServer/api/dict/basic
-    url: `/GCLSHMToolsServer/api/dict/basic?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        // /GCLSHMToolsServer/api/dict/basic
+        url: `/GCLSHMToolsServer/api/dict/basic?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 
 export function getLogin(MethodName, data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSFileServer/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSFileServer/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 
 export function getContentFile(
-  MethodName,
-  data
-) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSFileServer/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
+    MethodName,
     data
-  })
+) {
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSFileServer/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 
 export function getStaticContent(MethodName, data) {
-  return request({
-    url: `/GCLSFileServer/ServiceInterface?MethodName=${MethodName}`,
-    method: 'post',
-    data
-  })
+    return request({
+        url: `/GCLSFileServer/ServiceInterface?MethodName=${MethodName}`,
+        method: 'post',
+        data
+    })
 }
 
 //获取分词结果 == gcls.helxsoft.cn/GCLSFCServer/ServiceInterface?userCode=2021052116-QA2HTCS5J6C6ZER&userType=STUDENT&sessionId=S-QPUKZAXLEFESNRBAZ0
 export function getSegContent(data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSFCServer/ServiceInterface?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSFCServer/ServiceInterface?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 export function LearnWebSI(MethodName, data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSLearnWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data,
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSLearnWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data,
+    })
 }
 //教材
 export function TextbookAPI(MethodName, data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSBookWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data,
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSBookWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data,
+    })
 }
 export function getLearnWebContent(MethodName, data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSLearnWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSLearnWebSI/ServiceInterface?MethodName=${MethodName}&UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 // 发送聊天
 export function sendrobot(data) {
-  return request({
-    url: `/GCLSAIServer/unit/utterance`,
-    method: 'post',
-    data
-  })
+    return request({
+        url: `/GCLSAIServer/unit/utterance`,
+        method: 'post',
+        data
+    })
 }
 // 语音识别 GCLSAIServer/speech/recognize
 export function speechrecognize(data) {
-  return request({
-    url: `/GCLSAIServer/speech/recognize`,
-    method: 'post',
-    data
-  })
+    return request({
+        url: `/GCLSAIServer/speech/recognize`,
+        method: 'post',
+        data
+    })
 }
 
 //分句
 export function segSentences(data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSHMToolsServer/api/nlp/chinese/text2Sentences?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSHMToolsServer/api/nlp/chinese/text2Sentences?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 //批量分词
 export function BatchSegContent(data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSHMToolsServer/api/nlp/chinese/text2word?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSHMToolsServer/api/nlp/chinese/text2word?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }
 // 生成拼音
 export function createPinyin(data) {
-  let userInfor = getToken();
-  let UserCode = '',
-    UserType = '',
-    SessionID = ''
-  if (userInfor) {
-    let user = JSON.parse(getToken());
-    UserCode = user.user_code;
-    UserType = user.user_type;
-    SessionID = user.session_id;
-  }
-  return request({
-    url: `/GCLSFCServer/GCLSHMToolsServer/api/nlp/chinese/text2pinyin?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
-    method: 'post',
-    data
-  })
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSFCServer/GCLSHMToolsServer/api/nlp/chinese/text2pinyin?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
+}
+// 百度汉语接口-取释义
+export function getHZChineseInfo(data) {
+    let userInfor = getToken();
+    let UserCode = '',
+        UserType = '',
+        SessionID = ''
+    if (userInfor) {
+        let user = JSON.parse(getToken());
+        UserCode = user.user_code;
+        UserType = user.user_type;
+        SessionID = user.session_id;
+    }
+    return request({
+        url: `/GCLSHMToolsServer/api/baidu/chineseInfo?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        method: 'post',
+        data
+    })
 }

BIN
src/assets/NPC/chinaTianRed.png


BIN
src/assets/NPC/strock-play-red-click.png


+ 7 - 2
src/components/Adult/Preview.vue

@@ -10,8 +10,8 @@
     </div>
     <div class="NNPE-Book-content-inner" v-if="cur">
       <div v-for="(item, index) in cur.cur_fn_data" :key="index">
-        <h2 v-if="item.Ztitle">{{ item.Ztitle }}</h2>
-        <h3 v-if="item.Ftitle">{{ item.Ftitle }}</h3>
+        <h2 v-if="item.title_z">{{ item.title_z }}</h2>
+        <h3 v-if="item.title_f">{{ item.title_f }}</h3>
         <div
           :class="['NNPE-tableList', item.Isbg ? 'NNPE-tableList-hasBg' : '']"
         >
@@ -58,6 +58,9 @@
                     :NNPEAnnotationList="NNPEAnnotationList"
                   />
                 </template>
+                <template v-if="itemss.data.type == 'input_record'">
+                    <InputHasRecord :curQue="itemss.data" />
+                </template>
               </template>
             </div>
           </div>
@@ -75,6 +78,7 @@ import ArticleTemChs from "./preview/ArticleViewChs/index.vue"; // 文章模板
 import WordPhrase from "./preview/WordPhrase.vue"; // 生词 短语
 import Notes from "./preview/Notes.vue"; // 注释
 import Ligature from "./preview/Ligature.vue";
+import InputHasRecord from "./preview/InputHasRecord.vue" // 输入加录音
 export default {
   name: "preview",
   components: {
@@ -85,6 +89,7 @@ export default {
     WordPhrase,
     Notes,
     Ligature,
+    InputHasRecord,
   },
   props: ["context", "fatherName"],
   data() {

+ 41 - 9
src/components/Adult/preview/ArticleViewChs/WordModelChs.vue

@@ -20,9 +20,7 @@
               v-for="(pItem, pIndex) in item.wordsList"
               :key="'wordsList' + pIndex"
               :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
-              @click="handleChangeTime(resObj.timeList[index])"
-              @mouseover="showWordDetail($event, pItem.chs)"
-              @mouseleave="hideWordDetail"
+              @click="showWordDetail($event, pItem.chs)"
             >
               <template v-if="!pItem.width">
                 <span
@@ -64,7 +62,7 @@
         class="NNPE-wordDetail"
         :style="{ top: top + 'px', left: left + 'px' }"
       >
-        {{ hz }}
+      <Wordcard :word="word" :changeWordCard="changeWordCard" />
       </div>
     </template>
   </div>
@@ -73,11 +71,13 @@
 <script>
 import { timeStrToSen } from "@/utils/index";
 import AudioLine from "../AudioLine.vue";
+import Wordcard from "../components/Wordcard.vue"; // 卡片
 export default {
   name: "WordModelChs",
-  props: ["curQue", "bodyLeft"],
+  props: ["curQue", "bodyLeft","NNPENewWordList"],
   components: {
     AudioLine,
+    Wordcard
   },
   data() {
     return {
@@ -88,14 +88,26 @@ export default {
       newWords: ["鱼", "辩礼义"],
       isShow: false,
       hz: "",
+      oldHz: '',
+      word: null,
       top: 0,
       left: 0,
       contentWidth: 732,
       articleImg: {}, // 文章图片
+
     };
   },
   computed: {},
-  watch: {},
+  watch: {
+      hz: {
+        handler: function (val, oldVal) {
+            let _this = this;
+            this.handleNewWords(val, this.top, this.left);
+        },
+        // 深度观察监听
+        deep: true,
+      },
+  },
   //方法集合
   methods: {
     getCurTime(curTime) {
@@ -210,12 +222,30 @@ export default {
     hideWordDetail() {
       this.isShow = false;
     },
+    changeWordCard(isShow) {
+      this.isShow = isShow;
+      this.oldHz = "";
+      this.hz = "";
+    },
+    // 处理分词数据
+    handleNewWords(val, top, left) {
+      this.isShow = true;
+      this.word = null;
+      for (let i = 0; i < this.NNPENewWordList.length; i++) {
+        let item = this.NNPENewWordList[i];
+        if (item.new_word.trim() == val.trim()) {
+          let wordlist = val.split("");
+          this.word = { list: wordlist, detail: item, top: top, left: left };
+          break;
+        }
+      }
+      this.oldHz = val;
+    },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {},
   //生命周期 - 挂载完成(可以访问DOM元素)
   mounted() {
-    console.log(this.curQue);
     if (this.curQue) {
       this.handleData();
     }
@@ -224,7 +254,9 @@ export default {
   beforeMount() {}, //生命周期 - 挂载之前
   beforeUpdate() {}, //生命周期 - 更新之前
   updated() {}, //生命周期 - 更新之后
-  beforeDestroy() {}, //生命周期 - 销毁之前
+  beforeDestroy() {
+      this.isShow = false
+  }, //生命周期 - 销毁之前
   destroyed() {}, //生命周期 - 销毁完成
   activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
 };
@@ -306,6 +338,6 @@ export default {
   position: fixed;
   width: 260px;
   height: 200px;
-  background: #cc0;
+//   background: #cc0;
 }
 </style>

+ 2 - 1
src/components/Adult/preview/ArticleViewChs/index.vue

@@ -61,6 +61,7 @@
         :wordFontsize="wordFontsize"
         :bodyLeft="bodyLeft"
         :bodyWidth="bodyWidth"
+        :NNPENewWordList="NNPENewWordList"
         v-if="showWord"
       />
     </div>
@@ -74,7 +75,7 @@ import WordModel from "./WordModelChs.vue"; // 语音练习模式
 
 export default {
   name: "ArticleView",
-  props: ["curQue"],
+  props: ["curQue","NNPENewWordList"],
   components: { Preview, Practice, WordModel },
   data() {
     return {

+ 88 - 0
src/components/Adult/preview/InputHasRecord.vue

@@ -0,0 +1,88 @@
+<!--  -->
+<template>
+  <div class="Big-Book-prev-Textdes InputHasRecord" v-if="curQue">
+      <div v-for="(items, indexs) in curQue.option" :key="indexs">
+          <p v-if="items.con">{{items.con}}</p>
+          <div class="inputInner">
+              <el-input :class="['textarea',items.record?'':'textareaNoRecord']" type="textarea" v-model="textareaCon" placeholder="输入"></el-input>
+              <Soundrecord @handleWav="handleWav" type="promax" class="luyin-box" v-if="items.record"/>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import Soundrecord from "../preview/Soundrecord.vue"; // 录音模板
+export default {
+  components: {Soundrecord},
+  props: ["curQue"],
+  data() {
+    return {
+        textareaCon: '', // 输入框
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+      handleWav(data) {
+        
+      },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+  },
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.Big-Book-prev-Textdes{
+    width: 100%;
+    .inputInner{
+        border-radius: 8px;
+        border: 1px solid rgba(0, 0, 0, 0.1);
+        background: #fff;
+        overflow: hidden;
+        margin: 8px 0 16px 0;
+    }
+    p{
+        font-size: 16px;
+        line-height: 150%;
+        color: #000000;
+        margin: 0 4px;
+    }
+    .luyin-box{
+        border-top: 1px solid rgba(0, 0, 0, 0.1);
+        justify-content: start;
+        padding: 4px 12px;
+        height: 40px;
+    }
+}
+</style>
+<style lang="scss">
+.InputHasRecord{
+    .textarea{
+        &.textareaNoRecord{
+            textarea{
+                height: 104px;
+            }
+        }
+        textarea{
+            resize: none;
+            border: none;
+            height: 64px;
+            padding: 8px 16px;
+        }
+    }
+}
+</style>

+ 103 - 0
src/components/Adult/preview/components/AudioRed.vue

@@ -0,0 +1,103 @@
+<!--  -->
+<template>
+    <div @click="handlePlayVoice" class="content-voices" v-if="mp3">
+        <img :src="voiceSrc">
+    </div>
+</template>
+
+<script>
+export default {
+    components: {},
+    props: ["seconds", "mp3", "wav"],
+    data () {
+        return {
+            audio: new Audio(),
+            voiceSrc: "",
+            // voicePauseSrc: require("../../assets/common/icon-voice-red.png"),
+            // voicePlaySrc: require("../../assets/common/icon-voice-red-play.png"),
+        };
+    },
+    computed: {},
+    watch: {},
+    //方法集合
+    methods: {
+        handlePlayVoice () {
+            if (!this.audio.paused) {
+                this.audio.pause();
+            } else {
+                let _this = this;
+                _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();
+            }
+        },
+    },
+    //生命周期 - 创建完成(可以访问当前this实例)
+    created () {
+        var that = this;
+        window.stopAudioVoice = function () {
+            if (that.audio) {
+                that.audio.pause();
+            }
+        };
+    },
+    //生命周期 - 挂载完成(可以访问DOM元素)
+    mounted () {
+        let _this = this;
+        _this.voiceSrc = _this.voicePauseSrc;
+        _this.audio.addEventListener("play", function () {
+            console.log("播放");
+            _this.voiceSrc = _this.voicePlaySrc;
+        });
+        _this.audio.addEventListener("pause", function () {
+            _this.voiceSrc = _this.voicePauseSrc;
+        });
+        _this.audio.addEventListener("ended", function () {
+            console.log("停止");
+            _this.voiceSrc = _this.voicePauseSrc;
+        });
+    },
+    beforeCreate () { }, //生命周期 - 创建之前
+    beforeMount () { }, //生命周期 - 挂载之前
+    beforeUpdate () { }, //生命周期 - 更新之前
+    updated () { }, //生命周期 - 更新之后
+    beforeDestroy () {
+    }, //生命周期 - 销毁之前
+    destroyed () {
+    }, //生命周期 - 销毁完成
+    activated () { }, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</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 {
+        height: 24px;
+        float: left;
+    }
+}
+</style>

+ 432 - 0
src/components/Adult/preview/components/Practice.vue

@@ -0,0 +1,432 @@
+<!--  -->
+<template>
+  <div class="practice practiceSingle">
+    <div
+      :key="item.con + index"
+      class="Book_content"
+      v-for="(item, index) in cur.stem"
+    >
+      <!-- <img
+        @click="changePraShow()"
+        class="close-icon"
+        src="../../assets/common/close-icon.png"
+      /> -->
+      <div class="left-content">
+        <Audio :mp3="item.mp3_url" :pinyin="item.pinyin" />
+
+        <div class="strockplay">
+          <Strockplay
+            :Book_text="item.con"
+            :playStorkes="cur.playStorkes"
+            :targetDiv="'pra' + item.con + index"
+          />
+        </div>
+        <div class="footer">
+          <!-- <div @click="collectFlag = !collectFlag" class="bg-box">
+            <img
+              :src="
+                collectFlag
+                  ? require('../../assets/common/coll-icon-1.png')
+                  : require('../../assets/common/coll-icon.png')
+              "
+              class="practice-icon"
+            />
+          </div> -->
+          <div @click="changeLearnMode(1)" class="bg-box">
+            <!-- <img
+              class="practice-icon"
+              src="../../assets/common/dict-icon.png"
+            /> -->
+          </div> 
+          <div @click="changeLearnMode(2)" class="bg-box">
+            <!-- <img
+              class="practice-icon"
+              src="../../assets/common/write-icon-1.png"
+            /> -->
+          </div>
+        </div>
+      </div>
+      <template v-if="learn_mode == 2">
+        <div class="right-content">
+          <ul class="nav-list">
+            <li :class="navIndex == 0 ? 'active' : ''" @click="changeNav(0)">
+              描红模式
+            </li>
+            <li :class="navIndex == 1 ? 'active' : ''" @click="changeNav(1)">
+              自由书写
+            </li>
+          </ul>
+
+          <div class="right-strockred">
+            <template v-if="navIndex == 0">
+              <Strockred
+                :Book_text="cur.stem[0].con"
+                :hanzicolor="hanzicolor"
+                :playStorkes="playStorkes"
+                :targetDiv="'write-pra' + cur.stem[0].con"
+              />
+            </template>
+            <template v-else>
+              <Freewrite
+                :cur="cur"
+                :lineColor="hanzicolor"
+                :lineWidth="hanziweight"
+                ref="freewrite"
+              />
+            </template>
+          </div>
+
+          <div class="footer">
+            <div class="pen-colors">
+              <!-- <img
+                class="write-icon-3"
+                src="../../assets/common/write-icon-3.png"
+              /> -->
+              <ul class="colors-list">
+                <li
+                  :class="
+                    colorIndex == index ? 'color-item-active' + index : ''
+                  "
+                  :key="'color' + index"
+                  @click="changeColor(index)"
+                  v-for="(item, index) in 5"
+                >
+                  <span :class="'color-item' + index"></span>
+                </li>
+              </ul>
+              <!-- <img
+                @click="resetHuahua(index)"
+                class="clean-btn"
+                src="../../assets/common/icon-clean.png"
+              /> -->
+            </div>
+            <div class="pen" v-if="navIndex == 1">
+              <img
+                :src="penIndex == 0 ? thinpenActive : thinpen"
+                @click="changePen(0)"
+                class="pen-img"
+              />
+              <img
+                :src="penIndex == 1 ? thickpenActive : thickpen"
+                @click="changePen(1)"
+                class="pen-img"
+              />
+            </div>
+          </div>
+        </div>
+      </template>
+      <template v-else>
+        <ChinaDict :cur="cur" />
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+// import Strockplay from "../common/Strockplay";
+// import Strockred from "../common/Strockred";
+// import Freewrite from "../common/Freewrite";
+// import ChinaDict from "../common/ChinaDict";
+// import Audio from "../common/Audio";
+export default {
+  components: {
+    // Strockplay,
+    // Strockred,
+    // Freewrite,
+    // ChinaDict,
+    // Audio,
+  },
+  props: ["cur", "changePraShow"],
+  data() {
+    return {
+    //   learn_mode: "",
+    //   playStorkes: false,
+    //   navIndex: 0,
+    //   colorsList: ["#404040", "#f65d4d", "#19b068", "#52a1ea", "#ff8c49"],
+    //   weightList: [6, 10],
+    //   colorIndex: 0,
+    //   penIndex: 0,
+    //   hanzicolor: "",
+    //   hanziweight: "",
+    //   thinpen: require("../../assets/common/thin-pen.png"), //细笔
+    //   thinpenActive: require("../../assets/common/thin-pen-active.png"),
+    //   thickpen: require("../../assets/common/thick-pen.png"),
+    //   thickpenActive: require("../../assets/common/thick-pen-active.png"),
+    //   collectFlag: false, // 是否收藏
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    changeNav(index) {
+      this.navIndex = index;
+    },
+    changeColor(index) {
+      let _this = this;
+      _this.colorIndex = index;
+      let color = _this.colorsList[index];
+      _this.hanzicolor = color;
+    },
+    changePen(index) {
+      let _this = this;
+      _this.penIndex = index;
+      _this.hanziweight = _this.weightList[_this.penIndex];
+    },
+    changeLearnMode(mode) {
+      this.learn_mode = mode;
+    },
+    resetHuahua(index) {
+      console.log(this.$refs.freewrite);
+      this.$refs.freewrite[index].handelReset();
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    // console.log(this.cur);
+    // let _this = this;
+    // let color = _this.colorsList[_this.colorIndex];
+    // _this.hanzicolor = color;
+    // _this.hanziweight = 6;
+    // if (_this.cur) {
+    //   _this.learn_mode = _this.cur.learn_mode ? _this.cur.learn_mode : 2;
+    // }
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+// .practice {
+//   width: 1368px;
+//   max-height: 840px;
+//   overflow: auto;
+//   margin: 0 auto;
+//   background: #21ba71;
+//   box-shadow: inset 0px 4px 0px rgba(255, 255, 255, 0.25);
+//   border-radius: 40px;
+//   .clean-btn {
+//     width: 34px;
+//     margin: 0 16px;
+//     cursor: pointer;
+//   }
+//   .close-icon {
+//     position: absolute;
+//     top: 18px;
+//     right: 18px;
+//     width: 84px;
+//     height: 84px;
+//     cursor: pointer;
+//   }
+//   .Book_content {
+//     width: 100%;
+//     height: 100%;
+//     display: flex;
+//     box-sizing: border-box;
+//     padding: 72px 48px 48px;
+//     position: relative;
+//     align-items: flex-start;
+//   }
+//   .left-content {
+//     display: flex;
+//     flex-direction: column;
+//     justify-content: center;
+//   }
+//   .right-content {
+//     position: relative;
+//     width: 720px;
+//     height: 720px;
+//     background: #ffffff;
+//     box-shadow: 0px 6px 0px rgba(0, 149, 78, 0.4);
+//     border-radius: 24px;
+//     box-sizing: border-box;
+//     padding: 42px 40px 24px 40px;
+//     display: flex;
+//     flex-direction: column;
+//     justify-content: flex-start;
+//     align-items: center;
+//     margin-left: 64px;
+//     .nav-list {
+//       width: 312px;
+//       height: 44px;
+//       background: rgba(49, 212, 134, 0.2);
+//       border-radius: 240px;
+//       display: flex;
+//       justify-content: flex-start;
+//       align-items: center;
+//       padding: 0;
+//       margin-bottom: 44px;
+//       list-style: none;
+//       > li {
+//         height: 52px;
+//         width: 156px;
+//         text-align: center;
+//         font-style: normal;
+//         font-weight: bold;
+//         font-size: 28px;
+//         line-height: 52px;
+//         color: #19b068;
+//         cursor: pointer;
+//         &.active {
+//           background: #19b068;
+//           border-radius: 240px;
+//           color: #ffffff;
+//         }
+//       }
+//     }
+//     .right-strockred {
+//       width: 448px;
+//       height: 448px;
+//     }
+//     .footer {
+//       position: absolute;
+//       bottom: 24px;
+//       width: 640px;
+//       display: flex;
+//       justify-content: space-between;
+//       align-items: center;
+//       .pen-colors {
+//         display: flex;
+//         justify-content: flex-start;
+//         align-items: center;
+//         .write-icon-3 {
+//           width: 25px;
+//           height: 37px;
+//           margin-right: 26px;
+//         }
+//         .colors-list {
+//           display: flex;
+//           justify-content: flex-start;
+//           align-items: center;
+//           margin: 0;
+//           padding: 0;
+//           > li {
+//             width: 34px;
+//             height: 34px;
+//             border: 2px solid #fff;
+//             box-sizing: border-box;
+//             background: #fff;
+//             margin: 0 8px;
+//             display: flex;
+//             justify-content: center;
+//             align-items: center;
+//             border-radius: 100%;
+//             cursor: pointer;
+//             > span {
+//               width: 26px;
+//               height: 26px;
+//               border-radius: 100%;
+//               &.color-item0 {
+//                 background: #404040;
+//               }
+//               &.color-item1 {
+//                 background: #f65d4d;
+//               }
+//               &.color-item2 {
+//                 background: #19b068;
+//               }
+//               &.color-item3 {
+//                 background: #52a1ea;
+//               }
+//               &.color-item4 {
+//                 background: #ff8c49;
+//               }
+//             }
+
+//             &.color-item-active0 {
+//               border: 2px solid #404040;
+//             }
+//             &.color-item-active1 {
+//               border: 2px solid #f65d4d;
+//             }
+//             &.color-item-active2 {
+//               border: 2px solid #19b068;
+//             }
+//             &.color-item-active3 {
+//               border: 2px solid #52a1ea;
+//             }
+//             &.color-item-active4 {
+//               border: 2px solid #ff8c49;
+//             }
+//           }
+//         }
+//       }
+//       .pen {
+//         display: flex;
+//         justify-content: flex-start;
+//         align-items: center;
+//         > img {
+//           width: 42px;
+//           height: 38px;
+//           margin-left: 9px;
+//           cursor: pointer;
+//         }
+//       }
+//     }
+//   }
+// }
+// .strockplay {
+//   margin-bottom: 41px;
+//   width: 444px;
+//   height: 444px;
+//   border-radius: 24px;
+//   box-shadow: 0px 6px 0px rgba(0, 149, 78, 0.4);
+// }
+// .footer {
+//   width: 100%;
+//   display: flex;
+//   justify-content: center;
+//   align-items: center;
+//   cursor: pointer;
+//   .bg-box {
+//     width: 124px;
+//     height: 72px;
+//     background: url("../../assets/common/bg-green.png") center no-repeat;
+//     background-size: 100% 100%;
+//     text-align: center;
+//     &:nth-child(2) {
+//       margin: 0 24px;
+//     }
+//   }
+//   .bg-box:active {
+//     background: url("../../assets/common/bg-green-click.png") center no-repeat;
+//     background-size: 100% 100%;
+//     .practice-icon {
+//       margin-top: 15px;
+//     }
+//   }
+//   .practice-icon {
+//     height: 36px;
+//     margin-top: 12px;
+//   }
+//   > span {
+//     margin-bottom: 9px;
+//     font-weight: 600;
+//     font-family: "FZJCGFKTK";
+//     font-size: 24px;
+//     line-height: 34px;
+//     /* identical to box height */
+
+//     text-align: center;
+
+//     color: #ba7d21;
+//   }
+// }
+
+</style>
+<style lang="scss">
+.practiceSingle {
+  .strock-play-box {
+    width: 84px !important;
+    height: 84px !important;
+  }
+}
+</style>

+ 472 - 0
src/components/Adult/preview/components/Practicewords.vue

@@ -0,0 +1,472 @@
+<!--  -->
+<template>
+  <div class="practice">
+    <div
+      :key="item.con + index"
+      class="Book_content"
+      v-for="(item, index) in cur.stem"
+    >
+      <!-- <img
+        @click="changePraShow()"
+        class="close-icon"
+        src="../../assets/common/close-icon.png"
+      /> -->
+      <div class="left-content">
+        <Audio :mp3="item.mp3_url" :pinyin="item.pinyin" />
+        <div class="strockplay_box">
+          <div
+            :key="conindex"
+            class="strockplay"
+            v-for="(conItem, conindex) in item.con"
+          >
+            <Strockplay
+              :Book_text="conItem"
+              :playStorkes="true"
+              :targetDiv="'pra' + conindex"
+              wordNum="2"
+            />
+          </div>
+        </div>
+        <div class="footer">
+          <!-- <div @click="collectFlag = !collectFlag" class="bg-box">
+            <img
+              :src="
+                collectFlag
+                  ? require('../../assets/common/coll-icon-1.png')
+                  : require('../../assets/common/coll-icon.png')
+              "
+              class="practice-icon"
+            />
+          </div> -->
+          <div @click="changeLearnMode(1)" class="bg-box">
+            <!-- <img
+              class="practice-icon"
+              src="../../assets/common/dict-icon.png"
+            /> -->
+          </div>
+          <div @click="changeLearnMode(2)" class="bg-box">
+            <!-- <img
+              class="practice-icon"
+              src="../../assets/common/write-icon-1.png"
+            /> -->
+          </div>
+        </div>
+      </div>
+      <template v-if="learn_mode == 2">
+        <div class="right-content">
+          <ul class="nav-list">
+            <li :class="navIndex == 0 ? 'active' : ''" @click="changeNav(0)">
+              描红模式
+            </li>
+            <li :class="navIndex == 1 ? 'active' : ''" @click="changeNav(1)">
+              自由书写
+            </li>
+          </ul>
+
+          <div class="right-strockred">
+            <template v-if="navIndex == 0">
+              <div class="strockred_con">
+                <div
+                  :key="'write-pra' + conindex"
+                  class="strockred_box"
+                  v-for="(conItem, conindex) in cur.stem[0].con"
+                >
+                  <Strockred
+                    :Book_text="conItem"
+                    :hanzicolor="hanzicolor"
+                    :playStorkes="playStorkes"
+                    :targetDiv="'write-pra' + conindex"
+                    wordNum="2"
+                  />
+                </div>
+              </div>
+            </template>
+            <template v-else>
+              <Freewrite
+                :cur="cur"
+                :lineColor="hanzicolor"
+                :lineWidth="hanziweight"
+                ref="freewrite"
+                wordNum="2"
+              />
+            </template>
+          </div>
+
+          <div class="footer">
+            <div class="pen-colors">
+              <!-- <img
+                class="write-icon-3"
+                src="../../assets/common/write-icon-3.png"
+              /> -->
+              <ul class="colors-list">
+                <li
+                  :class="
+                    colorIndex == index ? 'color-item-active' + index : ''
+                  "
+                  :key="'color' + index"
+                  @click="changeColor(index)"
+                  v-for="(item, index) in 5"
+                >
+                  <span :class="'color-item' + index"></span>
+                </li>
+              </ul>
+              <!-- <img
+                @click="resetHuahua(index)"
+                class="clean-btn"
+                src="../../assets/common/icon-clean.png"
+              /> -->
+            </div>
+            <div class="pen" v-if="navIndex == 1">
+              <img
+                :src="penIndex == 0 ? thinpenActive : thinpen"
+                @click="changePen(0)"
+                class="pen-img"
+              />
+              <img
+                :src="penIndex == 1 ? thickpenActive : thickpen"
+                @click="changePen(1)"
+                class="pen-img"
+              />
+            </div>
+          </div>
+        </div>
+      </template>
+      <template v-else>
+        <ChinaDict :cur="cur" wordNum="2" />
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+// import Strockplay from "../common/Strockplay";
+// import Strockred from "../common/Strockred";
+// import Freewrite from "../common/Freewrite";
+// import ChinaDict from "../common/ChinaDict";
+// import Audio from "../common/Audio";
+export default {
+  components: {
+    // Strockplay,
+    // Strockred,
+    // Freewrite,
+    // ChinaDict,
+    // Audio,
+  },
+  props: ["cur", "changePraShow"],
+  data() {
+    return {
+    //   learn_mode: "",
+    //   playStorkes: false,
+    //   navIndex: 0,
+    //   colorsList: ["#404040", "#f65d4d", "#19b068", "#52a1ea", "#ff8c49"],
+    //   weightList: [6, 10],
+    //   colorIndex: 0,
+    //   penIndex: 0,
+    //   hanzicolor: "",
+    //   hanziweight: "",
+    //   thinpen: require("../../assets/common/thin-pen.png"), //细笔
+    //   thinpenActive: require("../../assets/common/thin-pen-active.png"),
+    //   thickpen: require("../../assets/common/thick-pen.png"),
+    //   thickpenActive: require("../../assets/common/thick-pen-active.png"),
+    //   collectFlag: false, // 是否收藏
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    changeNav(index) {
+      this.navIndex = index;
+    },
+    changeColor(index) {
+      let _this = this;
+      _this.colorIndex = index;
+      let color = _this.colorsList[index];
+      _this.hanzicolor = color;
+    },
+    changePen(index) {
+      let _this = this;
+      _this.penIndex = index;
+      _this.hanziweight = _this.weightList[_this.penIndex];
+    },
+    changeLearnMode(mode) {
+      this.learn_mode = mode;
+    },
+    resetHuahua(index) {
+      this.$refs.freewrite[index].handelReset();
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    let _this = this;
+    let color = _this.colorsList[_this.colorIndex];
+    _this.hanzicolor = color;
+    _this.hanziweight = 6;
+    if (_this.cur) {
+      _this.learn_mode = _this.cur.learn_mode ? _this.cur.learn_mode : 2;
+    }
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    console.log(this.cur);
+  },
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+// .practice {
+//   width: 1368px;
+//   max-height: 840px;
+//   overflow: auto;
+//   margin: 0 auto;
+//   background: #21ba71;
+//   box-shadow: inset 0px 4px 0px rgba(255, 255, 255, 0.25);
+//   border-radius: 40px;
+//   .clean-btn {
+//     width: 34px;
+//     margin: 0 16px;
+//     cursor: pointer;
+//   }
+//   .close-icon {
+//     position: absolute;
+//     top: 18px;
+//     right: 18px;
+//     width: 84px;
+//     height: 84px;
+//     cursor: pointer;
+//   }
+//   .Book_content {
+//     width: 100%;
+//     height: 100%;
+//     box-sizing: border-box;
+//     padding: 72px 48px 48px;
+//     position: relative;
+//   }
+//   .left-content {
+//     width: 100%;
+//     display: flex;
+//     flex-direction: column;
+//     justify-content: center;
+
+//     .strockplay_box {
+//       display: flex;
+//       justify-content: center;
+//       align-items: center;
+//       flex-wrap: wrap;
+//       margin-bottom: 38px;
+//       padding-top: 24px;
+//       .strockplay {
+//         width: 252px;
+//         height: 252px;
+//         margin: 0 12px;
+//         margin-bottom: 10px;
+//       }
+//     }
+//     .footer {
+//       width: 100%;
+//       display: flex;
+//       justify-content: center;
+//       align-items: center;
+//       cursor: pointer;
+//       margin-bottom: 36px;
+//       .bg-box {
+//         width: 144px;
+//         height: 72px;
+//         background: url("../../assets/common/bg-green.png") center no-repeat;
+//         background-size: 100% 100%;
+//         text-align: center;
+//         &:nth-child(2) {
+//           margin: 0 24px;
+//         }
+//       }
+//       .bg-box:active {
+//         background: url("../../assets/common/bg-green-click.png") center
+//           no-repeat;
+//         background-size: 100% 100%;
+//         .practice-icon {
+//           margin-top: 15px;
+//         }
+//       }
+//       .practice-icon {
+//         height: 36px;
+//         margin-top: 12px;
+//       }
+//       > span {
+//         margin-bottom: 9px;
+//         font-weight: 600;
+//         font-family: "FZJCGFKTK";
+//         font-size: 24px;
+//         line-height: 34px;
+//         /* identical to box height */
+
+//         text-align: center;
+
+//         color: #ba7d21;
+//       }
+//     }
+//   }
+//   .right-content {
+//     position: relative;
+//     width: 100%;
+//     background: #ffffff;
+//     box-shadow: 0px 6px 0px rgba(0, 149, 78, 0.4);
+//     border-radius: 24px;
+//     box-sizing: border-box;
+//     padding: 42px 40px 24px 40px;
+//     display: flex;
+//     flex-direction: column;
+//     justify-content: flex-start;
+//     align-items: center;
+//     .nav-list {
+//       width: 312px;
+//       height: 44px;
+//       background: rgba(49, 212, 134, 0.2);
+//       border-radius: 240px;
+//       display: flex;
+//       justify-content: flex-start;
+//       align-items: center;
+//       padding: 0;
+//       margin-bottom: 44px;
+//       list-style: none;
+//       > li {
+//         height: 52px;
+//         width: 156px;
+//         text-align: center;
+//         font-style: normal;
+//         font-weight: bold;
+//         font-size: 28px;
+//         line-height: 52px;
+//         color: #19b068;
+//         cursor: pointer;
+//         &.active {
+//           background: #19b068;
+//           border-radius: 240px;
+//           color: #ffffff;
+//         }
+//       }
+//     }
+//     .right-strockred {
+//       width: 100%;
+//       padding-bottom: 80px;
+//     }
+//     .strockred_con {
+//       display: flex;
+//       justify-content: center;
+//       align-items: center;
+//       flex-wrap: wrap;
+//       width: 100%;
+//       padding: 0 100px;
+//     }
+//     .strockred_box {
+//       width: 220px;
+//       height: 220px;
+//       padding: 12px 12px;
+//     }
+//     .footer {
+//       position: absolute;
+//       bottom: 24px;
+//       left: 40px;
+//       width: 1223px;
+//       display: flex;
+//       justify-content: space-between;
+//       align-items: center;
+//       .pen-colors {
+//         display: flex;
+//         justify-content: flex-start;
+//         align-items: center;
+//         .write-icon-3 {
+//           width: 25px;
+//           height: 37px;
+//           margin-right: 26px;
+//         }
+//         .colors-list {
+//           display: flex;
+//           justify-content: flex-start;
+//           align-items: center;
+//           margin: 0;
+//           padding: 0;
+//           > li {
+//             width: 34px;
+//             height: 34px;
+//             border: 2px solid #fff;
+//             box-sizing: border-box;
+//             background: #fff;
+//             margin: 0 8px;
+//             display: flex;
+//             justify-content: center;
+//             align-items: center;
+//             border-radius: 100%;
+//             cursor: pointer;
+//             > span {
+//               width: 26px;
+//               height: 26px;
+//               border-radius: 100%;
+//               &.color-item0 {
+//                 background: #404040;
+//               }
+//               &.color-item1 {
+//                 background: #f65d4d;
+//               }
+//               &.color-item2 {
+//                 background: #19b068;
+//               }
+//               &.color-item3 {
+//                 background: #52a1ea;
+//               }
+//               &.color-item4 {
+//                 background: #ff8c49;
+//               }
+//             }
+
+//             &.color-item-active0 {
+//               border: 2px solid #404040;
+//             }
+//             &.color-item-active1 {
+//               border: 2px solid #f65d4d;
+//             }
+//             &.color-item-active2 {
+//               border: 2px solid #19b068;
+//             }
+//             &.color-item-active3 {
+//               border: 2px solid #52a1ea;
+//             }
+//             &.color-item-active4 {
+//               border: 2px solid #ff8c49;
+//             }
+//           }
+//         }
+//       }
+//       .pen {
+//         display: flex;
+//         justify-content: flex-start;
+//         align-items: center;
+//         > img {
+//           width: 42px;
+//           height: 38px;
+//           margin-left: 9px;
+//           cursor: pointer;
+//         }
+//       }
+//     }
+//   }
+//   .Chineseexplain {
+//     margin: 0;
+//     width: auto;
+//   }
+// }
+</style>
+<style lang="scss">
+.practice {
+  .strock-play-box {
+    width: 48px;
+    height: 48px;
+  }
+}
+</style>

+ 117 - 0
src/components/Adult/preview/components/Strockplayredline.vue

@@ -0,0 +1,117 @@
+<!--  -->
+<template>
+  <div class="strockplayRedInner">
+    <div @click="playHanzi" class="strock-play-box" v-if="playStorkes"></div>
+
+    <div :id="targetDiv" class="character-target-div"></div>
+  </div>
+</template>
+
+<script>
+const HanziWriter = require("hanzi-writer");
+export default {
+  components: {},
+  props: ["targetDiv", "Book_text", "playStorkes", "strokeColor", "wordNum"],
+  data() {
+    return {
+      writer: null,
+    };
+  },
+  computed: {},
+  watch: {
+    targetDiv: {
+      handler: function (val, oldVal) {
+        if (val != oldVal) {
+          let _this = this;
+          _this.$nextTick(() => {
+            _this.initHanziwrite();
+          });
+        }
+      },
+      // 深度观察监听
+      deep: true,
+    },
+  },
+  //方法集合
+  methods: {
+    initHanziwrite() {
+      let _this = this;
+      _this.writer = null;
+      //var ren = require("hanzi-writer-data/国");
+      _this.writer = HanziWriter.default.create(
+        _this.targetDiv,
+        _this.Book_text,
+        {
+          padding: 5,
+          showOutline: true,
+          strokeColor: _this.strokeColor ? _this.strokeColor : "#000",
+        }
+      );
+    },
+    playHanzi() {
+      let _this = this;
+      _this.writer.animateCharacter();
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    // let _this = this;
+    // _this.$nextTick(() => {
+    //   _this.initHanziwrite();
+    // });
+  },
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.strockplayRedInner {
+  position: relative;
+
+  width: 126px; //444px
+  height: 100%; //480px
+}
+
+.character-target-div {
+  width: 126px;
+  height: 126px;
+  background: #fff url("../../../../assets/NPC/chinaTianRed.png") center no-repeat;
+  background-size: 100% 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 99999;
+  font-family: "FZJCGFKTK";
+}
+.strock-play-box {
+  position: absolute;
+  right: -1px;
+  top: -1px;
+  z-index: 999;
+  width: 32px;
+  height: 32px;
+  background: url("../../../../assets/NPC/strock-play-red-click.png");
+  background-size: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  cursor: pointer;
+}
+.strock-play-box:active {
+  background: url("../../../../assets/NPC/strock-play-red-click.png");
+  background-size: 100%;
+}
+.animate-butto {
+  width: 240px;
+  height: 160px;
+  font-size: 28px;
+}
+</style>

+ 279 - 0
src/components/Adult/preview/components/Wordcard.vue

@@ -0,0 +1,279 @@
+<!--  -->
+<template>
+  <div class="wordCard" v-if="word">
+    <div class="closeBox">
+      <i class="el-icon-close" @click="changeWordCard(false)"></i>
+    </div>
+    <div class="bwc-top" v-if="word.detail">
+      <Audio
+        :fontSize="20"
+        :mp3="word.detail.mp3_url ? word.detail.mp3_url : ''"
+        :pinyin="word.detail.pinyin"
+      />
+    </div>
+    <div
+      class="bwc-Strockplay"
+      :style="{ width: word.detail.new_word.length * 126 + 6 + 'px' }"
+      v-if="word.detail.new_word.length<5"
+    >
+      <div
+        :key="conindex"
+        class="strockplay"
+        v-for="(conItem, conindex) in word.detail.new_word"
+      >
+        <Strockplayredline
+          :Book_text="conItem"
+          :playStorkes="true"
+          :targetDiv="'bwcHanziIntp' + conItem + conindex"
+          :wordNum="word.detail.new_word.length"
+        />
+        <div class="bwc-line" v-if="conindex < word.detail.new_word.length - 1"></div>
+      </div>
+    </div>
+    <p v-else class="bwc-tolength"><span v-for="(item,index) in word.detail.new_word" :key="index">{{item}}</span></p>
+    <div class="bwc-word-en" v-if="word.detail && word.detail.en">spring</div>
+    <div class="bwc-more-intp" @click="viewIntp">更多释义</div>
+    <div class="bwc-footer">
+      <button class="bwc-btn">
+        <!-- <img
+          src="../../assets/common/icon-collect-red.png"
+          class="collect-icon"
+        /> -->
+        收藏
+      </button>
+      <button class="bwc-btn" @click="writeWord">
+        <!-- <img
+          src="../../assets/common/icon-write-red.png"
+          class="collect-icon"
+        /> -->
+        写一写
+      </button>
+    </div>
+    <div class="practiceBox" v-if="isPraShow">
+      <template v-if="word.list.length < 2 && curData">
+        <Practice :changePraShow="changePraShow" :cur="curData" />
+      </template>
+      <template v-if="word.list.length > 1 && curData">
+        <Practicewords :changePraShow="changePraShow" :cur="curData" />
+      </template>
+    </div>
+    <div class="practiceBox" v-if="isIntpShow">
+      <Wordintp :changeIntpShow="changeIntpShow" :word="word" />
+    </div>
+  </div>
+</template>
+
+<script>
+import Audio from "./AudioRed.vue";
+import Strockplayredline from "./Strockplayredline.vue";
+import Practice from "./Practice.vue";
+import Practicewords from "./Practicewords.vue";
+import Wordintp from "./Wordintp.vue";
+import { getHZChineseInfo } from "@/api/ajax";
+
+export default {
+  name: "Wordcard",
+  components: {
+    Strockplayredline,
+    Audio,
+    Practice,
+    Practicewords,
+    Wordintp,
+  },
+  props: ["word", "changeWordCard"],
+  data() {
+    return {
+      isPraShow: false,
+      isIntpShow: false,
+      curData: null,
+    };
+  },
+  computed: {},
+  watch: {
+    word: {
+      handler: function (val, oldVal) {
+        let _this = this;
+        this.curData = {
+          stem: [
+            {
+              con: val.detail && val.detail.new_word ? val.detail.new_word : "",
+              pinyin: val.detail && val.detail.pinyin ? val.detail.pinyin : "",
+              mp3_url: "",
+            },
+          ],
+        };
+      },
+      // 深度观察监听
+      deep: true,
+    },
+  },
+  //方法集合
+  methods: {
+    writeWord() {
+      this.isPraShow = true;
+    },
+    changePraShow() {
+      this.isPraShow = false;
+    },
+    viewIntp() {
+      this.isIntpShow = true;
+    },
+    changeIntpShow() {
+      this.isIntpShow = false;
+    },
+    getChineseInfo(){
+        let data = {
+            query: this.word.detail.new_word,
+        };
+      getHZChineseInfo(data).then((res) => {
+        
+      });
+    }
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+      console.log(this.word)
+      this.getChineseInfo()
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    if (this.word) {
+      this.curData = {
+        stem: [
+          {
+            con:
+              _this.word.detail && _this.word.detail.new_word
+                ? _this.word.detail.new_word
+                : "",
+            pinyin:
+              _this.word.detail && _this.word.detail.pinyin
+                ? _this.word.detail.pinyin
+                : "",
+            mp3_url: "",
+          },
+        ],
+      };
+    }
+  },
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.wordCard {
+  .practiceBox {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 999;
+    width: 100%;
+    height: 100vh;
+    background: rgba(0, 0, 0, 0.19);
+    padding-top: 32px;
+    box-sizing: border-box;
+    overflow: hidden;
+    overflow-y: auto;
+  }
+  .closeBox {
+    width: 100%;
+    display: flex;
+    justify-content: flex-end;
+    > i {
+      cursor: pointer;
+    }
+  }
+  min-width: 312px;
+  min-height: 360px;
+  background: #ffffff;
+  box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.15);
+  border-radius: 8px;
+  padding: 24px;
+  box-sizing: border-box;
+  .bwc-top {
+    margin-bottom: 16px;
+    width: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .bwc-Strockplay {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    min-width: 130px;
+    height: 130px;
+    margin: 0 auto;
+    margin-bottom: 16px;
+    border: 2px solid #ff5757;
+    border-radius: 8px;
+    box-sizing: border-box;
+    .strockplay {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
+    .bwc-line {
+      width: 2px;
+      height: 126px;
+      background: #ff5757;
+    }
+  }
+  .bwc-tolength{
+      color: #404040;
+      font-size: 30px;
+      line-height: 1.5;
+      font-family: FZJCGFKTK;
+      text-align: center;
+  }
+  .bwc-word-en {
+    font-style: normal;
+    font-weight: 600;
+    font-size: 20px;
+    line-height: 150%;
+    text-align: center;
+    color: #2c2c2c;
+    margin-bottom: 8px;
+  }
+  .bwc-more-intp {
+    font-weight: normal;
+    font-size: 14px;
+    line-height: 20px;
+    color: #2c2c2c;
+    opacity: 0.5;
+    text-align: center;
+    margin-bottom: 24px;
+    cursor: pointer;
+  }
+  .bwc-footer {
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    > button {
+      width: 128px;
+      height: 40px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #ff5757;
+      background: rgba(255, 87, 87, 0.1);
+      border-radius: 4px;
+      outline: 0;
+      border: 0;
+      cursor: pointer;
+      > img {
+        width: 24px;
+        height: 24px;
+        margin-right: 8px;
+      }
+    }
+  }
+}
+</style>

+ 232 - 0
src/components/Adult/preview/components/Wordintp.vue

@@ -0,0 +1,232 @@
+<!--  -->
+<template>
+  <div class="wordIntp" v-if="word">
+    <div class="closeBox">
+      <i class="el-icon-close" @click="changeIntpShow(false)"></i>
+    </div>
+    <div class="bwc-top" v-if="word.detail">
+      <Audio
+        :fontSize="20"
+        :mp3="word.detail.mp3_url ? word.detail.mp3_url : ''"
+        :pinyin="word.detail.pinyin"
+      />
+    </div>
+    <div
+      class="bwc-Strockplay"
+      :style="{ width: word.list.length * 126 + 8 + 'px' }"
+      v-if="word.list.length<5"
+    >
+      <div
+        :key="conindex"
+        class="strockplay"
+        v-for="(conItem, conindex) in word.list"
+      >
+        <Strockplayredline
+          :Book_text="conItem"
+          :playStorkes="true"
+          :targetDiv="'bwcIntp' + conItem + conindex"
+          :wordNum="word.list.length"
+        />
+        <div class="bwc-line" v-if="conindex < word.list.length - 1"></div>
+      </div>
+    </div>
+    <p v-else class="bwc-tolength"><span v-for="(item,index) in word.list" :key="index">{{item}}</span></p>
+    <el-menu
+      :default-active="activeIndex"
+      class="el-menu-demo"
+      mode="horizontal"
+      @select="handleSelect"
+    >
+      <el-menu-item index="1">释义</el-menu-item>
+      <el-menu-item index="2" disabled>近/反义词</el-menu-item>
+      <el-menu-item index="3" disabled>造句</el-menu-item>
+    </el-menu>
+    <template v-if="activeIndex == '1'">
+      <ul class="bwc-intp" v-if="word.detail">
+        <li v-for="(item, index) in word.detail.definition_list" :key="index">
+          {{ item }}
+        </li>
+      </ul>
+    </template>
+  </div>
+</template>
+
+<script>
+// import Audio from "./Audio.vue";
+// import Strockplayredline from "./Strockplayredline.vue";
+
+export default {
+  name: "WordIntp",
+  components: {
+    // Strockplayredline,
+    // Audio,
+  },
+  props: ["word", "changeIntpShow"],
+  data() {
+    return {
+      isPraShow: false,
+      curData: null,
+      activeIndex: "1",
+    };
+  },
+  computed: {},
+  watch: {
+    word: {
+      handler: function (val, oldVal) {
+        let _this = this;
+      },
+      // 深度观察监听
+      deep: true,
+    },
+  },
+  //方法集合
+  methods: {
+    writeWord() {
+      this.isPraShow = true;
+    },
+    changePraShow() {
+      this.isPraShow = false;
+    },
+    handleSelect() {},
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    console.log(this.word);
+  },
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.wordIntp {
+  width: 600px;
+  height: 100vh;
+  overflow: hidden;
+  overflow-y: auto;
+  margin: 0 auto;
+  .bwc-intp {
+    > li {
+      font-weight: normal;
+      font-size: 16px;
+      line-height: 150%;
+      color: #2c2c2c;
+    }
+  }
+  .practiceBox {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 999;
+    width: 100%;
+    height: 100vh;
+    background: rgba(0, 0, 0, 0.19);
+    padding-top: 32px;
+    box-sizing: border-box;
+    overflow: hidden;
+    overflow-y: auto;
+  }
+  .closeBox {
+    width: 100%;
+    display: flex;
+    justify-content: flex-end;
+    > i {
+      cursor: pointer;
+    }
+  }
+  min-width: 312px;
+  min-height: 360px;
+  background: #ffffff;
+  box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.15);
+  border-radius: 8px;
+  padding: 24px;
+  box-sizing: border-box;
+  .bwc-top {
+    margin-bottom: 16px;
+    width: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .bwc-Strockplay {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    min-width: 130px;
+    height: 130px;
+    margin: 0 auto;
+    margin-bottom: 16px;
+    border: 2px solid #ff5757;
+    border-radius: 8px;
+    box-sizing: border-box;
+    .strockplay {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
+    .bwc-line {
+      width: 2px;
+      height: 126px;
+      background: #ff5757;
+    }
+  }
+  .bwc-tolength{
+      color: #404040;
+      font-size: 30px;
+      line-height: 1.5;
+      font-family: FZJCGFKTK;
+      text-align: center;
+  }
+  .bwc-word-en {
+    font-style: normal;
+    font-weight: 600;
+    font-size: 20px;
+    line-height: 150%;
+    text-align: center;
+    color: #2c2c2c;
+    margin-bottom: 8px;
+  }
+  .bwc-more-intp {
+    font-weight: normal;
+    font-size: 14px;
+    line-height: 20px;
+    color: #2c2c2c;
+    opacity: 0.5;
+    text-align: center;
+    margin-bottom: 24px;
+    cursor: pointer;
+  }
+  .bwc-footer {
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    > button {
+      width: 128px;
+      height: 40px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #ff5757;
+      background: rgba(255, 87, 87, 0.1);
+      border-radius: 4px;
+      outline: 0;
+      border: 0;
+      cursor: pointer;
+      > img {
+        width: 24px;
+        height: 24px;
+        margin-right: 8px;
+      }
+    }
+  }
+}
+</style>