|
@@ -0,0 +1,248 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { showSuccessToast } from 'vant'
|
|
|
+import GameAPI, { type GameResultVO, type GameVO, type Result, type ResultLevel } from '@/api/game'
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+
|
|
|
+const subjectInfo = ref<GameVO>({})
|
|
|
+
|
|
|
+// 控制倒计时的显隐
|
|
|
+const showCountDown = ref(true)
|
|
|
+// 显示题目文本
|
|
|
+const showSpanText = ref('')
|
|
|
+// 测试总次数
|
|
|
+const totalCount = ref(0)
|
|
|
+// 当前题答案
|
|
|
+const currentAnswer = ref(0)
|
|
|
+// 正确总次数
|
|
|
+const rightCount = ref(0)
|
|
|
+// 当前轮正确次数
|
|
|
+const currentRoundRightCount = ref(0)
|
|
|
+// 连续对3次
|
|
|
+const rightThree = ref(0)
|
|
|
+// 连续错两次
|
|
|
+const wrongTwo = ref(0)
|
|
|
+// 当前轮需要计算的数字个数
|
|
|
+const additionNumCount = ref(2)
|
|
|
+// 统计每个层级答对个数
|
|
|
+const rightCountList: Result[] = reactive([])
|
|
|
+// 测试时长 100 秒
|
|
|
+const gameDuration = ref(10 * 1000)
|
|
|
+// 游戏结束时间戳
|
|
|
+const gameEndTime = ref(0)
|
|
|
+// 游戏开始时间戳
|
|
|
+const gameStartTime = ref(0)
|
|
|
+// 游戏收集的数据
|
|
|
+const gameData: GameResultVO = {
|
|
|
+ finish: '1',
|
|
|
+ gameId: subjectInfo.value.id,
|
|
|
+ gameName: subjectInfo.value.name,
|
|
|
+ userId: sessionStorage.getItem('userId'),
|
|
|
+ paramList: [],
|
|
|
+ levelList: [],
|
|
|
+}
|
|
|
+
|
|
|
+function nNumRightCount() {
|
|
|
+ const isIndex = rightCountList.findIndex(item => Number.parseInt(item.name) === additionNumCount.value)
|
|
|
+ if (isIndex !== -1) {
|
|
|
+ if (typeof rightCountList[isIndex].value === 'number') {
|
|
|
+ rightCountList[isIndex].value++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ rightCountList.push({
|
|
|
+ name: additionNumCount.value.toString(),
|
|
|
+ value: 1,
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function createComputeSpanText() {
|
|
|
+ // 生成下一道题和答案
|
|
|
+ const tempSpanText: number[] = []
|
|
|
+ let additionResult = 0
|
|
|
+ for (let i = additionNumCount.value; i > 0; i--) {
|
|
|
+ const tempNum = Math.floor(Math.random() * 10)
|
|
|
+ additionResult += tempNum
|
|
|
+ tempSpanText.push(tempNum)
|
|
|
+ }
|
|
|
+ showSpanText.value = tempSpanText.join('+')
|
|
|
+ currentAnswer.value = additionResult % 10
|
|
|
+}
|
|
|
+
|
|
|
+function userClick(answer: number) {
|
|
|
+ // 如果游戏时长大于或等于 100 秒,则游戏结束
|
|
|
+ gameEndTime.value = performance.now()
|
|
|
+ const duration = gameEndTime.value - gameStartTime.value
|
|
|
+ if (duration >= gameDuration.value) {
|
|
|
+ // 游戏结束,发送数据
|
|
|
+ sendData()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 用户点击动作
|
|
|
+ totalCount.value++
|
|
|
+ if (answer === currentAnswer.value) {
|
|
|
+ // 正确次数
|
|
|
+ rightCount.value++
|
|
|
+ // 当前数字个数计算正确数加1
|
|
|
+ nNumRightCount()
|
|
|
+ // 本轮正确次数
|
|
|
+ currentRoundRightCount.value++
|
|
|
+
|
|
|
+ rightThree.value++
|
|
|
+ wrongTwo.value = 0
|
|
|
+ if (rightThree.value >= 3 && wrongTwo.value === 0) {
|
|
|
+ additionNumCount.value++
|
|
|
+ rightThree.value = 0
|
|
|
+ wrongTwo.value = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // 正式测试时要做降级处理
|
|
|
+ currentRoundRightCount.value = 0
|
|
|
+ rightThree.value = 0
|
|
|
+ wrongTwo.value++
|
|
|
+ if (additionNumCount.value > 2 && rightThree.value === 0 && wrongTwo.value >= 2) {
|
|
|
+ additionNumCount.value--
|
|
|
+ rightThree.value = 0
|
|
|
+ wrongTwo.value = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成下一道题
|
|
|
+ createComputeSpanText()
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 倒计时结束时的回调
|
|
|
+ */
|
|
|
+function endCountDown() {
|
|
|
+ // 隐藏倒计时组件
|
|
|
+ showCountDown.value = false
|
|
|
+ // 开始生成游戏的第一道题
|
|
|
+ createComputeSpanText()
|
|
|
+ // 记录游戏开始时间戳
|
|
|
+ gameStartTime.value = performance.now()
|
|
|
+ // 重置游戏结束时间戳
|
|
|
+ gameEndTime.value = 0
|
|
|
+ // 重置收集的游戏数据
|
|
|
+}
|
|
|
+
|
|
|
+function sendData() {
|
|
|
+ const totalScore = rightCountList.reduce((acc, curr) => {
|
|
|
+ acc += curr.value as number * 2 ** (Number.parseInt(curr.name) - 2)
|
|
|
+ return acc
|
|
|
+ }, 0)
|
|
|
+
|
|
|
+ gameData.levelList = rightCountList.map((item) => {
|
|
|
+ return {
|
|
|
+ level: item.name,
|
|
|
+ levelParamList: [{ item }] as Result,
|
|
|
+ } as ResultLevel
|
|
|
+ })
|
|
|
+
|
|
|
+ gameData.paramList = [
|
|
|
+ {
|
|
|
+ code: 'totalScore',
|
|
|
+ name: '总分',
|
|
|
+ value: totalScore === 0 ? 0 : Number.parseFloat(Math.log2(totalScore).toString()).toFixed(2),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ code: 'totalCount',
|
|
|
+ name: '题目总数',
|
|
|
+ value: totalCount.value,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ code: 'rightCount',
|
|
|
+ name: '总正确数',
|
|
|
+ value: rightCount.value,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ GameAPI.add(gameData).then(() => {
|
|
|
+ showSuccessToast('本次训练已结束')
|
|
|
+ setTimeout(() => {
|
|
|
+ router.go(-1)
|
|
|
+ }, 1300)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const temp = sessionStorage.getItem('subjectInfo')
|
|
|
+ if (temp) {
|
|
|
+ subjectInfo.value = JSON.parse(temp)
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <section class="app-container">
|
|
|
+ <van-nav-bar class="self-nav-bar" :title="subjectInfo.name" left-arrow @click-left="router.go(-1)" />
|
|
|
+ <count-down v-if="showCountDown" :time="5" color="white" @end-count-down="endCountDown" />
|
|
|
+ <div v-else style="" class="w-[90%] mx-auto mt-[15px] p-[15px] border-6 border-white border-solid rounded-[8px] bg-[#425363]">
|
|
|
+ <div class="h-[80px] flex flex-row justify-center items-center bg-[#D2E2F1] rounded-[8px]">
|
|
|
+ <span class="text-[40px] text-[#222222]">{{ showSpanText }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-row justify-between mt-[24px]">
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(1)">
|
|
|
+ <span class="text-[32px] text-[#222222]">1</span>
|
|
|
+ </div>
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(2)">
|
|
|
+ <span class="text-[32px] text-[#222222]">2</span>
|
|
|
+ </div>
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(3)">
|
|
|
+ <span class="text-[32px] text-[#222222]">3</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-row justify-between mt-[24px]">
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(4)">
|
|
|
+ <span class="text-[32px] text-[#222222]">4</span>
|
|
|
+ </div>
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(5)">
|
|
|
+ <span class="text-[32px] text-[#222222]">5</span>
|
|
|
+ </div>
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(6)">
|
|
|
+ <span class="text-[32px] text-[#222222]">6</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-row justify-between mt-[24px]">
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(7)">
|
|
|
+ <span class="text-[32px] text-[#222222]">7</span>
|
|
|
+ </div>
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(8)">
|
|
|
+ <span class="text-[32px] text-[#222222]">8</span>
|
|
|
+ </div>
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(9)">
|
|
|
+ <span class="text-[32px] text-[#222222]">9</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-row justify-center mt-[24px]">
|
|
|
+ <div class="w-[72px] h-[72px] flex flex-row justify-center items-center bg-white rounded-[8px]" @click="userClick(0)">
|
|
|
+ <span class="text-[32px] text-[#222222]">0</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+.app-container {
|
|
|
+ background-image: url('/static/image/game/bg-continue-addition.png');
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-position: center center;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+
|
|
|
+ :deep(.van-nav-bar) {
|
|
|
+ &.self-nav-bar {
|
|
|
+ .van-nav-bar__title {
|
|
|
+ color: #ffffff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .van-icon {
|
|
|
+ color: #ffffff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|