SanHQin hai 6 meses
pai
achega
7657beecc6

+ 1 - 0
package.json

@@ -39,6 +39,7 @@
     "vue-h5-template": "file:",
     "vue-markdown": "^2.2.4",
     "vue-mobile-calendar": "^3.3.0",
+    "vue-qrcode-reader": "^3.2.0",
     "vue-router": "^3.1.5",
     "vue-video-player": "^5.0.2",
     "vue-wechat-title": "^2.0.7",

+ 234 - 0
src/components/sweepPage.vue

@@ -0,0 +1,234 @@
+<template>
+  <div class="sweep" v-if="show">
+    <QrcodeStream
+      class="ku-scanner"
+      v-if="show"
+      :camera="camera"
+      :torch="torchActive"
+      @decode="onDecode"
+      @init="onInit"
+    >
+      <div class="ku-scanner-content">
+        <div class="ku-scanner-tooltip">
+          将二维码/条码放入框内,即自动扫描
+        </div>
+        <div class="ku-scanner-section">
+          <div class="ku-scanner-section-animation-line"></div>
+          <div class="ku-scanner-section-angle"></div>
+        </div>
+      </div>
+    </QrcodeStream>
+    <span class="closeBtn" @click="close">
+      <svg t="1733477770331" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4265" width="64" height="64"><path d="M623.807 528.693a113.756 113.756 0 0 0-0.139-33.126l252.787-252.692c26.245-26.236 26.245-68.772 0-95.006-26.248-26.236-68.798-26.236-95.043 0L528.281 400.902c-5.296-0.762-10.708-1.164-16.216-1.164s-10.92 0.402-16.216 1.164l-253.13-253.031c-26.245-26.236-68.796-26.236-95.043 0-26.245 26.234-26.245 68.77 0 95.006l252.789 252.692a113.726 113.726 0 0 0-0.14 33.124L147.676 781.247c-26.245 26.236-26.245 68.77 0 95.006 26.248 26.236 68.798 26.236 95.043 0L494.85 624.218c5.613 0.859 11.362 1.305 17.215 1.305s11.602-0.446 17.215-1.305l252.13 252.035c26.245 26.236 68.796 26.236 95.043 0 26.245-26.236 26.245-68.77 0-95.006L623.807 528.693z" fill="#000000" p-id="4266"></path><path d="M512.063 444.326c37.407 0 67.73 30.327 67.73 67.736 0 37.41-30.323 67.735-67.73 67.735-37.405 0-67.728-30.325-67.728-67.735 0.001-37.408 30.323-67.736 67.728-67.736z" fill="#000000" p-id="4267"></path></svg>
+    </span>
+  </div>
+</template>
+
+<script>
+import { QrcodeStream } from 'vue-qrcode-reader'
+export default {
+  components: {
+    QrcodeStream
+  },
+  data() {
+    return {
+      show: false,
+      camera: 'auto', //front auto environment
+      torchActive: false,
+      flag: 0,
+      paused: true,
+      timer: null
+      // constraints:{
+      // 	width:300,
+      // 	height:300
+      // }
+    }
+  },
+  methods: {
+    open() {
+      this.show = true
+    },
+    close() {
+      clearInterval(this.timer)
+      this.show = false
+    },
+    onDecode(result) {
+      this.$emit('success', result)
+      // this.$toast(result)
+    },
+    async onInit(promise) {
+      const { capabilities } = await promise
+
+      const TORCH_IS_SUPPORTED = !!capabilities.torch
+      try {
+        await promise
+      } catch (error) {
+        this.close()
+        if (error.name === 'NotAllowedError') {
+          this.$toast.fail('您需要授予相机访问权限')
+        } else if (error.name === 'NotFoundError') {
+          this.$toast.fail('这个设备上没有摄像头')
+        } else if (error.name === 'NotSupportedError') {
+          this.$toast.fail('所需的安全上下文(HTTPS、本地主机)')
+        } else if (error.name === 'NotReadableError') {
+          this.$toast.fail('相机被占用')
+        } else if (error.name === 'OverconstrainedError') {
+          this.$toast.fail('安装摄像头不合适')
+        } else if (error.name === 'StreamApiNotSupportedError') {
+          this.$toast.fail('此浏览器不支持流API')
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.sweep {
+  width: 100vw;
+  height: 100vh;
+  z-index: 9990;
+  background-color: #000;
+  position: fixed;
+  top: 0;
+  left: 0;
+}
+
+.closeBtn {
+  width: 40px;
+  height: 40px;
+  position: absolute;
+  top: 20px;
+  border-radius: 50%;
+  background-color: #ffffff80;
+  right: 20px;
+  z-index: 9992;
+	box-sizing: border-box;
+	padding:10px;
+	svg{
+		width: 100%;
+		height: 100%;
+
+	}
+}
+
+
+
+.ku-scanner {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 9991;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+  .ku-scanner-content {
+
+    background-size: 3rem 3rem;
+    background-position: -1rem -1rem;
+    width: 100%;
+    height: 100%;
+    position: relative;
+    background-color: rgba(18, 18, 18, 0);
+		margin: auto;
+    // 提示信息
+    .ku-scanner-tooltip {
+      width: 100%;
+      height: 35px;
+      line-height: 35px;
+      font-size: 14px;
+      text-align: center; /* color: #f9f9f9; */
+      margin: 0 auto;
+      position: absolute;
+      top: 0;
+      left: 0;
+      color: #ffffff;
+    }
+    .ku-scanner-section {
+      width: 213px;
+      height: 213px;
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+      overflow: hidden;
+      border: 0.1rem solid rgba(86, 247, 118, 0.301);
+      // // 装饰角
+      // &:after {
+      //   content: '';
+      //   display: block;
+      //   position: absolute;
+      //   width: 12px;
+      //   height: 12px;
+      //   border: 0.2rem solid transparent;
+      //   top: 0;
+      //   border-top-color: #2ffc58;
+      //   right: 0;
+      //   border-right-color: #2ffc58;
+      // }
+      // &:before {
+      //   content: '';
+      //   display: block;
+      //   position: absolute;
+      //   width: 12px;
+      //   height: 12px;
+      //   border: 0.2rem solid transparent;
+      //   top: 0;
+      //   border-top-color: #2ffc58;
+      //   left: 0;
+      //   border-left-color: #2ffc58;
+      // }
+      // // 装饰角
+      // .ku-scanner-section-angle {
+      //   &:after {
+      //     content: '';
+      //     display: block;
+      //     position: absolute;
+      //     width: 12px;
+      //     height: 12px;
+      //     border: 0.2rem solid transparent;
+      //     bottom: 0;
+      //     border-bottom-color: #2ffc58;
+      //     right: 0;
+      //     border-right-color: #2ffc58;
+      //   }
+      //   &:before {
+      //     content: '';
+      //     display: block;
+      //     position: absolute;
+      //     width: 12px;
+      //     height: 12px;
+      //     border: 0.2rem solid transparent;
+      //     bottom: 0;
+      //     border-bottom-color: #2ffc58;
+      //     left: 0;
+      //     border-left-color: #2ffc58;
+      //   }
+      // }
+      // 扫描活动线
+      .ku-scanner-section-animation-line {
+        height: calc(100% - 2px);
+        width: 100%;
+        background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #2ffc58 211%);
+        border-bottom: 3px solid #2ffc58;
+        transform: translateY(-100%);
+        animation: radar-beam 2s infinite alternate;
+        animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
+        animation-delay: 1.4s;
+      }
+    }
+  }
+}
+// 扫描活动线--上下 动画
+@keyframes radar-beam {
+  0% {
+    transform: translateY(-100%);
+  }
+
+  100% {
+    transform: translateY(0);
+  }
+}
+</style>

+ 169 - 0
src/views/testDetail/components/sweep.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="c_box">
+    <div class="choice_box">
+      <div class="title" style="display: flex;">
+        <span style="min-width: fit-content;">{{ tindex + 1 + '、' }}</span>
+        <span>{{ checkJson.title }}</span>
+      </div>
+      <div
+        class="detail"
+        v-if="checkJson.detail"
+        v-html="checkJson.detail"
+        style="color: #00000099;margin-top: 5px;"
+      ></div>
+
+			<div
+        class="detail"
+        v-if="checkJson.answer2 && typeof checkJson.answer2=='string'"
+        v-html="checkJson.answer2"
+        style="color: #000000;margin-top: 5px;"
+      ></div>
+
+      <div class="choices">
+        <el-button type="primary" size="small" @click="sweepBtn">扫一扫</el-button>
+      </div>
+    </div>
+		<sweepPage ref="sweepPageRef" @success="sweepSuccess"/>
+  </div>
+</template>
+
+<script>
+import sweepPage from '@/components/sweepPage.vue';
+export default {
+  props: {
+    tindex: {
+      type: Number
+    },
+    cJson: {
+      type: Object
+    },
+    checktype: {
+      type: Number,
+      default: 1
+    },
+    see: {
+      type: Boolean,
+      default: false
+    }
+  },
+	components:{
+		sweepPage
+	},
+  data() {
+    return {
+      option: {
+        1: { name: '附件' }
+      },
+      userid: this.$route.query.userid,
+      checkJson: {
+				title:"",
+				detail:""
+			},
+    }
+  },
+  watch: {
+    checkJson: {
+      handler(newValue) {
+        this.$emit('update:cJson', newValue)
+      },
+      deep: true
+    }
+  },
+  methods: {
+    depthCopy(s) {
+      return JSON.parse(JSON.stringify(s))
+    },
+		sweepBtn(){
+			this.$refs.sweepPageRef.open();
+		},
+		sweepSuccess(result){
+			this.checkJson.answer2 = result;
+			this.$refs.sweepPageRef.close();
+		}
+  },
+  mounted() {
+    this.checkJson = this.cJson ? this.depthCopy(this.cJson) : undefined
+   
+  }
+}
+</script>
+
+<style scoped>
+.c_box {
+  width: 100%;
+  position: relative;
+}
+
+/* .mask {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    z-index: 2;
+} */
+
+.choice_box {
+  white-space: pre-line;
+}
+
+.choice_box > .title {
+  font-weight: bold;
+  width: 100%;
+  word-break: break-all;
+}
+
+.choice_box > .choices {
+  margin-top: 10px;
+}
+
+.choices > .page {
+  margin-top: 10px;
+  display: flex;
+  align-items: center;
+}
+
+.p_page {
+  margin: 0 10px;
+}
+
+.course {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+}
+
+.course + .course {
+  margin-top: 10px;
+}
+
+.course > .banner {
+  min-width: 100px;
+  width: 100px;
+  height: 100px;
+  border-radius: 5px;
+  overflow: hidden;
+  border: 1px solid #3896fc;
+  box-sizing: border-box;
+  padding: 5px;
+  margin-right: 15px;
+}
+.course > .banner > img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+.course > .content {
+  max-width: calc(100% - 100px - 15px);
+}
+.course > .content > .c_c {
+  display: flex;
+}
+.course > .content > .c_c + .c_c {
+  margin-top: 5px;
+}
+.course > .content > .c_c span:nth-child(1) {
+  min-width: fit-content;
+}
+.course > .content > .c_c span:nth-child(2) {
+  word-break: break-word;
+}
+</style>

+ 48 - 5
src/views/testDetail/components/topic.vue

@@ -82,6 +82,12 @@
               :issetPage.sync="issetPage"
               :tid="tid"
             ></courseV2>
+						<sweep :tindex="index"
+              :cJson.sync="item.json"
+              :checktype="checktype"
+              v-else-if="item.type == 12"
+              :see="see"
+              :isTeacher="isTeacher"></sweep>
             <!-- <span v-else>暂未设置题目</span> -->
           </div>
           <div v-for="(item2, index2) in item.array" :key="`${index}-${index2}`" class="check_box_xia">
@@ -157,6 +163,12 @@
                 :issetPage.sync="issetPage"
                 :tid="tid"
               ></courseV2>
+							<sweep  :tindex="index2"
+                :cJson.sync="item2.json"
+                :checktype="checktype"
+                v-else-if="item2.type == 12"
+                :see="see"
+                :isTeacher="isTeacher"></sweep>
               <!-- <span v-else>暂未设置题目</span> -->
             </div>
           </div>
@@ -236,6 +248,12 @@
               :issetPage.sync="issetPage"
               :tid="tid"
             ></courseV2>
+						<sweep  :tindex="index"
+              :cJson.sync="item.json"
+              :checktype="checktype"
+              v-else-if="item.type == 12"
+              :see="see"
+              :isTeacher="isTeacher"></sweep>
             <!-- <span v-else>暂未设置题目</span> -->
           </div>
           <div v-for="(item2, index2) in item.array" :key="`${index}-${index2}`" class="check_box_xia">
@@ -311,6 +329,12 @@
                 :issetPage.sync="issetPage"
                 :tid="tid"
               ></coursev2>
+							<sweep  :tindex="index2"
+                :cJson.sync="item2.json"
+                :checktype="checktype"
+                v-else-if="item2.type == 12"
+                :see="see"
+                :isTeacher="isTeacher"></sweep>
               <!-- <span v-else>暂未设置题目</span> -->
             </div>
           </div>
@@ -340,7 +364,7 @@ import courseV from './course.vue'
 import evaV from './eva.vue'
 import timeV from './time.vue'
 import courseV2 from './course2.vue'
-
+import sweep from './sweep.vue'
 export default {
   props: {
     cJson: {
@@ -384,7 +408,8 @@ export default {
     courseV,
     evaV,
     timeV,
-    courseV2
+    courseV2,
+		sweep
   },
   data() {
     return {
@@ -496,7 +521,7 @@ export default {
         const checkArray = _json.filter(item => {
           if (item.array) {
             item.array = item.array.filter(item2 => {
-              if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type != 6 && item.type != 7) {
+              if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type != 6 && item.type != 7 && item.type != 12) {
                 item2.json.answer2 = []
               } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type == 6) {
                 item2.json.answer2 = this.gcourseid ? this.gcourseid : item2.json.courses[0]
@@ -516,10 +541,18 @@ export default {
                 item2.type == 8
               ) {
                 item2.json.answer2 = ''
+              }else if (
+                item2.ttype == 1 &&
+                item2.json &&
+                !item2.json.answer2 &&
+                item2.json.answer2 !== 0 &&
+                item2.type == 12
+              ) {
+                item2.json.answer2 = ''
               }
               if (item2.array) {
                 item2.array = item2.array.filter(item3 => {
-                  if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type != 6 && item3.type != 7) {
+                  if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type != 6 && item3.type != 7 && item3.type != 12) {
                     item3.json.answer2 = []
                   } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type == 6) {
                     item3.json.answer2 = this.gcourseid ? this.gcourseid : item3.json.courses[0]
@@ -539,6 +572,14 @@ export default {
                     item3.type == 8
                   ) {
                     item3.json.answer2 = ''
+                  }else if (
+                    item3.ttype == 1 &&
+                    item3.json &&
+                    !item3.json.answer2 &&
+                    item3.json.answer2 !== 0 &&
+                    item3.type == 12
+                  ) {
+                    item3.json.answer2 = ''
                   }
                   return item3
                 })
@@ -546,7 +587,7 @@ export default {
               return (item2.ttype != 1 && item2.array.length > 0) || item2.ttype == 1
             })
           }
-          if (item.ttype == 1 && item.json && !item.json.answer2 && item.type != 6 && item.type != 7) {
+          if (item.ttype == 1 && item.json && !item.json.answer2 && item.type != 6 && item.type != 7 && item.type != 12) {
             item.json.answer2 = []
           } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.type == 6) {
             item.json.answer2 = this.gcourseid ? this.gcourseid : item.json.courses[0]
@@ -554,6 +595,8 @@ export default {
             item.json.answer2 = ''
           } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.json.answer2 !== 0 && item.type == 8) {
             item.json.answer2 = ''
+          } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.json.answer2 !== 0 && item.type == 12) {
+            item.json.answer2 = ''
           }
           console.log(item.array)
           return (item.ttype != 1 && item.array.length > 0) || item.ttype == 1