Browse Source

Merge branch 'NPC-lhd'

natasha 4 years ago
parent
commit
3112f25ad9
25 changed files with 5285 additions and 166 deletions
  1. 21 3
      src/api/ajax.js
  2. BIN
      src/assets/NPC/chinaTianRed.png
  3. BIN
      src/assets/NPC/strock-play-red-click.png
  4. 29 28
      src/components/Adult/Preview.vue
  5. 88 0
      src/components/Adult/inputModules/ArticleTemChs/components/ArticleChs.vue
  6. 10 9
      src/components/Adult/inputModules/ArticleTemChs/components/ClauseresultChs.vue
  7. 11 6
      src/components/Adult/inputModules/ArticleTemChs/components/ParagraphChs.vue
  8. 1 0
      src/components/Adult/inputModules/ArticleTemChs/components/SegbywordChs.vue
  9. 2951 21
      src/components/Adult/inputModules/ArticleTemChs/index.vue
  10. 73 0
      src/components/Adult/inputModules/DialogueArticleChs/components/ArticleChs.vue
  11. 10 10
      src/components/Adult/inputModules/DialogueArticleChs/components/ParagraphChs.vue
  12. 129 0
      src/components/Adult/inputModules/DialogueArticleChs/components/Pinyin.vue
  13. 80 20
      src/components/Adult/inputModules/DialogueArticleChs/components/RoleChs.vue
  14. 88 33
      src/components/Adult/inputModules/DialogueArticleChs/index.vue
  15. 41 9
      src/components/Adult/preview/ArticleViewChs/WordModelChs.vue
  16. 2 1
      src/components/Adult/preview/ArticleViewChs/index.vue
  17. 88 0
      src/components/Adult/preview/InputHasRecord.vue
  18. 103 0
      src/components/Adult/preview/components/AudioRed.vue
  19. 432 0
      src/components/Adult/preview/components/Practice.vue
  20. 472 0
      src/components/Adult/preview/components/Practicewords.vue
  21. 117 0
      src/components/Adult/preview/components/Strockplayredline.vue
  22. 279 0
      src/components/Adult/preview/components/Wordcard.vue
  23. 232 0
      src/components/Adult/preview/components/Wordintp.vue
  24. 26 26
      src/main.js
  25. 2 0
      src/views/adultInput.vue

+ 21 - 3
src/api/ajax.js

@@ -184,7 +184,7 @@ export function segSentences(data) {
         SessionID = user.session_id;
     }
     return request({
-        url: `/GCLSFCServer/segement/split?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        url: `/GCLSHMToolsServer/api/nlp/chinese/text2Sentences?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
         method: 'post',
         data
     })
@@ -202,7 +202,7 @@ export function BatchSegContent(data) {
         SessionID = user.session_id;
     }
     return request({
-        url: `/GCLSFCServer/sentenceList/split?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        url: `/GCLSHMToolsServer/api/nlp/chinese/text2word?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
         method: 'post',
         data
     })
