Bläddra i källkod

PhraseModelChs

guanchunjie 3 år sedan
förälder
incheckning
e89f78e9ba
33 ändrade filer med 1909 tillägg och 738 borttagningar
  1. 1 1
      package.json
  2. BIN
      src/assets/NPC/close-icon-red.png
  3. 2 1
      src/components/Adult/common/AudioControlModule.vue
  4. 2 1
      src/components/Adult/common/DialogueModule.vue
  5. 2 1
      src/components/Adult/common/HzModule.vue
  6. 1 1
      src/components/Adult/common/InputRecordModule.vue
  7. 2 1
      src/components/Adult/common/Inputmodule.vue
  8. 3 2
      src/components/Adult/common/JudgeModule.vue
  9. 3 2
      src/components/Adult/common/LigatureModule.vue
  10. 2 2
      src/components/Adult/common/NewordPhraseModule.vue
  11. 2 2
      src/components/Adult/common/RecordModule.vue
  12. 11 3
      src/components/Adult/common/SentenceModule.vue
  13. 3 2
      src/components/Adult/common/SingleModule.vue
  14. 3 2
      src/components/Adult/inputModules/ArticleTemChs/index.vue
  15. 1 1
      src/components/Adult/inputModules/BgControl.vue
  16. 1 1
      src/components/Adult/inputModules/DialogueArticleChs/components/RoleChs.vue
  17. 3 2
      src/components/Adult/inputModules/DialogueArticleChs/index.vue
  18. 2 1
      src/components/Adult/inputModules/Sentence.vue
  19. 24 47
      src/components/Adult/inputModules/UploadControl.vue
  20. 130 74
      src/components/Adult/preview/ArticleViewChs/PhraseModelChs.vue
  21. 119 86
      src/components/Adult/preview/ArticleViewChs/WordModelChs.vue
  22. 8 6
      src/components/Adult/preview/ArticleViewChs/index.vue
  23. 44 37
      src/components/Adult/preview/UploadControlView.vue
  24. 306 0
      src/components/Adult/preview/components/ChinaDict.vue
  25. 193 0
      src/components/Adult/preview/components/Freewrite.vue
  26. 202 203
      src/components/Adult/preview/components/Practice.vue
  27. 130 0
      src/components/Adult/preview/components/Strockplay.vue
  28. 168 0
      src/components/Adult/preview/components/Strockred.vue
  29. 82 51
      src/components/Adult/preview/components/Wordcard.vue
  30. 281 31
      src/components/Adult/preview/components/Wordintp.vue
  31. 78 78
      src/utils/request.js
  32. 4 4
      src/views/adultInput2.vue
  33. 96 95
      vue.config.js

+ 1 - 1
package.json

@@ -35,7 +35,7 @@
         "vue-element-utils": "^0.2.1",
         "vue-esign": "^1.0.5",
         "vue-i18n": "^8.24.4",
-        "vue-pdf": "^4.3.0",
+        "vue-pdf": "^4.2.0",
         "vue-router": "3.0.6",
         "vue-slider-component": "^3.2.14",
         "vue-video-player": "^5.0.2",

BIN
src/assets/NPC/close-icon-red.png


+ 2 - 1
src/components/Adult/common/AudioControlModule.vue

@@ -102,7 +102,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }

+ 2 - 1
src/components/Adult/common/DialogueModule.vue

@@ -199,7 +199,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }

+ 2 - 1
src/components/Adult/common/HzModule.vue

@@ -210,7 +210,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }

+ 1 - 1
src/components/Adult/common/InputRecordModule.vue

@@ -103,7 +103,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
             media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);

+ 2 - 1
src/components/Adult/common/Inputmodule.vue

@@ -126,7 +126,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }

+ 3 - 2
src/components/Adult/common/JudgeModule.vue

@@ -163,7 +163,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }
@@ -180,7 +181,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }

+ 3 - 2
src/components/Adult/common/LigatureModule.vue

@@ -188,7 +188,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }
@@ -205,7 +206,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }

+ 2 - 2
src/components/Adult/common/NewordPhraseModule.vue

@@ -145,7 +145,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
             media_duration: item.response.file_info_list[0].media_duration,
             file_relative_path:
               item.response.file_info_list[0].file_relative_path,
@@ -165,7 +165,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
             file_relative_path: file_relative_path,
           };
           articleImgRes.push(obj);

+ 2 - 2
src/components/Adult/common/RecordModule.vue

@@ -190,7 +190,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
             media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
@@ -207,7 +207,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }

+ 11 - 3
src/components/Adult/common/SentenceModule.vue

@@ -50,6 +50,15 @@
     >
       <img src="../../../assets/adult/pro-plus.png" alt="" />
     </div>
+    <div class="Big-Book-top" v-if="type == 'inputItem_chs'">
+      <span>音频</span>
+      <Upload
+        :changeFillId="changeMp3"
+        :datafileList="fileCon.mp3_list"
+        :filleNumber="mp3Number"
+        :uploadType="'mp3'"
+      />
+    </div>
     <!-- <div class="Big-Book-mp3">
       <span>音频</span>
       <Upload
@@ -151,7 +160,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
             media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
@@ -168,7 +177,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }
@@ -253,7 +262,6 @@ export default {
     // display: flex;
     // justify-content: flex-start;
     // align-items: center;
-
     > div {
       display: flex;
       justify-content: flex-start;

+ 3 - 2
src/components/Adult/common/SingleModule.vue

@@ -159,7 +159,8 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }
@@ -176,7 +177,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }

+ 3 - 2
src/components/Adult/inputModules/ArticleTemChs/index.vue

@@ -2949,7 +2949,8 @@ export default {
             name: item.name,
             duration: item.response.file_info_list[0].media_duration,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }
@@ -2963,7 +2964,7 @@ export default {
         const obj = {
           name: file.name,
           url: file.response.file_info_list[0].file_url,
-          id: file.response.file_info_list[0].file_id,
+          id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           imgNumber: 0,
         };
         this.curQue.img_list.push(obj);

+ 1 - 1
src/components/Adult/inputModules/BgControl.vue

@@ -45,7 +45,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }

+ 1 - 1
src/components/Adult/inputModules/DialogueArticleChs/components/RoleChs.vue

@@ -136,7 +136,7 @@ export default {
           const obj = {
             name: item.name,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           };
           articleImgRes.push(obj);
         }

+ 3 - 2
src/components/Adult/inputModules/DialogueArticleChs/index.vue

@@ -213,7 +213,8 @@ export default {
             name: item.name,
             duration: item.response.file_info_list[0].media_duration,
             url: item.response.file_info_list[0].file_url,
-            id: item.response.file_info_list[0].file_id,
+            id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
+            media_duration: item.response.file_info_list[0].media_duration, //音频时长
           };
           articleImgRes.push(obj);
         }
@@ -226,7 +227,7 @@ export default {
         const obj = {
           name: file.name,
           url: file.response.file_info_list[0].file_url,
-          id: file.response.file_info_list[0].file_id,
+          id: "[FID##" + item.response.file_info_list[0].file_id + "#FID]",
           imgNumber: 0,
         };
         this.curQue.img_list.push(obj);

+ 2 - 1
src/components/Adult/inputModules/Sentence.vue

@@ -1,6 +1,6 @@
 <!--  -->
 <template>
-  <div class="Big-Book-sentence">
+  <div class="Big-Book-sentence" v-if="curQue">
     <div
       class="Big-Book-Single-content"
       style="margin-left: 50px; margin-top: 20px"
@@ -70,6 +70,7 @@ export default {
             con: "",
             answer: "",
             IsRecord: false,
+            mp3_url: [],
           },
         ],
       },

+ 24 - 47
src/components/Adult/inputModules/UploadControl.vue

@@ -5,9 +5,9 @@
       :changeFillId="changeFillId"
       :accept="accept"
       :filleNumber="1"
-      :fileList="fileList"
+      :fileList="curQue.fileList"
     />
-    <div class="dv">
+    <div class="dv" v-loading="loading">
       <div class="main">
         <div class="content">
           <template v-if="curQue.data">
@@ -23,24 +23,12 @@
               <pdf
                 ref="pdf"
                 :src="curQue.data.fileRelativePath"
-                v-for="i in numPages"
+                v-for="i in curQue.data.numPages"
                 :key="i"
                 :page="i"
               >
               </pdf>
             </template>
-            <template v-else>
-              <iframe
-                :src="
-                  'https://view.officeapps.live.com/op/view.aspx?src=' +
-                  `${curQue.data.file_url}`
-                "
-                width="100%"
-                height="1000px"
-                id="if"
-              >
-              </iframe>
-            </template>
           </template>
         </div>
       </div>
@@ -68,17 +56,12 @@ export default {
       numPages: null,
       accept: ".png,.jpg,.pdf",
       data_structure: {
-        type: "recordHZ_inputPY_chs",
-        name: "读汉字写拼音",
+        type: "upload_control_chs",
+        name: "上传控件",
         title: "",
-        option: [
-          {
-            number: "",
-            con: "",
-            answer: "",
-          },
-        ],
+        fileList: [],
       },
+      loading: false,
     };
   },
   computed: {},
