Browse Source

工作记忆修复

周玉佂 2 weeks ago
parent
commit
532716c87a
27 changed files with 2676 additions and 451 deletions
  1. 3 2
      .env.development
  2. BIN
      public/static/image/game/WorkingMemory/A.png
  3. BIN
      public/static/image/game/WorkingMemory/E.png
  4. BIN
      public/static/image/game/WorkingMemory/H.png
  5. BIN
      public/static/image/game/WorkingMemory/J.png
  6. BIN
      public/static/image/game/WorkingMemory/M.png
  7. BIN
      public/static/image/game/WorkingMemory/P.png
  8. BIN
      public/static/image/game/WorkingMemory/T.png
  9. BIN
      public/static/image/game/WorkingMemory/U.png
  10. BIN
      public/static/image/game/WorkingMemory/中上.png
  11. BIN
      public/static/image/game/WorkingMemory/中下.png
  12. BIN
      public/static/image/game/WorkingMemory/右上.png
  13. BIN
      public/static/image/game/WorkingMemory/右下.png
  14. BIN
      public/static/image/game/WorkingMemory/右中.png
  15. BIN
      public/static/image/game/WorkingMemory/左上.png
  16. BIN
      public/static/image/game/WorkingMemory/左下.png
  17. BIN
      public/static/image/game/WorkingMemory/左中.png
  18. 2 0
      src/types/components.d.ts
  19. 27 1
      src/views/dashboard/index.vue
  20. 578 0
      src/views/gameCenter/components/games/WorkingMemory/components/ability/index.vue
  21. 104 0
      src/views/gameCenter/components/games/WorkingMemory/components/ability/topics.json
  22. 579 0
      src/views/gameCenter/components/games/WorkingMemory/components/blend/index.vue
  23. 104 0
      src/views/gameCenter/components/games/WorkingMemory/components/blend/topics.json
  24. 613 447
      src/views/gameCenter/components/games/WorkingMemory/index.vue
  25. 557 0
      src/views/gameCenter/components/games/WorkingMemory/index.vue.bak
  26. 104 0
      src/views/gameCenter/components/games/WorkingMemory/topics.json
  27. 5 1
      src/views/information/manage/doc.vue

+ 3 - 2
.env.development

@@ -2,8 +2,8 @@
 VITE_NODE_ENV = 'development'
 
 # 应用端口
+#VITE_APP_PORT = 3000
 VITE_APP_PORT = 3000
-# VITE_APP_PORT = 5588
 
 # 代理前缀
 VITE_APP_BASE_API = '/dev-api'
@@ -12,7 +12,8 @@ VITE_APP_BASE_API = '/dev-api'
 # VITE_APP_API_URL = 'http://192.168.0.21:8001'
 
 # 公司本地
-VITE_APP_API_URL = 'http://192.168.1.5:8107'
+# VITE_APP_API_URL = 'http://192.168.1.5:8107'
+VITE_APP_API_URL = 'http://192.168.1.4:8107'
 
 # 家里本地
 # VITE_APP_API_URL = 'http://192.168.1.3:8107'

BIN
public/static/image/game/WorkingMemory/A.png


BIN
public/static/image/game/WorkingMemory/E.png


BIN
public/static/image/game/WorkingMemory/H.png


BIN
public/static/image/game/WorkingMemory/J.png


BIN
public/static/image/game/WorkingMemory/M.png


BIN
public/static/image/game/WorkingMemory/P.png


BIN
public/static/image/game/WorkingMemory/T.png


BIN
public/static/image/game/WorkingMemory/U.png


BIN
public/static/image/game/WorkingMemory/中上.png


BIN
public/static/image/game/WorkingMemory/中下.png


BIN
public/static/image/game/WorkingMemory/右上.png


BIN
public/static/image/game/WorkingMemory/右下.png


BIN
public/static/image/game/WorkingMemory/右中.png


BIN
public/static/image/game/WorkingMemory/左上.png


BIN
public/static/image/game/WorkingMemory/左下.png


BIN
public/static/image/game/WorkingMemory/左中.png


+ 2 - 0
src/types/components.d.ts

