Quellcode durchsuchen

Merge branch 'master' of http://60.205.254.193:3000/GCLS/GCLS_Page_Exercise

dusenyao vor 1 Jahr
Ursprung
Commit
1b392df746

+ 48 - 41
package-lock.json

@@ -2406,6 +2406,49 @@
         "webpack-merge": "^5.7.3",
         "webpack-virtual-modules": "^0.4.2",
         "whatwg-fetch": "^3.6.2"
+      },
+      "dependencies": {
+        "@vue/vue-loader-v15": {
+          "version": "npm:vue-loader@15.11.1",
+          "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz",
+          "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
+          "dev": true,
+          "requires": {
+            "@vue/component-compiler-utils": "^3.1.0",
+            "hash-sum": "^1.0.2",
+            "loader-utils": "^1.1.0",
+            "vue-hot-reload-api": "^2.3.0",
+            "vue-style-loader": "^4.1.0"
+          },
+          "dependencies": {
+            "hash-sum": {
+              "version": "1.0.2",
+              "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz",
+              "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
+              "dev": true
+            }
+          }
+        },
+        "json5": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz",
+          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "loader-utils": {
+          "version": "1.4.2",
+          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz",
+          "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
+          "dev": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^1.0.1"
+          }
+        }
       }
     },
     "@vue/cli-shared-utils": {
@@ -2593,47 +2636,6 @@
       "integrity": "sha512-RoorRB50WehYbsiWu497q8egZBYlrvOo9KBUG41uth4O023Cbs+7POLm9uw2CAiViBAIhvpw1Y4w4i+MZxOfXw==",
       "dev": true
     },
-    "@vue/vue-loader-v15": {
-      "version": "npm:vue-loader@15.11.1",
-      "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz",
-      "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
-      "dev": true,
-      "requires": {
-        "@vue/component-compiler-utils": "^3.1.0",
-        "hash-sum": "^1.0.2",
-        "loader-utils": "^1.1.0",
-        "vue-hot-reload-api": "^2.3.0",
-        "vue-style-loader": "^4.1.0"
-      },
-      "dependencies": {
-        "hash-sum": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz",
-          "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz",
-          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.2",
-          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz",
-          "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        }
-      }
-    },
     "@vue/web-component-wrapper": {
       "version": "1.3.0",
       "resolved": "https://registry.npmmirror.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz",
@@ -5861,6 +5863,11 @@
       "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
       "dev": true
     },
