Ver código fonte

Merge branch 'master' of http://192.168.0.115:3000/chenzimin2/ZGZQBWG

aamin 1 ano atrás
pai
commit
dc41fbdb3c

+ 19 - 2
game/src/api.js

@@ -1,5 +1,5 @@
 import axios from "axios"
-import { encodeStr } from "@/pass.js"
+import { encodeStr, decodeStr } from "@/pass.js"
 import { Base64 } from "js-base64"
 import store from "@/store/index.js"
 import router from "@/router"
@@ -147,7 +147,7 @@ export async function findPassowrd(account, phone, verifiCode) {
     return
   }
 }
-export async function changePassword(newPassword, oldPassword) {
+export async function changePassword(newPassword, oldPassword, verifiCode) {
   const pwdNewEncrypted = encodeStr(Base64.encode(newPassword))
   const pwdOldEncrypted = encodeStr(Base64.encode(oldPassword))
   const res = await axios({
@@ -156,6 +156,7 @@ export async function changePassword(newPassword, oldPassword) {
     data: {
       newPassword: pwdNewEncrypted,
       oldPassword: pwdOldEncrypted,
+      randCode: verifiCode,
     },
     headers: {
       token: store.state.token,
@@ -243,6 +244,22 @@ export async function getExamQuestionList() {
     return res.data.data
   }
 }
+export async function checkExamAnswer(questionId, answerVal) {
+  const res = await axios({
+    method: 'get',
+    url: `${process.env.VUE_APP_DEPLOY_ORIGIN}/api/show/question/verify/${questionId}/${answerVal}`,
+  })
+  if (res.data.code !== 0) {
+    throw (`查询答题结果失败:${res.data.msg}`)
+  } else {
+    let resDecoded = Base64.decode(decodeStr(res.data.data))
+    if (resDecoded === 'true') {
+      return true
+    } else {
+      return false
+    }
+  }
+}
 /*
 createTime: "2024-01-08 19:07:01"
 creatorId: 1

+ 62 - 56
game/src/pass.js

@@ -1,4 +1,3 @@
-/* eslint-disable */
 function NoToChinese (num) {
   num = String(num)
   var chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
@@ -29,17 +28,16 @@ function randomWord (randomFlag, min, max) {
   return str
 }
 
-module.exports = {
-  formatDate: function (time) {
-    var weekArr = ['日', '一', '二', '三', '四', '五', '六']
-    var date = new Date(time)
-    var year = date.getFullYear()
-    var month = date.getMonth() + 1
-    var day = date.getDate()
-    var week = '星期' + weekArr[date.getDay()]
-    if (window.innerWidth < 1700) {
-      return (
-        year +
+export function formatDate (time) {
+  var weekArr = ['日', '一', '二', '三', '四', '五', '六']
+  var date = new Date(time)
+  var year = date.getFullYear()
+  var month = date.getMonth() + 1
+  var day = date.getDate()
+  var week = '星期' + weekArr[date.getDay()]
+  if (window.innerWidth < 1700) {
+    return (
+      year +
         '年' +
         (String(month).length > 1 ? month : '0' + month) +
         '月' +
@@ -47,10 +45,10 @@ module.exports = {
         '日' +
         '<br/>' +
         week
-      )
-    }
-    return (
-      year +
+    )
+  }
+  return (
+    year +
       '年' +
       (String(month).length > 1 ? month : '0' + month) +
       '月' +
@@ -58,49 +56,57 @@ module.exports = {
       '日' +
       ' ' +
       week
-    )
-  },
-  smoothscrollpos: function (domName) {
-    if (domName == '/') {
-      return window.scrollTo(0, 0)
-    }
-    const smoothscroll = () => {
-      const dom = document.getElementById(domName)
-      // window.scrollTo({
-      //   top:dom.offsetTop - 100,
-      //   left:0,
-      //   behavior: "smooth"
-      // })
-      dom && window.scrollTo(0, dom.offsetTop - 120)
-    }
-    smoothscroll()
-  },
+  )
+}
 
-  formatTime: function (time, fan = false) {
-    let t1 = time.split(' ')[0].split('-')
-    if (fan) {
-      t1 = t1.map((item) => {
-        const t = NoToChinese(item)
-        return t
-      })
-    }
-    return t1
-  },
-  encodeStr: function (str, strv = '') {
-    const NUM = 2
-    const front = randomWord(false, 8)
-    const middle = randomWord(false, 8)
-    const end = randomWord(false, 8)
+export function smoothscrollpos (domName) {
+  if (domName == '/') {
+    return window.scrollTo(0, 0)
+  }
+  const smoothscroll = () => {
+    const dom = document.getElementById(domName)
+    // window.scrollTo({
+    //   top:dom.offsetTop - 100,
+    //   left:0,
+    //   behavior: "smooth"
+    // })
+    dom && window.scrollTo(0, dom.offsetTop - 120)
+  }
+  smoothscroll()
+}
 
-    const str1 = str.substring(0, NUM)
-    const str2 = str.substring(NUM)
+export function formatTime (time, fan = false) {
+  let t1 = time.split(' ')[0].split('-')
+  if (fan) {
+    t1 = t1.map((item) => {
+      const t = NoToChinese(item)
+      return t
+    })
+  }
+  return t1
+}
+export function encodeStr (str, strv = '') {
+  const NUM = 2
+  const front = randomWord(false, 8)
+  const middle = randomWord(false, 8)
+  const end = randomWord(false, 8)
 
-    if (strv) {
-      const strv1 = strv.substring(0, NUM)
-      const strv2 = strv.substring(NUM)
-      return [front + str2 + middle + str1 + end, front + strv2 + middle + strv1 + end]
-    }
+  const str1 = str.substring(0, NUM)
+  const str2 = str.substring(NUM)
 
-    return front + str2 + middle + str1 + end
+  if (strv) {
+    const strv1 = strv.substring(0, NUM)
+    const strv2 = strv.substring(NUM)
+    return [front + str2 + middle + str1 + end, front + strv2 + middle + strv1 + end]
   }
+
+  return front + str2 + middle + str1 + end
 }
+export function decodeStr (str) {
+  const NUM = 2
+  const str1 = str.substring(8)
+  const str2 = str1.substring(0, str1.length - 8)
+  const front = str2.slice(-NUM)
+  const end = str2.substring(0, str2.length - 8 - NUM)
+  return front + end
+}

+ 115 - 3
game/src/views/ChangePassword.vue

@@ -68,6 +68,35 @@
         @blur="isPasswordRepeatInputOver=true"
       >
     </div>
+    <div class="form-item form-item-verifi">
+      <div class="title">
+        <img
+          src="@/assets/images/icon-mail.png"
+          alt=""
+          draggable="false"
+        >
+        <span>邮箱验证码</span>
+      </div>
+      <div class="row">
+        <input
+          v-model="verifiCode"
+          placeholder="请输入4位验证码"
+          :class="{
+            invalid: isVerifiCodeInputOver && !isVerifiCodeValid
+          }"
+          @blur="isVerifiCodeInputOver=true"
+        >
+        <button
+          class="get-verifi-code"
+          :class="{
+            disabled: isVerifiCodeSent
+          }"
+          @click="onClickVerifiCode"
+        >
+          {{ isVerifiCodeSent ? `${verifiCodeCountDown}s` : '发送验证码' }}
+        </button>
+      </div>
+    </div>
 
     <button
       class="submit"
@@ -88,8 +117,8 @@
 import { ref, computed, watch, onMounted } from "vue"
 import { useRoute, useRouter } from "vue-router"
 import { useStore } from "vuex"
-import { showDialog } from 'vant'
-import { changePassword } from '@/api.js'
+import { showDialog, showNotify } from 'vant'
+import { sendEmail, changePassword } from '@/api.js'
 
 const route = useRoute()
 const router = useRouter()
@@ -103,6 +132,7 @@ const {
 const passwordOld = ref('')
 const password = ref('')
 const passwordRepeat = ref('')
+const verifiCode = ref('')
 
 const passwordOldTrimed = computed(() => {
   return passwordOld.value.trim()
@@ -113,6 +143,9 @@ const passwordTrimed = computed(() => {
 const passwordRepeatTrimed = computed(() => {
   return passwordRepeat.value.trim()
 })
+const verifiCodeTrimed = computed(() => {
+  return verifiCode.value.trim()
+})
 
 const isPasswordOldValid = computed(() => {
   return passwordOldTrimed.value.length >= 6 && passwordOldTrimed.value.length <= 10 && passwordTrimed.value.search(/^[0-9a-zA-Z].*$/) === 0
@@ -123,10 +156,45 @@ const isPasswordValid = computed(() => {
 const isPasswordRepeatValid = computed(() => {
   return passwordTrimed.value === passwordRepeatTrimed.value
 })
+const isVerifiCodeValid = computed(() => {
+  return verifiCodeTrimed.value.length > 0
+})
 
 const isPasswordOldInputOver = ref(false)
 const isPasswordInputOver = ref(false)
 const isPasswordRepeatInputOver = ref(false)
+const isVerifiCodeInputOver = ref(false)
+
+const isVerifiCodeSent = ref(false)
+const verifiCodeCountDown = ref(60)
+watch(isVerifiCodeSent, (v) => {
+  if (v) {
+    setInterval(() => {
+      verifiCodeCountDown.value--
+      if (verifiCodeCountDown.value === 0) {
+        isVerifiCodeSent.value = false
+        verifiCodeCountDown.value = 60
+      }
+    }, 1000)
+  }
+})
+const onClickVerifiCode = utils.throttle(() => {
+  if (isVerifiCodeSent.value) {
+    return
+  }
+  sendEmail(store.state.userInfo.userName).then(() => {
+    showNotify({
+      type: 'success',
+      message: `验证码已发送至邮箱${store.state.userInfo.userName},请在邮箱中查收`,
+    })
+    isVerifiCodeSent.value = true
+  }).catch((e) => {
+    showDialog({
+      message: e,
+      theme: 'round-button',
+    })
+  })
+}, 333)
 
 function submit() {
   if (!isPasswordOldValid.value) {
@@ -154,7 +222,7 @@ function submit() {
     return
   }
 
-  changePassword(passwordTrimed.value, passwordOldTrimed.value).then(() => {
+  changePassword(passwordTrimed.value, passwordOldTrimed.value, verifiCode.value).then(() => {
     showDialog({
       message: '密码修改成功',
       theme: 'round-button',
@@ -239,6 +307,50 @@ function submit() {
       border-bottom: 1px solid red;
     }
   }
+  >.form-item{
+    >div.row{
+      display: flex;
+      justify-content: space-between;
+      align-items: flex-end;
+      margin-top: calc(-11 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      >input{
+        width: 50%;
+        height: calc(29 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        border-bottom: 1px solid #D9D9D9;
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: 400;
+        color: black;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        &::placeholder {
+          font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          font-family: Source Han Sans SC, Source Han Sans SC;
+          font-weight: 400;
+          color: #B8B8B8;
+          line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        }
+      }
+      >input.invalid{
+        border-bottom: 1px solid red;
+      }
+      >button.get-verifi-code{
+        width: calc(108 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        height: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        background: #FFFFFF;
+        border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        border: 1px solid #D1B489;
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: 400;
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        color: #D1B489;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        text-align: center;
+        &.disabled{
+          pointer-events: none;
+        }
+      }
+    }
+  }
   >button.submit{
     width: calc(332 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
     height: calc(56 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));

+ 22 - 46
game/src/views/ExamPaper2.vue

@@ -39,8 +39,8 @@
         class="option"
         :class="{
           selected: selectedIdx === index,
-          rightOption: questionList[currentQuestionIdx].rightOptionIdx === index,
-          wrongOption: questionList[currentQuestionIdx].rightOptionIdx !== index,
+          rightOption: isCorrect === true,
+          wrongOption: isCorrect === false,
           submitted: isSubmitted,
           notSubmitted: !isSubmitted,
         }"
@@ -58,7 +58,7 @@
           </div>
         </div>
         <div
-          v-show="isSubmitted && selectedIdx === index && questionList[currentQuestionIdx].rightOptionIdx === index"
+          v-show="isSubmitted && selectedIdx === index && isCorrect"
           class="result-tip"
         >
           <img
@@ -69,7 +69,7 @@
           >
         </div>
         <div
-          v-show="isSubmitted && selectedIdx === index && questionList[currentQuestionIdx].rightOptionIdx !== index"
+          v-show="isSubmitted && selectedIdx === index && isCorrect === false"
           class="result-tip"
         >
           <img
@@ -113,6 +113,7 @@
     </div>
     <button
       class="next"
+      :disabled="isSubmitted && isCorrect === undefined"
       @click="onClickNext"
     >
       下一题
@@ -146,13 +147,12 @@ import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from "vue"
 import { useRoute, useRouter } from "vue-router"
 import { useStore } from "vuex"
 import dayjs from 'dayjs'
-import { addScore, getScore, getExamQuestionList, notifyQuit } from '@/api.js'
+import { addScore, getScore, getExamQuestionList, checkExamAnswer, notifyQuit } from '@/api.js'
 import GameRule from '@/components/GameRule.vue'
 import NotifyComp from '@/components/NotifyComp.vue'
 import { Base64 } from "js-base64"
 import MusicBg from '@/assets/audio/1.mp3'
 
-
 const route = useRoute()
 const router = useRouter()
 const store = useStore()
@@ -169,27 +169,14 @@ const isShowLoading = ref(true)
 getExamQuestionList().then((res) => {
   questionList.value = res.map((questionItem) => {
     const optionsAndAnswer = JSON.parse(questionItem.answer)
-
-    // 对正确答案解密
-    const decodeStr = (str) => {
-      const NUM = 2
-      const str1 = str.substring(8)
-      const str2 = str1.substring(0, str1.length - 8)
-      const front = str2.slice(-NUM)
-      const end = str2.substring(0, str2.length - 8 - NUM)
-      return front + end
-    }
-    optionsAndAnswer.correct = Base64.decode(decodeStr(optionsAndAnswer.correct))
-
-    // console.log(optionsAndAnswer)
-
     const ret = {
+      id: questionItem.id,
       question: questionItem.question,
       answerOptions: optionsAndAnswer.answer.map((answerItem) => {
         return answerItem.name
       }),
-      rightOptionIdx: optionsAndAnswer.answer.findIndex((answerItem) => {
-        return answerItem.val === optionsAndAnswer.correct
+      answerOptionValues: optionsAndAnswer.answer.map((answerItem) => {
+        return answerItem.val
       }),
       desc: questionItem.description
     }
@@ -255,25 +242,6 @@ const questionList = ref([
   //     '是',
   //     '不是',
   //   ],
-  //   rightOptionIdx: 0,
-  //   desc: '这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本',
-  // },
-  // {
-  //   question: '你是sb吗?',
-  //   answerOptions: [
-  //     '是',
-  //     '不是',
-  //   ],
-  //   rightOptionIdx: 0,
-  //   desc: '这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本',
-  // },
-  // {
-  //   question: '你是sb吗?',
-  //   answerOptions: [
-  //     '是',
-  //     '不是',
-  //   ],
-  //   rightOptionIdx: 0,
   //   desc: '这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本',
   // },
 ])
@@ -281,19 +249,27 @@ const currentQuestionIdx = ref(0)
 const isSubmitted = computed(() => {
   return selectedIdx.value !== null
 })
-function onClickOption(idx) {
+const isCorrect = ref(undefined)
+async function onClickOption(idx) {
   selectedIdx.value = idx
-  if (selectedIdx.value === questionList.value[currentQuestionIdx.value].rightOptionIdx) {
-    if (store.state.loginStatus && !store.state.ifScoreLimitReached) {
-      bonusPoint.value += store.state.gameRuleList[1].score
+  try {
+    isCorrect.value = await checkExamAnswer(questionList.value[currentQuestionIdx.value].id, questionList.value[currentQuestionIdx.value].answerOptionValues[selectedIdx.value])
+    console.log(isCorrect.value)
+    if (isCorrect.value) {
+      if (store.state.loginStatus && !store.state.ifScoreLimitReached) {
+        bonusPoint.value += store.state.gameRuleList[1].score
+      }
+      correntCount.value++
     }
-    correntCount.value++
+  } catch (error) {
+
   }
 }
 function onClickNext() {
   if (currentQuestionIdx.value < questionList.value.length - 1) {
     currentQuestionIdx.value++
     selectedIdx.value = null
+    isCorrect.value = undefined
   } else {
     if (store.state.loginStatus && !store.state.ifScoreLimitReached && bonusPoint.value !== 0) {
       addScore(bonusPoint.value, '一起来助农').then(() => {

+ 1 - 2
game/src/views/SignUp.vue

@@ -138,7 +138,7 @@ import { ref, computed, watch, onMounted, nextTick, inject } from "vue"
 import { useRoute, useRouter } from "vue-router"
 import { useStore } from "vuex"
 import { showDialog, showNotify } from 'vant'
-import { sendEmail, signUp, login } from '@/api.js'
+import { sendEmail, signUp } from '@/api.js'
 
 const route = useRoute()
 const router = useRouter()
@@ -198,7 +198,6 @@ const isPhoneInputOver = ref(false)
 const isPasswordInputOver = ref(false)
 const isPasswordRepeatInputOver = ref(false)
 
-// todo: 倒计时搬移到组件外部
 const isVerifiCodeSent = ref(false)
 const verifiCodeCountDown = ref(60)
 watch(isVerifiCodeSent, (v) => {