@@ -87,16 +70,17 @@ export default {
   methods: {
     remove() {
       this.data = null;
-      tis.curQue.data = null;
-      this.fileList = [];
+      this.curQue.data = null;
+      this.curQue.fileList = [];
+      this.$message.success("删除成功");
     },
     changeFillId(fileList, item, index) {
-      this.fileList = fileList;
-      this.curQue.data = this.fileList[0].response.file_info_list[0];
+      this.curQue.fileList = fileList;
+      this.curQue.data = fileList[0].response.file_info_list[0];
       if (this.curQue.data.file_name.indexOf("pdf" != -1)) {
+        this.curQue.data = fileList[0].response.file_info_list[0];
         this.curQue.data.fileRelativePath =
           process.env.VUE_APP_BASE_API + this.curQue.data.file_relative_path;
-        this.curQue.data = this.fileList[0].response.file_info_list[0];
         this.getNumPages();
       }
     },
@@ -107,13 +91,19 @@ export default {
         _this.curQue.data.fileRelativePath
       );
       loadingTask.promise
-        .then((pdf) => {
-          _this.numPages = pdf.numPages;
+        .then((pdff) => {
+          _this.numPages = pdff.numPages;
+          _this.curQue.data.numPages = pdff.numPages;
+          this.$forceUpdate();
         })
         .catch((err) => {
-          console.error("pdf 加载失败", err);
+          this.$message.success("pdf 加载失败", err);
+          this.data = null;
+          this.curQue.data = null;
+          this.curQue.fileList = [];
         });
     },
+
     initcurQue() {
       let data = JSON.parse(JSON.stringify(this.data_structure));
       this.changeCurQue(data);
@@ -123,24 +113,11 @@ export default {
   created() {
     if (!this.curQue) {
       this.initcurQue();
+    } else {
     }
   },
   //生命周期 - 挂载完成(可以访问DOM元素)
-  mounted() {
-    if (this.curQue.data && this.curQue.data.file_name.indexOf("pdf") != -1) {
-      let _this = this;
-      let loadingTask = pdf.createLoadingTask(
-        _this.curQue.data.fileRelativePath
-      );
-      loadingTask.promise
-        .then((pdf) => {
-          _this.numPages = pdf.numPages;
-        })
-        .catch((err) => {
-          console.error("pdf 加载失败", err);
-        });
-    }
-  },
+  mounted() {},
   beforeCreate() {}, //生命周期 - 创建之前
   beforeMount() {}, //生命周期 - 挂载之前
   beforeUpdate() {}, //生命周期 - 更新之前

+ 130 - 74
src/components/Adult/preview/ArticleViewChs/PhraseModelChs.vue

@@ -7,83 +7,85 @@
       ref="audioLine"
     />
     <template v-if="resArr.length > 0">
-      <div
-        :class="['NNPE-detail', item.isTitle ? 'NNPE-detail-title' : '']"
-        v-for="(item, index) in resArr"
-        :key="'detail' + index"
-      >
-        <div class="wordsList-box">
-          <img :src="articleImg[index]" v-if="articleImg[0] && index == 0" />
-          <div>
-            <div
-              class="NNPE-words"
-              v-for="(pItem, pIndex) in item.wordsList"
-              :key="'wordsList' + pIndex"
-              :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
-              @click="showWordDetail($event, pItem.chs)"
-            >
-              <template v-if="!pItem.width">
-                <template v-if="pItem.isShow">
-                  <template
-                    v-if="
-                      item.wordsList[pIndex + 1].chs &&
-                      chsFhList.indexOf(item.wordsList[pIndex + 1].chs) > -1
-                    "
-                  >
-                    <span class="NNPE-words-box">
+      <div class="NPC-sentences-list">
+        <div
+          :class="['NNPE-detail', item.isTitle ? 'NNPE-detail-title' : '']"
+          v-for="(item, index) in resArr"
+          :key="'detail' + index"
+        >
+          <div class="wordsList-box">
+            <img :src="articleImg[index]" v-if="articleImg[0] && index == 0" />
+            <div>
+              <div
+                class="NNPE-words"
+                v-for="(pItem, pIndex) in item.wordsList"
+                :key="'wordsList' + pIndex"
+                :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
+                @click="showWordDetail($event, pItem.chs)"
+              >
+                <template v-if="!pItem.width">
+                  <template v-if="pItem.isShow">
+                    <template
+                      v-if="
+                        item.wordsList[pIndex + 1].chs &&
+                        chsFhList.indexOf(item.wordsList[pIndex + 1].chs) > -1
+                      "
+                    >
+                      <span class="NNPE-words-box">
+                        <span
+                          class="NNPE-pinyin"
+                          :class="[pItem.className ? pItem.className : '']"
+                          >{{ pItem.pinyin }}</span
+                        >
+                        <span
+                          :class="[
+                            'NNPE-chs',
+                            newWordList.indexOf(pItem.chs) > -1 ? 'active' : '',
+                          ]"
+                          >{{ pItem.chs }}</span
+                        >
+                      </span>
+                      <span class="NNPE-words-box">
+                        <span class="NNPE-pinyin" style="text-align: left">{{
+                          item.wordsList[pIndex + 1].pinyin
+                        }}</span>
+                        <span class="NNPE-chs" style="text-align: left">{{
+                          item.wordsList[pIndex + 1].chs
+                        }}</span>
+                      </span>
+                    </template>
+                    <template v-else>
                       <span
                         class="NNPE-pinyin"
-                        :class="[pItem.className ? pItem.className : '']"
+                        :class="[
+                          pItem.padding ? 'padding' : '',
+                          pItem.className ? pItem.className : '',
+                        ]"
                         >{{ pItem.pinyin }}</span
                       >
                       <span
+                        class="NNPE-chs"
                         :class="[
-                          'NNPE-chs',
+                          pItem.padding ? 'padding' : '',
                           newWordList.indexOf(pItem.chs) > -1 ? 'active' : '',
                         ]"
                         >{{ pItem.chs }}</span
                       >
-                    </span>
-                    <span class="NNPE-words-box">
-                      <span class="NNPE-pinyin" style="text-align: left">{{
-                        item.wordsList[pIndex + 1].pinyin
-                      }}</span>
-                      <span class="NNPE-chs" style="text-align: left">{{
-                        item.wordsList[pIndex + 1].chs
-                      }}</span>
-                    </span>
-                  </template>
-                  <template v-else>
-                    <span
-                      class="NNPE-pinyin"
-                      :class="[
-                        pItem.padding ? 'padding' : '',
-                        pItem.className ? pItem.className : '',
-                      ]"
-                      >{{ pItem.pinyin }}</span
-                    >
-                    <span
-                      class="NNPE-chs"
-                      :class="[
-                        pItem.padding ? 'padding' : '',
-                        newWordList.indexOf(pItem.chs) > -1 ? 'active' : '',
-                      ]"
-                      >{{ pItem.chs }}</span
-                    >
+                    </template>
                   </template>
                 </template>
-              </template>
-              <template v-else>
-                <span
-                  :style="{
-                    height: pItem.height + 'px',
-                    width: pItem.width + 'px',
-                  }"
-                ></span>
-              </template>
+                <template v-else>
+                  <span
+                    :style="{
+                      height: pItem.height + 'px',
+                      width: pItem.width + 'px',
+                    }"
+                  ></span>
+                </template>
+              </div>
             </div>
+            <img :src="articleImg[index + 1]" v-if="articleImg[index + 1]" />
           </div>
-          <img :src="articleImg[index + 1]" v-if="articleImg[index + 1]" />
         </div>
       </div>
     </template>
@@ -104,7 +106,7 @@ import AudioLine from "../AudioLine.vue";
 import Wordcard from "../components/Wordcard.vue"; // 卡片
 export default {
   name: "PhraseModelChs",
-  props: ["curQue", "NNPENewWordList"],
+  props: ["curQue", "bodyLeft", "NNPENewWordList"],
   components: {
     AudioLine,
     Wordcard,
@@ -127,7 +129,18 @@ export default {
     };
   },
   computed: {},
-  watch: {},
+  watch: {
+    hz: {
+      handler: function (val, oldVal) {
+        let _this = this;
+        if (val) {
+          _this.handleNewWords(val, _this.top, _this.left);
+        }
+      },
+      // 深度观察监听
+      deep: true,
+    },
+  },
   //方法集合
   methods: {
     getCurTime(curTime) {
@@ -248,24 +261,54 @@ export default {
       });
       this.newWordList = JSON.parse(JSON.stringify(NewWordList));
     },
+
     showWordDetail(e, word) {
       let _this = this;
-      let wordArr = this.NNPENewWordList.filter(
-        (item) => item.new_word == word
-      );
-      this.word = wordArr[0];
-      console.log(this.word);
-      this.isShow = true;
-
+      if (_this.oldHz != word) {
+        this.isShow = false;
+        setTimeout(() => {
+          _this.hz = word;
+        }, 50);
+      }
       _this.top = e.clientY + 20;
       let left = e.clientX;
+      let width = 0;
+      if (word.length == 1 || word.length == 2) {
+        width = 304;
+      } else if (word.length == 3 || word.length == 4) {
+        width = 432;
+      } else if (word.length > 3) {
+        width = 560;
+      }
       if (left - this.bodyLeft > this.contentWidth / 2) {
-        _this.left = left - 560;
+        _this.left = left - width;
       } else {
         _this.left = left;
       }
     },
-    changeWordCard() {},
+    hideWordDetail() {
+      this.isShow = false;
+    },
+    changeWordCard(isShow) {
+      this.isShow = isShow;
+      this.oldHz = "";
+      this.hz = "";
+    },
+    // 处理分词数据
+    handleNewWords(val, top, left) {
+      debugger;
+      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() {},
@@ -294,6 +337,9 @@ export default {
 //@import url(); 引入公共css类
 .NNPE-ArticleView {
   width: 100%;
+  .NPC-sentences-list {
+    padding: 24px 0;
+  }
   .NNPE-detail {
     clear: both;
     overflow: hidden;
@@ -385,11 +431,21 @@ export default {
     .wordsList-box {
       width: 100%;
       padding: 6px 24px 12px 24px;
+      > div {
+        overflow: hidden;
+        clear: both;
+      }
       > img {
         width: 100%;
         display: block;
       }
     }
   }
+  .NNPE-wordDetail {
+    position: fixed;
+    //   width: 260px;
+    //   height: 200px;
+    //   background: #cc0;
+  }
 }
 </style>

+ 119 - 86
src/components/Adult/preview/ArticleViewChs/WordModelChs.vue

@@ -7,97 +7,99 @@
       ref="audioLine"
     />
     <template v-if="resArr.length > 0">
-      <div
-        :class="['NNPE-detail', item.isTitle ? 'NNPE-detail-title' : '']"
-        v-for="(item, index) in resArr"
-        :key="'detail' + index"
-      >
-        <div class="wordsList-box">
-          <img :src="articleImg[index]" v-if="articleImg[0] && index == 0" />
-          <div>
-            <div
-              class="NNPE-words"
-              v-for="(pItem, pIndex) in item.wordsList"
-              :key="'wordsList' + pIndex"
-              :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
-              @click="showWordDetail($event, pItem.chs)"
-            >
-              <template v-if="!pItem.width">
-                <template v-if="pItem.isShow">
-                  <template
-                    v-if="
-                      item.wordsList[pIndex + 1].chs &&
-                      chsFhList.indexOf(item.wordsList[pIndex + 1].chs) > -1
-                    "
-                  >
-                    <span class="NNPE-words-box">
+      <div class="NPC-sentences-list">
+        <div
+          :class="['NNPE-detail', item.isTitle ? 'NNPE-detail-title' : '']"
+          v-for="(item, index) in resArr"
+          :key="'detail' + index"
+        >
+          <div class="wordsList-box">
+            <img :src="articleImg[index]" v-if="articleImg[0] && index == 0" />
+            <div>
+              <div
+                class="NNPE-words"
+                v-for="(pItem, pIndex) in item.wordsList"
+                :key="'wordsList' + pIndex"
+                :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
+                @click="showWordDetail($event, pItem.chs, pItem.pinyin)"
+              >
+                <template v-if="!pItem.width">
+                  <template v-if="pItem.isShow">
+                    <template
+                      v-if="
+                        item.wordsList[pIndex + 1].chs &&
+                        chsFhList.indexOf(item.wordsList[pIndex + 1].chs) > -1
+                      "
+                    >
+                      <span class="NNPE-words-box">
+                        <span
+                          class="NNPE-pinyin"
+                          :class="[pItem.className ? pItem.className : '']"
+                          >{{ pItem.pinyin }}</span
+                        >
+                        <span
+                          class="NNPE-chs"
+                          :class="[
+                            curTime >= item.timeList[pItem.sentIndex].bg &&
+                            curTime <= item.timeList[pItem.sentIndex].ed
+                              ? 'active'
+                              : '',
+                          ]"
+                          >{{ pItem.chs }}</span
+                        >
+                      </span>
+                      <span class="NNPE-words-box">
+                        <span class="NNPE-pinyin" style="text-align: left">{{
+                          item.wordsList[pIndex + 1].pinyin
+                        }}</span>
+                        <span
+                          class="NNPE-chs"
+                          style="text-align: left"
+                          :class="[
+                            curTime >= item.timeList[pItem.sentIndex].bg &&
+                            curTime <= item.timeList[pItem.sentIndex].ed
+                              ? 'active'
+                              : '',
+                          ]"
+                          >{{ item.wordsList[pIndex + 1].chs }}</span
+                        >
+                      </span>
+                    </template>
+                    <template v-else>
                       <span
                         class="NNPE-pinyin"
-                        :class="[pItem.className ? pItem.className : '']"
-                        >{{ pItem.pinyin }}</span
-                      >
-                      <span
-                        class="NNPE-chs"
                         :class="[
-                          curTime >= item.timeList[pItem.sentIndex].bg &&
-                          curTime <= item.timeList[pItem.sentIndex].ed
-                            ? 'active'
-                            : '',
+                          pItem.padding ? 'padding' : '',
+                          pItem.className ? pItem.className : '',
                         ]"
-                        >{{ pItem.chs }}</span
+                        >{{ pItem.pinyin }}</span
                       >
-                    </span>
-                    <span class="NNPE-words-box">
-                      <span class="NNPE-pinyin" style="text-align: left">{{
-                        item.wordsList[pIndex + 1].pinyin
-                      }}</span>
                       <span
                         class="NNPE-chs"
-                        style="text-align: left"
                         :class="[
                           curTime >= item.timeList[pItem.sentIndex].bg &&
                           curTime <= item.timeList[pItem.sentIndex].ed
                             ? 'active'
                             : '',
+                          pItem.padding ? 'padding' : '',
                         ]"
