|
@@ -0,0 +1,446 @@
|
|
|
+<template>
|
|
|
+ <div class="txt-center">
|
|
|
+ <div v-show="state.testResultStrShow" style="width: 650px; margin: 20px auto; line-height: 2">
|
|
|
+ <p style="margin-top: 20%; font-size: 30px">
|
|
|
+ {{ state.testResultStr }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div v-if="state.testFlag" :class="{ testMainDiv: !state.testState, activeTask: state.testState }"
|
|
|
+ @contextmenu.prevent="" @click.left="userClick('L')" @click.right="userClick('R')">
|
|
|
+ <div class="taskHead">
|
|
|
+ <div class="scale" @click.stop="screen">
|
|
|
+ <img src="../../assets/small-big.png" alt="" />
|
|
|
+ </div>
|
|
|
+ <el-progress class="main_progress" color="linear-gradient(to right, #ffd650, #ff8431)" :stroke-width="48"
|
|
|
+ :text-inside="true" :format="format" :percentage="(state.imgIndex * 100) / 120" v-if="state.testTypeCode == 1"
|
|
|
+ style="width:50%"></el-progress>
|
|
|
+ </div>
|
|
|
+ <div class="glass">
|
|
|
+ <p v-show="state.countDownShow" class="countdownStr">
|
|
|
+ {{ state.countDownStr }}
|
|
|
+ </p>
|
|
|
+ <img v-show="state.showDuckEgg" :src="state.examImgUrl" alt="" class="shapeImg" />
|
|
|
+ </div>
|
|
|
+ <!-- <img v-show="showWhiteFlag" src='../../assets/congnitiveAblitity/whiteFlag.png' alt="" style="width: 50px; height: 50px; margin-top: 20%"> -->
|
|
|
+ <!-- 演示使用 -->
|
|
|
+ <!-- <div class="steering">
|
|
|
+ <el-button type="primary" icon="el-icon-arrow-left" @click="userClick('L')"></el-button>
|
|
|
+ <el-button type="primary" @click="userClick('R')"><i class="el-icon-arrow-right el-icon--right"></i></el-button>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
|
|
|
+import { useRoute } from 'vue-router';
|
|
|
+import { userInfoStore } from '@/stores';
|
|
|
+import { saveEggRecordApi } from '@/api/record';
|
|
|
+import { format as myFormat } from 'date-fns';
|
|
|
+import { preloader } from '@/utils/utils';
|
|
|
+import screenfull from 'screenfull';
|
|
|
+import { requireImg } from '@/utils/utils';
|
|
|
+
|
|
|
+const userInfo = userInfoStore();
|
|
|
+const route = useRoute();
|
|
|
+
|
|
|
+// 定义响应式数据
|
|
|
+const state = reactive({
|
|
|
+ userId: "",
|
|
|
+ userTestResult: {},
|
|
|
+ imgUrl: "",
|
|
|
+ examImgUrl: "",
|
|
|
+ taskId: "", // 认知任务id
|
|
|
+ testFlag: false,
|
|
|
+ testState: false,
|
|
|
+ saveFlag: false, // 结果保存按钮显示标志
|
|
|
+ subjectInfo: "", // 认知任务详情
|
|
|
+ button0Show: true, // 控制按钮显示隐藏
|
|
|
+ button1Show: false, // 控制按钮显示隐藏
|
|
|
+ buttonName: "开始测试", // 正式测试 // 重新练习
|
|
|
+ testTypeCode: 0, // 0-练习测试 1-正式测试 2-重新测试
|
|
|
+ imgIndex: 0,
|
|
|
+ userTestPicList: [], // 用户点击图片列表
|
|
|
+ showImage: true,
|
|
|
+ difficultList: [0], // [0,10,30,45,60,90,120,180,360]
|
|
|
+ testPicCount: 10, // 测试数目
|
|
|
+ userRightClickDirection: "", // 测试者应该点击的方向
|
|
|
+ userRightResponseCount: 0, // 测试者反应正确的次数
|
|
|
+ showDuckEgg: false,
|
|
|
+ countDownTime: 6, // 开始前的倒计时
|
|
|
+ countDownStr: "练习马上开始!",
|
|
|
+ countDownShow: true,
|
|
|
+ testTunrnCount: 0, // 正式测试轮数
|
|
|
+ testEndFlag: false, // 测试结束标志
|
|
|
+ testResultStrShow: false, // 测试结果展示
|
|
|
+ testResultStr: "", // 测试成绩
|
|
|
+ userCanClick: true, // 用户标识用户单次刺激只能点击一次
|
|
|
+ myInterval: null,
|
|
|
+ timeOne: null,
|
|
|
+ timeTwo: null,
|
|
|
+ startMilliSeconds: 0, // 反应时
|
|
|
+ userResponseRecords: [], // 用户测试反应记录
|
|
|
+ saveFalg: true,
|
|
|
+ requireImg: requireImg
|
|
|
+});
|
|
|
+
|
|
|
+// 页面初始化函数
|
|
|
+const init = (taskId) => {
|
|
|
+ startTest(1);
|
|
|
+};
|
|
|
+
|
|
|
+// 用户点击事件
|
|
|
+const userClick = (clickFlag) => {
|
|
|
+ if (state.countDownShow || !state.userCanClick) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ state.userCanClick = false;
|
|
|
+ const milliSecondsCount = new Date().getTime() - state.startMilliSeconds;
|
|
|
+ let userResponseStr = "Wrong";
|
|
|
+ clearTimeout(state.timeOne);
|
|
|
+
|
|
|
+ // 用户反应正确性判断
|
|
|
+ if (state.userRightClickDirection === clickFlag) {
|
|
|
+ state.userRightResponseCount++;
|
|
|
+ userResponseStr = "Right";
|
|
|
+ }
|
|
|
+ // 判断是否测试结束
|
|
|
+ if (state.imgIndex === state.userTestPicList.length) {
|
|
|
+ state.testEndFlag = true;
|
|
|
+ }
|
|
|
+ // 记录用户反应
|
|
|
+ if (state.testTypeCode === 1) {
|
|
|
+ state.userResponseRecords.push({
|
|
|
+ index: state.imgIndex,
|
|
|
+ rightOrWrong: userResponseStr,
|
|
|
+ responseTime: milliSecondsCount,
|
|
|
+ diff: state.userTestPicList[state.imgIndex - 1].diff,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ state.showDuckEgg = false;
|
|
|
+ state.timeTwo = setTimeout(() => {
|
|
|
+ showTargetNow();
|
|
|
+ }, 500);
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化进度条文本
|
|
|
+const format = (percentage) => {
|
|
|
+ return percentage === 100 ? "测试已完成" : "任务进度";
|
|
|
+};
|
|
|
+
|
|
|
+// 切换全屏
|
|
|
+const screen = () => {
|
|
|
+ screenfull.toggle();
|
|
|
+};
|
|
|
+
|
|
|
+// 开始测试
|
|
|
+const startTest = (testType) => {
|
|
|
+ if (testType === 0) {
|
|
|
+ state.testTypeCode = 0;
|
|
|
+ } else {
|
|
|
+ state.saveFalg = true;
|
|
|
+ state.testTypeCode = 1;
|
|
|
+ }
|
|
|
+ state.userId = sessionStorage.getItem("b80bb7740288fda1f201890375a60c8f");
|
|
|
+ if (state.testTypeCode === 1) {
|
|
|
+ state.difficultList = [360, 180, 90, 60, 30, 0];
|
|
|
+ state.imgIndex = 0;
|
|
|
+ state.countDownStr = "马上开始!";
|
|
|
+ state.countDownTime = 6;
|
|
|
+ state.testEndFlag = false;
|
|
|
+ state.showDuckEgg = false;
|
|
|
+ state.userTestPicList = [];
|
|
|
+ }
|
|
|
+ state.countDownShow = true;
|
|
|
+ userTestPicListCreate();
|
|
|
+ // 预加载图片后开始测试
|
|
|
+ preloader(state.userTestPicList, () => {
|
|
|
+ state.testFlag = true;
|
|
|
+ state.testState = true;
|
|
|
+ countDown();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 显示目标图片
|
|
|
+const showTargetNow = () => {
|
|
|
+ state.showDuckEgg = false;
|
|
|
+ if (state.testEndFlag) {
|
|
|
+ computeScore();
|
|
|
+ } else {
|
|
|
+ state.userRightClickDirection = state.userTestPicList[state.imgIndex].imgDirection;
|
|
|
+ state.examImgUrl = state.userTestPicList[state.imgIndex].imgUrl;
|
|
|
+ state.showDuckEgg = true;
|
|
|
+ state.imgIndex++;
|
|
|
+ state.startMilliSeconds = new Date().getTime();
|
|
|
+ state.userCanClick = true;
|
|
|
+
|
|
|
+ if (state.imgIndex === state.userTestPicList.length) {
|
|
|
+ state.testEndFlag = true;
|
|
|
+ }
|
|
|
+ state.timeOne = setTimeout(ifShowNextOne, 10 * 1000, state.imgIndex);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 超时显示下一个目标
|
|
|
+const ifShowNextOne = (needClickIndex) => {
|
|
|
+ if (needClickIndex === state.imgIndex) {
|
|
|
+ userClick("NULL");
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 计算分数
|
|
|
+const computeScore = async () => {
|
|
|
+ screenfull.exit();
|
|
|
+ if (state.testTypeCode === 0) {
|
|
|
+ state.testFlag = false;
|
|
|
+ state.testState = false;
|
|
|
+ state.countDownStr = "练习马上开始!";
|
|
|
+ state.userRightResponseCount = 0;
|
|
|
+ state.imgIndex = 0;
|
|
|
+ state.countDownTime = 6;
|
|
|
+ state.testEndFlag = false;
|
|
|
+ state.showDuckEgg = false;
|
|
|
+ state.userTestPicList = [];
|
|
|
+ state.button1Show = true;
|
|
|
+ alert("测试结束!");
|
|
|
+ } else {
|
|
|
+ const userScore = ((state.userRightResponseCount / state.userResponseRecords.length) * 100).toFixed(2);
|
|
|
+ state.testFlag = false;
|
|
|
+ state.testState = false;
|
|
|
+ state.button0Show = false;
|
|
|
+ state.button1Show = false;
|
|
|
+ if (state.saveFalg) {
|
|
|
+ const result = {
|
|
|
+ beginTime: myFormat(new Date().getTime(), "yyyy-MM-dd HH:mm:ss"),
|
|
|
+ id: "string",
|
|
|
+ orgName: userInfo.userInfo.orgName,
|
|
|
+ orgNo: userInfo.userInfo.orgNo,
|
|
|
+ planId: "8af17884920ed25001920edbf62f003a",
|
|
|
+ planName: "",
|
|
|
+ taskFlag: "SHAPE_RANDOM",
|
|
|
+ taskName: "形状知觉测试(随机)",
|
|
|
+ testRecord: JSON.stringify(state.userResponseRecords),
|
|
|
+ testResult: JSON.stringify({ userScore }),
|
|
|
+ type: 1,
|
|
|
+ userName: userInfo.userInfo.userName,
|
|
|
+ userNo: userInfo.userInfo.userNo
|
|
|
+ };
|
|
|
+ const res = await saveEggRecordApi(result);
|
|
|
+ console.log(res);
|
|
|
+ alert("测试结束!");
|
|
|
+ state.saveFalg = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 创建用户测试图片列表
|
|
|
+const userTestPicListCreate = () => {
|
|
|
+ let imgObj = {
|
|
|
+ // imgUrl: '',
|
|
|
+ // imgDirection: '',
|
|
|
+ // userClickDirection: ''
|
|
|
+ };
|
|
|
+ if (state.testTypeCode === 0) {
|
|
|
+ const imgIndexList = getRandomNumber(10, 20);
|
|
|
+ for (let j = 0; j < state.difficultList.length; j++) {
|
|
|
+ for (let i = 0; i < imgIndexList.length; i++) {
|
|
|
+ imgObj = {};
|
|
|
+ if (i % 2 === 0) {
|
|
|
+ imgObj.imgUrl = requireImg(`../assets/cognize/shapeIntuition/R_ELP_test_jitter${state.difficultList[j]}_s${imgIndexList[i]}.jpg`);
|
|
|
+ imgObj.imgDirection = "R";
|
|
|
+ imgObj.userClickDirection = "";
|
|
|
+ } else {
|
|
|
+ imgObj.imgUrl = requireImg(`../assets/cognize/shapeIntuition/ELP_test_jitter${state.difficultList[j]}_s${imgIndexList[i]}.jpg`);
|
|
|
+ imgObj.imgDirection = "L";
|
|
|
+ imgObj.userClickDirection = "";
|
|
|
+ }
|
|
|
+ state.userTestPicList.push(imgObj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ shuffle(state.userTestPicList);
|
|
|
+ } else {
|
|
|
+ for (let j = 0; j < state.difficultList.length; j++) {
|
|
|
+ const tempList = [];
|
|
|
+ for (let i = 1; i < 11; i++) {
|
|
|
+ imgObj = {};
|
|
|
+ imgObj.imgUrl = requireImg(`../assets/cognize/shapeIntuition/R_ELP_test_jitter${state.difficultList[j]}_s${i}.jpg`);
|
|
|
+ imgObj.imgDirection = "R";
|
|
|
+ imgObj.userClickDirection = "";
|
|
|
+ imgObj.diff = state.difficultList[j];
|
|
|
+ tempList.push(imgObj);
|
|
|
+ imgObj = {};
|
|
|
+ imgObj.imgUrl = requireImg(`../assets/cognize/shapeIntuition/ELP_test_jitter${state.difficultList[j]}_s${i}.jpg`);
|
|
|
+ imgObj.imgDirection = "L";
|
|
|
+ imgObj.userClickDirection = "";
|
|
|
+ imgObj.diff = state.difficultList[j];
|
|
|
+ tempList.push(imgObj);
|
|
|
+ }
|
|
|
+ state.userTestPicList = state.userTestPicList.concat(tempList);
|
|
|
+ state.testPicCount = state.userTestPicList.length;
|
|
|
+ }
|
|
|
+ shuffle(state.userTestPicList);
|
|
|
+ console.log(state.userTestPicList);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 生成随机数
|
|
|
+const getRandomNumber = (size, maxNumber) => {
|
|
|
+ const numberList = [];
|
|
|
+ for (let i = 0; i < size; i++) {
|
|
|
+ numberList.push(Math.floor(Math.random() * maxNumber) + 1);
|
|
|
+ }
|
|
|
+ return numberList;
|
|
|
+};
|
|
|
+
|
|
|
+// 倒计时
|
|
|
+const countDown = () => {
|
|
|
+ state.myInterval = setInterval(() => {
|
|
|
+ state.countDownTime--;
|
|
|
+ state.countDownStr = state.countDownTime;
|
|
|
+ if (state.countDownTime === 0) {
|
|
|
+ state.countDownShow = false;
|
|
|
+ showTargetNow();
|
|
|
+ clearInterval(state.myInterval);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+};
|
|
|
+
|
|
|
+// 洗牌算法
|
|
|
+const shuffle = (arr) => {
|
|
|
+ let i = arr.length, t, j;
|
|
|
+ while (i) {
|
|
|
+ j = Math.floor(Math.random() * i--);
|
|
|
+ t = arr[i];
|
|
|
+ arr[i] = arr[j];
|
|
|
+ arr[j] = t;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 页面初始化
|
|
|
+onMounted(() => {
|
|
|
+ state.taskId = route.query.taskId;
|
|
|
+ init(state.taskId);
|
|
|
+});
|
|
|
+
|
|
|
+// 清理定时器
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ clearInterval(state.myInterval);
|
|
|
+ clearTimeout(state.timeOne);
|
|
|
+ clearTimeout(state.timeTwo);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.testMainDiv {
|
|
|
+ margin: 0 auto;
|
|
|
+ margin-top: 10px;
|
|
|
+ background: gray;
|
|
|
+ background-size: cover;
|
|
|
+ /* text-align:center; */
|
|
|
+ width: 500px;
|
|
|
+ height: 300px;
|
|
|
+ /* object-fit:fill; */
|
|
|
+}
|
|
|
+
|
|
|
+.activeTask {
|
|
|
+ background: url(../assets/cognize/shapeIntuition.png) no-repeat center;
|
|
|
+ background-size: cover;
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.scaleName {
|
|
|
+ margin-top: 70px;
|
|
|
+ background-size: cover;
|
|
|
+}
|
|
|
+
|
|
|
+.scaleButton {
|
|
|
+ margin-top: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ background-size: cover;
|
|
|
+}
|
|
|
+
|
|
|
+.steering {
|
|
|
+ width: 50%;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 20%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+
|
|
|
+.steering .left {
|
|
|
+ width: 60px;
|
|
|
+ height: 60px;
|
|
|
+ background: url(../../assets/left.png) no-repeat center;
|
|
|
+}
|
|
|
+
|
|
|
+.steering .right {
|
|
|
+ width: 60px;
|
|
|
+ height: 60px;
|
|
|
+ background: url(../../assets/right.png) no-repeat center;
|
|
|
+ margin-left: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.imgBox {
|
|
|
+ font-size: 50px;
|
|
|
+ color: black;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+}
|
|
|
+
|
|
|
+.shapeImg {
|
|
|
+ width: 20vw;
|
|
|
+ min-width: 200px;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+}
|
|
|
+
|
|
|
+.addImg {
|
|
|
+ width: 71px;
|
|
|
+ width: 71px;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+}
|
|
|
+
|
|
|
+.countdownStr {
|
|
|
+ width: 70%;
|
|
|
+ position: absolute;
|
|
|
+ top: 40%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ color: black;
|
|
|
+ font-size: 70px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 100px;
|
|
|
+}
|
|
|
+
|
|
|
+.main_progress .el-progress-bar__inner {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #ff3c3c !important;
|
|
|
+ text-align: right;
|
|
|
+ border-radius: 100px;
|
|
|
+ line-height: 1;
|
|
|
+ white-space: nowrap;
|
|
|
+ transition: width 0.6s ease;
|
|
|
+ background-image: linear-gradient(to right, #ffd650, #ff8431) !important;
|
|
|
+}
|
|
|
+
|
|
|
+.main_progress {
|
|
|
+ width: 50%;
|
|
|
+ margin-left: 10%;
|
|
|
+}
|
|
|
+</style>
|