Browse Source

fix: downloadFile 出错问题

lvkun996 1 year ago
parent
commit
0333718989

+ 5 - 0
package-lock.json

@@ -2432,6 +2432,11 @@
       "resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
       "resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
       "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
       "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
     },
     },
+    "lottie-web": {
+      "version": "5.12.2",
+      "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz",
+      "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg=="
+    },
     "lru-cache": {
     "lru-cache": {
       "version": "5.1.1",
       "version": "5.1.1",
       "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz",
       "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz",

+ 1 - 0
package.json

@@ -55,6 +55,7 @@
     "hammerjs": "^2.0.8",
     "hammerjs": "^2.0.8",
     "js-base64": "^3.7.5",
     "js-base64": "^3.7.5",
     "less-loader": "^6.2.0",
     "less-loader": "^6.2.0",
+    "lottie-web": "^5.12.2",
     "pinia": "^2.0.33",
     "pinia": "^2.0.33",
     "vconsole": "^3.15.0",
     "vconsole": "^3.15.0",
     "vue": "^3.2.45",
     "vue": "^3.2.45",

File diff suppressed because it is too large
+ 0 - 0
src/ani/lottie-success.json


File diff suppressed because it is too large
+ 0 - 0
src/ani/lottie-wrong.json


+ 0 - 0
src/ani/test.json


BIN
src/assets/GameViewV2/back.png


BIN
src/assets/GameViewV2/board.png


BIN
src/assets/GameViewV2/hand.png


BIN
src/assets/GameViewV2/open-icon.png


BIN
src/assets/GameViewV2/read.png


BIN
src/assets/GameViewV2/success-ani.gif


BIN
src/assets/GameViewV2/success.png


BIN
src/assets/GameViewV2/tip.png


BIN
src/assets/GameViewV2/wrong-ani.gif


BIN
src/assets/GameViewV2/wrong.png


BIN
src/audio/ao.mp3


BIN
src/audio/success.mp3


BIN
src/audio/timeout.mp3


BIN
src/audio/wrong.mp3


+ 729 - 69
src/components/luojigou-board-v2/luojigou-board-v2.vue

@@ -1,98 +1,540 @@
 <template>
 <template>
-  <view class="luojigou-board-v2" >
-    <view class="process" >
-      <span>{{process + 1}}</span>/6
-    </view>
+  <view class="luojigou-board-v2" :style="{width: widget.boardWidth + 'px', height: widget.boardHeight + 'px'}">
+    <canvas  canvas-id='canvasId' id="canvasId" style="width: 111px;height: 584px;position: fixed;left: -2000px;" ref="canvasDom" ></canvas>
     <view class="board" >
     <view class="board" >
+      <view class="process" >
+        <view class="count" >{{process + 1}}</view>
+        <view class="symbol" >/</view>
+        <view>6</view>
+      </view>
       <view class="button-list" >
       <view class="button-list" >
-        <view class="button" v-for="(item, index) in buttonListCpd" :key="item" >
-          <image class="icon" :src="staticImg[item]" alt="" />
+        <view class="button" :style="{opacity: index < process ? 0.4 : 1 }" v-for="(item, index) in buttonListCpd" :key="item" >
+          <image class="icon"   :src="staticImg[item]" alt="" />
           <image v-if="index < process" class="right-icon" :src="staticImg.rightIcon" alt="" />
           <image v-if="index < process" class="right-icon" :src="staticImg.rightIcon" alt="" />
         </view>
         </view>
       </view>
       </view>
-      <view :class="['question-card', aniState ? 'question-card-small' : 'question-card-ani']" >
-        <!-- <image :src="staticImg.green" alt="" /> -->
+      <view class="question-card" >
+        <view :class="questionCardAni" >
+          <image class="ques-item-url" :src="quesCard.current" />
+        </view>
+        <view class="ques-card-next" >
+          <image class="ques-item-url" :src="quesCard.next" />
+        </view>
+        <view :class="questionAni"  @click="previewCard" >
+          <image class="card" :src="props.card.board.quesUrl" alt="" />
+          <image class="open-icon" v-if="aniState" :src="staticImg.openIcon" />
+        </view>
       </view>
       </view>
     </view>
     </view>
     <view class="answer" >
     <view class="answer" >
-      <view class="answer-list" >
-        <view class="answer-item" > 
-
+      <!-- :key="keyCount" -->
+      <view class="answer-list"  >
+        <view
+          class="answer-item"
+          v-for="(item, index) in ansList"
+          :key="item.id"
+          :style="{top: item.top + 'px', left: item.left + 'px'}"
+          :animation="aniListRef[index]"
+          @click="selectAnswer(item)"
+        >
+          <image class="ans-img"  :src="item.url" />
+          <view :class="ansResultClass" v-if="item.select" >
+            <image :src="ans === 1 ? staticImg.success : staticImg.wrong" />
+          </view>
+          <image class="hand" v-if="tipState && item.isAns" :src="staticImg.hand" />
         </view>
         </view>
       </view>
       </view>
     </view>
     </view>
   </view>
   </view>
+
+  <view class="opra-container" >
+    <view class="read"   :style="{opacity: !readState ? 0 : 1}" id="lottie-dom-read" @click="stopReadQuestion"   > </view>
+    <image class="read" v-if="!readState"  @click="readQuestion" :src="staticImg.read" />
+    <image class="tip" @click="openTip"  :src="staticImg.tip" />
+  </view>
+
+  <view class="lottie-dom" id="lottie-dom-wrong"></view>
+  <view class="lottie-dom" id="lottie-dom-success"></view>
+
+  <view class="preview-card" v-if="previewState" @click="previewCard" >
+    <image :src="props.card.board.quesUrl" />
+  </view>
 </template>
 </template>
 
 
 <script setup lang="ts" >
 <script setup lang="ts" >
-import { useStaticImg, useSchedulerOnce } from '@/hooks'
-import { computed, onMounted, ref } from 'vue';
+import { useStaticImg,useScheduler, useSchedulerOnce, useAudioMange } from '@/hooks'
+import { computed, ref, nextTick, watch, onMounted, getCurrentInstance } from 'vue';
+import { useCalcQuantityV2Store } from '@/store/gameTool';
+import ao from '@/audio/ao.mp3'
+import successMp3 from '@/audio/success.mp3'
+import wrongMp3 from '@/audio/wrong.mp3'
+import timeoutMp3 from '@/audio/timeout.mp3'
+import lottie from 'lottie-web'
 
 
 interface IProps {
 interface IProps {
-  process: number
-} 
+  card: {
+    board: API.BoardV2,
+    cardAble: string
+    cardDesc: string
+    cardName: string
+    cardType: number
+    audio: string
+  }
+}
+
+interface AnsList {
+  top: number,
+  left: number, 
+  url: string,
+  isAns: boolean,
+  select: boolean
+  id: string
+}
+
+const {
+  proxy: { $forceUpdate },
+}: any = getCurrentInstance();
+
+const { windowWidth, windowHeight } = uni.getSystemInfoSync()
+
+const isPad = windowHeight / windowWidth > 0.6
+
+const posValue = isPad ? 180 : 125
+
+const ansListData: AnsList[] =  [
+  {top: 0, left: 0, url: '', isAns: false, select: false, id: '0' },
+  {top: 0, left: posValue, url: '', isAns: false, select: false, id: '1'}, 
+  {top: posValue, left: 0, url: '', isAns: false, select: false, id: '2'},
+  {top: posValue, left: posValue, url: '', isAns: false, select: false, id: '3'}   
+]
+
+const props = defineProps<IProps>()
 
 
 const staticImg = useStaticImg()
 const staticImg = useStaticImg()
 
 
-const aniState = ref<boolean>(false)
+const audioMange = useAudioMange()
+
+const luojigouBoardV2Dom = ref()
+
+const calcQuantityV2Store = useCalcQuantityV2Store()
+
+const process = ref(0)
 
 
 const buttonList = ['red', 'green', 'blue', 'orange', 'purple', 'yellow']
 const buttonList = ['red', 'green', 'blue', 'orange', 'purple', 'yellow']
 
 
-const buttonListCpd = computed(() => buttonList.slice(0, props.process + 1)) 
+const buttonListCpd = computed(() => buttonList.slice(0, process.value + 1))
 
 
-const props = defineProps<IProps>()
+const keyCount = ref(0)
 
 
-useSchedulerOnce(() => {
-  aniState.value = true
-}, 1900)
+const canvasDom = ref()
 
 
+const ans = ref(0)  //  0 未选择  1 正确 2 错误
 
 
-// 卡片展示的1s动画
-onMounted(() => {
+const ansList = ref<AnsList[]>(JSON.parse(JSON.stringify(ansListData)))
+
+const answerPictureList = ref<string[]>([])
+
+const tipState = ref<boolean>(false)
+
+
+
+const questionAni = ref(['ques-url'])
+
+const ansResultClass = ref(['result'])
+
+const questionCardAni = ref(['ques-card-current'])
+
+const aniState = ref(false)
+
+const previewState = ref(false)
+
+const widget = { boardWidth: 581 / (812 / windowWidth),  boardHeight: 398 / (812 / windowWidth)}
+
+
+
+const emits = defineEmits(['loadingStart', 'loadingEnd', 'gameover'])
+
+const readState = ref(false)
+
+const stopReadQuestion = () => {
+  readState.value = false
+  audioMange.destroy()
+}
+
+const readQuestion = () => {
+
+  audioMange.play(props.card.audio)
+  readState.value = true
+  audioMange.onplayend(() => {
+    lottieReadRef.value.stop()
+    readState.value = false
+  })
+  lottieReadRef.value.play()
+}
+
+const ansPictureRandom = () => {
+
+  const r: number[] = []
+
+  const arr = [0, 1, 2, 3, 4, 5]
+
+  const count = 3
 
 
+  const ansIndex = props.card.board.list[process.value].ansIndex
+
+  const randomArr = arr.filter( item => item !== ansIndex )
+
+  for (let i = 0; i < count; i++) {
+    const randomCount = randomArr[ Math.floor(Math.random() * 5)] 
+    if (r.includes(randomCount)) {
+      i--
+    } else {
+      r.push(randomCount)
+      ansList.value[i].url = answerPictureList.value[randomCount]
+      ansList.value[i].isAns = false
+    }
+  }
+
+  const rc = Math.floor(Math.random() * 4)
+
+  ansList.value[3].url = ansList.value[rc].url
+
+  ansList.value[3].isAns = false
+
+  ansList.value[rc].url = answerPictureList.value[ansIndex] 
+
+  ansList.value[rc].isAns = true
+
+  console.log( ansList.value[rc].url);
+
+  $forceUpdate()
+}
+
+const reset = () => {
+
+  ansResultClass.value = ['result']
+  
+  useSchedulerOnce(() => {
+    emits('gameover', process.value, () => {
+      ansList.value.forEach( item => item.id =  Math.random().toString(16).slice(2) )
+      questionCardAni.value.push('ques-card-ani')
+      useSchedulerOnce(() => {
+        process.value++
+        useSchedulerOnce(() => {
+          questionCardAni.value.pop()
+        }, 1000)
+      }, 1000)
+      useSchedulerOnce(() => {
+        ansPictureRandom()
+      }, 1000)
+   
+    })
+  }, 1200)
+}
+
+const clearTimeRef = ref()
+
+
+const selectAnswer = (record: {isAns: boolean, select: boolean}) => {
+  // 关闭一些状态
+  readState.value = false
+  tipState.value = false
+  ansList.value.forEach( item => item.select = false)
+  if (ansResultClass.value.length === 2) ansResultClass.value.pop()
+  record.select = true
+  lottieReadRef.value.stop()
+  clearTimeRef.value && clearTimeRef.value()
+  // 关闭一些状态
+
+  if (record.isAns) {
+
+    emits('loadingStart')
+
+    ansResultClass.value.push('success')
+
+    ans.value = 1
+
+    lottieSuccessRef.value.play()
+
+    if (calcQuantityV2Store.wrongCount <= 1) {
+      audioMange.play(successMp3)
+    } else {
+      audioMange.play(wrongMp3)
+    }
+
+    clearTimeRef.value = useSchedulerOnce(() => {
+      reset()
+      record.select = false
+      ans.value = 0
+    }, 1000)
+
+  } else {
+    ansResultClass.value.push('wrong')
+    ans.value = 2
+    audioMange.play(ao)
+    calcQuantityV2Store.wrongCount++
+    clearTimeRef.value =  useSchedulerOnce(() => {
+      record.select = false
+      ansResultClass.value.pop()
+      ans.value = 0
+    }, 2000)
+    
+    lottieWrongRef.value.play()
+
+  }
+
+  calcQuantityV2Store.totalCount++
+}
+
+const quesCard = computed(() => {
+  if (props.card.board.list && process.value <= 6) {
+    return {
+      current: props.card.board.list[process.value].quesImg,
+      next: process.value === 6 ? '' : props.card.board.list[process.value].quesImg,
+    }
+  }
+  return {
+    current: '',
+    next: ''
+  }
 })
 })
 
 
+watch(
+  () => props.card.board.ansUrl,
+  async () => {
+    console.log('card.board.quesUrl:', props.card.board.ansUrl);
+    
+    if ( props.card.board.quesUrl) {
+      nextTick(async () => {
+        await croppingPicture(props.card.board.ansUrl)
+        nextTick(() => {
+          ansPictureRandom()
+          readQuestion()
+          questionAni.value.push('question-card-ani')
+          useSchedulerOnce(() => {
+            questionAni.value.push('question-card-small')
+            aniState.value = true
+          }, 1700)
+        })
+      })
+    }
+  },
+  {
+    deep: true,
+    // immediate: true
+  }
+)
 
 
-</script>
+// 预览题卡
+const previewCard = () => previewState.value = !previewState.value
+
+const openTip = () => {
+  console.log('tipState.value = true');
+  
+  tipState.value = true
+}
+
+const aniListRef = ref()
+// 动画列表
+const aniList = () => {
+  const a1 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
+  const a2 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
+  const a3 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
+  const a4 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
+  return [
+    a1.top(60).left(60).step({delay: 0}).top(0).left(0).step({delay: 300}).export(),
+    a2.top(60).left(60).step({delay: 0}).top(0).left(posValue).step({delay: 300}).export(),
+    a3.top(60).left(60).step({delay: 0}).top(posValue).left(0).step({delay: 300}).export(),
+    a4.top(60).left(60).step({delay: 0}).top(posValue).left(posValue).step({delay: 300}).export(),
+  ]
+}
+
+aniListRef.value = aniList()
+
+
+// 切割答案的图片
+const croppingPicture = (img: string) => {
+
+  return new Promise((resolve) => {
+    const ctx = uni.createCanvasContext('canvasId')
+
+      const imgae = new Image()
+
+      imgae.src = img
+
+      imgae.onload = () => {
+        console.log(imgae.width, imgae.height);
+
+        // const imgPng = img.endsWith('jpeg') ? img.replace('jpeg', 'png') : img
 
 
+        // console.log('imgPng:', imgPng);
+        
+        uni.downloadFile({
+          url: img,
+          header: {
+            "Content-Type": "application/x-www-form-urlencoded",
+            "Content-Disposition":  'attachment;filename=',
+          },
+          success(result) {
+            nextTick(() => {
+              console.log('会出错嘛:', result);
+              
+//            
+              // canvasDom.value.width = imgae.width / 4
+              // canvasDom.value.height = imgae.height / 4
+
+              // ctx.drawImage(result.tempFilePath, 0, 0, 222, imgae.height / 2)
+              ctx.drawImage(result.tempFilePath, 0, 0, imgae.width / 8, imgae.height / 8)
+
+              ctx.draw(false, () => {
+                useSchedulerOnce(() => {
+                for (let i = 0; i < 6; i++) {
+                  uni.canvasToTempFilePath({
+                    x: 0,
+                    y: 184 * i / 4 + 12 * i / 4,
+                    width: 222 / 4,
+                    height: 184 / 4,
+                    canvasId: 'canvasId',
+                    
+                    success: function(res) {
+                      
+                      answerPictureList.value.push(res.tempFilePath)
+                      resolve(true)
+                    },
+                    fail(result) {
+                        console.log('canvasToTempFilePath:', result);
+                        
+                    },
+                    complete(result) {
+                      console.log('complete--->canvasToTempFilePath:', result);
+                    },
+                  })
+                  }
+              }, 5) 
+              })
+
+                 
+            })
+          },
+          fail(result) {
+              console.log('downloadFile:', result);
+              
+          },
+        })
+      }
+  })
+
+
+}
+
+const lottieWrongRef = ref()
+
+const lottieSuccessRef = ref()
+
+const lottieReadRef = ref()
+
+// lottie-web
+const initLottieWeb = () => {
+  lottieWrongRef.value = lottie.loadAnimation({
+    container: document.getElementById('lottie-dom-wrong'),
+    renderer: 'svg',
+    loop: false,
+    autoplay: false,
+    path: 'https://luojigou-game-res.luojigou.vip/lottie-wrong.json',
+  })
+
+  lottieWrongRef.value.onComplete = function () {lottieWrongRef.value.stop() }
+
+  lottieSuccessRef.value = lottie.loadAnimation({
+    container: document.getElementById('lottie-dom-success'),
+    renderer: 'svg',
+    loop: false,
+    autoplay: false,
+    path: 'https://luojigou-game-res.luojigou.vip/lottie-success-1.json'
+  })
+
+  lottieSuccessRef.value.onComplete = function () {lottieSuccessRef.value.stop() }
+
+  lottieReadRef.value = lottie.loadAnimation({
+    container: document.getElementById('lottie-dom-read'),
+    renderer: 'svg',
+    loop: true,
+    autoplay: false,
+    path: 'https://luojigou-game-res.luojigou.vip/trump.json'
+  })
+
+  lottieReadRef.value.stop()
+
+}
+
+onMounted(() => {
+  initLottieWeb()
+})
+
+const stx = useScheduler(() => audioMange.play(timeoutMp3), 15000)
+stx.start()
+
+document.body.addEventListener('click', () => {
+  stx.stop()
+  stx.start()
+})
+
+</script>
 
 
 <style lang="less" scoped >
 <style lang="less" scoped >
 .luojigou-board-v2 {
 .luojigou-board-v2 {
   position: relative;
   position: relative;
-  .process {
-    width: 32rpx;
-    height: 65rpx;
-    background: #FFC047;
-    position: absolute;
-    top: 61rpx;
-    left: -5rpx;
-    font-size: 10rpx;
-    font-family: PingFang SC-Semibold, PingFang SC;
-    font-weight: 400;
-    color: #FFFFFF;
-    white-space: normal;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    border-top-left-radius: 14rpx;
-    border-bottom-left-radius: 14rpx;
-    span {
-      font-size: 16rpx;
-      font-weight: 600;
-    }
-  }
   .board {
   .board {
-    width: 354rpx;
-    height: 354rpx;
-    background: url('@/assets/GameViewV2/board.png') no-repeat top right;
+    width: 60%;
+    height: 100%;
+    background: url('@/assets/GameViewV2/board.png') no-repeat top left;
+    background-size: 100%;
+    position: relative;
+    top: 10%;
+    .process {
+      width: 10.5%;
+      height: 16.33%;
+      background: #FFC047;
+      position: absolute;
+      top: 16.33%;
+      left: -10.5%;
+      z-index: 2;
+      // font-size: 90%;
+      font-family: PingFang SC-Semibold, PingFang SC;
+      font-weight: 400;
+      color: #FFFFFF;
+      white-space: normal;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      border-top-left-radius: 14rpx;
+      border-bottom-left-radius: 14rpx;
+      vertical-align: bottom;
+      .count {
+        font-size: 130%;
+        font-weight: 600;
+        vertical-align: bottom;
+        margin-bottom: 6%;
+      }
+      .symbol {
+        margin-bottom: 6%;
+      }
+      view {
+        display: inline-block;
+        line-height: 24px;
+        vertical-align: bottom;
+      }
+    }
     .button-list {
     .button-list {
+      width: 20%;
+      height: 60%;
       position: absolute;
       position: absolute;
-      top: 24rpx;
-      right: 12rpx;
+      top: 6%;
+      right: -6%;
       .button {
       .button {
-        width: 36rpx;
-        height: 36rpx;
-        margin-bottom: 11rpx;
+        width: 55%;
+        height: 16%;
+        margin-bottom: 17%;
         display: flex;
         display: flex;
         justify-content: center;
         justify-content: center;
         align-items: center;
         align-items: center;
@@ -103,8 +545,8 @@ onMounted(() => {
           display: block;
           display: block;
         }
         }
         .right-icon {
         .right-icon {
-          width: 20rpx;
-          height: 20rpx;
+          width: 60%;
+          height: 60%;
           position: absolute;
           position: absolute;
           top: 50%;
           top: 50%;
           left: 50%;
           left: 50%;
@@ -113,43 +555,261 @@ onMounted(() => {
       }
       }
     }
     }
     .question-card {
     .question-card {
-      width: 254rpx;
-      height: 284rpx;
-      background-color: #fff;
-      border-radius: 20rpx;
+      width:  78%;
+      height: 72%;
       position: absolute;
       position: absolute;
-      top: 12rpx;
-      left: 41rpx;
-      transform-origin: 100% 0%;
-      image {
+      top: 6%;
+      left: 4%;
+      // background-color: #fff;
+      border-radius: 6%;
+      z-index: 11;
+      .ques-card-current {
+        width: 100%;
+        height: 100%;
+        background-color: #fff;
+        border-radius: 6%;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        z-index: 11;
+        transform-origin: 50% 50%;
+        .ques-item-url {
+          width: 76%;
+          height: 79%;
+          display: block;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%, -50%);
+          z-index: 1;
+          border-radius: 6%;
+        }
+      }
+      .ques-card-ani {
+        animation: ques-card-current-ani  0.9s;
+      }
+      @keyframes ques-card-current-ani {
+          0% {
+            rotate: 0deg;
+            left: 50%;
+            opacity: 1;
+          }
+          33% {
+            rotate: 4deg;
+            left: 50%;
+            opacity: 1;
+          }
+          66% {
+            rotate: 0deg;
+            left: 50%;
+            opacity: 1;
+          }
+          100% {
+            opacity: 0;
+            left: 20%;
+          }
+      }
+      .ques-card-next {
+        width: 100%;
+        height: 100%;
+        background-color: #fff;
+        border-radius: 6%;
+        .ques-item-url {
+          width: 76%;
+          height: 79%;
+          display: block;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%, -50%);
+          z-index: 1;
+          border-radius: 6%;
+        }
+      }
+      .ques-url {
         width: 100%;
         width: 100%;
         height: 100%;
         height: 100%;
         display: block;
         display: block;
+        position: absolute;
+        top: 0%;
+        left: 0%;
+        z-index: 22;
+        transform-origin: 96% 4%;
+        border-radius: 6%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        background-color: #fff;
+        .card {
+          width: 58%;
+          height: 100%;
+          border-radius: 6%;
+          object-fit: contain;
+
+        }
+        .open-icon {
+          width: 30%;
+          height: 30%;
+          position: absolute;
+          bottom: 2vw;
+          right: 8vw;
+        }
       }
       }
     }
     }
 
 
     .question-card-ani {
     .question-card-ani {
-      animation: card-ani 1s ease 1s;  
+      animation: card-ani 1s ease 0.9s;
     }
     }
 
 
     .question-card-small {
     .question-card-small {
-      scale: 20%;
+      transform: scale(32%) translateX(20%);
+      background-color: transparent !important;
+      .card {
+        border: 2px solid #D0D0D0;
+      }
     }
     }
   }
   }
   .answer {
   .answer {
+    width: 45%;
+    height: 60%;
+    position: absolute;
+    top: 50%;
+    left: 66%;
+    transform: translateY(-50%);
     .answer-list {
     .answer-list {
-      
+      display: grid;
+      grid-template-columns: 11vw 6vw 11vw;
+      grid-template-rows: 11vw 6vw 11vw;
+      //   width: 34%;
+        // height: 37%;
+      .answer-item {
+        width: 11vw;
+        height: 11vw;
+        background-color: #fff;
+        box-shadow: 0px 0px 1vw 0px #FFC04C;
+        border-radius: 16%;
+        border: 0.5vw solid rgba(255, 192, 76, 0.2);
+        position: absolute;
+        box-sizing: border-box;
+        // overflow: hidden;
+        .ans-img {
+          width: 100%;
+          height: 100%;
+          border-radius: 16%;
+          object-fit: cover;
+        }
+        .hand {
+          width: 6vw;
+          height: 6vw;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          animation: hand-ani 1s infinite;
+        }
+        .result {
+          width: 100%;
+          height: 100%;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%, -50%);
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          border-radius: 16%;
+          image {
+            width: 37.5%;
+            height: 37.5%;
+            display: block;
+          }
+        }
+        .success {
+          background: rgba(34,193,52,0.5);
+          border: 0.5vw solid #22C134;
+        }
+        .wrong {
+          background: rgba(234,71,71,0.5);
+          border: 0.5vw solid #EA4747;
+        }
+      }
     }
     }
   }
   }
 }
 }
 
 
+.opra-container {
+  position: fixed;
+  right: 3vw;
+  bottom: 3vw;
+  display: flex;
+  flex-direction: column;
+  .read {
+    width: 5.5vw;
+    height: 5.5vw;
+    position: absolute;
+    bottom: 6.5vw;
+  }
+  image {
+    width: 5.5vw;
+    height: 5.5vw;
+    margin-top: 2vw;
+  }
+}
+
+
+.lottie-dom {
+  width: 24vw;
+  height: 24vw;
+  position: fixed;
+  left: 0;
+  bottom: 0;
+  z-index: 120;
+}
+
+
+
+.preview-card {
+  width: 100vw;
+  height: 100vh;
+  background-color: rgba(0, 0, 0, 0.6);
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 11;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  image {
+    width: 58vh;
+    height: 100vh;
+  }
+}
+@keyframes hand-ani {
+  0% {
+    transform: translate(0vw, 0vw)
+  };
+  50% {
+    transform: translate(2vw, 2vw)
+  };
+  100% {
+    transform: translate(0vw, 0vw)
+  }
+} 
 
 
 @keyframes card-ani {
 @keyframes card-ani {
   0% {
   0% {
-    scale: 100%;
+    transform: scale(100%);
+  };
+  78% {
+    transform: scale(100%);
+    background-color: #fff;
+  };
+  80% {
+    background-color: transparent;
   };
   };
   100% {
   100% {
-    scale: 20%;
+    transform: scale(32%) translateX(20%);
+    background-color: transparent;
   }
   }
 }
 }
 </style>
 </style>

+ 21 - 12
src/components/rive-ani/rive-ani.vue

@@ -1,17 +1,17 @@
 <template>
 <template>
   <view class="rive-ani" id="rive-ani" v-if="state.comVisable" >
   <view class="rive-ani" id="rive-ani" v-if="state.comVisable" >
 
 
-    <view class="coin-max-tip"  v-if="state.maxTipVisible" :style="{backgroundImage: `url(${staticImg.blockRect})`, top: navbarInfo.top}" >
+    <view class="coin-max-tip"  v-if="state.maxTipVisible" :style="{backgroundImage: `url(${staticImg.blockRect})`, top: '3vw'}" >
       已达上限
       已达上限
     </view>
     </view>
 
 
-    <view class="coin-total" :style="{top: navbarInfo.top }" >
+    <view class="coin-total" :style="{top: '3vw' }" >
       <span>{{wisdomCoinStore.total || 0}}</span>
       <span>{{wisdomCoinStore.total || 0}}</span>
       <view class="coin-logo" id="coin-logo" :animation="state.heartbeatAni" >
       <view class="coin-logo" id="coin-logo" :animation="state.heartbeatAni" >
         <img :src="staticImg.coinTotal" alt="">
         <img :src="staticImg.coinTotal" alt="">
       </view>
       </view>
     </view>
     </view>
-    <view class="coin-ani" id="coin-ani" v-if="state.visible"  >
+    <view class="coin-ani" id="coin-ani" v-if="state.visible" :key="state.aniKey"  >
         <view
         <view
           class="coin-item"
           class="coin-item"
           v-for="item in state.cointCount" 
           v-for="item in state.cointCount" 
@@ -20,6 +20,7 @@
           :id="`coin-item-${item}`"
           :id="`coin-item-${item}`"
         >
         >
           <img  :src="staticImg.coinAni" alt=""   >
           <img  :src="staticImg.coinAni" alt=""   >
+
         </view>
         </view>
       <view class="coin-count" id="coin-count"   >+ {{state.cointCount}}</view>
       <view class="coin-count" id="coin-count"   >+ {{state.cointCount}}</view>
     </view>
     </view>
@@ -33,6 +34,7 @@ import { Rive } from "@rive-app/canvas"
 import { useStaticImg, useQueryElInfo, useSchedulerOnce, useNavbarInfo } from '@/hooks/index'
 import { useStaticImg, useQueryElInfo, useSchedulerOnce, useNavbarInfo } from '@/hooks/index'
 import { useWisdomCoinStore } from '@/store'
 import { useWisdomCoinStore } from '@/store'
 import { AudioController } from '@/controller/AudioController';
 import { AudioController } from '@/controller/AudioController';
+// import threeStarRiv from '@/ani/three_star.riv'
 
 
 enum AniEnum {
 enum AniEnum {
   'one',
   'one',
@@ -59,6 +61,7 @@ interface State {
   comVisable: boolean,
   comVisable: boolean,
   cardType: 0 | 1,
   cardType: 0 | 1,
   maxTipVisible: boolean
   maxTipVisible: boolean
+  aniKey: number
 }
 }
 
 
 const state = reactive<Partial<State>>({
 const state = reactive<Partial<State>>({
@@ -68,7 +71,8 @@ const state = reactive<Partial<State>>({
   cointCount: 0,
   cointCount: 0,
   comVisable: false,
   comVisable: false,
   cardType: 0,
   cardType: 0,
-  maxTipVisible: false
+  maxTipVisible: false,
+  aniKey: 0
 })
 })
 
 
 const staticImg = useStaticImg()
 const staticImg = useStaticImg()
@@ -111,11 +115,13 @@ const initRive = () => {
   document.getElementById('rive-ani')?.appendChild(canvas)
   document.getElementById('rive-ani')?.appendChild(canvas)
   
   
   rive = new Rive({
   rive = new Rive({
-    src: "https://res-game.luojigou.vip/coin1234.riv",
+    // src: "https://res-game.luojigou.vip/coin1234.riv",
+    src: 'https://res-game.luojigou.vip/three_star.riv',
     canvas: canvas,
     canvas: canvas,
     autoplay: false,
     autoplay: false,
     stateMachines: "bumpy",
     stateMachines: "bumpy",
-    artboard: state.cardType === 0 ? 'si-xing' : 'six-xing',
+    // artboard: state.cardType === 0 ? 'si-xing' : 'six-xing',
+    artboard: 'Three Star Board',
     onLoad: () => {
     onLoad: () => {
       
       
       rive.resizeToCanvas()
       rive.resizeToCanvas()
@@ -123,6 +129,7 @@ const initRive = () => {
       console.log(rive);
       console.log(rive);
 
 
       rive.play(AniEnum[state.cointCount! - 1])
       rive.play(AniEnum[state.cointCount! - 1])
+      // rive.play('one')
       
       
       for (let i = 0; i < state.cointCount!; i++) {
       for (let i = 0; i < state.cointCount!; i++) {
        
        
@@ -191,6 +198,7 @@ const goBezier = () => {
     _resolve()
     _resolve()
     state.comVisable = false
     state.comVisable = false
     state.visible = false
     state.visible = false
+    state.animation = []
     document.getElementById('coin-count')!.style.display = 'block'
     document.getElementById('coin-count')!.style.display = 'block'
   }, 1200 + state.cointCount! * 600)
   }, 1200 + state.cointCount! * 600)
 
 
@@ -201,6 +209,7 @@ const start = async (starCount: number, cardType: 0 | 1) => {
   state.comVisable = true
   state.comVisable = true
   state.cointCount = starCount
   state.cointCount = starCount
   state.cardType = cardType
   state.cardType = cardType
+  state.aniKey = Math.random()
 
 
   if (cardType === 0) {
   if (cardType === 0) {
     starCount <= 2 ? AudioController.playFail() : AudioController.playPass()
     starCount <= 2 ? AudioController.playFail() : AudioController.playPass()
@@ -276,7 +285,7 @@ onMounted(() => {
     background: #414141;
     background: #414141;
     border-radius: 19px;
     border-radius: 19px;
     position: absolute;
     position: absolute;
-    right: 26px;
+    right: 2vw;
     display: flex;
     display: flex;
     align-items: center;
     align-items: center;
     padding: 0 8px;
     padding: 0 8px;
@@ -325,16 +334,16 @@ onMounted(() => {
       }      
       }      
     }
     }
     img {
     img {
-      width: 152rpx;
-      height: 152rpx;
+      width: 30%;
+      height: 30%;;
     }
     }
     .coin-count {
     .coin-count {
-      font-size: 56rpx;
+      font-size: 200%;
       font-family: PingFangSC-Semibold, PingFang SC;
       font-family: PingFangSC-Semibold, PingFang SC;
       font-weight: 600;
       font-weight: 600;
       color: #FF8024;
       color: #FF8024;
-      margin-left: 250rpx;
-      margin-bottom: 20rpx;
+      // margin-left: 250rpx;
+      // margin-bottom: 20rpx;
     }
     }
   }
   }
 }
 }

+ 4 - 0
src/controller/AudioController.ts

@@ -14,6 +14,10 @@ export class AudioController {
 
 
   static fail = 'https://res-game.luojigou.vip/fail.MP3'
   static fail = 'https://res-game.luojigou.vip/fail.MP3'
 
 
+  play (src: string) {
+    audioMange.play(src)
+  }
+
   static playCorrect () {
   static playCorrect () {
     audioMange.play(AudioController.correntUrl)
     audioMange.play(AudioController.correntUrl)
   }
   }

+ 14 - 9
src/hooks/index.ts

@@ -62,12 +62,16 @@ export const useScheduler = (cb: () => void, delay: number) => {
 export const useSchedulerOnce = (
 export const useSchedulerOnce = (
   cb: () => void,
   cb: () => void,
   delay: number = 4
   delay: number = 4
-): void => {
+): () => void => {
+
   const timeId = setTimeout(() => {
   const timeId = setTimeout(() => {
     cb()
     cb()
     clearTimeout(timeId)
     clearTimeout(timeId)
   }, delay)
   }, delay)
+
   onUnmounted(() => clearTimeout(timeId))
   onUnmounted(() => clearTimeout(timeId))
+
+  return () => clearTimeout(timeId)
 }
 }
 
 
 /**
 /**
@@ -138,12 +142,13 @@ export const useQueryElInfo = (
  */
  */
 export const useAudioMange = (src?: string) => {
 export const useAudioMange = (src?: string) => {
 
 
-  const audioInstance = ref< UniApp.InnerAudioContext>()
+  const audioInstance = ref<UniApp.InnerAudioContext>()
  
  
   audioInstance.value = uni.createInnerAudioContext()
   audioInstance.value = uni.createInnerAudioContext()
 
 
+  
+
   if (src) {
   if (src) {
-    
     audioInstance.value.src = src
     audioInstance.value.src = src
   }
   }
 
 
@@ -151,32 +156,32 @@ export const useAudioMange = (src?: string) => {
 
 
   const play = (src: string) => {
   const play = (src: string) => {
     audioInstance.value!.src = src
     audioInstance.value!.src = src
-    console.log(src, audioInstance.value);
-    
     useSchedulerOnce(() => {
     useSchedulerOnce(() => {
-      console.log('play');
       audioInstance.value?.play()
       audioInstance.value?.play()
-    }, 500)
+    }, 100)
 
 
   }
   }
 
 
   audioInstance.value.autoplay = true
   audioInstance.value.autoplay = true
 
 
   audioInstance.value!.onCanplay((e) => {
   audioInstance.value!.onCanplay((e) => {
-    console.log('onCanplay:111', e);
+    console.log('onCanplay:', e);
   })
   })
 
 
   audioInstance.value?.onError((e) => {
   audioInstance.value?.onError((e) => {
     console.log(e);
     console.log(e);
   })
   })
 
 
-  const onplayend = (cb: Function) => audioInstance.value?.onEnded(() => cb && cb())
+  const onplayend = (cb: Function) => audioInstance.value?.onEnded(() => {
+    cb && cb()
+  })
 
 
   onUnmounted(() => {
   onUnmounted(() => {
     destroy()
     destroy()
   })
   })
 
 
   const atx = {
   const atx = {
+    audioInstance,
     destroy,
     destroy,
     play,
     play,
     onplayend,
     onplayend,

+ 1 - 3
src/pages/GameView/index.vue

@@ -88,6 +88,7 @@ const gameCountdownStore = useGameCountdownStore()
 const calcQuantityStore = useCalcQuantityStore()
 const calcQuantityStore = useCalcQuantityStore()
 
 
 const wisdomCoinStore = useWisdomCoinStore()
 const wisdomCoinStore = useWisdomCoinStore()
+
 const base64 = useBase64()
 const base64 = useBase64()
 
 
 const staticImg = useStaticImg()
 const staticImg = useStaticImg()
@@ -244,8 +245,6 @@ const onSubmitCard = async () => {
   calcQuantityStore.clear()
   calcQuantityStore.clear()
   
   
   GetCardDetailById()
   GetCardDetailById()
-
-  
 }
 }
 
 
 // 提交题卡
 // 提交题卡
@@ -271,7 +270,6 @@ const gameCompleted = async () => {
 
 
   // 如果opraMode 的是learn 则跳转到app-web页面
   // 如果opraMode 的是learn 则跳转到app-web页面
   if (state.opraMode == OpraModeEnum.LEARN) {
   if (state.opraMode == OpraModeEnum.LEARN) {
-
     window.location.href = `https://nginx.test.luojigou.vip/app_web/learn-plan.html#/?from='exercise'`
     window.location.href = `https://nginx.test.luojigou.vip/app_web/learn-plan.html#/?from='exercise'`
   }
   }
   
   

+ 202 - 21
src/pages/GameViewV2/index.vue

@@ -1,31 +1,96 @@
 <template>
 <template>
-  <view class="game-view-v2" >
+  <view class="game-view-v2" :style="{pointerEvents: screenTouchState ? 'none' : 'all'}" >
     <image @click="backPage" class="back-icon" :src="staticImg.backIcon" />
     <image @click="backPage" class="back-icon" :src="staticImg.backIcon" />
     <view class="rockon-by-time" >
     <view class="rockon-by-time" >
       {{rockonByTimeRef}}s
       {{rockonByTimeRef}}s
     </view>
     </view>
-    <view class="luojigou-board-v2-container" >
-      <luojigou-board-v2 :process="0" />
+    <view class="luojigou-board-v2-container"  >
+      <luojigou-board-v2
+        ref="luojigouBoardV2Dom"
+        :card="state.card"
+        @loadingStart="openProhibitTouch"
+        @gameover="gameover"
+      />
     </view>
     </view>
+
+    <rive-ani ref="riveAniDom" />
+
   </view>
   </view>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { ref } from 'vue';
-import { useScheduler, useStaticImg } from '@/hooks'
+import { ref, reactive, onMounted } from 'vue';
+import { useScheduler, useStaticImg, useBase64, useAudioMange } from '@/hooks'
 import { useAppBridge } from '@/hooks/app'
 import { useAppBridge } from '@/hooks/app'
-import { onMounted } from 'vue';
+import { onLoad } from '@dcloudio/uni-app';
+import { CardModeEnum, OpraModeEnum } from '@/enum/constant';
+import {
+  usePracticeStore, 
+  useOpraRecordStore, 
+  useGameCountdownStore, 
+  useCalcQuantityStore, 
+  useWisdomCoinStore,
+  useCalcQuantityV2Store
+} from '@/store'
+import { getCollectionDetailById } from '@/api/collection'
+import { getCardDetailById, submitlearnPortAns } from '@/api/card'
+
+export interface QueryParams {
+  mode: CardModeEnum,
+  collectionId: string,
+  cardId?: string,
+  opraMode: OpraModeEnum,
+}
+
+interface State extends QueryParams {
+  card: {board: Partial<API.Board>, audio: string, cardAble: string},
+  cardIds: string[],
+  playLoading: boolean,
+  userCardAnswerList: any[],
+  queryParams: API.P | null
+}
 
 
 const staticImg = useStaticImg()
 const staticImg = useStaticImg()
 
 
+const wisdomCoinStore = useWisdomCoinStore()
+
+const base64 = useBase64()
+
+const practiceStore = usePracticeStore()
+
 // 计时
 // 计时
 const rockonByTimeRef = ref(0)
 const rockonByTimeRef = ref(0)
 
 
-// 答题进度
-const questionProcess = ref(0)
+const luojigouBoardV2Dom = ref()
 
 
 const appBridge = useAppBridge()
 const appBridge = useAppBridge()
 
 
+const screenTouchState = ref<boolean>(false)
+
+const riveAniDom = ref()
+
+const calcQuantityV2Store = useCalcQuantityV2Store()
+
+const state = reactive<State>({
+  opraMode: OpraModeEnum.COMPE,
+  mode: CardModeEnum.PREVIEW,
+  collectionId: '',
+  cardIds: [],
+  cardId: '',
+  card: {
+    audio: '',
+    board: {
+      quesUrl: '',
+      ansUrl: '',
+      buttons: [],
+      ansList: []
+    }
+  },
+  playLoading: false,
+  userCardAnswerList: [],
+  queryParams: null,
+})
+
 const stx = useScheduler(() => {
 const stx = useScheduler(() => {
   rockonByTimeRef.value++
   rockonByTimeRef.value++
 }, 1000)
 }, 1000)
@@ -34,14 +99,107 @@ const backPage = () => {
   appBridge.back()
   appBridge.back()
 }
 }
 
 
-const readQuestion = () => {
 
 
+
+// 获取试题集详情
+const GetCollectionDetailById = async () => {
+  const { data } = await getCollectionDetailById(state.collectionId)
+  
+  if ( state.opraMode === OpraModeEnum.PRACTICE) {
+    state.cardIds = practiceStore.get(state.collectionId, data.cardIds)
+    state.cardId = practiceStore.nextId(state.cardIds)
+  } else {
+    state.cardIds = data.cardIds
+  }
+
+  if ( state.cardIds.length > 0) {
+    state.cardId = state.cardIds[0]
+    GetCardDetailById()
+  }
+}
+
+// 获取题卡详情
+const GetCardDetailById = async () => {
+  const { data } = await getCardDetailById(state.cardId!, state.mode)
+  state.card = data
+}
+
+// 开始屏幕禁止点击
+const openProhibitTouch = () => {
+  screenTouchState.value = !screenTouchState.value
+}
+
+// 游戏结束 提交题卡
+const submitQuestionCardData = async () => {
+
+  const $par = {
+    "attach": {
+      "itemId": state.queryParams?.attach.itemId,
+      "recordId": state.queryParams?.attach.recordId
+    },
+    "data": {
+      "correctQuantity": 6,
+      "gameDuration": rockonByTimeRef.value,
+      "totalQuantity": calcQuantityV2Store.allCount,
+      "userCardAnswerList": calcQuantityV2Store.userCardAnswerList.map(item => {
+        return {
+          ...item,
+          capability: state.card.cardAble
+        }
+      }),
+      "winWisdomCoin":  wisdomCoinStore.itemCoin
+    }
+  }
+  console.log('提交');
+  
+  await submitlearnPortAns($par, state.queryParams?.submitUrl!)
 }
 }
 
 
-const tip = () => {
 
 
+
+const processRef = ref(0)
+// 游戏结束
+const gameover = async (process: number, cb: Function) => {
+  processRef.value = process
+  screenTouchState.value = true
+  const star = calcQuantityV2Store.getStar()
+  if (process >= 5 ) {
+    stx.stop()
+    submitQuestionCardData()
+  }
+  await riveAniDom.value.start(star, 1)
+  screenTouchState.value = false
+  calcQuantityV2Store.clear()
+  // 如果opraMode 的是learn 则跳转到app-web页面
+  if (state.opraMode == OpraModeEnum.LEARN && process >= 5) {
+    window.location.href = `https://zaojiao.net/app_web/learn-plan.html#/?from='exercise'`
+  }
+  cb()
 }
 }
 
 
+onLoad(query => {
+  let options
+  if (import.meta.env.MODE === "development") {
+    state.queryParams = base64.decode<API.P>(query!.p)
+    state.opraMode = state.queryParams.data.opraMode
+    options = state.queryParams.data
+  } else {
+    state.queryParams = base64.decode<API.P>(query!.p)
+    state.opraMode = state.queryParams.data.opraMode
+    options = state.queryParams.data
+  } 
+
+  console.log(' state.queryParams:',  state.queryParams);
+  
+  state.mode = options.mode || CardModeEnum.PREVIEW
+  state.collectionId = options.collectionId
+  if (options.cardId) state.cardId = options.cardId
+
+  wisdomCoinStore.total = options.userWisdomCoin
+  wisdomCoinStore.remainderWisdomCoin = options.remainderWisdomCoin
+  GetCollectionDetailById()
+})
+
 onMounted(() => {
 onMounted(() => {
   stx.start()
   stx.start()
 })
 })
@@ -54,23 +212,25 @@ onMounted(() => {
   height: 100vh;
   height: 100vh;
   background: url('@/assets/GameViewV2/bg.png');
   background: url('@/assets/GameViewV2/bg.png');
   position: relative;
   position: relative;
+
   .back-icon {
   .back-icon {
     position: absolute;
     position: absolute;
-    width: 45rpx;
-    height: 45rpx;
-    top: 16rpx;
-    left: 32rpx;
+    width: 6vw;
+    height: 6vw;
+    top: 3vw;
+    left: 3vw;
+    z-index: 2;
   }
   }
   .rockon-by-time {
   .rockon-by-time {
-    padding: 0 10rpx;
-    height: 24rpx;
+    padding: 0 2vw;
+    height: 3.5vw;
     background: rgba(0,0,0,0.26);
     background: rgba(0,0,0,0.26);
     box-shadow: inset 0px 1px 1px 0px rgba(162,76,0,0.1);
     box-shadow: inset 0px 1px 1px 0px rgba(162,76,0,0.1);
     border-radius: 20px;
     border-radius: 20px;
     position: absolute;
     position: absolute;
-    top: 34rpx;
-    right: 24rpx;
-    font-size: 14rpx;
+    top: 3vw;
+    right: 2vw;
+    font-size: 100%;
     font-family: PingFang SC-Medium, PingFang SC;
     font-family: PingFang SC-Medium, PingFang SC;
     font-weight: 500;
     font-weight: 500;
     color: #FFFFFF;
     color: #FFFFFF;
@@ -80,8 +240,29 @@ onMounted(() => {
   }
   }
   .luojigou-board-v2-container {
   .luojigou-board-v2-container {
     position: absolute;
     position: absolute;
-    top: 21rpx;
-    left: 140rpx;
+    top:0;
+    bottom:0;
+    left:0;
+    right:0;
+    // transform: translate(-50%, -50%);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    
+  overflow: hidden;
+  }
+
+  .opra-container {
+    position: fixed;
+    right: 40rpx;
+    bottom: 40rpx;
+    display: flex;
+    flex-direction: column;
+    image {
+      width: 40rpx;
+      height: 40rpx;
+      margin-top: 10rpx;
+    }
   }
   }
 }
 }
 
 

+ 1 - 4
src/service/index.ts

@@ -11,7 +11,7 @@ interface Params {
 }
 }
 
 
 // const BASEURL = import.meta.env.MODE === 'development' ? 'http://local.luojigou.vip:8888' : 'https://open.api.luojigou.vip'
 // const BASEURL = import.meta.env.MODE === 'development' ? 'http://local.luojigou.vip:8888' : 'https://open.api.luojigou.vip'
-const BASEURL = import.meta.env.MODE === 'development' ? 'https://open.api.luojigou.vip' : 'https://open.api.luojigou.vip'
+const BASEURL = import.meta.env.MODE === 'development' ? 'https://open.test.luojigou.vip' : 'https://open.api.luojigou.vip'
 //  'https://open.test.luojigou.vip'
 //  'https://open.test.luojigou.vip'
 // window.location.href.split('#')[0] + 'zd-api'
 // window.location.href.split('#')[0] + 'zd-api'
 // https://open.test.luojigou.vip
 // https://open.test.luojigou.vip
@@ -22,9 +22,6 @@ export const request = async <T>(
 ) => {
 ) => {
 
 
   let data = params.params || {};
   let data = params.params || {};
-
-  console.log("data:", data);
-  
   let url = (params.baseURL ? params.baseURL: BASEURL) + params.url;
   let url = (params.baseURL ? params.baseURL: BASEURL) + params.url;
   let method = params.method
   let method = params.method
   let responseType = params.responseType
   let responseType = params.responseType

+ 58 - 4
src/store/gameTool.ts

@@ -1,8 +1,7 @@
 import { ConstantLocalStorage } from '@/utils/constant'
 import { ConstantLocalStorage } from '@/utils/constant'
 import { ConstantStore } from '@/utils/constant'
 import { ConstantStore } from '@/utils/constant'
 import { defineStore } from 'pinia'
 import { defineStore } from 'pinia'
-import { toRefs } from 'vue'
-import { reactive } from 'vue'
+import { reactive, toRefs, ref } from 'vue'
 import { useSessionStorageState } from 'vue-hooks-plus'
 import { useSessionStorageState } from 'vue-hooks-plus'
 
 
 
 
@@ -31,7 +30,7 @@ export const useGameCountdownStore = defineStore(ConstantStore.COUNTDOWN, () =>
 /**
 /**
  * 计算用户本张题卡获得的星星数
  * 计算用户本张题卡获得的星星数
  * @param wrongCount 错误次数
  * @param wrongCount 错误次数
- * @param totalStart 
+ * @param totalStart
  */
  */
 export const useCalcStartStore = defineStore(ConstantStore.STAR, () => {
 export const useCalcStartStore = defineStore(ConstantStore.STAR, () => {
 
 
@@ -59,7 +58,7 @@ export const useCalcStartStore = defineStore(ConstantStore.STAR, () => {
 
 
 })
 })
 
 
-
+// 竖版 三张题卡的计算方式
 export const useCalcQuantityStore = defineStore(ConstantStore.QUANTITY, () => {
 export const useCalcQuantityStore = defineStore(ConstantStore.QUANTITY, () => {
 
 
   const state = reactive({
   const state = reactive({
@@ -86,7 +85,62 @@ export const useCalcQuantityStore = defineStore(ConstantStore.QUANTITY, () => {
 
 
 })
 })
 
 
+// 横版 一张题卡的计算 
+export const useCalcQuantityV2Store = defineStore(ConstantStore.QUANTITYV2, () => {
+
+  const state = reactive({
+    correctQuantity: 0,
+    totalQuantity: 0,
+    wrongCount: 0
+  })
+
+  const userCardAnswerList = reactive([])
+
+  const wrongCount = ref(0)
+
+  // 总共选择答案的次数
+  const totalCount = ref(0)
+
+  const allCount = ref(0)
+  
+  const getStar = () => {
+
+    let star = 0
 
 
+    if (wrongCount.value <= 0) {
+      star = 3
+    } else if (wrongCount.value === 1) {
+      star = 2
+    } else {
+      star = 1
+    }
+
+    userCardAnswerList.push({
+      correctQuantity: star,
+      totalQuantity: totalCount.value,
+      wrongCount: wrongCount.value,
+    })
+
+    allCount.value += totalCount.value
+
+    return star
+  }
+
+  const clear = () => {
+    wrongCount.value = 0
+    totalCount.value = 0
+  }
+
+  return {
+    allCount,
+    totalCount,
+    wrongCount,
+    userCardAnswerList,
+    getStar,
+    clear
+  }
+  
+})
 
 
 
 
 export const useWisdomCoinStore = defineStore(ConstantStore.WISDOMCOIN, () => {
 export const useWisdomCoinStore = defineStore(ConstantStore.WISDOMCOIN, () => {

+ 2 - 1
src/store/index.ts

@@ -8,5 +8,6 @@ export {
   useGameCountdownStore,
   useGameCountdownStore,
   useCalcStartStore,
   useCalcStartStore,
   useCalcQuantityStore,
   useCalcQuantityStore,
-  useWisdomCoinStore
+  useWisdomCoinStore,
+  useCalcQuantityV2Store
 } from './gameTool'
 } from './gameTool'

+ 10 - 0
src/typing.d.ts

@@ -62,6 +62,16 @@ declare namespace API {
     tipsButton: number
     tipsButton: number
   }
   }
 
 
+  interface BoardV2 {
+    list: {
+      ansIndex: number,
+      quesImg: string
+    }[],
+    ansUrl: string
+    quesUrl: string,
+    buttons: {x: string, y: string, color: Color}[]
+  }
+
   interface Collect {
   interface Collect {
     id: string,
     id: string,
     collectionName:  string // 题集名称
     collectionName:  string // 题集名称

+ 1 - 0
src/utils/constant.ts

@@ -16,5 +16,6 @@ export enum ConstantStore {
   'COUNTDOWN' = 'COUNTDOWN',
   'COUNTDOWN' = 'COUNTDOWN',
   'STAR' = 'STAR',
   'STAR' = 'STAR',
   'QUANTITY' = 'QUANTITY',
   'QUANTITY' = 'QUANTITY',
+  'QUANTITYV2' = 'QUANTITYV2',
   'WISDOMCOIN' = 'WISDOMCOIN'
   'WISDOMCOIN' = 'WISDOMCOIN'
 }
 }

+ 25 - 1
src/utils/static.ts

@@ -30,6 +30,14 @@ import phone from '@/assets/phone.png'
 import rotateArrow from '@/assets/rotateArrow.png'
 import rotateArrow from '@/assets/rotateArrow.png'
 import backIcon from '@/assets/GameViewV2/back.png'
 import backIcon from '@/assets/GameViewV2/back.png'
 import rightIcon from '@/assets/GameViewV2/right.png'
 import rightIcon from '@/assets/GameViewV2/right.png'
+import wrong from '@/assets/GameViewV2/wrong.png'
+import success from '@/assets/GameViewV2/success.png'
+import hand from '@/assets/GameViewV2/hand.png'
+import tip from '@/assets/GameViewV2/tip.png'
+import read from '@/assets/GameViewV2/read.png'
+import wrongAni from '@/assets/GameViewV2/wrong-ani.gif'
+import successAni from '@/assets/GameViewV2/success-ani.gif'
+import openIcon from '@/assets/GameViewV2/open-icon.png'
 
 
 export interface StaticImg {
 export interface StaticImg {
   logo: string
   logo: string
@@ -67,6 +75,14 @@ export interface StaticImg {
   rotateArrow: string,
   rotateArrow: string,
   backIcon: string
   backIcon: string
   rightIcon: string
   rightIcon: string
+  wrong: string
+  success: string
+  hand: string
+  tip: string
+  read: string
+  wrongAni: string
+  successAni: string
+  openIcon: string
 }
 }
 
 
 let staticImg: Partial<StaticImg> = {
 let staticImg: Partial<StaticImg> = {
@@ -105,7 +121,15 @@ let staticImg: Partial<StaticImg> = {
   phone,
   phone,
   rotateArrow,
   rotateArrow,
   backIcon,
   backIcon,
-  rightIcon
+  rightIcon,
+  wrong,
+  success,
+  hand,
+  tip,
+  read,
+  wrongAni,
+  successAni,
+  openIcon
 }
 }
 
 
 
 

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