@@ -220,7 +220,25 @@ export function createPinyin(data) {
         SessionID = user.session_id;
     }
     return request({
-        url: `/GCLSFCServer/sentenceList/pinyin?UserCode=${UserCode}&UserType=${UserType}&SessionID=${SessionID}`,
+        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


+ 29 - 28
src/components/Adult/Preview.vue

@@ -10,14 +10,14 @@
     </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' : '']"
         >
           <div
             class="NNPE-tableList-tr"
-            v-for="(items, indexs) in item.tableList"
+            v-for="(items, indexs) in item.table_list"
             :key="indexs"
           >
             <div
@@ -28,36 +28,39 @@
               v-for="(itemss, indexss) in items"
               :key="indexss"
             >
-              <template v-if="itemss.que">
-                <template v-if="itemss.que.type == 'ligature'">
+              <template v-if="itemss.data">
+                <template v-if="itemss.data.type == 'ligature'">
                   <Ligature :curQue="itemss.que" />
                 </template>
-                <template v-if="itemss.que.type == 'image_chs'">
-                  <Picture :curQue="itemss.que" />
+                <template v-if="itemss.data.type == 'image_chs'">
+                  <Picture :curQue="itemss.data" />
                 </template>
-                <template v-if="itemss.que.type == 'record_chs'">
-                  <Record :curQue="itemss.que" />
+                <template v-if="itemss.data.type == 'record_chs'">
+                  <Record :curQue="itemss.data" />
                 </template>
-                <template v-if="itemss.que.type == 'phrase_chs'">
-                  <WordPhrase :curQue="itemss.que" />
+                <template v-if="itemss.data.type == 'phrase_chs'">
+                  <WordPhrase :curQue="itemss.data" />
                 </template>
-                <template v-if="itemss.que.type == 'NewWord_chs'">
-                  <WordPhrase :curQue="itemss.que" />
+                <template v-if="itemss.data.type == 'NewWord_chs'">
+                  <WordPhrase :curQue="itemss.data" />
                 </template>
-                <template v-if="itemss.que.type == 'annotation_chs'">
-                  <WordPhrase :curQue="itemss.que" />
+                <template v-if="itemss.data.type == 'annotation_chs'">
+                  <WordPhrase :curQue="itemss.data" />
                 </template>
-                <template v-if="itemss.que.type == 'notes_chs'">
-                  <Notes :curQue="itemss.que" />
+                <template v-if="itemss.data.type == 'notes_chs'">
+                  <Notes :curQue="itemss.data" />
                 </template>
-                <template v-if="itemss.que.type == 'article_chs'">
+                <template v-if="itemss.data.type == 'article_chs'">
                   <ArticleTemChs
-                    :curQue="itemss.que"
+                    :curQue="itemss.data"
                     :NNPENewWordList="NNPENewWordList"
                     :NNPENewPhraseList="NNPENewPhraseList"
                     :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() {
@@ -130,19 +135,15 @@ export default {
           _this.cur = list[_this.queIndex];
           _this.queTotal = list.length;
           _this.cur.cur_fn_data.forEach((item) => {
-            item.tableList.forEach((items) => {
+            item.table_list.forEach((items) => {
               items.forEach((itemss) => {
-                if (itemss.que && itemss.que.type == "NewWord") {
+                if (itemss.data && itemss.data.type == "NewWord_chs") {
                   _this.NNPENewWordList = _this.NNPENewWordList.concat(
-                    itemss.que.option
-                  );
-                } else if (itemss.que && itemss.que.type == "phrase") {
-                  _this.NNPENewPhraseList = _this.NNPENewPhraseList.concat(
-                    itemss.que.option
+                    itemss.data.option
                   );
-                } else if (itemss.que && itemss.que.type == "annotation") {
+                } else if (itemss.data && itemss.data.type == "notes_chs") {
                   _this.NNPEAnnotationList = _this.NNPEAnnotationList.concat(
-                    itemss.que.option
+                    itemss.data.option
                   );
                 }
               });

+ 88 - 0
src/components/Adult/inputModules/ArticleTemChs/components/ArticleChs.vue

@@ -0,0 +1,88 @@
+<!--  -->
+<template>
+  <div class="NPC-Dialogue-article" v-if="curQue">
+    <span class="Big-Book-left-text">文章:</span>
+    <el-input
+      style="width: 85%"
+      class="NPC-Dialogue-input"
+      type="textarea"
+      :autosize="{ minRows: 10 }"
+      placeholder="请输入文章"
+      v-model="curQue.article"
+      @blur="onBlur(curQue, 'article')"
+    ></el-input>
+    <div>
+      <el-button type="primary" size="small" @click="createPara"
+        >生成段落</el-button
+      >
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  props: ["curQue", "changeIsPara"],
+  data() {
+    return {
+      detailItem: {
+        paraIndex: 0,
+        para: "",
+        sentences: [],
+        segList: [],
+        seg_words: [],
+        wordsList: [],
+        timeList: [],
+        isTitle: false,
+      },
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    onBlur(item, field) {
+      item[field] = item[field] ? item[field].trim() : "";
+    },
+    createPara() {
+      let paraArr = this.curQue.article.split(/\n+/g);
+
+      //this.$set(this.curQue, "detail", []);
+      for (let i = 0; i < paraArr.length; i++) {
+        let con = paraArr[i];
+        let detailItem = JSON.parse(JSON.stringify(this.detailItem));
+        if (this.curQue.detail.length == 0) {
+          detailItem.para = con;
+          detailItem.paraIndex = i;
+          this.curQue.detail.push(detailItem);
+        } else {
+          if (!(this.curQue.detail[i] && this.curQue.detail[i].para == con)) {
+            this.$set(this.curQue.detail[i], "para", con);
+          }
+        }
+      }
+      this.changeIsPara();
+      this.$message.success("生成成功");
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.NPC-Dialogue-article {
+  .NPC-Dialogue-input {
+    margin: 20px 0;
+  }
+}
+</style>

+ 10 - 9
src/components/Adult/inputModules/ArticleTemChs/components/ClauseresultChs.vue

@@ -2,7 +2,7 @@
 <template>
   <div class="Big-Book-Maxwidth">
     <div class="Big-Book-con-top">
-      <span class="Big-Book-left-text">文章分句:</span>
+      <span class="Big-Book-left-text">分句结果:</span>
     </div>
     <div
       class="NPC-sentence-list"
@@ -11,6 +11,7 @@
     >
       <template v-if="item.para">
         <el-input
+          style="width: 85%;white-space:nowrap;"
           type="textarea"
           :autosize="{ minRows: 3 }"
           placeholder="请输入内容"
@@ -19,18 +20,17 @@
           @change="handleChange"
           @blur="onBlur(item, 'para')"
         ></el-input>
-        <el-button
-          v-if="!item.isReadonly"
-          type="primary"
-          size="small"
-          @click="sureClause(index)"
-          >确定</el-button
-        >
-        <el-button v-else type="danger" size="small" @click="editClause(item)"
+        <el-button type="danger" size="small" @click="editClause(item)"
           >编辑</el-button
         >
+        <el-button type="primary" size="small" @click="sureClause(index)"
+          >生词分词</el-button
+        >
       </template>
     </div>
+    <!-- <el-button type="primary" size="small" @click="oneClickResult"
+      >一键生成分词</el-button
+    > -->
   </div>
 </template>
 
@@ -93,6 +93,7 @@ export default {
     editClause(item) {
       item.isReadonly = false;
     },
+    oneClickResult() {},
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {},

+ 11 - 6
src/components/Adult/inputModules/ArticleTemChs/components/ParagraphChs.vue

@@ -11,7 +11,7 @@
               size="small"
               @click="editPara"
               v-if="readonly"
-              >编辑文章</el-button
+              >编辑段落</el-button
             >
           </div>
           <div
@@ -19,7 +19,9 @@
             v-for="(item, index) in curQue.detail"
             :key="'para' + index"
           >
+            <span class="NPC-para-number">{{ index + 1 }}.</span>
             <el-input
+            style="width: 82%;"
               type="textarea"
               :autosize="{ minRows: 3 }"
               placeholder="请输入内容"
@@ -27,20 +29,18 @@
               @blur="onBlur(item, 'para')"
               :readonly="readonly"
             ></el-input>
-            <template v-if="index == 0 && !readonly">
+            <template v-if="index == 0">
               <el-checkbox v-model="item.isTitle">文章标题</el-checkbox>
             </template>
             <img
-              v-if="!readonly"
               @click="deleteOption(index)"
               class="close"
               src="../../../../../assets/adult/del-close.png"
               alt=""
+              v-if="!readonly"
             />
           </div>
-          <div class="NPC-footer-btn" v-if="!readonly">
-            <div class="addoption" @click="addOption">添加段落</div>
-            <div class="sureSegbtn" @click="sureSegResult">确定分句</div>
+            <el-button type="primary" size="small" @click="sureSegResult">确定分句</el-button>
           </div>
         </div>
       </div>
@@ -188,6 +188,11 @@ export default {
     justify-content: flex-start;
     align-items: flex-start;
     margin-bottom: 10px;
+    .NPC-para-number {
+      width: 28px;
+      margin-right: 5px;
+      text-align: right;
+    }
   }
   .close {
     width: 24px;

+ 1 - 0
src/components/Adult/inputModules/ArticleTemChs/components/SegbywordChs.vue

@@ -184,6 +184,7 @@ export default {
     },
     //获取段落中句子分词结果
     getParaSegWordsResult() {
+      debugger;
       let detail = this.curQue.detail;
       for (let i = 0; i < detail.length; i++) {
         if (detail[i].paraIndex == this.paraIndex) {

File diff suppressed because it is too large
+ 2951 - 21
src/components/Adult/inputModules/ArticleTemChs/index.vue


+ 73 - 0
src/components/Adult/inputModules/DialogueArticleChs/components/ArticleChs.vue

@@ -0,0 +1,73 @@
+<!--  -->
+<template>
+  <div class="NPC-Dialogue-article" v-if="curOption">
+    <el-input
+      class="NPC-Dialogue-input"
+      type="textarea"
+      :autosize="{ minRows: 10 }"
+      placeholder="请输入内容"
+      v-model="curOption.article"
+      @blur="onBlur(curOption, 'article')"
+    ></el-input>
+    <el-button @click="createPara">生成段落</el-button>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  props: ["curOption", "changeActive"],
+  data() {
+    return {
+      detailItem: {
+        paraIndex: 0,
+        para: "",
+        sentences: [],
+        segList: [],
+        seg_words: [],
+        wordsList: [],
+        timeList: [],
+        isTitle: false,
+      },
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    onBlur(item, field) {
+      item[field] = item[field] ? item[field].trim() : "";
+    },
+    createPara() {
+      let paraArr = this.curOption.article.split(/\n+/g);
+
+      for (let i = 0; i < paraArr.length; i++) {
+        let con = paraArr[i];
+        let detailItem = JSON.parse(JSON.stringify(this.detailItem));
+        detailItem.para = con;
+        this.curOption.detail.push(detailItem);
+      }
+      this.changeActive(2);
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.NPC-Dialogue-article {
+  .NPC-Dialogue-input {
+    margin: 20px 0;
+  }
+}
+</style>

+ 10 - 10
src/components/Adult/inputModules/DialogueArticleChs/components/ParagraphChs.vue

@@ -1,11 +1,11 @@
 <!--分句组件-->
 <template>
-  <div class="Big-Book-Maxwidth" v-if="curQue">
+  <div class="Big-Book-Maxwidth" v-if="curOption">
     <div class="Big-Book-content m">
       <div class="Big-Book-main">
         <div class="Big-Book-con">
           <div class="Big-Book-con-top">
-            <span class="Big-Book-left-text">文章:</span>
+            <span class="Big-Book-left-text">段落:</span>
             <el-button
               type="text"
               size="small"
@@ -16,7 +16,7 @@
           </div>
           <div
             class="NPC-para-list"
-            v-for="(item, index) in curQue.detail"
+            v-for="(item, index) in curOption.detail"
             :key="'para' + index"
           >
             <el-input
@@ -52,7 +52,7 @@ import "@/utils/pinyin_dict_withtone";
 import "@/utils/pinyinUtil";
 export default {
   components: {},
-  props: ["curQue", "sureSeg", "isClause", "changeIsClause"],
+  props: ["curOption", "sureSeg", "isClause", "changeIsClause"],
   data() {
     return {
       imgNumber: 10,
@@ -76,8 +76,8 @@ export default {
       item[field] = item[field] ? item[field].trim() : "";
     },
     onBlurIndex(index, field) {
-      let res = this.curQue[field][index].trim();
-      this.$set(this.curQue[field], index, res);
+      let res = this.curOption[field][index].trim();
+      this.$set(this.curOption[field], index, res);
     },
     sureSegResult() {
       let _this = this;
@@ -107,11 +107,11 @@ export default {
         this.$message.warning("不能全部删除");
         return;
       }
-      this.curQue.detail.splice(index, 1);
+      this.curOption.detail.splice(index, 1);
     },
     addOption() {
-      let leg = this.curQue.detail.length;
-      let last = this.curQue.detail[leg - 1].para;
+      let leg = this.curOption.detail.length;
+      let last = this.curOption.detail[leg - 1].para;
       if (!last) {
         this.$message.warning("数据不能全是空");
         return;
@@ -125,7 +125,7 @@ export default {
         wordsList: [],
         timeList: [],
       };
-      this.curQue.detail.push(obj);
+      this.curOption.detail.push(obj);
     },
     editPara() {
       this.$confirm("此操作需要重新校对分句分词, 是否继续?", "提示", {

+ 129 - 0
src/components/Adult/inputModules/DialogueArticleChs/components/Pinyin.vue

@@ -0,0 +1,129 @@
+<!--  -->
+<template>
+  <div class="NPC-words-box" v-if="wordsList">
+    <span class="Big-Book-left-text">校对拼音:</span>
+    <div class="NPC-proof-pinyin">
+      <div class="NPC-words-list">
+        <el-table :data="wordsList" border style="width: 400px">
+          <el-table-column prop="chs" label="词" width="180"> </el-table-column>
+          <el-table-column label="拼音" width="220">
+            <template slot-scope="scope">
+              <el-input
+                v-model="scope.row.pinyin"
+                placeholder="请输入拼音"
+                @blur="onBlur(scope.row, 'pinyin')"
+              ></el-input>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div></div>
+      </div>
+      <div class="yunmu">
+        <span>点击可复制</span>
+        <table border="1" class="yunmu-table">
+          <tr v-for="(item, index) in tableData" :key="'tableData' + index">
+            <td
+              v-for="(tdItem, tdIndex) in item"
+              :key="'pinyin' + index + tdIndex"
+              :id="'pinyin' + index + tdIndex"
+              @click="CopyToClipboard('pinyin' + index + tdIndex)"
+            >
+              {{ tdItem }}
+            </td>
+          </tr>
+        </table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  props: ["wordsList"],
+  data() {
+    return {
+      tableData: [
+        ["ā", "á", "ǎ", "à"],
+        ["ō", "ó", "ǒ", "ò"],
+        ["ē", "é", "ě", "è"],
+        ["ī", "í", "ǐ", "ì"],
+        ["ū", "ú", "ǔ", "ù"],
+        ["ǖ", "ǘ", "ǚ", "ǜ"],
+        ["Ā", "Á", "Â", "À"],
+        ["Ō", "Ó", "Ô", "Ò"],
+        ["Ē", "É", "Ê", "È"],
+        ["Ī", "Í", "Î", "Ì"],
+        ["Ū", "Ú", "Û", "Ù"],
+      ],
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    onBlur(item, field) {
+      item[field] = item[field] ? item[field].trim() : "";
+      item[field] = item[field].replace(/\s+/g, "");
+    },
+    CopyToClipboard(element) {
+      var doc = document,
+        text = doc.getElementById(element),
+        range,
+        selection;
+      if (doc.body.createTextRange) {
+        range = doc.body.createTextRange();
+        range.moveToElementText(text);
+        range.select();
+      } else if (window.getSelection) {
+        selection = window.getSelection();
+        range = doc.createRange();
+        range.selectNodeContents(text);
+        selection.removeAllRanges();
+        selection.addRange(range);
+      }
+      document.execCommand("copy");
+      this.$message({
+        message: "复制成功",
+        type: "success",
+      });
+      window.getSelection().removeAllRanges();
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.NPC-words-box {
+  position: relative;
+  .NPC-proof-pinyin {
+    display: flex;
+    justify-content: flex-start;
+  }
+  .yunmu {
+    margin-left: 36px;
+    &-table {
+      width: 260px;
+      > tr {
+        td {
+          cursor: pointer;
+          text-align: center;
+          font-size: 16px;
+          height: 26px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 80 - 20
src/components/Adult/inputModules/DialogueArticleChs/components/RoleChs.vue

@@ -4,13 +4,13 @@
     <div class="NPC-da-role-flex">
       <span class="NPC-da-role-text">角色:</span>
       <el-input
+        style="width: 100px"
         class="NPC-role-input"
         placeholder="请输入角色"
-        v-model="curRole.role"
-        @blur="onBlur(item, 'para')"
-        :readonly="readonly"
+        v-model="curRole.roleName"
+        @blur="onBlur(curRole, 'roleName')"
       ></el-input>
-      或
+      <span style="margin-right: 10px"></span>
       <Upload
         type="image"
         :changeFillId="changeImage"
@@ -25,8 +25,7 @@
         class="NPC-role-input"
         placeholder="请输入内容"
         v-model="curRole.fullName"
-        @blur="onBlur(item, 'fullName')"
-        :readonly="readonly"
+        @blur="onBlur(curRole, 'fullName')"
       ></el-input>
       <el-button type="danger" @click="segWord(curRole.fullName)"
         >分词</el-button
@@ -38,20 +37,29 @@
         class="NPC-role-input"
         placeholder="请输入分词结果"
         v-model="curRole.seg_words"
-        @blur="onBlur(item, 'fullName')"
-        :readonly="readonly"
+        @change="handleChange"
+        @blur="onBlur(curRole, 'seg_words')"
       ></el-input>
-      <el-button type="danger" @click="proofName">生成拼音</el-button>
+      <el-button type="danger" @click="_createPinyin">生成拼音</el-button>
+    </div>
+    <div v-if="curRole && curRole.wordsList && curRole.wordsList.length > 0">
+      <Pinyin :wordsList="curRole.wordsList" />
     </div>
   </div>
 </template>
 
 <script>
+import Upload from "../../../common/Upload.vue";
+import Pinyin from "./Pinyin.vue";
+const Base64 = require("js-base64").Base64;
 import { segSentences, BatchSegContent, createPinyin } from "@/api/ajax";
 export default {
   name: "role",
-  components: {},
-  props: ["curRole"],
+  components: {
+    Upload,
+    Pinyin,
+  },
+  props: ["curRole", "Upload"],
   data() {
     return {
       fileCon: {
@@ -59,17 +67,28 @@ export default {
         img_list: [],
       },
       imgNumber: 1,
+      loading: false,
     };
   },
   computed: {},
   watch: {},
   //方法集合
   methods: {
-    onBlur() {},
-    proofName() {},
+    onBlur(item, field) {
+      item[field] = item[field] ? item[field].trim() : "";
+    },
+    handleChange(val) {
+      this.curRole.seg_words = val.replace(/\s+/g, " ");
+      let arr = this.curRole.seg_words.split(/\s+/);
+      this.$set(this.curRole, "segList", arr);
+    },
     //生成分词
-    segByWord(sentences) {
-      console.log(sentences);
+    segWord(sentence) {
+      if (!sentence) {
+        this.$message.warning("姓名不能为空");
+        return;
+      }
+      let sentences = [sentence];
       this.loading = true;
       let textList = [];
       sentences.forEach((item) => {
@@ -80,19 +99,60 @@ export default {
         textList: textList,
       };
       BatchSegContent(data).then((res) => {
-        this.paraIndex = paraIndex;
         this.loading = false;
         let list = res.data.result.list;
-        this.$set(this.curQue.detail[paraIndex], "segList", list);
-        this.segList = list;
-        this.isByWord = true;
+        this.$set(this.curRole, "segList", list);
+        let seg_words = list.join(" ");
+        this.$set(this.curRole, "seg_words", seg_words);
+      });
+    },
+    //生成拼音
+    _createPinyin() {
+      let res_str = this.curRole.seg_words.replace(/\s+/g, "");
+      let org_sent = this.curRole.fullName;
+      if (res_str.trim() != org_sent.trim()) {
+        this.$message.warning("跟原句不一致,请检查是否误删除或新增其他内容");
+        return;
+      }
+      let textListList = [];
+      let segArr = JSON.parse(JSON.stringify(this.curRole.segList));
+      segArr.forEach((item) => {
+        let str = Base64.encode(item);
+        textListList.push(str);
+      });
+      let data = {
+        textListList: [textListList],
+      };
+      createPinyin(data).then((res) => {
+        let wordsList = res.data.result[0];
+        this.$set(this.curRole, "wordsList", wordsList);
       });
     },
+    changeImage(fileList) {
+      const articleImgList = JSON.parse(JSON.stringify(fileList));
+      const articleImgRes = [];
+      articleImgList.forEach((item) => {
+        if (item.response) {
+          const obj = {
+            name: item.name,
+            url: item.response.file_info_list[0].file_url,
+            id: item.response.file_info_list[0].file_id,
+          };
+          articleImgRes.push(obj);
+        }
+      });
+      //this.articleImgList = articleImgRes;
+      this.curQueItem.img_list = JSON.parse(JSON.stringify(articleImgRes));
+    },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {},
   //生命周期 - 挂载完成(可以访问DOM元素)
-  mounted() {},
+  mounted() {
+    if (this.curRole) {
+      this.fileCon.img_list = this.curRole.img_list;
+    }
+  },
   beforeCreate() {}, //生命周期 - 创建之前
   beforeMount() {}, //生命周期 - 挂载之前
   beforeUpdate() {}, //生命周期 - 更新之前

+ 88 - 33
src/components/Adult/inputModules/DialogueArticleChs/index.vue

@@ -64,7 +64,9 @@
       </div>
       <!--对话内容-->
       <div class="NPC-da-article">
-        <el-button type="primary">编辑文章</el-button>
+        <el-button type="primary" @click="editDialogue(item, index)"
+          >编辑对话内容</el-button
+        >
       </div>
       <!--标注信息-->
       <div class="NPC-da-tag">
@@ -78,13 +80,51 @@
         <el-button type="primary" @click="saveTimeList">保 存</el-button>
       </span>
     </el-dialog>
-    <el-dialog title="编辑角色" :visible.sync="isEditRole" width="50%">
+    <el-dialog title="编辑角色" :visible.sync="isEditRole" width="60%">
       <template v-if="curOption">
         <RoleChs ref="roleChs" :curRole="curOption.role" />
       </template>
       <span slot="footer" class="dialog-footer">
-        <el-button @click="cTVisible = false">取 消</el-button>
-        <el-button type="primary" @click="saveTimeList">保 存</el-button>
+        <el-button @click="isEditRole = false">取 消</el-button>
+        <el-button type="primary" @click="saveRole">保 存</el-button>
+      </span>
+    </el-dialog>
+    <el-dialog
+      title="编辑对话内容"
+      top="30px"
+      :visible.sync="isEditDia"
+      width="60%"
+    >
+      <template v-if="curOption">
+        <el-steps
+          :active="active"
+          finish-status="success"
+          simple
+          style="margin-top: 20px"
+        >
+          <el-step title="对话内容"></el-step>
+          <el-step title="分段结果"></el-step>
+          <el-step title="分句结果"></el-step>
+          <el-step title="分词结果"></el-step>
+        </el-steps>
+        <template v-if="active == 1">
+          <ArticleChs
+            ref="articleChs"
+            :curOption="curOption"
+            :changeActive="changeActive"
+          />
+        </template>
+        <template v-if="active == 2">
+          <ParagraphChs
+            ref="articleChs"
+            :curOption="curOption"
+            :changeActive="changeActive"
+          />
+        </template>
+      </template>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="isEditDia = false">取 消</el-button>
+        <el-button type="primary" @click="saveDialogue">保 存</el-button>
       </span>
     </el-dialog>
   </div>
@@ -95,23 +135,25 @@ import { segSentences, BatchSegContent, createPinyin } from "@/api/ajax";
 const Base64 = require("js-base64").Base64;
 import Upload from "../../common/Upload.vue";
 import UploadArt from "../../common/UploadArt.vue";
-import Paragraph from "./components/ParagraphChs.vue";
+import ParagraphChs from "./components/ParagraphChs.vue";
 import Clauseresult from "./components/ClauseresultChs.vue";
 import Segbyword from "./components/SegbywordChs.vue";
 import Createtimelist from "./components/CreatetimelistChs.vue";
 
 import RoleChs from "./components/RoleChs.vue";
+import ArticleChs from "./components/ArticleChs.vue";
 
 export default {
-  name: "ArticleTemChs",
+  name: "DialogueArticleChs",
   components: {
     Upload,
     UploadArt,
-    Paragraph,
+    ParagraphChs,
     Clauseresult,
     Segbyword,
     Createtimelist,
     RoleChs,
+    ArticleChs,
   },
   props: ["curQue", "changeCurQue", "tmIndex"],
   data() {
@@ -129,8 +171,11 @@ export default {
       loading: false,
       segList: null,
       isEditRole: false,
+      isEditDia: false,
       curOpIndex: -1,
       curOption: null,
+      active: 1,
+
       data_structure: {
         type: "dialog_article_chs",
         name: "对话课文",
@@ -143,20 +188,13 @@ export default {
             role: {
               roleName: "",
               fullName: "",
+              segList: [],
+              seg_words: "",
+              wordsList: [],
               namePinyin: "",
             },
-            detail: [
-              {
-                paraIndex: 0,
-                para: "",
-                sentences: [],
-                segList: [],
-                seg_words: [],
-                wordsList: [],
-                timeList: [],
-                isTitle: false,
-              },
-            ],
+            article: "",
+            detail: [],
           },
         ],
       },
@@ -292,11 +330,28 @@ export default {
       let res_data = JSON.parse(JSON.stringify(this.data_structure));
       this.changeCurQue(res_data);
     },
+    //编辑角色
     editRole(item, index) {
       this.isEditRole = true;
       this.curOption = item;
       this.curOpIndex = index;
     },
+    //保存角色
+    saveRole() {
+      this.isEditRole = false;
+      console.log(this.curQue);
+    },
+    //编辑对话内容
+    editDialogue(item, index) {
+      this.isEditDia = true;
+      this.curOption = item;
+      this.curOpIndex = index;
+    },
+    //保存对话内容
+    saveDialogue() {},
+    changeActive(active) {
+      this.active = active;
+    },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {},
@@ -305,20 +360,20 @@ export default {
     console.log("ArticleTem");
     console.log(this.curQue);
     if (this.curQue) {
-      if (this.curQue.detail[0].sentences.length > 0) {
-        this.isClause = true;
-      }
-      if (this.curQue.detail[0].seg_words.length > 0) {
-        this.isByWord = true;
-      }
-      if (!this.curQue.img_list) {
-        this.curQue.img_list = [];
-      }
-      if (!this.curQue.mp3_list) {
-        this.curQue.mp3_list = [];
-      }
-      this.fileCon.img_list = JSON.parse(JSON.stringify(this.curQue.img_list));
-      this.fileCon.mp3_list = JSON.parse(JSON.stringify(this.curQue.mp3_list));
+      // if (this.curQue.detail[0].sentences.length > 0) {
+      //   this.isClause = true;
+      // }
+      // if (this.curQue.detail[0].seg_words.length > 0) {
+      //   this.isByWord = true;
+      // }
+      // if (!this.curQue.img_list) {
+      //   this.curQue.img_list = [];
+      // }
+      // if (!this.curQue.mp3_list) {
+      //   this.curQue.mp3_list = [];
+      // }
+      // this.fileCon.img_list = JSON.parse(JSON.stringify(this.curQue.img_list));
+      // this.fileCon.mp3_list = JSON.parse(JSON.stringify(this.curQue.mp3_list));
     } else {
       this.initCurQueData();
     }

+ 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>

+ 26 - 26
src/main.js

@@ -29,29 +29,29 @@ import VideoPlayer from 'vue-video-player'
 require('video.js/dist/video-js.css')
 require('vue-video-player/src/custom-theme.css')
 Vue.use(VideoPlayer)
-    /**
-     * If you don't want to use mock-server
-     * you want to use MockJs for mock api
-     * you can execute: mockXHR()
-     *
-     * Currently MockJs will be used in the production environment,
-     * please remove it before going online ! ! !
-     */
-    // set ElementUI lang to EN
-    // Vue.use(ElementUI, { locale })
-    // 如果想要中文版 element-ui,按如下方式声明
-    // element 下拉框下拉加载
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online ! ! !
+ */
+// set ElementUI lang to EN
+// Vue.use(ElementUI, { locale })
+// 如果想要中文版 element-ui,按如下方式声明
+// element 下拉框下拉加载
 Vue.directive('loadmore', {
-    bind(el, binding) {
-        // 获取element-ui定义好的scroll盒子
-        const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
-        SELECTWRAP_DOM.addEventListener('scroll', function() {
-            const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
-            if (CONDITION) {
-                binding.value()
-            }
-        })
-    }
+  bind(el, binding) {
+    // 获取element-ui定义好的scroll盒子
+    const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
+    SELECTWRAP_DOM.addEventListener('scroll', function () {
+      const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
+      if (CONDITION) {
+        binding.value()
+      }
+    })
+  }
 })
 
 Vue.use(ElementUI)
@@ -62,8 +62,8 @@ Vue.use(elementUtils)
 Vue.config.productionTip = false
 
 new Vue({
-    el: '#app',
-    router,
-    store,
-    render: h => h(App)
+  el: '#app',
+  router,
+  store,
+  render: h => h(App)
 })

+ 2 - 0
src/views/adultInput.vue

@@ -467,6 +467,7 @@ export default {
       //   "que",
       //   null
       // );
+      item.type = "";
       item.data = null;
       this.TopicIndex = null;
       this.RowIndex = null;
@@ -557,6 +558,7 @@ export default {
       ) {
         this.$message.warning("每列只能添加一个模板");
       } else {
+        debugger;
         console.log("不存在");
         this.module_type = item.type;
         this.$set(

Some files were not shown because too many files changed in this diff