@@ -73,6 +73,8 @@ declare module 'vue' {
     LayoutSelect: (typeof import('./../layout/components/Settings/components/LayoutSelect.vue'))['default']
     LogicalReasoning: (typeof import('./../views/gameCenter/components/games/LogicalReasoning/index.vue'))['default']
     NumMdel: (typeof import('./../views/gameCenter/components/games/LogicalReasoning/components/numMdel/index.vue'))['default']
+    Ability: (typeof import('@/views/gameCenter/components/games/WorkingMemory/components/ability/index.vue'))['default']
+    Blend: (typeof import('@/views/gameCenter/components/games/WorkingMemory/components/blend/index.vue'))['default']
     Login: (typeof import('./../views/login/components/login/index.vue'))['default']
     MessageItem: (typeof import('./../components/Chat/MessageItem/index.vue'))['default']
     MultiUpload: (typeof import('./../components/Upload/MultiUpload.vue'))['default']

+ 27 - 1
src/views/dashboard/index.vue

@@ -128,7 +128,33 @@
     <!--    </el-row>-->
   </div>
   <div v-else>
-    <h1>{{ greetings }}</h1>
+    <el-card shadow="never">
+      <el-row justify="space-between">
+        <el-col :span="18" :xs="24">
+          <div class="flex h-full items-center">
+            <img class="w-[80px] h-[80px] mr-[20px] rounded-full" :src="userStore.user.avatar" />
+            <div>
+              <p class="text-[14px]">{{ greetings }}</p>
+              <p class="text-[16px] line-height-[18px] text-gray">今日天气晴朗,气温在15℃至25℃之间,东南风。</p>
+            </div>
+          </div>
+        </el-col>
+
+        <el-col :span="6" :xs="24">
+          <div class="flex h-full items-center justify-around">
+            <el-statistic v-for="item in statisticData" :key="item.key" :value="item.value">
+              <template #title>
+                <div class="flex items-center">
+                  <svg-icon :icon-class="item.iconClass" size="20px" />
+                  <span class="text-[16px] ml-[4px]">{{ item.title }}</span>
+                </div>
+              </template>
+              <template v-if="item.suffix" #suffix>/100</template>
+            </el-statistic>
+          </div>
+        </el-col>
+      </el-row>
+    </el-card>
   </div>
 </template>
 

+ 578 - 0
src/views/gameCenter/components/games/WorkingMemory/components/ability/index.vue

@@ -0,0 +1,578 @@
+<template>
+  <!--  <ResidualDialog ref="openDialogRef" close-color="#F00" @close-dialog="handleClose">-->
+  <!--  <div class="breadth-training-container w-full h-full flex flex-col items-center relative">-->
+  <div
+    class="child-container bor-radius-8 bg-[#ffffff] w-[1960px] h-[960px] mt-[100px] flex flex-col justify-center items-center gap-y-[30px]"
+  >
+    <div id="myButton" class="absolute top-[350px]">
+      <div class="bg-1" v-if="divShow && !showAdd">
+        <img :src="onceData.question" alt="question" class="w-[460px] h-[460px]" />
+      </div>
+    </div>
+  </div>
+  <!--  </div>-->
+  <voice-imp ref="VoiceImpRef" />
+  <!--  </ResidualDialog>-->
+</template>
+
+<script setup lang="ts">
+import { getCurrentInstance, onMounted, ref } from 'vue'
+// 游戏所有等级和试次的图片数据
+import Topics from './topics.json'
+import AchievementAPI from '@/api/tester/rehabilitation/training/achievement'
+import { RTPlanMgrQuery } from '@/api/tester/rehabilitation/training/plain'
+import { useUserStore } from '@/store'
+
+const $emits = defineEmits(['gameOver'])
+
+interface LevelData {
+  level: number
+  correct: boolean
+  score: number
+  responseStartTime: number
+  responseEndTime: number
+}
+
+interface OnceItem {
+  question: string
+  choices: string[]
+  answer: string
+}
+
+const openDialogRef = ref()
+const VoiceImpRef = ref()
+const gameData = ref(Topics as OnceItem[][])
+// 当前试次的游戏图片数据
+const onceData = ref({} as OnceItem)
+const countDownVisible = ref(false) // 倒计时是否可见
+const fistOpen = ref(true) // 第一屏
+const flage1 = ref(true) // 视觉模式选项
+const flage2 = ref(false) // 听觉模式选项
+const flage3 = ref(false) // 混合模式选项
+const next_stepFlag1 = ref(false) // 图片游戏开始
+const next_stepFlag2 = ref(false) // 数字模式开始
+// const next_stepflag = ref(true) // 第二屏
+const countDownVal = ref(560) // 倒计时时间
+const showAdd = ref(false)
+const divShow = ref(true)
+
+// 得分列表
+const scoreList = [10, 30, 60, 100, 150, 210]
+// 在60秒内猜中50个物品额外得50分
+const extraScore = 50
+// 最大游戏等级 6
+const maxLevel = 0
+// 当前游戏等级
+let currentLevel = 0
+// 游戏最大时长 60 秒
+const gameMaxDuration = 60 * 1000
+// 游戏开始时间
+let gameStartTime = 0
+// 游戏结束时间
+let gameEndTime = 0
+// 游戏收集的数据
+let gameList: LevelData[] = []
+// 游戏模式:'1' 呈现轮廓,选择彩色物品、'2' 呈现彩色物品,选择轮廓
+const gameMode = '1'
+// 每个等级的最大试次 15
+const maxNumber = 9
+// 当前试次
+let currentNumber = 0
+// 响应开始时间戳
+let responseStartTime = 0
+
+let timerId: any
+let divShowInteval: any
+let gameStartTime_record = 0
+
+const planInfo = ref<RTPlanMgrQuery>()
+const instance = getCurrentInstance()
+const userStore = useUserStore()
+const setTimetiming = () => {
+  let elapsedSeconds = 0
+  function startTimer() {
+    timerId = setInterval(() => {
+      elapsedSeconds++
+      if (elapsedSeconds > 1) {
+        // executeMethod()
+        elapsedSeconds = 0
+        showAdd.value = true
+        nextOnce()
+      }
+    }, 1000)
+    // if (elapsedSeconds >= 60) {
+    //   clearInterval(timerId)
+    //   elapsedSeconds = 0
+    //   return
+    // }
+  }
+  // divShow.value = true
+  startTimer()
+}
+// 随机排列数组
+function shuffleArray(array: any) {
+  const newArray = [...array]
+  for (let i = newArray.length - 1; i > 0; i--) {
+    const j = Math.floor(Math.random() * (i + 1))
+    ;[newArray[i], newArray[j]] = [newArray[j], newArray[i]]
+  }
+  return newArray
+}
+const chengFlagek = () => {
+  console.log('开始')
+  if (flage1.value) {
+    setTimetiming()
+    next_stepFlag1.value = true
+    next_stepFlag2.value = false
+    fistOpen.value = false
+    countDownVisible.value = true
+  } else if (flage2.value) {
+    fistOpen.value = false
+    next_stepFlag2.value = true
+    next_stepFlag1.value = false
+    // countDownVisible.value = true
+  } else {
+  }
+}
+const chengFlage1 = (answer: string) => {
+  console.log('haaahaha', answer)
+  if (answer === '1') {
+    // flage1.value = false
+    // flage2.value = true
+    // flage3.value = true
+  } else if (answer === '2') {
+    flage1.value = true
+    flage2.value = false
+    flage3.value = false
+  } else if (answer === '3') {
+    // flage2.value = false
+    // flage1.value = true
+    // flage3.value = true
+  } else if (answer === '4') {
+    flage2.value = true
+    flage1.value = false
+    flage3.value = false
+  } else if (answer === '5') {
+    // flage2.value = true
+    // flage1.value = true
+    // flage3.value = false
+  } else if (answer === '6') {
+    flage2.value = false
+    flage1.value = false
+    flage3.value = true
+  }
+}
+const nextOnce = () => {
+  console.log(onceData.value.choices, 'onceData392')
+  // console.log(showAdd.value, divShow.value)
+  // const a = document.getElementById('countdown');
+  // dingshqi()
+  gameEndTime = performance.now()
+  const gameDuration = gameEndTime - gameStartTime
+  // console.log(gameDuration, 'gameDuration')
+  // console.log(gameEndTime, 'gameEndTime')
+  // console.log(gameStartTime, 'gameStartTime')
+  const currentLevelList = gameList.filter((it) => it.level === currentLevel)
+  // 当前等级进行 10 个试次以上时,计算正确率
+  if (currentLevelList.length >= 10) {
+    // 当前等级正确试次个数
+    const count = currentLevelList.reduce((acc, curr) => {
+      if (curr.correct) {
+        acc++
+      }
+      return acc
+    }, 0)
+
+    // 当前等级正确率
+    const accuracy = (count / currentLevelList.length) * 100
+
+    // 升降级规则:正确率达到80%难度升级,低于40%降级
+    if (accuracy >= 80) {
+      if (currentLevel < maxLevel) {
+        currentLevel++
+        // 删除升级之后的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        // 重置当前等级试次索引
+        currentNumber = 0
+        console.log('80%难度升级')
+      }
+    } else if (accuracy < 40) {
+      if (currentLevel > 0) {
+        // 删除降级之前的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        currentLevel--
+        // 删除降级之后的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        // 重置当前等级试次索引
+        currentNumber = 0
+        console.log('低于40%降级')
+      }
+    }
+  }
+
+  // 如果当前等级的试次小于最大试次,则试次加一,否则应该进入下一等级
+  if (currentNumber < maxNumber) {
+    currentNumber++
+  } else {
+    // 如果当前等级小于最大等级,则等级加一,否则游戏结束
+    if (currentLevel < maxLevel) {
+      currentLevel++
+      // 删除升级之后的已有数据
+      gameList = gameList.filter((it) => it.level !== currentLevel)
+      // 重置当前等级试次索引
+      currentNumber = 0
+    } else {
+      // 游戏结束
+      console.log('游戏结束2')
+      clearInterval(timerId)
+      clearInterval(divShowInteval)
+      // sendData()
+      return
+    }
+  }
+  divShow.value = true
+  setTimeout(() => {
+    showAdd.value = false
+  }, 1000)
+
+  // 根据当前等级和当前试次改变游戏素材
+  setOnceData()
+}
+
+function getTime() {
+  const countdownElement = document.getElementById('countdown')
+  let remainingSeconds = 60
+
+  function updateCountdown() {
+    countdownElement ? (countdownElement.textContent = '00分' + remainingSeconds + '秒') : ''
+    if (remainingSeconds % 5 === 0) {
+      // nextOnce()
+    }
+    remainingSeconds--
+    if (remainingSeconds < 0) {
+      clearInterval(countdownInterval)
+      // countdownElement.textContent = '倒计时结束';
+    }
+  }
+
+  const countdownInterval = setInterval(updateCountdown, 1000)
+}
+
+const submitFn = () => {
+  console.log('------------------------')
+  sendData()
+}
+
+const setOnceData = () => {
+  responseStartTime = performance.now()
+  // console.log(currentNumber, 'currentNumber')
+  onceData.value = gameData.value[currentLevel][currentNumber]
+  //     timerId = setInterval(() => {
+  //       elapsedSeconds++
+  //       if (elapsedSeconds > 3) {
+  //         executeMethod()
+  //         elapsedSeconds = 0
+  //       }
+  //     }, 1000)
+  // divShow.value = true
+  //
+  // divShowInteval = setInterval(() => {
+  //   showAdd.value = true
+  //   nextOnce()
+  // }, 2000)
+  // onceData.value.choices = shuffleArray(onceData.value.choices)
+}
+
+const handleClick = (answer: string) => {
+  const correct = onceData.value.answer === answer
+  VoiceImpRef.value.videoPlay('click')
+  setTimeout(() => {
+    if (correct) {
+      console.log(VoiceImpRef.value, 'hbbbbbbbbbbbbbbbbbbbbbbbbbdf=============>')
+
+      VoiceImpRef.value.videoPlay('right')
+    } else {
+      VoiceImpRef.value.videoPlay('error')
+    }
+  }, 200)
+  // 收集当前试次的用户操作数据
+  gameList.push({
+    level: currentLevel,
+    correct: correct,
+    score: correct ? scoreList[currentLevel] : 0,
+    responseEndTime: performance.now(),
+    responseStartTime: responseStartTime
+  })
+  console.log(gameList)
+
+  // 开始下一次
+  nextOnce()
+}
+
+// 发送请求
+const sendData = () => {
+  if (planInfo.value) {
+    // 计算正确反应数和总反应时
+    let { correctCount, totalResponseTime, totalScore } = gameList.reduce(
+      (obj, curr) => {
+        if (curr.correct) {
+          obj.correctCount++
+        }
+        obj.totalScore += curr.score
+        obj.totalResponseTime += curr.responseEndTime - curr.responseStartTime
+        return obj
+      },
+      { correctCount: 0, totalResponseTime: 0, totalScore: 0 }
+    )
+
+    // 平均反应时 = 总反应时 / 总试次
+    const avrResponseTime = `${(totalResponseTime / gameList.length).toFixed(2)}ms`
+
+    // 如果在60秒内猜中50个物品得30分
+    if (correctCount >= 50) {
+      totalScore += 50
+    }
+
+    const { gameId, gameName, id: planId } = planInfo.value
+    const data = {
+      finish: '1',
+      gameId,
+      gameName,
+      paramList: [
+        {
+          code: 'score',
+          name: '得分',
+          value: totalScore
+        },
+        {
+          code: 'correctCount',
+          name: '正确反应数',
+          value: correctCount
+        },
+        {
+          code: 'avrResponseTime',
+          name: '平均反应时',
+          value: avrResponseTime
+        },
+        {
+          code: 'avrResponseTime',
+          name: '最大难度',
+          value: currentLevel + 1
+        },
+        {
+          code: 'gameTotalTime',
+          name: '游戏总时长',
+          value: (Date.now() - gameStartTime_record) / 1000
+        }
+      ],
+      planId,
+      gamelevel: currentLevel + 1,
+      score: totalScore,
+      userId: userStore.user.id,
+      gameTotalTime: Date.now() - gameStartTime_record
+    }
+
+    console.log('发送数据', data)
+
+    AchievementAPI.add(data).then(() => {
+      ElMessage.success('本次训练已结束')
+      clearInterval(timerId)
+
+      handleClose(() => {})
+
+      instance?.proxy?.$Bus.emit('trainList-refresh')
+    })
+  } else {
+    ElMessage.success('本次训练已结束')
+    clearInterval(timerId)
+
+    handleClose(() => {})
+    instance?.proxy?.$Bus.emit('trainList-refresh')
+  }
+}
+
+const handleClose = (done: () => void) => {
+  clearInterval(timerId)
+  $emits('gameOver', 'WorkingMemory')
+}
+
+async function exec() {
+  // openDialogRef.value.openDialog()
+  gameStartTime_record = Date.now()
+  let tempPlan = sessionStorage.getItem('currentPlanInfo')
+  // console.log(onceData.value,'onceData392');
+
+  // onceData.choices = shuffleArray(onceData.choices)
+  if (tempPlan) {
+    planInfo.value = JSON.parse(tempPlan)
+  }
+  // 记录游戏开始时间戳
+  gameStartTime = performance.now()
+  // 重置游戏结束时间戳
+  gameEndTime = 0
+  // 重置当前等级
+  currentLevel = 0
+  // 重置当前试次
+  currentNumber = 0
+  // 清空游戏数据
+  gameList = []
+  // 设置第一个试次的游戏素材
+  setOnceData()
+}
+onMounted(() => {
+  exec()
+  nextTick(() => {
+    countDownVisible.value = true
+    setTimetiming()
+    // console.log(onceData.value.choices, 'onceData392')
+    // onceData.value = shuffleArray(onceData.value)
+    // onceData.value.choices = shuffleArray(onceData.value.choices)
+    // countDownVisible.value = true
+    // 倒计时
+    // getTime()
+    // setTimetiming()
+  })
+})
+watchEffect(() => {
+  // console.log(onceData.value.choices, 'onceData.value.choices')
+  // onceData.value.choices = shuffleArray(onceData.value.choices)
+})
+onUnmounted(() => {
+  clearInterval(timerId)
+})
+</script>
+
+<style scoped lang="scss">
+// .object-recognition-containers {
+//   background-color: #eff2f4;
+// }
+.breadth-training-container {
+  //background-color: #f5f4e9;
+  //background-color: #2bae68;
+  background-image: url('/static/image/game/bg-WorkMemory.png');
+  background-size: 100% 100%;
+  background-position: center center;
+
+  :deep(.el-progress-bar__outer) {
+    background-color: rgba(0, 0, 0, 0.1);
+  }
+
+  .choice-div {
+    &:hover {
+      box-shadow: 0 0 8px 1px rgba(255, 255, 255, 0.7);
+    }
+  }
+  .center-bg-1 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-1.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-2 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-2.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-3 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-3.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-4 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-4.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-k {
+    background-image: url('/static/image/game/LogicalReasoning/bg-k.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .buttonFist {
+    position: absolute;
+    bottom: 150px;
+    font-size: 88px;
+    width: 540px;
+    height: 180px;
+    border-radius: 18px;
+
+    &:hover {
+      background-color: transparent;
+    }
+
+    &.next {
+      background-image: url('/static/image/game/ResidueRecognition/btn-next.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      border-color: transparent;
+    }
+
+    &.start {
+      background-image: url('/static/image/game/ResidueRecognition/btn-start.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      border-color: transparent;
+    }
+  }
+
+  .bg-1 {
+    // margin-top: 20px;
+    // position: absolute;
+    // top: 80px;
+    background-image: url('/static/image/game/ResidueRecognition/bg-2.png');
+    background-size: 100% 100%;
+    background-position: center center;
+  }
+
+  .bg-2a {
+    cursor: pointer;
+    transition: All 0.4s ease-in-out; //设置动画执行的时间为0.6s
+
+    :hover {
+      transform: scale(1.1);
+    }
+
+    .bg-2 {
+      background-image: url('/static/image/game/ResidueRecognition/bg-3.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      padding: 50px;
+    }
+  }
+}
+
+.first-pass {
+  width: 400px;
+  height: 100px;
+  background-image: url('/static/image/game/ResidueRecognition/bg-4.png');
+  background-size: 100% 100%;
+  background-position: center center;
+  position: absolute;
+  font-size: 58px;
+  top: 130px;
+  left: 240px;
+  text-align: center;
+  font-weight: normal;
+  font-size: 39px;
+  color: #ffffff;
+  line-height: 100px;
+  text-shadow: 0px 4px 8px rgba(1, 54, 142, 0.53);
+
+  .first-pass-1 {
+    width: 182px;
+    height: 37px;
+    text-align: center;
+    margin-left: -40px;
+    margin-top: 20px;
+    // font-family: Alibaba PuHuiTi 2.0;
+    font-weight: normal;
+    font-size: 39px;
+    color: #a76202;
+    // line-height: 100px;
+  }
+}
+</style>

+ 104 - 0
src/views/gameCenter/components/games/WorkingMemory/components/ability/topics.json

@@ -0,0 +1,104 @@
+[
+  [
+    {
+      "question": "/static/image/game/WorkingMemory/A.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/E.png",
+        "/static/image/game/WorkingMemory/中下.png",
+        "/static/image/game/WorkingMemory/右上.png",
+        "/static/image/game/WorkingMemory/右下.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/H.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/H.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/H.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/E.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/A.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/J.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/J.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/M.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/M.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/P.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/P.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/A.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/T.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/U.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/U.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/A.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/A.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/E.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/E.png"
+    }
+  ]
+]

+ 579 - 0
src/views/gameCenter/components/games/WorkingMemory/components/blend/index.vue

@@ -0,0 +1,579 @@
+<template>
+  <!--  <ResidualDialog ref="openDialogRef" close-color="#F00" @close-dialog="handleClose">-->
+  <!--  <div class="breadth-training-container w-full h-full flex flex-col items-center relative">-->
+  <div
+    class="child-container bor-radius-8 bg-[#ffffff] w-[1960px] h-[960px] mt-[100px] flex flex-col justify-center items-center gap-y-[30px]"
+  >
+    <div id="myButton" class="absolute top-[350px]">
+      <div class="bg-1" v-if="divShow && !showAdd">
+        <img :src="onceData.question" alt="question" class="w-[460px] h-[460px]" />
+      </div>
+    </div>
+  </div>
+  <!--  </div>-->
+  <voice-imp ref="VoiceImpRef" />
+  <!--  </ResidualDialog>-->
+</template>
+
+<script setup lang="ts">
+import { getCurrentInstance, onMounted, ref } from 'vue'
+// 游戏所有等级和试次的图片数据
+import Topics from './topics.json'
+import AchievementAPI from '@/api/tester/rehabilitation/training/achievement'
+import { RTPlanMgrQuery } from '@/api/tester/rehabilitation/training/plain'
+import { useUserStore } from '@/store'
+
+const $emits = defineEmits(['gameOver'])
+
+interface LevelData {
+  level: number
+  correct: boolean
+  score: number
+  responseStartTime: number
+  responseEndTime: number
+}
+
+interface OnceItem {
+  question: string
+  choices: string[]
+  answer: string
+}
+
+const openDialogRef = ref()
+const VoiceImpRef = ref()
+const gameData = ref(Topics as OnceItem[][])
+// 当前试次的游戏图片数据
+const onceData = ref({} as OnceItem)
+const countDownVisible = ref(false) // 倒计时是否可见
+const fistOpen = ref(true) // 第一屏
+const flage1 = ref(true) // 视觉模式选项
+const flage2 = ref(false) // 听觉模式选项
+const flage3 = ref(false) // 混合模式选项
+const next_stepFlag1 = ref(false) // 图片游戏开始
+const next_stepFlag2 = ref(false) // 数字模式开始
+// const next_stepflag = ref(true) // 第二屏
+const countDownVal = ref(560) // 倒计时时间
+const showAdd = ref(false)
+const divShow = ref(true)
+
+// 得分列表
+const scoreList = [10, 30, 60, 100, 150, 210]
+// 在60秒内猜中50个物品额外得50分
+const extraScore = 50
+// 最大游戏等级 6
+const maxLevel = 0
+// 当前游戏等级
+let currentLevel = 0
+// 游戏最大时长 60 秒
+const gameMaxDuration = 60 * 1000
+// 游戏开始时间
+let gameStartTime = 0
+// 游戏结束时间
+let gameEndTime = 0
+// 游戏收集的数据
+let gameList: LevelData[] = []
+// 游戏模式:'1' 呈现轮廓,选择彩色物品、'2' 呈现彩色物品,选择轮廓
+const gameMode = '1'
+// 每个等级的最大试次 15
+const maxNumber = 9
+// 当前试次
+let currentNumber = 0
+// 响应开始时间戳
+let responseStartTime = 0
+
+let timerId: any
+let divShowInteval: any
+let gameStartTime_record = 0
+
+const planInfo = ref<RTPlanMgrQuery>()
+const instance = getCurrentInstance()
+const userStore = useUserStore()
+const setTimetiming = () => {
+  let elapsedSeconds = 0
+  function startTimer() {
+    timerId = setInterval(() => {
+      elapsedSeconds++
+      if (elapsedSeconds > 1) {
+        // executeMethod()
+        elapsedSeconds = 0
+        showAdd.value = true
+        nextOnce()
+      }
+    }, 1000)
+    // if (elapsedSeconds >= 60) {
+    //   clearInterval(timerId)
+    //   elapsedSeconds = 0
+    //   return
+    // }
+  }
+  // divShow.value = true
+  startTimer()
+}
+// 随机排列数组
+function shuffleArray(array: any) {
+  const newArray = [...array]
+  for (let i = newArray.length - 1; i > 0; i--) {
+    const j = Math.floor(Math.random() * (i + 1))
+    ;[newArray[i], newArray[j]] = [newArray[j], newArray[i]]
+  }
+  return newArray
+}
+
+const chengFlagek = () => {
+  console.log('开始')
+  if (flage1.value) {
+    setTimetiming()
+    next_stepFlag1.value = true
+    next_stepFlag2.value = false
+    fistOpen.value = false
+    countDownVisible.value = true
+  } else if (flage2.value) {
+    fistOpen.value = false
+    next_stepFlag2.value = true
+    next_stepFlag1.value = false
+    // countDownVisible.value = true
+  } else {
+  }
+}
+const chengFlage1 = (answer: string) => {
+  console.log('haaahaha', answer)
+  if (answer === '1') {
+    // flage1.value = false
+    // flage2.value = true
+    // flage3.value = true
+  } else if (answer === '2') {
+    flage1.value = true
+    flage2.value = false
+    flage3.value = false
+  } else if (answer === '3') {
+    // flage2.value = false
+    // flage1.value = true
+    // flage3.value = true
+  } else if (answer === '4') {
+    flage2.value = true
+    flage1.value = false
+    flage3.value = false
+  } else if (answer === '5') {
+    // flage2.value = true
+    // flage1.value = true
+    // flage3.value = false
+  } else if (answer === '6') {
+    flage2.value = false
+    flage1.value = false
+    flage3.value = true
+  }
+}
+const nextOnce = () => {
+  console.log(onceData.value.choices, 'onceData392')
+  // console.log(showAdd.value, divShow.value)
+  // const a = document.getElementById('countdown');
+  // dingshqi()
+  gameEndTime = performance.now()
+  const gameDuration = gameEndTime - gameStartTime
+  // console.log(gameDuration, 'gameDuration')
+  // console.log(gameEndTime, 'gameEndTime')
+  // console.log(gameStartTime, 'gameStartTime')
+  const currentLevelList = gameList.filter((it) => it.level === currentLevel)
+  // 当前等级进行 10 个试次以上时,计算正确率
+  if (currentLevelList.length >= 10) {
+    // 当前等级正确试次个数
+    const count = currentLevelList.reduce((acc, curr) => {
+      if (curr.correct) {
+        acc++
+      }
+      return acc
+    }, 0)
+
+    // 当前等级正确率
+    const accuracy = (count / currentLevelList.length) * 100
+
+    // 升降级规则:正确率达到80%难度升级,低于40%降级
+    if (accuracy >= 80) {
+      if (currentLevel < maxLevel) {
+        currentLevel++
+        // 删除升级之后的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        // 重置当前等级试次索引
+        currentNumber = 0
+        console.log('80%难度升级')
+      }
+    } else if (accuracy < 40) {
+      if (currentLevel > 0) {
+        // 删除降级之前的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        currentLevel--
+        // 删除降级之后的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        // 重置当前等级试次索引
+        currentNumber = 0
+        console.log('低于40%降级')
+      }
+    }
+  }
+
+  // 如果当前等级的试次小于最大试次,则试次加一,否则应该进入下一等级
+  if (currentNumber < maxNumber) {
+    currentNumber++
+  } else {
+    // 如果当前等级小于最大等级,则等级加一,否则游戏结束
+    if (currentLevel < maxLevel) {
+      currentLevel++
+      // 删除升级之后的已有数据
+      gameList = gameList.filter((it) => it.level !== currentLevel)
+      // 重置当前等级试次索引
+      currentNumber = 0
+    } else {
+      // 游戏结束
+      console.log('游戏结束2')
+      clearInterval(timerId)
+      clearInterval(divShowInteval)
+      // sendData()
+      return
+    }
+  }
+  divShow.value = true
+  setTimeout(() => {
+    showAdd.value = false
+  }, 1000)
+
+  // 根据当前等级和当前试次改变游戏素材
+  setOnceData()
+}
+
+function getTime() {
+  const countdownElement = document.getElementById('countdown')
+  let remainingSeconds = 60
+
+  function updateCountdown() {
+    countdownElement ? (countdownElement.textContent = '00分' + remainingSeconds + '秒') : ''
+    if (remainingSeconds % 5 === 0) {
+      // nextOnce()
+    }
+    remainingSeconds--
+    if (remainingSeconds < 0) {
+      clearInterval(countdownInterval)
+      // countdownElement.textContent = '倒计时结束';
+    }
+  }
+
+  const countdownInterval = setInterval(updateCountdown, 1000)
+}
+
+const submitFn = () => {
+  console.log('------------------------')
+  sendData()
+}
+
+const setOnceData = () => {
+  responseStartTime = performance.now()
+  // console.log(currentNumber, 'currentNumber')
+  onceData.value = gameData.value[currentLevel][currentNumber]
+  //     timerId = setInterval(() => {
+  //       elapsedSeconds++
+  //       if (elapsedSeconds > 3) {
+  //         executeMethod()
+  //         elapsedSeconds = 0
+  //       }
+  //     }, 1000)
+  // divShow.value = true
+  //
+  // divShowInteval = setInterval(() => {
+  //   showAdd.value = true
+  //   nextOnce()
+  // }, 2000)
+  // onceData.value.choices = shuffleArray(onceData.value.choices)
+}
+
+const handleClick = (answer: string) => {
+  const correct = onceData.value.answer === answer
+  VoiceImpRef.value.videoPlay('click')
+  setTimeout(() => {
+    if (correct) {
+      console.log(VoiceImpRef.value, 'hbbbbbbbbbbbbbbbbbbbbbbbbbdf=============>')
+
+      VoiceImpRef.value.videoPlay('right')
+    } else {
+      VoiceImpRef.value.videoPlay('error')
+    }
+  }, 200)
+  // 收集当前试次的用户操作数据
+  gameList.push({
+    level: currentLevel,
+    correct: correct,
+    score: correct ? scoreList[currentLevel] : 0,
+    responseEndTime: performance.now(),
+    responseStartTime: responseStartTime
+  })
+  console.log(gameList)
+
+  // 开始下一次
+  nextOnce()
+}
+
+// 发送请求
+const sendData = () => {
+  if (planInfo.value) {
+    // 计算正确反应数和总反应时
+    let { correctCount, totalResponseTime, totalScore } = gameList.reduce(
+      (obj, curr) => {
+        if (curr.correct) {
+          obj.correctCount++
+        }
+        obj.totalScore += curr.score
+        obj.totalResponseTime += curr.responseEndTime - curr.responseStartTime
+        return obj
+      },
+      { correctCount: 0, totalResponseTime: 0, totalScore: 0 }
+    )
+
+    // 平均反应时 = 总反应时 / 总试次
+    const avrResponseTime = `${(totalResponseTime / gameList.length).toFixed(2)}ms`
+
+    // 如果在60秒内猜中50个物品得30分
+    if (correctCount >= 50) {
+      totalScore += 50
+    }
+
+    const { gameId, gameName, id: planId } = planInfo.value
+    const data = {
+      finish: '1',
+      gameId,
+      gameName,
+      paramList: [
+        {
+          code: 'score',
+          name: '得分',
+          value: totalScore
+        },
+        {
+          code: 'correctCount',
+          name: '正确反应数',
+          value: correctCount
+        },
+        {
+          code: 'avrResponseTime',
+          name: '平均反应时',
+          value: avrResponseTime
+        },
+        {
+          code: 'avrResponseTime',
+          name: '最大难度',
+          value: currentLevel + 1
+        },
+        {
+          code: 'gameTotalTime',
+          name: '游戏总时长',
+          value: (Date.now() - gameStartTime_record) / 1000
+        }
+      ],
+      planId,
+      gamelevel: currentLevel + 1,
+      score: totalScore,
+      userId: userStore.user.id,
+      gameTotalTime: Date.now() - gameStartTime_record
+    }
+
+    console.log('发送数据', data)
+
+    AchievementAPI.add(data).then(() => {
+      ElMessage.success('本次训练已结束')
+      clearInterval(timerId)
+
+      handleClose(() => {})
+
+      instance?.proxy?.$Bus.emit('trainList-refresh')
+    })
+  } else {
+    ElMessage.success('本次训练已结束')
+    clearInterval(timerId)
+
+    handleClose(() => {})
+    instance?.proxy?.$Bus.emit('trainList-refresh')
+  }
+}
+
+const handleClose = (done: () => void) => {
+  clearInterval(timerId)
+  $emits('gameOver', 'WorkingMemory')
+}
+
+async function exec() {
+  // openDialogRef.value.openDialog()
+  gameStartTime_record = Date.now()
+  let tempPlan = sessionStorage.getItem('currentPlanInfo')
+  // console.log(onceData.value,'onceData392');
+
+  // onceData.choices = shuffleArray(onceData.choices)
+  if (tempPlan) {
+    planInfo.value = JSON.parse(tempPlan)
+  }
+  // 记录游戏开始时间戳
+  gameStartTime = performance.now()
+  // 重置游戏结束时间戳
+  gameEndTime = 0
+  // 重置当前等级
+  currentLevel = 0
+  // 重置当前试次
+  currentNumber = 0
+  // 清空游戏数据
+  gameList = []
+  // 设置第一个试次的游戏素材
+  setOnceData()
+}
+onMounted(() => {
+  exec()
+  nextTick(() => {
+    countDownVisible.value = true
+    setTimetiming()
+    // console.log(onceData.value.choices, 'onceData392')
+    // onceData.value = shuffleArray(onceData.value)
+    // onceData.value.choices = shuffleArray(onceData.value.choices)
+    // countDownVisible.value = true
+    // 倒计时
+    // getTime()
+    // setTimetiming()
+  })
+})
+watchEffect(() => {
+  // console.log(onceData.value.choices, 'onceData.value.choices')
+  // onceData.value.choices = shuffleArray(onceData.value.choices)
+})
+onUnmounted(() => {
+  clearInterval(timerId)
+})
+</script>
+
+<style scoped lang="scss">
+// .object-recognition-containers {
+//   background-color: #eff2f4;
+// }
+.breadth-training-container {
+  //background-color: #f5f4e9;
+  //background-color: #2bae68;
+  background-image: url('/static/image/game/bg-WorkMemory.png');
+  background-size: 100% 100%;
+  background-position: center center;
+
+  :deep(.el-progress-bar__outer) {
+    background-color: rgba(0, 0, 0, 0.1);
+  }
+
+  .choice-div {
+    &:hover {
+      box-shadow: 0 0 8px 1px rgba(255, 255, 255, 0.7);
+    }
+  }
+  .center-bg-1 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-1.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-2 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-2.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-3 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-3.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-4 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-4.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .center-bg-k {
+    background-image: url('/static/image/game/LogicalReasoning/bg-k.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
+  }
+  .buttonFist {
+    position: absolute;
+    bottom: 150px;
+    font-size: 88px;
+    width: 540px;
+    height: 180px;
+    border-radius: 18px;
+
+    &:hover {
+      background-color: transparent;
+    }
+
+    &.next {
+      background-image: url('/static/image/game/ResidueRecognition/btn-next.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      border-color: transparent;
+    }
+
+    &.start {
+      background-image: url('/static/image/game/ResidueRecognition/btn-start.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      border-color: transparent;
+    }
+  }
+
+  .bg-1 {
+    // margin-top: 20px;
+    // position: absolute;
+    // top: 80px;
+    background-image: url('/static/image/game/ResidueRecognition/bg-2.png');
+    background-size: 100% 100%;
+    background-position: center center;
+  }
+
+  .bg-2a {
+    cursor: pointer;
+    transition: All 0.4s ease-in-out; //设置动画执行的时间为0.6s
+
+    :hover {
+      transform: scale(1.1);
+    }
+
+    .bg-2 {
+      background-image: url('/static/image/game/ResidueRecognition/bg-3.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      padding: 50px;
+    }
+  }
+}
+
+.first-pass {
+  width: 400px;
+  height: 100px;
+  background-image: url('/static/image/game/ResidueRecognition/bg-4.png');
+  background-size: 100% 100%;
+  background-position: center center;
+  position: absolute;
+  font-size: 58px;
+  top: 130px;
+  left: 240px;
+  text-align: center;
+  font-weight: normal;
+  font-size: 39px;
+  color: #ffffff;
+  line-height: 100px;
+  text-shadow: 0px 4px 8px rgba(1, 54, 142, 0.53);
+
+  .first-pass-1 {
+    width: 182px;
+    height: 37px;
+    text-align: center;
+    margin-left: -40px;
+    margin-top: 20px;
+    // font-family: Alibaba PuHuiTi 2.0;
+    font-weight: normal;
+    font-size: 39px;
+    color: #a76202;
+    // line-height: 100px;
+  }
+}
+</style>

+ 104 - 0
src/views/gameCenter/components/games/WorkingMemory/components/blend/topics.json

@@ -0,0 +1,104 @@
+[
+  [
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/中上.png",
+        "/static/image/game/WorkingMemory/中下.png",
+        "/static/image/game/WorkingMemory/右上.png",
+        "/static/image/game/WorkingMemory/右下.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/右上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/左中.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/右下.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中下.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/左下.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/左上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/右上.png"
+    }
+  ]
+]

+ 613 - 447
src/views/gameCenter/components/games/WorkingMemory/index.vue

@@ -1,365 +1,478 @@
 <template>
-  <my-full-screen-dialog ref="openDialogRef" close-color="white" @close-dialog="handleClose">
-    <div class="working-memory-container w-full h-full flex-center">
+  <ResidualDialog ref="openDialogRef" close-color="#F00" @close-dialog="handleClose">
+    <div class="breadth-training-container w-full h-full flex flex-col items-center relative">
+      <!--      <div class="first-pass">-->
+      <!--        第{{ currentLevel + 1 }}关-->
+      <!--        <div-->
+      <!--          class="first-pass-1 h-[1px] absolute left-[160px] top-[120px] z-29 text-center line-height-[88px] text-[42px] text-[white] font-600"-->
+      <!--        >-->
+      <!--          <format-count-down-->
+      <!--            ref="FormatCountDownRef"-->
+      <!--            v-model:visible="countDownVisible"-->
+      <!--            :time="countDownVal"-->
+      <!--            @count-down-end="submitFn()"-->
+      <!--          />-->
+      <!--        </div>-->
+      <!--      </div>-->
       <div
-        class="w-[88%] h-[88%] border-[3px] border-white bg-[#ffffffe5] rounded-[8px] shadow-lg"
-        v-if="data.testFlag"
-        @click="userClick()"
+        class="child-container bor-radius-8 bg-[#ffffff] w-[1960px] h-[960px] mt-[100px] flex flex-col justify-center items-center gap-y-[30px]"
+        @click="handleKeyDown()"
       >
-        <div class="sable absolute left-[180px] top-[120px] Deadlock w-[1250px] h-[850px] ml-6">
-          <h1 class="sable absolute left-[400px] top-[-60px]" style="text-align: center; font-size: 80px">
-            ({{ data.nbackIndex }}-back)
-          </h1>
-          <h2
-            v-if="data.countDownSpanShow"
-            class="txt-center sable absolute left-[100px] top-[70px]"
-            style="text-align: center; font-size: 80px"
+        <div v-if="fistOpen" class="absolute left-[225px] top-[170px] color-[#111111] text-[35px]">
+          <h1>请选择游戏模式:</h1>
+        </div>
+        <div v-if="fistOpen" class="bg-2a">
+          <div
+            v-if="flage1"
+            @click="chengFlage1('1')"
+            class="absolute top-[400px] text-[46px] color-[#0097a2] left-[400px] w-[400px] h-[165px]"
+          >
+            <h1>视觉模式</h1>
+          </div>
+          <div
+            v-if="!flage1"
+            @click="chengFlage1('2')"
+            class="absolute top-[400px] text-[46px] left-[400px] w-[400px] h-[170px]"
+          >
+            <h1>视觉模式</h1>
+          </div>
+          <div
+            v-if="flage2"
+            @click="chengFlage1('3')"
+            class="absolute top-[400px] color-[#0097a2] left-[900px] text-[46px] w-[400px] h-[170px]"
+          >
+            <h1>听觉模式</h1>
+          </div>
+          <div
+            v-if="!flage2"
+            @click="chengFlage1('4')"
+            class="absolute top-[400px] text-[46px] left-[900px] w-[400px] h-[170px]"
+          >
+            <h1>听觉模式</h1>
+          </div>
+          <div
+            v-if="flage3"
+            @click="chengFlage1('5')"
+            class="absolute top-[400px] color-[#0097a2] left-[1400px] text-[46px] w-[400px] h-[170px]"
+          >
+            <h1>混合模式</h1>
+          </div>
+          <div
+            v-if="!flage3"
+            @click="chengFlage1('6')"
+            class="absolute top-[400px] text-[46px] left-[1400px] w-[400px] h-[170px]"
           >
-            将在<span style="color: red; font-size: 80px">{{ data.countDownTime }}</span
-            >秒后继续测试
-          </h2>
-          <!-- <div class="letterCss txt-center" v-if="data.divShow && !data.showAdd">
-            <div class="big-square  w-[600px] h-[600px] mt-[135px]">
-              <div class="small-square" v-for="i in 9" :key="i"></div>
-            </div>
-            {{ data.currentLetter }}
-          </div> -->
-          <div class="letterCss absolute left-[180px] txt-center" v-if="data.divShow && !data.showAdd">
-            <!--          <div class="letterCss absolute left-[180px] txt-center">-->
-            <div class="big-square w-[600px] h-[600px] mt-[135px] main">
-              <div v-show="data.smallsquare === 1" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div v-show="data.smallsquare === 2" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div v-show="data.smallsquare === 3" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div v-show="data.smallsquare === 4" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div class="w-[150px] h-[150px] m-[25px]">
-                <span style="color: #ffffff; font-size: 80px">{{ data.currentLetter }}</span>
-              </div>
-              <div v-show="data.smallsquare === 6" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div v-show="data.smallsquare === 7" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div v-show="data.smallsquare === 8" class="w-[150px] h-[150px] m-[25px]"></div>
-              <div v-show="data.smallsquare === 9" class="w-[150px] h-[150px] m-[25px]"></div>
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]">-->
-              <!--                <span style="color: #ffffff; font-size: 80px">{{ data.currentLetter }}</span>-->
-              <!--              </div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
-            </div>
+            <h1>混合模式</h1>
           </div>
+          <div
+            @click="chengFlagek"
+            class="absolute top-[700px] left-[915px] color-[#0097a2] text-[46px] w-[400px] h-[130px]"
+          >
+            <h1>开始游戏</h1>
+          </div>
+        </div>
+        <div v-if="next_stepFlag1" class="absolute color-[#] top-[180px] left-[222px]">
+          <!--          <h1 class="text-[68px]">图像匹配 :<span class="text-[36px]">找出规律并选择与其他图片不同的一张</span></h1>-->
+        </div>
+        <div v-if="next_stepFlag1" id="myButton" class="">
+          <div class="bg-1" v-if="divShow && !showAdd">
+            <img :src="onceData.question" alt="question" class="w-[460px] h-[460px]" />
+          </div>
+        </div>
+        <div v-if="next_stepFlag2" id="myButton" class="flex flex-row justify-center gap-x-[20px] mt-[340px]">
+          <ability @handle-close="handleClose" />
+        </div>
+        <div v-if="next_stepFlag3" id="myButton" class="flex flex-row justify-center gap-x-[20px] mt-[340px]">
+          <blend @handle-close="handleClose" />
         </div>
       </div>
     </div>
-    <VoiceImp ref="VoiceImpRef" />
-  </my-full-screen-dialog>
+    <voice-imp ref="VoiceImpRef" />
+  </ResidualDialog>
 </template>
 
 <script setup lang="ts">
-/*
- * 组件名: WorkingMemory
- * 组件用途: 工作记忆
- * 创建日期: 2024/9/9
- * 编写者: JutarryWu
- */
-import { getCurrentInstance } from 'vue'
-import { getRandomInt } from '@/utils'
+import { getCurrentInstance, onMounted, ref } from 'vue'
+// 游戏所有等级和试次的图片数据
+import Topics from './topics.json'
 import AchievementAPI from '@/api/tester/rehabilitation/training/achievement'
 import { RTPlanMgrQuery } from '@/api/tester/rehabilitation/training/plain'
 import { useUserStore } from '@/store'
 
-interface AnswerList {
-  [key: string]: string[]
-}
-const data = reactive({
-  countDownTime: 8,
-  countDownSpanShow: false,
-  sourceLetterList: [],
-  currentLetter: '',
-  currentLetterIndex: 0,
-  resultData: {
-    exerciseList: [],
-    examList: {
-      back0: ['M', 'B', 'M', 'G', 'M', 'C', 'K', 'V', 'M', 'E'],
-      back1: ['Y', 'K', 'Y', 'Y', 'P', 'K', 'O', 'O', 'A', 'A'],
-      back2: ['M', 'B', 'M', 'B', 'M', 'C', 'K', 'C', 'K', 'O']
-    }
-  },
-  smallsquare: 0,
-  currentLetterList: [],
-  currentLetterListA: [3, 6, 3, 7, 3, 8, 4, 7, 8, 3],
-  nbackIndex: 0,
-  taskName: 'back0',
-  testTurnCount: 0,
-  taskId: '',
-  saveFlag: false,
-  subjectInfo: '',
-  divShow: false,
-  showAdd: false,
-  buttonShow: true,
-  passTestExam: false,
-  saveSuccess: false,
-  testFlag: false,
-  testType: '练习测试',
-  buttonName: '开始练习',
-  testTypeCode: 0,
-  startMilliSeconds: 0,
-  divShowInteval: null,
-  countDownInterval: null,
-  userId: '',
-  testResult: {},
-  userAnswerList: {
-    back0: [],
-    back1: [],
-    back2: []
-  },
-  testState: false,
-  back0SuccessRate: '',
-  back1SuccessRate: '',
-  back2SuccessRate: '',
-  back0backAverageTime: '',
-  back1backAverageTime: '',
-  back2backAverageTime: '',
-  count: 0
-})
-let countDownInterval: any
-let divShowInteval: any
 const $emits = defineEmits(['gameOver'])
+
+interface LevelData {
+  level: number
+  correct: boolean
+  ifNeedClick: boolean
+  ifUserClick: boolean
+  score: number
+  responseStartTime: number
+  responseEndTime: number
+}
+
+interface OnceItem {
+  question: string
+  choices: string[]
+  answer: string
+}
+
 const openDialogRef = ref()
 const VoiceImpRef = ref()
-const handleClose = (done: () => void) => {
-  $emits('gameOver', 'WorkingMemory')
-  clearInterval(countDownInterval)
-  clearInterval(divShowInteval)
-}
+const gameData = ref(Topics as OnceItem[][])
+// 当前试次的游戏图片数据
+const onceData = ref({} as OnceItem)
+const countDownVisible = ref(false) // 倒计时是否可见
+const fistOpen = ref(true) // 第一屏
+const flage1 = ref(true) // 视觉模式选项
+const flage2 = ref(false) // 听觉模式选项
+const flage3 = ref(false) // 混合模式选项
+const next_stepFlag1 = ref(false) // 视觉游戏开始
+const next_stepFlag2 = ref(false) // 听觉模式开始
+const next_stepFlag3 = ref(false) // 混合模式开始
 
-const instance = getCurrentInstance()
-const planInfo = ref<RTPlanMgrQuery>()
-const userStore = useUserStore()
+// const next_stepflag = ref(true) // 第二屏
+const countDownVal = ref(560) // 倒计时时间
+const showAdd = ref(false)
+const divShow = ref(true)
+
+// 得分列表
+const scoreList = [10, 30, 60, 100, 150, 210]
+// 在60秒内猜中50个物品额外得50分
+const extraScore = 50
+// 最大游戏等级 6
+const maxLevel = 0
+// 当前游戏等级
+let currentLevel = 0
+// 游戏最大时长 60 秒
+const gameMaxDuration = 60 * 1000
+// 游戏开始时间
+let gameStartTime = 0
+// 游戏结束时间
+let gameEndTime = 0
+// 游戏收集的数据
+let gameList: LevelData[] = []
+// 游戏模式:'1' 呈现轮廓,选择彩色物品、'2' 呈现彩色物品,选择轮廓
+const gameMode = '1'
+// 每个等级的最大试次 15
+const maxNumber = 9
+// 当前试次
+let currentNumber = 0
+// 响应开始时间戳
+let responseStartTime = 0
+let currentLetterList = []
+let timerId: any
+let divShowInteval: any
 let gameStartTime_record = 0
 
-async function exec() {
-  openDialogRef.value.openDialog()
-  const tempPlan = sessionStorage.getItem('currentPlanInfo')
-  gameStartTime_record = Date.now()
-  if (tempPlan) {
-    planInfo.value = JSON.parse(tempPlan)
-  }
-  await nextTick(() => {
-    // countDown()
-    startTest()
-  })
+const planInfo = ref<RTPlanMgrQuery>()
+const instance = getCurrentInstance()
+const userStore = useUserStore()
+function executeMethod() {
+  // gameList.push({
+  //   level: currentLevel,
+  //   correct: false,
+  //   score: 0,
+  //   ifNeedClick: gameData.value[currentLevel][0].answer === onceData.value.question,
+  //   ifUserClick: false,
+  //   responseEndTime: performance.now(),
+  //   responseStartTime: responseStartTime
+  // })
+  nextOnce()
+  console.log('执行此方法。')
+  // createCurrentLetterList(onceData.value)
 }
-function countDown() {
-  // 测试时间倒计时
-  countDownInterval = setInterval(() => {
-    data.countDownTime--
-    if (data.countDownTime == 0) {
-      //开始测试
-      // this.startTest();
-      startTest()
-      // 清除定时器
-      clearInterval(countDownInterval)
-      data.countDownTime = 8
-      // startTest();
-      // countDown()
+function createCurrentLetterList(sourceLetterList: any) {
+  currentLetterList = []
+  for (var i = 0; i < sourceLetterList.length; i++) {
+    let tempObj = {
+      letter: sourceLetterList[i],
+      ifNeedClick: false,
+      ifUserClick: false,
+      userResponseTime: 0
     }
-  }, 1000)
+    currentLetterList.push(tempObj)
+    console.log(currentLetterList, 'currentLetterList')
+  }
 }
-function startTest() {
-  data.divShow = true
-  data.countDownSpanShow = false
-  pageDataInit()
-
-  divShowInteval = setInterval(() => {
-    data.showAdd = true
-    // data.backgroundColor = ''
-    // if (data.testTypeCode == 1) {
-    //   data.count++;
+const setTimetiming = () => {
+  let elapsedSeconds = 0
+  function startTimer() {
+    timerId = setInterval(() => {
+      elapsedSeconds++
+      if (elapsedSeconds > 1) {
+        // executeMethod()
+        elapsedSeconds = 0
+        showAdd.value = true
+        // nextOnce()
+        executeMethod()
+      }
+    }, 1000)
+    // if (elapsedSeconds >= 60) {
+    //   clearInterval(timerId)
+    //   elapsedSeconds = 0
+    //   return
     // }
-    divRandomShow()
-  }, 2000)
+  }
+  // divShow.value = true
+  startTimer()
 }
-function divRandomShow() {
-  // console.log('执行了')
-  // showRandomValue()
-  // console.log(data.currentLetterIndex, 'data.currentLetterIndex146')
-
-  if (data.currentLetterIndex == data.currentLetterList.length) {
-    // console.log('长度相等清除定时器', data.currentLetterList.length)
-    clearInterval(divShowInteval)
-    currentTurnCompute()
-  } else {
-    let tempObj = data.currentLetterList[data.currentLetterIndex]
-    data.smallsquare = data.currentLetterListA[data.currentLetterIndex]
-    // console.log(data.currentLetterList, 'data.currentLetterList');
-    // console.log(tempObj, 'tempObjdata.currentLetter', data.currentLetterIndex, '显示字母索引')
-    data.currentLetter = ''
-    setTimeout(() => {
-      data.currentLetter = tempObj.letter
-      data.startMilliSeconds = new Date().getTime()
-      data.showAdd = false
-    }, 1000)
-    data.currentLetterIndex++
+// 随机排列数组
+function shuffleArray(array: any) {
+  const newArray = [...array]
+  for (let i = newArray.length - 1; i > 0; i--) {
+    const j = Math.floor(Math.random() * (i + 1))
+    ;[newArray[i], newArray[j]] = [newArray[j], newArray[i]]
   }
+  return newArray
+}
 
-  // if (this.currentLetterIndex == this.currentLetterList.length) {
-  //       clearInterval(this.divShowInteval);
-  //       this.currentTurnCompute();
-  //     } else {
-  //       let tempObj = this.currentLetterList[this.currentLetterIndex];
-  //       this.currentLetter = tempObj.letter;
-  //       setTimeout(() => {
-  //         this.startMilliSeconds = new Date().getTime();
-  //         this.showAdd = false;
-  //       }, 1000);
-  //       this.currentLetterIndex++;
-  //     }
+const chengFlagek = () => {
+  console.log('开始')
+  if (flage1.value) {
+    setTimetiming()
+    next_stepFlag1.value = true
+    next_stepFlag2.value = false
+    next_stepFlag3.value = false
+    fistOpen.value = false
+    countDownVisible.value = true
+  } else if (flage2.value) {
+    fistOpen.value = false
+    next_stepFlag2.value = true
+    next_stepFlag1.value = false
+    next_stepFlag3.value = false
+    // countDownVisible.value = true
+  } else {
+    fistOpen.value = false
+    next_stepFlag2.value = false
+    next_stepFlag1.value = false
+    next_stepFlag3.value = true
+  }
 }
-function currentTurnCompute() {
-  //正式测试时,需要根据情况进行切换任务类型
-  //正式测试时的逻辑
-  data.divShow = false
-  data.testTurnCount++
-  data.currentLetterIndex = 0
-  // console.log(data.testTurnCount, '153', data.nbackIndex)
-  // console.log(data.userAnswerList, 'data.userAnswerList', data.currentLetterList, 'data.currentLetterList')
-  if (data.nbackIndex == 0) {
-    data.userAnswerList.back0.push(data.currentLetterList)
-
-    if (data.testTurnCount == 2) {
-      data.nbackIndex++
-      data.countDownSpanShow = true
-      data.taskName = 'back' + data.nbackIndex
-      data.testTurnCount = 0
-    }
-    data.countDownSpanShow = true
-    countDown()
-  } else if (data.nbackIndex == 1) {
-    data.userAnswerList.back1.push(data.currentLetterList)
-    if (data.testTurnCount == 2) {
-      data.nbackIndex++
-      data.countDownSpanShow = true
-      data.taskName = 'back' + data.nbackIndex
-      data.testTurnCount = 0
+const chengFlage1 = (answer: string) => {
+  console.log('haaahaha', answer)
+  if (answer === '1') {
+    // flage1.value = false
+    // flage2.value = true
+    // flage3.value = true
+  } else if (answer === '2') {
+    flage1.value = true
+    flage2.value = false
+    flage3.value = false
+  } else if (answer === '3') {
+    // flage2.value = false
+    // flage1.value = true
+    // flage3.value = true
+  } else if (answer === '4') {
+    flage2.value = true
+    flage1.value = false
+    flage3.value = false
+  } else if (answer === '5') {
+    // flage2.value = true
+    // flage1.value = true
+    // flage3.value = false
+  } else if (answer === '6') {
+    flage2.value = false
+    flage1.value = false
+    flage3.value = true
+  }
+}
+const nextOnce = () => {
+  console.log(onceData.value.choices, 'onceData392')
+  // console.log(showAdd.value, divShow.value)
+  // const a = document.getElementById('countdown');
+  // dingshqi()
+  console.log(onceData.value, onceData.value.answer)
+  // console.log(onceData, 'onceData', gameData.value[currentLevel])
+  // gameList.push({
+  //   level: currentLevel,
+  //   correct: false,
+  //   score: 0,
+  //   ifNeedClick: gameData.value[currentLevel][0].answer === onceData.value.question,
+  //   ifUserClick: false,
+  //   responseEndTime: performance.now(),
+  //   responseStartTime: responseStartTime
+  // })
+  gameEndTime = performance.now()
+  const gameDuration = gameEndTime - gameStartTime
+  // console.log(gameDuration, 'gameDuration')
+  // console.log(gameEndTime, 'gameEndTime')
+  // console.log(gameStartTime, 'gameStartTime')
+  const currentLevelList = gameList.filter((it) => it.level === currentLevel)
+  // 当前等级进行 10 个试次以上时,计算正确率
+  if (currentLevelList.length >= 10) {
+    // 当前等级正确试次个数
+    const count = currentLevelList.reduce((acc, curr) => {
+      if (curr.correct) {
+        acc++
+      }
+      return acc
+    }, 0)
+
+    // 当前等级正确率
+    const accuracy = (count / currentLevelList.length) * 100
+
+    // 升降级规则:正确率达到80%难度升级,低于40%降级
+    if (accuracy >= 80) {
+      if (currentLevel < maxLevel) {
+        currentLevel++
+        // 删除升级之后的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        // 重置当前等级试次索引
+        currentNumber = 0
+        console.log('80%难度升级')
+      }
+    } else if (accuracy < 40) {
+      if (currentLevel > 0) {
+        // 删除降级之前的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        currentLevel--
+        // 删除降级之后的已有数据
+        gameList = gameList.filter((it) => it.level !== currentLevel)
+        // 重置当前等级试次索引
+        currentNumber = 0
+        console.log('低于40%降级')
+      }
     }
-    data.countDownSpanShow = true
-    countDown()
-  } else if (data.nbackIndex == 2) {
-    data.userAnswerList.back2.push(data.currentLetterList)
-    if (data.testTurnCount == 2) {
-      data.testState = false
-      data.testFlag = false
-      //用户数据保存
-      sendData()
-      // data.userAnswerPost();
-      clearInterval(countDownInterval)
-      // this.$message({
-      //   message: "测试结束!",
-      //   type: "success",
-      // });
-      // screenfull.exit();
-      return ''
+  }
+
+  // 如果当前等级的试次小于最大试次,则试次加一,否则应该进入下一等级
+  if (currentNumber < maxNumber) {
+    currentNumber++
+  } else {
+    // 如果当前等级小于最大等级,则等级加一,否则游戏结束
+    if (currentLevel < maxLevel) {
+      currentLevel++
+      // 删除升级之后的已有数据
+      gameList = gameList.filter((it) => it.level !== currentLevel)
+      // 重置当前等级试次索引
+      currentNumber = 0
     } else {
-      data.countDownSpanShow = true
-      countDown()
+      // 游戏结束
+      console.log('游戏结束2')
+      console.log(gameList, '游戏数据')
+      clearInterval(timerId)
+      clearInterval(divShowInteval)
+      // sendData()
+      return
     }
   }
+  divShow.value = true
+  setTimeout(() => {
+    showAdd.value = false
+  }, 1000)
+
+  // 根据当前等级和当前试次改变游戏素材
+  setOnceData()
 }
-function pageDataInit() {
-  data.testFlag = true
-  // console.log('pageDataInit', 'data.testTypeCode', data.testTypeCode, 'data.taskName', data.taskName)
-  // console.log('data.resultData.examList', data.resultData.examList[data.taskName])
-  // data.sourceLetterList = data.resultData.examList[data.taskName][data.testTurnCount];
-  // console.log(data.sourceLetterList, 'data.sourceLetterList')
-  // data.currentLetterList = data.resultData.examList[data.taskName]
-  data.sourceLetterList = data.resultData.examList[data.taskName]
-  createCurrentLetterList(data.sourceLetterList)
-}
-function createCurrentLetterList(sourceLetterList: any) {
-  data.currentLetterList = []
-  for (var i = 0; i < sourceLetterList.length; i++) {
-    let tempObj = {
-      letter: sourceLetterList[i],
-      ifNeedClick: false,
-      ifUserClick: false,
-      userResponseTime: 0
+
+function getTime() {
+  const countdownElement = document.getElementById('countdown')
+  let remainingSeconds = 60
+
+  function updateCountdown() {
+    countdownElement ? (countdownElement.textContent = '00分' + remainingSeconds + '秒') : ''
+    if (remainingSeconds % 5 === 0) {
+      // nextOnce()
     }
-    if (i == 0 || i < data.nbackIndex) {
-      data.currentLetterList.push(tempObj)
-    } else {
-      if (
-        (data.sourceLetterList[i] == sourceLetterList[0] && data.nbackIndex == 0) ||
-        (data.sourceLetterList[i] == sourceLetterList[i - data.nbackIndex] && data.nbackIndex != 0)
-      ) {
-        tempObj.ifNeedClick = true
-      }
-      data.currentLetterList.push(tempObj)
+    remainingSeconds--
+    if (remainingSeconds < 0) {
+      clearInterval(countdownInterval)
+      // countdownElement.textContent = '倒计时结束';
     }
   }
-  console.log(data.currentLetterList, '.letter')
+
+  const countdownInterval = setInterval(updateCountdown, 1000)
 }
-function userClick() {
+
+const submitFn = () => {
+  console.log('------------------------')
+  sendData()
+}
+
+const setOnceData = () => {
+  responseStartTime = performance.now()
+  // console.log(currentNumber, 'currentNumber')
+  onceData.value = gameData.value[currentLevel][currentNumber]
+  console.log(currentLevel, '当前游戏等级')
+  gameList.push({
+    level: currentLevel,
+    correct: false,
+    score: 0,
+    ifNeedClick: gameData.value[currentLevel][0].answer === onceData.value.question,
+    ifUserClick: false,
+    responseEndTime: performance.now(),
+    responseStartTime: responseStartTime
+  })
+}
+
+const handleKeyDown = (event: any) => {
+  // if ()
+  console.log(event.button, '判断鼠标点击左键还是右键')
+  console.log(event.key, '判断鼠标点j还是f')
+  // console.log(currentLetterList, 'currentLetterList')
+  console.log(currentNumber, '当前试次', gameList, gameList[currentNumber])
   //用户点击动作
-  if (data.currentLetterIndex - 1 >= 0) {
-    data.currentLetterList[data.currentLetterIndex - 1].ifUserClick = true
-    data.currentLetterList[data.currentLetterIndex - 1].userResponseTime = new Date().getTime() - data.startMilliSeconds
-    // console.log(new Date().getTime() - data.startMilliSeconds)
-    // console.log(data.currentLetterList, 'currentLetterList')
+  // if (currentNumber - 1 >= 0) {
+  gameList[currentNumber].ifUserClick = true
+  // console.log(new Date().getTime() - data.startMilliSeconds)
+  // console.log(data.currentLetterList, 'currentLetterList')
+  console.log(gameList[currentNumber].ifUserClick, gameList[currentNumber].ifNeedClick, '数据收集处理')
+  // const correct = gameList[currentNumber].ifUserClick === gameList[currentNumber].ifNeedClick
+
+  if (gameList[currentNumber].ifUserClick === gameList[currentNumber].ifNeedClick) {
+    gameList[currentNumber].correct = true
   }
-  console.log(data.currentLetterList, 'currentLetterList', 312)
+  // }
+  // // VoiceImpRef.value.videoPlay('click')
+  // // setTimeout(() => {
+  // //   if (correct) {
+  // //     console.log(VoiceImpRef.value, 'hbbbbbbbbbbbbbbbbbbbbbbbbbdf=============>')
+  // //
+  // //     VoiceImpRef.value.videoPlay('right')
+  // //   } else {
+  // //     VoiceImpRef.value.videoPlay('error')
+  // //   }
+  // // }, 200)
+  // // 收集当前试次的用户操作数据
+  // // gameList.push({
+  // //   level: currentLevel,
+  // //   correct: correct,
+  // //   score: correct ? scoreList[currentLevel] : 0,
+  // //   responseEndTime: performance.now(),
+  // //   responseStartTime: responseStartTime
+  // // })
+  // // 开始下一次
+  // // nextOnce()
+  // console.log(gameList, '当前试次用户操作数据')
 }
+
 // 发送请求
 const sendData = () => {
-  let correctCount = 0,
-    totalResponseTime = 0,
-    totalScore = 0
   if (planInfo.value) {
-    data.userAnswerList.back0.map((item) => {
-      console.log(item, item, 'back0')
-      item.map((item1) => {
-        console.log(item1.ifNeedClick, item1.ifUserClick, '0')
-        if (item1.ifNeedClick === true && item1.ifUserClick === true) {
-          console.log('正确')
-
-          totalScore += 10
-          correctCount++
-          totalResponseTime += item1.userResponseTime
+    // 计算正确反应数和总反应时
+    let { correctCount, totalResponseTime, totalScore } = gameList.reduce(
+      (obj, curr) => {
+        if (curr.correct) {
+          obj.correctCount++
         }
-      })
-    })
-    data.userAnswerList.back1.map((item) => {
-      console.log(item, 'back1')
-      item.map((item1) => {
-        console.log(item1.ifNeedClick, item1.ifUserClick, '0')
-        if (item1.ifNeedClick === true && item1.ifUserClick === true) {
-          console.log('正确')
-
-          totalScore += 10
-          correctCount++
-          totalResponseTime += item1.userResponseTime
-        }
-      })
-    })
-    data.userAnswerList.back2.map((item) => {
-      console.log(item, 'back2')
-      item.map((item1) => {
-        console.log(item1.ifNeedClick, item1.ifUserClick, '0')
-        if (item1.ifNeedClick === true && item1.ifUserClick === true) {
-          console.log('正确')
-          totalScore += 30
-          correctCount++
-          totalResponseTime += item1.userResponseTime
-        }
-      })
-    })
-    // const avrResponseTime = `${totalResponseTime}`
-    const avrResponseTime = `${(totalResponseTime / 60).toFixed(2)}ms`
+        obj.totalScore += curr.score
+        obj.totalResponseTime += curr.responseEndTime - curr.responseStartTime
+        return obj
+      },
+      { correctCount: 0, totalResponseTime: 0, totalScore: 0 }
+    )
+
+    // 平均反应时 = 总反应时 / 总试次
+    const avrResponseTime = `${(totalResponseTime / gameList.length).toFixed(2)}ms`
+
+    // 如果在60秒内猜中50个物品得30分
+    if (correctCount >= 50) {
+      totalScore += 50
+    }
+
     const { gameId, gameName, id: planId } = planInfo.value
-    const sendData = {
+    const data = {
       finish: '1',
       gameId,
       gameName,
@@ -379,179 +492,232 @@ const sendData = () => {
           name: '平均反应时',
           value: avrResponseTime
         },
+        {
+          code: 'avrResponseTime',
+          name: '最大难度',
+          value: currentLevel + 1
+        },
         {
           code: 'gameTotalTime',
           name: '游戏总时长',
           value: (Date.now() - gameStartTime_record) / 1000
         }
-        // {
-        //   code: 'avrResponseTime',
-        //   name: '最大难度',
-        //   value: 3
-        // }
       ],
       planId,
-      // gamelevel: currentLevel + 1,
+      gamelevel: currentLevel + 1,
       score: totalScore,
       userId: userStore.user.id,
       gameTotalTime: Date.now() - gameStartTime_record
     }
-    // AchievementAPI.add(sendData).then(() => {
-    //   ElMessage.success('本次训练已结束')
-    //   clearInterval(countDownInterval)
-    //   clearInterval(divShowInteval)
-    //   handleClose(() => { })
-
-    //   instance?.proxy?.$Bus.emit('trainList-refresh')
-    // })
-    // console.log('发送数据', sendData)
+
+    console.log('发送数据', data)
+
+    AchievementAPI.add(data).then(() => {
+      ElMessage.success('本次训练已结束')
+      clearInterval(timerId)
+
+      handleClose(() => {})
+
+      instance?.proxy?.$Bus.emit('trainList-refresh')
+    })
   } else {
     ElMessage.success('本次训练已结束')
-    // clearInterval(timerId)
-    clearInterval(countDownInterval)
-    clearInterval(divShowInteval)
+    clearInterval(timerId)
+
     handleClose(() => {})
     instance?.proxy?.$Bus.emit('trainList-refresh')
   }
 }
+
+const handleClose = (done: () => void) => {
+  clearInterval(timerId)
+  $emits('gameOver', 'WorkingMemory')
+}
+// const handleKeyDown = (event: any) => {
+//   if (event.altKey && event.key === 'f') {
+//     // 在这里执行要触发的逻辑
+//     console.log('Alt + B is pressed!')
+//   }
+// }
+async function exec() {
+  openDialogRef.value.openDialog()
+  gameStartTime_record = Date.now()
+  let tempPlan = sessionStorage.getItem('currentPlanInfo')
+  // console.log(onceData.value,'onceData392');
+
+  // onceData.choices = shuffleArray(onceData.choices)
+  if (tempPlan) {
+    planInfo.value = JSON.parse(tempPlan)
+  }
+  // 记录游戏开始时间戳
+  gameStartTime = performance.now()
+  // 重置游戏结束时间戳
+  gameEndTime = 0
+  // 重置当前等级
+  currentLevel = 0
+  // 重置当前试次
+  currentNumber = 0
+  // 清空游戏数据
+  gameList = []
+  // 设置第一个试次的游戏素材
+  setOnceData()
+}
 onMounted(() => {
   exec()
+  nextTick(() => {
+    window.addEventListener('keydown', handleKeyDown)
+    countDownVisible.value = true
+    // setTimetiming()
+    // console.log(onceData.value.choices, 'onceData392')
+    // onceData.value = shuffleArray(onceData.value)
+    // onceData.value.choices = shuffleArray(onceData.value.choices)
+    // countDownVisible.value = true
+    // 倒计时
+    // getTime()
+    // setTimetiming()
+  })
+})
+watchEffect(() => {
+  // console.log(onceData.value.choices, 'onceData.value.choices')
+  // onceData.value.choices = shuffleArray(onceData.value.choices)
 })
-//页面销毁方法
 onUnmounted(() => {
-  //将定时器进行清除
-  clearInterval(divShowInteval)
-  clearInterval(countDownInterval)
+  clearInterval(timerId)
 })
+// 添加键盘事件监听
 </script>
 
 <style scoped lang="scss">
-.working-memory-container {
-  background-color: #f5f4e9;
-
-  //.big-square {
-  //  // margin-top: 150px;
-  //  // width: 600px;
-  //  // height: 600px;
-  //  border: 1px solid black;
-  //  background-color: black;
-  //  display: grid;
-  //  padding: 10px;
-  //  grid-template-columns: repeat(3, 1fr);
-  //  grid-template-rows: repeat(3, 1fr);
-  //}
-
-  //.small-square {
-  //  background-color: #006fbf;
-  //  margin: 10px;
-  //}
-
-  .sable {
-    // border: 1px solid #ef49ad;
-    background: aqua;
-  }
-
-  .letterCss {
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    background-size: cover;
-    font-size: 480px;
-    font-family: PingFang SC;
-    font-weight: 800;
-    line-height: 200px;
-    color: #333333;
-    text-shadow: 0px 3px 6px rgb(0, 0, 0, 0.76);
-    opacity: 1;
-  }
-
+// .object-recognition-containers {
+//   background-color: #eff2f4;
+// }
+.breadth-training-container {
   //background-color: #f5f4e9;
+  //background-color: #2bae68;
   background-image: url('/static/image/game/bg-WorkMemory.png');
   background-size: 100% 100%;
   background-position: center center;
-  background-repeat: repeat;
 
-  .center-area {
-    background-image: url('/static/image/game/ADL/bg-center.png');
-    background-size: 100% 100%;
-    background-repeat: no-repeat;
-    background-position: center;
-    /* 可选,让图片居中对齐 */
-  }
-  .main {
-    //display: flex;
-    position: relative;
-    //flex-direction: row;
-    //justify-content: space-around;
-    //align-items: center;
-    //width: calc(100%);
-    //height: 500px;
-    background-color: black;
+  :deep(.el-progress-bar__outer) {
+    background-color: rgba(0, 0, 0, 0.1);
   }
 
-  .main > div {
-    //width: 100px;
-    //height: 100px;
-    //margin: 40px;
+  .choice-div {
+    &:hover {
+      box-shadow: 0 0 8px 1px rgba(255, 255, 255, 0.7);
+    }
   }
-
-  .main > div:nth-child(1) {
-    position: absolute;
-    top: 0;
-    left: 0;
-    background-color: #006fbf;
+  .center-bg-1 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-1.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
   }
-
-  .main > div:nth-child(2) {
-    position: absolute;
-    top: 0;
-    right: 33%;
-    //margin: 0 auto;
-    background-color: #006fbf;
+  .center-bg-2 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-2.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
   }
-
-  .main > div:nth-child(3) {
-    position: absolute;
-    top: 0;
-    right: 0;
-    background-color: #006fbf;
+  .center-bg-3 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-3.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
   }
-  .main > div:nth-child(4) {
-    position: absolute;
-    top: 33%;
-    left: 0;
-    background-color: #006fbf;
+  .center-bg-4 {
+    background-image: url('/static/image/game/LogicalReasoning/bg-4.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
   }
-  .main > div:nth-child(5) {
-    position: absolute;
-    top: 5%;
-    right: 28%;
-    //background-color: #006fbf;
+  .center-bg-k {
+    background-image: url('/static/image/game/LogicalReasoning/bg-k.png');
+    background-size: 100% 100%;
+    background-position: center center;
+    background-repeat: repeat;
   }
-  .main > div:nth-child(6) {
+  .buttonFist {
     position: absolute;
-    top: 33%;
-    right: 0;
-    background-color: #006fbf;
+    bottom: 150px;
+    font-size: 88px;
+    width: 540px;
+    height: 180px;
+    border-radius: 18px;
+
+    &:hover {
+      background-color: transparent;
+    }
+
+    &.next {
+      background-image: url('/static/image/game/ResidueRecognition/btn-next.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      border-color: transparent;
+    }
+
+    &.start {
+      background-image: url('/static/image/game/ResidueRecognition/btn-start.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      border-color: transparent;
+    }
   }
-  .main > div:nth-child(7) {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    background-color: #006fbf;
+
+  .bg-1 {
+    // margin-top: 20px;
+    // position: absolute;
+    // top: 80px;
+    background-image: url('/static/image/game/ResidueRecognition/bg-2.png');
+    background-size: 100% 100%;
+    background-position: center center;
   }
-  .main > div:nth-child(8) {
-    position: absolute;
-    bottom: 0;
-    right: 32%;
-    background-color: #006fbf;
+
+  .bg-2a {
+    cursor: pointer;
+    transition: All 0.4s ease-in-out; //设置动画执行的时间为0.6s
+
+    :hover {
+      transform: scale(1.1);
+    }
+
+    .bg-2 {
+      background-image: url('/static/image/game/ResidueRecognition/bg-3.png');
+      background-size: 100% 100%;
+      background-position: center center;
+      padding: 50px;
+    }
   }
-  .main > div:nth-child(9) {
-    position: absolute;
-    bottom: 0;
-    right: 0;
-    background-color: #006fbf;
+}
+
+.first-pass {
+  width: 400px;
+  height: 100px;
+  background-image: url('/static/image/game/ResidueRecognition/bg-4.png');
+  background-size: 100% 100%;
+  background-position: center center;
+  position: absolute;
+  font-size: 58px;
+  top: 130px;
+  left: 240px;
+  text-align: center;
+  font-weight: normal;
+  font-size: 39px;
+  color: #ffffff;
+  line-height: 100px;
+  text-shadow: 0px 4px 8px rgba(1, 54, 142, 0.53);
+
+  .first-pass-1 {
+    width: 182px;
+    height: 37px;
+    text-align: center;
+    margin-left: -40px;
+    margin-top: 20px;
+    // font-family: Alibaba PuHuiTi 2.0;
+    font-weight: normal;
+    font-size: 39px;
+    color: #a76202;
+    // line-height: 100px;
   }
 }
 </style>

+ 557 - 0
src/views/gameCenter/components/games/WorkingMemory/index.vue.bak

@@ -0,0 +1,557 @@
+<template>
+  <my-full-screen-dialog ref="openDialogRef" close-color="white" @close-dialog="handleClose">
+    <div class="working-memory-container w-full h-full flex-center">
+      <div
+        class="w-[88%] h-[88%] border-[3px] border-white bg-[#ffffffe5] rounded-[8px] shadow-lg"
+        v-if="data.testFlag"
+        @click="userClick()"
+      >
+        <div class="sable absolute left-[180px] top-[120px] Deadlock w-[1250px] h-[850px] ml-6">
+          <h1 class="sable absolute left-[400px] top-[-60px]" style="text-align: center; font-size: 80px">
+            ({{ data.nbackIndex }}-back)
+          </h1>
+          <h2
+            v-if="data.countDownSpanShow"
+            class="txt-center sable absolute left-[100px] top-[70px]"
+            style="text-align: center; font-size: 80px"
+          >
+            将在<span style="color: red; font-size: 80px">{{ data.countDownTime }}</span
+            >秒后继续测试
+          </h2>
+          <!-- <div class="letterCss txt-center" v-if="data.divShow && !data.showAdd">
+            <div class="big-square  w-[600px] h-[600px] mt-[135px]">
+              <div class="small-square" v-for="i in 9" :key="i"></div>
+            </div>
+            {{ data.currentLetter }}
+          </div> -->
+          <div class="letterCss absolute left-[180px] txt-center" v-if="data.divShow && !data.showAdd">
+            <!--          <div class="letterCss absolute left-[180px] txt-center">-->
+            <div class="big-square w-[600px] h-[600px] mt-[135px] main">
+              <div v-show="data.smallsquare === 1" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div v-show="data.smallsquare === 2" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div v-show="data.smallsquare === 3" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div v-show="data.smallsquare === 4" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div class="w-[150px] h-[150px] m-[25px]">
+                <span style="color: #ffffff; font-size: 80px">{{ data.currentLetter }}</span>
+              </div>
+              <div v-show="data.smallsquare === 6" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div v-show="data.smallsquare === 7" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div v-show="data.smallsquare === 8" class="w-[150px] h-[150px] m-[25px]"></div>
+              <div v-show="data.smallsquare === 9" class="w-[150px] h-[150px] m-[25px]"></div>
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]">-->
+              <!--                <span style="color: #ffffff; font-size: 80px">{{ data.currentLetter }}</span>-->
+              <!--              </div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+              <!--              <div class="w-[150px] h-[150px] m-[25px]"></div>-->
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <VoiceImp ref="VoiceImpRef" />
+  </my-full-screen-dialog>
+</template>
+
+<script setup lang="ts">
+/*
+ * 组件名: WorkingMemory
+ * 组件用途: 工作记忆
+ * 创建日期: 2024/9/9
+ * 编写者: JutarryWu
+ */
+import { getCurrentInstance } from 'vue'
+import { getRandomInt } from '@/utils'
+import AchievementAPI from '@/api/tester/rehabilitation/training/achievement'
+import { RTPlanMgrQuery } from '@/api/tester/rehabilitation/training/plain'
+import { useUserStore } from '@/store'
+
+interface AnswerList {
+  [key: string]: string[]
+}
+const data = reactive({
+  countDownTime: 8,
+  countDownSpanShow: false,
+  sourceLetterList: [],
+  currentLetter: '',
+  currentLetterIndex: 0,
+  resultData: {
+    exerciseList: [],
+    examList: {
+      back0: ['M', 'B', 'M', 'G', 'M', 'C', 'K', 'V', 'M', 'E'],
+      back1: ['Y', 'K', 'Y', 'Y', 'P', 'K', 'O', 'O', 'A', 'A'],
+      back2: ['M', 'B', 'M', 'B', 'M', 'C', 'K', 'C', 'K', 'O']
+    }
+  },
+  smallsquare: 0,
+  currentLetterList: [],
+  currentLetterListA: [3, 6, 3, 7, 3, 8, 4, 7, 8, 3],
+  nbackIndex: 0,
+  taskName: 'back0',
+  testTurnCount: 0,
+  taskId: '',
+  saveFlag: false,
+  subjectInfo: '',
+  divShow: false,
+  showAdd: false,
+  buttonShow: true,
+  passTestExam: false,
+  saveSuccess: false,
+  testFlag: false,
+  testType: '练习测试',
+  buttonName: '开始练习',
+  testTypeCode: 0,
+  startMilliSeconds: 0,
+  divShowInteval: null,
+  countDownInterval: null,
+  userId: '',
+  testResult: {},
+  userAnswerList: {
+    back0: [],
+    back1: [],
+    back2: []
+  },
+  testState: false,
+  back0SuccessRate: '',
+  back1SuccessRate: '',
+  back2SuccessRate: '',
+  back0backAverageTime: '',
+  back1backAverageTime: '',
+  back2backAverageTime: '',
+  count: 0
+})
+let countDownInterval: any
+let divShowInteval: any
+const $emits = defineEmits(['gameOver'])
+const openDialogRef = ref()
+const VoiceImpRef = ref()
+const handleClose = (done: () => void) => {
+  $emits('gameOver', 'WorkingMemory')
+  clearInterval(countDownInterval)
+  clearInterval(divShowInteval)
+}
+
+const instance = getCurrentInstance()
+const planInfo = ref<RTPlanMgrQuery>()
+const userStore = useUserStore()
+let gameStartTime_record = 0
+
+async function exec() {
+  openDialogRef.value.openDialog()
+  const tempPlan = sessionStorage.getItem('currentPlanInfo')
+  gameStartTime_record = Date.now()
+  if (tempPlan) {
+    planInfo.value = JSON.parse(tempPlan)
+  }
+  await nextTick(() => {
+    // countDown()
+    startTest()
+  })
+}
+function countDown() {
+  // 测试时间倒计时
+  countDownInterval = setInterval(() => {
+    data.countDownTime--
+    if (data.countDownTime == 0) {
+      //开始测试
+      // this.startTest();
+      startTest()
+      // 清除定时器
+      clearInterval(countDownInterval)
+      data.countDownTime = 8
+      // startTest();
+      // countDown()
+    }
+  }, 1000)
+}
+function startTest() {
+  data.divShow = true
+  data.countDownSpanShow = false
+  pageDataInit()
+
+  divShowInteval = setInterval(() => {
+    data.showAdd = true
+    // data.backgroundColor = ''
+    // if (data.testTypeCode == 1) {
+    //   data.count++;
+    // }
+    divRandomShow()
+  }, 2000)
+}
+function divRandomShow() {
+  // console.log('执行了')
+  // showRandomValue()
+  // console.log(data.currentLetterIndex, 'data.currentLetterIndex146')
+
+  if (data.currentLetterIndex == data.currentLetterList.length) {
+    // console.log('长度相等清除定时器', data.currentLetterList.length)
+    clearInterval(divShowInteval)
+    currentTurnCompute()
+  } else {
+    let tempObj = data.currentLetterList[data.currentLetterIndex]
+    data.smallsquare = data.currentLetterListA[data.currentLetterIndex]
+    // console.log(data.currentLetterList, 'data.currentLetterList');
+    // console.log(tempObj, 'tempObjdata.currentLetter', data.currentLetterIndex, '显示字母索引')
+    data.currentLetter = ''
+    setTimeout(() => {
+      data.currentLetter = tempObj.letter
+      data.startMilliSeconds = new Date().getTime()
+      data.showAdd = false
+    }, 1000)
+    data.currentLetterIndex++
+  }
+
+  // if (this.currentLetterIndex == this.currentLetterList.length) {
+  //       clearInterval(this.divShowInteval);
+  //       this.currentTurnCompute();
+  //     } else {
+  //       let tempObj = this.currentLetterList[this.currentLetterIndex];
+  //       this.currentLetter = tempObj.letter;
+  //       setTimeout(() => {
+  //         this.startMilliSeconds = new Date().getTime();
+  //         this.showAdd = false;
+  //       }, 1000);
+  //       this.currentLetterIndex++;
+  //     }
+}
+function currentTurnCompute() {
+  //正式测试时,需要根据情况进行切换任务类型
+  //正式测试时的逻辑
+  data.divShow = false
+  data.testTurnCount++
+  data.currentLetterIndex = 0
+  // console.log(data.testTurnCount, '153', data.nbackIndex)
+  // console.log(data.userAnswerList, 'data.userAnswerList', data.currentLetterList, 'data.currentLetterList')
+  if (data.nbackIndex == 0) {
+    data.userAnswerList.back0.push(data.currentLetterList)
+
+    if (data.testTurnCount == 2) {
+      data.nbackIndex++
+      data.countDownSpanShow = true
+      data.taskName = 'back' + data.nbackIndex
+      data.testTurnCount = 0
+    }
+    data.countDownSpanShow = true
+    countDown()
+  } else if (data.nbackIndex == 1) {
+    data.userAnswerList.back1.push(data.currentLetterList)
+    if (data.testTurnCount == 2) {
+      data.nbackIndex++
+      data.countDownSpanShow = true
+      data.taskName = 'back' + data.nbackIndex
+      data.testTurnCount = 0
+    }
+    data.countDownSpanShow = true
+    countDown()
+  } else if (data.nbackIndex == 2) {
+    data.userAnswerList.back2.push(data.currentLetterList)
+    if (data.testTurnCount == 2) {
+      data.testState = false
+      data.testFlag = false
+      //用户数据保存
+      sendData()
+      // data.userAnswerPost();
+      clearInterval(countDownInterval)
+      // this.$message({
+      //   message: "测试结束!",
+      //   type: "success",
+      // });
+      // screenfull.exit();
+      return ''
+    } else {
+      data.countDownSpanShow = true
+      countDown()
+    }
+  }
+}
+function pageDataInit() {
+  data.testFlag = true
+  // console.log('pageDataInit', 'data.testTypeCode', data.testTypeCode, 'data.taskName', data.taskName)
+  // console.log('data.resultData.examList', data.resultData.examList[data.taskName])
+  // data.sourceLetterList = data.resultData.examList[data.taskName][data.testTurnCount];
+  // console.log(data.sourceLetterList, 'data.sourceLetterList')
+  // data.currentLetterList = data.resultData.examList[data.taskName]
+  data.sourceLetterList = data.resultData.examList[data.taskName]
+  createCurrentLetterList(data.sourceLetterList)
+}
+function createCurrentLetterList(sourceLetterList: any) {
+  data.currentLetterList = []
+  for (var i = 0; i < sourceLetterList.length; i++) {
+    let tempObj = {
+      letter: sourceLetterList[i],
+      ifNeedClick: false,
+      ifUserClick: false,
+      userResponseTime: 0
+    }
+    if (i == 0 || i < data.nbackIndex) {
+      data.currentLetterList.push(tempObj)
+    } else {
+      if (
+        (data.sourceLetterList[i] == sourceLetterList[0] && data.nbackIndex == 0) ||
+        (data.sourceLetterList[i] == sourceLetterList[i - data.nbackIndex] && data.nbackIndex != 0)
+      ) {
+        tempObj.ifNeedClick = true
+      }
+      data.currentLetterList.push(tempObj)
+    }
+  }
+  console.log(data.currentLetterList, '.letter')
+}
+function userClick() {
+  //用户点击动作
+  if (data.currentLetterIndex - 1 >= 0) {
+    data.currentLetterList[data.currentLetterIndex - 1].ifUserClick = true
+    data.currentLetterList[data.currentLetterIndex - 1].userResponseTime = new Date().getTime() - data.startMilliSeconds
+    // console.log(new Date().getTime() - data.startMilliSeconds)
+    // console.log(data.currentLetterList, 'currentLetterList')
+  }
+  console.log(data.currentLetterList, 'currentLetterList', 312)
+}
+// 发送请求
+const sendData = () => {
+  let correctCount = 0,
+    totalResponseTime = 0,
+    totalScore = 0
+  if (planInfo.value) {
+    data.userAnswerList.back0.map((item) => {
+      console.log(item, item, 'back0')
+      item.map((item1) => {
+        console.log(item1.ifNeedClick, item1.ifUserClick, '0')
+        if (item1.ifNeedClick === true && item1.ifUserClick === true) {
+          console.log('正确')
+
+          totalScore += 10
+          correctCount++
+          totalResponseTime += item1.userResponseTime
+        }
+      })
+    })
+    data.userAnswerList.back1.map((item) => {
+      console.log(item, 'back1')
+      item.map((item1) => {
+        console.log(item1.ifNeedClick, item1.ifUserClick, '0')
+        if (item1.ifNeedClick === true && item1.ifUserClick === true) {
+          console.log('正确')
+
+          totalScore += 10
+          correctCount++
+          totalResponseTime += item1.userResponseTime
+        }
+      })
+    })
+    data.userAnswerList.back2.map((item) => {
+      console.log(item, 'back2')
+      item.map((item1) => {
+        console.log(item1.ifNeedClick, item1.ifUserClick, '0')
+        if (item1.ifNeedClick === true && item1.ifUserClick === true) {
+          console.log('正确')
+          totalScore += 30
+          correctCount++
+          totalResponseTime += item1.userResponseTime
+        }
+      })
+    })
+    // const avrResponseTime = `${totalResponseTime}`
+    const avrResponseTime = `${(totalResponseTime / 60).toFixed(2)}ms`
+    const { gameId, gameName, id: planId } = planInfo.value
+    const sendData = {
+      finish: '1',
+      gameId,
+      gameName,
+      paramList: [
+        {
+          code: 'score',
+          name: '得分',
+          value: totalScore
+        },
+        {
+          code: 'correctCount',
+          name: '正确反应数',
+          value: correctCount
+        },
+        {
+          code: 'avrResponseTime',
+          name: '平均反应时',
+          value: avrResponseTime
+        },
+        {
+          code: 'gameTotalTime',
+          name: '游戏总时长',
+          value: (Date.now() - gameStartTime_record) / 1000
+        }
+        // {
+        //   code: 'avrResponseTime',
+        //   name: '最大难度',
+        //   value: 3
+        // }
+      ],
+      planId,
+      // gamelevel: currentLevel + 1,
+      score: totalScore,
+      userId: userStore.user.id,
+      gameTotalTime: Date.now() - gameStartTime_record
+    }
+    // AchievementAPI.add(sendData).then(() => {
+    //   ElMessage.success('本次训练已结束')
+    //   clearInterval(countDownInterval)
+    //   clearInterval(divShowInteval)
+    //   handleClose(() => { })
+
+    //   instance?.proxy?.$Bus.emit('trainList-refresh')
+    // })
+    // console.log('发送数据', sendData)
+  } else {
+    ElMessage.success('本次训练已结束')
+    // clearInterval(timerId)
+    clearInterval(countDownInterval)
+    clearInterval(divShowInteval)
+    handleClose(() => {})
+    instance?.proxy?.$Bus.emit('trainList-refresh')
+  }
+}
+onMounted(() => {
+  exec()
+})
+//页面销毁方法
+onUnmounted(() => {
+  //将定时器进行清除
+  clearInterval(divShowInteval)
+  clearInterval(countDownInterval)
+})
+</script>
+
+<style scoped lang="scss">
+.working-memory-container {
+  background-color: #f5f4e9;
+
+  //.big-square {
+  //  // margin-top: 150px;
+  //  // width: 600px;
+  //  // height: 600px;
+  //  border: 1px solid black;
+  //  background-color: black;
+  //  display: grid;
+  //  padding: 10px;
+  //  grid-template-columns: repeat(3, 1fr);
+  //  grid-template-rows: repeat(3, 1fr);
+  //}
+
+  //.small-square {
+  //  background-color: #006fbf;
+  //  margin: 10px;
+  //}
+
+  .sable {
+    // border: 1px solid #ef49ad;
+    background: aqua;
+  }
+
+  .letterCss {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background-size: cover;
+    font-size: 480px;
+    font-family: PingFang SC;
+    font-weight: 800;
+    line-height: 200px;
+    color: #333333;
+    text-shadow: 0px 3px 6px rgb(0, 0, 0, 0.76);
+    opacity: 1;
+  }
+
+  //background-color: #f5f4e9;
+  background-image: url('/static/image/game/bg-WorkMemory.png');
+  background-size: 100% 100%;
+  background-position: center center;
+  background-repeat: repeat;
+
+  .center-area {
+    background-image: url('/static/image/game/ADL/bg-center.png');
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    background-position: center;
+    /* 可选,让图片居中对齐 */
+  }
+  .main {
+    //display: flex;
+    position: relative;
+    //flex-direction: row;
+    //justify-content: space-around;
+    //align-items: center;
+    //width: calc(100%);
+    //height: 500px;
+    background-color: black;
+  }
+
+  .main > div {
+    //width: 100px;
+    //height: 100px;
+    //margin: 40px;
+  }
+
+  .main > div:nth-child(1) {
+    position: absolute;
+    top: 0;
+    left: 0;
+    background-color: #006fbf;
+  }
+
+  .main > div:nth-child(2) {
+    position: absolute;
+    top: 0;
+    right: 33%;
+    //margin: 0 auto;
+    background-color: #006fbf;
+  }
+
+  .main > div:nth-child(3) {
+    position: absolute;
+    top: 0;
+    right: 0;
+    background-color: #006fbf;
+  }
+  .main > div:nth-child(4) {
+    position: absolute;
+    top: 33%;
+    left: 0;
+    background-color: #006fbf;
+  }
+  .main > div:nth-child(5) {
+    position: absolute;
+    top: 5%;
+    right: 28%;
+    //background-color: #006fbf;
+  }
+  .main > div:nth-child(6) {
+    position: absolute;
+    top: 33%;
+    right: 0;
+    background-color: #006fbf;
+  }
+  .main > div:nth-child(7) {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    background-color: #006fbf;
+  }
+  .main > div:nth-child(8) {
+    position: absolute;
+    bottom: 0;
+    right: 32%;
+    background-color: #006fbf;
+  }
+  .main > div:nth-child(9) {
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    background-color: #006fbf;
+  }
+}
+</style>

+ 104 - 0
src/views/gameCenter/components/games/WorkingMemory/topics.json

@@ -0,0 +1,104 @@
+[
+  [
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/中上.png",
+        "/static/image/game/WorkingMemory/中下.png",
+        "/static/image/game/WorkingMemory/右上.png",
+        "/static/image/game/WorkingMemory/右下.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/右上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/左中.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/右下.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中下.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/左下.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/中上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    },
+    {
+      "question": "/static/image/game/WorkingMemory/左上.png",
+      "choices": [
+        "/static/image/game/WorkingMemory/右中.png",
+        "/static/image/game/WorkingMemory/左上.png",
+        "/static/image/game/WorkingMemory/左下.png",
+        "/static/image/game/WorkingMemory/左中.png"
+      ],
+      "answer": "/static/image/game/WorkingMemory/中上.png"
+    }
+  ]
+]

+ 5 - 1
src/views/information/manage/doc.vue

@@ -222,7 +222,11 @@ const submitForm = async (formEl: FormInstance | undefined) => {
         type: ruleForm.type,
         phone: ruleForm.phone
       }
-      UserAPI.update(params).then((response) => {})
+      UserAPI.update(params).then((response) => {
+        console.log(response, '更新')
+        ElMessage.success('更新成功')
+        getUserInfo()
+      })
     } else {
       console.log('error submit!', fields)
     }