-                        >{{ item.wordsList[pIndex + 1].chs }}</span
+                        >{{ pItem.chs }}</span
                       >
-                    </span>
-                  </template>
-                  <template v-else>
-                    <span
-                      class="NNPE-pinyin"
-                      :class="[
-                        pItem.padding ? 'padding' : '',
-                        pItem.className ? pItem.className : '',
-                      ]"
-                      >{{ pItem.pinyin }}</span
-                    >
-                    <span
-                      class="NNPE-chs"
-                      :class="[
-                        curTime >= item.timeList[pItem.sentIndex].bg &&
-                        curTime <= item.timeList[pItem.sentIndex].ed
-                          ? 'active'
-                          : '',
-                        pItem.padding ? 'padding' : '',
-                      ]"
-                      >{{ pItem.chs }}</span
-                    >
+                    </template>
                   </template>
                 </template>
-              </template>
-              <template v-else>
-                <span
-                  :style="{
-                    height: pItem.height + 'px',
-                    width: pItem.width + 'px',
-                  }"
-                ></span>
-              </template>
+                <template v-else>
+                  <span
+                    :style="{
+                      height: pItem.height + 'px',
+                      width: pItem.width + 'px',
+                    }"
+                  ></span>
+                </template>
+              </div>
             </div>
+            <img :src="articleImg[index + 1]" v-if="articleImg[index + 1]" />
           </div>
-          <img :src="articleImg[index + 1]" v-if="articleImg[index + 1]" />
         </div>
       </div>
     </template>