+    "hanzi-writer": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/hanzi-writer/-/hanzi-writer-3.6.0.tgz",
+      "integrity": "sha512-2fDdpnNq33rFihiOX2iHIKjWwNPoo6yl95wqAyhtq/PRRMwTTzKNT8JgtqwCebMJi9TjyXySBIfs3xI1FLSsvA=="
+    },
     "hard-rejection": {
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/hard-rejection/-/hard-rejection-2.1.0.tgz",

+ 1 - 0
package.json

@@ -14,6 +14,7 @@
     "core-js": "^3.33.2",
     "dompurify": "^3.0.6",
     "element-ui": "^2.15.14",
+    "hanzi-writer": "^3.6.0",
     "js-audio-recorder": "^1.0.7",
     "js-cookie": "^3.0.5",
     "md5": "^2.3.0",

+ 4 - 0
src/api/exercise.js

@@ -105,3 +105,7 @@ export function PageQueryExerciseShareRecordList(data) {
 export function PageQueryExerciseUserAnswerRecordList(data) {
   return http.post(`/TeachingServer/ExerciseManager/PageQueryExerciseUserAnswerRecordList`, data);
 }
+
+export function GetStaticResources(MethodName, data) {
+  return http.post(`/GCLSFileServer/ServiceInterface?MethodName=${MethodName}`, data);
+}

+ 6 - 0
src/icons/svg/hanzi-strock-play.svg

@@ -0,0 +1,6 @@
+<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group 4124">
+<path id="Rectangle 7" d="M0 0H11V11C5.50879 9.77973 1.22027 5.49121 0 0Z" fill="currentColor"/>
+<path id="play.fill" d="M6.26786 6C6.34821 6 6.41901 5.96579 6.50702 5.90422L8.76658 4.34664C8.93112 4.23261 9 4.14367 9 4C9 3.85633 8.93112 3.76967 8.76658 3.65336L6.50702 2.09578C6.41901 2.03421 6.34821 2 6.26786 2C6.11097 2 6 2.14367 6 2.36944V5.63056C6 5.85861 6.11097 6 6.26786 6Z" fill="white"/>
+</g>
+</svg>

+ 3 - 0
src/icons/svg/hanzi-writer-bg.svg

@@ -0,0 +1,3 @@
+<svg width="62" height="62" viewBox="0 0 62 62" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="&#232;&#190;&#185;&#230;&#161;&#134;" d="M0 31H62M31 62V0" stroke="currentColor" stroke-dasharray="3 6"/>
+</svg>

+ 1 - 0
src/styles/variables.scss

@@ -10,6 +10,7 @@ $fill-color: #f2f3f5;
 $text-color: #86909c;
 $border-color: #e5e6eb;
 $border: 1px solid $border-color;
+$hanzi-writer-color: #de4444;
 
 // px
 $header-h: 64px;

+ 22 - 7
src/views/exercise_questions/preview/ChinesePreview.vue

@@ -14,23 +14,33 @@
     </template>
     <template v-else>
       <!-- 笔画学习 -->
-      <div class="words-box">
-        <div v-for="(item, index) in data.option_list" :key="index" class="words-item">
-          <div class="words-info">
-            <AudioPlay :file-id="item.audio_file_id" theme-color="gray" />
-            <span class="pinyin">{{ item.pinyin }}</span>
-          </div>
+    </template>
+    <div class="words-box">
+      <div v-for="(item, index) in data.option_list" :key="index" class="words-item">
+        <div class="words-info">
+          <AudioPlay :file-id="item.audio_file_id" theme-color="gray" />
+          <span class="pinyin">{{ item.pinyin }}</span>
         </div>
+        <Strockplayredline
+          :play-storkes="true"
+          :book-text="item.content"
+          :target-div="'pra' + item.content + index"
+          class="strock-chinese"
+        />
       </div>
-    </template>
+    </div>
   </div>
 </template>
 
 <script>
 import PreviewMixin from './components/PreviewMixin';
+import Strockplayredline from './components/common/Strockplayredline.vue';
 
 export default {
   name: 'ChinesePreview',
+  components: {
+    Strockplayredline,
+  },
   mixins: [PreviewMixin],
   data() {
     return {};
@@ -89,6 +99,11 @@ export default {
         color: #000;
       }
     }
+
+    .strock-chinese {
+      margin-top: 9px;
+      border: 1px solid #e81b1b;
+    }
   }
 }
 </style>

+ 1 - 0
src/views/exercise_questions/preview/ChooseTonePreview.vue

@@ -285,6 +285,7 @@ export default {
 
       .item-con,
       .items-con {
+        font-family: 'League';
         color: #000;
         cursor: pointer;
 

+ 1 - 1
src/views/exercise_questions/preview/RepeatPreview.vue

@@ -95,7 +95,7 @@ export default {
       .option-content {
         flex: 1;
         max-width: 306px;
-        padding: 12px 24px;
+        padding: 8px 16px;
         color: #706f78;
         background-color: #f9f8f9;
         border-radius: 40px;

+ 151 - 0
src/views/exercise_questions/preview/components/common/Strockplayredline.vue

@@ -0,0 +1,151 @@
+<!--  -->
+<template>
+  <div class="strockplay-redInner">
+    <div v-if="playStorkes" :class="['strock-play-box']" @click="playHanzi">
+      <SvgIcon icon-class="hanzi-strock-play" class="strock-play-btn" />
+    </div>
+    <div class="character-target-box">
+      <SvgIcon icon-class="hanzi-writer-bg" class="character-target-bg" />
+      <div :id="targetDiv" class="character-target-div"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { GetStaticResources } from '@/api/exercise';
+const HanziWriter = require('hanzi-writer');
+export default {
+  components: {},
+  // props: ['targetDiv', 'BookText', 'playStorkes', 'strokeColor', 'themeColor'],
+  props: {
+    bookText: {
+      type: String,
+      default: '',
+    },
+    targetDiv: {
+      type: String,
+      default: '',
+    },
+    playStorkes: {
+      type: Boolean,
+      default: true,
+    },
+    strokeColor: {
+      type: String,
+      default: '',
+    },
+  },
+  data() {
+    return {
+      writer: null,
+    };
+  },
+  computed: {},
+  watch: {
+    targetDiv: {
+      handler(val, oldVal) {
+        if (val !== oldVal) {
+          let _this = this;
+          _this.$nextTick(() => {
+            _this.initHanziwrite();
+          });
+        }
+      },
+      // 深度观察监听
+      deep: true,
+    },
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {
+    let _this = this;
+    _this.$nextTick(() => {
+      _this.initHanziwrite();
+    });
+  },
+  beforeCreate() {}, // 生命周期 - 创建之前
+  beforeMount() {}, // 生命周期 - 挂载之前
+  beforeUpdate() {}, // 生命周期 - 更新之前
+  updated() {}, // 生命周期 - 更新之后
+  beforeDestroy() {}, // 生命周期 - 销毁之前
+  destroyed() {}, // 生命周期 - 销毁完成
+  activated() {},
+  // 方法集合
+  methods: {
+    initHanziwrite() {
+      let _this = this;
+      // _this.writer = null;
+      _this.writer = HanziWriter.default.create(_this.targetDiv, _this.bookText, {
+        charDataLoader(char, onComplete) {
+          console.log(_this.bookText);
+          let MethodName = 'hz_resource_manager-GetHZStrokesContent';
+          let data = {
+            hz: char,
+          };
+          GetStaticResources(MethodName, data).then((res) => {
+            onComplete(res);
+          });
+        },
+        padding: 5,
+        showOutline: true,
+        strokeColor: _this.strokeColor ? _this.strokeColor : '#000',
+      });
+    },
+    playHanzi(event) {
+      let _this = this;
+      _this.writer.animateCharacter();
+      event.stopPropagation();
+    },
+  }, // 如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang="scss" scoped>
+//@import url(); 引入公共css类
+.strockplay-redInner {
+  position: relative;
+  width: 64px; //444px
+  height: 64px; //480px
+}
+
+.character-target-div {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 99;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+}
+
+.character-target-box {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.character-target-bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  color: #dedede;
+}
+
+.strock-play-box {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 100;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 11px;
+  height: 11px;
+  color: $hanzi-writer-color;
+  cursor: pointer;
+}
+</style>