@@ -133,6 +135,7 @@ export default {
       isShow: false,
       hz: "",
       oldHz: "",
+      pinyin: "",
       word: null,
       top: 0,
       left: 0,
@@ -145,7 +148,9 @@ export default {
     hz: {
       handler: function (val, oldVal) {
         let _this = this;
-        this.handleNewWords(val, this.top, this.left);
+        if (val) {
+          _this.handleNewWords(val, _this.top, _this.left);
+        }
       },
       // 深度观察监听
       deep: true,
@@ -260,14 +265,27 @@ export default {
       this.curTime = time;
       this.$refs.audioLine.onTimeupdateTime(time / 1000);
     },
-    showWordDetail(e, word) {
+    showWordDetail(e, word, pinyin) {
       let _this = this;
-      this.isShow = true;
-      _this.hz = word;
+      if (_this.oldHz != word) {
+        this.isShow = false;
+        setTimeout(() => {
+          _this.hz = word;
+          _this.pinyin = pinyin;
+        }, 50);
+      }
       _this.top = e.clientY + 20;
       let left = e.clientX;
+      let width = 0;
+      if (word.length == 1 || word.length == 2) {
+        width = 304;
+      } else if (word.length == 3 || word.length == 4) {
+        width = 432;
+      } else if (word.length > 3) {
+        width = 560;
+      }
       if (left - this.bodyLeft > this.contentWidth / 2) {
-        _this.left = left - 200;
+        _this.left = left - width;
       } else {
         _this.left = left;
       }
@@ -284,14 +302,22 @@ export default {
     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;
-        }
-      }
+      let wordlist = val.split("");
+      let option = {
+        definition_list: [],
+        mp3_list: [],
+        new_word: val,
+        pinyin: this.pinyin,
+      };
+      this.word = { list: wordlist, detail: option, top: top, left: left };
+      //   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;
     },
   },
@@ -318,6 +344,9 @@ export default {
 //@import url(); 引入公共css类
 .NNPE-ArticleView {
   width: 100%;
+  .NPC-sentences-list {
+    padding: 24px 0;
+  }
   .NNPE-detail {
     clear: both;
     overflow: hidden;
@@ -409,6 +438,10 @@ export default {
     .wordsList-box {
       width: 100%;
       padding: 6px 24px 12px 24px;
+      > div {
+        overflow: hidden;
+        clear: both;
+      }
       > img {
         width: 100%;
         display: block;

+ 8 - 6
src/components/Adult/preview/ArticleViewChs/index.vue

@@ -32,7 +32,7 @@
         @change="handleSwitchChange('showPhrases', 'showPractice')"
       >
       </el-switch>
-      <div class="setting-fontsize">
+      <!-- <div class="setting-fontsize">
         <a @click="handleFontsize('-')"
           ><img src="../../../../assets/newImage/common/btn-reduce.png"
         /></a>
@@ -40,14 +40,16 @@
         <a @click="handleFontsize('+')"
           ><img src="../../../../assets/newImage/common/btn-increase.png"
         /></a>
-      </div>
+      </div> -->
     </div>
     <div class="ArticleView-body" ref="ArticleViewbody">
-      <Preview
+      <NormalModelChs
         :curQue="curQue"
         :titleFontsize="titleFontsize"
         :wordFontsize="wordFontsize"
-        v-if="showPreview"
+        :bodyLeft="bodyLeft"
+        :bodyWidth="bodyWidth"
+        v-if="!showPhrases && !showPractice && !showWord"
       />
       <PhraseModel
         :curQue="curQue"
@@ -77,14 +79,14 @@
 
 <script>
 import PhraseModel from "./PhraseModelChs.vue";
-import Preview from "./NormalModelChs.vue";
+import NormalModelChs from "./NormalModelChs.vue";
 import Practice from "./Practicechs.vue"; // 语音练习模式
 import WordModel from "./WordModelChs.vue"; // 语音练习模式
 
 export default {
   name: "ArticleView",
   props: ["curQue", "NNPENewWordList"],
-  components: { Preview, Practice, WordModel, PhraseModel },
+  components: { NormalModelChs, Practice, WordModel, PhraseModel },
   data() {
     return {
       showPreview: true, // 全文预览

+ 44 - 37
src/components/Adult/preview/UploadControlView.vue

@@ -6,9 +6,9 @@
         :changeFillId="changeFillId"
         :accept="accept"
         :filleNumber="1"
-        :fileList="fileList"
+        :fileList="curQue.fileList"
       />
-      <div class="uploadBtn">
+      <div class="uploadBtn" @click="downLoad">
         <img
           style="width: 24px; height: 24px"
           src="../../../assets/adult/download.png"
@@ -18,7 +18,7 @@
       </div>
     </div>
 
-    <div class="dv">
+    <div class="dv" v-loading="loading">
       <div class="main">
         <div class="content">
           <template v-if="curQue.data">
@@ -34,24 +34,12 @@
               <pdf
                 ref="pdf"
                 :src="curQue.data.fileRelativePath"
-                v-for="i in numPages"
+                v-for="i in curQue.data.numPages"
                 :key="i"
                 :page="i"
               >
               </pdf>
             </template>
-            <template v-else>
-              <iframe
-                :src="
-                  'https://view.officeapps.live.com/op/view.aspx?src=' +
-                  `${curQue.data.file_url}`
-                "
-                width="100%"
-                height="1000px"
-                id="if"
-              >
-              </iframe>
-            </template>
           </template>
         </div>
       </div>
@@ -65,12 +53,14 @@
 <script>
 import UploadView from "../common/UploadView.vue";
 import pdf from "vue-pdf";
+import { getToken } from "@/utils/auth";
+
 export default {
   components: {
     UploadView,
     pdf,
   },
-  props: ["curQue", "changeCurQue"],
+  props: ["curQue", "fn_data"],
   data() {
     return {
       uploadType: "",
@@ -90,24 +80,49 @@ export default {
           },
         ],
       },
+      loading: false,
     };
   },
   computed: {},
   watch: {},
   //方法集合
   methods: {
+    //   下载表格
+    downLoad() {
+      let userInfor = JSON.parse(getToken());
+      let UserCode = "",
+        UserType = "",
+        SessionID = "";
+      if (userInfor) {
+        UserCode = userInfor.user_code;
+        UserType = userInfor.user_type;
+        SessionID = userInfor.session_id;
+      }
+      let FileID = this.curQue.data.file_id;
+      let data = {
+        SessionID,
+        UserCode,
+        UserType,
+        FileID,
+      };
+      location.href =
+        process.env.VUE_APP_BASE_API +
+        `/GCLSFileServer/WebFileDownload?UserCode=${data.UserCode}&UserType=${data.UserType}&SessionID=${data.SessionID}&FileID=${data.FileID}`;
+    },
     remove() {
       this.data = null;
-      tis.curQue.data = null;
-      this.fileList = [];
+      this.curQue.data = null;
+      this.curQue.fileList = [];
+      this.$message.success("删除成功")
+
     },
     changeFillId(fileList, item, index) {
-      this.fileList = fileList;
-      this.curQue.data = this.fileList[0].response.file_info_list[0];
+      this.curQue.fileList = fileList;
+      this.curQue.data = fileList[0].response.file_info_list[0];
       if (this.curQue.data.file_name.indexOf("pdf" != -1)) {
+        this.curQue.data = fileList[0].response.file_info_list[0];
         this.curQue.data.fileRelativePath =
           process.env.VUE_APP_BASE_API + this.curQue.data.file_relative_path;
-        this.curQue.data = this.fileList[0].response.file_info_list[0];
         this.getNumPages();
       }
     },
@@ -118,8 +133,11 @@ export default {
         _this.curQue.data.fileRelativePath
       );
       loadingTask.promise
-        .then((pdf) => {
-          _this.numPages = pdf.numPages;
+        .then((pdff) => {
+          _this.numPages = pdff.numPages;
+          _this.curQue.data.numPages = pdff.numPages;
+          this.$forceUpdate();
+
         })
         .catch((err) => {
           console.error("pdf 加载失败", err);
@@ -132,19 +150,7 @@ export default {
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {
-    if (!this.curQue) {
-      this.initcurQue();
-    } else {
-      if (this.curQue.data && this.curQue.data.file_name.indexOf("pdf") != -1) {
-        let _this = this;
-        let loadingTask = pdf.createLoadingTask(
-          _this.curQue.data.fileRelativePath
-        );
-        loadingTask.promise.then((pdf) => {
-          _this.numPages = pdf.numPages;
-        });
-      }
-    }
+
   },
   //生命周期 - 挂载完成(可以访问DOM元素)
   mounted() {},
@@ -199,6 +205,7 @@ export default {
     line-height: 150%;
     color: #000000;
     margin-left: 16px;
+    cursor: pointer;
     img {
       margin-right: 13px;
     }

+ 306 - 0
src/components/Adult/preview/components/ChinaDict.vue

@@ -0,0 +1,306 @@
+<template>
+    <!-- 中文汉字 解释 -->
+    <div class="Chineseexplain">
+        <div class="Chineseexplain_top" v-if="wordNum != '2'">
+            <div class="penobey">
+                <span>笔顺:<b style="font-family:none;font-weight:normal;">一 一 一 丿 ㇏ 丨 𠃍 一 一</b></span>
+            </div>
+            <div class="top_conten">
+                <span>部首</span>
+                <div>日</div>
+                <span>笔画</span>
+                <div>9</div>
+                <span>繁体</span>
+                <div>春</div>
+            </div>
+        </div>
+        <div :class="wordNum == '2' ? 'moreMain' : ''" class="main">
+            <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="main-content" v-if="navIndex == 0">
+                <p style="color: #19b068;font-famaily:GB-PINYINOK-B">chūn</p>
+                <p>1.春季:~景。温暖如~。</p>
+                <p>2.指一年的时间:一卧东山三十~。</p>
+                <!-- <p class="combine-words">
+                    <span>~校</span>
+                    <span>~局</span>
+                    <span>~公司</span>
+                </p> -->
+                <p>3.指男女情欲:怀~。~心。</p>
+                <p>4.比喻生机:妙手回~。</p>
+                <p>5.姓。</p>
+            </div>
+            <div class="main-content" v-else>
+                <p>
+                    春,chun,会意。甲骨文字形,从艹(木),草木春时生长;中间是“屯”字,似草木破土而出,土上臃肿部分,即刚破土的胚芽形,表示春季万木生长。“屯”亦兼作声符。小篆字形,隶变以后,除“日”之外,其他部分都看不出来了。本义:春。四季的第一季。春,是一年四季之首,俗话说得好:“一年之计在于春,一日之计在于晨”。万物生长的季节。植物萌芽生长、动物繁殖、农夫下地播种。古代把“历史”叫做“春秋”,那是因为庄稼春生秋熟,春生相当于历史之因,秋熟相当于历史之果,春来秋去的循环就是时间,而时间的循环就是历史。春季开始是在立春(2月2日至5日之间),春季结束在立夏(5月5日至7日之间)。在欧美,春季从中国的春分开始,到夏至结束。在爱尔兰,2月、3月和4月被定为春季,在南半球,一般9月、10月和11月被定为春季。另有朱自清的散文《春》和巴金的小说《春》以及其他一些文学艺术作品。
+                </p>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: "Chineseexplain",
+    props: ["wordNum"],
+    data () {
+        return {
+            navIndex: 0,
+        };
+    },
+    methods: {
+        changeNav (index) {
+            this.navIndex = index;
+        },
+    },
+};
+</script>
+
+<style lang='scss' scoped>
+.Chineseexplain {
+    margin-left: 80px;
+    overflow: auto;
+    width: 748px;
+}
+.Chineseexplain_top {
+    background: #fff;
+    box-shadow: 4px 4px 0px 4px rgba(44, 136, 69, 0.17);
+    border-radius: 24px;
+    height: 200px;
+    padding-top: 20px;
+    margin-bottom:40px;
+}
+.penobey {
+    width: 85%;
+    margin: 0 auto;
+    display: flex;
+    align-items: center;
+}
+.Chineseexplain_top span {
+    font-family: FZJCGFKTK;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 32px;
+    color: #19b068;
+}
+.top_conten {
+    width: 90%;
+    margin: 30px auto;
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+}
+.top_conten > div {
+    width: 72px;
+    height: 72px;
+    font-family: FZJCGFKTK;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 48px;
+    border-radius: 8px;
+    background: url('../../assets/common/chinaTian.png') no-repeat 100% 100%;
+    background-size: 100% 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    color: #4d4b51;
+}
+.main {
+    //   margin-top: 30px;
+    // width: 720px;
+    background: #eefff7;
+    box-shadow: 4px 4px 0px 4px rgba(44, 136, 69, 0.17);
+    border-radius: 24px;
+    padding: 40px 0;
+    &.moreMain {
+        width: 100%;
+    }
+}
+.nav-list {
+    width: 312px;
+    height: 44px;
+    margin: 0 auto;
+    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;
+        }
+    }
+}
+.main-content {
+    padding: 48px 48px 0 48px;
+    text-align: left;
+    margin: 0 auto;
+    .combine-words {
+        padding-left: 10px;
+        span {
+            margin-left: 20px;
+        }
+    }
+}
+.main-content p {
+    font-size: 36px;
+    font-family: FZJCGFKTK;
+    font-style: normal;
+    font-weight: normal;
+    color: #404040;
+}
+.questionMiddle {
+    .Chineseexplain {
+        margin-left: 53px;
+        width: 513px;
+    }
+    .Chineseexplain_top {
+        background: #fff;
+        box-shadow: 3px 3px 0px 3px rgba(44, 136, 69, 0.17);
+        border-radius: 16px;
+        height: 133px;
+        padding-top: 14px;
+        margin-bottom:30px;
+    }
+    .penobey {
+        width: 85%;
+        margin: 0 auto;
+    }
+    .Chineseexplain_top span {
+        font-size: 22px;
+    }
+    .top_conten {
+        width: 90%;
+        margin: 20px auto;
+    }
+    .top_conten > div {
+        width: 48px;
+        height: 48px;
+        font-size: 32px;
+        border-radius: 6px;
+        background: url('../../assets/common/chinaTian.png') no-repeat 100% 100%;
+        background-size: 100% 100%;
+    }
+    .main {
+        //   margin-top: 30px;
+        // width: 480px;
+        box-shadow: 3px 3px 0px 3px rgba(44, 136, 69, 0.17);
+        border-radius: 16px;
+        padding: 26px 0;
+        &.moreMain {
+            width: 100%;
+        }
+    }
+    .nav-list {
+        width: 208px;
+        height: 30px;
+        border-radius: 160px;
+        margin-bottom: 30px;
+        > li {
+            height: 34px;
+            width: 104px;
+            font-size: 18px;
+            line-height: 34px;
+            &.active {
+                background: #19b068;
+                border-radius: 160px;
+                color: #ffffff;
+            }
+        }
+    }
+    .main-content {
+        padding: 32px 32px 0 32px;
+        .combine-words {
+            padding-left: 6px;
+            span {
+                margin-left: 14px;
+            }
+        }
+    }
+    .main-content p {
+        font-size: 24px;
+    }
+}
+.questionSmall {
+    .Chineseexplain {
+        margin-left: 40px;
+        width: 374px;
+    }
+    .Chineseexplain_top {
+        box-shadow: 2px 2px 0px 2px rgba(44, 136, 69, 0.17);
+        border-radius: 12px;
+        height: 100px;
+        padding-top: 10px;
+        margin-bottom:20px;
+    }
+    .Chineseexplain_top span {
+        font-size: 16px;
+    }
+    .top_conten {
+        margin: 15px auto;
+    }
+    .top_conten > div {
+        width: 36px;
+        height: 36px;
+        font-size: 24px;
+        border-radius: 4px;
+        background: url('../../assets/common/chinaTian.png') no-repeat 100% 100%;
+        background-size: 100% 100%;
+    }
+    .main {
+        //   margin-top: 30px;
+        // width: 360px;
+        box-shadow: 2px 2px 0px 2px rgba(44, 136, 69, 0.17);
+        border-radius: 12px;
+        padding: 20px 0;
+        &.moreMain {
+            width: 100%;
+        }
+    }
+    .nav-list {
+        width: 156px;
+        height: 22px;
+        border-radius: 120px;
+        margin-bottom: 22px;
+        > li {
+            height: 26px;
+            width: 78px;
+            font-size: 14px;
+            line-height: 26px;
+            &.active {
+                background: #19b068;
+                border-radius: 120px;
+                color: #ffffff;
+            }
+        }
+    }
+    .main-content {
+        padding: 24px 24px 0 24px;
+        .combine-words {
+            padding-left: 5px;
+            span {
+                margin-left: 10px;
+            }
+        }
+    }
+    .main-content p {
+        font-size: 18px;
+    }
+}
+</style>

+ 193 - 0
src/components/Adult/preview/components/Freewrite.vue

@@ -0,0 +1,193 @@
+<!--  -->
+<template>
+    <div class="freewrite">
+        <div class="strockred" :class="wordNum ? '' : 'strockred_single'">
+            <!-- <div class="strock-play-box" @click="handelReset">
+        <img src="@/assets/common/strock-play.png" class="strock-play" />
+            </div>-->
+            <div :class="wordNum ? 'character-target-div_more' : 'character-target-div_single'" class="character-target-div">
+                <vueEsign
+                    :bgColor.sync="bgColor"
+                    :height="height"
+                    :isCrop="isCrop"
+                    :lineColor="lineColor"
+                    :lineWidth="lineWidth"
+                    :width="width"
+                    class="vueEsign"
+                    ref="esign"
+                />
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import vueEsign from "vue-esign";
+export default {
+    components: {
+        vueEsign,
+    },
+    props: ["lineColor", "lineWidth", "cur", "wordNum"],
+    data () {
+        return {
+            width: this.wordNum != "2" ? 444 : 800,
+            height: 444,
+            bgColor: "",
+            isCrop: false,
+        };
+    },
+    computed: {},
+    watch: {
+        // lineColor(newVal, oldVal) {
+        //   this.updateColor(newVal);
+        // }
+    },
+    //方法集合
+    methods: {
+        handelReset () {
+            this.$refs.esign.reset();
+        },
+        handleGenerate () {
+            this.$refs.esign
+                .generate()
+                .then((res) => {
+                    let Book_img = res.replace("data:image/png;base64,", "");
+                    //console.log(Book_img);
+                    //this.textOcr(res.replace("data:image/png;base64,", ""));
+                })
+                .catch((err) => {
+                    console.log(err);
+                });
+        },
+    },
+    //生命周期 - 创建完成(可以访问当前this实例)
+    created () { },
+    //生命周期 - 挂载完成(可以访问DOM元素)
+    mounted () { },
+    beforeCreate () { }, //生命周期 - 创建之前
+    beforeMount () { }, //生命周期 - 挂载之前
+    beforeUpdate () { }, //生命周期 - 更新之前
+    updated () { }, //生命周期 - 更新之后
+    beforeDestroy () { }, //生命周期 - 销毁之前
+    destroyed () { }, //生命周期 - 销毁完成
+    activated () { }, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+//@import url(); 引入公共css类
+.freewrite {
+    width: 100%;
+    .strockred {
+        position: relative;
+        margin: 0 auto;
+        width: 100%;
+        height: 448px;
+        .character-target-div {
+            width: 100%;
+            height: 448px;
+            // background: url('../../assets/common/bg-field.png') center no-repeat;
+            // background-size: 100% 100%;
+            border-radius: 24px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            z-index: 99999;
+            &_more {
+                width: 100%;
+                background: 0 0;
+                background-size: 100% 100%;
+            }
+            .vueEsign {
+                width: 444px;
+                height: 448px;
+            }
+        }
+    }
+}
+.questionMiddle {
+    .freewrite {
+        .strockred {
+            .character-target-div {
+                // background: url('../../assets/common/bg-field.png') center no-repeat;
+                // background-size: 100% 100%;
+                border-radius: 16px;
+                .vueEsign {
+                    width: 296px;
+                    height: 296px;
+                }
+                &.character-target-div_single{
+                    height: 296px;
+                }
+            }
+            &.strockred_single{
+                height: 296px;
+            }
+        }
+    }
+}
+.questionSmall {
+    .freewrite {
+        .strockred {
+            .character-target-div {
+                // background: url('../../assets/common/bg-field.png') center no-repeat;
+                // background-size: 100% 100%;
+                border-radius: 12px;
+                .vueEsign {
+                    width: 222px;
+                    height: 222px;
+                }
+                &.character-target-div_single{
+                    height: 222px;
+                }
+            }
+            &.strockred_single{
+                height: 222px;
+            }
+        }
+    }
+}
+</style>
+<style lang="scss">
+.strock-play-box {
+    position: absolute;
+    right: 0;
+    top: 0;
+    z-index: 999;
+    width: 84px;
+    height: 84px;
+    background: url('../../assets/common/strock-play.png');
+    background-size: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+    > img {
+        width: 19px;
+        height: 24px;
+    }
+}
+.strock-play-box:active {
+    background: url('../../assets/common/strock-play-click.png');
+    background-size: 100%;
+}
+.questionMiddle {
+    .strock-play-box {
+        width: 56px;
+        height: 56px;
+        > img {
+            width: 13px;
+            height: 16px;
+        }
+    }
+}
+.questionSmall {
+    .strock-play-box {
+        width: 42px;
+        height: 42px;
+        > img {
+            width: 10px;
+            height: 12px;
+        }
+    }
+}
+</style>

+ 202 - 203
src/components/Adult/preview/components/Practice.vue

@@ -6,11 +6,11 @@
       class="Book_content"
       v-for="(item, index) in cur.stem"
     >
-      <!-- <img
+      <img
         @click="changePraShow()"
         class="close-icon"
-        src="../../assets/common/close-icon.png"
-      /> -->
+        src="../../../../assets/NPC/close-icon-red.png"
+      />
       <div class="left-content">
         <Audio :mp3="item.mp3_url" :pinyin="item.pinyin" />
 
@@ -123,14 +123,14 @@
 </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";
+import Strockplay from "./Strockplay.vue";
+// import Strockred from "./Strockred";
+// import Freewrite from "./Freewrite";
+// import ChinaDict from "./ChinaDict";
+// import Audio from "./AudioRed.vue";
 export default {
   components: {
-    // Strockplay,
+    Strockplay,
     // Strockred,
     // Freewrite,
     // ChinaDict,
@@ -204,188 +204,187 @@ export default {
 };
 </script>
 <style lang='scss' scoped>
-//@import url(); 引入公共css类
-// .practice {
-//   width: 1368px;
-//   max-height: 840px;
-//   overflow: auto;
-//   margin: 0 auto;
+.practice {
+  width: 504px;
+  max-height: 434px;
+  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;
-//               }
-//             }
+  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;
+            &.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;
@@ -403,23 +402,23 @@ export default {
 //       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 */
+  .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;
+    text-align: center;
 
-//     color: #ba7d21;
-//   }
-// }
+    color: #ba7d21;
+  }
+}
 
 </style>
 <style lang="scss">

+ 130 - 0
src/components/Adult/preview/components/Strockplay.vue

@@ -0,0 +1,130 @@
+<!--  -->
+<template>
+  <div class="strockplayInner" :class="className">
+    <div @click="playHanzi" class="strock-play-box" v-if="playStorkes">
+      <!-- <img class="strock-play" src="../../assets/common/strock-play.png"> -->
+    </div>
+    <div
+      :class="wordNum == '2' ? 'morewords' : ''"
+      :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",
+    "className",
+  ],
+  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;
+      //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类
+.strockplayInner {
+  position: relative;
+  margin: 0 auto;
+  width: 100%; //444px
+  height: 100%; //480px
+}
+.character-target-div {
+  width: 100%; //444px
+  height: 100%; //480px
+  background: #fff url("../../../../assets/NPC/chinaTianRed.png") center no-repeat;
+  background-size: 100% 100%;
+  border-radius: 24px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 99999;
+  &.morewords {
+    background: url("../../../../assets/NPC/chinaTianRed.png") center no-repeat;
+    background-size: 100% 100%;
+  }
+}
+.animate-butto {
+  width: 240px;
+  height: 160px;
+  font-size: 28px;
+}
+// .adult-strockplay {
+//   .character-target-div {
+//     background: #fff url("../../assets/adult/adult-hz-tian.png") center
+//       no-repeat;
+//     background-size: 100% 100%;
+//   }
+//   .strock-play-box {
+//     position: absolute;
+//     top: 0;
+//     right: 0;
+//     width: 20px;
+//     height: 20px;
+//     background: #fff url("../../assets/adult/adult-play-strock.png") center
+//       no-repeat;
+//     background-size: 100% 100%;
+//   }
+// }
+</style>

+ 168 - 0
src/components/Adult/preview/components/Strockred.vue

@@ -0,0 +1,168 @@
+<!--  -->
+<template>
+    <div class="strockredBox">
+        <div class="strockred">
+            <div @click="resetHanzi" class="strock-play-box" v-if="playStorkes">
+                <!-- <img src="../../assets/common/strock-play.png" class="strock-play" /> -->
+            </div>
+            <div
+                :class="wordNum == '2' ? 'character-target-div_220' : ''"
+                :id="targetDiv"
+                class="character-target-div"
+            ></div>
+        </div>
+    </div>
+</template>
+
+<script>
+const HanziWriter = require("hanzi-writer");
+export default {
+    name: "Strockred",
+    components: {},
+    props: ["targetDiv", "hanzicolor", "Book_text", "playStorkes", "wordNum"],
+    data () {
+        return {
+            writer: null,
+            colorsList: ["#404040", "#f65d4d", "#19b068", "#52a1ea", "#ff8c49"],
+        };
+    },
+    computed: {},
+    watch: {
+        hanzicolor (newVal, oldVal) {
+            this.updateColor(newVal);
+        },
+        Book_text: {
+            handler: function (val, oldVal) {
+                if (val != oldVal) {
+                    let _this = this;
+                    _this.$nextTick(() => {
+                        _this.initHanziwrite();
+                    });
+                }
+            },
+            // 深度观察监听
+            deep: true,
+        },
+    },
+    //方法集合
+    methods: {
+        initHanziwrite () {
+            let _this = this;
+            let options = {
+                padding: 5,
+                showCharacter: false,
+                strokeColor: _this.hanzicolor,
+                drawingColor: _this.hanzicolor,
+                drawingWidth: 6,
+            };
+            _this.writer = HanziWriter.default.create(
+                _this.targetDiv,
+                _this.Book_text,
+                options
+            );
+            _this.writer.quiz();
+        },
+        resetHanzi () {
+            let _this = this;
+            _this.writer.quiz();
+        },
+        updateColor (color) {
+            let _this = this;
+            _this.writer.updateColor("strokeColor", color);
+            _this.writer.updateColor("drawingColor", color);
+        },
+    },
+    //生命周期 - 创建完成(可以访问当前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类
+.strockredBox {
+    width: 100%;
+    height: 100%;
+}
+.strockred {
+    position: relative;
+    margin: 0 auto;
+    width: 100%;
+    height: 100%;
+    //chinawrite220.png
+    .character-target-div {
+        width: 100%;
+        height: 100%;
+        background: url('../../assets/common/bg-field.png') center no-repeat;
+        background-size: 100% 100%;
+        border-radius: 24px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        z-index: 99999;
+        &_220 {
+            background: url('../../assets/common/chinawrite220.png') center
+                no-repeat;
+            background-size: 100% 100%;
+            border-radius: 0;
+        }
+    }
+    .animate-butto {
+        width: 240px;
+        height: 160px;
+        font-size: 28px;
+    }
+}
+.questionMiddle {
+    .strockred {
+        .character-target-div {
+            background: url('../../assets/common/bg-field.png') center no-repeat;
+            background-size: 100% 100%;
+            border-radius: 16px;
+            &_220 {
+                background: url('../../assets/common/chinawrite220.png') center
+                    no-repeat;
+                background-size: 100% 100%;
+                border-radius: 0;
+            }
+        }
+        .animate-butto {
+            width: 160px;
+            height: 106px;
+            font-size: 18px;
+        }
+    }
+}
+.questionSmall {
+    .strockred {
+        .character-target-div {
+            background: url('../../assets/common/bg-field.png') center no-repeat;
+            background-size: 100% 100%;
+            border-radius: 12px;
+            &_220 {
+                background: url('../../assets/common/chinawrite220.png') center
+                    no-repeat;
+                background-size: 100% 100%;
+                border-radius: 0;
+            }
+        }
+        .animate-butto {
+            width: 120px;
+            height: 80px;
+            font-size: 14px;
+        }
+    }
+}
+</style>

+ 82 - 51
src/components/Adult/preview/components/Wordcard.vue

@@ -5,9 +5,10 @@
       <i class="el-icon-close" @click="changeWordCard(false)"></i>
     </div>
     <div class="bwc-top" v-if="word.detail">
+        <span v-if="word.detail.pinyin">{{word.detail.pinyin}}</span>
       <Audio
         :fontSize="20"
-        :mp3="word.detail.mp3_url ? word.detail.mp3_url : ''"
+        :mp3="word.detail.mp3_list.length>0 ? word.detail.mp3_list[0].url : ''"
         :pinyin="word.detail.pinyin"
       />
     </div>
@@ -27,11 +28,21 @@
           :targetDiv="'bwcHanziIntp' + conItem + conindex"
           :wordNum="word.detail.new_word.length"
         />
+        <img
+          src="../../../../assets/NPC/icon-write-red.png"
+          class="collect-icon"
+          v-if="word.detail.new_word.length>1"
+          @click="writeWord(conItem)"
+        />
         <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-word-en" v-if="word.detail && word.detail.definition_list.length>0">
+        <span v-for="(item,index) in word.detail.definition_list" :key="index">
+            {{item}}{{index==word.detail.definition_list.length-1?'':';'}}
+        </span>
+    </div>
     <div class="bwc-more-intp" @click="viewIntp">更多释义</div>
     <div class="bwc-footer">
       <button class="bwc-btn">
@@ -41,7 +52,7 @@
         />
         收藏
       </button>
-      <button class="bwc-btn" @click="writeWord">
+      <button class="bwc-btn bwc-btn2" @click="writeWord(word.detail.new_word,word.detail.pinyin)" v-if="word.detail.new_word.length==1">
         <img
           src="../../../../assets/NPC/icon-write-red.png"
           class="collect-icon"
@@ -50,12 +61,7 @@
       </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" />
@@ -67,9 +73,7 @@
 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",
@@ -77,7 +81,6 @@ export default {
     Strockplayredline,
     Audio,
     Practice,
-    Practicewords,
     Wordintp,
   },
   props: ["word", "changeWordCard"],
@@ -93,15 +96,15 @@ export default {
     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: "",
-            },
-          ],
-        };
+        // 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,
@@ -109,8 +112,23 @@ export default {
   },
   //方法集合
   methods: {
-    writeWord() {
+    writeWord(words,pinyin) {
       this.isPraShow = true;
+      this.curData = {
+        stem: [
+          {
+            con:
+              words
+                ? words
+                : "",
+            pinyin:
+              pinyin && pinyin
+                ? pinyin
+                : "",
+            mp3_url: "",
+          },
+        ],
+      };
     },
     changePraShow() {
       this.isPraShow = false;
@@ -121,40 +139,30 @@ export default {
     changeIntpShow() {
       this.isIntpShow = false;
     },
-    getChineseInfo(){
-        let data = {
-            query: this.word.detail.new_word,
-        };
-        debugger
-        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: "",
-          },
-        ],
-      };
+    //   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() {}, //生命周期 - 创建之前
@@ -194,7 +202,8 @@ export default {
     }
   }
   min-width: 304px;
-  min-height: 360px;
+  max-width: 560px;
+//   min-height: 360px;
   background: #ffffff;
   box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.15);
   border-radius: 8px;
@@ -206,6 +215,16 @@ export default {
     display: flex;
     justify-content: center;
     align-items: center;
+    .content-voices{
+        width: 24px;
+    }
+    >span{
+        font-family: 'GB-PINYINOK-B';
+        color: #2C2C2C;
+        font-size: 20px;
+        line-height: 24px;
+        margin-right: 4px;
+    }
   }
   .bwc-Strockplay {
     display: flex;
@@ -223,6 +242,14 @@ export default {
       display: flex;
       justify-content: center;
       align-items: center;
+      position: relative;
+      .collect-icon{
+          width: 16px;
+          position: absolute;
+          right: 4px;
+          bottom: 4px;
+          cursor: pointer;
+      }
     }
     .bwc-line {
       width: 2px;
@@ -239,12 +266,11 @@ export default {
   }
   .bwc-word-en {
     font-style: normal;
-    font-weight: 600;
-    font-size: 20px;
+    font-size: 16px;
     line-height: 150%;
     text-align: center;
     color: #2c2c2c;
-    margin-bottom: 8px;
+    margin-bottom: 14px;
   }
   .bwc-more-intp {
     font-weight: normal;
@@ -262,7 +288,8 @@ export default {
     justify-content: space-between;
     align-items: center;
     > button {
-      width: 128px;
+    //   width: 128px;
+      flex: 1;
       height: 40px;
       display: flex;
       justify-content: center;
@@ -275,12 +302,16 @@ export default {
       cursor: pointer;
       border: 1px solid rgba(0, 0, 0, 0.1);
       font-size: 16px;
+      &.bwc-btn2{
+        margin-left: 8px;
+      }
       > img {
         width: 24px;
         height: 24px;
         margin-right: 4px;
       }
     }
+    
   }
 }
 </style>

+ 281 - 31
src/components/Adult/preview/components/Wordintp.vue

@@ -2,19 +2,20 @@
 <template>
   <div class="wordIntp" v-if="word">
     <div class="closeBox">
+      <span>数据来自百度汉语</span>
       <i class="el-icon-close" @click="changeIntpShow(false)"></i>
     </div>
     <div class="bwc-top" v-if="word.detail">
+        <span v-if="word.detail.pinyin">{{word.detail.pinyin}}</span>
       <Audio
         :fontSize="20"
-        :mp3="word.detail.mp3_url ? word.detail.mp3_url : ''"
-        :pinyin="word.detail.pinyin"
+        :mp3="mp3Url ? mp3Url : ''"
       />
     </div>
     <div
       class="bwc-Strockplay"
-      :style="{ width: word.list.length * 126 + 8 + 'px' }"
-      v-if="word.list.length<5"
+      :style="{ width: word.detail.new_word.length * 126 + 8 + 'px' }"
+      v-if="word.detail.new_word.length<5"
     >
       <div
         :key="conindex"
@@ -25,12 +26,12 @@
           :Book_text="conItem"
           :playStorkes="true"
           :targetDiv="'bwcIntp' + conItem + conindex"
-          :wordNum="word.list.length"
+          :wordNum="word.detail.new_word.length"
         />
-        <div class="bwc-line" v-if="conindex < word.list.length - 1"></div>
+        <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.list" :key="index">{{item}}</span></p>
+    <p v-else class="bwc-tolength"><span v-for="(item,index) in word.detail.new_word" :key="index">{{item}}</span></p>
     <el-menu
       :default-active="activeIndex"
       class="el-menu-demo"
@@ -38,28 +39,58 @@
       @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-item index="2">近/反义词</el-menu-item>
+      <el-menu-item index="3">组词</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>
+      <div class="bwc-intp">
+        <!-- 基本释义 -->
+        <h1>基本释义</h1>
+        <span v-if="word.detail.pinyin" class="pinyin">{{word.detail.pinyin}}</span>
+        <p v-for="(itemss,indexss) in paraphrase" :key="indexss" class="paraphrase">
+            {{itemss['@value']}}
+        </p>
+        <hr />
+      </div>
+    </template>
+    <template v-if="activeIndex == '2'">
+      <div class="bwc-intp">
+        <h1 v-if="synonymList.length>0">近义词</h1>
+        <ul class="synonym">
+            <li v-for="(itemss,indexss) in synonymList" :key="indexss" class="paraphrase">
+                {{itemss['@value']}}
+            </li>
+        </ul>
+        <h1 v-if="antonymList.length>0">反义词</h1>
+        <ul class="synonym">
+            <li v-for="(itemss,indexss) in antonymList" :key="indexss" class="paraphrase">
+                {{itemss['@value']}}
+            </li>
+        </ul>
+      </div>
+    </template>
+    <template v-if="activeIndex == '3'">
+      <div class="bwc-intp">
+        <ul class="synonym">
+            <li v-for="(itemss,indexss) in termsList" :key="indexss" class="paraphrase">
+                {{itemss['@value']}}
+            </li>
+        </ul>
+      </div>
     </template>
   </div>
 </template>
 
 <script>
-// import Audio from "./Audio.vue";
-// import Strockplayredline from "./Strockplayredline.vue";
+import Audio from "./AudioRed.vue";
+import Strockplayredline from "./Strockplayredline.vue";
+import { getHZChineseInfo } from "@/api/ajax";
 
 export default {
   name: "WordIntp",
   components: {
-    // Strockplayredline,
-    // Audio,
+    Strockplayredline,
+    Audio,
   },
   props: ["word", "changeIntpShow"],
   data() {
@@ -67,6 +98,88 @@ export default {
       isPraShow: false,
       curData: null,
       activeIndex: "1",
+      mp3Url:'', // 音频
+      paraphrase:[], // 释义
+      synonymList:[], // 近义词
+      antonymList:[], // 反义词
+      termsList:[], // 组词
+      dataDetail: [
+            {
+                "request":{
+                    "query":"熊掌",
+                    "queryType":"entity"
+                },
+                "response":{
+                    "voice":"熊掌,意思是:熊的脚掌。",
+                    "sourceUrl":"https://hanyu.baidu.com/zici/s?wd=%E7%86%8A%E6%8E%8C&amp;query=%E7%86%8A%E6%8E%8C&amp;srcid=28243&amp;from=kg2",
+                    "answer":[
+                        "熊掌"
+                    ],
+                    "sourceName":"百度汉语",
+                    "title":"熊掌",
+                    "entity":[
+                        {
+                            "@type":[
+                                "term"
+                            ],
+                            "name":"熊掌",
+                            "attrs":[
+                                {
+                                    "objects":[
+                                        {
+                                            "@value":"https://hanyu.baidu.com/zici/s?wd=%E7%86%8A%E6%8E%8C&amp;query=%E7%86%8A%E6%8E%8C&amp;srcid=28243&amp;from=kg2"
+                                        }
+                                    ],
+                                    "label":"详情页",
+                                    "type":"simple",
+                                    "key":"url"
+                                },
+                                {
+                                    "objects":[
+                                        {
+                                            "@value":"熊的脚掌。"
+                                        }
+                                    ],
+                                    "label":"释义",
+                                    "type":"simple",
+                                    "key":"definition"
+                                },
+                                {
+                                    "objects":[
+                                        {
+                                            "@value":"https://dss0.baidu.com/6KAZsjip0QIZ8tyhnq/text2audio?tex=%E7%86%8A%28xiong2%29%E6%8E%8C%28zhang3%29&amp;cuid=dict&amp;lan=ZH&amp;ctp=1&amp;pdt=30&amp;vol=9&amp;per=4100"
+                                        }
+                                    ],
+                                    "label":"读音",
+                                    "type":"simple",
+                                    "key":"pronunciation"
+                                },
+                                {
+                                    "objects":[
+                                        {
+                                            "@value":"[xióng zhǎng]"
+                                        }
+                                    ],
+                                    "label":"拼音",
+                                    "type":"simple",
+                                    "key":"spell"
+                                },
+                                {
+                                    "objects":[
+                                        {
+                                            "@value":"ceip"
+                                        }
+                                    ],
+                                    "label":"五笔",
+                                    "type":"simple",
+                                    "key":"wubi"
+                                }
+                            ]
+                        }
+                    ]
+                }
+            }
+        ]
     };
   },
   computed: {},
@@ -87,7 +200,51 @@ export default {
     changePraShow() {
       this.isPraShow = false;
     },
-    handleSelect() {},
+    handleSelect(val) {
+        this.activeIndex = val
+    },
+    getChineseInfo(){
+        let _this = this
+        let data = {
+            query: this.word.detail.new_word,
+            //  query: "开心",
+        };
+        debugger
+        getHZChineseInfo(data).then((res) => {
+            _this.dataDetail = res.data.result
+            _this.handleChineseDetail()
+        });
+    },
+    // 处理数据
+    handleChineseDetail(){
+        let _this = this
+        _this.dataDetail.forEach(item=>{
+            if(item.request.queryType=='entity'){
+                // 读音
+                item.response.entity.forEach(items=>{
+                    items.attrs.forEach(itemss=>{
+                        if(itemss.key=="pronunciation"){
+                            // 音频
+                             _this.mp3Url = itemss.objects[0]['@value']?itemss.objects[0]['@value']:''
+                        }else if(itemss.key=="definition"){
+                            // 释义
+                             _this.paraphrase = itemss.objects
+                        }else if(itemss.key=="synonym"){
+                            // 近义词
+                             _this.synonymList = itemss.objects
+                        }else if(itemss.key=="antonym"){
+                            // 反义词
+                             _this.antonymList = itemss.objects
+                        }else if(itemss.key=="terms"){
+                            // 反义词
+                             _this.termsList = itemss.objects
+                        }
+                    })
+                })
+               
+            }
+        })
+    }
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {},
@@ -95,6 +252,8 @@ export default {
   mounted() {
     let _this = this;
     console.log(this.word);
+    //   this.getChineseInfo()
+    _this.handleChineseDetail()
   },
   beforeCreate() {}, //生命周期 - 创建之前
   beforeMount() {}, //生命周期 - 挂载之前
@@ -109,17 +268,59 @@ export default {
 //@import url(); 引入公共css类
 .wordIntp {
   width: 600px;
-  height: 100vh;
+//   height: 100vh;
   overflow: hidden;
   overflow-y: auto;
   margin: 0 auto;
+  position: relative;
   .bwc-intp {
-    > li {
-      font-weight: normal;
-      font-size: 16px;
-      line-height: 150%;
-      color: #2c2c2c;
-    }
+      padding: 16px 0;
+      h1{
+          color: #000000;
+          font-size: 20px;
+          line-height: 150%;
+          font-weight: normal;
+          margin: 8px 0 8px 0;
+      }
+      .pinyin{
+          color: #DE4444;
+          font-size: 24px;
+          line-height: 36px;
+          margin-bottom: 8px;
+          font-family: 'GB-PINYINOK-B';
+          display: block;
+      }
+      .paraphrase{
+          margin-bottom: 8px;
+          margin-top: 0;
+          color: #000000;
+          font-size: 16px;
+          line-height: 150%;
+      }
+      hr{
+          margin: 16px 0 0 0;
+          background: rgba($color: #000000, $alpha: 0.15);
+          height: 1px;
+          border: none;
+      }
+      ul.synonym{
+          display: flex;
+          flex-flow: wrap;
+          margin-left: -4px;
+          padding: 4px 0;
+          li{
+              padding: 4px 8px;
+              background: #FFFFFF;
+              border: 1px solid rgba(0, 0, 0, 0.15);
+              border-radius: 4px;
+              margin: 4px;
+              font-size: 16px;
+              line-height: 150%;
+              color: #000000;
+              text-align: center;
+              min-width: 127px;
+          }
+      }
   }
   .practiceBox {
     position: fixed;
@@ -137,17 +338,29 @@ export default {
   .closeBox {
     width: 100%;
     display: flex;
-    justify-content: flex-end;
+    justify-content: space-between;
+    position: absolute;
+    left: 0;
+    top: 0;
+    padding: 12px;
     > i {
+        font-size: 16px;
+        color:#000000;
       cursor: pointer;
     }
+    span{
+        color: #000000;
+        opacity: 0.2;
+        font-size: 14px;
+        line-height: 130%;
+    }
   }
   min-width: 312px;
   min-height: 360px;
   background: #ffffff;
   box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.15);
   border-radius: 8px;
-  padding: 24px;
+  padding: 52px 32px 32px;
   box-sizing: border-box;
   .bwc-top {
     margin-bottom: 16px;
@@ -155,6 +368,16 @@ export default {
     display: flex;
     justify-content: center;
     align-items: center;
+    .content-voices{
+        width: 24px;
+    }
+    >span{
+        font-family: 'GB-PINYINOK-B';
+        color: #2C2C2C;
+        font-size: 20px;
+        line-height: 24px;
+        margin-right: 4px;
+    }
   }
   .bwc-Strockplay {
     display: flex;
@@ -163,19 +386,28 @@ export default {
     min-width: 130px;
     height: 130px;
     margin: 0 auto;
-    margin-bottom: 16px;
-    border: 2px solid #ff5757;
+    margin-bottom: 6px;
+    border: 2px solid #DE4444;
     border-radius: 8px;
     box-sizing: border-box;
+    overflow: hidden;
     .strockplay {
       display: flex;
       justify-content: center;
       align-items: center;
+      position: relative;
+      .collect-icon{
+          width: 16px;
+          position: absolute;
+          right: 4px;
+          bottom: 4px;
+          cursor: pointer;
+      }
     }
     .bwc-line {
       width: 2px;
       height: 126px;
-      background: #ff5757;
+      background: #DE4444;
     }
   }
   .bwc-tolength{
@@ -230,3 +462,21 @@ export default {
   }
 }
 </style>
+<style lang="scss">
+.wordIntp{
+    .el-menu--horizontal > .el-menu-item {
+        width: 33.33%;
+        text-align: center;
+        color: #000000;
+        font-size: 18px;
+    }
+    .el-menu.el-menu--horizontal{
+        border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+    }
+    .el-menu--horizontal>.el-menu-item.is-active{
+        color: #DE4444;
+        font-weight: bold;
+        border-bottom: 2px solid #DE4444;
+    }
+}
+</style>

+ 78 - 78
src/utils/request.js

@@ -10,94 +10,94 @@ axios.defaults.dataType = 'json'
 axios.defaults.headers['cache-control'] = 'no-cache'
 axios.defaults.headers['Content-Type'] = 'application/json'
 axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
-// create an axios instance
+    // create an axios instance
 const service = axios.create({
-  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
-  // withCredentials: true, // send cookies when cross-domain requests
-  timeout: 60000 // request timeout
+    baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
+    // withCredentials: true, // send cookies when cross-domain requests
+    timeout: 60000 // request timeout
 })
 
 // request interceptor
 service.interceptors.request.use(
-  config => {
-    // do something before request is sent
-    // let each request carry token
-    // ['X-Token'] is a custom headers key
-    // please modify it according to the actual situation
-    config.headers['Content-Type'] = 'application/json'
-    return config
-  },
-  error => {
-    // do something with request error
-    console.log(error) // for debug
-    return Promise.reject(error)
-  }
+    config => {
+        // do something before request is sent
+        // let each request carry token
+        // ['X-Token'] is a custom headers key
+        // please modify it according to the actual situation
+        config.headers['Content-Type'] = 'application/json'
+        return config
+    },
+    error => {
+        // do something with request error
+        console.log(error) // for debug
+        return Promise.reject(error)
+    }
 )
 
 // response interceptor
 service.interceptors.response.use(
-  /**
-   * If you want to get http information such as headers or status
-   * Please return  response => response
-   */
+    /**
+     * If you want to get http information such as headers or status
+     * Please return  response => response
+     */
 
-  /**
-   * Determine the request status by custom code
-   * Here is just an example
-   * You can also judge the status by HTTP Status Code
-   */
-  response => {
-    const res = response.data
-    console.log(res)
-    let msg = null
-    // if the custom code is not 20000, it is judged as an error.
-    if (res.status == 0 || res.status == -2) {
-      // 执行错误  JSON 数据格式错误
-      msg = Message({
-        message: res.msg || res.error || 'Error',
-        type: 'error',
-        showClose: true,
-        duration: 0
-      })
-      return Promise.reject(new Error(res.message || res.error || 'Error'))
-    } else if (res.status === -1) {
-      // 登录失效
-      Cookies.remove('session_id')
-      Cookies.remove('user_code')
-      Cookies.remove('user_real_name')
-      Cookies.remove('user_type')
-      removeToken();
-      msg = Message({
-        message: '登录会话失效,请重新登录',
-        type: 'error',
-        showClose: true,
-        duration: 0
-      })
-      if (process.env.NODE_ENV === 'development') {
-        router.push(`/login`)
-      } else {
-        window.location.href = '/';
-      }
-      return false
-    } else {
-      Message.closeAll()
-      return res
-    }
-  },
-  error => {
-    // || (error+1).indexOf('500') > -1
-    if ((error + 1).indexOf('401') > -1) {
-      // console.log(router)
-      // store.dispatch('user/postError')
-      // router.push(`/login`)
+    /**
+     * Determine the request status by custom code
+     * Here is just an example
+     * You can also judge the status by HTTP Status Code
+     */
+    response => {
+        const res = response.data
+        console.log(res)
+        let msg = null
+            // if the custom code is not 20000, it is judged as an error.
+        if (res.status == 0 || res.status == -2) {
+            // 执行错误  JSON 数据格式错误
+            msg = Message({
+                message: res.msg || res.error || 'Error',
+                type: 'error',
+                showClose: true,
+                duration: 0
+            })
+            return Promise.reject(new Error(res.message || res.error || 'Error'))
+        } else if (res.status === -1) {
+            // 登录失效
+            Cookies.remove('session_id')
+            Cookies.remove('user_code')
+            Cookies.remove('user_real_name')
+            Cookies.remove('user_type')
+            removeToken();
+            msg = Message({
+                message: '登录会话失效,请重新登录',
+                type: 'error',
+                showClose: true,
+                duration: 0
+            })
+            if (process.env.NODE_ENV === 'development') {
+                router.push(`/login`)
+            } else {
+                window.location.href = '/';
+            }
+            return false
+        } else {
+            Message.closeAll()
+            return res
+        }
+    },
+    error => {
+        // || (error+1).indexOf('500') > -1
+        if ((error + 1).indexOf('401') > -1) {
+            // console.log(router)
+            // store.dispatch('user/postError')
+            // router.push(`/login`)
+        }
+        Message({
+            message: '网络错误,请稍后重试',
+            type: 'error',
+            duration: 2 * 1000
+        })
+        return Promise.reject(error)
     }
-    Message({
-      message: '网络错误,请稍后重试',
-      type: 'error',
-      duration: 2 * 1000
-    })
-    return Promise.reject(error)
-  }
 )
 
-export default service
+export default service

+ 4 - 4
src/views/adultInput2.vue

@@ -174,7 +174,7 @@
                     选择模板
                   </div>
                   <div
-                    v-if="!topicIitem.data && topicIitem.is_addModule"
+                    v-if="!topicIitem.data && topicIitem.is_add_module"
                     class="addoption"
                     @click="addModule(toindex, rowIndex, lineIndex, topicIitem)"
                   >
@@ -414,7 +414,7 @@ export default {
           for (let j = 0; j < this.line; j++) {
             let obj = {
               text: `第${i + 1}行,第${j + 1}列`,
-              is_addModule: true,
+              is_add_module: true,
               is_edit: true,
             };
             rowArr.push(obj);
@@ -433,7 +433,7 @@ export default {
       this.TopicIndex = topicIndex;
       this.RowIndex = rowindex;
       this.LineIndex = lineIndex;
-      item.is_addModule = false;
+      item.is_add_module = false;
     },
     // 删除模板
     remoeModule(topicIndex, rowindex, lineIndex, item) {
@@ -451,7 +451,7 @@ export default {
       this.TopicIndex = null;
       this.RowIndex = null;
       this.LineIndex = null;
-      item.is_addModule = true;
+      item.is_add_module = true;
     },
     handleClosePre() {
       if (window.stopAudioVoice) window.stopAudioVoice();

+ 96 - 95
vue.config.js

@@ -3,7 +3,7 @@ const path = require('path')
 const defaultSettings = require('./src/settings.js')
 
 function resolve(dir) {
-  return path.join(__dirname, dir)
+    return path.join(__dirname, dir)
 }
 
 const name = defaultSettings.title || '发展汉语' // page title
@@ -19,102 +19,103 @@ const webpack = require('webpack')
 
 // All configuration item explanations can be find in https://cli.vuejs.org/config/
 module.exports = {
-  /**
-   * You will need to set publicPath if you plan to deploy your site under a sub path,
-   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
-   * then publicPath should be set to "/bar/".
-   * In most cases please use '/' !!!
-   * Detail: https://cli.vuejs.org/config/#publicpath
-   */
-  publicPath: process.env.NODE_ENV === 'development' ? '/' : '/GCLS-Book',
-  outputDir: 'dist',
-  assetsDir: 'static',
-  lintOnSave: false,
-  productionSourceMap: false,
-  devServer: {
-    port: port,
-    open: true,
-    overlay: {
-      warnings: false,
-      errors: true
-    },
-    proxy: {
-      // change xxx-api/login => mock/login
-      // detail: https://cli.vuejs.org/config/#devserver-proxy
-      [process.env.VUE_APP_BASE_API]: {
-        target: `http://gcls.helxsoft.cn/`,
-        changeOrigin: true,
-        pathRewrite: {
-          ['^' + process.env.VUE_APP_BASE_API]: ''
-        }
-      }
+    /**
+     * You will need to set publicPath if you plan to deploy your site under a sub path,
+     * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
+     * then publicPath should be set to "/bar/".
+     * In most cases please use '/' !!!
+     * Detail: https://cli.vuejs.org/config/#publicpath
+     */
+    publicPath: process.env.NODE_ENV === 'development' ? '/' : '/GCLS-Book',
+    outputDir: 'dist',
+    assetsDir: 'static',
+    lintOnSave: false,
+    productionSourceMap: false,
+    devServer: {
+        port: port,
+        open: true,
+        overlay: {
+            warnings: false,
+            errors: true
+        },
+        proxy: {
+            // change xxx-api/login => mock/login
+            // detail: https://cli.vuejs.org/config/#devserver-proxy
+            [process.env.VUE_APP_BASE_API]: {
+                target: `http://gcls.helxsoft.cn/`,
+                changeOrigin: true,
+                pathRewrite: {
+                    ['^' + process.env.VUE_APP_BASE_API]: ''
+                }
+            },
+        },
+
+        after: require('./mock/mock-server.js')
     },
-    after: require('./mock/mock-server.js')
-  },
-  chainWebpack(config) {
-    // it can improve the speed of the first screen, it is recommended to turn on preload
-    config.plugin('preload').tap(() => [{
-      rel: 'preload',
-      // to ignore runtime.js
-      // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
-      fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
-      include: 'initial'
-    }])
+    chainWebpack(config) {
+        // it can improve the speed of the first screen, it is recommended to turn on preload
+        config.plugin('preload').tap(() => [{
+            rel: 'preload',
+            // to ignore runtime.js
+            // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
+            fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
+            include: 'initial'
+        }])
 
-    // when there are many pages, it will cause too many meaningless requests
-    config.plugins.delete('prefetch')
+        // when there are many pages, it will cause too many meaningless requests
+        config.plugins.delete('prefetch')
 
-    // set svg-sprite-loader
-    config.module
-      .rule('svg')
-      .exclude.add(resolve('src/icons'))
-      .end()
-    config.module
-      .rule('icons')
-      .test(/\.svg$/)
-      .include.add(resolve('src/icons'))
-      .end()
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
-      .options({
-        symbolId: 'icon-[name]'
-      })
-      .end()
+        // set svg-sprite-loader
+        config.module
+            .rule('svg')
+            .exclude.add(resolve('src/icons'))
+            .end()
+        config.module
+            .rule('icons')
+            .test(/\.svg$/)
+            .include.add(resolve('src/icons'))
+            .end()
+            .use('svg-sprite-loader')
+            .loader('svg-sprite-loader')
+            .options({
+                symbolId: 'icon-[name]'
+            })
+            .end()
 
-    config.when(process.env.NODE_ENV !== 'development', config => {
-      config
-        .plugin('ScriptExtHtmlWebpackPlugin')
-        .after('html')
-        .use('script-ext-html-webpack-plugin', [{
-          // `runtime` must same as runtimeChunk name. default is `runtime`
-          inline: /runtime\..*\.js$/
-        }])
-        .end()
-      config.optimization.splitChunks({
-        chunks: 'all',
-        cacheGroups: {
-          libs: {
-            name: 'chunk-libs',
-            test: /[\\/]node_modules[\\/]/,
-            priority: 10,
-            chunks: 'initial' // only package third parties that are initially dependent
-          },
-          elementUI: {
-            name: 'chunk-elementUI', // split elementUI into a single package
-            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
-          },
-          commons: {
-            name: 'chunk-commons',
-            test: resolve('src/components'), // can customize your rules
-            minChunks: 3, //  minimum common number
-            priority: 5,
-            reuseExistingChunk: true
-          }
-        }
-      })
-      // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
-      config.optimization.runtimeChunk('single')
-    })
-  }
+        config.when(process.env.NODE_ENV !== 'development', config => {
+            config
+                .plugin('ScriptExtHtmlWebpackPlugin')
+                .after('html')
+                .use('script-ext-html-webpack-plugin', [{
+                    // `runtime` must same as runtimeChunk name. default is `runtime`
+                    inline: /runtime\..*\.js$/
+                }])
+                .end()
+            config.optimization.splitChunks({
+                    chunks: 'all',
+                    cacheGroups: {
+                        libs: {
+                            name: 'chunk-libs',
+                            test: /[\\/]node_modules[\\/]/,
+                            priority: 10,
+                            chunks: 'initial' // only package third parties that are initially dependent
+                        },
+                        elementUI: {
+                            name: 'chunk-elementUI', // split elementUI into a single package
+                            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+                            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+                        },
+                        commons: {
+                            name: 'chunk-commons',
+                            test: resolve('src/components'), // can customize your rules
+                            minChunks: 3, //  minimum common number
+                            priority: 5,
+                            reuseExistingChunk: true
+                        }
+                    }
+                })
+                // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
+            config.optimization.runtimeChunk('single')
+        })
+    }
 }